Java/Kotlin/Spring引导。发生异常时,我们如何自动检索参数值?

Java/Kotlin/Spring引导。发生异常时,我们如何自动检索参数值?,java,spring-boot,kotlin,stack-trace,interceptor,Java,Spring Boot,Kotlin,Stack Trace,Interceptor,考虑到我们正在使用Kotlin、Spring Boot、注释和其他相关库 如果我们的代码抛出异常,我们如何在异常发生时自动检索方法参数值 我们可以使用AOP、Spring拦截器或其他技术来实现这一点吗 我们希望用它来丰富我们的错误消息,这样我们就可以从错误发生的地方复制错误 请注意,我们正在寻找一种解决方案,它不需要注释所有可能的方法,而是在发生异常时处理代码的方法。我们可以使用JavaStackTrace元素来检索一些有用的信息,比如发生异常的方法、行和文件,但是我们没有参数值 在Spring

考虑到我们正在使用Kotlin、Spring Boot、注释和其他相关库

如果我们的代码抛出异常,我们如何在异常发生时自动检索方法参数值

我们可以使用AOP、Spring拦截器或其他技术来实现这一点吗

我们希望用它来丰富我们的错误消息,这样我们就可以从错误发生的地方复制错误

请注意,我们正在寻找一种解决方案,它不需要注释所有可能的方法,而是在发生异常时处理代码的方法。我们可以使用JavaStackTrace元素来检索一些有用的信息,比如发生异常的方法、行和文件,但是我们没有参数值

在Spring中,我们有控制器建议功能,可以用来处理所有的异常,因此我们想在这里放一些东西,例如

编辑

添加一些示例代码:

fun exceptionHandler(throwable: Throwable) {
    logger.severe("""
        Error ${throwable.message}
        File: ${throwable.stackTrace[2].fileName}
        Class: ${throwable.stackTrace[2].className}
        Method: ${throwable.stackTrace[2].methodName}
        Line: ${throwable.stackTrace[2].lineNumber}
        Parameters: ## Somehow get the parameters values here, in this case "Hello, 1, false"
    """.trimIndent())
    }

fun myController() {
    myMethodWithErrors("Hello", 1, false)
}

fun myMethodWithErrors(param1: String, param2: Int, param3: Boolean) {
    throw RuntimeException("Some bad thing happened here when executing this code.")
}

我假设您讨论的是RESTAPI参数,而不是每个java方法参数。您可以实现捕获RESTAPI调用中所有异常的

@ControllerAdvice
public class ExceptionHandler {

    @ExceptionHandler(value = [Exception::class])
    @ResponseBody
    fun onException(exception: Exception, request: WebRequest): ResponseEntity<ErrorDetailsClass> {
         log.error("error when request with parameters ${request.parameterMap} ")
         return buildDetails(request)
    }
}

通过这种方式,您既可以检索正确的错误消息,也可以出于错误跟踪的目的在内部记录一些内容

我假设您讨论的是RESTAPI参数,而不是每个java方法参数。您可以实现捕获RESTAPI调用中所有异常的

@ControllerAdvice
public class ExceptionHandler {

    @ExceptionHandler(value = [Exception::class])
    @ResponseBody
    fun onException(exception: Exception, request: WebRequest): ResponseEntity<ErrorDetailsClass> {
         log.error("error when request with parameters ${request.parameterMap} ")
         return buildDetails(request)
    }
}

通过这种方式,您既可以检索正确的错误消息,也可以出于错误跟踪的目的在内部记录一些内容

我正在编写的示例是在spring boot中使用org.springframework.web.bind.annotation.ExceptionHandler注释

它对我来说非常好

假设我向发出Get请求,那么我们的api将验证该用户id是否存在,如果不存在,将抛出一条正确的消息,包括哪些参数无效或有错误

答复例1:

{
"apierror": {
    "dateTime": "2020-02-13T06:24:14.985",
    "timestamp": "1581603854985",
    "status": 404,
    "error": "Not Found",
    "message": "User not found",
    "debugMessage": null,
    "errors": [
        {
            "field": "userId",
            "rejectedValue": "a535c777-c906-45e2-b1c3-940965a507f2q",
            "message": "User not found with userId:a535c777-c906-45e2-b1c3-940965a507f2q"
        }
    ]
}
}

