JAVA课程笔记系列: 基于SpringBoot的Data Solr搜索引擎开发

基于SpringBoot的Data Solr搜索引擎开发

关于Apache Solr的简介

Solr它是一种开放源码的、基于 Lucene Java 的搜索服务器,易于加入到 Web 应用程序中。Solr 提供了层面搜索(就是统计)、命中醒目显示并且支持多种输出格式(包括XML/XSLT 和JSON等格式)。它易于安装和配置,而且附带了一个基于HTTP 的管理界面。可以使用 Solr 的表现优异的基本搜索功能,也可以对它进行扩展从而满足企业的需要。Solr的特性包括:

  • 高级的全文搜索功能
  • 专为高通量的网络流量进行的优化
  • 基于开放接口(XML和HTTP)的标准
  • 综合的HTML管理界面
  • 可伸缩性-能够有效地复制到另外一个Solr搜索服务器
  • 使用XML配置达到灵活性和适配性
  • 可扩展的插件体系
  • 支持像英语,德语,中国,日本,法国和许多主要语言

Apache Solr和Lucene的关系

Solr 与Lucene 并不是竞争对立关系,恰恰相反Solr 依存于Lucene ,因为Solr 底层的核心技术是使用Apache Lucene 来实现的,简单的说Solr 是Lucene 的服务器化。需要注意的是Solr 并不是简单的对Lucene 进行封装,它所提供的大部分功能都区别于Lucene。

Apache Solr 相关目录说明

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vWhiwMGT-1578972293816)(1.png)]

Solr程序包的结构说明

  • bin :solr相关运行脚本
  • docs:相关API参考文档和wiki资料等
  • licenses:存放了solr相关证书
  • contrib :solr相关扩展的jar包
  • dist :存放Solr 构建完成的JAR 文件、WAR 文件和Solr 依赖的JAR 文件。
  • example :是一个安装好的Jetty 中间件,其中包括一些样本数据和Solr 的配置信息。
  • example/etc :Jetty 的配置文件。
  • example/multicore :当安装Slor multicore 时,用来放置多个Solr 主目录。
  • example/solr :默认安装时一个Solr 的主目录。
  • example/example-DIH:数据库做索引数据源的示例
  • example/webapps :Solr 的WAR 文件部署在这里。
  • src :Solr 相关源码。
  • src/java :Slor 的Java 源码。
  • src/scripts :一些在大型产品发布时一些有用的Unix bash shell 脚本。
  • src/solrj :Solr 的Java 客户端。
  • src/test :Solr 的测试源码和测试文件。
  • src/webapp :Solr web 管理界面。管理界面的Jsp 文件都放在web/admin/ 下面,可以根据你的需要修改这些文件。

Solr 主目录结构说明

  • bin :建议将集群复制脚本放在这个目录下。
  • conf :放置配置文件。
  • conf/schema.xml :建立索引的schema 包含了字段类型定义和其相关的分析器。
  • conf/solrconfig.xml :这个是Solr 主要的配置文件。
  • conf/xslt :包含了很多xslt 文件,这些文件能将Solr 的XML 的查询结果转换为特定的格式,比如:Atom/RSS。
  • data :放置Lucene 产生的索引数据。
  • lib :放置可选的JAR 文件比如对Slor 扩展的插件,这些JAR 文件将会在Solr 启动时加载。

第一章:搭建Apache Solr开发环境

准备步骤 :Tomcat 8以上、JDK7以上、solr5.5.4版本

  1. 将 solr 压缩包解压,并将solr-5.5.4\solr_webapps下的文件夹webapp,将之复制到Tomcat\webapps\目录下,并且改名为solr(名字自己定义)
  2. 将 solr 压缩包中 solr-5.5.4\server\lib\ext所有jar包 全部复制到 Tomcat\ webapps\solr\WEB-INF\lib目录中
  3. 将 solr 压缩包中 solr-5.5.4\ server\resources \log4j.properties 复制到Tomcat\ webapps\solr\WEB-INF 目录中
  4. 创建一个solr_home 的目录(用户可以根据操作系统决定),并将 solr 压缩包中example下的solr 目录除了bin所有文件复制D:\solr_home目录下,如图所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h3fAidlT-1578972293821)(2.png)]

  1. 打开Tomcat/webapps/solr/WEB-INF下的web.xml,增加如下配置内容(初始状态下该内容是被注释掉的):
