SpringBoot实现RESTful接口架构应用

1、认识REST

1.1 什么是REST

REST是软件架构的规范体系结构,它将资源的状态以适合客户端的形式从服务器端发送到客户端(或相反方向)。在REST中,通过URL进行资源定位, 用HTTP动作(GET、POST、DELETE、PUSH等)描述操作,完成功能。

遵循RESTful风格,可以使开发的接口通用,以便调用者理解接口的作用。基于REST构建的API就是RESTful (REST风格) API。各大机构提供的API基本都是RESTful风格的。这样可以统一规范, 减少沟通、学习和开发的成本。

1.2 HTTP方法与CRUD动作映射

RESTful风格使用同一个URL,通过约定不同的HTTP方法来实施不同的业务。

普通网页的CRUD和RESTful风格的CRUD的区别,如下表:

动作普通CRUD的URL普通CRUD的HTTP方法RESTful的URLRESTful的CRUD的HTTP方法
查询user/id=1GETuser/{id}GET
增加user?name=xxxGET/POSTuserPOST
修改user/update?id=1GETuser/{id}PUT 或 PATCH
删除user/delete?id=1GETuser/{id}DELETE

可以看出,RESTful风格的CRUD比传统的CRUD简单明了,它通过HTTP方法来区分查询、增加、修改、删除。

 

2、创建项目与数据表

2.1 创建项目

(1)创建SpringBoot项目,项目结构如下图:

(2)添加pom.xml配置信息

由于实例中使用到了JPA,所以需要添加JPA和MySQL数据库的依赖:

<!-- Spring Data JPA依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

<!-- MySQL的JDBC数据库驱动 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.19</version>
</dependency>

(3)配置数据库连接信息

SpringBoot项目使用MySQL等关系型数据库,需要配置连接信息。

将默认的application.properties文件的后缀修改为“.yml”,即配置文件名称为:application.yml,并配置以下MySQL数据库的连接信息:

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/db_admin?useSSL=false&amp
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver
  jpa:
    database: MYSQL
    show-sql: true
    open-in-view: true
    properties:
      hibernate:
        enable_lazy_load_no_trans: true #使用延时加载时控制Session的生命周期
        dialect: org.hibernate.dialect.MySQL5Dialect
        ddl-auto: update

2.2 创建数据库表

使用MySQL数据库,创建 tb_user 用户信息表,并添加数据。

-- 判断数据表是否存在,存在则删除
DROP TABLE IF EXISTS tb_user;
 
-- 创建“用户信息”数据表
CREATE TABLE IF NOT EXISTS tb_user
( 
	user_id INT AUTO_INCREMENT PRIMARY KEY COMMENT '用户编号',
	user_name VARCHAR(50) NOT NULL COMMENT '用户姓名',
	blog_url VARCHAR(50) NOT NULL COMMENT '博客地址',
	blog_remark VARCHAR(50) COMMENT '博客信息'
) COMMENT = '用户信息表';
 
-- 添加数据
INSERT INTO tb_user(user_name,blog_url,blog_remark) VALUES('pan_junbiao的博客','https://blog.csdn.net/pan_junbiao','您好,欢迎访问 pan_junbiao的博客');
INSERT INTO tb_user(user_name,blog_url,blog_remark) VALUES('pan_junbiao的博客_02','https://blog.csdn.net/pan_junbiao','您好,欢迎访问 pan_junbiao的博客');

 

3、设计统一的RESTful风格的应用

近年来,随着移动互联网的发展,各种类型的客户端层出不穷。如果不统一数据接口,则会造成冗余代码,增加成本。RESTful风格的API正适合通过一套统一的接口为PC、手机APP等设备提供数据服务。

3.1 创建实体类(Entity层)

创建UserInfo类(用户信息的持久化类)。

import javax.persistence.*;

/**
 * 用户信息的持久化类
 * @author pan_junbiao
 **/
@Entity
@Table(name = "tb_user")
public class UserInfo
{
    //用户ID
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "user_id")
    private int userId;

    //用户姓名
    @Column(name = "user_name")
    private String userName;

    //博客地址
    @Column(name = "blog_url")
    private String blogUrl;

    //博客信息
    @Column(name = "blog_remark")
    private String blogRemark;

    //省略getter与setter方法...
}

3.2 定义统一返回的格式(Model层)

创建ApiStatusCode枚举(API执行状态编码枚举)。

/**
 * API执行状态编码枚举
 * @author pan_junbiao
 **/
