Java/Kotlin/Spring引导。发生异常时,我们如何自动检索参数值?
考虑到我们正在使用Kotlin、Spring Boot、注释和其他相关库 如果我们的代码抛出异常,我们如何在异常发生时自动检索方法参数值 我们可以使用AOP、Spring拦截器或其他技术来实现这一点吗 我们希望用它来丰富我们的错误消息,这样我们就可以从错误发生的地方复制错误 请注意,我们正在寻找一种解决方案,它不需要注释所有可能的方法,而是在发生异常时处理代码的方法。我们可以使用JavaStackTrace元素来检索一些有用的信息,比如发生异常的方法、行和文件,但是我们没有参数值 在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
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方法的异常。但是,正如您所建议的那样,在其中包含控制器参数也很好。但是,正如您所建议的那样,在其中包含控制器参数也很好