基於SpringMVC進行REST服務開發
基於SpringMVC進行REST服務開發
背景
REST的概念這裡不多過多闡述。在REST中,資源通過URL進行識別和定位。一般來說,以下這些HTTP方法通常會匹配為如下的CRUD動作:
Create:POST
Read:GET
Update:PUT或PATCH
Delete:DELETE
@ResponseBody:此註解會告知Spring,我們要將返回的物件作為資源傳送給客戶端,並將其轉化為客戶端可接受的表現形式。如果客戶端的Accept頭部資訊表明它接受"application/json",並且jackson JSON庫位於應用程式的路徑下,那麼會將返回結果列表轉化為json格式。
@RestController
@ResponseEntity:作為@ResponseBody的替代方案,@ResponseEntity中可以包含響應相關的元資料(如頭部資訊和狀態碼)以及要轉換成資源表述的物件。
@ResponseStatus:此註解可以指定狀態碼。
環境搭建相關
SpringMVC相關的jar包全部引入便是
c3p0相關jar包:
jackson相關jar包:
oracle jdbc 相關jar包:
spring.xml 檔案程式碼如下圖所示:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!-- 定義要掃描 controller的包 --> <context:component-scan base-package="cn.com.restapi.controller" /> <context:component-scan base-package="cn.com.restapi.daoimpl"/> <context:component-scan base-package="cn.com.restapi.serviceimpl"/> <mvc:default-servlet-handler /> <!-- 啟動註解驅動 SpringMVC 功能 --> <mvc:annotation-driven /> <!-- 引用配置檔案 --> <context:property-placeholder location="classpath:jdbc.properties"/> <!-- 配置檢視解析器解析路徑 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver"> <!-- 定義檢視存放路徑 --> <property name="prefix" value="/WEB-INF/jsp/" /> <!-- 定義檢視字尾 --> <property name="suffix" value=".jsp" /> </bean> <!-- 1、宣告資料來源物件:C3P0連線池 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <!-- 載入jdbc驅動 --> <property name="driverClass" value="${driverClass}"></property> <!-- jdbc連線地址 --> <property name="jdbcUrl" value="${jdbcUrl}"></property> <!-- 連線資料庫的使用者名稱 --> <property name="user" value="${user}"></property> <!-- 連線資料庫的密碼 --> <property name="password" value="${password}"></property> <!-- 資料庫的初始化連線數 --> <property name="initialPoolSize" value="3"></property> <!-- 資料庫的最大連線數 --> <property name="maxPoolSize" value="10"></property> <!-- 資料庫最多執行的事務 --> <property name="maxStatements" value="100"></property> <!-- 連線數量不夠時每次的增量 --> <property name="acquireIncrement" value="2"></property> </bean> <!-- 建立jdbcTemplate物件 --> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"> </property> </bean> </beans>
jdbc.properties 配置檔案如下圖所示:
整個專案的目錄如下圖所示:
實體類Employee.java程式碼:
package cn.com.restapi.model;
public class Employee {
private int employeeID;
private String employeeName;
private int age;
private String address;
private String sex;
@Override
public String toString(){
return "Employee[EMPLOYEE_ID=" + employeeID + ",EMPLOYEENAME=" + employeeName + ",AGE=" + age + ",ADDRESS=" + address + ",SEX=" + sex + "]";
}
//get and set........
}
dao層程式碼:
import java.util.List;
import cn.com.restapi.model.Employee;
public interface EmployeeDao {
public List<Employee> getEmployees();
public Employee getEmployeeByID(int id);
public int createEmployee(Employee employee);
public int updateEmployee(Employee employee);
public int deleteEmployee(Employee employee);
public boolean ifEmployeeExist(Employee employee);
}
daoimpl層程式碼,此處使用c3p0資料來源和Spring中的JdbcTemplate模板。
package cn.com.restapi.daoimpl;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;
import cn.com.restapi.dao.EmployeeDao;
import cn.com.restapi.model.Employee;
@Repository
public class EmployeeDaoImpl implements EmployeeDao{
@Autowired
private JdbcTemplate jdbcTemplate;
private Log log = LogFactory.getLog(EmployeeDaoImpl.class.getName());
@Override
public List<Employee> getEmployees() {
// TODO Auto-generated method stub
String sql = "SELECT EMPLOYEE_ID,EMPLOYEE_NAME,AGE,ADDRESS,SEX FROM EMPLOYEE";
log.info(sql);
return jdbcTemplate.query(sql, new EmployeeRowMapper());
}
@Override
public Employee getEmployeeByID(int id) {
// TODO Auto-generated method stub
String sql = "SELECT EMPLOYEE_ID,EMPLOYEE_NAME,AGE,ADDRESS,SEX FROM EMPLOYEE WHERE EMPLOYEE_ID = ?";
log.info(sql);
List<Employee> employees = this.jdbcTemplate.query(sql, new EmployeeRowMapper(),id);
if (employees.isEmpty()) {
return null;
}
return employees.get(0);
}
@Override
public int createEmployee(Employee employee) {
// TODO Auto-generated method stub
String sql = "INSERT INTO EMPLOYEE(EMPLOYEE_ID,EMPLOYEE_NAME,AGE,ADDRESS,SEX) VALUE(?,?,?,?,?)";
log.info(sql);
int rowNum = this.jdbcTemplate.update(sql,employee.getEmployeeID(),employee.getEmployeeName(),employee.getAge(),employee.getAddress(),employee.getSex());
return rowNum;
}
@Override
public int updateEmployee(Employee employee) {
// TODO Auto-generated method stub
String sql = "UPDATE EMPLOYEE SET EMPLOYEE_NAME = ?,AGE = ?,ADDRESS = ?,SEX = ? WHERE EMPLOYEE_ID = ?";
log.info(sql);
int rowNum = this.jdbcTemplate.update(sql,employee.getEmployeeName(),employee.getAge(),employee.getAddress(),employee.getSex(),employee.getEmployeeID());
return rowNum;
}
@Override
public int deleteEmployee(Employee employee) {
// TODO Auto-generated method stub
String sql = "DELETE EMPLOYEE WHERE EMPLOYEE_ID = ?";
log.info(sql);
int rowNum = this.jdbcTemplate.update(sql,employee.getEmployeeID());
return rowNum;
}
public class EmployeeRowMapper implements RowMapper<Employee>{
@Override
public Employee mapRow(ResultSet rSet, int rowNum) throws SQLException {
// TODO Auto-generated method stub
Employee employee = new Employee();
employee.setEmployeeID(rSet.getInt("EMPLOYEE_ID"));
employee.setEmployeeName(rSet.getString("EMPLOYEE_NAME"));
employee.setAddress(rSet.getString("ADDRESS"));
employee.setAge(rSet.getInt("AGE"));
employee.setSex(rSet.getString("SEX"));
return employee;
}
}
@Override
public boolean ifEmployeeExist(Employee employee) {
// TODO Auto-generated method stub
Employee employee2 = this.getEmployeeByID(employee.getEmployeeID());
if (employee2 == null) {
return true;
}
return false;
}
}
Service層程式碼:
package cn.com.restapi.service;
import java.util.List;
import cn.com.restapi.model.Employee;
public interface EmployeeService {
public List<Employee> getEmployees();
public Employee getEmployee(int id);
public int createEmployee(Employee employee);
public int updateEmployee(Employee employee);
public int deleteEmployee(Employee employee);
public boolean ifEmployeeExist(Employee employee);
}
ServiceImpl層程式碼:
package cn.com.restapi.serviceimpl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import cn.com.restapi.dao.EmployeeDao;
import cn.com.restapi.model.Employee;
import cn.com.restapi.service.EmployeeService;
@Service
public class EmployeeServiceImpl implements EmployeeService{
@Autowired
private EmployeeDao employeeDao;
@Override
public List<Employee> getEmployees() {
// TODO Auto-generated method stub
List<Employee> employees = employeeDao.getEmployees();
return employees;
}
@Override
public Employee getEmployee(int id) {
// TODO Auto-generated method stub
Employee employee = employeeDao.getEmployeeByID(id);
return employee;
}
@Override
public int createEmployee(Employee employee) {
// TODO Auto-generated method stub
int rowNum = employeeDao.createEmployee(employee);
return rowNum;
}
@Override
public int updateEmployee(Employee employee) {
// TODO Auto-generated method stub
int rowNum = employeeDao.updateEmployee(employee);
return rowNum;
}
@Override
public int deleteEmployee(Employee employee) {
// TODO Auto-generated method stub
int rowNum = employeeDao.deleteEmployee(employee);
return rowNum;
}
@Override
public boolean ifEmployeeExist(Employee employee) {
// TODO Auto-generated method stub
boolean b = employeeDao.ifEmployeeExist(employee);
return b;
}
}
Controller層程式碼,分別對Employee表實現CRUD操作:
package cn.com.restapi.controller;
import java.net.URI;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
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.ExceptionHandler;
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.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.util.UriComponentsBuilder;
import cn.com.restapi.model.Employee;
import cn.com.restapi.model.EmployeeNotFoundException;
import cn.com.restapi.model.Error;
import cn.com.restapi.service.EmployeeService;
@RestController
public class EmployeeController {
@Autowired
public EmployeeService employeeService;
public Log log = LogFactory.getLog(EmployeeController.class.getName());
@RequestMapping(value="/employee",method = RequestMethod.GET)
public ResponseEntity<List<Employee>> getEmployees(){
log.info("getEmployee method called");
List<Employee> employees = employeeService.getEmployees();
if (employees.isEmpty()) {
return new ResponseEntity<List<Employee>>(employees,HttpStatus.NO_CONTENT);
}
return new ResponseEntity<List<Employee>>(employees,HttpStatus.OK);
}
@RequestMapping(value="/employee/{id}",method = RequestMethod.GET)
public Employee getEmployeeByID(@PathVariable("id") int id){
log.info("getEmployeeByID method called");
Employee employee = employeeService.getEmployee(id);
if (employee == null) {throw new EmployeeNotFoundException(id);}
return employee;
}
@ExceptionHandler(EmployeeNotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public ResponseEntity<Error> EmployeeNotFound(EmployeeNotFoundException e){
int employeeId = e.getEmployeeId();
Error error = new Error(4, "Employee [" + employeeId + "] not found");
return new ResponseEntity<Error>(error,HttpStatus.NOT_FOUND);
}
@RequestMapping(value="/employee",method = RequestMethod.POST,consumes="application/json")
public ResponseEntity<?> creatEmployee(@RequestBody Employee employee,UriComponentsBuilder ucb){
if (employeeService.ifEmployeeExist(employee)) {
Error error = new Error(4, "Employee [id=" + employee.getEmployeeID() + "] already exist");
return new ResponseEntity<Error>(error,HttpStatus.CONFLICT);
}
employeeService.createEmployee(employee);
HttpHeaders headers = new HttpHeaders();
URI locationUri = ucb.path("/RESTAPI/").path(String.valueOf(employee.getEmployeeID())).build().toUri();
headers.setLocation(locationUri);
ResponseEntity<Employee> responseEntity = new ResponseEntity<Employee>(employee,headers,HttpStatus.CREATED);
return responseEntity;
}
@RequestMapping(value="/employee",method = RequestMethod.PUT,consumes="application/json")
public ResponseEntity<?> updateEmployee(@RequestBody Employee employee,UriComponentsBuilder ucb){
if (!employeeService.ifEmployeeExist(employee)) {
Error error = new Error(4, "Employee [id=" + employee.getEmployeeID() + "] not found");
return new ResponseEntity<Error>(error,HttpStatus.NOT_FOUND);
}
employeeService.updateEmployee(employee);
HttpHeaders headers = new HttpHeaders();
URI locationUri = ucb.path("/RESTAPI/").path(String.valueOf(employee.getEmployeeID())).build().toUri();
headers.setLocation(locationUri);
ResponseEntity<Employee> responseEntity = new ResponseEntity<Employee>(employee,headers,HttpStatus.OK);
return responseEntity;
}
@RequestMapping(value="/employee",method=RequestMethod.DELETE,consumes="application/json")
public ResponseEntity<?> deleteEmployee(@RequestBody Employee employee){
if (!employeeService.ifEmployeeExist(employee)) {
Error error = new Error(4, "Employee [id=" + employee.getEmployeeID() + "] not found");
return new ResponseEntity<Error>(error,HttpStatus.NOT_FOUND);
}
employeeService.deleteEmployee(employee);
return new ResponseEntity<Employee>(HttpStatus.NO_CONTENT);
}
}
Controller層中有兩個實體類Error,EmployeeNotFoundException。用於返回錯誤資訊:
package cn.com.restapi.model;
public class Error {
private int code;
private String message;
public Error(int code,String message){
this.code = code;
this.message = message;
}
public int getCode(){
return code;
}
public String getMessage(){
return message;
}
}
package cn.com.restapi.model;
public class EmployeeNotFoundException extends RuntimeException{
private int EmployeeId;
public EmployeeNotFoundException(int employeeId){
this.EmployeeId = employeeId;
}
public int getEmployeeId(){
return EmployeeId;
}
}