题记:
上一篇我们讲解了Spring Boot开发RESTful API的基础知识,本篇将继续这方面的学习,通过一个样例来展示使用Spring Boot开发RESTful Web API,另外,本篇还使用MyBatis来访问数据库数据。
一、使用MyBatis
1、什么是 MyBatis ?
MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。
2、引入MyBatis依赖
MyBatis的最新版是3.4.6,Spring Boot 通过mybatis-spring-boot-starter整合了MyBatis,我们这里使用mybatis-spring-boot-starter的1.3.2版本。
需要在POM.xml中添加依赖:
org.mybatis.spring.boot
mybatis-spring-boot-starter
1.3.2
完成后,即可通过 mybatis-spring-boot-starter 使用MyBatis了。
附录:本文使用样例的pom.xml配置(其他配置项全部使用工程创建时的默认配置,仅需要在依赖中添加如下配置项即可):
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-data-jpa
org.mybatis.spring.boot
mybatis-spring-boot-starter
1.3.2
mysql
mysql-connector-java
3、数据库配置
在/web-api/src/main/resources/application.properties中,添加如下配置:
## 数据源配置
spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
二、统一返回值
新建package utils,在该package中构建返回值类,来统一返回格式
package com.example.demo.utils;
/**
* 默认响应
*
* @author light
*
*/
public class ResponseMsg {
/**
* 返回结果
*/
private boolean result;
/**
* 错误码
*/
private int code = 0;
/**
* 错误描述
*/
private String description = "";
/**
* 数据
*/
private T data = null;
public ResponseMsg(boolean result, int code, String description) {
this.result = result;
this.code = code;
this.description = description;
this.data = null;
}
public ResponseMsg(boolean result, int code, String description, T data) {
this.result = result;
this.code = code;
this.description = description;
this.data = data;
}
public boolean isResult() {
return result;
}
public void setResult(boolean result) {
this.result = result;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
三、在domain中添加实体
添加User实体,具体类如下:
package com.example.demo.domain;
/**
* 用户实体类
*
* @author light
*
*/
public class User {
/**
* 用户id
* */
private int id;
/**
* 姓名
* */
private String name;
/**
* 年龄
* */
private int age;
public int getId() {
return id;
}
public void setId(int 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;
}
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("[userid=");
sb.append(id);
sb.append(",username=");
sb.append(name);
sb.append(",userage=");
sb.append(age);
sb.append("]");
return sb.toString();
}
}
四、在repository中添加数据访问类
这里的数据库访问实体,其实就是我们通常开发使用的dao层,具体类如下:
package com.example.demo.repository;
import java.util.List;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import com.example.demo.domain.User;
/**
* 用户访问数据
*
* @author light
*
*/
@Mapper
public interface UserRepository {
/**
* 获取全部用户信息
*
* @return
*/
@Select("select * from t_user1")
@Results({
@Result(property = "id", column = "id"),
@Result(property = "name", column = "name"),
@Result(property = "age", column = "age") })
List queryAll();
/**
* 用户数据新增
*/
@Insert("insert into t_user1(id,name,age) values (#{id},#{name},#{age})")
void addUser(User user);
/**
* 用户数据修改
*/
@Update("update t_user1 set name=#{name},age=#{age} where id=#{id}")
void updateUser(User user);
/**
* 用户数据删除
*/
@Delete("delete from t_user1 where id=#{id}")
void deleteUser(int id);
/**
* 根据用户ID查询用户信息
*
*/
@Select("SELECT id,name,age FROM t_user1 where id=#{userId}")
@Results({
@Result(property = "id", column = "id"),
@Result(property = "name", column = "name"),
@Result(property = "age", column = "age") })
User findById(@Param("userId") int userId);
}
@Param("id"):全局限定别名,定义查询参数在sql语句中的位置不再是顺序下标0,1,2,3......的形式,而是对应名称,该名称在此处定义。
@Results是以@Result为元素的数组,@Result表示单条属性——字段的映射关系,id = true表示该id字段是主键,查询时mybatis会给予必要的优化。数组中所有的@Result组成了单个记录的映射关系,而@Results则是单个记录的集合。另外,还有一个非常重要的注解@ResultMap,其与@Results类似
@Select("查询语句")、@Insert("增加语句")、@Update("更新语句")和@Delete("删除语句")表示对数据进行查询、添加、更新和删除的操作。
五、添加service实现
1、添加UserService
package com.example.demo.service;
import com.example.demo.domain.User;
import com.example.demo.utils.ResponseMsg;
/**
* UserService 接口
*
* @author light
*
*/
public interface UserService {
/**
* 获取所有用户列表
*
* @return
*/
ResponseMsg> getUsers();
/**
* 新增用户
*
* @param user
* @return
*/
ResponseMsg> addUser(User user);
/**
* 修改用户
*
* @param user
* @return
*/
ResponseMsg> updateUser(User user);
/**
* 删除用户
*
* @param id
* @return
*/
ResponseMsg> deleteUser(int id);
/**
* 根据用户ID查询用户信息
*
* @param userId
*/
ResponseMsg> findUserById(int userId);
}
2、添加UserService的实现
package com.example.demo.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.example.demo.domain.User;
import com.example.demo.repository.UserRepository;
import com.example.demo.utils.EmptyData;
import com.example.demo.utils.ResponseMsg;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserRepository userRepo;
@Override
public ResponseMsg> getUsers() {
ResponseMsg> res = new ResponseMsg>(true, 0, "");
try {
List users = userRepo.queryAll();
if (null != users && users.size() > 0) {
res.setData(users);
} else {
res.setCode(2);
res.setDescription("no user is existed!");
}
} catch (Exception e) {
e.printStackTrace();
res.setResult(false);
res.setCode(10000);
res.setDescription("Exception ");
}
return res;
}
@Override
public ResponseMsg> addUser(User user) {
ResponseMsg res = new ResponseMsg(true, 0, "", new EmptyData());
try {
userRepo.addUser(user);
} catch (Exception e) {
e.printStackTrace();
res.setResult(false);
res.setCode(10000);
res.setDescription("Exception ");
}
return res;
}
@Override
public ResponseMsg> updateUser(User user) {
ResponseMsg res = new ResponseMsg(true, 0, "", new EmptyData());
try {
userRepo.updateUser(user);
} catch (Exception e) {
e.printStackTrace();
res.setResult(false);
res.setCode(10000);
res.setDescription("Exception ");
}
return res;
}
@Override
public ResponseMsg> deleteUser(int id) {
ResponseMsg res = new ResponseMsg(true, 0, "", new EmptyData());
try {
userRepo.deleteUser(id);
} catch (Exception e) {
e.printStackTrace();
res.setResult(false);
res.setCode(10000);
res.setDescription("Exception ");
}
return res;
}
@Override
public ResponseMsg> findUserById(int userId) {
try {
User user = userRepo.findById(userId);
if (null != user) {
System.out.println("find user with " + userId + ", return user: " + user.toString());
return new ResponseMsg(true, 0, "", user);
} else {
return new ResponseMsg(false, 1, "User does not exists!");
}
} catch (Exception e) {
e.printStackTrace();
return new ResponseMsg(false, 1000, "Exception !!");
}
}
}
六、添加controller层实现
本例实现接口将通过统一路径的方式访问,形如:{ip}:{port}/api/user/{path}。
package com.example.demo.controller;
import org.springframework.beans.factory.annotation.Autowired;
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 com.example.demo.domain.User;
import com.example.demo.service.UserService;
import com.example.demo.utils.ResponseMsg;
/**
* API接口核心控制层
*
* @author light
*
*/
@RestController
@RequestMapping(value = "/api/user")
public class UserController {
@Autowired
private UserService userService;
/**
* 获取全部用户信息
*
* @return
*/
@RequestMapping(value = "/users", method = RequestMethod.GET)
public ResponseMsg> queryAll() {
System.out.println("开始查询全部用户");
return userService.getUsers();
}
/**
* 特别说明:在POST请求的BODY中传送参数,务必加上@RequestBody注解
*
* @param user
* @return
*/
@RequestMapping(value = "/addUser", method = RequestMethod.POST)
public ResponseMsg> addUser(@RequestBody User user) {
System.out.println("开始新增... user:" + user.toString());
return userService.addUser(user);
}
/**
* 特别说明:在PUT请求的BODY中传送参数,务必加上@RequestBody注解
*
* @param user
* @return
*/
@RequestMapping(value = "/updateUser", method = RequestMethod.PUT)
public ResponseMsg> updateUser(@RequestBody User user) {
System.out.println("开始更新...user:" + user.toString());
return userService.updateUser(user);
}
@RequestMapping(value = "/deleteUser", method = RequestMethod.DELETE)
public ResponseMsg> delete(@RequestParam(value = "userId", required = true) int userId) {
System.out.println("开始删除..., userid=" + userId);
return userService.deleteUser(userId);
}
@RequestMapping(value = "/userId", method = RequestMethod.GET)
public ResponseMsg> findByUserId(@RequestParam(value = "userId", required = true) int userId) {
System.out.println("开始查询..., userid=" + userId);
return userService.findUserById(userId);
}
}
七、运行验证
运行验证较为简单,可以使用Postman工具进行验证,较为简单,这里就不列出来了。
总结:
使用Spring Boot 开发 Web API 接口,是当前微服务开发模式下最为流程的开发方式,目前公司各个新的业务模块,特别是针对APP的模块已经全面切换到Spring Boot 进行 Web API 开发了。当然了,仅仅提供接口不足以支撑商业应用,基于Spring Boot 的开发还有很多的配套设施要做,后续将逐步展开。
参考:
http://www.mybatis.org/mybatis-3/zh/index.html
https://blog.csdn.net/gebitan505/article/details/54929287
https://blog.csdn.net/travellersy/article/details/78620247