[TOC]
## 步驟 1 : 先運行,看到效果,再學習
先將完整的 spring 項目(向老師要相關資料),配置運行起來,確認可用之后,再學習做了哪些步驟以達到這樣的效果。
## 步驟 2 : 模仿和排錯
在確保可運行項目能夠正確無誤地運行之后,再嚴格照著教程的步驟,對代碼模仿一遍。
模仿過程難免代碼有出入,導致無法得到期望的運行結果,此時此刻通過比較**正確答案** ( 可運行項目 ) 和自己的代碼,來定位問題所在。
采用這種方式,**學習有效果,排錯有效率**,可以較為明顯地提升學習速度,跨過學習路上的各個檻。
## 步驟 3 : 頁面截圖
重啟tomcat,通過訪問地址
`http://127.0.0.1:8080/tmall_ssm/admin_propertyValue_edit?productId=5`
可以看到產品屬性設置的界面
>注: 這productId=4是產品的id,根據你的實際運行情況,采取不同的id值
>

## 步驟 4 : PropertyValue
為PropertyValue增加一個Property屬性以及getter,setter
~~~
package com.dodoke.tmall.pojo;
public class PropertyValue {
private Integer id;
private String value;
private Integer productId;
private Integer propertyId;
/* 非數據庫字段 */
private Property property;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value == null ? null : value.trim();
}
public Integer getProductId() {
return productId;
}
public void setProductId(Integer productId) {
this.productId = productId;
}
public Integer getPropertyId() {
return propertyId;
}
public void setPropertyId(Integer propertyId) {
this.propertyId = propertyId;
}
public Property getProperty() {
return property;
}
public void setProperty(Property property) {
this.property = property;
}
}
~~~
## 步驟 5 : PropertyValueService
創建PropertyValueService,提供多個方法,各個方法的作用在接下來的實現類PropertyValueServiceImpl中講解
~~~
package com.dodoke.tmall.service;
import java.util.List;
import com.dodoke.tmall.pojo.Product;
import com.dodoke.tmall.pojo.PropertyValue;
public interface PropertyValueService {
void init(Product p);
void update(PropertyValue pv);
PropertyValue get(int propertyId, int productId);
List<PropertyValue> list(int productId);
}
~~~
## 步驟 6 : PropertyValueServiceImpl
PropertyValueServiceImpl實現了PropertyValueService:
1. get(int propertyId, int productId)
根據屬性id和產品id獲取PropertyValue對象
2. list(int productId)
根據產品id獲取所有的屬性值
3. init方法
3.1 這個方法的作用是初始化PropertyValue。 為什么要初始化呢? 因為對于PropertyValue的管理,沒有增加,只有修改。 所以需要通過初始化來進行自動地增加,以便于后面的修改。
3.2 首先根據產品獲取分類,然后獲取這個分類下的所有屬性集合
3.3 然后用屬性和產品id去查詢,看看這個屬性和這個產品,是否已經存在屬性值了。
3.4 如果不存在,那么就創建一個屬性值,并設置其屬性和產品,接著插入到數據庫中。
這樣就完成了屬性值的初始化。
4. update(PropertyValue pv)
更新
~~~
package com.dodoke.tmall.service.impl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.dodoke.tmall.mapper.PropertyValueMapper;
import com.dodoke.tmall.pojo.Product;
import com.dodoke.tmall.pojo.Property;
import com.dodoke.tmall.pojo.PropertyValue;
import com.dodoke.tmall.pojo.PropertyValueExample;
import com.dodoke.tmall.service.PropertyService;
import com.dodoke.tmall.service.PropertyValueService;
@Service
public class PropertyValueServiceImpl implements PropertyValueService {
@Autowired
PropertyValueMapper propertyValueMapper;
@Autowired
PropertyService propertyService;
/**
* 初始化PropertyValue
*/
@Override
public void init(Product p) {
// 根據產品獲取分類,然后獲取這個分類下的所有屬性集合
List<Property> pts = propertyService.list(p.getCategoryId());
for (Property pt : pts) {
// 用屬性和產品id去查詢對應屬性值
PropertyValue pv = get(pt.getId(), p.getId());
// 看看這個屬性和這個產品,是否已經存在屬性值了。若不存在,那么就創建一個屬性值,并設置其屬性和產品,接著插入到數據庫中
if (null == pv) {
pv = new PropertyValue();
pv.setProductId(p.getId());
pv.setPropertyId(pt.getId());
propertyValueMapper.insert(pv);
}
}
}
/**
* 更新
*/
@Override
public void update(PropertyValue pv) {
propertyValueMapper.updateByPrimaryKeySelective(pv);
}
/**
* 根據屬性id和產品id獲取PropertyValue對象
*/
@Override
public PropertyValue get(int propertyId, int productId) {
PropertyValueExample example = new PropertyValueExample();
example.createCriteria().andPropertyIdEqualTo(propertyId).andProductIdEqualTo(productId);
List<PropertyValue> pvs = propertyValueMapper.selectByExample(example);
if (pvs.isEmpty())
return null;
return pvs.get(0);
}
/**
* 根據產品id獲取所有的屬性值
*/
@Override
public List<PropertyValue> list(int productId) {
PropertyValueExample example = new PropertyValueExample();
example.createCriteria().andProductIdEqualTo(productId);
List<PropertyValue> result = propertyValueMapper.selectByExample(example);
for (PropertyValue pv : result) {
Property property = propertyService.get(pv.getPropertyId());
pv.setProperty(property);
}
return result;
}
}
~~~
## 步驟 7 : PropertyValueController
準備PropertyValueController類
~~~
package com.dodoke.tmall.controller;
import java.util.List;
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.ResponseBody;
import com.dodoke.tmall.pojo.Product;
import com.dodoke.tmall.pojo.PropertyValue;
import com.dodoke.tmall.service.ProductService;
import com.dodoke.tmall.service.PropertyValueService;
@Controller
@RequestMapping("")
public class PropertyValueController {
@Autowired
PropertyValueService propertyValueService;
@Autowired
ProductService productService;
/**
* 屬性值編輯
*
* @param model
* 模型
* @param productId
* 產品id
* @return 頁面路徑
*/
@RequestMapping("admin_propertyValue_edit")
public String edit(Model model, int productId) {
// 根據產品id, 獲取產品對象
Product p = productService.get(productId);
// 初始化屬性值
propertyValueService.init(p);
List<PropertyValue> pvs = propertyValueService.list(p.getId());
model.addAttribute("p", p);
model.addAttribute("pvs", pvs);
return "admin/editPropertyValue";
}
/**
* 屬性值更新
* @param pv 屬性值對象
* @return 提示信息字符串
*/
@RequestMapping("admin_propertyValue_update")
@ResponseBody
public String update(PropertyValue pv) {
propertyValueService.update(pv);
return "success";
}
}
~~~
## 步驟 8 : editPropertyValue.jsp
增加editPropertyValue.jsp
## 步驟 9 : 編輯功能講解
通過產品管理界面的設置屬性,跳到編輯頁面
調用PropertyValueController的edit方法:
1. 根據productId獲取product對象,因為面包屑導航里需要顯示產品的名稱和分類的連接。
2. 初始化屬性值: propertyValueService.init(p)。 因為在第一次訪問的時候,這些屬性值是不存在的,需要進行初始化。
3. 根據產品,獲取其對應的屬性值集合。
4. 服務端跳轉到editPropertyValue.jsp 上
5. 在editPropertyValue.jsp上,用c:forEach遍歷出這些屬性值