public enum ApiStatusCode
{
    SUCCESS(2000, "操作成功"),
    NO_ACCESS(4000,"无访问权限"),
    BUSINESS_EXCEPTION(5000,"业务异常"),
    PARAM_INVALID(5001,"参数缺失或无效"),
    NOT_LOGIN_IN(5002,"未登录"),
    SYSTEM_EXCEPTION(6000,"系统异常"),
    FAILED(9000,"操作失败");

    private final int code; //状态码
    private final String description; //描述

    private ApiStatusCode(int code, String description)
    {
        this.code = code;
        this.description = description;
    }

    public int getCode()
    {
        return code;
    }

    public String getDescription()
    {
        return description;
    }
}

创建ApiResultModel类(Api返回结果类)。

/**
 * Api返回结果类
 * @author pan_junbiao
 **/
public class ApiResultModel
{
    public int statusCode; //状态码
    public String message; //返回消息描述
    public Object data; //返回数据

    public int getStatusCode()
    {
        return statusCode;
    }

    public void setStatusCode(int statusCode)
    {
        this.statusCode = statusCode;
    }

    public String getMessage()
    {
        return message;
    }

    public void setMessage(String message)
    {
        this.message = message;
    }

    public Object getData()
    {
        return data;
    }

    public void setData(Object data)
    {
        this.data = data;
    }
}

3.3 实现数据库访问接口层(Dao层)

创建UserDao.java(用户信息数据库访问接口),并继承JpaRepository接口。

import com.pjb.entity.UserInfo;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

/**
 * 用户信息数据库访问接口
 * @author pan_junbiao
 **/
@Repository
public interface UserDao extends JpaRepository<UserInfo,Integer>
{
}

3.4 实现控制器方法(Controller层)

创建UserController(用户控制器),实现用户数据的查询、新增、修改、删除,并实现数据的返回。

import com.pjb.dao.UserDao;
import com.pjb.entity.UserInfo;
import com.pjb.model.ApiResultModel;
import com.pjb.model.ApiStatusCode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;

/**
 * 用户控制器
 * @author pan_junbiao
 **/
@RestController
@RequestMapping("user")
public class UserController
{
    @Autowired
    private UserDao userDao;

    /**
     * 获取用户列表
     */
    @RequestMapping(value = "/", method = RequestMethod.GET)
    public ApiResultModel getUserList()
    {
        //获取用户列表
        List<UserInfo> userInfoList = userDao.findAll();

        //返回结果
        ApiResultModel apiResultModel = new ApiResultModel();
        apiResultModel.statusCode = ApiStatusCode.SUCCESS.getCode();
        apiResultModel.message = ApiStatusCode.SUCCESS.getDescription();
        apiResultModel.data = userInfoList;
        return apiResultModel;
    }

    /**
     * 获取用户信息
     */
    @RequestMapping(value = "/{id}", method = RequestMethod.GET)
    public ApiResultModel getUserInfo(@PathVariable("id")int userId)
    {
        //根据用户ID,获取用户信息
        UserInfo userInfo = userDao.findById(userId).orElse(null);

        //返回结果
        ApiResultModel apiResultModel = new ApiResultModel();
        apiResultModel.statusCode = ApiStatusCode.SUCCESS.getCode();
        apiResultModel.message = ApiStatusCode.SUCCESS.getDescription();
        apiResultModel.data = userInfo;
        return apiResultModel;
    }

    /**
     * 新增用户信息
     */
    @RequestMapping(value = "/", method = RequestMethod.POST)
    public ApiResultModel addUser(@RequestBody UserInfo userInfo)
    {
        //参数验证
        if(userInfo.getUserName()==null || userInfo.getUserName().length()==0)
        {
            //返回参数缺失
            ApiResultModel apiResultModel = new ApiResultModel();
            apiResultModel.statusCode = ApiStatusCode.PARAM_INVALID.getCode();
            apiResultModel.message = ApiStatusCode.PARAM_INVALID.getDescription();
            apiResultModel.data = false;
            return apiResultModel;
        }

        //新增用户信息
        userDao.save(userInfo);

        //返回结果
        ApiResultModel apiResultModel = new ApiResultModel();
        apiResultModel.statusCode = ApiStatusCode.SUCCESS.getCode();
        apiResultModel.message = ApiStatusCode.SUCCESS.getDescription();
        apiResultModel.data = true;
        return apiResultModel;
    }

