商铺项目(商品类别模块二)

商品编辑的后端开发:

package com.ouyan.o2o.dao;

import java.util.List;

import org.apache.ibatis.annotations.Param;

import com.ouyan.o2o.entity.Product;

public interface ProductDao {
    /**
     * 查询商品列表并分页,可输入的条件有: 商品名(模糊),商品状态,店铺Id,商品类别
     * 
     * @param productCondition
     * @param beginIndex
     * @param pageSize
     * @return
     */
    List<Product> queryProductList(@Param("productCondition") Product productCondition, @Param("rowIndex") int rowIndex,
            @Param("pageSize") int pageSize);

    /**
     * 查询对应的商品总数
     * 
     * @param productCondition
     * @return
     */
    int queryProductCount(@Param("productCondition") Product productCondition);

    /**
     * 通过productId查询唯一的商品信息
     * 
     * @param productId
     * @return
     */
    Product queryProductById(long productId);

    /**
     * 插入商品
     * 
     * @param product
     * @return
     */
    int insertProduct(Product product);

    /**
     * 更新商品信息
     * 
     * @param product
     * @return
     */
    int updateProduct(Product product);

    /**
     * 删除商品类别之前,将商品类别ID置为空
     * 
     * @param productCategoryId
     * @return
     */
    int updateProductCategoryToNull(long productCategoryId);

    /**
     * 删除商品
     * 
     * @param productId
     * @return
     */
    int deleteProduct(@Param("productId") long productId, @Param("shopId") long shopId);
}
package com.ouyan.o2o.dao;

import java.util.List;

import com.ouyan.o2o.entity.ProductImg;

public interface ProductImgDao {

    /**
     * 列出某个商品的详情图列表
     * 
     * @param productId
     * @return
     */
    List<ProductImg> queryProductImgList(long productId);

    /**
     * 批量添加商品详情图片
     * 
     * @param productImgList
     * @return
     */
    int batchInsertProductImg(List<ProductImg> productImgList);

    /**
     * 删除指定商品下的所有详情图
     * 
     * @param productId
     * @return
     */
    int deleteProductImgByProductId(long productId);
}
package com.ouyan.o2o.dao;

import java.util.List;

import org.apache.ibatis.annotations.Param;

import com.ouyan.o2o.entity.Product;

public interface ProductDao {
    /**
     * 查询商品列表并分页,可输入的条件有: 商品名(模糊),商品状态,店铺Id,商品类别
     * 
     * @param productCondition
     * @param beginIndex
     * @param pageSize
     * @return
     */
    List<Product> queryProductList(@Param("productCondition") Product productCondition, @Param("rowIndex") int rowIndex,
            @Param("pageSize") int pageSize);

    /**
     * 查询对应的商品总数
     * 
     * @param productCondition
     * @return
     */
    int queryProductCount(@Param("productCondition") Product productCondition);

    /**
     * 通过productId查询唯一的商品信息
     * 
     * @param productId
     * @return
     */
    Product queryProductById(long productId);

    /**
     * 插入商品
     * 
     * @param product
     * @return
     */
    int insertProduct(Product product);

    /**
     * 更新商品信息
     * 
     * @param product
     * @return
     */
    int updateProduct(Product product);

    /**
     * 删除商品类别之前,将商品类别ID置为空
     * 
     * @param productCategoryId
     * @return
     */
    int updateProductCategoryToNull(long productCategoryId);

    /**
     * 删除商品
     * 
     * @param productId
     * @return
     */
    int deleteProduct(@Param("productId") long productId, @Param("shopId") long shopId);
}
package com.ouyan.o2o.dao;

import java.util.List;

import com.ouyan.o2o.entity.ProductImg;

public interface ProductImgDao {

    /**
     * 列出某个商品的详情图列表
     * 
     * @param productId
     * @return
     */
    List<ProductImg> queryProductImgList(long productId);

    /**
     * 批量添加商品详情图片
     * 
     * @param productImgList
     * @return
     */
    int batchInsertProductImg(List<ProductImg> productImgList);

    /**
     * 删除指定商品下的所有详情图
     * 
     * @param productId
     * @return
     */
    int deleteProductImgByProductId(long productId);
}

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ouyan.o2o.dao.ProductImgDao">
    <select id="queryProductImgList" resultType="com.ouyan.o2o.entity.ProductImg">
        SELECT
        product_img_id,
        img_addr,
        img_desc,
        priority,
        create_time,
        product_id
        FROM tb_product_img
        WHERE product_id=#{productId}
        ORDER BY
        product_img_id ASC
    </select>
    <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.imgDesc},
            #{productImg.priority},
            #{productImg.createTime},
            #{productImg.productId}
            )
        </foreach>
    </insert>

    <delete id="deleteProductImgByProductId">
        <!-- 具体的sql -->
        DELETE FROM
        tb_product_img
        WHERE
        product_id =
        #{productId}
    </delete>

