从控制层到持久层数据方法模板封装

本文介绍了如何在SpringBoot+Mybatis-Plus的环境中,通过模板模式对常见的CRUD操作进行封装,以提高开发效率。通过定义BaseModel、DO、VO、Query对象,以及实现Controller、Service、Dao层的模板接口和抽象类,实现了通用的查询、删除、修改和新增功能。同时,利用Mybatis-Plus的二次封装工具,简化了数据库操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

由于公司产品属于初始搭建阶段,数据库库表的不断增多,在基于控制层,业务层,持久层这种模式的开发下的话,目录结构等更改频繁,实现基础功能如增删改查的话太过于繁琐,于是思考决定采用模板模式对这些功能进行封装

技术栈采用 springboot+mybatis方向,因为持久层用的mybatis,所以直接采用二次封装好的工具mybatis-plus, 除mybatis-plus提供好的模板方法外,另外做了一些方法扩展 ,主要实现基于继承和泛型来实现

领域模型

为简单描述,这里只采用此三种领域模型对象,如
VO(展示对象,这里也用作除查询对象外请求响应对象),
DO(数据对象,于数据库字段一一对应),
Query(数据查询对象)等等,
继承关系为,VO继承DO Query继承DO 可见DO为基础类

BaseModel

先从业务角度出发思考基本的操作场景,大多数为增加,删除,修改,查询
以下只以查询为例,进行阐述
在查询场景中,这里直说基础查询,如条件查询,查询列表,查询分页,模糊查询,根据主键查询,根据主键集合查询,查询区间,排序查询等等
由于使用Query查询对象,以上查询不限于都以该对象为条件,所以对查询模型进行扩展,定义为基础模型
定义如下

public class BaseModel implements Serializable {

    private final static Pattern AZ=Pattern.compile("[A-Z]");

    /**
     * ids  主键集合
     */
     private List<Integer> ids;


    /**
     * 排序 asc desc
     */
     private  String orderBy;


    /**
     * 排序的字段
     */
     private  String orderByName;


	/**
	 * 排序的字段集合
	 */
     private  List<String> orderByNames;

 
    /**
     * 分页大小
     */
     private  Integer size;

    /**
     * 当前页数
     */
     private  Integer page;

    /**
     * keyword关键字查询
     */
     private  String keyword;

    /**
     * 用户id
     */
	private String userId;
	
		....省略get/set方法

以用户表领域对象创建

DO对象

@Data
public class TUser extends BaseModel implements Serializable {
	
    /**
     * @TableId 为mybatis-plus主键标识 type = IdType.AUTO 意思为主键自增
     */
    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;

    /**
     * 用户名
     */
    private String username;

	 /**
     * 密码
     */
    private String password;

VO对象

@Data
public class TUserVO  extends TUser implements Serializable {
}

Query对象

@Data
public class TUserQuery  extends TUser implements Serializable {

}

常规开发模板

以下模板基于mybatis-plus之上

controller控制层

@RestController
@RequestMapping("/user")
@Slf4j
public class TUserController {
    @Autowired
    private TUserService tUserService;
    /*
     * 查询用户列表
     * */
    @RequestMapping("/getList")
    public ResultUtil<List<TUserVO>> getList(@RequestBody TUserQuery tUserQuery) {
        List<TUserVO> tUserList= tUserService.getList(tUser);
        return ResultUtil.ok(tUserList);
    }
	-----删除
	-----更改
	-----新增

service业务层

/**
 * 业务层接口定义
 */
public interface TUserService extends IService<TUser> {
	List<TUserVO> getList(TUserQuery tUserQuery)
}

/**
 *业务接口实现
 */
public class TUserServiceImpl extends ServiceImpl<TUserMapper, TUser> implements TUserService {
    @Override
    public List<TUserVO> getList(TUserQuery tUserQuery) {
    	return new ArrayList<TUserVO>();
    }
}

dao持久层

@Repository
public interface TUserMapper extends BaseMapper<TUser> {
    List<TUser> getList(TUserQuery tUser);	
    ...
}

控制层模板方法

ContorllerExtend(控制层模板接口定义)

由常规控制层可见,基本每张表都要如此定义出基础增删改查,那么基础增删改查就是共性存在,作为上班时间兼职摸鱼的搬砖人员是忍受不了的,抱着面向接口编程的思想,我们先定义控制层基础方法接口

/**
 * controller 方法扩展
 * @param <DO> 持久层对象
 * @param <VO> vo模型
 * @param <Query> 查询模型
 *
 * @author cyp
 * @Date: 2021/4/26 14:42
 */
public interface ContorllerExtend<DO,VO,Query>  {
    /**
     * 查询单表数据列表
     * @param query
     * @return
     */
    ResultUtil<List<VO>> getList(Query query);

 
}

因为响应数据对象,接受数据对象,查询数据对象都涉及领域模型,定义定义领域模型接口

有接口肯定就有实现,我们定义BaseController来作为实现

BaseController(控制层模板接口实现)

采用继承方式定义BaseController


/**
 * Basecontorller 基础模板控制器,可直接继承使用
 *
 * @author cyp
 * @Date: 2021/4/26 16:08
 */
public abstract class BaseController<DO extends BaseModel, VO, Query > implements ContorllerExtend<DO, VO, Query> {


