Vue+SpringBoot 前后端分离小实验

1、概述

业务模型:员工+部门,多对一,实现增删改查(CRUD)

后端:Spring Boot + Spring MVC + Spring REST Data

前端:Vue + axios

2、后端开发

POM依赖

<?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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>demo</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-rest</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-rest-hal-browser</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>bootstrap</artifactId>
            <version>4.1.3</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.7.0</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.7.0</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/io.springfox/springfox-bean-validators -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-bean-validators</artifactId>
            <version>2.7.0</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/io.springfox/springfox-spi -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-spi</artifactId>
            <version>2.7.0</version>
        </dependency>

        <dependency>
        <groupId>javax.xml.bind</groupId>
        <artifactId>jaxb-api</artifactId>
        <version>2.3.0</version>
    </dependency>
    <dependency>
        <groupId>com.sun.xml.bind</groupId>
        <artifactId>jaxb-impl</artifactId>
        <version>2.3.0</version>
    </dependency>
    <dependency>
        <groupId>com.sun.xml.bind</groupId>
        <artifactId>jaxb-core</artifactId>
        <version>2.3.0</version>
    </dependency>
    <dependency>
        <groupId>javax.activation</groupId>
        <artifactId>activation</artifactId>
        <version>1.1.1</version>
    </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>

        </plugins>
    </build>


</project>

(1)业务实体

员工(`Employee`)

package com.example.demo.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.springframework.format.annotation.DateTimeFormat;

import javax.persistence.*;
import javax.validation.constraints.Email;
import javax.validation.constraints.Size;
import java.io.Serializable;
import java.sql.Timestamp;
import java.util.Date;

@Entity(name = "tbl_emp")
@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode
public class Employee implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "emp_id")
    private Long id;

    @Column(name = "last_name",length = 100,nullable = false,unique = false)
    @Size(min = 2,max = 50)
    private String lastName;

    @Email(message = "邮箱格式不正确!")
    @Column(name = "email",length = 100,nullable = false,unique = true)
    private String email;

    @Column(name = "phone_number",length = 11, nullable = false,unique = false)
    @Size(min = 11,max = 11)
    private String phoneNumber;

    @DateTimeFormat(pattern = "yyyy-MM-dd")
    @Column(name = "birth")
    private Date birth;

    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @Column(name = "create_time",columnDefinition="timestamp default current_timestamp")
    private Timestamp createTime;

    @ManyToOne
    @JoinColumn(name = "dept_id")
    private Department department;
}

部门(`Department`)

package com.example.demo.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;

import javax.persistence.*;
import javax.validation.constraints.Size;
import java.io.Serializable;

/**
 * @author Blessed
 */
@Entity(name = "tbl_dept")
@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode
public class Department implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "department_id")
    private Long id;
    @Column(name = "department_name")
    @Size(min = 2,max = 50)
    private String departmentName;
}

其中用`Lombok`来简化代码长度

(2)数据访问层

`EmployeeRepository`

package com.example.demo.repository;

import com.example.demo.entity.Employee;
import io.swagger.annotations.Api;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
import org.springframework.web.bind.annotation.CrossOrigin;

/**
 * @author Blessed
 */
@Api(tags = "Employee Entity") //Swagger REST API 但是好像目前需要一些插件,由于版本冲突,不能显示
@CrossOrigin(origins = {"http://localhost:8090","null"}) //CORS 跨域请求设置
@RepositoryRestResource(path = "emp") //配置生成REST API和对应Controller,path属性指定访问路径,按道理应该是复数(emps)这里就忽略了
public interface EmployeeRepository extends JpaRepository<Employee,Long> {
}

`DepartmentRepository`

package com.example.demo.repository;

import com.example.demo.entity.Department;
import io.swagger.annotations.Api;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
import org.springframework.web.bind.annotation.CrossOrigin;

/**
 *
 * @author Blessed
 */
@Api(tags = "Department Entity")
@CrossOrigin(origins = {"http://localhost:8090","null"})
@RepositoryRestResource(path = "dept")
public interface DepartmentRepository extends JpaRepository<Department,Long> {
}

到此,后端大功告成,打包

mvn clean package

通过`java -jar jarName`来启动Spring Boot项目

java -jar demo-0.0.1-SNAPSHOT.jar

项目启动

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.0.5.RELEASE)

......
: Mapped "{[/{repository}/{id}],methods=[HEAD],produces=[application/hal+json || application/json]}"

Mapped "{[/{repository}/{id}],methods=[OPTIONS],produces=[application/hal+json || application/json]}"

