基础框架一:“零代码”实现单表增删改查、唯一性校验、枚举类型翻译

摘要:
概述在日常开发中,有许多模块,如基本信息,即单个表的添加、删除和修改。如果每个表都必须编写自己的添加、删除和修改代码,无疑会增加很多不必要的开发成本。本文封装了单个表的添加、删除和修改,并通过EasyCode生成模块代码。无需编写任何代码,即可实现单个表的添加、删除和修改、唯一性验证和数据字典翻译。
概述

在日常开发中,有很多模块如基础信息都是单表的增删改查,如果每个单表都要自己编写增删改查代码,无疑增加了很多不必要的开发成本。本文通过对增删改查进行封装,通过EasyCode生成模块代码,无需编写任何代码,即可实现单表增删改查、唯一性校验、数据字典翻译。

模块介绍

本文主要分为以下几个模块

  1. Controller :封装对外暴露的增删改查restful接口
  2. Service ,封装具体的增删改查逻辑,包括唯一性校验、增删改操作前后的个性操作
  3. Mapper ,继承Mybatisplus的BaseMapper接口
  4. DTO ,返回给前端的实体,包含字段校验、枚举翻译等

在介绍之前先看下一个完整的案例,熟悉下使用方式(下面案例代码均可由EasyCode生成)

以用户模块为例:

UserController
注:对外暴露用户的增删改查接口

@RestController
@RequestMapping("user")
public class UserController extends YaoBaseController<UserParam, UserEntity, UserDTO> {

    @Autowired
    private UserService userService;
    
    @Override
    public YaoBaseService<UserParam, UserEntity> getService() {
        return userService;
    }

    @Override
    public UserDTO getDTO() {
        return new UserDTO();
    }

    @Override
    public UserEntity getEntity() {
        return new UserEntity();
    }
}

UserDTO
注:用户字段校验,枚举翻译( @Formatter)等

/**
 * 用户DTO
 * @author YAO
 * @since 2020-06-13
 */
public class UserDTO extends YaoBaseDTO implements Serializable {
    /**
     * 用户名
     */
    @NotNull
    private String username;

    /**
     * 别名即真实姓名
     */
    private String nickname;
    /**
     * 是否有效,将 1:翻译成有效,0:翻译成无效
     */
    @Formatter(dictCode = "enabled", targetField = "enabledStr")
    private Integer enabled;

    private String enabledStr;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getNickname() {
        return nickname;
    }

    public void setNickname(String nickname) {
        this.nickname = nickname;
    }
    public Integer getEnabled() {
        return enabled;
    }

    public void setEnabled(Integer enabled) {
        this.enabled = enabled;
    }
        public String getEnabledStr() {
        return enabledStr;
    }

    public void setEnabledStr(String enabledStr) {
        this.enabledStr = enabledStr;
    }
}

UserParam
注:只要username非空,自动查询指定username对应的用户,无需编写其他代码

/**
 * 用户请求参数
 * @author Yao
 * @since 2020-07-02
 */
public class UserParam extends PageParam {

    private String username;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }
}

UserService

/**
 * 用户service
 * @author YAO
 * @since 2020-06-13
 */
public interface UserService extends YaoBaseService<UserParam, UserEntity> {
}

UserServiceImpl

/**
 * 用户service的实现类
 *
 * @author YAO
 * @since 2020-06-13
 */
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;
    
    @Override
    public YaoBaseMapper<UserEntity> getMapper() {
        return userMapper;
    }
}

UserMapper

/**
 * 用户数据库操作
 * @author YAO
 * @since 2020-06-13
 */
@Mapper
public interface UserMapper extends YaoBaseMapper<UserEntity> {

}

UserEntity

/**
 * 用户实体
 * @author YAO
 * @since 2020-06-13
 */
@TableName("user")
public class UserEntity extends YaoBaseEntity implements Serializable {

    /**
     * 用户名
     */
    private String username;
    /**
     * 别名即真实姓名
     */
    private String nickname;
    
    /**
     * 是否有效
     */
    private Integer enabled;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getNickname() {
        return nickname;
    }

