上一篇我们利用高级模板表的简单又快速搭建一个具有搜索和数据展示能力页面,它本身也有快捷设置和分页功能,只不过因为没数据它默认隐藏了。这篇我们就来实现接口和真正的数据展示。
首先请用你的IDE工具切换到qmock-service-api代码项目。继续用之前spring接口开发讨论,创建各个层级的代码架子。
因查询的参数会很多,所以我们单独创建个请求参数实体类 /entity/requests/InterfaceSearchRequest
package cn.daqi.mock.api.entity.requests;
import lombok.Data;
@Data
public class InterfaceSearchRequest {
// 项目ID
private Integer projectId;
// 分类ID
private Integer tagId;
// 接口名称
private String title;
// 是否启用
private Integer enable;
// 接口方法
private String method;
// 接口路径(模糊匹配)
private String path;
// 接口名称
private Integer current=1;
// 请求页数
private Integer pageSize=20;
}
同时我们还需要接口详细对应实体类/entity/MockInterfaceEntity
package cn.daqi.mock.api.entity;
import lombok.Data;
@Data
public class MockInterfaceEntity extends BaseEntity{
// 接口名称
private Integer id;
// 归属分类
private Integer tagId;
// 归属项目
private Integer projectId;
// 接口名称
private String title;
// 接口方法
private String method;
// 接口路径
private String path;
// 状态 默认0启用 1关闭 2删除
private String enable;
// 接口描述
private String desc;
// 默认状态码
private Integer responseCode;
// 默认返回值
private String responseDefault;
}
定义 /service/MockInterfaceService
服务方法接口类
package cn.daqi.mock.api.service;
import cn.daqi.mock.api.commons.RespResult;
import cn.daqi.mock.api.entity.requests.InterfaceSearchRequest;
RespResult searchMockInterface(InterfaceSearchRequest reqs);
创建接口查询 /controller/InterfaceController
,请求方法为POST
@RestController
@RequestMapping("/api/mock")
public class InterfaceController {
@Autowired
MockInterfaceService mockInterfaceService;
@PostMapping(value = "/interface/list")
public RespResult getInterfaceList(@RequestBody InterfaceSearchRequest reqs) {
return mockInterfaceService.searchMockInterface(reqs);
}
}
按照上边步骤来搞,虽然有点繁琐,但能保证清晰的思路。最后服务这块还差mapper的实现,之前的项目管理比较简单,所以我们是直接在方法上使用了注解的形式搞定的,而本篇接口查询条件比较多,所以我们换Mbybatis mapper xml来实现复杂的数据库查询需求,既学习下XML映射知识点。
XML映射简介
Mybatis 的 Mapper XML 映射文件是 MyBatis 核心配置文件之一,用于定义数据库操作的 SQL 语句以及如何将 SQL 查询结果映射为 Java 对象
Mapper XML 文件 的根节点是 <mapper>
元素,它包含以下属性:
Mapper XML 文件 中可以包含以下子元素:
基础示例
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.apache.org//DTD Mapper 3.0//EN"
"http://mybatis.apache.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.dao.UserDao">
<select id="selectUserById" resultType="com.example.model.User">
SELECT * FROM users WHERE id = #{id}
</select>
<insert id="insertUser">
INSERT INTO users (name, email) VALUES (#{name}, #{email})
</insert>
</mapper>
更全面的知识参考官方 https://mybatis.org/mybatis-3/sqlmap-xml.html 在本实战项目也会陆续应用到。
在 /mapper/MockInterfaceMapper
实现一个接口类,接受请求参数request类,并返回接口对象列表。注意这里仅仅声明接口类型方法即可,无需再用其他注解实现查询操作。
package cn.daqi.mock.api.mapper;
import cn.daqi.mock.api.entity.MockInterfaceEntity;
import cn.daqi.mock.api.entity.requests.InterfaceSearchRequest;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface MockInterfaceMapper {
List<MockInterfaceEntity> selectMockInterface(InterfaceSearchRequest reqs);
}
映射重点在resources先创建一个mppper文件夹用于路径匹配,这里你要检查项目初始化时候是否在application.yml最有对应配置,如果没有参照下边做对应配置。
mybatis:
mapper-locations: classpath:mapper/*.xml # 指定mapper xml 所在位置
如果已有请继续,需要创建一个与MockInterfaceMapper.java 同名的 MockInterfaceMapper.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="">
</mapper>
继续补充namespace完成接口类映射
<mapper namespace="cn.daqi.mock.api.mapper.MockInterfaceMapper">
参考之前注解查询操作,同样需要创建resultMap内标签,来作为实体类和数据字段的映射。
<mapper namespace="cn.daqi.mock.api.mapper.MockInterfaceMapper">
<resultMap type="cn.daqi.mock.api.entity.MockInterfaceEntity" id="InterfaceResponseMap">
<result property="id" column="api_id" jdbcType="INTEGER"/>
<result property="tagId" column="api_tag_id" jdbcType="INTEGER"/>
<result property="projectId" column="api_project_id" jdbcType="INTEGER"/>
<result property="title" column="api_title" jdbcType="VARCHAR"/>
<result property="method" column="api_method" jdbcType="VARCHAR"/>
<result property="path" column="api_path" jdbcType="VARCHAR"/>
<result property="enable" column="api_enable" jdbcType="INTEGER"/>
<result property="desc" column="api_desc" jdbcType="VARCHAR"/>
<result property="responseCode" column="responseCode" jdbcType="INTEGER"/>
<result property="responseDefault" column="responseDefault" jdbcType="VARCHAR"/>
<result property="createUser" column="create_user" jdbcType="VARCHAR"/>
<result property="createDate" column="create_date" jdbcType="TIMESTAMP"/>
<result property="updateUser" column="update_user" jdbcType="VARCHAR"/>
<result property="updateDate" column="update_date" jdbcType="TIMESTAMP"/>
</resultMap>
</mapper>
有了结果返回映射,接着来创建查询标签
#{}
为属性赋值语法<select id="selectMockInterface" resultMap="InterfaceResponseMap" parameterType="cn.daqi.mock.api.entity.requests.InterfaceSearchRequest">
select * from mock_api
<where>
api_project_id=#{projectId} and api_enable != 2
<if test="tagId != null and tagId != ''">
and api_tag_id = #{tagId}
</if>
<if test="title != null and title != ''">
and api_title like CONCAT('%',#{title},'%')
</if>
<if test="method != null and method != ''">
and api_method = #{method}
</if>
<if test="path != null and path != ''">
and api_path = #{path}
</if>
<if test="enable != null and enable != ''">
and api_enable = #{enable}
</if>
</where>
</select>
这里有个题标模糊查询用的是CONCAT关键词实现的,关注这个xml模糊查询用法还有其他方式,将在下篇扩展知识点给出一些讲解。这里继续实现本篇实战内容,最终我们来到接口查询的实现类,实现数据查询调用,并再次用上PageHelper做数据分页处理。
类 /service/impl/MockInterfaceServiceImpl
代码实现
package cn.daqi.mock.api.service.impl;
import cn.daqi.mock.api.commons.RespResult;
import cn.daqi.mock.api.entity.requests.InterfaceSearchRequest;
import cn.daqi.mock.api.mapper.MockInterfaceMapper;
import cn.daqi.mock.api.service.MockInterfaceService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service
public class MockInterfaceServiceImpl implements MockInterfaceService {
@Resource
MockInterfaceMapper mockInterfaceMapper;
@Override
public RespResult searchMockInterface(InterfaceSearchRequest reqs) {
PageHelper.startPage(reqs.getCurrent(), reqs.getPageSize());
PageInfo pageData = new PageInfo(mockInterfaceMapper.selectMockInterface(reqs));
return RespResult.success(pageData);
}
}
启动后端springboot服务,测试下接口请求
Img
查询接口列表必须的一个参数就是关联的项目ID,然而上一篇我们实现的时候只是实现了空跳,这里需要利用umi的做一个代参转跳优化,即跳转页面的时候通过URI带键值过去,在接口查询页面通过useSearchParams
获取。
// src/pages/Project/index.jsx
import { Link } from 'umi'
{dataIndex:"option",title:"操作",
render: (text, record) => (
<Space>
<Link to={'/project/interface?id='+record.id}>接口管理</Link>
<a onClick={() => editAction(record)}>编辑</a>
<a onClick={() => deleteConfirmWithPromise(record)}>删除</a>
</Space>
),
},
在完成查询接口请求之前,我们需要再创建一个接口请求ts来管理未来整个页面所有接口。创建路径为\src\services\ant-design-pro\interface.ts
,并完成POST异步的请求。这里有一点因为是TS语法,所以额外加了个params关于页码页数的类型声明,当然这个也可以省略。
import {request} from "@/.umi/exports";
export async function searchInterface(
params: {
current?: number;
pageSize?: number;
},
options?: { [key: string]: any },
) {
return request<API.RuleList>('/api/mock/interface/list', {
method: 'POST',
data: {
...params,
},
...(options || {}),
});
}
万事俱备,来到接口绑定的最后代码实现,首先是定义一个fetchApiData接口请求方法,并绑定到request。另外还要用useSearchParams获取URL中的参数值,并在ProTable的属性params额外传递。
// src/pages/Interface/index.tsx
import { useSearchParams } from 'umi'
import { searchInterface } from '@/services/ant-design-pro/interface';
...省略...
const fetchApiData = async (params, sort, filter) => {
const reps = await searchInterface(params);
return reps;
};
...省略...
export default () => {
// 此用法来自uim插件官方
const [searchParams, setSearchParams] = useSearchParams();
return (
<ProTable
params={{ projectId: searchParams.get('id') }}
// params 是需要自带的参数
// 这个参数优先级更高,会覆盖查询表单的参数
columns={apiolumns}
request={fetchApiData}
>
</ProTable>
)
};
特别说明下fetchApiData调用的时候param的参数值会是自定义参数值+查询表单里有填写属性的值,为了让大家清楚,做了三个实际请求对比:
到这里,通过上边三个请求操作,可以再次看这个高级table会节省多少代码,如果一个中台管理平台大部分都是增删改查的操作,那么将大大提高开发效率。
对于这个ProTable默认情况表格右上角还有一些快捷设置,可以自行探索下,另外还有一些模式\样式的设置大家也可以按需参考官方文档当时调整看看效果。本篇最后录个GIF看下实现效果。
本篇重点内容有三点: