您的位置:首页 > 编程语言 > Java开发

Spring controller异常的统一处理

2016-05-29 13:58 375 查看

网站的异常处理最好是解耦的,并且都放在一个地方集中管理。

比如访问权限不够,跳转到指定页面,比如访问的页面不存在,或者404 500之类的错误。

本文介绍Spring的@ControllerAdvice来对这些异常统一进行处理。

 

 

import java.io.IOException;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.NoHandlerFoundException;

@ControllerAdvice(annotations = {RestController.class})
public class ExceptionReaper {

private static final Logger logger = LogManager.getLogger(ExceptionReaper.class);

@ExceptionHandler(value = { IOException.class , RuntimeException.class })
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ModelAndView exception(Exception exception, WebRequest request) {
logger.info("Catch an exception", exception);
return  new ModelAndView("error/errorPage");
}

@ExceptionHandler(value = { NoHandlerFoundException.class })
@ResponseStatus(HttpStatus.NOT_FOUND)
public ModelAndView noMapping(Exception exception, WebRequest request) {
logger.info("No mapping exception", exception);
return  new ModelAndView("error/notFound");
}

}

 

 

网上大部分的异常处理大致分为这么几种

 

1.web.xml配置对404和500之类的错误进行处理,比如访问不存在页面时跳转到一个静态页面,缺点是必须静态页面而且不太好用

 

<error-page>
<error-code>404</error-code>
<location>/building.jsp</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/error.jsp</location>
</error-page>

 

 

2.配置exception handler,这样的话每个controller都要配置异常处理,或者在一个super controller里配置异常处理,所有controller继承他,缺点也是显而易见的。

 

@Controller
public class MyController {
@ExceptionHandler(RuntimeException.class)
@ResponseBody
public String runtimeExceptionHandler(RuntimeException runtimeException) {
logger.error("error", runtimeException);
return "error";
}
}

 

 

3.在applicationContext里面配置SimpleMappingExceptionResolver

 

@Bean
public SimpleMappingExceptionResolver exceptionResolver() {
SimpleMappingExceptionResolver exceptionResolver = new SimpleMappingExceptionResolver();
Properties exceptionMappings = new Pr
4000
operties();
exceptionMappings.put("java.lang.Exception", "error/errorPage");
exceptionMappings.put("java.lang.RuntimeException", "error/errorPage");
exceptionResolver.setExceptionMappings(exceptionMappings);
Properties statusCodes = new Properties();
statusCodes.put("error/404", "404");
statusCodes.put("error/error", "500");
exceptionResolver.setStatusCodes(statusCodes);
return exceptionResolver;
}

 

 

上面这三种处理方法比较常见,但是我觉得都不如@ControllerAdvice来的方便好用

完全可以把@ExceptionHandler放在@ControllerAdvice统一处理,不用每个controller都配置

 

import java.io.IOException;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.NoHandlerFoundException;

@ControllerAdvice(annotations = {RestController.class})
public class ExceptionReaper {

private static final Logger logger = LogManager.getLogger(ExceptionReaper.class);

@ExceptionHandler(value = { IOException.class , RuntimeException.class })
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ModelAndView exception(Exception exception, WebRequest request) {
logger.info("Catch an exception", exception);
return  new ModelAndView("error/errorPage");
}

@ExceptionHandler(value = { NoHandlerFoundException.class })
@ResponseStatus(HttpStatus.NOT_FOUND)
public ModelAndView noMapping(Exception exception, WebRequest request) {
logger.info("No mapping exception", exception);
return  new ModelAndView("error/notFound");
}

}

@ControllerAdvice(annotations = {RestController.class}) 配置你需要拦截的类,

 

@ControllerAdvice(basePackages = "com.demo") 这也可以

 

然后下面放@ExceptionHandler作为全局的异常处理

@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) 告诉浏览器这是什么错误类型

最后就可以记录日志,根据需求做一些处理,返回对应的ModelAndView跳转到对应的错误页面

 

需要注意的是,上面这些配置,只能配置你的程序中抛出的错误

1.如果是用户请求了一个不存在的页面,没有对应的@RequestMapping,此时Spring的DispatcherServlet就会处理掉返回404,不会进入任何一个controller

2.还有比如spring security之类的权限管理模块,如果用户的密码正确,但是该账户的权限组没有权限访问当前页面,此时权限模块会有自己的AccessDeniedHandler处理,也不会进入刚才配置的@ControllerAdvice

 

所以对于2中的情况,一般通过权限管理模块提供的方法去处理异常

比如spring security中

 

@Override
protected void configure(HttpSecurity http) throws Exception {

http
.authorizeRequests()
.antMatchers("/resources/**")
.permitAll()
.anyRequest()
.authenticated()
.and()
.exceptionHandling()
.accessDeniedPage("/error/accessDenied.html")
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();

}

 

 

对于1中的情况,我们可以配置Spring在没有对应的@RequestMapping时,不要自行处理,让他抛出一个NoHandlerFoundException的异常,从而让我们配置的@ControllerAdvice进行统一处理

如果是xml风格的配置,可以在DispatcherServlet对应的配置文件中配置

如果是之前介绍的class风格的配置,可以这样配置:

dispatcherServlet.setThrowExceptionIfNoHandlerFound(true);//for NoHandlerFoundException

 

 

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;

import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.request.RequestContextListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;

public class WebInit implements WebApplicationInitializer {

@Override
public void onStartup(ServletContext container) throws ServletException {
// Create the 'root' Spring application context
AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
rootContext.scan("com.demo");
// Manage the lifecycle of the root application context
container.addListener(new ContextLoaderListener(rootContext));
// Listener that exposes the request to the current thread
container.addListener(new RequestContextListener());
// Create the dispatcher servlet's Spring application context
AnnotationConfigWebApplicationContext dispatcherContext = new AnnotationConfigWebApplicationContext();
// Register and map the dispatcher servlet
DispatcherServlet dispatcherServlet = new DispatcherServlet(dispatcherContext);
dispatcherServlet.setThrowExceptionIfNoHandlerFound(true);//for NoHandlerFoundException
ServletRegistration.Dynamic dispatcher = container.addServlet("dispatcher",	dispatcherServlet);
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
}

}

 

 

网站的异常处理基本都能实现了

以上

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: