gpt4 book ai didi

spring - Spring MVC 中的异常处理程序

转载 作者:IT老高 更新时间:2023-10-28 13:49:48 25 4
gpt4 key购买 nike

我想创建一个异常处理程序,它将拦截我项目中的所有 Controller 。那有可能吗?看起来我必须在每个 Controller 中放置一个处理程序方法。谢谢你的帮助。我有一个发送 Json 响应的 Spring Controller 。因此,如果发生异常,我想发送一个可以从一个地方控制的错误响应。

最佳答案

(我在 Spring 3.1 中找到了实现它的方法,这在本答案的第二部分中进行了描述)

见章节16.11 Handling exceptions Spring 引用

除了使用 @ExceptionHandler 之外,还有更多的方法。 (见 gouki's answer)

  • 您可以实现 HandlerExceptionResolver (使用 servlet 而不是 portlet 包)——这是某种全局 @ExceptionHandler
  • 如果您没有特定的异常逻辑,而只有特定的 View ,那么您可以使用 SimpleMappingExceptionResolver ,这至少是 HandlerExceptionResolver 的实现您可以在其中指定异常名称模式和抛出异常时显示的 View (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>

Spring 3.2+ 中,可以使用 @ControllerAdvice 注释类, 所有 @ExceptionHandler此类中的方法以全局方式工作。


Spring 3.1 中没有 @ControllerAdvice .但只要稍加修改,就可以拥有类似的功能。

关键是理解方式@ExceptionHandler作品。在 Spring 3.1 中有一个类 ExceptionHandlerExceptionResolver .此类实现(借助其父类(super class))接口(interface) HandlerExceptionResolver 并负责调用 @ExceptionHandler方法。

HandlerExceptionResolver接口(interface)只有一个方法:

ModelAndView resolveException(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex);`.

当请求由 Spring 3.x Controller 方法处理时,此方法(由 org.springframework.web.method.HandlerMethod 表示)是 handler参数。

ExceptionHandlerExceptionResolver使用 handler ( HandlerMethod ) 获取 Controller 类并扫描它以查找带有 @ExceptionHandler 注释的方法.如果其中一种方法与异常 (ex) 匹配,则调用此方法以处理异常。 (否则返回 null 以表明此异常解析器认为没有责任)。

第一个想法是实现自己的HandlerExceptionResolver行为类似于 ExceptionHandlerExceptionResolver , 而不是搜索 @ExceptionHandler在 Controller 类中,它应该在一个特殊的 bean 中搜索它们。缺点是,必须(复制(或子类 ExceptionHandlerExceptionResolver )并且必须)手动配置所有漂亮的消息转换器、参数解析器和返回值处理程序(真正的唯一配置 ExceptionHandlerExceptionResolver 由自动弹起)。于是我想出了另一个主意:

实现一个简单的 HandlerExceptionResolver将异常“转发”到 THE(已配置)ExceptionHandlerExceptionResolver , 但带有修改后的 handler它指向包含全局异常处理程序的 bean(我称它们为全局,因为它们为所有 Controller 工作)。

这是实现: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);
}
}
}

全局 Handler 必须实现这个接口(interface)(为了找到并实现用于 fakeHanderMethodhandler

public interface GlobalMethodExceptionResolverContainer {
void fakeHanderMethod();
}

全局处理程序的示例:

@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;
}
}

顺便说一句:您不需要注册 GlobalMethodHandlerExeptionResolver因为spring会自动注册所有实现HandlerExceptionResolver的bean用于异常解析器。所以一个简单的<bean class="GlobalMethodHandlerExeptionResolver"/>够了。

关于spring - Spring MVC 中的异常处理程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6742324/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com