</mapper>

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ouyan.o2o.dao.ProductDao">
    <resultMap id="productMap" type="com.ouyan.o2o.entity.Product">
        <id column="product_id" property="productId" />
        <result column="product_name" property="productName" />
        <result column="product_desc" property="productDesc" />
        <result column="img_addr" property="imgAddr" />
        <result column="normal_price" property="normalPrice" />
        <result column="promotion_price" property="promotionPrice" />
        <result column="priority" property="priority" />
        <result column="create_time" property="createTime" />
        <result column="last_edit_time" property="lastEditTime" />
        <result column="enable_status" property="enableStatus" />
        <association property="productCategory" column="product_category_id"
            javaType="com.ouyan.o2o.entity.ProductCategory">
            <id column="product_category_id" property="productCategoryId" />
            <result column="product_category_name" property="productCategoryName" />
        </association>
        <association property="shop" column="shop_id"
            javaType="com.ouyan.o2o.entity.Shop">
            <id column="shop_id" property="shopId" />
            <result column="owner_id" property="ownerId" />
            <result column="shop_name" property="shopName" />
        </association>
        <collection property="productImgList" column="product_id"
            ofType="com.ouyan.o2o.entity.ProductImg">
            <id column="product_img_id" property="productImgId" />
            <result column="detail_img" property="imgAddr" />
            <result column="img_desc" property="imgDesc" />
            <result column="priority" property="priority" />
            <result column="create_time" property="createTime" />
            <result column="product_id" property="productId" />
        </collection>
    </resultMap>
    <select id="queryProductList" resultType="com.ouyan.o2o.entity.Product">
        SELECT
        product_id,
        product_name,
        product_desc,
        img_addr,
        normal_price,
        promotion_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语句的时候 一般都会写成 like '% %' 在mybatis里面写就是应该是 like '%${name} %' 而不是 
                '%#{name} %' ${name} 是不带单引号的,而#{name} 是带单引号的 -->
            <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>
            <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>
    <select id="queryProductById" resultMap="productMap"
        parameterType="Long">
        <!-- 具体的sql -->
        SELECT
        p.product_id,
        p.product_name,
        p.product_desc,
        p.img_addr,
        p.normal_price,
        p.promotion_price,
        p.priority,
        p.create_time,
        p.last_edit_time,
        p.enable_status,
        p.product_category_id,
        p.shop_id,
        pm.product_img_id,
        pm.img_addr AS detail_img,
        pm.img_desc,
        pm.priority,
        pm.create_time
        FROM
        tb_product p
        LEFT JOIN
        tb_product_img pm
        ON
        p.product_id =
        pm.product_id
        WHERE
        p.product_id =
        #{productId}
        ORDER BY
        pm.priority DESC
    </select>
    <insert id="insertProduct" parameterType="com.ouyan.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>
    <update id="updateProduct" parameterType="com.ouyan.o2o.entity.Product"
        keyProperty="product_id" useGeneratedKeys="true">
        UPDATE tb_product
        <set>
            <if test="productName != null">product_name=#{productName},</if>
            <if test="productDesc != null">product_desc=#{productDesc},</if>
            <if test="imgAddr != null">img_addr=#{imgAddr},</if>
            <if test="normalPrice != null">normal_price=#{normalPrice},</if>
            <if test="promotionPrice != null">promotion_price=#{promotionPrice},</if>
            <if test="priority != null">priority=#{priority},</if>
            <if test="lastEditTime != null">last_edit_time=#{lastEditTime},</if>
            <if test="enableStatus != null">enable_status=#{enableStatus},</if>
            <if
                test="productCategory != null
                 and productCategory.productCategoryId != null">
                product_category_id=#{productCategory.productCategoryId}
            </if>
        </set>
        WHERE product_id = #{productId}
        AND shop_id=#{shop.shopId}
    </update>
    <update id="updateProductCategoryToNull" parameterType="Long">
        UPDATE
        tb_product
        SET
        product_category_id = null
        WHERE product_category_id =
        #{productCategoryId}
    </update>
    <delete id="deleteProduct">
        DELETE FROM
        tb_product
        WHERE
        product_id = #{productId}
        AND shop_id=#{shopId}
    </delete>
</mapper>
package com.ouyan.o2o.dao;

import static org.junit.Assert.assertEquals;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runners.MethodSorters;
import org.springframework.beans.factory.annotation.Autowired;

import com.ouyan.o2o.BaseTest;
import com.ouyan.o2o.entity.ProductImg;

@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class ProductImgDaoTest extends BaseTest {
    @Autowired
    private ProductImgDao productImgDao;

    @Test
    public void testABatchInsertProductImg() throws Exception {
        // productId为1的商品里添加两个详情图片记录
        ProductImg productImg1 = new ProductImg();
        productImg1.setImgAddr("图片1");
        productImg1.setImgDesc("测试图片1");
        productImg1.setPriority(1);
        productImg1.setCreateTime(new Date());
        productImg1.setProductId(16L);
        ProductImg productImg2 = new ProductImg();
        productImg2.setImgAddr("图片2");
        productImg2.setPriority(1);
        productImg2.setCreateTime(new Date());
        productImg2.setProductId(16L);
        List<ProductImg> productImgList = new ArrayList<ProductImg>();
        productImgList.add(productImg1);
        productImgList.add(productImg2);
        int effectedNum = productImgDao.batchInsertProductImg(productImgList);
        assertEquals(2, effectedNum);
    }

    @Test
    public void testBQueryProductImgList() {
        // 检查productId为1的商品是否有且仅有两张商品详情图片
        List<ProductImg> productImgList = productImgDao.queryProductImgList(1L);
        assertEquals(2, productImgList.size());
    }

    @Test
    public void testCDeleteProductImgByProductId() throws Exception {
        // 删除新增的两条商品详情图片记录
        long productId = 16;
        int effectedNum = productImgDao.deleteProductImgByProductId(productId);
        assertEquals(2, effectedNum);
    }
}
package com.ouyan.o2o.dao;

import static org.junit.Assert.assertEquals;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.junit.FixMethodOrder;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runners.MethodSorters;
import org.springframework.beans.factory.annotation.Autowired;

import com.ouyan.o2o.BaseTest;
import com.ouyan.o2o.entity.Product;
import com.ouyan.o2o.entity.ProductCategory;
import com.ouyan.o2o.entity.ProductImg;
import com.ouyan.o2o.entity.Shop;

