900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > SpringMVC自定义拦截器与异常处理(自定义异常)

SpringMVC自定义拦截器与异常处理(自定义异常)

时间:2021-01-25 00:46:59

相关推荐

SpringMVC自定义拦截器与异常处理(自定义异常)

SpringMVC自定义拦截器与异常处理

拦截器概念

拦截器代码演示

创建maven工程

pom.xml

<?xml version="1.0" encoding="UTF-8"?><project xmlns="/POM/4.0.0" xmlns:xsi="/2001/XMLSchema-instance"xsi:schemaLocation="/POM/4.0.0 /xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>org.example</groupId><artifactId>day02_SpringMVC_Interceptor</artifactId><version>1.0-SNAPSHOT</version><packaging>war</packaging><!-- 版本锁定--><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><piler.source>1.8</piler.source><piler.target>1.8</piler.target><spring.version>5.1.9.RELEASE</spring.version></properties><dependencies><!-- spring--><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-web</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>${spring.version}</version></dependency><!-- servlet3.0规范的坐标 --><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>3.1.0</version><scope>provided</scope></dependency><!--jsp坐标--><dependency><groupId>javax.servlet.jsp</groupId><artifactId>jsp-api</artifactId><version>2.1</version><scope>provided</scope></dependency><!-- lombok--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.12</version></dependency><!--json相关坐标3个--><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId><version>2.9.0</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.9.0</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-annotations</artifactId><version>2.9.0</version></dependency></dependencies><build><plugins><!--tomcat插件--><plugin><groupId>org.apache.tomcat.maven</groupId><artifactId>tomcat7-maven-plugin</artifactId><version>2.2</version><configuration><port>80</port><path>/</path><!--配置tomcat插件编码,因为请求的数据会经过tomcat.所以在tomcat也要设置一下编码--><uriEncoding>UTF-8</uriEncoding></configuration></plugin></plugins></build></project>

web.xml

