[toc]

In other words, entering a company, if often CURD, is not very boring, but I have not thought, write module after module, how can make their code slightly better? This article is based on this background, arises at the historic moment.

1. Introduction

In other words, I once worked in a company, especially when I participated in the back-end to the operation side, such as the xx platform. Most of the demands I participated in accumulated year after year are to add, delete, edit and query the list one by one. After writing a lot of code, I will feel more or less, which part of code can be abstracted, which code can no longer CP/CV, so through generations of sublimation, born today’s topic -BaseModule, a three-layer abstract module package based on SpringMVC.

2. Think about

The features of most functional modules in daily life are as follows:

  • Function modules are capable of adding, editing, viewing details, paging query.
  • Data ORM objects are mostly single-table and have few associated query operations.
  • The data model returned to the front end is the same as the business process logic abstraction.
  • All are based on SpringMVC+MyBatis framework to achieve relevant functions.

3. The architecture

  • The first area, the base module of this article’s abstraction, is calledAbstract Module. It providesBaseMapper,BaseService,BaseFacadeAbstract encapsulation, with daily general function operation, no need to code repeated code. Also, the Impl endingBaseServiceImpl,BaseFacadeImplImplements dependency injection of related objects so that your code only needs to inherit from the abstract class.
  • The second area is that your functional modules need to use abstract parts, such as inheriting related interfaces or abstract classes, that can be extended.

In particular, we need to explain why a Facade layer is introduced here. In fact, we know that in order to wrap a Service, for example, we convert VO to Entity, for example, we need to return the same Result protocol type when we add and delete services.

Design of 4.

BaseMapper

DAO layer abstract encapsulation, their own functional module Mapper needs to inherit the interface.

package org.suze.framework.base;


import org.suze.framework.base.page.PageForm;

import java.io.Serializable;
import java.util.List;

/ * * *@description: Mapper base class *@Date : 下午3:36 2018/2/5
 * @param<E> Entity object *@param<PK> primary key, 1, return autoincrement ID; 2: queries the primary key of an object. 3: Deletes the primary key (combined primary key) * of the object@param<F> encapsulates query parameters *@Author: Shi Dong Dong -Heil Hitler */
public interface BaseMapper<E extends Serializable.PK.F extends Serializable>  {
    /** * Paged load data *@param form
     * @return* /
    List<E> queryByPage(PageForm<F> form);
    /** ** *@param form
     * @return* /
    int queryCount(PageForm<F> form);
    /** * query list *@param form
     * @return* /
    List<E> queryList(F form);

    /** * Query object * based on primary key ID@param uniqueKey
     * @return E
     */
    E selectByPrimaryKey(PK uniqueKey);