答复ex2:

        {
      "apierror": {
        "dateTime": "2020-02-13T06:43:23.377",
        "timestamp": "1581605003377",
        "status": 400,
        "error": "Bad Request",
        "message": "Validation error",
        "debugMessage": null,
        "errors": [
          {
            "field": "userName",
            "rejectedValue": "Ash",
            "message": "Username should have at least 6 characters"
          },
          {
            "field": "userName",
            "rejectedValue": "Ash",
            "message": "Invalid username"
          },
          {
            "field": "password",
            "rejectedValue": "shutosh@",
            "message": "Invalid password"
          }
        ]
      }
    }
根据api,未找到用户ID为a535c777-c906-45e2-b1c3-940965a507f2q的异常消息用户。 下面是用例

控制器:

@PrivilegeMapper.HasPlaceUserPrivilege
@GetMapping(value = "/{userId}", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ResponseEntity<?> getUserProfile(@NotBlank @PathVariable String userId) {
 return myService.buildUserProfile(userId);
}
服务:

 @Override
public ResponseEntity<?> buildUserProfile(final String userId) {

    ApiUser apiUser = userRepository.findById(userId)
            .orElseThrow(() -> new ApiUserNotFoundException("userId",userId));

    return ResponseEntity.ok(sirfUser);
}
例外类别:

    @Getter
    @Setter
    @ResponseStatus(value = HttpStatus.NOT_FOUND)
    public class ApiUserNotFoundException extends NotFoundException {

        public ApiUserNotFoundException(String msg, Throwable t) {
            super(msg, t);
        }

        public ApiUserNotFoundException(String msg) {
            super(msg);
        }

        public ApiUserNotFoundException(String key, String value) {
            super(key, value);
        }

        public ApiUserNotFoundException(String key, String value, List<Error> errors) {
            super(key, value, errors);
        }
    }   


    @Getter
    @Setter
    @ResponseStatus(code = HttpStatus.NOT_FOUND)
    public class NotFoundException extends RuntimeException {

        private String key;
        private String value;
        private List<Error> errors;

        public NotFoundException(String msg, Throwable t) {
            super(msg, t);
        }

        public NotFoundException(String msg) {
            super(msg);
        }

        public NotFoundException(String key, String value) {
            this.key = key;
            this.value = value;
        }

        public NotFoundException(String key, String value, List<Error> errors) {
            this.key = key;
            this.value = value;
            this.errors = errors;
        }

    }       
异常处理程序:

@ExceptionHandler(ApiUserNotFoundException.class)
protected ResponseEntity<Object> handleSirfUserNotFound(ApiUserNotFoundException ex) {
    log.error(String.format("User not found with %s:%s",ex.getKey(),ex.getValue()));
    ApiError apiError = new ApiError(NOT_FOUND);
    apiError.setMessage("User not found");
    List<Error> errors = new ArrayList<>();
    Error error = new ApiValidationError(SirfUser.class.getSimpleName());
    ((ApiValidationError) error).setMessage(String.format("User not found with %s:%s",ex.getKey(),ex.getValue()));
    ((ApiValidationError) error).setField(ex.getKey());
    ((ApiValidationError) error).setRejectedValue(ex.getValue());
    errors.add(error);
    apiError.setErrors(errors);
    return buildResponseEntity(apiError);
}

就是这样。你完了。这种类型的处理对于日志记录和ui透视图都很有用。

我正在编写的示例是在spring boot中使用org.springframework.web.bind.annotation.ExceptionHandler annotation

它对我来说非常好

假设我向发出Get请求,那么我们的api将验证该用户id是否存在,如果不存在,将抛出一条正确的消息,包括哪些参数无效或有错误

答复例1:

{
"apierror": {
    "dateTime": "2020-02-13T06:24:14.985",
    "timestamp": "1581603854985",
    "status": 404,
    "error": "Not Found",
    "message": "User not found",
    "debugMessage": null,
    "errors": [
        {
            "field": "userId",
            "rejectedValue": "a535c777-c906-45e2-b1c3-940965a507f2q",
            "message": "User not found with userId:a535c777-c906-45e2-b1c3-940965a507f2q"
        }
    ]
}
}

答复ex2:

        {
      "apierror": {
        "dateTime": "2020-02-13T06:43:23.377",
        "timestamp": "1581605003377",
        "status": 400,
        "error": "Bad Request",
        "message": "Validation error",
        "debugMessage": null,
        "errors": [
          {
            "field": "userName",
            "rejectedValue": "Ash",
            "message": "Username should have at least 6 characters"
          },
          {
            "field": "userName",
            "rejectedValue": "Ash",
            "message": "Invalid username"
          },
          {
            "field": "password",
            "rejectedValue": "shutosh@",
            "message": "Invalid password"
          }
        ]
      }
    }
根据api,未找到用户ID为a535c777-c906-45e2-b1c3-940965a507f2q的异常消息用户。 下面是用例

控制器:

@PrivilegeMapper.HasPlaceUserPrivilege
@GetMapping(value = "/{userId}", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ResponseEntity<?> getUserProfile(@NotBlank @PathVariable String userId) {
 return myService.buildUserProfile(userId);
}
服务:

 @Override
public ResponseEntity<?> buildUserProfile(final String userId) {

    ApiUser apiUser = userRepository.findById(userId)
            .orElseThrow(() -> new ApiUserNotFoundException("userId",userId));

    return ResponseEntity.ok(sirfUser);
}
例外类别:

    @Getter
    @Setter
    @ResponseStatus(value = HttpStatus.NOT_FOUND)
    public class ApiUserNotFoundException extends NotFoundException {

        public ApiUserNotFoundException(String msg, Throwable t) {
            super(msg, t);
        }

        public ApiUserNotFoundException(String msg) {
            super(msg);
        }

        public ApiUserNotFoundException(String key, String value) {
            super(key, value);
        }

        public ApiUserNotFoundException(String key, String value, List<Error> errors) {
            super(key, value, errors);
        }
    }   


    @Getter
    @Setter
    @ResponseStatus(code = HttpStatus.NOT_FOUND)
    public class NotFoundException extends RuntimeException {

        private String key;
        private String value;
        private List<Error> errors;

        public NotFoundException(String msg, Throwable t) {
            super(msg, t);
        }

        public NotFoundException(String msg) {
            super(msg);
        }

        public NotFoundException(String key, String value) {
            this.key = key;
            this.value = value;
        }

        public NotFoundException(String key, String value, List<Error> errors) {
            this.key = key;
            this.value = value;
            this.errors = errors;
        }

    }       
异常处理程序:

@ExceptionHandler(ApiUserNotFoundException.class)
protected ResponseEntity<Object> handleSirfUserNotFound(ApiUserNotFoundException ex) {
    log.error(String.format("User not found with %s:%s",ex.getKey(),ex.getValue()));
    ApiError apiError = new ApiError(NOT_FOUND);
    apiError.setMessage("User not found");
    List<Error> errors = new ArrayList<>();
    Error error = new ApiValidationError(SirfUser.class.getSimpleName());
    ((ApiValidationError) error).setMessage(String.format("User not found with %s:%s",ex.getKey(),ex.getValue()));
    ((ApiValidationError) error).setField(ex.getKey());
    ((ApiValidationError) error).setRejectedValue(ex.getValue());
    errors.add(error);
    apiError.setErrors(errors);
    return buildResponseEntity(apiError);
}

就是这样。你完了。这种类型的处理对于日志记录和ui透视图都很有用。

使用Spring AOP,可以通过建议满足此要求

下面的示例Aspect将截获包org.aop.bean.impl下的所有方法调用,这些调用会以异常退出。我们可以通过抛出属性进一步过滤到特定的异常类型。给定的示例过滤掉使用IllegalArgumentException退出的方法

方法调用期间的参数可以通过joinpoint.getArgs方法获得

从文件中

通常,您只希望在给定类型的异常出现时运行通知 您还经常需要访问中抛出的异常 咨询机构。可以使用“投掷”属性来限制这两个属性 如果需要匹配 — 否则,请将Throwable用作异常类型 并将抛出的异常绑定到通知参数


使用SpringAOP,可以通过建议满足此要求

下面的示例Aspect将截获包org.aop.bean.impl下的所有方法调用,这些调用会以异常退出。我们可以通过抛出属性进一步过滤到特定的异常类型。给定的示例过滤掉使用IllegalArgumentException退出的方法

方法调用期间的参数可以通过joinpoint.getArgs方法获得

从文件中

通常,您只希望在给定类型的异常出现时运行通知 您还经常需要访问中抛出的异常 咨询机构。可以使用“投掷”属性来限制这两个属性 如果需要匹配 — 否则,请将Throwable用作异常类型 并将抛出的异常绑定到通知参数


Java14将为NullPointerException自动执行类似的操作:如果您给出一段简单的示例代码,其中包含一个具体的
期望它会发生什么,我们可以更好地帮助你。Java 14会自动为NullPointerException做类似的事情:如果你给出一个简单的示例代码,具体期望它会发生什么,我们可以更好地帮助你。Hi Juan,更多的是关于任何Java/Kotlin方法的异常。但是,正如您所建议的那样,在其中包含控制器参数也很好。但是,正如您所建议的那样,在其中包含控制器参数也很好