1 Star 0 Fork 94

杜伯 / AJ-Gaea

forked from anji-plus / AJ-Gaea 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
devdoc.md 15.41 KB
一键复制 编辑 原始数据 按行查看 历史
WongBin 提交于 2021-04-11 08:49 . revert

开发手册

新项目初始化

全新的项目,代码框架初始化操作详见项目初始化

代码生成

代码增量模块,基于数据模型迭代开发,自动生成前后端基础功能,详见代码生成

UI国际化

代码生成时可以选择国际化版本,UI国际化维护详见UI国际化配置

单表的CRUD

如果是单表的操作,通过代码模板生成后,后端不需要修改任何代码,就已经有对应的分页查询,新增,修改,删除,查询详情等接口。

  • 对应的Controller需要继承GaeaBaseController。例如:
@RestController
@RequestMapping("/log")
@Api(value = "/log", tags = "")
public class GaeaLogController extends GaeaBaseController<GaeaLogParam, GaeaLog, GaeaLogDTO> {
    @Autowired
    private GaeaLogService gaeaLogService;

    @Override
    public GaeaBaseService<GaeaLogParam, GaeaLog> getService() {
        return gaeaLogService;
    }

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

    @Override
    public GaeaLogDTO getDTO() {
        return new GaeaLogDTO();
    }
}
  • 对应的Service需要继承GaeaBaseService。例如:
public interface GaeaLogService extends GaeaBaseService<GaeaLogParam, GaeaLog> {
}
  • 对应的Mapper需要继承GaeaBaseMapper。例如:
@Mapper
public interface GaeaLogMapper extends GaeaBaseMapper<GaeaLog> {
}

分页查询

  • GaeaBaseController基类提供的分页查询接口如下:
    /**
     * 分页模板
     *
     * @param param
     * @return
     */
    @GetMapping("/pageList")
    @Permission(code = "PAGE", name = "分页")
    @GaeaAuditLog(pageTitle = "查询")
    public ResponseBean pageList(P param) {
        IPage iPage = getService().page(param);
        List<T> records = iPage.getRecords();
        List<D> list = records.stream()
                .map(entity -> GaeaBeanUtils.copyAndFormatter(entity, getDTO()))
                .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 responseSuccessWithData(pageDto);
    }
  • 如果分页查询还有其他查询条件,就在生成的PageParam实体类中写对应的查询条件。例如:
@Setter
@Getter
public class GaeaLogParam extends PageParam implements Serializable {
    /**
     * 用户名称
     */
    @ApiModelProperty(value = "用户名称")
    private String userName;
    /**
     * 请求路径
     */
    @ApiModelProperty(value = "请求路径")
    private String requestUrl;
    /**
     * 访问时间,最小值与最大值用逗号隔开
     */
    @Query(QueryEnum.BWT)
    private String requestTime;
}
  • 如果分页查询列表需要显示字典项值,则在返回的dto的字段上需要使用注解@Formatter。如下:
@ApiModel(value = "用户表")
public class GaeaUserDTO extends GaeaBaseDTO {

    @ApiModelProperty(value = "用户登录名")
    @Unique
    private String username;
    /**
     * 1:可用 0:禁用
     */
    @ApiModelProperty(value = "1:可用 0:禁用")
    @Formatter(dictCode = "ENABLE_FLAG", targetField = "enabledStr")
    private Integer enabled;

其中的账号状态需要显示字典项值。dicCode表示的字典code,targetField表示的是返回的参数名称。

  • 分页查询接口,前端请求的url如下:
http://****/log/pageList?pageNumber=1&pageSize=10&pageTitle=&requestUrl=&userName=&requestTime=2021-03-23+10:00:00,2021-03-23+12:00:00

注:其中的requestTime是一个时间段,传给后端用逗号隔开

  • 如果分页查询列表需要加入排序,前端可以加入请求参数sort和order。例如:
pageList?dictCode=ALERT_CHANNEL&pageNumber=1&pageSize=10&sort=update_time&order=DESC

注:排序字段如果有多个,可以写为sort=update_time,create_time,降序为DESC,升序为ASC

新增

  • GaeaBaseController基类提供的新增接口如下:
/**
     * 插入
     *
     * @param dto
     * @return
     * @throws Exception
     */
    @PostMapping
    @Permission(code = "INSERT", name = "新增")
    @GaeaAuditLog(pageTitle = "新增")
    public ResponseBean insert(@Validated @RequestBody D dto) {
        logger.info("{}新增服务开始,参数:{}", this.getClass().getSimpleName(), GaeaUtils.toJSONString(dto));

        ResponseBean responseBean = responseSuccess();
        T entity = getEntity();
        //dto转为数据库实体
        BeanUtils.copyProperties(dto, entity);
        //插入
        getService().insert(entity);

        logger.info("{}新增服务结束,结果:{}", this.getClass().getSimpleName(), GaeaUtils.toJSONString(responseBean));
        return responseBean;
    }
  • 新增或者修改时可能需要校验某些字段的唯一性,可以使用@Unique注解。例如:
@TableName("table_name")
public class GaeaUser extends GaeaBaseEntity implements Serializable {

