校验框架

校验框架入门

表单校验的重要性

  • 表单校验保障了数据有效性、安全性

image-20200505144306747

数据可以随意输入,导致错误的结果。后端表单校验的重要性。

表单校验分类

  • 校验位置:
    • 客户端校验
    • 服务端校验
  • 校验内容与对应方式:
    • 格式校验
      • 客户端:使用Js技术,利用正则表达式校验
      • 服务端:使用校验框架
    • 逻辑校验
      • 客户端:使用ajax发送要校验的数据,在服务端完成逻辑校验,返回校验结果
      • 服务端:接收到完整的请求后,在执行业务操作前,完成逻辑校验

表单校验规则

  • 长度:例如用户名长度,评论字符数量
  • 非法字符:例如用户名组成
  • 数据格式:例如Email格式、 IP地址格式
  • 边界值:例如转账金额上限,年龄上下限
  • 重复性:例如用户名是否重复

表单校验框架

  • JSR(Java Specification Requests):Java 规范提案

    303:提供bean属性相关校验规则

  • JSR规范列表

    • 企业应用技术
      Contexts and Dependency Injection for Java (Web Beans 1.0) (JSR 299)
      Dependency Injection for Java 1.0 (JSR 330)@postConstruct, @PreDestroy
      Bean Validation 1.0 (JSR 303)
      Enterprise JavaBeans 3.1 (includes Interceptors 1.1) (JSR 318)
      Java EE Connector Architecture 1.6 (JSR 322)
      Java Persistence 2.0 (JSR 317)
      Common Annotations for the Java Platform 1.1 (JSR 250)
      Java Message Service API 1.1 (JSR 914)
      Java Transaction API (JTA) 1.1 (JSR 907)
      JavaMail 1.4 (JSR 919)
    • Web应用技术
      Java Servlet 3.0 (JSR 315)
      JavaServer Faces 2.0 (JSR 314)
      JavaServer Pages 2.2/Expression Language 2.2 (JSR 245)
      Standard Tag Library for JavaServer Pages (JSTL) 1.2 (JSR 52)
      Debugging Support for Other Languages 1.0 (JSR 45)
      模块化 (JSR 294)
      Swing应用框架 (JSR 296)
      JavaBeans Activation Framework (JAF) 1.1 (JSR 925)
      Streaming API for XML (StAX) 1.0 (JSR 173)
    • 管理与安全技术
      Java Authentication Service Provider Interface for Containers (JSR 196)
      Java Authorization Contract for Containers 1.3 (JSR 115)
      Java EE Application Deployment 1.2 (JSR 88)
      J2EE Management 1.1 (JSR 77)
       Java SE中与Java EE有关的规范
      JCache API (JSR 107)
      Java Memory Model (JSR 133)
      Concurrency Utilitie (JSR 166)
      Java API for XML Processing (JAXP) 1.3 (JSR 206)
      Java Database Connectivity 4.0 (JSR 221)
      Java Management Extensions (JMX) 2.0 (JSR 255)
      Java Portlet API (JSR 286)
  • Web Service技术
    Java Date与Time API (JSR 310)
    Java API for RESTful Web Services (JAX-RS) 1.1 (JSR 311)
    Implementing Enterprise Web Services 1.3 (JSR 109)
    Java API for XML-Based Web Services (JAX-WS) 2.2 (JSR 224)
    Java Architecture for XML Binding (JAXB) 2.2 (JSR 222)
    Web Services Metadata for the Java Platform (JSR 181)
    Java API for XML-Based RPC (JAX-RPC) 1.1 (JSR 101)
    Java APIs for XML Messaging 1.3 (JSR 67)
    Java API for XML Registries (JAXR) 1.0 (JSR 93)

  • JCP(Java Community Process):Java社区

  • Hibernate框架中包含一套独立的校验框架hibernate-validator

    导入坐标

    1
    2
    3
    4
    5
    6
    <!--支持tomcat8.5以上-->
    <dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>6.1.0.Final</version>
    </dependency>
1
2
3
4
5
6
<!--支持tomcat7-->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.2.1.Final</version>
</dependency>

注意:
tomcat7 :搭配hibernate-validator版本5...Final
tomcat8.5↑ :搭配hibernate-validator版本6...Final

快速使用

1.编写实体类,存放表单数据。并且设置校验规则

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
package cn.itcast.domain;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.validator.constraints.NotBlank;
import org.springframework.format.annotation.DateTimeFormat;

import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import java.util.Date;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
@NotBlank(message = "姓名不能为空")
private String name;

