目录
拦截器
一、过滤器作用域浏览器到dispatch之间,在springMVC中,dispatchservlet接收到请求后,会对请求进行处理,根据当前请求信息跟请求映射requestMapping进行匹配,找到相对应的请求映射,请求映射对应的控制器方法就是处理请求的方法,所以dispatchservlet会去调用controller,拦截器作用于控制器执行前后。
二、SpringMVC中的拦截器用于拦截控制器方法的执行,需要实现HandlerInterceptor
拦截器的配置
一、新建springMVC-demo5
项目,在html页面测试拦截器:<a th:href="@{/testInterceptor}">测试拦截器</a><br>
二、SpringMVC的拦截器必须在SpringMVC的配置文件中的mvc:interceptors
标签中进行配置,该标签中可以写ref、bean、interceptor标签,前两个是一样的:
- 一个Bean代表IOC中一个组件、一个对象,在
mvc:interceptors
标签中配置bean标签,表示某一个类型的对象就是一个拦截器:<bean class="com.atguigu.mvc.interceptors.FirstInterceptor"></bean>
,但是像这样写会拦截所有的请求 - ref可以引用当前IOC容器中某个bean的ID,所以我们可以在ref标签中引用某个拦截器bean的id:
<ref bean="firstInterceptor"></ref>
,但是像这样写也会拦截所有的请求
@Component// 把拦截器交给IOC管理,通过标识组件的方式,将拦截器标识为一个bean
public class FirstInterceptor implements HandlerInterceptor {
// 控制器方法执行之前执行
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("FirstInterceptor-->preHandle");
return true;// 返回true表示放行,返回false表示拦截
}
// 控制器方法执行之后执行
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("FirstInterceptor-->postHandle");
}
// 在视图渲染之后执行
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("FirstInterceptor-->afterCompletion");
}
}
mvc:mapping
的path可以设置需要拦截的路径,/*
代表访问上下文路径下面的一层目录,即只拦截/a或/b或/c之类的一层目录。/**
标识拦截所有请求,不管是/a还是/c/b/a还是/v/a都会被拦截
mvc:exclude-mapping
的path可以设置需要排除的请求,即不需要拦截的请求,也就是说可以设置除了哪个路径不拦截,其余都拦截
配置了以上两个后,再使用ref或者bean标签指定拦截器
<mvc:interceptor>
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path="/"/>
<ref bean="firstInterceptor"></ref>
</mvc:interceptor>
三、SpringMVC中的拦截器有三个抽象方法:
- preHandle:控制器方法执行之前执行preHandle(),其boolean类型的返回值表示是否拦截或放行,返回true为放行,即调用控制器方法;返回false表示拦截,即不调用控制器方法
- postHandle:控制器方法执行之后执行postHandle()
- afterComplation:处理完视图和模型数据,渲染视图完毕之后执行afterComplation()
四、多个拦截器的执行顺序:
- 若每个拦截器的preHandle()都返回true,此时多个拦截器的执行顺序和拦截器在SpringMVC的配置文件的配置顺序有关:preHandle()会按照配置的顺序执行,而postHandle()和afterComplation()会按照配置的反序执行,例如在本文中新建两个拦截器:前述的
FirstInterceptor
、SecondInterceptor
,SecondInterceptor
是复制FirstInterceptor
的,然后在配置文件springMVC.xml
中配置两个拦截器,配置顺序为先FirstInterceptor
,后SecondInterceptor
,具体如下:
<ref bean="firstInterceptor"></ref>
<ref bean="secondInterceptor"></ref>
点击页面上的链接<a th:href="@{/testInterceptor}">测试拦截器</a><br>
后输出如下:
- 若某个拦截器的preHandle()返回了false,preHandle()返回false和它之前的拦截器的preHandle()都会执行,postHandle()都不执行,返回false的拦截器之前的拦截器的afterComplation()会执行
异常处理器
一、SpringMVC提供了一个处理控制器方法执行过程中所出现的异常的接口:HandlerExceptionResolver,该接口的实现类有:DefaultHandlerExceptionResolver(处理默认异常)和SimpleMappingExceptionResolver(处理自定义异常)
二、设置异常处理器的方法:使用配置设置、使用注解设置
基于配置的异常处理
点击页面链接<a th:href="@{/testExceptionHandler}">测试异常处理</a><br>
会访问/testExceptionHandler
,这个请求被dispatchServlet拦截到,进行以下处理:
@RequestMapping("/testExceptionHandler")
public String testExceptionHandler(){
System.out.println(1/0);
return "success";
}
控制器中出现异常,在springMVC.xml
中配置异常处理
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<!--一个prop标签就是一个键值对,key是要处理的异常的全类名,标签体就是value,是一个新的视图名称,出现异常后会跳转到这个新视图-->
<prop key="java.lang.ArithmeticException">error</prop>
</props>
</property>
<!--exceptionAttribute用于设置将异常信息共享在请求域中的键
value用来存储存储在当前请求域的异常信息的健,即value用来存储异常信息的键,这个键默认存储在当前请求域中,
异常信息就是值,我们在页面中可以通过这个键获取值-->
<property name="exceptionAttribute" value="ex"></property>
</bean>
展示error页面,在error页面中去请求域中获取ex键存储的异常信息:
<body>
出现错误
<p th:text="${ex}"></p>
</body>
基于注解的异常处理
将上一节在springMVC.xml
中配置的异常处理代码注释掉,新增控制器ExceptionController.java
,在其中配置异常处理:
@ControllerAdvice// 这个注解包含controller的功能
public class ExceptionController {
// value = {当前可能出现的异常的class}
@ExceptionHandler(value = {ArithmeticException.class, NullPointerException.class})
public String testException(Exception ex, Model model){// 在这里通过ex获取异常,通过model获取请求域
model.addAttribute("ex", ex);// 把异常添加到请求域
return "error";// 如果出现了上面@ExceptionHandler注解指定的异常,跳转到error页面
}
}
其余的和上一节一样
注解配置SpringMVC
一、使用配置类和注解代替web.xml和SpringMVC配置文件的功能
二、web.xml是当前web工程的描述符,每当启动tomcat服务器,加载的第一个配置文件就是web.xml,服务器有三大组件:servlet、filter、listener,这三个东西我们不用管,是由服务器自己去调用的,如果我们创建了一个类,这个类继承了AbstractAnnotationConfigDispatcherServletInitializer
,这个类会在我们服务器启动时自动执行、加载
三、在Servlet3.0环境中,容器会在类路径中查找实现javax.servlet.ServletContainerInitializer
接口的类,如果找到的话就用它来配置Servlet容器,也就是tomcat服务器。 Spring提供了这个接口的实现,名为SpringServletContainerInitializer
,这个类反过来又会查找实现WebApplicationInitializer
的类并将配置的任务交给它们来完成。Spring3.2引入了一个便利的WebApplicationInitializer
基础实现,名为AbstractAnnotationConfigDispatcherServletInitializer
,当我们的类扩展了AbstractAnnotationConfigDispatcherServletInitializer
并将其部署到Servlet3.0容器的时候,容器会自动发现它,并用它来配置Servlet上下文。
创建初始化类,代替web.xml
新建项目springMVC-annotation
,不用创建web.xml,新建src/main/java/com/atguigu/mvc/config/WebInit.java
文件,WebInit类继承AbstractAnnotationConfigDispatcherServletInitializer
类并重写他的方法
//web工程的初始化类,用来代替web.xml
public class WebInit extends AbstractAnnotationConfigDispatcherServletInitializer {
/**
* 指定spring的配置类
* @return
*/
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{SpringConfig.class};// 将spring的配置类放在数组中
}
/**
* 指定springMVC的配置类
* @return
*/
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{WebConfig.class};// 将springMVC的配置类放在数组中
}
/**
* 指定DispatcherServlet的映射规则,即url-pattern
* @return
*/
@Override
protected String[] getServletMappings() {
return new String[]{"/"};// 把要配置的url-pattern放在String[]数组中返回
}
/**
* 注册过滤器
* @return
*/
@Override
protected Filter[] getServletFilters() {
CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();// 创建一个过滤器对象
// 设置初始化参数
characterEncodingFilter.setEncoding("UTF-8");
characterEncodingFilter.setForceResponseEncoding(true);
HiddenHttpMethodFilter hiddenHttpMethodFilter = new HiddenHttpMethodFilter();
// 可以创建多个过滤器,然后将它们放在Filter[]数组中返回即可
return new Filter[]{characterEncodingFilter, hiddenHttpMethodFilter};
}
}
创建SpringConfig配置类,代替spring的配置文件
新建spring的配置类src/main/java/com/atguigu/mvc/config/SpringConfig.java
,代码如下
@Configuration// 标识这个类是配置类
public class SpringConfig {//ssm整合之后,spring的配置信息写在此类中}
创建WebConfig配置类,代替SpringMVC的配置文件
一、新建springMVC的配置类src/main/java/com/atguigu/mvc/config/WebConfig.java
来代替SpringMVC的配置文件,WebConfig需要完成以下功能:扫描组件、视图解析器、view-controller、default-servlet-handler、mvc注解驱动、文件上传解析器、异常处理、拦截器
二、创建拦截器:新建src/main/java/com/atguigu/mvc/interceptor/TestInterceptor.java
文件,代码如下:
public class TestInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("TestInterceptor-->preHandle");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {}
}
三、WebConfig.java
代码如下:
@Configuration//将当前类标识为一个配置类
@ComponentScan("com.atguigu.mvc.controller")//1、扫描组件
@EnableWebMvc//5、mvc注解驱动
public class WebConfig implements WebMvcConfigurer {
//4、default-servlet-handler
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();// 默认的servlet可用
}
//8、拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
TestInterceptor testInterceptor = new TestInterceptor();
// addPathPatterns添加拦截路径,用来配置拦截路径
registry.addInterceptor(testInterceptor).addPathPatterns("/**");
}
//3、view-controller
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/hello").setViewName("hello");
}
//6、文件上传解析器
@Bean// 加上这个注解,方法的返回值就是IOC容器的一个bean
public MultipartResolver multipartResolver(){
CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver();
return commonsMultipartResolver;
}
//7、异常处理
@Override
public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
SimpleMappingExceptionResolver exceptionResolver = new SimpleMappingExceptionResolver();
Properties prop = new Properties();
prop.setProperty("java.lang.ArithmeticException", "error");// 设置键值对
exceptionResolver.setExceptionMappings(prop);// 设置异常映射
exceptionResolver.setExceptionAttribute("exception");// 设置在请求域中共享的错误信息的键
resolvers.add(exceptionResolver);
}
//配置生成模板解析器
@Bean
public ITemplateResolver templateResolver() {
WebApplicationContext webApplicationContext = ContextLoader.getCurrentWebApplicationContext();
// ServletContextTemplateResolver需要一个ServletContext作为构造参数,可通过WebApplicationContext 的方法获得
ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(
webApplicationContext.getServletContext());
templateResolver.setPrefix("/WEB-INF/templates/");// 调用属性的set方法来为属性赋值
templateResolver.setSuffix(".html");
templateResolver.setCharacterEncoding("UTF-8");
templateResolver.setTemplateMode(TemplateMode.HTML);
return templateResolver;
}
//生成模板引擎并为模板引擎注入模板解析器
@Bean
public SpringTemplateEngine templateEngine(ITemplateResolver templateResolver) {
// 当前参数类型是什么,spring会在IOC容器中找到一个bean,来为我们当前的参数赋值,所以参数就相当于我们之前讲过的自动装配
// 所以形参必须是能进行自动装配的,必须是当前spring的IOC容器中所拥有的bean,这个bean能为这个参数赋值的情况下,我们才能加这个参数
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(templateResolver);
return templateEngine;
}
//生成视图解析器并未解析器注入模板引擎
// SpringTemplateEngine是上一个方法的返回值,所以有bean来为templateEngine参数赋值
@Bean
public ViewResolver viewResolver(SpringTemplateEngine templateEngine) {
ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
viewResolver.setCharacterEncoding("UTF-8");
viewResolver.setTemplateEngine(templateEngine);
return viewResolver;
}
}
测试功能
@RequestMapping("/")
public String index(){
return "index";
}
可正常访问页面
SpringMVC执行流程
SpringMVC常用组件
一、DispatcherServlet
:前端控制器,不需要工程师开发,由框架提供
作用:统一处理请求和响应,整个流程控制的中心,由它调用其它组件处理用户的请求
二、HandlerMapping
:处理器映射器,不需要工程师开发,由框架提供
作用:根据请求的url、method等信息查找Handler,即控制器方法,就是将请求与控制器方法进行映射
三、Handler
:处理器,需要工程师开发,即控制器
作用:在DispatcherServlet
的控制下Handler对具体的用户请求进行处理
四、HandlerAdapter
:处理器适配器,不需要工程师开发,由框架提供
作用:通过HandlerAdapter对处理器(控制器方法)进行执行,用来调用相对应的控制器方法
五、ViewResolver
:视图解析器,不需要工程师开发,由框架提供
作用:进行视图解析,得到相应的视图,例如:ThymeleafView
、InternalResourceView
、RedirectView
六、View
:视图
作用:将模型数据通过页面展示给用户
DispatcherServlet初始化过程
DispatcherServlet 本质上是一个 Servlet,所以天然的遵循 Servlet 的生命周期。所以宏观上是Servlet生命周期来进行调度。