Compare commits
10 Commits
1a08b01e08
...
ce25ce5521
| Author | SHA1 | Date | |
|---|---|---|---|
| ce25ce5521 | |||
| aea9aa8829 | |||
| d53301b8a3 | |||
| b839300046 | |||
| 7b31aead91 | |||
| 12618ccb3e | |||
| 280eeea6f7 | |||
| 8244b5dbdf | |||
| 6baefd1a8a | |||
| 6fbaa3de65 |
5
pom.xml
5
pom.xml
@@ -96,6 +96,11 @@
|
|||||||
<artifactId>lombok</artifactId>
|
<artifactId>lombok</artifactId>
|
||||||
<version>1.18.36</version>
|
<version>1.18.36</version>
|
||||||
</path>
|
</path>
|
||||||
|
<path>
|
||||||
|
<groupId>org.hibernate</groupId>
|
||||||
|
<artifactId>hibernate-jpamodelgen</artifactId>
|
||||||
|
<version>6.6.8.Final</version>
|
||||||
|
</path>
|
||||||
<path>
|
<path>
|
||||||
<groupId>io.github.openfeign.querydsl</groupId>
|
<groupId>io.github.openfeign.querydsl</groupId>
|
||||||
<artifactId>querydsl-apt</artifactId>
|
<artifactId>querydsl-apt</artifactId>
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.controller;
|
package com.lanyuanxiaoyao.service.template.controller;
|
||||||
|
|
||||||
import com.lanyuanxiaoyao.service.template.controller.response.GlobalResponse;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 详情控制器接口,用于定义统一的获取实体详情的接口规范
|
* 详情控制器接口,用于定义统一的获取实体详情的接口规范
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -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<T> {
|
||||||
|
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<Object> responseError() {
|
||||||
|
return responseError(ERROR_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GlobalResponse<Object> responseError(String message) {
|
||||||
|
return new GlobalResponse<>(ERROR_STATUS, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GlobalResponse<Object> responseSuccess() {
|
||||||
|
return responseSuccess(SUCCESS_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GlobalResponse<Object> responseSuccess(String message) {
|
||||||
|
return responseSuccess(message, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <E> GlobalResponse<E> responseSuccess(E data) {
|
||||||
|
return responseSuccess(SUCCESS_MESSAGE, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <E> GlobalResponse<E> responseSuccess(String message, E data) {
|
||||||
|
return new GlobalResponse<>(SUCCESS_STATUS, message, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GlobalResponse<Map<String, Object>> responseMapData(Map<String, Object> data) {
|
||||||
|
return responseSuccess(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GlobalResponse<Map<String, Object>> responseMapData(String key, Object value) {
|
||||||
|
return responseMapData(Map.of(key, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> GlobalResponse<Map<String, Object>> responseCrudData(Iterable<T> data, Integer total) {
|
||||||
|
return responseCrudData(data, total.longValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> GlobalResponse<Map<String, Object>> responseCrudData(Iterable<T> data, Long total) {
|
||||||
|
return responseMapData(Map.of("items", data, "total", total));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GlobalResponse<Map<String, Object>> responseDetailData(Object detail) {
|
||||||
|
return responseMapData("detail", detail);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.controller;
|
package com.lanyuanxiaoyao.service.template.controller;
|
||||||
|
|
||||||
import com.lanyuanxiaoyao.service.template.controller.response.GlobalCrudResponse;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 列表控制器接口,用于定义统一的获取实体列表的接口规范
|
* 列表控制器接口,用于定义统一的获取实体列表的接口规范
|
||||||
@@ -65,7 +65,7 @@ public interface ListController<LIST_ITEM> {
|
|||||||
* @return GlobalCrudResponse<LIST_ITEM> 返回实体列表
|
* @return GlobalCrudResponse<LIST_ITEM> 返回实体列表
|
||||||
* @throws Exception 查询过程中可能抛出的异常
|
* @throws Exception 查询过程中可能抛出的异常
|
||||||
*/
|
*/
|
||||||
GlobalCrudResponse<LIST_ITEM> list() throws Exception;
|
GlobalResponse<Map<String, Object>> list() throws Exception;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据查询条件获取实体列表
|
* 根据查询条件获取实体列表
|
||||||
@@ -74,5 +74,5 @@ public interface ListController<LIST_ITEM> {
|
|||||||
* @return GlobalCrudResponse<LIST_ITEM> 返回符合条件的实体列表
|
* @return GlobalCrudResponse<LIST_ITEM> 返回符合条件的实体列表
|
||||||
* @throws Exception 查询过程中可能抛出的异常
|
* @throws Exception 查询过程中可能抛出的异常
|
||||||
*/
|
*/
|
||||||
GlobalCrudResponse<LIST_ITEM> list(Query query) throws Exception;
|
GlobalResponse<Map<String, Object>> list(Query query) throws Exception;
|
||||||
}
|
}
|
||||||
@@ -122,6 +122,30 @@ public class Query {
|
|||||||
* 指定字段不模糊匹配的条件映射(字段名 -> 匹配值)
|
* 指定字段不模糊匹配的条件映射(字段名 -> 匹配值)
|
||||||
*/
|
*/
|
||||||
private Map<String, String> notLike;
|
private Map<String, String> notLike;
|
||||||
|
/**
|
||||||
|
* 指定字段包含指定字符串的条件映射(字段名 -> 包含值)
|
||||||
|
*/
|
||||||
|
private Map<String, String> contain;
|
||||||
|
/**
|
||||||
|
* 指定字段不包含指定字符串的条件映射(字段名 -> 不包含值)
|
||||||
|
*/
|
||||||
|
private Map<String, String> notContain;
|
||||||
|
/**
|
||||||
|
* 指定字段以指定字符串开头的条件映射(字段名 -> 开头值)
|
||||||
|
*/
|
||||||
|
private Map<String, String> startWith;
|
||||||
|
/**
|
||||||
|
* 指定字段不以指定字符串开头的条件映射(字段名 -> 不开头值)
|
||||||
|
*/
|
||||||
|
private Map<String, String> notStartWith;
|
||||||
|
/**
|
||||||
|
* 指定字段以指定字符串结尾的条件映射(字段名 -> 结尾值)
|
||||||
|
*/
|
||||||
|
private Map<String, String> endWith;
|
||||||
|
/**
|
||||||
|
* 指定字段不以指定字符串结尾的条件映射(字段名 -> 不结尾值)
|
||||||
|
*/
|
||||||
|
private Map<String, String> notEndWith;
|
||||||
/**
|
/**
|
||||||
* 指定字段大于条件的映射(字段名 -> 值)
|
* 指定字段大于条件的映射(字段名 -> 值)
|
||||||
*/
|
*/
|
||||||
@@ -141,11 +165,11 @@ public class Query {
|
|||||||
/**
|
/**
|
||||||
* 指定字段值在指定范围内的条件映射(字段名 -> 值列表)
|
* 指定字段值在指定范围内的条件映射(字段名 -> 值列表)
|
||||||
*/
|
*/
|
||||||
private Map<String, List<Object>> in;
|
private Map<String, List<Object>> inside;
|
||||||
/**
|
/**
|
||||||
* 指定字段值不在指定范围内的条件映射(字段名 -> 值列表)
|
* 指定字段值不在指定范围内的条件映射(字段名 -> 值列表)
|
||||||
*/
|
*/
|
||||||
private Map<String, List<Object>> notIn;
|
private Map<String, List<Object>> notInside;
|
||||||
/**
|
/**
|
||||||
* 指定字段值在指定区间内的条件映射(字段名 -> 区间范围)
|
* 指定字段值在指定区间内的条件映射(字段名 -> 区间范围)
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.controller;
|
package com.lanyuanxiaoyao.service.template.controller;
|
||||||
|
|
||||||
import com.lanyuanxiaoyao.service.template.controller.response.GlobalResponse;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除控制器接口,用于定义统一的删除实体对象的接口规范
|
* 删除控制器接口,用于定义统一的删除实体对象的接口规范
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.controller;
|
package com.lanyuanxiaoyao.service.template.controller;
|
||||||
|
|
||||||
import com.lanyuanxiaoyao.service.template.controller.response.GlobalResponse;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 保存控制器接口,用于定义统一的保存实体对象的接口规范
|
* 保存控制器接口,用于定义统一的保存实体对象的接口规范
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.controller;
|
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.entity.SimpleEntity;
|
||||||
import com.lanyuanxiaoyao.service.template.helper.ObjectHelper;
|
import com.lanyuanxiaoyao.service.template.helper.ObjectHelper;
|
||||||
import com.lanyuanxiaoyao.service.template.service.SimpleServiceSupport;
|
import com.lanyuanxiaoyao.service.template.service.SimpleServiceSupport;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
@@ -128,10 +127,10 @@ public abstract class SimpleControllerSupport<ENTITY extends SimpleEntity, SAVE_
|
|||||||
*/
|
*/
|
||||||
@GetMapping(LIST)
|
@GetMapping(LIST)
|
||||||
@Override
|
@Override
|
||||||
public GlobalCrudResponse<LIST_ITEM> list() throws Exception {
|
public GlobalResponse<Map<String, Object>> list() throws Exception {
|
||||||
var mapper = listItemMapper();
|
var mapper = listItemMapper();
|
||||||
var result = service.list();
|
var result = service.list();
|
||||||
return GlobalCrudResponse.responseCrudData(
|
return GlobalResponse.responseCrudData(
|
||||||
result
|
result
|
||||||
.stream()
|
.stream()
|
||||||
.map(entity -> {
|
.map(entity -> {
|
||||||
@@ -155,13 +154,13 @@ public abstract class SimpleControllerSupport<ENTITY extends SimpleEntity, SAVE_
|
|||||||
*/
|
*/
|
||||||
@PostMapping(LIST)
|
@PostMapping(LIST)
|
||||||
@Override
|
@Override
|
||||||
public GlobalCrudResponse<LIST_ITEM> list(@RequestBody Query query) throws Exception {
|
public GlobalResponse<Map<String, Object>> list(@RequestBody Query query) throws Exception {
|
||||||
if (ObjectHelper.isNull(query)) {
|
if (ObjectHelper.isNull(query)) {
|
||||||
return GlobalCrudResponse.responseCrudData(List.of(), 0);
|
return GlobalResponse.responseCrudData(List.of(), 0);
|
||||||
}
|
}
|
||||||
var mapper = listItemMapper();
|
var mapper = listItemMapper();
|
||||||
var result = service.list(query);
|
var result = service.list(query);
|
||||||
return GlobalCrudResponse.responseCrudData(
|
return GlobalResponse.responseCrudData(
|
||||||
result.get()
|
result.get()
|
||||||
.map(entity -> {
|
.map(entity -> {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.controller.response;
|
|
||||||
|
|
||||||
public class GlobalCrudResponse<T> extends GlobalMapResponse {
|
|
||||||
public void setData(Iterable<T> list) {
|
|
||||||
setData("items", list);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTotal(Long total) {
|
|
||||||
setData("total", total);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTotal(Integer total) {
|
|
||||||
setTotal(total.longValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setData(Iterable<T> list, Long total) {
|
|
||||||
setData(list);
|
|
||||||
setTotal(total);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setData(Iterable<T> list, Integer total) {
|
|
||||||
setData(list, total.longValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.controller.response;
|
|
||||||
|
|
||||||
public class GlobalDetailResponse extends GlobalMapResponse {
|
|
||||||
public void setDetail(Object detail) {
|
|
||||||
setData("detail", detail);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
package com.lanyuanxiaoyao.service.template.controller.response;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class GlobalMapResponse extends GlobalResponse<Map<String, Object>> {
|
|
||||||
public GlobalMapResponse() {
|
|
||||||
setData(new HashMap<>());
|
|
||||||
}
|
|
||||||
|
|
||||||
public GlobalMapResponse setData(String key, Object value) {
|
|
||||||
getData().put(key, value);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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<T> {
|
|
||||||
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<Object> responseError() {
|
|
||||||
return responseError(ERROR_MESSAGE);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static GlobalResponse<Object> responseError(String message) {
|
|
||||||
GlobalResponse<Object> response = new GlobalResponse<>();
|
|
||||||
response.setStatus(ERROR_STATUS);
|
|
||||||
response.setMessage(message);
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static GlobalResponse<Object> responseSuccess() {
|
|
||||||
GlobalResponse<Object> response = new GlobalResponse<>();
|
|
||||||
response.setStatus(SUCCESS_STATUS);
|
|
||||||
response.setMessage(SUCCESS_MESSAGE);
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static GlobalResponse<Object> responseSuccess(String message) {
|
|
||||||
GlobalResponse<Object> response = new GlobalResponse<>();
|
|
||||||
response.setStatus(SUCCESS_STATUS);
|
|
||||||
response.setMessage(message);
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <E> GlobalResponse<E> responseSuccess(String message, E data) {
|
|
||||||
GlobalResponse<E> response = new GlobalResponse<>();
|
|
||||||
response.setStatus(SUCCESS_STATUS);
|
|
||||||
response.setMessage(message);
|
|
||||||
response.setData(data);
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <E> GlobalResponse<E> responseSuccess(E data) {
|
|
||||||
GlobalResponse<E> 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<String, Object> 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 <T> GlobalCrudResponse<T> responseCrudData(Iterable<T> data) {
|
|
||||||
GlobalCrudResponse<T> response = new GlobalCrudResponse<>();
|
|
||||||
response.setStatus(SUCCESS_STATUS);
|
|
||||||
response.setMessage(SUCCESS_MESSAGE);
|
|
||||||
response.setData(data);
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <T> GlobalCrudResponse<T> responseCrudData(Iterable<T> data, Integer total) {
|
|
||||||
GlobalCrudResponse<T> response = responseCrudData(data);
|
|
||||||
response.setTotal(total);
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <T> GlobalCrudResponse<T> responseCrudData(Iterable<T> data, Long total) {
|
|
||||||
GlobalCrudResponse<T> response = responseCrudData(data);
|
|
||||||
response.setTotal(total);
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static GlobalDetailResponse responseDetailData(Object detail) {
|
|
||||||
GlobalDetailResponse response = new GlobalDetailResponse();
|
|
||||||
response.setDetail(detail);
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,7 +3,6 @@ package com.lanyuanxiaoyao.service.template.service;
|
|||||||
import com.lanyuanxiaoyao.service.template.controller.Query;
|
import com.lanyuanxiaoyao.service.template.controller.Query;
|
||||||
import com.lanyuanxiaoyao.service.template.entity.SimpleEntity;
|
import com.lanyuanxiaoyao.service.template.entity.SimpleEntity;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
|
|
||||||
@@ -18,13 +17,9 @@ public interface SimpleService<ENTITY extends SimpleEntity> {
|
|||||||
|
|
||||||
Page<ENTITY> list(Query query) throws Exception;
|
Page<ENTITY> list(Query query) throws Exception;
|
||||||
|
|
||||||
Optional<ENTITY> 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;
|
|
||||||
|
|
||||||
void remove(Long id) throws Exception;
|
void remove(Long id) throws Exception;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ import jakarta.persistence.criteria.Path;
|
|||||||
import jakarta.persistence.criteria.Predicate;
|
import jakarta.persistence.criteria.Predicate;
|
||||||
import jakarta.persistence.criteria.Root;
|
import jakarta.persistence.criteria.Root;
|
||||||
import jakarta.transaction.Transactional;
|
import jakarta.transaction.Transactional;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -87,6 +89,7 @@ import org.springframework.data.domain.Sort;
|
|||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implements SimpleService<ENTITY> {
|
public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implements SimpleService<ENTITY> {
|
||||||
|
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||||
private static final Integer DEFAULT_PAGE_INDEX = 1;
|
private static final Integer DEFAULT_PAGE_INDEX = 1;
|
||||||
private static final Integer DEFAULT_PAGE_SIZE = 10;
|
private static final Integer DEFAULT_PAGE_SIZE = 10;
|
||||||
protected final SimpleRepository<ENTITY, Long> repository;
|
protected final SimpleRepository<ENTITY, Long> repository;
|
||||||
@@ -182,7 +185,7 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implemen
|
|||||||
if (ObjectHelper.isEmpty(column)) {
|
if (ObjectHelper.isEmpty(column)) {
|
||||||
throw new IllegalArgumentException("Column cannot be blank");
|
throw new IllegalArgumentException("Column cannot be blank");
|
||||||
}
|
}
|
||||||
var columns = column.split("/");
|
var columns = column.split("\\.");
|
||||||
Path<Y> path = root.get(columns[0]);
|
Path<Y> path = root.get(columns[0]);
|
||||||
for (int i = 1; i < columns.length; i++) {
|
for (int i = 1; i < columns.length; i++) {
|
||||||
path = path.get(columns[i]);
|
path = path.get(columns[i]);
|
||||||
@@ -213,6 +216,8 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implemen
|
|||||||
} else {
|
} else {
|
||||||
throw new IllegalArgumentException("枚举类型字段需要 String 类型的值");
|
throw new IllegalArgumentException("枚举类型字段需要 String 类型的值");
|
||||||
}
|
}
|
||||||
|
} else if (javaType.isAssignableFrom(LocalDateTime.class)) {
|
||||||
|
return LocalDateTime.parse(String.valueOf(value), DATE_TIME_FORMATTER);
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
@@ -271,71 +276,105 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implemen
|
|||||||
if (ObjectHelper.isNotEmpty(queryable.getLike())) {
|
if (ObjectHelper.isNotEmpty(queryable.getLike())) {
|
||||||
queryable.getLike().forEach((column, value) -> {
|
queryable.getLike().forEach((column, value) -> {
|
||||||
var path = column(root, column);
|
var path = column(root, column);
|
||||||
checkString(path, column);
|
checkString(path, value, column);
|
||||||
checkString(value, column);
|
|
||||||
predicates.add(builder.like(column(root, column), value));
|
predicates.add(builder.like(column(root, column), value));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (ObjectHelper.isNotEmpty(queryable.getNotLike())) {
|
if (ObjectHelper.isNotEmpty(queryable.getNotLike())) {
|
||||||
queryable.getNotLike().forEach((column, value) -> {
|
queryable.getNotLike().forEach((column, value) -> {
|
||||||
var path = column(root, column);
|
var path = column(root, column);
|
||||||
checkString(path, column);
|
checkString(path, value, column);
|
||||||
checkString(value, column);
|
|
||||||
predicates.add(builder.notLike(column(root, column), value));
|
predicates.add(builder.notLike(column(root, column), value));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (ObjectHelper.isNotEmpty(queryable.getContain())) {
|
||||||
|
queryable.getContain().forEach((column, value) -> {
|
||||||
|
var path = this.<String>column(root, column);
|
||||||
|
checkString(path, value, column);
|
||||||
|
predicates.add(builder.like(column(root, column), "%" + value + "%"));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (ObjectHelper.isNotEmpty(queryable.getNotContain())) {
|
||||||
|
queryable.getNotContain().forEach((column, value) -> {
|
||||||
|
var path = this.<String>column(root, column);
|
||||||
|
checkString(path, value, column);
|
||||||
|
predicates.add(builder.notLike(column(root, column), "%" + value + "%"));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (ObjectHelper.isNotEmpty(queryable.getStartWith())) {
|
||||||
|
queryable.getStartWith().forEach((column, value) -> {
|
||||||
|
var path = this.<String>column(root, column);
|
||||||
|
checkString(path, value, column);
|
||||||
|
predicates.add(builder.like(column(root, column), value + "%"));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (ObjectHelper.isNotEmpty(queryable.getNotStartWith())) {
|
||||||
|
queryable.getNotStartWith().forEach((column, value) -> {
|
||||||
|
var path = this.<String>column(root, column);
|
||||||
|
checkString(path, value, column);
|
||||||
|
predicates.add(builder.notLike(column(root, column), value + "%"));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (ObjectHelper.isNotEmpty(queryable.getEndWith())) {
|
||||||
|
queryable.getEndWith().forEach((column, value) -> {
|
||||||
|
var path = this.<String>column(root, column);
|
||||||
|
checkString(path, value, column);
|
||||||
|
predicates.add(builder.like(column(root, column), "%" + value));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (ObjectHelper.isNotEmpty(queryable.getNotEndWith())) {
|
||||||
|
queryable.getNotEndWith().forEach((column, value) -> {
|
||||||
|
var path = this.<String>column(root, column);
|
||||||
|
checkString(path, value, column);
|
||||||
|
predicates.add(builder.notLike(column(root, column), "%" + value));
|
||||||
|
});
|
||||||
|
}
|
||||||
if (ObjectHelper.isNotEmpty(queryable.getGreat())) {
|
if (ObjectHelper.isNotEmpty(queryable.getGreat())) {
|
||||||
queryable.getGreat().forEach((column, value) -> {
|
queryable.getGreat().forEach((column, value) -> {
|
||||||
var path = this.<Comparable<Object>>column(root, column);
|
var path = this.<Comparable<Object>>column(root, column);
|
||||||
checkComparable(path, column);
|
checkComparable(path, value, column);
|
||||||
checkComparable(value, column);
|
predicates.add(builder.greaterThan(path, (Comparable<Object>) value(path, value)));
|
||||||
predicates.add(builder.greaterThan(path, (Comparable<Object>) value));
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (ObjectHelper.isNotEmpty(queryable.getLess())) {
|
if (ObjectHelper.isNotEmpty(queryable.getLess())) {
|
||||||
queryable.getLess().forEach((column, value) -> {
|
queryable.getLess().forEach((column, value) -> {
|
||||||
var path = this.<Comparable<Object>>column(root, column);
|
var path = this.<Comparable<Object>>column(root, column);
|
||||||
checkComparable(path, column);
|
checkComparable(path, value, column);
|
||||||
checkComparable(value, column);
|
predicates.add(builder.lessThan(path, (Comparable<Object>) value(path, value)));
|
||||||
predicates.add(builder.lessThan(path, (Comparable<Object>) value));
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (ObjectHelper.isNotEmpty(queryable.getGreatEqual())) {
|
if (ObjectHelper.isNotEmpty(queryable.getGreatEqual())) {
|
||||||
queryable.getGreatEqual().forEach((column, value) -> {
|
queryable.getGreatEqual().forEach((column, value) -> {
|
||||||
var path = this.<Comparable<Object>>column(root, column);
|
var path = this.<Comparable<Object>>column(root, column);
|
||||||
checkComparable(path, column);
|
checkComparable(path, value, column);
|
||||||
checkComparable(value, column);
|
predicates.add(builder.greaterThanOrEqualTo(path, (Comparable<Object>) value(path, value)));
|
||||||
predicates.add(builder.greaterThanOrEqualTo(path, (Comparable<Object>) value));
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (ObjectHelper.isNotEmpty(queryable.getLessEqual())) {
|
if (ObjectHelper.isNotEmpty(queryable.getLessEqual())) {
|
||||||
queryable.getLessEqual().forEach((column, value) -> {
|
queryable.getLessEqual().forEach((column, value) -> {
|
||||||
var path = this.<Comparable<Object>>column(root, column);
|
var path = this.<Comparable<Object>>column(root, column);
|
||||||
checkComparable(path, column);
|
checkComparable(path, value, column);
|
||||||
checkComparable(value, column);
|
predicates.add(builder.lessThanOrEqualTo(path, (Comparable<Object>) value(path, value)));
|
||||||
predicates.add(builder.lessThanOrEqualTo(path, (Comparable<Object>) value));
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (ObjectHelper.isNotEmpty(queryable.getIn())) {
|
if (ObjectHelper.isNotEmpty(queryable.getInside())) {
|
||||||
queryable.getIn().forEach((column, value) -> predicates.add(builder.in(column(root, column)).value(value)));
|
queryable.getInside().forEach((column, value) -> predicates.add(builder.in(column(root, column)).value(value)));
|
||||||
}
|
}
|
||||||
if (ObjectHelper.isNotEmpty(queryable.getNotIn())) {
|
if (ObjectHelper.isNotEmpty(queryable.getNotInside())) {
|
||||||
queryable.getNotIn().forEach((column, value) -> predicates.add(builder.in(column(root, column)).value(value).not()));
|
queryable.getNotInside().forEach((column, value) -> predicates.add(builder.in(column(root, column)).value(value).not()));
|
||||||
}
|
}
|
||||||
if (ObjectHelper.isNotEmpty(queryable.getBetween())) {
|
if (ObjectHelper.isNotEmpty(queryable.getBetween())) {
|
||||||
queryable.getBetween().forEach((column, value) -> {
|
queryable.getBetween().forEach((column, value) -> {
|
||||||
var path = this.<Comparable<Object>>column(root, column);
|
var path = this.<Comparable<Object>>column(root, column);
|
||||||
checkComparable(path, column);
|
checkComparable(path, value, column);
|
||||||
checkComparable(value, column);
|
predicates.add(builder.between(column(root, column), (Comparable<Object>) value(path, value.getStart()), (Comparable<Object>) value(path, value.getEnd())));
|
||||||
predicates.add(builder.between(column(root, column), (Comparable<Object>) value.getStart(), (Comparable<Object>) value.getEnd()));
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (ObjectHelper.isNotEmpty(queryable.getNotBetween())) {
|
if (ObjectHelper.isNotEmpty(queryable.getNotBetween())) {
|
||||||
queryable.getNotBetween().forEach((column, value) -> {
|
queryable.getNotBetween().forEach((column, value) -> {
|
||||||
var path = this.<Comparable<Object>>column(root, column);
|
var path = this.<Comparable<Object>>column(root, column);
|
||||||
checkComparable(path, column);
|
checkComparable(path, value, column);
|
||||||
checkComparable(value, column);
|
predicates.add(builder.between(column(root, column), (Comparable<Object>) value(path, value.getStart()), (Comparable<Object>) value(path, value.getEnd())).not());
|
||||||
predicates.add(builder.between(column(root, column), (Comparable<Object>) value.getStart(), (Comparable<Object>) value.getEnd()).not());
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -351,21 +390,8 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implemen
|
|||||||
* @param column 字段名称
|
* @param column 字段名称
|
||||||
* @throws NotComparableException 当字段类型不可比较时抛出
|
* @throws NotComparableException 当字段类型不可比较时抛出
|
||||||
*/
|
*/
|
||||||
private void checkComparable(Path<?> path, String column) {
|
private void checkComparable(Path<?> path, Object value, String column) {
|
||||||
if (!ObjectHelper.isComparable(path.getJavaType())) {
|
if (!ObjectHelper.isComparable(path.getJavaType()) || !ObjectHelper.isComparable(value)) {
|
||||||
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);
|
throw new NotComparableException(column);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -377,9 +403,9 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implemen
|
|||||||
* @param column 字段名称
|
* @param column 字段名称
|
||||||
* @throws NotComparableException 当区间值不可比较时抛出
|
* @throws NotComparableException 当区间值不可比较时抛出
|
||||||
*/
|
*/
|
||||||
private void checkComparable(Query.Queryable.Between value, String column) {
|
private void checkComparable(Path<?> path, Query.Queryable.Between value, String column) {
|
||||||
checkComparable(value.getStart(), column);
|
checkComparable(path, value.getStart(), column);
|
||||||
checkComparable(value.getEnd(), column);
|
checkComparable(path, value.getEnd(), column);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -415,21 +441,8 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implemen
|
|||||||
* @param column 字段名称
|
* @param column 字段名称
|
||||||
* @throws NotStringException 当字段类型不是字符串时抛出
|
* @throws NotStringException 当字段类型不是字符串时抛出
|
||||||
*/
|
*/
|
||||||
private void checkString(Path<?> path, String column) {
|
private void checkString(Path<?> path, Object value, String column) {
|
||||||
if (!ObjectHelper.isString(path.getJavaType())) {
|
if (!ObjectHelper.isString(path.getJavaType()) || !ObjectHelper.isString(value)) {
|
||||||
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);
|
throw new NotStringException(column);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -491,8 +504,7 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implemen
|
|||||||
* @param id 实体ID
|
* @param id 实体ID
|
||||||
* @return Optional<ENTITY> 返回实体详情的Optional包装
|
* @return Optional<ENTITY> 返回实体详情的Optional包装
|
||||||
*/
|
*/
|
||||||
@Override
|
private Optional<ENTITY> detailOptional(Long id) {
|
||||||
public Optional<ENTITY> detailOptional(Long id) {
|
|
||||||
if (ObjectHelper.isNull(id)) {
|
if (ObjectHelper.isNull(id)) {
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
@@ -518,7 +530,7 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implemen
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public ENTITY detail(Long id) {
|
public ENTITY detail(Long id) {
|
||||||
return detailOrNull(id);
|
return detailOptional(id).orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -536,20 +548,6 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implemen
|
|||||||
return detailOptional(id).orElseThrow(() -> new IdNotFoundException(id));
|
return detailOptional(id).orElseThrow(() -> new IdNotFoundException(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据ID获取实体详情,不存在时返回null
|
|
||||||
* <p>
|
|
||||||
* 与[detail](file:///Users/lanyuanxiaoyao/Project/IdeaProjects/spring-boot-service-template/src/main/java/com/lanyuanxiaoyao/service/template/service/SimpleService.java#L21-L21)方法功能相同。
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @param id 实体ID
|
|
||||||
* @return ENTITY 返回实体详情,不存在时返回null
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public ENTITY detailOrNull(Long id) {
|
|
||||||
return detailOptional(id).orElse(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据ID删除实体
|
* 根据ID删除实体
|
||||||
* <p>
|
* <p>
|
||||||
@@ -574,13 +572,6 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implemen
|
|||||||
* </p>
|
* </p>
|
||||||
*/
|
*/
|
||||||
public static final class IdNotFoundException extends RuntimeException {
|
public static final class IdNotFoundException extends RuntimeException {
|
||||||
/**
|
|
||||||
* 构造函数(无参)
|
|
||||||
*/
|
|
||||||
public IdNotFoundException() {
|
|
||||||
super("资源不存在");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构造函数(带ID参数)
|
* 构造函数(带ID参数)
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -4,6 +4,15 @@ import com.blinkfox.fenix.EnableFenix;
|
|||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.lanyuanxiaoyao.service.template.entity.Company_;
|
||||||
|
import com.lanyuanxiaoyao.service.template.entity.Employee;
|
||||||
|
import com.lanyuanxiaoyao.service.template.entity.Employee_;
|
||||||
|
import com.lanyuanxiaoyao.service.template.entity.QEmployee;
|
||||||
|
import com.lanyuanxiaoyao.service.template.entity.Report;
|
||||||
|
import com.lanyuanxiaoyao.service.template.entity.Report_;
|
||||||
|
import com.lanyuanxiaoyao.service.template.repository.EmployeeRepository;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import java.util.List;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
@@ -29,6 +38,8 @@ public class TestApplication {
|
|||||||
private static final String BASE_URL = "http://localhost:2490";
|
private static final String BASE_URL = "http://localhost:2490";
|
||||||
private static final RestTemplate REST_CLIENT = new RestTemplate();
|
private static final RestTemplate REST_CLIENT = new RestTemplate();
|
||||||
private static final ObjectMapper MAPPER = new ObjectMapper();
|
private static final ObjectMapper MAPPER = new ObjectMapper();
|
||||||
|
@Resource
|
||||||
|
private EmployeeRepository employeeRepository;
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
SpringApplication.run(TestApplication.class, args);
|
SpringApplication.run(TestApplication.class, args);
|
||||||
@@ -67,11 +78,21 @@ public class TestApplication {
|
|||||||
" \"like\": {\n" +
|
" \"like\": {\n" +
|
||||||
" \"name\": \"Appl%\"\n" +
|
" \"name\": \"Appl%\"\n" +
|
||||||
" },\n" +
|
" },\n" +
|
||||||
|
" \"contain\": {\n" +
|
||||||
|
" \"name\": \"ple\"\n" +
|
||||||
|
" },\n" +
|
||||||
|
" \"startWith\": {\n" +
|
||||||
|
" \"name\": \"Appl\"\n" +
|
||||||
|
" },\n" +
|
||||||
|
" \"endWith\": {\n" +
|
||||||
|
" \"name\": \"le\"\n" +
|
||||||
|
" },\n" +
|
||||||
" \"less\": {\n" +
|
" \"less\": {\n" +
|
||||||
" \"members\": 50\n" +
|
" \"members\": 50\n" +
|
||||||
" },\n" +
|
" },\n" +
|
||||||
" \"greatEqual\": {\n" +
|
" \"greatEqual\": {\n" +
|
||||||
" \"members\": 0\n" +
|
" \"members\": 0,\n" +
|
||||||
|
" \"createdTime\": \"2025-01-01 00:00:00\"\n" +
|
||||||
" },\n" +
|
" },\n" +
|
||||||
" \"in\": {\n" +
|
" \"in\": {\n" +
|
||||||
" \"name\": [\n" +
|
" \"name\": [\n" +
|
||||||
@@ -127,6 +148,86 @@ public class TestApplication {
|
|||||||
System.exit(0);
|
System.exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@EventListener(ApplicationReadyEvent.class)
|
||||||
|
public void runSpecificationTests() 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 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 rid = saveItem("report", "{\"employeeId\": %d, \"score\": 56.38, \"level\": \"A\"}".formatted(eid1)).get("data").asLong();
|
||||||
|
var rid2 = saveItem("report", "{\"employeeId\": %d, \"score\": 78.98, \"level\": \"B\"}".formatted(eid2)).get("data").asLong();
|
||||||
|
|
||||||
|
log.debug(
|
||||||
|
"Results: {}",
|
||||||
|
employeeRepository.findAll(
|
||||||
|
builder -> builder
|
||||||
|
.andIsNotNull(Employee.Fields.name)
|
||||||
|
.andEquals(Employee.Fields.name, "Tom")
|
||||||
|
.andLike(Employee.Fields.name, "To%")
|
||||||
|
.andStartsWith(Employee.Fields.name, "To")
|
||||||
|
.andEndsWith(Employee.Fields.name, "om")
|
||||||
|
.andLessThan(Employee.Fields.age, 50)
|
||||||
|
.andGreaterThanEqual(Employee.Fields.age, 0)
|
||||||
|
.andIn(Employee.Fields.name, List.of("Tom", "Mike"))
|
||||||
|
.andBetween(Employee.Fields.age, 0, 50)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
log.debug(
|
||||||
|
"Results: {}",
|
||||||
|
employeeRepository.findAll(
|
||||||
|
(root, query, builder) ->
|
||||||
|
builder.and(
|
||||||
|
builder.isNotNull(root.get(Employee_.name)),
|
||||||
|
builder.equal(root.get(Employee_.name), "Tom"),
|
||||||
|
builder.like(root.get(Employee_.name), "To%"),
|
||||||
|
builder.lessThan(root.get(Employee_.age), 50),
|
||||||
|
builder.greaterThanOrEqualTo(root.get(Employee_.age), 0),
|
||||||
|
builder.in(root.get(Employee_.NAME)).value(List.of("Tom", "Mike")),
|
||||||
|
builder.between(root.get(Employee_.age), 0, 50),
|
||||||
|
builder.isNotEmpty(root.get(Employee_.company).get(Company_.employees)),
|
||||||
|
builder.notEqual(root.get(Employee_.company).get(Company_.name), "Apple")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
log.debug(
|
||||||
|
"Results: {}",
|
||||||
|
employeeRepository.findAll(
|
||||||
|
QEmployee.employee.name.isNotNull()
|
||||||
|
.and(QEmployee.employee.name.eq("Tom"))
|
||||||
|
.and(QEmployee.employee.name.like("To%"))
|
||||||
|
.and(QEmployee.employee.name.startsWith("To"))
|
||||||
|
.and(QEmployee.employee.name.endsWith("om"))
|
||||||
|
.and(QEmployee.employee.age.lt(50))
|
||||||
|
.and(QEmployee.employee.age.goe(0))
|
||||||
|
.and(QEmployee.employee.name.in("Tom", "Mike"))
|
||||||
|
.and(QEmployee.employee.age.between(0, 50))
|
||||||
|
.and(QEmployee.employee.company().employees.isNotEmpty())
|
||||||
|
.and(QEmployee.employee.company().employees.any().name.ne("Tom"))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
log.debug(
|
||||||
|
"Results: {}",
|
||||||
|
employeeRepository.findAll(
|
||||||
|
(root, query, builder) -> {
|
||||||
|
var reportRoot = query.from(Report.class);
|
||||||
|
return builder.and(
|
||||||
|
builder.equal(root.get(Employee_.id), reportRoot.get(Report_.employeeId)),
|
||||||
|
builder.equal(reportRoot.get(Report_.level), Report.Level.A)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
private HttpHeaders headers() {
|
private HttpHeaders headers() {
|
||||||
var headers = new HttpHeaders();
|
var headers = new HttpHeaders();
|
||||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||||
|
|||||||
@@ -0,0 +1,107 @@
|
|||||||
|
package com.lanyuanxiaoyao.service.template.controller;
|
||||||
|
|
||||||
|
import com.lanyuanxiaoyao.service.template.entity.Report;
|
||||||
|
import com.lanyuanxiaoyao.service.template.service.EmployeeService;
|
||||||
|
import com.lanyuanxiaoyao.service.template.service.ReportService;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.ToString;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("report")
|
||||||
|
public class ReportController extends SimpleControllerSupport<Report, ReportController.SaveItem, ReportController.ListItem, ReportController.DetailItem> {
|
||||||
|
private final EmployeeService employeeService;
|
||||||
|
|
||||||
|
public ReportController(ReportService service, EmployeeService employeeService) {
|
||||||
|
super(service);
|
||||||
|
this.employeeService = employeeService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Function<SaveItem, Report> saveItemMapper() {
|
||||||
|
return item -> {
|
||||||
|
var report = new Report();
|
||||||
|
report.setId(item.getId());
|
||||||
|
report.setScore(item.getScore());
|
||||||
|
report.setLevel(item.getLevel());
|
||||||
|
report.setEmployeeId(item.getEmployeeId());
|
||||||
|
return report;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Function<Report, ListItem> listItemMapper() {
|
||||||
|
return report -> {
|
||||||
|
var employee = employeeService.detailOrThrow(report.getEmployeeId());
|
||||||
|
return new ListItem(
|
||||||
|
report.getId(),
|
||||||
|
employee.getId(),
|
||||||
|
employee.getName(),
|
||||||
|
report.getScore(),
|
||||||
|
report.getLevel()
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Function<Report, DetailItem> detailItemMapper() {
|
||||||
|
return report -> {
|
||||||
|
var employee = employeeService.detailOrThrow(report.getEmployeeId());
|
||||||
|
return new DetailItem(
|
||||||
|
report.getId(),
|
||||||
|
employee.getId(),
|
||||||
|
employee.getName(),
|
||||||
|
report.getScore(),
|
||||||
|
report.getLevel(),
|
||||||
|
report.getCreatedTime(),
|
||||||
|
report.getModifiedTime()
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
|
@ToString
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public static class SaveItem {
|
||||||
|
private Long id;
|
||||||
|
private Double score;
|
||||||
|
private Report.Level level;
|
||||||
|
private Long employeeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
|
@ToString
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public static class ListItem {
|
||||||
|
private Long id;
|
||||||
|
private Long employeeId;
|
||||||
|
private String employeeName;
|
||||||
|
private Double score;
|
||||||
|
private Report.Level level;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
|
@ToString
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public static class DetailItem {
|
||||||
|
private Long id;
|
||||||
|
private Long employeeId;
|
||||||
|
private String employeeName;
|
||||||
|
private Double score;
|
||||||
|
private Report.Level level;
|
||||||
|
private LocalDateTime createdTime;
|
||||||
|
private LocalDateTime modifiedTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package com.lanyuanxiaoyao.service.template.entity;
|
||||||
|
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.EntityListeners;
|
||||||
|
import jakarta.persistence.EnumType;
|
||||||
|
import jakarta.persistence.Enumerated;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.ToString;
|
||||||
|
import lombok.experimental.FieldNameConstants;
|
||||||
|
import org.hibernate.annotations.Comment;
|
||||||
|
import org.hibernate.annotations.DynamicUpdate;
|
||||||
|
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
@FieldNameConstants
|
||||||
|
@Entity
|
||||||
|
@DynamicUpdate
|
||||||
|
@EntityListeners(AuditingEntityListener.class)
|
||||||
|
@Comment("报告")
|
||||||
|
public class Report extends SimpleEntity {
|
||||||
|
@Column(nullable = false)
|
||||||
|
@Comment("分数")
|
||||||
|
private Double score = 0.0;
|
||||||
|
@Column(nullable = false)
|
||||||
|
@Enumerated(EnumType.STRING)
|
||||||
|
@Comment("等级")
|
||||||
|
private Level level;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
@Comment("员工id")
|
||||||
|
private Long employeeId;
|
||||||
|
|
||||||
|
public enum Level {
|
||||||
|
A, B, C, D, E
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package com.lanyuanxiaoyao.service.template.repository;
|
||||||
|
|
||||||
|
import com.lanyuanxiaoyao.service.template.entity.Report;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface ReportRepository extends SimpleRepository<Report, Long> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package com.lanyuanxiaoyao.service.template.service;
|
||||||
|
|
||||||
|
import com.lanyuanxiaoyao.service.template.entity.Report;
|
||||||
|
import com.lanyuanxiaoyao.service.template.repository.ReportRepository;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class ReportService extends SimpleServiceSupport<Report> {
|
||||||
|
public ReportService(ReportRepository repository) {
|
||||||
|
super(repository);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user