简体   繁体   English

Spring Boot 异常处理程序:用户不存在

[英]Spring Boot Exception Handler: User Does not exist

I'm developing a spring boot web app for users and one feature is for users to be able to reset their password.我正在为用户开发一个 Spring Boot Web 应用程序,其中一项功能是让用户能够重置他们的密码。 In order to do so, they must provide their email address and have a verification message sent to them where they will be able to reset their password.为此,他们必须提供他们的电子邮件地址,并向他们发送验证消息,以便他们可以重置密码。 My question, though, is how do I make an error message specific to the situation where the email the user provides doesn't exist in the database?但是,我的问题是如何针对用户提供的电子邮件在数据库中不存在的情况生成错误消息? What I have so far is below in my GlobalExceptionHandler.java:到目前为止,我的 GlobalExceptionHandler.java 中的内容如下:

package bcoreHW.controllers;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.servlet.ModelAndView;

@ControllerAdvice
public class GlobalExceptionHandler {

    @Value("${message.error.exception}")
    private String exceptionMessage;
    
    @Value("${message.user.nonexistent}")
    private String userNonexistentMessage;

    @ResponseStatus(value = HttpStatus.NOT_FOUND)
    @ExceptionHandler(value=Exception.class)
    public ModelAndView defaultErrorHandler(HttpServletRequest req, Exception e) {
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.getModel().put("message", exceptionMessage);
        modelAndView.getModel().put("url", req.getRequestURL());
        modelAndView.getModel().put("exception", e);
        modelAndView.setViewName("app.exception");
        return modelAndView;
    }
}

And so the error I get as of now is the basic 404 HttpStatus.NOT_FOUND error, which I have simply saying "An error occurred."所以我现在得到的错误是基本的 404 HttpStatus.NOT_FOUND 错误,我只是说“发生错误”。 But of course I want this to be more specific so that the user knows more of the issue, and userNonexistentMessage will say "This user does not exist."但当然我希望这更具体,以便用户了解更多问题,并且 userNonexistentMessage 会说“此用户不存在”。

So, how do I add an exception handler for this case?那么,如何为这种情况添加异常处理程序? Thanks!谢谢!

A solution to handle errors in a flexible way can be complex, but you can start by creating an enum to define in a single place all the errors that your business logic can throw.以灵活的方式处理错误的解决方案可能很复杂,但您可以首先创建一个枚举,在一个地方定义您的业务逻辑可能抛出的所有错误。

The Java enum supports fields, so you can associate each literal with the error message and the status code. Java 枚举支持字段,因此您可以将每个文字与错误消息和状态代码相关联。

public enum ErrorCode {

    USER_NOT_FOUND(HttpStatus.NOT_FOUND, "This user does not exist"),
    USER_IS_LOCKED(HttpStatus.UNPROCESSABLE_ENTITY, "This user is locked");
    
    private HttpStatus httpStatus;
    private String message;
    
    private ErrorCode(HttpStatus httpStatus, String message) {
        this.httpStatus = httpStatus;
        this.message = message;
    }

    public HttpStatus getHttpStatus() {
        return httpStatus;
    }

    public String getMessage() {
        return message;
    }
}

Then you can create a custom API Exception that has an ErrorCode field, so you throw the Exception in your code passing the specific error in the Exception constructor.然后,您可以创建一个具有 ErrorCode 字段的自定义 API 异常,因此您可以在代码中抛出异常,并在 Exception 构造函数中传递特定错误。

Finally in the GlobalExceptionHandler you can add a method to handle your custom Exception, get the ErrorCode value contained in the Exception and from that ErrorCode obtain the error message, http status, or any other error-related information required to build your response.最后,在 GlobalExceptionHandler 中,您可以添加一个方法来处理您的自定义异常,获取包含在异常中的 ErrorCode 值,并从该 ErrorCode 中获取错误消息、http 状态或构建响应所需的任何其他错误相关信息。 That way you can handle all errors in a single way in your GlobalExceptionHandler instead of having specific error messages injected.这样您就可以在 GlobalExceptionHandler 中以单一方式处理所有错误,而不是注入特定的错误消息。

