Spring——MVC理论上

概述

Spring基于MVC设计模式的轻量级web框架。

与Spring关系

Spring——MVC理论_2020-04-24-13-18-30.png

SpringMVC是基于Spring的开源项目。以web项目为例:

servletContext容器是web项目根本容器。

Spring容器 会通过ServletContextListener监听类与context-param配置的xml文件创建。

SpringMVC容器 则通过 DispatcherServlet创建,并将Spring容器设为Parent。

  1. 为什么不用spring容器去扫描所有的Bean?

不可能,请求达到服务端后,找 DispatcherServlet 去处理,只会去 SpringMVC 容器中找,这就意味着 Controller 必须在 SpringMVC 容器中扫描。

  1. 为什么不在 SpringMVC 容器中扫描所有 Bean?

这个是可行的,但是为了配置文件的管理,以及在 Spring+SpringMVC+Hibernate 组合中,实际上也不支持这种写法。

工作流程及组件

Spring——MVC理论_2020-04-24-11-00-49.png

  1. DispatcherServlet:前端控制器

是整个流程控制的中心,相当于是 SpringMVC 的大脑,由它调用其它组件处理用户的请求,DispatcherServlet 的存在降低了组件之间的耦合性。

  1. HandlerMapping:处理器映射器

负责根据用户请求找到 Handler 即处理器(也就是我们所说的 Controller)。

  1. Handler:处理器

前端控制器的后端控制器,在DispatcherServlet 的控制下 Handler 对具体的用户请求进行处理。(这里所说的 Handler 就是指我们的 Controller)

4.HandlAdapter:处理器适配器

通过 HandlerAdapter 对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。

5.ViewResolver:视图解析器

ViewResolver 负责将处理结果生成 View 视图,ViewResolver 首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成 View 视图对象,最后对 View 进行渲染将处理结果通过页面展示给用户。

mvc:annotation-driven

1
2
3
4
5
6
7
@Controller
public class MyController3 {
@RequestMapping("/hello3")
public ModelAndView hello() {
return new ModelAndView("hello3");
}
}

要能够访问到这个接口,我们需要 RequestMappingHandlerMapping 才能定位到需要执行的方法,需要 RequestMappingHandlerAdapter,所以配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

<context:component-scan base-package="org.javaboy.helloworld"/>

<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping" id="handlerMapping"/>
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter" id="handlerAdapter"/>
<!--视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="viewResolver">
<property name="prefix" value="/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>

当然我们还有简化写法:

1
<mvc:annotation-driven>

@RequestMapping

这个注解用来标记一个接口, 表示我们用的是 RequestMappingHandlerMapping 这个处理器映射器。

请求url

标记请求 URL 很简单,只需要在相应的方法上添加该注解即可:

1
2
3
4
5
6
7
@Controller
public class HelloController {
@RequestMapping("/hello")
public ModelAndView hello() {
return new ModelAndView("hello");
}
}

当请求地址为 /hello 的时候,这个方法会被触发。其中,地址可以是多个,就是可以多个地址映射到同一个方法。

1
2
3
4
5
6
7
@Controller
public class HelloController {
@RequestMapping({"/hello","/hello2"})
public ModelAndView hello() {
return new ModelAndView("hello");
}
}

/hello 和 /hello2 都可以访问到该方法。

请求窄化

同一个项目中,会存在多个接口,例如订单相关的接口都是 /order/xxx 格式的,用户相关的接口都是 /user/xxx 格式的。为了方便处理,这里的前缀(就是 /order、/user)可以统一在 Controller 上面处理。

1
2
3
4
5
6
7
8
@Controller
@RequestMapping("/user")
public class HelloController {
@RequestMapping({"/hello","/hello2"})
public ModelAndView hello() {
return new ModelAndView("hello");
}
}

当类上加了 @RequestMapping 注解之后,此时,要想访问到 hello ,地址就应该是 /user/hello 或者 /user/hello2。

请求方法限定

使用 @RequestMapping 注解定义好的方法,可以被 GET 请求访问到,也可以被 POST 请求访问到,但是 DELETE 请求以及 PUT 请求不可以访问到。

当然,我们也可以指定具体的访问方法:

1
2
3
4
5
6
7
8
@Controller
@RequestMapping("/user")
public class HelloController {
@RequestMapping(value = "/hello",method = RequestMethod.GET)
public ModelAndView hello() {
return new ModelAndView("hello");
}
}

