Spring MVC 攔截器原理解析

Spring MVC支持配置多個攔截器,http請求將被配置的攔截器處理,處理後報錯信息拋異常,異常將被DispatcherServlet捕獲處理,每個攔截器對應的handler處理異常,包裝成ModelAndView返回。

web.xml 配置

<servlet>
	<servlet-name>myservlet</servlet-name>
	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
	<init-param>
		<param-name>springConfiguration</param-name>
		<param-value>classpath:conf/spring-config.xml</param-value>
	</init-param>
	<load-on-startup>1</load-on-startup>
</servlet>

DispatcherServlet配置好了主要處理各種前端的Http請求分派。

spring-config.xml 配置

<mvc:interceptor>
      <mvc:mapping path="/restful/**"/>
      <bean class="com.baobao.interceptor.ParamValidationInterceptor">
              <property name="localValidatorFactoryBean" ref="validator"></property>
      </bean>
</mvc:interceptor>

在該配置文件中可以配置bean的加載(例如可以用掃描包路徑的方式),各種攔截器、校驗器、Job等。

這次以restful請求的參數校驗爲例,說明攔截器的使用。攔截器必須實現HandlerInterceptor接口,該接口有三個方法,一般實現preHandle方法即可。

public class ParamValidationInterceptor implements HandlerInterceptor, InitializingBean {
    private LocallocalValidatorFactoryBean localValidatorFactoryBean;

    /**
     * Invoked by a BeanFactory after it has set all bean properties supplied
     * (and satisfied BeanFactoryAware and ApplicationContextAware).
     * <p>This method allows the bean instance to perform initialization only
     * possible when all bean properties have been set and to throw an
     * exception in the event of misconfiguration.
     *
     * @throws Exception in the event of misconfiguration (such
     *                   as failure to set an essential property) or if initialization fails.
     */
    @Override
    public void afterPropertiesSet() throws Exception {

    }

    /**
     * Intercept the execution of a handler. Called after HandlerMapping determined
     * an appropriate handler object, but before HandlerAdapter invokes the handler.
     * <p>DispatcherServlet processes a handler in an execution chain, consisting
     * of any number of interceptors, with the handler itself at the end.
     * With this method, each interceptor can decide to abort the execution chain,
     * typically sending a HTTP error or writing a custom response.
     *
     * @param request  current HTTP request
     * @param response current HTTP response
     * @param handler  chosen handler to execute, for type and/or instance evaluation
     * @return <code>true</code> if the execution chain should proceed with the
     * next interceptor or the handler itself. Else, DispatcherServlet assumes
     * that this interceptor has already dealt with the response itself.
     * @throws Exception in case of errors
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if(! (handler instanceof HandlerMethod)) {
            return true;
        }

        HandlerMethod method = (HandlerMethod) handler;
        MethodParameter[] parameters = method.getMethodParameters();
        Object[] parameterArray = new Object[parameters.length];
        ValidatorImpl validatorImpl = (ValidatorImpl) localValidatorFactoryBean.getValidator();
        Annotation[][] annotations = method.getMethod().getParameterAnnotations();

        for (int i = 0; i < annotations.length; i++) {
            for (int j = 0; j < annotations[i].length; j++) {
                if (annotations[i][j] instanceof RequestParam) {
                    String key = ((RequestParam) annotations[i][j]).value();
                    parameterArray[i] = request.getParameter(key);
                }
            }
        }

        Set<MethodConstraintViolation<Object>> errInfoSet
                = validatorImpl.validateAllParameters(method.getBean(), method.getMethod(), parameterArray);
        if (!CollectionUtils.isEmpty(errInfoSet)) {
            throw new BusiException(errInfoSet.iterator().next().getMessage());

        }
        return true;
    }

    /**
     * Intercept the execution of a handler. Called after HandlerAdapter actually
     * invoked the handler, but before the DispatcherServlet renders the view.
     * Can expose additional model objects to the view via the given ModelAndView.
     * <p>DispatcherServlet processes a handler in an execution chain, consisting
     * of any number of interceptors, with the handler itself at the end.
     * With this method, each interceptor can post-process an execution,
     * getting applied in inverse order of the execution chain.
     *
     * @param request      current HTTP request
     * @param response     current HTTP response
     * @param handler      chosen handler to execute, for type and/or instance examination
     * @param modelAndView the <code>ModelAndView</code> that the handler returned
     *                     (can also be <code>null</code>)
     * @throws Exception in case of errors
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }
}

Spring提供的校驗工廠支持各種校驗器的驗證,本文中是對Hibernate的實體的屬性的各種註解進行校驗,例如在控制層的方法入參配置了非空校驗,則這裏將會進行攔截判空。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章