fas*_*ava 20 spring spring-mvc custom-exceptions interceptor
我想创建一个异常处理程序,它将拦截我项目中的所有控制器.这可能吗?看起来我必须在每个控制器中放置一个处理程序方法.谢谢你的帮助.我有一个发送Json响应的弹簧控制器.因此,如果发生异常,我想发送一个可以从一个地方控制的错误响应.
Ral*_*lph 23
(我找到了一种在Spring 3.1中实现它的方法,这在本答案的第二部分中有描述)
请参见第16.11节"处理 Spring Reference的异常 "
还有一些方法比使用@ExceptionHandler
(见gouki的答案)
如果您没有特定的异常逻辑,但只有特定的视图,那么您可以使用SimpleMappingExceptionResolver,它至少是HandlerExceptionResolver
您可以指定异常名称模式的位置的实现,以及在显示时显示的视图(jsp)抛出异常.例如:
<bean
class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"
p:defaultErrorView="uncaughtException">
<property name="exceptionMappings">
<props>
<prop key=".DataAccessException">dataAccessFailure</prop>
<prop key=".TypeMismatchException">resourceNotFound</prop>
<prop key=".AccessDeniedException">accessDenied</prop>
</props>
</property>
</bean>
Run Code Online (Sandbox Code Playgroud)在Spring 3.2+中,可以用类注释一个类@ControllerAdvice
,@ExceptionHandler
这个类中的所有方法都以全局方式工作.
在Spring 3.1中没有@ControllerAdvice
.但是有点破解可能会有类似的功能.
关键是对工作方式的理解@ExceptionHandler
.在Spring 3.1中有一个类ExceptionHandlerExceptionResolver
.该类实现(在其超类的帮助下)接口HandlerExceptionResolver
并负责调用@ExceptionHandler
方法.
该HandlerExceptionResolver
接口只有一个方法:
ModelAndView resolveException(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex);`.
Run Code Online (Sandbox Code Playgroud)
当请求由Spring 3.x控制器方法处理时,此方法(由...表示org.springframework.web.method.HandlerMethod
)是handler
参数.
的ExceptionHandlerExceptionResolver
用途handler
(HandlerMethod
),以获得控制器类和扫描它用于与所注解的方法@ExceptionHandler
.如果其中一个方法与exception(ex
)匹配,则调用此方法以处理异常.(否则null
返回以表示此异常解析器感觉不负责任).
第一个想法是实现一个HandlerExceptionResolver
行为类似的自己ExceptionHandlerExceptionResolver
,但不是@ExceptionHandler
在控制器类中搜索,而是应该在一个特殊的bean中搜索它们.缺点是,必须(复制(或子类ExceptionHandlerExceptionResolver
)并且必须)手动配置所有好的消息转换器,参数解析器和返回值处理程序(真实的配置,并且仅ExceptionHandlerExceptionResolver
由spring自动完成).所以我提出了另一个想法:
实现一个HandlerExceptionResolver
将异常"转发"到THE(已经配置)的简单ExceptionHandlerExceptionResolver
,但是带有修改的handler
,指向包含全局异常处理程序的bean.(我将它们称为全局,因为所有控制器的工作.).
这是实施: GlobalMethodHandlerExeptionResolver
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.Ordered;
import org.springframework.util.StringUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver;
public class GlobalMethodHandlerExeptionResolver
implements HandlerExceptionResolver, Ordered {
@Override
public int getOrder() {
return -1; //
}
private ExceptionHandlerExceptionResolver realExceptionResolver;
private List<GlobalMethodExceptionResolverContainer> containers;
@Autowired
public GlobalMethodHandlerExeptionResolver(
ExceptionHandlerExceptionResolver realExceptionResolver,
List<GlobalMethodExceptionResolverContainer> containers) {
this.realExceptionResolver = realExceptionResolver;
this.containers = containers;
}
@Override
public ModelAndView resolveException(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) {
for (GlobalMethodExceptionResolverContainer container : this.containers) {
ModelAndView result = this.realExceptionResolver.resolveException(
request,
response,
handlerMethodPointingGlobalExceptionContainerBean(container),
ex);
if (result != null)
return result;
}
// we feel not responsible
return null;
}
protected HandlerMethod handlerMethodPointingGlobalExceptionContainerBean(
GlobalMethodExceptionResolverContainer container) {
try {
return new HandlerMethod(container,
GlobalMethodExceptionResolverContainer.class.
getMethod("fakeHanderMethod"));
} catch (NoSuchMethodException | SecurityException e) {
throw new RuntimeException(e);
}
}
}
Run Code Online (Sandbox Code Playgroud)
全局处理程序必须实现此接口(以便找到并实现fakeHanderMethod
用于handler
public interface GlobalMethodExceptionResolverContainer {
void fakeHanderMethod();
}
Run Code Online (Sandbox Code Playgroud)
以及全局处理程序的示例:
@Component
public class JsonGlobalExceptionResolver
implements GlobalMethodExceptionResolverContainer {
@Override
public void fakeHanderMethod() {
}
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ResponseBody
public ValidationErrorDto handleMethodArgumentNotValidException(
MethodArgumentNotValidException validationException,
Locale locale) {
...
/* map validationException.getBindingResult().getFieldErrors()
* to ValidationErrorDto (custom class) */
return validationErrorDto;
}
}
Run Code Online (Sandbox Code Playgroud)
顺便说一句:您不需要注册,GlobalMethodHandlerExeptionResolver
因为spring会自动注册HandlerExceptionResolver
为异常解析器实现的所有bean .所以简单<bean class="GlobalMethodHandlerExeptionResolver"/>
就足够了.
Vah*_*yan 15
从Spring 3.2开始,您可以使用@ControllerAdvice批注.您可以在@ControllerAdvice类中声明@ExceptionHandler方法,在这种情况下,它会处理来自所有控制器的@RequestMapping方法的异常.
@ControllerAdvice
public class MyGlobalExceptionHandler {
@ExceptionHandler(value=IOException.class)
public @ResponseBody String iOExceptionHandler(Exception ex){
//
//
}
// other exception handler methods
// ...
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
20058 次 |
最近记录: |