    /**
     * 控制层模板集合查询实现
     *
     * @param query 查询模型
     * @return
     */
    @Override
    @RequestMapping(value = "/getList", method = {RequestMethod.POST, RequestMethod.GET})
    public ResultUtil<List<VO>> getList(Query query) {
         return ResultUtil.ok();
    }

 

BaseController中DO模型之所以要继承BaseModel是要通过泛型用到基础查询方法字段,
比如query.getIds()得到传入的主键集合,至此接口,以及实现就完成
以上只实现了控制层,需要对业务层此进行调用,我们对BaseController进行改动,让能够对业务层进行调用


/**
 * Basecontorller 基础模板控制器,可直接继承使用
 *
 * @author cyp
 * @Date: 2021/4/26 16:08
 */
public abstract class
 BaseController<DO extends BaseModel,
  				VO,
  				Query,
  				Service extends IServiceExtend<DO, VO, Query>
  				> 	implements ContorllerExtend<DO, VO, Query> {


    @Autowired
    protected Service baseService;

    /**
     * 控制层模板集合查询实现
     *
     * @param query 查询模型
     * @return
     */
    @Override
    @RequestMapping(value = "/getList", method = {RequestMethod.POST, RequestMethod.GET})
    public ResultUtil<List<VO>> getList(Query query) {
         return ResultUtil.ok();
    }

Service extends IServiceExtend<DO, VO, Query> 该泛型继承类 为业务层模板扩展接口,Service为传入的实现对象,IServiceExtend为业务层接口对象,我们把它作为业务层模板方法接口的定义

IServiceExtend(业务层接口扩展)

public interface IServiceExtend<DO,VO,Query>  {
    /**
     * 查询表列表
     * @param query
     * @return
     */
    List<VO> getList(Query query); 
}

ServiceImplExtend(业务层接口实现)

同控制层模板接口实现一样,我们对此进行实现

public abstract class 
					ServiceImplExtend<
							DO extends BaseModel,
							VO extends DO,
							Query extends DO,
							M extends BaseMapperExtend<DO,Query>> extends ServiceImpl<M, DO>
					implements IServiceExtend<DO, VO, Query> {
	
	/**
	 * 业务层模板接口实现
	 */
    @Override
    public List<VO> getList(Query query) {
    	beforeQuery(query);
        List<DO> list = getBaseMapper().getList(query);
        afterQuery(list)
        return CollectionUtil.isNotEmpty(list)?JsonUtil.toList(list,voClass):Collections.emptyList();
    }


    /**
     * 查询前操作
     */
    public void beforeQuery(Query query){
    }

    /**
     * 查询后操作
     */
	public void afterQuery( List<DO> list){
    }
	  

  /**
     * 获取VO class
     * @return
     */
    public Class<DO> getDoClass() {
        Type superClass = getClass().getGenericSuperclass();
        return (Class<DO>) ((ParameterizedType) superClass).getActualTypeArguments()[0];
    }

    /**
     * 获取VO class
     * @return
     */
    public Class<VO> getVoClass() {
        Type superClass = getClass().getGenericSuperclass();
        return (Class<VO>) ((ParameterizedType) superClass).getActualTypeArguments()[1];
    }

    /**
     * 获取Query class
     * @return
     */
    public Class<Query> getQueryClass() {
        Type superClass = getClass().getGenericSuperclass();
        return (Class<Query>) ((ParameterizedType) superClass).getActualTypeArguments()[2];
    }
}

M extends BaseMapperExtend<DO,Query>> M是自己定义的dao层接口文件如TUserMapper
它继承的BaseMapperExtend是自己持久层接口的扩展接口

可自定义模板方法,如beforeQuery()查询前操作,afterQuery()查询后操作 ,在TUserServiceImpl 重写即可

BaseMapperExtend(持久层自定义接口)


/**
 * baseMapper扩展
 *
 * @param <DO>
 */
public interface BaseMapperExtend<DO,Query>  extends BaseMapper<DO> {

    /**
     * 条件查询列表
     * @param query
     * @return
     */
    List<DO> getList(Query query);
}

extends BaseMapper继承BaseMapper BaseMapper 为mybatis-plus封装好的方法

TUserMapper.xml

基于代码生成器生成xml sql文件

    <resultMap id="BaseResultMap" type="com.xnnf.system.MO.DO.TUser">
        <result column="id" property="id"/>
        <result column="username" property="username"/>
        <result column="password" property="password"/>
    </resultMap>
    <!-- 表字段 -->
    <sql id="baseColumns">
        id
        , username
        , password
    </sql>
    <!-- 查询全部 -->
    <select id="getList" resultMap="BaseResultMap">
        SELECT
        <include refid="baseColumns"/>
        FROM t_user
        <where>
            <if test="ids!=null and ids.size()!=0">
                and id in
                <foreach collection="ids" item="id" separator="," open="(" close=")" index="index">
                    #{id}
                </foreach>
            </if>
            <if test="id!=null">
                and id =#{id}
            </if>
            <if test="username!=null and username!='' ">
                and username =#{username}
            </if>
            <if test="password!=null and password!='' ">
                and password =#{password}
            </if>
        	<!-- 字符串模糊匹配-->
            <if test="keyword!=null and keyword!=''">
                and (
                username like concat('%',#{keyword,jdbcType=VARCHAR},'%')
                )
            </if>
			 <!--字段排序-->
			 <if test="orderBy!=null and orderBy!='' and orderByName!=null and orderByName!=''">
                and 1=1 order BY  ${orderByName}  ${orderBy}
            </if>

        </where>
    </select>

至此完成,定义好模板方法, 结合代码生成器,在新表操作时候提高效率

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值