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

huangapple go评论59阅读模式
英文:

Spring Boot Exception Handler: User Does not exist

问题

我正在开发一个用于用户的Spring Boot Web应用程序,其中一个功能是允许用户重置密码。为了实现这一点,他们必须提供他们的电子邮件地址,并收到一条验证消息,从而能够重置密码。我的问题是,当用户提供的电子邮件在数据库中不存在时,如何生成特定于此情况的错误消息?我在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;
    }
}

目前我得到的错误是基本的404 HttpStatus.NOT_FOUND错误,我只是简单地写着"An error occurred."。但当然我希望能更具体,以便用户了解更多情况,userNonexistentMessage将显示"This 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. 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:

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." 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."

So, how do I add an exception handler for this case? Thanks!

答案1

得分: 1

一个灵活处理错误的解决方案可能会比较复杂,但你可以通过创建枚举来开始,将所有业务逻辑可能抛出的错误都定义在一个地方。

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;
    }
}

然后,你可以创建一个自定义的API异常,其中包含一个ErrorCode字段,这样你可以在代码中抛出异常,在异常构造函数中传递特定的错误。

最后,在GlobalExceptionHandler中,你可以添加一个方法来处理你的自定义异常,获取异常中包含的ErrorCode值,然后从该ErrorCode中获取错误消息、HTTP状态或其他构建响应所需的任何其他与错误相关的信息。这样,你可以在GlobalExceptionHandler中以统一的方式处理所有错误,而不是注入特定的错误消息。

正如开始提到的,错误处理可以更加复杂。你的异常还可以接受动态参数以插入错误消息("邮箱为 {} 的用户不存在"),你可以为每个状态码单独添加业务异常,你可以添加i18N支持,将错误消息放入每种语言的属性文件中,而不是硬编码在错误枚举中,等等。但是我认为实现ErrorCode枚举和自定义异常是一个很好的起点。

英文:

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.

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.

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. That way you can handle all errors in a single way in your GlobalExceptionHandler instead of having specific error messages injected.

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.

答案2

得分: 0

以下是翻译的内容:

所以我查看了跟踪信息,并发现以下行对于确定手头的错误非常有趣:

2020-10-13 22:04:53.555 DEBUG 63687 --- [nio-8080-exec-8] o.s.web.servlet.DispatcherServlet        : POST“/forgotPassword”,参数={掩码}
2020-10-13 22:04:53.556 DEBUG 63687 --- [nio-8080-exec-8] s.w.s.m.m.a.RequestMappingHandlerMapping : 映射到bcoreHW.controllers.AuthController#forgotUserPassword(ModelAndView, SiteUser)
2020-10-13 22:04:53.654 DEBUG 63687 --- [nio-8080-exec-8] org.hibernate.SQL                        : 从用户中选择siteuser0_.user_id作为user_id1_3_,siteuser0_.email作为email2_3_,siteuser0_.enabled作为enabled3_3_,siteuser0_.password作为password4_3_,siteuser0_.role作为role5_3_从用户中选择siteuser0_。邮箱=?
Hibernate: 从用户中选择siteuser0_.user_id作为user_id1_3_,siteuser0_.email作为email2_3_,siteuser0_.enabled作为enabled3_3_,siteuser0_.password作为password4_3_,siteuser0_.role作为role5_3_从用户中选择siteuser0_。邮箱=?
2020-10-13 22:04:53.662 DEBUG 63687 --- [nio-8080-exec-8] .m.m.a.ExceptionHandlerExceptionResolver : 使用@ExceptionHandler bcoreHW.controllers.GlobalExceptionHandler#invalidUserMessage(HttpServletRequest, Exception)
2020-10-13 22:04:53.662 DEBUG 63687 --- [nio-8080-exec-8] .m.m.a.ExceptionHandlerExceptionResolver : 已解决[java.lang.NullPointerException]为ModelAndView[view=“app.exception”;model={message=无效用户、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        : 使用已解决的错误视图:ModelAndView[view=“app.exception”;model={message=无效用户、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 : 选择“text/html”为[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    : 视图名称“app.exception”,模型{message=无效用户、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        : 已完成200 OK

你可以在最后看到发生了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;
	}

这样我就避免了总体的404错误状态,并为无效用户设置了特定的错误消息。

英文:

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:

	@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.

huangapple
  • 本文由 发表于 2020年10月14日 01:42:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/64340419.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定