冰恋 发表于 2017-12-20 14:39:07

商城项目(八)

搜索系统搭建
  搜索功能需要发布服务共pc端、移动端使用。根据关键词搜索,得到json格式的搜索结果。
  
创建一个搜索系统,发布搜索服务。

系统架构
http://i2.muimg.com/1949/a3149f60f2737e92.png

创建搜索系统
  参考taotao-rest创建。

框架整合

Solr服务的搭建

CentOS单机版安装


[*]第一步:安装jdk、安装tomcat
[*]第二步:解压solr压缩包。
[*]第三步:把dist/solr-4.10.3.war部署到tomcat下。
[*]  第四步:解压缩war包。启动tomcat解压。
  

tail -f logs/catalina.out 看日志
[*]第五步:需要把/root/solr-4.10.3/example/lib/ext目录下的所有的jar包添加到solr工程中。
[*]第六步:创建solrhome。把/root/solr-4.10.3/example/solr文件夹复制一份作为solrhome。
[*]  第七步:告诉solr服务solrhome的位置。需要修改web.xml

  

<env-entry>  <env-entry-name>solr/home</env-entry-name>
  <env-entry-value>/usr/local/solr/solrhome</env-entry-value>
  <env-entry-type>java.lang.String</env-entry-type>
  
</env-entry>
  

  


[*]第八步:启动tomcat。
  

./startup.sh  

http://i2.muimg.com/1949/3d606fe30312a736.png

配置中文分析器、自定义业务域
  分析器使用IKAnalyzer。
  
使用方法:


[*]第一步:把IKAnalyzer依赖的jar包添加到solr工程中。把分析器使用的扩展词典添加到classpath中。
  

cp .jar /usr/local/solr/tomcat/webapps/solr/WEB-INF/lib  

cp ext_stopword.dic IKAnalyzer.cfg.xml mydict.dic /usr/local/solr/tomcat/webapps/solr/WEB-INF/classes  


[*]
[*]第二步:需要自定义一个FieldType。/usr/local/solr/solrhome/collection1/conf/Schema.xml中定义。可以在FieldType中指定中文分析器。
  

<fieldType name="text_ik">  <analyzer/>
  
</fieldType>
  

  


[*]第三步:自定义域。指定域的类型为自定义的FieldType。
  Sql语句:
  

SELECT  a.id,
  a.title,
  a.sell_point,
  a.price,
  a.image,
  b.`name` category_name,
  c.item_desc
  
FROM
  tb_item a
  
LEFT JOIN tb_item_cat b ON a.cid = b.id
  
LEFT JOIN tb_item_desc c ON a.id = c.item_id
  
WHERE
  a.`status` = 1
  

  加入/usr/local/solr/solrhome/collection1/conf/Schema.xml中
  

<field name="item_title" type="text_ik" indexed="true" stored="true"/>  
<field name="item_sell_point" type="text_ik" indexed="true" stored="true"/>
  
<field name="item_price"type="long" indexed="true" stored="true"/>
  
<field name="item_image" type="string" indexed="false" stored="true" />
  
<field name="item_category_name" type="string" indexed="true" stored="true" />
  
<field name="item_desc" type="text_ik" indexed="true" stored="false" />
  

  
<field name="item_keywords" type="text_ik" indexed="true" stored="false" multiValued="true"/>
  
<copyField source="item_title" dest="item_keywords"/>
  
<copyField source="item_sell_point" dest="item_keywords"/>
  
<copyField source="item_category_name" dest="item_keywords"/>
  
<copyField source="item_desc" dest="item_keywords"/>
  

  


[*]第四步:重新启动tomcat
索引库中导入数据
  dataimport插件

Solrj的使用
  测试类
  

