1. 前言

前后端分离模式,可以让后端和前端开发人员致力于自己擅长的领域,且可以让前端和后端业务逻辑高度解耦合。本文从一个简单的案例入手,讲解使用 spring bootvue3如何实现前后端的分离。

前后端分离有2 种模式:

  • 逻辑分离:在一个项目中的前后分离。项目整体架构还是MVC模式,适合于小型项目。
  • 物理分离:独立的前后端项目分离。因是不同项目,会涉及远程调用等问题,适合于中、大型项目。后端项目仅是API提供者,可以服务于不同平台的前端项目,如网页版、微信小程序版的前端项目。

本文将使用 Spring Boot、Vue3、Elemnet Plus分别构建这2种分离模式。

无论使用哪一种分离模式,其后端API都是一样的。所以,本文先搭建后端服务项目。

2. Spring Boot API

后端项目也称为服务器端,以提供API为主,数据的应用以及显示由前端负责。本文后端项目的开发工具为IDEA,当然,你也可以选择其它开发工具,关系数据库系统为mysql

2.1 创建项目

打开 IDEA。新建名为 MyBookSpring Boot项目。

vue spring boot 出参加解密 springboot vue3_spring

选择spring boot的版本2.7.12,且选择如下的依赖包:

  • Spring Boot DevTools
  • LomBok
  • Spring Web
  • MyBatis Framework
  • MySql Driver

确认后,项目的初始结构如下图所示:

vue spring boot 出参加解密 springboot vue3_java_02

打开项目的application.properties文件,配置项目的jdbc基本信息。

#配置数据库连接信息
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/bookstore?useUnicode=true&characterEncoding=UTF-8&serverTimezone=PRC
spring.datasource.username=root
spring.datasource.password=abc123

vue spring boot 出参加解密 springboot vue3_ios_03

2.2 设计 API

本项目是一个基础MVC架构项目,仅提供一个用于测试的API,功能是用来显示所有的书本信息。

本项目采用由下向上的设计流程,先创建数据库,并设计book表。

Tips:mysql数据库系统的安装过程这里就不单独讲解,数据库连接客服端使用Navicat Premium

数据库设计:

  • 启动mysql服务,打开Navicat Premium。创建名为bookstore的数据库,以及在数据库中创建名为 book的数据库表,其字段结构如下:

字段名

类型

备注

book_id(编号)

int

主键、自动增长

book_title(书名)

varchar

book_author(作者)

varchar

book_price(价格)

double

vue spring boot 出参加解密 springboot vue3_spring boot_04

  • 表命名为book,并向表中插入2 条测试数据。

vue spring boot 出参加解密 springboot vue3_mybatis_05

数据库设计好后,开始项目结构的搭建:因项目使用 mybatis jdbc框架,故先构建mapper层。

  • mapper层。

新建 mapper层前,先创建book类。使用lombok简化book类的代码。

package com.gk.mybook.bean;
import lombok.*;
@Data
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class Book {
    private Integer bookId;
    private String bookTitle;
    private String bookAuthor;
    private Double bookPrice;
}

新建 BookMapper类:提供查询所有书籍的方法的声明。

package com.gk.mybook.mapper;
import com.gk.mybook.bean.Book;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
import java.util.List;
@Mapper
@Repository
public interface BookMapper {
    List<Book> getAllBooks();
}

编写 SQL 语句:查询所有书籍。

SELECT book_id,book_title,book_author,book_price from book

sql文件书写在 BookMapper.xml文件中,此文件存储在项目的 resources中。为了让 BookMapper自动找到xml文件,在resources文件中创建com.gk.mybook.mapper结构的目录结构。

Tips:也可能自定义其它位置。

至此,项目结构如下图所示:

vue spring boot 出参加解密 springboot vue3_ios_06

  • BookService层:业务层。

定义业层接口IBookService层,为业务层声明功能。

