Spring Easy

Spring Easy

用途

通过自动配置,实现了一些国内 Spring Boot 开发时需要在 Spring Boot 框架基础上完成的一些配置工作,可以提升基于 Spring Boot 开发 Web 应用的效率。

安装

使用 Maven 进行包管理,可以从中央仓库安装依赖:

<dependency><groupId>cn.icexmoon</groupId><artifactId>spring-easy-boot-starter</artifactId><version>1.0.0</version>
</dependency>

功能说明

封装控制器方法返回值

提供对 JSON 返回的统一封装。

比如 Controller 方法:

@GetMapping("/say")
public Map<String, String> say() {return Map.of("msg", "hello");
}

Spring Boot 默认返回:

{"msg": "hello"
}

使用本应用后:

{"success": true,"message": null,"data": {"msg": "hello"}
}

这里利用返回值处理器 ResponseBodyAdvice 对控制器方法的返回值进行统一封装,将其封装为 Result 对象的 data 属性,然后由 Spring 的 ResponseBody 返回值处理器(Return Value Resolver)进行处理,即使用消息转换器(默认为 Jackson)将 Result 对象解析成 JSON 字符串作为响应报文体返回。

需要注意的是,由 @Response 注解标记,且返回类型是 String 的控制器方法比较特殊:

@GetMapping("/msg")
public String msg() {return "<h1>hello</h1>";
}

这个控制器方法的返回值不走 ResponseBody 返回值处理器,会被另一个返回值处理器处理,处理方式也很简单,直接作为字符串填充到响应报文体中返回。这也符合开发者需要,因为这种方式定义的控制器方法,通常会直接返回 Html 片段等,不需要返回值处理器进行消息转换等额外处理。

因此,对于这种类型的控制器方法,本项目同样不会进行封装,以便行为和 Spring Boot 的默认实现保持一致。

如果你需要返回给前端的内容只有一个字符串,且希望返回标准封装的形式,可以直接构造 Result 对象并返回:

@GetMapping("/msg2")
public Result<String> msg2() {return Result.success("hello", null);
}

本项目不会对 Result 类型的返回进行再次包装。

对于其他形式的基本类型返回,本项目都会进行封装,比如:

@GetMapping("/void")
public void voidMethod() {
}@GetMapping("/boolean")
public boolean booleanMethod() {return false;
}@GetMapping("/int")
public int intMethod() {return 11;
}

都会包装并返回 Result 对象的 JSON 字符串。

统一处理并返回错误信息

项目使用异常处理器(Exception Handler)ErrorControllerAdvice 对异常进行统一处理,并封装成标准返回值返回。

比如会产生异常的控制器方法:

@GetMapping("/default")
public Result<Void> defaultError() {int i = 1 / 0;return Result.success();
}

返回报文:

{"success": false,"message": "/ by zero","data": null
}

控制台中会由cn.icexmoon.springeasy.boot.ErrorControllerAdvice输出相关异常信息日志,日志级别为error

业务层面产生的异常,比如缺少用户信息等,应当使用自定义异常 BusinessException,这个异常同样会被捕获并封装成统一格式返回,区别在于默认异常的 HTTP 状态码是 500,业务异常的 HTTP 状态码是 200。

可以在任意需要返回业务错误的地方直接抛出 BusinessException,或者在需要的时候将其它类型的异常包装成业务异常抛出:

@GetMapping("/business")
public Result<Void> businessError() {try {int i = 1 / 0;} catch (Throwable e) {Map<String, ?> exceptionData = Map.of("cause", e,"businessCode", "1001");throw BusinessException.builder().cause(e).message(e.getMessage()).data(exceptionData).build();}return Result.success();
}

BusinessException 的 data 属性可以存放需要传递给前端的额外信息,它将被保存到 Result 对象的 data 属性后返回给前端。

对于 Servlet 异常(比如 Filter 产生的),定义了一个控制器 ServletErrorController 进行处理,以同样的返回标准 Result。控制器方法中只会进行简单异常信息打印和控制台异常调用日志输出:

@ResponseBody
public Result<?> error(HttpServletRequest request) {Throwable error = (Throwable) request.getAttribute((RequestDispatcher.ERROR_EXCEPTION));log.error(error.getMessage(), error);return Result.fail("Servlet 错误:" + error.getMessage());
}

如果不满足需要,可以覆盖这个 Bean 进行自定义。

该控制器默认使用 /error 路径进行内部跳转,如果你不想使用该路径(通常是被其它控制器方法已经占用),可以通过配置文件中的属性进行修改:

spring-easy:boot-starter:error-page-path: /servlet_error

时间类型转换

项目添加了针对 LocalDateTimeLocalDate 的类型转换器,以支持国内常见的 yyyy-MM-dd HH:mm:ssyyyy-MM-dd 格式的日期/时间字符串转换。

启用本项目后可以直接通过 URL 的查询参数传递时间字符串:

localhost:8080/hello/time?time=2025-07-09 11:08:03

控制器方法:

@GetMapping("/time")
public LocalDateTime time(@RequestParam LocalDateTime time) {log.info(time.toString());return time;
}

