- Filter即为过滤,用于在Servlet之外对Request或者Response进行修改。它主要用于对用户请求进行预处理,也可以对HttpServletResponse进行后处理。使用Fiter的完整流程:
Filter对用户请求进行预处理,接着将请求交给Servlet进行处理并生成响应,最后Filter再对服务器响应进行后处理。
在一个web应用中,可以开发编写多个Filter,这些Filter组合起来称之为一个Fiter链。
若是一个过滤器链:先配置先执行(请求时的执行顺序);响应时:以相反的顺序执行。
在HttpServletRequest 到达 Servlet之前,拦截客户的HttpServletRequest。根据需要检查 HttpServletRequest,也可以修改HttpServletRequest头和数据。
在HttpServletResponse到达客户端之前,拦截HttpServletResponse,根据需要检查 HttpServletResponse,也可以修改HttpServletResponse头和数据。
- 可以通过实现一个叫做
javax.servlet.Fileter
的接口来实现一个过滤器,其中定义了三个方法,inito() , doFilter(), destroy()
分别在相应的时机执行。后期观察生命周期。- Filter的实现只需要两步:
- step1:编写java类实现Fiter接口,并实现其
doFiter
方法。- Step2:通过
@WebFilter
注解设置它所能拦截的资源。
package com.liu.filter; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import java.io.IOException; /** * @author lms * @date 2021-09-25 - 15:02 */ // /* 表示拦截所有的请求 @WebFilter("/*") public class Filter03 implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { // 业务逻辑的过滤操作 // 选择性放行,否则请求无法到达处理器 filterChain.doFilter(servletRequest, servletResponse); } @Override public void destroy() { } }
package com.liu.servlet; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * @author lms * @date 2021-09-25 - 15:08 */ //表示 "/ser01" 的请求将会由当前的这个处理器进行处理请求服务 //@WebServlet("/ser01") public class Servlet01 extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("ser01正在被处理请求信息。。。。。。。。。。"); } }
目标:
只有当用户登录之后,才能访问其他的资源信息,非法访问直接跳转至登录页面。
package com.liu.filter; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * @author lms * @date 2021-09-25 - 17:25 * * 过滤器实现的登录拦截: * * 模拟登录拦截器:用户未登录,禁止访问指定的资源 * 非法访问拦截: * 拦截的资源: 拦截所有的资源 /* * 需要放行的资源: * 1.指定页面进行放行(无需登录就可以访问的页面,例如:登录页面,注册页面等) * 2.静态资源需要放行(比如:images,js,css文件) * 3.指定操作,放行(无需登录即可执行的操作,例如:登录操作,注册操作) * 4.如果当前是登录状态,放行(通过判断session中的用户信息是否为空) * * 如果上面的状态都不执行,就拦截让其重定向到登录页面 */ //拦截所有的请求路径 @WebFilter("/*") public class LoginFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } // 在这里设置需要被放行的路径信息(即不同登录也可以访问的资源/页面) @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { // 基于http请求 HttpServletRequest request = (HttpServletRequest) servletRequest; HttpServletResponse response = (HttpServletResponse) servletResponse; // 获取用户访问的路径 String uri = request.getRequestURI(); System.out.println("uri = " + uri); // 1.指定页面进行放行(无需登录就可以访问的页面,例如:登录页面,注册页面等) if (uri.contains("/login.jsp")){ filterChain.doFilter(request, response); return; } // 2.静态资源需要放行(比如:images,js,css文件) if (uri.contains("/js") || uri.contains("/css") || uri.contains("/images")){ filterChain.doFilter(request, response); return; } // 3.指定操作,放行(无需登录即可执行的操作,例如:登录操作,注册操作) if (uri.contains("/login")){ filterChain.doFilter(request, response); return; } // 4.是登录状态,放行(判断session中的用户信息是否为空) // 从session中获取保存的域对象信息 String user = (String) request.getSession().getAttribute("user"); // 判断user对象是否为空,不为空,这说明已经是登录状态,则放行 if (user != null){ filterChain.doFilter(request, response); return; } // 当用户未登录时,所有的非法访问拦截请求都会被重定向跳转到登录页面,登录之后才能访问其他资源 response.sendRedirect("login.jsp"); } @Override public void destroy() { } }
package com.liu.servlet; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * @author lms * @date 2021-09-25 - 17:30 * 处理用户请求 */ @WebServlet("/login") public class LoginServlet extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("用户登录中............."); String name = req.getParameter("name"); System.out.println("name = " + name); // 此时在登录页面,如果登录的用户是admin,则表示登录成功,重定向至登录成功的页面,否则登陆失败,请求转发到登录页面 if ("admin".equals(name)){ req.getSession().setAttribute("user", name); // 重定向到首页 resp.sendRedirect("index.jsp"); }else { // 转发到登录页面 req.getRequestDispatcher("login.jsp").forward(req, resp); } } }
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>首页</title> </head> <body> <h3>${user}, 登录成功</h3> </body> </html>
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>登录</title> <script type="text/javascript" src="js/jquery-3.4.1.js"></script> <script type="text/javascript"> // 判断用户名是否为空 function login() { var name = $("#name").val(); console.log(name); if (name != null && name.trim() != ''){ // 用户名不为空,则进行表单提交,提交到指定的路径上 $("#formData").submit(); } } </script> </head> <body> <form action="login" id="formData"> 用户名: <input type="text" name="name" id="name"><br> <button type="button" onclick="login()">登录</button> </form> </body> </html>
- Web 监听器是Servlet中一种的特殊的类,能帮助开发者监听web中的特定事件,比如
ServletContext,HttpSession,ServletRequest
的创建和销毁;变量的创建、销毁和修改等。可以在某些动作前后增加处理,实现监控。例如可以用来统计在线人数等
。
- 常用的监听器(监听生命周期)
ServletRequestListener
HttpSessionListener
ServletContextListener
package com.liu.listener; import javax.servlet.annotation.WebListener; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; /** * @author lms * @date 2021-09-25 - 16:27 * 开启监听器,并设置监听的对象 */ @WebListener public class Listener01 implements HttpSessionListener { @Override public void sessionCreated(HttpSessionEvent httpSessionEvent) { System.out.println("监听器被创建了。。。。。。。。。"); } @Override public void sessionDestroyed(HttpSessionEvent httpSessionEvent) { System.out.println("监听器被销毁了。。。。。。。。。"); } }
package com.liu.servlet; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.io.IOException; /** * @author lms * @date 2021-09-25 - 16:29 */ //创建session @WebServlet("/ser01") public class Servlet01 extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("servlet01 被调用了......"); // 创建session HttpSession session = req.getSession(); } }
package com.liu.servlet; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * @author lms * @date 2021-09-25 - 16:31 */ //销毁session @WebServlet("/ser02") public class Servlet02 extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("servlet02 被调用了......"); // 将session设置为过期 req.getSession().invalidate(); } }
package com.liu.listener; import javax.servlet.annotation.WebListener; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; /** * @author lms * @date 2021-09-25 - 16:48 * 实现在线人数的统计 */ @WebListener public class OnlineListener implements HttpSessionListener { // 记录在线的人数统计 private Integer onlineNum = 0; // 通过判断session的创建和销毁来判断人数登录和退出的统计 // 登录 @Override public void sessionCreated(HttpSessionEvent httpSessionEvent) { onlineNum++; // 为了让别的地方能够获取到onlineNum对象,将其设置在session域对象中 // session的作用域比较小,得让所有的浏览器都能看到互相的改变,所以设置在更大的作用域Context中 // HttpSession session = httpSessionEvent.getSession(); // session.setAttribute("onlineNum", onlineNum); httpSessionEvent.getSession().getServletContext().setAttribute("onlineNum", onlineNum); } // 退出 @Override public void sessionDestroyed(HttpSessionEvent httpSessionEvent) { onlineNum--; // 为了让别的地方能够获取到onlineNum对象,将其设置在session域对象中 // HttpSession session = httpSessionEvent.getSession(); // session.setAttribute("onlineNum", onlineNum); // 理由同上 httpSessionEvent.getSession().getServletContext().setAttribute("onlineNum", onlineNum); } }
package com.liu.servlet; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.io.IOException; /** * @author lms * @date 2021-09-25 - 16:52 */ @WebServlet("/online") public class OnlineServlet extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 设置字符编码格式 resp.setContentType("text/html;charset=UTF-8"); // 通过session获取当前在线的人数 HttpSession session = req.getSession(); // 退出的人数 String key = req.getParameter("key"); if (key != null && "logout".equalsIgnoreCase(key)){ session.invalidate(); return; } // 登录 Integer onlineNum = (Integer) session.getServletContext().getAttribute("onlineNum"); // 通过响应流字符流将在线人数输出到页面显示 // 如果online请求携带有参数,则表示退出的操作,没有携带为登录操作 resp.getWriter().write("<h3>当前在线的人数为: " + onlineNum + "</h3><br>" + "<a href='online?key=logout'>退出</a>"); } }
- SpringMVC中的Interceptor拦截器也是相当重要和相当有用的,它的
主要作用是拦截用户的请求并进行相应的处理
。比如通过它来进行权限验证,或者是来判断用户是否登陆等操作。原理:和过滤器原理相同
- 对于SpringMVC拦截器的定义方式有两种:
实现接口
:org.springframework.web.servlet.HandlerInterceptor
继承适配器
:org.springframework.web.servlet.handler.HandlerInterceptorAdapter
其间接实现了HandlerInterceptor接口
public interface HandlerInterceptor { default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // true: 表示允许目标方法(handler)(类似于过滤器的放行操作) // false:禁止目标方法的执行 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 { } }
- public abstract class HandlerInterceptorAdapter implements AsyncHandlerInterceptor - public interface AsyncHandlerInterceptor extends HandlerInterceptor
HandlerInterceptor
接口package com.liu.springmvc.interceptor; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * @author lms * @date 2021-09-25 - 19:36 * 实现拦截器HandlerInterceptor的接口,并重写3个方法 */ public class MyInterceptor01 implements HandlerInterceptor { /** * 在目标(handler)方法执行前 执行 * @param request * @param response * @param handler * @return true:执行handler(目标)方法,也就是放行 * false:禁止目标方法的执行 * @throws Exception */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("MyInterceptor01 ==> 目标方法之前执行了 ---> preHandle........"); 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........"); } }
web.xml
<!-- 配置拦截器,方式一:拦截所有的请求,表示哪些路径下的请求会被拦截--> <mvc:interceptors> <!-- 使用bean标签定义一个Interceptor拦截器 如果直接定义在mvc:interceptors标签中,表示项目下的所有的请求都会被拦截器进行拦截,等价于 /* --> <bean class="com.liu.springmvc.interceptor.MyInterceptor01"/> </mvc:interceptors>
<!-- 配置拦截器:方式二:拦截部分请求,放行部分请求 --> <mvc:interceptors> <!-- 在标签<mvc:interceptor>中,可以自定义需要被拦截和不被拦截的请求 可以定义多个拦截器 如果有多个拦截器,则会根据配置的先后顺序来执行 --> <mvc:interceptor> <!-- 通过<mvc:mapping标签配置需要被拦截的资源,支持通配符,可以配置多个 --> <!-- path="/**" 表示拦截所有的请求 --> <mvc:mapping path="/**"/> <!-- 通过<mvc:exclude-mapping标签配置不需要拦截的资源,支持通配符,可配置多个 --> <!-- path="/model/*" 表示model下的所有请求 --> <mvc:exclude-mapping path="/model/*"/> <bean class="com.liu.springmvc.interceptor.MyInterceptor01"/> </mvc:interceptor> </mvc:interceptors>
package com.liu.springmvc.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; /** * @author lms * @date 2021-09-25 - 9:23 */ @Controller public class HelloController { @RequestMapping("/hello") public ModelAndView hello(){ // 模拟异常(全局异常处理) // int i = 1 / 0; // 抛出自定义的异常信息 // if (1 == 1){ // // 参数异常 throw new ParamsException(); // // 业务异常 // throw new BusinessException(); // } System.out.println("hello请求被拦截了........."); ModelAndView modelAndView = new ModelAndView(); // 设置数据信息 modelAndView.addObject("name", "zhangsan"); // 设置跳转的视图 modelAndView.setViewName("hello"); return modelAndView; } }
package com.liu.springmvc.controller; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import java.util.Map; /** * @author lms * @date 2021-09-25 - 11:40 * * 请求域对象的设置方式(五种): * */ @Controller @RequestMapping("model") public class ModelController { /** * ModelAndView设置域对象 * @return */ @RequestMapping("/test01") public ModelAndView test01(){ ModelAndView modelAndView = new ModelAndView(); // 设置请求域对象 modelAndView.addObject("name", "hello model-1"); // 设置视图 modelAndView.setViewName("hello"); return modelAndView; } /** * Model设置域对象 * @return */ @RequestMapping("/test02") public String test02(Model model){ // 设置请求域对象 model.addAttribute("name", "hello model-2"); // 设置视图 return "hello"; } /** * ModelMap设置域对象 * @return */ @RequestMapping("/test03") public String test03(ModelMap model){ // 设置请求域对象 model.addAttribute("name", "hello model-3"); // 设置视图 return "hello"; } /** * ModelMap设置域对象 * @return */ @RequestMapping("/test04") public String test04(Map model){ // 设置请求域对象 model.put("name", "hello model-4"); // 设置视图 return "hello"; } /** * ModelMap设置域对象 * @return */ @RequestMapping("/test05") public String test05(HttpServletRequest request){ // 设置请求域对象 request.setAttribute("name", "hello model-5"); // 设置视图 return "hello"; } }
HandlerInterceptorAdapter
package com.liu.springmvc.interceptor; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * @author lms * @date 2021-09-25 - 20:33 */ public class MyInterceptor02 extends HandlerInterceptorAdapter { /** * 在目标方法(handler)执行前 执行 * * @param request * @param response * @param handler * @return true:执行handler(目标)方法,也就是放行 * false:禁止目标方法的执行 * @throws Exception */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("MyInterceptor02 ==> 目标方法执行之前执行了 ---> preHandle........"); return true; } }
配置拦截器
方式1
<mvc:interceptors> <mvc:interceptor> <!-- 被拦截的请求 --> <mvc:mapping path="/**"/> <!-- 拦截器不拦截的请求(放行的请求) --> <mvc:exclude-mapping path="/model/test01"/> <mvc:exclude-mapping path="/model/test02"/> <!-- 使用的拦截器 --> <bean class="com.liu.springmvc.interceptor.MyInterceptor02"/> </mvc:interceptor> </mvc:interceptors>
<mvc:interceptors> <!-- 拦截所有的请求,拦截器链(多个拦截器构成)按照先后的顺序执行拦截操作 先配置的拦截器的preHandler()方法先执行 先配置的拦截器的postHandler(),afterCompletion()方法后执行 --> <mvc:interceptor> <mvc:mapping path="/**"/> <bean class="com.liu.springmvc.interceptor.MyInterceptor01"/> </mvc:interceptor> <mvc:interceptor> <mvc:mapping path="/**"/> <!-- MyInterceptor02 在下面 --> <bean class="com.liu.springmvc.interceptor.MyInterceptor02"/> </mvc:interceptor> </mvc:interceptors>
- 使用拦截器完成用户是否登录的请求验证功能
- 注意:当前的模拟登陆是直接通过在地址栏中输入:
http://localhost:8080/项目名/userInfo/login
package com.liu.springmvc.controller; import com.liu.springmvc.bean.User; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpSession; /** * @author lms * @date 2021-09-25 - 21:26 * 非法请求拦截的模拟实现 * login:登录不拦截(不需要登录即可访问) * add: 未登录就拦截(访问前需要登录) * update:未登录就拦截(访问前需要登录) */ @Controller @RequestMapping("userInfo") public class LoginController { @RequestMapping("login") public ModelAndView login(HttpSession session) { ModelAndView modelAndView = new ModelAndView(); User user = new User(); user.setId(1); user.setName("admin"); user.setAge(20); // 将当前登录用户的信息设置在session中 session.setAttribute("user", user); modelAndView.setViewName("success"); return modelAndView; } @RequestMapping("add") public ModelAndView add() { ModelAndView modelAndView = new ModelAndView(); modelAndView.setViewName("success"); return modelAndView; } @RequestMapping("update") public ModelAndView update() { ModelAndView modelAndView = new ModelAndView(); modelAndView.setViewName("success"); return modelAndView; } }
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <h3>登录成功!</h3> </body> </html>
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <h3>登录页面!</h3> </body> </html>
package com.liu.springmvc.interceptor; import com.liu.springmvc.bean.User; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * @author lms * @date 2021-09-25 - 21:32 */ public class LoginInterceptor extends HandlerInterceptorAdapter { /** * 指定目标方法之前执行该方法 * * @param request * @param response * @param handler * @return * @throws Exception */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 获取session中的user信息 User user = (User) request.getSession().getAttribute("user"); // 未登录 if (user == null) { // 重定向到登录页面 response.sendRedirect(request.getContextPath() + "/" + "login.jsp"); // 禁止执行请求 return false; } // 否则放行,执行目标方法 return true; } }
<!-- 非法访问拦截 拦截器配置 --> <mvc:interceptors> <mvc:interceptor> <!-- 拦截所有的请求 --> <mvc:mapping path="/**"/> <!-- 不拦截登录请求 --> <mvc:exclude-mapping path="/userInfo/login"/> <bean class="com.liu.springmvc.interceptor.LoginInterceptor"/> </mvc:interceptor> </mvc:interceptors>
- 在 JavaEE项目的开发中,不管是对底层的数据库操作过程,还是业务层的处理过程,还是控制层的处理过程,都不可避免会遇到各种可预知的、不可预知的异常需要处理。每个过程都单独处理异常,系统的代码耦合度高,工作量大且不好统一,维护的工作量也很大。
- SpringMVC对于异常处理这块提供了支持,通过 SpringMVC提供的全局异常处理机制,能够将所有类型的异常处理从各处理过程解耦出来,既保证了相关处理过程的功能较单一,也实现了异常信息的统一处理和维护。
- 全局异常实现方式 Spring MVC处理异常有3种方式:
使用SpringMVC提供的简单异常处理器SimpleMappingExceptionResolver
- (需要在SpringMVC配置文件中进行配置,处理的是视图的异常,对于返回的是json数据的异常就会有缺陷,所以不推荐使用)实现Spring的异常处理接口 HandlerExceptionResolver自定义自己的异常处理器(推荐使用)
使用@ExceptionHandler注解实现异常处理
SimpleMappingExceptionResolver
<!-- 全局异常统一处理(3种) 1. 使用SpringMVC中提供的简单异常处理器 SimpleMappingExceptionResolver --> <!-- 方式1: 使用SpringMVC中提供的简单异常处理器 SimpleMappingExceptionResolver--> <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <!-- 页面在转发时出现异常,将跳转到error错误页面 --> <property name="defaultErrorView" value="error"/> <!-- 属性exceptionAttribute中包含了出现异常的信息,设置别名为ex --> <property name="exceptionAttribute" value="ex"/> <!-- 设置自定义异常和该异常对应的处理页面--> <property name="exceptionMappings"> <props> <!-- key表示具体的自定义异常的类,标签为出现该自定义异常要跳转到的处理页面 --> <prop key="com.liu.springmvc.exception.ParamsException">params_error</prop> <prop key="com.liu.springmvc.exception.BusinessException">business_error</prop> </props> </property> </bean>
package com.liu.springmvc.exception; /** * @author lms * @date 2021-09-26 - 10:34 */ //自定义参数异常类 public class ParamsException extends RuntimeException { private Integer code = 300; private String msg = "参数异常"; public ParamsException() { super("参数异常"); } public ParamsException(Integer code) { super("参数异常"); this.code = code; } public ParamsException(String msg) { super(msg); this.msg = msg; } public ParamsException(Integer code, String msg) { super(msg); this.code = code; } }
package com.liu.springmvc.exception; /** * @author lms * @date 2021-09-26 - 10:39 */ public class BusinessException extends RuntimeException { private Integer code = 400; private String msg = "业务异常"; public BusinessException() { super("业务异常"); } public BusinessException(String msg) { super(msg); this.msg = msg; } public BusinessException(Integer code) { super("业务异常"); this.code = code; } public Integer getCode() { return code; } public void setCode(Integer code) { this.code = code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } }
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>参数异常</title> </head> <body> <h3>异常信息: ${ex}</h3> </body> </html>
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>业务异常</title> </head> <body> <h3>异常信息: ${ex}</h3> </body> </html>
package com.liu.springmvc.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; /** * @author lms * @date 2021-09-25 - 9:23 */ @Controller public class HelloController { @RequestMapping("/hello") public ModelAndView hello(){ // 模拟异常(全局异常处理) // int i = 1 / 0; // 抛出自定义的异常信息 // if (1 == 1){ // // 参数异常 throw new ParamsException(); // // 业务异常 // throw new BusinessException(); // } System.out.println("hello请求被拦截了........."); ModelAndView modelAndView = new ModelAndView(); // 设置数据信息 modelAndView.addObject("name", "zhangsan"); // 设置跳转的视图 modelAndView.setViewName("hello"); return modelAndView; } }
- 使用
SimpleMappingExceptionResolver
进行异常处理,具有集成简单,有良好的的拓展性,对已有的代码没有入侵性等优点,但该方法仅能获取到异常信息,若出现异常时,对需要获取除了异常之外的数据的情况不适用。
HandlerExceptionResolver
package com.liu.springmvc; import com.liu.springmvc.exception.BusinessException; import com.liu.springmvc.exception.ParamsException; import org.springframework.web.servlet.HandlerExceptionResolver; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * @author lms * @date 2021-09-26 - 11:13 */ // 为了让当前的全局异常处理类生效,需要将其让IOC容器进行管理 // 方式2: 实现Spring的异常处理接口 HandlerExceptionResolver自定义自己的异常处理器(推荐使用) // 直接使用注解不生效,不知道为啥,所以需要在SpringMVC的配置文件中进行配置全局异常处理类 //@Component //@Component("handlerExceptionResolver") public class GlobalExceptionResolver implements HandlerExceptionResolver { @Override public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { // 设置默认的异常处理页面 ModelAndView mv = new ModelAndView("error"); mv.addObject("ex", "默认错误异常信息!"); // 判断是否是自定义异常信息 // 参数异常,跳转至参数异常页面 if (ex instanceof ParamsException) { mv.setViewName("params_error"); // 获取具体的异常信息 ParamsException e = (ParamsException) ex; mv.addObject("ex", e.getMessage()); } // 业务异常,跳转至业务异常页面 if (ex instanceof BusinessException) { mv.setViewName("business_error"); // 获取具体的异常信息 BusinessException e = (BusinessException) ex; mv.addObject("ex", e.getMessage()); } return mv; } }
<!-- 方式2: 实现Spring的异常处理接口 HandlerExceptionResolver自定义自己的异常处理器(推荐使用) --> <bean id="handlerExceptionResolver" class="com.liu.springmvc.GlobalExceptionResolver"/>
<!-- 未捕获的异常信息处理 --> <error-page> <exception-type>java.lang.Throwable</exception-type> <location>/500.jsp</location> </error-page> <error-page> <error-code>500</error-code> <location>/500.jsp</location> </error-page> <error-page> <error-code>404</error-code> <location>/404.jsp</location> </error-page>