回到最开始我们使用tomcat搭配web.xml。
Tomcat启动时加载配置有着先后顺序。
web.xml的加载顺序是:<context-param> -> <listener> -> <filter> -> <servlet>。
context-param设置应用的ServletContext上下文初始化参数,所以最先加载。
=========================================================
上面是传统的用web.xml来配置,但是我们现在已经使用实现WebMvcConfigurer的配置类SpringMvcConfig来替代web.xml。对比之下,可以看到:
对应的监听器listener通过WebAppRootListener 替代。
对应的过滤器filter通过在SpringMvcConfig重写addResourceHandlers替代。
对应的servlet通过DispatcherServlet分发搭配@Controller@RequestMapping等替代。
======================================================================
拦截器呢?Javaweb中好像没这个说法,springMVC才设计拦截器的概念,首次执行是在DispatcherServlet分发之后controller执行之前。只用Javaweb的话使用过滤器Filter或者代理能够实现相似的功能。
拦截器的常用场景:springmvc框架帮我们简化操作后的东西,能用拦截器就用拦截器,别用javax.servlet.Filter和自己写代理和AOP
=========================================================================
过滤器示例:
springMVC的过滤器addResourceHandlers。指向静态资源的路径。
@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {
@Autowired
private ProjectInterceptor projectInterceptor;
// 过滤器
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
}
//拦截器
@Override
protected void addInterceptors(InterceptorRegistry registry) {
//配置拦截器
registry.addInterceptor(projectInterceptor).addPathPatterns("/books", "/books/*");
}
}
拦截器示例:
springMVC的拦截器是实现 HandlerInterceptor或者WebRequestInterceptor,根据请求路径,对交给MVC对应的IOC容器管理的controller中的方法做增强,在方法执行前后加些操作。
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Component
//定义拦截器类,实现HandlerInterceptor接口
//注意当前类必须受Spring容器控制
public class ProjectInterceptor implements HandlerInterceptor {
@Override
//原始方法调用前执行的内容
//返回值类型可以拦截控制的执行,true放行,false终止
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String contentType = request.getHeader("Content-Type");
HandlerMethod hm = (HandlerMethod)handler;
System.out.println("preHandle..."+contentType);
return true;
}
@Override
//原始方法调用后执行的内容
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle...");
}
@Override
//原始方法调用完成后执行的内容
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion...");
}
}
//拦截器
@Override
protected void addInterceptors(InterceptorRegistry registry) {
//配置拦截器
registry.addInterceptor(projectInterceptor).addPathPatterns("/books", "/books/*");
}
有了拦截器还有必要写AOP吗?有。
因为按照我们之前的配置,只将controller交给了MVC对应的IOC容器管理,拦截器只能增强MVC对应的IOC容器中的controller中的方法,不能对service层dao层的接口实现类中的方法进行增强。而自己手写的@Pointcut("execution(* com.ldj.service.*Service.*(..))")和@Around("servicePt()")
AOP却可以对普通spring IOC容器和MVC IOC容器管理的bean中的方法都进行增强。
可以说拦截器是MVC帮我们包装过后的AOP操作,我们也可以自己根据AOP自己写拦截器,但spring MVC帮我们写好了一个HandlerInterceptor 接口直接拿来用方便多了。
========================================================================
官方文档拦截器示例:通过注解或者XML两种方式
You can configure HandlerInterceptors or WebRequestInterceptors to be applied to all
incoming requests or restricted to specific URL path patterns.
An example of registering interceptors in Java:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LocaleInterceptor());
registry.addInterceptor(new ThemeInterceptor()).addPathPatterns("/**").excludePathPatterns("/
admin/**");
registry.addInterceptor(new SecurityInterceptor()).addPathPatterns("/secure/*");
}
}
And in XML use the <mvc:interceptors> element:
<mvc:interceptors>
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"/>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path="/admin/**"/>
<bean class="org.springframework.web.servlet.theme.ThemeChangeInterceptor"/>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/secure/*"/>
<bean class="org.example.SecurityInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
老版本spring官方文档对拦截器的说明:
13.4.3。拦截请求——HandlerInterceptor接口
Spring的处理程序映射机制具有处理程序拦截器的概念,当您想要将特定的功能应用到特定的请求(例如,检查主体)时,它会非常有用。
位于处理程序映射中的拦截器必须从org.springframework.web.servlet包中实HandlerInterceptor。该接口定义了三个方法,一个方法将在实际处理程序执行之前调用,一个方法将在处理程序执行之后调用,另一个方法将在完整请求完成后调用。这三种方法应该提供足够的灵活性来进行各种预处理和后处理。
三种方法返回一个布尔值。您可以使用此方法中断或继续执行链的处理。该方法返回true时,处理程序链将继续执行,当它返回false, DispatcherServlet假定请求拦截器本身照顾(例如,呈现一个适当的视图),不继续执行其他拦截器和实际处理程序在执行链。下面的示例提供了一个拦截器,如果时间不在上午9点到下午6点之间,拦截所有请求并将用户路由到特定页面。
如上示例任何传入的请求都将被TimeBasedAccessInterceptor拦截,如果当前时间不在办公时间,用户将被重定向到一个静态html文件,例如,他只能在办公时间访问该网站。
如您所见,Spring有一个适配器类(巧妙地命名为HandlerInterceptorAdapter),以便更容易扩展HandlerInterceptor接口。