工程搭建
1. 创建SpringBoot工程
以IntelliJ IDEA为例,创建“Spring Initializr”或“Maven”工程。
组件选择如下:
- Developer Tools
- Spring Boot DevTools
- Lombok
- Web
- Spring Web
- NoSQL
- Spring Data for Apache Solr
2. 添加pom.xml依赖
如果创建的Maven工程,则可手动添加Solr集成相关依赖。
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-solr</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>
Solr连接
1. 通过Solr URL连接
application.yml
spring:application:name: solr-demodata:solr:host: http://bigdata-node1:8983/solr/db_syncserver:port: 8081
application.properties
spring.application.name=solr-springboot-exampleserver.port=8081# solr Configurationspring.data.solr.host=http://bigdata-node1:8983/solr/db_sync
2. 通过ZooKeeper连接
application.yml
spring:application:name: solr-springboot-exampledata:solr:zk-host: 192.168.0.101:2181,192.168.0.102:2181,192.168.0.103:2181server:port: 8081
application.properties
spring.application.name=solr-springboot-exampleserver.port=8081# solr Configurationspring.data.solr.zk-host=192.168.0.101:2181,192.168.0.102:2181,192.168.0.103:2181
案例
01. 简单示例
1. 分页查询
```java import org.apache.solr.client.solrj.SolrClient; import org.apache.solr.client.solrj.SolrQuery; import org.apache.solr.client.solrj.SolrServerException; import org.apache.solr.client.solrj.impl.CloudSolrClient; import org.apache.solr.client.solrj.response.QueryResponse; import org.apache.solr.common.SolrDocument; import org.apache.solr.common.SolrDocumentList; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import java.io.IOException;
@SpringBootTest public class SolrSampleTests {
@Autowiredprivate SolrClient solrClient;/*** 测试:分页查找*/@Testpublic void findPage() throws IOException, SolrServerException {/*** 集群版CloudSolrClient继承自SolrClient,需要进行强转* 单机版不需要,直接可以使用solrClient*/CloudSolrClient cloudSolrClient = (CloudSolrClient) solrClient;// 设置默认的操作实例cloudSolrClient.setDefaultCollection("db_sync");// 设置查找的参数SolrQuery query = new SolrQuery();query.setQuery("title:中国");// 第?页query.setStart(0);// 每页记录数query.setRows(5);// 执行查找QueryResponse response = cloudSolrClient.query(query);SolrDocumentList documentList = response.getResults();for (SolrDocument entries : documentList) {String title = (String) entries.getFieldValue("title");String id = (String) entries.getFieldValue("id");System.out.println(id + "-->" + title);}}
}
<a name="KHlW8"></a>### 2. 高亮显示```javaimport org.apache.solr.client.solrj.SolrClient;import org.apache.solr.client.solrj.SolrQuery;import org.apache.solr.client.solrj.SolrServerException;import org.apache.solr.client.solrj.impl.CloudSolrClient;import org.apache.solr.client.solrj.response.QueryResponse;import org.apache.solr.common.SolrDocument;import org.apache.solr.common.SolrDocumentList;import org.junit.jupiter.api.Test;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.context.SpringBootTest;import java.io.IOException;@SpringBootTestpublic class SolrSampleTests {@Autowiredprivate SolrClient solrClient;/*** 设置结果高亮显示** @throws IOException* @throws SolrServerException*/@Testpublic void highlight() throws IOException, SolrServerException {/*** 集群版CloudSolrClient继承自SolrClient,需要进行强转* 单机版不需要,直接可以使用solrClient*/CloudSolrClient cloudSolrClient = (CloudSolrClient) solrClient;// 设置默认的操作实例cloudSolrClient.setDefaultCollection("db_sync");// 设置查找的参数SolrQuery query = new SolrQuery();query.setQuery("title:中国");// 开启高亮query.setHighlight(true);// 设置高亮字段query.addHighlightField("title");// 前缀query.setHighlightSimplePre("<font color='red'>");// 后缀query.setHighlightSimplePost("</font>");// 执行查找QueryResponse response = cloudSolrClient.query(query);// 打印高亮信息System.out.println(response.getHighlighting());}}
02. 综合示例
1. 添加pom.xml依赖
<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.3.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.lonton.bigdata</groupId><artifactId>solr-springboot-example</artifactId><version>0.0.1-SNAPSHOT</version><name>solr-springboot-example</name><description>Solr SpringBoot集成</description><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-solr</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope><!-- 这个是JUnit5中为了支持使用JUint4所做的一个过度也就是说,你只需要在你的JUnit4旧项目中添加这个依赖,就能完美过渡,而不用修改之前代码这里用不到,自然也就排除了。--><exclusions><exclusion><groupId>org.junit.vintage</groupId><artifactId>junit-vintage-engine</artifactId></exclusion></exclusions></dependency><!-- https://mvnrepository.com/artifact/commons-beanutils/commons-beanutils --><dependency><groupId>commons-beanutils</groupId><artifactId>commons-beanutils</artifactId><version>1.9.3</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.61</version></dependency><dependency><groupId>org.assertj</groupId><artifactId>assertj-core</artifactId><version>3.11.1</version><scope>compile</scope></dependency><dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>25.0-jre</version><scope>compile</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin><!-- 将生成的jar复制到指定路径 --><plugin><artifactId>maven-antrun-plugin</artifactId><executions><execution><!-- 在maven进行package的时候执行--><phase>package</phase><configuration><tasks><!-- jar包保存位置 --><copy todir="E:\vagrant\mybox\bigdata_example\share"><!-- antrun自动生成的配置文件的保存位置,这里默认是父项目的target文件夹 --><fileset dir="${project.build.directory}"><include name="*.jar"/></fileset></copy></tasks></configuration><goals><goal>run</goal></goals></execution></executions></plugin></plugins><pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) --><plugins><!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle --><plugin><artifactId>maven-clean-plugin</artifactId><version>3.1.0</version></plugin><!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging --><plugin><artifactId>maven-resources-plugin</artifactId><version>3.0.2</version></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.8.0</version><configuration><source>1.8</source><target>1.8</target><encoding>UTF-8</encoding></configuration></plugin><plugin><artifactId>maven-surefire-plugin</artifactId><version>2.22.1</version></plugin><plugin><artifactId>maven-jar-plugin</artifactId><version>3.0.2</version></plugin><plugin><artifactId>maven-install-plugin</artifactId><version>2.5.2</version></plugin><plugin><artifactId>maven-deploy-plugin</artifactId><version>2.8.2</version></plugin><!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle --><plugin><artifactId>maven-site-plugin</artifactId><version>3.7.1</version></plugin><plugin><artifactId>maven-project-info-reports-plugin</artifactId><version>3.0.0</version></plugin></plugins></pluginManagement></build></project>
2. 工程配置
■ 配置(application.properties)
spring.application.name=solr-springboot-exampleserver.port=8081# solr Configurationspring.data.solr.zk-host=192.168.0.101:2181,192.168.0.102:2181,192.168.0.103:2181
3. 编写关键类
■ SolrClient配置(以下方法二选其一)
- 启动加载类(SolrClientRunner.java) ```java import org.apache.solr.client.solrj.SolrClient; import org.apache.solr.client.solrj.impl.CloudSolrClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; import org.springframework.stereotype.Component;
/**
Description 启动加载类(配置CloudSolrClient) */ @Component public class SolrClientRunner implements ApplicationRunner {
@Autowired private SolrClient client;
@Override public void run(ApplicationArguments args) throws Exception {
/*** 集群版CloudSolrClient继承自SolrClient,需要进行强转* 单机版不需要,直接可以使用solrClient*/// SolrClient client=SpringUtil.getBean(SolrClient.class);CloudSolrClient cloudSolrClient = (CloudSolrClient) client;// 设置默认的操作实例cloudSolrClient.setDefaultCollection("db_sync");
}
}
2. **配置类(SolrClientConfig.java)**```javaimport org.apache.solr.client.solrj.SolrClient;import org.apache.solr.client.solrj.impl.CloudSolrClient;import org.apache.solr.common.StringUtils;import org.springframework.beans.factory.annotation.Value;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import java.util.Arrays;import java.util.Optional;/*** Description 自定义配置类(SolrClinet)*/@Configurationpublic class SolrClientConfig {@Value("${spring.data.solr.zk-host}")private String zk_host;/*** 集群版CloudSolrClient继承自SolrClient,需要进行强转* 单机版不需要,直接可以使用solrClient*/@Bean(name = "solrClient")public SolrClient client() {if (StringUtils.isEmpty(zk_host)) {return null;}CloudSolrClient client = new CloudSolrClient.Builder(Arrays.asList(zk_host.split(",")),Optional.empty()).build();// 设置默认的操作实例client.setDefaultCollection("db_sync");client.setZkClientTimeout(5000);client.setZkConnectTimeout(5000);return client;}}
■ 服务接口(SolrService.java)
import org.apache.solr.client.solrj.SolrServerException;import org.apache.solr.common.SolrDocument;import org.apache.solr.common.SolrDocumentList;import java.io.IOException;import java.util.List;import java.util.Map;public interface SolrService {/*** 将Map对象添加(新增或修改)到Solr中** @param map* @return*/boolean saveOrUpdate(Map map);/*** 通过文档ID删除Solr中的文档** @param id 索引ID* @return*/boolean deleteById(String id);/*** 通过查询删除Solr中对应的数据集合** @param query 查询条件*/boolean deleteByQuery(String query);/*** 更新Solr中的文档,Map对象中必须存在id用于定位doc文档** @param map Key<String>代表数据域名称,Value<Object>代表修改值* @return*/boolean update(Map<String, Object> map);/*** 批量新增或更新记录** @param entities 新增或更新对象列表* @param <T> 泛型* @return* @throws SolrServerException* @throws IOException*/<T> boolean batchSaveOrUpdate(List<T> entities) throws SolrServerException, IOException;/*** 通过泛型获取Solr中的对象集合** @param clz 泛型类对应java.lang.Class* @param query 数据域名称:数据域的值;查询全部*:*;多条件查询 name:Java AND age:20* @param filterQueries 过滤条件* @param hlFieldsList 高亮显示数据域名称,是List<String>集合* @param page 第几页* @param rows 每页显示记录数* @return*/<T> SolrResultInfo<T> query(Class<T> clz, String query,String filterQueries, List<String> hlFieldsList, Integer page, Integer rows);/*** 将SolrDocument转换成Bean** @param record 索引对象* @param clz Class对象* @return*/<T> T toBean(SolrDocument record, Class<T> clz);/*** 将SolrDocumentList转换成BeanList** @param records 索引对象列表* @param clz Class对象* @return*/<T> List<T> toBeanList(SolrDocumentList records, Class<T> clz);/*** 根据ID获取记录** @param id 索引ID* @param clz Class对象* @param <T> 泛型* @return*/<T> T getById(String id, Class<T> clz) throws IOException, SolrServerException;}
■ 服务实现类(SolrServiceImpl.java)
import com.lonton.bigdata.service.SolrResultInfo;import com.lonton.bigdata.service.SolrService;import org.apache.commons.beanutils.BeanUtils;import org.apache.solr.client.solrj.SolrClient;import org.apache.solr.client.solrj.SolrQuery;import org.apache.solr.client.solrj.SolrServerException;import org.apache.solr.client.solrj.beans.DocumentObjectBinder;import org.apache.solr.client.solrj.impl.CloudSolrClient;import org.apache.solr.client.solrj.response.QueryResponse;import org.apache.solr.client.solrj.response.UpdateResponse;import org.apache.solr.common.SolrDocument;import org.apache.solr.common.SolrDocumentList;import org.apache.solr.common.SolrInputDocument;import org.apache.solr.common.StringUtils;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import org.springframework.transaction.annotation.Transactional;import java.io.IOException;import java.lang.reflect.Field;import java.lang.reflect.InvocationTargetException;import java.sql.Time;import java.sql.Timestamp;import java.util.*;@Servicepublic class SolrServiceImpl implements SolrService {private static final Logger log = LoggerFactory.getLogger(SolrServiceImpl.class);@Autowiredprivate SolrClient client;/*** 将Map对象添加(新增或修改)到Solr中** @param map Map对象* @return*/@Override@Transactional(rollbackFor = Exception.class)public boolean saveOrUpdate(Map map) {Set kSet = map.keySet();SolrInputDocument doc = new SolrInputDocument();for (Object k : kSet) {Object val = map.get(k);if (val != null) {doc.addField(k.toString(), val);}}try {client.add(doc);UpdateResponse resp = client.commit();if (resp.getStatus() == 0) {log.debug("saveOrUpdate successfully!");return true;}} catch (Exception e) {log.error(e.getMessage());e.printStackTrace();}log.debug("saveOrUpdate failure!");return false;}/*** 通过文档ID删除Solr中的文档** @param id 索引ID* @return*/@Override@Transactional(rollbackFor = Exception.class)public boolean deleteById(String id) {try {client.deleteById(id);UpdateResponse resp = client.commit();if (resp.getStatus() == 0) {log.debug("delete successfully!");return true;}} catch (Exception e) {log.error(e.getMessage());e.printStackTrace();}log.debug("delete failure!");return false;}/*** 通过查询删除Solr中对应的数据集合** @param query 查询条件*/@Override@Transactional(rollbackFor = Exception.class)public boolean deleteByQuery(String query) {try {client.deleteByQuery(query);UpdateResponse resp = client.commit();if (resp.getStatus() == 0) {log.debug("delete successfully!");return true;}} catch (Exception e) {log.error(e.getMessage());e.printStackTrace();}log.debug("delete failure!");return false;}/*** 更新Solr中的文档,Map对象中必须存在id用于定位doc文档** @param map Key<String>代表数据域名称,Value<Object>代表修改值* @return*/@Override@Transactional(rollbackFor = Exception.class)public boolean update(Map<String, Object> map) {try {String id = (String) map.get("id");SolrInputDocument doc = new SolrInputDocument();doc.addField("id", id);for (String key : map.keySet()) {// 数据域Id忽略更新if (!"id".equals(key)) {Map fieldMap = new HashMap();fieldMap.put("set", map.get(key));doc.addField(key, fieldMap);}}client.add(doc);UpdateResponse resp = client.commit();if (resp.getStatus() == 0) {log.debug("update successfully!");return true;}} catch (Exception e) {log.error(e.getMessage());e.printStackTrace();}log.debug("update failure!");return false;}/*** 批量新增或更新记录** @param entities 新增或更新对象列表* @param <T> 泛型* @return* @throws SolrServerException* @throws IOException*/@Override@Transactional(rollbackFor = Exception.class)public <T> boolean batchSaveOrUpdate(List<T> entities) throws SolrServerException, IOException {DocumentObjectBinder binder = new DocumentObjectBinder();int total = entities.size();int count = 0;for (T t : entities) {SolrInputDocument doc = binder.toSolrInputDocument(t);client.add(doc);log.debug("添加数据到索引中,总共要添加 %d 条记录,当前添加第%d条 %n", total, ++count);}client.commit();log.debug("batch Save Or Update successfully!");return true;}/*** 通过泛型获取Solr中的对象集合** @param clz 泛型类对应java.lang.Class* @param query 数据域名称:数据域的值;查询全部*:*;多条件查询 name:Java AND age:20* @param hlFieldsList 高亮显示数据域名称,是List<String>集合* @param page 第几页* @param rows 每页显示记录数* @return*/@Overridepublic <T> SolrResultInfo<T> query(Class<T> clz, String query,String filterQueries, List<String> hlFieldsList, Integer page, Integer rows) {try {// 定义返回自定义数据结构对象SolrResultInfo<T> resultInfo = new SolrResultInfo<T>();SolrQuery q = new SolrQuery();// 查询条件q.set("q", query);// 过滤条件if(StringUtils.isEmpty(filterQueries)){q.set("fl", "*");}else{q.setFilterQueries(filterQueries);}// 高亮设置(开启)q.setHighlight(true);// 高亮显示字段String hlField = "";for (String s : hlFieldsList) {hlField = hlField + s + ",";}if (hlField.endsWith(",")) {hlField = hlField.substring(0, hlField.length() - 1);}q.set("hl.fl", hlField);// 高亮样式q.setHighlightSimplePre("<font color=\"red\">");q.setHighlightSimplePost("</font>");// 分页设置q.setStart((page - 1) * rows);q.setRows(rows);// 查询响应对象QueryResponse qr = client.query(q);Map<String, Map<String, List<String>>> hlMap = qr.getHighlighting();log.debug(hlMap.toString());// 高亮结果处理SolrDocumentList lst = qr.getResults();List<T> rtn = new ArrayList<T>();Long total = qr.getResults().getNumFound();for (SolrDocument doc : lst) {String id = (String) doc.getFieldValue("id");T t = clz.newInstance();// 获取自定义类所有属性名称Field[] fields = getField(clz);for (Field field : fields) {String fieldName = field.getName();String solrFldName = getSolrFieldName(clz, field);String fObj = getSingleValue(doc.getFieldValue(solrFldName));if (fObj == null) {continue;}if (field.getType() == java.sql.Date.class) {Date dt = new Date(fObj);fObj = new java.sql.Date(dt.getTime()).toString();}if (field.getType() == Timestamp.class) {Date dt = new Date(fObj);fObj = new Timestamp(dt.getTime()).toString();}if (field.getType() == Time.class) {Date dt = new Date(fObj);fObj = new Time(dt.getTime()).toString();}// 高亮显示数据形式:Map<ID, Map<FieldName,[MultiValue]>>if (hlFieldsList.contains(fieldName)) {//Map<FieldName,List<MultiValue>>Map<String, List<String>> fldMap = hlMap.get(id);Object hlObj = fldMap.get(fieldName);String hlVal = getSingleValue(hlObj);if (hlVal != null)fObj = hlVal;}if (fObj != null) {BeanUtils.setProperty(t, fieldName, fObj);}}rtn.add(t);}resultInfo.setList(rtn);resultInfo.setTotal(total);return resultInfo;} catch (Exception e) {log.error(e.getMessage());e.printStackTrace();}return null;}@Overridepublic <T> T toBean(SolrDocument record, Class<T> clz) {T obj = null;try {obj = clz.newInstance();} catch (InstantiationException e1) {e1.printStackTrace();} catch (IllegalAccessException e1) {e1.printStackTrace();}Field[] fields = clz.getDeclaredFields();for(Field field:fields){Object value = record.get(field.getName());try {BeanUtils.setProperty(obj, field.getName(), value);} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}}return obj;}@Overridepublic <T> List<T> toBeanList(SolrDocumentList records, Class<T> clz) {List<T> list = new ArrayList();for(SolrDocument record : records){list.add(toBean(record,clz));}return list;}@Overridepublic <T> T getById(String id, Class<T> clz) throws IOException, SolrServerException {SolrDocument record = client.getById(id);return toBean(record,clz);}/*** 根据Class对象获取此类型的定义属性数据** @param clz class对象* @return*/private static Field[] getField(Class clz) {return clz.getDeclaredFields();}/*** 通过Field对象取得其上定义的注解名称** @param clz* @param fld* @return*/private static String getSolrFieldName(Class clz, Field fld) {org.apache.solr.client.solrj.beans.Field fld2 = fld.getAnnotation(org.apache.solr.client.solrj.beans.Field.class);if (fld2 == null) {return fld.getName();}if (fld2.value().equals("#default")) {return fld.getName();} else {return fld2.value();}}/*** 转化多值域为单值** @param obj* @return*/private static String getSingleValue(Object obj) {if (obj == null) {return null;}String val = obj.toString();if (val.startsWith("[") && val.endsWith("]")) {return val.substring(1, val.length() - 1);}return val;}}
■ 返回对象封装类(SolrResultInfo.java)
import java.util.List;/*** Description 查询Solr返回的对象,对象类型为T的集合,还包含Solr中符合条件记录总数*/public class SolrResultInfo<T> {private List<T> list = null;private Long total = null;public List<T> getList() {return list;}public void setList(List<T> list) {this.list = list;}public Long getTotal() {return total;}public void setTotal(Long total) {this.total = total;}}
**■ 实体类(Article.java
import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;import org.apache.solr.client.solrj.beans.Field;import org.springframework.data.solr.core.mapping.SolrDocument;import java.io.Serializable;/*** Description VO-文章类*/@Data@AllArgsConstructor@NoArgsConstructor@SolrDocument(solrCoreName = "db_sync")public class Article implements Serializable {@Field("id")private Integer id;@Field("content_id")private Long contentId;@Field("title")private String title;@Field("content")private String content;@Field("type")private Integer type;@Field("create_at")private Long createAt;@Field("publish_at")private Long publishAt;@Overridepublic String toString() {return "Article{" +"id=" + id +", contentId=" + contentId +", title='" + title + '\'' +", content='" + content + '\'' +", type=" + type +", createAt=" + createAt +", publishAt=" + publishAt +'}';}}
■ 工具类(CommonUtils.java)
import com.google.common.collect.Lists;import com.google.common.collect.Maps;import org.apache.commons.beanutils.BeanUtils;import org.springframework.cglib.beans.BeanMap;import java.util.List;import java.util.Map;/*** Description 工具类(Map与JavaBean互转)*/public class CommonUtils {/*** 把一个Map转换成指定类型的JavaBean对象** @param map Map对象* @param clazz Class对象* @param <T> 泛型* @return*/public static <T> T mapToBean(Map<String, ?> map, Class<T> clazz) {try {T bean = clazz.newInstance();BeanUtils.populate(bean, map);return bean;} catch (Exception e) {throw new RuntimeException(e);}}/*** 将List<Map<String,Object>>转换为List<T>** @param maps Map对象列表* @param clazz Class对象* @return* @throws InstantiationException* @throws IllegalAccessException*/public static <T> List<T> mapsToBeans(List<Map<String, Object>> maps, Class<T> clazz)throws InstantiationException, IllegalAccessException {List<T> list = Lists.newArrayList();if (maps != null && maps.size() > 0) {Map<String, Object> map;T bean;for (int i = 0, size = maps.size(); i < size; i++) {map = maps.get(i);bean = clazz.newInstance();list.add((T) mapToBean(map, bean.getClass()));}}return list;}/*** 将对象装换为map** @param bean* @return*/public static <T> Map<String, Object> beanToMap(T bean) {Map<String, Object> map = Maps.newHashMap();if (bean != null) {BeanMap beanMap = BeanMap.create(bean);for (Object key : beanMap.keySet()) {map.put(key + "", beanMap.get(key));}}return map;}/*** 将List<T>转换为List<Map<String, Object>>** @param beanList* @return*/public static <T> List<Map<String, Object>> beansToMap(List<T> beanList) {List<Map<String, Object>> list = Lists.newArrayList();if (beanList != null && beanList.size() > 0) {Map<String, Object> map;T bean;for (int i = 0, size = beanList.size(); i < size; i++) {bean = beanList.get(i);map = beanToMap(bean);list.add(map);}}return list;}}
4. 测试
■ 测试类(SolrServiceTests.java)
import com.lonton.bigdata.vo.Article;import org.apache.solr.client.solrj.SolrServerException;import org.junit.jupiter.api.Test;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.context.SpringBootTest;import java.io.IOException;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;/*** Description 单元测试(Solr服务)*/@SpringBootTestpublic class SolrServiceTests {@Autowiredprivate SolrService service;@Testpublic void saveOrUpdate() {Map<String, Object> map = new HashMap<>();map.put("id", "1");map.put("content_id", 101L);map.put("title", "北京");map.put("content", "test作为一个中国人,我感到很自豪。");map.put("type", 1);map.put("create_at", 1578912614123L);map.put("publish_at", 1578912614125L);assert service.saveOrUpdate(map);}@Testpublic void deleteById() {saveOrUpdate();assert service.deleteById("1");}@Testpublic void deleteByQuery() {saveOrUpdate();assert service.deleteByQuery("id:1");}@Testpublic void deleteAll() {assert service.deleteByQuery("*:*");}@Testpublic void update() {saveOrUpdate();Map<String, Object> map = new HashMap<>();map.put("id", "1");map.put("content_id", 999L);map.put("title", "update-test");map.put("content", "update-test");map.put("type", 1);map.put("create_at", 1578912614199L);map.put("publish_at", 1578912614199L);assert service.update(map);}@Testpublic void batchSaveOrUpdate() throws IOException, SolrServerException {List<Article> entities = new ArrayList<>();for (int i = 1; i <= 35; i++) {entities.add(new Article(i, i * 10L, "我是中国人,打倒小日本" + i, "作为一个中国人,我感到很自豪。", 1, 1578912614123L, 1578912614123L));}assert service.batchSaveOrUpdate(entities);}@Testpublic void query() throws IOException, SolrServerException {batchSaveOrUpdate();List<String> hlFieldsList = new ArrayList<>();hlFieldsList.add("title");hlFieldsList.add("content");int page = 1;int rows = 5;String filterQueries = "content_id:[1 TO *]";SolrResultInfo<Article> resultInfo = service.query(Article.class, "keywords:中国", filterQueries, hlFieldsList, page, rows);Long total = resultInfo.getTotal();System.out.println("total:" + total);if (total > 0) {for (Article article : resultInfo.getList()) {System.out.println(article);}}}}
■ 控制类(ArticleController.java)
import com.alibaba.fastjson.JSONArray;import com.alibaba.fastjson.JSONObject;import com.alibaba.fastjson.TypeReference;import com.lonton.bigdata.service.SolrResultInfo;import com.lonton.bigdata.service.SolrService;import com.lonton.bigdata.util.CommonUtils;import com.lonton.bigdata.vo.Article;import org.apache.solr.client.solrj.SolrServerException;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.*;import java.io.IOException;import java.util.ArrayList;import java.util.List;import java.util.Map;@RestController@RequestMapping("/solrService")public class ArticleController {@Autowiredprivate SolrService service;// http://localhost:8082/solrService/saveOrUpdate/record/*** 将Map对象添加(新增或修改)到Solr中<br/>* {* "id":"1",* "content_id":10,* "title":"我是中国人",* "content":"作为一个中国人,我感到很自豪。ArticleController",* "type":1,* "create_at":1578912614123,* "publish_at":1578912614123* }** @param jsonParam 接收前端JSON格式的数据* @return*/@ResponseBody@RequestMapping(value = "/saveOrUpdate/record", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")public boolean saveOrUpdate(@RequestBody JSONObject jsonParam) {Map<String, String> map = JSONObject.parseObject(jsonParam.toJSONString(), new TypeReference<Map<String, String>>() {});System.out.println(map);return service.saveOrUpdate(map);}// http://localhost:8082/solrService/deleteById/1/*** 根据id删除** @param id 索引ID*/@RequestMapping(value = "/deleteById/{id}", method = RequestMethod.POST)public boolean deleteById(@PathVariable("id") String id) {return service.deleteById(id);}// http://localhost:8082/solrService/deleteByQuery/id/1// http://localhost:8082/solrService/deleteByQuery/*/*/*** 通过查询删除Solr中对应的数据集合** @param key 字段* @param value 值* @return*/@RequestMapping(value = "/deleteByQuery/{key}/{value}", method = RequestMethod.POST)public boolean deleteByQuery(@PathVariable("key") String key, @PathVariable("value") String value) {return service.deleteByQuery(String.format("%s:%s", key, value));}// http://localhost:8082/solrService/update/record/*** 更新Solr中的文档,Map对象中必须存在id用于定位doc文档<br/>* {* "id":"1",* "content_id":10,* "title":"我是中国人update",* "content":"作为一个中国人,我感到很自豪。update",* "type":1,* "create_at":1578912614123,* "publish_at":1578912614123* }** @param jsonParam 接收前端JSON格式的数据* @return*/@ResponseBody@RequestMapping(value = "/update/record", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")public boolean update(@RequestBody JSONObject jsonParam) {Map<String, Object> map = JSONObject.parseObject(jsonParam.toJSONString(), new TypeReference<Map<String, Object>>() {});System.out.println(map);return service.update(map);}// http://localhost:8082/solrService/batchSaveOrUpdate/record/*** 批量新增或更新记录* [{* "id": "1",* "contentId": 101,* "title": "我是中国人add",* "content": "作为一个中国人,我感到很自豪。add",* "type": 1,* "createAt": 1578912614123,* "publishAt": 1578912614123* },* {* "id": "2",* "contentId": 102,* "title": "我是中国人add",* "content": "作为一个中国人,我感到很自豪。add",* "type": 1,* "createAt": 1578912614123,* "publishAt": 1578912614123* }]** @param jsonParam 接收前端JSON格式的数据* @return* @throws IllegalAccessException* @throws InstantiationException* @throws IOException* @throws SolrServerException*/@ResponseBody@RequestMapping(value = "/batchSaveOrUpdate/record", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")public boolean batchSaveOrUpdate(@RequestBody JSONArray jsonParam) throws Exception {List<Map<String, Object>> maps = (List<Map<String, Object>>) JSONArray.parse(jsonParam.toJSONString());// 方法1/*List<Article> list =new ArrayList<>();for (Map<String, String> map : maps) {// 1. 工具类将map转为JavaBeanlist.add(CommonUtils.mapToBean(map, Article.class));// 2. 从Map中取值对JavaBean进行setter*//*Article bean=new Article();bean.setId(Integer.valueOf(map.get("id")));bean.setContentId(Long.parseLong(String.valueOf(map.get("content_id"))));bean.setTitle(map.get("title"));bean.setContent(map.get("content"));bean.setType(Integer.valueOf(String.valueOf(map.get("type"))));bean.setCreateAt(Long.valueOf(String.valueOf(map.get("create_at"))));bean.setPublishAt(Long.valueOf(String.valueOf(map.get("publish_at"))));list.add(bean);*//*}*/// 方法2List<Article> list = CommonUtils.mapsToBeans(maps, Article.class);System.out.println(CommonUtils.beansToMap(list));return service.batchSaveOrUpdate(list);}// http://localhost:8082/solrService/getById/1/*** 根据id查询内容** @param id 索引ID* @return* @throws IOException* @throws SolrServerException*/@RequestMapping(value = "/getById/{id}", method = RequestMethod.GET)public Article getById(@PathVariable String id) throws IOException, SolrServerException {Article article = service.getById(id, Article.class);System.out.println(article);return article;}// http://localhost:8082/solrService/query/中国/1/5/*** 综合查询(条件、高亮等)** @param keywords 关键字* @param page 第?页* @param rows 每页显示所少条记录* @return*/@RequestMapping(value = "/query/{keywords}/{page}/{rows}", method = RequestMethod.GET)public SolrResultInfo query(@PathVariable String keywords, @PathVariable int page, @PathVariable int rows) {List<String> hlFieldsList = new ArrayList<>();hlFieldsList.add("title");hlFieldsList.add("content");String filterQueries = "content_id:[102 TO *]";SolrResultInfo<Article> resultInfo = service.query(Article.class,String.format("keywords:%s", keywords),filterQueries,hlFieldsList,page,rows);Long total = resultInfo.getTotal();System.out.println("total:" + total);if (total > 0) {for (Article article : resultInfo.getList()) {System.out.println(article);}}return resultInfo;}}
5. 完整示例代码
源码:solr-springboot-example-src.zip
参考
简书:Spring Boot和Solr整合
https://www.jianshu.com/p/05a161add1a6
CSDN:Spring Boot整合Solr,手把手教你使用Solr
https://blog.csdn.net/weixin_42129558/article/details/82682265
博客园:Spring Boot整合Solr
https://www.cnblogs.com/wdfordream/p/11377161.html
CSDN:Spring Boot+Solr配置入门
https://blog.csdn.net/hello_word2/article/details/80757396
