如您所知,在XML中,配置它的方法是:
<error-page>
<error-code>404</error-code>
<location>/my-custom-page-not-found.html</location>
</error-page>
但是我还没有找到在Java配置中执行此操作的方法。我尝试的第一种方式是:
@RequestMapping(value = "/**")
public String Error(){
return "error";
}
它似乎有效,但它在检索资源方面存在冲突。
有办法吗?
答案 0 :(得分:20)
在Spring Framework中,有许多处理异常的方法(特别是404错误)。这是documentation link。
error-page
标记,并自定义错误页面。这是example。其次,您可以为所有控制器使用一个@ExceptionHandler
,如下所示:
@ControllerAdvice
public class ControllerAdvisor {
@ExceptionHandler(NoHandlerFoundException.class)
public String handle(Exception ex) {
return "404";//this is view name
}
}
要使其正常工作,请在web.xml中为DispatcherServlet
将throwExceptionIfNoHandlerFound属性设置为true:
<init-param>
<param-name>throwExceptionIfNoHandlerFound</param-name>
<param-value>true</param-value>
</init-param>
您也可以将一些对象传递给错误视图,请参阅javadoc。
答案 1 :(得分:5)
使用in the doc描述的基于代码的Servlet容器初始化并覆盖 registerDispatcherServlet 方法将 throwExceptionIfNoHandlerFound 属性设置为true:
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return null;
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] { WebConfig.class };
}
@Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
@Override
protected void registerDispatcherServlet(ServletContext servletContext) {
String servletName = getServletName();
Assert.hasLength(servletName, "getServletName() may not return empty or null");
WebApplicationContext servletAppContext = createServletApplicationContext();
Assert.notNull(servletAppContext,
"createServletApplicationContext() did not return an application " +
"context for servlet [" + servletName + "]");
DispatcherServlet dispatcherServlet = new DispatcherServlet(servletAppContext);
// throw NoHandlerFoundException to Controller
dispatcherServlet.setThrowExceptionIfNoHandlerFound(true);
ServletRegistration.Dynamic registration = servletContext.addServlet(servletName, dispatcherServlet);
Assert.notNull(registration,
"Failed to register servlet with name '" + servletName + "'." +
"Check if there is another servlet registered under the same name.");
registration.setLoadOnStartup(1);
registration.addMapping(getServletMappings());
registration.setAsyncSupported(isAsyncSupported());
Filter[] filters = getServletFilters();
if (!ObjectUtils.isEmpty(filters)) {
for (Filter filter : filters) {
registerServletFilter(servletContext, filter);
}
}
customizeRegistration(registration);
}
}
然后创建一个异常处理程序:
@ControllerAdvice
public class ExceptionHandlerController {
@ExceptionHandler(Exception.class)
public String handleException(Exception e) {
return "404";// view name for 404 error
}
}
不要忘记在Spring configuration file上使用@EnableWebMvc注释:
@Configuration
@EnableWebMvc
@ComponentScan(basePackages= {"org.project.etc"})
public class WebConfig extends WebMvcConfigurerAdapter {
...
}
答案 2 :(得分:5)
在您的网络配置类中,
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter
声明一个bean,如下所示,
@Bean
public EmbeddedServletContainerCustomizer containerCustomizer() {
return new EmbeddedServletContainerCustomizer() {
@Override
public void customize(ConfigurableEmbeddedServletContainer container)
{
ErrorPage error401Page = new ErrorPage(HttpStatus.UNAUTHORIZED, "/401.html");
ErrorPage error404Page = new ErrorPage(HttpStatus.NOT_FOUND, "/404.html");
ErrorPage error500Page = new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/500.html");
container.addErrorPages(error401Page,error404Page,error500Page);
}
};
}
将提到的html文件(401.html
.etc)添加到/src/main/resources/static/
文件夹。
希望这有帮助
答案 3 :(得分:4)
100%免费xml的简单回答:
设置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[] { "/" };
}
@Override
protected void customizeRegistration(ServletRegistration.Dynamic registration) {
boolean done = registration.setInitParameter("throwExceptionIfNoHandlerFound", "true"); // -> true
if(!done) throw new RuntimeException();
}
}
创建@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";
}
}
答案 4 :(得分:3)
对于Java配置,setThrowExceptionIfNoHandlerFound(boolean throwExceptionIfNoHandlerFound)
中有一个方法DispatcherServlet
。通过将其设置为true
我猜你做的是同样的事情
<init-param>
<param-name>throwExceptionIfNoHandlerFound</param-name>
<param-value>true</param-value>
</init-param>
那么您可以在控制器建议中使用NoHandlerFoundException.class
,如上面的答案所述
它会像是
public class WebXml implements WebApplicationInitializer{
public void onStartup(ServletContext servletContext) throws ServletException {
WebApplicationContext context = getContext();
servletContext.addListener(new ContextLoaderListener(context));
DispatcherServlet dp = new DispatcherServlet(context);
dp.setThrowExceptionIfNoHandlerFound(true);
ServletRegistration.Dynamic dispatcher = servletContext.addServlet("DispatcherServlet", dp);
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping(MAPPING_URL);
}
}
答案 5 :(得分:1)
提议的解决方案in comments above确实有效:
@Override
protected void customizeRegistration(ServletRegistration.Dynamic registration)
{
registration.setInitParameter("throwExceptionIfNoHandlerFound", "true");
}
答案 6 :(得分:0)
Spring 5和Thymeleaf 3的解决方案。
在MyWebInitializer
中,启用setThrowExceptionIfNoHandlerFound()
引发异常。我们需要强制转换为DispatcherServlet
。
@Configuration
public class MyWebInitializer extends
AbstractAnnotationConfigDispatcherServletInitializer {
...
@Override
protected FrameworkServlet createDispatcherServlet(WebApplicationContext servletAppContext) {
var dispatcher = (DispatcherServlet) super.createDispatcherServlet(servletAppContext);
dispatcher.setThrowExceptionIfNoHandlerFound(true);
return dispatcher;
}
}
使用@ControllerAdvice
创建控制器建议,并将错误消息添加到ModealAndView
。
@ControllerAdvice
public class ControllerAdvisor {
@ExceptionHandler(NoHandlerFoundException.class)
public ModelAndView handle(Exception ex) {
var mv = new ModelAndView();
mv.addObject("message", ex.getMessage());
mv.setViewName("error/404");
return mv;
}
}
创建404错误模板,该模板显示错误消息。根据我的配置,文件为src/main/resources/templates/error/404.html
。
<!doctype html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<title>Resource not found</title>
</head>
<body>
<h2>404 - resource not found</h2>
<p>
<span th:text="${message}" th:remove="tag"></span>
</p>
</body>
</html>
为完整起见,我添加了Thymeleaf解析器配置。我们将Thymeleaf模板配置为位于类路径的templates
目录中。
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"com.zetcode"})
public class WebConfig implements WebMvcConfigurer {
@Autowired
private ApplicationContext applicationContext;
...
@Bean
public SpringResourceTemplateResolver templateResolver() {
var templateResolver = new SpringResourceTemplateResolver();
templateResolver.setApplicationContext(applicationContext);
templateResolver.setPrefix("classpath:/templates/");
templateResolver.setSuffix(".html");
return templateResolver;
}
...
}
答案 7 :(得分:0)
在springboot中,它甚至更简单。由于Spring的自动配置功能,spring创建了一个bean org.springframework.boot.autoconfigure.web.servlet.WebMvcProperties
。此类用@ConfigurationProperties(prefix = "spring.mvc")
注释,因此它将寻找带有spring.mvc前缀的属性。
javadoc的一部分:
Annotation for externalized configuration. Add this to a class definition or a
* @Bean method in a @Configuration class if you want to bind and validate
* some external Properties (e.g. from a .properties file).
您只需添加以下属性即可,即application.properties
文件:
spring.mvc.throwExceptionIfNoHandlerFound=true
spring.resources.add-mappings=false //this is for spring so it won't return default handler for resources that not exist
并添加异常解析器,如下所示:
@ControllerAdvice
public class ExceptionResponseStatusHandler {
@ExceptionHandler(NoHandlerFoundException.class)
public ModelAndView handle404() {
var out = new ModelAndView();
out.setViewName("404");//you must have view named i.e. 404.html
return out;
}
}