@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class ProductDaoTest extends BaseTest {

    @Autowired
    private ProductDao productDao;
    @Autowired
    private ProductImgDao productImgDao;

    @Test
    public void testAInsertProduct() throws Exception {
        Shop shop1 = new Shop();
        shop1.setShopId(62L);
        ProductCategory pc1 = new ProductCategory();
        pc1.setProductCategoryId(1L);
        // 初始化三个商品实例并添加进shopId为1的店铺里,
        // 同时商品类别Id也为1
        Product product1 = new Product();
        product1.setProductName("测试1");
        product1.setProductDesc("测试Desc1");
        product1.setImgAddr("test1");
        product1.setPriority(1);
        product1.setEnableStatus(1);
        product1.setCreateTime(new Date());
        product1.setLastEditTime(new Date());
        product1.setShop(shop1);
        product1.setProductCategory(pc1);
        Product product2 = new Product();
        product2.setProductName("测试2");
        product2.setProductDesc("测试Desc2");
        product2.setImgAddr("test2");
        product2.setPriority(2);
        product2.setEnableStatus(0);
        product2.setCreateTime(new Date());
        product2.setLastEditTime(new Date());
        product2.setShop(shop1);
        product2.setProductCategory(pc1);
        Product product3 = new Product();
        product3.setProductName("test3");
        product3.setProductDesc("测试Desc3");
        product3.setImgAddr("test3");
        product3.setPriority(3);
        product3.setEnableStatus(1);
        product3.setCreateTime(new Date());
        product3.setLastEditTime(new Date());
        product3.setShop(shop1);
        product3.setProductCategory(pc1);
        // 判断添加是否成功
        int effectedNum = productDao.insertProduct(product1);
        assertEquals(1, effectedNum);
        effectedNum = productDao.insertProduct(product2);
        assertEquals(1, effectedNum);
        effectedNum = productDao.insertProduct(product3);
        assertEquals(1, effectedNum);
    }

    @Test
    public void testBQueryProductList() throws Exception {
        Product productCondition = new Product();
        // 分页查询,预期返回三条结果
        List<Product> productList = productDao.queryProductList(productCondition, 0, 3);
        assertEquals(3, productList.size());
        // 查询名称为测试的商品总数
        int count = productDao.queryProductCount(productCondition);
        assertEquals(5, count);
        // 使用商品名称模糊查询,预期返回两条结果
        productCondition.setProductName("测试");
        productList = productDao.queryProductList(productCondition, 0, 3);
        assertEquals(2, productList.size());
        count = productDao.queryProductCount(productCondition);
        assertEquals(2, count);
    }

    @Test
    @Ignore
    public void testCQueryProductByProductId() throws Exception {
        long productId = 1;
        // 初始化两个商品详情图实例作为productId为1的商品下的详情图片
        // 批量插入到商品详情图表中
        ProductImg productImg1 = new ProductImg();
        productImg1.setImgAddr("图片1");
        productImg1.setImgDesc("测试图片1");
        productImg1.setPriority(1);
        productImg1.setCreateTime(new Date());
        productImg1.setProductId(productId);
        ProductImg productImg2 = new ProductImg();
        productImg2.setImgAddr("图片2");
        productImg2.setPriority(1);
        productImg2.setCreateTime(new Date());
        productImg2.setProductId(productId);
        List<ProductImg> productImgList = new ArrayList<ProductImg>();
        productImgList.add(productImg1);
        productImgList.add(productImg2);
        int effectedNum = productImgDao.batchInsertProductImg(productImgList);
        assertEquals(2, effectedNum);
        // 查询productId为1的商品信息并校验返回的详情图实例列表size是否为2
        Product product = productDao.queryProductById(productId);
        assertEquals(2, product.getProductImgList().size());
        // 删除新增的这两个商品详情图实例
        effectedNum = productImgDao.deleteProductImgByProductId(productId);
        assertEquals(2, effectedNum);
    }

    @Test
    @Ignore
    public void testDUpdateProduct() throws Exception {
        Product product = new Product();
        ProductCategory pc = new ProductCategory();
        Shop shop = new Shop();
        shop.setShopId(1L);
        pc.setProductCategoryId(2L);
        product.setProductId(1L);
        product.setShop(shop);
        product.setProductName("第二个产品");
        product.setProductCategory(pc);
        // 修改productId为1的商品的名称
        // 以及商品类别并校验影响的行数是否为1
        int effectedNum = productDao.updateProduct(product);
        assertEquals(1, effectedNum);
    }

    @Test
    public void testEUpdateProductCategoryToNull() {
        // 将productCategoryId为2的商品类别下面的商品的商品类别置为空
        int effectedNum = productDao.updateProductCategoryToNull(2L);
        assertEquals(1, effectedNum);
    }

    @Test
    @Ignore
    public void testFDeleteShopAuthMap() throws Exception {
        // 清除掉insert方法添加的商品
        Product productCondition = new Product();
        ProductCategory pc = new ProductCategory();
        pc.setProductCategoryId(1L);
        productCondition.setProductCategory(pc);
        // 通过输入productCategoryId为1去商品表中查出新增的三条测试数据
        List<Product> productList = productDao.queryProductList(productCondition, 0, 3);
        assertEquals(3, productList.size());
        // 循环删除这三条数据
        for (Product p : productList) {
            int effectedNum = productDao.deleteProduct(p.getProductId(), 1);
            assertEquals(1, effectedNum);
        }
    }
}
package com.ouyan.o2o.service;

import java.util.List;

import com.ouyan.o2o.dto.ImageHolder;
import com.ouyan.o2o.dto.ProductExecution;
import com.ouyan.o2o.entity.Product;
import com.ouyan.o2o.exceptions.ProductOperationException;

public interface ProductService {
    /**
     * 查询商品列表并分页,可输入的条件有: 商品名(模糊),商品状态,店铺Id,商品类别
     * 
     * @param productCondition
     * @param pageIndex
     * @param pageSize
     * @return
     */
    ProductExecution getProductList(Product productCondition, int pageIndex, int pageSize);

    /**
     * 通过商品Id查询唯一的商品信息
     * 
     * @param productId
     * @return
     */
    Product getProductById(long productId);

    /**
     * 添加商品信息以及图片处理
     * 
     * @param product
     * @param thumbnail
     * @param productImgs
     * @return
     * @throws ProductOperationException
     */
    ProductExecution addProduct(Product product, ImageHolder thumbnail, List<ImageHolder> productImgList)
            throws ProductOperationException;

    /**
     * 修改商品信息以及图片处理
     * 
     * @param product
     * @param thumbnail
     * @param productImgs
     * @return
     * @throws ProductOperationException
     */
    ProductExecution modifyProduct(Product product, ImageHolder thumbnail, List<ImageHolder> productImgHolderList)
            throws ProductOperationException;
}
package com.ouyan.o2o.web.shopadmin;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.ouyan.o2o.dto.ImageHolder;
import com.ouyan.o2o.dto.ProductExecution;
import com.ouyan.o2o.entity.Product;
import com.ouyan.o2o.entity.ProductCategory;
import com.ouyan.o2o.entity.Shop;
import com.ouyan.o2o.enums.ProductStateEnum;
import com.ouyan.o2o.exceptions.ProductOperationException;
import com.ouyan.o2o.service.ProductCategoryService;
import com.ouyan.o2o.service.ProductService;
import com.ouyan.o2o.util.CodeUtil;
import com.ouyan.o2o.util.HttpServletRequestUtil;

@Controller
@RequestMapping("/shopadmin")
public class ProductManagementController {
    @Autowired
    private ProductService productService;
    @Autowired
    private ProductCategoryService productCategoryService;

    // 支持上传商品详情图的最大数量
    private static final int IMAGEMAXCOUNT = 6;

    /**
     * 通过店铺id获取该店铺下的商品列表
     * 
     * @param request
     * @return
     */
    @RequestMapping(value = "/getproductlistbyshop", method = RequestMethod.GET)
    @ResponseBody
    private Map<String, Object> getProductListByShop(HttpServletRequest request) {
        Map<String, Object> modelMap = new HashMap<String, Object>();
        // 获取前台传过来的页码
        int pageIndex = HttpServletRequestUtil.getInt(request, "pageIndex");
        // 获取前台传过来的每页要求返回的商品数上限
        int pageSize = HttpServletRequestUtil.getInt(request, "pageSize");
        // 从当前session中获取店铺信息,主要是获取shopId
        Shop currentShop = (Shop) request.getSession().getAttribute("currentShop");
        // 空值判断
        if ((pageIndex > -1) && (pageSize > -1) && (currentShop != null) && (currentShop.getShopId() != null)) {
            // 获取传入的需要检索的条件,包括是否需要从某个商品类别以及模糊查找商品名去筛选某个店铺下的商品列表
            // 筛选的条件可以进行排列组合
            long productCategoryId = HttpServletRequestUtil.getLong(request, "productCategoryId");
            String productName = HttpServletRequestUtil.getString(request, "productName");
            Product productCondition = compactProductCondition(currentShop.getShopId(), productCategoryId, productName);
            // 传入查询条件以及分页信息进行查询,返回相应商品列表以及总数
            ProductExecution pe = productService.getProductList(productCondition, pageIndex, pageSize);
            modelMap.put("productList", pe.getProductList());
            modelMap.put("count", pe.getCount());
            modelMap.put("success", true);
        } else {
            modelMap.put("success", false);
            modelMap.put("errMsg", "empty pageSize or pageIndex or shopId");
        }
        return modelMap;
    }

