目录
1 复习下业务流程
区域服务管理是为运营地区设置要运营的服务项,不同地区所运营的服务项可能不同,比如:本平台在北京运营了老人陪护服务,而在郑州没有运营老人陪护服务。
- 进入区域列表 点击“设置服务”
- 进入设置服务页面 这个页面应该展示了该区域当前正在运营及停止未运营的服务信息。
- 添加服务 进入添加服务界面,选择要添加的服务,点击“添加”
- 设置区域价格 区域价格即该服务在该区域的运营价格,输入修改后的价格。
- 上架 服务上架后用户可以在首页的服务列表点击该服务进行下单购买。
ps:当区域服务的状态为草稿状态或下架状态时方可上架。 - 下架 服务下架后用户将不能对该服务下单。
ps:当区域服务的状态为上架状态方可下架。 - 删除 当状态为草稿状态方可删除。
- 设置热门/取消热门 服务设置为热门将在首页显示
2 接口设计
2.1 查询区域服务
2.1.1 接口梳理
通过上述分析在区域服务模块包括以下接口:
- 区域服务分页查询接口
- 区域服务新增接口
- 区域服务删除接口
- 区域服务价格修改接口
- 区域服务设置热门接口
- 区域服务取消热门接口
- 区域服务上架接口
- 区域服务下架接口
2.1.2 接口设计
首先明确该接口是一个前后端交互接口,该接口由前端通过HTTP协议进行调用,前端去调用接口需要知道以下内容:
- HTTP请求方法
- 接口路径
- 请求参数类型
- 请求参数内容
- 响应结果类型
- 响应结果状态码
- 响应结果内容
所以我们设计接口需要设计这些内容。
-
HTTP请求方法
根据RESTful规范:
查询方法用Get,请求参数比较多可用POST
新增方法用POST
修改方法用PUT
删除方法用DELETE
本接口是一个分页查询接口,查询条件我们用GET。 -
接口路径
定义为RESTful风格的路径。
接口路径为:/foundations/operation/serve/page
可以在类上边使用@RequestMapping指定该类中接口的路径的基础路径。
在方法中指定具体的路径。 -
请求参数类型
常用的有:
json格式:application/json,传递json格式字符串,当传递的参数是属于一个对象的属性时可用此格式,比如:新增、修改时通常传递的数据是某个对象的信息就可以使用此格式。
表单格式:application/x-www-form-urlencoded,传递key/value串,就是在url后通过?和&进行拼接的参数,比如:/foundations/operation/serve/page?pageNo=1&pageSize=10
当传递的参数比较杂且不属于某个特定的对象时使用此格式,本接口使用application/x-www-form-urlencoded格式。 -
请求参数内容
请求参数的内容根据需求文档和界面原型去识别。
分页式查询首先有当前页码和每页显示记录数。
对于查询类的接口还有常用的参数有:排序方式、排序字段。
再根据需求的梳理,查询某个区域下的服务需要传递一个区域id。
请求参数如下
参数名称 | 参数说明 | 是否必须 |
---|---|---|
regionId | 区域ID | TRUE |
isASC1 | 排序字段1是否升序 | FALSE |
isASC2 | 排序字段2是否升序 | FALSE |
orderBy1 | 排序字段1 | FALSE |
orderBy2 | 排序字段2 | FALSE |
pageNo | 页码数 | FALSE |
pageSize | 每页条数 | FALSE |
-
响应结果类型
常见的类型有:text/html、text/plain、application/json等。
本项目统一使用application/json -
响应结果状态码规定
HTTP状态码是服务器返回给客户端的数字代码(三位数字),共分为五类:
1xx: 表示服务器接收到了客户端请求并正在处理
2xx: 表示成功状态码
3xx:表示重向定状态码
4xx:表示客户端错误状态码
5xx: 表示服务端错误状态码
当服务端处理成功返回200,其它表示失败。 -
响应结果内容
分页查询通用的响应内容有:数据列表、总页数、总记录数
数据列表中需要分析具体的属性,根据界面原型进行分析:
参数名称 | 参数说明 |
---|---|
severTpeId | 服务类型id |
serveItemName | 服务项名称 |
updateTime | 更新时间 |
saleStatus | 售卖状态 :0草稿,1下架,2上架 |
serveItemId | 服务项id |
referencePrice | 参考价格 |
createTime | 创建时间 |
regionId | 区域id |
price | 价格 |
id | 主键 |
isHot | 是否为热门 |
serveTypeName | 服务类型名称 |
制定分页查询通用的响应内容如下:
msg、code、 data、total、pages是固定的。
data中List数据的内容对于不同的分页查询会不一样。
响应案例:
{
"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
}
}
2.1.3 接口定义
2.1.3.1 controller开发
/**
*
* 区域服务管理相关接口
*/
@RestController("operationServeController")
@RequestMapping("/operation/serve")
@Api(tags = "运营端区域服务管理相关接口")
public class SeverController {
@GetMapping("/page")
@ApiOperation("区域服务分页查询")
public List<ServeResDTO> page(ServePageQueryReqDTO servePageQueryReqDTO){
return null;
}
}
2.1.3.2 查看接口文档
测试一下,打个断点debug下
没问题了,在公司业务里,这个接口就可以交给前端进行开发了
2.1.3.1 Mapper开发
因为不是单表查询,不能直接用MP,因此需要手写SQL语句
select st.id serveTypeId,
st.name serveTypeName,
si.id serveItemId,
si.name serveItemName,
serve.update_time,
serve.sale_status,
si.reference_price,
serve.region_id,
serve.id,
serve.price,
serve.is_hot
from serve
inner join serve_item si on serve.serve_item_id = si.id
inner join serve_type st on si.serve_type_id = st.id
where region_id = ?
接着定义接口
public interface ServeMapper extends BaseMapper<Serve> {
public List<ServeResDTO> queryServeListByRegionId(@Param("regionId") Long regionId);
}
接着定义xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.jzo2o.foundations.mapper.ServeMapper">
<select id="queryServeListByRegionId" resultType="com.jzo2o.foundations.model.dto.response.ServeResDTO">
select st.id serveTypeId,
st.name serveTypeName,
si.id serveItemId,
si.name serveItemName,
serve.update_time,
serve.sale_status,
si.reference_price,
serve.region_id,
serve.id,
serve.price,
serve.is_hot
from serve
inner join serve_item si on serve.serve_item_id = si.id
inner join serve_type st on si.serve_type_id = st.id
where region_id = #{regionId}
</select>
</mapper>
最后单元测试下:
@SpringBootTest
@Slf4j
public class ServerMapperTest {
@Autowired
private ServeMapper serveMapper;
@Test
public void test_queryServeListByRegionId(){
List<ServeResDTO> serveResDTOS = serveMapper.queryServeListByRegionId(1686303222843662337L);
Assert.notEmpty(serveResDTOS,"查询结果为空");
}
}
测试通过:
2.1.3.2 Service层开发
先定义个接口吧:
public interface IServeService extends IService<Serve> {
/**
* 区域服务分页查询
* @param servePageQueryReqDTO
* @return
*/
PageResult<ServeResDTO> page(ServePageQueryReqDTO servePageQueryReqDTO);
}
那接下来实现这个接口
插一嘴,需要进行分页,那么目前分页方法有哪些呢?
MP的?肯定不行,因为我们要用我们写的SQL
那就需要别的分页方法了,这里我们使用pagehelper分页组件
@Service
public class ServeServiceImpl extends ServiceImpl<ServeMapper, Serve> implements IServeService {
/**
* 区域服务分页查询
* @param servePageQueryReqDTO
* @return
*/
@Override
public PageResult<ServeResDTO> page(ServePageQueryReqDTO servePageQueryReqDTO){
return PageHelperUtils.selectPage(servePageQueryReqDTO,
() -> baseMapper.queryServeListByRegionId(servePageQueryReqDTO.getRegionId()));
}
}
最后来单元测试下:
@Autowired
private IServeService iServeService;
@Test
public void test_page(){
ServePageQueryReqDTO servePageQueryReqDTO = new ServePageQueryReqDTO();
servePageQueryReqDTO.setRegionId(1686303222843662337L);
servePageQueryReqDTO.setPageNo(1L);
servePageQueryReqDTO.setPageSize(2L);
PageResult<ServeResDTO> page = iServeService.page(servePageQueryReqDTO);
Assert.notNull(page,"没数据");
}
2.1.3.3 分页方法底层
PageHelperUtils是项目封装的一个工具类,进入selectPage方法,调用PageHelper.startPage方法设置分页参数,通过一层一层进入源码,发现他是将分页参数设置到ThreadLocal
通过PageInterceptor拦截器拦截 MyBatis的Executor 的 query() 方法得到原始的sql语句,首先得到count总数,然后从newThreadLocal中取出分页参数,在原始sql语句中添加分页参数查询分页数据。
2.1.4 查询服务功能测试
- 接口测试
- 前后端联调
2.2 添加区域服务
2.2.1 回顾需求与接口分析
首先进入某个区域的服务列表:
点击添加服务。选择服务并且添加:
最终向serve表添加数据,表结构如下:
create table serve
(
id bigint not null comment '服务id'
primary key,
serve_item_id bigint not null comment '服务项id',
region_id bigint not null comment '区域id',
city_code varchar(255) not null comment '城市编码',
sale_status int default 0 not null comment '售卖状态,0:草稿,1下架,2上架',
price decimal(10, 2) not null comment '价格',
is_hot int default 0 not null comment '是否为热门,0非热门,1热门',
hot_time_stamp bigint null comment '更新为热门的时间戳',
create_time datetime default CURRENT_TIMESTAMP not null comment '创建时间',
update_time datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间',
create_by bigint null comment '创建者',
update_by bigint null comment '更新者'
)
那么,这些字段是需要我们全部传入还是自动生成呢?分析一下:
字段 | 来源 |
---|---|
服务id | 主键,雪花算法自动生成 |
服务项id | 接口传入/前端传入 |
区域id | 接口传入/前端传入 |
城市编码 | 根据区域id查region获得 |
售卖状态 | 数据库默认设置为草稿 |
价格 | 默认设置为服务项价格,用户可以修改 |
是否热门 | 默认设置为非热门 |
更新为热门的时间戳 | 默认为null |
创建/更新时间 | 数据库默认设置 |
创建人/更新人 | 拦截器自动处理 |
根据上边的分析,通过接口传入服务项id、区域id、价格,支持多个服务传入,实现批量添加。
传入参数内容为数组,所以使用json格式。
传入参数内容包括:服务项id、区域id、价格。
响应结果内容可为空,前端根据状态码判断是否添加成功。
接口设计信息:
接口路径:POST/foundations/operation/serve/batch
请求数据类型 application/json
2.2.2 接口定义
2.2.2.1 Mapper开发
添加接口只向serve表添加数据所以使用mybatisplus提供的单表CRUD方法即可无需自定义mapper接口
2.2.2.2 Service层开发
首先,对于增删改操作,一定要先做校验,对当前需求来说,需要校验服务项是:
- 否是开启状态,只有服务项开启才可以添加相应的区域服务项
- 校验区域服务项是否以及存在
@Autowired
private ServeItemMapper serveItemMapper;
@Autowired
private IServeService iServeService;
@Autowired
private RegionMapper regionMapper;
@Override
public void batchAdd(List<ServeUpsertReqDTO> serveUpsertReqDTOS) {
//遍历传入的List
for(ServeUpsertReqDTO serveUpsertReqDTO:serveUpsertReqDTOS){
//校验 服务项是否开启
Long serveItemId = serveUpsertReqDTO.getServeItemId();
ServeItem serveItem = serveItemMapper.selectById(serveItemId);
if(ObjectUtils.isNull(serveItem) || serveItem.getActiveStatus() != FoundationStatusEnum.ENABLE.getStatus()){
throw new ForbiddenOperationException("服务项不存在或未启用不允许添加");
}
//校验服务项是否已经存在
LambdaQueryWrapper<Serve> lambdaQuery = Wrappers.lambdaQuery(Serve.class);
lambdaQuery.eq(Serve::getServeItemId,serveUpsertReqDTO.getServeItemId())
.eq(Serve::getRegionId,serveUpsertReqDTO.getRegionId());
int count = iServeService.count(lambdaQuery);
if(count > 0){
throw new ForbiddenOperationException("服务项已存在");
}
//插入数据
Serve serve = BeanUtils.toBean(serveUpsertReqDTO, Serve.class);
Long regionId = serve.getRegionId();
Region region = regionMapper.selectById(regionId);
String cityCode = region.getCityCode();
serve.setCityCode(cityCode);
iServeService.save(serve);
}
}
2.2.2.3 Controller层开发
@PostMapping("/batch")
@ApiOperation("添加区域服务")
public void add(@RequestBody List<ServeUpsertReqDTO> serveUpsertReqDTOS){
iServeService.batchAdd(serveUpsertReqDTOS);
}
2.2.3 测验
2.3 修改价格
2.3.1 接口设计
输入价格进行修改
传入参数内容:价格、区域服务ID(serve表主键)
传入参数类型:form表单格式
响应结果内容可为空,前端根据状态码判断是否添加成功。
接口设计信息如下:
接口路径:PUT/foundations/operation/serve/{id}
请求数据类型 application/x-www-form-urlencoded
2.3.2 接口定义
2.3.2.1 Controller层
@PutMapping("/{id}")
@ApiOperation("修改区域服务价格")
@ApiImplicitParams({
@ApiImplicitParam(name = "id", value = "服务id", required = true, dataTypeClass = Long.class),
@ApiImplicitParam(name = "price", value = "价格", required = true, dataTypeClass = BigDecimal.class)
})
public void update(@PathVariable("id") Long id, @RequestParam("price") BigDecimal price){
iServeService.update(id,price);
}
2.3.2.2 Service层
@Override
public Serve update(Long id, BigDecimal price) {
LambdaUpdateWrapper<Serve> updateWrapper = Wrappers.lambdaUpdate(Serve.class);
updateWrapper.eq(Serve::getId,id)
.set(Serve::getPrice,price);
boolean res = iServeService.update(updateWrapper);
if(!res){
throw new CommonException("修改价格失败");
}else{
Serve serve = serveMapper.selectById(id);
return serve;
}
}
2.3.3 测试
刚开始:
修改价格:
测试成功
2.3.4 小结
如何设计修改接口?
修改接口最终向数据库提交数据,根据界面原型结合表结构进行设计,分析更新的数据有哪些,再分析更新数据的依据是什么,本接口是根据serve表的主键修改价格字段。
如果传入的要修改的参数比较多此时可用json格式,如果比较少可用form表单格式即可。通常添加、修改、删除接口没有特殊要求可根据状态码判断是否添加成功,有特殊要求则需要返回json数据。
2.4 服务上架
2.4.1 接口设计
在区域服务列表中点击“上架”,此服务在该区域将生效,用户即可对该服务进行下单。
业务流程如下:
在serve表有一个售卖状态sale_status,服务上架后将状态更改为“上架”,代码为2。
下边分析接口的传入参数类型、参数内容、响应结果内容。
传入参数内容:区域服务Id(serve表的主键),
传入参数类型:form表单格式
响应结果内容: 内容可为空,前端根据状态码判断是否添加成功。
接口信息如下:
接口路径:PUT/foundations/operation/serve/onSale/{id}
请求数据类型 application/x-www-form-urlencoded
2.4.2 接口定义
2.4.2.1 Controller层
2.4.2.2 Service层
还是要记得增删改操作先校验
@Override
public Serve onSale(Long id) {
//校验id有没有
Serve serve = serveMapper.selectById(id);
if(ObjectUtils.isNull(serve)){
throw new ForbiddenOperationException("区域服务信息不存在")
}
//校验serve的sale_status是0/1可以上架
Integer saleStatus = serve.getSaleStatus();
if(!(saleStatus==FoundationStatusEnum.INIT.getStatus() || saleStatus==FoundationStatusEnum.INIT.getStatus())){
throw new ForbiddenOperationException("当前区域的状态为草稿或下架才可以上架");
}
//服务项没有启用不能上架
Long serveItemId = serve.getServeItemId();
ServeItem serveItem = serveItemMapper.selectById(serveItemId);
Integer activeStatus = serveItem.getActiveStatus();
if(!(activeStatus!=FoundationStatusEnum.ENABLE.getStatus())){
throw new ForbiddenOperationException("服务项状态未启用不能上架");
}
//上架操作
LambdaUpdateWrapper<Serve> lambdaUpdate = Wrappers.lambdaUpdate(Serve.class);
lambdaUpdate.eq(Serve::getId,id)
.set(Serve::getSaleStatus,FoundationStatusEnum.ENABLE.getStatus());
boolean update = iServeService.update(lambdaUpdate);
if(!update){
throw new CommonException("区域服务上架失败");
}
return serveMapper.selectById(id);
}
}
2.4.3 测试接口
再来测个异常情况:
测试成功
2.5 删除区域服务开发
2.5.1 接口设计
2.5.2 接口开发
2.5.1 Controller开发
@DeleteMapping("/{id}")
@ApiOperation("区域服务")
@ApiImplicitParams({
@ApiImplicitParam(name = "id", value = "服务id", required = true, dataTypeClass = Long.class)
})
public void delete(@PathVariable("id") Long id){
iServeService.delete(id);
}
2.5.2 Service开发
@Override
public void delete(Long id) {
//id得存在
Serve serve = serveMapper.selectById(id);
if(ObjectUtils.isNull(serve)){
throw new ForbiddenOperationException("区域服务不存在");
}
//草稿状态才可以删除
if(serve.getSaleStatus()!=FoundationStatusEnum.INIT.getStatus()){
throw new ForbiddenOperationException("只有草稿状态才可以删除");
}
//删除
iServeService.delete(id);
}
2.5.3 接口测试
测试成功
2.6 区域服务下架
2.6.1 接口设计
2.6.2 接口开发
2.6.2.1 Controller开发
@PutMapping("offSale/{id}")
@ApiOperation("区域服务下架")
@ApiImplicitParams({
@ApiImplicitParam(name = "id", value = "服务id", required = true, dataTypeClass = Long.class),
})
public void offSale(@PathVariable("id") Long id){
iServeService.offSale(id);
}
2.6.2.2 Service开发
@Override
public Serve offSale(Long id) {
//区域服务id存在才可以下架
Serve serve = serveMapper.selectById(id);
if(ObjectUtils.isNull(serve)){
throw new ForbiddenOperationException("区域服务有不存在");
}
//区域服务上架中才可以下架
Integer saleStatus = serve.getSaleStatus();
if(saleStatus != FoundationStatusEnum.ENABLE.getStatus()){
throw new ForbiddenOperationException("上架状态的服务项目才可以下架");
}
//下架
LambdaUpdateWrapper<Serve> updateWrapper = Wrappers.lambdaUpdate(Serve.class);
updateWrapper.eq(Serve::getId,id)
.set(Serve::getSaleStatus,FoundationStatusEnum.DISABLE.getStatus());
iServeService.update(updateWrapper);
return serveMapper.selectById(id);
}
2.6.3 接口测试
测试成功
2.7 设置/取消热门开发
2.7.1 接口介绍
要求:实现更新serve表的是否热门字段。
2.7.2 接口开发
2.7.2.1 Controller开发
@PutMapping("onHot/{id}")
@ApiOperation("区域服务设置热门")
@ApiImplicitParams({
@ApiImplicitParam(name = "id", value = "服务id", required = true, dataTypeClass = Long.class)
})
public void onHot(@NotNull(message = "id不能为空") @PathVariable("id") Long id){
iServeService.changeHotStatus(id,1);
}
@PutMapping("/offHot/{id}")
@ApiOperation("区域服务取消热门")
@ApiImplicitParams({
@ApiImplicitParam(name = "id", value = "服务id", required = true, dataTypeClass = Long.class)
})
public void offHot(@NotNull(message = "id不能为空") @PathVariable("id") Long id){
iServeService.changeHotStatus(id,0);
}
2.7.2.2 Service开发
@Override
public void changeHotStatus(Long id, Integer flag) {
LambdaUpdateWrapper<Serve> updateWrapper = Wrappers.lambdaUpdate(Serve.class);
updateWrapper.eq(Serve::getId,id)
.set(Serve::getSaleStatus,flag);
iServeService.update(updateWrapper);
}
2.7.3 接口测试
设置热门
取消热门
2.8 启用区域功能
2.8.1 接口设计
参考业务流程图进行功能完善,如下图:
也就是说需要增加校验:区域下存在上架的服务方可启用。
2.8.2 接口开发
2.8.2.1 Controller开发
@PutMapping("/activate/{id}")
@ApiOperation("区域启用")
@ApiImplicitParams({
@ApiImplicitParam(name = "id", value = "区域id", required = true, dataTypeClass = Long.class),
})
public void activate(@PathVariable("id") Long id) {
regionService.active(id);
}
2.8.2.2 Service开发
@Override
public int queryServeCountByRegionIdAndSaleStatus(Long regionId, Integer saleStatus) {
LambdaQueryWrapper<Serve> lambdaQuery = Wrappers.lambdaQuery(Serve.class);
lambdaQuery.eq(Serve::getRegionId,regionId)
.eq(Serve::getSaleStatus,saleStatus);
int count = iServeService.count(lambdaQuery);
return count;
}
public void active(Long id) {
//区域信息
Region region = baseMapper.selectById(id);
//启用状态
Integer activeStatus = region.getActiveStatus();
//草稿或禁用状态方可启用
if (!(FoundationStatusEnum.INIT.getStatus() == activeStatus || FoundationStatusEnum.DISABLE.getStatus() == activeStatus)) {
throw new ForbiddenOperationException("草稿或禁用状态方可启用");
}
//如果需要启用区域,需要校验该区域下是否有上架的服务
int count = iServeService.queryServeCountByRegionIdAndSaleStatus(id, FoundationStatusEnum.ENABLE.getStatus());
if (count <= 0) {
throw new ForbiddenOperationException("区域下不存在上架的服务,不允许启用");
}
//更新启用状态
LambdaUpdateWrapper<Region> updateWrapper = Wrappers.<Region>lambdaUpdate()
.eq(Region::getId, id)
.set(Region::getActiveStatus, FoundationStatusEnum.ENABLE.getStatus());
update(updateWrapper);
}
2.8.3 接口测试
测试成功
2.9 禁用区域功能
2.9.1 接口设计
参考业务流程图进行功能完善,如下图:
增加校验:区域下不存在上架的服务方可禁用。
2.9.2 接口设计
2.9.2.1 Controller开发
@PutMapping("/deactivate/{id}")
@ApiOperation("区域禁用")
@ApiImplicitParams({
@ApiImplicitParam(name = "id", value = "区域id", required = true, dataTypeClass = Long.class),
})
public void deactivate(@PathVariable("id") Long id) {
regionService.deactivate(id);
}
2.9.2.2 Service开发
/**
* 区域禁用
*
* @param id 区域id
*/
@Override
@Caching(evict = {
@CacheEvict(value = RedisConstants.CacheName.JZ_CACHE, key = "'ACTIVE_REGIONS'", beforeInvocation = true),
@CacheEvict(value = RedisConstants.CacheName.SERVE_ICON, key = "#id", beforeInvocation = true),
@CacheEvict(value = RedisConstants.CacheName.HOT_SERVE, key = "#id", beforeInvocation = true),
@CacheEvict(value = RedisConstants.CacheName.SERVE_TYPE, key = "#id", beforeInvocation = true)
})
public void deactivate(Long id) {
//区域信息
Region region = baseMapper.selectById(id);
//启用状态
Integer activeStatus = region.getActiveStatus();
//启用状态方可禁用
if (!(FoundationStatusEnum.ENABLE.getStatus() == activeStatus)) {
throw new ForbiddenOperationException("启用状态方可禁用");
}
//1.如果禁用区域下有上架的服务则无法禁用
int count = iServeService.queryServeCountByRegionIdAndSaleStatus(id, FoundationStatusEnum.ENABLE.getStatus());
if(count > 0){
throw new ForbiddenOperationException("区域下存在上架的服务,不允许禁用");
}
//更新禁用状态
LambdaUpdateWrapper<Region> updateWrapper = Wrappers.<Region>lambdaUpdate()
.eq(Region::getId, id)
.set(Region::getActiveStatus, FoundationStatusEnum.DISABLE.getStatus());
update(updateWrapper);
}
2.9.3 接口测试
测试成功