Mapped "{[/{repository}],methods=[GET],produces=[application/hal+json || application/json]}"
//获取对应实体的所有的记录,比如发送GET /emp 获取数据库中所有员工信息,支持分页

Mapped "{[/{repository}],methods=[OPTIONS],produces=[application/hal+json || application/json]}"

Mapped "{[/{repository}],methods=[GET],produces=[application/x-spring-data-compact+json || text/uri-list]}"

Mapped "{[/{repository}],methods=[HEAD],produces=[application/hal+json || application/json]}"

Mapped "{[/{repository}],methods=[POST],produces=[application/hal+json || application/json]}"
//添加一条记录,用JSON发送

Mapped "{[/{repository}/{id}],methods=[PATCH],produces=[application/hal+json || application/json]}"

Mapped "{[/{repository}/{id}],methods=[PUT],produces=[application/hal+json || application/json]}"
//修改实体内容,修改内容放在JSON发送

Mapped "{[/{repository}/{id}],methods=[GET],produces=[application/hal+json || application/json]}"
//获取对应id的实体信息,比如 GET /emp/2 获取ID为2的员工信息

Mapped "{[/{repository}/{id}],methods=[DELETE],produces=[application/hal+json || application/json]}"
//删除对应id的实体,比如 DELETE /emp/2 删除员工ID为2的记录

Mapped "{[/{repository}/{id}/{property}],methods=[DELETE],produces=[application/hal+json || application/json]}"
//获取详细配置信息
...

(3)Postman测试

发送 GET http://localhost:8080/emp

{
    "_embedded": {
        "employees": [
            {
                "lastName": "Blessed",
                "email": "AAA@163.com",
                "phoneNumber": "15850720606",
                "birth": "1996-03-29T00:00:00.000+0000",
                "createTime": "2018-09-18T15:11:02.000+0000",
                "_links": {
                    "self": {
                        "href": "http://localhost:8080/emp/1"
                    },
                    "employee": {
                        "href": "http://localhost:8080/emp/1"
                    },
                    "department": {
                        "href": "http://localhost:8080/emp/1/department"
                    }
                }
            },
            {
                "lastName": "Ryan",
                "email": "Rayn@163.com",
                "phoneNumber": "15850720606",
                "birth": "1996-02-12T00:00:00.000+0000",
                "createTime": "2018-09-18T20:00:00.000+0000",
                "_links": {
                    "self": {
                        "href": "http://localhost:8080/emp/2"
                    },
                    "employee": {
                        "href": "http://localhost:8080/emp/2"
                    },
                    "department": {
                        "href": "http://localhost:8080/emp/2/department"
                    }
                }
            },
            {
                "lastName": "Helen",
                "email": "Halen@163.com",
                "phoneNumber": "12345698725",
                "birth": "1996-05-05T00:00:00.000+0000",
                "createTime": "2018-09-19T00:00:00.000+0000",
                "_links": {
                    "self": {
                        "href": "http://localhost:8080/emp/3"
                    },
                    "employee": {
                        "href": "http://localhost:8080/emp/3"
                    },
                    "department": {
                        "href": "http://localhost:8080/emp/3/department"
                    }
                }
            },
            {
                "lastName": "Bob",
                "email": "Bob@163.com",
                "phoneNumber": "15452368460",
                "birth": "1996-05-05T00:00:00.000+0000",
                "createTime": "2019-09-23T12:00:00.000+0000",
                "_links": {
                    "self": {
                        "href": "http://localhost:8080/emp/6"
                    },
                    "employee": {
                        "href": "http://localhost:8080/emp/6"
                    },
                    "department": {
                        "href": "http://localhost:8080/emp/6/department"
                    }
                }
            },
            {
                "lastName": "Jack",
                "email": "jack@163.com",
                "phoneNumber": "25136587541",
                "birth": "1996-07-12T00:00:00.000+0000",
                "createTime": "2019-09-24T12:00:00.000+0000",
                "_links": {
                    "self": {
                        "href": "http://localhost:8080/emp/7"
                    },
                    "employee": {
                        "href": "http://localhost:8080/emp/7"
                    },
                    "department": {
                        "href": "http://localhost:8080/emp/7/department"
                    }
                }
            }
        ]
    },
    "_links": {
        "self": {
            "href": "http://localhost:8080/emp{?page,size,sort}",
            "templated": true
        },
        "profile": {
            "href": "http://localhost:8080/profile/emp"
        }
    },
    "page": {
        "size": 20,
        "totalElements": 5,
        "totalPages": 1,
        "number": 0
    }
}

其他方法就不一一试了

3、前端开发

