美文网首页
第8章 商品模块

第8章 商品模块

作者: cuzz_ | 来源:发表于2018-05-06 13:57 被阅读0次

商品添加

Dao层的实现

  • 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可以产生一个主键赋值到实体类当中
    <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测试
    @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("测试1");
        product1.setProductDesc("测试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测试
    @Test
    public void testABatchInsertProductImg() throws Exception {
        ProductImg productImg1 = new ProductImg();
        productImg1.setImgAddr("图片1");
        productImg1.setImgDesc("测试图片1");
        productImg1.setPriority(1);
        productImg1.setCreateTime(new Date());
        productImg1.setProductId(4L);

        ProductImg productImg2 = new ProductImg();
        productImg2.setImgAddr("图片2");
        productImg2.setImgDesc("测试图片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层的实现

  • 接口
    /**
     *  添加商品以及图片处理
     * @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;

我们发现输出流和文件名,我封装一下
在dto中新建一个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个参数,也更清新

   /**
     *  添加商品以及图片处理
     * @param product
     * @param thumbnail
     * @param thumbnailName
     * @param productImgList
     * @param productImgNameList
     * @return
     * @throws ProductOperationException
     */
    ProductExecution addProduct(Product product,
                                ImageHolder thumbnail,
                                List<ImageHolder> imageHolderList) throws ProductOperationException;
}
  • 实现类
public class ProductServiceImpl implements ProductService {
    @Autowired
    private ProductDao productDao;
    @Autowired
    private ProductImgDao productImgDao;

    // 1. 处理缩略图,获取缩略图相对路径并赋值给product
    // 2. 往tb_product写入商品信息,获取productId
    // 3. 结合productId批量处理商品详情图
    // 4. 将商品的详情图列表批量插入tb_product_img中

    @Override
    // 事务管理
    @Transactional
    public ProductExecution addProduct(Product product, ImageHolder thumbnail, List<ImageHolder> imageHolderList)
            throws ProductOperationException {
        // 空值判断
        if (product !=null && product.getShop().getShopId() != null) {
            // 给商品设置默认属性
            product.setCreateTime(new Date());
            product.setLastEditTime(new Date());
            // 默认为上架状态
            product.setEnableStatus(1);
            // 若商品缩略图不为空则添加
            if (thumbnail != null) {
                addThumbnail(product, thumbnail);
            }

            try {
                // 创建商品信息
                int effectNum = productDao.insertProduct(product);
                if (effectNum <= 0) {
                    throw new ProductOperationException("创建商品失败");
                }
            } catch (Exception e) {
                throw new ProductOperationException("创建商品失败" + e.getMessage());
            }
            // 若商品详情图不为空则添加
            if (imageHolderList != null && imageHolderList.size() > 0) {
                addProductImgList(product, imageHolderList);
            }
            return new ProductExecution(ProductStateEnum.SUCCESS, product);
        } else {
            // 传入的参数为空
            return new ProductExecution(ProductStateEnum.EMPTY);
        }
    }

    /**
     * 批量添加图
     * @param product
     * @param imageHolderList
     */
    private void addProductImgList(Product product, List<ImageHolder> imageHolderList) {
        // 获取图片储存的路径,这里直接放在相应的店铺的文件夹底下
        String dest = PathUtil.getShopImagePath(product.getShop().getShopId());
        List<ProductImg> productImgList = new ArrayList<>();
        // 遍历图片一次去处理,并添加进productImg实体类
        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);
        }

        // 如果确实是有图片需要添加的 就执行批量添加
        if (productImgList.size() > 0) {
            try {
                int effectedNum = productImgDao.batchInsertProductImg(productImgList);
                if (effectedNum <= 0) {
                    throw new ProductOperationException("创建商品详情图片失败");
                }
            } catch (Exception e) {
                throw new ProductOperationException("创建商品详情图片失败" + 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);
    }
}
  • 测试
    @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("测试商品1");
        product.setProductDesc("测试");
        product.setPriority(0);

        // 创建缩略图文件流
        File thumbnailFile = new File("D:\\123.jpg");
        InputStream thumbnail = new FileInputStream(thumbnailFile);
        ImageHolder imageHolder = new ImageHolder(thumbnailFile.getName(), thumbnail);

        // 创建详情图片列表
        File thumbnailFile2 = new File("D:\\456.png");
        InputStream thumbnail2 = new FileInputStream(thumbnailFile2);
        ImageHolder imageHolder2 = new ImageHolder(thumbnailFile2.getName(), thumbnail2);

        List<ImageHolder> list = new ArrayList<>();
        // 不能使用同一个流, 报错!!!找了好久
//        list.add(imageHolder);
        list.add(imageHolder2);

        // 添加商品并验证
        ProductExecution productExecution = productService.addProduct(product, imageHolder, list);
        assertEquals(ProductStateEnum.SUCCESS.getState(), productExecution.getState());
  • 测试结果


    image.png

Controller层的实现

  • 显示编辑页面
    @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<>();
        // 验证码验证

        // 接受前端参数的变量的的初始化,包括商品,缩略图, 详情图片实体
        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 {
            // 如果请求中存在文件流,则取出相关文件(包括缩略图,和详情图)
            if (multipartResolver.isMultipart(request)) {
                multipartRequest = (MultipartHttpServletRequest) request;
                // 取出缩略图并构建ImageHolder对象
                CommonsMultipartFile thumbnailFile = (CommonsMultipartFile) multipartRequest.getFile("thumbnail");
                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;
                    }
                }
            } 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流并将其转化成Product实体类
            product = mapper.readValue(productStr, Product.class);
        } catch (Exception e) {
            modelMap.put("success", false);
            modelMap.put("errMsg", e.getMessage());
            return modelMap;
        }


        // 如果Product信息,缩略图已经详情图片列表都不为空,则开始进行商品添加操作
        if (product != null && thumbnail != null && productImgList.size() > 0) {
            try {
                // 从session中获取当前的店铺id并赋值给product 减少对前端的依赖
                Shop currentShop = (Shop) request.getSession().getAttribute("currentShop");
                Shop shop = new Shop();
                shop.setShopId(currentShop.getShopId());
                product.setShop(shop);

                // 执行并添加操作
                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", "请输入商品信息");
        }

        return modelMap;
    }

  • 测试


    image.png
    image.png

商品编辑

Dao层的实现

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

    /**
     * 更新商品的实体类
     * @param product
     * @return
     */
    int updateProduct(Product product);

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

商品列表展示

Dao层的实现

  • 接口
    /**
     * 查询
     * @param productCondition
     * @param rowIndex
     * @param pageSize
     * @return
     */
    List<Product> queryProductList(@Param("productCondition") Product productCondition,
                                   @Param("rowIndex") int rowIndex,
                                   @Param("pageSize") int pageSize);

    /**
     * 查询对应的商品总数
     * @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语句的时候一般都会写成like '% %'在mybaits写就应该写是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>
            <!-- 写like语句的时候一般都会写成like '% %'在mybaits写就应该写是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>
    </select>
  • 测试
    @Test
    public void testBQueryProductList() throws Exception {
        Product product = new Product();
        List<Product> productList = productDao.queryProductList(product, 0, 3);
        System.out.println(productList.size());

    }

service层的实现

  • 接口
    /**
     * 查询商品列表并且分页
     * @param productCondition
     * @param pageIndex
     * @param pageSize
     * @return
     */
    ProductExecution getProductList(Product productCondition, int pageIndex, int pageSize);
  • 实现类
    @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;
    }

Controller层的实现

  • getproductlistbyshop
   @RequestMapping(value = "/getproductlistbyshop", method = RequestMethod.GET)
    @ResponseBody
    private Map<String, Object> getProductListByShop(HttpServletRequest request) {
        Map<String, Object> modelMap = new HashMap<>();
        // 获取前台传过来的页面
        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)) {
            // 获取传入的需要的检索条件
            long productCategoryId = HttpServletRequestUtil.getLong(request, "categoryId");
            String productName = HttpServletRequestUtil.getString(request, "productName");
            Product productCadition = compactProductCondition(currentShop.getShopId(), productCategoryId, productName);
            // 传入查询条件已经分页查询 返回相应的商品列表已经总数
            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);
        // 如果有指定类别的要求添加进去
        if (productCategoryId != -1L) {
            ProductCategory productCategory = new ProductCategory();
            productCategory.setProductCategoryId(productCategoryId);
            productCondition.setProductCategory(productCategory);
        }
        // 如果有商品模糊查询添加进去
        if (productName != null) {
            productCondition.setProductName(productName);
        }
        return productCondition;
    }
  • 测试结果


    image.png

测试页面

image.png

解除商品与商品类别的联系

  • 前面我们删除productCategory的时候没有把,相应的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设置类空
    * @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());
        }
    }
  • 测试


    image.png
    image.png

    product_category_id变为null了

相关文章

  • 电商_前端开发[2]

    第6章 商品模块开发 本章我会带着同学们分析,拆解商品模块的功能与技术点,并手把手带大家实现商品首页,商品列表,商...

  • 第8章 商品模块

    商品添加 Dao层的实现 ProductDao ProductImgDao ProductDao.xmluseGe...

  • 项目整体架构

    从程序开发角度来看:前台(商品模块,用户模块,订单模块)和后台(商品,用户,订单) 从电子商务角度来看:商品、用户...

  • 商品模块

    商品添加,新的知识点批量添加图片,商品详情和商品是多对一的。 product实体类 productimg实体类 d...

  • 商品模块

    现有两个属性:【颜色】【尺码】那么对应的数据表数据为: specs_name(规格名称表) 【颜色】属性有两个属性...

  • 电商系统-商品模块

    商品模块是做什么的? 顾名思义,商品模块是电商系统管理商品信息的地方,这个模块看似简单,看起来无非就是存储商品名称...

  • 7.商品管理

    商品管理模块后台主要功能(7个)有:商品更新/商品添加、商品搜索、商品列表、商品上下架、商品详情、富文本上传图片、...

  • 第7章 商品类别模块

    商品类别列表 Dao层的实现 ProductCategoryDao接口 在mapper中添加ProductCate...

  • 校园交易平台后台系统git操作全过程

    项目初始化 配置文件完成 用户模块完成 商品模块完成 收货地址模块完成

  • 电子商务系统的组成

    电子商务系统的组成一般包含以下模块: 1、商品管理模块 功能有商品批量上下架、批量调价、库存调度、商品名称撰写、商...

网友评论

      本文标题:第8章 商品模块

      本文链接:https://www.haomeiwen.com/subject/dullrftx.html