使用java配置在Spring中重定向404错误
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/23574869/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
404 error redirect in Spring with java config
提问by Carlos López
As you know, in XML, the way to configure this is:
如您所知,在 XML 中,配置它的方法是:
<error-page>
<error-code>404</error-code>
<location>/my-custom-page-not-found.html</location>
</error-page>
But I haven't found a way to do it in Java config. The first way I tried was:
但是我还没有找到在 Java 配置中做到这一点的方法。我尝试的第一种方法是:
@RequestMapping(value = "/**")
public String Error(){
return "error";
}
And it appeared to work, but it has conflicts retrieving the resources.
它似乎有效,但在检索资源时存在冲突。
Is there a way to do it?
有没有办法做到这一点?
回答by Eugene
In Spring Framework, there are number of ways of handing exceptions (and particularly 404 error). Here is a documentation link.
在 Spring Framework 中,有多种处理异常(尤其是 404 错误)的方法。这是一个文档链接。
- First, you can still use
error-page
tag in web.xml, and customize error page. Here is an example. Second, you can use one
@ExceptionHandler
for all controllers, like this:@ControllerAdvice public class ControllerAdvisor { @ExceptionHandler(NoHandlerFoundException.class) public String handle(Exception ex) { return "404";//this is view name } }
For this to work, set throwExceptionIfNoHandlerFoundproperty to true for
DispatcherServlet
in web.xml:<init-param> <param-name>throwExceptionIfNoHandlerFound</param-name> <param-value>true</param-value> </init-param>
You can also pass some objects to error view, see javadocfor this.
- 首先,您仍然可以
error-page
在 web.xml 中使用标签,并自定义错误页面。这是一个例子。 其次,您可以
@ExceptionHandler
为所有控制器使用一个,如下所示:@ControllerAdvice public class ControllerAdvisor { @ExceptionHandler(NoHandlerFoundException.class) public String handle(Exception ex) { return "404";//this is view name } }
为此,在 web.xml中将throwExceptionIfNoHandlerFound属性设置为 true
DispatcherServlet
:<init-param> <param-name>throwExceptionIfNoHandlerFound</param-name> <param-value>true</param-value> </init-param>
您还可以将一些对象传递给错误视图,请参阅javadoc。
回答by leshkin
Use code-based Servlet container initialization as described in the docand override registerDispatcherServletmethod to set throwExceptionIfNoHandlerFoundproperty to true:
使用文档中描述的基于代码的 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);
}
}
Then create an exception handler:
然后创建一个异常处理程序:
@ControllerAdvice
public class ExceptionHandlerController {
@ExceptionHandler(Exception.class)
public String handleException(Exception e) {
return "404";// view name for 404 error
}
}
Don't forget about using @EnableWebMvc annotation on your Spring configuration file:
不要忘记在Spring 配置文件上使用 @EnableWebMvc 注释:
@Configuration
@EnableWebMvc
@ComponentScan(basePackages= {"org.project.etc"})
public class WebConfig extends WebMvcConfigurerAdapter {
...
}
回答by Dhruv Pal
For Java config there is a method setThrowExceptionIfNoHandlerFound(boolean throwExceptionIfNoHandlerFound)
in DispatcherServlet
. By settting it to true
I guess you are doing same thing
对于 Java 配置,setThrowExceptionIfNoHandlerFound(boolean throwExceptionIfNoHandlerFound)
在DispatcherServlet
. 通过将其设置为true
我猜你在做同样的事情
<init-param>
<param-name>throwExceptionIfNoHandlerFound</param-name>
<param-value>true</param-value>
</init-param>
then you can can this NoHandlerFoundException.class
in controller advice as stated in above answer
那么您可以NoHandlerFoundException.class
在控制器建议中进行此操作,如上述答案所述
it will be like something
它会像什么
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);
}
}
回答by Christian Rudolph
The most clean solution since spring 4.2 RC3 is using the new createDispatcherServlet
hook within the class extending AbstractDispatcherServletInitializer
(or indirectly through extending AbstractAnnotationConfigDispatcherServletInitializer
) like this:
自 spring 4.2 RC3 以来最干净的解决方案是createDispatcherServlet
在类扩展中使用新钩子AbstractDispatcherServletInitializer
(或间接通过扩展AbstractAnnotationConfigDispatcherServletInitializer
),如下所示:
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return null;
}
/* ... */
@Override
protected DispatcherServlet createDispatcherServlet(WebApplicationContext servletAppContext) {
final DispatcherServlet dispatcherServlet = super.createDispatcherServlet(servletAppContext);
dispatcherServlet.setThrowExceptionIfNoHandlerFound(true);
return dispatcherServlet;
}
}
Then you can use a global @ControllerAdvice
(a class that is annotated with @ControllerAdvice
) as described in the reference docs. Within the advice you can handle the NoHandlerFoundException
with an @ExceptionHandler
as described here.
然后,您可以使用参考文档中所述的全局@ControllerAdvice
(用 注释的类@ControllerAdvice
)。在通知您可以处理与所描述这里。NoHandlerFoundException
@ExceptionHandler
This could look something like this:
这可能看起来像这样:
@ControllerAdvice
public class NoHandlerFoundControllerAdvice {
@ExceptionHandler(NoHandlerFoundException.class)
public ResponseEntity<String> handleNoHandlerFoundException(NoHandlerFoundException ex) {
// prepare responseEntity
return responseEntity;
}
}
回答by Jaffadog
The solution proposed in comments abovereally works:
上面评论中提出的解决方案确实有效:
@Override
protected void customizeRegistration(ServletRegistration.Dynamic registration)
{
registration.setInitParameter("throwExceptionIfNoHandlerFound", "true");
}
回答by SerdukovAA
Simple answer for 100% free xml:
100% 免费 xml 的简单答案:
Set properties for
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(); } }
Create
@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"; } }
设置属性
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"; } }
回答by tharindu_DG
In your web configuration class,
在您的 Web 配置类中,
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter
Declare a bean as follows,
声明一个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);
}
};
}
Add the mentioned html files(401.html
.etc) to /src/main/resources/static/
folder.
将提到的 html 文件(401.html
.etc)添加到/src/main/resources/static/
文件夹。
Hope this helps
希望这可以帮助
回答by Jan Bodnar
A solution for Spring 5 and Thymeleaf 3.
Spring 5 和 Thymeleaf 3 的解决方案。
In MyWebInitializer
, enable exception throwing with setThrowExceptionIfNoHandlerFound()
. We need to do casting to DispatcherServlet
.
在 中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;
}
}
Create a controller advice with @ControllerAdvice
and add error message to the ModealAndView
.
创建控制器建议@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;
}
}
Create 404 error template, which displays the error message. Based on my configuration, the file is src/main/resources/templates/error/404.html
.
创建 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>
For completeness, I add the Thymeleaf resolver configuration. We configure the Thymeleaf templates to be in templates
directory on the classpath.
为了完整起见,我添加了 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;
}
...
}
回答by bpawlowski
In springboot it is even simplier. Because of Spring autoconfiguration stuff, spring creates a bean org.springframework.boot.autoconfigure.web.servlet.WebMvcProperties
. This class is annotated with @ConfigurationProperties(prefix = "spring.mvc")
and therefore it will seek for properties with spring.mvc prefix.
在 springboot 中,它甚至更简单。由于 Spring 自动配置的东西,spring 创建了一个 bean org.springframework.boot.autoconfigure.web.servlet.WebMvcProperties
。此类带有注释,@ConfigurationProperties(prefix = "spring.mvc")
因此它将寻找带有 spring.mvc 前缀的属性。
Part from javadoc:
部分来自 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).
You just have to add to your i.e. application.properties
file following properties:
您只需将application.properties
以下属性添加到您的 ie文件中:
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
and add exception resolver as follows:
并添加异常解析器如下:
@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;
}
}