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

## 步驟 4 : ProductImage
ProductImage直接使用自動生成的,沒有變化,略過不表
## 步驟 5 : ProductImageService
創建ProductImageService,提供CURD。
同時還提供了兩個常量,分別表示單個圖片和詳情圖片:
~~~
String type_single = "type_single";
String type_detail = "type_detail";
~~~
除此之外,還提供了根據產品id和圖片類型查詢的list方法
`List list(int productId, String type);`
~~~
package com.dodoke.tmall.service;
import java.util.List;
import com.dodoke.tmall.pojo.ProductImage;
public interface ProductImageService {
String type_single = "type_single";
String type_detail = "type_detail";
void add(ProductImage pi);
void delete(int id);
void update(ProductImage pi);
ProductImage get(int id);
List list(int productId, String type);
}
~~~
## 步驟 6 : ProductImageServiceImpl
創建ProductImageServiceImpl,實現CURD相關方法
關于list方法,使用了ProductImageExample 類,這樣的寫法表示同時匹配productId和type。
~~~
example.createCriteria().andProductIdEqualTo(productId).andTypeEqualTo(type);
~~~
~~~
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.ProductImageMapper;
import com.dodoke.tmall.pojo.ProductImage;
import com.dodoke.tmall.pojo.ProductImageExample;
import com.dodoke.tmall.service.ProductImageService;
@Service
public class ProductImageServiceImpl implements ProductImageService {
@Autowired
ProductImageMapper productImageMapper;
@Override
public void add(ProductImage pi) {
productImageMapper.insert(pi);
}
@Override
public void delete(int id) {
productImageMapper.deleteByPrimaryKey(id);
}
@Override
public void update(ProductImage pi) {
productImageMapper.updateByPrimaryKeySelective(pi);
}
@Override
public ProductImage get(int id) {
return productImageMapper.selectByPrimaryKey(id);
}
@Override
public List list(int productId, String type) {
ProductImageExample example = new ProductImageExample();
example.createCriteria().andProductIdEqualTo(productId).andTypeEqualTo(type);
example.setOrderByClause("id desc");
return productImageMapper.selectByExample(example);
}
}
~~~
## 步驟 7 : ProductImageController
ProductImageController提供了list,add和delete方法。 edit和update沒有相關業務,所以不提供。
~~~
package com.dodoke.tmall.controller;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.List;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpSession;
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 com.dodoke.tmall.pojo.Product;
import com.dodoke.tmall.pojo.ProductImage;
import com.dodoke.tmall.service.ProductImageService;
import com.dodoke.tmall.service.ProductService;
import com.dodoke.tmall.util.ImageUtil;
import com.dodoke.tmall.util.UploadedImageFile;
@Controller
@RequestMapping("")
public class ProductImageController {
@Autowired
ProductService productService;
@Autowired
ProductImageService productImageService;
/**
* 新增產品圖片
* @param pi 產品圖片對象
* @param session 用于在后續獲取當前應用的路徑
* @param uploadedImageFile 用于接受上傳的圖片
* @return 頁面路徑
*/
@RequestMapping("admin_productImage_add")
public String add(ProductImage pi, HttpSession session, UploadedImageFile uploadedImageFile) {
productImageService.add(pi);
String fileName = pi.getId() + ".jpg";
String imageFolder;
String imageFolder_small = null;
String imageFolder_middle = null;
if (ProductImageService.type_single.equals(pi.getType())) {
imageFolder = session.getServletContext().getRealPath("img/productSingle");
imageFolder_small = session.getServletContext().getRealPath("img/productSingle_small");
imageFolder_middle = session.getServletContext().getRealPath("img/productSingle_middle");
} else {
imageFolder = session.getServletContext().getRealPath("img/productDetail");
}
File f = new File(imageFolder, fileName);
f.getParentFile().mkdirs();
try {
uploadedImageFile.getImage().transferTo(f);
BufferedImage img = ImageUtil.change2jpg(f);
ImageIO.write(img, "jpg", f);
if (ProductImageService.type_single.equals(pi.getType())) {
File f_small = new File(imageFolder_small, fileName);
File f_middle = new File(imageFolder_middle, fileName);
ImageUtil.resizeImage(f, 56, 56, f_small);
ImageUtil.resizeImage(f, 217, 190, f_middle);
}
} catch (Exception e) {
e.printStackTrace();
}
return "redirect:admin_productImage_list?productId=" + pi.getProductId();
}
/**
* 刪除產品圖片
* @param id 產品圖片id
* @param session 用于在后續獲取當前應用的路徑
* @return 頁面路徑
*/
@RequestMapping("admin_productImage_delete")
public String delete(int id, HttpSession session) {
ProductImage pi = productImageService.get(id);
String fileName = pi.getId() + ".jpg";
String imageFolder;
String imageFolder_small = null;
String imageFolder_middle = null;
if (ProductImageService.type_single.equals(pi.getType())) {
imageFolder = session.getServletContext().getRealPath("img/productSingle");
imageFolder_small = session.getServletContext().getRealPath("img/productSingle_small");
imageFolder_middle = session.getServletContext().getRealPath("img/productSingle_middle");
File imageFile = new File(imageFolder, fileName);
File f_small = new File(imageFolder_small, fileName);
File f_middle = new File(imageFolder_middle, fileName);
imageFile.delete();
f_small.delete();
f_middle.delete();
} else {
imageFolder = session.getServletContext().getRealPath("img/productDetail");
File imageFile = new File(imageFolder, fileName);
imageFile.delete();
}
productImageService.delete(id);
return "redirect:admin_productImage_list?productId=" + pi.getProductId();
}
/**
* 產品列表
* @param productId 產品id
* @param model 模型
* @return 頁面路徑
*/
@RequestMapping("admin_productImage_list")
public String list(int productId, Model model) {
Product p = productService.get(productId);
List<ProductImage> pisSingle = productImageService.list(productId, ProductImageService.type_single);
List<ProductImage> pisDetail = productImageService.list(productId, ProductImageService.type_detail);
model.addAttribute("p", p);
model.addAttribute("pisSingle", pisSingle);
model.addAttribute("pisDetail", pisDetail);
return "admin/listProductImage";
}
}
~~~
## 步驟 8 : listProductImage.jsp
增加`listProductImage.jsp`
```
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@include file="../include/admin/adminHeader.jsp"%>
<%@include file="../include/admin/adminNavigator.jsp"%>
<title>產品圖片管理</title>
<div class="workingArea">
<ol class="breadcrumb">
<li><a href="admin_category_list">所有分類</a></li>
<li><a href="admin_product_list?categoryId=${p.category.id}">${p.category.name}</a></li>
<li class="active">${p.name}</li>
<li class="active">產品圖片管理</li>
</ol>
<table class="addPictureTable" align="center">
<tr>
<td class="addPictureTableTD">
<div>
<div class="panel panel-warning addPictureDiv">
<div class="panel-heading">新增產品<b class="text-primary"> 單個 </b>圖片</div>
<div class="panel-body">
<form method="post" class="addFormSingle" action="admin_productImage_add" enctype="multipart/form-data">
<table class="addTable">
<tr>
<td>請選擇本地圖片 尺寸400X400 為佳</td>
</tr>
<tr>
<td>
<input id="filepathSingle" type="file" name="image" />
</td>
</tr>
<tr class="submitTR">
<td align="center">
<input type="hidden" name="type" value="type_single" />
<input type="hidden" name="productId" value="${p.id}" />
<button type="submit" class="btn btn-success">提 交</button>
</td>
</tr>
</table>
</form>
</div>
</div>
<table class="table table-striped table-bordered table-hover table-condensed">
<thead>
<tr class="success">
<th>ID</th>
<th>產品單個圖片縮略圖</th>
<th>刪除</th>
</tr>
</thead>
<tbody>
<c:forEach items="${pisSingle}" var="pi">
<tr>
<td>${pi.id}</td>
<td>
<a title="點擊查看原圖" href="img/productSingle/${pi.id}.jpg"><img height="50px" src="img/productSingle/${pi.id}.jpg"></a>
</td>
<td><a deleteLink="true"
href="admin_productImage_delete?id=${pi.id}"><span
class=" glyphicon glyphicon-trash"></span></a></td>
</tr>
</c:forEach>
</tbody>
</table>
</div>
</td>
<td class="addPictureTableTD">
<div>
<div class="panel panel-warning addPictureDiv">
<div class="panel-heading">新增產品<b class="text-primary"> 詳情 </b>圖片</div>
<div class="panel-body">
<form method="post" class="addFormDetail" action="admin_productImage_add" enctype="multipart/form-data">
<table class="addTable">
<tr>
<td>請選擇本地圖片 寬度790 為佳</td>
</tr>
<tr>
<td>
<input id="filepathDetail" type="file" name="image" />
</td>
</tr>
<tr class="submitTR">
<td align="center">
<input type="hidden" name="type" value="type_detail" />
<input type="hidden" name="productId" value="${p.id}" />
<button type="submit" class="btn btn-success">提 交</button>
</td>
</tr>
</table>
</form>
</div>
</div>
<table class="table table-striped table-bordered table-hover table-condensed">
<thead>
<tr class="success">
<th>ID</th>
<th>產品詳情圖片縮略圖</th>
<th>刪除</th>
</tr>
</thead>
<tbody>
<c:forEach items="${pisDetail}" var="pi">
<tr>
<td>${pi.id}</td>
<td>
<a title="點擊查看原圖" href="img/productDetail/${pi.id}.jpg"><img height="50px" src="img/productDetail/${pi.id}.jpg"></a>
</td>
<td><a deleteLink="true"
href="admin_productImage_delete?id=${pi.id}"><span
class=" glyphicon glyphicon-trash"></span></a></td>
</tr>
</c:forEach>
</tbody>
</table>
</div>
</td>
</tr>
</table>
</div>
<script>
$(function(){
$(".addFormSingle").submit(function(){
if(checkEmpty("filepathSingle","圖片文件")){
$("#filepathSingle").value("");
return true;
}
return false;
});
$(".addFormDetail").submit(function(){
if(checkEmpty("filepathDetail","圖片文件"))
return true;
return false;
});
});
</script>
```
## 步驟 9 : 查詢功能講解
通過產品頁面的圖片管理訪問ProductImageController的list()方法
1. 獲取參數productId
2. 根據productId獲取Product對象
3. 根據productId對象獲取單個圖片的集合pisSingle
4. 根據productId對象獲取詳情圖片的集合pisDetail
5. 把product 對象,pisSingle ,pisDetail放在model上
6. 服務端跳轉到admin/listProductImage.jsp頁面
7. 在listProductImage.jsp,使用c:forEach 遍歷pisSingle
8. 在listProductImage.jsp,使用c:forEach 遍歷pisDetail

