From 6baefd1a8aa4f1f0154a71e9241e6c5800a7e59b Mon Sep 17 00:00:00 2001 From: lanyuanxiaoyao Date: Thu, 21 Aug 2025 10:36:21 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BC=98=E5=8C=96Global=E8=BF=94?= =?UTF-8?q?=E5=9B=9E=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../template/controller/DetailController.java | 20 +- .../template/controller/GlobalResponse.java | 77 ++ .../template/controller/ListController.java | 34 +- .../service/template/controller/Query.java | 264 ++-- .../template/controller/RemoveController.java | 20 +- .../template/controller/SaveController.java | 20 +- .../controller/SimpleControllerSupport.java | 251 ++-- .../response/GlobalCrudResponse.java | 24 - .../response/GlobalDetailResponse.java | 7 - .../response/GlobalMapResponse.java | 15 - .../controller/response/GlobalResponse.java | 105 -- .../service/template/entity/IdOnlyEntity.java | 20 +- .../service/template/entity/SimpleEntity.java | 38 +- .../service/template/helper/ObjectHelper.java | 176 +-- .../template/repository/SimpleRepository.java | 2 +- .../template/service/SimpleService.java | 20 +- .../service/SimpleServiceSupport.java | 1080 ++++++++--------- .../service/template/TestApplication.java | 278 ++--- .../controller/CompanyController.java | 126 +- .../controller/EmployeeController.java | 148 +-- .../service/template/entity/Company.java | 18 +- .../service/template/entity/Employee.java | 38 +- .../repository/EmployeeRepository.java | 6 +- .../template/service/CompanyService.java | 6 +- .../template/service/EmployeeService.java | 6 +- 25 files changed, 1359 insertions(+), 1440 deletions(-) create mode 100644 src/main/java/com/lanyuanxiaoyao/service/template/controller/GlobalResponse.java delete mode 100644 src/main/java/com/lanyuanxiaoyao/service/template/controller/response/GlobalCrudResponse.java delete mode 100644 src/main/java/com/lanyuanxiaoyao/service/template/controller/response/GlobalDetailResponse.java delete mode 100644 src/main/java/com/lanyuanxiaoyao/service/template/controller/response/GlobalMapResponse.java delete mode 100644 src/main/java/com/lanyuanxiaoyao/service/template/controller/response/GlobalResponse.java diff --git a/src/main/java/com/lanyuanxiaoyao/service/template/controller/DetailController.java b/src/main/java/com/lanyuanxiaoyao/service/template/controller/DetailController.java index b51060c..3adfd16 100644 --- a/src/main/java/com/lanyuanxiaoyao/service/template/controller/DetailController.java +++ b/src/main/java/com/lanyuanxiaoyao/service/template/controller/DetailController.java @@ -1,7 +1,5 @@ package com.lanyuanxiaoyao.service.template.controller; -import com.lanyuanxiaoyao.service.template.controller.response.GlobalResponse; - /** * 详情控制器接口,用于定义统一的获取实体详情的接口规范 * @@ -16,14 +14,14 @@ import com.lanyuanxiaoyao.service.template.controller.response.GlobalResponse; * @author lanyuanxiaoyao */ public interface DetailController { - String DETAIL = "/detail/{id}"; + String DETAIL = "/detail/{id}"; - /** - * 根据ID获取实体详情 - * - * @param id 实体ID - * @return GlobalResponse 返回实体详情 - * @throws Exception 查询过程中可能抛出的异常 - */ - GlobalResponse detail(Long id) throws Exception; + /** + * 根据ID获取实体详情 + * + * @param id 实体ID + * @return GlobalResponse 返回实体详情 + * @throws Exception 查询过程中可能抛出的异常 + */ + GlobalResponse detail(Long id) throws Exception; } \ No newline at end of file diff --git a/src/main/java/com/lanyuanxiaoyao/service/template/controller/GlobalResponse.java b/src/main/java/com/lanyuanxiaoyao/service/template/controller/GlobalResponse.java new file mode 100644 index 0000000..e1575fe --- /dev/null +++ b/src/main/java/com/lanyuanxiaoyao/service/template/controller/GlobalResponse.java @@ -0,0 +1,77 @@ +package com.lanyuanxiaoyao.service.template.controller; + +import java.util.Map; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +@Setter +@Getter +@ToString +public class GlobalResponse { + 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"; + private Integer status; + private String message; + private T data; + + private GlobalResponse() { + this(SUCCESS_STATUS, SUCCESS_MESSAGE, null); + } + + private GlobalResponse(Integer status, String message) { + this(status, message, null); + } + + private GlobalResponse(Integer status, String message, T data) { + this.status = status; + this.message = message; + this.data = data; + } + + public static GlobalResponse responseError() { + return responseError(ERROR_MESSAGE); + } + + public static GlobalResponse responseError(String message) { + return new GlobalResponse<>(ERROR_STATUS, message); + } + + public static GlobalResponse responseSuccess() { + return responseSuccess(SUCCESS_MESSAGE); + } + + public static GlobalResponse responseSuccess(String message) { + return responseSuccess(message, null); + } + + public static GlobalResponse responseSuccess(E data) { + return responseSuccess(SUCCESS_MESSAGE, data); + } + + public static GlobalResponse responseSuccess(String message, E data) { + return new GlobalResponse<>(SUCCESS_STATUS, message, data); + } + + public static GlobalResponse> responseMapData(Map data) { + return responseSuccess(data); + } + + public static GlobalResponse> responseMapData(String key, Object value) { + return responseMapData(Map.of(key, value)); + } + + public static GlobalResponse> responseCrudData(Iterable data, Integer total) { + return responseCrudData(data, total.longValue()); + } + + public static GlobalResponse> responseCrudData(Iterable data, Long total) { + return responseMapData(Map.of("items", data, "total", total)); + } + + public static GlobalResponse> responseDetailData(Object detail) { + return responseMapData("detail", detail); + } +} diff --git a/src/main/java/com/lanyuanxiaoyao/service/template/controller/ListController.java b/src/main/java/com/lanyuanxiaoyao/service/template/controller/ListController.java index bd2e9ad..e0f97fe 100644 --- a/src/main/java/com/lanyuanxiaoyao/service/template/controller/ListController.java +++ b/src/main/java/com/lanyuanxiaoyao/service/template/controller/ListController.java @@ -1,6 +1,6 @@ package com.lanyuanxiaoyao.service.template.controller; -import com.lanyuanxiaoyao.service.template.controller.response.GlobalCrudResponse; +import java.util.Map; /** * 列表控制器接口,用于定义统一的获取实体列表的接口规范 @@ -57,22 +57,22 @@ import com.lanyuanxiaoyao.service.template.controller.response.GlobalCrudRespons * @author lanyuanxiaoyao */ public interface ListController { - String LIST = "/list"; + String LIST = "/list"; - /** - * 获取所有实体列表 - * - * @return GlobalCrudResponse 返回实体列表 - * @throws Exception 查询过程中可能抛出的异常 - */ - GlobalCrudResponse list() throws Exception; + /** + * 获取所有实体列表 + * + * @return GlobalCrudResponse 返回实体列表 + * @throws Exception 查询过程中可能抛出的异常 + */ + GlobalResponse> list() throws Exception; - /** - * 根据查询条件获取实体列表 - * - * @param query 查询条件对象 - * @return GlobalCrudResponse 返回符合条件的实体列表 - * @throws Exception 查询过程中可能抛出的异常 - */ - GlobalCrudResponse list(Query query) throws Exception; + /** + * 根据查询条件获取实体列表 + * + * @param query 查询条件对象 + * @return GlobalCrudResponse 返回符合条件的实体列表 + * @throws Exception 查询过程中可能抛出的异常 + */ + GlobalResponse> list(Query query) throws Exception; } \ No newline at end of file diff --git a/src/main/java/com/lanyuanxiaoyao/service/template/controller/Query.java b/src/main/java/com/lanyuanxiaoyao/service/template/controller/Query.java index a013dad..7537b98 100644 --- a/src/main/java/com/lanyuanxiaoyao/service/template/controller/Query.java +++ b/src/main/java/com/lanyuanxiaoyao/service/template/controller/Query.java @@ -9,7 +9,7 @@ import lombok.ToString; /** * 查询条件封装类,用于构建复杂的查询条件 * 包含查询条件、排序条件和分页条件 - * + * *

前端传入的JSON格式示例:

*
  * {
@@ -45,7 +45,7 @@ import lombok.ToString;
  *   }
  * }
  * 
- * + * *

查询条件说明:

