Переглянути джерело

设备经纬度地址查询与删除

LiTaohong 7 роки тому
батько
коміт
aa73b2d26b

+ 7 - 0
common/common-request-mapping/src/main/java/com/yihu/jw/rm/iot/IotRequestMapping.java

@ -121,6 +121,13 @@ public class IotRequestMapping {
        public static final String updatePatientDevice= "updatePatientDevice";
        public static final String findListByPatient= "findListByPatient";
        public static final String findAllLocations= "findAllLocations";
        public static final String findLocationByIdCard= "findLocationByIdCard";
        public static final String findLocationBySn= "findLocationBySn";
        public static final String deleteLocation= "deteleLocation";
        public static final String updateLocation= "deteleLocation";
    }

+ 15 - 0
common/common-rest-model/pom.xml

@ -51,5 +51,20 @@
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-elasticsearch</artifactId>
            <version>2.1.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>io.searchbox</groupId>
            <artifactId>jest-common</artifactId>
            <version>2.4.0</version>
        </dependency>
        <dependency>
            <groupId>com.yihu.base</groupId>
            <artifactId>common-data-es</artifactId>
            <version>1.0.0</version>
        </dependency>
    </dependencies>
</project>

+ 90 - 0
common/common-rest-model/src/main/java/com/yihu/jw/restmodel/iot/device/LocationDataVO.java

@ -0,0 +1,90 @@
package com.yihu.jw.restmodel.iot.device;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.yihu.base.es.config.model.SaveModel;
import io.searchbox.annotations.JestId;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import org.springframework.data.elasticsearch.core.geo.GeoPoint;
/**
 * Created by chenweida on 2018/2/12.
 */
@JsonInclude(JsonInclude.Include.ALWAYS)
@ApiModel(value = "设备地址信息", description = "设备地址信息")
public class LocationDataVO extends SaveModel {
    @ApiModelProperty("设备绑定的居民身份证")
    private String idCard;
    @ApiModelProperty("设备类型标识")
    private String categoryCode;
    @ApiModelProperty("设备SnID")
    private String deviceSn;
    @ApiModelProperty("设备经纬度")
    private GeoPoint location;
    @ApiModelProperty("设备绑定时间")
    private String deviceTime;
    @ApiModelProperty("创建时间")
    private String createTime;
    public String getIdCard() {
        return idCard;
    }
    public void setIdCard(String idCard) {
        this.idCard = idCard;
    }
    public String getDeviceSn() {
        return deviceSn;
    }
    public void setDeviceSn(String deviceSn) {
        this.deviceSn = deviceSn;
    }
    public String getCategoryCode() {
        return categoryCode;
    }
    public void setCategoryCode(String categoryCode) {
        this.categoryCode = categoryCode;
    }
    public GeoPoint getLocation() {
        return location;
    }
    public void setLocation(GeoPoint location) {
        this.location = location;
    }
    public String getDeviceTime() {
        return deviceTime;
    }
    public void setDeviceTime(String deviceTime) {
        this.deviceTime = deviceTime;
    }
    public String getCreateTime() {
        return createTime;
    }
    public void setCreateTime(String createTime) {
        this.createTime = createTime;
    }
    public void setLocation(Double lat, Double lng) {
        GeoPoint geoPoint = new GeoPoint(lat, lng);
        this.location = geoPoint;
    }
}

+ 33 - 0
svr/svr-iot/sql-scripts/device_location_es.sql

@ -0,0 +1,33 @@
-- 设备地址elasticsearch 新增mapping
curl -XPUT http://url/device_location_index
{
        "mappings": {
            "device_location_type": {
                "properties": {
                    "categoryCode": {
                        "type": "string"
                    },
                    "createTime": {
                        "type": "date",
                        "format": "yyyy-MM-dd HH:mm:ss"
                    },
                    "deviceSn": {
                        "type": "string"
                    },
                    "deviceTime": {
                        "type": "date",
                        "format": "yyyy-MM-dd HH:mm:ss"
                    },
                    "idCard": {
                        "type": "string"
                    },
                    "location": {
                        "type": "geo_point"
                    }
                }
            }
        }
}

+ 59 - 2
svr/svr-iot/src/main/java/com/yihu/iot/controller/device/IotPatientDeviceController.java