public>
  @Test
  public void testSolrJ() throws Exception {
  // 创建连接
  SolrServer solrServer = new HttpSolrServer("http://192.168.204.132:8080/solr");
  // 创建一个文档对象
  SolrInputDocument document = new SolrInputDocument();
  document.addField("id", "solrtest01");
  document.addField("item_title", "测试商品");
  document.addField("item_sell_point", "卖点");
  // 添加到索引库
  solrServer.add(document);
  // 提交
  solrServer.commit();
  }
  

  @Test
  public void testQuery() throws Exception {
  // 创建连接
  SolrServer solrServer = new HttpSolrServer("http://192.168.204.132:8080/solr");
  // 创建一个查询对象
  SolrQuery solrQuery = new SolrQuery();
  solrQuery.setQuery("*:*");
  // 执行查询
  QueryResponse queryResponse = solrServer.query(solrQuery);
  // 取查询结果
  SolrDocumentList solrDocumentList = queryResponse.getResults();
  for (SolrDocument solrDocument : solrDocumentList) {
  System.out.println(solrDocument.get("id"));
  System.out.println(solrDocument.get("item_title"));
  System.out.println(solrDocument.get("item_sell_point"));
  }
  }
  
}
  

导入数据

清除原来的数据
http://i4.buimg.com/1949/a07ec85ed55c9a55.png

分析
  从数据库中根据sql语句查询数据,遍历数据创建文档对象,把文档对象写入索引库。

Dao层
  Sql语句:
  

SELECT  a.id,
  a.title,
  a.sell_point,
  a.price,
  a.image,
  b.`name` category_name,
  c.item_desc
  
FROM
  tb_item a
  
LEFT JOIN tb_item_cat b ON a.cid = b.id
  
LEFT JOIN tb_item_desc c ON a.id = c.item_id
  
WHERE
  a.`status` = 1
  

  创建一个Mapper文件
  

public interface ItemMapper {  

  List<SearchItem> getItemList();
  
}
  

  

<mapper namespace="com.taotao.search.mapper.ItemMapper" >  <select resultType="com.taotao.search.pojo.SearchItem">
  SELECT
  a.id,
  a.title,
  a.sell_point,
  a.price,
  a.image,
  b.`name` category_name,
  c.item_desc
  FROM
  tb_item a
  LEFT JOIN tb_item_cat b ON a.cid = b.id
  LEFT JOIN tb_item_desc c ON a.id = c.item_id
  WHERE
  a.`status` = 1
  </select>
  
</mapper>
  

<bean>  <property name="basePackage" value="com.taotao.mapper, com.taotao.search.mapper" />
  
</bean>
  

Service层
  取商品列表,遍历列表,创建文档对象,把文档对象写入索引库。
  
要操作索引库需要SolrServer对象,可以把SolrServer放到spring容器中,注入到Service。
  

<!--单机版solr客户端-->  
<bean>
  <constructor-arg name="baseURL" value="http://192.168.204.132:8080/solr"></constructor-arg>
  
</bean>
  

@Service
  
public>  

  @Autowired
  private SolrServer solrServer;
  @Autowired
  private ItemMapper itemMapper;
  

  @Override
  public TaotaoResult importItems() throws Exception {
  // 查询数据库获取商品列表
  List<SearchItem> searchItems = itemMapper.getItemList();
  // 遍历列表
  for (SearchItem item : searchItems) {
  // 创建文档对象
  SolrInputDocument document = new SolrInputDocument();
  document.addField("id", item.getId());
  document.addField("item_title", item.getTitle());
  document.addField("item_sell_point", item.getSell_point());
  document.addField("item_price", item.getPrice());
  document.addField("item_image", item.getImage());
  document.addField("item_category_name", item.getCategory_name());
  document.addField("item_desc", item.getItem_desc());
  // 写入索引库
  solrServer.add(document);
  }
  // 提交
  solrServer.commit();
  return TaotaoResult.ok();
  }
  
}
  

Controller层
  请求一个url,返回TaotaoResult。
  

@Controller  
public>  

  @Autowired
  private ItemService itemService;
  

  @RequestMapping("/importall")
  @ResponseBody
  public TaotaoResult importAll() {
  try {
  TaotaoResult result = itemService.importItems();
  return result;
  } catch (Exception e) {
  e.printStackTrace();
  return TaotaoResult.build(500, ExceptionUtil.getStackTrace(e));
  }
  }
  
}
  

  pom.xml
  

<build>  <resources>
  <resource>
  <directory>src/main/java</directory>
  <includes>
  <include>**/*.properties</include>
  <include>**/*.xml</include>
  </includes>
  <filtering>false</filtering>
  </resource>
  <resource>
  <directory>src/main/resources</directory>
  <includes>
  <include>**/*.properties</include>
  <include>**/*.xml</include>
  </includes>
  <filtering>false</filtering>
  </resource>
  </resources>
  </build>
  

