美文网首页
单表增删改查通用方法(也涉及多表关联),使用反射动态返回Obje

单表增删改查通用方法(也涉及多表关联),使用反射动态返回Obje

作者: 墨色尘埃 | 来源:发表于2018-10-30 15:21 被阅读94次

    有一个需求:对一个页面上的操作进行增删改查,每一个页面的增、删、改、查都涉及到两张表,即原表和备份表。因为涉及到的增删改查太多,所以增/删/改/查分别用一个通用方法来实现

    页面结构.png image.png

    1、如果只用一个通用的方法会遇到一个问题,即权限问题。通过分配url权限控制某人只能对人口库进行操作而不能对经济库操作,所以将通用方法写在一个父类BaseController中,子类xxControl继承BaseController,即可对url进行权限控制了。

    BaseController

    package com.cicdi.servertemplate.modules.baselibrary.control;
    
    import com.baomidou.mybatisplus.mapper.BaseMapper;
    import com.baomidou.mybatisplus.plugins.Page;
    import com.baomidou.mybatisplus.service.impl.ServiceImpl;
    import com.cicdi.servertemplate.common.model.ResponseObj;
    import com.cicdi.servertemplate.common.model.RetCode;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.transaction.annotation.Transactional;
    import org.springframework.web.bind.annotation.ModelAttribute;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    
    import java.io.Serializable;
    import java.lang.reflect.InvocationTargetException;
    import java.util.List;
    
    import javax.validation.Valid;
    
    /**
     * 增删改差基础Controller
     *
     * @param <S> Service类型
     * @param <M> Mapper类型
     * @param <T> 增删改差的对象类型
     * @param <I> id的类型,主键的数据类型
     */
    public class BaseController<S extends ServiceImpl<M, T>, M extends BaseMapper<T>, T, I extends Serializable> {
    
        @Autowired
        protected S service;
    
        @Autowired
        protected M mapper;
    
        @Autowired
        private BaseExecute<T> baseExecute;
    
    
        /**
         * 查询过滤属性使用,直接将要过滤的属性设置为Null即可
         *
         * @param object
         * @return
         */
        protected void queryFilter(T object) {
    
        }
    
    
        /**
         * 插入需要变换的值,或者校验的值
         *
         * @param object
         * @return
         */
        protected boolean commitFilter(T object) {
            return true;
        }
    
    
        /**
         * @param model 传入id查询
         * @return 返回Object而不是泛型T
         * selectOne
         * selectPage
         */
        @RequestMapping(value = "/selectById", method = RequestMethod.GET)
        public ResponseObj<Object> selectById(@ModelAttribute T model) {
            return baseExecute.selectById(model,service);
    
        }
    
    
    //    /**
    //     * 返回列表
    //     *
    //     * @return
    //     */
    //    @RequestMapping(value = "/list", method = RequestMethod.GET)
    //    public ResponseObj<List<T>> list(@ModelAttribute T model) {
    //        return baseExecute.list(model, service);
    //    }
    
    
        /**
         * @param page 查询一般传入参数为current和size, 例如/listPage?current=1&size=5,
         * @return 返回分页数据
         */
        @RequestMapping(value = "/page", method = RequestMethod.GET)
        public ResponseObj<Page<T>> listPage(@ModelAttribute Page<T> page, @ModelAttribute T model) {
    
            return baseExecute.listPage(page, model, service);
        }
    
    
        /**
         * insert主要是在insert和update要分开权限的时候使用
         *
         * @param object
         * @return
         */
        @RequestMapping(value = "/insert", method = RequestMethod.POST)
        @Transactional
        public ResponseObj<Boolean> insert(@RequestBody @Valid T object) throws NoSuchMethodException,
                IllegalAccessException, InvocationTargetException {
            return baseExecute.insert(object);
        }
    
        /**
         * update主要是在insert和update要分开权限的时候使用
         *
         * @param object
         * @return
         */
        @RequestMapping(value = "/upd", method = RequestMethod.POST)
        @Transactional
        public ResponseObj<Boolean> update(@RequestBody @Valid T object) {
            return baseExecute.update(object);
        }
    
    
        /**
         * 根据ID删除数据
         *
         * @return
         */
        @RequestMapping(value = "/del", method = RequestMethod.POST)
        @Transactional
        public ResponseObj<Boolean> del(@RequestBody List<T> list) {
            return baseExecute.deletebylogic(list);
        }
    
    
        /**
         * 批量删除
         */
        @RequestMapping(value = "/deleteBatch", method = RequestMethod.POST)
        @Transactional
        public ResponseObj<Boolean> delList(@RequestBody List<I> ids) {
            boolean result = service.deleteBatchIds(ids);
            RetCode retCode = result ? RetCode.SUCCESS : RetCode.FAIL;
            return new ResponseObj<>(result, retCode);
        }
    
    
    }
    
    

    BaseExecute
    ①对于selectById方法,参数传入ServiceImpl service,而这个service是BaseController中定义的,传入service之后可以使用mybatis-plus的一些方法
    ②对于listPage方法,使用了分页查询,传入的参数object即是条件,如果同时需要模糊查询,对model中的对应属性上加@TableField(condition = SqlCondition.LIKE)

    package com.cicdi.servertemplate.modules.baselibrary.control;
    
    
    import com.baomidou.mybatisplus.mapper.EntityWrapper;
    import com.baomidou.mybatisplus.plugins.Page;
    import com.baomidou.mybatisplus.service.impl.ServiceImpl;
    import com.cicdi.servertemplate.common.model.ResponseObj;
    import com.cicdi.servertemplate.common.model.RetCode;
    import com.cicdi.servertemplate.common.util.MapBeanUtil;
    
    import org.apache.ibatis.session.SqlSession;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Component;
    import org.springframework.web.bind.annotation.ModelAttribute;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestParam;
    
    import java.util.List;
    import java.util.Map;
    
    @Component
    public class BaseExecute<T> {
        @Autowired
        public SqlSession sqlSession;
    
        @Value("${pName}")
        private String pName;
    
        @Value("${modelName}")
        private String modelName;
    
        /**
         * 通用查询接口
         * 根据主键id和条件返回查询结果
         *
         * @param object  传入的查询条件
         * @param service 对应的service,这个参数很重要!!
         * @return
         */
        public ResponseObj<Object> selectById(@ModelAttribute Object object, ServiceImpl service) {
            Object o1 = service.selectOne(new EntityWrapper(object).eq("IS_DELETE", "0"));
            return new ResponseObj<>(o1, RetCode.SUCCESS);
    
        }
    
    
        /**
         * 通用接口
         * 获取列表,没有分页
         *
         * @return
         */
        public ResponseObj<List<T>> list(Object object, ServiceImpl service) {
            List<T> pageList = service.selectList(new EntityWrapper<>(object));
            return new ResponseObj<>(pageList, RetCode.SUCCESS);
        }
    
        /**
         * 通用接口
         * 获取列表,可以分页。详情接口
         *
         * @param page    分页
         * @param object  传入的查询条件
         * @param service 对应的service,这个参数很重要!!
         * @return
         */
        public ResponseObj<Page<T>> listPage(Page page, Object object, ServiceImpl service) {
            Class<?> clazz = object.getClass();        //获取obj的Class
            String tableName = clazz.getSimpleName();
            Page<T> pageList = null;
            Object obj = null;
            Map<String, Object> map = MapBeanUtil.beanToMap(object);
            if (tableName.endsWith("WithBLOBs")) {
                String[] withBLOBses = tableName.split("WithBLOBs");
                tableName = withBLOBses[0].toString();
                obj = MapBeanUtil.returnObj(tableName, map);  //备份表结构
                pageList = service.selectPage(page, new EntityWrapper<>(obj).eq("IS_DELETE", "0"));
            } else {
                pageList = service.selectPage(page, new EntityWrapper<>(object).eq("IS_DELETE", "0"));
            }
            return new ResponseObj<>(pageList, RetCode.SUCCESS);
        }
    
    
        /**
         * 通用接口:新增
         * mybatis-plus框架主键自动生成
         * Object obj接收前端数据,其实里面是LinkHashMap,索性这里直接用Map map
         * 备份表也插入一条记录:BAK_ID后台生成、IS_NEW=1、OPERATION=0、BATCH_TIME=服务器时间
         * OPERATION:操作标志0:插入,1:更新,2:删除
         *
         * @return
         */
        public ResponseObj<Boolean> insert(@RequestBody Object object) {
            Class<?> c = object.getClass();        //获取obj的Class
            String tableName = c.getSimpleName();
            String tableNameBak;
            Object objBak = null;
            Object objBakBak = null;
            Object logicObject = null;
            Map map2;
            Map<String, Object> map = MapBeanUtil.beanToMap(object);
            int i;
            int j;
            tableNameBak = c.getSimpleName() + "Bak";
            objBak = MapBeanUtil.returnObj(tableNameBak, map);  //备份表结构
    //        String id = String.valueOf(IdWorker.getId()); //雪花算法生成id,mybatis不能自动生成id,使用mybatis-plus框架可以
    //        int pos = 0;
    //        for (Iterator<String> iterator = map.keySet().iterator(); iterator.hasNext(); pos++) {
    //            String keyId = iterator.next();
    //            if (pos == 0) {  //备份表中的外键,取map中的第二个元素
    //                map.put(keyId, id);
    //            }
    //        }
    //        logicObject = MapBeanUtil.mapToBean(map, c);
    //        i = sqlSession.insert(pName + tableName + "Mapper.insertSelective", logicObject); //新增成功之后id会自动赋值
            i = sqlSession.insert(pName + tableName + "Mapper.insert", object); //新增成功之后id会自动赋值
            map2 = MapBeanUtil.transMap(object, objBak, "insert");
            objBakBak = MapBeanUtil.returnObj(tableNameBak, map2);
            j = sqlSession.insert(pName + tableNameBak + "Mapper.insert", objBakBak);
    
            if (i == 1 && j == 1)
                return new ResponseObj<Boolean>(true, RetCode.SUCCESS);
            return new ResponseObj<Boolean>(false, RetCode.FAIL);
    
        }
    
        /**
         * 通用接口:修改
         * 修改备份表"IS_NEW=1 and 原表主键字段=当前传过来的主键"的记录的 IS_NEW=0;
         * 备份表插入一条记录:BAK_ID后台生成、IS_NEW=1、OPERATION=1、BATCH_TIME=服务器时间;
         * OPERATION:操作标志0:插入,1:更新,2:删除
         *
         * @return
         */
        public ResponseObj<Boolean> update(@RequestBody Object object) {
            Class<?> c = object.getClass(); //获取obj的Class, object原表结构
            String tableName = c.getSimpleName();
            String tableNameBak;
            Object objBak = null;
            Object objBakBak = null;
            Map map2;
            Map<String, Object> map = MapBeanUtil.beanToMap(object);
            int i;
            int j;
            int k;
    
            tableNameBak = c.getSimpleName() + "Bak";
            objBak = MapBeanUtil.returnObj(tableNameBak, map);  //备份表结构
            i = sqlSession.update(pName + tableName + "Mapper.updateByPrimaryKeySelective", object);
            j = sqlSession.update(pName + tableNameBak + "Mapper.updateByPrimaryKeySelective", objBak);
            map2 = MapBeanUtil.transMap(object, objBak, "update");
            objBakBak = MapBeanUtil.returnObj(tableNameBak, map2);
            k = sqlSession.insert(pName + tableNameBak + "Mapper.insert", objBakBak);
    
            if (i == 1 && j == 1 && k == 1)
                return new ResponseObj<Boolean>(true, RetCode.SUCCESS);
            return new ResponseObj<Boolean>(false, RetCode.FAIL);
        }
    
        /**
         * 通用接口:逻辑删除,逻辑删除原表
         * 修改备份表"IS_NEW=1 and 原表主键字段=当前传过来的主键"的记录的 IS_NEW=0;
         * 备份表插入一条记录:BAK_ID后台生成、IS_NEW=1、OPERATION=2、BATCH_TIME=服务器时间;
         * OPERATION:操作标志0:插入,1:更新,2:删除
         *
         * @return
         */
        public ResponseObj<Boolean> deletebylogic(@RequestBody List<T> list) {
            int i1 = 0;
            int j1 = 0;
            int k1 = 0;
            if (list != null && list.size() > 0) {
                for (T object : list) {
                    Class<?> c = object.getClass(); //获取obj的Class
                    String tableName = c.getSimpleName();
                    String tableNameBak;
                    Object objBak = null; //原表
                    Object objBakBak = null; //备份表结构
                    Object logicObject = null; //逻辑删除原表
                    Map map2;
                    int i;
                    int j;
                    int k;
                    Map<String, Object> map = MapBeanUtil.beanToMap(object);
                    map.put("isDelete", "1");  //0没有删除 1逻辑删除
                    try {
                        logicObject = MapBeanUtil.mapToBean(map, c);
                    } catch (Exception e) {
    
                    }
                    tableNameBak = c.getSimpleName() + "Bak";
                    map.put("isDelete", null);
                    objBak = MapBeanUtil.returnObj(tableNameBak, map);  //备份表结构
                    //修改原表isDelete字段
                    i = sqlSession.update(pName + tableName + "Mapper.updateByPrimaryKeySelective", logicObject);
                    j = sqlSession.update(pName + tableNameBak + "Mapper.updateByPrimaryKeySelective", objBak);
                    map2 = MapBeanUtil.transMap(object, objBak, "delete");
                    objBakBak = MapBeanUtil.returnObj(tableNameBak, map2);
                    k = sqlSession.insert(pName + tableNameBak + "Mapper.insert", objBakBak);
                    if (i == 1)
                        i1++;
                    if (j == 1)
                        j1++;
                    if (k == 1)
                        k1++;
                }
            }
            if (i1 == list.size() && j1 == list.size() && k1 == list.size())
                return new ResponseObj<Boolean>(true, RetCode.SUCCESS);
            return new ResponseObj<Boolean>(false, RetCode.FAIL);
        }
    
        /**
         * 物理删除
         *
         * @return
         */
        public ResponseObj<Boolean> delete(@RequestParam Object object) {
            Class<?> c = object.getClass(); //获取obj的Class
            String tableName = c.getSimpleName();
            String tableNameBak = c.getSimpleName() + "Bak";
            Map<String, Object> map = MapBeanUtil.beanToMap(object);
    
    //        String tableName = (String) map.get("_tbName");
    //        String tableNameBak = (String) map.get("_tbNameBak");  //备份表
    //        Object obj = MapBeanUtil.returnObj(tableName, map); //原表结构
            Object objBak = MapBeanUtil.returnObj(tableNameBak, map); //备份表结构
            int i = sqlSession.delete(pName + tableName + "Mapper.deleteByPrimaryKey", object);
            int j = sqlSession.delete(pName + tableNameBak + "Mapper.deleteByPrimaryKey", objBak);
            if (i == 1 & j == 1)
                return new ResponseObj<Boolean>(true, RetCode.SUCCESS);
            return new ResponseObj<Boolean>(false, RetCode.FAIL);
        }
    
    
    }
    
    

    PbHouseController
    子类xxControl继承BaseController,其中@TargetDataSource("ds3")指定使用哪个数据源

    /**
     * 子类继承的时候必须指定类型:<PbzHouseDwell>
     */
    @TargetDataSource("ds3")
    @RestController
    @RequestMapping("/api/pbHouse")
    public class PbHouseController extends /*SingleRecordControl<PbzHouseDwell>*/
            BaseController<PbHouseService,
                    PbHouseMapper,
                    PbHouse, Long> {
    
    
    }
    

    对于不适用这些方法的需求,在各自xxControl中自定义接口方法。比如多表关联查询同时需要将查出来的结果分页
    PbHujiController

    @TargetDataSource("ds3")
    @RestController
    @RequestMapping("/api/pbHuji")
    public class PbHujiController extends BaseController<PbHujiService,
            PbHujiMapper,
            PbHuji, Long> {
    
        /**
         * 多表关联分页查询
         *
         * @param page  分页参数
         * @param model 搜索条件
         */
        @RequestMapping(value = "/list", method = RequestMethod.GET)
        public ResponseObj<Page<PbHuji>> list(@ModelAttribute Page<PbHuji> page,
                                              @ModelAttribute PbHuji model) {
            Page<PbHuji> pageList = service.list(page, new EntityWrapper<>(model));
            return new ResponseObj<>(pageList, RetCode.SUCCESS);
        }
    }
    

    对应的PbHujiService

    @Service
    public class PbHujiService extends ServiceImpl<PbHujiMapper, PbHuji> {
        
        public Page<PbHuji> list(Page<PbHuji> page, Wrapper<PbHuji> wrapper) {
            return page.setRecords(baseMapper.list(page, wrapper));
        }
    }
    

    对应的baseMapper

        /**
         * 不能使用selectList这个方法名,与BaseMapper中的方法名重复了
         * 根据 entity 条件,查询全部记录并分页
         * @param rowBounds 分页条件
         * @param wrapper 查询条件
         * @return
         */
        List<PbHuji> list(RowBounds rowBounds, @Param("ew") Wrapper<PbHuji> wrapper);
    

    对应的baseMapper.xml

      <select id="list" resultType="com.cicdi.servertemplate.modules.baselibrary.model.PbHuji">
        SELECT
          ph.*, pc.COMM_NAME,
          px.XIAOQU_NAME,
          pbl.BUILD_NAME
        FROM
          pb_huji ph
        LEFT JOIN pb_community pc ON ph.COMMUNITY_ID = pc.COMMUNITY_ID
        AND pc.IS_DELETE = 0
        LEFT JOIN pb_xiaoqu px ON ph.XIAOQU_ID = px.XIAOQU_ID
        AND px.IS_DELETE = 0
        LEFT JOIN pb_building pbl ON ph.BUILD_ID = pbl.BUILD_ID
        AND pbl.IS_DELETE = 0
        WHERE (ph.IS_DELETE = '0')
        <if test="ew!=null">
          <if test="ew.entity!=null">
            <if test="ew.entity.headName!=null">
              AND ph.HEAD_NAME LIKE CONCAT('%',#{ew.entity.headName},'%')
            </if>
            <if test="ew.entity.headCardNo!=null">
              AND ph.HEAD_CARD_NO LIKE CONCAT('%',#{ew.entity.headCardNo},'%')
            </if>
            <if test="ew.entity.hujiAddr!=null">
              AND ph.HUJI_ADDR LIKE CONCAT('%',#{ew.entity.hujiAddr},'%')
            </if>
            <if test="ew.entity.liveAddr!=null">
              AND ph.LIVE_ADDR LIKE CONCAT('%',#{ew.entity.liveAddr},'%')
            </if>
          </if>
          <if test="ew.sqlSegment!=null">
            ${ew.sqlSegment}
          </if>
        </if>
      </select>
    

    相关文章

      网友评论

          本文标题:单表增删改查通用方法(也涉及多表关联),使用反射动态返回Obje

          本文链接:https://www.haomeiwen.com/subject/lhugtqtx.html