    /**
     * 通过商品id获取商品信息
     * 
     * @param productId
     * @return
     */
    @RequestMapping(value = "/getproductbyid", method = RequestMethod.GET)
    @ResponseBody
    private Map<String, Object> getProductById(@RequestParam Long productId) {
        Map<String, Object> modelMap = new HashMap<String, Object>();
        // 非空判断
        if (productId > -1) {
            // 获取商品信息
            Product product = productService.getProductById(productId);
            // 获取该店铺下的商品类别列表
            List<ProductCategory> productCategoryList = productCategoryService
                    .getProductCategoryList(product.getShop().getShopId());
            modelMap.put("product", product);
            modelMap.put("productCategoryList", productCategoryList);
            modelMap.put("success", true);
        } else {
            modelMap.put("success", false);
            modelMap.put("errMsg", "empty productId");
        }
        return modelMap;
    }

    @RequestMapping(value = "/addproduct", method = RequestMethod.POST)
    @ResponseBody
    private Map<String, Object> addProduct(HttpServletRequest request) {
        Map<String, Object> modelMap = new HashMap<String, Object>();
        // 验证码校验
        if (!CodeUtil.checkVerifyCode(request)) {
            modelMap.put("success", false);
            modelMap.put("errMsg", "输入了错误的验证码");
            return modelMap;
        }
        // 接收前端参数的变量的初始化,包括商品,缩略图,详情图列表实体类
        ObjectMapper mapper = new ObjectMapper();
        Product product = null;
        ImageHolder thumbnail = null;
        List<ImageHolder> productImgList = new ArrayList<ImageHolder>();
        CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(
                request.getSession().getServletContext());
        try {
            // 若请求中存在文件流,则取出相关的文件(包括缩略图和详情图)
            if (multipartResolver.isMultipart(request)) {
                thumbnail = handleImage(request, thumbnail, productImgList);
            } else {
                modelMap.put("success", false);
                modelMap.put("errMsg", "上传图片不能为空");
                return modelMap;
            }
        } catch (Exception e) {
            modelMap.put("success", false);
            modelMap.put("errMsg", e.toString());
            return modelMap;
        }
        try {
            String productStr = HttpServletRequestUtil.getString(request, "productStr");
            // 尝试获取前端传过来的表单string流并将其转换成Product实体类
            product = mapper.readValue(productStr, Product.class);
        } catch (Exception e) {
            modelMap.put("success", false);
            modelMap.put("errMsg", e.toString());
            return modelMap;
        }
        // 若Product信息,缩略图以及详情图列表为非空,则开始进行商品添加操作
        if (product != null && thumbnail != null && productImgList.size() > 0) {
            try {
                // 从session中获取当前店铺的Id并赋值给product,减少对前端数据的依赖
                Shop currentShop = (Shop) request.getSession().getAttribute("currentShop");
                product.setShop(currentShop);
                // 执行添加操作
                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.toString());
                return modelMap;
            }
        } else {
            modelMap.put("success", false);
            modelMap.put("errMsg", "请输入商品信息");
        }
        return modelMap;
    }

    private ImageHolder handleImage(HttpServletRequest request, ImageHolder thumbnail, List<ImageHolder> productImgList)
            throws IOException {
        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
        // 取出缩略图并构建ImageHolder对象
        CommonsMultipartFile thumbnailFile = (CommonsMultipartFile) multipartRequest.getFile("thumbnail");
        if (thumbnailFile != null) {
            thumbnail = new ImageHolder(thumbnailFile.getOriginalFilename(), thumbnailFile.getInputStream());
        }
        // 取出详情图列表并构建List<ImageHolder>列表对象,最多支持六张图片上传
        for (int i = 0; i < IMAGEMAXCOUNT; i++) {
            CommonsMultipartFile productImgFile = (CommonsMultipartFile) multipartRequest.getFile("productImg" + i);
            if (productImgFile != null) {
                // 若取出的第i个详情图片文件流不为空,则将其加入详情图列表
                ImageHolder productImg = new ImageHolder(productImgFile.getOriginalFilename(),
                        productImgFile.getInputStream());
                productImgList.add(productImg);
            } else {
                // 若取出的第i个详情图片文件流为空,则终止循环
                break;
            }
        }
        return thumbnail;
    }

    /**
     * 商品编辑
     * 
     * @param request
     * @return
     */
    @RequestMapping(value = "/modifyproduct", method = RequestMethod.POST)
    @ResponseBody
    private Map<String, Object> modifyProduct(HttpServletRequest request) {
        Map<String, Object> modelMap = new HashMap<String, Object>();
        // 是商品编辑时候调用还是上下架操作的时候调用
        // 若为前者则进行验证码判断,后者则跳过验证码判断
        boolean statusChange = HttpServletRequestUtil.getBoolean(request, "statusChange");
        // 验证码判断
        if (!statusChange && !CodeUtil.checkVerifyCode(request)) {
            modelMap.put("success", false);
            modelMap.put("errMsg", "输入了错误的验证码");
            return modelMap;
        }
        // 接收前端参数的变量的初始化,包括商品,缩略图,详情图列表实体类
        ObjectMapper mapper = new ObjectMapper();
        Product product = null;
        ImageHolder thumbnail = null;
        List<ImageHolder> productImgList = new ArrayList<ImageHolder>();
        CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(
                request.getSession().getServletContext());
        // 若请求中存在文件流,则取出相关的文件(包括缩略图和详情图)
        try {
            if (multipartResolver.isMultipart(request)) {
                thumbnail = handleImage(request, thumbnail, productImgList);
            }
        } catch (Exception e) {
            modelMap.put("success", false);
            modelMap.put("errMsg", e.toString());
            return modelMap;
        }
        try {
            String productStr = HttpServletRequestUtil.getString(request, "productStr");
            // 尝试获取前端传过来的表单string流并将其转换成Product实体类
            product = mapper.readValue(productStr, Product.class);
        } catch (Exception e) {
            modelMap.put("success", false);
            modelMap.put("errMsg", e.toString());
            return modelMap;
        }
        // 非空判断
        if (product != null) {
            try {
                // 从session中获取当前店铺的Id并赋值给product,减少对前端数据的依赖
                Shop currentShop = (Shop) request.getSession().getAttribute("currentShop");
                product.setShop(currentShop);
                // 开始进行商品信息变更操作
                ProductExecution pe = productService.modifyProduct(product, thumbnail, productImgList);
                if (pe.getState() == ProductStateEnum.SUCCESS.getState()) {
                    modelMap.put("success", true);
                } else {
                    modelMap.put("success", false);
                    modelMap.put("errMsg", pe.getStateInfo());
                }
            } catch (RuntimeException e) {
                modelMap.put("success", false);
                modelMap.put("errMsg", e.toString());
                return modelMap;
            }

        } else {
            modelMap.put("success", false);
            modelMap.put("errMsg", "请输入商品信息");
        }
        return modelMap;
    }

    /**
     * 封装商品查询条件到Product实例中
     * 
     * @param shopId(mandatory)
     * @param productCategoryId(optional)
     * @param productName(optional)
     * @return
     */
    private Product compactProductCondition(long shopId, long productCategoryId, String productName) {
        Product productCondition = new Product();
        Shop shop = new Shop();
        shop.setShopId(shopId);
        productCondition.setShop(shop);
        // 若有指定类别的要求则添加进去
        if (productCategoryId != -1L) {
            ProductCategory productCategory = new ProductCategory();
            productCategory.setProductCategoryId(productCategoryId);
            productCondition.setProductCategory(productCategory);
        }
        // 若有商品名模糊查询的要求则添加进去
        if (productName != null) {
            productCondition.setProductName(productName);
        }
        return productCondition;
    }
}
package com.ouyan.o2o.service;

