原文网址: SpringBoot--全局格式处理--方法/实例_IT利刃出鞘的博客-CSDN博客
简介
说明
本文用实例介绍SpringBoot如何进行全局格式处理。
方案简介
全局格式处理有很多方案,见:此文。本文介绍这种方案:@ControllerAdvice+@InitBinder
Spring MVC中提供了一个注解@InitBinder,它的作用是在执行控制器方法前,处理器会先执行@InitBinder标注的方法。这时可以将WebDataBinder对象作为参数传递到方法中,通过这层关系得到WebDataBinder对象。
可以进行的操作:设置时间格式、自定义参数。
在Controller下直接使用@InitBinder只对当前Controller生效。想全局生效,可用@ControllerAdvice或者WebBindingInitializer。
系列文章
SpringBoot全局处理我写了一个系列:
- SpringBoot--全局异常处理--方法/实例_IT利刃出鞘的博客-CSDN博客
- SpringBoot--全局响应处理--方法/实例_IT利刃出鞘的博客-CSDN博客
- SpringBoot--全局请求处理--方法/实例_IT利刃出鞘的博客-CSDN博客
- SpringBoot--全局格式处理--方法/实例_IT利刃出鞘的博客-CSDN博客
@ControllerAdvice介绍
说明
@ControllerAdvice里边有@Component,用于类,可包含@ExceptionHandler,@InitBinder和@ModelAttribute方法,适用于所有使用@RequestMapping方法。(因此是全局的处理方法)。
可以在多个类上使用@ControllerAdvice,可通过@Order来控制顺序。不能通过实现Order接口来控制顺序,因为这部分源码里只支持@Order这种方式。见:调整多个ControllerAdvice的执行顺序_felixu的博客-CSDN博客。
在Spring4及之后, @ControllerAdvice支持配置控制器的子集,可通过annotations(), basePackageClasses(), basePackages()方法选择控制器子集。
官网网址
springmvc 注解总结 - SpringMVC中文官网
使用场景
- @ControllerAdvice+@ExceptionHandler:全局异常处理
- 捕获Controller中抛出的指定类型异常,可对不同类型的异常区别处理
- @ControllerAdvice+ 实现ResponseBodyAdvice接口:全局响应处理(处理返回值)
- 其标注的方法将会在目标Controller方法执行之后执行。
- @ControllerAdvice+@ModelAttribute:全局请求处理
- 其标注的方法将会在目标Controller方法执行之前执行。
- 使用场景示例:鉴权/授权、全局处理格式
- @ControllerAdvice+@InitBinder:全局请求处理
- 其标注的方法将会在目标Controller方法执行之前执行。
- request中自定义参数解析方式进行注册
- 使用场景示例:全局处理格式
SpringBoot--LocalDateTime--全局格式转换/前后端/前端入参/响应给前端_IT利刃出鞘的博客-CSDN博客
实例1:全局处理
代码
全局格式处理
package com.example.common.advice;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.InitBinder;
import java.beans.PropertyEditorSupport;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
@ControllerAdvice
public class GlobalRequestFormatAdvice {
@InitBinder
protected void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(LocalDateTime.class, new PropertyEditorSupport() {
@Override
public void setAsText(String text) throws IllegalArgumentException {
setValue(LocalDateTime.parse(text, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
}
});
binder.registerCustomEditor(LocalDate.class, new PropertyEditorSupport() {
@Override
public void setAsText(String text) throws IllegalArgumentException {
setValue(LocalDate.parse(text, DateTimeFormatter.ofPattern("yyyy-MM-dd")));
}
});
binder.registerCustomEditor(LocalTime.class, new PropertyEditorSupport() {
@Override
public void setAsText(String text) throws IllegalArgumentException {
setValue(LocalTime.parse(text, DateTimeFormatter.ofPattern("HH:mm:ss")));
}
});
}
}
Controller
package com.example.business.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDateTime;
@RestController
@RequestMapping("user")
public class UserController {
@GetMapping("/initBinder")
public Object localDateTimeTest(LocalDateTime localDateTime) {
System.out.println(localDateTime);
return localDateTime;
}
}
测试
postman访问:http://localhost:8080/user/initBinder?localDateTime=2020-08-20 12:12:34
postman结果
后端结果
实例:单个Controller写法
代码
设置时间参数
package com.example.controller;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.beans.PropertyEditorSupport;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
@RestController
@RequestMapper("user")
public class UserController {
@InitBinder
protected void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(LocalDateTime.class, new PropertyEditorSupport() {
@Override
public void setAsText(String text) throws IllegalArgumentException {
setValue(LocalDateTime.parse(text, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
}
});
binder.registerCustomEditor(LocalDate.class, new PropertyEditorSupport() {
@Override
public void setAsText(String text) throws IllegalArgumentException {
setValue(LocalDate.parse(text, DateTimeFormatter.ofPattern("yyyy-MM-dd")));
}
});
binder.registerCustomEditor(LocalTime.class, new PropertyEditorSupport() {
@Override
public void setAsText(String text) throws IllegalArgumentException {
setValue(LocalTime.parse(text, DateTimeFormatter.ofPattern("HH:mm:ss")));
}
});
}
@RequestMapping(value = "/initBinder")
public Object localDateTimeTest(LocalDateTime localDateTime) {
System.out.println(localDateTime);
return localDateTime;
}
}
value属性(全局、单独Controller都适用)
若指定了value值,那么只有方法参数名(或者模型名)匹配上了此注解方法才会执行(若不指定,都执行)。
package com.example.controller;
import com.example.entity.User;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
@RestController
public class HelloController {
@InitBinder({"param", "user"})
public void initBinder(WebDataBinder binder, HttpServletRequest request) {
System.out.println("当前key:" + binder.getObjectName());
}
@ResponseBody
@RequestMapping("/initbinder")
public Object testInitBinder(String param, String date,
@ModelAttribute("user") User user) {
System.out.println(user.getName());
return param + ":" + date;
}
}
测试
浏览器访问:http://localhost:8080/initbinder?param=abc&date=2019&user.name=demoUser
后端输出
当前key:param
当前key:user
null
前端输出
abc:2019
虽然此处有key是user.name,但是User对象可是不会封装到此值的(因为request.getParameter('user')没这个key。
解决方法:
法1:加前缀
package com.example.controller;
import com.example.entity.User;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*;
@RestController
public class HelloController {
@InitBinder({"param"})
public void initBinderParam(WebDataBinder binder) {
System.out.println("当前key:" + binder.getObjectName());
}
@InitBinder({"user"})
public void initBinderUser(WebDataBinder binder) {
binder.setFieldDefaultPrefix("user.");
System.out.println("当前key:" + binder.getObjectName());
}
@ResponseBody
@RequestMapping("/initbinder")
public Object testInitBinder(String param, String date,
@ModelAttribute("user") User user) {
System.out.println(user.getName());
return param + ":" + date;
}
}
后端输出
当前key:param
当前key:user
demoUser
前端输出
abc:2019