LocalDateTime类型的@RequestParam参数可以被正常解析,不需要使用其他额外的类型转换注解。

为了能够让 jackson 正确解析和编码同样格式的时间字符串,本项目添加了相应的 jackson 解析器/编码器。因此如果使用本项目的时间类型转换功能,最好不要替换 Spring Boot 默认的消息转换器 jackson。

IEnum 枚举类型转换

如果你的项目使用 MyBatisPlus,且实体类中存在枚举字段,使用IEnum接口是最方便的:

@TableName(value = "user")
@Data
public class User {public enum Sex implements IDescEnum<Integer> {MALE(5, "男"), FEMALE(6, "女");private final Integer value;private final String desc;Sex(Integer value, String desc) {this.value = value;this.desc = desc;}@Overridepublic Integer getValue() {return value;}@Overridepublic String getDesc() {return desc;}}/****/@TableId(type = IdType.AUTO)private Long id;/*** 姓名*/private String name;/*** 性别 5 男,6 女*/private Sex sex;
}

这里使用的 IDescEnum 接口是对 IEnum 接口的一个扩展,本质是一样的,只是额外记录枚举常量的中文信息。

MyBatisPlus 实现了 Service 层和数据库的 IEnum 和 int 值的转换,但如果将 IEnum 类型的枚举用于控制器方法参数或返回值,就会被 Spring Boot 当做普通的枚举类型进行处理。

本项目通过添加类型转换器和 jackson 编码器/解析器,实现了 int 和 IEnum 枚举的转换。

关闭部分功能

本项目默认开启所有功能,如果要关闭相关功能,可以通过配置文件:

spring-easy:boot-starter:wrap-result: truewrap-error: truetime-converter: trueenum-converter: true

相应的属性设置为 false 即可。需要更高程度的自由定制可以查看源码后覆盖相应的 bean 定义。

示例

spring-easy-test 是一个包含了所有功能的完整 Spring Boot 示例,展示了如何添加本项目以及使用相应功能。

开源

项目使用 Apache 2 许可证开源,仓库地址 icexmoon/spring-easy。

项目代码结构为:

  • spring-easy-boot-starter,Spring Boot 的自动配置相关
  • spring-easy-parent,Maven 依赖版本控制以及项目编译
  • spring-easy-test,一个用于测试/示例的 Spring Boot Web 项目
  • spring-easy-util,核心类,包含 jackson 解析器/编码器、Spring 类型转换器等

反馈

Issues · icexmoon/spring-easy

更新日志

1.0.0

发布

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/88758.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/88758.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Node.js】文本与 pdf 的相互转换

pdf 转文本 主要使用 pdf-parse 这个库&#xff0c;直接识别提取我们 pdf 文件中的文字。 const express require("express"); const fs require("fs"); const PDFParser require("pdf-parse"); const cors require("cors");const…

分布式ID方案

目录 &#x1f4ca; 分布式ID方案核心指标对比 &#x1f50d; 分方案深度解析 ⚙️ 1. UUID (Universally Unique Identifier) ❄️ 2. Snowflake (Twitter开源) ☘️ 3. 美团Leaf 号段模式 Snowflake模式 &#x1f504; 4. 百度UidGenerator &#x1f680; 5. CosId …

张量类型转换

一.前言本章节我们来讲解张量的类型转换&#xff0c;掌握张量的转换方法&#xff0c;张量的类型转换也是经常使⽤的⼀种操作&#xff0c;是必须掌握的知识点。在本⼩节&#xff0c;我们主要学习如何将 numpy 数组和 PyTorch Tensor 的转化⽅法.二.张量转换为 numpy 数组使⽤ Te…

JavaEE-初阶-多线程初阶

概念第一个多线程程序 可以通过查看jdk路径来找到jdk的控制可以通过jconsole来查看线程。创建线程这是实现多线程的其中一种方法&#xff0c;继承Thread类&#xff0c;实现run方法&#xff0c;之后实例化继承了Thread类的MyThread方法&#xff0c;调用start方法&#xff0c;就会…

解释全连接层的“参数数量”和“计算过程”,保证像看动画片一样直观~

假设场景输入图像&#xff1a;一张极小的 灰度图&#xff08;即 H2,W2&#xff0c;共4个像素&#xff09;&#xff0c;像素值如图所示&#xff1a;隐藏层&#xff1a;假设隐藏层也是 &#xff08;即 H2,W2&#xff0c;共4个神经元&#xff09;&#xff0c;每个神经元用 ( 表示…

DOM编程实例(不重要,可忽略)

文章目录 简介 表格增加删除&#xff0c;效果如下图 样式属性案例 简介 DOM---表格添加删除&#xff0c;样式属性案例 表格增加删除&#xff0c;效果如下图 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><met…

​Windows API 介绍及核心函数分类表

Windows API 介绍​ Windows API&#xff08;Application Programming Interface&#xff09;&#xff0c;也称为WinAPI&#xff0c;是微软Windows操作系统的核心编程接口。它提供了一系列函数、消息、数据结构、宏和系统服务&#xff0c;允许开发者创建运行在Windows平台上的应…

Kubernetes Dashboard UI 部署安装

