3 SpringBoot+VUE案例开发

经过对SpringBoot及VUE的学习,我们已经对他们的开发流程有了一定的了解,我们将这两个框架进行整合,并实现一个简单的前后的开发案例“HelloWorld”。这个案例我们主要实现:(1)系统的登陆、退出;(2)用户的查询、新增、修改、删除。系统架构如下图所示:
3架构

从架构图中可以看到前端UI采用VUE框架开发, vue框架整合了mock、validator、vuex等组件。后端包括:控制层、业务服务层和数据访问层,基于SpringBoot2开发,控制层主要实现了rest的http服务以及权限控制;业务服务层主要用于实现业务逻辑,同时也具备了日志、事物、缓存等功能;数据访问层采用mybatis框架实现。本节案例开发采用mysql作为数据库。

3.1 后端开发

3.1.1 创建工程

后端框架采用SpringBoot2+mybatis+redis整合框架开发,可以参照我们在SpringBoot开发的第一个工程,我们创建一个helloworld的后端工程。结构如下:
创建工程

3.1.2 工程配置

SpringBoot工程的主要配置文件包括maven的POM文件和application.properties配置文件。

pom文件内容为:

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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.5.RELEASE</version>
<relativePath/>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>helloworld</artifactId>
<packaging>jar</packaging>
<version>1.0.1.RELEASE</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<lombok.version>1.16.18</lombok.version>
<commons-lang3.version>3.8.1</commons-lang3.version>
<commons-collections.version>3.2.1</commons-collections.version>

<redis.version>2.9.0</redis.version>
<fastjson.version>1.2.21</fastjson.version>
<swagger2.version>2.2.2</swagger2.version>
<oracle.version>11.2.0.3</oracle.version>
<mysql.version>8.0.11</mysql.version>
<druid-starte.version>1.1.1</druid-starte.version>
<junit.version>4.12</junit.version>
<log4j.version>1.2.15</log4j.version>
<net.minidev.json-smart.version>2.2.1</net.minidev.json-smart.version>
<net.minidev.asm.version>1.0.2</net.minidev.asm.version>
<httpclient.version>4.5.2</httpclient.version>
<shiro.version>1.4.0</shiro.version>
<shiro-redis.version>3.1.0</shiro-redis.version>
<mybatis-spring.version>1.3.2</mybatis-spring.version>
<mybatis-mapper.version>3.4.0</mybatis-mapper.version>
<mybatis-pagehelper.version>1.2.10</mybatis-pagehelper.version>
<guava.version>18.0</guava.version>
<jwt.verson>0.9.0</jwt.verson>

<docker.host>http://127.0.0.1:2375</docker.host>
<docker.repostory>127.0.0.1:5000</docker.repostory>
<docker.registry.name>zone7</docker.registry.name>
<docker.plugin.version>0.4.13</docker.plugin.version>
<skipDockerBuild>false</skipDockerBuild>
</properties>

<dependencies>




<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<!-- 移除嵌入式tomcat插件,需要增加servlet-api,打包时打开注解 -->
<!--<exclusion>-->
<!--<groupId>org.springframework.boot</groupId>-->
<!--<artifactId>spring-boot-starter-tomcat</artifactId>-->
<!--</exclusion>-->
<!-- 移除springboot自带的logback日志管理 -->
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>

<!-- 移除嵌入式tomcat插件,需要增加servlet-api,打包时打开注解 -->
<!--<dependency>-->
<!--<groupId>javax.servlet</groupId>-->
<!--<artifactId>javax.servlet-api</artifactId>-->
<!--<version>3.1.0</version>-->
<!--<scope>provided</scope>-->
<!--</dependency>-->

<!-- 引入依赖之后spring.aop.auto默认开启,不需要添加@EnableAspectJAutoProxy来启动 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>


<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>

<!--安全验证相关-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-security</artifactId>
<version>2.1.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.0.14.RELEASE</version>
</dependency>

<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
<version>2.1.5.RELEASE</version>
</dependency>

<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-jwt</artifactId>
<version>1.0.10.RELEASE</version>
</dependency>
<!--解析JWT-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>${jwt.verson}</version>
</dependency>
<!-- 安全相关 -->


<!-- log4j2日志管理 (springboot1.4以上不支持log4j) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<dependency>
<groupId>com.lmax</groupId>
<artifactId>disruptor</artifactId>
<version>3.4.1</version>
</dependency>
<!-- log4j2日志管理-->

<!--junit-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.minidev</groupId>
<artifactId>json-smart</artifactId>
<version>2.2.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.minidev</groupId>
<artifactId>asm</artifactId>
<version>1.0.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
</dependency>
<!--junit-->

<!-- mybatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis-spring.version}</version>
</dependency>
<!-- mybatis -->

<!-- mybatis通用mapper -->
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper</artifactId>
<version>${mybatis-mapper.version}</version>
</dependency>
<!-- mybatis通用mapper -->

