从0到1开发一个接口

最近在学习黑马的项目时,突然让手写一个接口,原本以为是个简单的任务,结果发现动手实践起来还是有一些容易忽略的点,本文将从接口设计开始简述开发接口的一般步骤。

接口设计

进入前后端分离式开发时代后,一般是由后端开发人员设计接口并将接口文档提供给前端人员。

不管是什么类型的接口,都是通过HTTP请求来完成由前端发起调用,后端执行程序得到结果返回前端这一过程来实现的。

一个规范的接口应该包含以下内容:

  • HTTP请求方法
  • 接口路径
  • 请求参数类型
  • 请求参数内容
  • 响应结果类型
  • 响应结果状态码
  • 响应结果内容

HTTP请求方法

根据RESTful规范:

  • 新增方法用POST
  • 修改方法用PUT
  • 删除方法用DELETE

接口路径

定义为RESTful风格的路径。

  • 在类上使用@RequestMapping指定该类中接口的路径的基础路径。
  • 在方法中指定具体的路径。

比如:

image-20240624203033675

请求参数类型

常用的有:

  • json格式:
    • application/json,传递json格式字符串,当传递的参数是属于一个对象的属性时可用此格式,比如:新增、修改时通常传递的数据是某个对象的信息就可以使用此格式。
  • 表单格式:
    • application/x-www-form-urlencoded,传递key/value串,就是在url后通过?和&进行拼接的参数,比如:/foundations/operation/serve/page?pageNo=1&pageSize=10
    • 当传递的参数比较杂且不属于某个特定的对象时使用此格式

请求参数内容

请求参数的内容应当根据需求文档和界面原型去识别。 分页式查询首先有当前页码和每页显示记录数。 对于查询类的接口还有常用的参数有:排序方式、排序字段。

响应结果类型

常见的类型有:text/html、text/plain、application/json等。

响应结果状态码

HTTP状态码是服务器返回给客户端的数字代码(三位数字),共分为五类:

  • 1xx: 表示服务器接收到了客户端请求并正在处理
  • 2xx: 表示成功状态码
  • 3xx:表示重向定状态码
  • 4xx:表示客户端错误状态码
  • 5xx: 表示服务端错误状态码

当服务端处理成功返回200,其它表示失败。

响应结果内容

分页查询通用的响应内容有:数据列表、总页数、总记录数

数据列表中需要分析具体的属性,根据界面原型进行分析

对于分页查询结果,我们通常将其封装为统一式响应:

参数名称参数说明类型
msg响应消息string
code状态码,200-成功,其它-失败integer(int32)
data分页数据消息体
total总条数integer(int64)
pages总页数integer(int64)

以下是一个常见的响应示例:

{
        "msg": "OK",
        "code": 200,
        "data": {
                "list": [
                        {
                                "serveTypeId": 0,
                                "serveItemName": "",
                                "updateTime": "",
                                "saleStatus": 0,
                                "serveItemId": 0,
                                "referencePrice": 0,
                                "createTime": "",
                                "regionId": 0,
                                "price": 0,
                                "id": 0,
                                "isHot": 0,
                                "serveTypeName": ""
                        }
                ],
                "total": 0,
                "pages": 0
        }
}

实例

页面原型: image-20240624204034036

接口文档: image-20240624204150264

image-20240624204214997

根据上面的说明,不难分析出:

  1. 这是个GET请求
  2. 接口路径是:/foundations/operation/region/page
  3. 请求参数类型是:application/x-www-form-urlencoded,即为表单类型:image-20240624204420495
  4. 请求参数内容:一般封装为实体:image-20240624204514553
  5. 响应结果内容:image-20240624204613614

接口定义

完成了接口设计之后,就要开始着手书写接口了。

经过第一小节的分析,我们不难写出如下接口:

@RestController("operationServeController")
@RequestMapping("/operation/serve")
@Api(tags = "运营端 - 区域服务相关接口")
public class ServeController {
    @Resource
    private IServeService serveService;

    @GetMapping("/page")
    @ApiOperation("区域服务分页查询")
    public PageResult<ServeResDTO> page(ServePageQueryReqDTO servePageQueryReqDTO) {
        PageResult<ServeResDTO> page = serveService.page(servePageQueryReqDTO);
        return page;
    }
    ...
}   

注意:当请求参数格式为json需要在方法参数前加@RequestBody注解,这里请求参数类型为from表单格式不用添加此注解。

接下来,使用swagger来初步测试接口功能: image-20240624205047139

image-20240624205250368

在MVC架构当中,一般会先从Mapper层,即持久层开始开发。

Mapper层开发

Mapper是Spring提供给我们操作数据库的利器,使用Mapper分为两种情况:

  • 涉及到多表查询,需要自定义SQL
  • 仅涉及到单表简单查询

先安装MyBatisPlus插件,并设置对应数据库。

