GVKun编程网logo

创建自定义ErrorWebExceptionHandler失败(创建自定义异常)

12

在本文中,我们将详细介绍创建自定义ErrorWebExceptionHandler失败的各个方面,并为您提供关于创建自定义异常的相关解答,同时,我们也将为您带来关于@ControllerAdvice+

在本文中,我们将详细介绍创建自定义ErrorWebExceptionHandler失败的各个方面,并为您提供关于创建自定义异常的相关解答,同时,我们也将为您带来关于@ControllerAdvice + @ExceptionHandler 全局处理异常、@ExceptionHandler 和 @ControllerAdvice 统一处理异常、@ExceptionHandler 异常处理、Angular 2 RC 2如何将路由器注入自定义ExceptionHandler的有用知识。

本文目录一览:

创建自定义ErrorWebExceptionHandler失败(创建自定义异常)

创建自定义ErrorWebExceptionHandler失败(创建自定义异常)

我试图ErrorWebExceptionHandler通过扩展默认启动项在Spring Boot
2中创建自己的启动项,但是我的应用程序无法以以下消息启动:

Caused by: java.lang.IllegalArgumentException: Property ''messageWriters'' is requiredat org.springframework.boot.autoconfigure.web.reactive.error.AbstractErrorWebExceptionHandler.afterPropertiesSet(AbstractErrorWebExceptionHandler.java:214) ~[spring-boot-autoconfigure-2.0.4.RELEASE.jar:2.0.4.RELEASE]

我的处理程序(科特琳代码):

