Jelajahi Sumber

删除`assert`模块,新增`ElasticSearch`模块

mxd 3 tahun lalu
induk
melakukan
4c12753247

+ 5 - 0
magic-api-spring-boot-starter/pom.xml

@@ -28,6 +28,11 @@
             <artifactId>spring-boot-starter-data-mongodb</artifactId>
             <scope>provided</scope>
         </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
+            <scope>provided</scope>
+        </dependency>
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-web</artifactId>

+ 1 - 3
magic-api-spring-boot-starter/src/main/java/org/ssssssss/magicapi/spring/boot/starter/MagicAPIAutoConfiguration.java

@@ -87,7 +87,7 @@ import java.util.function.BiFunction;
 @Configuration
 @ConditionalOnClass({RequestMappingHandlerMapping.class})
 @EnableConfigurationProperties(MagicAPIProperties.class)
-@Import({MagicRedisAutoConfiguration.class, MagicMongoAutoConfiguration.class, MagicJsonAutoConfiguration.class, ApplicationUriPrinter.class})
+@Import({MagicRedisAutoConfiguration.class, MagicElasticSearchAutoConfiguration.class, MagicMongoAutoConfiguration.class, MagicJsonAutoConfiguration.class, ApplicationUriPrinter.class})
 @EnableWebSocket
 public class MagicAPIAutoConfiguration implements WebMvcConfigurer, WebSocketConfigurer {
 
@@ -500,8 +500,6 @@ public class MagicAPIAutoConfiguration implements WebMvcConfigurer, WebSocketCon
 		MagicResourceLoader.addModule("request", new RequestModule(multipartResolver));
 		logger.info("注册模块:{} -> {}", "response", ResponseModule.class);
 		MagicResourceLoader.addModule("response", new ResponseModule(resultProvider));
-		logger.info("注册模块:{} -> {}", "assert", AssertModule.class);
-		MagicResourceLoader.addModule("assert", new AssertModule());
 		magicModules.forEach(module -> {
 			logger.info("注册模块:{} -> {}", module.getModuleName(), module.getClass());
 			MagicResourceLoader.addModule(module.getModuleName(), module);

+ 21 - 0
magic-api-spring-boot-starter/src/main/java/org/ssssssss/magicapi/spring/boot/starter/MagicElasticSearchAutoConfiguration.java

@@ -0,0 +1,21 @@
+package org.ssssssss.magicapi.spring.boot.starter;
+
+import org.elasticsearch.client.RestHighLevelClient;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.ssssssss.magicapi.modules.ElasticSearchModule;
+
+@Configuration
+@ConditionalOnMissingBean(ElasticSearchModule.class)
+@ConditionalOnClass(RestHighLevelClient.class)
+public class MagicElasticSearchAutoConfiguration {
+
+	@Bean
+	@ConditionalOnBean(RestHighLevelClient.class)
+	public ElasticSearchModule elasticSearchModule(RestHighLevelClient restHighLevelClient){
+		return new ElasticSearchModule(restHighLevelClient.getLowLevelClient());
+	}
+}

+ 5 - 0
magic-api/pom.xml

@@ -41,6 +41,11 @@
             <artifactId>spring-boot-starter-web</artifactId>
             <scope>provided</scope>
         </dependency>
+        <dependency>
+            <groupId>org.elasticsearch.client</groupId>
+            <artifactId>elasticsearch-rest-high-level-client</artifactId>
+            <scope>provided</scope>
+        </dependency>
         <dependency>
             <groupId>org.springframework</groupId>
             <artifactId>spring-jdbc</artifactId>

+ 1 - 1
magic-api/src/main/java/org/ssssssss/magicapi/model/JsonCodeConstants.java

@@ -41,7 +41,7 @@ public interface JsonCodeConstants {
 
 	JsonCode FILE_PATH_NOT_EXISTS = new JsonCode(1015, "配置的文件路径不存在,请检查");
 
-	JsonCode REQUEST_PATH_CONFLICT = new JsonCode(1016, "接口[{}({})]与应用冲突,无法注册");
+	JsonCode REQUEST_PATH_CONFLICT = new JsonCode(1016, "接口[%s(%s)]与应用冲突,无法注册");
 
 	JsonCode SCRIPT_REQUIRED = new JsonCode(1017, "脚本内容不能为空");
 

+ 0 - 102
magic-api/src/main/java/org/ssssssss/magicapi/modules/AssertModule.java

@@ -1,102 +0,0 @@
-package org.ssssssss.magicapi.modules;
-
-import org.apache.commons.lang3.StringUtils;
-import org.ssssssss.magicapi.config.MagicModule;
-import org.ssssssss.script.annotation.Comment;
-import org.ssssssss.script.exception.MagicScriptAssertException;
-
-import java.util.regex.Pattern;
-
-/**
- * 断言模块
- *
- * @author mxd
- */
-public class AssertModule implements MagicModule {
-
-	/**
-	 * 判断值不能为null
-	 *
-	 * @param value   值
-	 * @param code    状态码
-	 * @param message 状态说明
-	 */
-	@Comment("判断值不能为空")
-	public void notNull(@Comment(name = "value", value = "值") Object value,
-						@Comment(name = "code", value = "判断失败时的code") int code,
-						@Comment(name = "message", value = "判断失败时的说明") String message) {
-		if (value == null) {
-			throw new MagicScriptAssertException(code, message);
-		}
-	}
-
-	/**
-	 * 判断值不能为empty
-	 *
-	 * @param value   值
-	 * @param code    状态码
-	 * @param message 状态说明
-	 */
-	@Comment("判断值不能为Empty")
-	public void notEmpty(@Comment(name = "value", value = "值") String value,
-						 @Comment(name = "code", value = "判断失败时的code") int code,
-						 @Comment(name = "message", value = "判断失败时的说明") String message) {
-		if (StringUtils.isEmpty(value)) {
-			throw new MagicScriptAssertException(code, message);
-		}
-	}
-
-	/**
-	 * 判断值不能为blank
-	 *
-	 * @param value   值
-	 * @param code    状态码
-	 * @param message 状态说明
-	 */
-	@Comment("判断值不能为Blank")
-	public void notBlank(@Comment(name = "value", value = "值") String value,
-						 @Comment(name = "code", value = "判断失败时的code") int code,
-						 @Comment(name = "message", value = "判断失败时的说明") String message) {
-		if (StringUtils.isBlank(value)) {
-			throw new MagicScriptAssertException(code, message);
-		}
-	}
-
-	/**
-	 * 正则验证值
-	 *
-	 * @param value   值
-	 * @param code    状态码
-	 * @param message 状态说明
-	 */
-	@Comment("正则判断")
-	public void regx(@Comment(name = "value", value = "值") String value, String pattern,
-					 @Comment(name = "code", value = "判断失败时的code") int code,
-					 @Comment(name = "message", value = "判断失败时的说明") String message) {
-		if (value == null || !Pattern.compile(pattern).matcher(value).matches()) {
-			throw new MagicScriptAssertException(code, message);
-		}
-	}
-
-	/**
-	 * 判断值值是否为true
-	 *
-	 * @param value   值
-	 * @param code    状态码
-	 * @param message 状态说明
-	 */
-	@Comment("判断值是否为true")
-	public void isTrue(@Comment(name = "value", value = "值") boolean value,
-					   @Comment(name = "code", value = "判断失败时的code") int code,
-					   @Comment(name = "message", value = "判断失败时的说明") String message) {
-		if (!value) {
-			throw new MagicScriptAssertException(code, message);
-		}
-	}
-
-
-	@Override
-	public String getModuleName() {
-		return "assert";
-	}
-}

+ 32 - 0
magic-api/src/main/java/org/ssssssss/magicapi/modules/ElasticSearchModule.java

@@ -0,0 +1,32 @@
+package org.ssssssss.magicapi.modules;
+
+import org.elasticsearch.client.RestClient;
+import org.ssssssss.magicapi.config.MagicModule;
+import org.ssssssss.magicapi.modules.elasticsearch.ElasticSearchConnection;
+import org.ssssssss.magicapi.modules.elasticsearch.ElasticSearchIndex;
+import org.ssssssss.script.annotation.Comment;
+
+public class ElasticSearchModule implements MagicModule {
+
+	private static final String DOC = "_doc";
+
+	private final RestClient restClient;
+
+	public ElasticSearchModule(RestClient restClient) {
+		this.restClient = restClient;
+	}
+
+	@Comment(value = "ElasticSearch REST Api")
+	public ElasticSearchConnection rest(String url){
+		return new ElasticSearchConnection(this.restClient, url);
+	}
+
+	public ElasticSearchIndex index(String indexName){
+		return new ElasticSearchIndex(this.restClient, indexName, DOC);
+	}
+
+	@Override
+	public String getModuleName() {
+		return "elasticsearch";
+	}
+}

+ 58 - 0
magic-api/src/main/java/org/ssssssss/magicapi/modules/elasticsearch/ElasticSearchConnection.java

@@ -0,0 +1,58 @@
+package org.ssssssss.magicapi.modules.elasticsearch;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.entity.ContentType;
+import org.apache.http.util.EntityUtils;
+import org.elasticsearch.client.Request;
+import org.elasticsearch.client.Response;
+import org.elasticsearch.client.RestClient;
+import org.elasticsearch.client.ml.PutJobResponse;
+import org.ssssssss.magicapi.utils.JsonUtils;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.Map;
+import java.util.Objects;
+
+public class ElasticSearchConnection extends ElasticSearchRest {
+
+	public ElasticSearchConnection(RestClient restClient, String endpoint) {
+		super(restClient);
+		super.endpoint(endpoint);
+	}
+
+	public ElasticSearchConnection parameter(String key, String value) {
+		if (value != null) {
+			parameters.put(key, value);
+		}
+		return this;
+	}
+
+	public ElasticSearchConnection parameters(Map<String, String> params) {
+		if (params != null) {
+			parameters.putAll(params);
+		}
+		return this;
+	}
+
+	public Object put(Object data) throws IOException {
+		return processResponse(json(data).doPut());
+	}
+
+	public Object delete() throws IOException {
+		return processResponse(doDelete());
+	}
+
+	public Object delete(Object data) throws IOException {
+		return processResponse(json(data).doDelete());
+	}
+
+	public Object post(Object data) throws IOException {
+		return processResponse(json(data).doPost());
+	}
+
+	public Object get() throws IOException {
+		return processResponse(doGet());
+	}
+
+}

+ 77 - 0
magic-api/src/main/java/org/ssssssss/magicapi/modules/elasticsearch/ElasticSearchIndex.java

@@ -0,0 +1,77 @@
+package org.ssssssss.magicapi.modules.elasticsearch;
+
+import org.elasticsearch.client.RestClient;
+import org.ssssssss.magicapi.utils.JsonUtils;
+import org.ssssssss.script.annotation.Comment;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+public class ElasticSearchIndex {
+
+	private final RestClient restClient;
+
+	private final String name;
+
+	private final String type;
+
+
+	public ElasticSearchIndex(RestClient restClient, String name, String type) {
+		this.restClient = restClient;
+		this.name = name;
+		this.type = type;
+	}
+
+	@Comment("根据`_id`保存,当存在时更新,不存在时插入")
+	public Object save(@Comment(value = "_id", name = "_id")String _id, @Comment(value = "保存对象", name = "data")Object data) throws IOException {
+		return connect("/%s/%s/%s", this.name, this.type, _id).post(data);
+	}
+
+	@Comment("不指定`_id`插入")
+	public Object insert(@Comment(value = "插入对象", name = "data")Object data) throws IOException {
+		return connect("/%s/%s", this.name, this.type).post(data);
+	}
+
+	@Comment("指定`_id`插入,当`_id`存在时不会更新")
+	public Object insert(@Comment(value = "_id", name = "_id")String _id, @Comment(value = "插入对象", name = "data")Object data) throws IOException {
+		return connect("/%s/%s/%s/_create", this.name, this.type, _id).post(data);
+	}
+
+	@Comment("根据`id`删除")
+	public Object delete(@Comment(value = "id", name = "id")String id) throws IOException {
+		return connect("/%s/%s/%s", this.name, this.type, id).delete();
+	}
+
+	@Comment("批量保存,当包含`id`时,则使用该列值匹配保存")
+	public Object bulkSave(@Comment(value = "保存内容", name = "list") List<Map<String, Object>> list) throws IOException {
+		StringBuilder builder = new StringBuilder();
+		list.forEach(item -> {
+			Object id = item.get("id");
+			if(id != null){
+				builder.append(String.format("{ \"index\":{ \"_id\": \"%s\" } }\r\n", id));
+			} else {
+				builder.append("{ \"index\":{} }\r\n");
+			}
+			builder.append(JsonUtils.toJsonStringWithoutPretty(item));
+			builder.append("\r\n");
+		});
+		return connect("/%s/%s/_bulk", this.name, this.type).post(builder.toString());
+	}
+
+	@Comment("根据`_id`修改")
+	public Object update(@Comment(value = "_id", name = "_id")String _id, @Comment(value = "修改项", name = "data")Object data) throws IOException {
+		return connect("/%s/%s/%s", this.name, this.type, _id).post(Collections.singletonMap("doc", data));
+	}
+
+	@Comment("搜索")
+	public Object search(@Comment(value = "搜索`DSL`语句", name = "dsl")Map<String, Object> dsl) throws IOException {
+		return connect("/%s/_search", this.name).post(dsl);
+	}
+
+	private ElasticSearchConnection connect(String format, Object... args) {
+		return new ElasticSearchConnection(this.restClient, String.format(format, args));
+	}
+}

+ 97 - 0
magic-api/src/main/java/org/ssssssss/magicapi/modules/elasticsearch/ElasticSearchRest.java

@@ -0,0 +1,97 @@
+package org.ssssssss.magicapi.modules.elasticsearch;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.entity.ContentType;
+import org.apache.http.nio.entity.NStringEntity;
+import org.apache.http.util.EntityUtils;
+import org.elasticsearch.ElasticsearchException;
+import org.elasticsearch.client.Request;
+import org.elasticsearch.client.Response;
+import org.elasticsearch.client.RestClient;
+import org.elasticsearch.common.io.stream.StreamInput;
+import org.elasticsearch.common.xcontent.XContentParserUtils;
+import org.ssssssss.magicapi.utils.JsonUtils;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+public class ElasticSearchRest {
+
+	private final RestClient restClient;
+
+	private String method;
+
+	private String endpoint = "/";
+
+	private HttpEntity entity;
+
+	protected final Map<String, String> parameters = new HashMap<>();
+
+	public ElasticSearchRest(RestClient restClient) {
+		this.restClient = restClient;
+	}
+
+	ElasticSearchRest endpoint(String endpoint){
+		this.endpoint = endpoint;
+		return this;
+	}
+
+	Response doGet() throws IOException {
+		this.method = "GET";
+		return execute();
+	}
+
+	Response doPost() throws IOException {
+		this.method = "POST";
+		return execute();
+	}
+
+	Response doDelete() throws IOException {
+		this.method = "DELETE";
+		return execute();
+	}
+
+	Response doPut() throws IOException {
+		this.method = "PUT";
+		return execute();
+	}
+
+	ElasticSearchRest json(Object data){
+		if(data == null){
+			return this;
+		}
+		String json = null;
+		if(data instanceof CharSequence){
+			json = data.toString();
+		} else {
+			json = JsonUtils.toJsonString(data);
+		}
+		if(json != null){
+			this.entity = new NStringEntity(json, ContentType.APPLICATION_JSON);
+		}
+		return this;
+	}
+
+	private Response execute() throws IOException {
+		Request request = new Request(method, this.endpoint);
+		request.addParameters(parameters);
+		request.setEntity(entity);
+		return this.restClient.performRequest(request);
+	}
+
+	Object processResponse(Response response) throws IOException {
+		int code = response.getStatusLine().getStatusCode();
+		if (code >= 200 && code < 300) {    // 2xx
+			HttpEntity entity = response.getEntity();
+			String resp = EntityUtils.toString(entity, StandardCharsets.UTF_8);
+			ContentType contentType = ContentType.get(entity);
+			if (Objects.equals(ContentType.APPLICATION_JSON.getMimeType(), contentType.getMimeType())) {
+				return JsonUtils.readValue(resp, Object.class);
+			}
+		}
+		return response;
+	}
+}

+ 9 - 0
magic-api/src/main/java/org/ssssssss/magicapi/utils/JsonUtils.java

@@ -44,6 +44,15 @@ public class JsonUtils {
 		}
 	}
 
+	public static String toJsonStringWithoutPretty(Object target) {
+		try {
+			return MAPPER.writeValueAsString(target);
+		} catch (JsonProcessingException e) {
+			logger.error("json序列化失败", e);
+			return null;
+		}
+	}
+
 	public static String toJsonStringWithoutLog(Object target) {
 		try {
 			return MAPPER.writeValueAsString(target);

+ 7 - 1
pom.xml

@@ -30,7 +30,8 @@
     </scm>
     <properties>
         <spring-boot.version>2.4.5</spring-boot.version>
-        <magic-script.version>1.6.3</magic-script.version>
+        <magic-script.version>1.6.4</magic-script.version>
+        <elasticsearch.version>7.15.0</elasticsearch.version>
         <commons-compress.version>1.21</commons-compress.version>
         <commons-io.version>2.7</commons-io.version>
         <commons-text.version>1.6</commons-text.version>
@@ -102,6 +103,11 @@
                 <artifactId>springfox-swagger2</artifactId>
                 <version>${swagger.version}</version>
             </dependency>
+            <dependency>
+                <groupId>org.elasticsearch.client</groupId>
+                <artifactId>elasticsearch-rest-high-level-client</artifactId>
+                <version>${elasticsearch.version}</version>
+            </dependency>
         </dependencies>
     </dependencyManagement>
     <build>