实战SSM_O2O商铺_32【商品】商品编辑之Dao层的实现

简介: 实战SSM_O2O商铺_32【商品】商品编辑之Dao层的实现

概述

完成了商品的添加Dao层到View层功能之后,

实战SSM_O2O商铺_28【商品】商品添加之Dao层的实现

实战SSM_O2O商铺_29【商品】商品添加之Service层的实现及重构

实战SSM_O2O商铺_30【商品】商品添加之Controller层的实现

实战SSM_O2O商铺_31【商品】商品添加之View层的实现

我们先来看下商品的编辑,最后做商品列表展示,当然了,可根据个人习惯,调整开发顺序。


说到商品编辑,

  • 首先肯定要根据productId查到对应Product相关的信息,既然这里是Dao层的开发,所以需要在Dao层需要开发一个 selectProductById 方法
  • 商品信息有商品缩略图和详情图片,这里我们先约定好:如果用户传入了新的商品缩略图和详情图片,就将原有的商品缩略图和详情图片删除掉。
  • 商品缩略图的地址存放在tb_product的img_addr字段,所以只需要更新改表即可。 所以对应Dao层应该有个方法updateProduct
  • 图片缩略图还涉及磁盘上的文件的删除,需要根据productId获取到Product ,然后获取Product的imgAddr属性,复用selectProductById 解渴
  • 详情图片的地址存放在tb_product_img中,根据product_id可以查找到对应商品下的全部详情图片,所以对应Dao层应该有个方法deleteProductImgById
  • 图片详情还涉及磁盘上的文件的删除,需要根据productId获取到List ,然后遍历该list,获取集合中每个ProductImg的imgAddr地址,所以还需要有个selectProductImgList方法

Dao层接口

ProductDao#selectProductById

/**
   * 
   * 
   * @Title: selectProductById
   * 
   * @Description: 根据productId查询product
   * 
   * @param productId
   * 
   * @return: Product
   */
  Product selectProductById(long productId)

ProductDao#updateProduct

/**
   * 
   * 
   * @Title: updateProduct
   * 
   * @Description: 修改商品
   * 
   * @param product
   * 
   * @return: int
   */
  int updateProduct(Product product);

ProductImgDao#deleteProductImgById

/**
   * 
   * 
   * @Title: deleteProductImgById
   * 
   * @Description: 删除商品对应的商品详情图片
   * 
   * @param productId
   * 
   * @return: int
   */
  int deleteProductImgById(long productId);

ProductImgDao#selectProductImgList

/**
   * 
   * 
   * @Title: selectProductImgList
   * 
   * @Description: 根据productId查询商铺对应的图片详情信息
   * 
   * @param productId
   * 
   * @return: List<ProductImg>
   */
  List<ProductImg> selectProductImgList(long productId);

Mapper映射文件

ProductDao.xml

说明见注释