    @Unique(code = RespCommonCode.USER_CODE_ISEXIST)
    private String username;
}

注:其中的code是返回给前端的提示语代码,需要国际化处理

修改

  • GaeaBaseController基类提供的修改接口如下:
/**
     * 根据ID修改对应记录
     *
     * @param dto
     * @return
     * @throws Exception
     */
    @PutMapping
    @Permission(code = "UPDATE", name = "更新")
    @GaeaAuditLog(pageTitle = "修改")
    public ResponseBean update(@Validated @RequestBody D dto) {
        String username = UserContentHolder.getContext().getUsername();
        logger.info("{}更新服务开始,更新人:{},参数:{}", this.getClass().getSimpleName(), username, GaeaUtils.toJSONString(dto));
        T entity = getEntity();
        //dto转换entity
        BeanUtils.copyProperties(dto, entity);

        getService().update(entity);

        logger.info("{}更新服务结束,结果:{}", this.getClass().getSimpleName(), GaeaUtils.toJSONString(entity));

        return responseSuccess();
    }

删除

目前提供的删除接口都是属于物理删除

  • GaeaBaseController基类提供的删除接口如下:
/**
     * 根据ID删除指定记录,这里被删除的记录会进入删除记录表
     *
     * @param id
     * @return
     */
    @DeleteMapping("/{id}")
    @Permission(code = "DELETE", name = "删除")
    @GaeaAuditLog(pageTitle = "删除")
    public ResponseBean deleteById(@PathVariable("id") Long id) {
        logger.info("{}删除服务开始,参数ID:{}", this.getClass().getSimpleName(), id);
        getService().deleteById(id);
        logger.info("{}删除服务结束", this.getClass().getSimpleName());
        return responseSuccess();
    }

批量删除

  • GaeaBaseController基类提供的批量删除接口如下:
    /**
     * 删除批量ID对应的记录
     *
     * @param ids
     * @return
     */
    @PostMapping("/delete/batch")
    @Permission(code = "BATCH_DELETE", name = "批量删除")
    @GaeaAuditLog(pageTitle = "批量删除")
    public ResponseBean deleteBatchIds(@RequestBody List<Serializable> ids) {
        logger.info("{}批量删除服务开始,批量参数Ids:{}", this.getClass().getSimpleName(), GaeaUtils.toJSONString(ids));
        boolean deleteCount = getService().deleteByIds(ids);

        ResponseBean responseBean = responseSuccessWithData(deleteCount);

        logger.info("{}批量删除服务结束,结果:{}", this.getClass().getSimpleName(), GaeaUtils.toJSONString(responseBean));
        return responseBean;
    }

扩展增强

  • 如果说想在操作CRUD之前或者之后做其他处理,对应的Service实现类可以重写GaeaBaseService中的相关方法。
    /**
     * 操作前处理
     *
     * @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 {
    }
  • 例如需要新增用户之前,给用户的密码设置默认密码: GaeaUserServiceImpl实现类可以重写GaeaBaseService中的processBeforeOperation方法。
/**
     * 新增用户,需要设置默认密码
     * @param entity        前端传递的对象
     * @param operationEnum 操作类型
     * @throws BusinessException
     */
    @Override
    public void processBeforeOperation(GaeaUser entity, BaseOperationEnum operationEnum) throws BusinessException {
        switch (operationEnum) {
            case INSERT:
                setDefaultPwd(entity);
                break;
            default:
        }
    }

相关注解

  • @Unique 校验数据唯一性
  • @Formatter 数据格式化

参数校验

对于接口参数校验方面,就用Spring Boot中的注解@Validated来完成。

  • 在对应的controller层方法参数上使用@Validated。例如:
/**
     * 用户修改密码
     * @param reqParam
     * @return
     */
    @PostMapping("/updatePassword")
    @GaeaAuditLog(pageTitle = "修改密码")
    public ResponseBean updatePassword(@Validated @RequestBody GaeaUserPasswordParam reqParam){
        return responseSuccessWithData(gaeaUserService.updatePassword(reqParam));
    }
  • 在参数上面加入对应的校验注解。例如:
@Getter
@Setter
public class GaeaUserPasswordParam implements Serializable {
    private String username;
    /**
     * 新密码
     */
    @NotBlank(message = "password not empty")
    @Size(min = 8,message ="Password at least 8 characters" )
    private String password;
}
  • 常用的校验注解如下:
注解名称 描述
@Null 检查该字段为空
@NotNull 不能为null
@NotBlank 不能为空,常用于检查空字符串
@NotEmpty 不能为空,多用于检测list是否size是0
@Max 该字段的值只能小于或等于该值
@Min 该字段的值只能大于或等于该值
@Email 检查是否是一个有效的email地址
@Pattern(regex=,flag=) 被注释的元素必须符合指定的正则表达式
@Size(min=, max=) 检查该字段的size是否在min和max之间,可以是字符串、数组、集合、Map等
@Length(min=,max=) 检查所属的字段的长度是否在min和max之间,只能用于字符串
@AssertTrue 用于boolean字段,该字段只能为true
@AssertFalse 该字段的值只能为false

上传下载