通过 @RequestMapping 注解,指定了该接口只能被 GET 请求访问到,此时,该接口就不可以被 POST 以及请求请求访问到了。

当然,限定的方法也可以有多个:

1
2
3
4
5
6
7
8
@Controller
@RequestMapping("/user")
public class HelloController {
@RequestMapping(value = "/hello",method = {RequestMethod.GET,RequestMethod.POST,RequestMethod.PUT,RequestMethod.DELETE})
public ModelAndView hello() {
return new ModelAndView("hello");
}
}

此时,这个接口就可以被 GET、POST、PUT、以及 DELETE 访问到了。

视图解析器

配置:

1
2
3
4
5
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>

对于/hello请求,DispatcherServlet会将请求转发到前缀+ view-name + suffix = /WEB-INF/jsp/hello.jsp。

Controller 方法的返回值

返回 ModelAndView

如果是前后端不分的开发,大部分情况下,我们返回 ModelAndView,即数据模型+视图:

1
2
3
4
5
6
7
8
9
10
@Controller
@RequestMapping("/user")
public class HelloController {
@RequestMapping("/hello")
public ModelAndView hello() {
ModelAndView mv = new ModelAndView("hello");
mv.addObject("username", "javaboy");
return mv;
}
}

Model 中,放我们的数据,然后在 ModelAndView 中指定视图名称。

返回 Void

没有返回值。没有返回值,并不一定真的没有返回值,只是方法的返回值为 void,我们可以通过其他方式给前端返回。实际上,这种方式也可以理解为 Servlet 中的那一套方案。

注意,由于默认的 Maven 项目没有 Servlet,因此这里需要额外添加一个依赖:

1
2
3
4
5
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>

服务端跳转:

1
2
3
4
@RequestMapping("/hello2")
public void hello2(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.getRequestDispatcher("/jsp/hello.jsp").forward(req,resp);//服务器端跳转
}

重定向:

1
2
3
4
@RequestMapping("/hello3")
public void hello3(HttpServletRequest req, HttpServletResponse resp) throws IOException {
resp.sendRedirect("/hello.jsp");
}

返回字符串

返回逻辑视图

1
2
3
4
5
@RequestMapping("/hello5")
public String hello5(Model model) {
model.addAttribute("username", "javaboy");//这是数据模型
return "hello";//表示去查找一个名为 hello 的视图
}

服务端跳转

1
2
3
4
@RequestMapping("/hello5")
public String hello5() {
return "forward:/jsp/hello.jsp";
}

客户端跳转

1
2
3
4
@RequestMapping("/hello5")
public String hello5() {
return "redirect:/user/hello";
}

真的返回字符串

1
2
3
4
5
@RequestMapping("/hello5")
@ResponseBody
public String hello5() {
return "redirect:/user/hello";
}

上面代码表示就是想返回一段内容为 redirect:/user/hello 的字符串,他没有特殊含义。注意,这里如果单纯的返回一个中文字符串,是会乱码的,可以在 @RequestMapping 中添加 produces 属性来解决:

1
2
3
4
5
@RequestMapping(value = "/hello5",produces = "text/html;charset=utf-8")
@ResponseBody
public String hello5() {
return "Java 语言程序设计";
}

参数绑定

默认支持的参数类型

默认支持的参数类型,就是可以直接写在 @RequestMapping 所注解的方法中的参数类型,一共有四类:

  • HttpServletRequest
  • HttpServletResponse
  • HttpSession
  • Model/ModelMap

简单数据类型

Integer、Boolean、Double 等等简单数据类型也都是支持的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Controller
public class BookController {
@RequestMapping("/book")
public String addBook() {
return "addbook";
}

@RequestMapping(value = "/doAdd",method = RequestMethod.POST)
@ResponseBody
public void doAdd(String name,String author,Double price,Boolean ispublic) {
System.out.println(name);
System.out.println(author);
System.out.println(price);
System.out.println(ispublic);
}
}

POST 请求传上来的中文会乱码,所以,我们在 web.xml 中再额外添加一个编码过滤器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<filter>
<filter-name>encoding</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceRequestEncoding</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

在上面的绑定中,有一个要求,表单中字段的 name 属性要和接口中的变量名一一对应,才能映射成功,否则服务端接收不到前端传来的数据。

如果前后端不一致,这个时候我们可以通过 @RequestParam 注解来解决。

这个注解的的功能主要有三方面:

  • 给变量取别名
  • 设置变量是否必填
  • 给变量设置默认值
