自定义处理之@ControllerAdvice

自定义异常处理之@ControllerAdvice

     1 @ControllerAdvice的介绍:  

              在Spring3.2中,新增了@ControllerAdvice注解,可以用于定义@ExceptionHandler,@InitBinder,@ModelAttribute,然后与@RequestMapping配合使用。

     2 @ControllerAdvice的使用:

         2.1 如果我们想要完成一个自定义异常,我们需要使用@ControllerAdvice注解来实现一个全局异常处理类来处理我们的目标异常。代码实例:GlobalExceptionResolver.java

package com.test.exception;

import com.test.exception.CustomException;
import com.test.exception.message.MessageDecodingException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ControllerAdvice;
import java.util.HashMap;
import java.util.Map;

/**
 * Global exception.
 */
@ControllerAdvice
public class GlobalExceptionResolver {
    private static Logger logger = LoggerFactory.getLogger(GlobalExceptionResolver.class);

    /**
     * 应用到所有@RequestMapping注解方法,在其执行之前初始化数据绑定器
     * @param binder
     */
    @InitBinder
    public void initBinder(WebDataBinder binder) {
    }

    /**
     * 把值绑定到Model中,使全局@RequestMapping可以获取到该值
     * @param model
     */
    @ModelAttribute
    public void addAttributes(Model model) {
        model.addAttribute("author", "Magical Sam");
    }

    /**
     * System Exception
     */
    @ExceptionHandler(value = Exception.class)
    public Map<String, Object> handle(Exception e) {
        logger.error("System Exception:", e);
        Map<String, Object> errorMap = new HashMap<>();
        return errorMap;
    }


    /**
     * 自定义验证异常
     */
    @ExceptionHandler(value = MessageDecodingException.class)
    public Map<String, Object> handle(MessageDecodingException e) {
        logger.error("Defined Message Decode Exception", e);
        Map<String, Object> errorMap = new HashMap<>();
        return errorMap;
    }


    /**
     * Runtime Exception
     */
    @ExceptionHandler(value = RuntimeException.class)
    public Map<String, Object> handle(RuntimeException e) {
        logger.error("Runtime Exception:", e);
        Map<String, Object> errorMap = new HashMap<>();
        return errorMap;
    }

    /**
     * Custom
     * CustomException
     */
    @ExceptionHandler(value = CustomException.class)
    public Map<String, Object> handle(CustomException e) {
        logger.error("CustomException Exception:", e);
        Map<String, Object> errorMap = new HashMap<>();
        errorMap.put("errorCode", e.getErrorCode());
        errorMap.put("errorMessage", e.getErrorMessage());
        errorMap.put("parameter", e.getParameter());
        return errorMap;
    }
}

       2.2 所谓自定义异常当然也需要自定义的异常来处理,GlobalExceptionResolver.java只是一个全局异常处理类,所以我们要编写一个自定义异常来提供处理。代码如下:CustomException.java,他继承了RuntimeException类:

package com.test.exception;

import com.test.exception.enum.Error;
import java.util.List;
import java.util.Set;

/**
 * @ClassName CustomException
 * @Description TODO
 * @Author calm_encode
 * @Date 12/6/2019 3:36 PM
 * @Version 1.0
 **/
public class CustomException extends RuntimeException {

    private final String errorCode;
    private final String errorMessage;
    private final String parameter;

    public CustomException(Throwable t) {
        super(t);
        this.errorCode = Error.SYSTEM_EXCEPTION.getErrorCode();
        this.errorMessage = t.getMessage() + "" + t.getClass().getName();
        this.parameter = null;
    }

    public CustomException(String errorCode, String errorMessage, String parameter) {
        super();
        this.errorCode = errorCode;
        this.errorMessage = errorMessage;
        this.parameter = parameter;
    }

    public CustomException(String errorCode) {
        super();
        this.errorCode = errorCode;
        this.errorMessage = null;
        this.parameter = null;
    }

