shiro实例
1 Solr案例实战
1.1 需求
使用Solr实现电商网站中商品信息搜索功能,可以根据关键字、分类、价格搜索商品信息,也可以根据价格进行排序,并且实现分页功能。
界面如下:
1.2 分析
开发人员需要的文档:静态页面(根据UI设计由美工给出)、数据库设计、原型设计
1.2.1 UI分析
1.2.2 架构分析
spring容器 |
表现层 springmvc |
Service层
|
Dao层 |
Solr索引库 |
mysql数据库 商品信息 |
Tomcat
|
Solr服务 |
索引、搜索请求 |
架构分为:
(1)、solr服务器。(已经做完,同入门示例)
(2)、自己开发的应用(重点)
(3)、数据库mysql
自己开发的应用
Controller 负责和前端页面进行请求和响应的交互
Service 封装查询条件,调用dao。
Dao 搜索索引库,返回搜索结果。
1.3 环境准备
Solr:4.10.3
Jdk环境:1.7.0_72(solr4.10 不能使用jdk1.7以下)
Ide环境:Eclipse
Web服务器(servlet容器):Tomcat 7X
1.4 功能开发
1.4.1 第一步:创建web工程,导入jar包
--导入的jar包说明:
Solrj的包
Solr服务的日志包
Spring的包(包含springmvc)
核心包 4个 core 、bean、context、expresstion
注解包 aop
Web包 web、webmvc
Commons日志包 common-logging
Jstl包
--导入静态资源和jsp页面说明:
静态资源放在webapp目录下,jsp页面放到/WEB-INF/目录下
1.4.2 第二步:Spring整合Solr、Springmvc
1.4.2.1 创建springmvc.xml
在config包下,创建springmvc.xml文件
<?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:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd "> <!-- 配置扫描包 --> <context:component-scan base-package="cn.gzsxt" /> <!-- 配置注解驱动 --> <mvc:annotation-driven />
<!-- jsp视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 前缀 --> <property name="prefix" value="/WEB-INF/jsp/"></property> <!-- 后缀 --> <property name="suffix" value=".jsp"></property> </bean> <bean class="org.apache.solr.client.solrj.impl.HttpSolrServer"> <constructor-arg value="http://localhost:8080/solr/solrCore0719"></constructor-arg> </bean>
</beans> |
1.4.2.2 创建Web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1"> <display-name>JD0719</display-name>
<!-- 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> </servlet> <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <filter> <filter-name>Character 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>Character Encoding</filter-name> <url-pattern>*.action</url-pattern> </filter-mapping> </web-app> |
1.4.3 第三步:整合测试
1.4.3.1 需求:
访问搜索页面。
1.4.3.2 创建PageController类
package cn.gzsxt.solr.controller;
import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping;
@Controller public class PageController {
@RequestMapping(value="/{page}") public String showPage(@PathVariable("page")String page){
return page; } } |
1.4.3.3 注意事项
(1)Solr服务器要先开启。
(2)Solr服务器部署的Tomcat和本web应用的部署的Tomcat不是同一个。
(3)要同时启动两个Tomcat,要注意端口冲突问题。
1.4.3.4 修改Solr服务器的Tomcat的端口
--在server.xml文件中,修改端口
--tomcat端口说明:
8005:关机端口
8080:默认服务端口
8009:请求转向端口。
--注意:这三个端口都需要修改。不然启动会冲突
本次课程中,将solr的tomcat端口,修改为8888.
1.4.3.5 修改Springmvc.xml
--修改Solr服务的端口
<bean class="org.apache.solr.client.solrj.impl.HttpSolrServer"> <constructor-arg value="http://localhost:8888/solr/solrCore0719"></constructor-arg> </bean>
|
1.4.3.6 访问搜索页面
地址:http://localhost:8080/solr-demo-02-jd/product_list.action
整合成功!!!
1.4.4 第四步:搜索功能实现
分析代码结构:
请求路径 |
list.action |
请求方式 |
POST |
请求参数 |
queryString、catalog_name、price、curPage、sort(共5个) |
返回结果 |
定义Product 以及ProductModel |
1.4.4.1 Pojo
1.4.4.1.1 分析
结合查询界面,分析得出:
--需要一个商品的pojo(Product),存放商品信息
--需要一个包装pojo(ResultModel),它包括商品列表信息、商品分页信息
1.4.4.1.2 创建Product类
public class Product { // 商品编号 private String pid; // 商品名称 private String name; // 商品分类名称 private String catalog_name; // 价格 private double price; // 商品描述 private String description; // 图片名称 private String picture; } |
1.4.4.1.3 创建ResultModel类
public class ResultModel { private List<Product> productList; // 商品总数 private Long recordCount; // 总页数 private int pageCount; // 当前页 private int currentPage; } |
1.4.4.2 Dao
1.4.4.2.1 功能
接收service层传递过来的参数,根据参数查询索引库,返回查询结果。
1.4.4.2.2 创建ProductDao接口,定义一个查询方法
public interface ProductDao {
//查询商品信息,包括分页信息 public ResultModel queryProduct(SolrQuery query) throws Exception; } |
1.4.4.2.3 创建ProductDaoImpl,重新改查询方法
package cn.gzsxt.dao.impl;
import java.util.ArrayList; import java.util.List; import java.util.Map;
import org.apache.solr.client.solrj.SolrQuery; import org.apache.solr.client.solrj.impl.HttpSolrServer; import org.apache.solr.client.solrj.response.QueryResponse; import org.apache.solr.common.SolrDocument; import org.apache.solr.common.SolrDocumentList; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository;
import cn.gzsxt.bean.Product; import cn.gzsxt.bean.ResultModel; import cn.gzsxt.dao.ProductDao;
@Repository public class ProductDaoImpl implements ProductDao {
@Autowired private HttpSolrServer server;
@Override public ResultModel queryProduct(SolrQuery query) throws Exception { ResultModel result = new ResultModel(); // 通过server查询索引库 QueryResponse response = server.query(query); // 获得查询结果 SolrDocumentList documentList = response.getResults(); // 把查询结果总数设置到ResultModel result.setRecordCount(documentList.getNumFound());
List<Product> productList = new ArrayList<>(); Product product = null; // 高亮信息 Map<String, Map<String, List<String>>> highlighting = response .getHighlighting(); for (SolrDocument solrDocument : documentList) { product = new Product(); product.setPid((String) solrDocument.get("id"));
String prodName = (String) solrDocument.get("product_name");
List<String> list = highlighting.get(solrDocument.get("id")).get( "product_name"); if (list != null) prodName = list.get(0);
product.setName(prodName); product.setCatalog_name((String) solrDocument .get("product_catalog_name")); product.setPrice((float) solrDocument.get("product_price")); product.setPicture((String) solrDocument.get("product_picture"));
productList.add(product); }
// 把商品列表放到ResultMap中 result.setProductList(productList); return result; }
} |
1.4.4.3 Service
1.4.4.3.1 功能分析
接收action传递过来的参数,根据参数拼装一个查询条件,调用dao层方法,查询商品列表。
接收返回的商品列表和商品的总数量,根据每页显示的商品数量计算总页数。
1.4.4.3.2 创建ProductService接口,定义一个查询方法
public interface ProductService { public ResultModel queryProduct(String queryString, String cataName, String price, String sort, Integer curPage) throws Exception; } |
1.4.4.3.3 创建ProductServiceImpl类,重写改查询方法
package cn.gzsxt.service.impl;
import org.apache.solr.client.solrj.SolrQuery; import org.apache.solr.client.solrj.SolrQuery.ORDER; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service;
import cn.gzsxt.dao.ProductDao; import cn.gzsxt.service.ProductService; import cn.gzsxt.vo.ResultModel;
@Service public class ProductServiceImpl implements ProductService {
@Autowired private ProductDao productDao; @Override public ResultModel queryProduct(String queryString, String cataName, String price, String sort, Integer curPage) throws Exception {
//封装查询条件 SolrQuery query = new SolrQuery();
//判断查询条件是否为空 if(!"".equals(queryString)&& null != queryString){ query.setQuery(queryString); }else{ query.setQuery("*:*"); }
//判断过滤条件是否为空 if(!"".equals(cataName)&& null !=cataName){ query.addFilterQuery("product_catalog_name:"+cataName); }
//判断商品价格是否为空 if(!"".equals(price) && null != price){ String[] prices = price.split("-"); if(prices.length == 2){ query.addFilterQuery("product_price:["+prices[0]+" TO "+prices[1]+"]"); } }
//设置排序 if("1".equals(sort)){ query.setSort("product_price", ORDER.desc); }else { query.setSort("product_price", ORDER.asc); }
//设置分页信息 if(null == curPage){ curPage = 1; } query.setStart((curPage-1)*20); query.setRows(20); //每页20条数据
//设置默认搜索域 query.set("df","product_name");
query.setHighlight(true); query.addHighlightField("product_name"); query.setHighlightSimplePre("<font style=\"color:red\">"); query.setHighlightSimplePost("</font>");
ResultModel result = productDao.queryProduct(query); result.setCurrentPage(curPage); // 总页数 = 总数量 / 每页数据条数 结果向上取整 double ceil = Math.ceil(result.getRecordCount().doubleValue()/20); result.setPageCount((int)ceil);
return result; } } |
1.4.4.4 Controller
1.4.4.4.1 创建ProductController类,定义查询接口
package cn.gzsxt.controller;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.RequestMapping;
import cn.gzsxt.service.ProductService; import cn.gzsxt.vo.ResultModel;
@Controller public class ProductController {
@Autowired private ProductService productService;
@RequestMapping("/list.action") public String queryProduct(String queryString, String catalog_name, String price, String sort, Integer curPage, ModelMap model) throws Exception {
ResultModel resultModel = productService.queryProduct(queryString, catalog_name, price, sort, curPage); model.addAttribute("result", resultModel); model.addAttribute("queryString", queryString); model.addAttribute("catalog_name", catalog_name); model.addAttribute("price", price); model.addAttribute("sort", sort); model.addAttribute("page", curPage);
return "product_list"; } } |
1.4.4.5 测试搜索功能
地址:http://localhost:8080/solr-demo-02-jd/list.action