一、使用SimpleMappingExceptionResolver解析器
1.1在mvc中进行 配置。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!--spring mvc的配置文件--> <!--开启mvc的注解--> <mvc:annotation-driven conversion-service="conversionService" > <!--配置转换器 转换日期的格式。--> <mvc:message-converters> <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> <property name="objectMapper"> <bean class="com.fasterxml.jackson.databind.ObjectMapper"> <property name="dateFormat"> <bean class="java.text.SimpleDateFormat"> <constructor-arg type="java.lang.String" value="yyyy-MM-dd"/> </bean> </property> </bean> </property> </bean> </mvc:message-converters> </mvc:annotation-driven> <!--配置日期转换器--> <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"> <property name="converters"> <set> <bean class="com.aaa.controller.DateConverter"/> </set> </property> </bean> <mvc:default-servlet-handler/> <!--扫描器:扫描控制器的注解--> <context:component-scan base-package="com.aaa.controller"/> <!--4.静态资源注解--> <mvc:default-servlet-handler/> <!--<mvc:resource mapping="/static/**" location="/static/"/>--> <!--3.视图解析器:进行视图解析 prefix+ 视图名字+suffix --> <!--5.文件上传的解析器 可以设置相关的属性。--> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="defaultEncoding" value="utf-8"/> <!--文件上传的大小:单位:字节--> <property name="maxUploadSize" value="#{10*1024*1024}"/> </bean> <!-- 异常处理 1. 配置解析器 --> <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <!--1.1默认的错误视图 发生异常时, 跳转到的页面--> <property name="defaultErrorView" value="error"/> <!--1.2 异常的属性 捕获到的错误信息。--> <property name="exceptionAttribute" value="ex"/> <!--1.3exceptionMappings --> <property name="exceptionMappings"> <props> <prop key="异常类型1"> error1 </prop> <prop key="异常类型2"> error2 </prop> </props> </property> </bean> <!--6. 配置一个拦截器 --> <mvc:interceptors> <!--<mvc:interceptor>--> <!--<!– 拦截的路径 –>--> <!--<mvc:mapping path="/**"/>--> <!--<!– 配置拦截器的bean –>--> <!--<!– 放行路径 –>--> <!--<mvc:exclude-mapping path="/user/login"/>--> <!--<bean class="com.aaa.interceptors.MyIntercept"/>--> <!--</mvc:interceptor>--> <mvc:interceptor> <mvc:mapping path="/**"/> <bean class="com.aaa.interceptors.Demo02"/> </mvc:interceptor> </mvc:interceptors> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/> <property name="prefix" value="/"/> <!--视图前缀--> <property name="suffix" value=".jsp"/> <!--视图后缀--> </bean> <aop:config ></aop:config> </beans>
1.2、建立一个jsp页面,来接收错误的信息。注意路径 ,我的放在 webapp 下。
<%-- Created by IntelliJ IDEA. User: Administrator Date: 2019/8/14 Time: 14:57 To change this template use File | Settings | File Templates. --%> <%--isErrorPage 是否设置错误的页面 --%> <%@ page contentType="text/html;charset=UTF-8" language="java" isErrorPage="true" %> <html> <head> <title>错误页面</title> </head> <body> <h1>本页面,接收异常数据:${ex}</h1> </body> </html>
1.3 后台控制层
package com.aaa.controller; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.*; import org.apache.shiro.subject.Subject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import javax.servlet.http.HttpSession; // if (!currentUser.isAuthenticated()) { // //用户名密码令牌 // UsernamePasswordToken token = new UsernamePasswordToken(username, password); // //记住我 // token.setRememberMe(true); // try { // //调用Suject.login方法 ---》安全管理器--->认证器 ,授权器 // currentUser.login(token); // } catch (UnknownAccountException uae) {//账号不存在 // log.info("There is no user with username of " + token.getPrincipal()); // } catch (IncorrectCredentialsException ice) {//密码错误 // log.info("Password for account " + token.getPrincipal() + " was incorrect!"); // throw new IncorrectCredentialsException("密码错误"); // } catch (LockedAccountException lae) {//账号锁死 // log.info("The account for username " + token.getPrincipal() + " is locked. " + // "Please contact your administrator to unlock it."); // } // // ... catch more exceptions here (maybe custom ones specific to your application? // catch (AuthenticationException ae) { // //unexpected condition? error? // } // } @Controller @RequestMapping("/user") public class UserController { //获取日志对象 private static final transient Logger log= LoggerFactory.getLogger(UserController.class); @RequestMapping("/login") public String login(String username,String password, HttpSession session){ //获得封装的对象 Subject currentUser= SecurityUtils.getSubject(); //获得的令牌中的信息 UsernamePasswordToken token = new UsernamePasswordToken(username, password); //记住我 token.setRememberMe(true); currentUser.login(token); //密码正确 就让它 跳转到指定的页面 return "view/ok"; } }
二、使用@ExceptionHandler 注解, 只能控制当前 控制器的异常。 可以自定义异常的处理方法。
2.1 控制层 BaseController中自定义 异常处理方式
package com.aaa.controller; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authz.AuthorizationException; import org.springframework.beans.propertyeditors.CustomDateEditor; import org.springframework.ui.Model; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.InitBinder; import javax.sound.midi.Soundbank; import java.text.SimpleDateFormat; import java.util.Date; /* *1.实体类中添加注解。 * * 2.创建BaseController * * 3.定义全局的类型转换器 * */ public class BaseController { @InitBinder public void init(WebDataBinder binder){ SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); //严格转换 不会自动进行日期的增减处理 simpleDateFormat.setLenient(false); //注册一个类型转换器 binder.registerCustomEditor(Date.class,new CustomDateEditor(simpleDateFormat,true)); } //自定的方法。 只能控制当前 控制器的异常 @ExceptionHandler(RuntimeException.class) public String handler(RuntimeException ex, Model model){ //将异常放在model里面 捕获信息 model.addAttribute("ex",ex); //模拟根据异常不同的情况 返回不同的视图 if (ex instanceof AuthenticationException){ System.out.println("处理方案一"); model.addAttribute("ex",ex); return "error"; }else if (ex instanceof AuthorizationException){ System.out.println("处理方案二"); model.addAttribute("ex",ex); return "error"; } //根据不同的异常情况可以,返回不同的界面。 return "error"; } }
2.2 UserController
package com.aaa.controller; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.*; import org.apache.shiro.subject.Subject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import javax.servlet.http.HttpSession; // if (!currentUser.isAuthenticated()) { // //用户名密码令牌 // UsernamePasswordToken token = new UsernamePasswordToken(username, password); // //记住我 // token.setRememberMe(true); // try { // //调用Suject.login方法 ---》安全管理器--->认证器 ,授权器 // currentUser.login(token); // } catch (UnknownAccountException uae) {//账号不存在 // log.info("There is no user with username of " + token.getPrincipal()); // } catch (IncorrectCredentialsException ice) {//密码错误 // log.info("Password for account " + token.getPrincipal() + " was incorrect!"); // throw new IncorrectCredentialsException("密码错误"); // } catch (LockedAccountException lae) {//账号锁死 // log.info("The account for username " + token.getPrincipal() + " is locked. " + // "Please contact your administrator to unlock it."); // } // // ... catch more exceptions here (maybe custom ones specific to your application? // catch (AuthenticationException ae) { // //unexpected condition? error? // } // } @Controller @RequestMapping("/user") public class UserController extends BaseController{ //获取日志对象 private static final transient Logger log= LoggerFactory.getLogger(UserController.class); @RequestMapping("/login") public String login(String username,String password, HttpSession session){ //获得封装的对象 Subject currentUser= SecurityUtils.getSubject(); //获得的令牌中的信息 UsernamePasswordToken token = new UsernamePasswordToken(username, password); //记住我 token.setRememberMe(true); currentUser.login(token); //密码正确 就让它 跳转到指定的页面 return "view/ok"; } }
三、 使用 @ControllerAdvice + @ExceptionHandler 注解
3.1 同步方式。 就不需要再继承,直接创建一个exception controller 。
package com.aaa.controller; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authz.AuthorizationException; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; /* * 建立异常的 处理器。 * * 通知 advice 把这个controller 当做一个切面 * 把这个方法当做切面加到 代理到个个 执行的过程中 * */ @ControllerAdvice //切面 aop的思想 public class ExceptionController { @ExceptionHandler(RuntimeException.class) public String handler1(RuntimeException ex, Model model){ if (ex instanceof AuthenticationException){ model.addAttribute("ex",ex); return "error"; }else if (ex instanceof AuthorizationException){ model.addAttribute("ex",ex); return "error"; } return "error"; } }
3.2 异步方式。 返回json数据
1.创建实体类
2.下载 lombok jar包 ,自动生成一些set get 方法。
package com.aaa.entity; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.ToString; /* * 实体类中定义 状态码等属性 * * lombok 自动生成实体类中的属性 加上注解即可 * * */ @Data @AllArgsConstructor //代餐的构造函数 @NoArgsConstructor //空参 @ToString public class Result { private Integer satusCode; private String message; }
3.控制层
package com.aaa.controller; import com.aaa.entity.Result; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authz.AuthorizationException; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; /* * 一、 建立异常的 处理器。 * 通知 advice 把这个controller 当做一个切面 * 把这个方法当做切面加到 代理到个个 执行的过程中 * * * 二、异步方式 * 1.自定义实体类 下载lombok 使用注解。 * 2.控制器中返回 json数据格式。 * */ @ControllerAdvice //切面 aop的思想 public class ExceptionController { // @ExceptionHandler(RuntimeException.class) // public String handler1(RuntimeException ex, Model model){ // if (ex instanceof AuthenticationException){ // model.addAttribute("ex",ex); // return "error"; // }else if (ex instanceof AuthorizationException){ // model.addAttribute("ex",ex); // return "error"; // } // return "error"; // } @ExceptionHandler(RuntimeException.class) @ResponseBody //返回定义的实体类 result 就不能用视图 model 就不要了。 //对象当做json数据返回。 public Result handler1(RuntimeException ex){ Result result = new Result(); if (ex instanceof AuthenticationException){ //返回一个状态码 自定义 result.setSatusCode(501); result.setMessage("密码认证异常"+ex.getMessage()); }else if (ex instanceof AuthorizationException){ result.setSatusCode(502); result.setMessage("授权异常"+ex.getMessage()); } return result; } }
4. 效果
四,实现异常处理的接口 HandlerExceptionResolver
package com.aaa.controller; import org.springframework.web.servlet.HandlerExceptionResolver; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; //了解一下。 public class ExceptionDemo implements HandlerExceptionResolver { @Override //返回一个model 视图 还需要 配置xml文件 public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) { return null; } }