<env-entry>
      <env-entry-name>solr/home</env-entry-name>
      <env-entry-value>D:/solr_home</env-entry-value>
      <env-entry-type>java.lang.String</env-entry-type>
</env-entry><env-entry-value>中的内容改成你的solrhome路径,这里是D:/solr_home

这项配置,主要是建立tomcat 与solr之间的关系的,它的作用是让tomcat找到你所配置的solr 目录。
  1. 启动tomcat,从地址栏输入如下网址:http://localhost:8080/solr会出现如下界面:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N0JKGKyh-1578972293824)(3.png)]

第二章:Apache Solr 从MySQL数据库中导入数据

  1. 导入solr自带的数据导入包放到tomcat 中的solr工程的web-inf下lib中
    在collection1的目录中添加lib包,把data-import需要用的包拷贝到lib中
    其中包括mysql包

  2. 在磁盘中的solr_home 打开solrconfig.xml 添加如下代码

    <requestHandler name="/dataimport" class="org.apache.solr.handler.dataimport.DataImportHandler">
        <lst name="defaults">
          <str name="config">data-config.xml</str>
        </lst>
      </requestHandler>
    

  3. 在同级目录下创建一个data-config.xml文件,添加如下内容

    <?xml version="1.0" encoding="UTF-8" ?>
    <dataConfig>
    <dataSource type="JdbcDataSource" driver="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost/mydb" user="root" password="root" />
       <document name="userinfo">
           <entity name="userinfo" query="select id,name,address,birthday,age from userinfo ">
               <field column="ID" name="user_id" />
               <field column="NAME" name="user_name" />
               <field column="ADDRESS" name="user_address" />
               <field column="BIRTHDAY" name="user_birthday" />
               <field column="AGE" name="user_age" />
           </entity>
       </document>
    </dataConfig>
    

    备注说明:

    document:表示搜索引擎的文档

    entity:表示对应的实体类

    query:执行的SQL查询语句

    field:搜索引擎对应的域

    column:数据库对应的列

    name:搜索引擎对应的域名

  4. 在同级目录下schema.xml下配置如下代码,将数据库的字段和域一一对应关系配置好。

<field name="user_id" type="int" indexed="true" stored="true"/>
<field name="user_name" type="string" indexed="true" stored="true"/>
<field name="user_address" type="string" indexed="true" stored="true"/>
<field name="user_birthday" type="date" indexed="true" stored="true"/>
<field name="user_age" type="int" indexed="true" stored="true"/>

第三章:Apache Solr配置中文分词器

1、中文分词器采用的是lucene-analyzers-smartcn来做为Apache Solr的分词器,将该jar包拷贝到tomcat下的webapps-solr

工程中的WEB-INF的lib中。

2、在配置的solr_home目录中打开配置好的collection1下的conf的managed-schema文件添加如下代码

<!-- 添加中文分词器 -->
<dynamicField name="*_txt_cn" type="text_cn" indexed="true" stored="true"/>
<fieldType name="text_cn" class="solr.TextField">
   <analyzer class="org.apache.lucene.analysis.cn.smart.SmartChineseAnalyzer"/>
</fieldType>

启动控制台,从地址栏中输入http://localhost:8080/solr会出现如下界面:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jvRYed8l-1578972293827)(4.png)]

第四章:使用SpringBoot搭建solr开发环境

工程目录结构如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UnXedDLl-1578972293830)(5.png)]

第一步:配置SpringBoot的属性文件

spring.data.solr.host=http://localhost:8081/solr
spring.thymeleaf.cache=false
spring.thymeleaf.encoding=utf-8
spring.thymeleaf.mode=HTML
spring.thymeleaf.suffix=.html

第二步:编写Apache Solr对应的实体类

