增强 SpringBoot 快速开发工具

项目地址:https://gitee.com/sanri/web-ui

优点:这是一个 web 通用配置的组件,即插即用,可用于新项目或私活。是对 SpringBoot 快速开发的一种补充,它内置了大量的配置来简化开发,遵循约定高于配置原则。

它解决的问题:

  • 固定了输入输出格式
  • 不用像公司的返回结构一样,需要自己包装类型,直接返回原始类型,如果需要可以返回 void
  • 支持树结构数据返回,可以一个注解就转换结构为树形结构
  • 如果项目中出现业务操作不符合或调用第三方出错,可使用异常或断言抛出,我们将拦截成统一格式返回
  • 自带参数空格过滤功能,还可以定义特殊字符和谐
  • 支持校验器,添加了大量常用验证器
  • 支持大文件分片上传,已内置 Controller
  • 支持方法日志参数记录

发现BUG可以提Issue,可以给我发邮件,可以加我QQ,可以进9420技术群讨论.

作者QQ: 2441719087

作者邮箱: ningxiangsanri@163.com

9420 技术交流群: 645576465

作者微信:sanri1993-

项目功能

我新开的一个项目,总结了多年的开发经验所得,它具有的功能有

  • 固定了输入输出格式

    1. // 普通输出格式
    2. @Data
    3. public class ResponseDto<T> implements Serializable {
    4. // 0 字符串表示成功,否则失败
    5. private String code = "0";
    6. private String message;
    7. private T data;
    8. }
    9. // 分页输出格式,是包裹在普通输出格式中的,PageResponseDto 做为 data 属性
    10. @Data
    11. public class PageResponseDto<T> {
    12. private List<T> rows;
    13. private Integer total;
    14. }
    15. // 分页输入格式
    16. @Setter
    17. public class PageParam {
    18. private String pageNo;
    19. private String pageSize;
    20. }
  • 对于 Controller 中的返回不用关心包装类型,返回你所需要的类型就可以了,对于 insert 单表操作可以直接返回 void

    示例一:

    1. @PostMapping("/insertUser")
    2. public void insertUser(User user){
    3. xxxService.insert(user);
    4. }

    它将会返回这样的数据结构

    1. {
    2. "code":"0",
    3. "message":"ok",
    4. "data":null
    5. }

    示例二:

    1. @GetMapping("/queryUserById")
    2. public User queryUserById(Integer userId){
    3. xxxService.queryUserById(userId);
    4. }

    它将会返回这样的数据结构

    1. {
    2. "code":"0",
    3. "message":"ok",
    4. "data":{
    5. "userId":1,
    6. "username":"9420"
    7. }
    8. }

    示例三:

    对于分页数据的处理

    1. @GetMapping("/queryUserPage")
    2. public PageResponseDto<User> pageQuery(PageParam pageParam,Map<String,String> queryParams){
    3. PageHelper.startPage(pageParam.getPageNo(),pageParam.getPageSize());
    4. Page page = (Page) xxxService.pageQuery(queryParams);
    5. List result = page.getResult();
    6. long total = page.getTotal();
    7. return new PageResponseDto(result,total);
    8. }

    它将会返回这样的数据结构

    1. {
    2. "code":"0",
    3. "message":"ok",
    4. "data":{
    5. "total":100,
    6. "rows":[{...},{...}]
    7. }
    8. }

    示例四: 树结构返回

    对于树型结构数据,你可以用简单数据返回,即原来的 List<Dto> 也可以添加一个注解,使其成为树状结构

    1. //rootId 指定为根结点 id
    2. @GetMapping("/treeShowMenu")
    3. @TreeResponse(type = MenuDto.class,rootId = "1")
    4. public List<Menu> treeShowMenu(){
    5. List<Menu> menus = new ArrayList<>();
    6. menus.add(new Menu(1,"全国",-1));
    7. menus.add(new Menu(2,"湖南",1));
    8. menus.add(new Menu(3,"长沙",2));
    9. menus.add(new Menu(4,"深圳",1));
    10. return menus;
    11. }
    1. // 树状结构消息类
    2. public class MenuDto extends RootTreeResponseDto<Menu> {
    3. public MenuDto(Menu origin) {
    4. super(origin);
    5. }
    6. @Override
    7. public String getId() {return origin.getId()+"";}
    8. @Override
    9. public String getParentId() {return origin.getPid()+"";}
    10. @Override
    11. public String getLabel() {return origin.getText();}
    12. @Override
    13. public Menu getOrigin() {return origin;}
    14. }

    它将返回如下数据结构

    1. {
    2. "code": "0",
    3. "message": "ok",
    4. "data": [{
    5. "origin": {
    6. "id": 1,
    7. "text": "全国",
    8. "pid": -1
    9. },
    10. "childrens": [{
    11. "origin": {
    12. "id": 2,
    13. "text": "湖南",
    14. "pid": 1
    15. },
    16. "childrens": [{
    17. "origin": {
    18. "id": 3,
    19. "text": "长沙",
    20. "pid": 2
    21. },
    22. "childrens": [],
    23. "id": "3",
    24. "label": "长沙",
    25. "parentId": "2"
    26. }],
    27. "id": "2",
    28. "label": "湖南",
    29. "parentId": "1"
    30. }, {
    31. "origin": {
    32. "id": 4,
    33. "text": "深圳",
    34. "pid": 1
    35. },
    36. "childrens": [],
    37. "id": "4",
    38. "label": "深圳",
    39. "parentId": "1"
    40. }],
    41. "id": "1",
    42. "label": "全国",
    43. "parentId": "-1"
    44. }]
    45. }
  • 如果项目中出现业务操作不符合或调用第三方出错,可使用异常抛出,我们将拦截成统一格式返回

    示例一:

    1. if(业务条件不满足){
    2. throw BusinessException.create("业务提示信息");
    3. }

    它将会返回这样的数据结构,code 是随机生成的

    1. {
    2. "code":"234234",
    3. "message":"业务提示信息",
    4. "data":null
    5. }

    示例二:

    自定义 code 示例方法一

    1. if(业务条件不满足){
    2. throw BusinessException.create("E007","业务提示信息");
    3. }

    它将会返回这样的数据结构

    1. {
    2. "code":"E007",
    3. "message":"业务提示信息",
    4. "data":null
    5. }

    示例三:

    自定义 code 示例方法二

    1. // 配置异常代码
    2. public enum SystemMessage implements ExceptionCause<BusinessException> {
    3. SIGN_ERROR(4005,"签名错误,你的签名串为 [%s]"),;
    4. ResponseDto responseDto = new ResponseDto();
    5. private SystemMessage(int returnCode,String message){
    6. responseDto.setCode(returnCode+"");
    7. responseDto.setMessage(message);
    8. }
    9. public BusinessException exception(Object...args) {
    10. return BusinessException.create(this,args);
    11. }
    12. }

    使用异常

    1. if(业务条件不满足){
    2. throw SystemMessage.SIGN_ERROR.exception("签名串");
    3. }

    它将会返回这样的数据结构

    1. {
    2. "code":"4005",
    3. "message":"签名错误,你的签名串为 [签名串]",
    4. "data":null
    5. }
  • 你以为它就这么点能耐吗,它还自带参数空格过滤功能,还可以定义特殊字符和谐

    你只需要注入一个处理器,它就能工作,注入方式如下

    1. @Bean("paramHandler")
    2. public Function paramHandler(){
    3. return param -> param.replace("<","《");
    4. }
  • 自带了日期转化(输入)功能,可以支持的日期格式有

    1. final String[] parsePatterns = new String[]{"yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm:ss.S"};

    现在是固定这三种格式 ,后面会放开让使用者自己配置

  • 支持校验器,已经帮你设置好了两个 group ,直接使用即可

    1. public interface Insert {
    2. }
    3. public interface Update {
    4. }
  • 支持大文件上传,文件秒传,文件验证;你只需要配置几个选项即可使用

    1. # 文件上传的位置
    2. sanri.webui.upload.basePath=d:/test/
    3. # 临时文件路径
    4. spring.servlet.multipart.location=d:/tmp

    或者你想上传到别的地方,那就需要自己实现 com.sanri.web.bigfile.BigFileStorage然后注入 IOC 到容器

    1. @Bean
    2. public BigFileStorage bigFileStorage(){
    3. return new LocalBigFileStorage();
    4. }

