[项目构建 七]babasport 商品上架及Solr使用实例.

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

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

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

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

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

一, 商品上架

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

1 <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事件:

 1 <script type="text/javascript">
 2 //上架
 3 function isShow(name,brandId,isShow,pageNo){
 4     //请至少选择一个
 5     var size = $("input[name=‘ids‘]:checked").size();
 6     if(size == 0){
 7         alert("请至少选择一个");
 8         return;
 9     }
10     //你确定上架吗
11     if(!confirm("你确定上架吗")){
12         return;
13     }
14     //提交 Form表单
15     $("#jvForm").attr("action","/product/isShow.do?name="+ name +"&brandId="+brandId+"&isShow="+isShow+"&pageNo="+pageNo);
16     $("#jvForm").attr("method","post");
17     $("#jvForm").submit();
18
19 }
20 </script>

接着到Controller层:
ProductController.java:

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

接着看Service层:
ProdcutServiceImpl.java:

 1 //上架
     @Autowired
	private SolrServer solrServer;
 2     public void isShow(Long[] ids){
 3         Product product = new Product();
 4         product.setIsShow(true);
 5         for (Long id : ids) {
 6             //上下架状态
 7             product.setId(id);
 8             productDao.updateByPrimaryKeySelective(product);
 9
10             //TODO 保存商品信息到Solr服务器
11             SolrInputDocument doc = new SolrInputDocument();
12             //ID
13             doc.setField("id", id);
14             //名称
15             Product p = productDao.selectByPrimaryKey(id);
16             doc.setField("name_ik", p.getName());
17             //图片URL
18             doc.setField("url", p.getImgUrls()[0]);
19             //品牌 ID
20             doc.setField("brandId", p.getBrandId());
21             //价格 sql查询语句: select price from bbs_sku where product_id = ? order by price asc limit 1
22             SkuQuery skuQuery = new SkuQuery();
23             skuQuery.createCriteria().andProductIdEqualTo(id);
24             skuQuery.setOrderByClause("price asc");
25             skuQuery.setPageNo(1);
26             skuQuery.setPageSize(1);
27             List<Sku> skus = skuDao.selectByExample(skuQuery);
28             doc.setField("price", skus.get(0).getPrice());
29             //...时间等 剩下的省略
30
31             try {
32                 solrServer.add(doc);
33                 solrServer.commit();
34             } catch (Exception e) {
35                 // TODO Auto-generated catch block
36                 e.printStackTrace();
37             }
38             //TODO 静态化
39         }
40     }

这里使用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文件:

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
 3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
 5     http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
 6
 7     <!-- Post过滤器 -->
 8     <filter>
 9         <filter-name>encoding</filter-name>