<?xml version="1.0" encoding="UTF-8"?><web-app xmlns="/xml/ns/javaee"xmlns:xsi="/2001/XMLSchema-instance"xsi:schemaLocation="/xml/ns/javaee/xml/ns/javaee/web-app_3_0.xsd"version="3.0"><!--springMVC程序启动流程1.tomcat启动首先加载web.xml2.保证DispatcherServlet能够正常加载配置文件3.spring配置文件必须扫描有spring注解的的包--><!-- 配置调度服务器(前端控制器),配置后就能够去调度controller中的路径--><servlet><servlet-name>dispatcherServlet</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><!-- 初始化DispatcherServlet,初始化springIOC容器,读取类路径下的spring-mvc.xml配置文件(target/classes/就会有这个配置文件),扫描controller注解下的RequestMapping的路径--><param-name>contextConfigLocation</param-name><!-- <param-value>classpath:spring-mvc.xml</param-value>--><param-value>classpath:spring-mvc.xml</param-value></init-param><!-- 配置load-on-startup元素表示这个servlet应该是在启动时加载(实例化并调用其init())的web应用程序。--><load-on-startup>1</load-on-startup></servlet><!--配置请求调度服务--><servlet-mapping><!-- 配置调度服务--><servlet-name>dispatcherServlet</servlet-name><!--在spring中, / /*/ : 匹配所有的请求/* :匹配所有的请求,查询结果页面,都是以文本显示,不会做任何的渲染页面,包括jsp页面--><url-pattern>/</url-pattern></servlet-mapping><!--配置过滤器,来解决post请求乱码问题--><filter><filter-name>characterEncodingFilter</filter-name><!-- 加载spring提供的过滤器--><filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class><!--设置过滤器中的属性值--><init-param><param-name>encoding</param-name><param-value>UTF-8</param-value></init-param><!--启动过滤器--><init-param><param-name>forceEncoding</param-name><param-value>true</param-value></init-param></filter><!--过滤所有请求--><filter-mapping><filter-name>characterEncodingFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping></web-app>

spring-mvc.xml

注意在核心配置文件中配置自定义拦截器的bean

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="/schema/beans"xmlns:xsi="/2001/XMLSchema-instance"xmlns:context="/schema/context"xmlns:mvc="/schema/mvc"xsi:schemaLocation="/schema/beans /schema/beans/spring-beans.xsd /schema/context /schema/context/spring-context.xsd /schema/mvc /schema/mvc/spring-mvc.xsd"><!-- 设置扫描spring注解的包--><context:component-scan base-package="com.fs.springmvc"/><!-- 静态资源加载,核心控制器拦截的是所有请求,需要对静态资源请求进行放行,通过配置放行资源实现下面这个配置是可以放行所有的普通资源调用让springMVC不处理静态资源,如 .css .js .html .MP3 等--><mvc:default-servlet-handler/><!-- 配置注解驱动的Spring MVC控制器编程模型.一、mvc:annotation-driven的作用Spring 3.0.x中使用了mvc:annotation-driven后,默认会帮我们注册默认处理请求,参数和返回值的类,其中最主要的两个类:DefaultAnnotationHandlerMapping 和 AnnotationMethodHandlerAdapter ,分别为HandlerMapping的实现类和HandlerAdapter的实现类,从3.1.x版本开始对应实现类改为了RequestMappingHandlerMapping和RequestMappingHandlerAdapter。HandlerMapping的实现类的作用实现类RequestMappingHandlerMapping,它会处理@RequestMapping 注解,并将其注册到请求映射表中。HandlerAdapter的实现类的作用实现类RequestMappingHandlerAdapter,则是处理请求的适配器,确定调用哪个类的哪个方法,并且构造方法参数,返回值。当配置了mvc:annotation-driven/后,Spring就知道了我们启用注解驱动。然后Spring通过context:component-scan/标签的配置,会自动为我们将扫描到的@Component,@Controller,@Service,@Repository等注解标记的组件注册到工厂中,来处理我们的请求。--><mvc:annotation-driven/><!-- 配置视图解析器,方便访问jsp页面,并交给spring管理--><bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"><!-- 视图解析前缀(访问前缀)--><property name="prefix" value="/WEB-INF/pages/"/><!-- 视图解析后缀(访问后缀)--><property name="suffix" value=".jsp"/></bean><!--开启拦截器使用--><mvc:interceptors><!--开启具体的拦截器的使用,可以配置多个--><mvc:interceptor><!--设置拦截器的拦截路径,支持*通配--><!--/** 表示拦截所有映射--><!--/*表示拦截所有/开头的映射--><!--/user/*表示拦截所有/user/开头的映射--><!--/user/add* 表示拦截所有/user/开头,且具体映射名称以add开头的映射--><!--/user/*All 表示拦截所有/user/开头,且具体映射名称以All结尾的映射--><mvc:mapping path="/*"/><mvc:mapping path="/**"/><mvc:mapping path="/handleRun*"/><!--设置拦截排除的路径(配置不拦截的路径),配置/**或/*,达到快速配置的目的--><mvc:exclude-mapping path="/b*"/><!--指定具体的拦截器类--><bean class="com.fs.springmvc.interceptor.MyInterceptor"/></mvc:interceptor><!--配置多个拦截器,配置顺序即为最终运行顺序--><mvc:interceptor><mvc:mapping path="/*"/><bean class="com.fs.springmvc.interceptor.MyInterceptor2"/></mvc:interceptor><mvc:interceptor><mvc:mapping path="/*"/><bean class="com.fs.springmvc.interceptor.MyInterceptor3"/></mvc:interceptor></mvc:interceptors></beans>

创建自定义拦截器类(代码中注释有详细解释)

MyInterceptor

package com.fs.springmvc.interceptor;/*拦截器与过滤器有什么不同Interceptor拦截器是SpringMVC的技术,拦截控制的controller,拦截springIOC中的controllerfilter过滤器是tomcat中所有的接收到的请求都可以被拦截,包括spring中的controller//三个方法的运行顺序为 preHandle -> controller中被拦截的方法执行 ->postHandle -> afterCompletion//如果preHandle返回值为false,三个方法仅运行preHandle由HandlerInterceptor接口源码得知,方法被default修饰了(java8新特性)被默认实现了方法的,所以我们自定义拦截器没有强制我们重写接口中的方法所以我们需要自己重写接口中的方法实现自定义拦截器的具体功能HandlerInterceptor接口源码public interface HandlerInterceptor {default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {return true;}default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {}default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {}}*/import org.springframework.web.servlet.HandlerInterceptor;import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;//自定义拦截器需要实现HandleInterceptor接口,实现这个接口没有被强制现实所有方法//是因为HandlerInterceptor接口中的方法有默认的default实现方法,所以我们需要自己重写接口中的方法public class MyInterceptor implements HandlerInterceptor {//处理器运行之前执行@Overridepublic boolean preHandle(HttpServletRequest request,//请求携带的requestHttpServletResponse response,//响应携带的Response//handler就是我们执行的controller方法路径Object handler) throws Exception {//下面打印的就是我们自己写的controller的方法,使用反射技术//public java.lang.String com.fs.springmvc.controller.InterceptorController.handleRun()///System.out.println(handler.toString());System.out.println("前置运行----a1");//返回值为false将拦截原始处理器的运行,访问的controller中的方法不会被执行,//而且后面的postHandle,afterCompletion也不会执行//如果配置多拦截器,返回值为false将终止当前拦截器后面配置的拦截器的运行return true;}//处理器运行之后执行@Overridepublic void postHandle(HttpServletRequest request,HttpServletResponse response,Object handler,//controller执行方法后要返回的视图ModelAndViewModelAndView modelAndView) throws Exception {System.out.println("后置运行----b1");}//所有拦截器的后置执行全部结束后,执行该操作@Overridepublic void afterCompletion(HttpServletRequest request,HttpServletResponse response,Object handler,//Exception ex) throws Exception {System.out.println("完成运行----c1");}//三个方法的运行顺序为 preHandle -> postHandle -> afterCompletion//如果preHandle返回值为false,三个方法仅运行preHandle}