大文件上传的几个接口说明

已经帮你添加了一个 controller ,用于大文件上传,下面是接口说明

  • GET /upload/file/fileMetaData?originFileName=原始文件名&fileSize=文件大小&md5=文件 md5

    返回 FileMetaData 数据,重要的数据是那个相对路径 relativePath 因为它是接下来所有接口的入参

  • GET /upload/file/filePosition?relativePath=相对路径

    返回 文件当前上传的大小,用于断点续传

  • POST /upload/file/uploadPart?relativePath=相对路径

    body 中添加 form-data 参数,file=文件

    返回上传文件位置

  • GET /upload/file/validateFile?relativePath=相对路径&fileSize=文件大小&md5=文件 md5 值

    返回文件是否正常上传,无损坏

使用说明

引入包或下载 jar 包文件

  1. <dependency>
  2. <groupId>com.sanri.web</groupId>
  3. <artifactId>web-ui</artifactId>
  4. <version>1.0-SNAPSHOT</version>
  5. </dependency>

开启快速开发

  1. @EnableWebUI

如果想开启大文件上传

  1. @EnableBigFileUpload

更新列表

update 2019/10/24 增加日志组件

可以为方法标记记录日志功能,这是很常见的一个功能,感谢网友 东莞-队长(qq: 1178130627) 的朋友提出

