天天看點

從控制層到持久層資料方法模闆封裝

由于公司産品屬于初始搭建階段,資料庫庫表的不斷增多,在基于控制層,業務層,持久層這種模式的開發下的話,目錄結構等更改頻繁,實作基礎功能如增删改查的話太過于繁瑣,于是思考決定采用模闆模式對這些功能進行封裝

技術棧采用 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>

           

至此完成,定義好模闆方法, 結合代碼生成器,在新表操作時候提高效率