MyInterceptor2

package com.fs.springmvc.interceptor;import org.springframework.web.servlet.HandlerInterceptor;import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class MyInterceptor2 implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request,HttpServletResponse response,Object handler) throws Exception {System.out.println("前置运行------a2");return true;}@Overridepublic void postHandle(HttpServletRequest request,HttpServletResponse response,Object handler,ModelAndView modelAndView) throws Exception {System.out.println("后置运行------b2");}@Overridepublic void afterCompletion(HttpServletRequest request,HttpServletResponse response,Object handler,Exception ex) throws Exception {System.out.println("完成运行------c2");}}

MyInterceptor3

package com.fs.springmvc.interceptor;import org.springframework.web.servlet.HandlerInterceptor;import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class MyInterceptor3 implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request,HttpServletResponse response,Object handler) throws Exception {System.out.println("前置运行--------a3");return true;}@Overridepublic void postHandle(HttpServletRequest request,HttpServletResponse response,Object handler,ModelAndView modelAndView) throws Exception {System.out.println("后置运行--------b3");}@Overridepublic void afterCompletion(HttpServletRequest request,HttpServletResponse response,Object handler,Exception ex) throws Exception {System.out.println("完成运行--------c3");}}

controller

InterceptorController

package com.fs.springmvc.controller;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.servlet.config.annotation.EnableWebMvc;//@Controllerpublic class InterceptorController {@RequestMapping("/handleRun")public String handleRun() {System.out.println("controller业务处理器运行------------main");return "page";}}

测试

输入地址访问:

控制台输出

拦截器执行流程

拦截器参数

核心配置文件中关于拦截器的配置

拦截器链配置

异常处理

我们在controller中调用业务层出现了异常,我们不可能给前端响应一大堆异常信息,所以,我们需要将我们的异常进行封装返回给前端,然后前端对异常进行友好的提示告知客户

HandlerExceptionResolver接口方式(异常处理器)

