近期看到了ControllerAdvice这个注解,本身只是为了看下全局异常处理的,简单了解后发现可以分别与@ExceptionHandler、@ModelAttribute、@InitBinder实现 全局异常、全局参数、请求参数预处理 的功能。
目录
- 一、全局异常处理
- 二、全局参数处理
- 三、请求参数预处理
一、全局异常处理
实现全局异常处理需要配合@ExceptionHandler注解进行处理
导入maven
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<!-- 阿里巴巴json转换 -->
<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.75</version>
</dependency><!-- lombok -->
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.6</version><scope>provided</scope>
</dependency><!-- 校验包 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId>
</dependency>
自定义处理器代码
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)@ResponseBodypublic 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 {// 设置全局参数@ModelAttributepublic void presetParam(Model model){model.addAttribute("globalAttr","globalAttr_Number1");}// //注意@ModelAttribute若加括号不传任何参数的时候默认key为map,这种写法与上述写法不一致之处在于会包裹一层map
// @ModelAttribute()
// public Map<String, String> presetParam(){
// Map<String, String> map = new HashMap<String, String>();
// 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 {// 请求参数预处理@InitBinderpublic 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注解的使用。