近期看到了ControllerAdvice这个注解,本身只是为了看下全局异常处理的,简单了解后发现可以分别与@ExceptionHandler、@ModelAttribute、@InitBinder实现 全局异常、全局参数、请求参数预处理 的功能。
目录
- 一、全局异常处理
- 二、全局参数处理
- 三、请求参数预处理
实现全局异常处理需要配合@ExceptionHandler注解进行处理
导入maven
com.alibaba
fastjson
1.2.75
org.projectlombok
lombok
1.18.6
provided
org.springframework.boot
spring-boot-starter-validation
自定义处理器代码
import com.zhangximing.springboot_annotate.pojo.ErrorResponse;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
//全局处理器
@ControllerAdvice
public class GlobalHandler {
// 异常处理器
@ExceptionHandler(Exception.class)
@ResponseBody
public ErrorResponse handleException(Exception e) {
// 这里可以根据需要记录异常信息,发送通知等
System.err.println("发生异常: " + e.getMessage());
// 返回错误信息
ErrorResponse response = new ErrorResponse(500,"服务器发生异常("+e.getMessage()+"),请稍后重试");
return response;
}
}
实体代码
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 异常处理实体
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ErrorResponse {
private int code;
private String message;
}
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.http.HttpStatus;
/**
* 统一API响应结果封装实体
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result {
private int code;
private String message;
private Object data;
public static Result success() {
return new Result(HttpStatus.OK.value(), "操作成功", null);
}
public static Result success(Object data) {
return new Result(HttpStatus.OK.value(), "操作成功", data);
}
public static Result error(String message) {
return new Result(HttpStatus.BAD_REQUEST.value(), message, null);
}
}
测试方法
import com.alibaba.fastjson.JSONObject;
import com.zhangximing.springboot_annotate.pojo.Result;
import lombok.SneakyThrows;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/test")
public class TestController {
// 测试全局异常
@SneakyThrows
@RequestMapping("/globalException")
public Result globalException(@Validated @RequestBody JSONObject param) {
// 设置验证门槛
String authCode = param.getString("authCode");
// 验证不通过抛异常
if (null == authCode || !"XM_PASS".equals(authCode.trim())){
throw new Exception("authCode error");
}
return Result.success();
}
}
测试结果
实现全局参数处理需要配合@ModelAttribute注解进行处理
引入的pom以及实体代码与上同
import com.zhangximing.springboot_annotate.pojo.ErrorResponse;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.beans.propertyeditors.StringTrimmerEditor;
import org.springframework.ui.Model;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
//全局处理器
@ControllerAdvice
public class GlobalHandler {
// 设置全局参数
@ModelAttribute
public void presetParam(Model model){
model.addAttribute("globalAttr","globalAttr_Number1");
}
// //注意@ModelAttribute若加括号不传任何参数的时候默认key为map,这种写法与上述写法不一致之处在于会包裹一层map
// @ModelAttribute()
// public Map presetParam(){
// Map map = new HashMap();
// map.put("globalAttr", "globalAttr_Number2");
// return map;
// }
}
测试方法
// 测试全局预设参数
// 预设情况一 (直接model转换map)
@GetMapping("presetOne")
public String presetOne(Model model){
Map<String, Object> modelMap = model.asMap();
return JSONObject.toJSONString(modelMap);
}
// 预设情况二(指定全局异常变量)
@GetMapping("presetTwo")
public String presetTwo(@ModelAttribute("globalAttr") String globalAttr){
return globalAttr;
}
// 预设情况三(指定modelMap对象)
@GetMapping("presetThree")
public String presetThree(ModelMap modelMap) {
return JSONObject.toJSONString(modelMap);
}
测试结果
实现请求参数预处理需要配合@InitBinder注解进行处理
这部分参考了博客:https://blog.csdn.net/qq_36829919/article/details/101210250
import com.zhangximing.springboot_annotate.pojo.ErrorResponse;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.beans.propertyeditors.StringTrimmerEditor;
import org.springframework.ui.Model;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
//全局处理器
@ControllerAdvice
public class GlobalHandler {
// 请求参数预处理
@InitBinder
public void processParam(WebDataBinder dataBinder){
/*
* 创建一个字符串微调编辑器
* 参数{boolean emptyAsNull}: 是否把空字符串("")视为 null
*/
StringTrimmerEditor trimmerEditor = new StringTrimmerEditor(true);
/*
* 注册自定义编辑器
* 接受两个参数{Class> requiredType, PropertyEditor propertyEditor}
* requiredType:所需处理的类型
* propertyEditor:属性编辑器,StringTrimmerEditor就是 propertyEditor的一个子类
*/
dataBinder.registerCustomEditor(String.class, trimmerEditor);
//同上,当日期类型时
dataBinder.registerCustomEditor(Date.class,
new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), false));
}
}
测试方法
// 测试全局预处理
@RequestMapping("initDeal")
public Map<String, Object> test(String str, Date date) throws Exception {
Map<String, Object> map = new HashMap<String, Object>();
map.put("str", str);
map.put("data", date);
return map;
}
测试结果
个人理解:ControllerAdvice该注解的作用原理跟aop相似,都是进行拦截,而需要拦截处理的具体功能是由其他注解来协助(类似于aop的Advice)。
以上我学习整理的ControllerAdvice注解的使用。