@NotNull(message = "年龄不能为空")//此处不能用NotBlank,因为该注解只能校验字符串,而age是数字
@Max(message = "年龄不能超过100",value = 100)
@Min(message = "年龄不能小于1",value = 1)
private Integer age;
}

2.编写处理器,接受表单数据,并且启用校验

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
package cn.itcast.controller;

import cn.itcast.domain.User;
import org.springframework.stereotype.Controller;
import org.springframework.validation.Errors;
import org.springframework.validation.FieldError;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.HashMap;
import java.util.Map;

@Controller
@RequestMapping("/user")
@CrossOrigin
public class UserController {

@RequestMapping("/reg")
@ResponseBody
public Map method(@Validated User user, Errors errors){//errors中存放校验失败的提示信息
HashMap<Object, Object> map = new HashMap<>();
HashMap<Object, Object> errorInfo = new HashMap<>();//存放字段名对应的错误提示
//判断是否有错误信息
if(errors.hasErrors()){
for (FieldError e : errors.getFieldErrors()) {//errors.getFieldErrors()获取所有的错误信息
//e.getField()表示获取属性名,e.getDefaultMessage()获取错误提示信息
errorInfo.put(e.getField(),e.getDefaultMessage());
}
}

if(errorInfo.size()==0){//没有错误数据
map.put("status",true);
}else{
map.put("status",false);
map.put("errorInfos",errorInfo);
}

return map;
}
}

3.测试,访问 http://localhost/user/reg?name&age 结果如下

注意:测试的时候必须写清楚发送给服务器哪些字段,如果不写,服务器可能不校验。

1
2
3
4
5
6
7
{
"errorInfos": {
"name": "姓名不能为空",
"age": "请输入年龄"
},
"status": false
}

1593222887618

多规则校验

  • 同一个属性可以添加多个校验器
1
2
3
4
@NotNull(message = "请输入您的年龄")
@Max(value = 60,message = "年龄最大值不允许超过60岁")
@Min(value = 18,message = "年龄最小值不允许低于18岁")
private Integer age;//员工年龄
  • 3种判定空校验器的区别

image-20200506160725709

@Null 限制只能为null
@NotNull 限制必须不为null
@AssertFalse 限制必须为false
@AssertTrue 限制必须为true
@DecimalMax(value) 限制必须为一个不大于指定值的数字
@DecimalMin(value) 限制必须为一个不小于指定值的数字
@Digits(integer,fraction) 限制必须为一个小数,且整数部分的位数不能超过integer,小数部分的位数不能超过fraction
@Future 限制必须是一个将来的日期
@Max(value) 限制必须为一个不大于指定值的数字
@Min(value) 限制必须为一个不小于指定值的数字
@Past 限制必须是一个过去的日期
@Pattern(value) 限制必须符合指定的正则表达式
@Size(max,min) 限制字符长度必须在min到max之间
@Past 验证注解的元素值(日期类型)比当前时间早
@NotEmpty 验证注解的元素值不为null且不为空(字符串长度不为0、集合大小不为0)
@NotBlank 验证注解的元素值不为空(不为null、去除首位空格后长度为0),不同于@NotEmpty,**@NotBlank只应用于字符串且在比较时会去除字符串的空格**
@Email 验证注解的元素值是Email,也可以通过正则表达式和flag指定自定义的email格式
需要注意每个注解对应的数据类型

嵌套校验

 名称:@Valid
 类型:属性注解
 位置:实体类中的引用类型属性上方
 作用:设定当前应用类型属性中的属性开启校验
 范例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package cn.itcast.domain;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.validator.constraints.NotBlank;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Address {
@NotBlank(message = "省名不能为空")
/**省的名字*/
private String province;

@NotBlank(message = "城市名不能为空")
/**城市的名字*/
private String city;
}
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
package cn.itcast.domain;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.validator.constraints.NotBlank;
import org.springframework.format.annotation.DateTimeFormat;

import javax.validation.Valid;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import java.util.Date;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
@NotBlank(message = "姓名不能为空")
@Pattern(regexp = "^[A-Za-z_@.]{6,10}$",message = "用户名必须是6-10位之间的字母、下划线、@、.")
private String name;

@NotNull(message = "年龄不能为空")//此处不能用NotBlank,因为该注解只能校验字符串,而age是数字
@Max(message = "年龄不能超过100",value = 100)
@Min(message = "年龄不能小于1",value = 1)
private Integer age;

@Valid
private Address address;
}

注意:开启嵌套校验后,被校验对象内部需要添加对应的校验规则

在访问接口的时候,必须加字段名,否则可能不校验

1593226005067

