本文介绍SpringMVC中的异常处理,@Controller注解的方法可能由于各种各样的原因抛出异常,如果没有写try...catch()...语句,异常的堆栈信息将直接抛给浏览器,这样对用户来说很不友好,并且异常的堆栈信息可能含有一些敏感信息(如数据库的表字段,sql语句等等...)是不能暴露出去的。因此在程序中最好捕捉到所有的异常并处理后将友好的界面或者信息返回给客户端,SpringMVC提供了一个Handler,该handler指定一种异常,并返回一个view,举个例子,增加一个Controller,叫ExceptionController:
?
- package?org.springframework.samples.mvc.exceptions; ??
- ??
- import?org.springframework.stereotype.Controller; ??
- import?org.springframework.web.bind.annotation.ExceptionHandler; ??
- import?org.springframework.web.bind.annotation.RequestMapping; ??
- import?org.springframework.web.bind.annotation.ResponseBody; ??
- ??
- @Controller??
- public?class?ExceptionController?{ ??
- ??
- ????@ExceptionHandler??
- ????public?@ResponseBody?String?handle(IllegalStateException?e)?{ ??
- ????????return?"IllegalStateException?handled!"; ??
- ????} ??
- ???? ??
- ????@RequestMapping("/exception") ??
- ????public?@ResponseBody?String?exception()?{ ??
- ????????throw?new?IllegalStateException("Sorry!"); ??
- ????} ??
- ??
- }??
package org.springframework.samples.mvc.exceptions; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; @Controller public class ExceptionController { @ExceptionHandler public @ResponseBody String handle(IllegalStateException e) { return "IllegalStateException handled!"; } @RequestMapping("/exception") public @ResponseBody String exception() { throw new IllegalStateException("Sorry!"); } }
?
@ExceptionHandler注解的方法接收一个异常类型的参数,返回值类型和@RequestMapping一样(String,void,ModelAndView...),
访问http://localhost:8080/web/exception,浏览器显示"IllegalStateException handled!"
?
------------------------------------------------------
------------------------------------------------------
?
本文介绍SpringMVC的验证(validation),在Convert一文中,我们知道SpringMVC能很方便的将提交的参数转成(convert)自定义的JavaBean,现在加入对JavaBean的验证,比如要求JavaBean的属性number(private Integer number)不允许为null且最大为5,属性date(private Date date)满足时间是未来的(今天以后的日期)。为此,pom.xml中需要添加两个依赖:
- <!--?JSR?303?with?Hibernate?Validator?-->??
- <dependency>??
- ????<groupId>javax.validation</groupId>??
- ????<artifactId>validation-api</artifactId>??
- ????<version>1.0.0.GA</version>??
- </dependency>??
- <dependency>??
- ????<groupId>org.hibernate</groupId>??
- ????<artifactId>hibernate-validator</artifactId>??
- ????<version>4.1.0.Final</version>??
- </dependency>??
<!-- JSR 303 with Hibernate Validator --> <dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>1.0.0.GA</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>4.1.0.Final</version> </dependency>
?javax.validation.validation-api-1.0.0.GA.jar是一个标准,只有接口方法(以javax开头的包一般都是接口包,业界定义的一些标准,比如servlet-api-2.5.jar中的javax.servlet.HttpServletRequest),还有一个是Hibernate提供的实现包org.hibernate.hibernate-validator-4.1.0.Final。
增加一个Controller,ValidationController:
- package?org.springframework.samples.mvc.validation; ??
- ??
- import?javax.validation.Valid; ??
- ??
- import?org.springframework.stereotype.Controller; ??
- import?org.springframework.validation.BindingResult; ??
- import?org.springframework.web.bind.annotation.RequestMapping; ??
- import?org.springframework.web.bind.annotation.ResponseBody; ??
- ??
- @Controller??
- public?class?ValidationController?{ ??
- ??
- ????//?enforcement?of?constraints?on?the?JavaBean?arg?require?a?JSR-303?provider?on?the?classpath ??
- ???? ??
- ????@RequestMapping("/validate") ??
- ????public?@ResponseBody?String?validate(@Valid?JavaBean?bean,?BindingResult?result)?{ ??
- ????????if?(result.hasErrors())?{ ??
- ????????????return?"Object?has?validation?errors"; ??
- ????????}?else?{ ??
- ????????????return?"No?errors"; ??
- ????????} ??
- ????} ??
- ??
- }??
package org.springframework.samples.mvc.validation; import javax.validation.Valid; import org.springframework.stereotype.Controller; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; @Controller public class ValidationController { // enforcement of constraints on the JavaBean arg require a JSR-303 provider on the classpath @RequestMapping("/validate") public @ResponseBody String validate(@Valid JavaBean bean, BindingResult result) { if (result.hasErrors()) { return "Object has validation errors"; } else { return "No errors"; } } }
和一个JavaBean:
- package?org.springframework.samples.mvc.validation; ??
- ??
- import?java.util.Date; ??
- ??
- import?javax.validation.constraints.Future; ??
- import?javax.validation.constraints.Max; ??
- import?javax.validation.constraints.NotNull; ??
- ??
- import?org.springframework.format.annotation.DateTimeFormat; ??
- import?org.springframework.format.annotation.DateTimeFormat.ISO; ??
- ??
- public?class?JavaBean?{ ??
- ???? ??
- ????@NotNull??
- ????@Max(5) ??
- ????private?Integer?number; ??
- ??
- ????@NotNull??
- ????@Future??
- ????@DateTimeFormat(iso=ISO.DATE) ??
- ????private?Date?date; ??
- ??
- ????public?Integer?getNumber()?{ ??
- ????????return?number; ??
- ????} ??
- ??
- ????public?void?setNumber(Integer?number)?{ ??
- ????????this.number?=?number; ??
- ????} ??
- ??
- ????public?Date?getDate()?{ ??
- ????????return?date; ??
- ????} ??
- ??
- ????public?void?setDate(Date?date)?{ ??
- ????????this.date?=?date; ??
- ????} ??
- ??
- }???
package org.springframework.samples.mvc.validation; import java.util.Date; import javax.validation.constraints.Future; import javax.validation.constraints.Max; import javax.validation.constraints.NotNull; import org.springframework.format.annotation.DateTimeFormat; import org.springframework.format.annotation.DateTimeFormat.ISO; public class JavaBean { @NotNull @Max(5) private Integer number; @NotNull @Future @DateTimeFormat(iso=ISO.DATE) private Date date; public Integer getNumber() { return number; } public void setNumber(Integer number) { this.number = number; } public Date getDate() { return date; } public void setDate(Date date) { this.date = date; } }?
??@NotNull、@Future就是javax.validation.validation-api-1.0.0.GA.jar中定义的注解,满足之前说到的需求。
ValidationController的validate方法绑定了一个参数BindingResult result,通过这个变量就可以得到具体的验证信息,比如在validate方法中,如果验证不通过(result.hasErrors()),返回给浏览器文本"Object has validation errors"。
?
1. 访问"http://localhost:8080/web/validate",浏览器显示"Object has validation errors",number和date不能为空;
?
2. 访问"http://localhost:8080/web/validate?number=1",浏览器显示"Object has validation errors",date不能为空;
?
3. 访问"http://localhost:8080/web/validate?number=1&date=2012-03-31",浏览器显示"Object has validation errors",非今天以后的日期;
?
4. 访问"http://localhost:8080/web/validate?number=1&date=2012-04-01",浏览器显示"No errors";
?
5. 访问"http://localhost:8080/web/validate?number=6&date=2012-04-01",浏览器显示"Object has validation errors",number不能大于5;