1
2
3
4
5
6
7
8
@RequestMapping(value = "/doAdd",method = RequestMethod.POST)
@ResponseBody
public void doAdd(@RequestParam("name") String bookname, String author, Double price, Boolean ispublic) {
System.out.println(bookname);
System.out.println(author);
System.out.println(price);
System.out.println(ispublic);
}

注解中的 “name” 表示给 bookname 这个变量取的别名,也就是说,bookname 将接收前端传来的 name 这个变量的值。在这个注解中,还可以添加 required 属性和 defaultValue 属性,如下:

1
2
3
4
5
6
7
8
@RequestMapping(value = "/doAdd",method = RequestMethod.POST)
@ResponseBody
public void doAdd(@RequestParam(value = "name",required = true,defaultValue = "三国演义") String bookname, String author, Double price, Boolean ispublic) {
System.out.println(bookname);
System.out.println(author);
System.out.println(price);
System.out.println(ispublic);
}

required 属性默认为 true,即只要添加了 @RequestParam 注解,这个参数默认就是必填的,如果不填,请求无法提交,会报 400 错误,如果这个参数不是必填项,可以手动把 required 属性设置为 false。但是,如果同时设置了 defaultValue,这个时候,前端不传该参数到后端,即使 required 属性为 true,它也不会报错。

实体类

参数除了是简单数据类型之外,也可以是实体类。实际上,在开发中,大部分情况下,都是实体类。

1
2
3
4
5
@RequestMapping(value = "/doAdd",method = RequestMethod.POST)
@ResponseBody
public void doAdd(Book book) {
System.out.println(book);
}

前端页面传值的时候和上面的一样,只需要写属性名就可以了,不需要写 book 对象名。

自定义参数转换

特殊的数据类型,系统无法自动转换,例如日期。例如前端传一个日期到后端,后端不是用字符串接收,而是使用一个 Date 对象接收,这个时候就会出现参数类型转换失败。这个时候,需要我们手动定义参数类型转换器,将日期字符串手动转为一个 Date 对象。

1
2
3
4
5
6
7
8
9
10
11
12
@Component
public class DateConverter implements Converter<String, Date> {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
public Date convert(String source) {
try {
return sdf.parse(source);
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
}

在自定义的参数类型转换器中,将一个 String 转为 Date 对象,同时,将这个转换器注册为一个 Bean。

1
2
3
4
5
6
7
8
<mvc:annotation-driven conversion-service="conversionService"/>
<bean class="org.springframework.format.support.FormattingConversionServiceFactoryBean" id="conversionService">
<property name="converters">
<set>
<ref bean="dateConverter"/>
</set>
</property>
</bean>

配置完成后,在服务端就可以接收前端传来的日期参数了。

集合类的参数

String数组

String 数组可以直接用数组去接收,前端传递的时候,数组的传递其实就多相同的 key,这种一般用在 checkbox 中较多。

前端:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<form action="/doAdd" method="post">
<table>
<tr>
<td>书名:</td>
<td><input type="text" name="name"></td>
</tr>
<tr>
<td>作者姓名:</td>
<td><input type="text" name="author.name"></td>
</tr>
<tr>
<td>作者年龄:</td>
<td><input type="text" name="author.age"></td>
</tr>
<tr>
<td>出生日期:</td>
<td><input type="date" name="author.birthday"></td>
</tr>
<tr>
<td>兴趣爱好:</td>
<td>
<input type="checkbox" name="favorites" value="足球">足球
<input type="checkbox" name="favorites" value="篮球">篮球
<input type="checkbox" name="favorites" value="乒乓球">乒乓球
</td>
</tr>
<tr>
<td>价格:</td>
<td><input type="text" name="price"></td>
</tr>
<tr>
<td>是否上架:</td>
<td>
<input type="radio" value="true" name="ispublic">
<input type="radio" value="false" name="ispublic">
</td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="添加">
</td>
</tr>
</table>
</form>
1
2
3
4
5
6
@RequestMapping(value = "/doAdd",method = RequestMethod.POST)
@ResponseBody
public void doAdd(Book book,String[] favorites) {
System.out.println(Arrays.toString(favorites));
System.out.println(book);
}

注意,前端传来的数组对象,服务端不可以使用 List 集合去接收。

list集合

如果需要使用 List 集合接收前端传来的数据,List 集合本身需要放在一个封装对象中,这个时候,List 中,可以是基本数据类型,也可以是对象。例如有一个班级类,班级里边有学生,学生有多个:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
public class MyClass {
private Integer id;
private List<Student> students;

@Override
public String toString() {
return "MyClass{" +
"id=" + id +
", students=" + students +
'}';
}

public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}

public List<Student> getStudents() {
return students;
}

public void setStudents(List<Student> students) {
this.students = students;
}
}
public class Student {
private Integer id;
private String name;

@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}

public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}