分组校验

  • 同一个模块,根据执行的业务不同,需要校验的属性会有不同
    • 新增用户
    • 修改用户
  • 对不同种类的属性进行分组,在校验时可以指定参与校验的字段所属的组类别
    • 定义组(通用)
    • 为属性设置所属组,可以设置多个
    • 开启组校验

下图是简易版步骤图

1593181917458

第一步:定义了两个组,一个是注册的时候校验,一个是修改的时候校验

1
2
3
4
package cn.itcast.group;

public interface RegGroup {
}
1
2
3
4
package cn.itcast.group;

public interface UpdateUserGroup {
}

第二步:定义User\Address实体类,指定校验规则,并分组校验

规则:注册的时候校验帐号和密码,修改的时候校验密码和地址

Address

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package cn.itcast.domain;

import cn.itcast.group.RegGroup;
import cn.itcast.group.UpdateUserGroup;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.validator.constraints.NotBlank;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Address {
@NotBlank(message = "省名不能为空",groups = {UpdateUserGroup.class})
/**省的名字*/
private String province;

@NotBlank(message = "城市名不能为空",groups = {UpdateUserGroup.class})
/**城市的名字*/
private String city;
}

User

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
package cn.itcast.domain;

import cn.itcast.group.RegGroup;
import cn.itcast.group.UpdateUserGroup;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.validator.constraints.NotBlank;
import org.springframework.format.annotation.DateTimeFormat;

import javax.validation.Valid;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import java.util.Date;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
@NotBlank(message = "用户名不能为空",groups = RegGroup.class)
@Pattern(regexp = "^[A-Za-z_@.]{6,10}$",message = "用户名必须是6-10位之间的字母、下划线、@、.",groups = RegGroup.class)
private String username;

@NotBlank(message = "密码不能为空",groups = {RegGroup.class, UpdateUserGroup.class})
@Pattern(regexp = "^[A-Za-z_@.]{6,10}$",message = "密码必须是6-10位之间的字母、下划线、@、.",groups = {RegGroup.class, UpdateUserGroup.class})
private String password;

@Valid()
private Address address;
}

第三步 在controller层,分别定义两个接口,一个是注册接口,使用注册的校验规则,另一个是修改接口,使用修改的校验规则

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
57
58
59
60
61
62
63
64
65
package cn.itcast.controller;

import cn.itcast.domain.User;
import cn.itcast.group.RegGroup;
import cn.itcast.group.UpdateUserGroup;
import org.springframework.stereotype.Controller;
import org.springframework.validation.Errors;
import org.springframework.validation.FieldError;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.HashMap;
import java.util.Map;

@Controller
@RequestMapping("/user")
@CrossOrigin
public class UserController {

@RequestMapping("/reg")
@ResponseBody
public Map reg(@Validated(RegGroup.class) User user, Errors errors){//errors中存放校验失败的提示信息
HashMap<Object, Object> map = new HashMap<>();
HashMap<Object, Object> errorInfo = new HashMap<>();//存放字段名对应的错误提示
//判断是否有错误信息
if(errors.hasErrors()){
for (FieldError e : errors.getFieldErrors()) {//errors.getFieldErrors()获取所有的错误信息
//e.getField()表示获取属性名,e.getDefaultMessage()获取错误提示信息
errorInfo.put(e.getField(),e.getDefaultMessage());
}
}

if(errorInfo.size()==0){//没有错误数据
map.put("status",true);
}else{
map.put("status",false);
map.put("errorInfos",errorInfo);
}

return map;
}
@RequestMapping("/update")
@ResponseBody
public Map update(@Validated(UpdateUserGroup.class) User user, Errors errors){//errors中存放校验失败的提示信息
HashMap<Object, Object> map = new HashMap<>();
HashMap<Object, Object> errorInfo = new HashMap<>();//存放字段名对应的错误提示
//判断是否有错误信息
if(errors.hasErrors()){
for (FieldError e : errors.getFieldErrors()) {//errors.getFieldErrors()获取所有的错误信息
//e.getField()表示获取属性名,e.getDefaultMessage()获取错误提示信息
errorInfo.put(e.getField(),e.getDefaultMessage());
}
}

if(errorInfo.size()==0){//没有错误数据
map.put("status",true);
}else{
map.put("status",false);
map.put("errorInfos",errorInfo);
}

return map;
}
}

测试结果

注册:没有校验地址

1593226827447

修改:没有校验帐号

1593226807450

ssm整合

整合流程简介

首先要明白Spring管理非controller层,springmvc管理controller层

1.配置Spring集成MyBatis

1.1开启包扫描,不扫描controller层

1.2集成Mybatis

1.3集成PageHelper

1.4开启事物

2.配置SpringMVC的spring-mvc.xml