package com.sudojava.springboot_solr.domain;

import org.apache.solr.client.solrj.beans.Field;

public class Product {

    @Field
    private String id;
    @Field
    private String price;
    @Field
    private String title;
    @Field
    private String pic_url;
    @Field
    private String selling_price;
    @Field
    private String sales_volume;
    @Field
    private String coupon_title;

    @Override
    public String toString() {
        return "Product{" +
                "id='" + id + '\'' +
                ", price='" + price + '\'' +
                ", title='" + title + '\'' +
                ", pic_url='" + pic_url + '\'' +
                ", selling_price='" + selling_price + '\'' +
                ", sales_volume='" + sales_volume + '\'' +
                ", coupon_title='" + coupon_title + '\'' +
                '}';
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getPrice() {
        return price;
    }

    public void setPrice(String price) {
        this.price = price;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getPic_url() {
        return pic_url;
    }

    public void setPic_url(String pic_url) {
        this.pic_url = pic_url;
    }

    public String getSelling_price() {
        return selling_price;
    }

    public void setSelling_price(String selling_price) {
        this.selling_price = selling_price;
    }

    public String getSales_volume() {
        return sales_volume;
    }

    public void setSales_volume(String sales_volume) {
        this.sales_volume = sales_volume;
    }

    public String getCoupon_title() {
        return coupon_title;
    }

    public void setCoupon_title(String coupon_title) {
        this.coupon_title = coupon_title;
    }
}

第三步:编写产品查询列表的Service以及实现类

package com.sudojava.springboot_solr.service;

import com.sudojava.springboot_solr.domain.Product;

import java.util.List;

public interface ProductService {

    public List<Product> searchProductByName(String title);

}
package com.sudojava.springboot_solr.service;

import com.sudojava.springboot_solr.common.StringTrim;
import com.sudojava.springboot_solr.domain.Product;
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.response.QueryResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;

@Service
public class ProductServiceImp implements ProductService {

    @Autowired
    private SolrClient client;

    @Override
    public List<Product> searchProductByName(String title) {
        SolrQuery query = new SolrQuery();
        query.setQuery("title:" + title);
        query.set("df", "title");//设置查询的域
        query.setHighlight(true);
        //设置高亮显示的标签
        query.setHighlightSimplePre("<font color=\"red\">");
        query.setHighlightSimplePost("</font>");
        query.addHighlightField("title");
        query.setHighlightFragsize(150);//高亮的标题长度
        query.setHighlightSnippets(1);//获取高亮分片数,一般搜索词可能分布在文章中的不同位置,其所在一定长度的
        //语句即为一个片段,默认为1,但根据业务需要有时候需要多取出几个分片

        QueryResponse response;
        List<Product> list = new ArrayList<>();
        try {
            response = client.query("collection1", query);

            Map<String, Map<String, List<String>>> highlighting = response.getHighlighting();

            if (response.getStatus() == 0) {
                response.getResults().forEach(new Consumer<SolrDocument>() {
                    @Override
                    public void accept(SolrDocument entries) {
                        Product product = new Product();
                        product.setId(StringTrim.trim(entries.get("id")));
                        product.setCoupon_title(StringTrim.trim(entries.get("coupon_title")));
                        product.setPic_url(StringTrim.trim(entries.get("pic_url")));
                        product.setPrice(StringTrim.trim(entries.get("price")));
                        product.setSales_volume(StringTrim.trim(entries.get("sales_volume")));
                        product.setSelling_price(StringTrim.trim(entries.get("selling_price")));
                        Map<String, List<String>> map = highlighting.get(entries.get("id"));
                        List<String> result = map.get("title");
                        if (result != null && result.size() > 0) {
                            product.setTitle(StringTrim.trim(result.get(0)));
                        } else {
                            product.setTitle(StringTrim.trim(entries.get("title")));
                        }

                        list.add(product);
                    }
                });
            }
        } catch (SolrServerException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return list;
    }
}

第四步:编写产品检索的Controller类以及Index初始化页面、工具类

package com.sudojava.springboot_solr.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class IndexController {

    @RequestMapping(value = "/",method = RequestMethod.GET)
    public String index(){
        return "/index";
    }
}
package com.sudojava.springboot_solr.controller;

import com.sudojava.springboot_solr.domain.Product;
import com.sudojava.springboot_solr.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import java.util.List;

@Controller
public class ProductSearchController {

    @Autowired
    private ProductService service;

    @RequestMapping(value = "/search", method = RequestMethod.POST)
    public String searchProduct(String title, Model model) {
        System.out.println("---title-->>"+title);
        List<Product> list = service.searchProductByName(title);
        System.out.println("----->>" + list);
        model.addAttribute("list", list);
        return "/index";
    }

}
package com.sudojava.springboot_solr.common;

public class StringTrim {

    public static String trim(Object str) {
        if (null == str) {
            str = "";
        }
        return str.toString();
    }
}

第五步:编写查询的界面,采用Thymeleaf模板引擎显示数据

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Solr查询产品界面</title>

    <meta charset="utf-8"/>
    <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
    <meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no"/>
    <!--引入CSS样式-->
    <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/>
    <style>
        .mainCSS {
            margin: 0 auto;
            width: 1050px;
        }

        * {
            padding: 0;
            margin: 5px;
            list-style: none;
        }

        html, body {
            width: 100%;
        }

        #wrap {
            width: 1050px;
            margin: 0 auto;
        }

        #wrap ul {
            width: 100%;
            background-color: lightgray;
            box-sizing: border-box;
        }