10         <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
11         <init-param>
12             <param-name>encoding</param-name>
13             <param-value>UTF-8</param-value>
14         </init-param>
15     </filter>
16
17     <filter-mapping>
18         <filter-name>encoding</filter-name>
19         <url-pattern>/</url-pattern>
20     </filter-mapping>
21
22     <!-- 前端控制器 -->
23     <servlet>
24         <servlet-name>portal</servlet-name>
25         <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
26         <init-param>
27             <param-name>contextConfigLocation</param-name>
28             <!-- 默认读取的是 WEB-INF/console-servlet.xml -->
29             <param-value>classpath:springmvc-portal.xml</param-value>
30         </init-param>
31         <load-on-startup>1</load-on-startup>
32     </servlet>
33
34     <servlet-mapping>
35         <servlet-name>portal</servlet-name>
36         <!--
37             /*: 拦截视图请求: .jsp  .js  .css  几乎不用,配置静态资源过滤
38             /: 拦截所有,不拦截.jsp 文件, 但是同样拦截.js .css  如果使用也需要配置静态资源过滤(前台系统使用)
39             *.do:拦截所有以.do请求, 后台开发应用*.do
40          -->
41         <url-pattern>/</url-pattern>
42     </servlet-mapping>
43 </web-app>

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

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

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

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

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

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

 1 @Autowired
 2     private SearchService searchService;
 3
 4     //去首页
 5     @RequestMapping(value="/")
 6     public String index(){
 7         return "index";
 8     }
 9
10     //搜索
11     @RequestMapping(value="/search")
12     public String search(Integer pageNo, String keyword, String price, Long brandId,  Model model){
13         //品牌结果集  Redis中
14         List<Brand> brands = searchService.selectBrandListFromRedis();
15         model.addAttribute("brands", brands);
16
17         //map 装已经选择的条件
18         Map<String, String> map = new HashMap<String, String>();
19         if(null != brandId){
20             for (Brand brand : brands) {
21                 if(brandId.equals(brand.getId())){
22                     map.put("品牌", brand.getName());
23                     break;
24                 }
25             }
26         }
27         //价格 0-99 1600以上
28         if(null != price){
29             String[] split = price.split("-");
30             //如果切割后的长度等于2 就说明这是一个价格区间
31             if(split.length == 2){
32                 map.put("价格", price);
33             }else {
34                 map.put("价格", price + "以上");
35             }
36         }
37         model.addAttribute("map", map);
38
39         Pagination pagination = searchService.selectPaginationFromSolr(pageNo, keyword, price, brandId);
40         model.addAttribute("pagination", pagination);
41         model.addAttribute("keyword", keyword);
42         model.addAttribute("price", price);
43         model.addAttribute("brandId", brandId);
44
45         return "search";
46     }

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

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

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

 1 <c:if test="${empty brandId }">
 2 <div class="J_selectorLine s-brand">
 3     <div class="sl-wrap">
 4         <div class="sl-key"><strong>品牌:</strong></div>
 5         <div class="sl-value">
 6             <div class="sl-v-list">
 7                 <ul class="J_valueList v-fixed">
 8                 <c:forEach items="${brands }" var="brand">
 9                     <li id="brand-38118" data-initial="j" style="display:block;">
10                         <a href="javascript:;" onclick="fqBrand(‘${brand.id }‘)" title="${brand.name }"><i></i>${brand.name }</a>
11                     </li>
12                 </c:forEach>
13                 </ul>
14             </div>
15         </div>
16     </div>
17 </div>
18 </c:if>
19 <c:if test="${empty price }">
20 <div id="J_selectorPrice" class="J_selectorLine s-line">
21     <div class="sl-wrap">
22         <div class="sl-key"><span>价格:</span></div>
23         <div class="sl-value">
24             <div class="sl-v-list">
25                 <ul class="J_valueList">
26                     <li>
27                         <a href="javascript:;" onclick="fqPrice(‘0-99‘)"><i></i>0-99</a>
28                     </li>
29                     <li>
30                         <a href="javascript:;" onclick="fqPrice(‘100-299‘)"><i></i>100-299</a>
31                     </li>
32                     <li>
33                         <a href="javascript:;" onclick="fqPrice(‘300-599‘)"><i></i>300-599</a>
34                     </li>
35                     <li>
36                         <a href="javascript:;" onclick="fqPrice(‘600-999‘)"><i></i>600-999</a>
37                     </li>
38                     <li>
39                         <a href="javascript:;" onclick="fqPrice(‘1000-1599‘)"><i></i>1000-1599</a>
40                     </li>
41                     <li>
42                         <a href="javascript:;" onclick="fqPrice(‘1600‘)"><i></i>1600以上</a>
43                     </li>
44                 </ul>
45             </div>
46         </div>
47     </div>
48 </div>
49 </c:if>

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

 1 <script type="text/javascript">
 2     var price = ‘${price}‘;
 3     var brandId = ‘${brandId}‘;
 4     //过滤品牌id
 5     function fqBrand(id){
 6         if(‘‘ != price){
 7             window.location.href="/search?keyword="+ ${keyword} + "&brandId="+ id+"&price="+price;
 8         }else{
 9             window.location.href="/search?keyword="+ ${keyword} + "&brandId="+ id;
10         }
11     }
12
13     //过滤价格
14     function fqPrice(id){
15         if(‘‘ != brandId){
16             window.location.href = "/search?keyword=${keyword}" + "&brandId=" + brandId + "&price=" + id;
17         }else{
18             window.location.href = "/search?keyword=${keyword}" + "&price=" + id;
19         }
20     }
21 </script>

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

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

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

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

 1 @Autowired
 2     private Jedis jedis;
 3     //查询Redis中的品牌结果集
 4     public List<Brand> selectBrandListFromRedis(){
 5         List<Brand> brands = new ArrayList<Brand>();
 6         Map<String, String> hgetAll = jedis.hgetAll("brand");
 7         Set<Entry<String, String>> entrySet = hgetAll.entrySet();
 8         for (Entry<String, String> entry : entrySet) {
 9             Brand brand = new Brand();
10             brand.setId(Long.parseLong(entry.getKey()));
11             brand.setName(entry.getValue());
12             brands.add(brand);
13         }
14
15         return brands;
16     }

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

  1 @Autowired
  2     private SolrServer solrServer;
  3     //查询商品信息从Solr
  4     public Pagination selectPaginationFromSolr(Integer pageNo, String keyword, String price, Long brandId){
  5         ProductQuery productQuery = new ProductQuery();
  6         //当前页
  7         productQuery.setPageNo(Pagination.cpn(pageNo));
  8         //每页数
  9         productQuery.setPageSize(8);
 10
 11         SolrQuery solrQuery = new SolrQuery();
 12         //关键词 商品名称
 13         solrQuery.set("q", "name_ik:"+keyword);
 14         //回显数据
 15         StringBuilder params = new StringBuilder();
 16         params.append("keyword=").append(keyword);
 17
 18         //排序
 19         solrQuery.addSort("price", ORDER.asc);
 20
 21         //高亮
 22         //1,设置, 打开高亮的开关
 23         solrQuery.setHighlight(true);
 24         //2, 设置高亮字段
 25         solrQuery.addHighlightField("name_ik");
 26         //3, 设置关键字高亮的样式 <span style=‘color:red‘>2016</span>
 27         //设置前缀和后缀
 28         solrQuery.setHighlightSimplePre("<span style=‘color:red‘>");
 29         solrQuery.setHighlightSimplePost("</span>");
 30
 31         //过滤条件 品牌
 32         if(null != brandId){
 33             solrQuery.addFilterQuery("brandId:"+brandId);
 34             params.append("&brandId=").append(brandId);
 35         }
 36         //过滤价格 0-99  1600
 37         if(null != price){
 38             String[] split = price.split("-");
 39             //如果切割后的长度等于2 就说明这是一个价格区间
 40             if(split.length == 2){
 41                 solrQuery.addFilterQuery("price:["+split[0]+" TO "+split[1]+"]");
 42             }else {
 43                 solrQuery.addFilterQuery("price:["+split[0]+" TO *]");
 44             }
 45             params.append("&price=").append(price);
 46         }
 47
 48         //分页  limit 开始行,每页数
 49         solrQuery.setStart(productQuery.getStartRow());
 50         solrQuery.setRows(productQuery.getPageSize());
 51
 52         QueryResponse response = null;
 53         try {
 54             response = solrServer.query(solrQuery);
 55
 56         } catch (Exception e) {
 57             e.printStackTrace();
 58         }
 59         //分析这个Map
 60         //第一层Map: Key String == ID : Value: Map
 61         //第二层Map: Key String == name_ik : Value: List
 62         //获取到List: String 0,1,2....
 63         Map<String, Map<String, List<String>>> highlighting = response.getHighlighting();
 64
 65
 66         List<Product> products = new ArrayList<Product>();
 67         //结果集
 68         SolrDocumentList docs = response.getResults();
 69         //总条数
 70         long numFound = docs.getNumFound();
 71         for (SolrDocument doc : docs) {
 72             Product product = new Product();
 73             //商品的ID
 74             String id = (String)doc.get("id");
 75             product.setId(Long.parseLong(id));
 76
 77             //取第二层Map
 78             Map<String, List<String>> map = highlighting.get(id);
 79             //取List集合
 80             List<String> list = map.get("name_ik");
 81
 82             //商品名称
 83             //String name = (String)doc.get("name_ik");
 84             //product.setName(name);
 85             product.setName(list.get(0)); //list.get(0) 中的name是已经设置为高亮的
 86
 87             //图片
 88             String url = (String)doc.get("url");
 89             product.setImgUrl(url);
 90             //价格 这里的价格本身是保存在bbs_sku表中的, 而我们在这里将price属性直接添加到了Product中
 91             //因为我们在做上架的时候, 查询的是bbs_sku中price最小的值 然后保存到solr中的, 所以这里我们就直接将price属性添加到product中了
 92             //这里的价格只有一个值
 93             //Float price = (Float)doc.get("price");
 94             product.setPrice((Float)doc.get("price"));
 95             //品牌ID
 96             //Integer brandId = (Integer)doc.get("brandId");
 97             product.setBrandId(Long.parseLong(String.valueOf((Integer)doc.get("brandId"))));
 98             products.add(product);
 99         }
100
101         Pagination pagination = new Pagination(
102                     productQuery.getPageNo(),
103                     productQuery.getPageSize(),
104                     (int)numFound,
105                     products
106                 );
107         //页面展示
108         String url = "/search";
109         pagination.pageView(url, params.toString());
110
111         return pagination;
112     }

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

 

 

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

时间: 2024-10-08 19:03:17

[项目构建 七]babasport 商品上架及Solr使用实例.的相关文章

[项目构建 八]babasport ActiveMQ的介绍及使用实例.

今天就来说下 这个项目中使用ActiveMQ的情况, MQ: message queue, 顾名思义就是消息队列的意思. 一: 使用场景:  消息队列在大型电子商务类网站,如京东.淘宝.去哪儿等网站有这深入的应用,队列的主要作用是消除高并发访问高峰,加快网站的响应速度.在不使用消息队列的情况下,用户的请求数据直接写入数据库,在高并发的情况下,会对数据库造成巨大的压力,同时也使得系统响应延迟加剧.在使用队列后,用户的请求发给队列后立即返回(当然不能直接给用户提示订单提交成功,京东上提示:您“您提交

[项目构建 九]babasport 页面静态化技术Freemarker技术的介绍及使用实例.

一.FreeMarker简介 1.动态网页和静态网页差异 在进入主题之前我先介绍一下什么是动态网页,动态网页是指跟静态网页相对应的一种网页编程技术.静态网页,随着HTML代码的生成,页面的内容和显示效 果就不会再发生变化(除非你修改页面代码).而动态网页则不然,页面代码虽然没有发生变化,但是显示的内容却是可以随着时间.环境或者数据库操作的结果而 发生相应的变化.简而言之,动态网页是基本的HTML语法规范与java.VB.VC等高级程序设计语言.数据库编程等多种技术的融合,以实现对网站内容 和风格

[项目构建 十一]babasport 购物车的原理及实现.

今天来开始写一下关于购物车的东西, 这里首先抛出四个问题: 1)用户没登陆用户名和密码,添加商品, 关闭浏览器再打开后 不登录用户名和密码 问:购物车商品还在吗? 2)用户登陆了用户名密码,添加商品,关闭浏览器再打开后 不登录用户名和密码 问:购物车商品还在吗? 3)用户登陆了用户名密码,添加商品, 关闭浏览器,然后再打开,登陆用户名和密码  问:购物车商品还在吗? 4)用户登陆了用户名密码,添加商品, 关闭浏览器 外地老家打开浏览器  登陆用户名和密码 问:购物车商品还在吗? 上面四个问题都是

[项目构建 十]babasport 集群下session共享问题的解决方案.

这一篇博客来讲解下babasport这个项目中使用的Login功能, 当然这里说的只是其中的一些简单的部分, 记录在此 方便以后查阅. 一: 去登录页面首先我们登录需要注意的事项是, 当用户点击登录按钮时,转入登录页面时也要记住之前用户是从哪个页面发送请求过来的, 这样登录成功后还能继续跳回到用户之前浏览的那个页面.我们页面展示显示的登录按钮都是集成在一个common的jsp中, 前台每个页面都是引用的这个jsp, 所以需要在这个common的jsp中直接添加点击登录按钮跳转的页面.这里点击登录

[项目构建 六]babasport Mybatis逆向工程构建项目实例.

mybaits需要程序员自己编写sql语句,mybatis官方提供逆向工程 可以针对单表自动生成mybatis执行所需要的代码(mapper.java,mapper.xml.pojo等)有了sql表的结构后, 我们就可以利用逆向工程直接生成相应的Dao和JavaBean代码, 这样能够大大减少我们平时开发的工作量. 但是我还是觉得使用逆向工程局限性很大, 例如我们的逆向工程main方法只能执行一次, 如果再次执行就会继续生成相应的Dao和JavaBean, 除非我们把之前生成的全都删除. 这样对

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

在项目中使用了Redis, 因为在项目中暂时只涉及到使用Redis生成主键, 那么本文就来讲一下Redis安装的方法和Redis生成主键的优点以及和其他几种方式生成主键的对比. 1,Redis安装首先将Redis的tar包拷贝到Linux下的根目录 然后解压到redis文件夹下:(先使用mkdir创建redis文件夹) 接下来就是解压tar包到redis目录下: 解压后的目录结构: 编译: 使用Make命令 安装: 安装好之后的目录:  6379 下的目录结构:(这个rdb文件时: redis

[项目构建 五]babasport ajax图片上传及FastDFS入门案例.

今天来开始写图片上传的功能, 现在的图片上传都讲求 上传完成后立刻回显且页面不刷新, 这里到底是怎么做的呢? 当然是借助于ajax了, 但是ajax又不能提交表单, 这里我们还要借助一个插件: jquery.form.js剩下的一个是FastDFS, 那么什么是FastDFS呢? FastDFS是一个开源的轻量级分布式文件系统,由跟踪服务器(tracker server).存储服务器(storage server)和客户端(client)三个部分组成,主要解决了海量数据存储问题,特别适合以中小文

[项目构建 十三]babasport Nginx负载均衡的详细配置及使用案例详解.

在这里再次说明下, 这个项目是从网上 找到的一套学习资料, 自己在 空闲时间学习了这些东西. 这里面的code当然会有很多不完善的地方, 但是确实也能学到很多新东西.感谢看过这一些列博文和评论的小伙伴, 我把自己所看到的学到的拿到这里来分享是想和大家一起学习进步, 想听听园友给出的意见, 也是对自己学习过程的一个总结. 最后我会将这套资料的所有内容共享出来, 如果有愿意学习的同学可以下载下来使用.PS: 我自认为 这些内容对于刚工作1-2年的同学来说真的很适用. 技术无止境, 我们仍需努力! 1

[项目构建 十五]babasport 项目总结及源码分享.

终于把这个项目自己手动的敲了一遍且总结了其中的知识点, 现在来做一个整体性的总结. 总目录: [项目构建 一]babasport 项目环境搭建. [项目构建 二]babasport SSM 三大框架整合 [项目构建 三]babasport Dubbo的使用及浅析. [项目构建 四]babasport 分页的使用及解析. [项目构建 五]babasport ajax图片上传及FastDFS入门案例. [项目构建 六]babasport Mybatis逆向工程构建项目实例. [项目构建 六]baba