404 переадресация ошибок в Spring с помощью java config
Как вы знаете, в 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";
}
И он, похоже, работает, но он имеет проблемы с поиском ресурсов.
Есть ли способ сделать это?
Ответы
Ответ 1
В Spring Framework существует несколько способов передачи исключений (и, в частности, ошибки 404). Вот ссылка .
- Во-первых, вы можете использовать тег
error-page
в web.xml и настроить страницу с ошибкой. Вот пример .
-
Во-вторых, вы можете использовать один @ExceptionHandler
для всех контроллеров, например:
@ControllerAdvice
public class ControllerAdvisor {
@ExceptionHandler(NoHandlerFoundException.class)
public String handle(Exception ex) {
return "404";//this is view name
}
}
Чтобы это сработало, установите для свойства throwExceptionIfNoHandlerFound значение true для DispatcherServlet
в web.xml:
<init-param>
<param-name>throwExceptionIfNoHandlerFound</param-name>
<param-value>true</param-value>
</init-param>
Вы также можете передать некоторые объекты в окно ошибок, см. javadoc.
Ответ 2
Самое чистое решение, так как 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;
}
}
Затем вы можете использовать глобальный @ControllerAdvice
(класс, аннотированный с помощью @ControllerAdvice
), как описано в справочных документах. В рамках совета вы можете обрабатывать NoHandlerFoundException
с помощью @ExceptionHandler
, как описано здесь.
Это может выглядеть примерно так:
@ControllerAdvice
public class NoHandlerFoundControllerAdvice {
@ExceptionHandler(NoHandlerFoundException.class)
public ResponseEntity<String> handleNoHandlerFoundException(NoHandlerFoundException ex) {
// prepare responseEntity
return responseEntity;
}
}
Ответ 3
Используйте инициализацию контейнера сервлетов на основе кода, как описано в методе doc, и переопределите метод 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
}
}
Не забудьте использовать аннотацию @EnableWebMvc в файле конфигурации Spring:
@Configuration
@EnableWebMvc
@ComponentScan(basePackages= {"org.project.etc"})
public class WebConfig extends WebMvcConfigurerAdapter {
...
}
Ответ 4
В вашем классе веб-конфигурации
@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/
.
Надеюсь, что это поможет
Ответ 5
Простой ответ для 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";
}
}
Ответ 6
Для конфигурации 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);
}
}
Ответ 7
Предлагаемое решение в комментариях выше действительно работает:
@Override
protected void customizeRegistration(ServletRegistration.Dynamic registration)
{
registration.setInitParameter("throwExceptionIfNoHandlerFound", "true");
}
Ответ 8
Решение для Spring 5 и Thymeleaf 3.
В MyWebInitializer
включите 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>