ProductImageController:
~~~
@RequestMapping("admin_productImage_list")
public String list(int productId, Model model) {
Product p = productService.get(productId);
List<ProductImage> pisSingle = productImageService.list(productId, ProductImageService.type_single);
List<ProductImage> pisDetail = productImageService.list(productId, ProductImageService.type_detail);
model.addAttribute("p", p);
model.addAttribute("pisSingle", pisSingle);
model.addAttribute("pisDetail", pisDetail);
return "admin/listProductImage";
}
~~~
listProductImage.jsp 片段1:
~~~
<c:forEach items="${pisSingle}" var="pi">
<tr>
<td>${pi.id}</td>
<td>
<a title="點擊查看原圖" href="img/productSingle/${pi.id}.jpg"><img height="50px" src="img/productSingle/${pi.id}.jpg"></a>
</td>
<td><a deleteLink="true"
href="admin_productImage_delete?id=${pi.id}"><span
class=" glyphicon glyphicon-trash"></span></a></td>
</tr>
</c:forEach>
~~~
listProductImage.jsp 片段2:
~~~
<c:forEach items="${pisDetail}" var="pi">
<tr>
<td>${pi.id}</td>
<td>
<a title="點擊查看原圖" href="img/productDetail/${pi.id}.jpg"><img height="50px" src="img/productDetail/${pi.id}.jpg"></a>
</td>
<td><a deleteLink="true"
href="admin_productImage_delete?id=${pi.id}"><span
class=" glyphicon glyphicon-trash"></span></a></td>
</tr>
</c:forEach>
~~~
## 步驟 10 : 增加功能講解
增加產品圖片分單個和詳情兩種,其區別在于增加所提交的type類型不一樣。
這里就對單個的進行講解,詳情圖片的處理同理。
首先, 在listProductImage.jsp準備一個form,提交到admin_productImage_add
<form method="post" class="addFormSingle" action="admin_productImage_add" enctype="multipart/form-data">
接著在ProductImageController的add()方法中進行處理
1. 通過pi對象接受type和productId的注入
2. 借助productImageService,向數據庫中插入數據。
3. 根據session().getServletContext().getRealPath( "img/productSingle"),定位到存放單個產品圖片的目錄
除了productSingle,還有productSingle_middle和productSingle_small。 因為每上傳一張圖片,都會有對應的正常,中等和小的三種大小圖片,并且放在3個不同的目錄下
4. 文件命名以保存到數據庫的產品圖片對象的id+".jpg"的格式命名
5. 通過uploadedImageFile保存文件
6. 借助ImageUtil.change2jpg()方法把格式真正轉化為jpg,而不僅僅是后綴名為.jpg
7. 再借助ImageUtil.resizeImage把正常大小的圖片,改變大小之后,分別復制到productSingle_middle和productSingle_small目錄下。
8. 處理完畢之后,客戶端條跳轉到admin_productImage_list?productId=,并帶上productId。
詳情圖片做的是一樣的事情,區別在于復制到目錄productDetail下,并且不需要改變大小
> 注:ImageUtil.resizeImage 使用了swing自帶的修改圖片大小的API,底層工作原理不必深入研究,反正這么寫就行了。