2.1开启包扫描,只扫描controller层

2.2开启springmvc的注解驱动

2.3开启静态资源访问

2.4配置视图解析器

3.配置web.xml

3.1配置DispatcherServlet,加载并解析spring-mvc.xml

3.2配置乱码过滤器

3.3配置监听器,tomcat启动时加载applicationContext.xml

4.创建Result,统一返回的数据

5.创建异常处理器

项目环境初始化

引入依赖

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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
<dependencies>
<!--jackson-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.0</version>
</dependency>
<!-- servlet3.1规范的坐标 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!--jsp坐标-->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>

<!--Lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.6</version>
</dependency>

<!--文件上传-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.3</version>
</dependency>
<!--数据校验,支持tomcat7-->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.2.1.Final</version>
</dependency>
<!--spring的坐标-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
<!--spring web的坐标-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
<!--springmvc的坐标-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
<!--Spring集成Junit测试-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<!--Spring集成Aspect切面-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.13</version>
</dependency>
<!--Spring 事物-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.3</version>
</dependency>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.46</version>
</dependency>
<!--spring连接数据库-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
<!--数据库连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.21</version>
</dependency>
<!--spring集成mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.0</version>
</dependency>
<!--spring集成junit-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!--分页插件-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.1.2</version>
</dependency>
</dependencies>

<build>
<plugins>
<!--jdk编译插件-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>utf-8</encoding>
</configuration>
</plugin>

<!--tomcat插件-->
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<!-- tomcat7的插件, 不同tomcat版本这个也不一样 -->
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.1</version>
<configuration>
<!-- 通过maven tomcat7:run运行项目时,访问项目的端口号 -->
<port>80</port>
<!-- 项目虚拟路径 如果配置的, 则访问路径为localhost:8080/-->
<path>/</path>
</configuration>
</plugin>
</plugins>
</build>

创建数据库

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
/*
SQLyog Ultimate v12.09 (64 bit)
MySQL - 5.5.40 : Database - spring01
*********************************************************************
*/


/*!40101 SET NAMES utf8 */;

/*!40101 SET SQL_MODE=''*/;

/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/`spring01` /*!40100 DEFAULT CHARACTER SET utf8 */;

USE `spring01`;

/*Table structure for table `account` */

DROP TABLE IF EXISTS `account`;

CREATE TABLE `account` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(24) DEFAULT NULL,
`money` double(10,2) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

/*Data for the table `account` */

insert into `account`(`id`,`name`,`money`) values (1,'jack',1000.00),(2,'tom',1000.00),(3,'rose',1000.00);

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

创建dao\service\domain

创建实体类 Account

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package cn.itcast.domain;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Account {
private Integer id;
private String name;
private Double money;
}

创建 Dao

1
2
3
4
5
6
7
8
9
10
package cn.itcast.dao;

import cn.itcast.domain.Account;

import java.util.List;

public interface AccountDao {
@Select("select * from account")
List<Account> findAll();
}

创建Service

1
2
3
4
5
6
7
8
9
package cn.itcast.service;

import cn.itcast.domain.Account;

import java.util.List;

public interface AccountService {
List<Account> findAll() ;
}

创建Service实现类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package cn.itcast.service.impl;

import cn.itcast.dao.AccountDao;
import cn.itcast.domain.Account;
import cn.itcast.service.AccountService;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

@Service
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao accountDao;

public List<Account> findAll() {
return accountDao.findAll();
}
}

创建jdbc.properties

1
2
3
4
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring01?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true
jdbc.username=root
jdbc.password=root

编写Spring核心配置(3步)

1.配置包扫描

2.集成MyBatis(顺便集成分页插件),集成mybatis需要三个bean

3.配置事物

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
57
<?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:tx="http://www.springframework.org/schema/tx"
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/tx http://www.springframework.org/schema/tx/spring-tx.xsd
">


<!--1.配置包扫描-->
<context:component-scan base-package="cn.itcast">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>


<!--2.集成MyBatis-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<bean class="com.alibaba.druid.pool.DruidDataSource" id="dataSource">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>

<bean class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="typeAliasesPackage" value="cn.itcast.domain"></property>
<!--4.集成分页-->
<property name="plugins">
<array>
<bean class="com.github.pagehelper.PageInterceptor">
<property name="properties">
<props>
<prop key="helperDialect">mysql</prop>
<!--reasonable:分页合理化参数,默认值为false。当该参数设置为 true 时,pageNum<=0 时会查询第一页,
pageNum>pages(超过总数时),会查询最后一页。
默认false 时,直接根据参数进行查询。-->
<prop key="reasonable">true</prop>
</props>
</property>
</bean>
</array>
</property>
</bean>