PropertyValueController 代碼片段:
~~~
/**
* 屬性值編輯
*
* @param model
* 模型
* @param productId
* 產品id
* @return 頁面路徑
*/
@RequestMapping("admin_propertyValue_edit")
public String edit(Model model, int productId) {
// 根據產品id, 獲取產品對象
Product p = productService.get(productId);
// 初始化屬性值
propertyValueService.init(p);
List<PropertyValue> pvs = propertyValueService.list(p.getId());
model.addAttribute("p", p);
model.addAttribute("pvs", pvs);
return "admin/editPropertyValue";
}
~~~
editPropertyValue.jsp:
~~~
<c:forEach items="${pvs}" var="pv">
<div class="eachPV">
<span class="pvName" >${pv.property.name}</span>
<span class="pvValue"><input class="pvValue" pvid="${pv.id}" type="text" value="${pv.value}"></span>
</div>
</c:forEach>
~~~
## 步驟 10 : 修改功能講解
修改功能采用的是使用post方式提交ajax的異步調用方式
1. 監聽輸入框上的keyup事件
2. 獲取輸入框里的值
3. 獲取輸入框上的自定義屬性pvid,這就是當前PropertyValue對應的id
4. 把邊框的顏色修改為黃色,表示正在修改的意思
5. 借助JQuery的ajax函數 $.post,把id和值,提交到admin_propertyValue_update
6. admin_propertyValue_update導致PropertyValueController的update方法被調用
* 參數 PropertyValue 獲取瀏覽器Ajax方式提交的參數
* 通過 propertyValueService.update(propertyValue) 更新到數據庫
* 結合方法update上的注解@ResponseBody和return "success" 就會向瀏覽器返回字符串 "success"
* propertyValueService調用的是`propertValueMapper.updateByPrimaryKeySelective(pv); `這個方法只會更新propertyValue存在的字段,而參數PropertyValue只有id和value有值,所以即便這個PropertyValue對象沒有productId和propertyId值,修改的時候也不會影響該PropertyValue的productId和propertyId。
7. 瀏覽器判斷如果返回值是"success",那么就把邊框設置為綠色,表示修改成功,否則設置為紅色,表示修改失敗