    public CustomException(String errorCode, String errorMessage) {
        super();
        this.errorCode = errorCode;
        this.errorMessage = errorMessage;
        this.parameter = null;
    }

    public CustomException(Error error) {
        super();
        this.errorCode = error.getErrorCode();
        this.errorMessage = error.getErrorMessage();
        this.parameter = null;
    }

    public CustomException(Error error, String parameter) {
        super();
        this.errorCode = error.getErrorCode();
        this.errorMessage = error.getErrorMessage();
        this.parameter = parameter;

    }

    public String getErrorCode() {
        return errorCode;
    }

    public String getErrorMessage() {
        return errorMessage;
    }

    public String getParameter() {
        return parameter;
    }

    @Override
    public String toString() {
        return "CustomException{" +
                "errorCode='" + errorCode + '\'' +
                ", errorMessage='" + errorMessage + '\'' +
                ", parameter=" + parameter +
                '}';
    }
}

       2.3 除上述代码实例提供的自定义异常处理所需的自定义异常之外,我们应该补充我们的错误类别实例,为自定义异常提供我们的目标异常。基于这个需求我们可以使用一下两步实现错误类别实例的创建。

              2.3.1 编写一个自定义异常错误接口定义需要实现的方法:

            package com.test.exception.enum;

            import org.springframework.http.HttpStatus;

            import java.io.Serializable;

            public interface IError extends Serializable {

                String getErrorCode();

                String getErrorMessage();

                HttpStatus getHttpStatus();
            }

             2.3.2 编写一个自定义异常错误接口实现类:

            package com.test.exception.enum;

            import org.springframework.http.HttpStatus;

            /**
             * @author Calm_encode
             */
            public enum Error implements IError {

                SYSTEM_EXCEPTION("SDK_Fabric_500","System Exception",HttpStatus.INTERNAL_SERVER_ERROR),
                UNDEFINED_EXCEPTION("SDK_Fabric_400","Undefined Exception",HttpStatus.BAD_REQUEST),
                CHAIN_CODE_EXCEPTION("Chain_code_500","Chain code Exception", HttpStatus.INTERNAL_SERVER_ERROR),
                MISSING_MANDATORY_FIELD("SDK_Fabric_400", "Missing Mandatory Field", HttpStatus.BAD_REQUEST),
                VALUE_NOT_ALLOWED("SDK_Fabric_400", "Value Not Allowed", HttpStatus.BAD_REQUEST),
                BAD_REQUEST("SDK_Fabric_400","Exist empty value of the Parameters",HttpStatus.BAD_REQUEST),
                INVALID_ID("SDK_Fabric_400","Don't exist the correlation data about the ID",HttpStatus.BAD_REQUEST);

                private String errorCode;
                private String errorMessage;
                private HttpStatus httpStatus;

                Error(){}

                Error(String errorCode, String errorMessage, HttpStatus httpStatus){
                    this.errorCode = errorCode;
                    this.errorMessage = errorMessage;
                    this.httpStatus = httpStatus;
                }

                public void setErrorCode(String errorCode) {
                    this.errorCode = errorCode;
                }

                public void setErrorMessage(String errorMessage) {
                    this.errorMessage = errorMessage;
                }

                public void setHttpStatus(HttpStatus httpStatus) {
                    this.httpStatus = httpStatus;
                }

                @Override
                public String getErrorCode() {
                    return errorCode;
                }

                @Override
                public String getErrorMessage() {
                    return errorMessage;
                }

                @Override
                public HttpStatus getHttpStatus() {
                    if (httpStatus == null) {
                        return HttpStatus.OK;
                    }
                    return httpStatus;
                }

                public static Error getErrorByCode(String errorCode){
                    Error error = Error.SYSTEM_EXCEPTION;

                    for (Error e : Error.values()){
                        if(e.errorCode.equals(errorCode)){
                            error = e;
                            break;
                        }
                    }
                    return error;
                }

                public static Error getErrorByMessage(String errorMessage){
                    Error error = Error.UNDEFINED_EXCEPTION;
                    error.setErrorMessage(errorMessage);
                    for(Error e : Error.values()) {
                        if(e.getErrorMessage().equals(errorMessage)){
                            error = e;
                            break;
                        }
                    }
                    return error;
                }
            }

