tags: 移动商城项目
属性选项卡
第三个选项卡涉及到了我们的手机属性,因此,还是需要用到我们其他的数据库表:EB_FEATURE
继续做逆向工程:
查询出普通属性和特殊属性:
<select id="selectCommFeature" resultMap="BaseResultMap">
select * from eb_feature t where t.is_spec = 0
</select>
<select id="selectSpecFeature" resultMap="BaseResultMap">
select * from eb_feature t where t.is_spec = 1
</select>
dao和service和controller
dao实现
/**
* 继承SqlSessionDaoSupport能够得到sessionFactory的引用,非常方便!
*/
@Repository
public class EbFeatureDaoImpl extends SqlSessionDaoSupport implements EbFeatureDao {
String nameSpace = "com.rl.ecps.sqlMap.EbFeatureMapper.";
public List<EbFeature> selectCommFeature() {
return this.getSqlSession().selectList(nameSpace + "selectCommFeature");
}
public List<EbFeature> selectSpecFeature() {
return this.getSqlSession().selectList(nameSpace + "selectSpecFeature");
}
}
service实现
@Service
public class EbFeatureServiceImpl implements EbFeatureService {
@Autowired
private EbFeatureDao featureDao;
public List<EbFeature> selectCommFeature() {
return featureDao.selectCommFeature();
}
public List<EbFeature> selectSpecFeature() {
return featureDao.selectSpecFeature();
}
}
controller调用service拿到对应的普通属性和特殊属性。
/**
* 跳转到添加商品页面
*
* @return
*/
@RequestMapping("/toAddItem.do")
public String toAddItem(Model model) {
List<EbBrand> ebBrands = ebBrandService.selectBrand();
List<EbFeature> commFeature = featureService.selectCommFeature();
List<EbFeature> specFeature = featureService.selectSpecFeature();
model.addAttribute("ebBrands", ebBrands);
model.addAttribute("commFeature", commFeature);
model.addAttribute("specFeature", specFeature);
return "item/addItem";
}
JSP显示普通属性:
- forEach标签默认支持遍历以“,”逗号分割的数据!
<div id="tab_3" class="edit set" style="display: none">
<c:if test="${fn:length(commFeature) == 0}">
<p><label></label>无属性</p>
</c:if>
<%--判断每个属性的录入方式并显示--%>
<c:forEach items="${commFeature}" var="feature">
<p>
<label>${feature.featureName }:</label>
<%--如果输入类型为1,那么就是下拉框方式--%>
<c:if test="${feature.inputType==1}">
<select name="${feature.featureId}">
<%--这里需要设置一个空值,否则后台是可以获取到数据“请选择”--%>
<option value="">请选择</option>
<c:forEach items="${feature.selectValues}" var="value">
<option value="${value}">${value}</option>
</c:forEach>
</select>
</c:if>
<%--如果输入类型为2,那么就是单选框方式--%>
<c:if test="${feature.inputType==2}">
<c:forEach items="${feature.selectValues}" var="value">
<input type="radio" name="${feature.featureId}" value="${value}">${value}
</c:forEach>
</c:if>
<%--如果输入类型为3,那么就是多选框方式--%>
<c:if test="${feature.inputType==3}">
<c:forEach items="${feature.selectValues}" var="value">
<input type="checkbox" name="${feature.featureId}" value="${value}">${value}
</c:forEach>
</c:if>
</p>
</c:forEach>
</div>
属性存放
想要把我们在页面上选定的基本属性进行保存的话,我们是使用另一张表来进行保存的。Featrue表仅仅保存了相对应的属性,是不做保存功能的!
因此,我们需要对EB_PARA_VALUE做逆向工程!
我们参数表的主键是不需要被其他的表用的, 因此我们直接使用序列来管理进行的。并不需要主键返回
<insert id="insert" parameterType="com.rl.ecps.model.EbParaValue" >
insert into EB_PARA_VALUE (PARA_ID, ITEM_ID, FEATURE_ID,
PARA_VALUE)
values (seqparavalueid.nextval, #{itemId,jdbcType=DECIMAL}, #{featureId,jdbcType=DECIMAL},
#{paraValue,jdbcType=VARCHAR})
</insert>
编写参数表的dao
public interface EbParaValueDao {
/**
*由于我们的参数数据是多个的,不想在service做循环而浪费我们的数据库连接
* 因此就使用了List集合作为参数
* @param ebParaValues
* @param itemId
*/
void saveParaValue(List<EbParaValue> ebParaValues, Long itemId);
}
@Repository
public class EbParaValueDaoImpl extends SqlSessionDaoSupport implements EbParaValueDao {
private String nameSpace = "com.rl.ecps.sqlMap.EbParaValueMapper.";
public void saveParaValue(List<EbParaValue> ebParaValues, Long itemId) {
//获取数据库连接,通过一个连接把数据存到数据库里边去
SqlSession sqlSession = this.getSqlSession();
for (EbParaValue ebParaValue : ebParaValues) {
ebParaValue.setItemId(itemId);
sqlSession.insert(nameSpace + "insert", ebParaValue);
}
}
}
controller
回到我们的网页上,我们发现属性是非常多的,那么我们在controller是怎么接收的呢???
我们将JSP页面的name属性都设置为我们的featureId
由于我们该页面上的数据都是从数据库中查询出来的,数据库中的记录有多少,在页面上显示的就有多少
因此,我们可以这么干:
- 我们使用request对象来获取页面上所有的勾选出来的数据属性
- 再次从数据库中查询数据,遍历这些数据,如果发现有勾选出来的数据,那么我们就保存在EbParaValue对象中!
代码:
//查询出所有的属性数据
List<EbFeature> commFeature = featureService.selectCommFeature();
//创建一个集合来装载我们所有的参数数据
List<EbParaValue> ebParaValues = new ArrayList<EbParaValue>();
for (EbFeature feature : commFeature) {
//得到录入方式
Short inputType = feature.getInputType();
//复选,复选的值是有多个的
if (inputType == 3) {
String[] parameterValues = request.getParameterValues(feature.getFeatureId() + "");
//装载参数数据
String value = "";
//如果得到的数据不为null,那么就使用一个字符串来对其进行拼接
if (parameterValues != null && parameterValues.length > 0) {
for (String parameterValue : parameterValues) {
value = value + parameterValue + ",";
}
//去除最后一个逗号
value = value.substring(0, value.length() - 1);
//把数据封装到参数对象上
EbParaValue ebParaValue = new EbParaValue();
ebParaValue.setFeatureId(feature.getFeatureId());
ebParaValue.setParaValue(value);
//装载到集合中
ebParaValues.add(ebParaValue);
}
}else{
//非复选的值都只有一个
String parameter = request.getParameter(feature.getFeatureId() + "");
//如果拿到的数据不为null
if (StringUtils.isNotBlank(parameter)) {
//把数据封装到参数对象上
EbParaValue ebParaValue = new EbParaValue();
ebParaValue.setFeatureId(feature.getFeatureId());
ebParaValue.setParaValue(parameter);
//装载到集合中
ebParaValues.add(ebParaValue);
}
}
}
测试:
最小库存单元选项卡来到我们的最小库存单元选项卡,我们是需要把我们的特殊属性查询出来的,供用户选择。
查询出特殊属性:
<c:forEach items="${specFeature }" var="spec">
<tr>
<td>${spec.featureName }:</td>
<td>
<c:forEach items="${spec.selectValues}" var="para">
<input type="radio" name="${spec.featureId}" value="${para}">${para}
</c:forEach>
</td>
</tr>
</c:forEach>
当我们想点击增加规格的时候,就应该多那么一个div在页面上显示!那为什么我们需要多个规格呢??如下所示:
对该按钮添加单击事件
//实现页面规格的自动增加和删除
$("#button2").click(function () {
//得到想要控件div所有的内容,不包含自己的标签
var htmlDiv = $("#sp_0").html();
//把自己的标签包含进去
htmlDiv = "<div class='sp_0'>"+htmlDiv+"</div>";
//在下一个div之前插入
$(".page_c").before(htmlDiv);
});
当我们添加了对应的内容时,问题就随之而来了:我们的按钮选项互斥了!
- 当我们点击第一行的颜色时,想要点击第二行的颜色就不行了!【第一行的颜色选择没有了】
- 提交表单中的name属性多个重复了。
原因就是出在:
- name属性是一样的,radio只让选一个!
- 我们是直接把html内容复制过来的。
那么我们使用一个变量值,让每次的name属性都不一样即可!
//得到divNum的值
var divNum = $("#divNum").val();
//实现页面规格的自动增加和删除
$("#button2").click(function () {
divNum++;
//得到想要控件div所有的内容,不包含自己的标签
var htmlDiv = $("#sp_0").html();
//把自己的标签包含进去
htmlDiv = "<div class='sp_0' id='sp_"+divNum+"'>"+htmlDiv+"</div>";
//修改各个name的值,使用正则表达式就可以修改一部份的了
htmlDiv = htmlDiv.replace(/specradio1/g, "specradio"+divNum);
htmlDiv = htmlDiv.replace(/#sp_0/g, "#sp_"+divNum);
//skuType1 showStatus1 sort1 skuPrice1 marketPrice1 stockInventory1 skuUpperLimit1 sku1 location1
htmlDiv = htmlDiv.replace(/skuType1/g, "skuType"+divNum);
htmlDiv = htmlDiv.replace(/showStatus1/g, "showStatus"+divNum);
htmlDiv = htmlDiv.replace(/sort1/g, "sort"+divNum);
htmlDiv = htmlDiv.replace(/skuPrice1/g, "skuPrice"+divNum);
htmlDiv = htmlDiv.replace(/marketPrice1/g, "marketPrice"+divNum);
htmlDiv = htmlDiv.replace(/stockInventory1/g, "stockInventory"+divNum);
htmlDiv = htmlDiv.replace(/skuUpperLimit1/g, "skuUpperLimit"+divNum);
htmlDiv = htmlDiv.replace(/sku1/g, "sku"+divNum);
htmlDiv = htmlDiv.replace(/location1/g, "location"+divNum);
//重新设置div的值
$("#divNum").val(divNum);
//在下一个div之前插入
$(".page_c").before(htmlDiv);
});
还是就是我们不能删除第一个销售单元规格:
function clickRemove(id) {
var a = $(".sp_0").length;
if (a == 1) {
alert("默认规格不可删除");
return;
}
}
最小库存单元属性存放
我们的最小库存单元涉及到了两张数据库表:
首先我们来做逆向工程:
设置SKU有一个集合来保存所有的特殊属性值:
private List<EbSpecValue> specList;
public List<EbSpecValue> getSpecList() {
return specList;
}
public void setSpecList(List<EbSpecValue> specList) {
this.specList = specList;
}
sku的主键需要被SpecValue用到,因此需要返回主键
<selectKey keyProperty="skuId" order="BEFORE" resultType="long">
select seqskuid.nextval from dual
</selectKey>
specValue主键自动增长:
<insert id="insert" parameterType="com.rl.ecps.model.EbSpecValue" >
insert into EB_SPEC_VALUE (SPEC_ID, SKU_ID, FEATURE_ID,
SPEC_VALUE)
values (seqspecvalueid.nextval, #{skuId,jdbcType=DECIMAL}, #{featureId,jdbcType=DECIMAL},
#{specValue,jdbcType=VARCHAR})
</insert>
编写Dao
public interface EbSkuDao {
void saveEbSku(List<EbSku> ebSkus, Long itemId);
}
/**
* 继承SqlSessionDaoSupport能够得到sessionFactory的引用,非常方便!
*/
@Repository
public class EbSkuDaoImpl extends SqlSessionDaoSupport implements EbSkuDao {
String nameSpace = "com.rl.ecps.sqlMap.EbSkuMapper.";
String nameSpace1 = "com.rl.ecps.sqlMap.EbSpecValueMapper.";
public void saveEbSku(List<EbSku> ebSkus, Long itemId) {
SqlSession sqlSession = this.getSqlSession();
for (EbSku ebSku : ebSkus) {
//设置商品属性
ebSku.setItemId(itemId);
sqlSession.insert(nameSpace+"insert", ebSku);
List<EbSpecValue> specList = ebSku.getSpecList();
for (EbSpecValue ebSpecValue : specList) {
ebSpecValue.setSkuId(ebSku.getSkuId());
sqlSession.insert(nameSpace1 + "insert", ebSpecValue);
}
}
}
}
Controller获取页面数据
//使用集合来进行装sku的对象
List<EbSku> skuList = new ArrayList<EbSku>();
//遍历出特殊属性的值
List<EbFeature> specList = featureService.selectSpecFeature();
//获取页面有多少个单元格,对其进行遍历,取出对应的值
for (int i = 1; i <= divNum; i++) {
//获得商城价和库存,他们是必填的字段
String skuPrice = request.getParameter("skuPrice" + i);
String stock = request.getParameter("stockInventory" + i);
//如果上面的必填字段不是空说明数据有效
if (StringUtils.isNotBlank(skuPrice) && StringUtils.isNotBlank(stock)) {
String skuType = request.getParameter("skuType" + i);
String showStatus = request.getParameter("showStatus" + i);
String sort = request.getParameter("sort" + i);
String marketPrice = request.getParameter("marketPrice" + i);
String skuUpperLimit = request.getParameter("skuUpperLimit" + i);
String sku = request.getParameter("sku" + i);
String location = request.getParameter("location" + i);
//创建最小销售单元的对象,并且赋值
EbSku skuObj = new EbSku();
skuObj.setSkuPrice(new BigDecimal(skuPrice));
skuObj.setStockInventory(new Integer(stock));
if (StringUtils.isNotBlank(skuType) && !StringUtils.equals(skuType, "")) {
skuObj.setSkuType(new Short(skuType));
}
if (StringUtils.isNotBlank(showStatus) && !StringUtils.equals(showStatus, "")) {
skuObj.setShowStatus(new Short(showStatus));
}
if (StringUtils.isNotBlank(sort) && !StringUtils.equals(sort, "")) {
skuObj.setSkuSort(new Integer(sort));
}
if (StringUtils.isNotBlank(marketPrice) && !StringUtils.equals(marketPrice, "")) {
skuObj.setMarketPrice(new BigDecimal(marketPrice));
}
if (StringUtils.isNotBlank(skuUpperLimit) && !StringUtils.equals(skuUpperLimit, "")) {
skuObj.setSkuUpperLimit(new Integer(skuUpperLimit));
}
skuObj.setSku(sku);
skuObj.setLocation(location);
//装取特殊属性的集合
List<EbSpecValue> specValList = new ArrayList<EbSpecValue>();
for (EbFeature feature : specList) {
Long featureId = feature.getFeatureId();
//获得所选规格属性的值
String specVal = request.getParameter(featureId + "specradio" + i);
if (StringUtils.isNotBlank(specVal)) {
//创建规格对象
EbSpecValue spec = new EbSpecValue();
spec.setFeatureId(featureId);
spec.setSpecValue(specVal);
specValList.add(spec);
}
}
skuObj.setSpecList(specValList);
skuList.add(skuObj);
}
}
获取得到值:
将Item数据存进数据库到目前为止,我们4个选项卡的数据都可以拿到了。因此,我们可以把Item所需要的对象存入数据库了..
dao层编写
public void saveItem(EbItem ebItem) {
this.getSqlSession().insert(nameSpace + "insert", ebItem);
}
service层编写:
public void saveItem(EbItem ebItem, EbItemClob clob, List<EbSku> skus, List<EbParaValue> ebParaValues) {
itemDao.saveItem(ebItem);
clobDao.saveItemClob(clob, ebItem.getItemId());
skuDao.saveEbSku(skus, ebItem.getItemId());
paraValueDao.saveParaValue(ebParaValues, ebItem.getItemId());
}
controller编写:
@RequestMapping("/addItem.do")
public void addItem(EbItem ebItem, EbItemClob ebItemClob, HttpServletRequest request, Integer divNum) {
//为商品设置编号
ebItem.setItemNo(new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date()));
//查询出所有的属性数据
List<EbFeature> commFeature = featureService.selectCommFeature();
//创建一个集合来装载我们所有的参数数据
List<EbParaValue> ebParaValues = new ArrayList<EbParaValue>();
for (EbFeature feature : commFeature) {
//得到录入方式
Short inputType = feature.getInputType();
//复选,复选的值是有多个的
if (inputType == 3) {
String[] parameterValues = request.getParameterValues(feature.getFeatureId() + "");
//装载参数数据
String value = "";
//如果得到的数据不为null,那么就使用一个字符串来对其进行拼接
if (parameterValues != null && parameterValues.length > 0) {
for (String parameterValue : parameterValues) {
value = value + parameterValue + ",";
}
//去除最后一个逗号
value = value.substring(0, value.length() - 1);
//把数据封装到参数对象上
EbParaValue ebParaValue = new EbParaValue();
ebParaValue.setFeatureId(feature.getFeatureId());
ebParaValue.setParaValue(value);
//装载到集合中
ebParaValues.add(ebParaValue);
}
} else {
//非复选的值都只有一个
String parameter = request.getParameter(feature.getFeatureId() + "");
//如果拿到的数据不为null
if (StringUtils.isNotBlank(parameter)) {
//把数据封装到参数对象上
EbParaValue ebParaValue = new EbParaValue();
ebParaValue.setFeatureId(feature.getFeatureId());
ebParaValue.setParaValue(parameter);
//装载到集合中
ebParaValues.add(ebParaValue);
}
}
}
//使用集合来进行装sku的对象
List<EbSku> skuList = new ArrayList<EbSku>();
//遍历出特殊属性的值
List<EbFeature> specList = featureService.selectSpecFeature();
//获取页面有多少个单元格,对其进行遍历,取出对应的值
for (int i = 1; i <= divNum; i++) {
//获得商城价和库存,他们是必填的字段
String skuPrice = request.getParameter("skuPrice" + i);
String stock = request.getParameter("stockInventory" + i);
//如果上面的必填字段不是空说明数据有效
if (StringUtils.isNotBlank(skuPrice) && StringUtils.isNotBlank(stock)) {
String skuType = request.getParameter("skuType" + i);
String showStatus = request.getParameter("showStatus" + i);
String sort = request.getParameter("sort" + i);
String marketPrice = request.getParameter("marketPrice" + i);
String skuUpperLimit = request.getParameter("skuUpperLimit" + i);
String sku = request.getParameter("sku" + i);
String location = request.getParameter("location" + i);
//创建最小销售单元的对象,并且赋值
EbSku skuObj = new EbSku();
skuObj.setSkuPrice(new BigDecimal(skuPrice));
skuObj.setStockInventory(new Integer(stock));
if (StringUtils.isNotBlank(skuType) && !StringUtils.equals(skuType, "")) {
skuObj.setSkuType(new Short(skuType));
}
if (StringUtils.isNotBlank(showStatus) && !StringUtils.equals(showStatus, "")) {
skuObj.setShowStatus(new Short(showStatus));
}
if (StringUtils.isNotBlank(sort) && !StringUtils.equals(sort, "")) {
skuObj.setSkuSort(new Integer(sort));
}
if (StringUtils.isNotBlank(marketPrice) && !StringUtils.equals(marketPrice, "")) {
skuObj.setMarketPrice(new BigDecimal(marketPrice));
}
if (StringUtils.isNotBlank(skuUpperLimit) && !StringUtils.equals(skuUpperLimit, "")) {
skuObj.setSkuUpperLimit(new Integer(skuUpperLimit));
}
skuObj.setSku(sku);
skuObj.setLocation(location);
//装取特殊属性的集合
List<EbSpecValue> specValList = new ArrayList<EbSpecValue>();
for (EbFeature feature : specList) {
Long featureId = feature.getFeatureId();
//获得所选规格属性的值
String specVal = request.getParameter(featureId + "specradio" + i);
if (StringUtils.isNotBlank(specVal)) {
//创建规格对象
EbSpecValue spec = new EbSpecValue();
spec.setFeatureId(featureId);
spec.setSpecValue(specVal);
specValList.add(spec);
}
}
skuObj.setSpecList(specValList);
skuList.add(skuObj);
}
}
itemService.saveItem(ebItem, ebItemClob, skuList, ebParaValues);
return "redirect:listItem.do";
}
检查数据是否进去了
- 项目的id是自己查询出来的。
SELECT * from EB_ITEM WHERE ITEM_ID = 3073
SELECT * from EB_SKU where ITEM_ID = 3073
SELECT * from EB_PARA_VALUE WHERE ITEM_ID = 3073
SELECT * from EB_SPEC_VALUE WHERE SKU_ID = 3060
商品审核
接下来我们做的是商品审核的功能:
我们到修改url的地址,并且给出对应controller的方法
<li><a href="${path}/item/listAudit.do?auditStatus=0&showStatus=1"><samp class="t05"></samp>商品审核</a></li>
查询出未审核的商品其实就是条件查询的一种,因此该controller的代码和列出商品的代码几乎一样。
@RequestMapping("/listAudit.do")
public String listAudit(QueryCondition queryCondition,Model model) {
//查询出所有的品牌
List<EbBrand> ebBrands = ebBrandService.selectBrand();
//如果是第一次访问的话,那么默认是没有当前页号的,因此赋值为1
if (queryCondition.getPageNo() == null) {
queryCondition.setPageNo(1);
}
//得到分页数据
Page page = itemService.selectItemByCondition(queryCondition);
model.addAttribute("page", page);
model.addAttribute("ebBrands", ebBrands);
//回显条件数据
model.addAttribute("queryCondition", queryCondition);
return "item/listAudit";
}
处理下边的url并且随着条件,样式发生改变:
<h2 class="h2_ch"><span id="tabs" class="l">
<a id="label4" href="${base}/item/listAudit.do" title="全部实体商品" class="nor">全部</a>
<a id="label1" href="${path}/item/listItem.do?auditStatus=0&showStatus=1" title="待审核实体商品"
class="nor">待审核</a>
<a id="label2" href="${path}/item/listItem.do?auditStatus=2&showStatus=1" title="审核不通过实体商品"
class="nor">审核不通过</a>
<a id="label3" href="${path}/item/listItem.do?auditStatus=1&showStatus=1" title="已审核实体商品"
class="nor">已审核</a>
</span></h2>
数据回显
通过隐藏域拿到查询条件的值:
<input type="hidden" id="auditStatus" name="auditStatus" value="${queryCondition.auditStatus}"/>
通过判断隐藏域的值来改变我们的样式:
$(document).ready(function () {
if ($("#auditStatus").val() == '0') {
$("#label1").attr("class", "here");
}
else if ($("#auditStatus").val() == 2) {
$("#label2").attr("class", "here");
}
else if ($("#auditStatus").val() == 1) {
$("#label3").attr("class", "here");
}
else $("#label4").attr("class", "here");
})
查询条件以及回显:
<p>查询:
<ui:select name="catID" list="catList" rootId="0" defaulttext="所有分类" defaultvalue=""
currentValue="${catID}"/>
<select id="brandId" name="brandId"">
<option value="">全部品牌</option>
<c:forEach items="${ebBrands}" var="brand">
<option value="${brand.brandId}"
<%--这是数据回显--%>
<c:if test="${queryCondition.brandId==brand.brandId}"> selected </c:if>
>${brand.brandName}</option>
</c:forEach>
<%-- </select><select id="stock" name="stock" style="display:none;">
<option value="-1" selected="">全部库存</option>
<option value="0"<c:if test='${stock==0}'> selected</c:if>>已缺货</option>
<option value="1"<c:if test='${stock==1}'> selected</c:if>>即将缺货</option>
</select>--%>
<%--模糊查询--%>
<input type="text" id="searchText" name="itemName" value="${queryCondition.itemName}"
title="" class="text20 medium gray"/>
<input type="submit" id="goSearch"
class="hand btn60x20"
value="查询"/>
</p>
根据审核条件的不同,在显示商品的url中也应该是不同的。
- 只要在遍历的时候,判断对应的状态就行了。
处理审核:使用JavaScript方法来进行控制,把item的Id传递进去和审核对应的值。
<c:if test="${item.auditStatus==0}">
<a href="javascript:void(0);" onclick="isPass(${item.itemId}, 1)">通过</a>
<a href="javascript:void(0);" onclick="isPass(${item.itemId}, 2)">不通过</a>
</c:if>
审核通过和不通过总会有理由的,对于我们的理由我们使用一张表来保存的。
function isPass(itemId, auditStatus){
//修改浮动层的标题
$("#addItemNoteH2").html("商品审核");
//清空内容
$("#itemNote").val("");
tipShow("#addItemNote");
//给表单赋值
$("#itemId").val(itemId);
$("#myAuditStatus").val(auditStatus);
}
使用表单来处理我们的操作。其中notes是我们弹出框的数据。
- 我们使用一个表单就可以把不同方法中的数据集合在一起,我们只要把表单提交过去就行了!
<form action="${path }/item/auditItem.do" id="auditForm" method="post">
<input type="hidden" name="itemId" id="itemId">
<input type="hidden" name="auditStatus" id="myAuditStatus">
<input type="hidden" name="notes" id="notes">
</form>
响应事件,给表单赋值,提交表单
$("#addItemNoteConfirm").click(function(){
var notes = $("#itemNote").val();
//给表单赋值
$("#notes").val(notes);
//提交表单
$("#auditForm").submit();
});
我们是使用EB_CONSOLE_LOG这张数据表来保存我们后台操作的日志记录的。
表的字段如下:
既然我们要操作到表,我们就得逆向工厂...
设置主键为自动增长
<insert id="insert" parameterType="com.rl.ecps.model.EbConsoleLog" >
insert into EB_CONSOLE_LOG (CONSOLE_LOG_ID, ENTITY_NAME, ENTITY_ID,
USER_ID, OP_TYPE, OP_TIME,
NOTES, TABLE_NAME)
values (seqconsolelogid.nextval, #{entityName,jdbcType=VARCHAR}, #{entityId,jdbcType=DECIMAL},
#{userId,jdbcType=DECIMAL}, #{opType,jdbcType=VARCHAR}, #{opTime,jdbcType=TIMESTAMP},
#{notes,jdbcType=VARCHAR}, #{tableName,jdbcType=VARCHAR})
</insert>
编写dao
/**
* 继承SqlSessionDaoSupport能够得到sessionFactory的引用,非常方便!
*/
@Repository
public class EbConsoleLogDaoImpl extends SqlSessionDaoSupport implements EbConsoleLogDao {
String nameSpace = "com.rl.ecps.sqlMap.EbConsoleLogMapper.";
public void saveConsoleLog(EbConsoleLog ConsoleLog) {
this.getSqlSession().insert(nameSpace + "insert", ConsoleLog);
}
}
修改商品的属性,由于修改的状态个数是未知的,因此我们使用动态修改:
public void updateItem(EbItem ebItem) {
this.getSqlSession().update(nameSpace + "updateByPrimaryKeySelective", ebItem);
}
编写service
public void updateItem(Long itemId, Short auditStatus, String notes) {
//设置item的属性
EbItem ebItem = new EbItem();
ebItem.setItemId(itemId);
ebItem.setAuditStatus(auditStatus);
ebItem.setCheckerUserId((long) 222);
ebItem.setCheckTime(new Date());
//更新item
itemDao.updateItem(ebItem);
//操作日志
EbConsoleLog ebConsoleLog = new EbConsoleLog();
ebConsoleLog.setEntityId(itemId);
ebConsoleLog.setEntityName("商品表");
ebConsoleLog.setNotes(notes);
ebConsoleLog.setOpTime(new Date());
if(auditStatus == 1){
ebConsoleLog.setOpType("审核通过");
}else{
ebConsoleLog.setOpType("审核不通过");
}
ebConsoleLog.setTableName("EB_ITEM");
ebConsoleLog.setUserId(1l);
logDao.saveConsoleLog(ebConsoleLog);
}
controller
@RequestMapping("/auditItem.do")
public String auditItem(Long itemId, Short auditStatus, String notes) throws IOException {
itemService.updateItem(itemId, auditStatus, notes);
return "redirect:listAudit.do";
}
把商品的状态修改了,并且已经把操作记录写到数据库表中了。
上下价对于上下价和审核的逻辑基本是相同的...
根据不同的状态给出不同的超链接:
<a href="/ecps-console/shop/item/viewItem.jsp" title="查看">查看</a>
<c:if test="${item.showStatus == 1 }">
<a href="/ecps-console/ecps/console/item/editItem.do?type=1&itemId=2384">编辑</a>
<a href="javascript:void(0);" onclick="singleDel('2384')">删除</a>
<a href="javascript:void(0);" onclick="isShow(${item.itemId}, 0)">上架</a>
</c:if>
<c:if test="${item.showStatus == 0 }">
<a href="javascript:void(0);" onclick="isShow(${item.itemId}, 1)">下架</a>
<a href="javascript:void(0);">发布</a>
</c:if>
给表单赋值
function isShow(itemId, showStatus) {
tipShow("#confirm");
//给表单赋值
$("#itemId").val(itemId);
$("#myShowStatus").val(showStatus);
}
在弹出框中绑定提交事件,提交表单
$("#confirmOk").click(function () {
$("#showForm").submit();
});
编写controller和service
@RequestMapping("/showItem.do")
public String showItem(Long itemId, Short showStatus) throws IOException {
itemService.showItem(itemId, showStatus);
return "redirect:listItem.do";
}
public void showItem(Long itemId, Short showStatus) {
//设置item的属性
EbItem ebItem = new EbItem();
ebItem.setItemId(itemId);
ebItem.setShowStatus(showStatus);
ebItem.setCheckerUserId((long) 222);
ebItem.setCheckTime(new Date());
//更新item
itemDao.updateItem(ebItem);
//操作日志
EbConsoleLog ebConsoleLog = new EbConsoleLog();
ebConsoleLog.setEntityId(itemId);
ebConsoleLog.setEntityName("商品表");
ebConsoleLog.setOpTime(new Date());
if(showStatus == 1){
ebConsoleLog.setOpType("下架");
}else{
ebConsoleLog.setOpType("上架");
}
ebConsoleLog.setTableName("EB_ITEM");
ebConsoleLog.setUserId(1l);
logDao.saveConsoleLog(ebConsoleLog);
}
前台准备
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" class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="phoneClassification.jsp" frameBorder=0 scrolling=no width="100%" height="200%" ></iframe>
于是乎,我们把地址修改成访问controller,controller做跳转就行了。
<iframe id="itemListIframe" class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="${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和Service
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);
controller
/**
* 接收条件,查询出符合条件的商品
*
* @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>
总结
- 第三个选项卡是展示商品的普通属性字段的,拿到数据库的所有普通属性字段,在页面上判断输入的方式是哪一个,按照不同的输入方式来展示(有的下拉框、有的多选框、有的单选框)
- 展示完之后,那我们怎么获取选中的数据呢???页面上又有下拉框、又有多选框什么的。单单通过字符串数据的方式获取选中的数据是不行的。因为我们无法判断该属性是哪种输入方式。
- 我们可以这样干:页面展示的数据都是我们后台查询出来的。那么我们只要遍历原来的集合,获取选中的Id。
- 在遍历期间判断输入方式,如果是多选框,那我们就获取其字符串数组、如果是单选框、那么就直接获取其id。
- 只要id吻合了,那么就是页面选中的数据。只要将被选中的数据封装到对象中。
- 当然了,一个商品也是有很多参数的,在Dao层用集合来进行保存所有的参数,商品的Id也是需要外界传递进来的。用一个Session就要把所有的数据存入到数据库中。
- 对于最小销售单元,我们查询出特殊的属性在页面上展示。可能需要多个规格,可以使用Jquery来进行复制。
- 复制出来是会有问题的:name属性的名字是相同的,于是一个规格和第二个规格就会互斥、我们后台也不能拿到数据
- 既然知道根本的原因是name属性,我们只要在复制后,改变name属性的名称即可。我们通过一个变量,既可以记录我们增添了多少个规格,又可以用来标识不同的name属性
- 在复制完之后,使用正则表达式把对应的name名称替换即可了。
- 一个商品也对应着多个销售单元的,因此还是用集合来进行保存。同样需要外界对商品的Id传入。由于Sku和SkuValue需要同时在页面上展示,那么Sku还是需要使用List来维护SkuValue的。
- 在保存Sku时和ParaValue的逻辑是差不多的。
- 查看商品审核的数据本质上就是有条件地查询商品。与我们之前查询商品的逻辑代码是一样的
- 对于数据回显来说,还是一样,如果属性是表单内的。我们就判断或者直接进行回显。如果是表单外的数据,我们就通过隐藏域获取该值。通过Jquery来进行控制回显。
- 处理审核的时候,我们将审核的记录添加到数据库表中。要做到两个JavaScript方法共享数据:我们可以将数据使用form表单,表单内使用隐藏域。Jquery为隐藏域赋值就行了。最后提交表单
- 商品的上下架和商品审核逻辑几乎一样
- 准备前台页面,在web.xml一样是需要加载我们Core模块的bean.xml文件。需要自己手动去写一个springMVC的配置文件。
- 在筛选后台的时候,接收类型可以分成三类
- 价钱
- 品牌Id
- 要被筛选的条件。
- 对于这三类,我们很容易就能够把他们显示出来。最主要的问题是获取他们这些数据、然后根据这些数据进行查询
- 我是这样做的:把他们关联的表一次性写出来,内连接他们的相同条件。
- 价钱参数使用between and关键字来搜索
- 品牌用等值连接
- 被选中的参数用动态的SQL来进行查询
- 还有值得注意的就是最小销售单元,一般我们只会在页面上显示最低价的那款商品。因此我们用到分组函数。
- 我是这样做的:把他们关联的表一次性写出来,内连接他们的相同条件。
- 对于标准答案,是将被选中的参数使用exist关键字来对其进行过滤。一个条件对应一个exist。至于他俩有什么区别我倒不知道了,知道了再回来补吧。
- 那怎么获取这三类的值呢??可以在每个a标签上自定义类型,还有对应的值。当点击其中一个标签的时候,遍历这些标签,获取他们的值。
- 价钱使用字符串来接收,是一个范围。我们接收完在后台切割就行了。
- 品牌直接使用Long类型接收
- 被选中的标签也可以使用字符串来接收,同样在后台切割就行了。
- 由于我们有3个参数、Dao层使用map集合来接收。
共同学习,写下你的评论
评论加载中...
作者其他优质文章