新手福利,通过一个简单示例快速上手Spring Boot+Vue前后端分离
- 2019 年 10 月 29 日
- 筆記
2、动态加载router,用Vue+Element UI搭建后台管理系统界面
Vue + Element UI 并不是真正的前后端分离,它只有前端服务,并没有后端服务提供数据接口,很多小伙伴在后台留言希望楠哥能写一篇完整的 Spring Boot + Vue 前后端分离教程。大家有需求,楠哥就会尽量满足,所以今天用一个简单易懂的例子,快速教会大家如何实现 Spring Boot + Vue 的前后端分离开发。
既然是前后端分离,那么我们就分开来写两个独立的服务,首先完成后端服务,提供数据接口。然后完成前端服务通过 Ajax 调用后端接口并动态绑定数据。后端服务我们使用 Spring Boot + MyBatis,前端服务使用 Vue + Element UI。
后端服务
1、我们以查询图书为例,完成基于 RESTful 的接口开发,数据库建表语句如下所示。
DROP TABLE IF EXISTS `bookcase`; CREATE TABLE `bookcase` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(20) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8; LOCK TABLES `bookcase` WRITE; INSERT INTO `bookcase` VALUES (1,'社会'), (2,'情感'), (3,'国学'), (4,'推理'), (5,'绘画'), (6,'心理学'), (7,'传记'), (8,'科技'), (9,'计算机'), (10,'小说'); UNLOCK TABLES; DROP TABLE IF EXISTS `book`; CREATE TABLE `book` ( `id` int(10) NOT NULL AUTO_INCREMENT, `name` varchar(20) DEFAULT NULL, `author` varchar(20) DEFAULT NULL, `publish` varchar(20) DEFAULT NULL, `pages` int(10) DEFAULT NULL, `price` float(10,2) DEFAULT NULL, `bookcaseid` int(10) DEFAULT NULL, `abled` int(10) DEFAULT NULL, PRIMARY KEY (`id`), KEY `FK_ieh6qsxp6q7oydadktc9oc8t2` (`bookcaseid`), CONSTRAINT `FK_ieh6qsxp6q7oydadktc9oc8t2` FOREIGN KEY (`bookcaseid`) REFERENCES `bookcase` (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=74 DEFAULT CHARSET=utf8; LOCK TABLES `book` WRITE; INSERT INTO `book` VALUES (1,'解忧杂货店','东野圭吾','电子工业出版社',102,27.30,9,0), (2,'追风筝的人','卡勒德·胡赛尼','上海人民出版社',230,33.50,3,0), (3,'人间失格','太宰治','作家出版社',150,17.30,1,1), (4,'这就是二十四节气','高春香','电子工业出版社',220,59.00,3,1), (5,'白夜行','东野圭吾','南海出版公司',300,27.30,4,1), (6,'摆渡人','克莱儿·麦克福尔','百花洲文艺出版社',225,22.80,1,1), (7,'暖暖心绘本','米拦弗特毕','湖南少儿出版社',168,131.60,5,1), (8,'天才在左疯子在右','高铭','北京联合出版公司',330,27.50,6,1), (9,'我们仨','杨绛','生活.读书.新知三联书店',89,17.20,7,1), (10,'活着','余华','作家出版社',100,100.00,6,1), (11,'水浒传','施耐庵','三联出版社',300,50.00,1,1), (12,'三国演义','罗贯中','三联出版社',300,50.00,2,1), (13,'红楼梦','曹雪芹','三联出版社',300,50.00,5,1), (14,'西游记','吴承恩','三联出版社',300,60.00,3,1); UNLOCK TABLES;
2、新建 Maven 工程,pom.xml 引入相关依赖。
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.5.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.1</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.16</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> </dependencies>
3、创建实体类。
@Data public class BookCase { private int id; private String name; } @Data public class Book { private int id; private String name; private String author; private String publish; private int pages; private double price; private BookCase bookCase; } @Data public class BookVO { private Integer total; private List<Book> data; private Integer pageSize; }
4、创建 Repository 接口。
public interface BookRepository { public List<Book> find(Integer index,Integer limit); public Integer count(); } public interface BookCaseRepository { public BookCase findById(Integer id); }
5、在 resources/mapping 路径下创建 Repository 对应的 Mapper.xml。
<mapper namespace="com.southwind.repository.BookRepository"> <resultMap id="bookMap" type="Book"> <id property="id" column="id"/> <result property="name" column="name"/> <result property="author" column="author"/> <result property="publish" column="publish"/> <result property="pages" column="pages"/> <result property="price" column="price"/> <association property="bookCase" javaType="BookCase" select="com.southwind.repository.BookCaseRepository.findById" column="bookcaseid"></association> </resultMap> <select id="find" resultMap="bookMap"> select * from book limit #{param1},#{param2} </select> <select id="count" resultType="Integer"> select count(*) from book </select> </mapper> <mapper namespace="com.southwind.repository.BookCaseRepository"> <select id="findById" parameterType="java.lang.Integer" resultType="BookCase"> select * from bookcase where id = #{id} </select> </mapper>
6、创建 Service 接口及实现类。
public interface BookService { public BookVO findByPage(Integer page); } @Service public class BookServiceImpl implements BookService { @Autowired private BookRepository bookRepository; private Integer limit = 10; @Override public BookVO findByPage(Integer page) { Integer index = (page-1)*limit; BookVO bookVO = new BookVO(); bookVO.setData(bookRepository.find(index,limit)); bookVO.setTotal(bookRepository.count()); bookVO.setPageSize(limit); return bookVO; } }
7、创建 Handler。
@RestController @RequestMapping("/book") public class BookHandler { @Autowired private BookService bookService; @GetMapping("/findByPage/{page}") public BookVO findByPage(@PathVariable("page") Integer page){ return bookService.findByPage(page); } }
8、前端服务调用后端接口时存在跨域问题,在 Spring Boot 中可以通过实现 WebMvcConfigurer 接口来解决跨域问题。
@Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("*") .allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS") .allowCredentials(true) .maxAge(3600) .allowedHeaders("*"); } }
9、在 resources 路径下创建配置文件 application.yml。
server: port: 8181 spring: datasource: url: jdbc:mysql://localhost:3306/library?useUnicode=true&characterEncoding=UTF-8 username: root password: root driver-class-name: com.mysql.cj.jdbc.Driver mybatis: mapper-locations: classpath:/mapping/*.xml type-aliases-package: com.southwind.entity logging: level: com.southwind.repository.*: debug
10、创建启动类 Application 并运行。
@SpringBootApplication @MapperScan("com.southwind.repository") public class Application { public static void main(String[] args) { SpringApplication.run(Application.class,args); } }
11、启动成功后使用 Postman 测试 Handler 接口,如下图所示。

端口为 8181 的后端服务创建成功,接下来完成前端服务,并调用后端服务接口 。
前端服务
1、创建 Vue 工程,并安装 Element UI 和 axios。
2、我们使用 Element UI 来搭建前端界面,Element UI 提供了数据表格的组件,非常简单,直接查看 Element UI 官方文档即可,官方示例代码如下所示。
<template> <el-table :data="tableData" border style="width: 100%"> <el-table-column fixed prop="date" label="日期" width="150"> </el-table-column> <el-table-column prop="name" label="姓名" width="120"> </el-table-column> <el-table-column prop="province" label="省份" width="120"> </el-table-column> <el-table-column prop="city" label="市区" width="120"> </el-table-column> <el-table-column prop="address" label="地址" width="300"> </el-table-column> <el-table-column prop="zip" label="邮编" width="120"> </el-table-column> <el-table-column fixed="right" label="操作" width="100"> <template slot-scope="scope"> <el-button @click="handleClick(scope.row)" type="text" size="small">查看</el-button> <el-button type="text" size="small">编辑</el-button> </template> </el-table-column> </el-table></template><script> export default { methods: { handleClick(row) { console.log(row); } }, data() { return { tableData: [ {date: '2016-05-03',name: '王小虎',province: '上海',city: '普陀区',address: '上海市普陀区金沙江路 1518 弄',zip: 200333}, {date: '2016-05-03',name: '王小虎',province: '上海',city: '普陀区',address: '上海市普陀区金沙江路 1518 弄',zip: 200333}, {date: '2016-05-03',name: '王小虎',province: '上海',city: '普陀区',address: '上海市普陀区金沙江路 1518 弄',zip: 200333}, {date: '2016-05-03',name: '王小虎',province: '上海',city: '普陀区',address: '上海市普陀区金沙江路 1518 弄',zip: 200333} ] } } } </script>
3、运行结果如下图所示。

4、在 Vue 工程 components 路径下创建 Table.Vue,在初始化方法中通过 axios 调用后端服务的数据接口并完成动态绑定,代码如下所示。
<template> <div> <div> <el-table :data="tableData" border style="width: 80%;margin-left: 100px;margin-top: 30px;"> <el-table-column fixed prop="id" label="编号" width="100"> </el-table-column> <el-table-column prop="name" label="图书" width="150"> </el-table-column> <el-table-column prop="author" label="作者" width="150"> </el-table-column> <el-table-column prop="publish" label="出版社" width="180"> </el-table-column> <el-table-column prop="pages" label="总页数" width="100"> </el-table-column> <el-table-column prop="price" label="价格" width="100"> </el-table-column> <el-table-column prop="bookCase.name" label="分类" width="120"> </el-table-column> <el-table-column fixed="right" label="操作" width="100"> <template slot-scope="scope"> <el-button type="text" size="small">修改</el-button> <el-button type="text" size="small">删除</el-button> </template> </el-table-column> </el-table> <el-pagination background layout="prev, pager, next" :total="total" :page-size="pageSize" @current-change="change" > </el-pagination> </div> </div> </template> <script> export default { methods: { change(currentPage) { this.currentPage = currentPage const _this = this axios.get('http://localhost:8181/book/findByPage/'+currentPage).then(function (resp) { _this.tableData = resp.data.data }) } }, data() { return { total:0, pageSize:5, tableData: [], currentPage:0 } }, created() { const _this = this axios.get('http://localhost:8181/book/findByPage/1').then(function (resp) { console.log(resp.data) _this.pageSize = resp.data.pageSize _this.total = resp.data.total _this.tableData = resp.data.data }) } } </script>
5、在 router.js 中设置 Table.Vue 路由,代码如下所示。
import Table from '../components/Table' routes:[ { path: '/table', component: Table, name: '查询图书' } ]
6、在终端执行命令 npm run serve 启动 Vue 服务,打开浏览器访问 http://localhost:8080/table,结果如下图所示。

这样我们就完成了 Spring Boot + Vue 前后端分离的开发,很简单吧,你学会了吗