到此处,基于@ControllerAdvice的自定义异常处理就写好了,现在@ControllerAdvice注解实现自定义异常处理的实现过程如下:

       由于业务逻辑是在Service的实现类中处理,所以我们写好的业务需要抛出异常时,我们会相应的代码块中使用throw关键字来抛出我们想要的异常。

        而Controller层时不会有任何逻辑代码的,它仅仅提供一个api的请求方法入口来设置请求的方法是post,get,put,delete还是 update,以及请求的放回方式是以页面返回使用@Contoller注解,还是以Restful风格返回相应的json数据,同时决定了客户端发送请求是需要传入的参数形式,以及参数个数。

        所以正确的异常处理代码流程是:

               1.Service层的业务逻辑产生异常,然后抛出异常到Controller层。

               2.由于Spring boot 默认情况下会映射到 /error 进行异常处理,但是提示并不十分友好,一般只是提示SytemException的错误信息以及500的错误码,所以我们需要在Controller增加自定义异常处理来使得错误信息显示的更加详细。

               3.使用@ControllerAdvice来实现自定义异常处理。同时@ExceptionHandler拦截了异常,我们可以通过该注解实现自定义异常处理。其中,@ExceptionHandler 配置的 value 指定需要拦截的异常类型。

        而上述统一异常处理类GlobalExceptionResolver.java,自定义异常类CustomException.java,自定义异常错误方法实例接口IError.java以及自定义异常错误处理实例接口实现类Error.java为自定义异常处理提供了处理方法以及相应的错误方法参数实例。

         产生异常的serivce层代码如下:

    public TestDTO create(TestDTO testDTO) {

        logger.info("Create : " + gson.toJson(testDTO));
        if (ObjectUtils.isEmpty(testDTO)) {
            throw new CustomException(Error.BAD_REQUEST);
        }

        try {
            String result = clientApp.invoke(testName, contractName, create, campaignConfigurationDTO.getId(), gson.toJson(testDTO));
            return gson.fromJson(result, TestDTO.class);
        } catch (Exception e) {
            /*logger.error(e.getMessage());
            throw new CustomException(Error.CHAIN_CODE_EXCEPTION);*/
            e.printStackTrace();
        }
        return null;
    }

上述代码是将错误信息以json格式的数据返回,当我们将所有的异常信息使用json格式返回时,可以使用@RestControllerAdvice

来替换@ControllerAdvice与@ResponseBody注解的使用,效果相同。

如@RestController的作用效果同@Controller和@ResponseBody的效果相同的道理类同。

3.使用@Controller,@ContollerAdvice注解实现异常信息页面渲染并在浏览器中显示:

             3.1 异常处理方法如下:

            @ExceptionHandler(value = CustomException.class)
            public ModelAndView handler(CustomException e) {
                ModelAndView modelAndView = new ModelAndView();
                modelAndView.setViewName("error");
                modelAndView.addObject("code", e.getErrorCode());
                modelAndView.addObject("msg", e.getErrorMessage());
                modelAndView.addObject("parameter", e.getParameter());
                return modelAndView;
            }Error

             3.2 在 templates 目录下,添加 error.ftl,使用freemarker 进行错误页面渲染:

            <!DOCTYPE html>
            <html lang="en">
            <head>
                <meta charset="UTF-8">
                <title>错误页面</title>
            </head>
            <body>
                <h1>${code}</h1>
                <h1>${msg}</h1>
                <h1>${parameter}</h1>
            </body>
            </html>

 

 

 

     

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值