http://i4.buimg.com/1949/e0c052dc5d4ebad6.png

搜索系统的实现

搜索服务发布
  调用服务传递过来一个查询条件,根据查询条件进行查询。返回查询结果。参数中包括分页条件。
  
参数:


[*]String queryString
[*]Int page
[*]  Int rows

[*]返回结果:返回json数据。
[*]包含查询结果的列表。使用商品的pojo来描述。SearchItem
[*]包含查询结果总记录数。
[*]包含查询结果的总页数。
[*]包含当前页码。
[*]包含查询的状态。
[*]  包含错误信息。

  创建一个SearchResult
  
包含四个属性:


[*]1、商品列表
[*]2、查询结果总记录数
[*]3、查询结果的总页数
[*]4、当前页码
  

public>

  private List<SearchItem> itemList;
  private Long recordCount;
  private int pageCount;
  private int curPage;
  

  public List<SearchItem> getItemList() {
  return itemList;
  }
  

  public void setItemList(List<SearchItem> itemList) {
  this.itemList = itemList;
  }
  

  public Long getRecordCount() {
  return recordCount;
  }
  

  public void setRecordCount(Long recordCount) {
  this.recordCount = recordCount;
  }
  

  public int getPageCount() {
  return pageCount;
  }
  

  public void setPageCount(int pageCount) {
  this.pageCount = pageCount;
  }
  

  public int getCurPage() {
  return curPage;
  }
  

  public void setCurPage(int curPage) {
  this.curPage = curPage;
  }
  
}
  

Dao层
  根据查询条件进行查询,返回查询结果。


[*]参数:SolrQuery对象  
返回结果:

[*]1、查询结果的商品列表
[*]2、查询结果的总记录数  
返回SearchResult

  

@Service
  
public>  

  @Autowired
  private SolrServer solrServer;
  

  @Override
  public SearchResult search(SolrQuery query) throws Exception {
  // 执行查询
  QueryResponse response = solrServer.query(query);
  // 取查询结果列表
  SolrDocumentList solrDocumentList = response.getResults();
  List<SearchItem> itemList = new ArrayList<>();
  for (SolrDocument solrDocument : solrDocumentList) {
  // 创建一个SearchItem对象
  SearchItem item = new SearchItem();
  item.setCategory_name((String) solrDocument.get("item_category_name"));
  item.setId((String) solrDocument.get("id"));
  item.setImage((String) solrDocument.get("item_image"));
  item.setPrice((Long) solrDocument.get("item_price"));
  item.setSell_point((String) solrDocument.get("item_sell_point"));
  //取高亮显示
  Map<String, Map<String, List<String>>> highlighting = response.getHighlighting();
  List<String> list = highlighting.get(solrDocument.get("id")).get("item_title");
  String itemTitle = "";
  if (list != null && list.size() > 0) {
  itemTitle = list.get(0);
  } else {
  itemTitle = (String) solrDocument.get("item_title");
  }
  item.setTitle(itemTitle);
  //添加到列表
  itemList.add(item);
  }
  SearchResult result = new SearchResult();
  result.setItemList(itemList);
  //查询结果总数量
  result.setRecordCount(solrDocumentList.getNumFound());
  return result;
  }
  
}
  

Service层
  1、接收查询条件、分页条件。
  
2、创建SolrQuery对象,设置查询条件、分页条件。
  
3、调用dao进行搜索
  
4、计算总页数,把总页数设置到SearchResult对象中,设置当前页属性。
  
5、返回SearchResult
  参数:
  
1、查询条件
  
2、Page
  
3、Rows
  返回结果:
  
SearchResult
  

@Service
  
public>  

  @Autowired
  private SearchDao searchDao;
  

  @Override
  public SearchResult search(String queryString, int page, int rows) throws Exception {
  //创建查询条件
  SolrQuery query = new SolrQuery();
  //设置查询条件
  query.setQuery(queryString);
  //设置分页条件
  query.setStart((page-1)*rows);
  query.setRows(rows);
  //设置默认搜索域
  query.set("df", "item_title");
  //设置高亮
  query.setHighlight(true);
  query.addHighlightField("item_title");

  query.setHighlightSimplePre("<font>  query.setHighlightSimplePost("</font>");
  //执行查询
  SearchResult searchResult = searchDao.search(query);
  //计算总页数
  Long recordCount = searchResult.getRecordCount();
  int pageCount = (int) (recordCount / rows);
  if (recordCount % rows > 0) {
  pageCount++;
  }
  searchResult.setPageCount(pageCount);
  searchResult.setCurPage(page);
  return searchResult;
  }
  
}
  