*
    *
  • nullEqual: 字段值为null的条件
  • @@ -70,154 +70,154 @@ import lombok.ToString; @Getter @ToString public class Query { + /** + * 查询条件 + */ + private Queryable query; + /** + * 排序条件列表 + */ + private List sort; + /** + * 分页条件 + */ + private Pageable page; + + /** + * 可查询条件类,封装各种查询条件 + */ + @Setter + @Getter + @ToString + public static class Queryable { /** - * 查询条件 + * 指定字段值为null的条件列表 */ - private Queryable query; + private List nullEqual; /** - * 排序条件列表 + * 指定字段值不为null的条件列表 */ - private List sort; + private List notNullEqual; /** - * 分页条件 + * 指定字段值为空的条件列表(如空字符串、空集合等) */ - private Pageable page; + private List empty; + /** + * 指定字段值不为空的条件列表 + */ + private List notEmpty; + /** + * 指定字段值相等的条件映射(字段名 -> 值) + */ + private Map equal; + /** + * 指定字段值不相等的条件映射(字段名 -> 值) + */ + private Map notEqual; + /** + * 指定字段模糊匹配的条件映射(字段名 -> 匹配值) + */ + private Map like; + /** + * 指定字段不模糊匹配的条件映射(字段名 -> 匹配值) + */ + private Map notLike; + /** + * 指定字段大于条件的映射(字段名 -> 值) + */ + private Map great; + /** + * 指定字段小于条件的映射(字段名 -> 值) + */ + private Map less; + /** + * 指定字段大于等于条件的映射(字段名 -> 值) + */ + private Map greatEqual; + /** + * 指定字段小于等于条件的映射(字段名 -> 值) + */ + private Map lessEqual; + /** + * 指定字段值在指定范围内的条件映射(字段名 -> 值列表) + */ + private Map> in; + /** + * 指定字段值不在指定范围内的条件映射(字段名 -> 值列表) + */ + private Map> notIn; + /** + * 指定字段值在指定区间内的条件映射(字段名 -> 区间范围) + */ + private Map between; + /** + * 指定字段值不在指定区间内的条件映射(字段名 -> 区间范围) + */ + private Map notBetween; /** - * 可查询条件类,封装各种查询条件 + * 区间范围类,用于表示起始值和结束值 */ @Setter @Getter @ToString - public static class Queryable { - /** - * 指定字段值为null的条件列表 - */ - private List nullEqual; - /** - * 指定字段值不为null的条件列表 - */ - private List notNullEqual; - /** - * 指定字段值为空的条件列表(如空字符串、空集合等) - */ - private List empty; - /** - * 指定字段值不为空的条件列表 - */ - private List notEmpty; - /** - * 指定字段值相等的条件映射(字段名 -> 值) - */ - private Map equal; - /** - * 指定字段值不相等的条件映射(字段名 -> 值) - */ - private Map notEqual; - /** - * 指定字段模糊匹配的条件映射(字段名 -> 匹配值) - */ - private Map like; - /** - * 指定字段不模糊匹配的条件映射(字段名 -> 匹配值) - */ - private Map notLike; - /** - * 指定字段大于条件的映射(字段名 -> 值) - */ - private Map great; - /** - * 指定字段小于条件的映射(字段名 -> 值) - */ - private Map less; - /** - * 指定字段大于等于条件的映射(字段名 -> 值) - */ - private Map greatEqual; - /** - * 指定字段小于等于条件的映射(字段名 -> 值) - */ - private Map lessEqual; - /** - * 指定字段值在指定范围内的条件映射(字段名 -> 值列表) - */ - private Map> in; - /** - * 指定字段值不在指定范围内的条件映射(字段名 -> 值列表) - */ - private Map> notIn; - /** - * 指定字段值在指定区间内的条件映射(字段名 -> 区间范围) - */ - private Map between; - /** - * 指定字段值不在指定区间内的条件映射(字段名 -> 区间范围) - */ - private Map notBetween; - - /** - * 区间范围类,用于表示起始值和结束值 - */ - @Setter - @Getter - @ToString - public static class Between { - /** - * 起始值 - */ - private Object start; - /** - * 结束值 - */ - private Object end; - } + public static class Between { + /** + * 起始值 + */ + private Object start; + /** + * 结束值 + */ + private Object end; } + } + + /** + * 可排序条件类,用于指定排序字段和排序方向 + */ + @Setter + @Getter + @ToString + public static class Sortable { + /** + * 排序字段名 + */ + private String column; + /** + * 排序方向 + */ + private Direction direction; /** - * 可排序条件类,用于指定排序字段和排序方向 + * 排序方向枚举 */ - @Setter - @Getter - @ToString - public static class Sortable { - /** - * 排序字段名 - */ - private String column; - /** - * 排序方向 - */ - private Direction direction; - - /** - * 排序方向枚举 - */ - public enum Direction { - /** - * 升序排列 - */ - ASC, - /** - * 降序排列 - */ - DESC, - } + public enum Direction { + /** + * 升序排列 + */ + ASC, + /** + * 降序排列 + */ + DESC, } + } + /** + * 可分页条件类,用于指定分页参数 + */ + @Setter + @Getter + @ToString + public static class Pageable { /** - * 可分页条件类,用于指定分页参数 + * 页码索引(从0开始) */ - @Setter - @Getter - @ToString - public static class Pageable { - /** - * 页码索引(从0开始) - */ - private Integer index; - /** - * 每页大小 - */ - private Integer size; - } + private Integer index; + /** + * 每页大小 + */ + private Integer size; + } } \ No newline at end of file diff --git a/src/main/java/com/lanyuanxiaoyao/service/template/controller/RemoveController.java b/src/main/java/com/lanyuanxiaoyao/service/template/controller/RemoveController.java index a8c5289..6ef5007 100644 --- a/src/main/java/com/lanyuanxiaoyao/service/template/controller/RemoveController.java +++ b/src/main/java/com/lanyuanxiaoyao/service/template/controller/RemoveController.java @@ -1,7 +1,5 @@ package com.lanyuanxiaoyao.service.template.controller; -import com.lanyuanxiaoyao.service.template.controller.response.GlobalResponse; - /** * 删除控制器接口,用于定义统一的删除实体对象的接口规范 * @@ -15,14 +13,14 @@ import com.lanyuanxiaoyao.service.template.controller.response.GlobalResponse; * @author lanyuanxiaoyao */ public interface RemoveController { - String REMOVE = "/remove/{id}"; + String REMOVE = "/remove/{id}"; - /** - * 根据ID删除实体对象 - * - * @param id 需要删除的实体ID - * @return GlobalResponse 返回删除结果 - * @throws Exception 删除过程中可能抛出的异常 - */ - GlobalResponse remove(Long id) throws Exception; + /** + * 根据ID删除实体对象 + * + * @param id 需要删除的实体ID + * @return GlobalResponse 返回删除结果 + * @throws Exception 删除过程中可能抛出的异常 + */ + GlobalResponse remove(Long id) throws Exception; } \ No newline at end of file diff --git a/src/main/java/com/lanyuanxiaoyao/service/template/controller/SaveController.java b/src/main/java/com/lanyuanxiaoyao/service/template/controller/SaveController.java index 4f5e454..e6e4291 100644 --- a/src/main/java/com/lanyuanxiaoyao/service/template/controller/SaveController.java +++ b/src/main/java/com/lanyuanxiaoyao/service/template/controller/SaveController.java @@ -1,7 +1,5 @@ package com.lanyuanxiaoyao.service.template.controller; -import com.lanyuanxiaoyao.service.template.controller.response.GlobalResponse; - /** * 保存控制器接口,用于定义统一的保存实体对象的接口规范 * @@ -19,14 +17,14 @@ import com.lanyuanxiaoyao.service.template.controller.response.GlobalResponse; * @author lanyuanxiaoyao */ public interface SaveController { - String SAVE = "/save"; + String SAVE = "/save"; - /** - * 保存实体对象 - * - * @param item 需要保存的实体对象 - * @return GlobalResponse 返回保存后的实体ID - * @throws Exception 保存过程中可能抛出的异常 - */ - GlobalResponse save(SAVE_ITEM item) throws Exception; + /** + * 保存实体对象 + * + * @param item 需要保存的实体对象 + * @return GlobalResponse 返回保存后的实体ID + * @throws Exception 保存过程中可能抛出的异常 + */ + GlobalResponse save(SAVE_ITEM item) throws Exception; } \ No newline at end of file diff --git a/src/main/java/com/lanyuanxiaoyao/service/template/controller/SimpleControllerSupport.java b/src/main/java/com/lanyuanxiaoyao/service/template/controller/SimpleControllerSupport.java index 5863fa6..acd41a8 100644 --- a/src/main/java/com/lanyuanxiaoyao/service/template/controller/SimpleControllerSupport.java +++ b/src/main/java/com/lanyuanxiaoyao/service/template/controller/SimpleControllerSupport.java @@ -1,11 +1,10 @@ package com.lanyuanxiaoyao.service.template.controller; -import com.lanyuanxiaoyao.service.template.controller.response.GlobalCrudResponse; -import com.lanyuanxiaoyao.service.template.controller.response.GlobalResponse; import com.lanyuanxiaoyao.service.template.entity.SimpleEntity; import com.lanyuanxiaoyao.service.template.helper.ObjectHelper; import com.lanyuanxiaoyao.service.template.service.SimpleServiceSupport; import java.util.List; +import java.util.Map; import java.util.function.Function; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.GetMapping; @@ -87,140 +86,140 @@ import org.springframework.web.bind.annotation.RequestBody; * *

    * - * @param 实体类型,必须继承SimpleEntity - * @param 保存项类型 - * @param 列表项类型 + * @param 实体类型,必须继承SimpleEntity + * @param 保存项类型 + * @param 列表项类型 * @param 详情项类型 * @author lanyuanxiaoyao */ @Slf4j public abstract class SimpleControllerSupport implements SimpleController { - protected final SimpleServiceSupport service; + protected final SimpleServiceSupport service; - /** - * 构造函数 - * - * @param service 简单服务支持类实例 - */ - public SimpleControllerSupport(SimpleServiceSupport service) { - this.service = service; + /** + * 构造函数 + * + * @param service 简单服务支持类实例 + */ + public SimpleControllerSupport(SimpleServiceSupport service) { + this.service = service; + } + + /** + * 保存实体对象 + * + * @param item 需要保存的项 + * @return GlobalResponse 返回保存后的实体ID + * @throws Exception 保存过程中可能抛出的异常 + */ + @PostMapping(SAVE) + @Override + public GlobalResponse save(@RequestBody SAVE_ITEM item) throws Exception { + var mapper = saveItemMapper(); + return GlobalResponse.responseSuccess(service.save(mapper.apply(item))); + } + + /** + * 获取所有实体列表 + * + * @return GlobalCrudResponse 返回实体列表 + * @throws Exception 查询过程中可能抛出的异常 + */ + @GetMapping(LIST) + @Override + public GlobalResponse> list() throws Exception { + var mapper = listItemMapper(); + var result = service.list(); + return GlobalResponse.responseCrudData( + result + .stream() + .map(entity -> { + try { + return mapper.apply(entity); + } catch (Exception e) { + throw new RuntimeException(e); + } + }) + .toList(), + result.size() + ); + } + + /** + * 根据查询条件获取实体列表 + * + * @param query 查询条件对象 + * @return GlobalCrudResponse 返回符合条件的实体列表 + * @throws Exception 查询过程中可能抛出的异常 + */ + @PostMapping(LIST) + @Override + public GlobalResponse> list(@RequestBody Query query) throws Exception { + if (ObjectHelper.isNull(query)) { + return GlobalResponse.responseCrudData(List.of(), 0); } + var mapper = listItemMapper(); + var result = service.list(query); + return GlobalResponse.responseCrudData( + result.get() + .map(entity -> { + try { + return mapper.apply(entity); + } catch (Exception e) { + throw new RuntimeException(e); + } + }) + .toList(), + result.getTotalElements() + ); + } - /** - * 保存实体对象 - * - * @param item 需要保存的项 - * @return GlobalResponse 返回保存后的实体ID - * @throws Exception 保存过程中可能抛出的异常 - */ - @PostMapping(SAVE) - @Override - public GlobalResponse save(@RequestBody SAVE_ITEM item) throws Exception { - var mapper = saveItemMapper(); - return GlobalResponse.responseSuccess(service.save(mapper.apply(item))); - } + /** + * 根据ID获取实体详情 + * + * @param id 实体ID + * @return GlobalResponse 返回实体详情 + * @throws Exception 查询过程中可能抛出的异常 + */ + @GetMapping(DETAIL) + @Override + public GlobalResponse detail(@PathVariable("id") Long id) throws Exception { + var mapper = detailItemMapper(); + return GlobalResponse.responseSuccess(mapper.apply(service.detailOrThrow(id))); + } - /** - * 获取所有实体列表 - * - * @return GlobalCrudResponse 返回实体列表 - * @throws Exception 查询过程中可能抛出的异常 - */ - @GetMapping(LIST) - @Override - public GlobalCrudResponse list() throws Exception { - var mapper = listItemMapper(); - var result = service.list(); - return GlobalCrudResponse.responseCrudData( - result - .stream() - .map(entity -> { - try { - return mapper.apply(entity); - } catch (Exception e) { - throw new RuntimeException(e); - } - }) - .toList(), - result.size() - ); - } + /** + * 根据ID删除实体对象 + * + * @param id 需要删除的实体ID + * @return GlobalResponse 返回删除结果 + * @throws Exception 删除过程中可能抛出的异常 + */ + @GetMapping(REMOVE) + @Override + public GlobalResponse remove(@PathVariable("id") Long id) throws Exception { + service.remove(id); + return GlobalResponse.responseSuccess(); + } - /** - * 根据查询条件获取实体列表 - * - * @param query 查询条件对象 - * @return GlobalCrudResponse 返回符合条件的实体列表 - * @throws Exception 查询过程中可能抛出的异常 - */ - @PostMapping(LIST) - @Override - public GlobalCrudResponse list(@RequestBody Query query) throws Exception { - if (ObjectHelper.isNull(query)) { - return GlobalCrudResponse.responseCrudData(List.of(), 0); - } - var mapper = listItemMapper(); - var result = service.list(query); - return GlobalCrudResponse.responseCrudData( - result.get() - .map(entity -> { - try { - return mapper.apply(entity); - } catch (Exception e) { - throw new RuntimeException(e); - } - }) - .toList(), - result.getTotalElements() - ); - } + /** + * 保存项映射器,将保存项转换为实体对象 + * + * @return Function 保存项到实体的转换函数 + */ + protected abstract Function saveItemMapper(); - /** - * 根据ID获取实体详情 - * - * @param id 实体ID - * @return GlobalResponse 返回实体详情 - * @throws Exception 查询过程中可能抛出的异常 - */ - @GetMapping(DETAIL) - @Override - public GlobalResponse detail(@PathVariable("id") Long id) throws Exception { - var mapper = detailItemMapper(); - return GlobalResponse.responseSuccess(mapper.apply(service.detailOrThrow(id))); - } + /** + * 列表项映射器,将实体对象转换为列表项 + * + * @return Function 实体到列表项的转换函数 + */ + protected abstract Function listItemMapper(); - /** - * 根据ID删除实体对象 - * - * @param id 需要删除的实体ID - * @return GlobalResponse 返回删除结果 - * @throws Exception 删除过程中可能抛出的异常 - */ - @GetMapping(REMOVE) - @Override - public GlobalResponse remove(@PathVariable("id") Long id) throws Exception { - service.remove(id); - return GlobalResponse.responseSuccess(); - } - - /** - * 保存项映射器,将保存项转换为实体对象 - * - * @return Function 保存项到实体的转换函数 - */ - protected abstract Function saveItemMapper(); - - /** - * 列表项映射器,将实体对象转换为列表项 - * - * @return Function 实体到列表项的转换函数 - */ - protected abstract Function listItemMapper(); - - /** - * 详情项映射器,将实体对象转换为详情项 - * - * @return Function 实体到详情项的转换函数 - */ - protected abstract Function detailItemMapper(); + /** + * 详情项映射器,将实体对象转换为详情项 + * + * @return Function 实体到详情项的转换函数 + */ + protected abstract Function detailItemMapper(); } \ No newline at end of file diff --git a/src/main/java/com/lanyuanxiaoyao/service/template/controller/response/GlobalCrudResponse.java b/src/main/java/com/lanyuanxiaoyao/service/template/controller/response/GlobalCrudResponse.java deleted file mode 100644 index 3a7a887..0000000 --- a/src/main/java/com/lanyuanxiaoyao/service/template/controller/response/GlobalCrudResponse.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.lanyuanxiaoyao.service.template.controller.response; - -public class GlobalCrudResponse extends GlobalMapResponse { - public void setData(Iterable list) { - setData("items", list); - } - - public void setTotal(Long total) { - setData("total", total); - } - - public void setTotal(Integer total) { - setTotal(total.longValue()); - } - - public void setData(Iterable list, Long total) { - setData(list); - setTotal(total); - } - - public void setData(Iterable list, Integer total) { - setData(list, total.longValue()); - } -} diff --git a/src/main/java/com/lanyuanxiaoyao/service/template/controller/response/GlobalDetailResponse.java b/src/main/java/com/lanyuanxiaoyao/service/template/controller/response/GlobalDetailResponse.java deleted file mode 100644 index df17747..0000000 --- a/src/main/java/com/lanyuanxiaoyao/service/template/controller/response/GlobalDetailResponse.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.lanyuanxiaoyao.service.template.controller.response; - -public class GlobalDetailResponse extends GlobalMapResponse { - public void setDetail(Object detail) { - setData("detail", detail); - } -} diff --git a/src/main/java/com/lanyuanxiaoyao/service/template/controller/response/GlobalMapResponse.java b/src/main/java/com/lanyuanxiaoyao/service/template/controller/response/GlobalMapResponse.java deleted file mode 100644 index 269d04c..0000000 --- a/src/main/java/com/lanyuanxiaoyao/service/template/controller/response/GlobalMapResponse.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.lanyuanxiaoyao.service.template.controller.response; - -import java.util.HashMap; -import java.util.Map; - -public class GlobalMapResponse extends GlobalResponse> { - public GlobalMapResponse() { - setData(new HashMap<>()); - } - - public GlobalMapResponse setData(String key, Object value) { - getData().put(key, value); - return this; - } -} diff --git a/src/main/java/com/lanyuanxiaoyao/service/template/controller/response/GlobalResponse.java b/src/main/java/com/lanyuanxiaoyao/service/template/controller/response/GlobalResponse.java deleted file mode 100644 index e7bef4e..0000000 --- a/src/main/java/com/lanyuanxiaoyao/service/template/controller/response/GlobalResponse.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.lanyuanxiaoyao.service.template.controller.response; - -import java.util.Map; -import lombok.Getter; -import lombok.Setter; -import lombok.ToString; - -@Setter -@Getter -@ToString -public class GlobalResponse { - 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"; - private Integer status; - private String message; - private T data; - - public static GlobalResponse responseError() { - return responseError(ERROR_MESSAGE); - } - - public static GlobalResponse responseError(String message) { - GlobalResponse response = new GlobalResponse<>(); - response.setStatus(ERROR_STATUS); - response.setMessage(message); - return response; - } - - public static GlobalResponse responseSuccess() { - GlobalResponse response = new GlobalResponse<>(); - response.setStatus(SUCCESS_STATUS); - response.setMessage(SUCCESS_MESSAGE); - return response; - } - - public static GlobalResponse responseSuccess(String message) { - GlobalResponse response = new GlobalResponse<>(); - response.setStatus(SUCCESS_STATUS); - response.setMessage(message); - return response; - } - - public static GlobalResponse responseSuccess(String message, E data) { - GlobalResponse response = new GlobalResponse<>(); - response.setStatus(SUCCESS_STATUS); - response.setMessage(message); - response.setData(data); - return response; - } - - public static GlobalResponse responseSuccess(E data) { - GlobalResponse response = new GlobalResponse<>(); - response.setStatus(SUCCESS_STATUS); - response.setMessage(SUCCESS_MESSAGE); - response.setData(data); - return response; - } - - public static GlobalMapResponse responseMapData() { - GlobalMapResponse response = new GlobalMapResponse(); - response.setStatus(SUCCESS_STATUS); - response.setMessage(SUCCESS_MESSAGE); - return response; - } - - public static GlobalMapResponse responseMapData(Map data) { - GlobalMapResponse response = responseMapData(); - response.setData(data); - return response; - } - - public static GlobalMapResponse responseMapData(String key, Object value) { - GlobalMapResponse response = responseMapData(); - response.setData(key, value); - return response; - } - - public static GlobalCrudResponse responseCrudData(Iterable data) { - GlobalCrudResponse response = new GlobalCrudResponse<>(); - response.setStatus(SUCCESS_STATUS); - response.setMessage(SUCCESS_MESSAGE); - response.setData(data); - return response; - } - - public static GlobalCrudResponse responseCrudData(Iterable data, Integer total) { - GlobalCrudResponse response = responseCrudData(data); - response.setTotal(total); - return response; - } - - public static GlobalCrudResponse responseCrudData(Iterable data, Long total) { - GlobalCrudResponse response = responseCrudData(data); - response.setTotal(total); - return response; - } - - public static GlobalDetailResponse responseDetailData(Object detail) { - GlobalDetailResponse response = new GlobalDetailResponse(); - response.setDetail(detail); - return response; - } -} diff --git a/src/main/java/com/lanyuanxiaoyao/service/template/entity/IdOnlyEntity.java b/src/main/java/com/lanyuanxiaoyao/service/template/entity/IdOnlyEntity.java index c46c3e0..583be10 100644 --- a/src/main/java/com/lanyuanxiaoyao/service/template/entity/IdOnlyEntity.java +++ b/src/main/java/com/lanyuanxiaoyao/service/template/entity/IdOnlyEntity.java @@ -38,14 +38,14 @@ import org.springframework.data.jpa.domain.support.AuditingEntityListener; @MappedSuperclass @EntityListeners(AuditingEntityListener.class) public class IdOnlyEntity { - /** - * 实体唯一标识符 - *

    - * 使用Snowflake算法生成的Long类型ID,保证全局唯一性。 - *

    - */ - @Id - @SnowflakeId - @Comment("记录唯一标记") - private Long id; + /** + * 实体唯一标识符 + *

    + * 使用Snowflake算法生成的Long类型ID,保证全局唯一性。 + *

    + */ + @Id + @SnowflakeId + @Comment("记录唯一标记") + private Long id; } \ No newline at end of file diff --git a/src/main/java/com/lanyuanxiaoyao/service/template/entity/SimpleEntity.java b/src/main/java/com/lanyuanxiaoyao/service/template/entity/SimpleEntity.java index 7a78b09..9ae743f 100644 --- a/src/main/java/com/lanyuanxiaoyao/service/template/entity/SimpleEntity.java +++ b/src/main/java/com/lanyuanxiaoyao/service/template/entity/SimpleEntity.java @@ -39,23 +39,23 @@ import org.springframework.data.jpa.domain.support.AuditingEntityListener; @MappedSuperclass @EntityListeners(AuditingEntityListener.class) public class SimpleEntity extends IdOnlyEntity { - /** - * 记录创建时间 - *

    - * 由Spring Data JPA自动维护,当实体首次持久化时设置该字段的值。 - *

    - */ - @CreatedDate - @Comment("记录创建时间") - private LocalDateTime createdTime; - - /** - * 记录更新时间 - *

    - * 由Spring Data JPA自动维护,当实体每次更新时刷新该字段的值。 - *

    - */ - @LastModifiedDate - @Comment("记录更新时间") - private LocalDateTime modifiedTime; + /** + * 记录创建时间 + *

    + * 由Spring Data JPA自动维护,当实体首次持久化时设置该字段的值。 + *

    + */ + @CreatedDate + @Comment("记录创建时间") + private LocalDateTime createdTime; + + /** + * 记录更新时间 + *

    + * 由Spring Data JPA自动维护,当实体每次更新时刷新该字段的值。 + *

    + */ + @LastModifiedDate + @Comment("记录更新时间") + private LocalDateTime modifiedTime; } \ No newline at end of file diff --git a/src/main/java/com/lanyuanxiaoyao/service/template/helper/ObjectHelper.java b/src/main/java/com/lanyuanxiaoyao/service/template/helper/ObjectHelper.java index 8c6a88e..14a6d3e 100644 --- a/src/main/java/com/lanyuanxiaoyao/service/template/helper/ObjectHelper.java +++ b/src/main/java/com/lanyuanxiaoyao/service/template/helper/ObjectHelper.java @@ -5,105 +5,105 @@ import java.util.Map; import java.util.Optional; public class ObjectHelper { - /** - * 判断对象是否为null - * - * @param obj 待检查的对象 - * @return 如果对象为null返回true,否则返回false - */ - public static boolean isNull(Object obj) { - return obj == null; - } + /** + * 判断对象是否为null + * + * @param obj 待检查的对象 + * @return 如果对象为null返回true,否则返回false + */ + public static boolean isNull(Object obj) { + return obj == null; + } - /** - * 判断对象是否不为null - * - * @param obj 待判断的对象 - * @return 如果对象不为null则返回true,否则返回false - */ - public static boolean isNotNull(Object obj) { - return !isNull(obj); - } + /** + * 判断对象是否不为null + * + * @param obj 待判断的对象 + * @return 如果对象不为null则返回true,否则返回false + */ + public static boolean isNotNull(Object obj) { + return !isNull(obj); + } - /** - * 判断对象是否为空 - * - * @param obj 待判断的对象 - * @return 如果对象为null或为空则返回true,否则返回false - */ - public static boolean isEmpty(Object obj) { - // 首先判断对象是否为null - if (isNull(obj)) return true; - // 判断是否为集合类型 - else if (obj instanceof Collection collection) return collection.isEmpty(); - // 判断是否为Map类型 - else if (obj instanceof Map map) return map.isEmpty(); - // 判断是否为字符序列类型 - else if (obj instanceof CharSequence sequence) return sequence.isEmpty(); - // 判断是否为各种基本类型数组 - else if (obj instanceof Object[] array) return array.length == 0; - else if (obj instanceof byte[] array) return array.length == 0; - else if (obj instanceof short[] array) return array.length == 0; - else if (obj instanceof int[] array) return array.length == 0; - else if (obj instanceof long[] array) return array.length == 0; - else if (obj instanceof float[] array) return array.length == 0; - else if (obj instanceof double[] array) return array.length == 0; - else if (obj instanceof char[] array) return array.length == 0; - else if (obj instanceof boolean[] array) return array.length == 0; - // 判断是否为Optional类型 - else if (obj instanceof Optional optional) return optional.isEmpty(); - // 其他情况认为对象不为空 - else return false; - } + /** + * 判断对象是否为空 + * + * @param obj 待判断的对象 + * @return 如果对象为null或为空则返回true,否则返回false + */ + public static boolean isEmpty(Object obj) { + // 首先判断对象是否为null + if (isNull(obj)) return true; + // 判断是否为集合类型 + else if (obj instanceof Collection collection) return collection.isEmpty(); + // 判断是否为Map类型 + else if (obj instanceof Map map) return map.isEmpty(); + // 判断是否为字符序列类型 + else if (obj instanceof CharSequence sequence) return sequence.isEmpty(); + // 判断是否为各种基本类型数组 + else if (obj instanceof Object[] array) return array.length == 0; + else if (obj instanceof byte[] array) return array.length == 0; + else if (obj instanceof short[] array) return array.length == 0; + else if (obj instanceof int[] array) return array.length == 0; + else if (obj instanceof long[] array) return array.length == 0; + else if (obj instanceof float[] array) return array.length == 0; + else if (obj instanceof double[] array) return array.length == 0; + else if (obj instanceof char[] array) return array.length == 0; + else if (obj instanceof boolean[] array) return array.length == 0; + // 判断是否为Optional类型 + else if (obj instanceof Optional optional) return optional.isEmpty(); + // 其他情况认为对象不为空 + else return false; + } - public static boolean isNotEmpty(Object obj) { - return !isEmpty(obj); - } + public static boolean isNotEmpty(Object obj) { + return !isEmpty(obj); + } - public static T defaultIfNull(final T object, final T defaultValue) { - return isNull(object) ? defaultValue : object; - } + public static T defaultIfNull(final T object, final T defaultValue) { + return isNull(object) ? defaultValue : object; + } - /** - * 判断给定的类是否可比较 - * - * @param clazz 待判断的类对象 - * @return 如果类是枚举、字符序列、可比较接口的实现类或基本数据类型则返回true,否则返回false - */ - public static boolean isComparable(Class clazz) { - if (isNull(clazz)) return false; - // 判断类是否为可比较类型:枚举、字符序列、可比较接口实现类或基本数据类型 - return clazz.isEnum() || - CharSequence.class.isAssignableFrom(clazz) || - Comparable.class.isAssignableFrom(clazz) || - clazz.isPrimitive(); - } + /** + * 判断给定的类是否可比较 + * + * @param clazz 待判断的类对象 + * @return 如果类是枚举、字符序列、可比较接口的实现类或基本数据类型则返回true,否则返回false + */ + public static boolean isComparable(Class clazz) { + if (isNull(clazz)) return false; + // 判断类是否为可比较类型:枚举、字符序列、可比较接口实现类或基本数据类型 + return clazz.isEnum() || + CharSequence.class.isAssignableFrom(clazz) || + Comparable.class.isAssignableFrom(clazz) || + clazz.isPrimitive(); + } - public static boolean isComparable(Object obj) { - if (isNull(obj)) return false; - return isComparable(obj.getClass()); - } + public static boolean isComparable(Object obj) { + if (isNull(obj)) return false; + return isComparable(obj.getClass()); + } - public static boolean isCollection(Class clazz) { - if (isNull(clazz)) return false; - return Collection.class.isAssignableFrom(clazz); - } + public static boolean isCollection(Class clazz) { + if (isNull(clazz)) return false; + return Collection.class.isAssignableFrom(clazz); + } - public static boolean isCollection(Object obj) { - if (isNull(obj)) return false; - return isCollection(obj.getClass()); - } + public static boolean isCollection(Object obj) { + if (isNull(obj)) return false; + return isCollection(obj.getClass()); + } - public static boolean isString(Class clazz) { - if (isNull(clazz)) return false; - return String.class.isAssignableFrom(clazz); - } + public static boolean isString(Class clazz) { + if (isNull(clazz)) return false; + return String.class.isAssignableFrom(clazz); + } - public static boolean isString(Object obj) { - if (isNull(obj)) return false; - return isString(obj.getClass()); - } + public static boolean isString(Object obj) { + if (isNull(obj)) return false; + return isString(obj.getClass()); + } } \ No newline at end of file diff --git a/src/main/java/com/lanyuanxiaoyao/service/template/repository/SimpleRepository.java b/src/main/java/com/lanyuanxiaoyao/service/template/repository/SimpleRepository.java index 230549d..b7cdccd 100644 --- a/src/main/java/com/lanyuanxiaoyao/service/template/repository/SimpleRepository.java +++ b/src/main/java/com/lanyuanxiaoyao/service/template/repository/SimpleRepository.java @@ -96,7 +96,7 @@ import org.springframework.data.repository.query.QueryByExampleExecutor; * *

    * - * @param 实体类型 + * @param 实体类型 * @param 实体ID类型 * @author lanyuanxiaoyao */ diff --git a/src/main/java/com/lanyuanxiaoyao/service/template/service/SimpleService.java b/src/main/java/com/lanyuanxiaoyao/service/template/service/SimpleService.java index ed52749..697fce2 100644 --- a/src/main/java/com/lanyuanxiaoyao/service/template/service/SimpleService.java +++ b/src/main/java/com/lanyuanxiaoyao/service/template/service/SimpleService.java @@ -8,23 +8,23 @@ import java.util.Set; import org.springframework.data.domain.Page; public interface SimpleService { - Long save(ENTITY entity) throws Exception; + Long save(ENTITY entity) throws Exception; - Long count() throws Exception; + Long count() throws Exception; - List list() throws Exception; + List list() throws Exception; - List list(Set ids) throws Exception; + List list(Set ids) throws Exception; - Page list(Query query) throws Exception; + Page list(Query query) throws Exception; - Optional detailOptional(Long id) throws Exception; + Optional detailOptional(Long id) throws Exception; - ENTITY detail(Long id) throws Exception; + ENTITY detail(Long id) throws Exception; - ENTITY detailOrThrow(Long id) throws Exception; + ENTITY detailOrThrow(Long id) throws Exception; - ENTITY detailOrNull(Long id) throws Exception; + ENTITY detailOrNull(Long id) throws Exception; - void remove(Long id) throws Exception; + void remove(Long id) throws Exception; } diff --git a/src/main/java/com/lanyuanxiaoyao/service/template/service/SimpleServiceSupport.java b/src/main/java/com/lanyuanxiaoyao/service/template/service/SimpleServiceSupport.java index 18c2a2a..ef7ea6f 100644 --- a/src/main/java/com/lanyuanxiaoyao/service/template/service/SimpleServiceSupport.java +++ b/src/main/java/com/lanyuanxiaoyao/service/template/service/SimpleServiceSupport.java @@ -87,560 +87,560 @@ import org.springframework.data.domain.Sort; */ @Slf4j public abstract class SimpleServiceSupport implements SimpleService { - private static final Integer DEFAULT_PAGE_INDEX = 1; - private static final Integer DEFAULT_PAGE_SIZE = 10; - protected final SimpleRepository repository; + private static final Integer DEFAULT_PAGE_INDEX = 1; + private static final Integer DEFAULT_PAGE_SIZE = 10; + protected final SimpleRepository repository; + /** + * 构造函数 + * + * @param repository 简单仓库实例 + */ + public SimpleServiceSupport(SimpleRepository repository) { + this.repository = repository; + } + + /** + * 保存实体对象 + *

    + * 使用saveOrUpdateByNotNullProperties方法保存实体,只更新非空字段。 + * 该方法具有事务性,遇到任何异常都会回滚。 + *

    + * + * @param entity 需要保存的实体对象 + * @return Long 返回保存后的实体ID + */ + @Transactional(rollbackOn = Throwable.class) + @Override + public Long save(ENTITY entity) { + entity = repository.saveOrUpdateByNotNullProperties(entity); + return entity.getId(); + } + + /** + * 统计符合条件的实体数量 + *

    + * 根据[listPredicate](file:///Users/lanyuanxiaoyao/Project/IdeaProjects/spring-boot-service-template/src/main/java/com/lanyuanxiaoyao/service/template/service/SimpleServiceSupport.java#L261-L263)方法构建的条件统计实体数量。 + *

    + * + * @return Long 返回符合条件的实体数量 + */ + @Override + public Long count() { + return repository.count(this::listPredicate); + } + + /** + * 获取所有符合条件的实体列表 + *

    + * 根据[listPredicate](file:///Users/lanyuanxiaoyao/Project/IdeaProjects/spring-boot-service-template/src/main/java/com/lanyuanxiaoyao/service/template/service/SimpleServiceSupport.java#L261-L263)方法构建的条件查询所有实体。 + *

    + * + * @return List 返回符合条件的实体列表 + */ + @Override + public List list() { + return repository.findAll(this::listPredicate); + } + + /** + * 根据ID集合获取实体列表 + *

    + * 根据提供的ID集合查询对应的实体列表,并结合[listPredicate](file:///Users/lanyuanxiaoyao/Project/IdeaProjects/spring-boot-service-template/src/main/java/com/lanyuanxiaoyao/service/template/service/SimpleServiceSupport.java#L261-L263)方法构建的条件。 + *

    + * + * @param ids ID集合 + * @return List 返回ID集合对应的实体列表 + */ + @Override + public List list(Set ids) { + return repository.findAll( + (root, query, builder) -> { + var predicate = listPredicate(root, query, builder); + var idsPredicate = builder.in(root.get(IdOnlyEntity.Fields.id)).value(ids); + return ObjectHelper.isNull(predicate) + ? idsPredicate + : builder.and(predicate, idsPredicate); + } + ); + } + + /** + * 解析字段路径 + *

    + * 支持多级字段路径解析,使用"/"分隔多级字段。 + * 例如: "user/name" 表示实体的user属性的name字段。 + *

    + * + * @param root JPA Criteria查询根节点 + * @param column 字段路径字符串 + * @param 字段类型 + * @return Path 返回字段路径对象 + * @throws IllegalArgumentException 当字段路径为空时抛出 + */ + private Path column(Root root, String column) { + if (ObjectHelper.isEmpty(column)) { + throw new IllegalArgumentException("Column cannot be blank"); + } + var columns = column.split("/"); + Path path = root.get(columns[0]); + for (int i = 1; i < columns.length; i++) { + path = path.get(columns[i]); + } + return path; + } + + /** + * 处理字段值 + *

    + * 对于枚举类型字段,将字符串值转换为对应的枚举值。 + * 其他类型直接返回原值。 + *

    + * + * @param column 字段路径 + * @param value 字段值 + * @param 字段类型 + * @return Object 处理后的字段值 + * @throws IllegalArgumentException 当枚举类型字段的值不是字符串时抛出 + */ + @SuppressWarnings({"unchecked", "rawtypes"}) + private Object value(Path column, Object value) { + var javaType = column.getJavaType(); + if (javaType.isEnum()) { + if (value instanceof String enumName) { + var enumType = (Class) javaType; + return Enum.valueOf(enumType, enumName); + } else { + throw new IllegalArgumentException("枚举类型字段需要 String 类型的值"); + } + } + return value; + } + + /** + * 构建查询条件谓词列表 + *

    + * 根据Query.Queryable对象构建JPA Criteria查询的谓词列表。 + * 支持多种查询条件类型,包括相等、不等、模糊匹配、范围查询等。 + *

    + * + * @param queryable 查询条件对象 + * @param root JPA Criteria查询根节点 + * @param query JPA Criteria查询对象 + * @param builder JPA Criteria构建器 + * @return List 返回构建的谓词列表 + */ + @SuppressWarnings("unchecked") + protected Predicate queryPredicates(Query.Queryable queryable, Root root, CriteriaQuery query, CriteriaBuilder builder) { + var predicates = new ArrayList(); + if (ObjectHelper.isNull(queryable)) { + return null; + } + if (ObjectHelper.isNotEmpty(queryable.getNullEqual())) { + queryable.getNullEqual().forEach(column -> predicates.add(builder.isNull(column(root, column)))); + } + if (ObjectHelper.isNotEmpty(queryable.getNotNullEqual())) { + queryable.getNotNullEqual().forEach(column -> predicates.add(builder.isNotNull(column(root, column)))); + } + if (ObjectHelper.isNotEmpty(queryable.getEmpty())) { + queryable.getEmpty().forEach(column -> { + var path = this.>column(root, column); + checkCollection(path, column); + predicates.add(builder.isEmpty(path)); + }); + } + if (ObjectHelper.isNotEmpty(queryable.getNotEmpty())) { + queryable.getNotEmpty().forEach(column -> { + var path = this.>column(root, column); + checkCollection(path, column); + predicates.add(builder.isNotEmpty(path)); + }); + } + if (ObjectHelper.isNotEmpty(queryable.getEqual())) { + queryable.getEqual().forEach((column, value) -> { + var path = column(root, column); + predicates.add(builder.equal(path, value(path, value))); + }); + } + if (ObjectHelper.isNotEmpty(queryable.getNotEqual())) { + queryable.getEqual().forEach((column, value) -> { + var path = column(root, column); + predicates.add(builder.notEqual(path, value(path, value))); + }); + } + if (ObjectHelper.isNotEmpty(queryable.getLike())) { + queryable.getLike().forEach((column, value) -> { + var path = column(root, column); + checkString(path, column); + checkString(value, column); + predicates.add(builder.like(column(root, column), value)); + }); + } + if (ObjectHelper.isNotEmpty(queryable.getNotLike())) { + queryable.getNotLike().forEach((column, value) -> { + var path = column(root, column); + checkString(path, column); + checkString(value, column); + predicates.add(builder.notLike(column(root, column), value)); + }); + } + if (ObjectHelper.isNotEmpty(queryable.getGreat())) { + queryable.getGreat().forEach((column, value) -> { + var path = this.>column(root, column); + checkComparable(path, column); + checkComparable(value, column); + predicates.add(builder.greaterThan(path, (Comparable) value)); + }); + } + if (ObjectHelper.isNotEmpty(queryable.getLess())) { + queryable.getLess().forEach((column, value) -> { + var path = this.>column(root, column); + checkComparable(path, column); + checkComparable(value, column); + predicates.add(builder.lessThan(path, (Comparable) value)); + }); + } + if (ObjectHelper.isNotEmpty(queryable.getGreatEqual())) { + queryable.getGreatEqual().forEach((column, value) -> { + var path = this.>column(root, column); + checkComparable(path, column); + checkComparable(value, column); + predicates.add(builder.greaterThanOrEqualTo(path, (Comparable) value)); + }); + } + if (ObjectHelper.isNotEmpty(queryable.getLessEqual())) { + queryable.getLessEqual().forEach((column, value) -> { + var path = this.>column(root, column); + checkComparable(path, column); + checkComparable(value, column); + predicates.add(builder.lessThanOrEqualTo(path, (Comparable) value)); + }); + } + if (ObjectHelper.isNotEmpty(queryable.getIn())) { + queryable.getIn().forEach((column, value) -> predicates.add(builder.in(column(root, column)).value(value))); + } + if (ObjectHelper.isNotEmpty(queryable.getNotIn())) { + queryable.getNotIn().forEach((column, value) -> predicates.add(builder.in(column(root, column)).value(value).not())); + } + if (ObjectHelper.isNotEmpty(queryable.getBetween())) { + queryable.getBetween().forEach((column, value) -> { + var path = this.>column(root, column); + checkComparable(path, column); + checkComparable(value.getStart(), column); + checkComparable(value.getEnd(), column); + predicates.add(builder.between(column(root, column), (Comparable) value.getStart(), (Comparable) value.getEnd())); + }); + } + if (ObjectHelper.isNotEmpty(queryable.getNotBetween())) { + queryable.getNotBetween().forEach((column, value) -> { + var path = this.>column(root, column); + checkComparable(path, column); + checkComparable(value.getStart(), column); + checkComparable(value.getEnd(), column); + predicates.add(builder.between(column(root, column), (Comparable) value.getStart(), (Comparable) value.getEnd()).not()); + }); + } + + return predicates.size() == 1 + ? predicates.get(0) + : builder.and(predicates.toArray(Predicate[]::new)); + } + + /** + * 检查字段类型是否可比较 + * + * @param path 字段路径 + * @param column 字段名称 + * @throws NotComparableException 当字段类型不可比较时抛出 + */ + private void checkComparable(Path path, String column) { + if (!ObjectHelper.isComparable(path.getJavaType())) { + throw new NotComparableException(column); + } + } + + /** + * 检查值是否可比较 + * + * @param value 值对象 + * @param column 字段名称 + * @throws NotComparableException 当值不可比较时抛出 + */ + private void checkComparable(Object value, String column) { + if (!ObjectHelper.isComparable(value)) { + throw new NotComparableException(column); + } + } + + /** + * 检查区间值是否可比较 + * + * @param value 区间对象 + * @param column 字段名称 + * @throws NotComparableException 当区间值不可比较时抛出 + */ + private void checkComparable(Query.Queryable.Between value, String column) { + checkComparable(value.getStart(), column); + checkComparable(value.getEnd(), column); + } + + /** + * 检查字段类型是否为集合 + * + * @param path 字段路径 + * @param column 字段名称 + * @throws NotCollectionException 当字段类型不是集合时抛出 + */ + private void checkCollection(Path path, String column) { + if (!ObjectHelper.isCollection(path.getJavaType())) { + throw new NotCollectionException(column); + } + } + + /** + * 检查值是否为集合 + * + * @param value 值对象 + * @param column 字段名称 + * @throws NotCollectionException 当值不是集合时抛出 + */ + private void checkCollection(Object value, String column) { + if (!ObjectHelper.isCollection(value)) { + throw new NotCollectionException(column); + } + } + + /** + * 检查字段类型是否为字符串 + * + * @param path 字段路径 + * @param column 字段名称 + * @throws NotStringException 当字段类型不是字符串时抛出 + */ + private void checkString(Path path, String column) { + if (!ObjectHelper.isString(path.getJavaType())) { + throw new NotStringException(column); + } + } + + /** + * 检查值是否为字符串 + * + * @param value 值对象 + * @param column 字段名称 + * @throws NotStringException 当值不是字符串时抛出 + */ + private void checkString(Object value, String column) { + if (!ObjectHelper.isString(value)) { + throw new NotStringException(column); + } + } + + /** + * 构建列表查询条件 + *

    + * 子类可以重写此方法以添加特定的查询条件。 + * 默认返回空列表,表示不添加额外条件。 + *

    + * + * @param root JPA Criteria查询根节点 + * @param query JPA Criteria查询对象 + * @param builder JPA Criteria构建器 + * @return List 返回查询条件谓词列表 + */ + protected Predicate listPredicate(Root root, CriteriaQuery query, CriteriaBuilder builder) { + return null; + } + + /** + * 根据查询条件分页获取实体列表 + *

    + * 支持复杂的查询条件和分页功能。 + * 默认分页参数:第1页,每页10条记录,按创建时间降序排列。 + *

    + * + * @param listQuery 查询条件对象 + * @return Page 返回分页查询结果 + */ + @Override + public Page list(Query listQuery) { + var pageRequest = PageRequest.of(DEFAULT_PAGE_INDEX - 1, DEFAULT_PAGE_SIZE, Sort.by(SimpleEntity.Fields.createdTime).descending()); + if (ObjectHelper.isNotNull(listQuery.getPage())) { + pageRequest = PageRequest.of( + ObjectHelper.defaultIfNull(listQuery.getPage().getIndex(), DEFAULT_PAGE_INDEX) - 1, + ObjectHelper.defaultIfNull(listQuery.getPage().getSize(), DEFAULT_PAGE_SIZE), + Sort.by(SimpleEntity.Fields.createdTime).descending() + ); + } + return repository.findAll( + (root, query, builder) -> { + var predicate = listPredicate(root, query, builder); + var queryPredicate = queryPredicates(listQuery.getQuery(), root, query, builder); + return ObjectHelper.isNull(predicate) + ? queryPredicate + : builder.and(predicate, queryPredicate); + }, + pageRequest + ); + } + + /** + * 根据ID获取实体详情(Optional包装) + *

    + * 如果ID为空则返回空Optional,否则根据ID查询实体。 + *

    + * + * @param id 实体ID + * @return Optional 返回实体详情的Optional包装 + */ + @Override + public Optional detailOptional(Long id) { + if (ObjectHelper.isNull(id)) { + return Optional.empty(); + } + return repository.findOne( + (root, query, builder) -> { + var predicate = listPredicate(root, query, builder); + var idPredicate = builder.equal(root.get(IdOnlyEntity.Fields.id), id); + return ObjectHelper.isNull(predicate) + ? idPredicate + : builder.and(predicate, idPredicate); + } + ); + } + + /** + * 根据ID获取实体详情 + *

    + * 如果实体不存在则返回null。 + *

    + * + * @param id 实体ID + * @return ENTITY 返回实体详情,不存在时返回null + */ + @Override + public ENTITY detail(Long id) { + return detailOrNull(id); + } + + /** + * 根据ID获取实体详情,不存在时抛出异常 + *

    + * 如果实体不存在则抛出IdNotFoundException异常。 + *

    + * + * @param id 实体ID + * @return ENTITY 返回实体详情 + * @throws IdNotFoundException 当实体不存在时抛出 + */ + @Override + public ENTITY detailOrThrow(Long id) { + return detailOptional(id).orElseThrow(() -> new IdNotFoundException(id)); + } + + /** + * 根据ID获取实体详情,不存在时返回null + *

    + * 与[detail](file:///Users/lanyuanxiaoyao/Project/IdeaProjects/spring-boot-service-template/src/main/java/com/lanyuanxiaoyao/service/template/service/SimpleService.java#L21-L21)方法功能相同。 + *

    + * + * @param id 实体ID + * @return ENTITY 返回实体详情,不存在时返回null + */ + @Override + public ENTITY detailOrNull(Long id) { + return detailOptional(id).orElse(null); + } + + /** + * 根据ID删除实体 + *

    + * 具有事务性,遇到任何异常都会回滚。 + * 如果ID为空则不执行任何操作。 + *

    + * + * @param id 实体ID + */ + @Transactional(rollbackOn = Throwable.class) + @Override + public void remove(Long id) { + if (ObjectHelper.isNotNull(id)) { + repository.deleteById(id); + } + } + + /** + * ID未找到异常 + *

    + * 当根据ID查询实体但实体不存在时抛出此异常。 + *

    + */ + public static final class IdNotFoundException extends RuntimeException { + /** + * 构造函数(无参) + */ + public IdNotFoundException() { + super("资源不存在"); + } + + /** + * 构造函数(带ID参数) + * + * @param id 实体ID + */ + public IdNotFoundException(Long id) { + super("ID为 %d 的资源不存在".formatted(id)); + } + } + + /** + * 不可比较异常 + *

    + * 当尝试对不可比较的字段或值执行比较操作时抛出此异常。 + *

    + */ + public static final class NotComparableException extends RuntimeException { /** * 构造函数 * - * @param repository 简单仓库实例 + * @param variable 变量名称 */ - public SimpleServiceSupport(SimpleRepository repository) { - this.repository = repository; + public NotComparableException(String variable) { + super("变量 %s 不能比较".formatted(variable)); } + } + /** + * 非集合异常 + *

    + * 当尝试对非集合类型的字段或值执行集合操作时抛出此异常。 + *

    + */ + public static final class NotCollectionException extends RuntimeException { /** - * 保存实体对象 - *

    - * 使用saveOrUpdateByNotNullProperties方法保存实体,只更新非空字段。 - * 该方法具有事务性,遇到任何异常都会回滚。 - *

    + * 构造函数 * - * @param entity 需要保存的实体对象 - * @return Long 返回保存后的实体ID + * @param variable 变量名称 */ - @Transactional(rollbackOn = Throwable.class) - @Override - public Long save(ENTITY entity) { - entity = repository.saveOrUpdateByNotNullProperties(entity); - return entity.getId(); + public NotCollectionException(String variable) { + super("变量 %s 不是集合".formatted(variable)); } + } + /** + * 非字符串异常 + *

    + * 当尝试对非字符串类型的字段或值执行字符串操作时抛出此异常。 + *

    + */ + public static final class NotStringException extends RuntimeException { /** - * 统计符合条件的实体数量 - *

    - * 根据[listPredicate](file:///Users/lanyuanxiaoyao/Project/IdeaProjects/spring-boot-service-template/src/main/java/com/lanyuanxiaoyao/service/template/service/SimpleServiceSupport.java#L261-L263)方法构建的条件统计实体数量。 - *

    + * 构造函数 * - * @return Long 返回符合条件的实体数量 + * @param variable 变量名称 */ - @Override - public Long count() { - return repository.count(this::listPredicate); - } - - /** - * 获取所有符合条件的实体列表 - *

    - * 根据[listPredicate](file:///Users/lanyuanxiaoyao/Project/IdeaProjects/spring-boot-service-template/src/main/java/com/lanyuanxiaoyao/service/template/service/SimpleServiceSupport.java#L261-L263)方法构建的条件查询所有实体。 - *

    - * - * @return List 返回符合条件的实体列表 - */ - @Override - public List list() { - return repository.findAll(this::listPredicate); - } - - /** - * 根据ID集合获取实体列表 - *

    - * 根据提供的ID集合查询对应的实体列表,并结合[listPredicate](file:///Users/lanyuanxiaoyao/Project/IdeaProjects/spring-boot-service-template/src/main/java/com/lanyuanxiaoyao/service/template/service/SimpleServiceSupport.java#L261-L263)方法构建的条件。 - *

    - * - * @param ids ID集合 - * @return List 返回ID集合对应的实体列表 - */ - @Override - public List list(Set ids) { - return repository.findAll( - (root, query, builder) -> { - var predicate = listPredicate(root, query, builder); - var idsPredicate = builder.in(root.get(IdOnlyEntity.Fields.id)).value(ids); - return ObjectHelper.isNull(predicate) - ? idsPredicate - : builder.and(predicate, idsPredicate); - } - ); - } - - /** - * 解析字段路径 - *

    - * 支持多级字段路径解析,使用"/"分隔多级字段。 - * 例如: "user/name" 表示实体的user属性的name字段。 - *

    - * - * @param root JPA Criteria查询根节点 - * @param column 字段路径字符串 - * @param 字段类型 - * @return Path 返回字段路径对象 - * @throws IllegalArgumentException 当字段路径为空时抛出 - */ - private Path column(Root root, String column) { - if (ObjectHelper.isEmpty(column)) { - throw new IllegalArgumentException("Column cannot be blank"); - } - var columns = column.split("/"); - Path path = root.get(columns[0]); - for (int i = 1; i < columns.length; i++) { - path = path.get(columns[i]); - } - return path; - } - - /** - * 处理字段值 - *

    - * 对于枚举类型字段,将字符串值转换为对应的枚举值。 - * 其他类型直接返回原值。 - *

    - * - * @param column 字段路径 - * @param value 字段值 - * @param 字段类型 - * @return Object 处理后的字段值 - * @throws IllegalArgumentException 当枚举类型字段的值不是字符串时抛出 - */ - @SuppressWarnings({"unchecked", "rawtypes"}) - private Object value(Path column, Object value) { - var javaType = column.getJavaType(); - if (javaType.isEnum()) { - if (value instanceof String enumName) { - var enumType = (Class) javaType; - return Enum.valueOf(enumType, enumName); - } else { - throw new IllegalArgumentException("枚举类型字段需要 String 类型的值"); - } - } - return value; - } - - /** - * 构建查询条件谓词列表 - *

    - * 根据Query.Queryable对象构建JPA Criteria查询的谓词列表。 - * 支持多种查询条件类型,包括相等、不等、模糊匹配、范围查询等。 - *

    - * - * @param queryable 查询条件对象 - * @param root JPA Criteria查询根节点 - * @param query JPA Criteria查询对象 - * @param builder JPA Criteria构建器 - * @return List 返回构建的谓词列表 - */ - @SuppressWarnings("unchecked") - protected Predicate queryPredicates(Query.Queryable queryable, Root root, CriteriaQuery query, CriteriaBuilder builder) { - var predicates = new ArrayList(); - if (ObjectHelper.isNull(queryable)) { - return null; - } - if (ObjectHelper.isNotEmpty(queryable.getNullEqual())) { - queryable.getNullEqual().forEach(column -> predicates.add(builder.isNull(column(root, column)))); - } - if (ObjectHelper.isNotEmpty(queryable.getNotNullEqual())) { - queryable.getNotNullEqual().forEach(column -> predicates.add(builder.isNotNull(column(root, column)))); - } - if (ObjectHelper.isNotEmpty(queryable.getEmpty())) { - queryable.getEmpty().forEach(column -> { - var path = this.>column(root, column); - checkCollection(path, column); - predicates.add(builder.isEmpty(path)); - }); - } - if (ObjectHelper.isNotEmpty(queryable.getNotEmpty())) { - queryable.getNotEmpty().forEach(column -> { - var path = this.>column(root, column); - checkCollection(path, column); - predicates.add(builder.isNotEmpty(path)); - }); - } - if (ObjectHelper.isNotEmpty(queryable.getEqual())) { - queryable.getEqual().forEach((column, value) -> { - var path = column(root, column); - predicates.add(builder.equal(path, value(path, value))); - }); - } - if (ObjectHelper.isNotEmpty(queryable.getNotEqual())) { - queryable.getEqual().forEach((column, value) -> { - var path = column(root, column); - predicates.add(builder.notEqual(path, value(path, value))); - }); - } - if (ObjectHelper.isNotEmpty(queryable.getLike())) { - queryable.getLike().forEach((column, value) -> { - var path = column(root, column); - checkString(path, column); - checkString(value, column); - predicates.add(builder.like(column(root, column), value)); - }); - } - if (ObjectHelper.isNotEmpty(queryable.getNotLike())) { - queryable.getNotLike().forEach((column, value) -> { - var path = column(root, column); - checkString(path, column); - checkString(value, column); - predicates.add(builder.notLike(column(root, column), value)); - }); - } - if (ObjectHelper.isNotEmpty(queryable.getGreat())) { - queryable.getGreat().forEach((column, value) -> { - var path = this.>column(root, column); - checkComparable(path, column); - checkComparable(value, column); - predicates.add(builder.greaterThan(path, (Comparable) value)); - }); - } - if (ObjectHelper.isNotEmpty(queryable.getLess())) { - queryable.getLess().forEach((column, value) -> { - var path = this.>column(root, column); - checkComparable(path, column); - checkComparable(value, column); - predicates.add(builder.lessThan(path, (Comparable) value)); - }); - } - if (ObjectHelper.isNotEmpty(queryable.getGreatEqual())) { - queryable.getGreatEqual().forEach((column, value) -> { - var path = this.>column(root, column); - checkComparable(path, column); - checkComparable(value, column); - predicates.add(builder.greaterThanOrEqualTo(path, (Comparable) value)); - }); - } - if (ObjectHelper.isNotEmpty(queryable.getLessEqual())) { - queryable.getLessEqual().forEach((column, value) -> { - var path = this.>column(root, column); - checkComparable(path, column); - checkComparable(value, column); - predicates.add(builder.lessThanOrEqualTo(path, (Comparable) value)); - }); - } - if (ObjectHelper.isNotEmpty(queryable.getIn())) { - queryable.getIn().forEach((column, value) -> predicates.add(builder.in(column(root, column)).value(value))); - } - if (ObjectHelper.isNotEmpty(queryable.getNotIn())) { - queryable.getNotIn().forEach((column, value) -> predicates.add(builder.in(column(root, column)).value(value).not())); - } - if (ObjectHelper.isNotEmpty(queryable.getBetween())) { - queryable.getBetween().forEach((column, value) -> { - var path = this.>column(root, column); - checkComparable(path, column); - checkComparable(value.getStart(), column); - checkComparable(value.getEnd(), column); - predicates.add(builder.between(column(root, column), (Comparable) value.getStart(), (Comparable) value.getEnd())); - }); - } - if (ObjectHelper.isNotEmpty(queryable.getNotBetween())) { - queryable.getNotBetween().forEach((column, value) -> { - var path = this.>column(root, column); - checkComparable(path, column); - checkComparable(value.getStart(), column); - checkComparable(value.getEnd(), column); - predicates.add(builder.between(column(root, column), (Comparable) value.getStart(), (Comparable) value.getEnd()).not()); - }); - } - - return predicates.size() == 1 - ? predicates.get(0) - : builder.and(predicates.toArray(Predicate[]::new)); - } - - /** - * 检查字段类型是否可比较 - * - * @param path 字段路径 - * @param column 字段名称 - * @throws NotComparableException 当字段类型不可比较时抛出 - */ - private void checkComparable(Path path, String column) { - if (!ObjectHelper.isComparable(path.getJavaType())) { - throw new NotComparableException(column); - } - } - - /** - * 检查值是否可比较 - * - * @param value 值对象 - * @param column 字段名称 - * @throws NotComparableException 当值不可比较时抛出 - */ - private void checkComparable(Object value, String column) { - if (!ObjectHelper.isComparable(value)) { - throw new NotComparableException(column); - } - } - - /** - * 检查区间值是否可比较 - * - * @param value 区间对象 - * @param column 字段名称 - * @throws NotComparableException 当区间值不可比较时抛出 - */ - private void checkComparable(Query.Queryable.Between value, String column) { - checkComparable(value.getStart(), column); - checkComparable(value.getEnd(), column); - } - - /** - * 检查字段类型是否为集合 - * - * @param path 字段路径 - * @param column 字段名称 - * @throws NotCollectionException 当字段类型不是集合时抛出 - */ - private void checkCollection(Path path, String column) { - if (!ObjectHelper.isCollection(path.getJavaType())) { - throw new NotCollectionException(column); - } - } - - /** - * 检查值是否为集合 - * - * @param value 值对象 - * @param column 字段名称 - * @throws NotCollectionException 当值不是集合时抛出 - */ - private void checkCollection(Object value, String column) { - if (!ObjectHelper.isCollection(value)) { - throw new NotCollectionException(column); - } - } - - /** - * 检查字段类型是否为字符串 - * - * @param path 字段路径 - * @param column 字段名称 - * @throws NotStringException 当字段类型不是字符串时抛出 - */ - private void checkString(Path path, String column) { - if (!ObjectHelper.isString(path.getJavaType())) { - throw new NotStringException(column); - } - } - - /** - * 检查值是否为字符串 - * - * @param value 值对象 - * @param column 字段名称 - * @throws NotStringException 当值不是字符串时抛出 - */ - private void checkString(Object value, String column) { - if (!ObjectHelper.isString(value)) { - throw new NotStringException(column); - } - } - - /** - * 构建列表查询条件 - *

    - * 子类可以重写此方法以添加特定的查询条件。 - * 默认返回空列表,表示不添加额外条件。 - *

    - * - * @param root JPA Criteria查询根节点 - * @param query JPA Criteria查询对象 - * @param builder JPA Criteria构建器 - * @return List 返回查询条件谓词列表 - */ - protected Predicate listPredicate(Root root, CriteriaQuery query, CriteriaBuilder builder) { - return null; - } - - /** - * 根据查询条件分页获取实体列表 - *

    - * 支持复杂的查询条件和分页功能。 - * 默认分页参数:第1页,每页10条记录,按创建时间降序排列。 - *

    - * - * @param listQuery 查询条件对象 - * @return Page 返回分页查询结果 - */ - @Override - public Page list(Query listQuery) { - var pageRequest = PageRequest.of(DEFAULT_PAGE_INDEX - 1, DEFAULT_PAGE_SIZE, Sort.by(SimpleEntity.Fields.createdTime).descending()); - if (ObjectHelper.isNotNull(listQuery.getPage())) { - pageRequest = PageRequest.of( - ObjectHelper.defaultIfNull(listQuery.getPage().getIndex(), DEFAULT_PAGE_INDEX) - 1, - ObjectHelper.defaultIfNull(listQuery.getPage().getSize(), DEFAULT_PAGE_SIZE), - Sort.by(SimpleEntity.Fields.createdTime).descending() - ); - } - return repository.findAll( - (root, query, builder) -> { - var predicate = listPredicate(root, query, builder); - var queryPredicate = queryPredicates(listQuery.getQuery(), root, query, builder); - return ObjectHelper.isNull(predicate) - ? queryPredicate - : builder.and(predicate, queryPredicate); - }, - pageRequest - ); - } - - /** - * 根据ID获取实体详情(Optional包装) - *

    - * 如果ID为空则返回空Optional,否则根据ID查询实体。 - *

    - * - * @param id 实体ID - * @return Optional 返回实体详情的Optional包装 - */ - @Override - public Optional detailOptional(Long id) { - if (ObjectHelper.isNull(id)) { - return Optional.empty(); - } - return repository.findOne( - (root, query, builder) -> { - var predicate = listPredicate(root, query, builder); - var idPredicate = builder.equal(root.get(IdOnlyEntity.Fields.id), id); - return ObjectHelper.isNull(predicate) - ? idPredicate - : builder.and(predicate, idPredicate); - } - ); - } - - /** - * 根据ID获取实体详情 - *

    - * 如果实体不存在则返回null。 - *

    - * - * @param id 实体ID - * @return ENTITY 返回实体详情,不存在时返回null - */ - @Override - public ENTITY detail(Long id) { - return detailOrNull(id); - } - - /** - * 根据ID获取实体详情,不存在时抛出异常 - *

    - * 如果实体不存在则抛出IdNotFoundException异常。 - *

    - * - * @param id 实体ID - * @return ENTITY 返回实体详情 - * @throws IdNotFoundException 当实体不存在时抛出 - */ - @Override - public ENTITY detailOrThrow(Long id) { - return detailOptional(id).orElseThrow(() -> new IdNotFoundException(id)); - } - - /** - * 根据ID获取实体详情,不存在时返回null - *

    - * 与[detail](file:///Users/lanyuanxiaoyao/Project/IdeaProjects/spring-boot-service-template/src/main/java/com/lanyuanxiaoyao/service/template/service/SimpleService.java#L21-L21)方法功能相同。 - *

    - * - * @param id 实体ID - * @return ENTITY 返回实体详情,不存在时返回null - */ - @Override - public ENTITY detailOrNull(Long id) { - return detailOptional(id).orElse(null); - } - - /** - * 根据ID删除实体 - *

    - * 具有事务性,遇到任何异常都会回滚。 - * 如果ID为空则不执行任何操作。 - *

    - * - * @param id 实体ID - */ - @Transactional(rollbackOn = Throwable.class) - @Override - public void remove(Long id) { - if (ObjectHelper.isNotNull(id)) { - repository.deleteById(id); - } - } - - /** - * ID未找到异常 - *

    - * 当根据ID查询实体但实体不存在时抛出此异常。 - *

    - */ - public static final class IdNotFoundException extends RuntimeException { - /** - * 构造函数(无参) - */ - public IdNotFoundException() { - super("资源不存在"); - } - - /** - * 构造函数(带ID参数) - * - * @param id 实体ID - */ - public IdNotFoundException(Long id) { - super("ID为 %d 的资源不存在".formatted(id)); - } - } - - /** - * 不可比较异常 - *

    - * 当尝试对不可比较的字段或值执行比较操作时抛出此异常。 - *

    - */ - public static final class NotComparableException extends RuntimeException { - /** - * 构造函数 - * - * @param variable 变量名称 - */ - public NotComparableException(String variable) { - super("变量 %s 不能比较".formatted(variable)); - } - } - - /** - * 非集合异常 - *

    - * 当尝试对非集合类型的字段或值执行集合操作时抛出此异常。 - *

    - */ - public static final class NotCollectionException extends RuntimeException { - /** - * 构造函数 - * - * @param variable 变量名称 - */ - public NotCollectionException(String variable) { - super("变量 %s 不是集合".formatted(variable)); - } - } - - /** - * 非字符串异常 - *

    - * 当尝试对非字符串类型的字段或值执行字符串操作时抛出此异常。 - *

    - */ - public static final class NotStringException extends RuntimeException { - /** - * 构造函数 - * - * @param variable 变量名称 - */ - public NotStringException(String variable) { - super("变量 %s 不是字符串".formatted(variable)); - } + public NotStringException(String variable) { + super("变量 %s 不是字符串".formatted(variable)); } + } } \ No newline at end of file diff --git a/src/test/java/com/lanyuanxiaoyao/service/template/TestApplication.java b/src/test/java/com/lanyuanxiaoyao/service/template/TestApplication.java index 84da087..92b7223 100644 --- a/src/test/java/com/lanyuanxiaoyao/service/template/TestApplication.java +++ b/src/test/java/com/lanyuanxiaoyao/service/template/TestApplication.java @@ -25,161 +25,161 @@ import org.springframework.web.client.RestTemplate; @EnableFenix @EnableJpaAuditing public class TestApplication { - private static final Logger log = LoggerFactory.getLogger(TestApplication.class); - private static final String BASE_URL = "http://localhost:2490"; - private static final RestTemplate REST_CLIENT = new RestTemplate(); - private static final ObjectMapper MAPPER = new ObjectMapper(); + private static final Logger log = LoggerFactory.getLogger(TestApplication.class); + private static final String BASE_URL = "http://localhost:2490"; + private static final RestTemplate REST_CLIENT = new RestTemplate(); + private static final ObjectMapper MAPPER = new ObjectMapper(); - public static void main(String[] args) { - SpringApplication.run(TestApplication.class, args); - } + public static void main(String[] args) { + SpringApplication.run(TestApplication.class, args); + } - @EventListener(ApplicationReadyEvent.class) - public void runTests() throws JsonProcessingException { - // 增 - var cid1 = saveItem("company", "{\"name\": \"Apple\",\"members\": 10}").get("data").asLong(); - var cid2 = saveItem("company", "{\"name\": \"Banana\",\"members\": 20}").get("data").asLong(); - var cid3 = saveItem("company", "{\"name\": \"Cheery\",\"members\": 20}").get("data").asLong(); + @EventListener(ApplicationReadyEvent.class) + public void runTests() throws JsonProcessingException { + // 增 + var cid1 = saveItem("company", "{\"name\": \"Apple\",\"members\": 10}").get("data").asLong(); + var cid2 = saveItem("company", "{\"name\": \"Banana\",\"members\": 20}").get("data").asLong(); + var cid3 = saveItem("company", "{\"name\": \"Cheery\",\"members\": 20}").get("data").asLong(); - // 查 - var companies = listItems("company"); - Assert.isTrue(companies.at("/data/items").size() == 3, "数量错误"); - Assert.isTrue(companies.at("/data/total").asLong() == 3, "返回数量错误"); + // 查 + var companies = listItems("company"); + Assert.isTrue(companies.at("/data/items").size() == 3, "数量错误"); + Assert.isTrue(companies.at("/data/total").asLong() == 3, "返回数量错误"); - // language=JSON - var companies2 = listItems("company", "{\n" + - " \"page\": {\n" + - " \"index\": 1,\n" + - " \"size\": 2\n" + - " }\n" + - "}"); - Assert.isTrue(companies2.at("/data/items").size() == 2, "数量错误"); - Assert.isTrue(companies2.at("/data/total").asLong() == 3, "返回数量错误"); - // language=JSON - var companies3 = listItems("company", "{\n" + - " \"query\": {\n" + - " \"notNullEqual\": [\n" + - " \"name\"\n" + - " ],\n" + - " \"equal\": {\n" + - " \"name\": \"Apple\"\n" + - " },\n" + - " \"like\": {\n" + - " \"name\": \"Appl%\"\n" + - " },\n" + - " \"less\": {\n" + - " \"members\": 50\n" + - " },\n" + - " \"greatEqual\": {\n" + - " \"members\": 0\n" + - " },\n" + - " \"in\": {\n" + - " \"name\": [\n" + - " \"Apple\",\n" + - " \"Banana\"\n" + - " ]\n" + - " },\n" + - " \"between\": {\n" + - " \"members\": {\n" + - " \"start\": 0,\n" + - " \"end\": 50\n" + - " }\n" + - " }\n" + - " },\n" + - " \"page\": {\n" + - " \"index\": 1,\n" + - " \"size\": 2\n" + - " }\n" + - "}"); - Assert.isTrue(companies3.at("/data/items").size() == 1, "数量错误"); - Assert.isTrue(companies3.at("/data/total").asLong() == 1, "返回数量错误"); + // language=JSON + var companies2 = listItems("company", "{\n" + + " \"page\": {\n" + + " \"index\": 1,\n" + + " \"size\": 2\n" + + " }\n" + + "}"); + Assert.isTrue(companies2.at("/data/items").size() == 2, "数量错误"); + Assert.isTrue(companies2.at("/data/total").asLong() == 3, "返回数量错误"); + // language=JSON + var companies3 = listItems("company", "{\n" + + " \"query\": {\n" + + " \"notNullEqual\": [\n" + + " \"name\"\n" + + " ],\n" + + " \"equal\": {\n" + + " \"name\": \"Apple\"\n" + + " },\n" + + " \"like\": {\n" + + " \"name\": \"Appl%\"\n" + + " },\n" + + " \"less\": {\n" + + " \"members\": 50\n" + + " },\n" + + " \"greatEqual\": {\n" + + " \"members\": 0\n" + + " },\n" + + " \"in\": {\n" + + " \"name\": [\n" + + " \"Apple\",\n" + + " \"Banana\"\n" + + " ]\n" + + " },\n" + + " \"between\": {\n" + + " \"members\": {\n" + + " \"start\": 0,\n" + + " \"end\": 50\n" + + " }\n" + + " }\n" + + " },\n" + + " \"page\": {\n" + + " \"index\": 1,\n" + + " \"size\": 2\n" + + " }\n" + + "}"); + Assert.isTrue(companies3.at("/data/items").size() == 1, "数量错误"); + Assert.isTrue(companies3.at("/data/total").asLong() == 1, "返回数量错误"); - var company1 = detailItem("company", cid1); - Assert.isTrue(cid1 == company1.at("/data/id").asLong(), "id错误"); - Assert.isTrue("Apple".equals(company1.at("/data/name").asText()), "name错误"); + var company1 = detailItem("company", cid1); + Assert.isTrue(cid1 == company1.at("/data/id").asLong(), "id错误"); + Assert.isTrue("Apple".equals(company1.at("/data/name").asText()), "name错误"); - // 改 - var cid4 = saveItem("company", "{\"id\": %d, \"name\": \"Dog\"}".formatted(cid2)).get("data").asLong(); - Assert.isTrue(cid2 == cid4, "id错误"); - var company2 = detailItem("company", cid2); - Assert.isTrue("Dog".equals(company2.at("/data/name").asText()), "name错误"); + // 改 + var cid4 = saveItem("company", "{\"id\": %d, \"name\": \"Dog\"}".formatted(cid2)).get("data").asLong(); + Assert.isTrue(cid2 == cid4, "id错误"); + var company2 = detailItem("company", cid2); + Assert.isTrue("Dog".equals(company2.at("/data/name").asText()), "name错误"); - // 删 - removeItem("company", cid3); - Assert.isTrue(listItems("company").at("/data/items").size() == 2, "数量错误"); - Assert.isTrue(listItems("company").at("/data/total").asLong() == 2, "返回数量错误"); + // 删 + removeItem("company", cid3); + Assert.isTrue(listItems("company").at("/data/items").size() == 2, "数量错误"); + Assert.isTrue(listItems("company").at("/data/total").asLong() == 2, "返回数量错误"); - log.info(listItems("company").toPrettyString()); + log.info(listItems("company").toPrettyString()); - var eid1 = saveItem("employee", "{\"name\": \"Tom\",\"age\": 18, \"companyId\": %d}".formatted(cid1)).get("data").asLong(); - var eid2 = saveItem("employee", "{\"name\": \"Jerry\",\"age\": 18, \"companyId\": %d}".formatted(cid1)).get("data").asLong(); - var eid3 = saveItem("employee", "{\"name\": \"Mike\",\"age\": 18, \"companyId\": %d}".formatted(cid2)).get("data").asLong(); + var eid1 = saveItem("employee", "{\"name\": \"Tom\",\"age\": 18, \"companyId\": %d}".formatted(cid1)).get("data").asLong(); + var eid2 = saveItem("employee", "{\"name\": \"Jerry\",\"age\": 18, \"companyId\": %d}".formatted(cid1)).get("data").asLong(); + var eid3 = saveItem("employee", "{\"name\": \"Mike\",\"age\": 18, \"companyId\": %d}".formatted(cid2)).get("data").asLong(); - var employees = listItems("employee"); - Assert.isTrue(employees.at("/data/items").size() == 3, "数量错误"); - Assert.isTrue(employees.at("/data/total").asLong() == 3, "返回数量错误"); + var employees = listItems("employee"); + Assert.isTrue(employees.at("/data/items").size() == 3, "数量错误"); + Assert.isTrue(employees.at("/data/total").asLong() == 3, "返回数量错误"); - var employee1 = detailItem("employee", eid1); - Assert.isTrue(eid1 == employee1.at("/data/id").asLong(), "id错误"); - Assert.isTrue("Tom".equals(employee1.at("/data/name").asText()), "name错误"); - Assert.isTrue(18 == employee1.at("/data/age").asInt(), "age错误"); + var employee1 = detailItem("employee", eid1); + Assert.isTrue(eid1 == employee1.at("/data/id").asLong(), "id错误"); + Assert.isTrue("Tom".equals(employee1.at("/data/name").asText()), "name错误"); + Assert.isTrue(18 == employee1.at("/data/age").asInt(), "age错误"); - System.exit(0); - } + System.exit(0); + } - private HttpHeaders headers() { - var headers = new HttpHeaders(); - headers.setContentType(MediaType.APPLICATION_JSON); - return headers; - } + private HttpHeaders headers() { + var headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + return headers; + } - private JsonNode saveItem(String path, String body) throws JsonProcessingException { - var response = REST_CLIENT.postForEntity( - "%s/%s/save".formatted(BASE_URL, path), - new HttpEntity<>(body, headers()), - String.class - ); - Assert.isTrue(response.getStatusCode().is2xxSuccessful(), "请求失败"); - Assert.notNull(response.getBody(), "请求失败"); - return MAPPER.readTree(response.getBody()); - } + private JsonNode saveItem(String path, String body) throws JsonProcessingException { + var response = REST_CLIENT.postForEntity( + "%s/%s/save".formatted(BASE_URL, path), + new HttpEntity<>(body, headers()), + String.class + ); + Assert.isTrue(response.getStatusCode().is2xxSuccessful(), "请求失败"); + Assert.notNull(response.getBody(), "请求失败"); + return MAPPER.readTree(response.getBody()); + } - private JsonNode listItems(String path) throws JsonProcessingException { - var response = REST_CLIENT.getForEntity( - "%s/%s/list".formatted(BASE_URL, path), - String.class - ); - Assert.isTrue(response.getStatusCode().is2xxSuccessful(), "请求失败"); - Assert.notNull(response.getBody(), "请求失败"); - return MAPPER.readTree(response.getBody()); - } + private JsonNode listItems(String path) throws JsonProcessingException { + var response = REST_CLIENT.getForEntity( + "%s/%s/list".formatted(BASE_URL, path), + String.class + ); + Assert.isTrue(response.getStatusCode().is2xxSuccessful(), "请求失败"); + Assert.notNull(response.getBody(), "请求失败"); + return MAPPER.readTree(response.getBody()); + } - private JsonNode listItems(String path, String query) throws JsonProcessingException { - var response = REST_CLIENT.postForEntity( - "%s/%s/list".formatted(BASE_URL, path), - new HttpEntity<>(query, headers()), - String.class - ); - Assert.isTrue(response.getStatusCode().is2xxSuccessful(), "请求失败"); - Assert.notNull(response.getBody(), "请求失败"); - return MAPPER.readTree(response.getBody()); - } + private JsonNode listItems(String path, String query) throws JsonProcessingException { + var response = REST_CLIENT.postForEntity( + "%s/%s/list".formatted(BASE_URL, path), + new HttpEntity<>(query, headers()), + String.class + ); + Assert.isTrue(response.getStatusCode().is2xxSuccessful(), "请求失败"); + Assert.notNull(response.getBody(), "请求失败"); + return MAPPER.readTree(response.getBody()); + } - private JsonNode detailItem(String path, Long id) throws JsonProcessingException { - var response = REST_CLIENT.getForEntity( - "%s/%s/detail/%d".formatted(BASE_URL, path, id), - String.class - ); - Assert.isTrue(response.getStatusCode().is2xxSuccessful(), "请求失败"); - Assert.notNull(response.getBody(), "请求失败"); - return MAPPER.readTree(response.getBody()); - } + private JsonNode detailItem(String path, Long id) throws JsonProcessingException { + var response = REST_CLIENT.getForEntity( + "%s/%s/detail/%d".formatted(BASE_URL, path, id), + String.class + ); + Assert.isTrue(response.getStatusCode().is2xxSuccessful(), "请求失败"); + Assert.notNull(response.getBody(), "请求失败"); + return MAPPER.readTree(response.getBody()); + } - private void removeItem(String path, Long id) { - var response = REST_CLIENT.getForEntity( - "%s/%s/remove/%d".formatted(BASE_URL, path, id), - Void.class - ); - Assert.isTrue(response.getStatusCode().is2xxSuccessful(), "请求失败"); - } + private void removeItem(String path, Long id) { + var response = REST_CLIENT.getForEntity( + "%s/%s/remove/%d".formatted(BASE_URL, path, id), + Void.class + ); + Assert.isTrue(response.getStatusCode().is2xxSuccessful(), "请求失败"); + } } diff --git a/src/test/java/com/lanyuanxiaoyao/service/template/controller/CompanyController.java b/src/test/java/com/lanyuanxiaoyao/service/template/controller/CompanyController.java index 5923de7..0f2ac73 100644 --- a/src/test/java/com/lanyuanxiaoyao/service/template/controller/CompanyController.java +++ b/src/test/java/com/lanyuanxiaoyao/service/template/controller/CompanyController.java @@ -15,73 +15,73 @@ import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("company") public class CompanyController extends SimpleControllerSupport { - public CompanyController(CompanyService service) { - super(service); - } + public CompanyController(CompanyService service) { + super(service); + } - @Override - protected Function saveItemMapper() { - return item -> { - var company = new Company(); - company.setId(item.getId()); - company.setName(item.getName()); - company.setMembers(item.getMembers()); - return company; - }; - } + @Override + protected Function saveItemMapper() { + return item -> { + var company = new Company(); + company.setId(item.getId()); + company.setName(item.getName()); + company.setMembers(item.getMembers()); + return company; + }; + } - @Override - protected Function listItemMapper() { - return company -> new ListItem( - company.getId(), - company.getName(), - company.getMembers() - ); - } + @Override + protected Function listItemMapper() { + return company -> new ListItem( + company.getId(), + company.getName(), + company.getMembers() + ); + } - @Override - protected Function detailItemMapper() { - return company -> new DetailItem( - company.getId(), - company.getName(), - company.getMembers(), - company.getCreatedTime(), - company.getModifiedTime() - ); - } + @Override + protected Function detailItemMapper() { + return company -> new DetailItem( + company.getId(), + company.getName(), + company.getMembers(), + company.getCreatedTime(), + company.getModifiedTime() + ); + } - @Setter - @Getter - @ToString - @AllArgsConstructor - @NoArgsConstructor - public static class SaveItem { - private Long id; - private String name; - private Integer members; - } + @Setter + @Getter + @ToString + @AllArgsConstructor + @NoArgsConstructor + public static class SaveItem { + private Long id; + private String name; + private Integer members; + } - @Setter - @Getter - @ToString - @AllArgsConstructor - @NoArgsConstructor - public static class ListItem { - private Long id; - private String name; - private Integer members; - } + @Setter + @Getter + @ToString + @AllArgsConstructor + @NoArgsConstructor + public static class ListItem { + private Long id; + private String name; + private Integer members; + } - @Setter - @Getter - @ToString - @AllArgsConstructor - @NoArgsConstructor - public static class DetailItem { - private Long id; - private String name; - private Integer members; - private LocalDateTime createdTime; - private LocalDateTime modifiedTime; - } + @Setter + @Getter + @ToString + @AllArgsConstructor + @NoArgsConstructor + public static class DetailItem { + private Long id; + private String name; + private Integer members; + private LocalDateTime createdTime; + private LocalDateTime modifiedTime; + } } diff --git a/src/test/java/com/lanyuanxiaoyao/service/template/controller/EmployeeController.java b/src/test/java/com/lanyuanxiaoyao/service/template/controller/EmployeeController.java index aa2c342..c2f6359 100644 --- a/src/test/java/com/lanyuanxiaoyao/service/template/controller/EmployeeController.java +++ b/src/test/java/com/lanyuanxiaoyao/service/template/controller/EmployeeController.java @@ -16,85 +16,85 @@ import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("employee") public class EmployeeController extends SimpleControllerSupport { - private final CompanyService companyService; + private final CompanyService companyService; - public EmployeeController(EmployeeService service, CompanyService companyService) { - super(service); - this.companyService = companyService; - } + public EmployeeController(EmployeeService service, CompanyService companyService) { + super(service); + this.companyService = companyService; + } - @Override - protected Function saveItemMapper() { - return item -> { - var employee = new Employee(); - employee.setId(item.getId()); - employee.setName(item.getName()); - employee.setAge(item.getAge()); - employee.setRole(Employee.Role.USER); - employee.setCompany(companyService.detailOrThrow(item.getCompanyId())); - return employee; - }; - } + @Override + protected Function saveItemMapper() { + return item -> { + var employee = new Employee(); + employee.setId(item.getId()); + employee.setName(item.getName()); + employee.setAge(item.getAge()); + employee.setRole(Employee.Role.USER); + employee.setCompany(companyService.detailOrThrow(item.getCompanyId())); + return employee; + }; + } - @Override - protected Function listItemMapper() { - return employee -> new ListItem( - employee.getId(), - employee.getName(), - employee.getAge(), - employee.getRole() - ); - } + @Override + protected Function listItemMapper() { + return employee -> new ListItem( + employee.getId(), + employee.getName(), + employee.getAge(), + employee.getRole() + ); + } - @Override - protected Function detailItemMapper() { - return employee -> new DetailItem( - employee.getId(), - employee.getCompany().getId(), - employee.getName(), - employee.getAge(), - employee.getRole(), - employee.getCreatedTime(), - employee.getModifiedTime() - ); - } + @Override + protected Function detailItemMapper() { + return employee -> new DetailItem( + employee.getId(), + employee.getCompany().getId(), + employee.getName(), + employee.getAge(), + employee.getRole(), + employee.getCreatedTime(), + employee.getModifiedTime() + ); + } - @Setter - @Getter - @ToString - @AllArgsConstructor - @NoArgsConstructor - public static class SaveItem { - private Long id; - private Long companyId; - private String name; - private Integer age; - } + @Setter + @Getter + @ToString + @AllArgsConstructor + @NoArgsConstructor + public static class SaveItem { + private Long id; + private Long companyId; + private String name; + private Integer age; + } - @Setter - @Getter - @ToString - @AllArgsConstructor - @NoArgsConstructor - public static class ListItem { - private Long id; - private String name; - private Integer age; - private Employee.Role role; - } + @Setter + @Getter + @ToString + @AllArgsConstructor + @NoArgsConstructor + public static class ListItem { + private Long id; + private String name; + private Integer age; + private Employee.Role role; + } - @Setter - @Getter - @ToString - @AllArgsConstructor - @NoArgsConstructor - public static class DetailItem { - private Long id; - private Long companyId; - private String name; - private Integer age; - private Employee.Role role; - private LocalDateTime createdTime; - private LocalDateTime modifiedTime; - } + @Setter + @Getter + @ToString + @AllArgsConstructor + @NoArgsConstructor + public static class DetailItem { + private Long id; + private Long companyId; + private String name; + private Integer age; + private Employee.Role role; + private LocalDateTime createdTime; + private LocalDateTime modifiedTime; + } } diff --git a/src/test/java/com/lanyuanxiaoyao/service/template/entity/Company.java b/src/test/java/com/lanyuanxiaoyao/service/template/entity/Company.java index 39adbd3..b18db25 100644 --- a/src/test/java/com/lanyuanxiaoyao/service/template/entity/Company.java +++ b/src/test/java/com/lanyuanxiaoyao/service/template/entity/Company.java @@ -22,14 +22,14 @@ import org.springframework.data.jpa.domain.support.AuditingEntityListener; @EntityListeners(AuditingEntityListener.class) @Comment("企业") public class Company extends SimpleEntity { - @Column(nullable = false) - @Comment("名称") - private String name; - @Column(nullable = false) - @Comment("成员数") - private Integer members; + @Column(nullable = false) + @Comment("名称") + private String name; + @Column(nullable = false) + @Comment("成员数") + private Integer members; - @OneToMany(mappedBy = "company") - @ToString.Exclude - private Set employees; + @OneToMany(mappedBy = "company") + @ToString.Exclude + private Set employees; } diff --git a/src/test/java/com/lanyuanxiaoyao/service/template/entity/Employee.java b/src/test/java/com/lanyuanxiaoyao/service/template/entity/Employee.java index f2a5f2e..6722280 100644 --- a/src/test/java/com/lanyuanxiaoyao/service/template/entity/Employee.java +++ b/src/test/java/com/lanyuanxiaoyao/service/template/entity/Employee.java @@ -28,28 +28,28 @@ import org.springframework.data.jpa.domain.support.AuditingEntityListener; @DynamicUpdate @EntityListeners(AuditingEntityListener.class) @NamedEntityGraph(name = "employee.detail", attributeNodes = { - @NamedAttributeNode("company") + @NamedAttributeNode("company") }) @Comment("员工") public class Employee extends SimpleEntity { - @Column(nullable = false) - @Comment("名称") - private String name; - @Column(nullable = false) - @Comment("年龄") - private Integer age; - @Column(nullable = false) - @Enumerated(EnumType.STRING) - @Comment("角色") - private Role role; + @Column(nullable = false) + @Comment("名称") + private String name; + @Column(nullable = false) + @Comment("年龄") + private Integer age; + @Column(nullable = false) + @Enumerated(EnumType.STRING) + @Comment("角色") + private Role role; - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(nullable = false, foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT)) - @ToString.Exclude - private Company company; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(nullable = false, foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT)) + @ToString.Exclude + private Company company; - public enum Role { - USER, - ADMIN, - } + public enum Role { + USER, + ADMIN, + } } diff --git a/src/test/java/com/lanyuanxiaoyao/service/template/repository/EmployeeRepository.java b/src/test/java/com/lanyuanxiaoyao/service/template/repository/EmployeeRepository.java index 1c0266f..a33420e 100644 --- a/src/test/java/com/lanyuanxiaoyao/service/template/repository/EmployeeRepository.java +++ b/src/test/java/com/lanyuanxiaoyao/service/template/repository/EmployeeRepository.java @@ -9,7 +9,7 @@ import org.springframework.stereotype.Repository; @SuppressWarnings("NullableProblems") @Repository public interface EmployeeRepository extends SimpleRepository { - @EntityGraph(value = "employee.detail", type = EntityGraph.EntityGraphType.FETCH) - @Override - Optional findOne(Specification specification); + @EntityGraph(value = "employee.detail", type = EntityGraph.EntityGraphType.FETCH) + @Override + Optional findOne(Specification specification); } diff --git a/src/test/java/com/lanyuanxiaoyao/service/template/service/CompanyService.java b/src/test/java/com/lanyuanxiaoyao/service/template/service/CompanyService.java index 88af78d..1793f37 100644 --- a/src/test/java/com/lanyuanxiaoyao/service/template/service/CompanyService.java +++ b/src/test/java/com/lanyuanxiaoyao/service/template/service/CompanyService.java @@ -6,7 +6,7 @@ import org.springframework.stereotype.Service; @Service public class CompanyService extends SimpleServiceSupport { - public CompanyService(CompanyRepository repository) { - super(repository); - } + public CompanyService(CompanyRepository repository) { + super(repository); + } } diff --git a/src/test/java/com/lanyuanxiaoyao/service/template/service/EmployeeService.java b/src/test/java/com/lanyuanxiaoyao/service/template/service/EmployeeService.java index 3b3d0a9..f9886b3 100644 --- a/src/test/java/com/lanyuanxiaoyao/service/template/service/EmployeeService.java +++ b/src/test/java/com/lanyuanxiaoyao/service/template/service/EmployeeService.java @@ -6,7 +6,7 @@ import org.springframework.stereotype.Service; @Service public class EmployeeService extends SimpleServiceSupport { - public EmployeeService(EmployeeRepository repository) { - super(repository); - } + public EmployeeService(EmployeeRepository repository) { + super(repository); + } }