editPropertyValue.jsp:
~~~
$("input.pvValue").keyup(function(){
var value = $(this).val();
var page = "admin_propertyValue_update";
var pvid = $(this).attr("pvid");
var parentSpan = $(this).parent("span");
parentSpan.css("border","1px solid yellow");
$.post(
page,
{"value":value,"id":pvid},
function(result){
if("success"==result) {
parentSpan.css("border","1px solid green");
} else {
parentSpan.css("border","1px solid red");
}
}
);
});
~~~
PropertyValueController 代碼片段:
~~~
/**
* 屬性值更新
* @param pv 屬性值對象
* @return 提示信息字符串
*/
@RequestMapping("admin_propertyValue_update")
@ResponseBody
public String update(PropertyValue pv) {
propertyValueService.update(pv);
return "success";
}
~~~
## 步驟 11 : 刪除,增加功能不需要
屬性的維護是在分類中進行,這里僅僅做值的設置。 不提供刪除和增加功能
> 這里屬性不提供刪除功能,會導致沒辦法刪除帶有屬性的產品,其實,對于產品而言,要刪除還是挺麻煩的,最好標記成為刪除狀態比較好。 否則要刪除的數據太多了,產品圖片信息,屬性值信息,訂單項信息,評價信息,這些都是依賴產品的。
產品畢竟是核心數據,還是使用標記的好,不要輕易刪除的好。
- 項目簡介
- 功能一覽
- 前臺
- 后臺
- 開發流程
- 需求分析-展示
- 首頁
- 產品頁
- 分類頁
- 搜索結果頁
- 購物車查看頁
- 結算頁
- 確認支付頁
- 支付成功頁
- 我的訂單頁
- 確認收貨頁
- 確認收貨成功頁
- 評價頁
- 需求分析-交互
- 分類頁排序
- 立即購買
- 加入購物車
- 調整訂單項數量
- 刪除訂單項
- 生成訂單
- 訂單頁功能
- 確認付款
- 確認收貨
- 提交評價信息
- 登錄
- 注冊
- 退出
- 搜索
- 前臺需求列表
- 需求分析后臺
- 分類管理
- 屬性管理
- 產品管理
- 產品圖片管理
- 產品屬性設置
- 用戶管理
- 訂單管理
- 后臺需求列表
- 表結構設計
- 數據建模
- 表與表之間的關系
- 后臺-分類管理
- 可運行的項目
- 靜態資源
- JSP包含關系
- 查詢
- 分頁
- 增加
- 刪除
- 編輯
- 修改
- 做一遍
- 重構
- 分頁方式
- 分類逆向工程
- 所有逆向工程
- 后臺其他頁面
- 屬性管理實現
- 產品管理實現
- 產品圖片管理實現
- 產品屬性值設置
- 用戶管理實現
- 訂單管理實現
- 前端
- 前臺-首頁
- 可運行的項目
- 靜態資源
- ForeController
- home方法
- home.jsp
- homePage.jsp
- 前臺-無需登錄
- 注冊
- 登錄
- 退出
- 產品頁
- 模態登錄
- 分類頁
- 搜索
- 前臺-需要登錄
- 購物流程
- 立即購買
- 結算頁面
- 加入購物車
- 查看購物車頁面
- 登錄狀態攔截器
- 其他攔截器
- 購物車頁面操作
- 訂單狀態圖
- 生成訂單
- 我的訂單頁
- 我的訂單頁操作
- 評價產品
- 總結