package com.gk.mybook.service;
import com.gk.mybook.bean.Book;
import java.util.List;
/*
*书籍业务对象
*/
public interface IBookService {
    List<Book> getBooks();
}

构建业务对象BookService:实现IBookService接口,依赖BookMapper对象。

package com.gk.mybook.service.impl;
import com.gk.mybook.bean.Book;
import com.gk.mybook.mapper.BookMapper;
import com.gk.mybook.service.IBookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class BookService implements IBookService {
    @Autowired
    private BookMapper bookMapper;
    @Override
    public List<Book> getBooks() {
        return this.bookMapper.getAllBooks();
    }
}

此时,项目结构如下图所示:

vue spring boot 出参加解密 springboot vue3_spring_07

  • 控制器层,并向外映射接口。
package com.gk.mybook.action;
import com.gk.mybook.bean.Book;
import com.gk.mybook.service.IBookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("/book")
public class BookAction {
    @Autowired
    private IBookService bookService;
    @RequestMapping("/books")
    List<Book> getBooks(){
       return this.bookService.getBooks();
    }
}
  • 测试接口。为了简化操作,直接在浏览器中测试,启动项目之前,别忘记在启动类前面加@MappScan注解,其实新版本spring boot可以省略此注解。
package com.gk.mybook;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan(value = {"com.gk.mybook.mapper"})
public class MybookApplication {
    public static void main(String[] args) {
        SpringApplication.run(MybookApplication.class, args);
    }
}

运行程序后,打开浏览器,在地址栏中输入http://localhost:8080/book/books。如果能看到下面的结果,说明服务器搭建成功。

vue spring boot 出参加解密 springboot vue3_ios_08

3. Vue Project

如上所说,前后分离有 2 种使用方式。

3.1 逻辑分离

直接在服务器项目的view层的html页面中使用vue框架。

在后端项目的resources->static目录中新建index.html文件。在文件中引入Vue、Element plus、axios依赖库。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8"/>
    <meta name="viewport" content="width=device-width,initial-scale=1.0"/>
    <title>书籍</title>
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    <link rel="stylesheet" href="https://unpkg.com/element-plus/dist/index.css">
    <!-- import JavaScript -->
    <script src="https://unpkg.com/element-plus"></script>
    <script src="https://unpkg.com/vue-router@4"></script>
</head>
<body>
   <div id="app">
   </div>
</body>
</html>

项目结构如下图:

vue spring boot 出参加解密 springboot vue3_spring boot_09

编写如下JS代码,实现在页面中显示所有书籍信息。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8"/>
    <meta name="viewport" content="width=device-width,initial-scale=1.0"/>
    <title>书籍</title>
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    <link rel="stylesheet" href="https://unpkg.com/element-plus/dist/index.css">
    <!-- import JavaScript -->
    <script src="https://unpkg.com/element-plus"></script>
    <script src="https://unpkg.com/vue-router@4"></script>
</head>
<body>
<div id="app">
    <h1>{{title}}</h1>
    <el-table :data="books">
        <el-table-column v-for="book in cols" :key="book.en"
                         :prop="book.en"
                         :label="book.cn"
                         show-overflow-tooltip align="center" width="160px">
            <template #default="scope">
                {{ scope.row[book.en] }}
            </template>
        </el-table-column>
    </el-table>
</div>
<script>
    const {createApp} = Vue
    var app = createApp({
        data() {
            return {
                title: "我的书籍",
                cols: [{"en": "bookId", "cn": "编号"}, {"en": "bookTitle", "cn": "书名"}],
                books: []
            }
        },
        mounted() {
            axios
                .get('http://localhost:8080/book/books')
                .then(response => (
                    this.books = response.data
                ))
                .catch(function (error) { // 请求失败处理
                    console.log(error);
                });
        }
    }).use(ElementPlus).mount('#app')
</script>
</body>
</html>

测试结果: 运行spring boot项目,打开浏览器,直接输入http://localhost:8080/index.html。可看到如下图所示结果。