<?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.artisan.o2o.dao.ProductDao">
  <resultMap id="productMap" type="com.artisan.o2o.entity.Product" >
    <id column="product_id" property="productId"/>
    <!-- property对应实体类中的属性名  column 对应库表中的字段名 -->
    <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  
      product中的属性为productCategory, 通过数据库中的product_category_id关联起来的
      类型为 com.artisan.o2o.entity.ProductCategory-->
    <association property="productCategory" column="product_category_id"
      javaType="com.artisan.o2o.entity.ProductCategory">
      <!-- 对应ProductCategory中的属性 和 tb_product_category的字段 -->
      <id column="product_category_id" property="productCategoryId" />
      <result column="product_category_name" property="productCategoryName" />
    </association>
    <!-- 一对一使用association  
      product中的属性为shop, 通过数据库中的shop_id关联起来的
      类型为com.artisan.o2o.entity.Shop-->
    <association property="shop" column="shop_id"
      javaType="com.artisan.o2o.entity.Shop">
      <id column="shop_id" property="shopId" />
      <!-- 对应Shop中的属性 和 tb_shop的字段 ,如果是符合对象,使用xx.xxx的方式-->
      <result column="owner_id" property="owner.userId" />
      <result column="shop_name" property="shopName" />
    </association>
    <!-- 一对多使用collection  
      product中的属性为productImgList,并且是通过库表中的product_id关联起来的,
      保存的类型为com.imooc.myo2o.entity.ProductImg -->
    <collection property="productImgList" column="product_id"
      ofType="com.artisan.o2o.entity.ProductImg">
      <id column="product_img_id" property="productImgId" />
      <result column="img_addr" 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>
  <insert id="insertProduct" 
    parameterType="com.artisan.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>
  <select id="selectProductById" 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,
      pm.img_desc,
      pm.priority,
      pm.create_time
    FROM
      tb_product p
     <!-- 左连接LEFT JOIN,(即使该商品没有商品详情图片,也要查询出来该商铺) -->
    LEFT JOIN
      tb_product_img pm
    ON
      p.product_id =pm.product_id
    WHERE
      p.product_id = #{productId}
    ORDER BY
      pm.priority DESC
  </select>
  <update id="updateProduct" parameterType="com.artisan.o2o.entity.Product">
    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="createTime != null">create_time = #{createTime},</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>
</mapper>    

ProductImgDao.xml

<?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.artisan.o2o.dao.ProductImgDao">
  <insert id="batchInsertProductImg" 
    parameterType="com.artisan.o2o.entity.ProductImg" 
    useGeneratedKeys="true" keyProperty="productImgId" keyColumn="product_img_id">
    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="deleteProductImgById">
    DELETE FROM 
      tb_product_img 
    WHERE 
      product_id = #{produtId}
  </delete>
  <select id="selectProductImgList" resultType="com.artisan.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 
  </select>
</mapper>  

单元测试

ProductDaoTest

package com.artisan.o2o.dao;
import java.util.Date;
import org.junit.Assert;
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runners.MethodSorters;
import org.springframework.beans.factory.annotation.Autowired;
import com.artisan.o2o.BaseTest;
import com.artisan.o2o.entity.Product;
import com.artisan.o2o.entity.ProductCategory;
import com.artisan.o2o.entity.Shop;
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class ProductDaoTest extends BaseTest {
  @Autowired
  ProductDao productDao;
  @Test
  public void testA_InsertProdcut() {
    // 注意表中的外键关系,确保这些数据在对应的表中的存在
    ProductCategory productCategory = new ProductCategory();
    productCategory.setProductCategoryId(36L);
    // 注意表中的外键关系,确保这些数据在对应的表中的存在
    Shop shop = new Shop();
    shop.setShopId(5L);
    Product product = new Product();
    product.setProductName("test_product");
    product.setProductDesc("product desc");
    product.setImgAddr("/aaa/bbb");
    product.setNormalPrice("10");
    product.setPromotionPrice("8");
    product.setPriority(66);
    product.setCreateTime(new Date());
    product.setLastEditTime(new Date());
    product.setEnableStatus(1);
    product.setProductCategory(productCategory);
    product.setShop(shop);
    int effectNum = productDao.insertProduct(product);
    Assert.assertEquals(1, effectNum);
  }
  @Test
  public void testB_UpdateProduct() {
    // 注意表中的外键关系,确保这些数据在对应的表中的存在
    ProductCategory productCategory = new ProductCategory();
    productCategory.setProductCategoryId(36L);
    // 注意表中的外键关系,确保这些数据在对应的表中的存在
    Shop shop = new Shop();
    shop.setShopId(5L);
    Product product = new Product();
    product.setProductName("modifyProduct");
    product.setProductDesc("modifyProduct desc");
    product.setImgAddr("/mmm/ddd");
    product.setNormalPrice("350");
    product.setPromotionPrice("300");
    product.setPriority(66);
    product.setLastEditTime(new Date());
    product.setEnableStatus(1);
    product.setProductCategory(productCategory);
    product.setShop(shop);
    // 设置productId
    product.setProductId(2L);
    int effectNum = productDao.updateProduct(product);
    Assert.assertEquals(1, effectNum);
  }
}