listProductImage.jsp 片段:
~~~
<form method="post" class="addFormSingle" action="admin_productImage_add" enctype="multipart/form-data">
<table class="addTable">
<tr>
<td>請選擇本地圖片 尺寸400X400 為佳</td>
</tr>
<tr>
<td>
<input id="filepathSingle" type="file" name="image" />
</td>
</tr>
<tr class="submitTR">
<td align="center">
<input type="hidden" name="type" value="type_single" />
<input type="hidden" name="productId" value="${p.id}" />
<button type="submit" class="btn btn-success">提 交</button>
</td>
</tr>
</table>
</form>
~~~
ProductImageController.add():
~~~
/**
* 新增產品圖片
* @param pi 產品圖片對象
* @param session 用于在后續獲取當前應用的路徑
* @param uploadedImageFile 用于接受上傳的圖片
* @return 頁面路徑
*/
@RequestMapping("admin_productImage_add")
public String add(ProductImage pi, HttpSession session, UploadedImageFile uploadedImageFile) {
productImageService.add(pi);
String fileName = pi.getId() + ".jpg";
String imageFolder;
String imageFolder_small = null;
String imageFolder_middle = null;
if (ProductImageService.type_single.equals(pi.getType())) {
imageFolder = session.getServletContext().getRealPath("img/productSingle");
imageFolder_small = session.getServletContext().getRealPath("img/productSingle_small");
imageFolder_middle = session.getServletContext().getRealPath("img/productSingle_middle");
} else {
imageFolder = session.getServletContext().getRealPath("img/productDetail");
}
File f = new File(imageFolder, fileName);
f.getParentFile().mkdirs();
try {
uploadedImageFile.getImage().transferTo(f);
BufferedImage img = ImageUtil.change2jpg(f);
ImageIO.write(img, "jpg", f);
if (ProductImageService.type_single.equals(pi.getType())) {
File f_small = new File(imageFolder_small, fileName);
File f_middle = new File(imageFolder_middle, fileName);
ImageUtil.resizeImage(f, 56, 56, f_small);
ImageUtil.resizeImage(f, 217, 190, f_middle);
}
} catch (Exception e) {
e.printStackTrace();
}
return "redirect:admin_productImage_list?productId=" + pi.getProductId();
}
~~~
## 步驟 11 : 刪除功能講解
點擊刪除超鏈,進入ProductImageController的delete方法
1. 獲取id
2. 根據id獲取ProductImage 對象pi
3. 借助productImageService,刪除數據
4. 如果是單個圖片,那么刪除3張正常,中等,小號圖片
5. 如果是詳情圖片,那么刪除一張圖片
6. 客戶端跳轉到admin_productImage_list地址
~~~
/**
* 刪除產品圖片
* @param id 產品圖片id
* @param session 用于在后續獲取當前應用的路徑
* @return 頁面路徑
*/
@RequestMapping("admin_productImage_delete")
public String delete(int id, HttpSession session) {
ProductImage pi = productImageService.get(id);
String fileName = pi.getId() + ".jpg";
String imageFolder;
String imageFolder_small = null;
String imageFolder_middle = null;
if (ProductImageService.type_single.equals(pi.getType())) {
imageFolder = session.getServletContext().getRealPath("img/productSingle");
imageFolder_small = session.getServletContext().getRealPath("img/productSingle_small");
imageFolder_middle = session.getServletContext().getRealPath("img/productSingle_middle");
File imageFile = new File(imageFolder, fileName);
File f_small = new File(imageFolder_small, fileName);
File f_middle = new File(imageFolder_middle, fileName);
imageFile.delete();
f_small.delete();
f_middle.delete();
} else {
imageFolder = session.getServletContext().getRealPath("img/productDetail");
File imageFile = new File(imageFolder, fileName);
imageFile.delete();
}
productImageService.delete(id);
return "redirect:admin_productImage_list?productId=" + pi.getProductId();
}
~~~
## 步驟 12 : 編輯和修改
因為只有圖片,就不提供編輯和修改功能。**要做修改,先刪除,再增加即可**。
## 步驟 13 : Product
回到產品管理里的**頁面截圖**,在產品列表頁面,是沒有圖片的。 因為當時還沒有產品圖片管理功能,現在支持了,所以需要對Product做一些調整。
新增屬性:
`private ProductImage firstProductImage;`