    /** * delete * based on primary key@param uniqueKey
     * @return* /
    int deleteByPrimaryKey(PK uniqueKey);

    /** * Selective new object *@param record
     * @returnThe primary key id * /
    int insertSelective(E record);

    /** * New object *@param record
     * @returnThe primary key id * /
    int insert(E record);

    /** * Selectively update objects *@param record
     * @return* /
    int updateByPrimaryKeySelective(E record);

    /** * update *@param record
     * @return* /
    int updateByPrimaryKey(E record);
    /** * Add * in batches@param list
     * @return* /
    int batchInsert(List<E> list);

    /** * Add data in batches, ignoring existing data *@param list
     * @return* /
    int batchInsertIgnore(List<E> list);

    /** * Delete * in batches@param list
     * @return* /
    int batchDelete(List<E> list);

    /** * delete * according to condition@param form
     * @return* /
    int deleteByForm(F form);

}

Copy the code

BaseService

Abstract encapsulation of the Service layer. The corresponding Service needs to inherit this interface.

package org.suze.framework.base;


import org.suze.framework.base.page.PageForm;

import java.io.Serializable;
import java.util.List;

/**
 * BaseService
 * @Date: 2019/5/31 2:28 PM *@Author: Shi Dongdong -Seig Heil *@param<E> Database entity object *@param<P> Query primary key *@param<F> Query the conditional Form object */
public interface BaseService<E extends Serializable.P.F extends Serializable> {
    /** * Paged load data *@param form
     * @return* /
    List<E> queryByPage(PageForm<F> form);
    /** ** *@param form
     * @return* /
    int queryCount(PageForm<F> form);
    /** * Query entity object *@param primaryKey
     * @return* /
    E queryRecord(P primaryKey);
    /** * Add entity object *@param record
     * @return* /
    int insertRecord(E record);
    /** * Modify the entity object *@param record
     * @return* /
    int updateRecord(E record);

    /** * Modify the entity object *@param record
     * @return* /
    int updateByPrimaryKeySelective(E record);
    /** * Delete object *@param primaryKey
     * @return* /
    int deleteRecord(P primaryKey);
    /** * Add * in batches@param list
     * @return* /
    int batchInsert(List<E> list);

    /** ** ** ** ** ** ** ** ** ** ** *@param list
     * @return* /
    int batchInsertIgnore(List<E> list);
    /** * Delete * in batches@param list
     * @return* /
    int batchDelete(List<E> list);
    /** * delete * according to condition@param form
     * @return* /
    int deleteByForm(F form);
    /** * query list *@param form
     * @return* /
    List<E> queryList(F form);
}

Copy the code

BaseServiceImpl

Abstract encapsulation of the Service implementation class, the corresponding Service implementation class needs to inherit this interface.

package org.suze.framework.base.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.suze.framework.base.BaseMapper;
import org.suze.framework.base.BaseService;
import org.suze.framework.base.page.PageForm;

import java.io.Serializable;
import java.util.List;

/ * * *@description: BaseService
 * @Date: 2019/5/31 2:25 PM *@Author: Shi Dongdong -Seig Heil *@param<E> Database entity object *@param<P> Query primary key *@param<F> Query the conditional Form object */
public abstract class BaseServiceImpl<E extends Serializable.P.F extends Serializable> implements BaseService<E.P.F> {
    /** * mapper */
    protected BaseMapper<E,P,F> mapper;

    @Autowired
    public void setBaseMapper(BaseMapper<E, P, F> baseMapper) {
        this.mapper = baseMapper;
    }

    @Override
    public List<E> queryByPage(PageForm<F> form) {
        return mapper.queryByPage(form);
    }

    @Override
    public int queryCount(PageForm<F> form) {
        return mapper.queryCount(form);
    }

    @Override
    public E queryRecord(P primaryKey) {
        return mapper.selectByPrimaryKey(primaryKey);
    }

    @Override
    public int insertRecord(E record) {
        return mapper.insert(record);
    }

    @Override
    public int updateRecord(E record) {
        return mapper.updateByPrimaryKey(record);
    }

    @Override
    public int updateByPrimaryKeySelective(E record) {
        return mapper.updateByPrimaryKeySelective(record);
    }

    @Override
    public int deleteRecord(P primaryKey) {
        return mapper.deleteByPrimaryKey(primaryKey);
    }

    @Override
    public int batchInsert(List<E> list) {
        return mapper.batchInsert(list);
    }

    @Override
    public int batchInsertIgnore(List<E> list) {
        return mapper.batchInsertIgnore(list);
    }

    @Override
    public int batchDelete(List<E> list) {
        return mapper.batchDelete(list);
    }

    @Override
    public int deleteByForm(F form) {
        return mapper.deleteByForm(form);
    }