import static org.junit.Assert.assertEquals;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.junit.Ignore;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;

import com.ouyan.o2o.BaseTest;
import com.ouyan.o2o.dto.ImageHolder;
import com.ouyan.o2o.dto.ProductExecution;
import com.ouyan.o2o.entity.Product;
import com.ouyan.o2o.entity.ProductCategory;
import com.ouyan.o2o.entity.Shop;
import com.ouyan.o2o.enums.ProductStateEnum;
import com.ouyan.o2o.exceptions.ShopOperationException;

public class ProductServiceTest extends BaseTest {
    @Autowired
    private ProductService productService;

    @Test
    public void testAddProduct() throws ShopOperationException, FileNotFoundException {
        // 创建shopId为1且productCategoryId为1的商品实例并给其成员变量赋值
        Product product = new Product();
        Shop shop = new Shop();
        shop.setShopId(62L);
        ProductCategory pc = new ProductCategory();
        pc.setProductCategoryId(21L);
        product.setShop(shop);
        product.setProductCategory(pc);
        product.setProductName("测试商品1");
        product.setProductDesc("测试商品1");
        product.setPriority(20);
        product.setCreateTime(new Date());
        product.setEnableStatus(ProductStateEnum.SUCCESS.getState());
        // 创建缩略图文件流
        File thumbnailFile = new File("D:/haha.jpg");
        InputStream is = new FileInputStream(thumbnailFile);
        ImageHolder thumbnail = new ImageHolder(thumbnailFile.getName(), is);
        // 创建两个商品详情图文件流并将他们添加到详情图列表中
        File productImg1 = new File("/D:/haha.jpg");
        InputStream is1 = new FileInputStream(productImg1);
        File productImg2 = new File("D:/haha.jpg");
        InputStream is2 = new FileInputStream(productImg2);
        List<ImageHolder> productImgList = new ArrayList<ImageHolder>();
        productImgList.add(new ImageHolder(productImg1.getName(), is1));
        productImgList.add(new ImageHolder(productImg2.getName(), is2));
        // 添加商品并验证
        ProductExecution pe = productService.addProduct(product, thumbnail, productImgList);
        assertEquals(ProductStateEnum.SUCCESS.getState(), pe.getState());
    }

    @Test
    public void testModifyProduct() throws ShopOperationException, FileNotFoundException {
        // 创建shopId为1且productCategoryId为1的商品实例并给其成员变量赋值
        Product product = new Product();
        Shop shop = new Shop();
        shop.setShopId(1L);
        ProductCategory pc = new ProductCategory();
        pc.setProductCategoryId(1L);
        product.setProductId(1L);
        product.setShop(shop);
        product.setProductCategory(pc);
        product.setProductName("正式的商品");
        product.setProductDesc("正式的商品");
        // 创建缩略图文件流
        File thumbnailFile = new File("/Users/baidu/work/image/ercode.jpg");
        InputStream is = new FileInputStream(thumbnailFile);
        ImageHolder thumbnail = new ImageHolder(thumbnailFile.getName(), is);
        // 创建两个商品详情图文件流并将他们添加到详情图列表中
        File productImg1 = new File("/Users/baidu/work/image/xiaohuangren.jpg");
        InputStream is1 = new FileInputStream(productImg1);
        File productImg2 = new File("/Users/baidu/work/image/dabai.jpg");
        InputStream is2 = new FileInputStream(productImg2);
        List<ImageHolder> productImgList = new ArrayList<ImageHolder>();
        productImgList.add(new ImageHolder(productImg1.getName(), is1));
        productImgList.add(new ImageHolder(productImg2.getName(), is2));
        // 添加商品并验证
        ProductExecution pe = productService.modifyProduct(product, thumbnail, productImgList);
        assertEquals(ProductStateEnum.SUCCESS.getState(), pe.getState());
    }

}
package com.ouyan.o2o.service.impl;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.ouyan.o2o.dao.ProductDao;
import com.ouyan.o2o.dao.ProductImgDao;
import com.ouyan.o2o.dto.ImageHolder;
import com.ouyan.o2o.dto.ProductExecution;
import com.ouyan.o2o.entity.Product;
import com.ouyan.o2o.entity.ProductImg;
import com.ouyan.o2o.enums.ProductStateEnum;
import com.ouyan.o2o.exceptions.ProductOperationException;
import com.ouyan.o2o.service.ProductService;
import com.ouyan.o2o.util.ImageUtil;
import com.ouyan.o2o.util.PageCalculator;
import com.ouyan.o2o.util.PathUtil;

@Service
public class ProductServiceImpl implements ProductService {
    @Autowired
    private ProductDao productDao;
    @Autowired
    private ProductImgDao productImgDao;

    @Override
    public ProductExecution getProductList(Product productCondition, int pageIndex, int pageSize) {
        // 页码转换成数据库的行码,并调用dao层取回指定页码的商品列表
        int rowIndex = PageCalculator.calculateRowIndex(pageIndex, pageSize);
        List<Product> productList = productDao.queryProductList(productCondition, rowIndex, pageSize);
        // 基于同样的查询条件返回该查询条件下的商品总数
        int count = productDao.queryProductCount(productCondition);
        ProductExecution pe = new ProductExecution();
        pe.setProductList(productList);
        pe.setCount(count);
        return pe;
    }

    @Override
    public Product getProductById(long productId) {
        return productDao.queryProductById(productId);
    }