K8S 集群环境&#xff1a; Ubuntu 24 / K8S 1.28.21. 推荐使用helm 安装Kubernetes Dashboardsudo snap install helm --classic2. 部署Kubernetes Dashboard# Add kubernetes-dashboard repository helm repo add kubernetes-dashboard https://kubernetes.github.io/dashboar…

python-enumrate函数

文章目录基本语法基本用法基本遍历指定起始索引实际应用场景需要索引的循环创建字典映射处理文件行号与range(len())对比注意事项enumerate()是Python内置函数&#xff0c;用于在遍历序列&#xff08;如列表、元组或字符串&#xff09;时同时获取索引和值。基本语法 enumerate…

FPGA通信设计十问

1. FFT有什么用&#xff1f;FFT&#xff08;快速傅里叶变换&#xff09;是离散傅里叶变换&#xff08;DFT&#xff09;的高效实现算法&#xff0c;它的核心作用是快速将信号从时域转换到频域&#xff0c;从而简化信号分析和处理的过程。自然界的信号&#xff08;如声音、图像、…

代理模式——Java

代理模式 在Java中代理模式是一种设计模式&#xff0c;是通过代理类来代替原始的对象&#xff0c;可以在不改变原始对象的基础上&#xff0c;对它进行扩展&#xff08;新增一些新功能&#xff09;。在目标方法的执行的执行前后添加一些自定义的方法。 静态代理 步骤&#xff1a…

基于Catboost算法的茶叶数据分析及价格预测系统的设计与实现

文章目录有需要本项目的代码或文档以及全部资源&#xff0c;或者部署调试可以私信博主项目介绍数据采集数据预处理数据分析与可视化大屏设计模型构建系统展示每文一语有需要本项目的代码或文档以及全部资源&#xff0c;或者部署调试可以私信博主 项目介绍 本研究基于京东官网…

【数据库基础 1】MySQL环境部署及基本操作

目录 一、MySQL部署 1.更新软件包列表 2.查看合适的安装包&#xff1a; 3.安装MySQL 4.启动数据库服务并设置开机自启 5.检测MySQL当前状态 6.配置文件修改 二、基本操作指令 1.登陆MySQL 2.创建用户&修改用户密码 3.查看版本 4.退出MySQL 5.停止MySQL 6.数据…

(C++)任务管理系统(正式版)(迭代器)(list列表基础教程)(STL基础知识)

源代码&#xff1a;#include <iostream> #include <list> #include <string>using namespace std;void menu(){cout<<"\n 任务管理系统 "<<endl;cout<<"1.添加普通任务"<<endl;cout<<"2.添加紧急任务…

创建uniapp项目引入uni-id用户体系使用beforeRegister钩子创建默认昵称

需求描述 基于uniCloud开发项目&#xff0c;通常会使用用户体系&#xff0c;uni-id就是基于uniCloud的用户体系&#xff0c;满足常规需要的账号密码注册、登录&#xff0c;微信登录等快捷方式&#xff0c;如果使用uni-id自带的uni-id-pages插件&#xff0c;账号密码注册的话&a…

Opencv---深度学习开发

在OpenCV中进行深度学习开发&#xff0c;主要围绕其dnn模块展开&#xff0c;该模块支持加载预训练模型、预处理输入数据、执行推理计算以及解析输出结果。本文讲解基于OpenCV进行深度学习开发的基本流程。 一、准备工作 在开始开发前&#xff0c;需完成环境配置和资源准备&…

【C++11】右值引用详解

文章目录前言1. 左、右值的概念1.1 左值1.2 右值1.3 右值引用2. 右值引用的价值和使用场景2.1 左值引用的价值和缺陷2.2 右值引用的价值和使用场景2.3 小结3. 完美转发4. 类的移动构造和移动赋值前言 在C11之前&#xff0c;面对C11之前出现的临时对象的传参构造&#xff0c;都…

如何用自指理解世界

自指即自我指涉&#xff0c;即自己的描述关联到了自己&#xff0c;典型例子是“这句话是假话”这个悖论。人类对自指的研究由来已久&#xff0c;很多概念、定理都与之相关&#xff0c;由于它的巧妙性&#xff0c;很多学者对其展开了深入研究&#xff0c;并且认为自指是理解宇宙…

Next.js 实战笔记 2.0:深入 App Router 高阶特性与布局解构

Next.js 实战笔记 2.0&#xff1a;深入 App Router 高阶特性与布局解构 上一篇笔记&#xff1a; Next.js 实战笔记 1.0&#xff1a;架构重构与 App Router 核心机制详解 上篇笔记主要回顾了一些 Next12 到 Next15 的一些变化&#xff0c;这里继续学习/复习一些已有或者是新的…

TCP 传输时 sk_buff 的 clone 和 unclone

周一有位朋友咨询个问题&#xff0c;问题本身不重要&#xff0c;但牵扯出的细节却是非常有趣。 Linux 内核协议栈的 skb 设计非常高效和精巧&#xff0c;多个 skb 可以指向同一块 data&#xff0c;这就是 clone&#xff0c;当 data 不止一个 skb 指示时&#xff0c;任何一个 s…