web.xml
<listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:beans.xml</param-value> </context-param> <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>*.do</url-pattern> </servlet-mapping> <filter> <filter-name>SpringCharacterEncodingFilter</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>SpringCharacterEncodingFilter</filter-name> <url-pattern>*.do</url-pattern> </filter-mapping>
springmvc
<?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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd "> <context:component-scan base-package="com.rl.ecps.controller"/> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/shop/"></property> <property name="suffix" value=".jsp"></property> </bean> </beans>
访问首页:
@Controller @RequestMapping("/item") public class EbItemController { @RequestMapping("toIndex.do") public String toIndex() { return "index"; } }
由于下面使用了iframe,于是就出现了404错误了。 src是不能直接获取WEB-INF的JSP的。
<iframe id="itemListIframe" src="phoneClassification.jsp" frameBorder=0 scrolling=no width="100%" height="200%" ></iframe>
于是乎,我们把地址修改成访问controller,controller做跳转就行了。
<iframe id="itemListIframe" src="${path}/item/phoneClassification.do" frameBorder=0 scrolling=no width="100%" height="200%" ></iframe>
@RequestMapping("phoneClassification.do") public String phoneClassification() { return "phoneClassification"; }
设置完之后我们就可以能看到页面了。
我们要做的就是, 通过前台给出的参数,我们后台筛选出数据在前台展示。
首先,我们来分析一下可以筛选的参数把:
从参数上我们可以分为几类:
首先,我们把所有品牌先查询和对应的参数先查询出来吧。
@RequestMapping("toIndex.do") public String toIndex(Model model) { List<EbBrand> ebBrands = brandService.selectBrand(); List<EbFeature> isSelect = featureService.selectIsSelect(); model.addAttribute("ebBrands", ebBrands); model.addAttribute("isSelect", isSelect); return "index"; }
在页面上做展示
<c:forEach items="${isSelect}" var="feature"> <li style="display:none"><b>${feature.featureName}:</b> <p> <a href="javascript:void(0);" title="不限" class="here">不限</a> <c:forEach items="${feature.selectValues}" var="val"> <a href="javascript:void(0);" >${val}</a> </c:forEach> </p> </li> </c:forEach>
/** * 接收条件,查询出符合条件的商品 * @param brandId 品牌id * @param price 价钱 * @param param 被选中的参数 * @return */ @RequestMapping("listItem.do") public String listItem(Long brandId, String price, String param) { return "phoneClassification"; }
参数我们已经知道了,那我们怎么写这个SQL语句呢??
我的分析是这样子的:
/** 根据价钱,品牌,被选中属性查询符合条件的商品 涉及到的表: 1.商品 2.商品 3.参数值 4.价钱 */ SELECT * FROM EB_BRAND brand, EB_ITEM item, EB_PARA_VALUE para, EB_SKU sku WHERE brand.BRAND_ID = item.BRAND_ID AND para.ITEM_ID = item.ITEM_ID AND sku.ITEM_ID = item.ITEM_ID AND brand.BRAND_ID = 1002 AND sku.SKU_PRICE BETWEEN 1 AND 800000 AND para.PARA_VALUE = 'Android4.0';
在价钱中是一个范围,因此我们用between and 语法,而我们的参数传递过来可能是与很多的,因此只要我们使用动态SQL循环就行了。
因此,我们的mapper中的SQL是这样子的。
<select id="listItem" parameterType="map" resultMap="listItemRM"> SELECT item.*, sku.SKU_PRICE FROM EB_BRAND brand, EB_ITEM item, EB_PARA_VALUE para, EB_SKU sku <where> brand.BRAND_ID = item.BRAND_ID para.ITEM_ID = item.ITEM_ID AND sku.ITEM_ID = item.ITEM_ID AND <if test="brandId!=null"> brand.BRAND_ID = #{brandId} AND </if> <if test="minPrice!=null"> sku.SKU_PRICE BETWEEN #{minPrice} AND #{maxPrice} AND </if> <if test="paraList!=null"> <foreach collection="paraList" item="val" > para.PARA_VALUE = #{val} AND </foreach> </if> </where> </select>
由于我们的展示数据还需要价钱,返回的basemap不够用。我们就新创建了一个Map
<resultMap type="com.rl.ecps.model.EbItem" id="listItemRM" extends="BaseResultMap"> <result column="sku_price" property="skuPrice"/> </resultMap>
在实体中给予对应的属性
private BigDecimal skuPrice; public BigDecimal getSkuPrice() { return skuPrice; } public void setSkuPrice(BigDecimal skuPrice) { this.skuPrice = skuPrice; }
dao实现
public List<EbItem> listItem(Map<String, Object> map) { return this.getSqlSession().selectList(nameSpace + "listItem", map); }
service实现
public List<EbItem> listItem(Long brandId, String price, String param) { Map<String, Object> map = new HashedMap(); map.put("brandId", brandId); //将价钱进行分割成两部分 if (StringUtils.isNotBlank(price)) { String[] strings = price.split(","); map.put("minPrice", strings[0]); map.put("maxPrice", strings[1]); } //分割并装载到map中 List<String> list = new ArrayList<String>(); if (StringUtils.isNotBlank(param)) { String[] paras = param.split(","); for (String para : paras) { list.add(para); } map.put("paraList", list); } return itemDao.listItem(map); }
基于这么一个需求, 当我们点击一个条件的时候,我们要把当前所有获取的条件都获取出来。然后提交给服务器端就行了!
在点击选中事件上,我们获取数据
//使用变量状态我们的数据 var price = ""; var brandId = ""; var paraStr = ""; $(".filter li a").each(function () { //拿到选中的超链接 var clazz = $(this).attr("class"); if (clazz == "here") { //得到他们的类型【在html中我们自定义了3个类型】 var myType = $(this).attr("myType"); //根据不同的类型,对其进行不同的操作 if (myType == "brand") { brandId = $(this).attr("myBrandValue") } else if (myType == "price") { price = $(this).attr("myPriceValue"); } else if (myType == "para" && $(this).attr("myParaValue") != null) { var val = $(this).attr("myParaValue"); paraStr = paraStr + val+","; } } }); alert(price + "---" + brandId + "---" + paraStr);
修改iframe的请求路径,把我们的参数带过去
var iframePath = "${path}/item/listItem.do?price="+price+"&brandId="+brandId+"¶Str="+paraStr; $("#itemListIframe").attr("src", iframePath);
/** * 接收条件,查询出符合条件的商品 * * @param brandId 品牌id * @param price 价钱 * @param paraStr 被选中的参数 * @return */ @RequestMapping("/listItem.do") public String listItem(Long brandId, String price, String paraStr, Model model) { // TODO 基本效果出来了,但条件查询还有问题。 List<EbItem> items = itemService.listItem(brandId, price, paraStr); model.addAttribute("items", items); return "phoneClassification"; }
我们在查询的时候,发现很多相同价钱的手机都展示出来的。讲道理我们只要展示最低价钱那款就行了
想要展示最低价那款,还是要去修改SQL语句。需要用到分组函数了。
首先我有这么一个商品
它有两个最小销售单元,一般我们在页面上显示最便宜的那个就行了。
我们的SQL语句可以写成这样:
SELECT min(sku.SKU_PRICE) SKU_PRICE ,item.* FROM EB_ITEM item, EB_PARA_VALUE para, EB_SKU sku WHERE para.ITEM_ID = item.ITEM_ID AND sku.ITEM_ID = item.ITEM_ID AND item.BRAND_ID = 3069 AND sku.SKU_PRICE BETWEEN 1 AND 1000000 AND para.PARA_VALUE = 'Android' AND item.ITEM_ID=3080 GROUP BY item.ITEM_ID, item.ITEM_NAME, item.ITEM_NO, item.BRAND_ID, item.CAT_ID, item.TAG_IMG_ID, item.TAG_IMG, item.IS_NEW, item.IS_GOOD, item.IS_HOT, item.PROMOTION, item.AUDIT_STATUS, item.SHOW_STATUS, item.IMGS, item.KEYWORDS, item.PAGE_DESC, item.ITEM_RECYCLE, item.ON_SALE_TIME, item.CHECK_TIME, item.UPDATE_TIME, item.UPDATE_USER_ID, item.CREATE_TIME, item.CHECKER_USER_ID, item.FULL_PATH_DEPLOY, item.FULL_PATH_DEPLOY_OFFER, item.ORIGINAL_ITEM_ID, item.LAST_STATUS, item.MERCHANT_ID, item.ITEM_SORT, item.SALES, item.CREATE_USER_ID, item.SIM_LEVEL, item.GIFT_DESC, item.GIFT_IMG, item.GIFT_SHOW_TYPE, item.IMG_SIZE1 order by item.item_id desc
修改一下Mapper中的SQL语句:
<select id="listItem" parameterType="map" resultMap="listItemRM"> SELECT item.*, min(sku.SKU_PRICE) sku_price FROM EB_ITEM item, EB_PARA_VALUE para, EB_SKU sku <where> para.ITEM_ID = item.ITEM_ID AND sku.ITEM_ID = item.ITEM_ID <if test="brandId!=null"> AND item.BRAND_ID = #{brandId} </if> <if test="minPrice!=null"> AND sku.SKU_PRICE BETWEEN #{minPrice} AND #{maxPrice} </if> <if test="paraList!=null"> <foreach collection="paraList" item="val"> AND para.PARA_VALUE = #{val} </foreach> </if> </where> GROUP BY item.ITEM_ID, item.ITEM_NAME, item.ITEM_NO, item.BRAND_ID, item.CAT_ID, item.TAG_IMG_ID, item.TAG_IMG, item.IS_NEW, item.IS_GOOD, item.IS_HOT, item.PROMOTION, item.AUDIT_STATUS, item.SHOW_STATUS, item.IMGS, item.KEYWORDS, item.PAGE_DESC, item.ITEM_RECYCLE, item.ON_SALE_TIME, item.CHECK_TIME, item.UPDATE_TIME, item.UPDATE_USER_ID, item.CREATE_TIME, item.CHECKER_USER_ID, item.FULL_PATH_DEPLOY, item.FULL_PATH_DEPLOY_OFFER, item.ORIGINAL_ITEM_ID, item.LAST_STATUS, item.MERCHANT_ID, item.ITEM_SORT, item.SALES, item.CREATE_USER_ID, item.SIM_LEVEL, item.GIFT_DESC, item.GIFT_IMG, item.GIFT_SHOW_TYPE, item.IMG_SIZE1 order by item.item_id desc </select>
再次查看的时候,只出现一台了。
标准答案的SQL是使用exists关键字来进行查询的:在单表查询的情况下,看有没有符合条件的数据,如果符合,那么exists为ture
<select id="listItem" parameterType="map" resultMap="listItemRM"> select min(es.sku_price) sku_price, ei.* from eb_item ei, eb_sku es <where> ei.item_id = es.item_id <if test="minPrice != null"> and es.sku_price between #{minPrice} and #{maxPrice} </if> <if test="brandId != null"> and ei.brand_id = #{brandId} </if> <if test="paraList != null"> <foreach collection="paraList" item="paraValue"> and exists (select * from eb_para_value t where ei.item_id = t.item_id and t.para_value = #{paraValue}) </foreach> </if> </where> group by ei.ITEM_ID, ei.ITEM_NAME, ei.ITEM_NO, ei.BRAND_ID, ei.CAT_ID, ei.TAG_IMG_ID, ei.TAG_IMG, ei.IS_NEW, ei.IS_GOOD, ei.IS_HOT, ei.PROMOTION, ei.AUDIT_STATUS, ei.SHOW_STATUS, ei.IMGS, ei.KEYWORDS, ei.PAGE_DESC, ei.ITEM_RECYCLE, ei.ON_SALE_TIME, ei.CHECK_TIME, ei.UPDATE_TIME, ei.UPDATE_USER_ID, ei.CREATE_TIME, ei.CHECKER_USER_ID, ei.FULL_PATH_DEPLOY, ei.FULL_PATH_DEPLOY_OFFER, ei.ORIGINAL_ITEM_ID, ei.LAST_STATUS, ei.MERCHANT_ID, ei.ITEM_SORT, ei.SALES, ei.CREATE_USER_ID, ei.SIM_LEVEL, ei.GIFT_DESC, ei.GIFT_IMG, ei.GIFT_SHOW_TYPE, ei.IMG_SIZE1 order by ei.item_id desc </select>
对于这三类,我们很容易就能够把他们显示出来。 最主要的问题是获取他们这些数据、然后根据这些数据进行查询
对于标准答案,是将被选中的参数使用exist关键字来对其进行过滤。一个条件对应一个exist。至于他俩有什么区别我倒不知道了,知道了再回来补吧。
由于我们有3个参数、Dao层使用map集合来接收。