ProductImgDaoTest

package com.artisan.o2o.dao;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.junit.Assert;
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.artisan.o2o.BaseTest;
import com.artisan.o2o.entity.ProductImg;
/**
 * 
 * 
 * @ClassName: ProductImgDaoTest
 * 
 * @Description: 测试类的执行顺序可通过对测试类添加注解@FixMethodOrder(value) 来指定
 * 
 * @author: Mr.Yang
 * 
 * @date: 2018年6月30日 下午3:28:28
 */
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class ProductImgDaoTest extends BaseTest {
  @Autowired
  private ProductImgDao productImgDao;
  /**
   * 加入@Ignore 可以不执行该单元测试方法
   */
  @Test
  @Ignore
  public void testBatchInsertProductImg() {
    ProductImg productImg1 = new ProductImg();
    productImg1.setImgAddr("/xiaogongjiang/xxxx");
    productImg1.setImgDesc("商品详情图片1");
    productImg1.setPriority(99);
    productImg1.setCreateTime(new Date());
    productImg1.setProductId(2L);
    ProductImg productImg2 = new ProductImg();
    productImg2.setImgAddr("/artisan/xxxx");
    productImg2.setImgDesc("商品详情图片2");
    productImg2.setPriority(98);
    productImg2.setCreateTime(new Date());
    productImg2.setProductId(2L);
    // 添加到productImgList中
    List<ProductImg> productImgList = new ArrayList<ProductImg>();
    productImgList.add(productImg1);
    productImgList.add(productImg2);
    // 调用接口批量新增商品详情图片
    int effectNum = productImgDao.batchInsertProductImg(productImgList);
    Assert.assertEquals(2, effectNum);
  }
  @Test
  public void testA_BatchInsertProductImg() {
    ProductImg productImg1 = new ProductImg();
    productImg1.setImgAddr("/xxx/xxx");
    productImg1.setImgDesc("商品详情图片1x");
    productImg1.setPriority(88);
    productImg1.setCreateTime(new Date());
    productImg1.setProductId(3L);
    ProductImg productImg2 = new ProductImg();
    productImg2.setImgAddr("/yyy/yyyy");
    productImg2.setImgDesc("商品详情图片2y");
    productImg2.setPriority(66);
    productImg2.setCreateTime(new Date());
    productImg2.setProductId(3L);
    // 添加到productImgList中
    List<ProductImg> productImgList = new ArrayList<ProductImg>();
    productImgList.add(productImg1);
    productImgList.add(productImg2);
    // 调用接口批量新增商品详情图片
    int effectNum = productImgDao.batchInsertProductImg(productImgList);
    Assert.assertEquals(2, effectNum);
  }
  @Test
  public void testB_DeleteProductImgById() {
    Long productId = 3L;
    int effectNum = productImgDao.deleteProductImgById(productId);
    Assert.assertEquals(2, effectNum);
  }
}

单元测试通过.可以看到是按照方法名的升序顺序执行的,形成一个闭环。


SQL日志如下