    @Override
    public List<E> queryList(F form) {
        returnmapper.queryList(form); }}Copy the code

BaseFacade

Abstract encapsulation of the Facade layer, the corresponding Facade needs to inherit the interface.

package org.suze.framework.base;

import org.suze.framework.base.page.PageForm;
import org.suze.framework.base.page.PageVO;

import java.io.Serializable;

/ * * *@description: Facade Interface base class *@Date: 2019/5/31 2:45 PM *@Author: Shi Dongdong -Seig Heil *@paramThe <V> page displays the VO object *@param<E> Database entity object *@param<P> Query primary key *@param<F> Query the conditional Form object */
public interface BaseFacade<V extends Serializable.E extends Serializable.P.F extends Serializable> {
    /** * Paged load data *@param form
     * @return* /
    Result<PageVO<V>> loadRecords(PageForm<F> form);
    /** * Query entity object *@param primaryKey
     * @return* /
    Result<V> queryRecord(P primaryKey);
    /** * Saves the entity object *@param record
     * @return* /
    Result<String> saveRecord(E record);
    /** * Delete object *@param primaryKey
     * @return* /
    Result<String> deleteRecord(P primaryKey);

    /** * Update status *@param record
     * @return* /
    Result<String> modifyStatus(E record);
}

Copy the code

BaseFacadeImpl

The Facade implements the abstract encapsulation of the class, and the corresponding Facade implementation class needs to inherit the interface.

package org.suze.framework.base.impl;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.suze.framework.base.BaseConverter;
import org.suze.framework.base.BaseFacade;
import org.suze.framework.base.BaseService;
import org.suze.framework.base.Result;
import org.suze.framework.base.enums.RemoteEnum;
import org.suze.framework.base.page.PageForm;
import org.suze.framework.base.page.PageVO;

import java.io.Serializable;
import java.util.Collections;
import java.util.List;

/ * * *@description: BaseFacadeImpl, related function modules should inherit this class *@Date: 2019/5/31 10:04 p.m. *@Author: Shi Dongdong -Seig Heil *@paramThe <V> page displays the VO object *@param<E> Database entity object *@param<P> Query primary key *@param<F> Query the conditional Form object */
@Slf4j
public abstract class BaseFacadeImpl<V extends Serializable.E extends Serializable.P extends Serializable.F extends Serializable> implements BaseFacade<V.E.P.F> {
    /** * service */
    protected BaseService<E,P,F> service;

    /** * Whether to modify the operation *@param record
     * @return* /
    protected abstract boolean isModify(E record);

    /** * VO converter *@return* /
    protected abstract BaseConverter<V,E> converter(a);

    @Autowired
    public void setService(BaseService<E, P, F> service) {
        this.service = service;
    }

    @Override
    public Result<PageVO<V>> loadRecords(PageForm<F> form) {
        List<V> voList = Collections.emptyList();
        int count = 0;
        try {
            List<E> queryList = service.queryByPage(form);
            count = service.queryCount(form);
            voList = converter().convertList(queryList);
        } catch (Exception e) {
            log.error("loadRecords exception,form={}", JSON.toJSON(form),e);
            return Result.failInServer(PageVO.newInstance(count,voList));
        }
        return Result.suc(PageVO.newInstance(count,voList));
    }

    @Override
    public Result queryRecord(P primaryKey) {
        E entity = service.queryRecord(primaryKey);
        if(null == entity){
            return Result.fail(RemoteEnum.WARN_EMPTY_RECORD);
        }
        return Result.suc(converter().convert(entity));
    }

    @Override
    public Result<String> saveRecord(E record) {
        if(isModify(record)){
            service.updateRecord(record);
        }else{
            service.insertRecord(record);
        }
        return Result.suc();
    }

    @Override
    public Result<String> deleteRecord(P primaryKey) {
        service.deleteRecord(primaryKey);
        return Result.suc();
    }

    @Override
    public Result<String> modifyStatus(E record) {
        service.updateByPrimaryKeySelective(record);
        returnResult.suc(); }}Copy the code

In particular, on the Facade layer, we can see that saveRecord adds and edits by defining an abstract isModify method to distinguish between a common operation and an edit.

BaseConverter

Provide Entity conversion to VO, you need to implement the VO converter and inherit the abstract class.

package org.suze.framework.base;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/** * The value object is converted to the extraction class. The purpose is to convert the source object to the value object. *@Date: 2019/6/1 8:27 am *@Author: Shi Dongdong -Seig Heil *@param<R> Target value object *@param<O> Source object */
public abstract class BaseConverter<R extends Serializable.O extends Serializable> {
	/** * subclass to implement specific conversion rules. *@paramO Source pair *@return<R> Target value object */
	public abstract R convert(O o);
	/** * List to convert method *@paramEs source object list *@returnList<V> List of object values */
	public List<R> convertList(List<O> es) {
		if(null == es || es.isEmpty()){
			return Collections.emptyList();
		}
		List<R> voList = new ArrayList<>(es.size());
		for(O origin : es) {
			R vo = convert(origin);
			voList.add(vo);
		}
		returnvoList; }}Copy the code

PageForm

Encapsulation of page query parameters for paging query functionality.

package org.suze.framework.base.page;

import java.io.Serializable;

/** * Description: paging Form class <br/> *@authorShi Dong winter *@versionV1.0 by Heil Hitler on 2020/3/27 12:48 */
public class PageForm<T> implements Serializable {
    private static final long serialVersionUID = 1315360688901318671L;
    /** ** page start and end */
    private int start = 0;
    /** * page size (most pages per page) */
    private int limit = 20;
    /** * whether to page */
    private boolean paging = true;
    /** * page-wrapped Form conditions */
    private T form;

