SpringMVC09异常处理和类型转化器
public class User { private String name; private Integer age; public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public User(String name, Integer age) { super(); this.name = name; this.age = age; } public User() { super(); } @Override public String toString() { return "User [name=" + name + ", age=" + age + "]"; } }
对应的异常处理类
public class UserException extends Exception { public UserException() { super(); } public UserException(String message) { super(message); } }
public class NameException extends UserException { public NameException() { super(); } public NameException(String message) { super(message); } }
public class AgeException extends UserException { public AgeException() { super(); } public AgeException(String message) { super(message); } }
@Controller @RequestMapping("/user") public class MyController { /** * 跳转到/list * Model:跳转list方法时 携带的数据 * @throws UserException */ @RequestMapping(value = "/add") public String add(User user, Model mv) throws UserException { System.out.println("进入了add......"); // 01.模拟异常 System.out.println(5 / 0); // 02.模拟异常 name if (!user.getName().equals("admin")) { throw new NameException("用户名错误!"); } // 03.模拟异常 age if (user.getAge() > 50) { throw new AgeException("年龄不合法!"); } mv.addAttribute("name", user.getName()).addAttribute("age", user.getAge()); return "redirect:list"; } @RequestMapping(value = "/list") public String list(User user) { System.out.println("进入了list......"); System.out.println(user.getName()); System.out.println(user.getAge()); return "/success.jsp"; } }
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <!-- 配置需要扫描的包 --> <context:component-scan base-package="cn.bdqn.controller"/> <!-- 开启注解 --> <mvc:annotation-driven/> <!-- 设置异常处理 --> <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <!-- 01.出现异常时 跳转的界面--> <property name="defaultErrorView" value="/errors/error.jsp"/> <!-- 02.给用户提示信息 --> <property name="exceptionAttribute" value="ex"/> <!-- 03.自定义的异常跳转界面 --> <property name="exceptionMappings"> <props> <prop key="cn.bdqn.exception.NameException">/errors/nameError.jsp</prop> <prop key="cn.bdqn.exception.AgeException">/errors/ageError.jsp</prop> </props> </property> </bean>
需要的界面
<body> <form action="user/add" method="post"> <!-- 必须是User类中对应的属性名 --> 用户名:<input type="text" name="name"> 年龄:<input type="text" name="age"> <button type="submit">提交</button> </form> </body>
<body> <h1>错误界面</h1> ${ex.message} </body>
<body> <h1>name错误界面</h1> ${ex.message} </body>
<body> <h1>age错误界面</h1> ${ex.message} </body>
====================自定义异常处理器===========================
/** * 自定义的异常处理器 implements HandlerExceptionResolver */ public class MyExceptionResolver implements HandlerExceptionResolver { /** * handler:就是我们的controller * ex:controller出现的异常信息 */ public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { ModelAndView mv = new ModelAndView(); mv.addObject("ex", ex);// 保存异常信息 mv.setViewName("/errors/error.jsp"); // 其他异常处理 if (ex instanceof NameException) { mv.setViewName("/errors/nameError.jsp"); } if (ex instanceof AgeException) { mv.setViewName("/errors/ageError.jsp"); } return mv; } }
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <!-- 配置需要扫描的包 --> <context:component-scan base-package="cn.bdqn.controller"/> <!-- 开启注解 --> <mvc:annotation-driven/> <!-- 设置自定义的异常处理器--> <bean class="cn.bdqn.controller.MyExceptionResolver"/> </beans>
其他代码不需要更改!测试即可!
===================使用注解的方式实现异常处理=======================
删除上个例子中xml文件 配置的自定义异常处理器
/** *03.提取出来一个处理异常的类 */ @Controller public class BaseController { // 专门来处理 异常的 @ExceptionHandler // 其他的异常 public ModelAndView defaultException(Exception ex) { ModelAndView mv = new ModelAndView(); mv.addObject("ex", ex);// 保存异常信息 mv.setViewName("/errors/error.jsp"); // 其他异常处理 return mv; } @ExceptionHandler(NameException.class) // name的异常 public ModelAndView nameException(Exception ex) { ModelAndView mv = new ModelAndView(); mv.addObject("ex", ex);// 保存异常信息 mv.setViewName("/errors/nameError.jsp"); return mv; } @ExceptionHandler(AgeException.class) // age的异常 public ModelAndView ageException(Exception ex) { ModelAndView mv = new ModelAndView(); mv.addObject("ex", ex);// 保存异常信息 mv.setViewName("/errors/ageError.jsp"); return mv; } }
@Controller @RequestMapping("/user") public class MyController extends BaseController { /** * 跳转到/list * Model:跳转list方法时 携带的数据 * @throws UserException */ @RequestMapping(value = "/add") public String add(User user, Model mv) throws UserException { System.out.println("进入了add......"); // 01.模拟异常 // System.out.println(5 / 0); // 02.模拟异常 name if (!user.getName().equals("admin")) { throw new NameException("用户名错误!"); } // 03.模拟异常 age if (user.getAge() > 50) { throw new AgeException("年龄不合法!"); } mv.addAttribute("name", user.getName()).addAttribute("age", user.getAge()); return "redirect:list"; } @RequestMapping(value = "/list") public String list(User user) { System.out.println("进入了list......"); System.out.println(user.getName()); System.out.println(user.getAge()); return "/success.jsp"; } /** * 01.所有的异常的都在一个方法中 处理 @ExceptionHandler public ModelAndView resolveException(Exception ex) { ModelAndView mv = new ModelAndView(); mv.addObject("ex", ex);// 保存异常信息 mv.setViewName("/errors/error.jsp"); // 其他异常处理 if (ex instanceof NameException) { mv.setViewName("/errors/nameError.jsp"); } if (ex instanceof AgeException) { mv.setViewName("/errors/ageError.jsp"); } return mv; }*/ /** * 02.针对于每个异常 @ExceptionHandler // 其他的异常 public ModelAndView defaultException(Exception ex) { ModelAndView mv = new ModelAndView(); mv.addObject("ex", ex);// 保存异常信息 mv.setViewName("/errors/error.jsp"); // 其他异常处理 return mv; } @ExceptionHandler(NameException.class) // name的异常 public ModelAndView nameException(Exception ex) { ModelAndView mv = new ModelAndView(); mv.addObject("ex", ex);// 保存异常信息 mv.setViewName("/errors/nameError.jsp"); return mv; } @ExceptionHandler(AgeException.class) // age的异常 public ModelAndView ageException(Exception ex) { ModelAndView mv = new ModelAndView(); mv.addObject("ex", ex);// 保存异常信息 mv.setViewName("/errors/ageError.jsp"); return mv; } */ }
==================类型转化器============================
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML> <html> <head> <base href="<%=basePath%>"> <title>My JSP 'index.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> <!-- <link rel="stylesheet" type="text/css" href="styles.css"> --> </head> <body> ${ex.message} <form action="user/login" method="post"> <!-- 必须是User类中对应的属性名 --> 出生日期:<input type="text" name="birthday" value="${birthday}"> ${birthdayError}<br/> 年龄:<input type="text" name="age" value="${age}"> ${ageError} <button type="submit">提交</button> </form> </body> </html>
@Controller @RequestMapping("/user") public class MyController { /** * 登录 * Date 能自动类型转换 2015/ 02/02 */ @RequestMapping(value = "/login") public ModelAndView login(int age, Date birthday) { System.out.println("进入了login......"); System.out.println(age); System.out.println(birthday); ModelAndView mv = new ModelAndView(); mv.addObject("age", age).addObject("birthday", birthday) .setViewName("/success.jsp"); return mv; } /** * TypeMismatchException 类型转换不了的时候 抛出的异常 * HttpServletRequest request:数据的回显 * Exception ex:给用户提示 */ @ExceptionHandler(TypeMismatchException.class) public ModelAndView exceptionAge(HttpServletRequest request, Exception ex) { ModelAndView mv = new ModelAndView(); String age = request.getParameter("age"); String birthday = request.getParameter("birthday"); // 让用户看到错误的信息 String message = ex.getMessage(); if (message.contains(age)) { mv.addObject("ageError", "年龄输入有误!"); } if (message.contains(birthday)) { mv.addObject("birthdayError", "日期输入有误!"); } mv.addObject("age", age).addObject("birthday", birthday) .addObject("ex", ex).setViewName("/index.jsp"); return mv; } }
/** * * 自定义的类型转化器 * @param <S> the source type 前台表单中肯定是string * @param <T> the target type * * public interface Converter<S, T> { */ public class MyDateConverter implements Converter<String, Date> { /** * source:前台传递来的字符串 */ public Date convert(String source) { // 类型转化 SimpleDateFormat sdf = getDate(source); Date parse = null; try { parse = sdf.parse(source); } catch (ParseException e) { e.printStackTrace(); } return parse; } /** * @param source 传递来的日期格式的字符串 * */ private SimpleDateFormat getDate(String source) { SimpleDateFormat sdf = new SimpleDateFormat(); // 判断 if (Pattern.matches("^\\d{4}-\\d{2}-\\d{2}$", source)) { sdf = new SimpleDateFormat("yyyy-MM-dd"); } else if (Pattern.matches("^\\d{4}/\\d{2}/\\d{2}$", source)) { sdf = new SimpleDateFormat("yyyy/MM/dd"); } else if (Pattern.matches("^\\d{4}\\d{2}\\d{2}$", source)) { sdf = new SimpleDateFormat("yyyyMMdd"); } else { /** * 都不匹配了 就让它抛出 TypeMismatchException异常 * public TypeMismatchException(Object value, Class<?> requiredType) { * vallue 值能对应requiredType 类型 就不会出现异常 * 我们就得写一个不能转换的 */ throw new TypeMismatchException("", Date.class); } return sdf; } }
public class User { private String name; private Date birthday; private Integer age; public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Override public String toString() { return "User [name=" + name + ", birthday=" + birthday + ", age=" + age + "]"; } public User(String name, Date birthday, Integer age) { super(); this.name = name; this.birthday = birthday; this.age = age; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } public User() { super(); } }
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <!-- 配置需要扫描的包 --> <context:component-scan base-package="cn.bdqn.controller"/> <!-- 开启注解 --> <mvc:annotation-driven conversion-service="conversionService"/> <!-- 注册我们自己创建的类型转换器 --> <bean id="myDateConverter" class="cn.bdqn.controller.MyDateConverter"/> <!-- 创建一个类型转换器工厂 来加载我们自己创建的类型转换器 --> <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean"> <property name="converters"> <set> <ref bean="myDateConverter"/><!--如果需要配置多个类型转化器 只需要增加 ref节点 --> </set> </property> </bean> </beans>
<body> <h1>webroot success页面</h1> ${birthday}<br/> ${age} </body>
======================初始化类型绑定===================
在上面的例子中修改xml文件内容! 也就是把之前的类型转换器 删掉
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <!-- 配置需要扫描的包 --> <context:component-scan base-package="cn.bdqn.controller"/> <!-- 开启注解 --> <mvc:annotation-driven/> </beans>
修改controller中的代码
@Controller @RequestMapping("/user") public class MyController { /** * 登录 * Date 能自动类型转换 2015/ 02/02 */ @RequestMapping(value = "/login") public ModelAndView login(int age, Date birthday) { System.out.println("进入了login......"); System.out.println(age); System.out.println(birthday); ModelAndView mv = new ModelAndView(); mv.addObject("age", age).addObject("birthday", birthday) .setViewName("/success.jsp"); return mv; } /** * 初始化参数的绑定 * binder.registerCustomEditor(Date.class, new CustomDateEditor(df, true)) * Date.class:需要转换成的类型 * new CustomDateEditor:类型编辑器 * true代表 允许日期格式为空 */ @InitBinder public void initBinder(WebDataBinder binder) { DateFormat df = new SimpleDateFormat("yyyy-MM-dd"); // 只能匹配这种格式 binder.registerCustomEditor(Date.class, new CustomDateEditor(df, true)); } }
之后可以运行 测试!
创建自己定义的类型编辑器 来完成多种日期格式的绑定
/** * * 自定义的类型编辑器 */ public class MyDateEditor extends PropertiesEditor { @Override public void setAsText(String source) throws IllegalArgumentException { SimpleDateFormat sdf = getDate(source); Date parse = null; // 类型转化 try { parse = sdf.parse(source); setValue(parse); } catch (ParseException e) { e.printStackTrace(); } } /** * @param source 传递来的日期格式的字符串 * */ private SimpleDateFormat getDate(String source) { SimpleDateFormat sdf = new SimpleDateFormat(); // 判断 if (Pattern.matches("^\\d{4}-\\d{2}-\\d{2}$", source)) { sdf = new SimpleDateFormat("yyyy-MM-dd"); } else if (Pattern.matches("^\\d{4}/\\d{2}/\\d{2}$", source)) { sdf = new SimpleDateFormat("yyyy/MM/dd"); } else if (Pattern.matches("^\\d{4}\\d{2}\\d{2}$", source)) { sdf = new SimpleDateFormat("yyyyMMdd"); } else { /** * 都不匹配了 就让它抛出 TypeMismatchException异常 * public TypeMismatchException(Object value, Class<?> requiredType) { * vallue 值能对应requiredType 类型 就不会出现异常 * 我们就得写一个不能转换的 */ throw new TypeMismatchException("", Date.class); } return sdf; } }
修改controller中的代码
package cn.bdqn.controller; import java.util.Date; import org.springframework.stereotype.Controller; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.annotation.InitBinder; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; @Controller @RequestMapping("/user") public class MyController { /** * 登录 * Date 能自动类型转换 2015/ 02/02 */ @RequestMapping(value = "/login") public ModelAndView login(int age, Date birthday) { System.out.println("进入了login......"); System.out.println(age); System.out.println(birthday); ModelAndView mv = new ModelAndView(); mv.addObject("age", age).addObject("birthday", birthday) .setViewName("/success.jsp"); return mv; } /** * 初始化参数的绑定 * binder.registerCustomEditor(Date.class, new CustomDateEditor(df, true)) * Date.class:需要转换成的类型 * new CustomDateEditor:类型编辑器 * true代表 允许日期格式为空 @InitBinder public void initBinder(WebDataBinder binder) { DateFormat df = new SimpleDateFormat("yyyy-MM-dd"); // 只能匹配这种格式 binder.registerCustomEditor(Date.class, new CustomDateEditor(df, true)); }*/ /** * 绑定多种日期格式 */ @InitBinder public void initBinder(WebDataBinder binder) { // 使用自己定义的类型编辑器new MyDateEditor() binder.registerCustomEditor(Date.class, new MyDateEditor()); } }
其他代码不动 测试 即可!