package com.fs.springmvc.exception;import org.ponent;import org.springframework.web.servlet.HandlerExceptionResolver;import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;/*自定义异常类,必须实现异常处理程序解析器HandlerExceptionResolver接口,重写resolveException()方法自定义异常类(全局(IOC类)异常管理)@Component注解后spring发现这个类实现了HandlerExceptionResolver接口,就认定为异常处理的类,然后就会对所有的IOC管理的对象的方法进行异常处理,当IOC管理的类的方法执行出现异常了,就会到达异常处理类的resolveException()方法,执行里面的异常处理逻辑使用自定义异常类处理异常是在controller的方法加载参数后才会加载这个类,就会导致前端传递参数的时候,SpringMVC将前端传递过来参数封装到方法的参数的时候出现类型转换异常,就不会对这个异常进行处理所以争对这个问题,出现了注解方式处理异常.注解处理器就可以拦截Dao入参类型转换异常*/@Componentpublic class ExceptionResolver implements HandlerExceptionResolver {@Overridepublic ModelAndView resolveException(HttpServletRequest request,HttpServletResponse response,Object handler,Exception ex) {System.out.println("自定义异常类正在运行 ...."+ex);ModelAndView modelAndView = new ModelAndView();//对异常类型进行判断使用instanceof关键字if( ex instanceof NullPointerException){//将异常数据返回给前端modelAndView.addObject("msg","空指针异常");}else if ( ex instanceof ArithmeticException){//将异常数据返回给前端modelAndView.addObject("msg","算数运算异常");}else{//将异常数据返回给前端modelAndView.addObject("msg","未知的异常");}//然后跳转到异常页面展示modelAndView.setViewName("error.jsp");return modelAndView;}}

@ControllerAdvice注解实现异常分类管理@ExceptionHandler(常用方式)

**注意:**要在核心配置文件中添加==< mvc:annotation-driven/>mvc的注解支持==

两种异常推荐使用注解,因为注解可以拦截到入参类型转换异常

注解代码

package com.fs.springmvc.exception;import com.fs.springmvc.domain.ResultMapper;import com.fs.springmvc.domain.User;import org.ponent;import org.springframework.web.bind.annotation.ControllerAdvice;import org.springframework.web.bind.annotation.ExceptionHandler;import org.springframework.web.bind.annotation.ResponseBody;/*注解的方式处理异常(常用)@ControllerAdvice声明该类是一个Controller的通知类,声明后该类就会被加载成异常处理器使用注解异常处理器就可以拦截到入参类型转换异常而非注解(实现HandlerExceptionResolver接口)就无法拦截到入参类型转换异常*/@Component//使用注解开发异常处理器//声明该类是一个Controller的通知类,声明后该类就会被加载成异常处理器@ControllerAdvicepublic class ExceptionAdvice {/*//类中定义的方法携带@ExceptionHandler注解的会被作为异常处理器,后面添加实际处理的异常类型@ExceptionHandler(NullPointerException.class)@ResponseBodypublic String doNullException(Exception ex){return "空指针异常";}@ExceptionHandler(ArithmeticException.class)@ResponseBodypublic String doArithmeticException(Exception ex){return "ArithmeticException";}//处理大异常@ExceptionHandler(Exception.class)@ResponseBodypublic String doException(Exception ex){return "all";}*//*一般处理一个大异常就行了*///处理大异常,返回结果集对象,以json返回@ExceptionHandler(Exception.class)@ResponseBodypublic ResultMapper doExceptionTo(Exception ex){//给返回的结果集的数据准备User user = new User();user.setName("小付");user.setAge(18);ResultMapper resultMapper = new ResultMapper(500,false,"服务器繁忙~",user);return resultMapper;}//处理自定义异常,返回结果集对象,以json返回@ExceptionHandler(BusinessException.class)@ResponseBodypublic ResultMapper doExceptionToBusinessException(BusinessException ex){//给返回的结果集的数据准备User user = new User();user.setName("小花");user.setAge(18);ResultMapper resultMapper = new ResultMapper(500,false,ex.getMessage(),user);return resultMapper;}}

ResultMapper对返回的结果进行封装

package com.fs.springmvc.domain;import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;/*返回的结果对象*/@Data@NoArgsConstructor@AllArgsConstructorpublic class ResultMapper<T> {//状态码private Integer code;//是否成功private Boolean flag;//返回消息private String message;//返回的数据private T data;}

自定义异常

自定义异常BusinessException

package com.fs.springmvc.exception;//自定义异常继承RuntimeException,覆盖父类所有的构造方法public class BusinessException extends RuntimeException {public BusinessException() {}public BusinessException(String message) {super(message);}public BusinessException(String message, Throwable cause) {super(message, cause);}public BusinessException(Throwable cause) {super(cause);}public BusinessException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {super(message, cause, enableSuppression, writableStackTrace);}}

controller中一个请求方法模拟异常来测试我们的异常代码

package com.fs.springmvc.controller;import com.fs.springmvc.domain.User;import com.fs.springmvc.exception.BusinessException;import com.fs.springmvc.exception.SystemException;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestBody;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.ResponseBody;import java.util.ArrayList;import java.util.List;@Controllerpublic class UserController {@RequestMapping("/save")@ResponseBodypublic List<User> save(@RequestBody User user) {System.out.println("user controller save is running ...");//抛出自定义的异常throw new BusinessException("请勿连续刷新页面,谢谢~~");}// @RequestMapping("/save")// @ResponseBody// public List<User> save(@RequestBody User user) {// System.out.println("user controller save is running ...");//模拟业务层发起调用产生了异常// int i = 1/0;// String str = null;// str.length();//对用户的非法操作进行判定,并包装成异常对象进行处理,便于统一管理// if(user.getName().trim().length() < 8){// throw new BusinessException("对不起,用户名长度不满足要求,请重新输入!");// }// if(user.getAge() < 0){// throw new BusinessException("对不起,年龄必须是0到100之间的数字!");// }// if(user.getAge() > 100){// throw new SystemException("服务器连接失败,请尽快检查处理!");// }// User u1 = new User();// u1.setName("Tom");// u1.setAge(3);// User u2 = new User();// u2.setName("Jerry");// u2.setAge(5);// ArrayList<User> al = new ArrayList<User>();// al.add(u1);// al.add(u2);//// return al;// }}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。