Эх сурвалжийг харах

ES查询工具类
黑烟抓拍数据接口

459242451@qq.com 3 жил өмнө
parent
commit
7abbf4ee98

+ 77 - 0
ruoyi-admin/src/main/java/com/ruoyi/web/controller/gas/BlackGasController.java

@@ -0,0 +1,77 @@
+package com.ruoyi.web.controller.gas;
+
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import com.github.pagehelper.PageInfo;
+import com.ruoyi.common.constant.ElasticConstants;
+import com.ruoyi.common.constant.HttpStatus;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.page.PageDomain;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.core.page.TableSupport;
+import com.ruoyi.framework.config.ElasticSearchClient;
+import com.ruoyi.system.domain.ShipRecognition;
+import com.ruoyi.system.domain.SysConfig;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @Description: 黑烟接口
+ * @Author: huangcheng
+ * @Date: 2021/8/24
+ * @Version V1.0
+ */
+@RestController
+@RequestMapping("/black")
+@Api(tags = "黑烟接口")
+public class BlackGasController extends BaseController {
+
+    @Autowired
+    private ElasticSearchClient client;
+
+    @GetMapping("/list")
+    @ApiOperation("列表数据")
+    public TableDataInfo list(ShipRecognition shipRecognition) {
+        // 传来的参数
+        Map<String, Object> params = shipRecognition.getParams();
+        Map<String, Object> equalsCondition = new HashMap<>();
+        // 组装查询条件
+        equalsCondition.put("aisMmsi", ObjectUtil.isEmpty(shipRecognition.getAismmsi()) ? null : StrUtil.concat(true, "*", Convert.toStr(shipRecognition.getAismmsi()), "*"));
+        equalsCondition.put("aisShipName", StrUtil.isBlank(shipRecognition.getAisshipname()) ? null : StrUtil.concat(true, "*", shipRecognition.getAisshipname(), "*"));
+        equalsCondition.put("snapPos", StrUtil.isBlank(shipRecognition.getSnappos()) ? null : StrUtil.concat(true, "*", shipRecognition.getSnappos(), "*"));
+        equalsCondition.put("aisDst", StrUtil.isBlank(shipRecognition.getAisdst()) ? null : StrUtil.concat(true, "*", shipRecognition.getAisdst(), "*"));
+        equalsCondition.put("aisShipType", shipRecognition.getAisshiptype());
+        // 组装范围查询条件
+        Map<String, Object> rangeCondition = new HashMap<>();
+        if (ObjectUtil.isNotEmpty(params.get("beginTime"))) {
+            params.put("beginTime", params.get("beginTime") + " 00:00:00");
+        }
+        if (ObjectUtil.isNotEmpty(params.get("endTime"))) {
+            params.put("endTime", params.get("endTime") + " 23:59:59");
+        }
+        rangeCondition.put("snapTime", StrUtil.concat(true, "[", Convert.toStr(params.get("beginTime")), ",", Convert.toStr(params.get("endTime")), "]"));
+        List<String> orderBy = new ArrayList<>();
+        orderBy.add("-snapTime");
+        PageDomain pageDomain = TableSupport.buildPageRequest();
+        Map<String, Object> maps = client.searchDocument(ElasticConstants.HEIYAN_SHIP_RECOGNITION, equalsCondition, rangeCondition, orderBy, pageDomain.getPageNum(), pageDomain.getPageSize());
+
+        TableDataInfo rspData = new TableDataInfo();
+        rspData.setCode(HttpStatus.SUCCESS);
+        rspData.setMsg("查询成功");
+        rspData.setRows(Convert.toList(maps.get("pageList")));
+        rspData.setTotal(Convert.toLong(maps.get("totalNum")));
+        return rspData;
+    }
+
+}

+ 1 - 1
ruoyi-admin/src/main/java/com/ruoyi/web/controller/gas/ThresholdController.java

