一个多功用(聚合)查询接口,完成含糊、分页、主键、排序以及多条件查询
前语
写的烦琐了点,看作用请直接忽略中心,直接看后半部分。
引个流,公众号:小简聊开发
概念
瞎编的名字,哈哈哈,我就勉强称之为聚合查询吧,不知道概念符不符合。
咱们好,我是小简,很久没写文章了,确实是太忙了,今天我想入非非(其实也有很多相似的完成,只不过没去封装)的想去完成一个查询接口,不同条件不同查询的功用,简略的玩玩,假如咱们有更好的思路或者见解,能够评论区互动一下,我很菜,还请了解,大佬勿喷。
在日常开发中,咱们根本上是运用RESTful
接口,也便是一个接口对应一个功用,这很方便前端开发的对接,具体优势我想我就不用说了,咱们都在运用。
可是RESTful
假如功用过多,对应的接口也会随之增多,比方后台的查询接口和前台或许数据有区别需要额定写一个,或许前台查询数据某一个要含糊查询,某一个又要走主键查询,有的又是多条件查询。
那我就在想,要不试试一个查询接口,聚合N个完成?不同数据去不同完成然后不同拼合。
那其实这时分,GraphQL
这个玩意,其实就很符合我的料想,这玩意的接口查询便是一个接口完成的,大约意思和大致想法都是相同的。
可是GraphQL
的开发和运用复杂度要高一些,而且我仍是喜欢RESTful
一些,这儿不做过多介绍与对比,有兴趣能够前往浏览器查找一些,了解了解。
料想
那该怎样去完成呢?我的项目运用的是MyBatisPlus
作为ORM
结构,每一个实体都是去映射数据库表的,我要想这一个功用方便通用,那我肯定要去进行部分封装的。
首要考虑一下现在项目抱负状况:
- 实体映射数据库
- 数据库字段标准的选用蛇形命名,无一例外
- 实体类选用驼峰命名映射,无一例外
这种情况下,我只需要经过反射,将一个传过来的实体类的字段从驼峰转化为蛇形命名,作为查询条件的Key
,也便是数据库字段名。
然后获取对应的值,作为条件拼接,然后将查询条件目标丢到MyBatisPlus
的service
里边就能够了。
那么…开干!
查询条件拼接
咱们MP
是运用QueryWrapper
来构建条件查询目标的,总共有四种情况:
- 根本查询条件:
queryWrapper.eq()
- 含糊查询条件:
queryWrapper.like()
- 排序查询条件:
queryWrapper.orderByXXX()
至于主键查询,我料想是创立一个注解作为标识,假如在逻辑处理时分发现主键标识注解的字段值不为空,我就直接抛弃一切其他条件,直接走主键查询,ById
。
可是由于时刻原因,我就没去具体完成了。
获取目标字段与值
-
先经过反射获取目标一切特点并遍历。
-
假如特点值不为
null
就拼接。 -
运用
Hutool
中的StrUtil.toUnderlineCase
将特点名称转化蛇形。
拼接条件
代码如下:
/**
* 聚合查询目标拼接
*
* @param queries 查询目标
* @param obj 聚合查询特点目标
* @return 查询目标
*/
public static <Q> QueryWrapper<Q> splicingQueries(QueryWrapper<Q> queries, Object obj) {
Field[] declaredFields = obj.getClass().getDeclaredFields();
for (Field field : declaredFields) {
field.setAccessible(true);
String underlineCase = StrUtil.toUnderlineCase(field.getName());
try {
if (field.get(obj) != null) {
queries.eq(underlineCase, field.get(obj));
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
return queries;
}
大约代码便是这样的,然后我给了个泛型,为了束缚查询目标的类型。
那有人就说了:“那这样,含糊查询怎样办?排序怎样办?分页怎样办?”
哎哎哎,别急嘛,且听我娓娓道来。
拼接含糊
同理,去完成这个含糊查询的拼接办法封装。
/**
* 含糊查询目标拼接
*
* @param queries 查询目标
* @param obj 含糊查询特点目标
* @return 查询目标
*/
public static <Q> QueryWrapper<Q> splicingFuzzyQueries(QueryWrapper<Q> queries, Object obj) {
Field[] declaredFields = obj.getClass().getDeclaredFields();
for (Field field : declaredFields) {
field.setAccessible(true);
String underlineCase = StrUtil.toUnderlineCase(field.getName());
try {
if (field.get(obj) != null) {
queries.like(underlineCase, field.get(obj));
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
return queries;
}
拼接排序
/**
* 排序
*
* @param wrapper 查询目标
* @param sortField 排序字段
* @param sortType 排序类型
*/
private static <Q> void applySort(QueryWrapper<Q> wrapper, String sortField, int sortType) {
String field = StrUtil.toUnderlineCase(sortField);
if (sortType == 1) {
wrapper.orderByDesc(field);
} else {
wrapper.orderByAsc(field);
}
}
这儿其实能够优化sortType
为枚举,不过…嘿嘿,我比较懒,算了算了吧。
分页完成
分页先留在后边了,客官先往下看。
逻辑处理
到现在,功用的办法封装好了,收拾一下事务的逻辑。
在扫除主键(没时刻写啦)查询的情况下,逻辑总结如下:
假如存在肯定查询条件情况,如:ID查询、手机号查询、邮箱查询,直接性查询,就不拼接含糊查询了。
然后,根本查询条件,能够与肯定条件查询互补,也能够与含糊查询条件互补。
对于含糊查询,假如没有肯定查询条件的情况下,才会去拼接,含糊可与根本条件互补。
对于排序条件,只需数据存在就需要拼接,而且假如排序办法为
null
,默许升序。对于分页条件,我设置的是必传项,而且没去设置默许值(懒…)。
那将这个逻辑串联起来,就能够完成一个通用办法。
可是!!!
在完成这个办法之前,我怎么区分数据是要含糊仍是根本条件或者又是肯定查询条件?
所以,咱们需要先封装一个实体类,这个实体咱们或许每一个目标都有自己不相同的特点,所以咱们不能写死,直接泛化即可。
实体封装
先看我的注释,截个图:
再贴一切的代码:
/*
* Copyright (c) 2023. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
* Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan.
* Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna.
* Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus.
* Vestibulum commodo. Ut rhoncus gravida arcu.
* JanYork 2023年6月2日 23点37分
*/
/**
* <p>
* 泛型阐明:
* <ul>
* <li>T:直接性查询条件目标</li>
* <li>C:根本查询条件目标</li>
* <li>R:含糊查询条件目标</li>
* <li>泛型目标能够为空,为空时不进行查询</li>
* <li>泛型目标有必要是一个Bean</li>
* <li>泛型目标的特点<b>有必要是根本数据类型</b></li>
* </ul>
* </p>
*
* @author JanYork
* @version 1.0.0
* @date 2023/06/02
* @description 聚合查询目标
* @since 1.0.0
*/
@Data
@ApiModel(value = "聚合查询目标")
public class AggregateQueries<T, C, R> {
/**
* 直接性查询条件目标(T是一个Bean)
* <p>
* 直接性查询目标假如存在,<b>模块查询条件直接失效</b>,场景如:<br/> <b>ID直接查询</b>、<b>手机号直接查询</b>
* </p>
*/
@ApiModelProperty(value = "直接性查询条件目标")
private T queries;
/**
* 分页信息目标
* <p>
* 分页目标包含分页信息,<b>分页信息有必要存在</b>,场景如:<br/> <b>分页查询</b>
* </p>
*/
@ApiModelProperty(value = "分页信息目标")
private PaginationDTO pagination;
/**
* 根本查询条件目标(C是一个Bean)
* <p>
* 根本查询目标与直接性查询能够一起存在,<b>根本查询条件目标的查询条件会与直接性查询条件目标的查询条件进行组合</b>,场景如:<br/>
* <b>直接性查询ID为10001的用户</b>,<b>根赋性查询状况为true的用户</b>,结合后的查询条件为:<br/>
* <b>查询ID为10001且状况为true的用户</b>
* </p>
*/
@ApiModelProperty(value = "根本查询条件目标")
private C condition;
/**
* 含糊查询条件目标(R是一个Bean)
* <p>
* 含糊查询与直接性条件查询互斥,与根本查询条件目标互补,<b>含糊查询条件目标的查询条件会与根本查询条件目标的查询条件进行组合</b>,场景如:<br/>
* <b>根赋性查询状况为true的用户</b>,<b>含糊性查询用户名为张三的用户</b>,结合后的查询条件为:<br/>
* <b>查询状况为true且用户名包含张三的用户</b>
* </p>
*/
@ApiModelProperty(value = "含糊查询条件目标")
private R fuzzyQueries;
/**
* 排序字段
* <p>
* 排序字段能够为空,为空时不进行排序
* </p>
*/
@ApiModelProperty(value = "排序字段")
private String sortField;
/**
* 排序办法
* <p>
* 排序办法能够为空,为空时默许为升序,0:升序,1:降序
* </p>
*/
@ApiModelProperty(value = "排序办法")
private Integer sortType;
/**
* 是否存在直接性查询条件目标
*
* @return boolean true:存在,false:不存在
*/
public boolean hasQueries() {
return queries != null;
}
/**
* 是否存在分页信息目标
*
* @return boolean true:存在,false:不存在
*/
public boolean hasPagination() {
return pagination != null;
}
/**
* 是否存在根本查询条件目标
*
* @return boolean true:存在,false:不存在
*/
public boolean hasCondition() {
return condition != null;
}
/**
* 是否存在含糊查询条件目标
*
* @return boolean true:存在,false:不存在
*/
public boolean hasFuzzyQueries() {
return fuzzyQueries != null;
}
/**
* 是否存在排序字段
*
* @return boolean true:存在,false:不存在
*/
public boolean hasSortField() {
return sortField != null;
}
/**
* 是否存在排序办法
*
* @return boolean true:存在,false:不存在
*/
public boolean hasSortType() {
return sortType != null;
}
}
这儿面有一个PaginationDTO
,是一个分页信息目标,我也贴出来:
/**
* @author JanYork
* @version 1.0.0
* @date 2023/06/02
* @description 分页DTO
* @since 1.0.0
*/
@Data
@ApiModel(value = "分页数据目标")
public class PaginationDTO {
/**
* 页码
*/
@ApiModelProperty(value = "页码")
private Integer page;
/**
* 每页巨细
*/
@ApiModelProperty(value = "每页巨细")
private Integer size;
}
那这样咱们就封装成实体类了。
三个泛型?
三个泛型目标其实我在注释中已经说了:
泛型阐明:
- T:直接性查询条件目标
- C:根本查询条件目标
- R:含糊查询条件目标
- 泛型目标能够为空,为空时不进行查询(不拼接)
- 泛型目标有必要是一个Bean(实体),而且实体有必要映射数据表,字段有必要标准命名
- 泛型目标的特点有必要是根本数据类型
然后对于这三个泛型,咱们要创立不同的实体(费事归费事,标准仍是要),所以,接下来看看我怎样用的。
我这儿一个地址聚合查询和一个产品聚合查询。
构建实体?
Condition
结束的是根本查询条件目标,如:
/**
* @author JanYork
* @version 1.0.0
* @date 2023/06/02
* @description 地址根本条件查询目标
* @since 1.0.0
*/
@Data
@ApiModel("(地址)根本条件查询目标")
public class AddressCondition {
/**
* 省
*/
@ApiModelProperty(value = "省")
private String province;
/**
* 城市
*/
@ApiModelProperty(value = "城市")
private String city;
/**
* 县/区
*/
@ApiModelProperty(value = "县/区")
private String district;
}
这儿面的条件,假如存在,那就必定会拼接,与肯定查询条件或者含糊查询条件互补。
FuzzyQueries
结束的是含糊查询条件,如:
/**
* @author JanYork
* @version 1.0.0
* @date 2023/06/02
* @description 地址含糊查询目标
* @since 1.0.0
*/
@Data
@ApiModel("(地址)含糊查询目标")
public class AddressFuzzyQueries {
/**
* 用户手机号
*/
@ApiModelProperty(value = "用户手机号(可含糊)")
private String phone;
/**
* 用户名字
*/
@ApiModelProperty(value = "用户名字(可含糊)")
private String name;
/**
* 具体地址
*/
@ApiModelProperty(value = "具体地址(可含糊)")
private String address;
}
这个实体里边的条件与肯定查询条件互斥,且优先级低于肯定查询条件!
Queries
结束的是肯定查询条件,如:
/**
* @author JanYork
* @version 1.0.0
* @date 2023/06/02
* @description 地址直接性查询目标
* @since 1.0.0
*/
@Data
@ApiModel("(地址)直接性查询目标")
public class AddressQueries {
/**
* 用户ID
*/
@ApiModelProperty(value = "用户ID")
private Long userId;
/**
* 用户手机号
*/
@ApiModelProperty(value = "用户手机号")
private String phone;
}
这个实体条件优先级最高,假如存在必定拼接。
然后三个实体都有了,咱们还需要将上面逻辑处理段落总结的逻辑串联起来,完成一个通用办法。
通用办法完成
咱们开端已经封装了含糊、条件、排序的拼接办法,所以咱们能够直接调用封装好的办法去完成拼接的逻辑处理。
直接丢代码了:
/**
* 聚合查询目标拼接
*
* @param queries 查询目标
* @param aggregate 聚合查询目标
* @return {@link QueryWrapper}<{@link Q}>
*/
public static <Q, T, C, R> QueryWrapper<Q> splicingAggregateQueries(QueryWrapper<Q> queries, AggregateQueries<T, C, R> aggregate) {
if (aggregate.hasQueries()) {
splicingQueries(queries, aggregate.getQueries());
}
if (aggregate.hasCondition()) {
splicingQueries(queries, aggregate.getCondition());
}
if (aggregate.hasFuzzyQueries() && !aggregate.hasQueries()) {
splicingFuzzyQueries(queries, aggregate.getFuzzyQueries());
}
if (aggregate.hasSortField()) {
aggregate.setSortType(aggregate.hasSortType() ? aggregate.getSortType() : 0);
applySort(queries, aggregate.getSortField(), aggregate.getSortType());
}
return queries;
}
这个通用办法,主要便是完成通用性和逻辑贯穿处理,这儿没写过多注释,aggregate.hasXXXX
办法是判别是否存在条件实体目标或者字段值,逻辑还需要请各位亲自捋一下了,究竟也就几个if
。
运用聚合办法与分页操作
先看代码后讲解:
/**
* 聚合查询
*
* @param aggregate 聚合查询目标
* @return {@link ApiResponse}<{@link List}<{@link Address}>>
*/
@PostMapping("/get")
public ApiResponse<List<Address>> get(@RequestBody AggregateQueries<AddressQueries, AddressCondition, AddressFuzzyQueries> aggregate) {
if (!aggregate.hasPagination()) {
return ApiResponse.fail(null);
}
PaginationDTO pagination = aggregate.getPagination();
QueryWrapper<Address> wrapper = AggregateQueriesUtil.splicingAggregateQueries(new QueryWrapper<>(), aggregate);
Page<Address> page = new Page<>(pagination.getPage(), pagination.getSize());
return ApiResponse.ok(
addressService.page(page, wrapper).getRecords()
);
}
这儿,接口接收的参数便是映射咱们封装的聚合条件目标:AggregateQueries<AddressQueries, AddressCondition, AddressFuzzyQueries> aggregate
了。
这三个泛型便是咱们对于不同数据库实体的不同条件字段封装的不同POJO
。
分页
先前说了,分页是有必要的,所以咱们判别一下,分页目标不存在直接回来失利。
if (!aggregate.hasPagination()) {
return ApiResponse.fail(null);
}
假如存在咱们获取分页信息,使用MP
的分页插件,直接进行分页查询操作,这个插件就不多说了。
处理
这儿咱们直接使用咱们封装好的通用办法去获取拼接条件后的QueryWrapper
目标:
QueryWrapper<Address> wrapper = AggregateQueriesUtil.splicingAggregateQueries(new QueryWrapper<>(), aggregate);
由于是后台办理端的数据,我就懒得去Bean
拷贝到VO
目标了,直接便是实体回来。
作用演示
调试东西用什么好呢?上postman
吧。
数据库数据展现
1000 1658741489930473472 江西省 南昌市 南昌县 江西省南昌市南昌县万寿宫 16688880818 小简 28.68333 115.88333 0
1001 1658741489930473472 江西省 南市 南昌县 江西省南昌市南昌县东湖区ABCD6栋 16670080818 小简 28.68333 115.88333 0
1002 1658741489930473472 江西省 昌市 南昌县 江西省南昌市南昌县CCC写字楼 16676080818 小简 28.68333 115.88333 1
测试JSON
数据:
{
"queries": {
"phone":"16688880818"
},
"pagination": {
"page": 1,
"size": 3
},
"condition":{
"city":"南市"
},
"fuzzyQueries": {
"phone": "166",
"address": "CCC写字楼"
},
"sortField": "id",
"sortType": 1
}
肯定条件查询
数据:
{
"queries": {
"phone":"16688880818"
},
"pagination": {
"page": 1,
"size": 3
}
}
SQL
日志:
SELECT id,user_id,province,city,district,address,phone,name,latitude,longitude,is_default FROM address WHERE (phone = ?) LIMIT ?
MP
完好日志:
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@164276c] was not registered for synchronization because synchronization is not active
JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@71237c20] will not be managed by Spring
==> Preparing: SELECT COUNT(*) AS total FROM address WHERE (phone = ?)
==> Parameters: 16688880818(String)
<== Columns: total
<== Row: 1
<== Total: 1
==> Preparing: SELECT id,user_id,province,city,district,address,phone,name,latitude,longitude,is_default FROM address WHERE (phone = ?) LIMIT ?
==> Parameters: 16688880818(String), 3(Long)
<== Columns: id, user_id, province, city, district, address, phone, name, latitude, longitude, is_default
<== Row: 1000, 1658741489930473472, 江西省, 南昌市, 南昌县, 江西省南昌市南昌县万寿宫, 16688880818, 小简, 28.68333, 115.88333, 0
<== Total: 1
回调数据:
{
"code": 200,
"message": "success",
"data": [
{
"id": 1000,
"userId": 1658741489930473472,
"province": "江西省",
"city": "南昌市",
"district": "南昌县",
"address": "江西省南昌市南昌县万寿宫",
"phone": "16688880818",
"name": "小简",
"latitude": "28.68333",
"longitude": "115.88333",
"isDefault": false
}
]
}
肯定+根本
数据:
{
"queries": {
"phone":"16688880818"
},
"pagination": {
"page": 1,
"size": 3
},
"condition":{
"city":"南昌市"
}
}
SQL
日志:
SELECT id,user_id,province,city,district,address,phone,name,latitude,longitude,is_default FROM address WHERE (phone = ? AND city = ?) LIMIT ?
MP
日志:
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2e00c6c9] was not registered for synchronization because synchronization is not active
JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@5e68f14e] will not be managed by Spring
==> Preparing: SELECT COUNT(*) AS total FROM address WHERE (phone = ? AND city = ?)
==> Parameters: 16688880818(String), 南昌市(String)
<== Columns: total
<== Row: 1
<== Total: 1
==> Preparing: SELECT id,user_id,province,city,district,address,phone,name,latitude,longitude,is_default FROM address WHERE (phone = ? AND city = ?) LIMIT ?
==> Parameters: 16688880818(String), 南昌市(String), 3(Long)
<== Columns: id, user_id, province, city, district, address, phone, name, latitude, longitude, is_default
<== Row: 1000, 1658741489930473472, 江西省, 南昌市, 南昌县, 江西省南昌市南昌县万寿宫, 16688880818, 小简, 28.68333, 115.88333, 0
<== Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2e00c6c9]
回调数据:
{
"code": 200,
"message": "success",
"data": [
{
"id": 1000,
"userId": 1658741489930473472,
"province": "江西省",
"city": "南昌市",
"district": "南昌县",
"address": "江西省南昌市南昌县万寿宫",
"phone": "16688880818",
"name": "小简",
"latitude": "28.68333",
"longitude": "115.88333",
"isDefault": false
}
]
}
含糊
数据:
{
"pagination": {
"page": 1,
"size": 3
},
"fuzzyQueries": {
"phone": "166"
// "address": "CCC写字楼"
}
}
SQL
日志:
SELECT id,user_id,province,city,district,address,phone,name,latitude,longitude,is_default FROM address WHERE (phone LIKE ?) LIMIT ?
MP
日志:
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3646a7c1] was not registered for synchronization because synchronization is not active
JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@3e66a291] will not be managed by Spring
==> Preparing: SELECT COUNT(*) AS total FROM address WHERE (phone LIKE ?)
==> Parameters: %166%(String)
<== Columns: total
<== Row: 3
<== Total: 1
==> Preparing: SELECT id,user_id,province,city,district,address,phone,name,latitude,longitude,is_default FROM address WHERE (phone LIKE ?) LIMIT ?
==> Parameters: %166%(String), 3(Long)
<== Columns: id, user_id, province, city, district, address, phone, name, latitude, longitude, is_default
<== Row: 1000, 1658741489930473472, 江西省, 南昌市, 南昌县, 江西省南昌市南昌县万寿宫, 16688880818, 小简, 28.68333, 115.88333, 0
<== Row: 1001, 1658741489930473472, 江西省, 南市, 南昌县, 江西省南昌市南昌县东湖区ABCD6栋, 16670080818, 小简, 28.68333, 115.88333, 0
<== Row: 1002, 1658741489930473472, 江西省, 昌市, 南昌县, 江西省南昌市南昌县CCC写字楼, 16676080818, 小简, 28.68333, 115.88333, 1
<== Total: 3
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3646a7c1]
回调数据:
{
"code": 200,
"message": "success",
"data": [
{
"id": 1000,
"userId": 1658741489930473472,
"province": "江西省",
"city": "南昌市",
"district": "南昌县",
"address": "江西省南昌市南昌县万寿宫",
"phone": "16688880818",
"name": "小简",
"latitude": "28.68333",
"longitude": "115.88333",
"isDefault": false
},
{
"id": 1001,
"userId": 1658741489930473472,
"province": "江西省",
"city": "南市",
"district": "南昌县",
"address": "江西省南昌市南昌县东湖区ABCD6栋",
"phone": "16670080818",
"name": "小简",
"latitude": "28.68333",
"longitude": "115.88333",
"isDefault": false
},
{
"id": 1002,
"userId": 1658741489930473472,
"province": "江西省",
"city": "昌市",
"district": "南昌县",
"address": "江西省南昌市南昌县CCC写字楼",
"phone": "16676080818",
"name": "小简",
"latitude": "28.68333",
"longitude": "115.88333",
"isDefault": true
}
]
}
排序+含糊
数据:
{
"pagination": {
"page": 1,
"size": 3
},
"fuzzyQueries": {
"phone": "166"
},
"sortField": "id",
"sortType": 1
}
SQL
日志:
SELECT id,user_id,province,city,district,address,phone,name,latitude,longitude,is_default FROM address WHERE (phone LIKE ?) ORDER BY id DESC LIMIT ?
MP
日志:
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@26a0b246] was not registered for synchronization because synchronization is not active
JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@3deaaebe] will not be managed by Spring
==> Preparing: SELECT COUNT(*) AS total FROM address WHERE (phone LIKE ?)
==> Parameters: %166%(String)
<== Columns: total
<== Row: 3
<== Total: 1
==> Preparing: SELECT id,user_id,province,city,district,address,phone,name,latitude,longitude,is_default FROM address WHERE (phone LIKE ?) ORDER BY id DESC LIMIT ?
==> Parameters: %166%(String), 3(Long)
<== Columns: id, user_id, province, city, district, address, phone, name, latitude, longitude, is_default
<== Row: 1002, 1658741489930473472, 江西省, 昌市, 南昌县, 江西省南昌市南昌县CCC写字楼, 16676080818, 小简, 28.68333, 115.88333, 1
<== Row: 1001, 1658741489930473472, 江西省, 南市, 南昌县, 江西省南昌市南昌县东湖区ABCD6栋, 16670080818, 小简, 28.68333, 115.88333, 0
<== Row: 1000, 1658741489930473472, 江西省, 南昌市, 南昌县, 江西省南昌市南昌县万寿宫, 16688880818, 小简, 28.68333, 115.88333, 0
<== Total: 3
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@26a0b246]
回调数据:
{
"code": 200,
"message": "success",
"data": [
{
"id": 1002,
"userId": 1658741489930473472,
"province": "江西省",
"city": "昌市",
"district": "南昌县",
"address": "江西省南昌市南昌县CCC写字楼",
"phone": "16676080818",
"name": "小简",
"latitude": "28.68333",
"longitude": "115.88333",
"isDefault": true
},
{
"id": 1001,
"userId": 1658741489930473472,
"province": "江西省",
"city": "南市",
"district": "南昌县",
"address": "江西省南昌市南昌县东湖区ABCD6栋",
"phone": "16670080818",
"name": "小简",
"latitude": "28.68333",
"longitude": "115.88333",
"isDefault": false
},
{
"id": 1000,
"userId": 1658741489930473472,
"province": "江西省",
"city": "南昌市",
"district": "南昌县",
"address": "江西省南昌市南昌县万寿宫",
"phone": "16688880818",
"name": "小简",
"latitude": "28.68333",
"longitude": "115.88333",
"isDefault": false
}
]
}
其他作用
都能够自由组合,单排序、单分页、单含糊、排序+分页+含糊、排序+根本……
都是能够自由组合的,办法太多就不都去尝试了,咱们也能够去试试,苦楚的封装也会带来必定的优点。
也能够在此基础上,去创造一些新鲜的玩法和事务完成,感谢咱们阅读,下期再见啦!
我是小简,下期再见(不知道下期是多久了唉)。
尾述
为什么要去写一些七里八里的东东呢?
由于,创造性才是实质,我不期望被CRUD
的作业丢失我的兴趣与活泼的思维。
我以为,挣钱的永远是思维和大脑,而非单纯的、一味的技术。