由于solr在使用时需要进行参数拼接等大量重复操作,所以对solr调用这块进行了简单封装:
1、对应实体添加solr字段注解(注意:注解字段都要在solr的core中配置)
2、通过反射获取注解字段中非空值拼接搜索参数、可以设置字段精确匹配,默认非精确匹配
只需要传入对应实体,和分页参数即可、使用者不需要了解实现直接调用即可
先上使用实例:
实体注解:
@SolrField
private String title;
private String titleTranslation;
@SolrField(isLike=false)//精确匹配
private String journalName;
方法调用:
@RequestMapping(value = "list")
public String list(GxMagazine gxMagazine, Model model, HttpServletRequest request, HttpServletResponse response) {
Map<String, ORDER> sort = new HashMap<String, ORDER>();
sort.put("createDate", ORDER.desc);
Page<GxMagazine> page = new Page<>(request, response, pageSize);
SolrDocumentList results = SolrUtil.searchProcudt(gxMagazine, sort, page, Global.getConfig("solr_core_magazine"));
model.addAttribute("page", page);//分页对象
model.addAttribute("list", results);//数据结果集 把solr里的实体跟java的实体配成一样 直接调用即可
return "front/res/magazineList";
}
ok页面调用:
<c:forEach items="${list }" var="var" varStatus="status">
<span class="new-conDetail">${var.datasource }</span>
</c:forEach>
solr封装工具类:
package com.qhwl.common.solr;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrQuery.ORDER;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.HttpSolrClient;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocumentList;
import com.qhwl.admin.gx.entity.res.GxMagazine;
import com.qhwl.common.config.Global;
import com.qhwl.common.persistence.Page;
import com.qhwl.common.utils.StringUtils;
public class SolrUtil {
//指定solr服务器的地址
private final static String SOLR_URL = Global.getConfig("solr_url");
/**
*
* @param obj 搜索实体对象
* @param sortMap 排序
* @param page 分页对象
* @param solr_core solr对应core
* @return
*/
public static SolrDocumentList searchProcudt(Object obj,
Map<String, ORDER> sortMap, Page page,String solr_core ) {
// 建立连接
HttpSolrClient server = new HttpSolrClient.Builder(SOLR_URL + solr_core).withConnectionTimeout(10000).withSocketTimeout(60000).build();
// 查询条件
SolrQuery query = new SolrQuery();
Field[] fields = obj.getClass().getDeclaredFields();
StringBuilder sbl = new StringBuilder();
for (int i = 0; i < fields.length; i++) {
Field f = fields[i];
try {
// 设置字段可见否则无法获取私有属性
f.setAccessible(true);
Object o = f.get(obj);
// 只获取非空字段和配置solr注解字段
SolrField sf = f.getAnnotation(SolrField.class);
if (o != null && StringUtils.isNotBlank(o.toString()) && sf != null) {
sbl.append(" AND ");// AND
sbl.append(f.getName());
sbl.append(":");
if (sf.isLike()) {
sbl.append("*" + parseKeywords(f.get(obj).toString()) + "*");
} else {
sbl.append(parseKeywords(f.get(obj).toString()));
}
System.out.println("属性名:" + f.getName() + " 属性值:" + f.get(obj).toString());
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
if (sbl.length() > 0) {
String s = sbl.toString();
s = s.substring(" AND ".length(), sbl.length());
query.setQuery(s);// 按条件查询
} else {
query.setQuery("*:*");// 无参数,就查全部
}
// 排序
if (sortMap != null)
for (String key : sortMap.keySet()) {
ORDER value = sortMap.get(key);
if (StringUtils.isNotBlank(key) && value!=null) {
query.addSort(key, value);
}
}
// 分页
int start = (page.getPageNo() - 1) * page.getPageSize();
int size = page.getPageSize();
// 将初始偏移量指定到结果集中。可用于对结果进行分页。默认值为 0
query.set("start", start);
// 返回文档的最大数目。默认值为 10。
query.set("rows", size);
// 指定文档结果中应返回的 Field 集,作为逗号分隔。默认为 “*”,指所有的字段。“score” 指还应返回记分。
query.setParam("fl", "score,*");
// 执行查询
QueryResponse response = null;
try {
response = server.query(query);
} catch (SolrServerException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
SolrDocumentList results = response.getResults();
long rowCount = results.getNumFound();// 搜索到的总条数
int QTime = response.getQTime();// 耗时
int status = response.getStatus();// 状态
System.out.println("QTime:"+QTime+"|status:"+status);
page.setCount(rowCount);// 总条数
return results;
}
/**
* solr 官方的处理方法
* 如果query中带有非法字符串,结果直接报错,所以你对用户的输入必须要先做处理
* @param s
* @return
*/
protected static String parseKeywords(String s) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
// These characters are part of the query syntax and must be escaped
if (c == '\\' || c == '+' || c == '-' || c == '!' || c == '(' || c == ')' || c == ':' || c == '^' || c == '[' || c == ']' || c == '\"'
|| c == '{' || c == '}' || c == '~' || c == '*' || c == '?' || c == '|' || c == '&' || c == ';' || c == '/'
|| Character.isWhitespace(c)) {
sb.append('\\');
}
sb.append(c);
}
return sb.toString();
}
public static void main(String[] args) throws Exception {
// Map<String, Object> param=new HashMap<String, Object>();
// param.put("id", "1");
GxMagazine gxMagazine =new GxMagazine();
gxMagazine.setTitle("title");
Map<String, ORDER> sort=new HashMap<String, ORDER>();
sort.put("id", ORDER.desc);
SolrDocumentList results = searchProcudt(gxMagazine,sort,new Page<>(1, 10),Global.getConfig("solr_core_magazine"));
System.out.println("name:"+results.get(0).get("title"));
}
}
自定义solr注解:
package com.qhwl.common.solr;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**由于solr并不需要配置所有数据所以反射获取字段是只需要取注解字段即可
* solr获取字段注解定义
* @author ztj
* 默认有此注解便视为solr配置字段
*/
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface SolrField {
/**
* 是否模糊搜索字段
*/
boolean isLike() default true;
/**
* 反射类型
*/
Class<?> fieldType() default Class.class;
}
jar:
<dependency>
<groupId>org.apache.solr</groupId>
<artifactId>solr-solrj</artifactId>
<version>7.2.1</version>
</dependency>