请求转发和重定向
转发:跳转到页面或者跳转到其他处理器。
重定向:重定向相当于客户端再次发送请求,不能访问WEB-INF内部资源。
返回ModelAndView转发
可以不显式指出,若需要显式指出则需要在setViewName()指定的视图前添加forward,且此时的视图不会再与视图解析器中的前缀与后缀进行拼接。
请求转发到页面
当通过请求转发跳转到目标资源时,若需要向下传递数据,处理可以使用request,session外,还可以将数据存放于ModelAndView中的Model中。页面通过El表达式可直接访问该数据。
通过添加forward:标记表明了为请求转发,即使配置了视图解析器无法作用于当前路径。
@RequestMapping(value = "firstRequestFormByPerson.do", method = RequestMethod.POST)
public ModelAndView firstRequestFormByPerson(Person person, HttpServletRequest request) {
ModelAndView mv = new ModelAndView();
mv.addObject("person", person);
mv.setViewName("forward:/WEB-INF/acceptRequest.jsp");
return mv;
}
请求转发到处理器
@RequestMapping(value = "firstRequestForm.do", method = RequestMethod.POST)
public ModelAndView firstRequestForm(@RequestParam(name = "pname") String name,
@RequestParam(name = "page") int age)
throws Exception {
ModelAndView mv = new ModelAndView();
mv.addObject("name", name);
mv.addObject("age", age);
mv.setViewName("forward:firstRequestFormByPerson.do");
return mv;
}
@RequestMapping(value = "firstRequestFormByPerson.do", method = RequestMethod.POST)
public ModelAndView firstRequestFormByPerson(Person person, HttpServletRequest request) {
ModelAndView mv = new ModelAndView();
mv.addObject("person", person);
mv.setViewName("forward:/WEB-INF/acceptRequest.jsp");
return mv;
}
返回ModelAndView重定向
返回ModelAndView时的重定向,需在setViewName()指定的视图前添加redirect:,且此时的视图不会再与视图解析器中的前辍与后辍进行拼接。即必须写出相对于项目根的路径。故此时的视图解析器不再需要前辍与后辍。
重定向到页面
在重定向时,请求参数时无法通过request属性向下一级资源传递的。但可以通过以下方式将请求参数向下传递。
ModelAndView携带参数
当ModelAndView中的Model存入数据后,视图解析器InternalResourceViewResolver会将map中的key与value,以请求参数的形式放到请求的URL后。
但需要注意:
- 由于视图解析器会将Map的value放入到URL后作为请求参数传递出去,所以无论什么类型的value,均会变为String。故此,放入到Model中的value,只能是基本数据类型与String,不能是自定义类型的对象数据。
- 重定向的页面中是无法从request中读取数据的。但由于map中的key与value,以请求参数的形式放到了请求的URL后,所以,页面可以通过EL表达式中的请求参数param读取。
- 重定向的页面不能是/WEB-INF中的页面。
HttpSession携带参数
类似于Servlet中session用法,将模型存储session中转发给jsp文件,可以从jsp文件的session域中获取内容。
重定向到处理器
重定向到其它处理器时,若要携带参数,完全可以采用前面的方式。而对于目标Controller接收这些参数,则各不相同。
ModelAndView携带参数
目标Controller在接收这些参数时,只要保证目标Controller的方法形参名称与发送Controller发送的参数名称相同即可接收。当然,目标Controller也可以进行参数的整体接收。只要保证参数名称与目标Controller接收参数类型的属性名相同即可。
@RequestMapping("/redirect/")
@Controller
public class Redirection {
@RequestMapping("send.do")
public ModelAndView sendMessage() {
ModelAndView mv = new ModelAndView();
mv.addObject("message", "重定向到处理器");
mv.setViewName("redirect:accept.do");
return mv;
}
@RequestMapping("accept.do")
public ModelAndView acceptMessage(String message) {
ModelAndView mv = new ModelAndView();
mv.addObject("message", message);
mv.setViewName("forward:/redirect.jsp");
return mv;
}
}
重定向之后转发的内容显示在jsp上
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
${message}
</body>
</html>
重定向不能发送实体对象,但是可以接收实体对象,只需要将实体属性名一一对应进行传递,通过一个实体进行接收。
HttpSession携带参数
通过传递session对象重定向给另一个处理器
@RequestMapping("sendBySession.do")
public ModelAndView sendMessageBySession(HttpSession httpSession) {
ModelAndView mv = new ModelAndView();
httpSession.setAttribute("message", "重定向到处理器携带session");
mv.setViewName("redirect:acceptBySession.do");
return mv;
}
@RequestMapping("acceptBySession.do")
public ModelAndView acceptMessageBySession(HttpSession httpSession) {
ModelAndView mv = new ModelAndView();
String session = (String) httpSession.getAttribute("message");
System.out.println(session);
mv.addObject("sessin", session);
mv.setViewName("forward:/redirect.jsp");
return mv;
}
视图显示
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
${sessin}
</body>
</html>
返回String的请求转发
当处理器方法返回String时,该String即为要跳转的视图。在其前面加上前辍forward:,则可显式的指定跳转方式为请求转发。同样,视图解析器不会对其进行前辍与后辍的拼接。请求转发的目标资源无论是一个页面,还是一个Controller,用法相同。
注意,此时不能再使用ModelAndView传递数据了。因为在处理器方法中定义的ModelAndView对象就是个局部变量,方法运行结束,变量销毁。而当前的处理器方法返回的为String,而非ModelAndView,所以这个创建的ModelAndView就不起作用了。不过,需要注意的是,对于处理器方法返回字符串的情况,当处理器接收到请求中的参数后,发现用于接收这些参数的处理器方法形参为包装类对象,则除了会将参数封装为对象传递给形参外,还会存放到request域属性中。
@Controller
public class Forward {
@RequestMapping(value = "/forwardByString.do" ,method = RequestMethod.POST)
public String forWardByString(Person person) {
// person被存储在了request域中
return "forward:/forward_1.jsp";
}
}
修改视图文件
${requestScope.person}
返回String时的重定向
在处理器方法返回的视图字符串的前面添加前辍redirect:,则可实现重定向跳转。当重定向到目标资源时,若需要向下传递参数值,除了可以直接通过请求URL携带参数,通过HttpSession携带参数外,还可使用其它方式。
重定向到页面
形参Model
可以在Controller形参中添加Model参数,将要传递的数据放入Model中进行参数传递。该方式同样也是将参数拼接到了重定向请求的URL后,所以放入其中的数据只能是基本类型数据,不能是自定义类型。
@Controller
public class Forward {
@RequestMapping(value = "/forwardByString.do", method = RequestMethod.POST)
public String forWardByString(Person person, Model model) {
model.addAttribute("pname", person.getPname());
model.addAttribute("page", person.getPage());
return "redirect:/forward_1.jsp";
}
}
修改视图文件
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
${param.get("pname")}
${param.get("page")}
</body>
</html>
形参RedirectAttributes
RedirectAttributes是Spring3.1版本后新增的功能,专门是用于携带重定向参数的。它是一个继承自Model的接口,其底层仍然使用ModelMap实现。通过addAttribute()方法会将参数名及参数值放入该Map中,然后视图解析器会将其拼接到请求的URL中。所以,这种携带参数的方式,不能携带自定义对象。
@Controller
public class Forward {
@RequestMapping(value = "/forwardByString.do", method = RequestMethod.POST)
public String forWardByString(Person person, RedirectAttributes attributes) {
attributes.addAttribute("pname", person.getPname());
attributes.addAttribute("page", person.getPage());
return "redirect:/forward_1.jsp";
}
}
重定向到Controller
重定向到Controller时,携带参数的方式,除了可以使用请求URL后携带方式,HttpSession携带方式,Model形参携带方式,及RedirectAttributes形参的addAttibute()携带方式外,还可以使用RedirectAttributes形参的addFlushAttibute()携带方式。
Model形参携带参数
可以在Controller形参中添加Model参数,将要传递的数据放入Model中进行参数传递。该方式同样也是将参数拼接到了重定向请求的URL后,所以放入其中的数据只能是基本类型数据,不能是自定义类型
@Controller
public class Forward {
@RequestMapping(value = "/forwardByString.do", method = RequestMethod.POST)
public String forWardByString(Person person, Model model) {
model.addAttribute("pname", person.getPname());
model.addAttribute("page", person.getPage());
return "redirect:/acceptRedirectByString.do";
}
@RequestMapping(value = "/acceptRedirectByString.do", method = RequestMethod.GET)
public String accRedirectByString(String pname, int page, Model model) {
model.addAttribute("pname", pname);
model.addAttribute("page", page);
return "redirect:/forward_1.jsp";
}
}
RedirectAttributes形参(了解)
RedirectAttributes形参的addFlushAttibute()携带方式不会将放入其中的属性值通过请求URL传递,所以其中可以存放任意对象。
返回void请求转发与重定向
与Servlet调用一致。
异常处理
常用的SpringMVC异常处理方式主要有三种:
- 使用系统定义好的异常处理器SimpleMappingExceptionResolver
- 使用自定义异常处理器
- 使用异常处理注解
SimpleMappingExceptionResolver
该方式只需要在SpringMVC配置文件中注册该异常处理器Bean即可。该Bean比较特殊,没有id属性,无需显式调用或被注入给其它<bean/>,当异常发生时会自动执行该类。
自定义异常类
定义三个异常类:NameException、AgeException、PeopleException。其中PeopleException是另外两个异常的父类。
public class PeopleException extends Exception{
public PeopleException() {
}
public PeopleException(String message) {
super(message);
}
}
public class NameException extends PeopleException{
public NameException() {
}
public NameException(String message) {
super(message);
}
}
public class AgeException extends PeopleException{
public AgeException() {
}
public AgeException(String message) {
super(message);
}
}
修改Controller
@Controller
public class ExceptionController {
@RequestMapping(value = "/login.do", method = RequestMethod.POST)
public ModelAndView SimpleExceptionResolver(String name, int age) throws PeopleException {
ModelAndView mv = new ModelAndView();
if (!name.equals("翠花")) {
throw new NameException("登录名" + name + "错误");
}
if (age > 50 || age < 10) {
throw new AgeException("年龄不符");
}
Person person = new Person();
person.setPname(name);
person.setPage(age);
mv.addObject("person", person);
mv.setViewName("forward:/exceptionPage/success.jsp");
return mv;
}
}
注册异常处理器
<!--注册异常类-->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<!--
属性exceptionMappings:用于指定具体的不同类型的异常所对应的异常响应页面。
key为异常类的全限定性类名,value则为响应页面路径
属性defaultErrorView:对于没有在属性exceptionMapping中指定异常对应页面的
通过该属性指定默认跳转页面
属性exceptionAttribute:捕获到的异常对象
一般异常响应页面中使用
-->
<property name="exceptionMappings">
<props>
<prop key="cn.pu1satilla.Exception.NameException">/exceptionPage/nameError.jsp</prop>
<prop key="cn.pu1satilla.Exception.AgeException">/exceptionPage/ageError.jsp</prop>
</props>
</property>
<property name="defaultErrorView" value="/exceptionPage/error.jsp"/>
<property name="exceptionAttribute" value="ex"/>
</bean>
- exceptionMapping: 用于指定具体的不同类型的异常所对应的异常响应页面。Key为异常类的全限定性类名,value则为响应页面路径
- defaultErrorView: 指定默认的异常响应页面。若发生的异常不是
exceptionMappings中指定的异常,则使用默认异常响应页面。 - exceptionAttribute:捕获到的异常对象。一般异常响应页面中使用。
定义异常响应页面
分别建立配置文件中路径文件
<body>
${ex.message}
</body>
自定义异常处理器
使用SpringMVC定义好的SimpleMappingExceptionResolver异常处理器,可以实现发生指定异常后的跳转。但若要实现在捕获到指定异常时,执行一些操作的目的,它是完成不了的。此时,就需要自定义异常处理器。自定义异常处理器,需要实现HandlerExceptionResolver接口,并且该类需要在SpringMVC配置文件中进行注册。
定义异常处理器
当一个类实现了HandlerExceptionResolver接口后,只要有异常发生,无论什么异常,都会自动执行接口方法resolveException()。
public class PersonExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
ModelAndView mv = new ModelAndView();
// 1.将异常数据加入模型
mv.addObject("ex", ex);
// 2.设置默认错误响应页面
mv.setViewName("/exceptionPage/error.jsp");
// 3.如果异常对象是NameException,转发到nameException页面
if (ex instanceof NameException) {
mv.setViewName("/exceptionPage/nameException.jsp");
}
// 4.如果异常对象是ageException,转发到ageException页面
if (ex instanceof AgeException) {
mv.setViewName("/exceptionPage/ageException.jsp");
}
return mv;
}
}
注册异常处理器
<!--注册异常处理器-->
<bean class="cn.pu1satilla.controller.PersonExceptionResolver"/>
异常处理注解
使用注解@ExceptionHandler可以将一个方法指定为异常处理方法。
@Controller
public class ExceptionController {
@RequestMapping(value = "/login.do", method = RequestMethod.POST)
public ModelAndView SimpleExceptionResolver(String name, int age) throws PeopleException {
ModelAndView mv = new ModelAndView();
if (!name.equals("翠花")) {
throw new NameException("登录名" + name + "错误");
}
if (age > 50 || age < 10) {
throw new AgeException("年龄不符");
}
Person person = new Person();
person.setPname(name);
person.setPage(age);
mv.addObject("person", person);
mv.setViewName("forward:/exceptionPage/success.jsp");
return mv;
}
@ExceptionHandler(PeopleException.class)
public ModelAndView handlePeopleException(Exception ex) {
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("ex", ex);
modelAndView.setViewName("/exceptionPage/error.jsp");
return modelAndView;
}
}
不过,一般不这样使用。而是将异常处理方法专门定义在一个Controller中,让其它Controller继承该Controller即可。但是,这种用法的弊端也很明显:Java是“单继承多实现”的,这个Controller的继承将这唯一的一个继承机会使用了,使得若再有其它类需要继承,将无法直接实现。
类型转换器
在前面的程序中,表单提交的无论是int还是double类型的请求参数,用于处理该请求的处理器方法的形参,均可直接接收到相应类型的相应数据,而非接收到String再手工转换。那是因为在SpringMVC框架中,有默认的类型转换器。这些默认的类型转换器,可以将String类型的数据,自动转换为相应类型的数据。
但默认类型转换器并不是可以将用户提交的String,转换为所有用户需要的类型。此时,就需要自定义类型转换器了。例如,在SpringMVC的默认类型转换器中,没有日期类型的转换器,因为日期的格式太多。若要使表单中提交的日期字符串,被处理器方法形参直接接收为java.util.Date,则需要自定义类型转换器了。
搭建测试环境
注册页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="" method="post">
用户名:<input type="text" name="name"> <br>
生日:<input type="text" name="birthday"><br>
<input type="submit" value="注册">
</form>
</body>
</html>
控制器
@Controller
public class RegisterController {
@RequestMapping("/register.do")
public ModelAndView registerConverter(String name, Date date) {
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("name", name);
modelAndView.addObject("date", date);
modelAndView.setViewName("/converter/success.jsp");
return modelAndView;
}
}
转发页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
${name} <br>
${birthday}
</body>
</html>
自定义类型转换器
public class DateConverter implements Converter<String, Date> {
@Override
public Date convert(String source) {
Date date = new Date();
// 判断传入参数值不为空才进行转换
if (source != null && !source.equals("")) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
try {
date = dateFormat.parse(source);
} catch (ParseException e) {
e.printStackTrace();
}
}
return date;
}
}
配置类型转换器
类型转换器定义完毕后,需要在SpringMVC的配置文件中对类型转换进行配置。首先要注册类型转换器,然后再注册一个转换服务Bean。将类型转换器注入给该转换服务Bean。最后由处理器适配器来使用该转换服务Bean。
<!--注册异常处理器-->
<!--<bean class="cn.pu1satilla.controller.PersonExceptionResolver"/>-->
<!--注册类型转换器-->
<bean class="cn.pu1satilla.converter.DateConverter" id="dateConverter"/>
<!--注册类型转换服务-->
<bean class="org.springframework.context.support.ConversionServiceFactoryBean" id="conversionService">
<!--注入属性:单个类型转换器写法-->
<property name="converters" ref="dateConverter"/>
<!--当需要注入多个类型转换器:
<property name="converters">
<set>
<ref bean="dateConverter"/>
</set>
</property>
-->
</bean>
<!--注册mvc注解驱动-->
<mvc:annotation-driven conversion-service="conversionService"/>
配置多种日期类型转换器
使用正则表达式对传入source资源进行判断为哪种日期格式,不同的日期格式对应不同SimpleDataFormat对象。
public class DateConverter implements Converter<String, Date> {
@Override
public Date convert(String source) {
Date date = new Date();
// 判断传入参数值不为空才进行转换
if (source != null && !source.equals("")) {
SimpleDateFormat dateFormat = getSimpleDateFormat(source);
try {
date = dateFormat.parse(source);
} catch (ParseException e) {
e.printStackTrace();
}
}
return date;
}
/**
* 传入日期格式,对日期格式进行判断,符合则建该日期格式的SimpleDateFormat对象
*
* @param source 传入日期格式
* @return SimpleDateFormat对象
*/
private SimpleDateFormat getSimpleDateFormat(String source) {
SimpleDateFormat dateFormat = null;
if (Pattern.matches("^\\d{4}-\\d{2}-\\d{2}$", source)) {
dateFormat = new SimpleDateFormat("yyyy-MM-dd");
} else if (Pattern.matches("^\\d{4}/\\d{2}/\\d{2}$", source)) {
dateFormat = new SimpleDateFormat("yyyy/MM/dd");
} else if (Pattern.matches("^\\d{4}\\d{2}\\d{2}$", source)) {
dateFormat = new SimpleDateFormat("yyyy/MM/dd");
}
return dateFormat;
}
}
数据回显
当数据转换出现异常,表示用户输入格式有误,这时需要数据回显给用户进行重新输入,可以通过异常进行跳转完成。
转换器
当输入格式匹配不上,转换器抛出TypeMismatchException
public class DateConverter implements Converter<String, Date> {
@Override
public Date convert(String source) {
Date date = new Date();
// 判断传入参数值不为空才进行转换
if (source != null && !source.equals("")) {
SimpleDateFormat dateFormat = getSimpleDateFormat(source);
try {
date = dateFormat.parse(source);
} catch (ParseException e) {
e.printStackTrace();
}
}
return date;
}
/**
* 传入日期格式,对日期格式进行判断,符合则建该日期格式的SimpleDateFormat对象
*
* @param source 传入日期格式
* @return SimpleDateFormat对象
*/
private SimpleDateFormat getSimpleDateFormat(String source) {
SimpleDateFormat dateFormat = null;
if (Pattern.matches("^\\d{4}-\\d{2}-\\d{2}$", source)) {
dateFormat = new SimpleDateFormat("yyyy-MM-dd");
} else if (Pattern.matches("^\\d{4}/\\d{2}/\\d{2}$", source)) {
dateFormat = new SimpleDateFormat("yyyy/MM/dd");
} else if (Pattern.matches("^\\d{4}\\d{2}\\d{2}$", source)) {
dateFormat = new SimpleDateFormat("yyyy/MM/dd");
} else {
throw new TypeMismatchException("输入日期格式有误", Date.class);
}
return dateFormat;
}
}
处理器
在处理器内通过注解指定异常处理
@Controller
public class RegisterController {
@RequestMapping("/register.do")
public ModelAndView registerConverter(String name, Date birthday) {
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("name", name);
modelAndView.addObject("birthday", birthday);
modelAndView.setViewName("/converter/success.jsp");
return modelAndView;
}
@ExceptionHandler(TypeMismatchException.class)
public ModelAndView handleTypeMismatchException(Exception ex) {
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("ex", ex);
modelAndView.setViewName("/converter/regsiter.jsp");
return modelAndView;
}
}
测试
打开localhost:8080/register.do链接,发现异常信息阅读困难