@Component@Order(-2)class SampleErrorWebExceptionHandler(    errorAttributes: ErrorAttributes?,    resourceProperties: ResourceProperties?,    errorProperties: ErrorProperties?,    applicationContext: ApplicationContext?) : DefaultErrorWebExceptionHandler(errorAttributes, resourceProperties, errorProperties, applicationContext) {    override fun logError(request: ServerRequest, errorStatus: HttpStatus) {        // do something    }}

可能是什么原因?

答案1

小编典典

您需要messageWriters在该实例上设置on,因为这里需要它们。您可能应该将其创建为a @Bean,就像Spring
Boot在专用自动配置中所做的那样。

@ControllerAdvice + @ExceptionHandler 全局处理异常

@ControllerAdvice + @ExceptionHandler 全局处理异常

本文讲解使用 @ControllerAdvice + @ExceptionHandler 进行全局的 Controller 层异常处理,只要设计得当,就再也不用在 Controller 层进行 try-catch 了!

一、优缺点

  • 优点:将 Controller 层的异常和数据校验的异常进行统一处理,减少模板代码,减少编码量,提升扩展性和可维护性。
  • 缺点:只能处理 Controller 层未捕获(往外抛)的异常,对于 Interceptor(拦截器)层的异常,Spring 框架层的异常,就无能为力了。

二、基本使用示例

2.1 @ControllerAdvice 注解定义全局异常处理类

@ControllerAdvice
public class GlobalExceptionHandler {
}

请确保此 GlobalExceptionHandler 类能被扫描到并装载进 Spring 容器中。

2.2 @ExceptionHandler 注解声明异常处理方法

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(Exception.class)
    @ResponseBody
    String handleException(){
        return "Exception Deal!";
    }
}

方法 handleException() 就会处理所有 Controller 层抛出的 Exception 及其子类的异常,这是最基本的用法了。

三、处理 Service 层上抛的业务异常

有时我们会在复杂的带有数据库事务的业务中,当出现不和预期的数据时,直接抛出封装后的业务级运行时异常,进行数据库事务回滚,并希望该异常信息能被返回显示给用户。

3.1 代码示例

封装的业务异常类:

public class BusinessException extends RuntimeException {

    public BusinessException(String message){
        super(message);
    }
}

Service 实现类:

@Service
public class DogService {

    @Transactional
    public Dog update(Dog dog){

        // some database options

        // 模拟狗狗新名字与其他狗狗的名字冲突
        BSUtil.isTrue(false, "狗狗名字已经被使用了...");

        // update database dog info

        return dog;
    }

}
  • 其中辅助工具类 BSUtil
public static void isTrue(boolean expression, String error){
    if(!expression) {
        throw new BusinessException(error);
    }
}

那么,我们应该在 GlobalExceptionHandler 类中声明该业务异常类,并进行相应的处理,然后返回给用户。更贴近真实项目的代码,应该长这样子:

/**
 * Created by kinginblue on 2017/4/10.
 * @ControllerAdvice + @ExceptionHandler 实现全局的 Controller 层的异常处理
 */
@ControllerAdvice
public class GlobalExceptionHandler {

    private static final Logger LOGGER = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    /**
     * 处理所有不可知的异常
     * @param e
     * @return
     */
    @ExceptionHandler(Exception.class)
    @ResponseBody
    AppResponse handleException(Exception e){
        LOGGER.error(e.getMessage(), e);

        AppResponse response = new AppResponse();
        response.setFail("操作失败!");
        return response;
    }

    /**
     * 处理所有业务异常
     * @param e
     * @return
     */
    @ExceptionHandler(BusinessException.class)
    @ResponseBody
    AppResponse handleBusinessException(BusinessException e){
        LOGGER.error(e.getMessage(), e);

        AppResponse response = new AppResponse();
        response.setFail(e.getMessage());
        return response;
    }
}

Controller 层的代码,就不需要进行异常处理了

3.2 代码说明

Logger 进行所有的异常日志记录。

@ExceptionHandler(BusinessException.class) 声明了对 BusinessException 业务异常的处理,并获取该业务异常中的错误提示,构造后返回给客户端。

@ExceptionHandler(Exception.class) 声明了对 Exception 异常的处理,起到兜底作用,不管 Controller 层执行的代码出现了什么未能考虑到的异常,都返回统一的错误提示给客户端。

备注:以上 GlobalExceptionHandler 只是返回 Json 给客户端,更大的发挥空间需要按需求情况来做。

@ExceptionHandler 和 @ControllerAdvice 统一处理异常

@ExceptionHandler 和 @ControllerAdvice 统一处理异常

参考:

原文链接:https://blog.csdn.net/zzzgd_666/article/details/81544098

 

推薦參考:

https://www.cnblogs.com/goloving/p/9142222.html

 

之前敲代码的时候,避免不了各种 try…catch, 如果业务复杂一点,就会发现全都是 try…catch

try{
    ..........
}catch(Exception1 e){
    ..........
}catch(Exception2 e){
    ...........
}catch(Exception3 e){
    ...........
}

这样其实代码既不简洁好看,我们敲着也烦,一般我们可能想到用拦截器去处理,但是既然现在 Spring 这么火,AOP 大家也不陌生,那么 Spring 一定为我们想好了这个解决办法。果然:

@ExceptionHandler
源码

// 该注解作用对象为方法 @Target ({ElementType.METHOD})

// 在运行时有效 @Retention (RetentionPolicy.RUNTIME)

@Documented public @interface ExceptionHandler {//value () 可以指定异常类 Class<? extends Throwable>[] value () default {}; }

 

@ControllerAdvice
源码

 

从名字上可以看出大体意思是控制器增强

所以结合上面我们可以知道,使用 @ExceptionHandler,可以处理异常,但是仅限于当前 Controller 中处理异常,@ControllerAdvice 可以配置 basePackage 下的所有 controller. 所以结合两者使用,就可以处理全局的异常了.

 

 

使用:

这里需要声明的是,这个统一异常处理类,也是基于 ControllerAdvice,也就是控制层切面的,如果是过滤器抛出的异常,不会被捕获

 

在 @ControllerAdvice 注解下的类,里面的方法用 @ExceptionHandler 注解修饰的方法,会将对应的异常交给对应的方法处理。

@ExceptionHandler({IOException.class}) 
    public Result handleException(IOExceptione e) { 
          log.error("[handleException] ", e);
      return ResultUtil.failureDefaultError(); 
      
    }

比如这个,就是捕获 IO 异常并处理。

废话不多说,代码:

 

package com.zgd.shop.core.exception;

import com.zgd.shop.core.error.ErrorCache;
import com.zgd.shop.core.result.Result;
import com.zgd.shop.core.result.ResultUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.ValidationException;
import java.util.Set;

/**
 * GlobalExceptionHandle
 * 全局的异常处理
 *
 * @author zgd
 * @date 2019/7/19 11:01
 */
@ControllerAdvice
@ResponseBody
@Slf4j
public class GlobalExceptionHandle {
  /**
   * 请求参数错误
   */
  private final static String BASE_PARAM_ERR_CODE = "BASE-PARAM-01";
  private final static String BASE_PARAM_ERR_MSG = "参数校验不通过";
  /**
   * 无效的请求
   */
  private final static String BASE_BAD_REQUEST_ERR_CODE = "BASE-PARAM-02";
  private final static String BASE_BAD_REQUEST_ERR_MSG = "无效的请求";

  /**
   * 顶级的异常处理
   *
   * @param e
   * @return
   */
  @ResponseStatus(HttpStatus.OK)
  @ExceptionHandler({Exception.class})
  public Result handleException(Exception e) {
    log.error("[handleException] ", e);
    return ResultUtil.failureDefaultError();
  }

  /**
   * 自定义的异常处理
   *
   * @param ex
   * @return
   */
  @ResponseStatus(HttpStatus.OK)
  @ExceptionHandler({BizServiceException.class})
  public Result serviceExceptionHandler(BizServiceException ex) {
    String errorCode = ex.getErrCode();
    String msg = ex.getErrMsg() == null ? "" : ex.getErrMsg();
    String innerErrMsg;
    String outerErrMsg;
    if (BASE_PARAM_ERR_CODE.equalsIgnoreCase(errorCode)) {
      innerErrMsg = "参数校验不通过:" + msg;
      outerErrMsg = BASE_PARAM_ERR_MSG;
    } else if (ex.isInnerError()) {
      innerErrMsg = ErrorCache.getInternalMsg(errorCode);
      outerErrMsg = ErrorCache.getMsg(errorCode);
      if (StringUtils.isNotBlank(msg)) {
        innerErrMsg = innerErrMsg + "" + msg;
        outerErrMsg = outerErrMsg + "" + msg;
      }
    } else {
      innerErrMsg = msg;
      outerErrMsg = msg;
    }
    log.info("【错误码】:{},【错误码内部描述】:{},【错误码外部描述】:{}", errorCode, innerErrMsg, outerErrMsg);
    return ResultUtil.failure(errorCode, outerErrMsg);
  }

  /**
   * 缺少servlet请求参数抛出的异常
   *
   * @param e
   * @return
   */
  @ResponseStatus(HttpStatus.BAD_REQUEST)
  @ExceptionHandler({MissingServletRequestParameterException.class})
  public Result handleMissingServletRequestParameterException(MissingServletRequestParameterException e) {
    log.warn("[handleMissingServletRequestParameterException] 参数错误: " + e.getParameterName());
    return ResultUtil.failure(BASE_PARAM_ERR_CODE, BASE_PARAM_ERR_MSG);
  }

  /**
   * 请求参数不能正确读取解析时,抛出的异常,比如传入和接受的参数类型不一致
   *
   * @param e
   * @return
   */
  @ResponseStatus(HttpStatus.OK)
  @ExceptionHandler({HttpMessageNotReadableException.class})
  public Result handleHttpMessageNotReadableException(HttpMessageNotReadableException e) {
    log.warn("[handleHttpMessageNotReadableException] 参数解析失败:", e);
    return ResultUtil.failure(BASE_PARAM_ERR_CODE, BASE_PARAM_ERR_MSG);
  }

  /**
   * 请求参数无效抛出的异常
   *
   * @param e
   * @return
   */
  @ResponseStatus(HttpStatus.BAD_REQUEST)
  @ExceptionHandler({MethodArgumentNotValidException.class})
  public Result handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
    BindingResult result = e.getBindingResult();
    String message = getBindResultMessage(result);
    log.warn("[handleMethodArgumentNotValidException] 参数验证失败:" + message);
    return ResultUtil.failure(BASE_PARAM_ERR_CODE, BASE_PARAM_ERR_MSG);
  }

  private String getBindResultMessage(BindingResult result) {
    FieldError error = result.getFieldError();
    String field = error != null ? error.getField() : "";
    String code = error != null ? error.getDefaultMessage() : "";
    return String.format("%s:%s", field, code);
  }

  /**
   * 方法请求参数类型不匹配异常
   *
   * @param e
   * @return
   */
  @ResponseStatus(HttpStatus.BAD_REQUEST)
  @ExceptionHandler({MethodArgumentTypeMismatchException.class})
  public Result handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e) {
    log.warn("[handleMethodArgumentTypeMismatchException] 方法参数类型不匹配异常: ", e);
    return ResultUtil.failure(BASE_PARAM_ERR_CODE, BASE_PARAM_ERR_MSG);
  }

  /**
   * 请求参数绑定到controller请求参数时的异常
   *
   * @param e
   * @return
   */
  @ResponseStatus(HttpStatus.BAD_REQUEST)
  @ExceptionHandler({BindException.class})
  public Result handleHttpMessageNotReadableException(BindException e) {
    BindingResult result = e.getBindingResult();
    String message = getBindResultMessage(result);
    log.warn("[handleHttpMessageNotReadableException] 参数绑定失败:" + message);
    return ResultUtil.failure(BASE_PARAM_ERR_CODE, BASE_PARAM_ERR_MSG);
  }

  /**
   * javax.validation:validation-api 校验参数抛出的异常
   *
   * @param e
   * @return
   */
  @ResponseStatus(HttpStatus.BAD_REQUEST)
  @ExceptionHandler({ConstraintViolationException.class})
  public Result handleServiceException(ConstraintViolationException e) {
    Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
    ConstraintViolation<?> violation = violations.iterator().next();
    String message = violation.getMessage();
    log.warn("[handleServiceException] 参数验证失败:" + message);
    return ResultUtil.failure(BASE_PARAM_ERR_CODE, BASE_PARAM_ERR_MSG);
  }

  /**
   * javax.validation 下校验参数时抛出的异常
   *
   * @param e
   * @return
   */
  @ResponseStatus(HttpStatus.BAD_REQUEST)
  @ExceptionHandler({ValidationException.class})
  public Result handleValidationException(ValidationException e) {
    log.warn("[handleValidationException] 参数验证失败:", e);
    return ResultUtil.failure(BASE_PARAM_ERR_CODE, BASE_PARAM_ERR_MSG);
  }

  /**
   * 不支持该请求方法时抛出的异常
   *
   * @param e
   * @return
   */
  @ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
  @ExceptionHandler({HttpRequestMethodNotSupportedException.class})
  public Result handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
    log.warn("[handleHttpRequestMethodNotSupportedException] 不支持当前请求方法: ", e);
    return ResultUtil.failure(BASE_BAD_REQUEST_ERR_CODE, BASE_BAD_REQUEST_ERR_MSG);
  }

  /**
   * 不支持当前媒体类型抛出的异常
   *
   * @param e
   * @return
   */
  @ResponseStatus(HttpStatus.UNSUPPORTED_MEDIA_TYPE)
  @ExceptionHandler({HttpMediaTypeNotSupportedException.class})
  public Result handleHttpMediaTypeNotSupportedException(HttpMediaTypeNotSupportedException e) {
    log.warn("[handleHttpMediaTypeNotSupportedException] 不支持当前媒体类型: ", e);
    return ResultUtil.failure(BASE_BAD_REQUEST_ERR_CODE, BASE_BAD_REQUEST_ERR_MSG);
  }

}

 

 