    /**
     * 修改用户信息
     */
    @RequestMapping(value = "/", method = RequestMethod.PUT)
    public ApiResultModel updateUser(@RequestBody UserInfo userInfo)
    {
        //参数验证
        if(userInfo.getUserId()<=0 || userInfo.getUserName()==null || userInfo.getUserName().length()==0)
        {
            //返回参数缺失
            ApiResultModel apiResultModel = new ApiResultModel();
            apiResultModel.statusCode = ApiStatusCode.PARAM_INVALID.getCode();
            apiResultModel.message = ApiStatusCode.PARAM_INVALID.getDescription();
            apiResultModel.data = false;
            return apiResultModel;
        }

        //修改用户信息
        userDao.save(userInfo);

        //返回结果
        ApiResultModel apiResultModel = new ApiResultModel();
        apiResultModel.statusCode = ApiStatusCode.SUCCESS.getCode();
        apiResultModel.message = ApiStatusCode.SUCCESS.getDescription();
        apiResultModel.data = true;
        return apiResultModel;
    }

    /**
     * 删除用户信息
     */
    @RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
    public ApiResultModel deleteUserInfo(@PathVariable("id")int userId)
    {
        //删除用户信息
        userDao.deleteById(userId);

        //返回结果
        ApiResultModel apiResultModel = new ApiResultModel();
        apiResultModel.statusCode = ApiStatusCode.SUCCESS.getCode();
        apiResultModel.message = ApiStatusCode.SUCCESS.getDescription();
        apiResultModel.data = true;
        return apiResultModel;
    }
}

 

4、全局异常处理

Spring提供了非常方便的异常处理方案——控制器通知 (@ControllerAdvice 或 @RestControllerAdvice),它将所有控制器作为一 个切面,利用切面技术来实现。

通过基于@ControllerAdvice或@RestContollerAdvice的注解可以对异常进行全局统一处理,默认对所有的Controller有效。

这里由于是RESTful接口架构应用,所以使用@RestContollerAdvice注解来统一处理异常。

4.1 创建异常结果类

创建ExceptionResult类(异常结果类)。

/**
 * 异常结果类
 * @author pan_junbiao
 **/
public class ExceptionResult
{
    public int statusCode; //状态码
    public String message; //返回消息描述

    public int getStatusCode()
    {
        return statusCode;
    }

    public void setStatusCode(int statusCode)
    {
        this.statusCode = statusCode;
    }

    public String getMessage()
    {
        return message;
    }

    public void setMessage(String message)
    {
        this.message = message;
    }
}

4.2 自定义业务异常类

创建BusinessException类(业务异常类),继承RuntimeException类。

/**
 * 业务异常类
 * @author pan_junbiao
 **/
public class BusinessException extends RuntimeException
{
    private String errorMessage; //异常信息

    public BusinessException(String errorMessage)
    {
        super(errorMessage);
        this.errorMessage = errorMessage;
    }

    public String getErrorMessage()
    {
        return errorMessage;
    }

    public void setErrorMessage(String errorMessage)
    {
        this.errorMessage = errorMessage;
    }
}

4.3 创建全局异常处理器

创建BusinessExceptionHandler类(全局异常处理器)。

import com.pjb.model.ApiStatusCode;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

/**
 * 全局异常处理器
 * @author pan_junbiao
 **/
@RestControllerAdvice
public class BusinessExceptionHandler
{
    //日志对象
    private Logger logger = LogManager.getLogger(BusinessExceptionHandler.class);

    /**
     * 自定义业务异常处理
     */
    @ExceptionHandler(BusinessException.class)
    public ExceptionResult businessExceptionHandler(BusinessException ex)
    {
        //错误信息
        String errorMessage = ex.getErrorMessage();

        //记录异常日志
        logger.error("[业务异常]" + errorMessage);

        //返回错误信息
        ExceptionResult exceptionResult = new ExceptionResult();
        exceptionResult.statusCode = ApiStatusCode.BUSINESS_EXCEPTION.getCode();
        exceptionResult.message = errorMessage;
        return exceptionResult;
    }

    /**
     * 系统异常
     */
    @ExceptionHandler(Exception.class)
    public ExceptionResult exceptionHandler(Exception ex)
    {
        //记录异常日志
        logger.error("[系统异常]" + ex.toString());

        //返回错误信息
        ExceptionResult exceptionResult = new ExceptionResult();
        exceptionResult.statusCode = ApiStatusCode.SYSTEM_EXCEPTION.getCode();
        exceptionResult.message = "系统错误,请联系管理员";
        return exceptionResult;
    }
}

