经过对SpringBoot及VUE的学习,我们已经对他们的开发流程有了一定的了解,我们将这两个框架进行整合,并实现一个简单的前后的开发案例“HelloWorld”。这个案例我们主要实现:(1)系统的登陆、退出;(2)用户的查询、新增、修改、删除。系统架构如下图所示:
从架构图中可以看到前端UI采用VUE框架开发, vue框架整合了mock、validator、vuex等组件。后端包括:控制层、业务服务层和数据访问层,基于SpringBoot2开发,控制层主要实现了rest的http服务以及权限控制;业务服务层主要用于实现业务逻辑,同时也具备了日志、事物、缓存等功能;数据访问层采用mybatis框架实现。本节案例开发采用mysql作为数据库。
后端框架采用SpringBoot2+mybatis+redis整合框架开发,可以参照我们在SpringBoot开发的第一个工程,我们创建一个helloworld的后端工程。结构如下:
SpringBoot工程的主要配置文件包括maven的POM文件和application.properties配置文件。
pom文件内容为:
<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.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.1.5.RELEASEversion>
<relativePath/>
parent>
<modelVersion>4.0.0modelVersion>
<artifactId>helloworldartifactId>
<packaging>jarpackaging>
<version>1.0.1.RELEASEversion>
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
<java.version>1.8java.version>
<lombok.version>1.16.18lombok.version>
<commons-lang3.version>3.8.1commons-lang3.version>
<commons-collections.version>3.2.1commons-collections.version>
<redis.version>2.9.0redis.version>
<fastjson.version>1.2.21fastjson.version>
<swagger2.version>2.2.2swagger2.version>
<oracle.version>11.2.0.3oracle.version>
<mysql.version>8.0.11mysql.version>
<druid-starte.version>1.1.1druid-starte.version>
<junit.version>4.12junit.version>
<log4j.version>1.2.15log4j.version>
<net.minidev.json-smart.version>2.2.1net.minidev.json-smart.version>
<net.minidev.asm.version>1.0.2net.minidev.asm.version>
<httpclient.version>4.5.2httpclient.version>
<shiro.version>1.4.0shiro.version>
<shiro-redis.version>3.1.0shiro-redis.version>
<mybatis-spring.version>1.3.2mybatis-spring.version>
<mybatis-mapper.version>3.4.0mybatis-mapper.version>
<mybatis-pagehelper.version>1.2.10mybatis-pagehelper.version>
<guava.version>18.0guava.version>
<jwt.verson>0.9.0jwt.verson>
<docker.host>http://127.0.0.1:2375docker.host>
<docker.repostory>127.0.0.1:5000docker.repostory>
<docker.registry.name>zone7docker.registry.name>
<docker.plugin.version>0.4.13docker.plugin.version>
<skipDockerBuild>falseskipDockerBuild>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-loggingartifactId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-aopartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-cacheartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-securityartifactId>
<version>2.1.2.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframework.security.oauthgroupId>
<artifactId>spring-security-oauth2artifactId>
<version>2.0.14.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframework.security.oauth.bootgroupId>
<artifactId>spring-security-oauth2-autoconfigureartifactId>
<version>2.1.5.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframework.securitygroupId>
<artifactId>spring-security-jwtartifactId>
<version>1.0.10.RELEASEversion>
dependency>
<dependency>
<groupId>io.jsonwebtokengroupId>
<artifactId>jjwtartifactId>
<version>${jwt.verson}version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-log4j2artifactId>
dependency>
<dependency>
<groupId>com.lmaxgroupId>
<artifactId>disruptorartifactId>
<version>3.4.1version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>net.minidevgroupId>
<artifactId>json-smartartifactId>
<version>2.2.1version>
<scope>testscope>
dependency>
<dependency>
<groupId>net.minidevgroupId>
<artifactId>asmartifactId>
<version>1.0.2version>
<scope>testscope>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>${junit.version}version>
dependency>
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>${mybatis-spring.version}version>
dependency>
<dependency>
<groupId>tk.mybatisgroupId>
<artifactId>mapperartifactId>
<version>${mybatis-mapper.version}version>
dependency>
<dependency>
<groupId>com.github.pagehelpergroupId>
<artifactId>pagehelper-spring-boot-starterartifactId>
<version>${mybatis-pagehelper.version}version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druid-spring-boot-starterartifactId>
<version>${druid-starte.version}version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>fastjsonartifactId>
<version>${fastjson.version}version>
dependency>
<dependency>
<groupId>com.oraclegroupId>
<artifactId>ojdbc6artifactId>
<version>${oracle.version}version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>${mysql.version}version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-redisartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-mongodbartifactId>
dependency>
<dependency>
<groupId>io.springfoxgroupId>
<artifactId>springfox-swagger2artifactId>
<version>${swagger2.version}version>
dependency>
<dependency>
<groupId>io.springfoxgroupId>
<artifactId>springfox-swagger-uiartifactId>
<version>${swagger2.version}version>
dependency>
<dependency>
<groupId>org.apache.shirogroupId>
<artifactId>shiro-springartifactId>
<version>${shiro.version}version>
dependency>
<dependency>
<groupId>org.crazycakegroupId>
<artifactId>shiro-redisartifactId>
<version>${shiro-redis.version}version>
dependency>
<dependency>
<groupId>org.apache.httpcomponentsgroupId>
<artifactId>httpclientartifactId>
<version>${httpclient.version}version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
<dependency>
<groupId>com.google.guavagroupId>
<artifactId>guavaartifactId>
<version>${guava.version}version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-amqpartifactId>
<version>2.1.0.RELEASEversion>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>${lombok.version}version>
dependency>
<dependency>
<groupId>org.apache.commonsgroupId>
<artifactId>commons-lang3artifactId>
<version>${commons-lang3.version}version>
dependency>
<dependency>
<groupId>commons-collectionsgroupId>
<artifactId>commons-collectionsartifactId>
<version>${commons-collections.version}version>
dependency>
<dependency>
<groupId>commons-beanutilsgroupId>
<artifactId>commons-beanutilsartifactId>
<version>1.9.3version>
dependency>
<dependency>
<groupId>dom4jgroupId>
<artifactId>dom4jartifactId>
<version>1.6.1version>
dependency>
<dependency>
<groupId>net.sf.ezmorphgroupId>
<artifactId>ezmorphartifactId>
<version>1.0.6version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-autoconfigureartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-thymeleafartifactId>
dependency>
dependencies>
<build>
<finalName>appfinalName>
<plugins>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-compiler-pluginartifactId>
<configuration>
<source>${java.version}source>
<target>${java.version}target>
<encoding>${project.build.sourceEncoding}encoding>
configuration>
plugin>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-resources-pluginartifactId>
<version>2.4.3version>
<executions>
<execution>
<phase>compilephase>
execution>
executions>
<configuration>
<encoding>${project.build.sourceEncoding}encoding>
configuration>
plugin>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
<configuration>
<fork>truefork>
configuration>
plugin>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-surefire-pluginartifactId>
<version>2.20.1version>
<configuration>
<skipTests>trueskipTests>
configuration>
plugin>
<plugin>
<groupId>com.spotifygroupId>
<artifactId>docker-maven-pluginartifactId>
<version>${docker.plugin.version}version>
<executions>
<execution>
<id>build-imageid>
<phase>packagephase>
<goals>
<goal>buildgoal>
goals>
execution>
<execution>
<id>push-imageid>
<phase>deployphase>
<goals>
<goal>pushgoal>
goals>
<configuration>
<imageName>${docker.repostory}/${docker.registry.name}/${project.artifactId}:${project.version}imageName>
configuration>
execution>
executions>
<configuration>
<registryUrl>${docker.repostory}registryUrl>
<pushImage>truepushImage>
<dockerHost>${docker.host}dockerHost>
<dockerDirectory>${project.basedir}/src/main/dockerdockerDirectory>
<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}.jarinclude>
resource>
resources>
configuration>
plugin>
plugins>
build>
project>
application.properties配置文件,在这里我们将其配置为dev模式,同时在resources下增加一个application-dev.properties的配置文件,用于配置开发测试期间的参数。
文件application.properties
spring.profiles.active=dev
文件application-dev.properties
#================== 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
首先我们沿用第一章的SpringBoot工程,在 “/src/main/java/com/zone7/demo/helloworld/config/filter”下新增加一个安全过滤器,在实际应用中可以采用Oauth2、SpringSecurity或者Shiro来实现,这里只使用了session保存用户状态,并通过一个Filter的实现类来获取用户是否处于登陆状态来控制系统的安全访问。代码如下所示:
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工具打开工程,默认的结构如下图所示:
工程目录默认有了router、compotent、assets,我们还需要增加api、views、store、utils目录。api目录用于存放采用mock实现的前后端交互脚本,views用于存放功能页面vue模板,store用于存放采用vuex实现的状态管理功能,utils用于存放通用工具脚本。工程目录结构如下图所示: