本文仅仅使用一个示例来说明restful的使用,是以springboot的2.0版本作为基础的。

基于springboot的示例,包含get、post、put和delete,以及使用resttemplate接收json。参数形式可以使用restful,也可以使用形如:url?id=xx,使用方式不同。
通过浏览器地址访问的都是get的请求方式,post、put和delete则可能需要专门的代码或工具访问。也就是post、put和delete不能通过浏览器的地址栏访问。
本文分为三部分,即pom.xml、代码和测试。

一、pom.xml

<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.0.0.RELEASE</version>
	</parent>
	<dependencies>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<version>1.16.18</version>
			<scope>provided</scope>
		</dependency>
		<!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
		<dependency>
			<groupId>com.google.code.gson</groupId>
			<artifactId>gson</artifactId>
			<version>2.8.5</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient -->
		<dependency>
			<groupId>org.apache.httpcomponents</groupId>
			<artifactId>httpclient</artifactId>
			<version>4.5.6</version>
		</dependency>
		<dependency>
			<groupId>org.apache.httpcomponents</groupId>
			<artifactId>fluent-hc</artifactId>
			<version>4.5.6</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient-cache -->
		<dependency>
			<groupId>org.apache.httpcomponents</groupId>
			<artifactId>httpclient-cache</artifactId>
			<version>4.5.6</version>
		</dependency>

		<dependency>
			<groupId>net.sf.ehcache</groupId>
			<artifactId>ehcache</artifactId>
			<version>2.8.3</version>
		</dependency>

		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>3.8.1</version>
			<scope>test</scope>
		</dependency>
		<!-- Add typical dependencies for a web application -->
		<!-- Adds Tomcat and Spring MVC, along others -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>com.fasterxml.jackson.dataformat</groupId>
			<artifactId>jackson-dataformat-xml</artifactId>
		</dependency>

二、源码

由于没有业务,代码比较简单,一般也不需要进行什么说明,就是实现一个CRUD。本示例没有连接数据库,直接通过方法造一些数据放在list中。

1、UserBean

package com.win.model;

import java.io.Serializable;

import lombok.Data;

@Data
public class User implements Serializable {
	private static final long serialVersionUID = 1946944818933250011L;
	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;
	}

	@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 + "]";
	}

}

2、CustomErrorType

package com.win.util;


public class CustomErrorType {
    private String errorMessage;

    public CustomErrorType(String errorMessage){
        this.errorMessage = errorMessage;
    }

    public String getErrorMessage() {
        return errorMessage;
    }

}

3、Service接口

package com.win.service;


import java.util.List;

import com.win.model.User;

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();
	boolean isUserExist(User user);
}

4、Service接口实现

package com.win.service;

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

import org.springframework.stereotype.Service;

import com.win.model.User;

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

	private static final AtomicLong counter = new AtomicLong();

	private static List<User> users;

	static {
		users = populateDummyUsers();
	}

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

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

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

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

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

	@Override
	public void deleteUserById(long id) {

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

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

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

	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;
	}

}

5、Controller

package com.win.controller;

import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
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.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.util.UriComponentsBuilder;

import com.win.model.User;
import com.win.service.UserService;
import com.win.util.CustomErrorType;

@RestController
@RequestMapping("/api")
public class RestApiController {
	public static final Logger logger = LoggerFactory.getLogger(RestApiController.class);

	@Autowired
	UserService userService; 

	// -Retrieve All Users
	@RequestMapping(value = "/list", method = RequestMethod.GET)
	public ResponseEntity<List<User>> listAllUsers() {
		List<User> users = userService.findAllUsers();
		if (users.isEmpty()) {
			return new ResponseEntity(HttpStatus.NO_CONTENT);
		}
		return new ResponseEntity<List<User>>(users, HttpStatus.OK);
	}

	// Retrieve Single User
	@RequestMapping(value = "/list/{id}", method = RequestMethod.GET)
	public ResponseEntity<?> getUser(@PathVariable("id") long id) {
		logger.info("user id {}", id);
		User user = userService.findById(id);
		if (user == null) {
			logger.error("user id {} not found.", id);
			return new ResponseEntity(new CustomErrorType("user id " + id + " not found"), HttpStatus.NOT_FOUND);
		}
		return new ResponseEntity<User>(user, HttpStatus.OK);
	}

	// Retrieve Single User
	// url形如:http://localhost:8080/api/list2?id=4
	@RequestMapping(value = "/list2", method = RequestMethod.GET)
	public ResponseEntity<?> getUser2(@RequestParam long id) {
		logger.info("user id {}", id);
		User user = userService.findById(id);
		if (user == null) {
			logger.error("user id {} not found.", id);
			return new ResponseEntity(new CustomErrorType("user id " + id + " not found"), HttpStatus.NOT_FOUND);
		}
		return new ResponseEntity<User>(user, HttpStatus.OK);
	}

	@RequestMapping(value = "/testpostproxy/", method = RequestMethod.POST)
	public ResponseEntity<String> testHttpClientPostProxy(String name, String password) {
		logger.info("name : {}, password : {}", name, password);
		if (name == null || password == null) {
			return new ResponseEntity(new CustomErrorType("name or password is null ."), HttpStatus.NO_CONTENT);
		}
		return new ResponseEntity<String>("name=" + name + ",password=" + password, HttpStatus.OK);
	}

	// Create a User
	@RequestMapping(value = "/add/", method = RequestMethod.POST)
	public ResponseEntity<?> createUser(User user, UriComponentsBuilder ucBuilder) {
		logger.info("创建 User : {}", user);

		if (userService.isUserExist(user)) {
			logger.error("不能创建. name {} 已存在", user.getName());
			return new ResponseEntity(
					new CustomErrorType("不能创建. name " + user.getName() + " 已存在."),
					HttpStatus.CONFLICT);
		}
		userService.saveUser(user);

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

	@RequestMapping(value = "/add/json/", method = RequestMethod.POST)
	public ResponseEntity<?> createUserWithJson(@RequestBody User user, UriComponentsBuilder ucBuilder) {
		logger.info("创建 User : {}", user);

		if (userService.isUserExist(user)) {
			logger.error("不能创建. name {} 已存在", user.getName());
			return new ResponseEntity(
					new CustomErrorType("不能创建. name " + user.getName() + " 已存在."),
					HttpStatus.CONFLICT);
		}
		userService.saveUser(user);

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

	// Update a User
	@RequestMapping(value = "/update/{id}", method = RequestMethod.PUT)
	public ResponseEntity<?> updateUser(@PathVariable("id") long id, @RequestBody User user) {
		logger.info("更新user  id {}", id);

		User currentUser = userService.findById(id);

		if (currentUser == null) {
			logger.error("不能更新. id {} not found.", id);
			return new ResponseEntity(new CustomErrorType("不能更新. id " + id + " not found."),
					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 = "/delete/{id}", method = RequestMethod.DELETE)
	public ResponseEntity<?> deleteUser(@PathVariable("id") long id) {
		logger.info("删除用户 id {}", id);

		User user = userService.findById(id);
		if (user == null) {
			logger.error("不能删除, id {} not found.", id);
			return new ResponseEntity(new CustomErrorType("不能删除, id " + id + " not found."),
					HttpStatus.NOT_FOUND);
		}
		userService.deleteUserById(id);
		return new ResponseEntity<User>(HttpStatus.NO_CONTENT);
	}

	// Delete All Users
	@RequestMapping(value = "/delUsers/", method = RequestMethod.DELETE)
	public ResponseEntity<User> deleteAllUsers() {
		logger.info("删除所有用户");

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

}

6、系统配置文件

server:
  port: 8080

7、服务启动类

package com.win;

import java.util.Arrays;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;

@SpringBootApplication(scanBasePackages = { "com.win" }) // same as @Configuration @EnableAutoConfiguration
															// @ComponentScan combined
public class SpringBootRestApiApp {

	public static void main(String[] args) {
		ApplicationContext ctx = SpringApplication.run(SpringBootRestApiApp.class, args);
	}
}

三、测试类

也可以直接使用浏览器和postman一起进行验证,或者自己如下文写个测试用例验证。

package com.win;

import java.net.URI;
import java.util.LinkedHashMap;
import java.util.List;

import org.springframework.web.client.RestTemplate;
import org.testng.annotations.Test;

import com.win.model.User;

public class SpringBootRestTestClient {
	public static final String REST_SERVICE_URI = "http://localhost:8080/api";

	/* GET */
	@SuppressWarnings("unchecked")
	private static void listAllUsers() {
		System.out.println("Testing listAllUsers API-----------");

		RestTemplate restTemplate = new RestTemplate();
		List<LinkedHashMap<String, Object>> usersMap = restTemplate.getForObject(REST_SERVICE_URI + "/list",
				List.class);

		if (usersMap != null) {
			for (LinkedHashMap<String, Object> map : usersMap) {
				System.out.println("User : id=" + map.get("id") + ", Name=" + map.get("name") + ", Age="
						+ map.get("age") + ", Salary=" + map.get("salary"));
			}
		} else {
			System.out.println("No user exist----------");
		}
	}

	/* GET */
	private static void getUser() {
		System.out.println("Testing getUser API----------");
		RestTemplate restTemplate = new RestTemplate();
		User user = restTemplate.getForObject(REST_SERVICE_URI + "/list/1", User.class);
		System.out.println(user);
	}

	/* POST */
	@Test
	private static void createUser() {
		System.out.println("Testing create User API----------");
		RestTemplate restTemplate = new RestTemplate();
		User user = new User(0, "Sarah", 51, 134);
		URI uri = restTemplate.postForLocation(REST_SERVICE_URI + "/add/json/", user, User.class);
		System.err.println("Location : " + uri.toASCIIString());
	}

	/* PUT */
	@Test
	private static void updateUser() {
		System.out.println("Testing update User API----------");
		RestTemplate restTemplate = new RestTemplate();
		User user = new User(1, "Tomy", 33, 70000);
		restTemplate.put(REST_SERVICE_URI + "/update/1", user);
		System.out.println(user);
	}

	/* DELETE */
	@Test
	private static void deleteUser() {
		System.out.println("Testing delete User API----------");
		RestTemplate restTemplate = new RestTemplate();
		restTemplate.delete(REST_SERVICE_URI + "/delete/3");
	}

	/* DELETE */
	@Test
	private static void deleteAllUsers() {
		System.out.println("Testing all delete Users API----------");
		RestTemplate restTemplate = new RestTemplate();
		restTemplate.delete(REST_SERVICE_URI + "/delUsers/");
	}

}

以上简单的使用springboot实现了restful。