前面已经讲过 如果安装及配置Solr服务器了, 那么现在我们就来正式在代码中使用Solr.
1,这里Solr主要是怎么使用的呢? 

当我们在前台页面搜索商品名称关键词时, 我们这时是在Solr库中去查找相应的商品信息, 然后将搜索关键词高亮.

2,那么Solr库中的商品信息又是如何添加的呢? 

当我们在给商品上架的时候, 将商品信息update 到mysql数据库中的bbs_product表中, 然后同样的将相应的信息 添加到Solr库中.

接下来就看代码的具体实现吧:

一, 商品上架

我们在这里点击上架按钮: 
list.jsp:

 <div style="margin-top:15px;"><input class="del-button" type="button" value="删除" onclick="optDelete();"/><input class="add" type="button" value="上架" onclick="isShow('${name}', '${brandId }', '${isShow }' ,'${pagination.pageNo }')"/><input class="del-button" type="button" value="下架" onclick="isHide();"/></div>

点击上架触发isShow事件:

 <script type="text/javascript">
//上架
function isShow(name,brandId,isShow,pageNo){
//请至少选择一个
var size = $("input[name='ids']:checked").size();
if(size == 0){
alert("请至少选择一个");
return;
}
//你确定上架吗
if(!confirm("你确定上架吗")){
return;
}
//提交 Form表单
$("#jvForm").attr("action","/product/isShow.do?name="+ name +"&brandId="+brandId+"&isShow="+isShow+"&pageNo="+pageNo);
$("#jvForm").attr("method","post");
$("#jvForm").submit(); }
</script>

接着到Controller层:
ProductController.java:

 //添加页面
@RequestMapping("/isShow.do")
public String isShow(Long[] ids, Model model){
productService.isShow(ids);
return "forward:/product/list.do";
}

接着看Service层:
ProdcutServiceImpl.java:

 //上架
     @Autowired
private SolrServer solrServer;
public void isShow(Long[] ids){
Product product = new Product();
product.setIsShow(true);
for (Long id : ids) {
//上下架状态
product.setId(id);
productDao.updateByPrimaryKeySelective(product); //TODO 保存商品信息到Solr服务器
SolrInputDocument doc = new SolrInputDocument();
//ID
doc.setField("id", id);
//名称
Product p = productDao.selectByPrimaryKey(id);
doc.setField("name_ik", p.getName());
//图片URL
doc.setField("url", p.getImgUrls()[0]);
//品牌 ID
doc.setField("brandId", p.getBrandId());
//价格 sql查询语句: select price from bbs_sku where product_id = ? order by price asc limit 1
SkuQuery skuQuery = new SkuQuery();
skuQuery.createCriteria().andProductIdEqualTo(id);
skuQuery.setOrderByClause("price asc");
skuQuery.setPageNo(1);
skuQuery.setPageSize(1);
List<Sku> skus = skuDao.selectByExample(skuQuery);
doc.setField("price", skus.get(0).getPrice());
//...时间等 剩下的省略 try {
solrServer.add(doc);
solrServer.commit();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//TODO 静态化
}
}

这里使用SolrInputDocument 来保存商品信息, 其中doc.setField("name_ik", p.getName());的name_ik 是我们在solr 配置文件配置的IK 分词器的字段, doc.setField("url", p.getImgUrls()[0]); 这里我们也只是取第一张图片的url用来展示.
这里我们还用到了skuQuery, 因为一个商品中不同的颜色不同的尺码都可能有不同的价格, 我们在这里 是取到同一个productId下价格最小的来给显示~
然后再就是将我们已经设置好的SolrInputDocument 通过SolrServer 来提交到Solr服务器. SolrServer是已经在spring中注册好了的, 在这里直接注入即可使用.
spring来管理Solr:

到了这里上架的功能就做好了, 这也是给后面Solr查询做好铺垫.

二, 前台使用Solr查询
到了这里就开始查看前台页面了, 前台页面是扒的网上的, 具体业务逻辑是自己修改的, 页面如下:

