一、拦截器
SpringMVC可以使用拦截器对请求进行拦截处理,用户可以自定义拦截器来实现特定的功能,自定义的拦截器必须实现HandlerInterceptor接口。
public class FirstInterceptor implements HandlerInterceptor {
/**
* 渲染视图之后调用,释放资源
*/
@Override
public void afterCompletion(HttpServletRequest arg0,
HttpServletResponse arg1, Object arg2, Exception arg3)
throws Exception {
System.out.println("[FirstInterceptor] afterCompletion");
}
/**
* 调用目标方法之后渲染视图之前
* 修改对请求域中的或视图进行修改
*/
@Override
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1,
Object arg2, ModelAndView arg3) throws Exception {
System.out.println("[FirstInterceptor] postHandle");
}
/**
* 1.该方法在目标方法执行之前调用
* 2.若返回true,则继续调用后续的拦截器和目标方法。
* 3.若返回false,则不会调用后续的拦截器和目标方法。
*
* 可以考虑做权限、登陆、日志、事务等
*/
@Override
public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1,
Object arg2) throws Exception {
System.out.println("[FirstInterceptor] preHandle");
return true;
}
}
另一个拦截器SecondInterceptor将打印里面的FirstInterceptor换成SecondInterceptor。
配置拦截器
<mvc:interceptors>
<!-- 配置自定义拦截器 -->
<bean class="com.crystal.springmvc.interceptor.FirstInterceptor"></bean>
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"></bean>
<!-- 配置拦截器作用的路径或不作用的路径 -->
<mvc:interceptor>
<mvc:mapping path="/emps"/>
<bean class="com.crystal.springmvc.interceptor.SecondInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
执行结果
[FirstInterceptor] preHandle
[SecondInterceptor] preHandle
[SecondInterceptor] postHandle
[FirstInterceptor] postHandle
[SecondInterceptor] afterCompletion
[FirstInterceptor] afterCompletion
从打印结果可以看出,拦截器中的preHandle方法是根据配置顺序,而另外两个方法则是配置的逆序。
二、异常处理
SpringMVC 通过HandlerExceptionResolver来处理程序异常,包括Handler映射、数据绑定以及目标方法执行时发生的异常。
DispatcherServlet默认装配HandlerExceptionResolver(配置了mvc:annotation-dirven):
- ExceptionHandlerExceptionResolver:主要处理Handler中用@ExceptionHandler注解定义的方法(只在当前Handler类工作)。若找不到@ExceptionHandler注解定义的方法,会找@ContorllerAdvice中的@ExceptionHandler注解定义的方法(全局)。
/**
* 1.在方法入参中可以加入Exception类型的参数,该参数即对应发生大的异常对象
* 2.不能使用Map入参,如果想把错误信息传递到页面上,使用ModelAndView返回
* @param ex
* @return
*/
@ExceptionHandler({ArithmeticException.class})
public ModelAndView handleArithmeticException(Exception ex) {
System.out.println("出异常了--"+ex.getMessage());
ModelAndView view = new ModelAndView("error");
view.addObject("error", ex);
return view;
}
/**
* 处理异常类
* @author cye
* */
@ControllerAdvice
public class MyExceptionHandler {
@ExceptionHandler({ArithmeticException.class})
public ModelAndView handleArithmeticException(Exception ex) {
System.out.println("出异常了--"+ex.getMessage());
ModelAndView view = new ModelAndView("error");
view.addObject("error", ex);
return view;
}
}
- ResponseStatusExceptionResolver:在异常及异常父类中找到@ResponseStatus 注解,然后使用这个注解的属性进行处理。
@ResponseStatus(value=HttpStatus.FORBIDDEN, reason="用户名密码不匹配")
public class UserNameNotMatchPasswordException extends RuntimeException {
private static final long serialVersionUID = 86448864520759103L;
}
若处理器方法中抛出上面的异常且 ExceptionHandlerExceptionResolver 不解析上述异常。由于UserNameNotMatchPasswordException 带有 @ResponseStatus 注解,因此会被 ResponseStatusExceptionResolver 解析。最后响应 HttpStatus.FORBIDDEN 代码给客户端。
- DefaultHandlerExceptionResolver:对一些特殊异常进行处理,如NoSuchRequestHandlingMethodException等。
- SimpleMappingExceptionResolver:如果希望对所有异常进行统一处理可以使用该解析类,它将异常名映射为视图名,即发生异常时使用对应的视图报告异常。
<bean id="simpleMappingException" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<!-- exceptionAttribute设置异常名,默认exception -->
<property name="exceptionAttribute" value="error"></property>
<property name="exceptionMappings">
<props>
<prop key="java.lang.ArrayIndexOutOfBoundsException">error</prop>
</props>
</property>
</bean>