至于返回值,就可以理解为 controller 层方法的返回值,可以返回 @ResponseBody,或者页面。我这里是一个 @ResponseBody 的 Result<>,前后端分离。

我们也可以自己根据需求,捕获更多的异常类型。

包括我们自定义的异常类型。比如:

package com.zgd.shop.core.exception;

import lombok.Data;

/**
 * BizServiceException
 * 业务抛出的异常
 * @author zgd
 * @date 2019/7/19 11:04
 */
@Data
public class BizServiceException extends RuntimeException{

  private String errCode;

  private String errMsg;

  private boolean isInnerError;

  public BizServiceException(){
    this.isInnerError=false;
  }

  public BizServiceException(String errCode){
    this.errCode =errCode;
    this.isInnerError = false;
  }

  public BizServiceException(String errCode,boolean isInnerError){
    this.errCode =errCode;
    this.isInnerError = isInnerError;
  }

  public BizServiceException(String errCode,String errMsg){
    this.errCode =errCode;
    this.errMsg = errMsg;
    this.isInnerError = false;
  }

  public BizServiceException(String errCode,String errMsg,boolean isInnerError){
    this.errCode =errCode;
    this.errMsg = errMsg;
    this.isInnerError = isInnerError;
  }
}

 

@ExceptionHandler 异常处理

