业务模型:员工+部门,多对一,实现增删改查(CRUD)
后端:Spring Boot + Spring MVC + Spring REST Data
前端:Vue + axios
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
员工(`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`来简化代码长度
`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]}"
//获取详细配置信息
...
{
"_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
}
}
其他方法就不一一试了
简单用Vue脚手架创建项目,就一个helloworld
注意,此Hello项目的在WebStorm中启动的端口号为:8090
在`/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`使用了
监听函数的代码为:
// 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,就不管前端什么事了