~~~
package com.dodoke.tmall.pojo;
import java.util.Date;
public class Product {
private Integer id;
private String name;
private String subTitle;
private Float originalPrice;
private Float promotePrice;
private Integer stock;
private Date createDate;
private Integer categoryId;
/*非數據庫字段*/
private Category category;
private ProductImage firstProductImage;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name == null ? null : name.trim();
}
public String getSubTitle() {
return subTitle;
}
public void setSubTitle(String subTitle) {
this.subTitle = subTitle == null ? null : subTitle.trim();
}
public Float getOriginalPrice() {
return originalPrice;
}
public void setOriginalPrice(Float originalPrice) {
this.originalPrice = originalPrice;
}
public Float getPromotePrice() {
return promotePrice;
}
public void setPromotePrice(Float promotePrice) {
this.promotePrice = promotePrice;
}
public Integer getStock() {
return stock;
}
public void setStock(Integer stock) {
this.stock = stock;
}
public Date getCreateDate() {
return createDate;
}
public void setCreateDate(Date createDate) {
this.createDate = createDate;
}
public Integer getCategoryId() {
return categoryId;
}
public void setCategoryId(Integer categoryId) {
this.categoryId = categoryId;
}
public Category getCategory() {
return category;
}
public void setCategory(Category category) {
this.category = category;
}
public ProductImage getFirstProductImage() {
return firstProductImage;
}
public void setFirstProductImage(ProductImage firstProductImage) {
this.firstProductImage = firstProductImage;
}
}
~~~
## 步驟 14 : ProductService
新增方法:
` void setFirstProductImage(Product p);`
~~~
package com.dodoke.tmall.service;
import java.util.List;
import com.dodoke.tmall.pojo.Product;
public interface ProductService {
void add(Product c);
void delete(int id);
void update(Product c);
Product get(int id);
List list(int categoryId);
void setFirstProductImage(Product p);
}
~~~
## 步驟 15 : ProductServiceImpl
增加方法 setFirstProductImage(Product p):
根據productId和圖片類型查詢出所有的單個圖片,然后把第一個取出來放在firstProductImage上。
增加方法 setFirstProductImage(List<Product> ps)
給多個產品設置圖片
在get方法中調用setFirstProductImage(Product p) 為單個產品設置圖片
在list方法中調用setFirstProductImage(List<Product> ps) 為多個產品設置圖片
~~~
package com.dodoke.tmall.service.impl;
import java.util.Date;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.dodoke.tmall.mapper.ProductMapper;
import com.dodoke.tmall.pojo.Category;
import com.dodoke.tmall.pojo.Product;
import com.dodoke.tmall.pojo.ProductExample;
import com.dodoke.tmall.pojo.ProductImage;
import com.dodoke.tmall.service.CategoryService;
import com.dodoke.tmall.service.ProductImageService;
import com.dodoke.tmall.service.ProductService;
@Service
public class ProductServiceImpl implements ProductService {
@Autowired
ProductMapper productMapper;
@Autowired
CategoryService categoryService;
@Autowired
ProductImageService productImageService;
@Override
public void add(Product p) {
p.setCreateDate(new Date());
productMapper.insert(p);
}
@Override
public void delete(int id) {
productMapper.deleteByPrimaryKey(id);
}
@Override
public void update(Product p) {
productMapper.updateByPrimaryKeySelective(p);
}
@Override
public Product get(int id) {
Product p = productMapper.selectByPrimaryKey(id);
setFirstProductImage(p);
setCategory(p);
return p;
}
private void setCategory(Product p) {
int categoryId = p.getCategoryId();
Category category = categoryService.get(categoryId);
p.setCategory(category);
}
@Override
public List list(int categoryId) {
ProductExample example = new ProductExample();
example.createCriteria().andCategoryIdEqualTo(categoryId);
example.setOrderByClause("id desc");
List result = productMapper.selectByExample(example);
setFirstProductImage(result);
setCategory(result);
return result;
}
public void setCategory(List<Product> ps) {
for (Product p : ps) {
setCategory(p);
}
}
/**
* 根據productId和圖片類型查詢出所有的單個圖片,然后把第一個取出來放在firstProductImage上。
* @param p 產品
*/
@Override
public void setFirstProductImage(Product p) {
List<ProductImage> pis = productImageService.list(p.getId(), ProductImageService.type_single);
if (!pis.isEmpty()) {
ProductImage pi = pis.get(0);
p.setFirstProductImage(pi);
}
}
/**
* 給多個產品設置圖片
* @param ps 產品集合
*/
public void setFirstProductImage(List<Product> ps) {
for (Product p : ps) {
setFirstProductImage(p);
}
}
}
~~~
## 步驟 16 : listProduct.jsp
去掉關于圖片顯示的注釋
~~~
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@include file="../include/admin/adminHeader.jsp"%>
<%@include file="../include/admin/adminNavigator.jsp"%>
<title>產品管理</title>
<div class="workingArea">
<ol class="breadcrumb">
<li><a href="admin_category_list">所有分類</a></li>
<li><a href="admin_product_list?categoryId=${c.id}">${c.name}-產品</a></li>
<li class="active">產品管理</li>
</ol>
<div class="listDataTableDiv">
<table class="table table-striped table-bordered table-hover table-condensed">
<thead>
<tr class="success">
<th>ID</th>
<th>圖片</th>
<th>產品名稱</th>
<th>產品小標題</th>
<th width="53px">原價格</th>
<th width="80px">優惠價格</th>
<th width="80px">庫存數量</th>
<th width="80px">圖片管理</th>
<th width="80px">設置屬性</th>
<th width="42px">編輯</th>
<th width="42px">刪除</th>
</tr>
</thead>
<tbody>
<c:forEach items="${ps}" var="p">
<tr>
<td>${p.id}</td>
<td>
<c:if test="${!empty p.firstProductImage}">
<img width="40px" src="img/productSingle/${p.firstProductImage.id}.jpg">
</c:if>
</td>
<td>${p.name}</td>
<td>${p.subTitle}</td>
<td>${p.originalPrice}</td>
<td>${p.promotePrice}</td>
<td>${p.stock}</td>
<td><a href="admin_productImage_list?productId=${p.id}"><span
class="glyphicon glyphicon-picture"></span></a></td>
<td><a href="admin_propertyValue_edit?productId=${p.id}"><span
class="glyphicon glyphicon-th-list"></span></a></td>
<td><a href="admin_product_edit?id=${p.id}"><span
class="glyphicon glyphicon-edit"></span></a></td>
<td><a deleteLink="true"
href="admin_product_delete?id=${p.id}"><span
class=" glyphicon glyphicon-trash"></span></a></td>
</tr>
</c:forEach>
</tbody>
</table>
</div>
<div class="pageDiv">
<%@include file="../include/admin/adminPage.jsp" %>
</div>
<div class="panel panel-warning addDiv">
<div class="panel-heading">新增產品</div>
<div class="panel-body">
<form method="post" id="addForm" action="admin_product_add" enctype="multipart/form-data">
<table class="addTable">
<tr>
<td>產品名稱</td>
<td><input id="name" name="name" type="text" class="form-control"></td>
</tr>
<tr>
<td>產品小標題</td>
<td><input id="subTitle" name="subTitle" type="text"
class="form-control"></td>
</tr>
<tr>
<td>原價格</td>
<td><input id="originalPrice" value="99.98" name="originalPrice" type="text"
class="form-control"></td>
</tr>
<tr>
<td>優惠價格</td>
<td><input id="promotePrice" value="19.98" name="promotePrice" type="text"
class="form-control"></td>
</tr>
<tr>
<td>庫存</td>
<td><input id="stock" value="99" name="stock" type="text"
class="form-control"></td>
</tr>
<tr class="submitTR">
<td colspan="2" align="center">
<input type="hidden" name="categoryId" value="${c.id}">
<button type="submit" class="btn btn-success">提 交</button>
</td>
</tr>
</table>
</form>
</div>
</div>
</div>
<%@include file="../include/admin/adminFooter.jsp"%>
<script>
$(function(){
$("#addForm").submit(function(){
if(!checkEmpty("name","產品名稱")) {
return false;
}
// if (!checkEmpty("subTitle", "小標題"))
// return false;
if (!checkNumber("originalPrice", "原價格"))
return false;
if (!checkNumber("promotePrice", "優惠價格"))
return false;
if (!checkInt("stock", "庫存"))
return false;
return true;
});
});
</script>
~~~
## 步驟 17 : 產品縮略圖效果