@ExceptionHandler 异常处理

有时候我们想统一处理一个Controller中抛出的异常怎么搞呢?

直接在Controller里面加上用@ExceptionHandler标注一个处理异常的方法像下面这样子

@ExceptionHandler(MissingServletRequestParameterException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public void processMethod(MissingServletRequestParameterException ex,HttpServletRequest request ,HttpServletResponse response) throws IOException {
    System.out.println("抛异常了!"+ex.getLocalizedMessage());
    logger.error("抛异常了!"+ex.getLocalizedMessage());
    response.getWriter().printf(ex.getMessage());
    response.flushBuffer();
}

这样,Controller里面的方法抛出了MissingServletRequestParameterException异常就会执行上面的这个方法来进行异常处理。 像我下面的代码

@RequestMapping("/index")
public String index(@MyUser User user,@RequestParam String id,ModelMap modelMap){
    return "login";
}

如果我没有传入id值,那么就会抛出MissingServletRequestParameterException的异常,就会被上面的异常处理方法处理。

上面的@ExceptionHandler(MissingServletRequestParameterException.class)这个注解的value的值是一个Class[]类型的,这里的ExceptionClass是你自己指定的,你也可以指定多个需要处理的异常类型,比如这样@ExceptionHandler(value = {MissingServletRequestParameterException.class,BindException.class}),这样就会处理多个异常了。

但这个只会是在当前的Controller里面起作用,如果想在所有的Controller里面统一处理异常的话,可以用@ControllerAdvice来创建一个专门处理的类。

Angular 2 RC 2如何将路由器注入自定义ExceptionHandler

Angular 2 RC 2如何将路由器注入自定义ExceptionHandler

我正在使用Angular 2 RC2.我需要将Angular 2路由器注入我的自定义ExceptionHandler类.但是我收到以下错误

Error: Error: Cannot resolve all parameters for ‘ErrorHandler'(?).
Make sure that all the parameters are decorated with Inject or have
valid type annotations and that ‘ErrorHandler’ is decorated with
Injectable.

我确实试过装饰私有路由器:使用@Inject的路由器无济于事.我正在使用打字稿,因此我认为我不需要@Inject属性.

我的自定义ExceptionHandler看起来像这样

import { ExceptionHandler } from '@angular/core';
import { Router } from '@angular/router';

export class ErrorHandler extends ExceptionHandler{

    constructor(
        private router: Router 
    ){
        super(null,null);

    }

    call(error,stackTrace = null,reason = null) {
        console.log(error);
        this.router.navigate(['/error']);
    }
}

我的主要看起来像这样

import { bootstrap } from '@angular/platform-browser-dynamic';
import { AppComponent } from './app.component';

import { provide,ExceptionHandler } from '@angular/core';
import { ErrorHandler } from './error-handler/error-handler';

import { HTTP_PROVIDERS } from '@angular/http';
import { ROUTER_PROVIDERS } from '@angular/router';

bootstrap(AppComponent,[
    HTTP_PROVIDERS,ROUTER_PROVIDERS,provide(ExceptionHandler,{useClass: ErrorHandler})
]);

为什么我收到此错误?在ExceptionHandler实例化时,路由器是否可注入?

完整的源代码可在此处获得

https://github.com/harindaka/angular2-seed-typescript/tree/b368315ce6608085f3154a03bc53f0404ce16495

解决方法

见: ErrorHandler班.您可以添加Injectable装饰器来实现DI!

import { ErrorHandler,Injectable } from '@angular/core';

@Injectable()
export class GlobalErrorHandler implements ErrorHandler {

  private myService: MyService;

  constructor(private injector: Injector) {
     this.myService = injector.get(MyService);
  }

  handleError(error) {
    alert('Bad things happening');
  }
  
}

@NgModule({
  providers: [
    {
      provide: ErrorHandler,useClass: GlobalErrorHandler
    }
  ]
})
export class AppModule { }

注意:上面的答案使用ExceptionHandler,它在最终版本中被删除,有利于ErrorHandler.

关于创建自定义ErrorWebExceptionHandler失败创建自定义异常的问题就给大家分享到这里,感谢你花时间阅读本站内容,更多关于@ControllerAdvice + @ExceptionHandler 全局处理异常、@ExceptionHandler 和 @ControllerAdvice 统一处理异常、@ExceptionHandler 异常处理、Angular 2 RC 2如何将路由器注入自定义ExceptionHandler等相关知识的信息别忘了在本站进行查找喔。

本文标签: