商品添加
Dao層的實(shí)現(xiàn)
- ProductDao
public interface ProductDao {
/**
* 插入商品
* @param product
* @return
*/
int insertProduct(Product product);
}
- ProductImgDao
public interface ProductImgDao {
/**
* 批量添加圖片
* @param productImgList
* @return
*/
int batchInsertProductImg(List<ProductImg productImgList>);
}
- ProductDao.xml
useGeneratedKeys可以產(chǎn)生一個(gè)主鍵賦值到實(shí)體類當(dāng)中
<insert id="insertProduct" parameterType="com.imooc.o2o.entity.Product"
useGeneratedKeys="true" keyProperty="productId" keyColumn="product_id">
INSERT INTO
tb_product(product_name, product_desc, img_addr,
normal_price, promotion_price, priority, create_time,
last_edit_time, enable_status, product_category_id,
shop_id)
VALUES
(#{productName}, #{productDesc}, #{imgAddr},
#{normalPrice}, #{promotionPrice}, #{priority}, #{createTime},
#{lastEditTime}, #{enableStatus}, #{productCategory.productCategoryId},
#{shop.shopId})
</insert>
- ProductImgDao.xml
<mapper namespace="com.imooc.o2o.dao.ProductImgDao">
<insert id="batchInsertProductImg" parameterType="java.util.List">
INSERT INTO
tb_product_img(img_addr, img_desc, priority,
create_time, product_id)
VALUES
<foreach collection="list" item="productImg" index="index"
separator=",">
(#{productImg.imgAddr},
#{productImg.Desc},
#{productImg.priority},
#{productImg.createTime},
#{productImg.productId}
)
</foreach>
</insert>
- insertProduct測(cè)試
@Test
public void testAInsertProduct() throws Exception {
Shop shop1 = new Shop();
shop1.setShopId(5L);
ProductCategory pc1 = new ProductCategory();
pc1.setProductCategoryId(2L);
Product product1 = new Product();
product1.setProductName("測(cè)試1");
product1.setProductDesc("測(cè)試Desc1");
product1.setImgAddr("test1");
product1.setPriority(0);
product1.setEnableStatus(1);
product1.setCreateTime(new Date());
product1.setShop(shop1);
product1.setProductCategory(pc1);
int effectedNum = productDao.insertProduct(product1);
assertEquals(1, effectedNum);
}
- batchInsertProductImg測(cè)試
@Test
public void testABatchInsertProductImg() throws Exception {
ProductImg productImg1 = new ProductImg();
productImg1.setImgAddr("圖片1");
productImg1.setImgDesc("測(cè)試圖片1");
productImg1.setPriority(1);
productImg1.setCreateTime(new Date());
productImg1.setProductId(4L);
ProductImg productImg2 = new ProductImg();
productImg2.setImgAddr("圖片2");
productImg2.setImgDesc("測(cè)試圖片1");
productImg2.setPriority(1);
productImg2.setCreateTime(new Date());
productImg2.setProductId(4L);
List<ProductImg> productImgList = new ArrayList<ProductImg>();
productImgList.add(productImg1);
productImgList.add(productImg2);
int effectedNum = productImgDao.batchInsertProductImg(productImgList);
assertEquals(2, effectedNum);
service層的實(shí)現(xiàn)
- 接口
/**
* 添加商品以及圖片處理
* @param product
* @param thumbnail
* @param thumbnailName
* @param productImgList
* @param productImgNameList
* @return
* @throws ProductOperationException
*/
ProductExecution addProduct(Product product,
InputStream thumbnail,
String thumbnailName,
List<InputStream> productImgList,
List<String> productImgNameList) throws ProductOperationException;
我們發(fā)現(xiàn)輸出流和文件名含衔,我封裝一下
在dto中新建一個(gè)ImageHolder
package com.imooc.o2o.dto;
import java.io.InputStream;
public class ImageHolder {
private String imageName;
private InputStream image;
public ImageHolder(String imageName, InputStream image) {
this.imageName = imageName;
this.image = image;
}
public String getImageName() {
return imageName;
}
public void setImageName(String imageName) {
this.imageName = imageName;
}
public InputStream getImage() {
return image;
}
public void setImage(InputStream image) {
this.image = image;
}
}
修改一下耘柱,這樣只需要傳遞3個(gè)參數(shù)冤竹,也更清新
/**
* 添加商品以及圖片處理
* @param product
* @param thumbnail
* @param thumbnailName
* @param productImgList
* @param productImgNameList
* @return
* @throws ProductOperationException
*/
ProductExecution addProduct(Product product,
ImageHolder thumbnail,
List<ImageHolder> imageHolderList) throws ProductOperationException;
}
- 實(shí)現(xiàn)類
public class ProductServiceImpl implements ProductService {
@Autowired
private ProductDao productDao;
@Autowired
private ProductImgDao productImgDao;
// 1. 處理縮略圖右核,獲取縮略圖相對(duì)路徑并賦值給product
// 2. 往tb_product寫入商品信息,獲取productId
// 3. 結(jié)合productId批量處理商品詳情圖
// 4. 將商品的詳情圖列表批量插入tb_product_img中
@Override
// 事務(wù)管理
@Transactional
public ProductExecution addProduct(Product product, ImageHolder thumbnail, List<ImageHolder> imageHolderList)
throws ProductOperationException {
// 空值判斷
if (product !=null && product.getShop().getShopId() != null) {
// 給商品設(shè)置默認(rèn)屬性
product.setCreateTime(new Date());
product.setLastEditTime(new Date());
// 默認(rèn)為上架狀態(tài)
product.setEnableStatus(1);
// 若商品縮略圖不為空則添加
if (thumbnail != null) {
addThumbnail(product, thumbnail);
}
try {
// 創(chuàng)建商品信息
int effectNum = productDao.insertProduct(product);
if (effectNum <= 0) {
throw new ProductOperationException("創(chuàng)建商品失敗");
}
} catch (Exception e) {
throw new ProductOperationException("創(chuàng)建商品失敗" + e.getMessage());
}
// 若商品詳情圖不為空則添加
if (imageHolderList != null && imageHolderList.size() > 0) {
addProductImgList(product, imageHolderList);
}
return new ProductExecution(ProductStateEnum.SUCCESS, product);
} else {
// 傳入的參數(shù)為空
return new ProductExecution(ProductStateEnum.EMPTY);
}
}
/**
* 批量添加圖
* @param product
* @param imageHolderList
*/
private void addProductImgList(Product product, List<ImageHolder> imageHolderList) {
// 獲取圖片儲(chǔ)存的路徑少态,這里直接放在相應(yīng)的店鋪的文件夾底下
String dest = PathUtil.getShopImagePath(product.getShop().getShopId());
List<ProductImg> productImgList = new ArrayList<>();
// 遍歷圖片一次去處理,并添加進(jìn)productImg實(shí)體類
for (ImageHolder imageHolder : imageHolderList) {
String imgAddr = ImageUtil.generateNormalImg(imageHolder.getImage(), imageHolder.getImageName(), dest);
ProductImg productImg = new ProductImg();
productImg.setImgAddr(imgAddr);
productImg.setProductId(product.getProductId());
productImg.setCreateTime(new Date());
productImgList.add(productImg);
}
// 如果確實(shí)是有圖片需要添加的 就執(zhí)行批量添加
if (productImgList.size() > 0) {
try {
int effectedNum = productImgDao.batchInsertProductImg(productImgList);
if (effectedNum <= 0) {
throw new ProductOperationException("創(chuàng)建商品詳情圖片失敗");
}
} catch (Exception e) {
throw new ProductOperationException("創(chuàng)建商品詳情圖片失敗" + e.getMessage());
}
}
}
/**
* 添加縮略圖
* @param product
* @param thumbnail
*/
private void addThumbnail(Product product, ImageHolder thumbnail) {
// 獲取根路徑
String dest = PathUtil.getShopImagePath(product.getShop().getShopId());
String thumbnailAddr = ImageUtil.generateThumbnail(thumbnail.getImage(), thumbnail.getImageName(), dest);
product.setImgAddr(thumbnailAddr);
}
}
- 測(cè)試
@Test
public void testaddProduct() throws FileNotFoundException {
Product product = new Product();
Shop shop = new Shop();
shop.setShopId(4L);
ProductCategory productCategory = new ProductCategory();
productCategory.setProductCategoryId(1L);
product.setShop(shop);
product.setProductCategory(productCategory);
product.setProductName("測(cè)試商品1");
product.setProductDesc("測(cè)試");
product.setPriority(0);
// 創(chuàng)建縮略圖文件流
File thumbnailFile = new File("D:\\123.jpg");
InputStream thumbnail = new FileInputStream(thumbnailFile);
ImageHolder imageHolder = new ImageHolder(thumbnailFile.getName(), thumbnail);
// 創(chuàng)建詳情圖片列表
File thumbnailFile2 = new File("D:\\456.png");
InputStream thumbnail2 = new FileInputStream(thumbnailFile2);
ImageHolder imageHolder2 = new ImageHolder(thumbnailFile2.getName(), thumbnail2);
List<ImageHolder> list = new ArrayList<>();
// 不能使用同一個(gè)流, 報(bào)錯(cuò)9埂C自浮!找了好久
// list.add(imageHolder);
list.add(imageHolder2);
// 添加商品并驗(yàn)證
ProductExecution productExecution = productService.addProduct(product, imageHolder, list);
assertEquals(ProductStateEnum.SUCCESS.getState(), productExecution.getState());
-
測(cè)試結(jié)果
image.png
Controller層的實(shí)現(xiàn)
- 顯示編輯頁面
@RequestMapping(value = "/productedit")
public String ProductEdit() {
return "shop/productedit";
}
image.png
- addProduct
@ResponseBody
private Map<String, Object> addProduct(HttpServletRequest request) throws IOException {
Map<String, Object> modelMap = new HashMap<>();
// 驗(yàn)證碼驗(yàn)證
// 接受前端參數(shù)的變量的的初始化鼻吮,包括商品育苟,縮略圖, 詳情圖片實(shí)體
ObjectMapper mapper = new ObjectMapper();
Product product = null;
String productStr = HttpServletRequestUtil.getString(request, "productStr");
System.out.println(productStr);
MultipartHttpServletRequest multipartRequest = null;
ImageHolder thumbnail = null;
List<ImageHolder> productImgList = new ArrayList<>();
// 獲取文件流
CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(
request.getSession().getServletContext());
try {
// 如果請(qǐng)求中存在文件流椎木,則取出相關(guān)文件(包括縮略圖违柏,和詳情圖)
if (multipartResolver.isMultipart(request)) {
multipartRequest = (MultipartHttpServletRequest) request;
// 取出縮略圖并構(gòu)建ImageHolder對(duì)象
CommonsMultipartFile thumbnailFile = (CommonsMultipartFile) multipartRequest.getFile("thumbnail");
thumbnail = new ImageHolder(thumbnailFile.getOriginalFilename(),thumbnailFile.getInputStream());
// 取出詳情圖片列表并構(gòu)建List<ImageHolder>列表,最多支持六張圖片
for (int i = 0; i < IMAGEMAXCOUNT; i++) {
CommonsMultipartFile productImgFile =
(CommonsMultipartFile) multipartRequest.getFile("productImg" + i);
if (productImgFile != null) {
// 如果取出第i個(gè)詳情圖片的文件流不為空 則將其加入列表
ImageHolder productImg = new ImageHolder(
productImgFile.getOriginalFilename(), productImgFile.getInputStream());
productImgList.add(productImg);
} else {
// 若取出的第i個(gè)詳情圖片文件流為空号杠,則終止循環(huán)
break;
}
}
} else {
modelMap.put("success", false);
modelMap.put("errMsg", "上傳圖片不能空");
return modelMap;
}
} catch (Exception e) {
modelMap.put("success", false);
modelMap.put("errMsg", e.getMessage());
return modelMap;
}
try {
// 嘗試獲取前端傳過來的表單string流并將其轉(zhuǎn)化成Product實(shí)體類
product = mapper.readValue(productStr, Product.class);
} catch (Exception e) {
modelMap.put("success", false);
modelMap.put("errMsg", e.getMessage());
return modelMap;
}
// 如果Product信息篙贸,縮略圖已經(jīng)詳情圖片列表都不為空蹈垢,則開始進(jìn)行商品添加操作
if (product != null && thumbnail != null && productImgList.size() > 0) {
try {
// 從session中獲取當(dāng)前的店鋪id并賦值給product 減少對(duì)前端的依賴
Shop currentShop = (Shop) request.getSession().getAttribute("currentShop");
Shop shop = new Shop();
shop.setShopId(currentShop.getShopId());
product.setShop(shop);
// 執(zhí)行并添加操作
ProductExecution pe = productService.addProduct(product, thumbnail, productImgList);
if (pe.getState() == ProductStateEnum.SUCCESS.getState()) {
modelMap.put("success", true);
} else {
modelMap.put("success", false);
modelMap.put("errMsg", pe.getStateInfo());
}
} catch (ProductOperationException e) {
modelMap.put("success", false);
modelMap.put("errMsg", e.getMessage());
return modelMap;
}
} else {
modelMap.put("success", false);
modelMap.put("errMsg", "請(qǐng)輸入商品信息");
}
return modelMap;
}
-
測(cè)試
image.png
image.png
商品編輯
Dao層的實(shí)現(xiàn)
- 接口
/**
* 通過productId查詢唯一商品信息
* @param productId
* @return
*/
Product queryProductById(long productId);
/**
* 更新商品的實(shí)體類
* @param product
* @return
*/
int updateProduct(Product product);
/**
* 刪除指定商品下的所有詳情圖
* @param productId
* @return
*/
int deleteProductImgByProductId(long productId);
- mapper
商品列表展示
Dao層的實(shí)現(xiàn)
- 接口
/**
* 查詢
* @param productCondition
* @param rowIndex
* @param pageSize
* @return
*/
List<Product> queryProductList(@Param("productCondition") Product productCondition,
@Param("rowIndex") int rowIndex,
@Param("pageSize") int pageSize);
/**
* 查詢對(duì)應(yīng)的商品總數(shù)
* @param product
* @return
*/
int queryProductCount(@Param("productCondition") Product product);
- mapper
<select id="queryProductList" resultType="com.imooc.o2o.entity.Product">
SELECT
product_id,
product_name,
product_desc,
img_addr,
normal_price,
priority,
create_time,
last_edit_time,
enable_status,
product_category_id,
shop_id
FROM
tb_product
<where>
<if test="productCondition.shop != null and productCondition.shop.shopId != null">
AND shop_id = #{productCondition.shop.shopId}
</if>
<if test="productCondition.productCategory != null and productCondition.productCategory.productCategoryId != null">
AND product_category_id = #{productCondition.productCategory.productCategoryId}
</if>
<!-- 寫like語句的時(shí)候一般都會(huì)寫成like '% %'在mybaits寫就應(yīng)該寫是like '%${name}%'而不是
'%#{name}%', 因?yàn)?{name}是帶引號(hào)的 而${name}是不帶引號(hào)的 -->
<if test="productCondition.productName != null">
AND product_name LIKE '%${productCondition.productName}%'
</if>
<if test="productCondition.enableStatus != null">
AND enable_status = #{productCondition.enableStatus}
</if>
</where>
ORDER BY
priority DESC
LIMIT #{rowIndex}, #{pageSize}
</select>
<select id="queryProductCount" resultType="int">
SELECT count(1) FROM tb_product
<where>
<if test="productCondition.shop != null and productCondition.shop.shopId != null">
AND shop_id = #{productCondition.shop.shopId}
</if>
<if test="productCondition.productCategory != null and productCondition.productCategory.productCategoryId != null">
AND product_category_id = #{productCondition.productCategory.productCategoryId}
</if>
<!-- 寫like語句的時(shí)候一般都會(huì)寫成like '% %'在mybaits寫就應(yīng)該寫是like '%${name}%'而不是
'%#{name}%', 因?yàn)?{name}是帶引號(hào)的 而${name}是不帶引號(hào)的 -->
<if test="productCondition.productName != null">
AND product_name LIKE '%${productCondition.productName}%'
</if>
<if test="productCondition.enableStatus != null">
AND enable_status = #{productCondition.enableStatus}
</if>
</where>
</select>
- 測(cè)試
@Test
public void testBQueryProductList() throws Exception {
Product product = new Product();
List<Product> productList = productDao.queryProductList(product, 0, 3);
System.out.println(productList.size());
}
service層的實(shí)現(xiàn)
- 接口
/**
* 查詢商品列表并且分頁
* @param productCondition
* @param pageIndex
* @param pageSize
* @return
*/
ProductExecution getProductList(Product productCondition, int pageIndex, int pageSize);
- 實(shí)現(xiàn)類
@Override
public ProductExecution getProductList(Product productCondition, int pageIndex, int pageSize) {
// 頁面轉(zhuǎn)化成數(shù)據(jù)庫的行碼 并調(diào)用dao層取回指定頁碼的商品列表
int rowIndex = PageCalculator.calculateRowIndex(pageIndex, pageSize);
List<Product> productList = productDao.queryProductList(productCondition, rowIndex, pageSize);
// 基于同樣的查詢條件返回該條件下的商品總數(shù)
int count = productDao.queryProductCount(productCondition);
ProductExecution pe = new ProductExecution();
pe.setProductList(productList);
pe.setCount(count);
return pe;
}
Controller層的實(shí)現(xiàn)
- getproductlistbyshop
@RequestMapping(value = "/getproductlistbyshop", method = RequestMethod.GET)
@ResponseBody
private Map<String, Object> getProductListByShop(HttpServletRequest request) {
Map<String, Object> modelMap = new HashMap<>();
// 獲取前臺(tái)傳過來的頁面
int pageIndex = HttpServletRequestUtil.getInt(request, "pageindex");
// 獲取前臺(tái)穿過來的每頁要求返回帶商品上線
int pageSize = HttpServletRequestUtil.getInt(request, "pageSize");
// 從當(dāng)前session中獲取店鋪信息 主要獲取shopId
Shop currentShop = (Shop) request.getSession().getAttribute("currentShop");
// 空值判斷
if ((pageIndex > -1) && (pageSize > -1) && (currentShop != null)) {
// 獲取傳入的需要的檢索條件
long productCategoryId = HttpServletRequestUtil.getLong(request, "categoryId");
String productName = HttpServletRequestUtil.getString(request, "productName");
Product productCadition = compactProductCondition(currentShop.getShopId(), productCategoryId, productName);
// 傳入查詢條件已經(jīng)分頁查詢 返回相應(yīng)的商品列表已經(jīng)總數(shù)
ProductExecution productExecution = productService.getProductList(productCadition, pageIndex, pageSize);
System.out.println("************************");
System.out.println(productExecution.getProductList().size());
System.out.println("************************");
modelMap.put("productList", productExecution.getProductList());
modelMap.put("count", productExecution.getCount());
modelMap.put("success", true);
} else {
modelMap.put("success", false);
modelMap.put("errMsg", "empty pageSize or pageIndex or currentShop!!!");
}
return modelMap;
}
private Product compactProductCondition(Long shopId, long productCategoryId, String productName) {
Product productCondition = new Product();
Shop shop = new Shop();
shop.setShopId(shopId);
productCondition.setShop(shop);
// 如果有指定類別的要求添加進(jìn)去
if (productCategoryId != -1L) {
ProductCategory productCategory = new ProductCategory();
productCategory.setProductCategoryId(productCategoryId);
productCondition.setProductCategory(productCategory);
}
// 如果有商品模糊查詢添加進(jìn)去
if (productName != null) {
productCondition.setProductName(productName);
}
return productCondition;
}
-
測(cè)試結(jié)果
image.png
測(cè)試頁面
image.png
解除商品與商品類別的聯(lián)系
- 前面我們刪除productCategory的時(shí)候沒有把,相應(yīng)的product刪除
@Override
@Transactional
public ProductCategoryExecution deleteProductCategory(long productCategoryId, long shopId) throws ProductCategoryOperationException {
// TODO 將此商品類別下的商品的類別Id置為空
try {
int effectedNum = productCategoryDao.deleteProductCategory(productCategoryId, shopId);
if (effectedNum <= 0) {
throw new ProductCategoryOperationException("店鋪類別刪除失敗");
} else {
return new ProductCategoryExecution(ProductCategoryStateEnum.SUCCESS);
}
} catch (Exception e) {
throw new ProductCategoryOperationException("deleteProductCategory error:" + e.getMessage());
}
}
- Dao層
/**
* 刪除商品類別之前 將商品列表Id設(shè)置類空
* @param categoryId
* @return
*/
int updateProductCategoryToNull(long categoryId);
- mapper
<update id="updateProductCategoryToNull">
UPDATE
tb_product
SET
product_category_id = NULL
WHERE
product_category_id = #{productCategory_id}
</update>
- service層
@Override
@Transactional
public ProductCategoryExecution deleteProductCategory(long productCategoryId, long shopId) throws ProductCategoryOperationException {
// TODO 將此商品類別下的商品的類別Id置為空
try {
int effectNum = productDao.updateProductCategoryToNull(productCategoryId);
if (effectNum < 0) {
throw new ProductCategoryOperationException("店鋪類別刪除失敗");
}
} catch (Exception e) {
throw new ProductCategoryOperationException("店鋪類別刪除失敗" + e.getMessage());
}
try {
int effectedNum = productCategoryDao.deleteProductCategory(productCategoryId, shopId);
if (effectedNum <= 0) {
throw new ProductCategoryOperationException("店鋪類別刪除失敗");
} else {
return new ProductCategoryExecution(ProductCategoryStateEnum.SUCCESS);
}
} catch (Exception e) {
throw new ProductCategoryOperationException("deleteProductCategory error:" + e.getMessage());
}
}
-
測(cè)試
image.png
image.png
product_category_id變?yōu)閚ull了