vue spring boot 出参加解密 springboot vue3_java_10

3.2 物理分离

物理分离是真正意义上的前后端分离模板,此分离模式除了服务器端项目,还有独立的基于VUE框架的前端项目。项目中能使用VUE单页面,能真正意义上实现组件化编程思想。

创建VUE项目有很多种方式,也有很多优秀的前端开发工具,本文使用HBuild以及其项目创建向导构建VUE项目。

3.2.1 新建 VUE项目

打开HBuild,新建项目,且选择使用vite 构建项目。如下图所示:

vue spring boot 出参加解密 springboot vue3_spring_11

新建的项目自动依赖了VUE和vite模块。可以打开项目中的package.json查看相关信息。

vue spring boot 出参加解密 springboot vue3_spring_12

为了能使用axios和 Element Plus,需要在项目中安装这两个模块库。

右击项目,在弹出来的快捷菜单中选择使用命名行窗口打开所在目录。在HBuild下面可看到终端窗口。

vue spring boot 出参加解密 springboot vue3_ios_13

安装axios模块,在命令模式下输入:

Tipsaxios的使用请查阅官方文档。

npm install axios

安装element-plus模块,在命令模式下输入:

npm install element-plus --save

可以在package.json文件中查看模块的依赖信息。

vue spring boot 出参加解密 springboot vue3_ios_14

为了使用element plus的自动导入功能,还需要安装unplugin-vue-components 和 unplugin-auto-import插件。在命令模式下输入如下指令进行安装。

npm install -D unplugin-vue-components unplugin-auto-import

打开vite.config.js文件,添加如下的配置信息:

vue spring boot 出参加解密 springboot vue3_spring boot_15

为了实现axios的跨域访问。还需要后端项目中新建配置类,且添加如下内容。

@Configuration
public class CorsConfig {
    @Bean
    CorsFilter corsFilter() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOriginPatterns(Collections.singletonList("*"));
        configuration.setAllowedMethods(Collections.singletonList("*"));
        configuration.setAllowedHeaders(Collections.singletonList("*"));
        configuration.setAllowCredentials(true);
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return new CorsFilter(source);
    }
}

如下图所示:

vue spring boot 出参加解密 springboot vue3_java_16

3.2.2 创建前端页面

VUE项目中,页面可以是重用的组件。本文直接在已经创建的HelloWorld.vue文件中进行修改,同样实现读取所有书籍。内容如下:

<script setup>
	import {
		ref,
		reactive
	} from 'vue'
	import axios from 'axios'
	defineProps({
		msg: String
	})
	const data = reactive({
		books: null
	})
	/*
	 * 使用 axios 请求服务器数据
	 */
	const getData = function() {
		axios({
			url: 'http://localhost:8080/book/books',
			method: 'get',
			headers: {
				"Access-Control-Allow-Origin": "*",
			}
		}).then((res) => {
			data.books = res.data
			console.log(data.books)
		});
	}
</script>
<template>
	<h1>{{ msg }}</h1>
	<el-table :data="data.books" style="width: 100%">
		<el-table-column prop="bookId" label="编号" width="180" />
		<el-table-column prop="bookTitle" label="书名" width="180" />
		<el-table-column prop="bookAuthor" label="作者" />
	</el-table>
	<el-button type="primary" @click="getData">查阅书籍</el-button>
</template>
<style scoped>
	a {
		color: #42b983;
	}
</style>

vue spring boot 出参加解密 springboot vue3_spring boot_17

启动前端、后端项目:

npm run dev

打开浏览器,在地址栏中输入:http://localhost:3000

vue spring boot 出参加解密 springboot vue3_mybatis_18

点击查阅书籍:

vue spring boot 出参加解密 springboot vue3_ios_19

4. 总结

本文通过一个案例,简要介绍了使用spring bootvue3如何实现项目的前后端分离。