- 項目簡介
- 功能一覽
- 前臺
- 后臺
- 開發流程
- 需求分析-展示
- 首頁
- 產品頁
- 分類頁
- 搜索結果頁
- 購物車查看頁
- 結算頁
- 確認支付頁
- 支付成功頁
- 我的訂單頁
- 確認收貨頁
- 確認收貨成功頁
- 評價頁
- 需求分析-交互
- 分類頁排序
- 立即購買
- 加入購物車
- 調整訂單項數量
- 刪除訂單項
- 生成訂單
- 訂單頁功能
- 確認付款
- 確認收貨
- 提交評價信息
- 登錄
- 注冊
- 退出
- 搜索
- 前臺需求列表
- 需求分析后臺
- 分類管理
- 屬性管理
- 產品管理
- 產品圖片管理
- 產品屬性設置
- 用戶管理
- 訂單管理
- 后臺需求列表
- 表結構設計
- 數據建模
- 表與表之間的關系
- 后臺-分類管理
- 可運行的項目
- 靜態資源
- JSP包含關系
- 查詢
- 分頁
- 增加
- 刪除
- 編輯
- 修改
- 做一遍
- 重構
- 分頁方式
- 分類逆向工程
- 所有逆向工程
- 后臺其他頁面
- 屬性管理實現
- 產品管理實現
- 產品圖片管理實現
- 產品屬性值設置
- 用戶管理實現
- 訂單管理實現
- 前端
- 前臺-首頁
- 可運行的項目
- 靜態資源
- ForeController
- home方法
- home.jsp
- homePage.jsp
- 前臺-無需登錄
- 注冊
- 登錄
- 退出
- 產品頁
- 模態登錄
- 分類頁
- 搜索
- 前臺-需要登錄
- 購物流程
- 立即購買
- 結算頁面
- 加入購物車
- 查看購物車頁面
- 登錄狀態攔截器
- 其他攔截器
- 購物車頁面操作
- 訂單狀態圖
- 生成訂單
- 我的訂單頁
- 我的訂單頁操作
- 評價產品
- 總結