[英]Handle error 404 in web application - not REST application
I'm trying to handle 404 error using an @ControllerAdvice
in a Spring MVC application totally configured using Javaconfig. 我正在尝试使用完全使用Javaconfig配置的Spring MVC应用程序中的@ControllerAdvice
来处理404错误。
Spring MVC version is 4.1.5 Spring MVC版本是4.1.5
I have read this: 我读过这个:
But unfortunately it does not work for me. 但不幸的是,它对我不起作用。
Here you have my conf: 在这里你有我的conf:
SpringConfigurationInitializer SpringConfigurationInitializer
public class SpringConfigurationInitializer extends
AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { AppConfiguration.class };
}
@Override
protected Class<?>[] getServletConfigClasses() {
return null;
}
@Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
@Override
public void customizeRegistration(ServletRegistration.Dynamic registration) {
registration.setInitParameter("throwExceptionIfNoHandlerFound", "true");
}
}
Note that i'm using 请注意,我正在使用
registration.setInitParameter("throwExceptionIfNoHandlerFound", "true");
And 和
GlobalExceptionHandler (version 1) GlobalExceptionHandler(版本1)
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(NoHandlerFoundException.class)
public ModelAndView handleError404(HttpServletRequest request, Exception e) {
System.out.println("handled!!!");
ModelAndView mav = new ModelAndView("/errors/404");
mav.addObject("exception", e);
return mav;
}
}
GlobalExceptionHandler (version 2) GlobalExceptionHandler(版本2)
@ControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
@Override
public ResponseEntity handleNoHandlerFoundException(NoHandlerFoundException ex,
HttpHeaders headers, HttpStatus status, WebRequest request) {
System.out.println("handled¡¡¡");
return null;
}
}
Keep in mind that i'm not using any kind of xml config file and i'm trying to build a web application (not REST) 请记住,我没有使用任何类型的xml配置文件,我正在尝试构建一个Web应用程序(而不是REST)
AppConfiguration AppConfiguration
@Configuration
@ComponentScan({ "org.moyanojv.opendata.*" })
@Import({ MvcConfiguration.class, RepositoryConfiguration.class, SecurityConfig.class })
public class AppConfiguration extends WebMvcConfigurerAdapter{
}
MvcConfiguration MvcConfiguration
@EnableWebMvc
@Configuration
public class MvcConfiguration extends WebMvcConfigurerAdapter {
@Bean
public UrlBasedViewResolver viewResolver() {
UrlBasedViewResolver viewResolver = new UrlBasedViewResolver();
viewResolver.setViewClass(TilesView.class);
return viewResolver;
}
@Bean
public TilesConfigurer tilesConfigurer() {
TilesConfigurer tilesConfigurer = new TilesConfigurer();
tilesConfigurer.setDefinitions(new String[] { "/WEB-INF/tiles.xml" });
tilesConfigurer.setCheckRefresh(true);
return tilesConfigurer;
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
@Override
public void configureDefaultServletHandling(
DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
/* Localization section is started */
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(localeChangeInterceptor());
}
@Bean
public LocaleChangeInterceptor localeChangeInterceptor(){
LocaleChangeInterceptor localeChangeInterceptor=new LocaleChangeInterceptor();
localeChangeInterceptor.setParamName("lang");
return localeChangeInterceptor;
}
@Bean(name = "localeResolver")
public LocaleResolver getLocaleResolver(){
return new CookieLocaleResolver();
}
@Bean
public ResourceBundleMessageSource messageSource() {
ResourceBundleMessageSource source = new ResourceBundleMessageSource();
source.setBasename("i18n/messages");
source.setUseCodeAsDefaultMessage(true);
return source;
}
}
RepositoryConfiguration RepositoryConfiguration
@Configuration
public class RepositoryConfiguration {
}
SecurityConfig SecurityConfig
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth)
throws Exception {
auth.inMemoryAuthentication().withUser("admin").password("admin").roles("ADMIN");
auth.inMemoryAuthentication().withUser("user").password("user").roles("USER");
}
@Override
public void configure( WebSecurity web ) throws Exception
{
// This is here to ensure that the static content (JavaScript, CSS, etc)
// is accessible from the login page without authentication
web
.ignoring()
.antMatchers( "/resources/**" );
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
// access-denied-page: this is the page users will be
// redirected to when they try to access protected areas.
.exceptionHandling()
.accessDeniedPage( "/403" )
.and()
// The intercept-url configuration is where we specify what roles are allowed access to what areas.
// We specifically force the connection to https for all the pages, although it could be sufficient
// just on the login page. The access parameter is where the expressions are used to control which
// roles can access specific areas. One of the most important things is the order of the intercept-urls,
// the most catch-all type patterns should at the bottom of the list as the matches are executed
// in the order they are configured below. So /** (anyRequest()) should always be at the bottom of the list.
.authorizeRequests()
.antMatchers( "/admin" ).hasRole("ADMIN")
.antMatchers("/login**").permitAll()
.antMatchers("/home").permitAll()
.antMatchers("/404").permitAll()
.anyRequest().authenticated()
.and()
// This is where we configure our login form.
// login-page: the page that contains the login screen
// login-processing-url: this is the URL to which the login form should be submitted
// default-target-url: the URL to which the user will be redirected if they login successfully
// authentication-failure-url: the URL to which the user will be redirected if they fail login
// username-parameter: the name of the request parameter which contains the username
// password-parameter: the name of the request parameter which contains the password
.formLogin()
.loginPage( "/login" )
.failureUrl( "/login?err=1" )
.defaultSuccessUrl("/private")
.usernameParameter( "username" )
.passwordParameter( "password" )
.permitAll()
.and()
// This is where the logout page and process is configured. The logout-url is the URL to send
// the user to in order to logout, the logout-success-url is where they are taken if the logout
// is successful, and the delete-cookies and invalidate-session make sure that we clean up after logout
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/login?logout=1")
.invalidateHttpSession(true)
//.deleteCookies("JSESSIONID,SPRING_SECURITY_REMEMBER_ME_COOKIE")
.and()
.csrf()
.disable()
// The session management is used to ensure the user only has one session. This isn't
// compulsory but can add some extra security to your application.
.sessionManagement()
.maximumSessions(1);
}
@Override
@Bean
public UserDetailsService userDetailsServiceBean() throws Exception
{
return super.userDetailsServiceBean();
}
}
SpringSecurityInitializer SpringSecurityInitializer
public class SpringSecurityInitializer extends AbstractSecurityWebApplicationInitializer{
//do nothing
}
With this config i'm not able to handle 404 error code. 使用此配置,我无法处理404错误代码。
Thanks in advance. 提前致谢。
Updated to add more information about config files 已更新以添加有关配置文件的更多信息
Conclusion seems to be that setting throwExceptionIfNoHandlerFound to true does not throw an exception when no handler is found. 结论似乎是将throwExceptionIfNoHandlerFound设置为true不会在找不到处理程序时抛出异常。
The solution is quite simple. 解决方案非常简单。 From the javadoc @ DispatcherServlet.setThrowExceptionIfNoHandlerFound . 来自javadoc @ DispatcherServlet.setThrowExceptionIfNoHandlerFound 。 It states here that a NoHandlerFoundException will never be thrown if DefaultServletHttpRequestHandler is used. 它声明如果使用DefaultServletHttpRequestHandler,将永远不会抛出NoHandlerFoundException。
Solution hence is to remove the line 解决方案因此是删除线
configurer.enable();
from your MvcConfiguration. 来自你的MvcConfiguration。 The exception should fire now and your GlobalExceptionHandler should do the rest! 现在应该触发异常,你的GlobalExceptionHandler应该完成其余的工作!
Workaround: Add @RequestMapping("/**") 解决方法:添加@RequestMapping(“/ **”)
@Controller
@ControllerAdvice
public class GlobalExceptionHandler {
private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
@RequestMapping("/**")
public String handlerNotMappingRequest(HttpServletRequest request, HttpServletResponse response, HttpHeaders httpHeaders)
throws NoHandlerFoundException {
throw new NoHandlerFoundException("No handler mapping found.", request.getRequestURL().toString(), httpHeaders);
}
@ExceptionHandler(Throwable.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ModelAndView handleControllerException(Throwable ex) {
logger.error("ErrorLog: ", ex);
return new ModelAndView("error/exception", "exceptionMsg", "ExceptionHandler msg: " + ex.toString());
}
@ExceptionHandler(NoHandlerFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public ModelAndView handleNoHandlerFoundException(NoHandlerFoundException ex) {
logger.error("ErrorLog: ", ex);
return new ModelAndView("error/exception", "exceptionMsg", "NoHandlerFoundException msg: " + ex.toString());
}
}
The solution is to extend AbstractAnnotationConfigDispatcherServletInitializer
and override this method: 解决方案是扩展AbstractAnnotationConfigDispatcherServletInitializer
并覆盖此方法:
@Override
protected DispatcherServlet createDispatcherServlet(WebApplicationContext servletAppContext) {
final DispatcherServlet dispatcherServlet = (DispatcherServlet) super.createDispatcherServlet(servletAppContext);
dispatcherServlet.setThrowExceptionIfNoHandlerFound(true);
return dispatcherServlet;
}
OR this one: 或者这一个:
@Override
public void customizeRegistration(ServletRegistration.Dynamic registration) {
registration.setInitParameter("throwExceptionIfNoHandlerFound", "true");
}
And finally in your ControlerAdvice
use this: 最后在你的ControlerAdvice
使用:
@ExceptionHandler(NoHandlerFoundException.class)
public String error404(Exception ex) {
return new ModelAndView("404");
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.