【SpringMVC拦截器】

拦截器

一、过滤器作用域浏览器到dispatch之间,在springMVC中,dispatchservlet接收到请求后,会对请求进行处理,根据当前请求信息跟请求映射requestMapping进行匹配,找到相对应的请求映射,请求映射对应的控制器方法就是处理请求的方法,所以dispatchservlet会去调用controller,拦截器作用于控制器执行前后。
二、SpringMVC中的拦截器用于拦截控制器方法的执行,需要实现HandlerInterceptor

拦截器的配置

一、新建springMVC-demo5项目,在html页面测试拦截器:<a th:href="@{/testInterceptor}">测试拦截器</a><br>
二、SpringMVC的拦截器必须在SpringMVC的配置文件中的mvc:interceptors标签中进行配置,该标签中可以写ref、bean、interceptor标签,前两个是一样的:

  1. 一个Bean代表IOC中一个组件、一个对象,在mvc:interceptors标签中配置bean标签,表示某一个类型的对象就是一个拦截器:<bean class="com.atguigu.mvc.interceptors.FirstInterceptor"></bean>,但是像这样写会拦截所有的请求
  2. 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");
    }
}
  1. 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中的拦截器有三个抽象方法:

  1. preHandle:控制器方法执行之前执行preHandle(),其boolean类型的返回值表示是否拦截或放行,返回true为放行,即调用控制器方法;返回false表示拦截,即不调用控制器方法
  2. postHandle:控制器方法执行之后执行postHandle()
  3. afterComplation:处理完视图和模型数据,渲染视图完毕之后执行afterComplation()

四、多个拦截器的执行顺序:

  1. 若每个拦截器的preHandle()都返回true,此时多个拦截器的执行顺序和拦截器在SpringMVC的配置文件的配置顺序有关:preHandle()会按照配置的顺序执行,而postHandle()和afterComplation()会按照配置的反序执行,例如在本文中新建两个拦截器:前述的FirstInterceptorSecondInterceptorSecondInterceptor是复制FirstInterceptor的,然后在配置文件springMVC.xml中配置两个拦截器,配置顺序为先FirstInterceptor,后SecondInterceptor,具体如下:
<ref bean="firstInterceptor"></ref>
<ref bean="secondInterceptor"></ref>

点击页面上的链接<a th:href="@{/testInterceptor}">测试拦截器</a><br>后输出如下:
在这里插入图片描述

  1. 若某个拦截器的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:视图解析器,不需要工程师开发,由框架提供
作用:进行视图解析,得到相应的视图,例如:ThymeleafViewInternalResourceViewRedirectView
六、View:视图
作用:将模型数据通过页面展示给用户

DispatcherServlet初始化过程

DispatcherServlet 本质上是一个 Servlet,所以天然的遵循 Servlet 的生命周期。所以宏观上是Servlet生命周期来进行调度。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值