    public void setNickname(String nickname) {
        this.nickname = nickname;
    }

    public Integer getEnabled() {
        return enabled;
    }

    public void setEnabled(Integer enabled) {
        this.enabled = enabled;
    }
}

下面是各模块上层的代码封装:

1、Controller

自定义YaoBaseController,使用方式继承该类
自带增删改查restful接口,其中查询会对DTO中被 @Formatter 注解的字段进行翻译,如:“0,1” 翻译成“男、女",支持 JSR-303对字段进行校验

package com.jing.yao.component.controller;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jing.yao.annotation.ExcelFileName;
import com.jing.yao.annotation.Permission;
import com.jing.yao.bean.ResponseBean;
import com.jing.yao.component.dto.YaoBaseDTO;
import com.jing.yao.component.entity.YaoBaseEntity;
import com.jing.yao.component.params.page.PageParam;
import com.jing.yao.component.service.YaoBaseService;
import com.jing.yao.constant.ErrorCode;
import com.jing.yao.excel.ExcelUtil;
import com.jing.yao.exception.BusinessExceptionBuilder;
import com.jing.yao.holder.UserContentHolder;
import com.jing.yao.utils.YaoBeanUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import static com.jing.yao.bean.ResponseBean.builder;
import static com.jing.yao.component.constants.ResponseCode.ENTITY_NOT_FOUND;
import static com.jing.yao.component.constants.ResponseCode.FAIL_CODE;


/**
 * 基础controller
 *
 * @author Yao
 * @since 2020-06-13
 */
public abstract class YaoBaseController<P extends PageParam, T extends YaoBaseEntity, D extends YaoBaseDTO> {

    /**
     * 记录日志
     */
    protected Logger logger = LoggerFactory.getLogger(this.getClass());

    /**
     * 获取实际服务类
     *
     * @return
     */
    public abstract YaoBaseService<P, T> getService();

    /**
     * 获取当前Controller数据库实体Entity
     *
     * @return
     */
    public abstract T getEntity();

    /**
     * 获取当前Controller数据传输DTO
     *
     * @return
     */
    public abstract D getDTO();

    /**
     * 分页模板
     *
     * @param param
     * @return
     */
    @GetMapping("/pageList")
    public ResponseBean pageList(P param) {
        IPage iPage = getService().page(param);
        List<T> records = iPage.getRecords();
        List<D> list = records.stream().map(entity -> {
            D dto = getDTO();
            YaoBeanUtils.copyAndFormatter(entity, dto);
            return dto;
        }).collect(Collectors.toList());

        Page<D> pageDto = new Page<>();
        pageDto.setCurrent(iPage.getCurrent());
        pageDto.setRecords(list);
        pageDto.setPages(iPage.getPages());
        pageDto.setTotal(iPage.getTotal());
        pageDto.setSize(iPage.getSize());
        return successBean(pageDto);
    }


    /**
     * 根据ID查询相关记录
     *
     * @param id
     * @return
     */
    @GetMapping("/{id}")
    public ResponseBean selectById(@PathVariable("id") Long id) {
        logger.info("{}根据ID查询服务开始,id为:{}", this.getClass().getSimpleName(), id);
        T result = getService().selectOneById(id);
        if (result == null) {
            throw BusinessExceptionBuilder.build(ErrorCode.DETAIL_ID_NOT_EXIST);
        }
        ResponseBean responseBean = successBean(result);
        logger.info("{}根据ID查询结束,结果:{}", this.getClass().getSimpleName(), toJSONString(responseBean));
        return responseBean;
    }

    /**
     * 转换为JSON字符串
     *
     * @param object
     * @return
     */
    private String toJSONString(Object object) {
        ObjectMapper mapper = new ObjectMapper();
        String result = "";
        try {
            result = mapper.writeValueAsString(object);
        } catch (JsonProcessingException e) {
        }
        return result;
    }

