工程搭建
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-demo
data:
solr:
host: http://bigdata-node1:8983/solr/db_sync
server:
port: 8081
application.properties
spring.application.name=solr-springboot-example
server.port=8081
# solr Configuration
spring.data.solr.host=http://bigdata-node1:8983/solr/db_sync
2. 通过ZooKeeper连接
application.yml
spring:
application:
name: solr-springboot-example
data:
solr:
zk-host: 192.168.0.101:2181,192.168.0.102:2181,192.168.0.103:2181
server:
port: 8081
application.properties
spring.application.name=solr-springboot-example
server.port=8081
# solr Configuration
spring.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 {
@Autowired
private SolrClient solrClient;
/**
* 测试:分页查找
*/
@Test
public 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. 高亮显示
```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 {
@Autowired
private SolrClient solrClient;
/**
* 设置结果高亮显示
*
* @throws IOException
* @throws SolrServerException
*/
@Test
public 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-example
server.port=8081
# solr Configuration
spring.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)**
```java
import 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)
*/
@Configuration
public 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.*;
@Service
public class SolrServiceImpl implements SolrService {
private static final Logger log = LoggerFactory.getLogger(SolrServiceImpl.class);
@Autowired
private 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
*/
@Override
public <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;
}
@Override
public <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;
}
@Override
public <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;
}
@Override
public <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;
@Override
public 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服务)
*/
@SpringBootTest
public class SolrServiceTests {
@Autowired
private SolrService service;
@Test
public 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);
}
@Test
public void deleteById() {
saveOrUpdate();
assert service.deleteById("1");
}
@Test
public void deleteByQuery() {
saveOrUpdate();
assert service.deleteByQuery("id:1");
}
@Test
public void deleteAll() {
assert service.deleteByQuery("*:*");
}
@Test
public 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);
}
@Test
public 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);
}
@Test
public 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 {
@Autowired
private 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转为JavaBean
list.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);*//*
}*/
// 方法2
List<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