用处:统一结果处理与异常拦截。
2、配置步骤 2.1、创建一个spring boot项目(idea)完整项目结构!
2.2、导入依赖(需要使用到简化环境搭建)2.3、ymlorg.springframework.boot spring-boot-starter-aopcom.alibaba fastjson1.2.76 org.apache.commons commons-lang3org.springframework.boot spring-boot-starter-weborg.springframework.boot spring-boot-devtoolsruntime true org.projectlombok lomboktrue org.springframework.boot spring-boot-starter-testtest org.junit.vintage junit-vintage-engine
注意:我们这个测试不需要yml(写上来防止你们疑惑!)
spring:
application:
name: springboot-day02-aop-exception #服务名称(项目名)
2.4、需要使用的工具类
注意:直接复制使用,工具类方法太多所以直接抽取几个用到的方法(不是重点)。
1、StringUtils
public class StringUtils extends org.apache.commons.lang3.StringUtils
{
public static boolean isEmpty(String str)
{
return isNull(str) || "".equals(str.trim());
}
public static boolean isNotEmpty(String str)
{
return !isEmpty(str);
}
public static boolean isNull(Object object)
{
return object == null;
}
public static boolean isNotNull(Object object)
{
return !isNull(object);
}
}
2、ServletUtils
public class ServletUtils
{
public static String parseString(HttpServletResponse response, String string)
{
try
{
response.setStatus(200);
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");
response.getWriter().print(string);
}
catch (IOException e)
{
e.printStackTrace();
}
return null;
}
}
2.5、需要使用的枚举以及状态
1、ErrorEnum
public enum ErrorEnum {
P_ERROR_NULL("P0100", "参数%s不能为空"),
P_NOT_EXIST("P0101", "%s不存在"),
P_FORMAT_ERROR("P0102", "%s格式不正确"),
S_CATCH_AUTH("S0104", "%s"),
S_TOKEN_EXPIRED("S0104", "Token过期"),
S_ERROR("S0105","系统异常 练习管理员!佳佳吖!"),
;
private String code;
private String message;
ErrorEnum() {
}
ErrorEnum(String code, String message) {
this.code = code;
this.message = message;
}
public String getCode() {
return code;
}
public String getMessage() {
return message;
}
public String getMessage(String message) {
if (StringUtils.isNotEmpty(message)) {
return String.format(this.message, message);
}
return "";
}
public void setCode(String code) {
this.code = code;
}
public void setMessage(String message) {
this.message = message;
}
}
2、状态码常量类
public class HttpStatus
{
public static final int SUCCESS = 200;
public static final int BAD_METHOD = 405;
public static final int ERROR = 500;
}
2.6、统一结果返回格式对象
public class ResultReturn extends LinkedHashMap2.7、Controller统一返回结果(AOP){ public static final Date newDateTime = new Date(); public static final String CODE = "code"; public static final String MSG = "message"; public static final String DATE_TIME = "datetime"; public static final String DATA = "data"; public ResultReturn() {} public ResultReturn(Object code, String msg, Date datetime, Object data) { super.put(CODE, code); super.put(MSG, msg); super.put(DATE_TIME, datetime.getTime()); if (StringUtils.isNotNull(data)) { super.put(DATA, data); } } public static Object success(Object data) { return new ResultReturn(200, "success", newDateTime, data); } public static Object success() { return ResultReturn.success(null); } public static Object error(ErrorEnum errorEnum) { return new ResultReturn(errorEnum.getCode(), errorEnum.getMessage(), new Date(), null); } public static Object error(Object code, String errorMsg) { return new ResultReturn(code, errorMsg, newDateTime, null); } public static ResultReturn error(RuanjiaExceptionHandler e) { return new ResultReturn(e.getCode(), e.getMessage(), newDateTime, null); } }
1、自定义注解
作用:如果有不想被Aop拦截的controller方法,就是用该注解标识。
@Target({ ElementType.TYPE, ElementType.METHOD }) //用于方法上
@Retention(RetentionPolicy.RUNTIME) //保留政策:运行时
@Documented
public @interface OriginalReturn
{
}
2、统一结果拦截类(AOP切面类)
作用(重点):使用Aop实现统一结果拦截。
@Aspect
@Slf4j
@Component
public class ResultAspectj
{
@Pointcut("execution(public * com.ruanjia.controller..*.*(..))")
public void result() {};
@Around("result()")
public Object afterReturningMethod(ProceedingJoinPoint point) throws Throwable {
Object proceed = point.proceed();
if (proceed instanceof ModelAndView || proceed instanceof View) {
return proceed;
}
Method method = ((MethodSignature) point.getSignature()).getMethod();
if (method.isAnnotationPresent(OriginalReturn.class)) {
return proceed;
}
return ResultReturn.success(proceed);
}
}
2.8、全局异常拦截
1、自定义异常类
作用:处理系统业务异常(这里还可以细写,可以根据自己需要增加自定义异常!)
@Data
public class RuanjiaExceptionHandler extends RuntimeException
{
private Object code;
private String message;
public RuanjiaExceptionHandler(ErrorEnum errorCodeEnum)
{
this.code = errorCodeEnum.getCode();
this.message = errorCodeEnum.getMessage();
}
public RuanjiaExceptionHandler(ErrorEnum errorCodeEnum, String message)
{
super(errorCodeEnum.getMessage(message));
if (StringUtils.isNotEmpty(message)) {
this.message = errorCodeEnum.getMessage(message);
} else {
this.message = errorCodeEnum.getMessage();
}
this.code = errorCodeEnum.getCode();
}
public RuanjiaExceptionHandler(String message)
{
this.code = HttpStatus.ERROR;
this.message = message;
}
}
2、全局异常类
作用:拦截所有Controller异常
@Slf4j
@ControllerAdvice
public class SystemGlobalExceptionHandler
{
@ExceptionHandler(RuanjiaExceptionHandler.class)
public void ruanjiaExceptionHandler(RuanjiaExceptionHandler e, HttpServletResponse response)
{
log.error("===========RuanjiaExceptionHandler(自定义异常)==========");
e.printStackTrace();
ServletUtils.parseString(response, JSON.toJSONString(ResultReturn.error(e.getCode(), e.getMessage())));
}
@ExceptionHandler(ArithmeticException.class)
public void handlerArithmeticException(ArithmeticException e, HttpServletResponse response)
{
log.error("===========ArithmeticException(算术异常)==========");
e.printStackTrace();
ServletUtils.parseString(response, JSON.toJSONString(ResultReturn.error(HttpStatus.ERROR, e.getMessage())));
}
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
public void handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException e, HttpServletRequest request, HttpServletResponse response)
{
log.error("===========HttpRequestMethodNotSupportedException(GET/POST 不支持异常)==========");
String requestURI = request.getRequestURI();
log.error("请求地址'{}',不支持'{}'请求", requestURI, e.getMethod());
e.printStackTrace();
ServletUtils.parseString(response, JSON.toJSONString(ResultReturn
.error(HttpStatus.BAD_REQUEST,"请求地址【"+requestURI+"】,不支持【"+e.getMethod()+"】请求")));
}
}
此致!配置完成,进入测试环节!
2.9、编写Controller测试类
@RestController
public class TestController
{
@GetMapping("/result")
public Object result()
{
return "同意结果返回测试!";
}
@GetMapping("/error1")
public Object error()
{
int a = 10/0;
return a;
}
@GetMapping("/error2")
public Object error2(String username)
{
if (StringUtils.isEmpty(username))
{
throw new RuanjiaExceptionHandler(ErrorEnum.S_CATCH_AUTH, "用户名不能为空!");
}
return username;
}
}
效果图:
1、统一结果返回测试
2、系统算术异常拦截
3、自定义异常拦截
结束语:不要半途而废!