As mentioned in the beginning error handling can be more sophisticated.正如开头所提到的,错误处理可以更加复杂。 Your exception could accept also dynamic arguments to interpolate the error message ("The user with email {} does not exist"), you can have separate business exceptions for each status code, you can add i18N support to have the error message in a properties file for each language instead of hard-coded in the error enum, etc. But I think implementing the ErrorCode enum and the custom Exception is a good starting point.您的异常还可以接受动态参数来插入错误消息(“具有电子邮件{}的用户不存在”),您可以为每个状态代码设置单独的业务异常,您可以添加 i18N 支持以在属性中包含错误消息每种语言的文件,而不是在错误枚举等中进行硬编码。但我认为实现 ErrorCode 枚举和自定义 Exception 是一个很好的起点。

So I looked at the trace and found the following lines to be of interest for determining the error at hand:所以我查看了跟踪,发现以下几行对于确定手头的错误很有意义:

2020-10-13 22:04:53.555 DEBUG 63687 --- [nio-8080-exec-8] o.s.web.servlet.DispatcherServlet        : POST "/forgotPassword", parameters={masked}
2020-10-13 22:04:53.556 DEBUG 63687 --- [nio-8080-exec-8] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to bcoreHW.controllers.AuthController#forgotUserPassword(ModelAndView, SiteUser)
2020-10-13 22:04:53.654 DEBUG 63687 --- [nio-8080-exec-8] org.hibernate.SQL                        : select siteuser0_.user_id as user_id1_3_, siteuser0_.email as email2_3_, siteuser0_.enabled as enabled3_3_, siteuser0_.password as password4_3_, siteuser0_.role as role5_3_ from users siteuser0_ where siteuser0_.email=?
Hibernate: select siteuser0_.user_id as user_id1_3_, siteuser0_.email as email2_3_, siteuser0_.enabled as enabled3_3_, siteuser0_.password as password4_3_, siteuser0_.role as role5_3_ from users siteuser0_ where siteuser0_.email=?
2020-10-13 22:04:53.662 DEBUG 63687 --- [nio-8080-exec-8] .m.m.a.ExceptionHandlerExceptionResolver : Using @ExceptionHandler bcoreHW.controllers.GlobalExceptionHandler#invalidUserMessage(HttpServletRequest, Exception)
2020-10-13 22:04:53.662 DEBUG 63687 --- [nio-8080-exec-8] .m.m.a.ExceptionHandlerExceptionResolver : Resolved [java.lang.NullPointerException] to ModelAndView [view="app.exception"; model={message=Invalid user., url=http://localhost:8080/forgotPassword, exception=java.lang.NullPointerException}]
2020-10-13 22:04:53.662 DEBUG 63687 --- [nio-8080-exec-8] o.s.web.servlet.DispatcherServlet        : Using resolved error view: ModelAndView [view="app.exception"; model={message=Invalid user., url=http://localhost:8080/forgotPassword, exception=java.lang.NullPointerException}]
2020-10-13 22:04:53.663 DEBUG 63687 --- [nio-8080-exec-8] o.s.w.s.v.ContentNegotiatingViewResolver : Selected 'text/html' given [text/html, application/xhtml+xml, image/avif, image/webp, image/apng, application/xml;q=0.9, application/signed-exchange;v=b3;q=0.9, */*;q=0.8]
2020-10-13 22:04:53.663 DEBUG 63687 --- [nio-8080-exec-8] o.s.web.servlet.view.tiles3.TilesView    : View name 'app.exception', model {message=Invalid user., url=http://localhost:8080/forgotPassword, exception=java.lang.NullPointerException}
2020-10-13 22:04:53.768 DEBUG 63687 --- [nio-8080-exec-8] o.s.web.servlet.DispatcherServlet        : Completed 200 OK

You can see towards the end that there is a NullPointerException, and so I added the following to my controller shown in the question above:您可以看到最后有一个 NullPointerException,因此我将以下内容添加到上述问题中显示的控制器中:

    @ExceptionHandler(value=NullPointerException.class)
    public ModelAndView invalidUserMessage(HttpServletRequest req, Exception e) {
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.getModel().put("message", invalidUserMessage);
        modelAndView.getModel().put("url", req.getRequestURL());
        modelAndView.getModel().put("exception", e);
        modelAndView.setViewName("app.exception");
        return modelAndView;
    }

And so now I avoid the overarching 404 error status and have a specific error message for an invalid user.所以现在我避免了总体 404 错误状态,并为无效用户提供了特定的错误消息。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM