一、项目功能概述
电商秒杀需要完成的3个功能:
1.展示一个商品列表页面,我们可以从中看到可秒杀的商品列表
2.点击进入商品详情页,获取该商品的详细信息
3.秒杀时间开始后,点击进入下单确认页面,并支付成功
二、基于SpringBoot进行项目环境搭建
步骤1:创建一个maven工程,使用quickStart骨架。
步骤2:在pom.xml导入SpringBoot相关依赖。
1 <?xml version="1.0" encoding="UTF-8"?>
2
3 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5 <modelVersion>4.0.0</modelVersion>
6
7 <groupId>org.example</groupId>
8 <artifactId>Spike</artifactId>
9 <version>1.0-SNAPSHOT</version>
10
11 <name>Spike</name>
12 <!-- FIXME change it to the project's website -->
13 <url>http://www.example.com</url>
14
15 <parent>
16 <groupId>org.springframework.boot</groupId>
17 <artifactId>spring-boot-starter-parent</artifactId>
18 <version>2.0.5.RELEASE</version>
19 </parent>
20
21 <properties>
22 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
23 <maven.compiler.source>1.8</maven.compiler.source>
24 <maven.compiler.target>1.8</maven.compiler.target>
25 </properties>
26
27 <dependencies>
28 <dependency>
29 <groupId>org.springframework.boot</groupId>
30 <artifactId>spring-boot-starter-web</artifactId>
31 </dependency>
32 <dependency>
33 <groupId>junit</groupId>
34 <artifactId>junit</artifactId>
35 <version>4.11</version>
36 <scope>test</scope>
37 </dependency>
38 </dependencies>
39
40 <build>
41 <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
42 <plugins>
43 <!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
44 <plugin>
45 <artifactId>maven-clean-plugin</artifactId>
46 <version>3.1.0</version>
47 </plugin>
48 <!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
49 <plugin>
50 <artifactId>maven-resources-plugin</artifactId>
51 <version>3.0.2</version>
52 </plugin>
53 <plugin>
54 <artifactId>maven-compiler-plugin</artifactId>
55 <version>3.8.0</version>
56 </plugin>
57 <plugin>
58 <artifactId>maven-surefire-plugin</artifactId>
59 <version>2.22.1</version>
60 </plugin>
61 <plugin>
62 <artifactId>maven-jar-plugin</artifactId>
63 <version>3.0.2</version>
64 </plugin>
65 <plugin>
66 <artifactId>maven-install-plugin</artifactId>
67 <version>2.5.2</version>
68 </plugin>
69 <plugin>
70 <artifactId>maven-deploy-plugin</artifactId>
71 <version>2.8.2</version>
72 </plugin>
73 <!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
74 <plugin>
75 <artifactId>maven-site-plugin</artifactId>
76 <version>3.7.1</version>
77 </plugin>
78 <plugin>
79 <artifactId>maven-project-info-reports-plugin</artifactId>
80 <version>3.0.0</version>
81 </plugin>
82 </plugins>
83 </pluginManagement>
84 </build>
85 </project>
pom.xml
步骤3:在main/java/app中,我们对SpringBoot和SpringMVC进行简单的配置工作。掌握这几个注解的作用。
1 package org.example;
2
3 import org.springframework.boot.SpringApplication;
4 import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
5 import org.springframework.web.bind.annotation.RequestMapping;
6 import org.springframework.web.bind.annotation.RestController;
7
8 //SpringBoot会帮我们启动tomcat,并加载默认配置
9 @EnableAutoConfiguration
10 //SpringMVC相关配置
11 @RestController
12 public class App {
13 @RequestMapping("/")
14 public String home(){
15 //网页中输出
16 return "Hello World!";
17 }
18 public static void main( String[] args ){
19 //控制台输出
20 System.out.println( "Hello World!" );
21 SpringApplication.run(App.class,args);
22 }
23 }
运行结果:
用浏览器打开http://localhost:8080/,我们可以看到页面上输出:Hello World!
同时,控制台也输出了Hello World!,以及一些Spring相关的信息。
SpringBoot小技巧:可以在resource目录下创建一个application.propeties配置文件,在其中写:server.port = 端口号来设置端口号。
步骤4:接入mybatis,首先在pom.xml添加需要的依赖(mysql,druid连接池,mybatis)
写一个plugin标签,引入对应的mybatis自动生成文件的插件 {
添加对应的依赖:mybatis generator的core(第一次使用要单独在前面导入依赖,不可直接放在plugin中),mysql数据库的解析
写一个excution标签:设置允许移动生成的文件,允许自动覆盖文件(实际工作中不可以)
写一个configuration标签:指定mybatis generator 配置文件的路径 }
1 <?xml version="1.0" encoding="UTF-8"?>
2
3 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5 <modelVersion>4.0.0</modelVersion>
6
7 <groupId>org.example</groupId>
8 <artifactId>Spike</artifactId>
9 <version>1.0-SNAPSHOT</version>
10
11 <name>Spike</name>
12 <!-- FIXME change it to the project's website -->
13 <url>http://www.example.com</url>
14
15 <parent>
16 <groupId>org.springframework.boot</groupId>
17 <artifactId>spring-boot-starter-parent</artifactId>
18 <version>2.0.5.RELEASE</version>
19 </parent>
20
21 <properties>
22 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
23 <maven.compiler.source>1.8</maven.compiler.source>
24 <maven.compiler.target>1.8</maven.compiler.target>
25 </properties>
26
27 <dependencies>
28 <dependency>
29 <groupId>org.springframework.boot</groupId>
30 <artifactId>spring-boot-starter-web</artifactId>
31 </dependency>
32 <dependency>
33 <groupId>mysql</groupId>
34 <artifactId>mysql-connector-java</artifactId>
35 <version>5.1.6</version>
36 </dependency>
37 <dependency>
38 <groupId>com.alibaba</groupId>
39 <artifactId>druid</artifactId>
40 <version>1.1.3</version>
41 </dependency>
42 <dependency>
43 <groupId>org.mybatis.spring.boot</groupId>
44 <artifactId>mybatis-spring-boot-starter</artifactId>
45 <version>1.3.1</version>
46 </dependency>
47 <dependency>
48 <groupId>junit</groupId>
49 <artifactId>junit</artifactId>
50 <version>4.11</version>
51 <scope>test</scope>
52 </dependency>
53 <dependency>
54 <groupId>org.mybatis.generator</groupId>
55 <artifactId>mybatis-generator-core</artifactId>
56 <version>1.3.5</version>
57 </dependency>
58 </dependencies>
59
60 <build>
61 <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
62 <plugins>
63 <!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
64 <plugin>
65 <artifactId>maven-clean-plugin</artifactId>
66 <version>3.1.0</version>
67 </plugin>
68 <!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
69 <plugin>
70 <artifactId>maven-resources-plugin</artifactId>
71 <version>3.0.2</version>
72 </plugin>
73 <plugin>
74 <artifactId>maven-compiler-plugin</artifactId>
75 <version>3.8.0</version>
76 </plugin>
77 <plugin>
78 <artifactId>maven-surefire-plugin</artifactId>
79 <version>2.22.1</version>
80 </plugin>
81 <plugin>
82 <artifactId>maven-jar-plugin</artifactId>
83 <version>3.0.2</version>
84 </plugin>
85 <plugin>
86 <artifactId>maven-install-plugin</artifactId>
87 <version>2.5.2</version>
88 </plugin>
89 <plugin>
90 <artifactId>maven-deploy-plugin</artifactId>
91 <version>2.8.2</version>
92 </plugin>
93
94 <!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
95 <plugin>
96 <artifactId>maven-site-plugin</artifactId>
97 <version>3.7.1</version>
98 </plugin>
99 <plugin>
100 <artifactId>maven-project-info-reports-plugin</artifactId>
101 <version>3.0.0</version>
102 </plugin>
103
104 <plugin>
105 <groupId>org.mybatis.generator</groupId>
106 <artifactId>mybatis-generator-maven-plugin</artifactId>
107 <version>1.3.5</version>
108 <dependencies>
109 <dependency>
110 <groupId>org.mybatis.generator</groupId>
111 <artifactId>mybatis-generator-core</artifactId>
112 <version>1.3.5</version>
113 </dependency>
114 <dependency>
115 <groupId>mysql</groupId>
116 <artifactId>mysql-connector-java</artifactId>
117 <version>5.1.6</version>
118 </dependency>
119 </dependencies>
120 <executions>
121 <execution>
122 <id>mybatis generator</id>
123 <phase>package</phase>
124 <goals>
125 <goal>generate</goal>
126 </goals>
127 </execution>
128 </executions>
129 <configuration>
130 <!--允许移动生成的文件-->
131 <verbose>true</verbose>
132 <!--允许自动覆盖文件-->
133 <overwrite>true</overwrite>
134 <!--mybatis generator 配置文件的路径-->
135 <configurationFile>
136 src/main/resource/mybatis-generator.xml
137 </configurationFile>
138 </configuration>
139 </plugin>
140
141 </plugins>
142 </pluginManagement>
143 </build>
144 </project>
pom.xml
步骤5:创建mysql底层的数据库与相关表格
1.创建数据库spike
2.创建一个user_info表格
3.创建一个user_password表格,并设置user_id为外键关联user_info的id
步骤6:在步骤4中,我们最后指定了mybatis generator 配置文件的路径,于是我们在指定路径(resource目录下)创建一个mybatis generator.xml,并进行如下配置:
1 <?xml version="1.0" encoding="UTF-8"?>
2 <!DOCTYPE generatorConfiguration
3 PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
4 "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
5 <generatorConfiguration>
6 <context id="mysql" targetRuntime="MyBatis3" >
7 <!--数据库连接地址账号密码-->
8 <jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://127.0.0.1:3306/spike" userId="root" password="0322">
9 </jdbcConnection>
10 <!--生成Data Object类存放位置-->
11 <javaModelGenerator targetPackage="org.example.dataobject" targetProject="src/main/java">
12 <property name="enableSubPackages" value="true"/>
13 <property name="trimStrings" value="true"/>
14 </javaModelGenerator>
15 <!--生成映射文件存放位置-->
16 <sqlMapGenerator targetPackage="mapping" targetProject="src/main/resources">
17 <property name="enableSubPackages" value="true"/>
18 </sqlMapGenerator>
19 <!--生成dao类存放位置-->
20 <javaClientGenerator targetPackage="org.example.dao" type="XMLMAPPER" targetProject="src/main/java">
21 <property name="enableSubPackages" value="true"/>
22 </javaClientGenerator>
23 <!--生成对应表及类名-->
24 <table tableName="user_info" domainObjectName="UserDo" enableCountByExample="false"
25 enableUpdateByExample="false" enableDeleteByExample="false"
26 enableSelectByExample="false" selectByExampleQueryId="false"
27 ></table>
28 <table tableName="user_password" domainObjectName="UserPasswordDO" enableCountByExample="false"
29 enableUpdateByExample="false" enableDeleteByExample="false"
30 enableSelectByExample="false" selectByExampleQueryId="false"
31 ></table>
32 </context>
33 </generatorConfiguration>
步骤7:根据步骤6中指定的位置,我们在org.example目录下新建一个dataobject的包,一个dao包。并测试是否能够成功生成相应的文件:
run——edit configurations——+maven——command line:mybatis-generator:generate——apply
然后我们运行这个新建的命令,可以看到resources/mapping下多了两个文件:
dataobject包与dao包下生成了如下文件:
手动删除两个Example文件。
步骤8:为了接入mybatis对应mysql的数据源,我们继续编写application.properties文件
1 server.port = 8090
2 mybatis.mapperLocations = classpath:mapping/*.xml
3
4 spring.datasource.name = Spike
5 spring.datasource.url = jdbc:mysql://127.0.0.1:3306/Spike
6 spring.datasource.username = root
7 spring.datasource.password = 0322
8
9 #使用druid数据源
10 spring.datasource.type = com.alibaba.druid.pool.DruidDataSource
11 spring.datasource.driverClassName = com.mysql.jdbc.Driver
application
步骤9:回到app.java
将@EnableAutoConfiguration注解改为@SpringBootApplication(scanBasePackages = "org.example"),作用是将app交给spring托管,并且指定为主启动类。
添加注解@MapperScan("org.example.dao"),把dao存放的地方设置在对应注解下面。
最后,写一个方法来测试我们的搭建工作是否完成,(事先在表格中添加一条数据)
1 package org.example;
2
3 import org.example.dao.UserDoMapper;
4 import org.example.dataobject.UserDo;
5 import org.mybatis.spring.annotation.MapperScan;
6 import org.springframework.beans.factory.annotation.Autowired;
7 import org.springframework.boot.SpringApplication;
8 import org.springframework.boot.autoconfigure.SpringBootApplication;
9 import org.springframework.web.bind.annotation.RequestMapping;
10 import org.springframework.web.bind.annotation.RestController;
11
12 //SpringBoot会帮我们启动tomcat,并加载默认配置
13 @SpringBootApplication(scanBasePackages = {"org.example"})
14
15 //SpringMVC相关配置
16 @RestController
17 @MapperScan("org.example.dao")
18 public class App {
19 @Autowired
20 private UserDoMapper userDoMapper;
21
22 @RequestMapping("/")
23 public String home(){
24 UserDo userDo = userDoMapper.selectByPrimaryKey(1);
25 if(userDo == null){
26 return "用户对象不存在";
27 }else{
28 return userDo.getName();
29 }
30
31 }
32 public static void main( String[] args ){
33 //控制台输出
34 System.out.println( "Hello World!" );
35 SpringApplication.run(App.class,args);
36 }
37 }
app.java
打开http://localhost:8090/,我们可以看到页面上显示了我们添加的数据中name字段的内容。
三、用户模块开发
1.使用SpingMVC模式开发用户信息
步骤1:补全框架结构:
步骤2:service层的编写:
UserService接口:
1 package org.example.service;
2
3 import org.example.service.model.UserModel;
4
5 public interface UserService {
6 UserModel getUserById(Integer id);
7 }
UserService实现类:
1 @Service
2 public class UserServiceImpl implements UserService {
3 @Autowired
4 private UserDoMapper userDoMapper;
5
6 @Autowired
7 private UserPasswordDOMapper userPasswordDOMapper;
8
9 @Override
10 public UserModel getUserById(Integer id) {
11 UserDo userDo = userDoMapper.selectByPrimaryKey(id);
12 if(userDo == null){
13 return null;
14 }
15 //通过用户id获取对应的用户加密密码信息
16 UserPasswordDO userPasswordDO = userPasswordDOMapper.selectByUserId(userDo.getId());
17 return convertFromDataObject(userDo,userPasswordDO);
18 }
19
20 public UserModel convertFromDataObject(UserDo userDo, UserPasswordDO userPasswordDO) {
21 if(userDo == null){
22 return null;
23 }
24 UserModel userModel = new UserModel();
25 BeanUtils.copyProperties(userDo,userModel);
26 if(userPasswordDO != null){
27 userModel.setEncriptPassword(userPasswordDO.getEncriptPassword());
28 }
29 return userModel;
30 }
31 }
UserModel类:存放数据库的所有对应字段与getters&setters,用于service层与数据库数据的解耦,使service层无法直接接触数据库
1 package org.example.service.model;
2
3 public class UserModel {
4 private Integer id;
5 private String name;
6 private Byte gender;
7 private Integer age;
8 private String telephone;
9 private String registerMode;
10 private String thirdPartyId;
11 private String encriptPassword;
12
13 public Integer getId() {
14 return id;
15 }
16
17 public void setId(Integer id) {
18 this.id = id;
19 }
20
21 public String getName() {
22 return name;
23 }
24
25 public void setName(String name) {
26 this.name = name;
27 }
28
29 public Byte getGender() {
30 return gender;
31 }
32
33 public void setGender(Byte gender) {
34 this.gender = gender;
35 }
36
37 public Integer getAge() {
38 return age;
39 }
40
41 public void setAge(Integer age) {
42 this.age = age;
43 }
44
45 public String getTelephone() {
46 return telephone;
47 }
48
49 public void setTelephone(String telephone) {
50 this.telephone = telephone;
51 }
52
53 public String getRegisterMode() {
54 return registerMode;
55 }
56
57 public void setRegisterMode(String registerMode) {
58 this.registerMode = registerMode;
59 }
60
61 public String getThirdPartyId() {
62 return thirdPartyId;
63 }
64
65 public void setThirdPartyId(String thirdPartyId) {
66 this.thirdPartyId = thirdPartyId;
67 }
68
69 public String getEncriptPassword() {
70 return encriptPassword;
71 }
72
73 public void setEncriptPassword(String encriptPassword) {
74 this.encriptPassword = encriptPassword;
75 }
76 }
UserModel
步骤3:修改UserPasswordDOMapper.xml,添加一个selectByUserId操作的配置
1 <select id="selectByUserId" parameterType="java.lang.Integer" resultMap="BaseResultMap">
2 select
3 <include refid="Base_Column_List" />
4 from user_password
5 where user_id = #{userId,jdbcType=INTEGER}
6 </select>
同步修改UserPasswordDOMapper.java,添加一行代码:
UserPasswordDO selectByUserId(Integer userId);
步骤4:编写Controller包中的UserController.java
1 @Controller("user")
2 @RequestMapping("/user")
3 public class UserController {
4 @Autowired
5 private UserService userService;
6 @RequestMapping("/get")
7 @ResponseBody
8 public UserModel getUser(@RequestParam(name="id") Integer id) {
9 //调用service服务获取对应id的用户对象并返回给前端
10 UserModel userModel = userService.getUserById(id);
11 return userModel;
12 }
13 }
运行后,访问http://localhost:8090/user/get?id=1(需要事先添加好一条完整的数据),可以看到页面上输出了这条数据的完整信息。
步骤5:发现问题:在UserController中,我们把userModel模型直接返回给前端,导致密码直接输出在页面中,这是非常不专业的。
因此,我们在controller层(包)中需要新建一个模型对象。在controller层中新建一个viewobject包,并在其中写一个viewobject类,里面只写需要展示在前端的字段与getters&setters。
1 package org.example.controller.viewobject;
2
3 public class UserVO {
4 //只写前端用户所需要的信息
5 private Integer id;
6 private String name;
7 private Byte gender;
8 private Integer age;
9 private String telephone;
10
11 public Integer getId() {
12 return id;
13 }
14
15 public void setId(Integer id) {
16 this.id = id;
17 }
18
19 public String getName() {
20 return name;
21 }
22
23 public void setName(String name) {
24 this.name = name;
25 }
26
27 public Byte getGender() {
28 return gender;
29 }
30
31 public void setGender(Byte gender) {
32 this.gender = gender;
33 }
34
35 public Integer getAge() {
36 return age;
37 }
38
39 public void setAge(Integer age) {
40 this.age = age;
41 }
42
43 public String getTelephone() {
44 return telephone;
45 }
46
47 public void setTelephone(String telephone) {
48 this.telephone = telephone;
49 }
50 }
viewobject
同时,我们修改UserController类,将UserModel转化为viewobject后,再返回给前端。
1 @Controller("user")
2 @RequestMapping("/user")
3 public class UserController {
4 @Autowired
5 private UserService userService;
6 @RequestMapping("/get")
7 @ResponseBody
8 public UserVO getUser(@RequestParam(name="id") Integer id) {
9 //调用service服务获取对应id的用户对象并返回给前端
10 UserModel userModel = userService.getUserById(id);
11 //将核心领域模型对象转化为可供UI使用的viewobject
12 return convertFromModel(userModel);
13 }
14 private UserVO convertFromModel(UserModel userModel){
15 if(userModel == null){
16 return null;
17 }
18 UserVO userVO = new UserVO();
19 BeanUtils.copyProperties(userModel,userVO);
20 return userVO;
21 }
22 }
这一步中,我们做了一个完整的从数据库中读取数据,展示在前端页面上的操作。
controller层——>service层——>dao层
dataobject层负责数据存储到service的传输,并且在用户的service的服务中组装了对应的核心领域模型。
controller层做了到用户viewobject之间的传递,保证密码等信息不会输出到前端。
2.定义通用的返回对象
步骤1:自主管理前端页面的返回——返回正确信息
org.example包下创建一个response包,在其中创建一个CommonReturnType.java文件。
在该文件中,设置两个属性:status,data,并生成对应的getters&setters。然后写两个构造方法,包含了两个属性的设置。
1 package org.example.response;
2
3 public class CommonReturnType {
4 //表名对应请求的返回处理结果,success/fail
5 private String status;
6 //若status返回success,则data内返回前端需要的json数据
7 //若status返回success,则data内使用通用的错误码格式
8 private Object data;
9
10 //定义一个通用的创建方法
11 public static CommonReturnType create(Object result){
12 return CommonReturnType.create(result,"success");
13 }
14
15 public static CommonReturnType create(Object result,String status){
16 CommonReturnType type = new CommonReturnType();
17 type.setStatus(status);
18 type.setData(result);
19 return type;
20 }
21
22 public String getStatus() {
23 return status;
24 }
25
26 public void setStatus(String status) {
27 this.status = status;
28 }
29
30 public Object getData() {
31 return data;
32 }
33
34 public void setData(Object data) {
35 this.data = data;
36 }
37 }
CommonReturnType
修改我们的UserController.java,将返回值改为CommonReturnType,由CommonReturnType调用create方法来引用UserVO中的信息。以下代码为需要修改的部分:
1 public CommonReturnType getUser(@RequestParam(name="id") Integer id) {
2 //调用service服务获取对应id的用户对象并返回给前端
3 UserModel userModel = userService.getUserById(id);
4 //将核心领域模型对象转化为可供UI使用的viewobject
5 UserVO userVO = convertFromModel(userModel);
6 //返回通用对象
7 return CommonReturnType.create(userVO);
8 }
运行后,我们仍然访问http://localhost:8090/user/get?id=1,可以看到页面上输出了:
步骤2:自主管理前端页面的返回——返回错误信息
org.example包下创建一个error包,在其中创建一个CommonError接口,写3个方法:获取错误码,获取错误信息,设置错误信息
1 public interface CommonError {
2 public int getErrCode();
3 public String getErrMsg();
4 public CommonError setErrMsg(String errMsg);
5 }
error包下写一个枚举类型的EmBusinessError,实现CommonError接口。
1 package org.example.error;
2
3 public enum EmBusinessError implements CommonError{
4 //通用错误类型10001
5 PARAMETER_VALIDATION_ERROR(10001,"参数不合法"),
6 //未知错误10002
7 UNKNOWN_ERROR(10002,"未知错误"),
8
9 //20000开头相关为用户信息相关错误定义
10 USER_NOT_EXIST(20001,"用户不存在"),
11 ;
12
13 private EmBusinessError(int errCode,String errMsg){
14 this.errCode = errCode;
15 this.errMsg = errMsg;
16 }
17
18 private int errCode;
19 private String errMsg;
20
21 @Override
22 public int getErrCode() {
23 return this.errCode;
24 }
25
26 @Override
27 public String getErrMsg() {
28 return this.errMsg;
29 }
30
31 @Override
32 public CommonError setErrMsg(String errMsg) {
33 this.errMsg = errMsg;
34 return this;
35 }
36 }
error包下写一个BusinessException,实现CommonError接口,并继承Exception类。
1 public class BusinessException extends Exception implements CommonError{
2 private CommonError commonError;
3
4 //直接接收EmBusinessError的传参用于构造业务异常
5 public BusinessException(CommonError commonError) {
6 super();
7 this.commonError = commonError;
8 }
9
10 public BusinessException(CommonError commonError,String errMsg) {
11 super();
12 this.commonError = commonError;
13 this.commonError.setErrMsg(errMsg);
14 }
15
16 @Override
17 public int getErrCode() {
18 return this.commonError.getErrCode();
19 }
20
21 @Override
22 public String getErrMsg() {
23 return this.commonError.getErrMsg();
24 }
25
26 @Override
27 public CommonError setErrMsg(String errMsg) {
28 this.commonError.setErrMsg(errMsg);
29 return this;
30 }
31 }
UserController中添加如下代码:
1 //若获取的对应用户信息不存在
2 if(userModel==null){
3 throw new BusinessException(EmBusinessError.USER_NOT_EXIST);
4 }
步骤3:异常处理
在controller目录下单独写一个BaseController类,定义exceptionhandler解决未被controller层吸收的exception。
1 import java.util.Map;
2
3 public class BaseController {
4 //定义exceptionhandler解决未被controller层吸收的exception
5 @ExceptionHandler(Exception.class)
6 @ResponseStatus(HttpStatus.OK)
7 @ResponseBody
8 public Object handlerException(HttpServletRequest request, Exception ex){
9 Map<String,Object> responseData = new HashMap<>();
10 if(ex instanceof BusinessException){
11 BusinessException businessException = (BusinessException)ex;
12 responseData.put("errCode",businessException.getErrCode());
13 responseData.put("errMsg",businessException.getErrMsg());
14 }else{
15 responseData.put("errCode", EmBusinessError.UNKNOWN_ERROR.getErrCode());
16 responseData.put("errMsg",EmBusinessError.UNKNOWN_ERROR.getErrMsg());
17
18 }
19 return CommonReturnType.create(responseData,"fail");
20 }
21 }
然后,UserController类需要继承BaseController类。
运行后,我们访问http://localhost:8090/user/get?id=2,(id=2的数据是不存在的),可以看到页面为:
为了程序的健壮性,我们在BaseController中添加了一个unknown error。我们可以手动地来测试一下这段代码是否起了作用:
修改UserController部分代码如下:
1 if(userModel==null){
2 userModel.setEncriptPassword("123");
3 //throw new BusinessException(EmBusinessError.USER_NOT_EXIST);
4 }
运行后,我们再次访问http://localhost:8090/user/get?id=2,可以看到页面为:
总结:
在这一环节中,首先我们定义了一个CommonReturnType,能够用对应的status+objectdata的方式返回所有json序列化方式的固定对象,供前端解析使用。
然后,我们定义了EmBusinessError,统一管理我们所需要的错误码。
接着,我们在BaseController中定义了一个通用的ExceptionHandler的类来解决未被controller层吸收的exception(采用errorCode+errorMsg的统一定义方式),处理了所有不可预知的异常。
3.用户模型管理
步骤1:otp验证码获取
我们在userController类中编写如下代码,用于随机生成一个验证码,并与手机号关联。发送短信的过程我们暂时用控制台打印来替代。
1 @Autowired
2 private HttpServletRequest httpServletRequest;
3
4 //用户获取otp短信接口
5 @RequestMapping("/getotp")
6 @ResponseBody
7 public CommonReturnType getOtp(@RequestParam(name="telephone")String telephone){
8 //按照一定的规则生成otp验证码
9 Random random = new Random();
10 int randomInt = random.nextInt(99999);
11 randomInt += 10000;
12 String otpCode = String.valueOf(randomInt);
13 //将otp验证码桶对应用户的手机号关联,使用httpsession的方式绑定他的手机号与OTPCODE
14 httpServletRequest.getSession().setAttribute(telephone,otpCode);
15 //将otp验证码通过短信通道发送给用户,这里简化打印至控制台查看
16 System.out.println("telephone = " + telephone + " & otpCode = "+otpCode);
17 return CommonReturnType.create(null);
18 }
登录http://localhost:8090/user/getotp?telephone=13565656565(手机号任意),页面显示:
控制台中看到输出:
步骤2:用前后端分离的设计模式制作用户登录的界面
用Metronic模板写一个用于用户注册的html,与static文件夹放在一起,代码如下:
1 <html>
2 <head>
3 <meta charset="UTF-8">
4 <script src="static/assets/global/plugins/jquery-1.11.0.min.js" type="text/javascript"></script>
5 <title>Title</title>
6 </head>
7 <body>
8 <div>
9 <h3>获取otp信息</h3>
10 <div>
11 <label>手机号</label>
12 <div>
13 <input type="text" placeholder="手机号" name="telephone" id="telephone"/>
14 </div>
15 </div>
16 <div>
17 <button id="getotp" type="submit">
18 获取otp短信
19 </button>
20 </div>
21 </div>
22
23 </body>
24
25 <script>
26 jQuery(document).ready(function () {
27
28 //绑定otp的click事件用于向后端发送获取手机验证码的请求
29 $("#getotp").on("click",function () {
30
31 var telephone=$("#telephone").val();
32 if (telephone==null || telephone=="") {
33 alert("手机号不能为空");
34 return false;
35 }
36
37
38 //映射到后端@RequestMapping(value = "/getotp", method = {RequestMethod.POST}, consumes = {CONTENT_TYPE_FORMED})
39 $.ajax({
40 type:"POST",
41 contentType:"application/x-www-form-urlencoded",
42 url:"http://localhost:8090/user/getotp",
43 data:{
44 "telephone":$("#telephone").val(),
45 },
46 success:function (data) {
47 if (data.status=="success") {
48 alert("otp已经发送到了您的手机,请注意查收");
49 }else {
50 alert("otp发送失败,原因为" + data.data.errMsg);
51 }
52 },
53 error:function (data) {
54 alert("otp发送失败,原因为"+data.responseText);
55 }
56 });
57 });
58 });
59 </script>
60 </html>
getotp.html
在BaseController中定义一个常量如下:
public static final String CONTENT_TYPE_FORMED ="application/x-www-form-urlencoded";
在UserController中,我们修改RequestMapping注解为:
@RequestMapping(value = "/getotp", method = {RequestMethod.POST}, consumes = {CONTENT_TYPE_FORMED})
最后为了实现跨域请求,我们在UserController类上面添加一个@CrossOrigin注解。
运行project后,我们用google浏览器(千万不要用IE,会提示undefined错误!)打开getotp.html,界面如下:
输入任意手机号,点击按钮,浏览器提示:
控制台输出了手机号与otpcode。
html页面可以通过引入样式来美化,美化后代码如下:
1 <html>
2 <head>
3 <meta charset="UTF-8">
4 <script src = "static/assets/global/plugins/jquery-1.11.0.min.js" type="text/javascript"></script>
5 <link href="static/assets/global/plugins/bootstrap/css/bootstrap.min.css" rel="stylesheet" type="text/css"/>
6 <link href="static/assets/global/plugins/css/component.css" rel="stylesheet" type="text/css"/>
7 <link href="static/assets/admin/pages/css/login.css" rel="stylesheet" type="text/css"/>
8 </head>
9 <body class="login">
10 <div class="content">
11 <h3 class="form-title">获取otp信息</h3>
12 <div class="form-group">
13 <label class="control-label">手机号</label>
14 <div>
15 <input class="form-control" type="text" placeholder="手机号" name="telephone" id="telephone"/>
16 </div>
17 </div>
18 <div class="form-actions">
19 <button class="btn blue" id="getotp" type="submit">
20 获取otp短信
21 </button>
22 </div>
23 </div>
24
25 </body>
26
27
28 <script>
29 jQuery(document).ready(function () {
30
31 //绑定otp的click事件用于向后端发送获取手机验证码的请求
32 $("#getotp").on("click",function () {
33
34 var telephone=$("#telephone").val();
35 if (telephone==null || telephone=="") {
36 alert("手机号不能为空");
37 return false;
38 }
39
40
41 //映射到后端@RequestMapping(value = "/getotp", method = {RequestMethod.POST}, consumes = {CONTENT_TYPE_FORMED})
42 $.ajax({
43 type:"POST",
44 contentType:"application/x-www-form-urlencoded",
45 url:"http://localhost:8090/user/getotp",
46 data:{
47 "telephone":$("#telephone").val(),
48 },
49 success:function (data) {
50 if (data.status=="success") {
51 alert("otp已经发送到了您的手机,请注意查收");
52 }else {
53 alert("otp发送失败,原因为" + data.data.errMsg);
54 }
55 },
56 error:function (data) {
57 alert("otp发送失败,原因为"+data.responseText);
58 }
59 });
60 });
61 });
62 </script>
63 </html>
getotp.html
步骤3:用户注册功能的实现
UserController写一个用户注册的接口,用来接收前端写入的数据。
1 //用户注册接口
2 @RequestMapping(value = "/register", method = {RequestMethod.POST}, consumes = {CONTENT_TYPE_FORMED})
3 @ResponseBody
4 public CommonReturnType register(@RequestParam(name = "telephone") String telephone,
5 @RequestParam(name = "otpCode") String otpCode,
6 @RequestParam(name = "name") String name,
7 @RequestParam(name = "gender") String gender,
8 @RequestParam(name = "age") String age,
9 @RequestParam(name = "password") String password) throws BusinessException, UnsupportedEncodingException, NoSuchAlgorithmException {
10
11 //验证手机号和对应的otpCode相符合
12 String inSessionOtpCode = (String) this.httpServletRequest.getSession().getAttribute(telephone);
13 if (!com.alibaba.druid.util.StringUtils.equals(otpCode, inSessionOtpCode)) {
14 throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR, "短信验证码不符合");
15 }
16 //用户的注册流程
17 UserModel userModel = new UserModel();
18 userModel.setName(name);
19 userModel.setAge(Integer.valueOf(age));
20 userModel.setGender(Byte.valueOf(gender));
21 userModel.setTelephone(telephone);
22 userModel.setRegisterMode("byphone");
23
24 //密码加密
25 userModel.setEncriptPassword(this.EncodeByMd5(password));
26 userService.register(userModel);
27 return CommonReturnType.create(null);
28 }
29
30 //密码加密
31 public String EncodeByMd5(String str) throws NoSuchAlgorithmException, UnsupportedEncodingException {
32 //确定计算方法
33 MessageDigest md5 = MessageDigest.getInstance("MD5");
34 Base64Encoder base64en = new Base64Encoder();
35
36 //加密字符串
37 String newstr = base64en.encode(md5.digest(str.getBytes("utf-8")));
38 return newstr;
39 }
在pom中引入做校验的依赖:
1 <dependency>
2 <groupId>org.apache.commons</groupId>
3 <artifactId>commons-lang3</artifactId>
4 <version>3.7</version>
5 </dependency>
在UserServiceImpl中写register方法,将controller层传过来的数据与数据库做交互,并修改跨域注解为:
@CrossOrigin(allowCredentials = "true",allowedHeaders = "*")
1 @Override
2 @Transactional//声明事务
3 public void register(UserModel userModel) throws BusinessException {
4 //校验
5 if (userModel == null) {
6 throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR);
7 }
8 if (StringUtils.isEmpty(userModel.getName())
9 || userModel.getGender() == null
10 || userModel.getAge() == null
11 || StringUtils.isEmpty(userModel.getTelephone())) {
12 throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR);
13 }
14
15 //实现model->dataobject方法
16
17 UserDo userDO = convertFromModel(userModel);
18 //insertSelective相对于insert方法,不会覆盖掉数据库的默认值
19 userDoMapper.insertSelective(userDO);
20
21 userModel.setId(userDO.getId());
22
23 UserPasswordDO userPasswordDO = convertPasswordFromModel(userModel);
24 userPasswordDOMapper.insertSelective(userPasswordDO);
25
26 return;
27 }
28
29 private UserPasswordDO convertPasswordFromModel(UserModel userModel) {
30 if (userModel == null) {
31 return null;
32 }
33 UserPasswordDO userPasswordDO = new UserPasswordDO();
34 userPasswordDO.setEncriptPassword(userModel.getEncriptPassword());
35 userPasswordDO.setUserId(userModel.getId());
36
37 return userPasswordDO;
38 }
39
40 private UserDo convertFromModel(UserModel userModel) {
41 if (userModel == null) {
42 return null;
43 }
44 UserDo userDo = new UserDo();
45 BeanUtils.copyProperties(userModel,userDo);
46 return userDo;
47 }
制作前端界面:
修改getotp.html,验证码发送成功后写一个跳转,转到register.html(window是小写!),最后再添加一句允许跨域:
1 xhrFields:{withCredentials:true},
2 success:function (data) {
3 if (data.status=="success") {
4 alert("otp已经发送到了您的手机,请注意查收");
5 window.location.href="register.html";
6 }else {
7 alert("otp发送失败,原因为" + data.data.errMsg);
8 }
9 },
10 error:function (data) {
11 alert("otp发送失败,原因为"+data.responseText);
12 }
getotp.html改动部分
写一个register.html页面,用于输入用户信息:
1 <html>
2 <head>
3 <meta charset="UTF-8">
4 <script src = "static/assets/global/plugins/jquery-1.11.0.min.js" type="text/javascript"></script>
5 <link href="static/assets/global/plugins/bootstrap/css/bootstrap.min.css" rel="stylesheet" type="text/css"/>
6 <link href="static/assets/global/plugins/css/component.css" rel="stylesheet" type="text/css"/>
7 <link href="static/assets/admin/pages/css/login.css" rel="stylesheet" type="text/css"/>
8 </head>
9 <body class="login">
10 <div class="content">
11 <h3 class="form-title">用户注册</h3>
12 <div class="form-group">
13 <label class="control-label">手机号</label>
14 <div>
15 <input class="form-control" type="text" placeholder="手机号" name="telephone" id="telephone"/>
16 </div>
17 </div>
18 <div class="form-group">
19 <label class="control-label">验证码</label>
20 <div>
21 <input class="form-control" type="text" placeholder="验证码" name="otpCode" id="otpCode"/>
22 </div>
23 </div>
24 <div class="form-group">
25 <label class="control-label">用户昵称</label>
26 <div>
27 <input class="form-control" type="text" placeholder="用户昵称" name="name" id="name"/>
28 </div>
29 </div>
30 <div class="form-group">
31 <label class="control-label">性别</label>
32 <div>
33 <input class="form-control" type="text" placeholder="性别" name="gender" id="gender"/>
34 </div>
35 </div>
36 <div class="form-group">
37 <label class="control-label">年龄</label>
38 <div>
39 <input class="form-control" type="text" placeholder="年龄" name="age" id="age"/>
40 </div>
41 </div>
42 <div class="form-group">
43 <label class="control-label">密码</label>
44 <div>
45 <input class="form-control" type="password" placeholder="密码" name="password" id="password"/>
46 </div>
47 </div>
48 <div class="form-actions">
49 <button class="btn blue" id="register" type="submit">
50 提交注册
51 </button>
52 </div>
53 </div>
54
55 </body>
56
57 <script>
58 jQuery(document).ready(function () {
59
60 //绑定otp的click事件用于向后端发送获取手机验证码的请求
61 $("#register").on("click",function () {
62
63 var telephone=$("#telephone").val();
64 var otpCode=$("#otpCode").val();
65 var password=$("#password").val();
66 var age=$("#age").val();
67 var gender=$("#gender").val();
68 var name=$("#name").val();
69 if (telephone==null || telephone=="") {
70 alert("手机号不能为空");
71 return false;
72 }
73 if (otpCode==null || otpCode=="") {
74 alert("验证码不能为空");
75 return false;
76 }
77 if (name==null || name=="") {
78 alert("用户名不能为空");
79 return false;
80 }
81 if (gender==null || gender=="") {
82 alert("性别不能为空");
83 return false;
84 }
85 if (age==null || age=="") {
86 alert("年龄不能为空");
87 return false;
88 }
89 if (password==null || password=="") {
90 alert("密码不能为空");
91 return false;
92 }
93
94 //映射到后端@RequestMapping(value = "/register", method = {RequestMethod.POST}, consumes = {CONTENT_TYPE_FORMED})
95 $.ajax({
96 type:"POST",
97 contentType:"application/x-www-form-urlencoded",
98 url:"http://localhost:8090/user/register",
99 data:{
100 "telephone":telephone,
101 "otpCode":otpCode,
102 "password":password,
103 "age":age,
104 "gender":gender,
105 "name":name
106 },
107 //允许跨域请求
108 xhrFields:{withCredentials:true},
109 success:function (data) {
110 if (data.status=="success") {
111 alert("注册成功");
112 }else {
113 alert("注册失败,原因为" + data.data.errMsg);
114 }
115 },
116 error:function (data) {
117 alert("注册失败,原因为"+data.responseText);
118 }
119 });
120 return false;
121 });
122 });
123 </script>
124
125 </html>
register.html
修改UserDoMapper.xml与UserPasswordMapper.xml的insertSelective操作,修改insert标签头,使id自增
keyProperty="id" useGeneratedKeys="true"
踩雷:一定要保证数据库中的两张表格的约束正确,否则会出错(血泪史TAT)
要会debug:添加断点,然后点击右上角的小甲虫运行,在前端操作之后观察调试台的参数是否正确!
运行结果:输入手机号,页面跳转至输入信息页面,输入个人信息以及对应的手机号,otp验证码,页面提示注册成功,数据库中会增加一条刚刚输入的用户的数据。
步骤4:登录功能实现
UserController中写一个登录接口:
1 //用户登录接口
2 @RequestMapping(value = "/login", method = {RequestMethod.POST}, consumes = {CONTENT_TYPE_FORMED})
3 @ResponseBody
4 public CommonReturnType login(@RequestParam(name = "telephone") String telephone,
5 @RequestParam(name = "password") String password) throws BusinessException, UnsupportedEncodingException, NoSuchAlgorithmException {
6 //入参校验
7 if (StringUtils.isEmpty(telephone) || StringUtils.isEmpty(password)) {
8 throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR);
9 }
10
11 //用户登录服务,用来校验用户登录是否合法
12 //用户加密后的密码
13 UserModel userModel = userService.validateLogin(telephone, this.EncodeByMd5(password));
14
15 //将登陆凭证加入到用户登录成功的session内
16 this.httpServletRequest.getSession().setAttribute("IS_LOGIN", true);
17 this.httpServletRequest.getSession().setAttribute("LOGIN_USER", userModel);
18 return CommonReturnType.create(null);
19 }
UserDoMapper接口中增加一个方法:
UserDo selectByTelephone(String telephone);
UserDoMapper.xml中进行配置:
1 <select id="selectByTelephone" resultMap="BaseResultMap">
2 select
3 <include refid="Base_Column_List"/>
4 from user_info
5 where telephone = #{telephone,jdbcType=VARCHAR}
6 </select>
UserSeivice接口中添加一个方法:
UserModel validateLogin(String telephone, String encriptPassword) throws BusinessException;
然后我们就可以在UserServiceImpl中实现这个方法:
1 @Override
2 public UserModel validateLogin(String telephone, String encriptPassword) throws BusinessException {
3 //通过用户手机获取用户信息
4 UserDo userDo = userDoMapper.selectByTelephone(telephone);
5 if (userDo == null) {
6 throw new BusinessException(EmBusinessError.USER_LOGIN_FAIL);
7 }
8 UserPasswordDO userPasswordDO = userPasswordDOMapper.selectByUserId(userDo.getId());
9 UserModel userModel = convertFromDataObject(userDo, userPasswordDO);
10
11 //比对用户信息内加密的密码是否和传输进来的密码相匹配
12 if (StringUtils.equals(encriptPassword, userModel.getEncriptPassword())) {
13 throw new BusinessException(EmBusinessError.USER_LOGIN_FAIL);
14 }
15 return userModel;
16 }
建立前端页面:login.html
1 <html>
2 <head>
3 <meta charset="UTF-8">
4 <script src = "static/assets/global/plugins/jquery-1.11.0.min.js" type="text/javascript"></script>
5 <link href="static/assets/global/plugins/bootstrap/css/bootstrap.min.css" rel="stylesheet" type="text/css"/>
6 <link href="static/assets/global/plugins/css/component.css" rel="stylesheet" type="text/css"/>
7 <link href="static/assets/admin/pages/css/login.css" rel="stylesheet" type="text/css"/>
8 </head>
9 <body class="login">
10 <div class="content">
11 <h3 class="form-title">用户登录</h3>
12 <div class="form-group">
13 <label class="control-label">手机号</label>
14 <div>
15 <input class="form-control" type="text" placeholder="手机号" name="telephone" id="telephone"/>
16 </div>
17 </div>
18 <div class="form-group">
19 <label class="control-label">密码</label>
20 <div>
21 <input class="form-control" type="password" placeholder="密码" name="password" id="password"/>
22 </div>
23 </div>
24 <div class="form-actions">
25 <button class="btn blue" id="login" type="submit">
26 登录
27 </button>
28 <button class="btn green" id="register" type="submit">
29 注册
30 </button>
31 </div>
32 </div>
33
34 </body>
35
36 <script>
37 jQuery(document).ready(function () {
38
39 //绑定注册按钮的click事件用于跳转到注册页面
40 $("#register").on("click",function () {
41 window.location.href = "getotp.html";
42 });
43
44 //绑定登录按钮的click事件用于登录
45 $("#login").on("click",function () {
46
47 var telephone=$("#telephone").val();
48 var password=$("#password").val();
49 if (telephone==null || telephone=="") {
50 alert("手机号不能为空");
51 return false;
52 }
53 if (password==null || password=="") {
54 alert("密码不能为空");
55 return false;
56 }
57
58 //映射到后端@RequestMapping(value = "/login", method = {RequestMethod.POST}, consumes = {CONTENT_TYPE_FORMED})
59 $.ajax({
60 type:"POST",
61 contentType:"application/x-www-form-urlencoded",
62 url:"http://localhost:8090/user/login",
63 data:{
64 "telephone":telephone,
65 "password":password
66 },
67 //允许跨域请求
68 xhrFields:{withCredentials:true},
69 success:function (data) {
70 if (data.status=="success") {
71 alert("登录成功");
72 }else {
73 alert("登录失败,原因为" + data.data.errMsg);
74 }
75 },
76 error:function (data) {
77 alert("登录失败,原因为"+data.responseText);
78 }
79 });
80 return false;
81 });
82 });
83 </script>
84 </html>
login.html
运行project,我们进入login页面,输入已注册的手机号与密码,就会收到登录成功的提示。
步骤5:优化校验逻辑
引入validator依赖
1 <dependency>
2 <groupId>org.hibernate</groupId>
3 <artifactId>hibernate-validator</artifactId>
4 <version>5.2.4.Final</version>
5 </dependency>
org.example下新建一个validator包:
写一个validationResult类:
1 package org.example.validator;
2
3 import org.apache.commons.lang3.StringUtils;
4
5 import java.util.HashMap;
6 import java.util.Map;
7
8 public class ValidationResult {
9 //校验结果是否有错
10 private boolean hasErrors = false;
11
12 //存放错误信息的map
13 private Map<String, String> errorMsgMap = new HashMap<>();
14
15 public boolean isHasErrors() {
16 return hasErrors;
17 }
18
19 public void setHasErrors(boolean hasErrors) {
20 this.hasErrors = hasErrors;
21 }
22
23 public Map<String, String> getErrorMsgMap() {
24 return errorMsgMap;
25 }
26
27 public void setErrorMsgMap(Map<String, String> errorMsgMap) {
28 this.errorMsgMap = errorMsgMap;
29 }
30
31 //实现通用的通过格式化字符串信息获取错误结果的msg方法
32 public String getErrMsg() {
33 return StringUtils.join(errorMsgMap.values().toArray(), ",");
34 }
35 }
validationResult
写一个validatorImpl类:
1 @Component
2 public class ValidatorImpl implements InitializingBean {
3
4 private Validator validator;
5
6 //实现校验方法并返回校验结果
7 public ValidationResult validate(Object bean) {
8 final ValidationResult result = new ValidationResult();
9 Set<ConstraintViolation<Object>> constraintViolationSet = validator.validate(bean);
10 if (constraintViolationSet.size() > 0) {
11 //有错误
12 result.setHasErrors(true);
13 constraintViolationSet.forEach(constraintViolation ->{
14 String errMsg = constraintViolation.getMessage();
15 String propertyName = constraintViolation.getPropertyPath().toString();
16 result.getErrorMsgMap().put(propertyName, errMsg);
17 });
18 }
19 return result;
20 }
21
22 @Override
23 public void afterPropertiesSet() throws Exception {
24 //将hibernate validator通过工厂的初始化方式使其实例化
25 this.validator = Validation.buildDefaultValidatorFactory().getValidator();
26 }
27 }
validatorImpl
修改UserModel,加入校验相关的注解:
1 private Integer id;
2 @NotBlank(message = "用户名不能为空")
3 private String name;
4 @NotNull(message = "性别不能不填")
5 private Byte gender;
6 @NotNull(message = "年龄不能不填")
7 @Min(value = 0,message="年龄必须大于0岁")
8 @Max(value = 150,message = "年龄必须小于150岁")
9 private Integer age;
10 @NotNull(message = "手机号不能为空")
11 private String telephone;
12 private String registerMode;
13 private String thirdPartyId;
14 @NotNull(message = "密码不能为空")
15 private String encriptPassword;
在UserServiceImpl中引入并使用使用validator(先把原来的非空校验注释掉):
@Autowired
private ValidatorImpl validator;
1 /*
2 if (StringUtils.isEmpty(userModel.getName())
3 || userModel.getGender() == null
4 || userModel.getAge() == null
5 || StringUtils.isEmpty(userModel.getTelephone())) {
6 throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR);
7 }
8 */
9 ValidationResult result = validator.validate(userModel);
10 if (result.isHasErrors()) {
11 throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR, result.getErrMsg());
12 }
运行project,我们在注册时,可尝试输入一个大于150的年龄,提交后系统会报错:
项目上篇完结~