需要对代码进行改进
改进
在异常解析器修改传递参数为方便用户阅读中文:
@Controller
public class RegisterController {
@RequestMapping("/register.do")
public ModelAndView registerConverter(String name, Date birthday) {
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("name", name);
modelAndView.addObject("birthday", birthday);
modelAndView.setViewName("/converter/success.jsp");
return modelAndView;
}
@ExceptionHandler(TypeMismatchException.class)
public ModelAndView handleTypeMismatchException(Exception ex) {
ModelAndView modelAndView = new ModelAndView();
// 对异常信息进行判断
if (ex.getMessage().contains("ConversionFailedException")) {
modelAndView.addObject("ex", "日期格式转换失败,请重新输入!!!");
}
modelAndView.setViewName("/converter/regsiter.jsp");
return modelAndView;
}
}
数据验证
为了防止用户传入数据不正确导致多方面问题,需要对数据进行验证。输入验证分为客户端验证和服务器端验证,客户端主要通过JavaScript进行,而服务器端则主要通过Java代码进行验证。
搭建测试环境
导入jar包
在实体上添加验证注解
使用的验证器注解均为javax.validation.constraints包中的类。在注解的message属性中,可以使用{属性名}的方式来引用指定的注解的属性值。
public class Person {
@NotEmpty(message = "姓名不能为空")
@Size(min = 3, max = 6, message = "姓名长度必须在{min}-{max}之间")
private String pname;
@Min(value = 0, message = "年龄不能小于{value}")
@Max(value = 100, message = "年龄不能大于{value}")
@NotEmpty(message = "年龄不能为空")
private int page;
private School pschool;
public School getPschool() {
return pschool;
}
public void setPschool(School pschool) {
this.pschool = pschool;
}
public String getPname() {
return pname;
}
public void setPname(String pname) {
this.pname = pname;
}
public int getPage() {
return page;
}
public void setPage(int page) {
this.page = page;
}
@Override
public String toString() {
return "Person{" +
"pname='" + pname + '\'' +
", page=" + page +
", pschool=" + pschool +
'}';
}
}
Hibernate Validator中常用的验证注解介绍:
| 序号 | 验证注解 | 说明 |
|---|---|---|
| 1 | @AssertFalse | 验证注解的元素值是false |
| 2 | @AssertTrue | 验证注解的元素值是true |
| 3 | @DecimalMax(value=x) | 验证注解的元素值小于等于指定的十进制value值 |
| 4 | @DecimalMin(value=x) | 验证注解的元素值大于等于指定的十进制value值 |
| 5 | @Digits(integer=整数位数, fraction=小数位数) | 验证注解的元素值的整数位数和小数位数上限 |
| 6 | @Future | 验证注解的元素值(日期类型)比当前时间晚 |
| 7 | @Max(value=x) | 验证注解的元素值小于等于指定的value值 |
| 8 | @Min(value=x) | 验证注解的元素值大于等于指定的value值 |
| 9 | @NotNull | 验证注解的元素值丌是null |
| 10 | @Null | 验证注解的元素值是null |
| 11 | @Past | 验证注解的元素值(日期类型)比当前时间早 |
| 12 | @Pattern(regex=正则表达式) | 验证注解的元素值不指定的正则表达式匹配 |
| 13 | @Size(min=最小值, max=最大值) | 验证注解的元素值的在min和max(包含)指定区间之内,如字符长度、集合大小 |
| 14 | @Valid | 验证关联的对象,如账户对象里有一个订单对象,指定验证订单对象 |
| 15 | @NotEmpty | 验证注解的元素值丌为null且丌为空(字符串长度丌为0、集合大小丌为0) |
| 16 | @Range(min=最小值, max=最大值) | 验证注解的元素值在最小值和最大值之间 |
| 17 | @NotBlank | 验证注解的元素值丌为空(丌为null、去除首位空格后长度为0),丌同于@NotEmpty,@NotBlank只应用于字符串且在比较时会去除字符串的空格 |
| 18 | @Length(min=下限, max=上限) | 验证注解的元素值长度在min和max区间内 |
| 19 | 验证注解的元素值是Email,也可以通过正则表达式和flag指定自定义的email格式 |
控制器
当验证出现问题需要将错误信息携带到注册页面进行显示,要求重新输入,没有问题则顺利通过。
@Controller
public class RegisterValidatorController {
@RequestMapping("/validator/register.do")
public ModelAndView registerValidator(@Validated Person person, BindingResult bindingResult) {
ModelAndView modelAndView = new ModelAndView();
// 如果验证错误结果个数>0,传入验证结果,并且返回注册页面,重新注册
List<ObjectError> allErrors = bindingResult.getAllErrors();
if (allErrors.size() > 0) {
FieldError pname = bindingResult.getFieldError("pname");
FieldError page = bindingResult.getFieldError("page");
if (pname != null) {
// 传入名称错误信息到模型
modelAndView.addObject("pnameError", pname.getDefaultMessage());
}
if (page != null) {
// 传入年龄错误信息到模型
modelAndView.addObject("pageError", page.getDefaultMessage());
}
modelAndView.setViewName("/validator/register.jsp");
} else {
// 否则跳到成功页面
modelAndView.addObject("person", person);
modelAndView.setViewName("/validator/success.jsp");
}
return modelAndView;
}
}
前台文件
新建一个jsp页面,含有一个提交的表单,具有name跟age两项。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/validator/register.do">
姓 名:<input type="text" name="pname">${pnameError}<br>
年 龄:<input type="text" name="page">${pageError}<br>
学校 名: <input type="text" name="school.sname"><br>
学校地址:<input type="text" name="school.slocation"><br>
<input type="submit" value="注册">
</form>
</body>
</html>
文件上传
导入jar包
定义上传页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%--必须指定enctype类型,不然spring无法识别--%>
<form action="/upLoad/upLoad.do" method="post" enctype="multipart/form-data">
照片:<input type="file" name="photo"/> <br>
<input type="submit" value="上传">
</form>
</body>
</html>
注意:enctype类型必须指定,否则spring无法识别请求是否需要上传文件
定义处理器
@Controller
@RequestMapping("/upLoad")
public class UpLoadController {
/**
* 演示spring上传文件,以图片格式文件作为上传例子
*
* @param photo 上传文件参数
* @param request
* @return
*/
@RequestMapping(value = "/upLoad.do", method = RequestMethod.POST)
public ModelAndView upLoad(MultipartFile photo, HttpServletRequest request) throws IOException {
// 获取文件原始名称
String photoName = photo.getOriginalFilename();
// 获取存储路径
String realPath = request.getServletContext().getRealPath("/images");
// 判断文件是否为图片(.jpg|.png)格式
if (photoName.endsWith(".jpg") || photoName.endsWith(".png")) {
File file = new File(realPath, photoName);
photo.transferTo(file);
} else {
return new ModelAndView("/upLoad/fail.jsp");
}
return new ModelAndView("/upLoad/success.jsp");
}
}
配置文件类型处理器
<!--注册组件扫描器-->
<context:component-scan base-package="cn.pu1satilla.*"/>
<!--注册springmvc注解驱动-->
<mvc:annotation-driven/>
<!--
注册multipart解析器,这个id名字固定,是由DispatcherServlet直接调用的
属性:defaultEncoding ========= 默认编码格式
maxUploadSizePerFile ========= 每个上传文件大小
-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="utf-8"/>
<property name="maxUploadSizePerFile" value="1048576"/>
</bean>
出现的问题
- 在文件夹为空时,idea不能发布空文件到到项目包里,可以通过在空文件夹内新建一个无用文件解决。