JDBC Connection [com.mchange.v2.c3p0.impl.NewProxyConnection@5bf8fa12] will not be managed by Spring
==>  Preparing: INSERT INTO tb_product_img ( img_addr, img_desc, priority, create_time, product_id ) VALUES ( ?, ?, ?, ?, ? ) , ( ?, ?, ?, ?, ? ) 
==> Parameters: /xxx/xxx(String), 商品详情图片1x(String), 88(Integer), 2018-06-30 21:26:34.455(Timestamp), 3(Long), /yyy/yyyy(String), 商品详情图片2y(String), 66(Integer), 2018-06-30 21:26:34.455(Timestamp), 3(Long)
<==    Updates: 2
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7a67e3c6]
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1921ad94] was not registered for synchronization because synchronization is not active
JDBC Connection [com.mchange.v2.c3p0.impl.NewProxyConnection@30af5b6b] will not be managed by Spring
==>  Preparing: SELECT product_img_id, img_addr, img_desc, priority, create_time, product_id FROM tb_product_img WHERE product_id=? ORDER BY product_img_id 
==> Parameters: 3(Long)
<==    Columns: product_img_id, img_addr, img_desc, priority, create_time, product_id
<==        Row: 16, /xxx/xxx, 商品详情图片1x, 88, 2018-06-30 21:26:34.0, 3
<==        Row: 17, /yyy/yyyy, 商品详情图片2y, 66, 2018-06-30 21:26:34.0, 3
<==      Total: 2
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1921ad94]
ProductImg [productImgId=16, imgAddr=/xxx/xxx, imgDesc=商品详情图片1x, priority=88, createTime=Sat Jun 30 21:26:34 BOT 2018, productId=3]
ProductImg [productImgId=17, imgAddr=/yyy/yyyy, imgDesc=商品详情图片2y, priority=66, createTime=Sat Jun 30 21:26:34 BOT 2018, productId=3]
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@535779e4] was not registered for synchronization because synchronization is not active
JDBC Connection [com.mchange.v2.c3p0.impl.NewProxyConnection@6c0d9d86] will not be managed by Spring
==>  Preparing: DELETE FROM tb_product_img WHERE product_id = ? 
==> Parameters: 3(Long)
<==    Updates: 2
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@535779e4]
• 24

Github地址

代码地址: https://github.com/yangshangwei/o2o


相关文章
|
6月前
|
搜索推荐 JavaScript Java
计算机Java项目|基于SSM的个性化商铺系统
计算机Java项目|基于SSM的个性化商铺系统
|
6月前
|
JavaScript Java 测试技术
基于ssm+vue.js+uniapp小程序的商铺租赁管理系统附带文章和源代码部署视频讲解等
基于ssm+vue.js+uniapp小程序的商铺租赁管理系统附带文章和源代码部署视频讲解等
74 7
|
6月前
|
JavaScript Java 测试技术
基于ssm+vue.js+uniapp小程序的超市商品管理系统附带文章和源代码部署视频讲解等
基于ssm+vue.js+uniapp小程序的超市商品管理系统附带文章和源代码部署视频讲解等
46 4
|
7月前
|
JavaScript Java 测试技术
基于ssm+vue.js的会员制度管理的商品营销系统附带文章和源代码设计说明文档ppt
基于ssm+vue.js的会员制度管理的商品营销系统附带文章和源代码设计说明文档ppt
50 1
|
7月前
|
Java 关系型数据库 MySQL
基于SSM的商品分类管理系统
基于SSM的商品分类管理系统
75 1
|
6月前
|
JavaScript Java 测试技术
基于ssm+vue.js+uniapp小程序的二手商品网站附带文章和源代码部署视频讲解等
基于ssm+vue.js+uniapp小程序的二手商品网站附带文章和源代码部署视频讲解等
28 0
|
6月前
|
JavaScript Java 测试技术
基于ssm+vue.js+uniapp小程序的在线商品交易平台附带文章和源代码设计说明文档ppt
基于ssm+vue.js+uniapp小程序的在线商品交易平台附带文章和源代码设计说明文档ppt
82 0
|
7月前
ssm(Spring+Spring mvc+mybatis)Dao层实现类——DeptDaoImpl
ssm(Spring+Spring mvc+mybatis)Dao层实现类——DeptDaoImpl
|
7月前
ssm(Spring+Spring mvc+mybatis)Dao接口——IDeptDao
ssm(Spring+Spring mvc+mybatis)Dao接口——IDeptDao
|
4月前
|
Java 数据库连接 Maven
手把手教你如何搭建SSM框架、图书商城系统案例
这篇文章是关于如何搭建SSM框架以及实现一个图书商城系统的详细教程,包括了项目的配置文件整合、依赖管理、项目结构和运行效果展示,并提供了GitHub源码链接。
手把手教你如何搭建SSM框架、图书商城系统案例