Rest风格的后端web(SpringMVC)

前后端分离

天啦噜,我们希望『前后端分离』,前端的组件是css/js/html/图片,负责显示数据。数据打哪儿来?答案是后端。

后端服务器专门服务于前端,兢兢业业,勤勤恳恳,前端要什么,后端就给什么。

比如,前端向后端发出请求:www.ilovcecl.com/users/,目的是获取用户列表;逻辑复杂的后端服务器掐指一算,洞悉前端要的数据,便以JSON格式返回用户列表:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[
{
"id": 3,
"name": "Jerome",
"age": 45,
"salary": 30000
},
{
"id": 4,
"name": "Silvia",
"age": 50,
"salary": 40000
}
]

可见,前后端分离的过程中,后端会以JSON格式返回数据,数据URI符合Rest风格(当然前后端通信除了Rest外还有其它架构)。

本文给出的正是以JSON风格返回数据、符合Rest风格的后端web项目,不依赖于xml配置,结构简单。

操作说明

你可以从GitHub下载项目源码:https://github.com/qiuyongchen/rcs-web/archive/v1.0.0.zip
使用IntelliJ IDEA导入项目,自动刷新pom依赖(部分IDEA版本有Bug无法刷新,请在shell中输入mvn clean package,手动刷新);导入完成后配置tomcat,启动项目,访问http:localhost:8080/user/,耐心等待几秒钟,JSON即展现你眼前。

你也可以一步步地创建项目,添加文件,最后启动。

项目结构

本项目里,除了一个pom文件外,其余的均是java文件,不依赖传统的spring配置xml。
结构图:

src

pom文件

整个项目里唯一的配置有木有!!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.ilovecl</groupId>
<artifactId>rcs-web</artifactId>
<packaging>war</packaging>
<version>1.0.0</version>
<name>rcs-web</name>

<properties>
<springframework.version>4.2.0.RELEASE</springframework.version>
<jackson.version>2.5.3</jackson.version>
</properties>

<dependencies>
<!--SpringMVC Rest begin-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${springframework.version}</version>
</dependency>
<!--SpringMVC Rest end-->

<!--jackson begin-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<!--jackson end-->

<!--servlet begin-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
<!--servlet end-->
</dependencies>


<!--编译管理-->
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.4</version>
<configuration>
<warSourceDirectory>src/main/java</warSourceDirectory>
<warName>rcs-web</warName>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
</plugins>
</pluginManagement>
<finalName>rcs-web</finalName>
</build>
</project>

项目初始化 WebInitilizer.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package config;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

/**
* spring会自动在源码包中(pom->warSourceDirectory)寻找继承
* AbstractAnnotationConfigDispatcherServletInitializer的类,
* 将其作为web项目的初始化类
* Created by qiuyongchen on 2016/11/5.
*/
public class WebInitilizer extends AbstractAnnotationConfigDispatcherServletInitializer {

@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{WebConfiguration.class};
}

@Override
protected Class<?>[] getServletConfigClasses() {
return null;
}

@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}

}

项目配置类 WebConfiguration.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package config;

/**
* 如果源码直接放在pom->warSourceDirectory下,
* 则basePackages为'.'即可;
* 如果源码放在更深层级,
* 则需指定目录层级,如'com.xxx'
* Created by qiuyongchen on 2016/11/5.
*/

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = ".")
public class WebConfiguration {

}

控制类 RcsController.java

一个web项目最重要的类…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package controller;

/**
* 凡是带有注解@RestController的类,
* 都被当做controller处理
* Created by qiuyongchen on 2016/11/5.
*/

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.util.UriComponentsBuilder;

import model.User;
import service.UserService;

@RestController
public class RcsController {

@Autowired
UserService userService; //Service which will do all data retrieval/manipulation work


//-------------------Retrieve All Users--------------------------------------------------------

@RequestMapping(value = "/user/", method = RequestMethod.GET)
public ResponseEntity<List<User>> listAllUsers() {
List<User> users = userService.findAllUsers();
if (users.isEmpty()) {
return new ResponseEntity<List<User>>(HttpStatus.NO_CONTENT);//You many decide to return HttpStatus.NOT_FOUND
}
return new ResponseEntity<List<User>>(users, HttpStatus.OK);
}


//-------------------Retrieve Single User--------------------------------------------------------

@RequestMapping(value = "/user/{id}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<User> getUser(@PathVariable("id") long id) {
System.out.println("Fetching User with id " + id);
User user = userService.findById(id);
if (user == null) {
System.out.println("User with id " + id + " not found");
return new ResponseEntity<User>(HttpStatus.NOT_FOUND);
}
return new ResponseEntity<User>(user, HttpStatus.OK);
}


//-------------------Create a User--------------------------------------------------------

@RequestMapping(value = "/user/", method = RequestMethod.POST)
public ResponseEntity<Void> createUser(@RequestBody User user, UriComponentsBuilder ucBuilder) {
System.out.println("Creating User " + user.getName());

if (userService.isUserExist(user)) {
System.out.println("A User with name " + user.getName() + " already exist");
return new ResponseEntity<Void>(HttpStatus.CONFLICT);
}

userService.saveUser(user);

HttpHeaders headers = new HttpHeaders();
headers.setLocation(ucBuilder.path("/user/{id}").buildAndExpand(user.getId()).toUri());
return new ResponseEntity<Void>(headers, HttpStatus.CREATED);
}


//------------------- Update a User --------------------------------------------------------

@RequestMapping(value = "/user/{id}", method = RequestMethod.PUT)
public ResponseEntity<User> updateUser(@PathVariable("id") long id, @RequestBody User user) {
System.out.println("Updating User " + id);

User currentUser = userService.findById(id);

if (currentUser == null) {
System.out.println("User with id " + id + " not found");
return new ResponseEntity<User>(HttpStatus.NOT_FOUND);
}

currentUser.setName(user.getName());
currentUser.setAge(user.getAge());
currentUser.setSalary(user.getSalary());

userService.updateUser(currentUser);
return new ResponseEntity<User>(currentUser, HttpStatus.OK);
}

//------------------- Delete a User --------------------------------------------------------

@RequestMapping(value = "/user/{id}", method = RequestMethod.DELETE)
public ResponseEntity<User> deleteUser(@PathVariable("id") long id) {
System.out.println("Fetching & Deleting User with id " + id);

User user = userService.findById(id);
if (user == null) {
System.out.println("Unable to delete. User with id " + id + " not found");
return new ResponseEntity<User>(HttpStatus.NOT_FOUND);
}

userService.deleteUserById(id);
return new ResponseEntity<User>(HttpStatus.NO_CONTENT);
}

//------------------- Delete All Users --------------------------------------------------------

@RequestMapping(value = "/user/", method = RequestMethod.DELETE)
public ResponseEntity<User> deleteAllUsers() {
System.out.println("Deleting All Users");

userService.deleteAllUsers();
return new ResponseEntity<User>(HttpStatus.NO_CONTENT);
}

}

Model类 User.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
package model;

/**
* Created by qiuyongchen on 2016/11/5.
*/
public class User {

private long id;

private String name;

private int age;

private double salary;

public User() {
id = 0;
}

public User(long id, String name, int age, double salary) {
this.id = id;
this.name = name;
this.age = age;
this.salary = salary;
}

public long getId() {
return id;
}

public void setId(long id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

public double getSalary() {
return salary;
}

public void setSalary(double salary) {
this.salary = salary;
}

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) (id ^ (id >>> 32));
return result;
}

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
User other = (User) obj;
if (id != other.id)
return false;
return true;
}

@Override
public String toString() {
return "User [id=" + id + ", name=" + name + ", age=" + age
+ ", salary=" + salary + "]";
}

}

Service接口 UserService.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package service;

import model.User;

import java.util.List;

/**
* Created by qiuyongchen on 2016/11/5.
*/
public interface UserService {

User findById(long id);

User findByName(String name);

void saveUser(User user);

void updateUser(User user);

void deleteUserById(long id);

List<User> findAllUsers();

void deleteAllUsers();

public boolean isUserExist(User user);

}

Service接口实现类 UserServiceImpl.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
package service.impl;

/**
* Created by qiuyongchen on 2016/11/5.
*/

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import model.User;
import service.UserService;

@Service("userService")
@Transactional
public class UserServiceImpl implements UserService {

private static final AtomicLong counter = new AtomicLong();

private static List<User> users;

static {
users = populateDummyUsers();
}

public List<User> findAllUsers() {
return users;
}

public User findById(long id) {
for (User user : users) {
if (user.getId() == id) {
return user;
}
}
return null;
}

public User findByName(String name) {
for (User user : users) {
if (user.getName().equalsIgnoreCase(name)) {
return user;
}
}
return null;
}

public void saveUser(User user) {
user.setId(counter.incrementAndGet());
users.add(user);
}

public void updateUser(User user) {
int index = users.indexOf(user);
users.set(index, user);
}

public void deleteUserById(long id) {

for (Iterator<User> iterator = users.iterator(); iterator.hasNext(); ) {
User user = iterator.next();
if (user.getId() == id) {
iterator.remove();
}
}
}

public boolean isUserExist(User user) {
return findByName(user.getName()) != null;
}

private static List<User> populateDummyUsers() {
List<User> users = new ArrayList<User>();
users.add(new User(counter.incrementAndGet(), "Sam", 30, 70000));
users.add(new User(counter.incrementAndGet(), "Tom", 40, 50000));
users.add(new User(counter.incrementAndGet(), "Jerome", 45, 30000));
users.add(new User(counter.incrementAndGet(), "Silvia", 50, 40000));
return users;
}

public void deleteAllUsers() {
users.clear();
}

}