这里需要特殊说明一下, 我们配置的全局拦截器变成了: / , 而且过滤掉静态资源, 配置如下:
首先是babasport-portal project下的web.xml文件:

 <?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <!-- Post过滤器 -->
<filter>
<filter-name>encoding</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter> <filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/</url-pattern>
</filter-mapping> <!-- 前端控制器 -->
<servlet>
<servlet-name>portal</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<!-- 默认读取的是 WEB-INF/console-servlet.xml -->
<param-value>classpath:springmvc-portal.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet> <servlet-mapping>
<servlet-name>portal</servlet-name>
<!--
/*: 拦截视图请求: .jsp .js .css 几乎不用,配置静态资源过滤
/: 拦截所有,不拦截.jsp 文件, 但是同样拦截.js .css 如果使用也需要配置静态资源过滤(前台系统使用)
*.do:拦截所有以.do请求, 后台开发应用*.do
-->
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>

第二个就是babasport-portal project下的spring配置文件中设置过滤掉静态资源:

 <!-- 过滤静态资源 -->
<mvc:resources location="/js/" mapping="/js/*.*"/>
<mvc:resources location="/css/" mapping="/css/*.*"/>
<mvc:resources location="/images/" mapping="/images/*.*"/>

这样就就可以直接访问了.

当我们输入2016 点击查询后会出现什么? 我把已经做好的页面展示一下: 

那么就进入到实际的开发当中: 
当我们在搜索框输入2016 且点击 搜索时: 

然后到Controller层去找到search方法:

 @Autowired
private SearchService searchService; //去首页
@RequestMapping(value="/")
public String index(){
return "index";
} //搜索
@RequestMapping(value="/search")
public String search(Integer pageNo, String keyword, String price, Long brandId, Model model){
//品牌结果集 Redis中
List<Brand> brands = searchService.selectBrandListFromRedis();
model.addAttribute("brands", brands); //map 装已经选择的条件
Map<String, String> map = new HashMap<String, String>();
if(null != brandId){
for (Brand brand : brands) {
if(brandId.equals(brand.getId())){
map.put("品牌", brand.getName());
break;
}
}
}
//价格 0-99 1600以上
if(null != price){
String[] split = price.split("-");
//如果切割后的长度等于2 就说明这是一个价格区间
if(split.length == 2){
map.put("价格", price);
}else {
map.put("价格", price + "以上");
}
}
model.addAttribute("map", map); Pagination pagination = searchService.selectPaginationFromSolr(pageNo, keyword, price, brandId);
model.addAttribute("pagination", pagination);
model.addAttribute("keyword", keyword);
model.addAttribute("price", price);
model.addAttribute("brandId", brandId); return "search";
}

提示: 这里使用到了SolrService, 相信看我以前博文的朋友都知道这个地方还需要配置dubbo, 就是服务提供方和适用方, 这里为了简便直接略过, 实际开发中是必须要配置的, 否则就调用不了SolrService中的方法了.
这个controller 中往search.jsp中put了很多东西, 具体这些东西什么用我们可以先不管, 我们先看下search.jsp页面.
而且这个controller中查询brand 是从redis中查询出来的, 我们会在下面讲到这个.

 <c:if test="${fn:length(map) != 0 }">
<div class="sl-b-selected J_brandSelected">
<span class="crumbs-arrow">已选条件:</span>
<c:forEach items="${map }" var="m">
<a title="依琦莲(yiqilian)" href="javascript:;" class="crumb-select-item">
<b>${m.key }:</b><em>${m.value }</em><i></i>
</a>
</c:forEach>
</div>
</c:if>

上面这个地方就是为何要在controller设置map值了, 这个是显示已选择的过滤条件.

 <c:if test="${empty brandId }">
<div class="J_selectorLine s-brand">
<div class="sl-wrap">
<div class="sl-key"><strong>品牌:</strong></div>
<div class="sl-value">
<div class="sl-v-list">
<ul class="J_valueList v-fixed">
<c:forEach items="${brands }" var="brand">
<li id="brand-38118" data-initial="j" style="display:block;">
<a href="javascript:;" onclick="fqBrand('${brand.id }')" title="${brand.name }"><i></i>${brand.name }</a>
</li>
</c:forEach>
</ul>
</div>
</div>
</div>
</div>
</c:if>
<c:if test="${empty price }">
<div id="J_selectorPrice" class="J_selectorLine s-line">
<div class="sl-wrap">
<div class="sl-key"><span>价格:</span></div>
<div class="sl-value">
<div class="sl-v-list">
<ul class="J_valueList">
<li>
<a href="javascript:;" onclick="fqPrice('0-99')"><i></i>0-99</a>
</li>
<li>
<a href="javascript:;" onclick="fqPrice('100-299')"><i></i>100-299</a>
</li>
<li>
<a href="javascript:;" onclick="fqPrice('300-599')"><i></i>300-599</a>
</li>
<li>
<a href="javascript:;" onclick="fqPrice('600-999')"><i></i>600-999</a>
</li>
<li>
<a href="javascript:;" onclick="fqPrice('1000-1599')"><i></i>1000-1599</a>
</li>
<li>
<a href="javascript:;" onclick="fqPrice('1600')"><i></i>1600以上</a>
</li>
</ul>
</div>
</div>
</div>
</div>
</c:if>

接下来我们来看下对应的js方法:

 <script type="text/javascript">
var price = '${price}';
var brandId = '${brandId}';
//过滤品牌id
function fqBrand(id){
if('' != price){
window.location.href="/search?keyword="+ ${keyword} + "&brandId="+ id+"&price="+price;
}else{
window.location.href="/search?keyword="+ ${keyword} + "&brandId="+ id;
}
} //过滤价格
function fqPrice(id){
if('' != brandId){
window.location.href = "/search?keyword=${keyword}" + "&brandId=" + brandId + "&price=" + id;
}else{
window.location.href = "/search?keyword=${keyword}" + "&price=" + id;
}
}
</script>

这个就可以实现 添加 过滤条件的选项了.

三, 使用Redis 取出商品品牌列表
首先 当我们在后台添加或者修改品牌时, 我们应该同样将这个品牌添加到Redis中, 格式类似于: {"brandId":"brandName"}
controller层:(当我们在后台添加或者修改品牌)

 @Autowired
private Jedis jedis;
//修改
public void updateBrandById(Brand brand){
//保存或修改 时修改Redis中的品牌, hmset适合批量添加品牌
/*Map<String, String> map = new HashMap<String,String>();
map.put(String.valueOf(brand.getId()), brand.getName());
jedis.hmset("brand", map);*/
jedis.hset("brand", String.valueOf(brand.getId()), brand.getName());
brandDao.updateBrandById(brand);
}