添加班级的时候,可以传递多个 Student,前端页面写法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<form action="/addclass" method="post">
<table>
<tr>
<td>班级编号:</td>
<td><input type="text" name="id"></td>
</tr>
<tr>
<td>学生编号:</td>
<td><input type="text" name="students[0].id"></td>
</tr>
<tr>
<td>学生姓名:</td>
<td><input type="text" name="students[0].name"></td>
</tr>
<tr>
<td>学生编号:</td>
<td><input type="text" name="students[1].id"></td>
</tr>
<tr>
<td>学生姓名:</td>
<td><input type="text" name="students[1].name"></td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="提交">
</td>
</tr>
</table>
</form>
1
2
3
4
5
@RequestMapping("/addclass")
@ResponseBody
public void addClass(MyClass myClass) {
System.out.println(myClass);
}

Map

相对于实体类而言,Map 是一种比较灵活的方案,但是,Map 可维护性比较差,因此一般不推荐使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class MyClass {
private Integer id;
private List<Student> students;
private Map<String, Object> info;

@Override
public String toString() {
return "MyClass{" +
"id=" + id +
", students=" + students +
", info=" + info +
'}';
}

public Map<String, Object> getInfo() {
return info;
}

public void setInfo(Map<String, Object> info) {
this.info = info;
}

public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}

public List<Student> getStudents() {
return students;
}

public void setStudents(List<Student> students) {
this.students = students;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<form action="/addclass" method="post">
<table>
<tr>
<td>班级编号:</td>
<td><input type="text" name="id"></td>
</tr>
<tr>
<td>班级名称:</td>
<td><input type="text" name="info['name']"></td>
</tr>
<tr>
<td>班级位置:</td>
<td><input type="text" name="info['pos']"></td>
</tr>
<tr>
<td>学生编号:</td>
<td><input type="text" name="students[0].id"></td>
</tr>
<tr>
<td>学生姓名:</td>
<td><input type="text" name="students[0].name"></td>
</tr>
<tr>
<td>学生编号:</td>
<td><input type="text" name="students[1].id"></td>
</tr>
<tr>
<td>学生姓名:</td>
<td><input type="text" name="students[1].name"></td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="提交">
</td>
</tr>
</table>
</form>

服务端请求参数校验

普通校验

首先,我们需要加入校验需要的依赖:

1
2
3
4
5
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.1.0.Final</version>
</dependency>
1
2
3
4
<bean class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" id="validatorFactoryBean">
<property name="providerClass" value="org.hibernate.validator.HibernateValidator"/>
</bean>
<mvc:annotation-driven validator="validatorFactoryBean"/>

假设学生编号不能为空,学生姓名长度不能超过 10 且不能为空,邮箱地址要合法,年龄不能超过 150。那么在定义实体类的时候,就可以加入这个判断条件了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
public class Student {
@NotNull
private Integer id;
@NotNull
@Size(min = 2,max = 10)
private String name;
@Email
private String email;
@Max(150)
private Integer age;

public String getEmail() {
return email;
}

@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", email='" + email + '\'' +
", age=" + age +
'}';
}

public void setEmail(String email) {
this.email = email;
}

public Integer getAge() {
return age;
}

public void setAge(Integer age) {
this.age = age;
}

public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}

定义完成后,接下来,在 Controller 中定义接口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Controller
public class StudentController {
@RequestMapping("/addstudent")
@ResponseBody
public void addStudent(@Validated Student student, BindingResult result) {
if (result != null) {
//校验未通过,获取所有的异常信息并展示出来
List<ObjectError> allErrors = result.getAllErrors();
for (ObjectError allError : allErrors) {
System.out.println(allError.getObjectName()+":"+allError.getDefaultMessage());
}
}
}
}

在这里:

  • @Validated 表示 Student 中定义的校验规则将会生效
  • BindingResult 表示出错信息,如果这个变量不为空,表示有错误,否则校验通过。

分组校验

由于校验规则都是定义在实体类上面的,但是,在不同的数据提交环境下,校验规则可能不一样。例如,用户的 id 是自增长的,添加的时候,可以不用传递用户 id,但是修改的时候则必须传递用户 id,这种情况下,就需要使用分组校验。

