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

# 步驟 4 : ProductImage,ProductImageDao,ProductImageDaoImpl
見產品管理章節
# 步驟 5 : ProductImageServlet類
ProductImageServlet提供了list,add和delete方法。 edit和update方法直接返回null. 因為界面上沒有修改功能
```
package com.dodoke.controller;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.imageio.ImageIO;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.dodoke.bean.Product;
import com.dodoke.bean.ProductImage;
import com.dodoke.dao.inter.ProductImageDao;
import com.dodoke.util.ImageUtil;
import com.dodoke.util.Page;
/**
* Servlet implementation class ProductImageServlet
*/
@WebServlet("/ProductImageServlet")
public class ProductImageServlet extends BaseBackServlet {
private static final long serialVersionUID = 1L;
@Override
public String add(HttpServletRequest request, HttpServletResponse response) {
// 上傳文件的輸入流
InputStream is = null;
// 提交上傳文件時的其他參數
Map<String, String> params = new HashMap<>();
// 解析上傳
is = parseUpload(request, params);
// 根據上傳的參數生成productImage對象
String type = params.get("type");
int pid = Integer.parseInt(params.get("pid"));
Product p = productDao.get(pid);
ProductImage pi = new ProductImage();
pi.setType(type);
pi.setProduct(p);
productImageDao.add(pi);
// 生成文件
String fileName = pi.getId() + ".jpg";
String imageFolder;
String imageFolder_small = null;
String imageFolder_middle = null;
if (ProductImageDao.type_single.equals(pi.getType())) {
imageFolder = request.getSession().getServletContext().getRealPath("img/productSingle");
imageFolder_small = request.getSession().getServletContext().getRealPath("img/productSingle_small");
imageFolder_middle = request.getSession().getServletContext().getRealPath("img/productSingle_middle");
} else {
imageFolder = request.getSession().getServletContext().getRealPath("img/productDetail");
}
File f = new File(imageFolder, fileName);
f.getParentFile().mkdirs();
// 復制文件
try {
if (null != is && 0 != is.available()) {
try (FileOutputStream fos = new FileOutputStream(f)) {
byte b[] = new byte[1024 * 1024];
int length = 0;
while (-1 != (length = is.read(b))) {
fos.write(b, 0, length);
}
fos.flush();
// 通過如下代碼,把文件保存為jpg格式
BufferedImage img = ImageUtil.change2jpg(f);
ImageIO.write(img, "jpg", f);
if (ProductImageDao.type_single.equals(pi.getType())) {
File f_small = new File(imageFolder_small, fileName);
File f_middle = new File(imageFolder_middle, fileName);
f_small.getParentFile().mkdirs();
f_middle.getParentFile().mkdirs();
ImageUtil.resizeImage(f, 56, 56, f_small);
ImageUtil.resizeImage(f, 217, 190, f_middle);
}
} catch (Exception e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
return "@admin_productImage_list?pid=" + p.getId();
}
@Override
public String delete(HttpServletRequest request, HttpServletResponse response) {
int id = Integer.parseInt(request.getParameter("id"));
ProductImage pi = productImageDao.get(id);
productImageDao.delete(id);
if (ProductImageDao.type_single.equals(pi.getType())) {
String imageFolder_single = request.getSession().getServletContext().getRealPath("img/productSingle");
String imageFolder_small = request.getSession().getServletContext().getRealPath("img/productSingle_small");
String imageFolder_middle = request.getSession().getServletContext()
.getRealPath("img/productSingle_middle");
File f_single = new File(imageFolder_single, pi.getId() + ".jpg");
f_single.delete();
File f_small = new File(imageFolder_small, pi.getId() + ".jpg");
f_small.delete();
File f_middle = new File(imageFolder_middle, pi.getId() + ".jpg");
f_middle.delete();
} else {
String imageFolder_detail = request.getSession().getServletContext().getRealPath("img/productDetail");
File f_detail = new File(imageFolder_detail, pi.getId() + ".jpg");
f_detail.delete();
}
return "@admin_productImage_list?pid=" + pi.getProduct().getId();
}
@Override
public String edit(HttpServletRequest request, HttpServletResponse response) {
// TODO Auto-generated method stub
return null;
}
@Override
public String update(HttpServletRequest request, HttpServletResponse response) {
// TODO Auto-generated method stub
return null;
}
@Override
public String list(HttpServletRequest request, HttpServletResponse response, Page page) {
int pid = Integer.parseInt(request.getParameter("pid"));
Product p = productDao.get(pid);
List<ProductImage> pisSingle = productImageDao.list(p, ProductImageDao.type_single);
List<ProductImage> pisDetail = productImageDao.list(p, ProductImageDao.type_detail);
request.setAttribute("p", p);
request.setAttribute("pisSingle", pisSingle);
request.setAttribute("pisDetail", pisDetail);
return "admin/listProductImage.jsp";
}
}
```
# 步驟 6:listProductImage.jsp
```
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" import="java.util.*"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@include file="../include/admin/adminHeader.jsp"%>
<%@include file="../include/admin/adminNavigator.jsp"%>
<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>
<title>產品圖片管理</title>
<div class="workingArea">
<ol class="breadcrumb">
<li><a href="admin_category_list">所有分類</a></li>
<li><a href="admin_product_list?cid=${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="filepath" /></td>
</tr>
<tr class="submitTR">
<td align="center"><input type="hidden" name="type" value="type_single" /> <input type="hidden" name="pid" 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="filepath" /></td>
</tr>
<tr class="submitTR">
<td align="center"><input type="hidden" name="type" value="type_detail" /> <input type="hidden" name="pid" 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>
<%@include file="../include/admin/adminFooter.jsp"%>
```
# 步驟 7 : 查詢功能講解
通過產品頁面的圖片管理訪問ProductImageServlet的list()方法
1\. 獲取參數pid
2\. 根據pid獲取Product對象
3\. 根據product對象獲取單個圖片的集合pisSingle
4\. 根據product對象獲取詳情圖片的集合pisDetail
5\. 把product 對象,pisSingle ,pisDetail放在request上
6\. 服務端跳轉到admin/listProductImage.jsp頁面
7\. 在listProductImage.jsp,使用c:forEach 遍歷pisSingle
8\. 在listProductImage.jsp,使用c:forEach 遍歷pisDetail
ProductImageServlet
```
@Override
public String list(HttpServletRequest request, HttpServletResponse response, Page page) {
int pid = Integer.parseInt(request.getParameter("pid"));
Product p = productDao.get(pid);
List<ProductImage> pisSingle = productImageDao.list(p, ProductImageDao.type_single);
List<ProductImage> pisDetail = productImageDao.list(p, ProductImageDao.type_detail);
request.setAttribute("p", p);
request.setAttribute("pisSingle", pisSingle);
request.setAttribute("pisDetail", pisDetail);
return "admin/listProductImage.jsp";
}
```
listProductImage片段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片段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>
```
# 步驟 8 : 增加功能講解
增加產品圖片分單個和詳情兩種,其區別在于增加的提交的type類型不一樣。
這里就對單個的進行講解,詳情圖片的處理同理。
首先, 在listProductImage.jsp準備一個form,提交到admin\_productImage\_add
```
<form method="post" class="addFormSingle" action="admin_productImage_add" enctype="multipart/form-data">
```
接著在ProductImageServlet的add()方法中進行處理
1\. parseUpload 獲取上傳文件的輸入流
2\. parseUpload 方法會修改params 參數,并且把瀏覽器提交的type,pid信息放在其中
3\. 從params 中取出type,pid信息,并根據這個type,pid,借助productImageDAO,向數據庫中插入數據。
4\. 根據request.getSession().getServletContext().getRealPath( "img/productSingle"),定位到存放分類圖片的目錄
除了productSingle,還有productSingle\_middle和productSingle\_small。 因為每上傳一張圖片,都會有對應的正常,中等和小的三種大小圖片,并且放在3個不同的目錄下
5\. 文件命名以保存到數據庫的分類對象的id+".jpg"的格式命名
6\. 根據步驟1獲取的輸入流,把瀏覽器提交的文件,復制到目標文件
7\. 借助ImageUtil.change2jpg()方法把格式真正轉化為jpg,而不僅僅是后綴名為.jpg
8\. 再借助ImageUtil.resizeImage把正常大小的圖片,改變大小之后,分別復制到productSingle\_middle和productSingle\_small目錄下。
9\. 處理完畢之后,客戶端條跳轉到admin\_productImage\_list?pid=,并帶上pid。
詳情圖片做的是一樣的事情,區別在于復制到目錄productDetail下,并且不需要改變大小。
listProductImage
```
<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="filepath" /></td>
</tr>
<tr class="submitTR">
<td align="center"><input type="hidden" name="type" value="type_single" /> <input type="hidden" name="pid" value="${p.id}" />
<button type="submit" class="btn btn-success">提 交</button></td>
</tr>
</table>
</form>
```
ProductImageServlet
```
public String add(HttpServletRequest request, HttpServletResponse response) {
// 上傳文件的輸入流
InputStream is = null;
// 提交上傳文件時的其他參數
Map<String, String> params = new HashMap<>();
// 解析上傳
is = parseUpload(request, params);
// 根據上傳的參數生成productImage對象
String type = params.get("type");
int pid = Integer.parseInt(params.get("pid"));
Product p = productDao.get(pid);
ProductImage pi = new ProductImage();
pi.setType(type);
pi.setProduct(p);
productImageDao.add(pi);
// 生成文件
String fileName = pi.getId() + ".jpg";
String imageFolder;
String imageFolder_small = null;
String imageFolder_middle = null;
if (ProductImageDao.type_single.equals(pi.getType())) {
imageFolder = request.getSession().getServletContext().getRealPath("img/productSingle");
imageFolder_small = request.getSession().getServletContext().getRealPath("img/productSingle_small");
imageFolder_middle = request.getSession().getServletContext().getRealPath("img/productSingle_middle");
} else {
imageFolder = request.getSession().getServletContext().getRealPath("img/productDetail");
}
File f = new File(imageFolder, fileName);
f.getParentFile().mkdirs();
// 復制文件
try {
if (null != is && 0 != is.available()) {
try (FileOutputStream fos = new FileOutputStream(f)) {
byte b[] = new byte[1024 * 1024];
int length = 0;
while (-1 != (length = is.read(b))) {
fos.write(b, 0, length);
}
fos.flush();
// 通過如下代碼,把文件保存為jpg格式
BufferedImage img = ImageUtil.change2jpg(f);
ImageIO.write(img, "jpg", f);
if (ProductImageDao.type_single.equals(pi.getType())) {
File f_small = new File(imageFolder_small, fileName);
File f_middle = new File(imageFolder_middle, fileName);
f_small.getParentFile().mkdirs();
f_middle.getParentFile().mkdirs();
ImageUtil.resizeImage(f, 56, 56, f_small);
ImageUtil.resizeImage(f, 217, 190, f_middle);
}
} catch (Exception e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
return "@admin_productImage_list?pid=" + p.getId();
}
```
# 步驟 9 : 刪除功能講解
點擊刪除超鏈,進入ProductImageServlet的delete方法
1\. 獲取id
2\. 根據id獲取ProductImage 對象pi
3\. 借助productImageDAO,刪除數據
4\. 如果是單個圖片,那么刪除3張正常,中等,小號圖片
5\. 如果是詳情圖片,那么刪除一張圖片
6\. 客戶端跳轉到admin\_productImage\_list地址
```
public String delete(HttpServletRequest request, HttpServletResponse response) {
int id = Integer.parseInt(request.getParameter("id"));
ProductImage pi = productImageDao.get(id);
productImageDao.delete(id);
if (ProductImageDao.type_single.equals(pi.getType())) {
String imageFolder_single = request.getSession().getServletContext().getRealPath("img/productSingle");
String imageFolder_small = request.getSession().getServletContext().getRealPath("img/productSingle_small");
String imageFolder_middle = request.getSession().getServletContext()
.getRealPath("img/productSingle_middle");
File f_single = new File(imageFolder_single, pi.getId() + ".jpg");
f_single.delete();
File f_small = new File(imageFolder_small, pi.getId() + ".jpg");
f_small.delete();
File f_middle = new File(imageFolder_middle, pi.getId() + ".jpg");
f_middle.delete();
} else {
String imageFolder_detail = request.getSession().getServletContext().getRealPath("img/productDetail");
File f_detail = new File(imageFolder_detail, pi.getId() + ".jpg");
f_detail.delete();
}
return "@admin_productImage_list?pid=" + pi.getProduct().getId();
}
```
# 步驟10:編輯和修改
因為只有圖片,就不提供編輯和修改功能。 要做修改,先刪除,再增加即可
- 項目簡介
- 功能一覽
- 前臺
- 后臺
- 開發流程
- 需求分析-展示
- 首頁
- 產品頁
- 分類頁
- 搜索結果頁
- 購物車查看頁
- 結算頁
- 確認支付頁
- 支付成功頁
- 我的訂單頁
- 確認收貨頁
- 評價頁
- 頁頭信息展示
- 需求分析-交互
- 分類頁排序
- 立即購買
- 加入購物車
- 調整訂單項數量
- 刪除訂單項
- 生成訂單
- 訂單頁功能
- 確認付款
- 確認收貨
- 提交評價信息
- 登錄
- 注冊
- 退出
- 搜索
- 前臺需求列表
- 需求分析后臺
- 分類管理
- 屬性管理
- 產品管理
- 產品圖片管理
- 產品屬性設置
- 用戶管理
- 訂單管理
- 后臺需求列表
- 表結構設計
- 數據建模
- 表與表之間的關系
- 實體類設計
- DAO類設計
- 工具類
- CategoryDao設計
- Service業務類設計
- 后臺-分類管理
- 可運行的項目
- 靜態資源
- FILTER配合SERVLET
- JSP包含關系
- 查詢
- 分頁
- 增加
- 刪除
- 編輯
- 修改
- 后臺其他管理
- 屬性管理
- 產品管理
- 產品圖片管理
- 產品屬性值設置
- 用戶管理
- 訂單管理