redis中有了品牌列表后, 然后就是查询了:

 @Autowired
private Jedis jedis;
//查询Redis中的品牌结果集
public List<Brand> selectBrandListFromRedis(){
List<Brand> brands = new ArrayList<Brand>();
Map<String, String> hgetAll = jedis.hgetAll("brand");
Set<Entry<String, String>> entrySet = hgetAll.entrySet();
for (Entry<String, String> entry : entrySet) {
Brand brand = new Brand();
brand.setId(Long.parseLong(entry.getKey()));
brand.setName(entry.getValue());
brands.add(brand);
} return brands;
}

到了这里redis查询brand就完成了, 那么继续看下关于solr 是如何加入过滤条件的吧:

 @Autowired
private SolrServer solrServer;
//查询商品信息从Solr
public Pagination selectPaginationFromSolr(Integer pageNo, String keyword, String price, Long brandId){
ProductQuery productQuery = new ProductQuery();
//当前页
productQuery.setPageNo(Pagination.cpn(pageNo));
//每页数
productQuery.setPageSize(8); SolrQuery solrQuery = new SolrQuery();
//关键词 商品名称
solrQuery.set("q", "name_ik:"+keyword);
//回显数据
StringBuilder params = new StringBuilder();
params.append("keyword=").append(keyword); //排序
solrQuery.addSort("price", ORDER.asc); //高亮
//1,设置, 打开高亮的开关
solrQuery.setHighlight(true);
//2, 设置高亮字段
solrQuery.addHighlightField("name_ik");
//3, 设置关键字高亮的样式 <span style='color:red'>2016</span>
//设置前缀和后缀
solrQuery.setHighlightSimplePre("<span style='color:red'>");
solrQuery.setHighlightSimplePost("</span>"); //过滤条件 品牌
if(null != brandId){
solrQuery.addFilterQuery("brandId:"+brandId);
params.append("&brandId=").append(brandId);
}
//过滤价格 0-99 1600
if(null != price){
String[] split = price.split("-");
//如果切割后的长度等于2 就说明这是一个价格区间
if(split.length == 2){
solrQuery.addFilterQuery("price:["+split[0]+" TO "+split[1]+"]");
}else {
solrQuery.addFilterQuery("price:["+split[0]+" TO *]");
}
params.append("&price=").append(price);
} //分页 limit 开始行,每页数
solrQuery.setStart(productQuery.getStartRow());
solrQuery.setRows(productQuery.getPageSize()); QueryResponse response = null;
try {
response = solrServer.query(solrQuery); } catch (Exception e) {
e.printStackTrace();
}
//分析这个Map
//第一层Map: Key String == ID : Value: Map
//第二层Map: Key String == name_ik : Value: List
//获取到List: String 0,1,2....
Map<String, Map<String, List<String>>> highlighting = response.getHighlighting(); List<Product> products = new ArrayList<Product>();
//结果集
SolrDocumentList docs = response.getResults();
//总条数
long numFound = docs.getNumFound();
for (SolrDocument doc : docs) {
Product product = new Product();
//商品的ID
String id = (String)doc.get("id");
product.setId(Long.parseLong(id)); //取第二层Map
Map<String, List<String>> map = highlighting.get(id);
//取List集合
List<String> list = map.get("name_ik"); //商品名称
//String name = (String)doc.get("name_ik");
//product.setName(name);
product.setName(list.get(0)); //list.get(0) 中的name是已经设置为高亮的 //图片
String url = (String)doc.get("url");
product.setImgUrl(url);
//价格 这里的价格本身是保存在bbs_sku表中的, 而我们在这里将price属性直接添加到了Product中
//因为我们在做上架的时候, 查询的是bbs_sku中price最小的值 然后保存到solr中的, 所以这里我们就直接将price属性添加到product中了
//这里的价格只有一个值
//Float price = (Float)doc.get("price");
product.setPrice((Float)doc.get("price"));
//品牌ID
//Integer brandId = (Integer)doc.get("brandId");
product.setBrandId(Long.parseLong(String.valueOf((Integer)doc.get("brandId"))));
products.add(product);
} Pagination pagination = new Pagination(
productQuery.getPageNo(),
productQuery.getPageSize(),
(int)numFound,
products
);
//页面展示
String url = "/search";
pagination.pageView(url, params.toString()); return pagination;
}