分组校验,首先需要定义校验组,所谓的校验组,其实就是空接口:

1
2
3
4
public interface ValidationGroup1 {
}
public interface ValidationGroup2 {
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
public class Student {
@NotNull(message = "{student.id.notnull}",groups = ValidationGroup1.class)
private Integer id;
@NotNull(message = "{student.name.notnull}",groups = {ValidationGroup1.class, ValidationGroup2.class})
@Size(min = 2,max = 10,message = "{student.name.length}",groups = {ValidationGroup1.class, ValidationGroup2.class})
private String name;
@Email(message = "{student.email.error}",groups = {ValidationGroup1.class, ValidationGroup2.class})
private String email;
@Max(value = 150,message = "{student.age.error}",groups = {ValidationGroup2.class})
private Integer age;

public String getEmail() {
return email;
}

@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", email='" + email + '\'' +
", age=" + age +
'}';
}

public void setEmail(String email) {
this.email = email;
}

public Integer getAge() {
return age;
}

public void setAge(Integer age) {
this.age = age;
}

public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}

在 group 中指定每一个校验规则所属的组,一个规则可以属于一个组,也可以属于多个组。

最后,在接收参数的地方,指定校验组:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Controller
public class StudentController {
@RequestMapping("/addstudent")
@ResponseBody
public void addStudent(@Validated(ValidationGroup2.class) Student student, BindingResult result) {
if (result != null) {
//校验未通过,获取所有的异常信息并展示出来
List<ObjectError> allErrors = result.getAllErrors();
for (ObjectError allError : allErrors) {
System.out.println(allError.getObjectName()+":"+allError.getDefaultMessage());
}
}
}
}

配置完成后,属于 ValidationGroup2 这个组的校验规则,才会生效。

校验注解

校验注解,主要有如下几种:

  • @Null 被注解的元素必须为 null
  • @NotNull 被注解的元素必须不为 null
  • @AssertTrue 被注解的元素必须为 true
  • @AssertFalse 被注解的元素必须为 false
  • @Min(value) 被注解的元素必须是一个数字,其值必须大于等于指定的最小值
  • @Max(value) 被注解的元素必须是一个数字,其值必须小于等于指定的最大值
  • @DecimalMin(value) 被注解的元素必须是一个数字,其值必须大于等于指定的最小值
  • @DecimalMax(value) 被注解的元素必须是一个数字,其值必须小于等于指定的最大值
  • @Size(max=, min=) 被注解的元素的大小必须在指定的范围内
  • @Digits (integer, fraction) 被注解的元素必须是一个数字,其值必须在可接受的范围内
  • @Past 被注解的元素必须是一个过去的日期
  • @Future 被注解的元素必须是一个将来的日期
  • @Pattern(regex=,flag=) 被注解的元素必须符合指定的正则表达式
  • @NotBlank(message =) 验证字符串非 null,且长度必须大于0
  • @Email 被注解的元素必须是电子邮箱地址
  • @Length(min=,max=) 被注解的字符串的大小必须在指定的范围内
  • @NotEmpty 被注解的字符串的必须非空
  • @Range(min=,max=,message=) 被注解的元素必须在合适的范围内
文章目录
  1. 1. 概述
  2. 2. 与Spring关系
  3. 3. 工作流程及组件
  4. 4. mvc:annotation-driven
  5. 5. @RequestMapping
    1. 5.1. 请求url
    2. 5.2. 请求窄化
    3. 5.3. 请求方法限定
  6. 6. 视图解析器
  7. 7. Controller 方法的返回值
    1. 7.1. 返回 ModelAndView
    2. 7.2. 返回 Void
      1. 7.2.1. 服务端跳转:
      2. 7.2.2. 重定向:
    3. 7.3. 返回字符串
      1. 7.3.1. 返回逻辑视图
      2. 7.3.2. 服务端跳转
      3. 7.3.3. 客户端跳转
        1. 7.3.3.1. 真的返回字符串
  8. 8. 参数绑定
    1. 8.1. 默认支持的参数类型
    2. 8.2. 简单数据类型
    3. 8.3. 实体类
    4. 8.4. 自定义参数转换
    5. 8.5. 集合类的参数
      1. 8.5.1. String数组
      2. 8.5.2. list集合
      3. 8.5.3. Map
  9. 9. 服务端请求参数校验
    1. 9.1. 普通校验
    2. 9.2. 分组校验
    3. 9.3. 校验注解
|