由于公司産品屬于初始搭建階段,資料庫庫表的不斷增多,在基于控制層,業務層,持久層這種模式的開發下的話,目錄結構等更改頻繁,實作基礎功能如增删改查的話太過于繁瑣,于是思考決定采用模闆模式對這些功能進行封裝
技術棧采用 springboot+mybatis方向,因為持久層用的mybatis,是以直接采用二次封裝好的工具mybatis-plus, 除mybatis-plus提供好的模闆方法外,另外做了一些方法擴充 ,主要實作基于繼承和泛型來實作
文章目錄
-
- 領域模型
- BaseModel
- 以使用者表領域對象建立
- 正常開發模闆
-
- controller控制層
- service業務層
- dao持久層
- 控制層模闆方法
-
- ContorllerExtend(控制層模闆接口定義)
- BaseController(控制層模闆接口實作)
- IServiceExtend(業務層接口擴充)
- ServiceImplExtend(業務層接口實作)
- BaseMapperExtend(持久層自定義接口)
- TUserMapper.xml
領域模型
為簡單描述,這裡隻采用此三種領域模型對象,如
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>
至此完成,定義好模闆方法, 結合代碼生成器,在新表操作時候提高效率