本文基于2019.10.25的solr最新版本solr-8.2.0
实现对mysql数据库中的资源数据的圆选、框选。圆选及在地图上画圆,将圆心坐标以及半径作为参数传给后端,后端返回坐标处于圆内的资源数据,用于前端将资源标绘。框选即在地图上选择多个点组成多边形,将每个角的坐标传给后端,后端返回坐标在多边形(框)内的资源数据,用于前端将资源进行标绘。
上一篇已经讲过了,这里不再重复,不清楚的见solr8学习进阶(一)MySql整合。
data-config.xml文件配置:
<?xml version="1.0" encoding="UTF-8" ?>
<dataConfig>
<!-- 数据库信息 -->
<dataSource type="JdbcDataSource"
driver="com.mysql.jdbc.Driver"
url="jdbc:mysql://xxx.xxx.xxx.xxx:3306/test"
user="user" password="user"/>
<document>
<!-- document实体 name为数据库表;pk为managed-schema文件中定义的<uniqueKey>id</uniqueKey> -->
<entity name="app_db_disaster_shelter" pk="id"
<!-- 这里只查询数据库中我所需要的字段 -->
query="SELECT `i_id` as id,
`vc_name` as vcName,
`d_longitude` as x,
`d_latitude` as y,
`vc_address` as vcAddress,
`vc_remark` as vcRemark,
concat( d_longitude,' ',d_latitude) as GEO
FROM app_db_disaster_shelter where sys_i_status=0"
<!-- deltaQuery、deletedPkQuery、deltaImportQuery三个方法是用于定时增量同步数据库,这里暂时不讲解,留到后面 -->
deltaQuery="SELECT `i_id` AS `id` FROM `app_db_disaster_shelter` where sys_i_status=0 and
sys_dt_last_update>'${dataimporter.last_index_time}'"
deletedPkQuery="SELECT `i_id` AS `id` FROM `app_db_disaster_shelter` where sys_i_status!='0'"
deltaImportQuery="SELECT `i_id` as id,
`vc_name` as vcName,
`d_longitude` as x,
`d_latitude` as y,
`vc_address` as vcAddress,
`vc_remark` as vcRemark,
concat( d_longitude,' ',d_latitude) as GEO
from app_db_disaster_shelter where sys_i_status=0 and i_id='${dataimporter.delta.id}'">
<!-- 数据库字段映射solr字段 也可以不写,写出来是为了结构清晰,数据库字段和core的属性一一对应 -->
<field column="i_id" name="id"/>
<field column="vc_name" name="vcName"/>
<!-- <field column="i_area_id" name="iAreaId"/> -->
<!-- <field column="vc_dept" name="vcDept"/> -->
<field column="d_longitude" name="x"/>
<field column="d_latitude" name="y"/>
<field column="vc_address" name="vcAddress"/>
<!-- <field column="vc_traffic" name="vcTraffic"/> -->
<!-- <field column="vc_duty_tel" name="vcDutyTel"/> -->
<!-- <field column="vc_fax" name="vcFax"/> -->
<!-- <field column="vc_dept_address" name="vcDeptAddress"/> -->
<!-- <field column="vc_group" name="vcGroup"/> -->
<!-- <field column="dt_update_time" name="dtUpdateTime"/> -->
<field column="vc_remark" name="vcRemark"/>
<!-- <field column="dt_use_time" name="dtUseTime"/> -->
<!-- <field column="vc_basic_situation" name="vcBasicSituation"/> -->
<!-- <field column="d_area" name="dArea"/> -->
<!-- <field column="i_dept_id" name="iDeptId"/> -->
<!-- <field column="i_operate_id" name="iOperateId"/> -->
<!-- <field column="i_status" name="iStatus"/> -->
<!-- <field column="i_extend1" name="iExtend1"/> -->
<!-- <field column="i_extend2" name="iExtend2"/> -->
<!-- <field column="vc_extend1" name="vcExtend1"/> -->
<!-- <field column="vc_extend2" name="vcExtend2"/> -->
<!-- <field column="vc_extend3" name="vcExtend3"/> -->
<!-- <field column="sys_i_status" name="sysIStatus"/> -->
<!-- <field column="sys_dt_create" name="sysDtCreate"/> -->
<!-- <field column="sys_i_create_user" name="sysICreateUser"/> -->
<!-- <field column="sys_dt_last_update" name="sysDtLastUpdate"/> -->
<!-- <field column="sys_i_last_update_user" name="sysILastUpdateUser"/> -->
<!-- <field column="sys_vc_remark" name="sysVcRemark"/> -->
<!-- <field column="i_datasync_unit_id" name="iDatasyncUnitId"/> -->
<!-- <field column="dt_datasync_time" name="dtDatasyncTime"/> -->
<!-- <field column="i_datasync_id" name="iDatasyncId"/> -->
<!-- <field column="origin" name="origin"/> -->
</entity>
</document>
</dataConfig>
managed-schema文件配置如下:
<!-- name为属性,要和data-config.xml文件中定义的field的name属性一致;type从fieldType的name属性中选择,stored-是否存储;required-是否必须;multiValued-是否多值 -->
<field name="id" type="string" indexed="true" stored="true" required="true" multiValued="false" />
<field name="vcName" type="text_cn" indexed="true" stored="true" required="false" multiValued="false"/>
<field name="x" type="string" indexed="true" stored="true" required="false" multiValued="false"/>
<field name="y" type="string" indexed="true" stored="true" required="false" multiValued="false"/>
<field name="vcAddress" type="string" indexed="true" stored="true" required="false" multiValued="false"/>
<field name="vcRemark" type="string" indexed="true" stored="true" required="false" multiValued="false"/>
<field name="GEO" type="location_rpt" indexed="true" stored="true" required="false" multiValued="false"/>
注意:
然后就是启动solr了,导入数据了,前面都说过了
话不多说,直接上代码
/**
* Project Name: solr
* Package Name:com.solr.demo.contraller
* File Name:AppDbResourseController.java
* Data:2019年11月1日
*/
package com.solr.demo.contraller;
import com.solr.demo.DO.AppDbResourse;
import com.solr.demo.base.AppError;
import com.solr.demo.base.ResponseJSON;
import com.solr.demo.enums.CoreName;
import com.solr.demo.model.SearchParam;
import com.solr.demo.service.SearchService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author xrw
* @create 2019/11/01
* @description 提供solr的appDbMaterialAddress这个core的读写操作API
*/
@RestController
@RequestMapping("/solr/EmplusResources")
public class AppDbResourseController {
Logger logger = LoggerFactory.getLogger(AppDbResourseController.class);
@Autowired
SearchService searchService;
/**
* 应急资源圆选:根据圆心处经纬度、半径查找圈内所有应急资源
* @param x 经度
* @param y 纬度
* @param radius 半径,单位公里
* @param b_appDbDisasterShelter 是否查找庇护场所
* @param b_appDbMaterialAddress 是否查找物资库
* @param b_appDbProtectionobject 是否查找防护目标
* @param b_appDbRisk 是否查找风险隐患
* @param b_appDbTeam 是否查找救援队伍
* @return
*/
@RequestMapping("/searchAppDbResourseByPoint")
public ResponseJSON searchAppDbResourseByPoint(@RequestParam("x") Double x,
@RequestParam("y") Double y,
@RequestParam("radius") Double radius,
@RequestParam("appDbDisasterShelter") Boolean b_appDbDisasterShelter,
@RequestParam("appDbMaterialAddress") Boolean b_appDbMaterialAddress,
@RequestParam("appDbProtectionobject") Boolean b_appDbProtectionobject,
@RequestParam("appDbRisk") Boolean b_appDbRisk,
@RequestParam("appDbTeam") Boolean b_appDbTeam) {
SearchParam searchParam;
//参数不为空时,构建查询对象
if (x != null && y != null && radius != null) {
searchParam = new SearchParam(x, y, radius);
} else {
//为空时返回错误码
return new ResponseJSON(AppError.PARAM_NULL_ERROR);
}
Map<String, Object> reSoureseMap = new HashMap<>();
//是否查找庇护场所
if (b_appDbDisasterShelter) {
List<AppDbResourse> appDbDisasterShelter = searchService.searchAppDbResourseByPoint(searchParam, CoreName.appDbDisasterShelter.getCoreName());
reSoureseMap.put("appDbDisasterShelter", appDbDisasterShelter);
}
//是否查找物资库
if (b_appDbMaterialAddress) {
List<AppDbResourse> appDbMaterialAddress = searchService.searchAppDbResourseByPoint(searchParam, CoreName.appDbMaterialAddress.getCoreName());
reSoureseMap.put("appDbMaterialAddress", appDbMaterialAddress);
}
//是否查找防护目标
if (b_appDbProtectionobject) {
List<AppDbResourse> appDbProtectionobject = searchService.searchAppDbResourseByPoint(searchParam, CoreName.appDbProtectionobject.getCoreName());
reSoureseMap.put("appDbProtectionobject", appDbProtectionobject);
}
//是否查找风险隐患
if (b_appDbRisk) {
List<AppDbResourse> appDbRisk = searchService.searchAppDbResourseByPoint(searchParam, CoreName.appDbRisk.getCoreName());
reSoureseMap.put("appDbRisk", appDbRisk);
}
//是否查找救援队伍
if (b_appDbTeam) {
List<AppDbResourse> appDbTeam = searchService.searchAppDbResourseByPoint(searchParam, CoreName.appDbTeam.getCoreName());
reSoureseMap.put("appDbTeam", appDbTeam);
}
ResponseJSON responseJSON = new ResponseJSON();
responseJSON.put("data", reSoureseMap);
logger.info("searchAppDbResourseByPoint success!");
return responseJSON;
}
/**
* 应急资源框选:用一组闭环的坐标画一个多边形,将处于多边形内的应急资源返回给前端
* @param points 多边形坐标参数;参数示例:POLYGON((经度 纬度,经度 纬度,......));备注:(第一组经纬度和最后一组相同)
* @param b_appDbDisasterShelter 是否查询庇护场所
* @param b_appDbMaterialAddress 是否查询救援物资库
* @param b_appDbProtectionobject 是否查询防护目标
* @param b_appDbRisk 是否查询救援队伍
* @param b_appDbTeam 是否查询风险隐患
* @return
*/
@RequestMapping("/searchAppDbResourseByPolygon")
public ResponseJSON searchAppDbResourseByPolygon(@RequestParam("points") String points,
@RequestParam("appDbDisasterShelter") Boolean b_appDbDisasterShelter,
@RequestParam("appDbMaterialAddress") Boolean b_appDbMaterialAddress,
@RequestParam("appDbProtectionobject") Boolean b_appDbProtectionobject,
@RequestParam("appDbRisk") Boolean b_appDbRisk,
@RequestParam("appDbTeam") Boolean b_appDbTeam) {
SearchParam searchParam;
//参数不为空时,构建查询对象
if (points != null) {
searchParam = new SearchParam(points);
} else {
//为空时返回错误码
return new ResponseJSON(AppError.PARAM_NULL_ERROR);
}
Map<String, Object> reSoureseMap = new HashMap<>();
//是否查找庇护场所
if (b_appDbDisasterShelter) {
List<AppDbResourse> appDbDisasterShelter = searchService.searchAppDbResourseByPolygon(searchParam, CoreName.appDbDisasterShelter.getCoreName());
reSoureseMap.put("appDbDisasterShelter", appDbDisasterShelter);
}
//是否查找物资库
if (b_appDbMaterialAddress) {
List<AppDbResourse> appDbMaterialAddress = searchService.searchAppDbResourseByPolygon(searchParam, CoreName.appDbMaterialAddress.getCoreName());
reSoureseMap.put("appDbMaterialAddress", appDbMaterialAddress);
}
//是否查找防护目标
if (b_appDbProtectionobject) {
List<AppDbResourse> appDbProtectionobject = searchService.searchAppDbResourseByPolygon(searchParam, CoreName.appDbProtectionobject.getCoreName());
reSoureseMap.put("appDbProtectionobject", appDbProtectionobject);
}
//是否查找风险隐患
if (b_appDbRisk) {
List<AppDbResourse> appDbRisk = searchService.searchAppDbResourseByPolygon(searchParam, CoreName.appDbRisk.getCoreName());
reSoureseMap.put("appDbRisk", appDbRisk);
}
//是否查找救援队伍
if (b_appDbTeam) {
List<AppDbResourse> appDbTeam = searchService.searchAppDbResourseByPolygon(searchParam, CoreName.appDbTeam.getCoreName());
reSoureseMap.put("appDbTeam", appDbTeam);
}
ResponseJSON responseJSON = new ResponseJSON();
responseJSON.put("data", reSoureseMap);
logger.info("searchAppDbResourseByPolygon success!");
return responseJSON;
}
}
Service:
import com.solr.demo.DO.AppDbResourse;
import com.solr.demo.model.SearchParam;
import java.util.List;
public interface SearchService {
List<AppDbResourse> searchAppDbResourseByPoint(SearchParam searchParam,String m_coreName);
List<AppDbResourse> searchAppDbResourseByPolygon(SearchParam searchParam,String m_coreName);
}
ServiceImp:
package com.solr.demo.service.serviceImp;
import com.solr.demo.DO.AppDbResourse;
import com.solr.demo.model.SearchParam;
import com.solr.demo.service.SearchService;
import com.solr.demo.SolrClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* ClassName: SearchSerivceImpl
* Description: 空间搜索实现类
* Date: 2019年11月01日
*
*
* @author xrw
*
*/
@Service(value = "searchSerivceImpl")
public class SearchSerivceImpl implements SearchService {
Logger logger = LoggerFactory.getLogger(SearchService.class);
String coreName; // core名称
@Override
public List<AppDbResourse> searchAppDbResourseByPoint(SearchParam searchParam, String m_coreName) {
this.coreName = m_coreName;
SolrClient solrClient = SolrClient.getInstance(); // 获取solr实例
// 圆选条件,如有其筛选条件,必须放在此条件前面,否则其它条件不起作用
String criteria = "{!geofilt sfield=GEO pt=" + searchParam.getY() + "," + searchParam.getX() + " d="
+ searchParam.getRadius() + "}";
String[] solrAttribute = new String[]{
"id", "vcName", "x", "y", "vcAddress", "vcRemark", "GEO"}; // solr中的数据属性名
String[] beanAttribute = new String[]{
"id", "vcName", "x", "y", "vcAddress", "vcRemark", "GEO"}; // dto中的属性名
List<AppDbResourse> list = solrClient.getBeans(criteria, coreName, Integer.MAX_VALUE, 0, null, AppDbResourse.class,
solrAttribute, beanAttribute, null);
return list;
}
@Override
public List<AppDbResourse> searchAppDbResourseByPolygon(SearchParam searchParam, String m_coreName) {
this.coreName = m_coreName;
SolrClient solrClient = SolrClient.getInstance(); // 获取solr实例
//searchParam.getPolygon() 的示例
// String test = "POLYGON((0 0,0 90,112 90,112 0,0 0))";
String criteria = " GEO:\"IsWithin(" + searchParam.getPolygon() + ")\" "; // 查询条件
// logger.info(criteria);
String[] solrAttribute = new String[]{
"id", "vcName", "x", "y", "vcAddress", "vcRemark", "GEO"}; // solr中的数据属性名
String[] beanAttribute = new String[]{
"id", "vcName", "x", "y", "vcAddress", "vcRemark", "GEO"}; // dto中的属性名
List<AppDbResourse> list = solrClient.getBeans(criteria, coreName, Integer.MAX_VALUE, 0, null, AppDbResourse.class,
solrAttribute, beanAttribute, null);
return list;
}
}
import org.apache.commons.lang3.StringUtils;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrRequest;
import org.apache.solr.client.solrj.SolrServer;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.HttpSolrServer;
import org.apache.solr.client.solrj.request.QueryRequest;
import org.apache.solr.client.solrj.response.FacetField;
import org.apache.solr.client.solrj.response.FacetField.Count;
import org.apache.solr.client.solrj.response.Group;
import org.apache.solr.client.solrj.response.GroupCommand;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.client.solrj.response.TermsResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.common.util.NamedList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
/**
* ClassName: SolrClient
* Description: solr查询方法封装类
* Date: 2019年11月1日
*
*/
public class SolrClient {
private Logger log = LoggerFactory.getLogger(SolrClient.class);
/**
* SolrClient实例对象
*/
private static SolrClient mInstance;
/**
* ID唯一标识
*/
public static final String ID = "id";
/**
* solr服务哈希表,key为core名称,value为HttpSolrServer对象
*/
private HashMap<String, SolrServer> solrServers = new HashMap<String, SolrServer>();
/**
* UTF-8编码
*/
public static final String UTF8_CHARSET_NAME = "UTF-8";
/**
* solr的url key值
*/
private static String SOLR_URL_KEY = "sajRisk.solr_url";
/**
* 拆分词组URL,用于拆分词组
*/
public static final String URL_SPLIT_WORDS = "splitwords";
/**
* 代码词组的URL,用于根据代码得到标准词组
*/
public static final String URL_CODE_WORDS = "codewords";
/**
* 日期格式
*/
private static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
/** 字段业务名称--标准地址名称 */
public static final String FIELD_AC_STANDARD_ADDR_NAME = "AC_STANDARD_ADDR_NAME";
/** 字段业务名称--标准地址名称(字符串类型),冗余字段类型,用于ALL查询 */
public static final String FIELD_AC_STANDARD_ADDR_NAME_S = "AC_STANDARD_ADDR_NAME_S";
/** 注解字段常量--otherFields */
public static final String ANNOTATION_OTHERFIELDS = "otherFields";
/**
* 获取solrClient单一实例
*
* @return
*/
public static SolrClient getInstance() {
if (mInstance == null) {
synchronized (SolrClient.class) {
if (mInstance == null) {
mInstance = new SolrClient();
}
}
}
return mInstance;
}
/**
* 根据core名称得到SolrServer对象,如果不存在,就创建
*
* @param core
* solr的core名称
* @return
*/
public SolrServer getSolrServer(String core) {
if (solrServers.containsKey(core)) {
return solrServers.get(core);
}
Properties props = new Properties();
InputStream resourceStream = SolrClient.class.getClassLoader().getResourceAsStream("application.properties");
try {
props.load(resourceStream);
} catch (IOException e1) {
getLogger().error("SolrClient.getProperties() - Failed to load properties file", e1);
}
String solrCoreUrl = props.getProperty(SOLR_URL_KEY) + "/" + core;
SolrServer solrServer;
try {
solrServer = new HttpSolrServer(solrCoreUrl);
solrServer.ping();
solrServers.put(core, solrServer);
return solrServer;
} catch (Throwable e) {
log.error("SolrClient.getSolrServer() - Failed to connect:" + solrCoreUrl, e);
}
return null;
}
/**
* 获取得到对象化的数据列表
* 使用场景:
* 1.当没有过滤显示字段数组,转换对象的Class注解有@Field关联字段值进行映射,返回对象数据列表。
* 2.当有过滤显示字段数组并且没有过滤显示字段别名数组,过滤字段后,转换对象的Class注解有@Field关联字段值进行映射,返回对象数据列表。
*
* 3.当有过滤显示字段数组并且有过滤显示字段别名数组,不需要转换对象的Class注解有@Field字段:
* 1)长度顺序一致,即都设置有别名情况下,设置对应的别名,并且能找到与别名名称相同的转换对象Class的属性名,通过反射直接赋值。
* 2)顺序一致,但长度不一致,即有部分设置别名,有部分没有设置别名,设置对应的别名,并且能找到与别名名称相同的转换对象Class的属性名,
* 通过反射直接赋值,找不到相同的属性名则不做赋值处理。
*
* @param criteria
* 查询条件
* @param coreName
* core的名称
* @param rows
* 查询条数
* @param start
* 开始查询的位置
* @param sortParams
* 排序参数,以逗号隔开。如id desc,name desc
* @param clazz
* 要转换对象的Class
* @param fields
* 过滤显示字段数组,如果设置,只显示数组内的字段,数组为空,显示全部
* @param aliasFields
* 过滤显示字段别名数组,数组的顺序与fields字段数组的顺序一一对应,长度可不相同,当不相同时,
* 取回fields对应的字段名为别名,并且返回对象的属性名与别名一致。
* @param filterQueryParams
* 过滤查询条件,例如权重条件设置:a^2 b^0.3 c^1
* @return
*/
public <T extends Object> List<T> getBeans(String criteria, String coreName, int rows, int start, String sortParams,
Class<T> clazz, String[] fields, String[] aliasFields, String filterQueryParams) {
if (StringUtils.isNotEmpty(criteria) && StringUtils.isNotEmpty(coreName)) {
SolrServer solrServer = getSolrServer(coreName);
SolrQuery solrQuery = new SolrQuery().setQuery(criteria).setRows(rows).setStart(start);
this.setSortParams(sortParams, solrQuery);
this.setFieldListParams(fields, aliasFields, solrQuery);
this.setFilterQueryParams(filterQueryParams, solrQuery);
QueryRequest queryRequest = new QueryRequest(solrQuery);
queryRequest.setMethod(SolrRequest.METHOD.POST);
try {
QueryResponse response = queryRequest.process(solrServer);
if (response.getResults() != null) {
// 如果设置有别名,根据转换对象的Class,通过反射设置得到对应的转换对象列表,并返回
// 如果没有设置别名,返回solr原始getBeans方法得到的对象列表值。该getBeans方法是通过注解的方'式设置映射关系
if (fields != null && fields.length > 0 && aliasFields != null && aliasFields.length > 0) {
return this.getBeansByDocsAndClazz(response.getResults(), clazz);
} else {
return response.getBeans(clazz);
}
}
} catch (SolrServerException e) {
e.printStackTrace();
}
}
return Collections.emptyList();
}
/**
* 设置过滤查询参数
* 例如权重条件设置:a^2 b^0.3 c^1
*
* @param params
* 参数
* @param solrQuery
* solr查询类
*/
private void setFilterQueryParams(String params, SolrQuery solrQuery) {
if (StringUtils.isNotEmpty(params)) {
String[] paramPairs = params.trim().split(" * *");
for (String paramPair : paramPairs) {
solrQuery.addFilterQuery(paramPair);
}
}
}
/**
* 设置过虑字段参数,如果有别名,则设置别名
*
* @param fields
* 过滤显示字段数组,如果设置,只显示数组内的字段,数组为空,显示全部
* @param aliasFields
* 过滤显示字段别名数组,数组的顺序与fields字段数组的顺序一一对应,长度可不相同,当不相同时,
* 取回fields对应的字段名为别名
* @param solrQuery
* solr查询类
*/
private void setFieldListParams(String[] fields, String[] aliasFields, SolrQuery solrQuery) {
if (fields == null || fields.length <= 0) {
return;
}
// 判断字段别名数组不为空且长度与字段数组相等
if (aliasFields != null && aliasFields.length > 0) {
StringBuilder fieldSb = new StringBuilder();
// 别名的格式是: 别名:真实名
for (int i = 0; i < fields.length; i++) {
fieldSb.delete(0, fieldSb.length());
if (aliasFields.length - 1 >= i) {
if (StringUtils.isEmpty(aliasFields[i])) {
aliasFields[i] = fields[i];
}
fieldSb.append(aliasFields[i]).append(":").append(fields[i]);
} else {
fieldSb.append(fields[i]).append(":").append(fields[i]);
}
fields[i] = fieldSb.toString();
}
}
solrQuery.setFields(fields);
}
/**
* 根据solr文档列表和转换对象的Class,通过反射设置得到对应的转换对象列表
* 1.主要用于当已经设置过滤返回对象和别名后得到的docs文档列表,根据转换对象的Class,设置与文档key一致的属性值
* 2.当转换对象的Class注解有@Field("otherFields"),把那些没有设置到属性里的值,全部加入到注解有@Field(
* "otherFields")的Map对象中
* 3.如果没有找到注解有@Field("otherFields")的Map,那些没有设置到属性里的值全部丢弃掉
*
* @param docs
* solr文档对象列表
* @param clazz
* 要转换对象的Class
* @return
*/
private <T extends Object> List<T> getBeansByDocsAndClazz(List<SolrDocument> docs, Class<T> clazz) {
// solr文档对象列表为空,直接返回空列表
if (docs == null || docs.size() <= 0) {
return Collections.emptyList();
}
// 得到所有属性列表
Field[] declaredFields = clazz.getDeclaredFields();
// 对象实例
T obj = null;
// 其他字段值map
Map<String, String> otherFieldValueMap = null;
// solr字段Object对象变量
Object fieldValueObj = null;
// solr字段字符串变量
String fieldValueStr = null;
// 返回列表
List<T> rtnList = new ArrayList<T>();
// 是否有相同的字段名称
boolean hasSameFieldName = false;
for (SolrDocument doc : docs) {
// fieldValueMap = doc.getFieldValueMap();
try {
hasSameFieldName = false;
otherFieldValueMap = new HashMap<String, String>();
// 创建实例
obj = clazz.newInstance();
// 循环反射得到的字段列表,比较字段名是否一致,一致的话则赋值给对象。
for (Entry<String, Object> entry : doc.entrySet()) {
fieldValueObj = entry.getValue();
for (Field field : declaredFields) {
// 字段名一致
if (field.getName().equals(entry.getKey())) {
field.setAccessible(true);
// 类型转换,如果是solr文档对象是日期类型,并且与clazz属性类型不一致,则做日期格式转换
if (fieldValueObj instanceof Date) {
if (field.getType() == Date.class) {
field.set(obj, fieldValueObj);
} else {
field.set(obj, dateFormat.format(fieldValueObj));
}
} else {
// 除了日期类型之外,其他类型solr对象与bean对象属性类型一致,按原类型设置值
if (fieldValueObj.getClass() == field.getType()) {
field.set(obj, fieldValueObj);
} else {
field.set(obj, fieldValueObj.toString());
}
}
hasSameFieldName = true;
break;
}
}
if (!hasSameFieldName) {
// 那些没有找到相同属性名的值,全部加入Map对象中
if (fieldValueObj instanceof Date) {
fieldValueStr = dateFormat.format(fieldValueObj);
} else {
// 除了日期类型之外,其他类型按字符串类型设置值
fieldValueStr = fieldValueObj.toString();
}
otherFieldValueMap.put(entry.getKey(), fieldValueStr);
}
} // end-for (Entry entry : doc.entrySet())
// 通过反射,设置其他字段值map到对象实例
setOtherFieldValueMap(declaredFields, obj, otherFieldValueMap);
rtnList.add(obj);
} catch (InstantiationException e) {
// 出现异常,记录日志,不直接抛出中断流程
String error = "通过转换得到对应的转换对象列表方法时,出现InstantiationException异常!";
log.error(error, e);
} catch (IllegalAccessException e) {
// 出现异常,记录日志,不直接抛出中断流程
String error = "通过转换得到对应的转换对象列表方法时,出现IllegalAccessException异常!";
log.error(error, e);
}
}
return rtnList;
}
/**
* 通过反射,设置其他字段值map到对象实例
*
* @param declaredFields
* 所有属性字段的列表
* @param obj
* 要转换对象Class的对象实例
* @param otherFieldValueMap
* 其他字段值map
* @return
*/
private <T extends Object> T setOtherFieldValueMap(Field[] declaredFields, T obj,
Map<String, String> otherFieldValueMap) {
for (Field field : declaredFields) {
if (field.isAnnotationPresent(org.apache.solr.client.solrj.beans.Field.class)
&& field.getType() == Map.class) {
org.apache.solr.client.solrj.beans.Field annotationField = field
.getAnnotation(org.apache.solr.client.solrj.beans.Field.class);
// 注解的字段名是否为otherFields,则把除了有设置别名之外的需要返回的字段值,赋值给该字段值上
if (ANNOTATION_OTHERFIELDS.equals(annotationField.value())) {
try {
field.setAccessible(true);
field.set(obj, otherFieldValueMap);
} catch (IllegalArgumentException e) {
// 出现异常,记录日志,不直接抛出中断流程
String error = "通过反射设置其他字段值map到对象实例方法时,出现InstantiationException异常!";
log.error(error, e);
} catch (IllegalAccessException e) {
// 出现异常,记录日志,不直接抛出中断流程
String error = "通过反射设置其他字段值map到对象实例方法时,出现IllegalAccessException异常!";
log.error(error, e);
}
break;
}
}
}
return obj;
}
}
package com.solr.demo.model;
public class SearchParam {
//经度
private double x;
//纬度
private double y;
//半径
private double radius;
private String Polygon;
public SearchParam(double x, double y, double radius) {
this.x = x;
this.y = y;
this.radius = radius;
}
public SearchParam(String polygon) {
this.Polygon = polygon;
}
public double getX() {
return x;
}
public void setX(double x) {
this.x = x;
}
public double getY() {
return y;
}
public void setY(double y) {
this.y = y;
}
public double getRadius() {
return radius;
}
public void setRadius(double radius) {
this.radius = radius;
}
public String getPolygon() {
return Polygon;
}
public void setPolygon(String polygon) {
Polygon = polygon;
}
}
package com.solr.demo.enums;
public enum CoreName {
//庇护场所
appDbDisasterShelter("appDbDisasterShelter"),
//物资库
appDbMaterialAddress("appDbMaterialAddress"),
//防护目标
appDbProtectionobject("appDbProtectionobject"),
//救援队伍
appDbTeam("appDbTeam"),
//风险隐患
appDbRisk("appDbRisk");
private String coreName;
CoreName(String coreName) {
this.coreName = coreName;
}
public String getCoreName() {
return coreName;
}
}
这里提供一个抽象的资源实体类,具体的core的实体自己建
package com.solr.demo.DO;
/**
* @author xrw
* @create 2019/11/01
* 资源抽象实体实体
*/
public class AppDbResourse {
private String id;
private String vcName;
private String x;
private String y;
private String vcAddress;
private String vcRemark;
private String GEO;
public String getid() {
return id; }
public void setid(String id) {
this.id = id; }
public String getVcName() {
return vcName; }
public void setVcName(String vcName) {
this.vcName = vcName; }
public String getX() {
return x; }
public void setX(String x) {
this.x = x; }
public String getY() {
return y; }
public void setY(String y) {
this.y = y; }
public String getVcAddress() {
return vcAddress; }
public void setVcAddress(String vcAddress) {
this.vcAddress = vcAddress; }
public String getVcRemark() {
return vcRemark; }
public void setVcRemark(String vcRemark) {
this.vcRemark = vcRemark; }
public String getGEO() {
return GEO; }
public void setGEO(String GEO) {
this.GEO = GEO; }
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
AppDbResourse that = (AppDbResourse) o;
if (id != null ? !id.equals(that.id) : that.id != null) return false;
if (vcName != null ? !vcName.equals(that.vcName) : that.vcName != null) return false;
if (x != null ? !x.equals(that.x) : that.x != null) return false;
if (y != null ? !y.equals(that.y) : that.y != null) return false;
if (vcAddress != null ? !vcAddress.equals(that.vcAddress) : that.vcAddress != null) return false;
if (vcRemark != null ? !vcRemark.equals(that.vcRemark) : that.vcRemark != null) return false;
if (GEO != null ? !GEO.equals(that.GEO) : that.GEO != null) return false;
return true;
}
@Override
public int hashCode() {
int result = id != null ? id.hashCode() : 0;
result = 31 * result + (vcName != null ? vcName.hashCode() : 0);
result = 31 * result + (x != null ? x.hashCode() : 0);
result = 31 * result + (y != null ? y.hashCode() : 0);
result = 31 * result + (vcAddress != null ? vcAddress.hashCode() : 0);
result = 31 * result + (vcRemark != null ? vcRemark.hashCode() : 0);
result = 31 * result + (GEO != null ? GEO.hashCode() : 0);
return result;
}
}
package com.solr.demo.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
// @Value("${wedOrigin.name}")
// private String wn;
// @Autowired
// SysConfigService sysConfigService;
//允许跨域
@Bean
public CorsFilter corsFilter() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
// String [] result = wn.split(",");
// for (int i=0;i
// corsConfiguration.addAllowedOrigin(result[i]);
// }
corsConfiguration.addAllowedOrigin("*");
corsConfiguration.addAllowedHeader("*");
corsConfiguration.addAllowedMethod("*");
corsConfiguration.setAllowCredentials(true);
UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
return new CorsFilter(urlBasedCorsConfigurationSource);
}
}
package com.solr.demo.base;
import com.alibaba.fastjson.JSONObject;
import com.solr.demo.utils.PageWrapper;
import org.springframework.data.domain.Page;
/**
* @author xrw
* @create 2019/11/01
* @description 定义返回数据的标准格式
*/
public class ResponseJSON extends JSONObject {
private static final long serialVersionUID = -4919743721058849685L;
public ResponseJSON(){
super.put("errorCode", 0);
super.put("msg","success");
}
public ResponseJSON(String errorCode, String msg) {
super.put("errorCode", errorCode);
super.put("msg", msg);
}
public ResponseJSON(AppError appError){
super.put("errorCode",appError.errorCode);
super.put("msg",appError.msg);
}
public ResponseJSON(AppError appError, Object data) {
super.put("errorCode", appError.errorCode);
super.put("msg", appError.msg);
super.put("data", data);
}
public ResponseJSON(Object data) {
super.put("errorCode", 0);
super.put("msg", "SUCCESS");
if (data == null) {
super.put("data", "");
return;
}
super.put("data", data);
}
private Object preHandleData(Object data) {
if (data instanceof Page) {
return new PageWrapper<>((Page) data);
} else {
return data;
}
}
}
package com.solr.demo.base;
/**
* @author xrw
* @create 2019/11/01
* @description 请求异常返回错误数据
*/
public enum AppError {
//============错误返回数据=============
/**
* 接口异常
*/
PARAM_NULL_ERROR("20001","参数为空");
public String errorCode;
public String msg;
AppError(String errorCode, String msg) {
this.errorCode = errorCode;
this.msg = msg;
}
}
application.properties:
sajRisk.solr_url = http://xxx.xxx.xxx.xxx:8983/solr
server.port=8023
wedOrigin.name=*
上一篇:solr8学习进阶(一)MySql整合
下一篇:solr8学习进阶(三)定时增量导入MySql数据