    /**
     * 插入
     *
     * @param dto
     * @return
     * @throws Exception
     */
    @PostMapping
    @Permission(value = "add")
    public ResponseBean insert(@Valid @RequestBody D dto) {
        logger.info("{}新增服务开始,参数:{}", this.getClass().getSimpleName(), toJSONString(dto));

        ResponseBean responseBean = successBean();
        boolean insert;
        T entity = getEntity();
        try {
            //dto转为数据库实体
            BeanUtils.copyProperties(dto, entity);
            //新增前校验
            insert = getService().insert(entity);
        } catch (DuplicateKeyException exception) {
            exception.printStackTrace();
            return builder().code(FAIL_CODE).build();
        }

        //当插入记录小于1时,表示插入失败
        if (!insert) {
            responseBean = builder().code(FAIL_CODE).content(insert).build();
        }
        logger.info("{}新增服务结束,结果:{}", this.getClass().getSimpleName(), toJSONString(responseBean));
        return responseBean;
    }


    /**
     * 根据ID修改对应记录
     *
     * @param dto
     * @return
     * @throws Exception
     */
    @PutMapping
    @Permission(value = "edit")
    public ResponseBean updateById(@Valid @RequestBody D dto) {
        String username = UserContentHolder.getContext().getUsername();
        logger.info("{}更新服务开始,更新人:{},参数:{}", this.getClass().getSimpleName(), username, toJSONString(dto));
        T entity = getEntity();
        //dto转换entity
        BeanUtils.copyProperties(dto, entity);
        ResponseBean responseBean = null;
        boolean count;

        try {
            count = getService().update(entity);
        } catch (DuplicateKeyException exception) {
            return builder().code(FAIL_CODE).build();
        }

        //当更新记录小于1时,表示更新失败
        if (!count) {
            responseBean = builder().code(FAIL_CODE).content(count).build();
        }
        logger.info("{}更新服务结束,结果:{}", this.getClass().getSimpleName(), toJSONString(responseBean));

        return successBean(count);
    }


    /**
     * 根据ID删除指定记录,这里被删除的记录会进入删除记录表
     *
     * @param id
     * @return
     */
    @DeleteMapping("/{id}")
    @Permission(value = "del")
    public ResponseBean deleteById(@PathVariable("id") Long id) {
        logger.info("{}删除服务开始,参数ID:{}", this.getClass().getSimpleName(), id);
        boolean deleteCount = getService().removeById(id);
        ResponseBean responseBean = successBean(deleteCount);
        //当删除记录小于1时,表示更新失败
        if (!deleteCount) {
            responseBean = builder().code(FAIL_CODE).build();
        }

        logger.info("{}删除服务结束,结果:{}", this.getClass().getSimpleName(), toJSONString(responseBean));
        return responseBean;
    }
    
    /**
     * 构建成功响应实例
     *
     * @return
     */
    public ResponseBean successBean() {
        return builder().build();
    }

    /**
     * 构建成功响应实例
     *
     * @param data
     * @return
     */
    public ResponseBean successBean(Object data) {
        return builder().content(data).build();
    }
}

2、Service

自定义YaoBaseService,使用方式继承该类
主要提供以下功能
(1)封装基础的增删改查功能
(2)当查询有查询条件时,只需请求对应的Param对象中属性有值即可,无需写再写查询代码
自定义的参数对象继承 YaoBaseParams,并定义自己的属性即可。当然,如果想自定义查询条件只需重写 com.anji.plus.component.service.YaoBaseService#getWrapper即可

/**
 * 基础查询参数
 * @author Yao
 * @since 2020-06-13
 */
public class YaoBaseParams {
}

(3)前置后置处理器 processBeforeOperationprocessAfterOperation。当InsertUpdateDelete 执行前后需要增加些逻辑时,需重写前置后置处理器。比如:删除之前想校验数据是否能删除、保存更新后想操作下缓存(Redis)等
Demo:

  @Override
    public void processBeforeOperation(BmsApplyManagement entity, BaseOperationEnum operationEnum) throws BusinessException {
        switch (operationEnum) {
            case INSERT:
                break;
            case UPDATE:
                break;
            case DELETE:
                break;
            default:
        }
    }