因为日志每个系统有各自的做法,有的可能还需要把日志存储到 mongodb 中去,所以不可能全部统一起来,注解也是不支持继承的;所以我的解决办法是,我可以帮你尽可能的解析出一些参数来,但具体的实现逻辑还需要你自己来弄,框架默认会给你注入一个把日志打印到控制台的功能。

使用方法为使用注解标记当前方法,它将默认使用 com.sanri.web.logmark.Slf4jLogInfoHandler 来记录日志

  1. @GetMapping("/testParamTrim")
  2. @SysLogMark
  3. public void testParamTrim(TestParam testParam){}

兼容性说明 :

  1. 兼容 application/x-www-form-urlencoded 类型参数
  2. 兼容 application/form-data 类型参数
  3. 兼容 application/json 类型参数

当然,我会排除文件类型的参数,它太庞大了,不可能打印在日志里面

实现自己的日志记录方法:注入一个 LogInfoHandler 的 Bean 到 IOC 容器中

新增配置

  1. # 日志参数打印,可支持的项有 base,param,header,body
  2. sanri.webui.logmark.showInfos=base,param,header,body

update 2019/10/25 增加常用验证器和部分工具

一些常用校验器和通用预览和下载功能,比较常用,这里给全部集成了

参数校验器使用方法

  1. // 必须为强密码
  2. @NotNull
  3. @Password(strength = Password.Strength.STRONG)
  4. private String password;

其它常用验证器

  • @UserName 验证参数是否为用户名

  • @Password 验证参数是否为密码

  • @IdCard18 验证参数是否为 18 位身份证

    可以在 resources 目录下放置一个区域代码,做更强的验证,文件名为 areaCodes,文件内容以逗号分隔所有的区域代码

  • @EnumIntValue@EnumStringValue 验证参数是否为枚举值

增加一些文件下载,预览方法,和 request 请求信息的获取

  1. @Autowired
  2. RequestInfoHelper requestInfoHelper;
  3. @Autowired
  4. StreamHelper streamHelper;

修改处理器注入方式 ,使用自己的接口 ParamHandler,不使用 Function

  1. @Bean("paramHandler")
  2. public ParamHandler paramHandler(){
  3. return param -> param.replace("<","《");
  4. }

update 2019/10/27 增加树形数据返回

为解决前端 mm 需要后端人员返回树形结构数据问题,其实大部分框架已经支持简单树形数据,像 ztree ,但也有的前端框架是需要后端帮忙转化一下数据结构的,所以特加此功能

这个树形结构的转换使用了一个快速转换的机制,充分利用了对象在内存中地址的原理,实测在万条数据转换为 10ms 左右,使用方法是先实现一个 TreeResponseDto 的类,然后在 Controller 中添加一个注解

  1. @TreeResponse(type = MenuDto.class,rootId = "1")