@ -6,6 +6,7 @@ import com.yihu.jw.restmodel.common.Envelop;
import com.yihu.jw.restmodel.common.EnvelopRestController;
import com.yihu.jw.restmodel.iot.device.IotDeviceVO;
import com.yihu.jw.restmodel.iot.device.IotPatientDeviceVO;
import com.yihu.jw.restmodel.iot.device.LocationDataVO;
import com.yihu.jw.rm.iot.IotRequestMapping;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
@ -31,7 +32,7 @@ public class IotPatientDeviceController extends EnvelopRestController{
    @PostMapping(value = IotRequestMapping.PatientDevice.addPatientDevice)
    @ApiOperation(value = "设备绑定", notes = "设备绑定")
    public Envelop<IotPatientDeviceVO> create(@ApiParam(name = "json_data", value = "", defaultValue = "")
    public Envelop<IotPatientDeviceVO> create(@ApiParam(name = "jsonData", value = "", defaultValue = "")
                                       @RequestParam String jsonData) {
        try {
            //设备绑定
@ -144,7 +145,8 @@ public class IotPatientDeviceController extends EnvelopRestController{
            @ApiParam(name = "deviceSn", value = "sn码", defaultValue = "")
            @RequestParam(value = "deviceSn",required = true) String deviceSn,
            @ApiParam(name = "categoryCode", value = "设备类型", defaultValue = "")
            @RequestParam(value = "categoryCode",required = true) String categoryCode,
            @RequestParam(value = "categoryCode",required = true) String categoryCode
            ,
            @ApiParam(name = "userType", value = "按键号", defaultValue = "")
            @RequestParam(value = "userType",required = true) String userType) {
        try {
@ -180,4 +182,59 @@ public class IotPatientDeviceController extends EnvelopRestController{
        }
    }
    @GetMapping(value = IotRequestMapping.PatientDevice.findAllLocations)
    @ApiOperation(value = "查询所有设备地址", notes = "查询所有设备地址")
    public Envelop<List<LocationDataVO>> findAllDeviceLocations() {
        try {
            List<LocationDataVO> list = iotPatientDeviceService.findAllDeviceLocations();
            return Envelop.getSuccess(IotRequestMapping.Device.message_success_create,list);
        } catch (Exception e) {
            e.printStackTrace();
            return Envelop.getError(e.getMessage());
        }
    }
    @GetMapping(value = IotRequestMapping.PatientDevice.findLocationByIdCard)
    @ApiOperation(value = "根据idCard查询设备地址", notes = "根据idCard查询设备地址")
    public Envelop<List<LocationDataVO>> findDeviceLocationsByIdCard(@ApiParam(name = "jsonData", value = "jsonData", defaultValue = "")
                                                                     @RequestParam(value = "jsonData",required = true) String jsonData) {
        try {
            List<LocationDataVO> list = iotPatientDeviceService.findDeviceLocationsByIdCard(jsonData);
            return Envelop.getSuccess(IotRequestMapping.Device.message_success_create,list);
        } catch (Exception e) {
            e.printStackTrace();
            return Envelop.getError(e.getMessage());
        }
    }
    @GetMapping(value = IotRequestMapping.PatientDevice.findLocationBySn)
    @ApiOperation(value = "根据sn码查询设备地址", notes = "根据sn码查询设备地址")
    public Envelop<List<LocationDataVO>> findDeviceLocationsBySn(@ApiParam(name = "jsonData", value = "jsonData", defaultValue = "")
                                                                     @RequestParam(value = "jsonData",required = true) String jsonData) {
        try {
            List<LocationDataVO> list = iotPatientDeviceService.findDeviceLocationsBySn(jsonData);
            return Envelop.getSuccess(IotRequestMapping.Device.message_success_create,list);
        } catch (Exception e) {
            e.printStackTrace();
            return Envelop.getError(e.getMessage());
        }
    }
    @GetMapping(value = IotRequestMapping.PatientDevice.deleteLocation)
    @ApiOperation(value = "解绑设备删除地址", notes = "解绑设备删除地址")
    public Envelop deleteLocation(@ApiParam(name = "jsonData", value = "jsonData", defaultValue = "")
                                                                 @RequestParam(value = "jsonData",required = true) String jsonData) {
        try {
            boolean bool = iotPatientDeviceService.deleteLocationsByIdcardOrSn(jsonData);
            if(bool){
                return Envelop.getSuccess(IotRequestMapping.Device.message_success_create,"device delete success");
            }
            return Envelop.getError("delete fail,not exist");
        } catch (Exception e) {
            e.printStackTrace();
            return Envelop.getError(e.getMessage());
        }
    }
}

+ 8 - 258
svr/svr-iot/src/main/java/com/yihu/iot/datainput/service/DataSearchService.java

@ -7,6 +7,7 @@ import com.yihu.base.hbase.HBaseHelper;
import com.yihu.iot.datainput.enums.DataTypeEnum;
import com.yihu.iot.datainput.util.ConstantUtils;
import com.yihu.iot.datainput.util.RowKeyUtils;
import com.yihu.iot.service.common.ElasticSearchQueryGenerator;
import com.yihu.jw.iot.datainput.Data;
import com.yihu.jw.iot.datainput.StepInfoDO;
import com.yihu.jw.restmodel.iot.datainput.DataBodySignsVO;
@ -17,19 +18,11 @@ import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.hbase.util.CollectionUtils;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.beans.PropertyDescriptor;
import java.util.*;
@Component
@ -41,96 +34,16 @@ public class DataSearchService {
    private ElastricSearchHelper elastricSearchHelper;
    @Autowired
    private HBaseHelper hBaseHelper;
    private static Map<String,Set<String>> fieldsMap = new HashMap<>();
    @PostConstruct
    public static void init(){
        Set<String> fieldsSet = new HashSet<>();
        PropertyDescriptor[] properties = BeanUtils.getPropertyDescriptors(Data.class);
        for(PropertyDescriptor field:properties){
            fieldsSet.add(field.getName());
        }
        fieldsMap.put("data",fieldsSet);
        Set<String> fieldsSet2 = new HashSet<>();
        PropertyDescriptor[] properties2 = BeanUtils.getPropertyDescriptors(StepInfoDO.class);
        for(PropertyDescriptor field:properties2){
            fieldsSet2.add(field.getName());
        }
        fieldsMap.put("stepInfoList",fieldsSet2);
    }
    /**
     * 拼接es搜索json string
     * @param json
     * @return
     */
    public static String getQueryString(String json){
        JSONObject jsonObject = JSONObject.parseObject(json);
        //第一层query
        JSONObject query = new JSONObject();
        //bool层
        JSONObject boolQuery = new JSONObject();
        // and 还是 or,es中key为and--->must,or--->should
        JSONObject mustOrShouldQuery = new JSONObject();
        //匹配项,字段-值
        JSONArray jsonArray = new JSONArray();
        for(String key : jsonObject.keySet()){
            //默认为must
            if(StringUtils.equalsIgnoreCase("or",key) && StringUtils.equals("or",jsonObject.getString("or"))){
                mustOrShouldQuery.put("should",jsonArray);
            }else{
                mustOrShouldQuery.put("must",jsonArray);
            }
    private ElasticSearchQueryGenerator elasticSearchQueryGenerator;
            //分页用,from表示数据从第几条开始取
            if(StringUtils.equalsIgnoreCase("from",key)){
                query.put("from",jsonObject.getInteger("from"));
                continue;
            }
            //分页用,size表示获取几条数据
            if(StringUtils.equalsIgnoreCase("size",key)){
                query.put("size",jsonObject.getInteger("size"));
                continue;
            }
            //排序
            if(StringUtils.equalsIgnoreCase("sort",key)){
                JSONObject sortJsonObj = (JSONObject)jsonObject.get("sort");
                for(String sortKey:sortJsonObj.keySet()){
                    if(!StringUtils.equalsIgnoreCase("asc",sortJsonObj.getString(sortKey)) && !StringUtils.equalsIgnoreCase("desc",sortJsonObj.getString(sortKey) )){
                        JSONObject error = new JSONObject();
                        error.put("error","sort contains bad value !");
                        return error.toJSONString();
                    }
                }
                query.put("sort",sortJsonObj);
                continue;
            }
            JSONObject matchQuery = new JSONObject();
            JSONObject subQuery = new JSONObject();
            String baseName = DataTypeEnum.body_sign_params.name().toString();
            if(null != DataStandardConvertService.dataMap.get(baseName) && DataStandardConvertService.dataMap.get(baseName).contains(key) || StringUtils.equalsIgnoreCase("rid",key)){
                subQuery.put("data."+key,jsonObject.get(key)); //data数据里内嵌的字段,真正的数据值内容
            }else{
                subQuery.put(key,jsonObject.get(key));
            }
            matchQuery.put("match",subQuery);
            jsonArray.add(matchQuery);
        }
        boolQuery.put("bool",mustOrShouldQuery);
        query.put("query",boolQuery);
        return query.toJSONString();
    }
    @Autowired
    private HBaseHelper hBaseHelper;
    public String getData(String jsonData){
        logger.info("load data from elasticsearch start:" + org.apache.http.client.utils.DateUtils.formatDate(new Date(), DateUtil.yyyy_MM_dd_HH_mm_ss));
        JSONObject resultJsonObj = new JSONObject();
        JSONArray  resultArray = new JSONArray();
        SearchSourceBuilder query = getQueryBuilder("data",jsonData);
        SearchSourceBuilder query = elasticSearchQueryGenerator.getQueryBuilder("data",jsonData);
        SearchResult esResult = elastricSearchHelper.search(ConstantUtils.esIndex,ConstantUtils.esType,query.toString());
        if(esResult.getTotal() == 0){
            return "";
@ -158,147 +71,6 @@ public class DataSearchService {
//        }
    }
    /**
     * 构造es查询参数
     * @param jsonData
     *
             {
             "filter":[{"andOr":"and|or","condition":">|=|<|>=|<=|?","field":"<filed>","value":"<value>"},<{...}>],
                       - 参数说明:andOr跟数据库的中的AND和OR相似;condition指条件匹配程度,?相当于数据库中的like;filed指检索的字段;value为检索的值
            "page":1,  - 参数格式:页码,默认1,int类型 不需要分页,传""
            "size":10, - 参数格式:条数,默认10,int类型 不需要分页,传""
            "sort":[
                     {"key":{"order":"asc|desc"}}, - 参数格式:排序, key要排序的字段,order固定,取值asc或desc,不需要排序,传""
                     {"key":{"order":"asc|desc"}}
                  ]
            }
     * @return
     */
    private static SearchSourceBuilder getQueryBuilder(String nestedPath,String jsonData) {
        JSONObject json = JSONObject.parseObject(jsonData);
        List<Map<String, Object>> filter = (List)json.getJSONArray("filter");
        int page = json.getIntValue("page") == 0 ? 1:json.getIntValue("page"); //从第一页开始
        int size = json.getIntValue("size") == 0 ? 1:json.getIntValue("size"); //默认值为1,最少获取一条记录
        JSONArray sort = json.getJSONArray("sort");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        boolQueryBuilder = getBoolQueryBuilder(nestedPath,jsonData,false);//非嵌套的数据查询不需要nested
        NestedQueryBuilder nestedQueryBuilder = getNestedBuilder(nestedPath,jsonData);//嵌套的数据查询
        QueryFilterBuilder filterBuilder = QueryBuilders.queryFilter(nestedQueryBuilder);
        FilteredQueryBuilder filteredQueryBuilder = QueryBuilders.filteredQuery(boolQueryBuilder,filterBuilder);
        searchSourceBuilder.from((page -1)*size);
        searchSourceBuilder.size(size);
        //排序
        if(CollectionUtils.notEmpty(sort)){
            for(Object obj:sort){
                JSONObject object = JSONObject.parseObject(obj.toString());
                FieldSortBuilder fieldSortBuilder = null;
                for(String key:object.keySet()){
                    if(!CollectionUtils.isEmpty(fieldsMap.get(nestedPath)) && fieldsMap.get(nestedPath).contains(key)){
                        fieldSortBuilder = new FieldSortBuilder("data." + key);
                    }else{
                        fieldSortBuilder = new FieldSortBuilder(key);
                    }
                    JSONObject sortValue = object.getJSONObject(key);
                    if(StringUtils.equalsIgnoreCase(SortOrder.ASC.toString(),sortValue.getString("order"))){
                        fieldSortBuilder.order(SortOrder.ASC);
                    }else if(StringUtils.equalsIgnoreCase(SortOrder.DESC.toString(),sortValue.getString("order"))){
                        fieldSortBuilder.order(SortOrder.DESC);
                    }
                    fieldSortBuilder.setNestedPath("data");
                    searchSourceBuilder.sort(fieldSortBuilder);
                }
            }
        }
        searchSourceBuilder.query(filteredQueryBuilder);
        return searchSourceBuilder;
    }
    /**
     * 嵌套的查询query
     * @param nestedPath
     * @param queryCondition
     * @return
     */
    private static NestedQueryBuilder getNestedBuilder(String nestedPath,String queryCondition){
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        boolQueryBuilder = getBoolQueryBuilder(nestedPath,queryCondition,true);
        NestedQueryBuilder nestedQueryBuilder = QueryBuilders.nestedQuery(nestedPath,boolQueryBuilder);
        return nestedQueryBuilder;
    }
    /**
     * 构造bool查询(里面有匹配,过滤,范围等)
     * @param nestedPath
     * @param queryCondition
     * @return
     */
    private static BoolQueryBuilder getBoolQueryBuilder(String nestedPath,String queryCondition,Boolean isNested){
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        JSONObject jsonCondition = JSONObject.parseObject(queryCondition);
        List<Map<String, Object>> filter = (List)jsonCondition.getJSONArray("filter");
        for(Map<String, Object> param : filter) {
            String andOr = String.valueOf(param.get("andOr"));
            String condition = String.valueOf(param.get("condition"));
            String field = String.valueOf(param.get("field"));
            Object value = param.get("value");
            if(!isNested){
                if(!CollectionUtils.isEmpty(fieldsMap.get(nestedPath)) && fieldsMap.get(nestedPath).contains(field)){
                    continue;
                }
            }else{
                if(!CollectionUtils.isEmpty(fieldsMap.get(nestedPath)) && !fieldsMap.get(nestedPath).contains(field)){
                    continue;
                }
                field = nestedPath + "." + field;
            }
            if("null".equals(condition)){
                MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery(field, value);
                if("null".equals(andOr)) {
                    boolQueryBuilder.must(matchQueryBuilder);
                }
            }else if(condition.equals("=")) {
                MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery(field, value);
                if("and".equals(andOr)) {
                    boolQueryBuilder.must(matchQueryBuilder);
                }else if("or".equals(andOr)) {
                    boolQueryBuilder.should(matchQueryBuilder);
                }
            }else if (condition.equals("?")) {
                QueryStringQueryBuilder queryStringQueryBuilder = QueryBuilders.queryStringQuery(field + ":" + value);
                if("and".equals(andOr)) {
                    boolQueryBuilder.must(queryStringQueryBuilder);
                }else if("or".equals(andOr)) {
                    boolQueryBuilder.should(queryStringQueryBuilder);
                }
            }else {
                RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery(field);
                if(field.endsWith("Date")) {
                    rangeQueryBuilder.format("yyyy-MM-dd HH:mm:ss");
                }
                if(condition.equals(">")) {
                    rangeQueryBuilder.gt(value);
                }else if(condition.equals(">=")) {
                    rangeQueryBuilder.gte(value);
                }else if(condition.equals("<=")) {
                    rangeQueryBuilder.lte(value);
                }else if(condition.equals("<")) {
                    rangeQueryBuilder.lt(value);
                }
                if("and".equals(andOr)) {
                    boolQueryBuilder.must(rangeQueryBuilder);
                }else if("or".equals(andOr)) {
                    boolQueryBuilder.should(rangeQueryBuilder);
                }
            }
        }
        return boolQueryBuilder;
    }
    /**
@ -320,7 +92,7 @@ public class DataSearchService {
        filter.add(queryField);
        JSONObject query = new JSONObject();
        query.put("filter",filter);
        SearchSourceBuilder queryString = getQueryBuilder("data",query.toJSONString());
        SearchSourceBuilder queryString = elasticSearchQueryGenerator.getQueryBuilder("data",query.toJSONString());
        JSONArray datas = new JSONArray();
        JSONObject resultObject = new JSONObject();
        String _id = "";
@ -425,7 +197,7 @@ public class DataSearchService {
    public List<DataBodySignsVO> getDataToBean(String jsonData){
        List<DataBodySignsVO> result = new ArrayList<>();
        logger.info("load data from elasticsearch start:" + org.apache.http.client.utils.DateUtils.formatDate(new Date(), DateUtil.yyyy_MM_dd_HH_mm_ss));
        SearchSourceBuilder query = getQueryBuilder("data",jsonData);
        SearchSourceBuilder query = elasticSearchQueryGenerator.getQueryBuilder("data",jsonData);
        SearchResult esResult = elastricSearchHelper.search(ConstantUtils.esIndex,ConstantUtils.esType,query.toString());
        if(null== esResult || esResult.getTotal()==null || esResult.getTotal() == 0){
            return result;
@ -445,7 +217,7 @@ public class DataSearchService {
     */
    public List<WeRunDataVO> getWeRunDataList(String json){
        List<WeRunDataVO> result = new ArrayList<>();
        SearchSourceBuilder query = getQueryBuilder("stepInfoList",json);
        SearchSourceBuilder query = elasticSearchQueryGenerator.getQueryBuilder("stepInfoList",json);
        SearchResult esResult = elastricSearchHelper.search(ConstantUtils.weRunDataIndex,ConstantUtils.weRunDataType,query.toString());
        if(null != esResult && esResult.getTotal() == 0){
            return result;
@ -457,26 +229,4 @@ public class DataSearchService {
        return result;
    }
    public static void main(String args[]) {
        init();
        String str = "{\n" +
                "\t\"filter\":[{\n" +
                "\t\t\"andOr\":\"and\",\n" +
                "\t\t\"condition\":\"=\",\n" +
                "\t\t\"field\":\"usercode\",\n" +
                "\t\t\"value\":\"thisisjustatest\"\n" +
                "\t},\n" +
                "\t{\n" +
                "\t\t\"andOr\":\"and\",\n" +
                "\t\t\"condition\":\"=\",\n" +
                "\t\t\"field\":\"step\",\n" +
                "\t\t\"value\":100\n" +
                "\t}\n" +
                "\t]\n" +
                "}\n";
        getQueryBuilder("stepInfoList",str);
    }
}

+ 296 - 0
svr/svr-iot/src/main/java/com/yihu/iot/service/common/ElasticSearchQueryGenerator.java

@ -0,0 +1,296 @@
package com.yihu.iot.service.common;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.yihu.iot.datainput.enums.DataTypeEnum;
import com.yihu.iot.datainput.service.DataStandardConvertService;
import com.yihu.jw.iot.datainput.Data;
import com.yihu.jw.iot.datainput.StepInfoDO;
import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.hbase.util.CollectionUtils;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.beans.PropertyDescriptor;
import java.util.*;
@Component
public class ElasticSearchQueryGenerator {
    private static Map<String,Set<String>> fieldsMap = new HashMap<>();
    @PostConstruct
    public static void init(){
        Set<String> fieldsSet = new HashSet<>();
        PropertyDescriptor[] properties = BeanUtils.getPropertyDescriptors(Data.class);
        for(PropertyDescriptor field:properties){
            fieldsSet.add(field.getName());
        }
        fieldsMap.put("data",fieldsSet);
        Set<String> fieldsSet2 = new HashSet<>();
        PropertyDescriptor[] properties2 = BeanUtils.getPropertyDescriptors(StepInfoDO.class);
        for(PropertyDescriptor field:properties2){
            fieldsSet2.add(field.getName());
        }
        fieldsMap.put("stepInfoList",fieldsSet2);
    }
    /**
     * 构造es查询参数
     * @param jsonData
     *
    {
    "filter":[{"andOr":"and|or","condition":">|=|<|>=|<=|?","field":"<filed>","value":"<value>"},<{...}>],
    - 参数说明:andOr跟数据库的中的AND和OR相似;condition指条件匹配程度,?相当于数据库中的like;filed指检索的字段;value为检索的值
    "page":1,  - 参数格式:页码,默认1,int类型 不需要分页,传""
    "size":10, - 参数格式:条数,默认10,int类型 不需要分页,传""
    "sort":[
    {"key":{"order":"asc|desc"}}, - 参数格式:排序, key要排序的字段,order固定,取值asc或desc,不需要排序,传""
    {"key":{"order":"asc|desc"}}
    ]
    }
     * @return
     */
    public SearchSourceBuilder getQueryBuilder(String nestedPath, String jsonData) {
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        //什么都不传的情况下,构造查询所有的语句
        if(StringUtils.isEmpty(jsonData)){
            MatchAllQueryBuilder allQueryBuilder = QueryBuilders.matchAllQuery();
            return searchSourceBuilder.query(allQueryBuilder);
        }
        JSONObject json = JSONObject.parseObject(jsonData);
        List<Map<String, Object>> filter = (List)json.getJSONArray("filter");
        int page = json.getIntValue("page") == 0 ? 1:json.getIntValue("page"); //从第一页开始
        int size = json.getIntValue("size") == 0 ? 1:json.getIntValue("size"); //默认值为1,最少获取一条记录
        JSONArray sort = json.getJSONArray("sort");
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        boolQueryBuilder = getBoolQueryBuilder(nestedPath,jsonData,false);//非嵌套的数据查询不需要nested
        searchSourceBuilder.from((page -1)*size);
        searchSourceBuilder.size(size);
        //排序
        if(CollectionUtils.notEmpty(sort)){
            for(Object obj:sort){
                JSONObject object = JSONObject.parseObject(obj.toString());
                FieldSortBuilder fieldSortBuilder = null;
                for(String key:object.keySet()){
                    if(!CollectionUtils.isEmpty(fieldsMap.get(nestedPath)) && fieldsMap.get(nestedPath).contains(key)){
                        fieldSortBuilder = new FieldSortBuilder("data." + key);
                    }else{
                        fieldSortBuilder = new FieldSortBuilder(key);
                    }
                    JSONObject sortValue = object.getJSONObject(key);
                    if(StringUtils.equalsIgnoreCase(SortOrder.ASC.toString(),sortValue.getString("order"))){
                        fieldSortBuilder.order(SortOrder.ASC);
                    }else if(StringUtils.equalsIgnoreCase(SortOrder.DESC.toString(),sortValue.getString("order"))){
                        fieldSortBuilder.order(SortOrder.DESC);
                    }
                    fieldSortBuilder.setNestedPath("data");
                    searchSourceBuilder.sort(fieldSortBuilder);
                }
            }
        }
        if(StringUtils.isNotEmpty(nestedPath)){
            NestedQueryBuilder nestedQueryBuilder = getNestedBuilder(nestedPath,jsonData);//嵌套的数据查询
            QueryFilterBuilder filterBuilder = QueryBuilders.queryFilter(nestedQueryBuilder);
            QueryBuilder filteredQueryBuilder = QueryBuilders.filteredQuery(boolQueryBuilder,filterBuilder);
            searchSourceBuilder.query(filteredQueryBuilder);
        }else{
            searchSourceBuilder.query(boolQueryBuilder);
        }
        return searchSourceBuilder;
    }
    /**
     * 嵌套的查询query
     * @param nestedPath
     * @param queryCondition
     * @return
     */
    private NestedQueryBuilder getNestedBuilder(String nestedPath,String queryCondition){
        if(StringUtils.isEmpty(nestedPath)){
            return null;
        }
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        boolQueryBuilder = getBoolQueryBuilder(nestedPath,queryCondition,true);
        NestedQueryBuilder nestedQueryBuilder = QueryBuilders.nestedQuery(nestedPath,boolQueryBuilder);
        return nestedQueryBuilder;
    }
    /**
     * 构造bool查询(里面有匹配,过滤,范围等)
     * @param nestedPath
     * @param queryCondition
     * @return
     */
    private BoolQueryBuilder getBoolQueryBuilder(String nestedPath,String queryCondition,Boolean isNested){
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        JSONObject jsonCondition = JSONObject.parseObject(queryCondition);
        List<Map<String, Object>> filter = (List)jsonCondition.getJSONArray("filter");
        for(Map<String, Object> param : filter) {
            String andOr = String.valueOf(param.get("andOr"));
            String condition = String.valueOf(param.get("condition"));
            String field = String.valueOf(param.get("field"));
            Object value = param.get("value");
            //如果传过来的字段为空则表示查询全部
            if(StringUtils.isEmpty(field)){
                MatchAllQueryBuilder matchQueryBuilder = QueryBuilders.matchAllQuery();
                boolQueryBuilder.must(matchQueryBuilder);
                return boolQueryBuilder;
            }
            if(!isNested){
                if(!CollectionUtils.isEmpty(fieldsMap.get(nestedPath)) && fieldsMap.get(nestedPath).contains(field)){
                    continue;
                }
            }else{
                if(!CollectionUtils.isEmpty(fieldsMap.get(nestedPath)) && !fieldsMap.get(nestedPath).contains(field)){
                    continue;
                }
                field = nestedPath + "." + field;
            }
            if("null".equals(condition)){
                MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery(field, value);
                if("null".equals(andOr)) {
                    boolQueryBuilder.must(matchQueryBuilder);
                }
            }else if(condition.equals("=")) {
                MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery(field, value);
                if("and".equals(andOr)) {
                    boolQueryBuilder.must(matchQueryBuilder);
                }else if("or".equals(andOr)) {
                    boolQueryBuilder.should(matchQueryBuilder);
                }
            }else if (condition.equals("?")) {
                QueryStringQueryBuilder queryStringQueryBuilder = QueryBuilders.queryStringQuery(field + ":" + value);
                if("and".equals(andOr)) {
                    boolQueryBuilder.must(queryStringQueryBuilder);
                }else if("or".equals(andOr)) {
                    boolQueryBuilder.should(queryStringQueryBuilder);
                }
            }else {
                RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery(field);
                if(field.endsWith("Date")) {
                    rangeQueryBuilder.format("yyyy-MM-dd HH:mm:ss");
                }
                if(condition.equals(">")) {
                    rangeQueryBuilder.gt(value);
                }else if(condition.equals(">=")) {
                    rangeQueryBuilder.gte(value);
                }else if(condition.equals("<=")) {
                    rangeQueryBuilder.lte(value);
                }else if(condition.equals("<")) {
                    rangeQueryBuilder.lt(value);
                }
                if("and".equals(andOr)) {
                    boolQueryBuilder.must(rangeQueryBuilder);
                }else if("or".equals(andOr)) {
                    boolQueryBuilder.should(rangeQueryBuilder);
                }
            }
        }
        return boolQueryBuilder;
    }
    /**
     * 构造查询所有的语句
     * @return
     */
    public SearchSourceBuilder getQueryAllBuilder(){
        return getQueryBuilder("","");
    }
    /**
     * 拼接es搜索json string
     * @param json
     * @return
     */
    public static String getQueryString(String json){
        JSONObject jsonObject = JSONObject.parseObject(json);
        //第一层query
        JSONObject query = new JSONObject();
        //bool层
        JSONObject boolQuery = new JSONObject();
        // and 还是 or,es中key为and--->must,or--->should
        JSONObject mustOrShouldQuery = new JSONObject();
        //匹配项,字段-值
        JSONArray jsonArray = new JSONArray();
        for(String key : jsonObject.keySet()){
            //默认为must
            if(StringUtils.equalsIgnoreCase("or",key) && StringUtils.equals("or",jsonObject.getString("or"))){
                mustOrShouldQuery.put("should",jsonArray);
            }else{
                mustOrShouldQuery.put("must",jsonArray);
            }
            //分页用,from表示数据从第几条开始取
            if(StringUtils.equalsIgnoreCase("from",key)){
                query.put("from",jsonObject.getInteger("from"));
                continue;
            }
            //分页用,size表示获取几条数据
            if(StringUtils.equalsIgnoreCase("size",key)){
                query.put("size",jsonObject.getInteger("size"));
                continue;
            }
            //排序
            if(StringUtils.equalsIgnoreCase("sort",key)){
                JSONObject sortJsonObj = (JSONObject)jsonObject.get("sort");
                for(String sortKey:sortJsonObj.keySet()){
                    if(!StringUtils.equalsIgnoreCase("asc",sortJsonObj.getString(sortKey)) && !StringUtils.equalsIgnoreCase("desc",sortJsonObj.getString(sortKey) )){
                        JSONObject error = new JSONObject();
                        error.put("error","sort contains bad value !");
                        return error.toJSONString();
                    }
                }
                query.put("sort",sortJsonObj);
                continue;
            }
            JSONObject matchQuery = new JSONObject();
            JSONObject subQuery = new JSONObject();
            String baseName = DataTypeEnum.body_sign_params.name().toString();
            if(null != DataStandardConvertService.dataMap.get(baseName) && DataStandardConvertService.dataMap.get(baseName).contains(key) || StringUtils.equalsIgnoreCase("rid",key)){
                subQuery.put("data."+key,jsonObject.get(key)); //data数据里内嵌的字段,真正的数据值内容
            }else{
                subQuery.put(key,jsonObject.get(key));
            }
            matchQuery.put("match",subQuery);
            jsonArray.add(matchQuery);
        }
        boolQuery.put("bool",mustOrShouldQuery);
        query.put("query",boolQuery);
        return query.toJSONString();
    }
    public static void main(String args[]) {
//        elasticSearchQueryGenerator.init();
       /* String str = "{\n" +
                "\t\"filter\": [{\n" +
                "\t\t\"andOr\": \"and\",\n" +
                "\t\t\"condition\": \"=\",\n" +
                "\t\t\"field\": \"\",\n" +
                "\t\t\"value\": \"\"\n" +
                "\t}]\n" +
                "}";
        getQueryBuilder("",str);*/
    }
}

+ 77 - 3
svr/svr-iot/src/main/java/com/yihu/iot/service/device/IotPatientDeviceService.java

@ -2,14 +2,19 @@ package com.yihu.iot.service.device;
import com.alibaba.fastjson.JSONObject;
import com.yihu.base.es.config.ElastricSearchHelper;
import com.yihu.base.es.config.model.SaveModel;
import com.yihu.base.mysql.query.BaseJpaService;
import com.yihu.iot.dao.device.IotPatientDeviceDao;
import com.yihu.iot.datainput.util.ConstantUtils;
import com.yihu.iot.service.common.ElasticSearchQueryGenerator;
import com.yihu.jw.iot.device.IotPatientDeviceDO;
import com.yihu.jw.iot.device.LocationDataDO;
import com.yihu.jw.restmodel.iot.device.IotPatientDeviceVO;
import com.yihu.jw.restmodel.iot.device.LocationDataVO;
import com.yihu.jw.util.common.LatitudeUtils;
import com.yihu.jw.util.date.DateUtil;
import io.searchbox.client.JestResult;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@ -17,9 +22,7 @@ import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.*;
/**
 * @author yeshijie on 2018/1/16.
@ -32,6 +35,8 @@ public class IotPatientDeviceService extends BaseJpaService<IotPatientDeviceDO,I
    private IotPatientDeviceDao iotPatientDeviceDao;
    @Autowired
    private ElastricSearchHelper elastricSearchHelper;
    @Autowired
    private ElasticSearchQueryGenerator elasticSearchQueryGenerator;
    /**
     * 新增
@ -157,4 +162,73 @@ public class IotPatientDeviceService extends BaseJpaService<IotPatientDeviceDO,I
        return iotPatientDeviceDao.updatePatientDevice(patient, deviceSN, newDeviceSN, userType, sim);
    }
    /**
     * 查询所有设备地址
     * @return
     */
    public List<LocationDataVO> findAllDeviceLocations(){
        SearchSourceBuilder queryStr = elasticSearchQueryGenerator.getQueryAllBuilder();
        JestResult esResult = elastricSearchHelper.search(ConstantUtils.deviceLocationIndex,ConstantUtils.deviceLocationType,queryStr.toString());
        return getESResultBeanList(esResult);
    }
    /**
     * 根据居民绑定的idCard查询设备地址
     * @return
     */
    public List<LocationDataVO> findDeviceLocationsByIdCard(String jsonData){
        SearchSourceBuilder queryStr = elasticSearchQueryGenerator.getQueryBuilder("",jsonData);
        JestResult esResult = elastricSearchHelper.search(ConstantUtils.deviceLocationIndex,ConstantUtils.deviceLocationType,queryStr.toString());
        return getESResultBeanList(esResult);
    }
    /**
     * 根据设备SN码查询设备地址
     * @return
     */
    public List<LocationDataVO> findDeviceLocationsBySn(String jsonData){
        SearchSourceBuilder queryStr = elasticSearchQueryGenerator.getQueryBuilder("",jsonData);
        JestResult esResult = elastricSearchHelper.search(ConstantUtils.deviceLocationIndex,ConstantUtils.deviceLocationType,queryStr.toString());
        return getESResultBeanList(esResult);
    }
    /**
     * 返回对象集合
     * @param esResult
     * @return
     */
    private List<LocationDataVO> getESResultBeanList(JestResult esResult){
        List<LocationDataVO> resultList = new ArrayList<>();
        if(!esResult.isSucceeded()){
            return resultList;
        }
        return esResult.getSourceAsObjectList(LocationDataVO.class);
    }
    /**
     * 设备解绑,根据Sn或idCard删除地址
     * @return
     */
    public boolean deleteLocationsByIdcardOrSn(String jsonData){
        List<SaveModel> saveModelList = new ArrayList<>();
        SearchSourceBuilder queryStr = elasticSearchQueryGenerator.getQueryBuilder("",jsonData);
        JestResult esResult = elastricSearchHelper.search(ConstantUtils.deviceLocationIndex,ConstantUtils.deviceLocationType,queryStr.toString());
        List<LocationDataVO> resultList = getESResultBeanList(esResult);
        for(LocationDataVO locationDataVO : resultList){
            SaveModel saveModel = new SaveModel();
            saveModel.setId(locationDataVO.getId());
            saveModelList.add(saveModel);
        }
        boolean bool = true;
        try {
            elastricSearchHelper.deleteData(ConstantUtils.deviceLocationIndex,ConstantUtils.deviceLocationType,saveModelList);
        }catch (Exception e){
            bool = false;
        }
//        JestResult deleteResult = elastricSearchHelper.deleteData(ConstantUtils.deviceLocationIndex,ConstantUtils.deviceLocationType,saveModelList);
//        return deleteResult.isSucceeded();
        return bool;
    }
}