【示例】测试全局异常功能。

/**
 * 自定义异常测试
 * @author pan_junbiao
 */
@RequestMapping("/exceptionTest")
public void exceptionTest()
{
    throw new BusinessException("自定义异常信息");
}

执行结果:

 

5、运行测试

5.1 使用ajax请求

使用JQuery提供的Ajax功能请求。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>用户操作</title>
    <meta name="author" content="pan_junbiao的博客">
    <style>
        table { border-collapse: collapse; margin-bottom: 10px}
        table,table tr th, table tr td { border:1px solid #000000; padding: 5px 10px;}
    </style>
</head>
<body>
<div align="center">
    <table>
        <caption>用户信息</caption>
        <tr>
            <th>用户ID:</th>
            <td id="td_userId"></td>
        </tr>
        <tr>
            <th>用户名称:</th>
            <td id="td_userName"></td>
        </tr>
        <tr>
            <th>博客地址:</th>
            <td id="td_blogUrl"></td>
        </tr>
        <tr>
            <th>博客信息:</th>
            <td id="td_blogRemark"></td>
        </tr>
    </table>
    <input type="button" id="btnGetUser" value="获取用户"/>
    <input type="button" id="btnAddUser" value="新增用户"/>
    <input type="button" id="btnUpdateUser" value="修改用户"/>
    <input type="button" id="btnDeleteUser" value="删除用户"/>
</div>
</body>
<script src="/js/jquery-3.4.1.min.js"></script>
<script>
    //获取用户
    $("#btnGetUser").click(function ()
    {
        //执行Ajax请求
        $.ajax({
            type: "GET",
            url: "http://127.0.0.1:8080/user/1",
            contentType: "application/json; charset=UTF-8",
            success: function (result)
            {
                if(result.statusCode == 2000 && result.data)
                {
                    //绑定数据
                    $("#td_userId").html(result.data.userId);
                    $("#td_userName").html(result.data.userName);
                    $("#td_blogUrl").html(result.data.blogUrl);
                    $("#td_blogRemark").html(result.data.blogRemark);
                }
            }
        });
    });

    //新增用户
    $("#btnAddUser").click(function ()
    {
        //请求参数对象
        var params = {};
        params.userName = "pan_junbiao的博客";
        params.blogUrl = "https://blog.csdn.net/pan_junbiao";
        params.blogRemark = "您好,欢迎访问 pan_junbiao的博客";

        //执行Ajax请求
        $.ajax({
            type: "POST",
            url: "http://127.0.0.1:8080/user/",
            dataType: "json",
            contentType: "application/json; charset=UTF-8",
            data: JSON.stringify(params),
            success: function (result)
            {
                if(result.statusCode == 2000 && result.data == true)
                {
                    alert("新增用户成功")
                }
                else
                {
                    alert("操作失败:" + result.message);
                }
            }
        });
    });

    //修改用户
    $("#btnUpdateUser").click(function ()
    {
        //请求参数对象
        var params = {};
        params.userId = 3;
        params.userName = "pan_junbiao的博客_03";
        params.blogUrl = "https://blog.csdn.net/pan_junbiao";
        params.blogRemark = "您好,欢迎访问 pan_junbiao的博客";

        //执行Ajax请求
        $.ajax({
            type: "PUT",
            url: "http://127.0.0.1:8080/user/",
            dataType: "json",
            contentType: "application/json; charset=UTF-8",
            data: JSON.stringify(params),
            success: function (result)
            {
                if(result.statusCode == 2000 && result.data == true)
                {
                    alert("修改用户成功")
                }
                else
                {
                    alert("操作失败:" + result.message);
                }
            }
        });
    });

    //删除用户
    $("#btnDeleteUser").click(function ()
    {
        //执行Ajax请求
        $.ajax({
            type: "DELETE",
            url: "http://127.0.0.1:8080/user/3",
            contentType: "application/json; charset=UTF-8",
            success: function (result)
            {
                if(result.statusCode == 2000 && result.data == true)
                {
                    alert("删除用户成功")
                }
                else
                {
                    alert("操作失败:" + result.message);
                }
            }
        });
    });
</script>
</html>

执行结果:

5.2 使用Postman工具

第二种测试方法,使用Postman工具进行测试。

(1)使用GET方法发送请求获取用户信息,执行结果如下:

(2)使用POST方法发送请求新增用户信息,执行结果如下:

 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

pan_junbiao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值