简单用Vue脚手架创建项目,就一个helloworld

注意,此Hello项目的在WebStorm中启动的端口号为:8090

(1)配置代理(PS:才疏学浅,不知道为什么,不配就可能产生跨域的问题)

在`/config/index.js`中的`proxyTable`配置

    proxyTable: {
      '/api': {
        target: 'http://127.0.0.1:8080',
        changeOrigin: true,
        pathRewrite: {
          '^/api': ''
        }
      }
    },

以后比如发请求`http://127.0.0.1:8080/emp`,变成`/api/emp`,实际的发的请求就是:`http://localhost:8090/api/emp`

所以在发`POST`、`PUT`,`DELETE`请求的跨域时候就需要匹配后端的跨域设置

在前面后端开发中,在`repository`中配置了如下的注解

@CrossOrigin(origins = {"http://localhost:8090","null"})

注意是`8090`,而不是`8080`

接下里就是简单的`axios`使用了

<template>
  <div>
    <button @click="queryAllEmployees">查询所有员工</button>
    <button @click="addEmployee">添加员工</button>
    <button @click="deleteEmployee">删除员工</button>
    <button @click="updateEmployee">更新员工信息</button>
    <br><br>
    <button @click="deleteDept">删除部门</button>
    <button @click="addDept">添加部门</button>
    <button @click="updateDept">修改部门</button>
  </div>
</template>

监听函数的代码为:

// import qs from 'qs'
export default {
  name: 'HelloWorld',
  methods: {
    updateEmployee () {
      this.$axios({
        url: '/api/emp/1',
        method: 'PUT',
        data: "{\n" +
          "\t\"lastName\": \"Blessed\",\n" +
          "\t\"email\": \"blessed@163.com\",\n" +
          "\t\"phoneNumber\": \"12365478985\",\n" +
          "\t\"birth\": \"1996-03-29\",\n" +
          "\t\"createTime\": \"2018-09-24T21:52:52\",\n" +
          "\t\"department\": \"http://localhost:8080/dept/3\"\n" +
          "}",
        headers: {'Content-Type': 'application/json'}
      }).then(res => {console.log(res)}).catch(err => {console.log(err)})
    },
    deleteEmployee () {
      this.$axios({
        url: '/api/emp/3',
        method: 'DELETE'
      }).then(res => {console.log(res)}).catch(err => {console.log(err)})
    },
    updateDept () {
      this.$axios({
        url: '/api/dept/13',
        method: 'PUT',
        data: "{\"departmentName\": \"前台部门\"}",
        headers: {'Content-Type': 'application/json'}
      }).then(
        res => {console.log(res)}
      ).catch(err => {console.log(err)})
    },
    deleteDept () {
      this.$axios({
        url: '/api/dept/11',
        method: 'DELETE'
      }).then(
        res => {
          console.log(res)
        }
      ).catch(
        err => {
          alert('失败')
        }
      )
    },
    addEmployee () {
      alert('进入')
      this.$axios({
        url: '/api/emp',
        method: 'POST',
        data: "{\"lastName\": \"Jack\", \"email\": \"jack@163.com\", \"phoneNumber\": \"25136587541\", \"birth\": \"1996-07-12\", \"createTime\": \"2019-09-24T12:00:00\", \"department\": \"/api/dept/4\"}",
        headers: {'Content-Type': 'application/json'}
      }).then(
        res => {
          alert('成功')
          console.log(res)
        }
      ).catch(
        err => {
          alert('失败')
          console.log(err)
        }
      )
      alert('结束')
    },
    queryAllEmployees () {
      var url = '/api/emp'
      this.$axios.get(url).then(
        res => {
          console.log(res)
        }
      ).catch(
        err => {
          console.log(err)
        }
      )
    },
    addDept () {
      this.$axios({
        url: '/api/dept',
        method: 'post',
        data: "{\"departmentName\": \"前台接待部门\"}",
        headers: {'Content-Type': 'application/json'}
      }).then(
        res => {
          console.log(res)
        }
      ).catch(
        err => {
          console.log(err)
        }
      )
    }
  }
}

本人才接触Vue,就关掉了Eslint的检查,不然双引号会报错

【注意】:`data`属性应该是一个这样的格式:

{"param1": "value1", "param2": "value2"}
data: “{\"param1\": \"value1\", \"param2\": \"value2\"}”
//要是不这么发,后台会报错

另外注意的是,最好设置`Content-Type`为`application/json`

以上就可以进行简单的增删改查。而且后端再怎么复杂,只要规范暴露REST API,就不管前端什么事了

展开阅读全文

没有更多推荐了,返回首页