@@ -50,7 +50,7 @@ public class ThresholdController extends BaseController {
     /**
      * 修改参数配置
      */
-    @PreAuthorize("@ss.hasPermi('system:config:edit')")
+//    @PreAuthorize("@ss.hasPermi('system:config:edit')")
     @Log(title = "阈值更新", businessType = BusinessType.UPDATE)
     @PutMapping("/edit")
     @ApiOperation("阈值更新")

+ 23 - 23
ruoyi-admin/src/main/java/com/ruoyi/web/job/CanalScheduling.java

@@ -1,30 +1,25 @@
 package com.ruoyi.web.job;
 
+import cn.hutool.core.convert.Convert;
 import cn.hutool.core.util.StrUtil;
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.serializer.SerializerFeature;
 import com.alibaba.otter.canal.client.CanalConnector;
 import com.alibaba.otter.canal.client.CanalConnectors;
 import com.alibaba.otter.canal.protocol.CanalEntry;
 import com.alibaba.otter.canal.protocol.Message;
 import com.google.protobuf.InvalidProtocolBufferException;
+import com.ruoyi.common.constant.ElasticConstants;
+import com.ruoyi.common.utils.JdbcTypeUtil;
 import com.ruoyi.framework.config.ElasticSearchClient;
 import com.ruoyi.web.core.config.CanalConfig;
-import lombok.Data;
+import lombok.SneakyThrows;
 import lombok.extern.slf4j.Slf4j;
-import org.elasticsearch.action.index.IndexRequest;
-import org.elasticsearch.client.RequestOptions;
-import org.elasticsearch.client.RestHighLevelClient;
 import org.springframework.beans.BeansException;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.ApplicationContextAware;
 import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Component;
 
-import javax.annotation.Resource;
-import java.io.IOException;
 import java.net.InetSocketAddress;
 import java.util.HashMap;
 import java.util.List;
@@ -50,7 +45,7 @@ public class CanalScheduling implements Runnable, ApplicationContextAware {
     private CanalConfig canalConfig;
 
     @Override
-    @Scheduled(cron = "0/1 * * * * ?", fixedDelay = 100) //每隔100秒执行
+    @Scheduled(fixedDelay = 100) //每隔100秒执行
     public void run() {
         for (CanalConfig.Config config : canalConfig.getConfigs()) {
             // 创建链接
@@ -115,44 +110,49 @@ public class CanalScheduling implements Runnable, ApplicationContextAware {
             List<CanalEntry.Column> beforeColumnsList = rowData.getBeforeColumnsList();
             //获取改变后的数据
             List<CanalEntry.Column> afterColumnsList = rowData.getAfterColumnsList();
-            Map<String, Object> beforeColumnsToMap = parseColumnsToMap(beforeColumnsList);
-            Map<String, Object> afterColumnsToMap = parseColumnsToMap(afterColumnsList);
-            try {
-                //插入es
-                indexES(beforeColumnsToMap, afterColumnsToMap, eventType, database, tableName);
-            } catch (IOException e) {
-                e.printStackTrace();
-            }
+            Map<String, Object> beforeColumnsToMap = parseColumnsToMap(beforeColumnsList, tableName);
+            Map<String, Object> afterColumnsToMap = parseColumnsToMap(afterColumnsList, tableName);
+            //插入es
+            indexES(beforeColumnsToMap, afterColumnsToMap, eventType, database, tableName);
+
         });
     }
 
-    Map<String, Object> parseColumnsToMap(List<CanalEntry.Column> columns) {
+    Map<String, Object> parseColumnsToMap(List<CanalEntry.Column> columns, String tableName) {
         Map<String, Object> map = new HashMap<>();
         columns.forEach(column -> {
             if (column == null) {
                 return;
             }
-            map.put(column.getName(), column.getValue());
+            map.put(column.getName(), JdbcTypeUtil.typeConvert(tableName, column.getName(), column.getValue(), column.getSqlType(), column.getMysqlType()));
         });
         return map;
     }
 
-    private void indexES(Map<String, Object> beforeDataMap, Map<String, Object> afterDataMap, CanalEntry.EventType eventType, String database, String table) throws IOException {
+    @SneakyThrows
+    private void indexES(Map<String, Object> beforeDataMap, Map<String, Object> afterDataMap, CanalEntry.EventType eventType, String database, String table) {
         log.info("eventType:{},database:{},table:{}\nbeforeMap:{},\n afterMap:{}", eventType, database, table, beforeDataMap, afterDataMap);
-        if (!StrUtil.equals("test", database)) {
+        if (!StrUtil.equalsAnyIgnoreCase(database, "heiyan", "so2", "ais_database")) {
             return;
         }
 
         //不是user表中的数据不处理
-        if (!StrUtil.equals("user", table)) {
+        if (!StrUtil.equalsAnyIgnoreCase(table, "ship_recognition")) {
             return;
         }
 
         // 根据不同类型处理相应的逻辑
         switch (eventType) {
             case INSERT:
+                // 黑烟船舶数据入库
+                if (StrUtil.equalsIgnoreCase(database, "heiyan") && StrUtil.equalsIgnoreCase(table, "ship_recognition")) {
+                    client.createDocument(ElasticConstants.HEIYAN_SHIP_RECOGNITION, Convert.toStr(afterDataMap.get("id")), afterDataMap);
+                }
                 break;
             case UPDATE:
+                if (StrUtil.equalsIgnoreCase(database, "heiyan") && StrUtil.equalsIgnoreCase(table, "ship_recognition")) {
+                    client.updateDocument(ElasticConstants.HEIYAN_SHIP_RECOGNITION, Convert.toStr(afterDataMap.get("id")), afterDataMap);
+                }
                 break;
             case DELETE:
                 break;

+ 6 - 0
ruoyi-common/pom.xml

@@ -119,6 +119,12 @@
             <artifactId>javax.servlet-api</artifactId>
         </dependency>
 
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-core</artifactId>
+            <version>5.3.10</version>
+        </dependency>
+
     </dependencies>
 
 </project>

+ 44 - 0
ruoyi-common/src/main/java/com/ruoyi/common/constant/DefineConstant.java

@@ -0,0 +1,44 @@
+package com.ruoyi.common.constant;
+
+/**
+ * @Description: TODO
+ * @Author: huangcheng
+ * @Date: 2021/8/24
+ * @Version V1.0
+ */
+public class DefineConstant {
+    /**
+     * 逗号分隔符
+     */
+    public static final String COMMAN_SIGN = ",";
+
+    /**
+     * 等号分隔符
+     */
+    public static final String EQUALITY_SIGN = "=";
+
+    /**
+     * 冒号分隔符
+     */
+    public static final String COLON_SIGN = ":";
+
+    /**
+     * es的索引文档类型
+     */
+//    public static final String SEARCH_REQUEST_TYPE = "csrcb";
+
+    //区间左闭
+    public static final String INTERVAL_CLOSE_LEFT = "[";
+    //区间右闭
+    public static final String INTERVAL_CLOSE_RIGHT = "]";
+    //区间左开
+    public static final String INTERVAL_OPEN_LEFT = "(";
+    //区间右开
+    public static final String INTERVAL_OPEN_RIGHT = ")";
+
+    public static final String INTERVAL_OPEN_VALUE = "open";
+
+    public static final String INTERVAL_CLOSE_VALUE = "close";
+
+    public static final String ZERP_MONEY = "0.00";
+}

+ 11 - 0
ruoyi-common/src/main/java/com/ruoyi/common/constant/ElasticConstants.java

@@ -0,0 +1,11 @@
+package com.ruoyi.common.constant;
+
+/**
+ * @Description: TODO
+ * @Author: huangcheng
+ * @Date: 2021/8/24
+ * @Version V1.0
+ */
+public class ElasticConstants {
+    public static final String HEIYAN_SHIP_RECOGNITION = "heiyan_ship_recognition";
+}

+ 156 - 0
ruoyi-common/src/main/java/com/ruoyi/common/utils/JdbcTypeUtil.java

@@ -0,0 +1,156 @@
+package com.ruoyi.common.utils;
+
+import cn.hutool.core.date.DateUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.sql.Date;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.sql.Types;
+
+/**
+ * 类型转换工具类
+ *
+ * @author rewerma 2018-8-19 下午06:14:23
+ * @version 1.0.0
+ */
+public class JdbcTypeUtil {
+
+    private static Logger logger = LoggerFactory.getLogger(JdbcTypeUtil.class);
+
+    public static Object getRSData(ResultSet rs, String columnName, int jdbcType) throws SQLException {
+        if (jdbcType == Types.BIT || jdbcType == Types.BOOLEAN) {
+            return rs.getByte(columnName);
+        } else {
+            return rs.getObject(columnName);
+        }
+    }
+
+    public static Class<?> jdbcType2javaType(int jdbcType) {
+        switch (jdbcType) {
+            case Types.BIT:
+            case Types.BOOLEAN:
+                // return Boolean.class;
+            case Types.TINYINT:
+                return Byte.TYPE;
+            case Types.SMALLINT:
+                return Short.class;
+            case Types.INTEGER:
+                return Integer.class;
+            case Types.BIGINT:
+                return Long.class;
+            case Types.DECIMAL:
+            case Types.NUMERIC:
+                return BigDecimal.class;
+            case Types.REAL:
+                return Float.class;
+            case Types.FLOAT:
+            case Types.DOUBLE:
+                return Double.class;
+            case Types.CHAR:
+            case Types.VARCHAR:
+            case Types.LONGVARCHAR:
+                return String.class;
+            case Types.BINARY:
+            case Types.VARBINARY:
+            case Types.LONGVARBINARY:
+            case Types.BLOB:
+                return byte[].class;
+            case Types.DATE:
+                return Date.class;
+            case Types.TIME:
+                return Time.class;
+            case Types.TIMESTAMP:
+                return Timestamp.class;
+            default:
+                return String.class;
+        }
+    }
+
+    private static boolean isText(String columnType) {
+        return "LONGTEXT".equalsIgnoreCase(columnType) || "MEDIUMTEXT".equalsIgnoreCase(columnType)
+               || "TEXT".equalsIgnoreCase(columnType) || "TINYTEXT".equalsIgnoreCase(columnType);
+    }
+
+    public static Object typeConvert(String tableName ,String columnName, String value, int sqlType, String mysqlType) {
+        if (value == null
+            || (value.equals("") && !(isText(mysqlType) || sqlType == Types.CHAR || sqlType == Types.VARCHAR || sqlType == Types.LONGVARCHAR))) {
+            return null;
+        }
+
+        try {
+            Object res;
+            switch (sqlType) {
+                case Types.INTEGER:
+                    res = Integer.parseInt(value);
+                    break;
+                case Types.SMALLINT:
+                    res = Short.parseShort(value);
+                    break;
+                case Types.BIT:
+                case Types.TINYINT:
+                    res = Byte.parseByte(value);
+                    break;
+                case Types.BIGINT:
+                    if (mysqlType.startsWith("bigint") && mysqlType.endsWith("unsigned")) {
+                        res = new BigInteger(value);
+                    } else {
+                        res = Long.parseLong(value);
+                    }
+                    break;
+                // case Types.BIT:
+                case Types.BOOLEAN:
+                    res = !"0".equals(value);
+                    break;
+                case Types.DOUBLE:
+                case Types.FLOAT:
+                    res = Double.parseDouble(value);
+                    break;
+                case Types.REAL:
+                    res = Float.parseFloat(value);
+                    break;
+                case Types.DECIMAL:
+                case Types.NUMERIC:
+                    res = new BigDecimal(value);
+                    break;
+                case Types.BINARY:
+                case Types.VARBINARY:
+                case Types.LONGVARBINARY:
+                case Types.BLOB:
+                    res = value.getBytes("ISO-8859-1");
+                    break;
+                case Types.DATE:
+                    if (!value.startsWith("0000-00-00")) {
+                        res = DateUtils.parseDate(value);
+                    } else {
+                        res = null;
+                    }
+                    break;
+                case Types.TIME: {
+                    res = DateUtils.parseDate(value);
+                    break;
+                }
+                case Types.TIMESTAMP:
+                    if (!value.startsWith("0000-00-00")) {
+                        res = DateUtils.parseDate(value);
+                    } else {
+                        res = null;
+                    }
+                    break;
+                case Types.CLOB:
+                default:
+                    res = value;
+                    break;
+            }
+            return res;
+        } catch (Exception e) {
+            logger.error("table: {} column: {}, failed convert type {} to {}", tableName, columnName, value, sqlType);
+            return value;
+        }
+    }
+}

+ 219 - 92
ruoyi-framework/src/main/java/com/ruoyi/framework/config/ElasticSearchClient.java

@@ -1,8 +1,11 @@
 package com.ruoyi.framework.config;
 
+import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
+import com.ruoyi.common.constant.DefineConstant;
 import com.ruoyi.framework.config.properties.ElasticSearchConfig;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.http.HttpHost;
 import org.elasticsearch.action.ActionListener;
 import org.elasticsearch.action.DocWriteRequest;
@@ -34,24 +37,25 @@ import org.elasticsearch.common.xcontent.XContentBuilder;
 import org.elasticsearch.common.xcontent.XContentFactory;
 import org.elasticsearch.common.xcontent.XContentType;
 import org.elasticsearch.core.TimeValue;
-import org.elasticsearch.index.query.BoolQueryBuilder;
-import org.elasticsearch.index.query.GeoDistanceQueryBuilder;
-import org.elasticsearch.index.query.MultiMatchQueryBuilder;
-import org.elasticsearch.index.query.QueryBuilders;
+import org.elasticsearch.index.query.*;
 import org.elasticsearch.search.SearchHit;
 import org.elasticsearch.search.SearchHits;
 import org.elasticsearch.search.builder.SearchSourceBuilder;
 import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
 import org.elasticsearch.search.sort.FieldSortBuilder;
+import org.elasticsearch.search.sort.SortBuilder;
+import org.elasticsearch.search.sort.SortBuilders;
 import org.elasticsearch.search.sort.SortOrder;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Bean;
 import org.springframework.stereotype.Component;
 import org.springframework.util.CollectionUtils;
+import org.springframework.util.MultiValueMap;
 
 import javax.annotation.PostConstruct;
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -342,111 +346,234 @@ public class ElasticSearchClient {
     }
 
     /**
-     * 检索、分页
-     *
-     * @param indexName    索引名称
-     * @param mpParams     查询参数
-     * @param from         起始页
-     * @param size         每页数量
-     * @param fields       返回列
-     * @param preciseQuery 1:精确查询 2:模糊查询
+     * @param indexName       (索引名)也可以类似的说成表名
+     * @param equalsCondition 关键字等值条件
+     *                        若是一个字符串以%结尾,则匹配以去掉%的字符串开头的记录
+     *                        若是一个字符串以*开头或结尾,则模糊匹配去掉*的记录  类似于sql中的like '%str%'
+     *                        若传入的是一个普通的字符串,则等值查询
+     *                        若传入的是一个集合,则使用的是in条件查询
+     * @param rangeCondition  条件范围查询
+     *                        字段,字段对应值的区间,区间格式[,]/(,)/[,)/(,],逗号的左右可以没值
+     * @param orderBy         排序字段
+     *                        若是字段以中划线-开头,则使用降序排序,类似于sql中的desc
+     *                        若正常字段排序,则使用增序排序,类似于sql中的asc
+     * @param pageNum         页数
+     * @param pageSize        每页大小
      * @return
+     * @Description ElasticSearch条件查询
      */
-    public List<Map<String, Object>> searchDocument(String indexName, Map<String, Object> mpParams,
-                                                    int from, int size, String fields, String sorts, Integer preciseQuery) {
-        SearchRequest searchRequest = new SearchRequest(indexName);
-        // 大多数搜索参数添加到searchSourceBuilder
-        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
-        List<Map<String, Object>> mapList = new ArrayList<>();
-        try {
-            // 组合字段查询
-            BoolQueryBuilder boolQueryBuilder = this.getBoolQueryBuilder(mpParams, preciseQuery);
-            searchSourceBuilder.query(boolQueryBuilder);
-            // 自定义返回列
-            if (StrUtil.isNotBlank(fields)) {
-                searchSourceBuilder.fetchSource(new FetchSourceContext(true, fields.split(","), Strings.EMPTY_ARRAY));
+    public Map<String, Object> searchDocument(String indexName,
+                                                     Map<String, Object> equalsCondition,
+                                                     Map<String, Object> rangeCondition,
+                                                     List<String> orderBy,
+                                                     Integer pageNum,
+                                                     Integer pageSize) {
+        Map<String, Object> resultMap = new HashMap<>(8);
+        List<Map<String, Object>> queryResult = new ArrayList<>();
+        long totalNum = 0;
+        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
+        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
+        // and 等值查询
+        // 某一field=具体的值; 也可以某一field 的值 in 具体定义集合里的值
+        if (null != equalsCondition && !equalsCondition.isEmpty()) {
+            for (Map.Entry<String, Object> entry : equalsCondition.entrySet()) {
+                String key = entry.getKey();
+                //由于我创建索引的时候使用字符串不分词使用的.keyword类型
+                if (key.endsWith("_s")) {
+                    queryValueBuild(boolQueryBuilder, key + ".keyword", entry.getValue());
+                } else {
+                    queryValueBuild(boolQueryBuilder, key, entry.getValue());
+                }
             }
-            // 排序
-            if (StrUtil.isNotBlank(sorts)) {
-                searchSourceBuilder.sort(sorts + ".keyword", SortOrder.DESC);
+        }
+        //范围查询
+        if (null != rangeCondition && !rangeCondition.isEmpty()) {
+            rangeValueBuild(boolQueryBuilder, rangeCondition);
+        }
+        sourceBuilder.query(boolQueryBuilder);
+        //排序
+        if (null != orderBy && !orderBy.isEmpty()) {
+            buildSort(sourceBuilder, orderBy);
+        }
+        //分页(es分页查询默认是查询返回10条记录,而深度分页,默认是10000条数据,也就是一次性最多返回10000条,设置size就可以实现,但是如果实际数据量特别大,可以使用scroll游标查询,此处主要常规分页查询)
+        if (ObjectUtil.isNotEmpty(pageNum)) {
+            pageSize = pageSize == null ? 10000 : pageSize;
+            if (pageNum > 0) {
+                sourceBuilder.from(pageSize * (pageNum - 1));
+            } else {
+                sourceBuilder.from(0);
             }
-            // 分页
-            searchSourceBuilder.from(from);
-            searchSourceBuilder.size(size);
-            // 允许搜索的超时时长,10s
-            searchSourceBuilder.timeout(new TimeValue(elasticSearchConfig.getSearchTimeOut(), TimeUnit.SECONDS));
-            searchRequest.source(searchSourceBuilder);
-            SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
-            // 返回结果
-            SearchHits searchHitArray = searchResponse.getHits();
-            for (SearchHit searchHit : searchHitArray.getHits()) {
-                Map<String, Object> sourceAsMap = searchHit.getSourceAsMap();
-                mapList.add(sourceAsMap);
+            sourceBuilder.size(pageSize);
+        }
+
+        //执行查询
+        SearchResponse response = executeSearch(indexName, sourceBuilder);
+        SearchHits searchHits = response.getHits();
+        SearchHit[] hits = searchHits.getHits();
+        totalNum = searchHits.getTotalHits().value;
+        for (SearchHit hit : hits) {
+            Map<String, Object> sourceMap = hit.getSourceAsMap();
+            sourceMap.put("id_s", hit.getId());
+            queryResult.add(sourceMap);
+        }
+        resultMap.put("pageList", queryResult);
+        resultMap.put("totalNum", totalNum);
+        resultMap.put("pageNum", pageNum);
+        resultMap.put("pageSize", pageSize);
+        return resultMap;
+    }
+
+    /**
+     * @param boolQueryBuilder
+     * @param key
+     * @param value
+     * @Description 查询条件组装
+     */
+    private static void queryValueBuild(BoolQueryBuilder boolQueryBuilder, String key, Object value) {
+        TermQueryBuilder termQueryBuilder;
+        if (null != value && !"".equals(value)) {
+            if (value instanceof String) {
+                String strValue = (String) value;
+                if (strValue.endsWith("%")) {
+                    PrefixQueryBuilder prefixQueryBuilder = QueryBuilders.prefixQuery(key, strValue.replace("%", ""));
+                    boolQueryBuilder.must(prefixQueryBuilder);
+                } else if (strValue.startsWith("*") && strValue.endsWith("*")) {
+                    WildcardQueryBuilder wildcardQueryBuilder = QueryBuilders.wildcardQuery(key, strValue);
+                    boolQueryBuilder.must(wildcardQueryBuilder);
+                } else if (strValue.startsWith("*") || strValue.endsWith("*")) {
+                    MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery(key, strValue.replace("*", ""));
+                    boolQueryBuilder.must(matchQueryBuilder);
+                } else {
+                    termQueryBuilder = QueryBuilders.termQuery(key, strValue);
+                    boolQueryBuilder.must(termQueryBuilder);
+                }
+            } else if (value instanceof Collection) {
+                Collection<? extends Object> collectionValue = (Collection<? extends Object>) value;
+                //此处使用了多值条件
+                boolQueryBuilder.must(QueryBuilders.termsQuery(key, collectionValue));
+            } else {
+                termQueryBuilder = QueryBuilders.termQuery(key, value);
+                boolQueryBuilder.must(termQueryBuilder);
             }
-        } catch (Exception e) {
-            e.printStackTrace();
         }
-        return mapList;
     }
 
+    /**
+     * @param boolQueryBuilder
+     * @param rangeCondition
+     * @Description 范围条件查询组装
+     */
+    private static void rangeValueBuild(BoolQueryBuilder boolQueryBuilder, Map<String, Object> rangeCondition) {
+        for (Map.Entry<String, Object> entry : rangeCondition.entrySet()) {
+            Map<String, Object> range = intervalParse((String) entry.getValue());
+            String key = entry.getKey();
+            RangeQueryBuilder rangeQueryBuilder;
+            if (key.endsWith("_s")) {
+                rangeQueryBuilder = QueryBuilders.rangeQuery(key + ".keyword");
+            } else {
+                rangeQueryBuilder = QueryBuilders.rangeQuery(key);
+            }
+            if (!ObjectUtil.isEmpty(range.get("leftValue"))) {
+                if (DefineConstant.INTERVAL_OPEN_VALUE.equals(range.get("leftType"))) {
+                    rangeQueryBuilder.from(range.get("leftValue"), false);
+                } else if (DefineConstant.INTERVAL_CLOSE_VALUE.equals(range.get("leftType"))) {
+                    rangeQueryBuilder.from(range.get("leftValue"), true);
+                }
+            }
+            if (!ObjectUtil.isEmpty(range.get("rightValue"))) {
+                if (DefineConstant.INTERVAL_OPEN_VALUE.equals(range.get("rightType"))) {
+                    rangeQueryBuilder.to(range.get("rightValue"), false);
+                } else if (DefineConstant.INTERVAL_CLOSE_VALUE.equals(range.get("rightType"))) {
+                    rangeQueryBuilder.to(range.get("rightValue"), true);
+                }
+            }
+            boolQueryBuilder.must(rangeQueryBuilder);
+        }
+    }
 
     /**
-     * 组合字段查询条件
-     *
-     * @param mpParams
-     * @param preciseQuery 1:精确查询 2:模糊查询 3.匹配多个字段的模糊查询(使用IK中文分词器)
+     * @param interval
      * @return
+     * @Description 区间解析:[,]/(,)/[,)/(,]
      */
-    public BoolQueryBuilder getBoolQueryBuilder(Map<String, Object> mpParams, Integer preciseQuery) {
-        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
-        try {
-            if (null != mpParams.get("search") && null != mpParams.get("fields")) {
-                if (mpParams.get("fields") instanceof List) {
-                    String[] fields = (String[]) ((List) mpParams.get("fields")).
-                            toArray(new String[((List) mpParams.get("fields")).size()]);
-                    MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery(mpParams.get("search"), fields);
-                    boolQueryBuilder = boolQueryBuilder.must(multiMatchQueryBuilder);
+    private static Map<String, Object> intervalParse(String interval) {
+        Map<String, Object> range = new HashMap<>();
+        if (interval.startsWith(DefineConstant.INTERVAL_CLOSE_LEFT)) {
+            range.put("leftType", DefineConstant.INTERVAL_CLOSE_VALUE);
+        } else if (interval.startsWith(DefineConstant.INTERVAL_OPEN_LEFT)) {
+            range.put("leftType", DefineConstant.INTERVAL_OPEN_VALUE);
+        } else {
+            log.error("区间参数格式错误:{}", interval);
+            //若实际业务相关需要,抛出异常处理throw new Exception();
+        }
+        if (interval.endsWith(DefineConstant.INTERVAL_CLOSE_RIGHT)) {
+            range.put("rightType", DefineConstant.INTERVAL_CLOSE_VALUE);
+        } else if (interval.startsWith(DefineConstant.INTERVAL_OPEN_RIGHT)) {
+            range.put("rightType", DefineConstant.INTERVAL_OPEN_VALUE);
+        } else {
+            log.error("区间参数格式错误:{}", interval);
+            //若实际业务相关需要,抛出异常处理throw new Exception();
+        }
+        int strLen = interval.length();
+        String[] lr = interval.substring(1, strLen - 1).split(DefineConstant.COMMAN_SIGN, 2);
+        if (lr.length > 0) {
+            range.put("leftValue", lr[0]);
+        }
+        if (lr.length > 1) {
+            range.put("rightValue", lr[1]);
+        }
+        return range;
+    }
+
+    /**
+     * @param sourceBuilder
+     * @param orderBy
+     * @Description 查询排序
+     */
+    private static void buildSort(SearchSourceBuilder sourceBuilder, List<String> orderBy) {
+        SortBuilder<FieldSortBuilder> sortBuilder;
+        for (String sortField : orderBy) {
+            if (sortField.startsWith("-")) {
+                //降序排序
+                if (sortField.endsWith("_s")) {
+                    sortBuilder = SortBuilders.fieldSort(sortField.replace("-", "") + ".keyword").order(SortOrder.DESC);
+                } else {
+                    sortBuilder = SortBuilders.fieldSort(sortField.replace("-", "")).order(SortOrder.DESC);
+                }
+            } else {
+                //升序排序
+                if (sortField.endsWith("_s")) {
+                    sortBuilder = SortBuilders.fieldSort(sortField.replace("-", "") + ".keyword").order(SortOrder.ASC);
+                } else {
+                    sortBuilder = SortBuilders.fieldSort(sortField.replace("-", "")).order(SortOrder.ASC);
                 }
             }
-//            if (mpParams != null) {
-//
-//                if (preciseQuery != null && preciseQuery == 1) {
-//                    for (Map.Entry<String, Object> entry : mpParams.entrySet()) {
-//                        // 精确匹配
-//                        TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery(entry.getKey() + ".keyword", entry.getValue());
-//                        boolQueryBuilder = boolQueryBuilder.must(termQueryBuilder);
-//                    }
-//
-//                }
-//            } else if (preciseQuery != null && preciseQuery == 2) {
-//                for (Map.Entry<String, Object> entry : mpParams.entrySet()) {
-//                    // 模糊匹配
-//                    MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery(entry.getKey(), entry.getValue());
-//                    boolQueryBuilder = boolQueryBuilder.must(matchQueryBuilder);
-//                }
-//
-//            } else if (preciseQuery != null && preciseQuery == 3) {
-//                //多词模糊匹配
-////                List<Object> values = ((MultiValueMap) mpParams).get("fields");
-//
-//               /* for (String value : values) {
-//
-//                    log.info(key + ": " + value);
-//
-//                }*/
-//                ((MultiValueMap) mpParams).entrySet().forEach(entry -> {
-//
-//                    MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery("新品", entry.).minimumShouldMatch("50%");
-//                    boolQueryBuilder = boolQueryBuilder.must(multiMatchQueryBuilder);
-//                });
-//
-//            }
-        } catch (Exception e) {
-            e.printStackTrace();
+            sourceBuilder.sort(sortBuilder);
         }
-        return boolQueryBuilder;
     }
 
+    /**
+     * @param indexName     对应的es的index名
+     * @param sourceBuilder
+     * @return
+     * @Description 执行查询
+     */
+    private static SearchResponse executeSearch(String indexName, SearchSourceBuilder sourceBuilder) {
+        // 获取不同系统的换行符
+        String lineSeparator = System.lineSeparator();
+        log.info(lineSeparator + "ES查询:index:" + indexName + lineSeparator + "search:" + sourceBuilder.toString() + lineSeparator);
+        SearchRequest searchRequest = new SearchRequest(indexName);
+        SearchResponse response = null;
+        searchRequest.source(sourceBuilder);
+        try {
+            response = client.search(searchRequest, RequestOptions.DEFAULT);
+            log.info("search status:{}, totalNum:{}", response.status(), response.getHits().getTotalHits());
+        } catch (IOException e) {
+            //异常处理,实际业务中是需要根据需求具体处理,自定义异常捕获
+            log.error(e.getMessage());
+        }
+        return response;
+    }
 
     /**
      * 索引创建前,判断索引是否存在

+ 5 - 0
ruoyi-system/pom.xml

@@ -23,6 +23,11 @@
             <artifactId>ruoyi-common</artifactId>
         </dependency>
 
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+        </dependency>
+
     </dependencies>
 
 </project>

+ 183 - 0
ruoyi-system/src/main/java/com/ruoyi/system/domain/ShipRecognition.java

@@ -0,0 +1,183 @@
+package com.ruoyi.system.domain;
+
+import java.math.BigDecimal;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.core.domain.BaseEntity;
+
+/**
+ * 船舶信息对象 ship_recognition
+ * 
+ * @author ruoyi
+ * @date 2021-08-24
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class ShipRecognition extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 主键 */
+    private Long id;
+
+    /** AIS船舶距离, 单位:m */
+    @Excel(name = "AIS船舶距离, 单位:m")
+    private BigDecimal aisdist;
+
+    /** AIS吃水, 单位:m */
+    @Excel(name = "AIS吃水, 单位:m")
+    private BigDecimal aisdrt;
+
+    /** AIS目的地 */
+    @Excel(name = "AIS目的地")
+    private String aisdst;
+
+    /** 9位码。例如412119710, 0或null表示AIS未开启 */
+    @Excel(name = "9位码。例如412119710, 0或null表示AIS未开启")
+    private Long aismmsi;
+
+    /** AIS船长, 单位:m */
+    @Excel(name = "AIS船长, 单位:m")
+    private Long aisshiplen;
+
+    /** 可能是中文,AIS船名,为拼音。例如SU SU HUO 009 */
+    @Excel(name = "可能是中文,AIS船名,为拼音。例如SU SU HUO 009")
+    private String aisshipname;
+
+    /** AIS船速, 单位:m/s */
+    @Excel(name = "AIS船速, 单位:m/s")
+    private BigDecimal aisshipspd;
+
+    /** AIS船舶类型 */
+    @Excel(name = "AIS船舶类型")
+    private String aisshiptype;
+
+    /** AIS船宽, 单位:m */
+    @Excel(name = "AIS船宽, 单位:m")
+    private Long aisshipwidth;
+
+    /** 尺寸异常 */
+    @Excel(name = "尺寸异常")
+    private Long isabnormalsize;
+
+    /** AIS纬度,单位:度 */
+    @Excel(name = "AIS纬度,单位:度")
+    private BigDecimal latitude;
+
+    /** 黑烟:度数 */
+    @Excel(name = "黑烟:度数")
+    private Long rcgsoot;
+
+    /** 船舶过闸闸次 */
+    @Excel(name = "船舶过闸闸次")
+    private Long lockseq;
+
+    /** AIS经度,单位:度 */
+    @Excel(name = "AIS经度,单位:度")
+    private BigDecimal longitude;
+
+    /** 图像识别得到的载货类型。例如:钢筋,砂石。 */
+    @Excel(name = "图像识别得到的载货类型。例如:钢筋,砂石。")
+    private String rcgcargotype;
+
+    /** 图像识别得到的船舶载重吨位, 单位:t */
+    @Excel(name = "图像识别得到的船舶载重吨位, 单位:t")
+    private BigDecimal rcgdeadweightton;
+
+    /** 图像识别得到的,船舶距离相机直线距离。单位:m */
+    @Excel(name = "图像识别得到的,船舶距离相机直线距离。单位:m")
+    private BigDecimal rcgdist;
+
+    /** 图像识别得到的船舶吃水, 单位:m */
+    @Excel(name = "图像识别得到的船舶吃水, 单位:m")
+    private BigDecimal rcgdrt;
+
+    /** 是否为船队。0 否,即单机船; 1 是,即为船队 */
+    @Excel(name = "是否为船队。0 否,即单机船; 1 是,即为船队")
+    private Long rcgisfleet;
+
+    /** UNKNOWN 未知, EMPTY_LOAD 空载, HEAVY_LOAD 重载, OVER_LOAD 超载 */
+    @Excel(name = "UNKNOWN 未知, EMPTY_LOAD 空载, HEAVY_LOAD 重载, OVER_LOAD 超载")
+    private String rcgloadsts;
+
+    /** 图像识别得到的船舶水面上高度,单位:m */
+    @Excel(name = "图像识别得到的船舶水面上高度,单位:m")
+    private BigDecimal rcgshipheightabovewater;
+
+    /** 图像识别得到的船长,单位:m */
+    @Excel(name = "图像识别得到的船长,单位:m")
+    private BigDecimal rcgshiplen;
+
+    /** 图像识别得到的船名, 中文, 如: 苏宿货009 */
+    @Excel(name = "图像识别得到的船名, 中文, 如: 苏宿货009")
+    private String rcgshipname;
+
+    /** 图像识别得到的速度,带符号,单位m/s */
+    @Excel(name = "图像识别得到的速度,带符号,单位m/s")
+    private BigDecimal rcgshipspd;
+
+    /** 图像识别得到的船舶类型。例如: 货船,集装箱船,危化品船 */
+    @Excel(name = "图像识别得到的船舶类型。例如: 货船,集装箱船,危化品船")
+    private String rcgshiptype;
+
+    /** 图像识别得到的船宽,单位:m */
+    @Excel(name = "图像识别得到的船宽,单位:m")
+    private BigDecimal rcgshipwidth;
+
+    /** 船籍港 */
+    @Excel(name = "船籍港")
+    private String regportname;
+
+    /** 抓拍图片路径 */
+    @Excel(name = "抓拍图片路径")
+    private String snapimpath;
+
+    /** 抓拍地点 */
+    @Excel(name = "抓拍地点")
+    private String snappos;
+
+    /** 抓拍时间 */
+    @Excel(name = "抓拍时间")
+    private String snaptime;
+
+    /** 抓拍时间统一格式: 2020-12-12 12:00:11 */
+    @Excel(name = "抓拍时间统一格式: 2020-12-12 12:00:11")
+    private String snaptimefmt;
+
+    /** 状态 */
+    @Excel(name = "状态")
+    private String status;
+
+    /** 船名特征信息 */
+    @Excel(name = "船名特征信息")
+    private String textfeaturelabel;
+
+    /** 船名识别原图url */
+    @Excel(name = "船名识别原图url")
+    private String textimgurl;
+
+    /** 图像识别得到的船舶详细类型 */
+    @Excel(name = "图像识别得到的船舶详细类型")
+    private String rcgshiptypedetail;
+
+    /** useWarn: true, 使用外部输入预警信息 */
+    @Excel(name = "useWarn: true, 使用外部输入预警信息")
+    private Long usewarn;
+
+    /** 外部输入报警信息详情 */
+    @Excel(name = "外部输入报警信息详情")
+    private String warnlabellist;
+
+    /** 二维码识别内容 */
+    @Excel(name = "二维码识别内容")
+    private String qrcode;
+
+    /** 船名方向 */
+    @Excel(name = "船名方向")
+    private String shipnamedirection;
+
+}