<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="cn.itcast.dao"></property>
</bean>

<!--3.配置平台事物管理器,启用事物注解驱动在第一行-->
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="transactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
</beans>

测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package cn.itcast.service.impl;

import cn.itcast.service.AccountService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AccountServiceImplTest {

@Autowired
private AccountService accountService ;
@Test
public void findAll() {
System.out.println(accountService.findAll());
}
}

配置SpringMVC(4步)

1.配置包扫描,只扫controller

2.启用springmvc注解

3.静态资源放行

4.配置视图解析器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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">
<!--1.配置包扫描,只扫controller-->
<context:component-scan base-package="cn.itcast">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

<!--2.启用springmvc注解-->
<mvc:annotation-driven/>

<!--3.静态资源放行-->
<mvc:default-servlet-handler/>

<!--4.配置视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>

配置web.xml

配置web核心三大组件

1.listener:ContextLoaderListener

2.filter:CharacterEncodingFilter

3.servlet:DispatcherServlet

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
57
58
59
60
61
62
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
<display-name>Archetype Created Web Application</display-name>

<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>




<!--配置过滤器,解决中文乱码,支持restful风格代码-->
<filter>
<filter-name>characterEncodingFilter</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>
</filter>
<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<servlet-name>dispatcherServlet</servlet-name>
</filter-mapping>




<!--配置监听器 加载spring的核心配置-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>



<!--配置Servlet,加载springmvc的核心配置-->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>

编写Restful风格控制器

AccountController

测试地址:http://localhost/account

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
package cn.itcast.controller;

import cn.itcast.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/account")
public class AccountController {
@Autowired
private AccountService accountService;

/**
* 查询所有
* @return
*/
@GetMapping
public Object findAll(){
return accountService.findAll();
}
}

创建Result统一返回数据格式

Result

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package cn.itcast.domain;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Result implements Serializable {
/**操作成功或失败的状态*/
private boolean flag;
/**小时提示*/
private String message;
/**消息状态码*/
private Integer code;
/**数据*/
private Object data;
}

常量类

1
2
3
4
5
6
7
8
9
package cn.itcast.constant;

public class CodeConstant {
//账户模块以1开头,长度是6
/**查询账户成功*/
public static final Integer ACCOUNT_GET_SUCCESS = 100001;
/**查询账户失败*/
public static final Integer ACCOUNT_GET_ERROR = 100002;
}
1
2
3
4
5
6
7
8
9
package cn.itcast.constant;

public class MessageConstant {
//账户模块以1开头,长度是6
/**查询账户成功*/
public static final String ACCOUNT_GET_SUCCESS = "查询账户成功";
/**查询账户失败*/
public static final String ACCOUNT_GET_ERROR = "查询账户失败";
}

统一异常处理

Part5-2:自定义异常

  • 设定自定义异常,封装程序执行过程中出现的问题,便于表现层进行统一的异常拦截并进行处理
    • BusinessException
    • SystemException
  • 自定义异常消息返回时需要与业务正常执行的消息按照统一的格式进行处理

定义BusinessException

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
public class BusinessException extends RuntimeException {
//自定义异常中封装对应的错误编码,用于异常处理时获取对应的操作编码
private Integer code;

public Integer getCode() {
return code;
}

public void setCode(Integer code) {
this.code = code;
}

public BusinessException(Integer code) {
this.code = code;
}

public BusinessException(String message, Integer code) {
super(message);
this.code = code;
}

public BusinessException(String message, Throwable cause,Integer code) {
super(message, cause);
this.code = code;
}

public BusinessException(Throwable cause,Integer code) {
super(cause);
this.code = code;
}

public BusinessException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace,Integer code) {
super(message, cause, enableSuppression, writableStackTrace);
this.code = code;
}
}
1
2
3
4
5
6
7
@GetMapping("/{uuid}")
public Result get(@PathVariable Integer uuid){
User user = userService.get(uuid);
//模拟出现异常,使用条件控制,便于测试结果
if (uuid == 10 ) throw new BusinessException("查询出错啦,请重试!",Code.GET_ERROR);
return new Result(null != user ?Code.GET_OK: Code.GET_ERROR,user);
}

返回消息兼容异常信息

1
2
3
4
5
6
7
8
9
10
@Component
@ControllerAdvice
public class ProjectExceptionAdivce {
@ExceptionHandler(BusinessException.class)
@ResponseBody
//对出现异常的情况进行拦截,并将其处理成统一的页面数据结果格式
public Result doBusinessException(BusinessException e){
return new Result(e.getCode(),e.getMessage());
}
}