Spring MVC:如何返回自定义404 errorpages?

Chr*_*lph 31 java spring spring-mvc

当找不到请求的资源时,我正在寻找一种在Spring 4中返回自定义404错误的简洁方法.对不同域类型的查询应该导致不同的错误页面.

这里有一些代码来表明我的意图(Meter是一个域类):

@RequestMapping(value = "/{number}", method = RequestMethod.GET)
public String getMeterDetails(@PathVariable("number") final Long number, final Model model) {
    final Meter result = meterService.findOne(number);
    if (result == null) {
        // here some code to return an errorpage
    }

    model.addAttribute("meter", result);
    return "meters/details";
}
Run Code Online (Sandbox Code Playgroud)

我想到了几种处理问题的方法.首先,有可能创建RuntimeException类似的

@ResponseStatus(HttpStatus.NOT_FOUND)
public class MeterNotFoundExcption extends RuntimeException { }
Run Code Online (Sandbox Code Playgroud)

然后使用异常处理程序呈现自定义errorpage(可能包含指向米列表或任何适当的列表的链接).

但我不喜欢用很多小的例外来污染我的应用程序.

另一种可能是HttpServletResponse手动使用和设置状态代码:

@RequestMapping(value = "/{number}", method = RequestMethod.GET)
public String getMeterDetails(@PathVariable("number") final Long number, final Model model,
final HttpServletResponse response) {
    final Meter meter = meterService.findOne(number);
    if (meter == null) {
        response.setStatus(HttpStatus.NOT_FOUND.value());
        return "meters/notfound";
    }

    model.addAttribute("meter", meter);
    return "meters/details";
}
Run Code Online (Sandbox Code Playgroud)

但是使用这个解决方案,我必须复制许多控制器方法的前5行(如编辑,删除).

是否有一种优雅的方法可以防止多次重复这些行?

Chr*_*lph 36

解决方案比想象的要简单得多.可以使用ResourceNotFoundException如下定义的一个通用:

public class ResourceNotFoundException extends RuntimeException { }
Run Code Online (Sandbox Code Playgroud)

然后可以使用ExceptionHandler注释处理每个控制器中的错误:

class MeterController {
    // ...
    @ExceptionHandler(ResourceNotFoundException.class)
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public String handleResourceNotFoundException() {
        return "meters/notfound";
    }

    // ...

    @RequestMapping(value = "/{number}/edit", method = RequestMethod.GET)
    public String viewEdit(@PathVariable("number") final Meter meter,
                           final Model model) {
        if (meter == null) throw new ResourceNotFoundException();

        model.addAttribute("meter", meter);
        return "meters/edit";
    }
}
Run Code Online (Sandbox Code Playgroud)

每个控制器都可以定义自己ExceptionHandlerResourceNotFoundException.

  • 呃,不.这并没有真正按预期工作,因为在控制器内有这样的异常处理,当找不到`meter`时,响应的HTTP状态仍然是'200`而不是'404`.您确实为用户显示了一个不错的页面,但浏览器将收到一个响应,表明请求已成功处理. (9认同)
  • 谢谢你的提示.我只是重新检查了我的代码而你是对的.`ResponseStatus`注释应该放在异常处理程序上.我修正了我的答案. (4认同)

You*_*ddh 18

修改了您的web.xml文件.使用以下代码.

<display-name>App Name </display-name>
<error-page>
<error-code>500</error-code>
<location>/error500.jsp</location>
</error-page>

<error-page>
<error-code>404</error-code>
<location>/error404.jsp</location>
</error-page>
Run Code Online (Sandbox Code Playgroud)

通过以下代码访问它.

response.sendError(508802,"Error Message");
Run Code Online (Sandbox Code Playgroud)

现在在web.xml中添加此代码.

<error-page>
<error-code>508802</error-code>
<location>/error500.jsp</location>
</error-page>
Run Code Online (Sandbox Code Playgroud)


Eka*_*ogi 11

您可以在web.xml中映射错误代码,如下所示

    <error-page>
        <error-code>400</error-code>
        <location>/400</location>
    </error-page>

    <error-page>
        <error-code>404</error-code>
        <location>/404</location>
    </error-page>

    <error-page>
        <error-code>500</error-code>
        <location>/500</location>
    </error-page>
Run Code Online (Sandbox Code Playgroud)

现在,您可以创建一个控制器来映射发现任何这些错误时被击中的URL.

@Controller
public class HTTPErrorHandler{

    String path = "/error";

    @RequestMapping(value="/404")
    public String error404(){
       // DO stuff here 
        return path+"/404";
    }
    }
Run Code Online (Sandbox Code Playgroud)

有关完整示例,请参阅我的教程


小智 7

100% 免费 xml 的简单答案:

  1. 设置 DispatcherServlet 的属性

    public class SpringMvcInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
    
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[] { RootConfig.class  };
    }
    
    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[] {AppConfig.class  };
    }
    
    @Override
    protected String[] getServletMappings() {
        return new String[] { "/" };
    }
    
    //that's important!!
    @Override
    protected void customizeRegistration(ServletRegistration.Dynamic registration) {
        boolean done = registration.setInitParameter("throwExceptionIfNoHandlerFound", "true"); // -> true
        if(!done) throw new RuntimeException();
    }
    
    Run Code Online (Sandbox Code Playgroud)

    }

  2. 创建@ControllerAdvice:

    @ControllerAdvice
    public class AdviceController {
    
    @ExceptionHandler(NoHandlerFoundException.class)
    public String handle(Exception ex) {
        return "redirect:/404";
    }
    
    @RequestMapping(value = {"/404"}, method = RequestMethod.GET)
    public String NotFoudPage() {
        return "404";
    
    }
    
    Run Code Online (Sandbox Code Playgroud)

    }

  3. 创建包含任何内容的 404.jsp 页面

就这样。

  • 从 spring 4.2 RC 3 开始,有一种更简洁的方法来设置 `throwExceptionIfNoHandlerFound`。详细信息[这里](http://stackoverflow.com/a/31436535/3184859)。 (4认同)