SpringMVC(下篇)
1.响应数据
1.1请求转发和响应重定向
在 Spring MVC 中,Handler 方法返回值来实现快速转发,可以使用 redirect 或者 forward 关键字来实现重定向。
流程:
-
将方法的返回值,设置String类型
-
转发使用forward关键字,重定向使用redirect关键字
-
关键字: /路径
-
注意:如果是项目下的资源,转发和重定向都一样都是项目下路径!都不需要添加项目根路径!
控制层
@Controller
@RequestMapping("jsp")
public class JspController {
/**
*方法的返回值是字符串类型
*不能添加@ResponseBody,直接返回字符串给浏览器
*返回值对应中间的视图名即可
*/
@GetMapping("index")
public String index(HttpServletRequest request) {
request.setAttribute("data","你好黄金圣斗士");
System.out.println("成功找到视图");
return "index";
}
/**
*方法的返回值是字符串类型
*不能添加@ResponseBody,直接返回字符串给浏览器
*返回的字符串前forword:/转发地址
*/
@RequestMapping("forword")
public String forword(){
System.out.println("请求转发成功执行");
return "forword:/jsp/index";
}
/**
*方法的返回值是字符串类型
*不能添加@ResponseBody,直接返回字符串给浏览器
*返回的字符串前redirect:/重定向地址
*/
@RequestMapping("redirect")
public String redirect(){
System.out.println("响应重定向成功执行");
return "redirect:/jsp/index";
}
}
1.2Json数据返回
前置准备:
==============================导入jackson依赖================================
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.0</version>
</dependency>
======================添加json数据转化器(@EnableWebMvc)=======================
//TODO: SpringMVC对应组件的配置类 [声明SpringMVC需要的组件信息]
//TODO: 导入handlerMapping和handlerAdapter的三种方式
//1.自动导入handlerMapping和handlerAdapter [推荐]
//2.可以不添加,springmvc会检查是否配置handlerMapping和handlerAdapter,没有配置默认加载
//3.使用@Bean方式配置handlerMapper和handlerAdapter
@EnableWebMvc //json数据处理,必须使用此注解,因为他会加入json处理器
@Configuration
@ComponentScan(basePackages = "com.atguigu.controller") //TODO: 进行controller扫描
//WebMvcConfigurer springMvc进行组件配置的规范,配置组件,提供各种方法! 前期可以实现
public class SpringMvcConfig implements WebMvcConfigurer {
}
@ResponseBody注解(了解)
@ResponseBody
是 Spring MVC 框架中的一个注解,用于将控制器的返回值自动转换为 JSON 或 XML 格式,并写入 HTTP 响应体中。这个注解通常用在返回数据而不是视图名称的控制器方法上。
主要用途
-
自动反序列化 Java 对象:当你希望将 Java 对象(如 POJOs)直接转换为 JSON 或 XML 并发送给客户端时,可以使用
@ResponseBody
。 -
RESTful API 开发:在开发 RESTful Web 服务时,
@ResponseBody
非常有用,因为它允许你轻松地返回结构化数据而不是视图。
@RequestBody 注解(用的多)
@RequestBody
是 Spring MVC 中用于处理 HTTP 请求体的注解。当控制器方法的参数前使用 @RequestBody
注解时,Spring 会自动将请求体中的 JSON 或 XML 数据绑定到该参数对应的 Java 对象上。这对于接收客户端发送的复杂数据非常有用。
-
自动绑定请求体:
@RequestBody
注解告诉 Spring MVC,自动将请求体中的 JSON 或 XML 数据绑定到方法的参数上。这简化了数据接收的过程,使得开发者无需手动解析请求体。 -
支持复杂数据类型:通过
@RequestBody
,您可以轻松接收客户端发送的复杂数据结构,如对象、数组等,并将其转换为相应的 Java 对象。
@RestController注解
@RestController
是 Spring MVC 中的一个注解,它是 @Controller
和 @ResponseBody
注解的组合。当你使用 @RestController
注解一个类时,意味着这个类中的所有方法默认都会将返回值作为 HTTP 响应体返回,而不需要在每个方法上都添加 @ResponseBody
注解。
主要用途
-
返回值作为响应体:与
@Controller
注解不同,@RestController
注解的方法默认使用@ResponseBody
语义,即方法的返回值会被自动序列化为 JSON 或 XML 格式(取决于请求头的Accept
字段和配置的HttpMessageConverter
),并作为 HTTP 响应体返回给客户端。 -
RESTful 服务:
@RestController
通常用于构建 RESTful Web 服务,因为它简化了数据交换的过程,使得开发者可以专注于业务逻辑的实现,而不需要过多关注视图的渲染。 -
简化代码:使用
@RestController
可以减少模板代码,因为它自动为所有方法添加了@ResponseBody
注解,避免了重复书写。
①@ResponseBody注解可以加在方法和类上
加在类上相当于给类中的每一个方法都分配一个 @ResponseBody注解
数据直接放入响应体中返回,不会走视图解析器(用于将方法返回的对象序列化为 JSON 或 XML 格式的数据,并发送给客户端。具体来说,@ResponseBody 注解可以用来标识方法或者方法返回值,表示方法的返回值是要直接返回给客户端的数据,而不是由视图解析器来解析并渲染生成响应体(viewResolver没用)。)
②@RestController=@Controller+@ @ResponseBody
可以在类上声明@RestController注解
@Controller
@RequestMapping("json")
public class JsonController {
@ResponseBody
@GetMapping("data")
public User data(){
User user = new User();
user.setAge("18");
user.setName("huermosi");
return user;
}
@ResponseBody
@GetMapping("data1")
public List<User> dataList(){
User user = new User();
user.setAge("18");
user.setName("huermosi");
ArrayList<User> users = new ArrayList<>();
users.add(user);
return users;
}
}
1.3静态资源返回
静态资源:资源本身已经是可以直接拿到浏览器上使用的程度了,不需要在服务器端做任何运算、处理。典型的静态资源包括:
纯HTML文件
图片
CSS文件
JavaScript文件
......
准备:配置类要实现WebMvcConfigurer接口
在配置类中实现configureDefalutServletHandling方法,调用参数configurer的enable方法即可
如此在dispatcherServlet通过一个路径去handlerMapping中找对应的handler方法没找到时,就会继续通过此路径去找静态资源
配置类
@EnableWebMvc //json数据处理,必须使用此注解,因为他会加入json处理器
@Configuration
@ComponentScan(basePackages = "com.atguigu.controller") //TODO: 进行controller扫描
//WebMvcConfigurer springMvc进行组件配置的规范,配置组件,提供各种方法! 前期可以实现
public class SpringMvcConfig implements WebMvcConfigurer {
//配置jsp对应的视图解析器
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
//快速配置jsp模板语言对应的
registry.jsp("/WEB-INF/views/",".jsp");
}
//开启静态资源处理 <mvc:default-servlet-handler/>
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
2.RESTFUI风格
官网地址:
[RESTful]风格((Representational State Transfer))是一种网络应用程序的设计风格和开发方式,它基于[HTTP协议](如[GET]、[POST]、[PUT]、[DELETE])来操作资源,并通过[URI]进行资源定位。RESTful风格的核心思想是将Web应用程序的功能作为资源来表示,使用统一的标识符(URI)对这些资源进行操作。
规范的设计:
①url【地址】
②请求方式【GET,POST,PUT,DELETE】
③传递参数【param,json,path】
- 完整理解:Resource Representational State Transfer
- Resource:资源
- Representational:表现形式,比如用JSON,XML,JPEG等
- State Transfer:状态变化,通过HTTP的动词(GET、POST、PUT、DELETE)
- 实现 一句话:使用资源名作为URI,使用HTTP的请求方式表示对资源的操作
特点:
1.每一个URI代表1种资源(URI 是名词);
2.客户端使用GET、POST、PUT、DELETE 4个表示操作方式的动词对服务端资源进行操作:GET用来获取资源,POST用来新建资源(也可以用于更新资源),PUT用来更新资源,DELETE用来删除资源;
3.资源的表现形式是XML或者JSON;
4.客户端与服务端之间的交互在请求之间是无状态的,从客户端到服务端的每个请求都必须包含理解请求所必需的信息。
5.HTTP协议请求方式要求
REST 风格主张在项目设计、开发过程中,具体的操作符合HTTP协议定义的请求方式的语义。
根据接口的具体动作,选择具体的HTTP协议请求方式
路径设计从原来携带动标识,改成名词,对应资源的唯一标识即可
统一数据返回处理
为了返回的数据格式标准,我们构建一个统一数据返回类型。
具体的构建思路如下:我们希望返回给前端的数据由响应状态码,响应信息,响应数据 三个部分组成,首先我们声明出其对应的属性信息,由于返回的数据类型是动态变化的我们可以利用泛型来动态指定它要返回的数据类型。最后声明一些常用的静态方法,当业务成功执行时其状态码和响应信息是固定不变的,我们只需要动态的传入返回数据就可以了,当业务失败时其状态码与响应信息是动态变化的我们只需要动态传入状态码与响应信息就可以了。注意给所有的属性添加Getter和Setter方法
@Data
public class R<T> {
private Integer code;// 状态码
private String msg;//返回信息
private T data;//如果有返回数据,还会带有返回时所需要的数据
//封装好的静态方法,便于直接调用
//①封装成功的方法,状态码与返回信息固定,分别为200和ok
//【情况一】:有返回数据(可以有变化)
public static <T> R<T> ok(T data){
R<T> r = new R<>();
r.setCode(200);
r.setMsg("ok");
r.setData(data);
return r;
}
//【情况二】:没有返回数据
public static R ok(){
R r = new R<>();
r.setCode(200);
r.setMsg("ok");
return r;
}
//②封装失败的方法,一般情况下而言,失败返回时不带有数据信息
//失败方法的状态码和信息是动态变化的
public static <T> R<T> fail(){
R<T> r = new R<>();
r.setCode(500);
r.setMsg("fail");
return r;
}
public static R fail(Integer code,String msg){
R r = new R();
r.setCode(code);
r.setMsg("msg");
return r;
}
}
3.扩展
3.1全局异常处理机制
1编程式异常处理:是指在代码中显式地编写处理异常的逻辑。它通常涉及到对异常类型的检测及其处理,例如使用 try-catch 块来捕获异常,然后在 catch 块中编写特定的处理代码,或者在 finally 块中执行一些清理操作。在编程式异常处理中,开发人员需要显式地进行异常处理,异常处理代码混杂在业务代码中,导致代码可读性较差
2.声明式异常处理:则是将异常处理的逻辑从具体的业务逻辑中分离出来,通过配置等方式进行统一的管理和处理。在声明式异常处理中,开发人员只需要为方法或类标注相应的注解(如 @Throws 或 @ExceptionHandler),就可以处理特定类型的异常。相较于编程式异常处理,声明式异常处理可以使代码更加简洁、易于维护和扩展。
全局异常处理步骤
1.定义异常处理类(全局异常发生会走此类的handler):
全局异常处理类的声明:@ControllerAdvice,@RestControllerAdvice
使用@ControllerAdvice注解,可以返回逻辑视图,转发和重定向的
使用@RestControllerAdvice注解,等于@ControllerAdvice+@RequestBody直接返回json字符串
2.在对应的异常处理方法上添加@ExceptionHandler注解(给注解的对应属性进行赋值,对应的异常类抛出后会执行此方法内的代码)
3.在异常处理类中寻找对应的异常对象:
在没有精确的异常时,会寻找父异常
全局异常处理类构建
//@ControllerAdvice
/**
* projectName: com.atguigu.execptionhandler
*
* description: 全局异常处理器,内部可以定义异常处理Handler!
*/
/**
* @RestControllerAdvice = @ControllerAdvice + @ResponseBody
* @ControllerAdvice 代表当前类的异常处理controller!
*/
@RestControllerAdvice
public class GlobalException {
@ExceptionHandler(ArithmeticException.class)
public Object ArithmeticExceptionHandler(ArithmeticException e) {
e.getMessage();
return "ArithmeticException"+"出现全局异常";
}
/**
* 当发生空指针异常会触发此方法!
* @param e
* @return
*/
@ExceptionHandler(NullPointerException.class)
public Object NullPointerExceptionHandler(NullPointerException e) {
e.printStackTrace();
return "NullPointerException"+"出现全局异常";
}
/**
* 所有异常都会触发此方法!但是如果有具体的异常处理Handler!
* 具体异常处理Handler优先级更高!
* 例如: 发生NullPointerException异常!
* 会触发handlerNullException方法,不会触发handlerException方法!
* @param e
* @return
*/
@ExceptionHandler(Exception.class)
public Object ExceptionHandler(Exception e) {
e.printStackTrace();
return "Exception"+e.getMessage();
}
}
==============================全局异常处理方法模板=================================
/**
* 异常处理handler
* @ExceptionHandler(HttpMessageNotReadableException.class)
* 该注解标记异常处理Handler,并且指定发生异常调用该方法!
*
*
* @param e 获取异常对象!
* @return 返回handler处理结果!
*/
@ExceptionHandler(HttpMessageNotReadableException.class)
public Object handlerJsonDateException(HttpMessageNotReadableException e){
return null;
}
异常类构建
@Controller
@RequestMapping("user")
public class UserController {
@GetMapping("data")
public String data() {
String name=null;
name.toString();//空指针异常
return "ok";
}
@GetMapping("data1")
public String data1() {
int i=10/0;//除零异常
return "ok";
}
}
@ControllerAdvice注解
@ControllerAdvice
是 Spring MVC 中的一个注解,它用于定义全局的控制器增强器(Controller Advisor)。@ControllerAdvice
注解可以用于定义一些全局的配置,比如异常处理、数据绑定、数据预处理等,这些配置将会应用于所有使用 @RequestMapping
注解的控制器方法上。
主要用途
-
全局异常处理:通过实现
HandlerExceptionResolver
接口或使用@ExceptionHandler
注解的方法,可以全局捕获并处理控制器中抛出的异常。 -
全局数据绑定:通过实现
WebDataBinderFactory
接口或使用@InitBinder
注解的方法,可以在控制器方法执行之前对请求参数进行全局的数据绑定和验证。 -
全局数据预处理:通过实现
HandlerMethodArgumentResolver
接口或使用@ModelAttribute
注解的方法,可以在控制器方法执行之前对请求数据进行预处理,并将处理后的数据添加到 Model 中。 -
全局响应体后处理:通过实现
ResponseBodyAdvice
接口,可以对控制器的响应体进行全局的后处理,比如统一添加响应头、修改响应体等。
@RestControllerAdvice注解
@RestControllerAdvice
注解是 Spring MVC 和 Spring Boot 应用程序中用于定义全局异常处理类的注解。它是 @ControllerAdvice
注解的特殊版本,专为 RESTful 风格的应用程序设计。@RestControllerAdvice
可以捕获整个应用程序中抛出的异常,并对它们进行处理,从而实现整个应用程序范围内统一处理异常的目标。@RestControllerAdvice = @ControllerAdvice + @ResponseBody
主要用途
-
全局异常处理:通过实现
@ExceptionHandler
方法,可以捕获并处理控制器中抛出的异常,返回统一的错误响应格式。 -
全局数据绑定:通过实现
@InitBinder
方法,可以在控制器方法执行之前对请求参数进行全局的数据绑定和验证。 -
全局数据预处理:通过实现
@ModelAttribute
方法,可以在控制器方法执行之前对请求数据进行预处理,并将处理后的数据添加到 Model 中。
@ExceptionHandler注解
@ExceptionHandler
注解是 Spring MVC 提供的一个用于处理控制器中抛出的异常的注解。当控制器方法在执行过程中抛出异常时,Spring MVC 会查找是否有带有 @ExceptionHandler
注解的方法能够处理该异常,如果有,则会调用该方法来处理异常,而不是将异常信息直接返回给客户端。
主要用途
-
异常处理:通过
@ExceptionHandler
注解,你可以为控制器中的方法定义异常处理逻辑,从而避免异常信息直接暴露给客户端,提高应用程序的安全性和用户体验。 -
统一响应格式:你可以使用
@ExceptionHandler
注解来确保所有异常都按照统一的格式进行响应,这对于 RESTful API 尤为重要,因为它可以保持 API 的一致性。
最佳实践:
异常处理的最终方式:
①必须要有业务异常类:BizException。
自己构建一个专门服务于自己业务的异常类,其创建思路为,首先继承于RunTime Exception这个异常类。声明异常类的两个属性状态码(code),异常信息(msg)。最后业务异常类的全参构造方法。注意给所有的属性添加Getter和Setter方法
②必须要有异常枚举类:BizExceptionEnume。列举项目中每个模块将会出现的所有异常情况
自己构建一个专门服务于自己业务的枚举类,其构建思路为,首先声明枚举类中所需要的两个属性状态码(code),异常信息(msg)。私有化全参构造方法。最后声明有限的枚举实体,定义为--命名(状态码,错误信息)的格式,必要时可以加上枚举属性的Getter方法。
③编写业务的代码时候,只需要编写正确的业务逻辑,如果出现预期的问题,需要通过抛出异常的方式来中断业务逻辑并通知上层
④编写全局异常处理器:GlobalExceptionHandler。处理所有的异常,返回给前端对应的Json数据与错误码
全局异常处理构建思路:首先创建一个全局异常处理类GlobalExceptionHandler,在这个异常处理类上标注一个注解(二合一注解)@RestControllerAdvice,声明此类是控制增强类放入到容器里面管理,并且返回数据直接从返回体中获取返回不走视图解析器。然后在全局异常处理类中声明对应异常发生时所返回的数据处理逻辑使用@ExceptionHandler注解。
=========================业务异常类构建==================================================
@Data
public class BizException extends RuntimeException {
//自定义异常,便于统一处理
//在业务代码中,如果逻辑出现问题,则抛出此异常,暂停当前业务,并返回友好提示
private Integer code;
private String msg;
//构造方法,传入异常信息和状态码
public BizException(String message, Integer code) {
super(message);
this.code = code;
this.msg = message;
}
//可以声明一个方法,直接从BizEnume枚举类中获取异常信息
public BizException(BizEnume bizEnume) {
super(bizEnume.getMsg());
this.code = bizEnume.getCode();
this.msg = bizEnume.getMsg();
}
}
===============================业务异常枚举类构建===========================================
public enum BizEnume {
//枚举值,外部可以直接使用,进行赋值声明有关状态及其描述信息
//订单状态枚举
ORDER_CLOSE(10001,"订单关闭"),
ORDER_PAY(10002,"订单支付"),
ORDER_DELIVER(10003,"订单发货"),
ORDER_RECEIVE(10004,"订单收货"),
ORDER_COMMENT(10005,"订单评论");
//声明枚举的属性值
@Getter
private Integer code;
@Getter
private String msg;
//声明枚举的构造器
//构造器私有化,外部无法直接创建对象
private BizEnume(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
}
@RestControllerAdvice
public class GlobalExceptionHandler {
//在出现异常时,本来是在本类中寻找异常处理方法
// 本类中没有,则会去全局异常处理器中寻找
//当异常处理时,有对应异常的处理方法和对应异常的父类的处理方法时,优先使用子类的处理方法(优先详细原则)
@ExceptionHandler(BizException.class)
public R handleBizException(BizException e) {
Integer code = e.getCode();
String msg = e.getMsg();
return R.fail(code,msg);
}
//兜底异常处理方法,捕获所有异常
@ExceptionHandler(Throwable.class)
public R handleRuntimeException() {
return R.fail();
}
}
3.2拦截器
过滤器VS拦截器
1、过滤器和拦截器触发时机不一样,过滤器是在请求进入容器后,在请求进入servlet之前进行预处理的。请求结束返回也是,是在servlet处理完后,返回给前端之前。
2、拦截器可以获取IOC容器中的各个bean,而过滤器就不行,因为拦截器是spring提供并管理的,spring的功能可以被拦截器使用,在拦截器里注入一个service,可以调用业务逻辑。而过滤器是JavaEE标准,只需依赖servlet api ,不需要依赖spring。
3、过滤器的实现基于回调函数。而拦截器(代理模式)的实现基于反射
4、Filter是依赖于Servlet容器,属于Servlet规范的一部分,而拦截器则是独立存在的,可以在任何情况下使用。
5、Filter的执行由Servlet容器回调完成,而拦截器通常通过动态代理(反射)的方式来执行。
6、Filter的生命周期由Servlet容器管理,而拦截器则可以通过IoC容器来管理,因此可以通过注入等方式来获取其他Bean的实例,因此使用会更方便
拦截器实现步骤(流程分析)
- 拦截器执行顺序:顺序preHandle => 目标方法 => 倒序postHandle => 渲染 => 倒序afterCompletion
- 只有执行成功放行的 preHandle 会倒序执行 afterCompletion
- postHandle 、afterCompletion 从哪里炸,倒序链路从哪里结束
- postHandle 失败不会影响 afterCompletion 执行
1.创建一个拦截器类,实现HandlerInterceptor接口
2.重写三个方法preHandle,postHandle,afterCompletion
3.在SpringMVC配置类中注册添加创建的拦截器类。自己创建一个SpringMVC的配置类,实现WebMvcConfiguer接口,调用注册方法将自定义的拦截器注册进入SpringMvc的配置中
public class MyInterceptor implements HandlerInterceptor {
/**
*
* @param request 请求对象
* @param response 响应对象
* @param handler 我们要调用的方法对象
* @return true放行 false拦截
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("MyInterceptor.preHandle");
return true;
}
/**
* 当handler执行完毕后,触发的方法 没有拦截机制
* 结果处理,敏感词汇检查
*
* @param request 请求对象
* @param response 响应对象
* @param handler 我们要调用的方法对象
* @param modelAndView 返回的视图和共享域对象
* @throws Exception
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("MyInterceptor.postHandle");
}
/**
*
* @param request 请求对象
* @param response 响应对象
* @param handler 我们要调用的方法对象
* @param ex 异常对象(handler报错)
* @throws Exception
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("MyInterceptor.afterCompletion");
}
}
===================在SpringMVC配置类中注册拦截器============================================
@EnableWebMvc //json数据处理,必须使用此注解,因为他会加入json处理器
@Configuration
@ComponentScan(basePackages = {"com.atguigu.controller","com.atguigu.exceptionhandler"}) //TODO: 进行controller扫描
//WebMvcConfigurer springMvc进行组件配置的规范,配置组件,提供各种方法! 前期可以实现
public class SpringMvcConfig implements WebMvcConfigurer {
//添加拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
//将拦截器添加到Springmvc环境,默认拦截所有Springmvc分发的请求
registry.addInterceptor(new Process01Interceptor());
}
}
拦截器细节配置
1.拦截全部请求
registry.addInterceptor(new MyInterceptor());
2.指定拦截的地址
①具体地址拦截: registry.addInterceptor(newMyInterceptor()).addPathPatterns("/user/data");
②模糊地址拦截(* 任意一层字符串,** 任意多层字符串):
registry.addInterceptor(new MyInterceptor()).addPathPatterns("/user/**");
③排除地址拦截:
registry.addInterceptor(newMyInterceptor()).addPathPatterns("/user/**"). excludePathPatterns("/user/data");
@EnableWebMvc //json数据处理,必须使用此注解,因为他会加入json处理器
@Configuration
@ComponentScan(basePackages = {"com.atguigu.controller","com.atguigu.exceptionhandler"}) //TODO: 进行controller扫描
//WebMvcConfigurer springMvc进行组件配置的规范,配置组件,提供各种方法! 前期可以实现
public class SpringMvcConfig implements WebMvcConfigurer {
//配置jsp对应的视图解析器
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
//快速配置jsp模板语言对应的
registry.jsp("/WEB-INF/views/",".jsp");
}
//开启静态资源处理 <mvc:default-servlet-handler/>
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
//添加拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
//将拦截器添加到Springmvc环境,默认拦截所有Springmvc分发的请求
registry.addInterceptor(new Process01Interceptor());
}
}
3.3参数校验
相关依赖配置
<!-- 校验注解 -->
<dependency>
<groupId>jakarta.platform</groupId>
<artifactId>jakarta.jakartaee-web-api</artifactId>
<version>9.1.0</version>
<scope>provided</scope>
</dependency>
<!-- 校验注解实现-->
<!-- https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A&pos_id=ryVGRJGt//mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator -->
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>8.0.0.Final</version>
</dependency>
<!-- https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A&pos_id=ryVGRJGt//mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator-annotation-processor -->
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator-annotation-processor</artifactId>
<version>8.0.0.Final</version>
</dependency>
、
NotNull VS NotEmpty VS NotBlank
1NotNull :包装类型不为null
2 NotEmpty:集合长度大于零
3NotBlank:字符串不为null,且不为“ ”字符串
@Data
public class User {
@NotBlank(message="不能为空")
private String name;
@Length(min = 6)
private String password;
@Min(1)
private int age;
@Email(message="不符合邮件格式")
private String email;
@Past
private Date birthday;
}
-
在控制层的handler方法使用其实体类接收请求的数据时,在参数列表的其实体类类型的参数前,要加上@Validated注解
-
设置错误绑定信息的捕捉,在handler方法的参数列表中,在要校验的对象后加上一个BindingResult类型的对象,其中封装的都是参数校验的结果信息(BindingResult类型的对象必须跟在要校验的对象后面),在handler方法中加上一个if(result.hasErrors()){ }的条件语句,在条件语句中写发生错误绑定信息后的逻辑处理的代码
与全局异常处理整合:
参数校验出错后抛出的异常处理类为:MethodArgumentNotValidException,通过抛出的异常类获取到BindingResult对象里面封装了参数校验的结果信息。
3.4接口文档
接口文档是一种详细描述软件系统中不同组件或模块之间交互方式和规则的文档。它提供了关于如何调用接口、接口的参数、返回的数据格式以及可能的错误处理等信息。接口文档是软件开发、测试、集成和维护过程中的重要参考依据。可以
在SpringBoot项目中为了实时动态的进行接口测试,方便接口文档生成。这里提供一种可视化实时生成接口文档的工具类。Knife4j,官网操作手册如下,可以自行探索
Knife4j
Knife4j的前身是swagger-bootstrap-ui,前身swagger-bootstrap-ui是一个纯swagger-ui的ui皮肤项目取名knife4j是希望她能像一把匕首一样小巧,轻量,并且功能强悍,更名也是希望把她做成一个为Swagger接口文档服务的通用性解决方案,不仅仅只是专注于前端Ui前端.
总结:
- Swagger 可以快速生成实时接口文档,方便前后开发人员进行协调沟通。遵循 OpenAPI 规范。
- Knife4j 是基于 Swagger之上的增强套件
- 访问 http://ip:port/doc.html 即可查看接口文档
相关注解
注解 | 标注位置 | 作用 |
@Tag | controller 类 | 描述 controller 作用,对整个类的作用进行描述 |
@Parameter | 参数 | 标识参数作用 |
@Parameters | 参数 | 参数多重说明 |
@Schema | model 层的 JavaBean | 描述模型作用及每个属性 |
@Operation | 方法 | 描述方法作用,对方法操作的解释 |
@ApiResponse | 方法 | 描述响应状态码等 |
在SpringBoot3以上版本要引入以下依赖
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
<version>4.4.0</version>
</dependency>
配置文件如下写死,不用进行更改,唯一要注意的是,扫包配置自己controller的地址
# springdoc-openapi项目配置
springdoc:
swagger-ui:
path: /swagger-ui.html
tags-sorter: alpha
operations-sorter: alpha
api-docs:
path: /v3/api-docs
group-configs:
- group: 'default'
paths-to-match: '/**'
packages-to-scan: com.xiaominfo.knife4j.demo.web#自己controller的地址,唯一一处要进行更改的地方
# knife4j的增强配置,不需要增强可以不配
knife4j:
enable: true
setting:
language: zh_cn
一些配置信息操作如下:
@RestController
@RequestMapping("body")
@Tag(name = "body参数")
public class BodyController {
@Operation(summary = "普通body请求")
@PostMapping("/body")
public ResponseEntity<FileResp> body(@RequestBody FileResp fileResp){
return ResponseEntity.ok(fileResp);
}
@Operation(summary = "普通body请求+Param+Header+Path")
@Parameters({
@Parameter(name = "id",description = "文件id",in = ParameterIn.PATH),
@Parameter(name = "token",description = "请求token",required = true,in = ParameterIn.HEADER),
@Parameter(name = "name",description = "文件名称",required = true,in=ParameterIn.QUERY)
})
@PostMapping("/bodyParamHeaderPath/{id}")
public ResponseEntity<FileResp> bodyParamHeaderPath(@PathVariable("id") String id,@RequestHeader("token") String token, @RequestParam("name")String name,@RequestBody FileResp fileResp){
fileResp.setName(fileResp.getName()+",receiveName:"+name+",token:"+token+",pathID:"+id);
return ResponseEntity.ok(fileResp);
}
}
日期时间处理
使用@JsonFormat注解:日期处理