这个就是本博文的重中之重了, code上面都加了注释, 相信还是比较容易理解的.

 

 

[项目构建 六]babasport Redis使用实例.

Solr的原理及在项目中的使用实例.的更多相关文章

  1. EntityFramwork6 在项目中的应用实例

    在项目开发中使用的ROM大多采用EntityFramwork去完成,下边给出最新的EntityFramwork在项目中的应用实例 : 一.更新EntityFramwork 在安装.NetFramwor ...

  2. Java算法之递归打破及在真实项目中的使用实例

    开心一笑 刚才领导问开发:"你觉得这个项目的最大风险是什么",开发说:"加班猝死" , 气氛尴尬了一分钟!!! 提出问题 1.递归算法简单复习 2.如何实现递归 ...

  3. 项目中AOP的实例应用

    其中包括了权限管理.表单验证.事务管理.信息过滤.拦截器.过滤器.页面转发等等. 公司项目的应用:(涉及用户验证登录以及用户是否有管理员权限.心理用户权限等),还有涉及的其他日志管理代码就不一一举例了 ...

  4. 3.Web项目中使用Log4j实例

    转自:https://blog.csdn.net/luohai859/article/details/52250807 上面代码描述了Log4j的简单应用,其实使用Log4j也就是这样简单方便.当然除 ...

  5. Redis在Laravel项目中的应用实例详解

    https://mp.weixin.qq.com/s/axIgNPZLJDh9VFGVk7oYYA 在初步了解Redis在Laravel中的应用 那么我们试想这样的一个应用场景 一个文章或者帖子的浏览 ...

  6. vue项目中使用bpmn-流程图预览篇

    前情提要 上文已经实现了节点操作的前进.后退.导入.导出等操作,今日来实现“流程图预览”,以及视图的放大缩小 前提:项目安装过bpmn,安装可见上篇文章 实现要点 bpmn提供了两个神器:Modele ...

  7. vue项目中使用bpmn-节点篇

    前情提要 根据之前的操作,我们可以创建.导入.导出流程图,并对其进预览.通过此篇可以学到: 为节点添加点击.鼠标悬浮等事件 获取流程图内所有指定类型的节点 通过外部更新节点名字 获取节点实例的两种方法 ...

  8. vue项目中使用bpmn-为节点添加颜色

    内容概述 本系列 “vue项目中使用bpmn-xxxx” 分为五篇,均为自己使用过程中用到的实例,手工原创,目前属于陆续更新中.主要包括vue项目中bpmn使用实例.应用技巧.基本知识点总结和需要注意 ...

  9. vue项目中使用bpmn-基础篇

    内容概述 本系列“vue项目中使用bpmn-xxxx”分为五篇,均为自己使用过程中用到的实例,手工原创,目前属于陆续更新中.主要包括vue项目中bpmn使用实例.应用技巧.基本知识点总结和需要注意事项 ...

随机推荐

  1. PDA手持机 移动开单进销存系统 现场出打印凭据和扫码 新的亮点

    传统车销模式弊端:1.手写开单,效率低,动作慢2.现场手写开单明细不能打印,产品明细不规范3.电脑办公人员及车销人员对车上的库存情况掌握不清楚,销售人员对每种产品销售价格不清楚4.老板对员工工作的管控 ...

  2. selenium获取Cookie操作

    直接贴代码: Set cookies = dr.manage().getCookies(); for (Cookie cookie : cookies) { System.out.println(&q ...

  3. 一行代码解决各种IE兼容问题,IE6,IE7,IE8,IE9,IE10

    行代码解决各种IE兼容问题,IE6,IE7,IE8,IE9,IE10 2012-04-25 16:29:04| 分类: 学习 |字号 订阅 在网站开发中不免因为各种兼容问题苦恼,针对兼容问题,其实IE ...

  4. linux查看是什么操作系统是什么命令

    https://zhidao.baidu.com/question/361519585968730492.html

  5. [翻译] ORMLite document -- How to Use Part (一)

    前言 此文档翻译于第一次学习 ORMLite 框架,如果发现当中有什么不对的地方,请指正.若翻译与原文档出现任何的不相符,请以原文档为准.原则上建议学习原英文文档. ----------------- ...

  6. 【验证】C# dataSource 的记忆功能

    做项目时遇到的问题:dataSource被ComboBox引用过一次,会记忆最后一次选中的值,然后下一次再用时这个值会直接呈现在ComboBox中. 为验证是dataSource还是ComboBox自 ...

  7. lua 时间戳和时间互转

    1.时间戳转换成时间 local t = 1412753621000 function getTimeStamp(t)     return os.date("%Y%m%d%H", ...

  8. iOS中push视图的时候,屏幕中间会出现一条灰色的粗线的解决方案

    因为执行动画需要时间,所以在动画未完成又执行另一个切换动画,容易产生异常.所以在一个方法连续push不同的VC是没有问题的,但是不小心push同一个VC,并且animated为YES,可能多次跳转了 ...

  9. 在一定[min,max]区间,生成n个不重复的随机数的封装函数

    引:生成一个[min,max]区间的一个随机数,随机数生成相关问题参考→链接 var ran=parseInt(Math.random()*(max-min+1)+min); //生成一个[min,m ...

  10. dos清除缓存

    ipconfig /flushdns ,DNS缓存就被清除了. ipconfig /displaydns查看DNS缓存