        #wrap li {
            width: 200px;
            float: left;
            border: 1px solid #000;
            box-sizing: border-box;
        }

        #wrap li img {
            width: 95%;
        }

    </style>
</head>
<body>
<div class="mainCSS">
    <div class="panel panel-primary">
        <div class="panel-heading">
            <h3 class="panel-title">Solr查询产品界面</h3>
        </div>
        <div class="panel-body">
            <form class="form-inline" method="post" action="/search" role="form">
                <div class="form-group">
                    <label class="sr-only" for="name"></label>
                    <input type="text"
                           class="form-control" size="120" name="title" id="name"
                           placeholder="请输入搜索内容"/>
                </div>
                <button type="submit" class="btn btn-default">&nbsp;&nbsp;&nbsp;&nbsp;</button>
            </form>
        </div>
    </div>
</div>

<div id="wrap">
    <ul th:each="pro:${list}">

        <li>
            <img th:src="${pro.pic_url}" alt=""/>
            <h5></h5>
            <p>
                <strong>介绍:</strong><span th:utext="${pro.title}"><span/>
            </p>
            <p style="text-decoration: line-through;color: red;">
                <strong>原价:</strong><span th:text="${pro.price}"></span>
            </p>
            <p><strong>售价:</strong><span th:text="${pro.selling_price}"></span>
            </p>
            <p><strong>销量:</strong><span th:text="${pro.sales_volume}"></span>
            </p>
        </li>

    </ul>
</div>
</body>
</html>

第五章:使用SolrClient对Solr的索引库进行添加、删除、和修改操作

本章节主要是讲解使用MockMVC集成单元测试对Solr的索引库进行单元测试。

测试步骤如下:

第一步:定义对Solr的操作接口以及实现类

package com.sudojava.springboot_solr.service;

import com.sudojava.springboot_solr.domain.Product;

import java.util.List;

public interface ProductService {

    public List<Product> searchProductByName(String title);


    public int addProduct(Product product);


    public int deleteProduct(String id);

}
package com.sudojava.springboot_solr.service;

import com.sudojava.springboot_solr.common.StringTrim;
import com.sudojava.springboot_solr.domain.Product;
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.response.QueryResponse;
import org.apache.solr.client.solrj.response.UpdateResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.common.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;

@Service
public class ProductServiceImp implements ProductService {

    @Autowired
    private SolrClient client;