<!-- mybatis pagehelper -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>${mybatis-pagehelper.version}</version>
</dependency>
<!-- mybatis pagehelper -->

<!--druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>${druid-starte.version}</version>
</dependency>
<!--druid-->

<!--fastjson-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<!--fastjson-->

<!--oracle-->
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
<version>${oracle.version}</version>
</dependency>
<!--oracle-->

<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<!-- mysql -->


<!--redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--redis-->

<!-- mongodb -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<!-- mongodb -->

<!--swagger2-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${swagger2.version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${swagger2.version}</version>
</dependency>
<!--swagger2-->

<!--shiro-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>${shiro.version}</version>
</dependency>
<!--shiro redis支持-->
<dependency>
<groupId>org.crazycake</groupId>
<artifactId>shiro-redis</artifactId>
<version>${shiro-redis.version}</version>
</dependency>
<!--shiro-->

<!--httpclient-->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>${httpclient.version}</version>
</dependency>
<!--httpclient-->



<!-- 监控 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--guava-->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
<!--guava-->

<!-- rabbitmq -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
<version>2.1.0.RELEASE</version>
</dependency>
<!-- rabbitmq -->

<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
<!--lombok-->

<!--commons-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons-lang3.version}</version>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>${commons-collections.version}</version>
</dependency>

<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.3</version>
</dependency>

<!--commons-->


<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>net.sf.ezmorph</groupId>
<artifactId>ezmorph</artifactId>
<version>1.0.6</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>


</dependencies>

<build>
<finalName>app</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>

<!-- 设置资源文件的编码方式 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.4.3</version>
<executions>
<execution>
<phase>compile</phase>
</execution>
</executions>
<configuration>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork>
</configuration>

</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.20.1</version>
<configuration>
<!-- 不指定单元测试 -->
<skipTests>true</skipTests>
</configuration>
</plugin>

<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>${docker.plugin.version}</version>
<executions>
<execution>
<id>build-image</id>
<phase>package</phase>
<goals>
<goal>build</goal>
</goals>
</execution>
<execution>
<id>push-image</id>
<phase>deploy</phase>
<goals>
<goal>push</goal>
</goals>
<configuration>
<imageName>${docker.repostory}/${docker.registry.name}/${project.artifactId}:${project.version}</imageName>
</configuration>
</execution>
</executions>
<configuration>
<registryUrl>${docker.repostory}</registryUrl>
<pushImage>true</pushImage>
<dockerHost>${docker.host}</dockerHost>
<dockerDirectory>${project.basedir}/src/main/docker</dockerDirectory>
<imageName>${docker.repostory}/${docker.registry.name}/${project.artifactId}:${project.version}</imageName>
<imageTags>
<imageTag>${project.version}</imageTag>
</imageTags>
<resources>
<resource>
<targetPath>/</targetPath>
<directory>${project.build.directory}</directory>
<include>${project.build.finalName}.jar</include>
</resource>
</resources>
</configuration>
</plugin>
</plugins>
</build>

</project>

application.properties配置文件,在这里我们将其配置为dev模式,同时在resources下增加一个application-dev.properties的配置文件,用于配置开发测试期间的参数。

文件application.properties

1
spring.profiles.active=dev

文件application-dev.properties

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
#==================  server  ===================#
server.port=8080
#server.context-path=/springboot

#================== mybatis =====================#
mybatis.mapper-locations=classpath:mappers/**/*.xml
mybatis.configuration.map-underscore-to-camel-case=true
#================ mybatis pagehelper ==============#
pagehelper.helper-dialect=mysql
pagehelper.reasonable=true
pagehelper.support-methods-arguments=true
pagehelper.params=count=countSql

#================== database ===================#
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/zone-demo
spring.datasource.username=root
spring.datasource.password=zgq
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
#初始化大小,最小,最大
spring.datasource.initialSize=5
spring.datasource.minIdle=5
spring.datasource.maxActive=20
# 配置获取连接等待超时的时间
spring.datasource.maxWait=60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
spring.datasource.timeBetweenEvictionRunsMillis=60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
spring.datasource.minEvictableIdleTimeMillis=300000
spring.datasource.validationQuery=SELECT 1 FROM DUAL
spring.datasource.testWhileIdle=true
spring.datasource.testOnBorrow=false
spring.datasource.testOnReturn=false
# 打开PSCache,并且指定每个连接上PSCache的大小
spring.datasource.poolPreparedStatements=true

#================== redis ===================#
# redis 单节点地址
spring.redis.host=localhost
# redis 集群
#spring.redis.cluster.nodes=192.168.177.128:7001,192.168.177.128:7002,192.168.177.128:7003
#spring.redis.cluster.max-redirects=3
# Redis 数据库
spring.redis.database=0
# Redis 端口
spring.redis.port=6379
# Redis 密码
spring.redis.password=
# 连接池最大连接数(使用负值表示没有限制)
spring.redis.jedis.pool.max-active=8
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.jedis.pool.max-wait=-1
# 连接池中的最大空闲连接
spring.redis.jedis.pool.max-idle=8
# 连接池中的最小空闲连接
spring.redis.jedis.pool.min-idle=0
# 连接超时时间(毫秒)
spring.redis.timeout=3000