    public PageForm(a) {}public PageForm(T form) {
        this.form = form;
    }

    public PageForm(int start, int limit, T form) {
        this.start = start;
        this.limit = limit;
        this.form = form;
    }

    public PageForm(boolean paging) {
        this.paging = paging;
    }

    public PageForm(boolean paging, T form) {
        this.paging = paging;
        this.form = form;
    }

    /** * static instance method, external call *@paramStart page start and end *@paramLimit page size (most pages per page) *@paramForm page wrapped form criteria *@param <T>
     * @return* /
    public static <T> PageForm newInstance(int start, int limit, T form){
        return new PageForm(start,limit,form);
    }

    /** * static instance method, external call *@paramPaging whether to page *@paramForm page wrapped form criteria *@param <T>
     * @return* /
    public static <T> PageForm newInstance(boolean paging,T form){
        return new PageForm(paging,form);
    }

    public int getStart(a) {
        return start;
    }

    public void setStart(int start) {
        this.start = start;
    }

    public int getLimit(a) {
        return limit;
    }

    public void setLimit(int limit) {
        this.limit = limit;
    }

    public T getForm(a) {
        return form;
    }

    public void setForm(T form) {
        this.form = form;
    }

    public boolean isPaging(a) {
        return paging;
    }

    public void setPaging(boolean paging) {
        this.paging = paging; }}Copy the code

PageVO

Data result set encapsulation for paging query functionality.

package org.suze.framework.base.page;

import java.io.Serializable;
import java.util.List;

/** * <br/> *@authorShi Dong winter *@versionV1.0 by Heil Hitler on 2020/3/27 12:57 */
public class PageVO<T> implements Serializable {
    private static final long serialVersionUID = 1724063683524348852L;
    /** * total number of entries */
    private int recordsTotal;
    /** * result set */
    private List<T> data;

    public PageVO(a) {}public PageVO(int total, List<T> data){
        this.data = data;
        this.recordsTotal = total;
    }
    /** * static method, return instance object *@paramTotal Total number of items *@paramData Sets of data records *@param <T>
     * @return* /
    public static <T> PageVO newInstance(int total, List<T> data){
        return new PageVO(total,data);
    }

    public PageVO(List<T> data){
        this.data = data;
    }

    public int getRecordsTotal(a) {
        return recordsTotal;
    }

    public void setRecordsTotal(int recordsTotal) {
        this.recordsTotal = recordsTotal;
    }

    public List<T> getData(a) {
        return data;
    }

    public void setData(List<T> data) {
        this.data = data; }}Copy the code

Result

Encapsulate Restful API responses.

package org.suze.framework.base;

import lombok.Data;
import org.suze.framework.base.enums.RemoteEnum;

import java.io.Serializable;

/ * * *@description: used for DTO return generic use, providing Dobbo service as a data protocol *@Date: 11:49 am 2020/3/29 *@Author: Shi Dong Dong -Heil Hitler */
@Data
public class Result<E> implements Serializable {
    private final static int SUCCESS_CODE = 0;
    private final static int FAILURE_CODE = 1;
    private final static String SUCCESS_MSG = "Operation successful";
    private final static String FAILURE_MSG = "Operation failed";
    private static final long serialVersionUID = -6237151417035547947L;
    /** * Whether the command is executed successfully */
    private boolean success;
    /** * package */
    private E data;
    /** * perform the operation code */
    private int code;
    /** * Business message */
    private String msg;

    public Result(a) {}/** * constructor *@param success
     * @param data
     * @param code
     * @param msg
     */
    public Result(boolean success, E data, int code, String msg) {
        this.success = success;
        this.data = data;
        this.code = code;
        this.msg = msg;
    }