package com.jing.yao.component.service;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.jing.yao.annotation.UnionUnique;
import com.jing.yao.annotation.Unique;
import com.jing.yao.component.constants.BaseOperationEnum;
import com.jing.yao.component.constants.BmsConstants;
import com.jing.yao.component.dto.Query;
import com.jing.yao.component.dto.QueryEnum;
import com.jing.yao.component.entity.YaoBaseEntity;
import com.jing.yao.component.mapper.YaoBaseMapper;
import com.jing.yao.component.params.page.PageParam;
import com.jing.yao.exception.BusinessException;
import com.jing.yao.exception.BusinessExceptionBuilder;
import org.apache.commons.lang3.StringUtils;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;

import static com.jing.yao.component.constants.ResponseCode.ENTITY_NOT_FOUND;

/**
 * 基础service
 * @author Yao
 * @since 2020-06-13
 */
public interface YaoBaseService<P extends PageParam,T extends YaoBaseEntity> {
    /**
     * 获取直接操作数据库接口
     * @return
     */
    YaoBaseMapper<T> getMapper();

    /**
     * 根据id查询记录
     * @param id
     * @return
     */
    default T selectOneById(Long id) {
        return getMapper().selectById(id);
    }

    /**
     * 排序
     * @param pageParam
     * @return
     */
    default IPage<T> page(P pageParam) {
        Page<T> page = new Page<>();
        page.setCurrent(pageParam.getPageNumber());
        page.setSize(pageParam.getPageSize());

        //设置排序
        if(StringUtils.equals(BmsConstants.ASC,pageParam.getOrder()) && StringUtils.isNotBlank(pageParam.getOrder())){
            page.addOrder(OrderItem.asc(pageParam.getSort()));
        } else if(StringUtils.equals(BmsConstants.DESC,pageParam.getOrder()) && StringUtils.isNotBlank(pageParam.getOrder())){
            page.addOrder(OrderItem.desc(pageParam.getSort()));
        } else {
            page.addOrder(OrderItem.desc("update_time"));
        }
        TimeZone.setDefault(TimeZone.getTimeZone("GMT+8:00"));
        return getMapper().selectPage(page, getWrapper(pageParam));
    }