  • 文件相关配置 目前系统中文件上传支持的文件格式是可以配置的,文件的存放目录等信息。详见对应的配置:
file:
  dist-path: /app/disk/upload
  white-list: .png|.jpg|.gif|.icon|.pdf|.xlsx|.xls|.csv|.mp4|.avi
  excelSuffix: .xlsx|.xls|.csv
  downloadPath: http://***/business/file/download
  • 文件上传的记录 文件上传记录存在gaea_file表中,会给每一个文件生成一个唯一的UUID,便于访问。

上传接口

  • 文件上传提供的接口如下:
@RestController
@RequestMapping("/file")
@Api(value = "/file", tags = "")
public class GaeaFileController {
    @Autowired
    private GaeaFileService gaeaFileService;

    @PostMapping("/upload")
    public ResponseBean upload(@RequestParam("file") MultipartFile file) {
        return ResponseBean.builder().message("success").data((gaeaFileService.upload(file))).build();
    }
}

接口返回的是一个完整的访问路径。返回的该url也是下载的地址。

下载接口

  • 文件下载提供的接口如下:
@RestController
@RequestMapping("/file")
@Api(value = "/file", tags = "")
public class GaeaFileController {
    @Autowired
    private GaeaFileService gaeaFileService;

    @GetMapping(value="/download/{fileId}")
    public ResponseEntity<byte[]> download(HttpServletRequest request, HttpServletResponse response, @PathVariable("fileId") String fileId){
        return gaeaFileService.download(request, response, fileId);
    }
}

异常处理

对于后端程序来说,通过Try-catch代码块来捕捉异常是常见的,为了避免程序中出现大量的try-catch代码块,可以通过全局异常对异常进行统一处理。

  • 在盖亚项目里面通过使用@RestControllerAdvice已经对异常进行了统一处理。如下所示:
/**
 * 全局异常处理
 * @author lr
 * @since 2021-01-02
 */
@RestControllerAdvice
public class ExceptionHandlerAdvice {

    private Logger logger = LoggerFactory.getLogger(ExceptionHandlerAdvice.class);

    @Autowired
    private MessageSourceHolder messageSourceHolder;

    /**
     * 业务异常
     * @param businessException
     * @return
     */
    @ExceptionHandler(BusinessException.class)
    public ResponseBean handleBusinessException(BusinessException businessException) {
        return ResponseBean.builder().code(businessException.getCode()).args(businessException.getArgs()).build();
    }

    /**
     * 参数校验异常
     *
     * @param methodArgumentNotValidException
     * @return
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseBean methodArgumentNotValidException(MethodArgumentNotValidException methodArgumentNotValidException) {
        String code = methodArgumentNotValidException.getBindingResult().getFieldError().getDefaultMessage();
        String message;
        try {
            message = messageSourceHolder.getMessage(code, null);
        } catch (NoSuchMessageException exception) {
            message = code;
        }
        return ResponseBean.builder().code(FAIL_CODE).message(message).build();
    }

    /**
     * 业务异常
     * @param exception
     * @return
     */
    @ExceptionHandler(Exception.class)
    public ResponseBean exception(Exception exception){
        //返回值构建
        logger.error("系统异常", exception);
        ResponseBean.Builder builder = ResponseBean.builder();
        builder.code(FAIL_CODE);
        builder.message(messageSourceHolder.getMessage(FAIL_CODE, null));
        return builder.build();
    }

}
  • 项目中如何使用

可以手动抛出业务异常。如下:

	@Override
    public Boolean updatePassword(GaeaUserPasswordParam requestParam) {
        //参数校验
        if (!requestParam.getConfirmPassword().equals(requestParam.getPassword())) {
            //密码和确认密码不一致
            throw BusinessExceptionBuilder.build(RespCommonCode.AUTH_PASSWORD_NOTSAME);
        }
        //新密码不能与老密码一样
        if (StringUtils.equals(requestParam.getOldPassword(), requestParam.getPassword())) {
            throw BusinessExceptionBuilder.build(RespCommonCode.USER_PASSWORD_CONFIG_PASSWORD_CANOT_EQUAL);
        }
	}

文件导出

详见组件文档:导出组件

系统日志

详见组件文档:日志组件

数据归档

详见组件文档:数据归档

高级查询

详见组件文档:高级查询/自定义列

自定义列

详见组件文档:高级查询/自定义列

Java
1
https://gitee.com/dujingppeng/gaea.git
git@gitee.com:dujingppeng/gaea.git
dujingppeng
gaea
AJ-Gaea
dev

搜索帮助