Controller层
  发布服务。
  
搜索服务的url:/search/q?keyword=xxx&page=1&rows=30
  
参数keyword、page、rows
  
返回结果:json数据,使用TaotaoResult包装SearchResult。
  

@Controller
  
public>  

  @Autowired
  private SearchService searchService;
  

  @RequestMapping("/q")
  @ResponseBody
  public TaotaoResult search(@RequestParam(defaultValue="")String keyword,
  @RequestParam(defaultValue="1")Integer page,
  @RequestParam(defaultValue="30")Integer rows) {
  

  try {
  //转换字符集
  keyword = new String(keyword.getBytes("iso8859-1"), "utf-8");
  SearchResult searchResult = searchService.search(keyword, page, rows);
  return TaotaoResult.ok(searchResult);
  } catch (Exception e) {
  e.printStackTrace();
  return TaotaoResult.build(500, ExceptionUtil.getStackTrace(e));
  }
  }
  

  
}
  

  http://localhost:8093/search/q?keyword=%E6%89%8B%E6%9C%BA&page=1&rows=10
  
http://i1.piimg.com/1949/050122e7f92a7072.png

在portal中实现搜索

分析
  调用taotao-search发布的服务,实现搜索。使用HttpClient调用服务。返回json数据。需要把json转换成java对象。把java对象传递给页面。
  请求的url:http://localhost:8082/search.html
  
参数:q:查询条件
  
返回结果:jsp页面(search.jsp)
  Search.jsp分析:
  
数据:
  
Query:查询条件
  
totalPages:总页数
  
itemList:商品列表(每个元素可以是SearchItem)
  
Page:当前页

Service层
  参数:查询条件、page、rows。
  
根据查询调用taotao-search发布的服务,查询商品列表。得到json数据,需要把json转换成java对象,返回SearchResult。
  

@Service
  
public>  

  @Value("${SEARCH_BASE_URL}")
  private String SEARCH_BASE_URL;
  

  @Override
  public SearchResult search(String keyword, int page, int rows) {
  // 调用服务查询商品列表
  Map<String, String> param = new HashMap<>();
  param.put("keyword", keyword);
  param.put("page", page + "");
  param.put("rows", rows + "");
  // 调用服务
  String json = HttpClientUtil.doGet(SEARCH_BASE_URL, param);
  // 转换成java对象
  TaotaoResult taotaoResult = TaotaoResult.formatToPojo(json, SearchResult.class);
  // 取返回结果
  SearchResult searchResult = (SearchResult) taotaoResult.getData();
  return searchResult;
  }
  
}
  

Controller层
  接收三个参数:查询条件、page、rows
  
调用服务查询商品列表。
  
把商品列表传递给jsp、参数回显。
  
返回逻辑视图(search.jsp)
  
请求的url:/search
  

@Controller
  
public>  

  @Autowired
  private SearchService searchService;
  

  @RequestMapping("/search")
  public String search(@RequestParam("q") String keyword,
  @RequestParam(defaultValue = "1") Integer page,
  @RequestParam(defaultValue = "60") Integer rows, Model model) {
  // get乱码处理
  try {
  keyword = new String(keyword.getBytes("iso8859-1"), "utf-8");
  } catch (UnsupportedEncodingException e) {
  keyword = "";
  e.printStackTrace();
  }
  SearchResult searchResult = searchService.search(keyword, page, rows);
  // 参数传递给页面
  model.addAttribute("query", keyword);
  model.addAttribute("totalPages", searchResult.getPageCount());
  model.addAttribute("itemList", searchResult.getItemList());
  model.addAttribute("page", searchResult.getCurPage());
  // 返回逻辑视图
  return "search";
  }
  
}
  

  解决图片显示不出来的问题:
  

public String getImage() {  if (image != null && image.equals("")) {
  String[] strings = image.split(",");
  return strings;
  }
  return image;
  }
  
页: [1]
查看完整版本: 商城项目(八)