refactor(all): 调整模块依赖,划分代码范围
This commit is contained in:
@@ -1,68 +0,0 @@
|
||||
package com.lanyuanxiaoyao.service.template.common.controller;
|
||||
|
||||
import com.lanyuanxiaoyao.service.template.common.entity.GlobalResponse;
|
||||
import com.lanyuanxiaoyao.service.template.common.entity.Query;
|
||||
|
||||
/**
|
||||
* 查询控制器接口,用于定义统一的查询实体详情和列表的接口规范
|
||||
* <p>
|
||||
* 该接口提供了标准的查询功能,支持条件查询、分页查询和详情查询。
|
||||
* 所有实现类应当遵循统一的请求响应格式。
|
||||
* </p>
|
||||
*
|
||||
* <h3>查询条件说明</h3>
|
||||
* <ul>
|
||||
* <li><b>空值条件:</b> nullEqual、notNullEqual、empty、notEmpty</li>
|
||||
* <li><b>相等条件:</b> equal、notEqual</li>
|
||||
* <li><b>模糊匹配:</b> like、notLike、contain、notContain</li>
|
||||
* <li><b>前后缀匹配:</b> startWith、notStartWith、endWith、notEndWith</li>
|
||||
* <li><b>范围条件:</b> great、less、greatEqual、lessEqual</li>
|
||||
* <li><b>集合条件:</b> inside、notInside</li>
|
||||
* <li><b>区间条件:</b> between、notBetween</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param <LIST_ITEM> 列表查询结果的实体类型
|
||||
* @param <DETAIL_ITEM> 详情查询结果的实体类型
|
||||
*/
|
||||
public interface QueryController<LIST_ITEM, DETAIL_ITEM> {
|
||||
String LIST = "/list";
|
||||
String DETAIL = "/detail/{id}";
|
||||
|
||||
/**
|
||||
* 获取所有实体列表
|
||||
* <p>
|
||||
* 查询所有记录,不带任何过滤条件,返回分页格式的数据。
|
||||
* 适用于获取全量数据的场景。
|
||||
* </p>
|
||||
*
|
||||
* @return 返回包含实体列表的响应对象,格式:{status: 0, message: "OK", data: {items: [...], total: total}}
|
||||
* @throws Exception 查询过程中可能抛出的异常
|
||||
*/
|
||||
GlobalResponse<GlobalResponse.ListItem<LIST_ITEM>> list() throws Exception;
|
||||
|
||||
/**
|
||||
* 根据查询条件获取实体列表
|
||||
* <p>
|
||||
* 支持复杂的查询条件、排序和分页,返回符合条件的数据。
|
||||
* 查询条件包括相等、模糊匹配、范围查询、集合查询等。
|
||||
* </p>
|
||||
*
|
||||
* @param query 查询条件对象,包含过滤条件、排序规则和分页信息
|
||||
* @return 返回符合条件的实体列表响应对象,格式:{status: 0, message: "OK", data: {items: [...], total: total}}
|
||||
* @throws Exception 查询过程中可能抛出的异常
|
||||
*/
|
||||
GlobalResponse<GlobalResponse.ListItem<LIST_ITEM>> list(Query query) throws Exception;
|
||||
|
||||
/**
|
||||
* 根据ID获取实体详情
|
||||
* <p>
|
||||
* 根据主键ID查询单条记录的详细信息。
|
||||
* 适用于详情页面展示或数据编辑的场景。
|
||||
* </p>
|
||||
*
|
||||
* @param id 实体主键ID
|
||||
* @return 返回实体详情响应对象,格式:{status: 0, message: "OK", data: {item: 详情数据}}
|
||||
* @throws Exception 查询过程中可能抛出的异常
|
||||
*/
|
||||
GlobalResponse<DETAIL_ITEM> detail(Long id) throws Exception;
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package com.lanyuanxiaoyao.service.template.common.controller;
|
||||
|
||||
import com.lanyuanxiaoyao.service.template.common.entity.GlobalResponse;
|
||||
|
||||
/**
|
||||
* 删除控制器接口,用于定义统一的删除实体对象的接口规范
|
||||
* <p>
|
||||
* 该接口提供了标准的删除功能,通过主键ID删除单条记录。
|
||||
* 所有实现类应当遵循统一的请求响应格式。
|
||||
* </p>
|
||||
*/
|
||||
public interface RemoveController {
|
||||
String REMOVE = "/remove/{id}";
|
||||
|
||||
/**
|
||||
* 根据ID删除实体对象
|
||||
* <p>
|
||||
* 根据主键ID删除指定的记录,执行成功后返回操作结果。
|
||||
* 适用于单条记录删除的场景。
|
||||
* </p>
|
||||
*
|
||||
* @param id 需要删除的实体主键ID
|
||||
* @return 返回删除结果响应对象,格式:{status: 0, message: "OK", data: null}
|
||||
* @throws Exception 删除过程中可能抛出的异常
|
||||
*/
|
||||
GlobalResponse<Object> remove(Long id) throws Exception;
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package com.lanyuanxiaoyao.service.template.common.controller;
|
||||
|
||||
import com.lanyuanxiaoyao.service.template.common.entity.GlobalResponse;
|
||||
|
||||
/**
|
||||
* 保存控制器接口,用于定义统一的保存实体对象的接口规范
|
||||
* <p>
|
||||
* 该接口提供了标准的保存功能,支持新增和更新操作。
|
||||
* 所有实现类应当遵循统一的请求响应格式。
|
||||
* </p>
|
||||
*
|
||||
* @param <SAVE_ITEM> 保存操作的实体类型
|
||||
*/
|
||||
public interface SaveController<SAVE_ITEM> {
|
||||
String SAVE = "/save";
|
||||
|
||||
/**
|
||||
* 保存实体对象
|
||||
* <p>
|
||||
* 保存或更新实体对象,根据业务逻辑判断是新增还是更新操作。
|
||||
* 返回保存后的实体ID,便于前端获取操作结果。
|
||||
* </p>
|
||||
*
|
||||
* @param item 需要保存的实体对象,包含完整的字段信息
|
||||
* @return 返回保存后的实体ID响应对象,格式:{status: 0, message: "OK", data: 实体ID}
|
||||
* @throws Exception 保存过程中可能抛出的异常
|
||||
*/
|
||||
GlobalResponse<Long> save(SAVE_ITEM item) throws Exception;
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
package com.lanyuanxiaoyao.service.template.common.controller;
|
||||
|
||||
public interface SimpleController<SAVE_ITEM, LIST_ITEM, DETAIL_ITEM> extends SaveController<SAVE_ITEM>, QueryController<LIST_ITEM, DETAIL_ITEM>, RemoveController {
|
||||
}
|
||||
@@ -1,359 +0,0 @@
|
||||
package com.lanyuanxiaoyao.service.template.common.entity;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 全局统一API响应封装类
|
||||
* <p>
|
||||
* 该类用于统一封装RESTful API接口的响应结果,提供标准化的响应格式。
|
||||
* 通过状态码、消息和数据三个字段,清晰地表达请求的处理结果,便于前端统一处理。
|
||||
* </p>
|
||||
*
|
||||
* <h3>设计特点</h3>
|
||||
* <ul>
|
||||
* <li>使用Java Record实现,不可变,线程安全</li>
|
||||
* <li>泛型设计,支持任意类型的数据封装</li>
|
||||
* <li>提供丰富的静态工厂方法,简化响应对象创建</li>
|
||||
* <li>支持分页查询、详情查询等常见场景</li>
|
||||
* </ul>
|
||||
*
|
||||
* <h3>响应格式示例</h3>
|
||||
* <p><b>成功响应(无数据):</b></p>
|
||||
* <pre>
|
||||
* {
|
||||
* "status": 0,
|
||||
* "message": "OK",
|
||||
* "data": null
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p><b>成功响应(带数据):</b></p>
|
||||
* <pre>
|
||||
* {
|
||||
* "status": 0,
|
||||
* "message": "操作成功",
|
||||
* "data": {
|
||||
* "id": 1,
|
||||
* "name": "示例数据"
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p><b>分页列表响应:</b></p>
|
||||
* <pre>
|
||||
* {
|
||||
* "status": 0,
|
||||
* "message": "OK",
|
||||
* "data": {
|
||||
* "items": [
|
||||
* {"id": 1, "name": "数据1"},
|
||||
* {"id": 2, "name": "数据2"}
|
||||
* ],
|
||||
* "total": 100
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p><b>错误响应:</b></p>
|
||||
* <pre>
|
||||
* {
|
||||
* "status": 500,
|
||||
* "message": "系统异常,请稍后重试",
|
||||
* "data": null
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <h3>使用场景</h3>
|
||||
* <ul>
|
||||
* <li><b>RESTful API:</b> 作为所有API接口的标准响应格式</li>
|
||||
* <li><b>前后端分离:</b> 前端可统一处理成功/失败逻辑</li>
|
||||
* <li><b>微服务架构:</b> 服务间调用的标准化响应</li>
|
||||
* <li><b>移动端接口:</b> 移动端APP的统一数据格式</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param <T> 响应数据的类型,可以是任意对象、集合、Map或包装类
|
||||
* @param status 响应状态码
|
||||
* <ul>
|
||||
* <li>0 - 成功</li>
|
||||
* <li>500 - 服务器错误</li>
|
||||
* <li>其他 - 业务自定义状态码</li>
|
||||
* </ul>
|
||||
* @param message 响应消息,对状态码的简短描述,如"OK"、"ERROR"或具体的错误信息
|
||||
* @param data 响应数据,具体的业务数据,可以是任意类型。对于列表查询,通常封装为包含items和total的Map;对于详情查询,直接返回对象或Map
|
||||
*
|
||||
* @see #responseSuccess()
|
||||
* @see #responseError()
|
||||
* @see #responseListData(Iterable, Long)
|
||||
* @see #responseDetailData(Object)
|
||||
*/
|
||||
public record GlobalResponse<T>(Integer status, String message, T data) {
|
||||
/**
|
||||
* 成功状态码 - 表示请求处理成功
|
||||
*/
|
||||
private static final int SUCCESS_STATUS = 0;
|
||||
|
||||
/**
|
||||
* 错误状态码 - 表示服务器内部错误或业务异常
|
||||
*/
|
||||
private static final int ERROR_STATUS = 500;
|
||||
|
||||
/**
|
||||
* 成功默认消息 - 用于通用成功响应
|
||||
*/
|
||||
private static final String SUCCESS_MESSAGE = "OK";
|
||||
|
||||
/**
|
||||
* 错误默认消息 - 用于通用错误响应
|
||||
*/
|
||||
private static final String ERROR_MESSAGE = "ERROR";
|
||||
|
||||
/**
|
||||
* 返回默认错误响应
|
||||
* <p>
|
||||
* 使用默认错误消息"ERROR",状态码500,数据为null。
|
||||
* 适用于无法确定具体错误原因的通用异常场景。
|
||||
* </p>
|
||||
*
|
||||
* @return 错误响应对象,格式:{status: 500, message: "ERROR", data: null}
|
||||
*
|
||||
* @see #responseError(String)
|
||||
* @see #responseSuccess()
|
||||
*/
|
||||
public static GlobalResponse<Object> responseError() {
|
||||
return responseError(ERROR_MESSAGE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回指定错误消息的响应
|
||||
* <p>
|
||||
* 使用指定的错误消息,状态码500,数据为null。
|
||||
* 适用于需要向客户端传递具体错误信息的场景。
|
||||
* </p>
|
||||
*
|
||||
* @param message 错误消息内容,建议描述具体错误原因,便于前端展示和问题定位
|
||||
* @return 错误响应对象,格式:{status: 500, message: "自定义错误信息", data: null}
|
||||
*
|
||||
* @see #responseError()
|
||||
* @see #responseSuccess(String)
|
||||
*/
|
||||
public static GlobalResponse<Object> responseError(String message) {
|
||||
return new GlobalResponse<>(ERROR_STATUS, message, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回默认成功响应
|
||||
* <p>
|
||||
* 使用默认成功消息"OK",状态码0,数据为null。
|
||||
* 适用于操作成功但不需要返回数据的场景。
|
||||
* </p>
|
||||
*
|
||||
* @return 成功响应对象,格式:{status: 0, message: "OK", data: null}
|
||||
*
|
||||
* @see #responseSuccess(String)
|
||||
* @see #responseSuccess(Object)
|
||||
* @see #responseError()
|
||||
*/
|
||||
public static GlobalResponse<Object> responseSuccess() {
|
||||
return responseSuccess(SUCCESS_MESSAGE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回指定成功消息的响应
|
||||
* <p>
|
||||
* 使用指定的成功消息,状态码0,数据为null。
|
||||
* 适用于需要向客户端返回自定义成功提示的场景。
|
||||
* </p>
|
||||
*
|
||||
* @param message 成功消息内容,建议描述具体操作结果,便于用户理解
|
||||
* @return 成功响应对象,格式:{status: 0, message: "自定义成功信息", data: null}
|
||||
*
|
||||
* @see #responseSuccess()
|
||||
* @see #responseSuccess(Object)
|
||||
* @see #responseSuccess(String, Object)
|
||||
*/
|
||||
public static GlobalResponse<Object> responseSuccess(String message) {
|
||||
return responseSuccess(message, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回包含数据的成功响应
|
||||
* <p>
|
||||
* 使用默认成功消息"OK",状态码0,包含指定数据。
|
||||
* 适用于需要返回数据但不需要自定义消息的场景。
|
||||
* </p>
|
||||
*
|
||||
* @param <E> 数据类型,可以是任意Java对象
|
||||
* @param data 业务数据,可以是实体对象、Map、集合等
|
||||
* @return 成功响应对象,格式:{status: 0, message: "OK", data: 业务数据}
|
||||
*
|
||||
* @see #responseSuccess(String, Object)
|
||||
* @see #responseListData(Iterable, Long)
|
||||
* @see #responseDetailData(Object)
|
||||
*/
|
||||
public static <E> GlobalResponse<E> responseSuccess(E data) {
|
||||
return responseSuccess(SUCCESS_MESSAGE, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回包含指定消息和数据的成功响应
|
||||
* <p>
|
||||
* 使用指定的成功消息,状态码0,包含指定数据。
|
||||
* 这是最完整的方法,适用于需要同时自定义消息和返回数据的场景。
|
||||
* </p>
|
||||
*
|
||||
* @param <E> 数据类型
|
||||
* @param message 成功消息内容,描述具体操作结果
|
||||
* @param data 业务数据,可以是任意类型
|
||||
* @return 成功响应对象,格式:{status: 0, message: "自定义消息", data: 业务数据}
|
||||
*
|
||||
* @see #responseSuccess()
|
||||
* @see #responseSuccess(Object)
|
||||
* @see #responseSuccess(String)
|
||||
*/
|
||||
public static <E> GlobalResponse<E> responseSuccess(String message, E data) {
|
||||
return new GlobalResponse<>(SUCCESS_STATUS, message, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回Map类型数据的成功响应
|
||||
* <p>
|
||||
* 适用于需要返回结构化数据的场景,如分页查询结果、统计信息等。
|
||||
* 内部使用responseSuccess方法封装。
|
||||
* </p>
|
||||
*
|
||||
* @param data Map格式的业务数据,键为String,值为任意对象
|
||||
* @return 成功响应对象,格式:{status: 0, message: "OK", data: Map数据}
|
||||
*
|
||||
* @see #responseMapData(String, Object)
|
||||
* @see #responseSuccess(Object)
|
||||
*/
|
||||
public static GlobalResponse<Map<String, Object>> responseMapData(Map<String, Object> data) {
|
||||
return responseSuccess(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回单个键值对的成功响应
|
||||
* <p>
|
||||
* 将单个键值对封装为Map后返回,适用于返回单个配置项或简单结果的场景。
|
||||
* </p>
|
||||
*
|
||||
* @param key 数据键名,不能为null
|
||||
* @param value 数据值,可以是任意对象
|
||||
* @return 成功响应对象,格式:{status: 0, message: "OK", data: {key: value}}
|
||||
*
|
||||
* @see #responseMapData(Map)
|
||||
* @see #responseSuccess(Object)
|
||||
*/
|
||||
public static GlobalResponse<Map<String, Object>> responseMapData(String key, Object value) {
|
||||
return responseMapData(Map.of(key, value));
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回空列表的成功响应
|
||||
* <p>
|
||||
* 适用于查询结果为空的场景,返回空列表和总数为0。
|
||||
* </p>
|
||||
*
|
||||
* @param <T> 数据项类型
|
||||
* @return 成功响应对象,格式:{status: 0, message: "OK", data: {items: [], total: 0}}
|
||||
*
|
||||
* @see #responseListData(Iterable, Long)
|
||||
* @see #responseListData(Iterable, Integer)
|
||||
*/
|
||||
public static <T> GlobalResponse<ListItem<T>> responseListData() {
|
||||
return responseListData(List.of(), 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回CRUD列表数据的成功响应(Integer类型总数)
|
||||
* <p>
|
||||
* 适用于分页查询,将数据列表和总数封装为标准格式。
|
||||
* 自动将Integer类型的总数转换为Long类型。
|
||||
* </p>
|
||||
*
|
||||
* @param <T> 数据项类型
|
||||
* @param data 数据列表,可以是List、Set等Iterable实现
|
||||
* @param total 总记录数,Integer类型
|
||||
* @return 成功响应对象,格式:{status: 0, message: "OK", data: {items: [...], total: total}}
|
||||
*
|
||||
* @see #responseListData(Iterable, Long)
|
||||
* @see #responseListData()
|
||||
* @see #responseSuccess(Object)
|
||||
*/
|
||||
public static <T> GlobalResponse<ListItem<T>> responseListData(Iterable<T> data, Integer total) {
|
||||
return responseListData(data, total.longValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回CRUD列表数据的成功响应(Long类型总数)
|
||||
* <p>
|
||||
* 适用于分页查询,将数据列表和总数封装为标准格式。
|
||||
* 支持大数据量场景,使用Long类型避免整数溢出。
|
||||
* </p>
|
||||
*
|
||||
* @param <T> 数据项类型
|
||||
* @param data 数据列表,可以是List、Set等Iterable实现
|
||||
* @param total 总记录数,Long类型,支持大数据量
|
||||
* @return 成功响应对象,格式:{status: 0, message: "OK", data: {items: [...], total: total}}
|
||||
*
|
||||
* @see #responseListData(Iterable, Integer)
|
||||
* @see #responseListData()
|
||||
* @see ListItem
|
||||
* @see #responseSuccess(Object)
|
||||
*/
|
||||
public static <T> GlobalResponse<ListItem<T>> responseListData(Iterable<T> data, Long total) {
|
||||
return responseSuccess(new ListItem<>(data, total));
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回详情数据的成功响应
|
||||
* <p>
|
||||
* 适用于详情查询,将单条记录封装为标准格式。
|
||||
* 便于前端统一处理详情数据的展示。
|
||||
* </p>
|
||||
*
|
||||
* @param <T> 数据类型
|
||||
* @param data 详情数据,可以是实体对象、Map等
|
||||
* @return 成功响应对象,格式:{status: 0, message: "OK", data: {item: 详情数据}}
|
||||
*
|
||||
* @see #responseSuccess(Object)
|
||||
* @see DetailItem
|
||||
*/
|
||||
public static <T> GlobalResponse<DetailItem<T>> responseDetailData(T data) {
|
||||
return responseSuccess(new DetailItem<>(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表数据封装类
|
||||
* <p>
|
||||
* 用于封装分页查询的结果,包含数据列表和总记录数。
|
||||
* 便于前端进行分页控件的渲染和数据展示。
|
||||
* </p>
|
||||
*
|
||||
* @param <T> 数据项类型
|
||||
* @param items 数据列表,包含当前页的所有记录
|
||||
* @param total 总记录数,用于计算总页数和显示分页信息
|
||||
*
|
||||
* @see #responseListData(Iterable, Long)
|
||||
*/
|
||||
public record ListItem<T>(Iterable<T> items, Long total) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 详情数据封装类
|
||||
* <p>
|
||||
* 用于封装单条记录的查询结果,提供统一的详情数据结构。
|
||||
* 便于前端统一处理详情页面的数据展示。
|
||||
* </p>
|
||||
*
|
||||
* <p><b>注意:</b> item字段使用Object类型,可以存储任意类型的详情数据。</p>
|
||||
*
|
||||
* @param <T> 数据类型(主要用于类型提示)
|
||||
* @param item 单条记录数据,可以是实体对象、Map、VO对象等
|
||||
*
|
||||
* @see #responseDetailData(Object)
|
||||
*/
|
||||
public record DetailItem<T>(T item) {
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package com.lanyuanxiaoyao.service.template.common.entity;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 分页数据封装类
|
||||
* <p>
|
||||
* 用于封装分页查询的结果,包含数据流和总记录数。
|
||||
* 适用于需要流式处理大量数据的场景,同时提供总数用于分页计算。
|
||||
* </p>
|
||||
*
|
||||
* <h3>使用场景</h3>
|
||||
* <ul>
|
||||
* <li>数据库分页查询结果封装</li>
|
||||
* <li>大数据量流式处理</li>
|
||||
* <li>分页控件的数据源</li>
|
||||
* </ul>
|
||||
*
|
||||
* <h3>特点</h3>
|
||||
* <ul>
|
||||
* <li>使用Java Record实现,不可变,线程安全</li>
|
||||
* <li>支持流式数据处理,内存效率高</li>
|
||||
* <li>包含总记录数,便于分页计算</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param <ENTITY> 实体类型
|
||||
* @param items 数据流,包含当前页的所有记录
|
||||
* @param total 总记录数,用于计算总页数和显示分页信息
|
||||
*/
|
||||
public record Page<ENTITY>(List<ENTITY> items, long total) {
|
||||
}
|
||||
@@ -1,195 +0,0 @@
|
||||
package com.lanyuanxiaoyao.service.template.common.entity;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 查询条件封装类,用于构建复杂的查询条件
|
||||
* <p>
|
||||
* 该类统一封装了查询条件、排序条件和分页条件,支持多种复杂的查询场景。
|
||||
* 通过JSON格式传递查询参数,后端自动解析并转换为数据库查询条件。
|
||||
* </p>
|
||||
*
|
||||
* <p>前端传入的JSON格式示例:</p>
|
||||
* <pre>
|
||||
* {
|
||||
* "query": {
|
||||
* "equal": {
|
||||
* "name": "张三"
|
||||
* },
|
||||
* "like": {
|
||||
* "address": "%北京%"
|
||||
* },
|
||||
* "greatEqual": {
|
||||
* "age": 18
|
||||
* },
|
||||
* "less": {
|
||||
* "age": 60
|
||||
* },
|
||||
* "between": {
|
||||
* "salary": {
|
||||
* "start": 5000,
|
||||
* "end": 10000
|
||||
* }
|
||||
* }
|
||||
* },
|
||||
* "sort": [
|
||||
* {
|
||||
* "column": "createTime",
|
||||
* "direction": "DESC"
|
||||
* }
|
||||
* ],
|
||||
* "page": {
|
||||
* "index": 0,
|
||||
* "size": 10
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p>查询条件说明:</p>
|
||||
* <ul>
|
||||
* <li><b>nullEqual</b>: 字段值为null的条件列表</li>
|
||||
* <li><b>notNullEqual</b>: 字段值不为null的条件列表</li>
|
||||
* <li><b>empty</b>: 字段值为空的条件列表(如空字符串、空集合等)</li>
|
||||
* <li><b>notEmpty</b>: 字段值不为空的条件列表</li>
|
||||
* <li><b>equal</b>: 字段值相等的条件映射(字段名 -> 值)</li>
|
||||
* <li><b>notEqual</b>: 字段值不相等的条件映射(字段名 -> 值)</li>
|
||||
* <li><b>like</b>: 字段值模糊匹配的条件映射(字段名 -> 匹配值)</li>
|
||||
* <li><b>notLike</b>: 字段值不模糊匹配的条件映射(字段名 -> 匹配值)</li>
|
||||
* <li><b>contain</b>: 字段包含指定字符串的条件映射(字段名 -> 包含值)</li>
|
||||
* <li><b>notContain</b>: 字段不包含指定字符串的条件映射(字段名 -> 不包含值)</li>
|
||||
* <li><b>startWith</b>: 字段以指定字符串开头的条件映射(字段名 -> 开头值)</li>
|
||||
* <li><b>notStartWith</b>: 字段不以指定字符串开头的条件映射(字段名 -> 不开头值)</li>
|
||||
* <li><b>endWith</b>: 字段以指定字符串结尾的条件映射(字段名 -> 结尾值)</li>
|
||||
* <li><b>notEndWith</b>: 字段不以指定字符串结尾的条件映射(字段名 -> 不结尾值)</li>
|
||||
* <li><b>great</b>: 字段大于条件的映射(字段名 -> 值)</li>
|
||||
* <li><b>less</b>: 字段小于条件的映射(字段名 -> 值)</li>
|
||||
* <li><b>greatEqual</b>: 字段大于等于条件的映射(字段名 -> 值)</li>
|
||||
* <li><b>lessEqual</b>: 字段小于等于条件的映射(字段名 -> 值)</li>
|
||||
* <li><b>inside</b>: 字段值在指定范围内的条件映射(字段名 -> 值列表)</li>
|
||||
* <li><b>notInside</b>: 字段值不在指定范围内的条件映射(字段名 -> 值列表)</li>
|
||||
* <li><b>between</b>: 字段值在指定区间内的条件映射(字段名 -> 区间范围)</li>
|
||||
* <li><b>notBetween</b>: 字段值不在指定区间内的条件映射(字段名 -> 区间范围)</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param query 查询条件对象,包含所有查询条件的封装
|
||||
* @param sort 排序条件列表,支持多字段排序
|
||||
* @param page 分页条件对象,指定页码和每页大小
|
||||
*/
|
||||
public record Query(
|
||||
Queryable query,
|
||||
List<Sortable> sort,
|
||||
Pageable page
|
||||
) {
|
||||
/**
|
||||
* 可查询条件类,封装各种查询条件
|
||||
* <p>
|
||||
* 该类包含了所有支持的查询条件类型,每个字段对应一种查询条件。
|
||||
* 字段名即为JSON中的键名,字段类型决定了查询条件的值类型。
|
||||
* </p>
|
||||
*
|
||||
* @param nullEqual 字段值为null的条件列表,列表中的每个元素都是一个字段名
|
||||
* @param notNullEqual 字段值不为null的条件列表,列表中的每个元素都是一个字段名
|
||||
* @param empty 字段值为空的条件列表(如空字符串、空集合等),列表中的每个元素都是一个字段名
|
||||
* @param notEmpty 字段值不为空的条件列表,列表中的每个元素都是一个字段名
|
||||
* @param equal 字段值相等的条件映射,键为字段名,值为要相等的值
|
||||
* @param notEqual 字段值不相等的条件映射,键为字段名,值为要不相等的值
|
||||
* @param like 字段值模糊匹配的条件映射,键为字段名,值为模糊匹配的模式(支持%通配符)
|
||||
* @param notLike 字段值不模糊匹配的条件映射,键为字段名,值为不匹配的模式
|
||||
* @param contain 字段包含指定字符串的条件映射,键为字段名,值为要包含的字符串
|
||||
* @param notContain 字段不包含指定字符串的条件映射,键为字段名,值为不包含的字符串
|
||||
* @param startWith 字段以指定字符串开头的条件映射,键为字段名,值为开头字符串
|
||||
* @param notStartWith 字段不以指定字符串开头的条件映射,键为字段名,值为不开头的字符串
|
||||
* @param endWith 字段以指定字符串结尾的条件映射,键为字段名,值为结尾字符串
|
||||
* @param notEndWith 字段不以指定字符串结尾的条件映射,键为字段名,值为不结尾的字符串
|
||||
* @param great 字段大于条件的映射,键为字段名,值为比较的阈值
|
||||
* @param less 字段小于条件的映射,键为字段名,值为比较的阈值
|
||||
* @param greatEqual 字段大于等于条件的映射,键为字段名,值为比较的阈值
|
||||
* @param lessEqual 字段小于等于条件的映射,键为字段名,值为比较的阈值
|
||||
* @param inside 字段值在指定范围内的条件映射,键为字段名,值为允许的值列表
|
||||
* @param notInside 字段值不在指定范围内的条件映射,键为字段名,值为不允许的值列表
|
||||
* @param between 字段值在指定区间内的条件映射,键为字段名,值为区间范围对象
|
||||
* @param notBetween 字段值不在指定区间内的条件映射,键为字段名,值为区间范围对象
|
||||
*/
|
||||
public record Queryable(
|
||||
List<String> nullEqual,
|
||||
List<String> notNullEqual,
|
||||
List<String> empty,
|
||||
List<String> notEmpty,
|
||||
Map<String, ? extends Serializable> equal,
|
||||
Map<String, ? extends Serializable> notEqual,
|
||||
Map<String, String> like,
|
||||
Map<String, String> notLike,
|
||||
Map<String, String> contain,
|
||||
Map<String, String> notContain,
|
||||
Map<String, String> startWith,
|
||||
Map<String, String> notStartWith,
|
||||
Map<String, String> endWith,
|
||||
Map<String, String> notEndWith,
|
||||
Map<String, ? extends Serializable> great,
|
||||
Map<String, ? extends Serializable> less,
|
||||
Map<String, ? extends Serializable> greatEqual,
|
||||
Map<String, ? extends Serializable> lessEqual,
|
||||
Map<String, List<? extends Serializable>> inside,
|
||||
Map<String, List<? extends Serializable>> notInside,
|
||||
Map<String, Between> between,
|
||||
Map<String, Between> notBetween
|
||||
) {
|
||||
/**
|
||||
* 区间范围类,用于表示起始值和结束值
|
||||
* <p>
|
||||
* 主要用于 between 和 notBetween 查询条件,表示一个数值或时间的区间范围。
|
||||
* </p>
|
||||
*
|
||||
* @param start 区间起始值(包含)
|
||||
* @param end 区间结束值(包含)
|
||||
*/
|
||||
public record Between(
|
||||
Object start,
|
||||
Object end
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 排序条件类,用于指定排序字段和排序方向
|
||||
*
|
||||
* @param column 排序字段名,对应数据库表的列名或实体类的属性名
|
||||
* @param direction 排序方向,ASC表示升序,DESC表示降序
|
||||
*/
|
||||
public record Sortable(
|
||||
String column,
|
||||
Direction direction
|
||||
) {
|
||||
/**
|
||||
* 排序方向枚举
|
||||
*/
|
||||
public enum Direction {
|
||||
/**
|
||||
* 升序排列(从小到大)
|
||||
*/
|
||||
ASC,
|
||||
/**
|
||||
* 降序排列(从大到小)
|
||||
*/
|
||||
DESC,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 可分页条件类,用于指定分页参数
|
||||
* <p>
|
||||
* 页码从0开始计数,即第一页的索引为0。
|
||||
* </p>
|
||||
*
|
||||
* @param index 页码索引,从0开始(0表示第一页)
|
||||
* @param size 每页大小,即每页显示的记录数
|
||||
*/
|
||||
public record Pageable(
|
||||
Integer index,
|
||||
Integer size
|
||||
) {
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
package com.lanyuanxiaoyao.service.template.common.exception;
|
||||
|
||||
public class IdNotFoundException extends RuntimeException {
|
||||
public IdNotFoundException(Long id) {
|
||||
super("ID为 %d 的资源不存在".formatted(id));
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
package com.lanyuanxiaoyao.service.template.common.exception;
|
||||
|
||||
public class NotCollectionException extends RuntimeException {
|
||||
public NotCollectionException(String variable) {
|
||||
super("变量 %s 不是集合".formatted(variable));
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
package com.lanyuanxiaoyao.service.template.common.exception;
|
||||
|
||||
public class NotComparableException extends RuntimeException {
|
||||
public NotComparableException(String variable) {
|
||||
super("变量 %s 不能比较".formatted(variable));
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
package com.lanyuanxiaoyao.service.template.common.exception;
|
||||
|
||||
public class NotStringException extends RuntimeException {
|
||||
public NotStringException(String variable) {
|
||||
super("变量 %s 不是字符串".formatted(variable));
|
||||
}
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
package com.lanyuanxiaoyao.service.template.common.helper;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
public class SnowflakeHelper {
|
||||
/**
|
||||
* 起始的时间戳
|
||||
*/
|
||||
private final static long START_TIMESTAMP = 1;
|
||||
|
||||
/**
|
||||
* 序列号占用的位数
|
||||
*/
|
||||
private final static long SEQUENCE_BIT = 11;
|
||||
|
||||
/**
|
||||
* 序列号最大值
|
||||
*/
|
||||
private final static long MAX_SEQUENCE_BIT = ~(-1 << SEQUENCE_BIT);
|
||||
|
||||
/**
|
||||
* 时间戳值向左位移
|
||||
*/
|
||||
private final static long TIMESTAMP_OFFSET = SEQUENCE_BIT;
|
||||
|
||||
/**
|
||||
* 序列号
|
||||
*/
|
||||
private static long sequence = 0;
|
||||
/**
|
||||
* 上一次时间戳
|
||||
*/
|
||||
private static long lastTimestamp = -1;
|
||||
|
||||
public static synchronized long next() {
|
||||
long currentTimestamp = nowTimestamp();
|
||||
if (currentTimestamp < lastTimestamp) {
|
||||
throw new RuntimeException("Clock have moved backwards.");
|
||||
}
|
||||
|
||||
if (currentTimestamp == lastTimestamp) {
|
||||
// 相同毫秒内, 序列号自增
|
||||
sequence = (sequence + 1) & MAX_SEQUENCE_BIT;
|
||||
// 同一毫秒的序列数已经达到最大
|
||||
if (sequence == 0) {
|
||||
currentTimestamp = nextTimestamp();
|
||||
}
|
||||
} else {
|
||||
// 不同毫秒内, 序列号置为0
|
||||
sequence = 0;
|
||||
}
|
||||
|
||||
lastTimestamp = currentTimestamp;
|
||||
return (currentTimestamp - START_TIMESTAMP) << TIMESTAMP_OFFSET | sequence;
|
||||
}
|
||||
|
||||
private static long nextTimestamp() {
|
||||
long milli = nowTimestamp();
|
||||
while (milli <= lastTimestamp) {
|
||||
milli = nowTimestamp();
|
||||
}
|
||||
return milli;
|
||||
}
|
||||
|
||||
private static long nowTimestamp() {
|
||||
return Instant.now().toEpochMilli();
|
||||
}
|
||||
}
|
||||
@@ -1,125 +0,0 @@
|
||||
package com.lanyuanxiaoyao.service.template.common.service;
|
||||
|
||||
import com.lanyuanxiaoyao.service.template.common.entity.Query;
|
||||
import com.lanyuanxiaoyao.service.template.common.helper.ObjectHelper;
|
||||
|
||||
public abstract class QueryParser<O> {
|
||||
protected abstract void nullEqual(Query.Queryable queryable);
|
||||
|
||||
protected abstract void notNullEqual(Query.Queryable queryable);
|
||||
|
||||
protected abstract void empty(Query.Queryable queryable);
|
||||
|
||||
protected abstract void notEmpty(Query.Queryable queryable);
|
||||
|
||||
protected abstract void equal(Query.Queryable queryable);
|
||||
|
||||
protected abstract void notEqual(Query.Queryable queryable);
|
||||
|
||||
protected abstract void like(Query.Queryable queryable);
|
||||
|
||||
protected abstract void notLike(Query.Queryable queryable);
|
||||
|
||||
protected abstract void contain(Query.Queryable queryable);
|
||||
|
||||
protected abstract void notContain(Query.Queryable queryable);
|
||||
|
||||
protected abstract void startWith(Query.Queryable queryable);
|
||||
|
||||
protected abstract void notStartWith(Query.Queryable queryable);
|
||||
|
||||
protected abstract void endWith(Query.Queryable queryable);
|
||||
|
||||
protected abstract void notEndWith(Query.Queryable queryable);
|
||||
|
||||
protected abstract void great(Query.Queryable queryable);
|
||||
|
||||
protected abstract void less(Query.Queryable queryable);
|
||||
|
||||
protected abstract void greatEqual(Query.Queryable queryable);
|
||||
|
||||
protected abstract void lessEqual(Query.Queryable queryable);
|
||||
|
||||
protected abstract void inside(Query.Queryable queryable);
|
||||
|
||||
protected abstract void notInside(Query.Queryable queryable);
|
||||
|
||||
protected abstract void between(Query.Queryable queryable);
|
||||
|
||||
protected abstract void notBetween(Query.Queryable queryable);
|
||||
|
||||
protected abstract O build();
|
||||
|
||||
public O build(Query.Queryable queryable) {
|
||||
if (ObjectHelper.isNull(queryable)) {
|
||||
return null;
|
||||
}
|
||||
if (ObjectHelper.isNotEmpty(queryable.nullEqual())) {
|
||||
nullEqual(queryable);
|
||||
}
|
||||
if (ObjectHelper.isNotEmpty(queryable.notNullEqual())) {
|
||||
notNullEqual(queryable);
|
||||
}
|
||||
if (ObjectHelper.isNotEmpty(queryable.empty())) {
|
||||
empty(queryable);
|
||||
}
|
||||
if (ObjectHelper.isNotEmpty(queryable.notEmpty())) {
|
||||
notEmpty(queryable);
|
||||
}
|
||||
if (ObjectHelper.isNotEmpty(queryable.equal())) {
|
||||
equal(queryable);
|
||||
}
|
||||
if (ObjectHelper.isNotEmpty(queryable.notEqual())) {
|
||||
notEqual(queryable);
|
||||
}
|
||||
if (ObjectHelper.isNotEmpty(queryable.like())) {
|
||||
like(queryable);
|
||||
}
|
||||
if (ObjectHelper.isNotEmpty(queryable.notLike())) {
|
||||
notLike(queryable);
|
||||
}
|
||||
if (ObjectHelper.isNotEmpty(queryable.contain())) {
|
||||
contain(queryable);
|
||||
}
|
||||
if (ObjectHelper.isNotEmpty(queryable.notContain())) {
|
||||
notContain(queryable);
|
||||
}
|
||||
if (ObjectHelper.isNotEmpty(queryable.startWith())) {
|
||||
startWith(queryable);
|
||||
}
|
||||
if (ObjectHelper.isNotEmpty(queryable.notStartWith())) {
|
||||
notStartWith(queryable);
|
||||
}
|
||||
if (ObjectHelper.isNotEmpty(queryable.endWith())) {
|
||||
endWith(queryable);
|
||||
}
|
||||
if (ObjectHelper.isNotEmpty(queryable.notEndWith())) {
|
||||
notEndWith(queryable);
|
||||
}
|
||||
if (ObjectHelper.isNotEmpty(queryable.great())) {
|
||||
great(queryable);
|
||||
}
|
||||
if (ObjectHelper.isNotEmpty(queryable.less())) {
|
||||
less(queryable);
|
||||
}
|
||||
if (ObjectHelper.isNotEmpty(queryable.greatEqual())) {
|
||||
greatEqual(queryable);
|
||||
}
|
||||
if (ObjectHelper.isNotEmpty(queryable.lessEqual())) {
|
||||
lessEqual(queryable);
|
||||
}
|
||||
if (ObjectHelper.isNotEmpty(queryable.inside())) {
|
||||
inside(queryable);
|
||||
}
|
||||
if (ObjectHelper.isNotEmpty(queryable.notInside())) {
|
||||
notInside(queryable);
|
||||
}
|
||||
if (ObjectHelper.isNotEmpty(queryable.between())) {
|
||||
between(queryable);
|
||||
}
|
||||
if (ObjectHelper.isNotEmpty(queryable.notBetween())) {
|
||||
notBetween(queryable);
|
||||
}
|
||||
return build();
|
||||
}
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
package com.lanyuanxiaoyao.service.template.common.service;
|
||||
|
||||
import com.lanyuanxiaoyao.service.template.common.entity.Page;
|
||||
import com.lanyuanxiaoyao.service.template.common.entity.Query;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 查询服务接口,用于定义统一的查询实体详情和列表的服务规范
|
||||
* <p>
|
||||
* 该接口提供了标准的查询功能,支持详情查询、列表查询、分页查询和统计查询。
|
||||
* 所有实现类应当遵循统一的查询逻辑和异常处理规范。
|
||||
* </p>
|
||||
*
|
||||
* @param <ENTITY> 实体类型
|
||||
*/
|
||||
public interface QueryService<ENTITY> {
|
||||
|
||||
/**
|
||||
* 根据ID获取实体详情
|
||||
* <p>
|
||||
* 查询单条记录的详细信息,如果记录不存在返回null。
|
||||
* </p>
|
||||
*
|
||||
* @param id 实体主键ID
|
||||
* @return 实体详情,如果不存在则返回null
|
||||
* @throws Exception 查询过程中可能抛出的异常
|
||||
*/
|
||||
ENTITY detail(Long id) throws Exception;
|
||||
|
||||
/**
|
||||
* 根据ID获取实体详情,如果不存在则抛出异常
|
||||
* <p>
|
||||
* 查询单条记录的详细信息,如果记录不存在则抛出异常。
|
||||
* 适用于需要确保记录存在的场景。
|
||||
* </p>
|
||||
*
|
||||
* @param id 实体主键ID
|
||||
* @return 实体详情
|
||||
* @throws Exception 当记录不存在或查询失败时抛出异常
|
||||
*/
|
||||
ENTITY detailOrThrow(Long id) throws Exception;
|
||||
|
||||
/**
|
||||
* 获取实体总数
|
||||
* <p>
|
||||
* 统计所有记录的数量,不带任何过滤条件。
|
||||
* </p>
|
||||
*
|
||||
* @return 实体总数
|
||||
* @throws Exception 查询过程中可能抛出的异常
|
||||
*/
|
||||
Long count() throws Exception;
|
||||
|
||||
/**
|
||||
* 获取所有实体列表
|
||||
* <p>
|
||||
* 查询所有记录,不带任何过滤条件,返回完整列表。
|
||||
* 适用于数据量较小或需要全量数据的场景。
|
||||
* </p>
|
||||
*
|
||||
* @return 实体列表
|
||||
* @throws Exception 查询过程中可能抛出的异常
|
||||
*/
|
||||
List<ENTITY> list() throws Exception;
|
||||
|
||||
/**
|
||||
* 根据ID集合获取实体列表
|
||||
* <p>
|
||||
* 批量查询指定ID的记录,返回对应的实体列表。
|
||||
* 适用于需要批量获取特定记录的场景。
|
||||
* </p>
|
||||
*
|
||||
* @param ids 实体ID集合
|
||||
* @return 实体列表,包含集合中ID对应的记录
|
||||
* @throws Exception 查询过程中可能抛出的异常
|
||||
*/
|
||||
List<ENTITY> list(Set<Long> ids) throws Exception;
|
||||
|
||||
/**
|
||||
* 根据查询条件获取分页实体列表
|
||||
* <p>
|
||||
* 支持复杂的查询条件、排序和分页,返回符合条件的数据。
|
||||
* 这是最完整的查询方法,适用于大多数业务场景。
|
||||
* </p>
|
||||
*
|
||||
* @param query 查询条件对象,包含过滤条件、排序规则和分页信息
|
||||
* @return 分页实体列表,包含数据流和总记录数
|
||||
* @throws Exception 查询过程中可能抛出的异常
|
||||
*/
|
||||
Page<ENTITY> list(Query query) throws Exception;
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package com.lanyuanxiaoyao.service.template.common.service;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 删除服务接口,用于定义统一的删除实体对象的服务规范
|
||||
* <p>
|
||||
* 该接口提供了标准的删除功能,支持单条记录删除和批量删除。
|
||||
* 所有实现类应当遵循统一的删除逻辑和异常处理规范。
|
||||
* </p>
|
||||
*
|
||||
* @param <ENTITY> 实体类型
|
||||
*/
|
||||
public interface RemoveService<ENTITY> {
|
||||
|
||||
/**
|
||||
* 根据ID删除实体对象
|
||||
* <p>
|
||||
* 删除指定ID的单条记录,执行成功后无返回值。
|
||||
* 适用于单条记录删除的场景。
|
||||
* </p>
|
||||
*
|
||||
* @param id 需要删除的实体主键ID
|
||||
* @throws Exception 删除过程中可能抛出的异常
|
||||
*/
|
||||
void remove(Long id) throws Exception;
|
||||
|
||||
/**
|
||||
* 批量删除实体对象
|
||||
* <p>
|
||||
* 删除指定ID集合的多条记录,执行成功后无返回值。
|
||||
* 适用于批量删除的场景,提高删除效率。
|
||||
* </p>
|
||||
*
|
||||
* @param ids 需要删除的实体ID集合
|
||||
* @throws Exception 删除过程中可能抛出的异常
|
||||
*/
|
||||
void remove(Set<Long> ids) throws Exception;
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
package com.lanyuanxiaoyao.service.template.common.service;
|
||||
|
||||
/**
|
||||
* 保存服务接口,用于定义统一的保存实体对象的服务规范
|
||||
* <p>
|
||||
* 该接口提供了标准的保存功能,支持单条记录保存和批量保存。
|
||||
* 所有实现类应当遵循统一的保存逻辑和异常处理规范。
|
||||
* </p>
|
||||
*
|
||||
* @param <ENTITY> 实体类型
|
||||
*/
|
||||
public interface SaveService<ENTITY> {
|
||||
|
||||
/**
|
||||
* 保存实体对象
|
||||
* <p>
|
||||
* 保存或更新单条实体记录,根据业务逻辑判断是新增还是更新操作。
|
||||
* 返回保存后的实体ID,便于后续操作。
|
||||
* </p>
|
||||
*
|
||||
* @param entity 需要保存的实体对象,包含完整的字段信息
|
||||
* @return 保存后的实体主键ID
|
||||
* @throws Exception 保存过程中可能抛出的异常
|
||||
*/
|
||||
Long save(ENTITY entity) throws Exception;
|
||||
|
||||
/**
|
||||
* 批量保存实体对象
|
||||
* <p>
|
||||
* 批量保存或更新多条实体记录,提高数据处理效率。
|
||||
* 适用于批量数据导入或同步的场景。
|
||||
* </p>
|
||||
*
|
||||
* @param entities 需要保存的实体对象集合
|
||||
* @throws Exception 保存过程中可能抛出的异常
|
||||
*/
|
||||
void save(Iterable<ENTITY> entities) throws Exception;
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
package com.lanyuanxiaoyao.service.template.common.service;
|
||||
|
||||
public interface SimpleService<ENTITY> extends SaveService<ENTITY>, QueryService<ENTITY>, RemoveService<ENTITY> {
|
||||
}
|
||||
Reference in New Issue
Block a user