• solr_架构案例【京东站内搜索】(附程序源代码)


    注意事项:首先要保证部署solr服务的Tomcat容器和检索solr服务中数据的Tomcat容器,它们的端口号不能发生冲突,否则web程序是不可能运行起来的。

    一:solr服务的端口号、我这里的solr服务的tomcat容器的端口号已经修改为8083:

    二:检索solr服务中数据的tomcat容器的端口号、我这里是8080:

     

    最后必须要保证2个容器能正常访问。

    需求使用Solr实现电商网站中商品信息搜索功能,可以根据关键字搜索商品信息,根据商品分类、价格过滤搜索结果,也可以根据价格进行排序,实现分页。

    界面如下:

    1、架构分析:

    自己开发的应用:

    Controller层的作用:获取搜索条件,并响应搜索结果到前台页面。

    Service层的作用:接收Controller传递过来的参数,根据参数拼装一个查询条件,调用dao层方法,查询商品数据;接收返回的商品列表和商品的总数量,根据每页显示的商品数量计算总页数。

    Dao层的作用:接收Service层传递过来的参数,根据参数去检索solr索引库中的商品数据,返回查询结果。

    2、WEB工程的搭建(相关的jar必须得全部引入,环境搭建篇中已经注明了):

    需要说明的几点问题:

    (a)、在springmvc核心配置文件中配置solr服务时,一定将solr服务的连接地址配置正确,否则无法找到solr索引库:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" xmlns:mvc="http://www.springframework.org/schema/mvc"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
            http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
            http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
    
        <!-- 配置注解扫描-->
        <context:component-scan base-package="com.jd"/>
        
        <!-- 配置注解驱动: 就相当于自动替我们配置注解形式的处理器映射器和处理器适配器 -->
        <mvc:annotation-driven/>
        
        <!-- 配置视图解析器 -->
        <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
            <property name="prefix" value="/WEB-INF/jsp/"></property>
            <property name="suffix" value=".jsp"></property>
        </bean>
        
        <!-- 配置solrServer服务,供数据访问层检索数据使用: -->
        <bean id="solrServer" class="org.apache.solr.client.solrj.impl.HttpSolrServer">
            <!-- 配置构造方法 -->
            <constructor-arg value="http://localhost:8083/solr/collection1"/>
        </bean>
    </beans>

    (b)、在项目的web.xml配置文件中配置springmvc的前端控制器、post请求的乱码解决等问题:

      <!-- springMvc前端控制器 -->
        <servlet>
            <servlet-name>springmvc</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <init-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>classpath:SpringMvc.xml</param-value>
            </init-param>
            <load-on-startup>1</load-on-startup>
        </servlet>
        <servlet-mapping>
            <servlet-name>springmvc</servlet-name>
            <url-pattern>*.action</url-pattern>
        </servlet-mapping>
    
        <!-- 解决post乱码 -->
        <filter>
            <filter-name>CharacterEncodingFilter</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>CharacterEncodingFilter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>

    3、各个开发层的代码实现,程序中基本附带注释:

    【Dao层】

     1 package com.jd.dao;
     2 
     3 import org.apache.solr.client.solrj.SolrQuery;
     4 
     5 import com.jd.pojo.ResultModel;
     6 
     7 /**
     8  * 商品模块Dao接口:
     9  * @author zxz
    10  *
    11  */
    12 
    13 public interface ProductDao {
    14     
    15     /**
    16      * 根据检索条件检索solr服务上索引库中的数据:
    17      * @param solrQuery
    18      * @return
    19      * @throws Exception
    20      */
    21     public ResultModel search(SolrQuery solrQuery) throws Exception;
    22 
    23 }
     1 package com.jd.dao;
     2 
     3 import java.util.ArrayList;
     4 import java.util.List;
     5 import org.apache.solr.client.solrj.SolrQuery;
     6 import org.apache.solr.client.solrj.SolrServer;
     7 import org.apache.solr.client.solrj.response.QueryResponse;
     8 import org.apache.solr.common.SolrDocument;
     9 import org.apache.solr.common.SolrDocumentList;
    10 import org.springframework.beans.factory.annotation.Autowired;
    11 import org.springframework.stereotype.Repository;
    12 import com.jd.pojo.ProductModel;
    13 import com.jd.pojo.ResultModel;
    14 
    15 /**
    16  * 商品模块Dao层开发:
    17  * 核心功能:接收Service层传递过来的参数,根据参数去检索solr索引库中的商品数据,返回查询结果
    18  * @author zxz
    19  *
    20  */
    21 @Repository
    22 public class ProductDaoImpl implements ProductDao {
    23     
    24     //注入solr服务(该solr服务在springmvc的核心配置文件中已经进行配置了):
    25     @Autowired
    26     private SolrServer solrServer;
    27 
    28     //检索solr服务上索引库中的数据:
    29     @Override
    30     public ResultModel search(SolrQuery solrQuery) throws Exception {
    31         //1、查询并获取响应结果:
    32         QueryResponse response = solrServer.query(solrQuery);
    33         
    34         //2、从响应中获取结果集:
    35         SolrDocumentList results = response.getResults();
    36         
    37         //3、处理结果集:
    38         //专门用于存放响应结果集中的个个商品数据的集合
    39         List<ProductModel> productList = new ArrayList<ProductModel>();
    40         //用于将检索到的并处理好的数据封装到ResultModel对象中,用于返回给Service层:
    41         ResultModel resultModel = new ResultModel();
    42         //做非空校验,如果检索到的结果集不为空的话,就进行处理并封装结果数据:
    43         if(results != null){
    44             //(1)、封装查询到的商品总数:
    45             resultModel.setRecordCount(results.getNumFound());
    46             
    47             //(2)、遍历响应中的结果集,并将数据一一封装进ProductModel对象中:
    48             for (SolrDocument document : results) {
    49                 //创建ProductModel对象:
    50                 ProductModel product = new ProductModel();
    51                 //商品id:
    52                 product.setPid(String.valueOf(document.get("id")));
    53                 //商品名称:
    54                 product.setName(String.valueOf(document.get("product_name")));
    55                 //商品价格:
    56                 if(String.valueOf(document.get("product_price"))!=null &&
    57                         !"".equals(String.valueOf(document.get("product_price")))){
    58                     product.setPrice(Float.valueOf(String.valueOf(document.get("product_price"))));
    59                 }
    60                 //商品图片:
    61                 product.setPicture(String.valueOf(document.get("product_picture")));
    62                 
    63                 //将当前遍历并封装好的ProductModel对象添加到存放商品数据的集合中:
    64                 productList.add(product);
    65             }
    66             
    67             //循环处理并封装好结果集之后,将存放商品数据的集合设置到ResultModel对象中:
    68             resultModel.setProductList(productList);
    69         }
    70         
    71         //将封装好的数据返回给Service层处理:
    72         return resultModel;
    73     }
    74 }

    【Service层】

     1 package com.jd.service;
     2 
     3 import com.jd.pojo.ResultModel;
     4 
     5 /**
     6  * 商品模块Service层接口:
     7  * @author zxz
     8  *
     9  */
    10 
    11 public interface ProductService {
    12     
    13     /**
    14      * 根据各种检索条件去调用dao层的方法,得到符合检索条件的数据:
    15      * @param queryString
    16      * @param catalog_name
    17      * @param price
    18      * @param page
    19      * @param sort
    20      * @return
    21      * @throws Exception
    22      */
    23     public ResultModel search(String queryString, String catalog_name, 
    24             String price, Integer page, String sort) throws Exception;
    25 
    26 }
     1 package com.jd.service;
     2 
     3 import org.apache.solr.client.solrj.SolrQuery;
     4 import org.apache.solr.client.solrj.SolrQuery.ORDER;
     5 import org.springframework.beans.factory.annotation.Autowired;
     6 import org.springframework.stereotype.Service;
     7 import com.jd.dao.ProductDao;
     8 import com.jd.pojo.ResultModel;
     9 
    10 /**
    11  * 商品模块Service层开发:
    12  * 核心功能:接收Controller传递过来的参数,根据参数拼装一个查询条件,调用dao层方法,查询商品数据。
    13  *              接收返回的商品列表和商品的总数量,根据每页显示的商品数量计算总页数。
    14  * @author zxz
    15  *
    16  */
    17 @Service
    18 public class ProductServiceImpl implements ProductService {
    19     
    20     //注入Dao:
    21     @Autowired
    22     private ProductDao productDao;
    23     
    24     //定义常量,代表每页显示的商品条数:
    25     private final static Integer PAGE_SIZE = 60;
    26 
    27     //根据检索条件得到数据:
    28     @Override
    29     public ResultModel search(String queryString, String catalog_name, String price, Integer page, String sort)
    30             throws Exception {
    31         //1、封装查询条件对象,因为需要调用dao层的方法,dao层的检索方法就需要一个solr服务的查询条件对象:
    32         SolrQuery solrQuery = new SolrQuery();
    33         
    34         //2、设置默认查询的域(该默认的域已经在solrHome/collection1/conf/schema.xml配置文件中配置了业务域):
    35         solrQuery.setQuery("product_keywords");
    36         
    37         //3、设置查询的关键字:
    38         if(queryString!=null && !"".equals(queryString)){
    39             solrQuery.setQuery(queryString);
    40         }else{
    41             //如果没有查询的关键字,则默认查询所有商品数据:
    42             solrQuery.setQuery("*:*");
    43         }
    44         
    45         //4、根据商品分类进行过滤:
    46         if(catalog_name!=null && !"".equals(catalog_name)){
    47             //注意查询语法:不要忽略":"号
    48             solrQuery.addFilterQuery("product_catalog_name:" + catalog_name);
    49         }
    50         
    51         //5、根据商品价格进行过滤:
    52         if(price!=null && !"".equals(price)){
    53             //因为传递过来的的商品价格的格式为:100-300,所以需要切割并根据价格区间过滤商品数据:
    54             String[] split = price.split("-");
    55             if(split!=null && split.length>1){
    56                 //为什么判断长度必须大于1,因为根据价格过滤需要最小值和最大值,必须有俩个值才能过滤成功
    57                 solrQuery.addFilterQuery("product_price:["+split[0]+" TO "+split[1]+"]");
    58             }
    59         }
    60         
    61         //6、按照商品价格排序展示商品数据:
    62         if("1".equals(sort)){
    63             solrQuery.setSort("product_price",ORDER.asc);
    64         }else{
    65             solrQuery.setSort("product_price",ORDER.desc);
    66         }
    67         
    68         //7、分页查询商品数据:
    69         //首先校验数据合法性,如果当前页的值为空或小于1,则默认开始查询第一页数据:
    70         if(page == null){
    71             page = 1;
    72         }
    73         if(page < 1){
    74             page = 1;
    75         }
    76         //计算起始索引:
    77         Integer startIndex = (page-1) * PAGE_SIZE;
    78         //设置起始索引:
    79         solrQuery.setStart(startIndex);
    80         //设置每页显示的商品记录数:
    81         solrQuery.setRows(PAGE_SIZE);
    82         
    83         //8、根据封装后的SolrQuery查询对象查询商品数据:
    84         ResultModel resultModel = productDao.search(solrQuery);
    85         //设置当前页数:
    86         resultModel.setCurPage(page);
    87         //计算总页数:
    88         Long pageCount = (long) Math.ceil((resultModel.getRecordCount()*1.0) / PAGE_SIZE);
    89         //设置总页数:
    90         resultModel.setPageCount(pageCount);
    91         
    92         return resultModel;
    93     }
    94 }

    【Controller层】

     1 package com.jd.controller;
     2 
     3 import org.springframework.beans.factory.annotation.Autowired;
     4 import org.springframework.stereotype.Controller;
     5 import org.springframework.ui.Model;
     6 import org.springframework.web.bind.annotation.RequestMapping;
     7 import com.jd.pojo.ResultModel;
     8 import com.jd.service.ProductService;
     9 
    10 /**
    11  * 商品模块:
    12  * @author zxz
    13  *
    14  */
    15 
    16 @Controller
    17 public class ProductController {
    18     
    19     //注入Service接口:
    20     @Autowired
    21     private ProductService productService;
    22     
    23     @RequestMapping("/list")
    24     //根据条件和分页信息检索商品数据:
    25     public String proList(String queryString, String catalog_name, 
    26             String price, Integer page, String sort,Model model) throws Exception{
    27         
    28         //调用service层的方法得到检索后的数据:
    29         ResultModel resultModel = productService.search(queryString, catalog_name, price, page, sort);
    30         
    31         //将检索得到的数据返回给页面:
    32         model.addAttribute("result", resultModel);   //注意:这里的名称必须和jsp页面上获取数据的名称保持一致
    33         
    34         //回显查询条件:
    35         model.addAttribute("queryString", queryString);      //这里的条件回显时,名称也必须和jsp页面上获取数据的名称保持一致
    36         model.addAttribute("catalog_name", catalog_name);
    37         model.addAttribute("price", price);
    38         model.addAttribute("sort", sort);
    39         
    40         return "product_list";
    41     }
    42 }

    最后pojo类的数据模型截个图给大家分享一下(案例所需的基本程序都在这里了,希望能帮到大家,如果有什么不对的地方望各位指教!!!):

  • 相关阅读:
    在指定文件夹目录下打开jupyter notebook
    防止sql注入
    惰性函数——适合外层函数只需要执行一次
    Text类型
    怎样理解阻塞非阻塞与同步异步的区别?
    Element类型
    避免使用eval()
    javascript 连等赋值问题
    类数组转化为数组
    DOM10-1节点层次
  • 原文地址:https://www.cnblogs.com/1315925303zxz/p/6254016.html
Copyright © 2020-2023  润新知