    /** * static method, return success *@return* /
    public static Result suc(a){
        return suc(SUCCESS_MSG,SUCCESS_CODE,SUCCESS_MSG);
    }

    /** * static method, return success *@param t
     * @param <E>
     * @return* /
    public static <E> Result<E> suc(E t){
        return suc(t,SUCCESS_CODE,SUCCESS_MSG);
    }

    /** * static method, return success *@param t
     * @param code
     * @param msg
     * @param <E>
     * @return* /
    public static <E> Result<E> suc(E t,int code,String msg){
        return new Result<>(Boolean.TRUE,t,code,msg);
    }

    /** * static method, return success *@paramT returns the concrete wrapper object *@paramRemoteEnum Service enumeration object *@paramMSG Business information *@param <E>
     * @return* /
    public static <E> Result<E> suc(E t, RemoteEnum remoteEnum, String msg){
        return new Result<>(Boolean.TRUE,t,remoteEnum.getIndex(),msg);
    }

    /** * static method, return execution failed *@return* /
    public static Result<Object> fail(a){
        return fail(FAILURE_MSG,FAILURE_CODE,FAILURE_MSG);
    }

    /** * static method, return execution failed *@param t
     * @param <E>
     * @return* /
    @Deprecated
    public static <E> Result<E> fail(E t){
        return fail(t,FAILURE_CODE,FAILURE_MSG);
    }

    @Deprecated
    public static Result fail(String msg){
        return fail(null, -1, msg);
    }

    /** * static method, return execution failed *@paramCode Business code *@paramMSG Business information *@param <E>
     * @return* /
    public static <E> Result<E> fail(int code,String msg){
        return fail(null, code, msg);
    }

    /** * static method, return execution failed *@paramRemoteEnum Service enumeration *@paramMSG Business information *@param <E>
     * @return* /
    public static <E> Result<E> fail(RemoteEnum remoteEnum,String msg){
        return fail(null, remoteEnum.getIndex(), msg);
    }

    /** * static method, return execution failed *@param remoteEnum
     * @return* /
    public static <E> Result<E> fail(RemoteEnum remoteEnum){
        return new Result<>(Boolean.FALSE,null,remoteEnum.getIndex(),remoteEnum.getName());
    }
    /** * static method, return execution failed *@param t
     * @param code
     * @param msg
     * @param <E>
     * @return* /
    public static <E> Result<E> fail(E t,int code,String msg){
        return new Result<>(Boolean.FALSE,t,code,msg);
    }

    /** * static method, return success *@paramT returns the concrete wrapper object *@paramRemoteEnum Service enumeration object *@paramMSG Business information *@param <E>
     * @return* /
    public static <E> Result<E> fail(E t, RemoteEnum remoteEnum, String msg){
        return fail(t,remoteEnum.getIndex(),msg);
    }

    /** * static method, return execution failed: argument is empty *@param t
     * @param <E>
     * @return* /
    public static <E> Result<E> failWithEmptyParam(E t){
        return fail(t, RemoteEnum.ERROR_WITH_EMPTY_PARAM.getIndex(),RemoteEnum.ERROR_WITH_EMPTY_PARAM.getName());
    }
    /** * static method, return execution failed: server internal error *@param t
     * @param <E>
     * @return* /
    public static <E> Result<E> failInServer(E t){
        return fail(t, RemoteEnum.ERROR_IN_SERVER.getIndex(),RemoteEnum.ERROR_IN_SERVER.getName());
    }
    /** * static method, return execution failed: runtime error *@param t
     * @param <E>
     * @return* /
    public static <E> Result<E> failInRuntime(E t){
        returnfail(t, RemoteEnum.ERROR_IN_RUNTIME.getIndex(),RemoteEnum.ERROR_IN_RUNTIME.getName()); }}Copy the code

5. To summarize

The above three layers of Mapper, Service and Facade are our Abstract Module. The meaning of the Facade allows our day-to-day business processes to be handled through it without intruding into the Service layer.

Source: gitee.com/suze/base-m…

Next: After all the code written, can CURD be so simple?

The following is the qr code picture of my official account, welcome to follow.

Original text: blog.csdn.net/shichen2010…