    @Override
    public int addProduct(Product product) {
        //第一种添加索引方式
        SolrInputDocument document = new SolrInputDocument();
        document.addField("id", product.getId());
        document.addField("coupon_title", product.getCoupon_title());
        document.addField("pic_url", product.getPic_url());
        document.addField("price", product.getPrice());
        document.addField("sales_volume", product.getSales_volume());
        document.addField("selling_price", product.getSelling_price());
        UpdateResponse response = null;
        try {
            response = client.add("collection1",document);
            if (response.getStatus()==0) {
                client.commit("collection1");
            }
        } catch (SolrServerException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return response.getStatus();
    }


    @Override
    public int deleteProduct(String id) {
        UpdateResponse response = null;
        try {
            response = client.deleteById("collection1",id);
            if (response.getStatus()==0) {
                client.commit("collection1");
            }
        } catch (SolrServerException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return response.getStatus();
    }

    @Override
    public List<Product> searchProductByName(String title) {
        SolrQuery query = new SolrQuery();
        query.setQuery("title:" + title);
        query.set("df", "title");//设置查询的域
        query.setHighlight(true);

        //设置高亮显示的标签
        query.setHighlightSimplePre("<font color=\"red\">");
        query.setHighlightSimplePost("</font>");
        query.addHighlightField("title");
        query.setHighlightFragsize(150);//高亮的标题长度
        query.setHighlightSnippets(1);//获取高亮分片数,一般搜索词可能分布在文章中的不同位置,其所在一定长度的
        //语句即为一个片段,默认为1,但根据业务需要有时候需要多取出几个分片

        QueryResponse response;
        List<Product> list = new ArrayList<>();
        try {
            response = client.query("collection1", query);

            Map<String, Map<String, List<String>>> highlighting = response.getHighlighting();

            if (response.getStatus() == 0) {
                response.getResults().forEach(new Consumer<SolrDocument>() {
                    @Override
                    public void accept(SolrDocument entries) {
                        Product product = new Product();
                        product.setId(StringTrim.trim(entries.get("id")));
                        product.setCoupon_title(StringTrim.trim(entries.get("coupon_title")));
                        product.setPic_url(StringTrim.trim(entries.get("pic_url")));
                        product.setPrice(StringTrim.trim(entries.get("price")));
                        product.setSales_volume(StringTrim.trim(entries.get("sales_volume")));
                        product.setSelling_price(StringTrim.trim(entries.get("selling_price")));
                        Map<String, List<String>> map = highlighting.get(entries.get("id"));
                        List<String> result = map.get("title");
                        if (result != null && result.size() > 0) {
                            product.setTitle(StringTrim.trim(result.get(0)));
                        } else {
                            product.setTitle(StringTrim.trim(entries.get("title")));
                        }

                        list.add(product);
                    }
                });
            }
        } catch (SolrServerException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return list;
    }
}

Solr同时也支持对索引的实体类进行插入操作

 @Override
    public int addProduct(Product product) {
        //第一种添加索引方式
//        SolrInputDocument document = new SolrInputDocument();
//        document.addField("id", product.getId());
//        document.addField("coupon_title", product.getCoupon_title());
//        document.addField("pic_url", product.getPic_url());
//        document.addField("price", product.getPrice());
//        document.addField("sales_volume", product.getSales_volume());
//        document.addField("selling_price", product.getSelling_price());
        UpdateResponse response = null;
        try {
            response = client.addBean("collection1",product);
            if (response.getStatus()==0) {
                client.commit("collection1");
            }
        } catch (SolrServerException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return response.getStatus();
    }

第三步:创建添加、删除的Controller控制器

package com.sudojava.springboot_solr.controller;

import com.sudojava.springboot_solr.domain.Product;
import com.sudojava.springboot_solr.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import java.util.List;

@Controller
public class ProductSearchController {

    @Autowired
    private ProductService service;

    @RequestMapping(value = "/search", method = RequestMethod.POST)
    public ModelAndView searchProduct(String title) {
        System.out.println("---title-->>" + title);
        ModelAndView modelAndView = new ModelAndView();
        List<Product> list = service.searchProductByName(title);
        modelAndView.addObject("list", list);
        modelAndView.setViewName("/index");
        return modelAndView;
    }

    @RequestMapping(value = "/add", method = RequestMethod.POST)
    public String addProduct(Product product, Model model) {
        int flag = service.addProduct(product);
        System.out.println("-------->>"+flag);
        model.addAttribute("flag", "addProduct is success!!!" + flag);
        return "/index";
    }

    @RequestMapping(value = "/delete", method = RequestMethod.POST)
    public String deleteProduct(String  id, Model model) {
        int flag = service.deleteProduct(id);
        System.out.println("-------->>"+flag);
        model.addAttribute("flag", "deleteProduct is success!!!" + flag);
        return "/index";
    }


}

第四步:创建单元测试类进行测试操作

package com.sudojava.springboot_solr;

import com.sudojava.springboot_solr.common.StringTrim;
import com.sudojava.springboot_solr.domain.Product;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Bean;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.context.WebApplicationContext;

import java.io.IOException;

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@SpringBootTest
public class SpringbootSolrApplicationTests {

    private MockMvc mockMvc;

    @Autowired
    private WebApplicationContext context;

    @Before
    public void setup() {
        mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
    }


    @Test
    public void searchProduct() throws Exception{
        mockMvc.perform(MockMvcRequestBuilders.post("/search")
        .param("title","女装")
        )
                .andDo(MockMvcResultHandlers.print());
    }

    @Test
    public void deleteProduct() throws Exception{
        mockMvc.perform(MockMvcRequestBuilders.post("/delete")
                .param("id","10010234")
        )
                .andDo(MockMvcResultHandlers.print());
    }


    @Test
    public void add() throws Exception {

        Product product = new Product();
        product.setId("10010234");
        product.setTitle("衣服打折销售了");
        product.setSelling_price("1000");
        product.setSales_volume("200");
        product.setPrice("100");
        product.setCoupon_title("很好了www");
        product.setPic_url("http://img1.tbcdn.cn/tfscom/i1/TB1qBvJOXXXXXcwapXXXXXXXXXX_!!0-item_pic.jpg_450x10000.jpg");

//        LinkedMultiValueMap<String, String> map = new LinkedMultiValueMap<>();
//        map.add("id", product.getId());
//        map.add("coupon_title", product.getCoupon_title());
//        map.add("pic_url", product.getPic_url());
//        map.add("price", product.getPrice());
//        map.add("sales_volume", product.getSales_volume());
//        map.add("selling_price", product.getSelling_price());

        mockMvc.perform(MockMvcRequestBuilders.post("/add").
                param("id", product.getId()).
                param("coupon_title", product.getCoupon_title()).
                param("pic_url", product.getPic_url()).
                param("price", product.getPrice()).
                param("sales_volume", product.getSales_volume()).
                param("selling_price", product.getSelling_price())
        )
                .andDo(MockMvcResultHandlers.print());
    }

}

第六章:基于SpringBoot JPA 的Solr 数据查询

本章节主要是介绍SpringBoot 关于Solr查询的JPA规范。Spring家族提供的spring-data适用于关系型数据库和nosql数据库

例如 Spring Data JPA, Spring Data Hadoop, Spring Data MongoDB ,Spring Data Solr 等。

他们的共同特点是给我们提供了框架代码,spring Data能自动创建实体dao的实现类和自定义查询,不用我们去定义了,这样简化了对dao层的操作。

值得注意的是如果使用Spring Data Solr操作的话,必须要在Solr对应的实体类中添加一个标签


import org.apache.solr.client.solrj.beans.Field;
import org.springframework.data.solr.core.mapping.SolrDocument;

@SolrDocument(solrCoreName = "collection1")
public class Product {
  .......省略代码....
}

第一步:声明一个接口继承SolrCrudRepository接口

package com.sudojava.springboot_solr.repository;

import com.sudojava.springboot_solr.domain.Product;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.solr.repository.SolrCrudRepository;

public interface ProductRepository extends SolrCrudRepository<Product,String> {
    Page<Product> findByTitle(String title, Pageable pageable);
}

第二步:分别声明对应的JPA Service、ServiceImp、以及Controller类

package com.sudojava.springboot_solr.jpa;

import com.sudojava.springboot_solr.domain.Product;
import org.springframework.data.domain.Page;

public interface ProductJPAService {

    Page<Product> findByTitle(String title);


    public void addProduct(Product product);

    public void deleteProductByID(String id);
}
package com.sudojava.springboot_solr.jpa;

import com.sudojava.springboot_solr.domain.Product;
import com.sudojava.springboot_solr.repository.ProductRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;

@Service
public class ProductJPAServiceImp implements ProductJPAService {

    @Autowired
    private ProductRepository repository;

    @Override
    public Page<Product> findByTitle(String title) {

        return repository.findByTitle(title, PageRequest.of(1,6));
    }

    @Override
    public void addProduct(Product product) {
        repository.save(product);
    }

    @Override
    public void deleteProductByID(String id) {
        repository.deleteById(id);
    }
}
package com.sudojava.springboot_solr.jpa;

import com.sudojava.springboot_solr.domain.Product;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class ProductJPASearchController {


    @Autowired
    private ProductJPAService service;

  //做分页处理
    @RequestMapping(value = "/jpa/search", method = RequestMethod.POST)
    public String search(String title, Model model) {
        Page<Product> page = service.findByTitle(title);
        model.addAttribute("products", page.getContent());
        model.addAttribute("page", page);
        return "/index";
    }


    @RequestMapping(value = "/jpa/add", method = RequestMethod.POST)
    public String add(Product product) {
        service.addProduct(product);
        return "/index";
    }


    @RequestMapping(value = "/jpa/delete", method = RequestMethod.POST)
    public String delete(String id) {
        service.deleteProductByID(id);
        return "/index";
    }

}

第四步:声明单元测试类

package com.sudojava.springboot_solr;

import com.sudojava.springboot_solr.common.StringTrim;
import com.sudojava.springboot_solr.domain.Product;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Bean;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.context.WebApplicationContext;

import java.io.IOException;

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@SpringBootTest
public class SpringbootSolrApplicationTests {

    private MockMvc mockMvc;

    @Autowired
    private WebApplicationContext context;

    @Before
    public void setup() {
        mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
    }


    @Test
    public void searchProduct() throws Exception{
        mockMvc.perform(MockMvcRequestBuilders.post("/jpa/search")
        .param("title","女装")
        )
                .andDo(MockMvcResultHandlers.print());
    }

    @Test
    public void deleteProduct() throws Exception{
        mockMvc.perform(MockMvcRequestBuilders.post("/delete")
                .param("id","10010234")
        )
                .andDo(MockMvcResultHandlers.print());
    }


    @Test
    public void add() throws Exception {

        Product product = new Product();
        product.setId("10010234");
        product.setTitle("衣服打折销售了");
        product.setSelling_price("1000");
        product.setSales_volume("200");
        product.setPrice("100");
        product.setCoupon_title("很好了www");
        product.setPic_url("http://img1.tbcdn.cn/tfscom/i1/TB1qBvJOXXXXXcwapXXXXXXXXXX_!!0-item_pic.jpg_450x10000.jpg");

//        LinkedMultiValueMap<String, String> map = new LinkedMultiValueMap<>();
//        map.add("id", product.getId());
//        map.add("coupon_title", product.getCoupon_title());
//        map.add("pic_url", product.getPic_url());
//        map.add("price", product.getPrice());
//        map.add("sales_volume", product.getSales_volume());
//        map.add("selling_price", product.getSelling_price());

        mockMvc.perform(MockMvcRequestBuilders.post("/jpa/add").
                param("id", product.getId()).
                param("coupon_title", product.getCoupon_title()).
                param("pic_url", product.getPic_url()).
                param("price", product.getPrice()).
                param("sales_volume", product.getSales_volume()).
                param("selling_price", product.getSelling_price())
        )
                .andDo(MockMvcResultHandlers.print());
    }

}
发布了219 篇原创文章 · 获赞 201 · 访问量 39万+

猜你喜欢

转载自blog.csdn.net/qianfeng_dashuju/article/details/103970133