springboot 快速开发的定制补充的更多相关文章

  1. SpringBoot快速开发REST服务最佳实践

    一.为什么选择SpringBoot Spring Boot是由Pivotal团队提供的全新框架,被很多业内资深人士认为是可能改变游戏规则的新项目.早期我们搭建一个SSH或者Spring Web应用,需 ...

  2. springboot快速开发(简单web)

    这是一个springboot基础配置文件介绍的demo.只涉及到 控制层与前端的简单交互,用于验证代码的畅通. spring-boot  pom.xml解释 <?xml version=&quo ...

  3. spring-boot开发:使用内嵌容器进行快速开发及测试

    一.简述一下spring-boot微框架 1.spring-boot微框架是什么? 大家都知道,在使用spring框架进行应用开发时需要很多*.xml的初始化配置文件,而springBoot就是用来简 ...

  4. 基于SpringBoot+Mybatis+AntDesign快速开发平台,Jeecg-Boot 1.1 版本发布

    Jeecg-Boot 1.1 版本发布,初成长稳定版本 导读     平台首页UI升级,精美的首页支持多模式 提供4套代码生成器模板(支持单表.一对多) 集成Excel简易工具类,支持单表.一对多导入 ...

  5. 使用springBoot进行快速开发

    springBoot项目是spring的一个子项目,使用约定由于配置的思想省去了以往在开发过程中许多的配置工作(其实使用springBoot并不是零配置,只是使用了注解完全省去了XML文件的配置),达 ...

  6. fieldmeta 基于springboot的字段元数据管理,通用代码生成,快速开发引擎

    fieldmeta: 基于springboot的字段元数据管理 version:Alpha 0.0.1 ,码云地址:https://gitee.com/klguang/fieldmeta 元数据(Me ...

  7. JeecgBoot 2.1.1 代码生成器AI版本发布,基于SpringBoot+AntDesign的JAVA快速开发平台

    此版本重点升级了 Online 代码生成器,支持更多的控件生成,所见即所得,极大的提高开发效率:同时做了数据库兼容专项工作,让 Online 开发兼容更多数据库:Mysql.SqlServer.Ora ...

  8. 在线Online表单来了!JeecgBoot 2.1 版本发布——基于SpringBoot+AntDesign的快速开发平台

    项目介绍 Jeecg-Boot 是一款基于SpringBoot+代码生成器的快速开发平台! 采用前后端分离架构:SpringBoot,Ant-Design-Vue,Mybatis,Shiro,JWT. ...

  9. 基于SpringBoot+AntDesign的快速开发平台,JeecgBoot 2.0.2 版本发布

    Jeecg-Boot 是一款基于SpringBoot+代码生成器的快速开发平台! 采用前后端分离架构:SpringBoot,Ant-Design-Vue,Mybatis,Shiro,JWT. 强大的代 ...

随机推荐

  1. SpringCloud学习笔记(4):Hystrix容错机制

    简介 在微服务架构中,微服务之间的依赖关系错综复杂,难免的某些服务会出现故障,导致服务调用方出现远程调度的线程阻塞.在高负载的场景下,如果不做任何处理,可能会引起级联故障,导致服务调用方的资源耗尽甚至 ...

  2. 行数据库VS列数据库

    一.介绍 目前大数据存储有两种方案可供选择:行存储和列存储.业界对两种存储方案有很多争持,集中焦点是:谁能够更有效地处理海量数据,且兼顾安全.可靠.完整性.从目前发展情况看,关系数据库已经不适应这种巨 ...

  3. '\b'退格符号笔记

    今天在给小孩儿讲for循环输出最后一个输出项没有空格的情况 借助标记,选择在第二个至最后一个的输出项前添加空格 ; ; i < n; i++) { ) cout << a[i]; e ...

  4. EditPlus 全系列 注册码

    EditPlus4注册码 注册名:host1991 序列号:14F50-CD5C8-E13DA-51100-BAFE6  注册名:360xw 注册码:93A52-85B80-A3308-BF130-4 ...

  5. Java线程池Executor&ThreadPool

    java自1.5版本之后,提供线程池,供开发人员快捷方便的创建自己的多线程任务.下面简单的线程池的方法及说明. 1.Executor 线程池的顶级接口.定义了方法execute(Runnable),该 ...

  6. Linux入门基础之 下

    八.Linux 管道.重定向及文本处理 8.1.Linux 多命令协作:管道及重定向 8.1.1 开源文化 开源文化的核心理念之一就是不要重复发明轮子,很多的开源软件都是现有软件.代码.功能的重新组合 ...

  7. (2)安装elastic6.1.3及插件kibana,x-pack,essql,head,bigdesk,cerebro,ik

    5.2kibana安装 5.2.1解压kibana安装包,修改config/kibana.yml中端口,服务器地址,elastic连接地址 -linux-x86_64.tar.gz cd kibana ...

  8. jquery的api以及用法总结-选择器

    jQuery API及用法总结 选择器 基本选择器 * 通用选择器 .class 类选择器,一个元素可以有多个类(chrome使用原生js函数getElementByClassName()实现) 利用 ...

  9. Windows10安装多个版本的PostgreSQL数据库,但是均没有自动注册Windows服务的解决方法

    1.确保正确安装了PostgreSQL数据库,注意端口号不能相同 我的安装目录如图: 其中9.6版本的端口号为5432,10版本的端口号为5433,11版本的端口号为5434.若不知道端口号,可在Po ...

  10. 一个有意思的js块作用域问题

    1.问题 首先把问题放出来,昨天看了一个掘友发的一个问题,然后跟我同事一起研究了一下,没找出来是为什么,然后我回来一直在想为什么,然后各种找资料研究,从各个方面找为什么,比如js上下文,作用域,js垃 ...