随后设置代码生成规则: image-20240624205830364

  • 选择表:上图选择serve_type表。


  • 设置生成代码的根目录:上图设置generator


  • 设置包路径:上图设置为com.jzo2o.foundations


  • 主键生成策略:根据表中主键的生成策略进行选择,支持的主键生成策略如下图:image-20240624205909531


  • 勾选要生成的类及包路径(Entity、Mapper、Controller、Service、ServiceImpl)。


  • 勾选是否生成lombok注解、restController注解、swagger注解等。


由于MBP提供的查询是仅支持单表的,所以需要使用多表查询的情况需要自定义Mapper内容。

先定义Mapper接口: image-20240624210138122

点击左下角图标即可跳转到对应Mapper文件:

image-20240624210304641

Mapper构建完成之后,即可进行单元测试: image-20240624210418518

Test类通常生成在对应的Test包下: image-20240624210502393

@SpringBootTest
@Slf4j
class ServeMapperTest {
    @Resource
    private ServeMapper serveMapper;

    @Test
    void test_queryServeListByRegionId() {
        List<ServeResDTO> serveResDTOS = serveMapper.queryServeListByRegionId(1686303222843662337L);
        Assert.notEmpty(serveResDTOS,"列表为空");
    }

}

利用断点调试测试Mapper。

Service层

service接口是提供controller调用,service接口的参数由controller传入通常controller方法将它的形参直接传入service方法,对于通用的service方法则需要定义更通用的参数,service方法的返回值类型通常可以直接定义为controller方法的返回值类型。

比如:

public interface IServeService extends IService<Serve> {

    /**
     * 分页查询服务列表
     * @param servePageQueryReqDTO 查询条件
     * @return 分页结果
     */
    PageResult<ServeResDTO> page(ServePageQueryReqDTO servePageQueryReqDTO);
}

定义实现类:

这里我们使用的Mybatis-Plus提供的ServiceImpl类,如下代码,在此类中有baseMapper,baseMapper即是ServeMapper实例

@Service
public class ServeServiceImpl extends ServiceImpl<ServeMapper, Serve> implements IServeService {

    /**
     * 分页查询
     *
     * @param servePageQueryReqDTO 查询条件
     * @return 分页结果
     */
    @Override
    public PageResult<ServeResDTO> page(ServePageQueryReqDTO servePageQueryReqDTO) {
        //通过baseMapper调用queryServeListByRegionId方法
        
    }

}

这里有一些关于分页插件的问题需要注意,在用于举例的项目中存在两种分页方法:

  1. 使用的是mybatis-plus自带分页方法,通过selectPage方法实现分页


    public PageResult<ServeTypeResDTO> page(ServeTypePageQueryReqDTO serveTypePageQueryReqDTO) {
    Page<ServeType> page = PageUtils.parsePageQuery(serveTypePageQueryReqDTO, ServeType.class);
    Page<ServeType> serveTypePage = baseMapper.selectPage(page, new QueryWrapper<>());
    return PageUtils.toPage(serveTypePage, ServeTypeResDTO.class);
    }

  2. 使用com.github.pagehelper分页组件


    public PageResult<ServeItemResDTO> page(ServeItemPageQueryReqDTO serveItemPageQueryReqDTO) {
    return PageHelperUtils.selectPage(serveItemPageQueryReqDTO,
    () -> baseMapper.queryList(serveItemPageQueryReqDTO.getServeTypeId(), serveItemPageQueryReqDTO.getName(), serveItemPageQueryReqDTO.getActiveStatus()));
    }

第一种:mybatis-plus自带的分页方法,通过调用selectPage方法实现分页,适用于通过QueryWrapper拼装SQL。 第二种:pagehelper分页组件适用于自定义sql的分页查询。

使用com.github.pagehelper分页插件实现分页功能,下边是它的执行原理:

PageHelperUtils是一个工具类,进入selectPage方法,调用PageHelper.startPage方法设置分页参数,通过一层一层进入源码,最终将分页参数设置到ThreadLocalLOCAL_PAGE=newThreadLocal(); 中。

image-20240624211137396

通过PageInterceptor拦截器拦截 MyBatis的Executor 的 query() 方法得到原始的sql语句,首先得到count总数,然后从newThreadLocal中取出分页参数,在原始sql语句中添加分页参数查询分页数据。

image-20240624211310793
image-20240624211331621
image-20240624211340673

Controller层

在Controller层调用Service提供的方法即可。

前后端联调

经过前面的步骤,一个接口已经完成了99%,接下来的联调决定了接口是否设计成功。

作为后端开发人员,应该使用浏览器提供的开发者工具来跟踪请求,从请求路径分析道响应结果:

image-20240624211644400

至此,一个接口就开发完成了。

此作者没有提供个人介绍
最后更新于 2024-08-14