由于公司产品属于初始搭建阶段,数据库库表的不断增多,在基于控制层,业务层,持久层这种模式的开发下的话,目录结构等更改频繁,实现基础功能如增删改查的话太过于繁琐,于是思考决定采用模板模式对这些功能进行封装
技术栈采用 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>
至此完成,定义好模板方法, 结合代码生成器,在新表操作时候提高效率