Vue+SpringBoot 前后端分离小实验

1、概述

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

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

前端:Vue + axios

Vue+SpringBoot 前后端分离小实验_第1张图片

2、后端开发

POM依赖



    4.0.0

    com.example
    demo
    0.0.1-SNAPSHOT
    jar

    demo
    Demo project for Spring Boot

    
        org.springframework.boot
        spring-boot-starter-parent
        2.0.5.RELEASE
         
    

    
        UTF-8
        UTF-8
        1.8
    

    
        
            org.springframework.boot
            spring-boot-starter-actuator
        
        
            org.springframework.boot
            spring-boot-starter-data-jpa
        
        
            org.springframework.boot
            spring-boot-starter-data-rest
        
        
            org.springframework.data
            spring-data-rest-hal-browser
        
        
            org.springframework.boot
            spring-boot-starter-jdbc
        
        
            org.springframework.boot
            spring-boot-starter-web
        

        
            org.springframework.boot
            spring-boot-devtools
            runtime
        
        
            mysql
            mysql-connector-java
            runtime
        
        
            org.projectlombok
            lombok
            true
        
        
            org.springframework.boot
            spring-boot-starter-test
            test
        
        
            org.springframework.boot
            spring-boot-starter-thymeleaf
        
        
            org.webjars
            bootstrap
            4.1.3
        
        
        
            io.springfox
            springfox-swagger2
            2.7.0
        
        
        
            io.springfox
            springfox-swagger-ui
            2.7.0
        
        
        
            io.springfox
            springfox-bean-validators
            2.7.0
        
        
        
            io.springfox
            springfox-spi
            2.7.0
        

        
        javax.xml.bind
        jaxb-api
        2.3.0
    
    
        com.sun.xml.bind
        jaxb-impl
        2.3.0
    
    
        com.sun.xml.bind
        jaxb-core
        2.3.0
    
    
        javax.activation
        activation
        1.1.1
    
    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            

        
    



(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 {
}

`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 {
}

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

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": "[email protected]",
                "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": "[email protected]",
                "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": "[email protected]",
                "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": "[email protected]",
                "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": "[email protected]",
                "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`使用了

Vue+SpringBoot 前后端分离小实验_第2张图片

监听函数的代码为:

// 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\": \"[email protected]\",\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\": \"[email protected]\", \"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,就不管前端什么事了

你可能感兴趣的:(Java,Vue,axios)