    @Override
    @Transactional
    // 1.处理缩略图,获取缩略图相对路径并赋值给product
    // 2.往tb_product写入商品信息,获取productId
    // 3.结合productId批量处理商品详情图
    // 4.将商品详情图列表批量插入tb_product_img中
    public ProductExecution addProduct(Product product, ImageHolder thumbnail, List<ImageHolder> productImgHolderList)
            throws ProductOperationException {
        // 空值判断
        if (product != null && product.getShop() != null && product.getShop().getShopId() != null) {
            // 给商品设置上默认属性
            product.setCreateTime(new Date());
            product.setLastEditTime(new Date());
            // 默认为上架的状态
            product.setEnableStatus(1);
            // 若商品缩略图不为空则添加
            if (thumbnail != null) {
                try {
                    addThumbnail(product, thumbnail);
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            try {
                // 创建商品信息
                int effectedNum = productDao.insertProduct(product);
                if (effectedNum <= 0) {
                    throw new ProductOperationException("创建商品失败");
                }
            } catch (Exception e) {
                throw new ProductOperationException("创建商品失败:" + e.toString());
            }
            // 若商品详情图不为空则添加
            if (productImgHolderList != null && productImgHolderList.size() > 0) {
                addProductImgList(product, productImgHolderList);
            }
            return new ProductExecution(ProductStateEnum.SUCCESS, product);
        } else {
            // 传参为空则返回空值错误信息
            return new ProductExecution(ProductStateEnum.EMPTY);
        }
    }

    @Override
    @Transactional
    // 1.若缩略图参数有值,则处理缩略图,
    // 若原先存在缩略图则先删除再添加新图,之后获取缩略图相对路径并赋值给product
    // 2.若商品详情图列表参数有值,对商品详情图片列表进行同样的操作
    // 3.将tb_product_img下面的该商品原先的商品详情图记录全部清除
    // 4.更新tb_product_img以及tb_product的信息
    public ProductExecution modifyProduct(Product product, ImageHolder thumbnail,
            List<ImageHolder> productImgHolderList) throws ProductOperationException {
        // 空值判断
        if (product != null && product.getShop() != null && product.getShop().getShopId() != null) {
            // 给商品设置上默认属性
            product.setLastEditTime(new Date());
            // 若商品缩略图不为空且原有缩略图不为空则删除原有缩略图并添加
            if (thumbnail != null) {
                // 先获取一遍原有信息,因为原来的信息里有原图片地址
                Product tempProduct = productDao.queryProductById(product.getProductId());
                if (tempProduct.getImgAddr() != null) {
                    ImageUtil.deleteFileOrPath(tempProduct.getImgAddr());
                }
                try {
                    addThumbnail(product, thumbnail);
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            // 如果有新存入的商品详情图,则将原先的删除,并添加新的图片
            if (productImgHolderList != null && productImgHolderList.size() > 0) {
                deleteProductImgList(product.getProductId());
                addProductImgList(product, productImgHolderList);
            }
            try {
                // 更新商品信息
                int effectedNum = productDao.updateProduct(product);
                if (effectedNum <= 0) {
                    throw new ProductOperationException("更新商品信息失败");
                }
                return new ProductExecution(ProductStateEnum.SUCCESS, product);
            } catch (Exception e) {
                throw new ProductOperationException("更新商品信息失败:" + e.toString());
            }
        } else {
            return new ProductExecution(ProductStateEnum.EMPTY);
        }
    }

    /**
     * 添加缩略图
     * 
     * @param product
     * @param thumbnail
     * @throws IOException 
     */
    private void addThumbnail(Product product, ImageHolder thumbnail) throws IOException {
        String dest = PathUtil.getShopImagePath(product.getShop().getShopId());
        String thumbnailAddr = ImageUtil.generateThumbnail(thumbnail, dest);
        product.setImgAddr(thumbnailAddr);
    }

    /**
     * 批量添加图片
     * 
     * @param product
     * @param productImgHolderList
     */
    private void addProductImgList(Product product, List<ImageHolder> productImgHolderList) {
        // 获取图片存储路径,这里直接存放到相应店铺的文件夹底下
        String dest = PathUtil.getShopImagePath(product.getShop().getShopId());
        List<ProductImg> productImgList = new ArrayList<ProductImg>();
        // 遍历图片一次去处理,并添加进productImg实体类里
        for (ImageHolder productImgHolder : productImgHolderList) {
            String imgAddr = ImageUtil.generateNormalImg(productImgHolder, dest);
            ProductImg productImg = new ProductImg();
            productImg.setImgAddr(imgAddr);
            productImg.setProductId(product.getProductId());
            productImg.setCreateTime(new Date());
            productImgList.add(productImg);
        }
        // 如果确实是有图片需要添加的,就执行批量添加操作
        if (productImgList.size() > 0) {
            try {
                int effectedNum = productImgDao.batchInsertProductImg(productImgList);
                if (effectedNum <= 0) {
                    throw new ProductOperationException("创建商品详情图片失败");
                }
            } catch (Exception e) {
                throw new ProductOperationException("创建商品详情图片失败:" + e.toString());
            }
        }
    }

    /**
     * 删除某个商品下的所有详情图
     * 
     * @param productId
     */
    private void deleteProductImgList(long productId) {
        // 根据productId获取原来的图片
        List<ProductImg> productImgList = productImgDao.queryProductImgList(productId);
        // 干掉原来的图片
        for (ProductImg productImg : productImgList) {
            ImageUtil.deleteFileOrPath(productImg.getImgAddr());
        }
        // 删除数据库里原有图片的信息
        productImgDao.deleteProductImgByProductId(productId);
    }
}

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>商品管理</title>
<meta name="viewport" content="initial-scale=1, maximum-scale=1">
<link rel="shortcut icon" href="/favicon.ico">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<link rel="stylesheet"
    href="//g.alicdn.com/msui/sm/0.6.2/css/sm.min.css">
<link rel="stylesheet"
    href="//g.alicdn.com/msui/sm/0.6.2/css/sm-extend.min.css">
<link rel="stylesheet"
    href="../resources/css/shop/productmanagement.css">
</head>
<body>
    <header class="bar bar-nav">
        <h1 class="title">商品管理</h1>
    </header>
    <div class="content">
        <div class="content-block">
            <div class="row row-product">
                <div class="col-33">商品名称</div>
                <div class="col-20">优先级</div>
                <div class="col-40">操作</div>
            </div>
            <div class="product-wrap">
                <!-- <div class="row row-product">
                    <div class="col-33">#{商品名称}</div>
                    <div class="col-20">#{优先级}</div>
                    <div class="col-40">
                        <a href="#">编辑</a>
                        <a href="#">删除</a>
                        <a href="#">预览</a>
                    </div>
                </div> -->
            </div>
        </div>
        <div class="content-block">
            <div class="row">
                <div class="col-50">
                    <a href="/o2o/shopadmin/shopmanagement"
                        class="button button-big button-fill button-danger">返回</a>
                </div>
                <div class="col-50">
                    <a href="/o2o/shopadmin/productoperation" class="button button-big button-fill button-success"
                        id="new">新增</a>
                </div>
            </div>
        </div>
    </div>



    <script type='text/javascript'
        src='//g.alicdn.com/sj/lib/zepto/zepto.min.js' charset='utf-8'></script>
    <script type='text/javascript'
        src='//g.alicdn.com/msui/sm/0.6.2/js/sm.min.js' charset='utf-8'></script>
    <script type='text/javascript'
        src='//g.alicdn.com/msui/sm/0.6.2/js/sm-extend.min.js' charset='utf-8'></script>
    <script type='text/javascript'
        src='../resources/js/shop/productmanagement.js' charset='utf-8'></script>
</body>
</html>

.row-product {
    border: 1px solid #999;
    padding: .5rem;
    border-bottom: none;
}
.row-product * {
    white-space: nowrap;
    overflow: scroll;
}
.row-product:last-child {
    border-bottom: 1px solid #999;
}
.product-name {
    white-space: nowrap;
    overflow-x: scroll;
}
.product-wrap a {
    margin-right: 1rem;
}

$(function() {
    // 获取此店铺下的商品列表的URL
    var listUrl = '/o2o/shopadmin/getproductlistbyshop?pageIndex=1&pageSize=999';
    // 商品下架URL
    var statusUrl = '/o2o/shopadmin/modifyproduct';
    getList();
    /**
     * 获取此店铺下的商品列表
     * 
     * @returns
     */
    function getList() {
        // 从后台获取此店铺的商品列表
        $.getJSON(listUrl, function(data) {
            if (data.success) {
                var productList = data.productList;
                var tempHtml = '';
                // 遍历每条商品信息,拼接成一行显示,列信息包括:
                // 商品名称,优先级,上架\下架(含productId),编辑按钮(含productId)
                // 预览(含productId)
                productList.map(function(item, index) {
                    var textOp = "下架";
                    var contraryStatus = 0;
                    if (item.enableStatus == 0) {
                        // 若状态值为0,表明是已下架的商品,操作变为上架(即点击上架按钮上架相关商品)
                        textOp = "上架";
                        contraryStatus = 1;
                    } else {
                        contraryStatus = 0;
                    }
                    // 拼接每件商品的行信息
                    tempHtml += '' + '<div class="row row-product">'
                            + '<div class="col-33">'
                            + item.productName
                            + '</div>'
                            + '<div class="col-20">'
                            + item.priority
                            + '</div>'
                            + '<div class="col-40">'
                            + '<a href="#" class="edit" data-id="'
                            + item.productId
                            + '" data-status="'
                            + item.enableStatus
                            + '">编辑</a>'
                            + '<a href="#" class="status" data-id="'
                            + item.productId
                            + '" data-status="'
                            + contraryStatus
                            + '">'
                            + textOp
                            + '</a>'
                            + '<a href="#" class="preview" data-id="'
                            + item.productId
                            + '" data-status="'
                            + item.enableStatus
                            + '">预览</a>'
                            + '</div>'
                            + '</div>';
                });
                // 将拼接好的信息赋值进html控件中
                $('.product-wrap').html(tempHtml);
            }
        });
    }
    // 将class为product-wrap里面的a标签绑定上点击的事件
    $('.product-wrap')
            .on(
                    'click',
                    'a',
                    function(e) {
                        var target = $(e.currentTarget);
                        if (target.hasClass('edit')) {
                            // 如果有class edit则点击就进入店铺信息编辑页面,并带有productId参数
                            window.location.href = '/o2o/shopadmin/productoperation?productId='
                                    + e.currentTarget.dataset.id;
                        } else if (target.hasClass('status')) {
                            // 如果有class status则调用后台功能上/下架相关商品,并带有productId参数
                            changeItemStatus(e.currentTarget.dataset.id,
                                    e.currentTarget.dataset.status);
                        } else if (target.hasClass('preview')) {
                            // 如果有class preview则去前台展示系统该商品详情页预览商品情况
                            window.location.href = '/o2o/frontend/productdetail?productId='
                                    + e.currentTarget.dataset.id;
                        }
                    });
    function changeItemStatus(id, enableStatus) {
        // 定义product json对象并添加productId以及状态(上架/下架)
        var product = {};
        product.productId = id;
        product.enableStatus = enableStatus;
        $.confirm('确定么?', function() {
            // 上下架相关商品
            $.ajax({
                url : statusUrl,
                type : 'POST',
                data : {
                    productStr : JSON.stringify(product),
                    statusChange : true
                },
                dataType : 'json',
                success : function(data) {
                    if (data.success) {
                        $.toast('操作成功!');
                        getList();
                    } else {
                        $.toast('操作失败!');
                    }
                }
            });
        });
    }
});
package com.ouyan.o2o.service.impl;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.ouyan.o2o.dao.ProductCategoryDao;
import com.ouyan.o2o.dao.ProductDao;
import com.ouyan.o2o.dto.ProductCategoryExecution;
import com.ouyan.o2o.entity.ProductCategory;
import com.ouyan.o2o.enums.ProductCategoryStateEnum;
import com.ouyan.o2o.exceptions.ProductCategoryOperationException;
import com.ouyan.o2o.service.ProductCategoryService;

@Service
public class ProductCategoryServiceImpl implements ProductCategoryService {
    @Autowired
    private ProductCategoryDao productCategoryDao;
    @Autowired
    private ProductDao productDao;

    @Override
    public List<ProductCategory> getProductCategoryList(long shopId) {
        return productCategoryDao.queryProductCategoryList(shopId);
    }

    @Override
    @Transactional
    public ProductCategoryExecution batchAddProductCategory(List<ProductCategory> productCategoryList)
            throws ProductCategoryOperationException {
        if (productCategoryList != null && productCategoryList.size() > 0) {
            try {
                int effectedNum = productCategoryDao.batchInsertProductCategory(productCategoryList);
                if (effectedNum <= 0) {
                    throw new ProductCategoryOperationException("店铺类别创建失败");
                } else {
                    return new ProductCategoryExecution(ProductCategoryStateEnum.SUCCESS);
                }

            } catch (Exception e) {
                throw new ProductCategoryOperationException("batchAddProductCategory error: " + e.getMessage());
            }
        } else {
            return new ProductCategoryExecution(ProductCategoryStateEnum.EMPTY_LIST);
        }
    }

    @Override
    @Transactional
    public ProductCategoryExecution deleteProductCategory(long productCategoryId, long shopId)
            throws ProductCategoryOperationException {
        // 解除tb_product里的商品与该producategoryId的关联
        try {
            int effectedNum = productDao.updateProductCategoryToNull(productCategoryId);
            if (effectedNum < 0) {
                throw new ProductCategoryOperationException("商品类别更新失败");
            }
        } catch (Exception e) {
            throw new ProductCategoryOperationException("deleteProductCategory error: " + e.getMessage());
        }
        // 删除该productCategory
        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());
        }
    }

}
package com.ouyan.o2o.dao;

import java.util.List;

import org.apache.ibatis.annotations.Param;

import com.ouyan.o2o.entity.Product;

public interface ProductDao {
    /**
     * 查询商品列表并分页,可输入的条件有: 商品名(模糊),商品状态,店铺Id,商品类别
     * 
     * @param productCondition
     * @param beginIndex
     * @param pageSize
     * @return
     */
    List<Product> queryProductList(@Param("productCondition") Product productCondition, @Param("rowIndex") int rowIndex,
            @Param("pageSize") int pageSize);

    /**
     * 查询对应的商品总数
     * 
     * @param productCondition
     * @return
     */
    int queryProductCount(@Param("productCondition") Product productCondition);

    /**
     * 通过productId查询唯一的商品信息
     * 
     * @param productId
     * @return
     */
    Product queryProductById(long productId);

    /**
     * 插入商品
     * 
     * @param product
     * @return
     */
    int insertProduct(Product product);

    /**
     * 更新商品信息
     * 
     * @param product
     * @return
     */
    int updateProduct(Product product);

    /**
     * 删除商品类别之前,将商品类别ID置为空
     * 
     * @param productCategoryId
     * @return
     */
    int updateProductCategoryToNull(long productCategoryId);

    /**
     * 删除商品
     * 
     * @param productId
     * @return
     */
    int deleteProduct(@Param("productId") long productId, @Param("shopId") long shopId);
}
package com.ouyan.o2o.dao;

import static org.junit.Assert.assertEquals;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.junit.FixMethodOrder;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runners.MethodSorters;
import org.springframework.beans.factory.annotation.Autowired;

import com.ouyan.o2o.BaseTest;
import com.ouyan.o2o.entity.Product;
import com.ouyan.o2o.entity.ProductCategory;
import com.ouyan.o2o.entity.ProductImg;
import com.ouyan.o2o.entity.Shop;

@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class ProductDaoTest extends BaseTest {

    @Autowired
    private ProductDao productDao;
    @Autowired
    private ProductImgDao productImgDao;

    @Test
    public void testAInsertProduct() throws Exception {
        Shop shop1 = new Shop();
        shop1.setShopId(62L);
        ProductCategory pc1 = new ProductCategory();
        pc1.setProductCategoryId(1L);
        // 初始化三个商品实例并添加进shopId为1的店铺里,
        // 同时商品类别Id也为1
        Product product1 = new Product();
        product1.setProductName("测试1");
        product1.setProductDesc("测试Desc1");
        product1.setImgAddr("test1");
        product1.setPriority(1);
        product1.setEnableStatus(1);
        product1.setCreateTime(new Date());
        product1.setLastEditTime(new Date());
        product1.setShop(shop1);
        product1.setProductCategory(pc1);
        Product product2 = new Product();
        product2.setProductName("测试2");
        product2.setProductDesc("测试Desc2");
        product2.setImgAddr("test2");
        product2.setPriority(2);
        product2.setEnableStatus(0);
        product2.setCreateTime(new Date());
        product2.setLastEditTime(new Date());
        product2.setShop(shop1);
        product2.setProductCategory(pc1);
        Product product3 = new Product();
        product3.setProductName("test3");
        product3.setProductDesc("测试Desc3");
        product3.setImgAddr("test3");
        product3.setPriority(3);
        product3.setEnableStatus(1);
        product3.setCreateTime(new Date());
        product3.setLastEditTime(new Date());
        product3.setShop(shop1);
        product3.setProductCategory(pc1);
        // 判断添加是否成功
        int effectedNum = productDao.insertProduct(product1);
        assertEquals(1, effectedNum);
        effectedNum = productDao.insertProduct(product2);
        assertEquals(1, effectedNum);
        effectedNum = productDao.insertProduct(product3);
        assertEquals(1, effectedNum);
    }

    @Test
    public void testBQueryProductList() throws Exception {
        Product productCondition = new Product();
        // 分页查询,预期返回三条结果
        List<Product> productList = productDao.queryProductList(productCondition, 0, 3);
        assertEquals(3, productList.size());
        // 查询名称为测试的商品总数
        int count = productDao.queryProductCount(productCondition);
        assertEquals(5, count);
        // 使用商品名称模糊查询,预期返回两条结果
        productCondition.setProductName("测试");
        productList = productDao.queryProductList(productCondition, 0, 3);
        assertEquals(2, productList.size());
        count = productDao.queryProductCount(productCondition);
        assertEquals(2, count);
    }

    @Test
    @Ignore
    public void testCQueryProductByProductId() throws Exception {
        long productId = 1;
        // 初始化两个商品详情图实例作为productId为1的商品下的详情图片
        // 批量插入到商品详情图表中
        ProductImg productImg1 = new ProductImg();
        productImg1.setImgAddr("图片1");
        productImg1.setImgDesc("测试图片1");
        productImg1.setPriority(1);
        productImg1.setCreateTime(new Date());
        productImg1.setProductId(productId);
        ProductImg productImg2 = new ProductImg();
        productImg2.setImgAddr("图片2");
        productImg2.setPriority(1);
        productImg2.setCreateTime(new Date());
        productImg2.setProductId(productId);
        List<ProductImg> productImgList = new ArrayList<ProductImg>();
        productImgList.add(productImg1);
        productImgList.add(productImg2);
        int effectedNum = productImgDao.batchInsertProductImg(productImgList);
        assertEquals(2, effectedNum);
        // 查询productId为1的商品信息并校验返回的详情图实例列表size是否为2
        Product product = productDao.queryProductById(productId);
        assertEquals(2, product.getProductImgList().size());
        // 删除新增的这两个商品详情图实例
        effectedNum = productImgDao.deleteProductImgByProductId(productId);
        assertEquals(2, effectedNum);
    }

    @Test
    @Ignore
    public void testDUpdateProduct() throws Exception {
        Product product = new Product();
        ProductCategory pc = new ProductCategory();
        Shop shop = new Shop();
        shop.setShopId(1L);
        pc.setProductCategoryId(2L);
        product.setProductId(1L);
        product.setShop(shop);
        product.setProductName("第二个产品");
        product.setProductCategory(pc);
        // 修改productId为1的商品的名称
        // 以及商品类别并校验影响的行数是否为1
        int effectedNum = productDao.updateProduct(product);
        assertEquals(1, effectedNum);
    }

    @Test
    public void testEUpdateProductCategoryToNull() {
        // 将productCategoryId为2的商品类别下面的商品的商品类别置为空
        int effectedNum = productDao.updateProductCategoryToNull(2L);
        assertEquals(1, effectedNum);
    }

    @Test
    @Ignore
    public void testFDeleteShopAuthMap() throws Exception {
        // 清除掉insert方法添加的商品
        Product productCondition = new Product();
        ProductCategory pc = new ProductCategory();
        pc.setProductCategoryId(1L);
        productCondition.setProductCategory(pc);
        // 通过输入productCategoryId为1去商品表中查出新增的三条测试数据
        List<Product> productList = productDao.queryProductList(productCondition, 0, 3);
        assertEquals(3, productList.size());
        // 循环删除这三条数据
        for (Product p : productList) {
            int effectedNum = productDao.deleteProduct(p.getProductId(), 1);
            assertEquals(1, effectedNum);
        }
    }
}

 

posted @ 2017-10-20 23:08  虚极静笃  Views(732)  Comments(1Edit  收藏  举报