#================== cache ===================#
spring.cache.type=redis

#================== RabbitMq ===================#
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=admin
spring.rabbitmq.password=admin

spring.rabbitmq.listener.concurrency=10
spring.rabbitmq.listener.max-concurrency=20
spring.rabbitmq.listener.prefetch=50
#================== RabbitMq 队列配置 ===================#
mq.env=local
basic.info.mq.exchange.name=${mq.env}:basic:info:mq:exchange
basic.info.mq.routing.key.name=${mq.env}:basic:info:mq:routing:key
basic.info.mq.queue.name=${mq.env}:basic:info:mq:queue

#================== mongoDB 配置 ===================#
spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=test

#================== slf4j日志配置 ===================#
# 路径
logging.path=/Users/zgq/logs
logging.file=helloworld.log
#location of config file (default classpath:logback.xml for logback)
#logging.config=
# levels for loggers, e.g. "logging.level.org.springframework=DEBUG" (TRACE, DEBUG, INFO, WARN, ERROR, FATAL, OFF)
logging.level.com.zone7=INFO

#================== 默认密码 ===================#
system.default.password=123456

#================== 监控 ===================#
#actuator端口
management.server.port=8310
#修改访问路径,2.0之前默认是/,2.0默认是/actuator
management.endpoints.web.base-path=/actuator
#开放所有页面节点 ,默认只开启了health、info两个节点
management.endpoints.web.exposure.include=*
#显示健康具体信息,默认不会显示详细信息
management.endpoint.health.show-details=always

3.1.3 代码开发

3.1.3.1 用户安全验证

首先我们沿用第一章的SpringBoot工程,在 “/src/main/java/com/zone7/demo/helloworld/config/filter”下新增加一个安全过滤器,在实际应用中可以采用Oauth2、SpringSecurity或者Shiro来实现,这里只使用了session保存用户状态,并通过一个Filter的实现类来获取用户是否处于登陆状态来控制系统的安全访问。代码如下所示:

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
package com.zone7.demo.helloworld.config.filter;

import com.google.common.collect.Sets;
import com.zone7.demo.helloworld.sys.common.RequestHolder;
import com.zone7.demo.helloworld.sys.vo.SysUserVo;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.Set;

/**
* RequestFilter
* 请求过滤器
* 安全认证
* @author: zone7
* @time: 2019.02.19
*/
@WebFilter(filterName = "RequestFilter", urlPatterns = "/*")
public class RequestFilter implements Filter {

private static Set<String> URL_WHITE_LIST = Sets.newHashSet();

@Override
public void init(FilterConfig filterConfig) throws ServletException {
//忽略不过旅的路径
URL_WHITE_LIST.add("/unauth");
URL_WHITE_LIST.add("/login");
URL_WHITE_LIST.add("/logout");

URL_WHITE_LIST.add("/sys/unauth");
URL_WHITE_LIST.add("/sys/login");
URL_WHITE_LIST.add("/sys/logout");

URL_WHITE_LIST.add("/static");
URL_WHITE_LIST.add("/actuator");
URL_WHITE_LIST.add("/oauth");//oauth2.0默认接口
URL_WHITE_LIST.add("/api"); // 外部接口采用oauth进行权限验证
}

private boolean isWhiteUrl(String requestUrl){
if (URL_WHITE_LIST.contains(requestUrl)){
return true;
}
for(String str:URL_WHITE_LIST){

if(requestUrl.startsWith(str)){
return true;
}

}

return false;
}

@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
String requestUrl = request.getRequestURI();
if (isWhiteUrl(requestUrl)) {
filterChain.doFilter(servletRequest, servletResponse);
return;
}
SysUserVo userVo = (SysUserVo) request.getSession().getAttribute("user");
if (userVo == null) {
request.getRequestDispatcher("/unauth").forward(request, response);
return;
}

RequestHolder.add(userVo);
RequestHolder.add(request);


filterChain.doFilter(servletRequest, servletResponse);
}

@Override
public void destroy() {

}
}

3.2 前端开发
采用vue-cli 命令生成工程脚手架(创建命令:vue init webpack helloworld_web),前端工程的名称为“helloworld_web” 。采用IDEA工具打开工程,默认的结构如下图所示:
3.2a前端开发

工程目录默认有了router、compotent、assets,我们还需要增加api、views、store、utils目录。api目录用于存放采用mock实现的前后端交互脚本,views用于存放功能页面vue模板,store用于存放采用vuex实现的状态管理功能,utils用于存放通用工具脚本。工程目录结构如下图所示:
3.2b前端开发