diff --git a/powerjob-client/src/main/java/com/github/kfcfans/powerjob/client/OhMyClient.java b/powerjob-client/src/main/java/com/github/kfcfans/powerjob/client/OhMyClient.java index 3da848ed..b9c85fff 100644 --- a/powerjob-client/src/main/java/com/github/kfcfans/powerjob/client/OhMyClient.java +++ b/powerjob-client/src/main/java/com/github/kfcfans/powerjob/client/OhMyClient.java @@ -289,6 +289,14 @@ public class OhMyClient { return JSONObject.parseObject(post, INSTANCE_RESULT_TYPE); } + public ResultDTO> queryInstanceInfo(PowerQuery powerQuery) { + powerQuery.setAppIdEq(appId); + MediaType jsonType = MediaType.parse("application/json; charset=utf-8"); + String json = JsonUtils.toJSONStringUnsafe(powerQuery); + String post = postHA(OpenAPIConstant.QUERY_INSTANCE, RequestBody.create(jsonType, json)); + return JSONObject.parseObject(post, LIST_INSTANCE_RESULT_TYPE); + } + /* ************* Workflow API list ************* */ /** * Save one workflow diff --git a/powerjob-client/src/main/java/com/github/kfcfans/powerjob/client/TypeStore.java b/powerjob-client/src/main/java/com/github/kfcfans/powerjob/client/TypeStore.java index 52eddfb6..ab60f1b5 100644 --- a/powerjob-client/src/main/java/com/github/kfcfans/powerjob/client/TypeStore.java +++ b/powerjob-client/src/main/java/com/github/kfcfans/powerjob/client/TypeStore.java @@ -25,6 +25,8 @@ public class TypeStore { public static final TypeReference> INSTANCE_RESULT_TYPE = new TypeReference>() {}; + public static final TypeReference>> LIST_INSTANCE_RESULT_TYPE = new TypeReference>>(){}; + public static final TypeReference> WF_RESULT_TYPE = new TypeReference>() {}; public static final TypeReference> WF_INSTANCE_RESULT_TYPE = new TypeReference>() {}; diff --git a/powerjob-common/src/main/java/com/github/kfcfans/powerjob/common/OpenAPIConstant.java b/powerjob-common/src/main/java/com/github/kfcfans/powerjob/common/OpenAPIConstant.java index ca4af14b..5de3274a 100644 --- a/powerjob-common/src/main/java/com/github/kfcfans/powerjob/common/OpenAPIConstant.java +++ b/powerjob-common/src/main/java/com/github/kfcfans/powerjob/common/OpenAPIConstant.java @@ -28,6 +28,7 @@ public class OpenAPIConstant { public static final String RETRY_INSTANCE = "/retryInstance"; public static final String FETCH_INSTANCE_STATUS = "/fetchInstanceStatus"; public static final String FETCH_INSTANCE_INFO = "/fetchInstanceInfo"; + public static final String QUERY_INSTANCE = "/queryInstance"; /* ************* Workflow 区 ************* */ public static final String SAVE_WORKFLOW = "/saveWorkflow"; diff --git a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/common/utils/QueryConvertUtils.java b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/common/utils/QueryConvertUtils.java index 1683a87c..4a1f66a1 100644 --- a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/common/utils/QueryConvertUtils.java +++ b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/common/utils/QueryConvertUtils.java @@ -1,6 +1,6 @@ package com.github.kfcfans.powerjob.server.common.utils; -import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; import com.github.kfcfans.powerjob.common.PowerJobException; import com.github.kfcfans.powerjob.common.PowerQuery; import com.google.common.collect.Lists; @@ -26,9 +26,10 @@ public class QueryConvertUtils { return (Specification) (root, query, cb) -> { List predicates = Lists.newLinkedList(); - Field[ ] fields = query.getClass().getDeclaredFields(); + Field[] fields = powerQuery.getClass().getDeclaredFields(); try { for (Field field : fields) { + field.setAccessible(true); String fieldName = field.getName(); Object fieldValue = field.get(powerQuery); if (fieldValue == null) { @@ -42,10 +43,10 @@ public class QueryConvertUtils { predicates.add(cb.notEqual(root.get(colName), fieldValue)); } else if (fieldName.endsWith(PowerQuery.LIKE)) { String colName = StringUtils.substringBeforeLast(fieldName, PowerQuery.LIKE); - predicates.add(cb.like(root.get(colName), (String) fieldValue)); + predicates.add(cb.like(root.get(colName), convertLikeParams(fieldValue))); } else if (fieldName.endsWith(PowerQuery.NOT_LIKE)) { String colName = StringUtils.substringBeforeLast(fieldName, PowerQuery.NOT_LIKE); - predicates.add(cb.notLike(root.get(colName), (String) fieldValue)); + predicates.add(cb.notLike(root.get(colName), convertLikeParams(fieldValue))); } else if (fieldName.endsWith(PowerQuery.LESS_THAN)) { String colName = StringUtils.substringBeforeLast(fieldName, PowerQuery.LESS_THAN); predicates.add(cb.lessThan(root.get(colName), (Comparable)fieldValue)); @@ -60,10 +61,10 @@ public class QueryConvertUtils { predicates.add(cb.greaterThanOrEqualTo(root.get(colName), (Comparable)fieldValue)); } else if (fieldName.endsWith(PowerQuery.IN)) { String colName = StringUtils.substringBeforeLast(fieldName, PowerQuery.IN); - predicates.add(root.get(colName).in(fieldValue)); + predicates.add(root.get(colName).in(convertInParams(fieldValue))); } else if (fieldName.endsWith(PowerQuery.NOT_IN)) { String colName = StringUtils.substringBeforeLast(fieldName, PowerQuery.NOT_IN); - predicates.add(cb.not(root.get(colName).in(fieldValue))); + predicates.add(cb.not(root.get(colName).in(convertInParams(fieldValue)))); } else if (fieldName.endsWith(PowerQuery.IS_NULL)) { String colName = StringUtils.substringBeforeLast(fieldName, PowerQuery.IS_NULL); predicates.add(cb.isNull(root.get(colName))); @@ -73,16 +74,31 @@ public class QueryConvertUtils { } } } catch (Exception e) { - log.warn("[QueryConvertUtils] convert failed for query: {}", JSON.toJSON(query)); + log.warn("[QueryConvertUtils] convert failed for query: {}", query, e); throw new PowerJobException("convert query object failed, maybe you should redesign your query object!"); } + if (powerQuery.getAppIdEq() != null) { + predicates.add(cb.equal(root.get("appId"), powerQuery.getAppIdEq())); + } + return query.where(predicates.toArray(new Predicate[0])).getRestriction(); }; } - public static void main(String[] args) { - String s = "appIdEq"; - System.out.println(StringUtils.substringBeforeLast(s, "Eq")); + private static String convertLikeParams(Object o) { + String s = (String) o; + if (!s.startsWith("%")) { + s = "%" + s; + } + if (!s.endsWith("%")) { + s = s + "%"; + } + return s; + } + + private static Object[] convertInParams(Object o) { + // FastJSON, 永远滴神! + return JSONArray.parseArray(JSONArray.toJSONString(o)).toArray(); } } diff --git a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/persistence/core/repository/InstanceInfoRepository.java b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/persistence/core/repository/InstanceInfoRepository.java index 3742e3c8..0872cbab 100644 --- a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/persistence/core/repository/InstanceInfoRepository.java +++ b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/persistence/core/repository/InstanceInfoRepository.java @@ -3,6 +3,7 @@ package com.github.kfcfans.powerjob.server.persistence.core.repository; import com.github.kfcfans.powerjob.server.persistence.core.model.InstanceInfoDO; import com.google.errorprone.annotations.CanIgnoreReturnValue; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; @@ -16,7 +17,7 @@ import java.util.List; * @author tjq * @since 2020/4/1 */ -public interface InstanceInfoRepository extends JpaRepository { +public interface InstanceInfoRepository extends JpaRepository, JpaSpecificationExecutor { /** * 统计当前JOB有多少实例正在运行 diff --git a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/instance/InstanceService.java b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/instance/InstanceService.java index aafebb7d..5a210630 100644 --- a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/instance/InstanceService.java +++ b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/instance/InstanceService.java @@ -2,10 +2,7 @@ package com.github.kfcfans.powerjob.server.service.instance; import akka.actor.ActorSelection; import akka.pattern.Patterns; -import com.github.kfcfans.powerjob.common.InstanceStatus; -import com.github.kfcfans.powerjob.common.PowerJobException; -import com.github.kfcfans.powerjob.common.RemoteConstant; -import com.github.kfcfans.powerjob.common.SystemInstanceResult; +import com.github.kfcfans.powerjob.common.*; import com.github.kfcfans.powerjob.common.model.InstanceDetail; import com.github.kfcfans.powerjob.common.request.ServerQueryInstanceStatusReq; import com.github.kfcfans.powerjob.common.request.ServerStopInstanceReq; @@ -14,6 +11,7 @@ import com.github.kfcfans.powerjob.common.response.InstanceInfoDTO; import com.github.kfcfans.powerjob.server.akka.OhMyServer; import com.github.kfcfans.powerjob.server.common.constans.InstanceType; import com.github.kfcfans.powerjob.server.common.redirect.DesignateServer; +import com.github.kfcfans.powerjob.server.common.utils.QueryConvertUtils; import com.github.kfcfans.powerjob.server.common.utils.timewheel.TimerFuture; import com.github.kfcfans.powerjob.server.persistence.core.model.InstanceInfoDO; import com.github.kfcfans.powerjob.server.persistence.core.model.JobInfoDO; @@ -28,8 +26,10 @@ import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.time.Duration; import java.util.Date; +import java.util.List; import java.util.concurrent.CompletionStage; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; import static com.github.kfcfans.powerjob.common.InstanceStatus.RUNNING; import static com.github.kfcfans.powerjob.common.InstanceStatus.STOPPED; @@ -201,16 +201,21 @@ public class InstanceService { } } + public List queryInstanceInfo(PowerQuery powerQuery) { + return instanceInfoRepository + .findAll(QueryConvertUtils.autoConvert(powerQuery)) + .stream() + .map(InstanceService::directConvert) + .collect(Collectors.toList()); + } + /** * 获取任务实例的信息 * @param instanceId 任务实例ID * @return 任务实例的信息 */ public InstanceInfoDTO getInstanceInfo(Long instanceId) { - InstanceInfoDO instanceInfoDO = fetchInstanceInfo(instanceId); - InstanceInfoDTO instanceInfoDTO = new InstanceInfoDTO(); - BeanUtils.copyProperties(instanceInfoDO, instanceInfoDTO); - return instanceInfoDTO; + return directConvert(fetchInstanceInfo(instanceId)); } /** @@ -276,4 +281,10 @@ public class InstanceService { } return instanceInfoDO; } + + private static InstanceInfoDTO directConvert(InstanceInfoDO instanceInfoDO) { + InstanceInfoDTO instanceInfoDTO = new InstanceInfoDTO(); + BeanUtils.copyProperties(instanceInfoDO, instanceInfoDTO); + return instanceInfoDTO; + } } diff --git a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/web/controller/OpenAPIController.java b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/web/controller/OpenAPIController.java index e39bc075..e55191fb 100644 --- a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/web/controller/OpenAPIController.java +++ b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/web/controller/OpenAPIController.java @@ -131,6 +131,11 @@ public class OpenAPIController { return ResultDTO.success(instanceService.getInstanceInfo(instanceId)); } + @PostMapping(OpenAPIConstant.QUERY_INSTANCE) + public ResultDTO> queryInstance(@RequestBody PowerQuery powerQuery) { + return ResultDTO.success(instanceService.queryInstanceInfo(powerQuery)); + } + /* ************* Workflow 区 ************* */ @PostMapping(OpenAPIConstant.SAVE_WORKFLOW) public ResultDTO saveWorkflow(@RequestBody SaveWorkflowRequest request) throws Exception { diff --git a/powerjob-server/src/test/java/com/github/kfcfans/powerjob/server/common/utils/QueryConvertUtilsTest.java b/powerjob-server/src/test/java/com/github/kfcfans/powerjob/server/common/utils/QueryConvertUtilsTest.java new file mode 100644 index 00000000..d34595fb --- /dev/null +++ b/powerjob-server/src/test/java/com/github/kfcfans/powerjob/server/common/utils/QueryConvertUtilsTest.java @@ -0,0 +1,59 @@ +package com.github.kfcfans.powerjob.server.common.utils; + +import com.alibaba.fastjson.JSONObject; +import com.github.kfcfans.powerjob.common.PowerQuery; +import com.github.kfcfans.powerjob.common.response.JobInfoDTO; +import com.github.kfcfans.powerjob.server.persistence.core.model.JobInfoDO; +import com.github.kfcfans.powerjob.server.service.JobService; +import lombok.Data; +import lombok.Getter; +import lombok.Setter; +import org.apache.commons.lang3.time.DateUtils; +import org.assertj.core.util.Lists; +import org.junit.jupiter.api.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.test.context.junit4.SpringRunner; + +import javax.annotation.Resource; + +import java.util.Date; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * test QueryConvertUtils + * + * @author tjq + * @since 2021/1/16 + */ +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +class QueryConvertUtilsTest { + + @Resource + private JobService jobService; + + @Test + void autoConvert() { + JobInfoQuery jobInfoQuery = new JobInfoQuery(); + jobInfoQuery.setAppIdEq(1L); + jobInfoQuery.setJobNameLike("DAG"); + jobInfoQuery.setStatusIn(Lists.newArrayList(1)); + jobInfoQuery.setGmtCreateGt(DateUtils.addDays(new Date(), -300)); + + List list = jobService.queryJob(jobInfoQuery); + System.out.println("size: " + list.size()); + System.out.println(JSONObject.toJSONString(list)); + } + + @Getter + @Setter + public static class JobInfoQuery extends PowerQuery { + private String jobNameLike; + private Date gmtCreateGt; + private List statusIn; + } +} \ No newline at end of file diff --git a/powerjob-server/src/test/resources/application.properties b/powerjob-server/src/test/resources/application.properties index 4cbbeca3..ef264fe6 100644 --- a/powerjob-server/src/test/resources/application.properties +++ b/powerjob-server/src/test/resources/application.properties @@ -14,14 +14,15 @@ spring.servlet.multipart.max-request-size=209715200 ####### 数据库配置 ####### spring.datasource.core.driver-class-name=com.mysql.cj.jdbc.Driver -spring.datasource.core.jdbc-url=jdbc:mysql://remotehost:3391/oms-daily?useUnicode=true&characterEncoding=UTF-8 +spring.datasource.core.jdbc-url=jdbc:mysql://localhost:3306/powerjob-daily?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai spring.datasource.core.username=root spring.datasource.core.password=No1Bug2Please3! spring.datasource.core.hikari.maximum-pool-size=20 spring.datasource.core.hikari.minimum-idle=5 ####### mongoDB配置,非核心依赖,可移除 ####### -spring.data.mongodb.uri=mongodb://remotehost:27017/oms-daily +oms.mongodb.enable=true +spring.data.mongodb.uri=mongodb+srv://zqq:No1Bug2Please3!@cluster0.wie54.gcp.mongodb.net/powerjob_daily?retryWrites=true&w=majority ###### OhMyScheduler 自身配置(该配置只允许存在于 application.properties 文件中) ###### # akka ActorSystem 服务端口