    /**
     * 抽象查询条件
     * @param param 查询条件
     * @return
     */
    default Wrapper<T> getWrapper(P param) {
        QueryWrapper<T> queryWrapper = new QueryWrapper<>();

        //条件的值
        Field[] fields = param.getClass().getDeclaredFields();

        Arrays.stream(fields).forEach(field -> {
            try {
                boolean flag = false;
                field.setAccessible(true);
                if(field.get(param) instanceof String) {
                    flag = StringUtils.isNoneBlank((String)field.get(param));
                } else {
                    flag = field.get(param) != null;
                }
                //判断是否是模糊查询
                if(field.isAnnotationPresent(Query.class) && field.getAnnotation(Query.class).value() == QueryEnum.LIKE) {
                    queryWrapper.like(flag, com.baomidou.mybatisplus.core.toolkit.StringUtils.camelToUnderline(field.getName()), field.get(param));
                } else {
                    queryWrapper.eq(flag, com.baomidou.mybatisplus.core.toolkit.StringUtils.camelToUnderline(field.getName()), field.get(param));
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        });

        return queryWrapper;
    }

    /**
     * 操作前处理
     * @param entity 前端传递的对象
     * @param operationEnum 操作类型
     * @throws BusinessException 阻止程序继续执行或回滚事务
     */
    default void processBeforeOperation(T entity, BaseOperationEnum operationEnum) throws BusinessException{
    }

    /**
     * 操作后续处理
     * @param entity
     * @param operationEnum 操作类型
     * @throws BusinessException  阻止程序继续执行或回滚事务
     */
    default void processAfterOperation(T entity, BaseOperationEnum operationEnum) throws BusinessException {
    }

    /**
     * 插入数据
     * @param entity
     * @throws BusinessException 业务异常
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    default boolean insert(T entity) throws BusinessException {
        //保存前处理
        processBeforeOperation(entity, BaseOperationEnum.INSERT);
        checkUniqueField(entity);
        Integer result = getMapper().insert(entity);
        processAfterOperation(entity, BaseOperationEnum.INSERT);
        return result != null && result >= 1;
    }

    /**
     * 校验唯一
     * @param entity
     */
    default void checkUniqueField(T entity) {
        //获取所有属性
        Field[] fields = entity.getClass().getDeclaredFields();

        //判断单一索引
        for (Field field : fields) {
            if (field.isAnnotationPresent(Unique.class)) {
                Unique unique = field.getDeclaredAnnotation(Unique.class);
                QueryWrapper<T> wrapper = Wrappers.query();
                Integer integer = 0;
                try {
                    Object value = getFieldValue(entity, field);
                    if (entity.getId() != null) {
                        wrapper.ne("id", entity.getId());
                    }
                    wrapper.eq(unique.column(), value);
                    integer = getMapper().selectCount(wrapper);
                } catch (Exception e) {
                    continue;
                }
                if (integer >  0) {
                    throw BusinessExceptionBuilder.build(unique.code());
                }
            }
        }

        //判断联合索引
        QueryWrapper<T> unionWrapper = Wrappers.query();
        if (entity.getId() != null) {
            unionWrapper.ne("id", entity.getId());
        }
        Integer integer = 0;
        boolean flag = false;
        for (Field field : fields) {
            if (field.isAnnotationPresent(UnionUnique.class)) {
                UnionUnique unionUnique = field.getDeclaredAnnotation(UnionUnique.class);
                try {
                    Object value = getFieldValue(entity, field);
                    unionWrapper.eq(unionUnique.column(), value);
                    flag = true;
                } catch (Exception e) {
                    continue;
                }
            }
        }

        if (flag) {
            integer = getMapper().selectCount(unionWrapper);
            if (integer >  0) {
                throw BusinessExceptionBuilder.build(entity.getClass().getAnnotation(UnionUnique.class).code());
            }
        }
    }

    /**
     * 获取属性值
     * @param entity
     * @param field
     * @return
     * @throws IntrospectionException
     * @throws IllegalAccessException
     * @throws InvocationTargetException
     */
    default Object getFieldValue(T entity, Field field) throws IntrospectionException, IllegalAccessException, InvocationTargetException {
        PropertyDescriptor propertyDescriptor = new PropertyDescriptor(field.getName(), entity.getClass());
        Method readMethod = propertyDescriptor.getReadMethod();
        return readMethod.invoke(entity);
    }

    /**
     * 编辑数据
     * @param entity
     * @throws BusinessException 业务异常
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    default boolean update(T entity) throws BusinessException {
        //编辑前处理
        processBeforeOperation(entity, BaseOperationEnum.UPDATE);
        Integer result = getMapper().updateById(entity);
        processAfterOperation(entity, BaseOperationEnum.UPDATE);
        return result != null && result >= 1;
    }

    /**
     * 根据指定字段查询对应的值
     * @param column
     * @param value
     * @return
     */
    default List<T> list(String column, String value) {
        QueryWrapper<T> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(column, value);
        return getMapper().selectList(queryWrapper);
    }


    /**
     * 根据指定条件查询对应的记录
     * @param wrapper
     * @return
     */
    default List<T> list(Wrapper<T> wrapper) {
        return getMapper().selectList(wrapper);
    }

    /**
     * 根据ID查询记录
     * @param id
     * @return
     */
    default T getById(Serializable id) {
        return getMapper().selectById(id);
    }

    /**
     * 删除
     * @param id
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    default boolean removeById(Serializable id) {
        T t = getById(id);
        if(t == null) {
            throw BusinessExceptionBuilder.build(ENTITY_NOT_FOUND);
        }
        processBeforeOperation(t,BaseOperationEnum.DELETE);
        boolean result = SqlHelper.retBool(getMapper().deleteById(id));
        processAfterOperation(t,BaseOperationEnum.DELETE);
        return result;
    }

    /**
     * 删除
     * @param lambdaQueryWrapper
     */
    @Transactional(rollbackFor = Exception.class)
    default void delete(LambdaQueryWrapper<T> lambdaQueryWrapper) {
        getMapper().delete(lambdaQueryWrapper);
    }

    /**
     * 批量删除
     * @param idList
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    default boolean removeByIds(Collection<? extends Serializable> idList) {
        return SqlHelper.retBool(getMapper().deleteBatchIds(idList));
    }

    /**
     * 查询所有
     * @return
     */
    default List<T> findAll() {
        return getMapper().selectList(Wrappers.emptyWrapper());
    }

    /**
     * @Description 导出
     * @author wangxiaoliang
     * @date 2020-07-15 14:11
     */
    default List<T> exportList(P param, HttpServletResponse response) {
        Wrapper<T> wrapper = getWrapper(param);
        List<T> managementList = getMapper().selectList(wrapper);
       return managementList;
    }

    /**
     * 根据指定字段更新值
     * @param id
     * @param column
     * @param value
     */
    default void updateColumn(Long id, String column, Object value) {
        Map<String,Object> params = new HashMap<>();
        params.put(column, value);
        getMapper().updateFieldsById(params, id);
    }

}

3、Mapper

自定义YaoBaseMapper,项目中的Mapper只要实现该接口即可

/**
 * mybatis基础接口
 * @author Yao
 * @since 2020-06-23
 */
public interface YaoBaseMapper<T extends YaoBaseEntity> extends BaseMapper<T> {

    /**
     * 批量插入
     *
     * @param list
     * @return
     */
    int insertBatch(@Param("list") List<T> list);


    /**
     *  根据ID 更新指定字段
     * @param map 指定字段和值
     * @param id id
     * @return
     */
    int updateFieldsById(@Param("map") Map<String, Object> map, @Param("id") Long id);
}

数据库对应实体YaoBaseEntity,使用方式继承即可

package com.jing.yao.component.entity;

import com.baomidou.mybatisplus.annotation.*;

import java.util.Date;

/**
 * 基础数据库实体
 * @author Yao
 * @since 2020-06-13
 */
public class YaoBaseEntity {

    @TableId(value = "id",type = IdType.AUTO)
    private Long id;

    /**
     * 创建人
     */
    @TableField(fill = FieldFill.INSERT)
    private String createBy;

    /**
     * 创建时间
     */
    @TableField(fill = FieldFill.INSERT)
    private Date createTime;

    /**
     * 修改人
     */
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private String updateBy;

    /**
     * 修改时间
     */
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;

    /**
     * 版本号
     * @Version:乐观锁,,需要添加mybatis plus插件optimisticLockerInterceptor
     */
    @TableField(fill = FieldFill.INSERT_UPDATE, update="%s+1")
    @Version
    private Integer version;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getCreateBy() {
        return createBy;
    }

    public void setCreateBy(String createBy) {
        this.createBy = createBy;
    }

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

    public String getUpdateBy() {
        return updateBy;
    }

    public void setUpdateBy(String updateBy) {
        this.updateBy = updateBy;
    }

    public Date getUpdateTime() {
        return updateTime;
    }

    public void setUpdateTime(Date updateTime) {
        this.updateTime = updateTime;
    }

    public Integer getVersion() {
        return version;
    }

    public void setVersion(Integer version) {
        this.version = version;
    }
}

4、DTO

自定义YaoBaseDTO,项目中所有跟前端交互的对象都需要转换为DTO(不必纠结DTO作为传输对象,返回给前端适不适合),DTO包含了字段校验、翻译等。项目中的DTO需要继承该类。该对象配合注解 @Formatter可实现字段的翻译
YaoBaseDTO:

package com.jing.yao.component.dto;
import java.util.Date;

/**
 * 基础传输对象
 * @author Yao
 * @since 2020-06-13
 */
public class YaoBaseDTO {
    private Long id;

    /**
     * 创建人
     */
    private String createBy;

    /**
     * 创建时间
     */
    private Date createTime;

    /**
     * 修改人
     */
    private String updateBy;

    /**
     * 修改时间
     */
    private Date updateTime;

    /**
     * 版本号
     */
    private Integer version;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getCreateBy() {
        return createBy;
    }

    public void setCreateBy(String createBy) {
        this.createBy = createBy;
    }

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

    public String getUpdateBy() {
        return updateBy;
    }

    public void setUpdateBy(String updateBy) {
        this.updateBy = updateBy;
    }

    public Date getUpdateTime() {
        return updateTime;
    }

    public void setUpdateTime(Date updateTime) {
        this.updateTime = updateTime;
    }

    public Integer getVersion() {
        return version;
    }

    public void setVersion(Integer version) {
        this.version = version;
    }
}

@Formatter

package com.jing.yao.annotation;

import java.lang.annotation.*;

/**
 * 翻译
 * @author Yao
 * @since 2020-07-14
 */

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Formatter {

    /**
     * 对应的数据字典,用被注解字段的值取该字典中取值
     * @return
     */
    String dictCode() default "";


    /**
     * 字典翻译后,把翻译后的值赋值到该字段
     * @return
     */
    String targetField() default "";

    /**
     * 指定缓存Key,不用数据字典,直接从对应的可以取值
     * 但是对应Key在Redis的存储必须是Hash类型
     */
    String key() default "";
}

以上只是工作中使用的一部分,如果有问题或者建议欢迎各位老铁指出
代码仓库地址链接

免责声明:文章转载自《基础框架一:“零代码”实现单表增删改查、唯一性校验、枚举类型翻译》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Asp.Net WebApi Post请求整理(一)Linux OpenSSL安装和使用示例下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

深入 js 深拷贝对象

前言 对象是 JS 中基本类型之一,而且和原型链、数组等知识息息相关。不管是面试中,还是实际开发中我们都会碰见深拷贝对象的问题。 顾名思义,深拷贝就是完完整整的将一个对象从内存中拷贝一份出来。所以无论用什么办法,必然绕不开开辟一块新的内存空间。 通常有下面两种方法实现深拷贝: 迭代递归法 序列化反序列化法 我们会基于一个测试用例对常用的实现方法进行...

C#基础(六)--枚举的一些常用操作

本章将介绍以下几点:       1、如何把其它类型转换为枚举类型?    2、如何把枚举中的值添加到下拉菜单中? 一、如何把其它类型转换为枚举类型?        我们回顾一下有关字符串与数字之间的转换,如:        string strValue="12";        int value=int.Parse(strValue);    //使...

五大典型场景中的API自动化测试实践

一、API 测试的基本步骤 通常来讲,API 测试的基本步骤主要包括以下三大步骤: 1、准备测试数据; 2、通过通用的或自己开发的API测试工具发起对被测API的request; 3、验证返回结果的response。 常用的API测试工具有命令行工具cURL、图形界面工具Postman或SoapUI,支持API性能测试的JMeter等。 二、API复杂场景...

u-boot移植总结(三)(转)S3C2440对Nand Flash操作和电路原理(基于K9F2G08U0A)

S3C2440对Nand Flash操作和电路原理(基于K9F2G08U0A) 转载自:http://www.cnblogs.com/idle_man/archive/2010/12/23/1915303.html S3C2440内部集成了一个Nand flash控制器。S3C2440的Nand flash控制器包含了如下的特性: l        一...

张孝祥java高新技术 --- jkd1.5 新特性 -- 精华总结

1. 抽象方法的使用   如果一个方法中大量出现if语句, 那么, 就应该考虑使用抽象来处理. 如下例: package com.lxl; public class Weekend { //周日 public static Weekend SUN = new Weekend(); //周一...

ios学习之旅------玩转结构体

1.全局变量和局部变量 局部变量: 概念:定义函数内部变量 定义格式:变量类型 变量名称; 作用域:从定义那一行開始到所在代码块结束 生命周期:从代码运行到定义的哪一行開始,到其所在的代码的结束为止 特点:同样的代码块中不能够有同名的变量 不同的代码块中能够有同名的变量。内部的变量会覆盖外部定义的变量 全局变量: 概念:定义在函数外部变量 定义:变量类型...