概述
上篇博客 实战SSM_O2O商铺_26【商品类别】批量新增商品类别从Dao到View层的开发实现了商品目录的批量添加功能,我们按照既定的设计,继续来完成商品目录的修改吧。
Dao层
ProductCategoryDao接口增加接口方法
/** * * * @Title: deleteProductCategory * * @Description: 删除特定shop下的productCategory * * @param productCategoryId * @param shopId * * @return: int */ int deleteProductCategory(@Param("productCategoryId") Long productCategoryId, @Param("shopId") Long shopId);
ProductCategoryDao SQL映射文件
<delete id="deleteProductCategory"> DELETE FROM tb_product_category WHERE product_category_id = #{productCategoryId} and shop_id = #{shopId} </delete>
闭环的单元测试
这里我们使用Junit 4.11里及其以后的版本中增加的@FixMethodOrder注解来实现. 具体见代码注释。
package com.artisan.o2o.dao; import static org.junit.Assert.assertEquals; import java.util.ArrayList; import java.util.Date; import java.util.List; 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.ProductCategory; /** * * * @ClassName: ProductCategoryTest * * @Description: Junit 4.11里增加了指定测试方法执行顺序的特性 . * * 测试类的执行顺序可通过对测试类添加注解@FixMethodOrder(value) 来指定,其中value 为执行顺序 * * 三种执行顺序可供选择: * * 默认(MethodSorters.DEFAULT), * 默认顺序由方法名hashcode值来决定,如果hash值大小一致,则按名字的字典顺序确定 * 由于hashcode的生成和操作系统相关 * (以native修饰),所以对于不同操作系统,可能会出现不一样的执行顺序,在某一操作系统上,多次执行的顺序不变 * * 按方法名( MethodSorters.NAME_ASCENDING)【推荐】, * 按方法名称的进行排序,由于是按字符的字典顺序,所以以这种方式指定执行顺序会始终保持一致; * 不过这种方式需要对测试方法有一定的命名规则,如 测试方法均以testNNN开头(NNN表示测试方法序列号 001-999) * * JVM(MethodSorters.JVM) * 按JVM返回的方法名的顺序执行,此种方式下测试方法的执行顺序是不可预测的,即每次运行的顺序可能都不一样 * * * @author: Mr.Yang * * @date: 2018年6月21日 下午11:55:45 */ @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class ProductCategoryTest extends BaseTest { @Autowired ProductCategoryDao productCategoryDao; @Test public void testB_SelectProductCategoryList() { long shopId = 5L; List<ProductCategory> productCategories = productCategoryDao.selectProductCategoryList(shopId); // shopId = 5 有2条测试数据,期望list中有2条 assertEquals(2, productCategories.size()); // SQL中按照权重排序, product1 priority 99 ,期望第一条数据是 product1 assertEquals("product1", productCategories.get(0).getProductCategoryName()); for (ProductCategory productCategory : productCategories) { System.out.println(productCategory.toString()); } productCategories = productCategoryDao.selectProductCategoryList(6L); assertEquals(0, productCategories.size()); } @Test public void testA_BatchInsertProductCategory() { ProductCategory productCategory1 = new ProductCategory(); productCategory1.setProductCategoryName("product1"); productCategory1.setProductCategoryDesc("product1_desc"); productCategory1.setPriority(99); productCategory1.setCreateTime(new Date()); productCategory1.setLastEditTime(new Date()); productCategory1.setShopId(5L); ProductCategory productCategory2 = new ProductCategory(); productCategory2.setProductCategoryName("product2"); productCategory2.setProductCategoryDesc("product2_desc"); productCategory2.setPriority(98); productCategory2.setCreateTime(new Date()); productCategory2.setLastEditTime(new Date()); productCategory2.setShopId(5L); List<ProductCategory> productCategoryList = new ArrayList<ProductCategory>(); productCategoryList.add(productCategory1); productCategoryList.add(productCategory2); int effectNum = productCategoryDao.batchInsertProductCategory(productCategoryList); Assert.assertEquals(2, effectNum); } @Test public void testC_DeleteProductCategory() { // 查询出来shopId=5的商铺下面全部的商品目录 List<ProductCategory> productCategoryList = productCategoryDao.selectProductCategoryList(5L); // 遍历循环删除 for (ProductCategory productCategory : productCategoryList) { if ("product1".equals(productCategory.getProductCategoryName()) || "product2".equals(productCategory.getProductCategoryName())) { int effectNum = productCategoryDao.deleteProductCategory(productCategory.getProductCategoryId(), 5L); assertEquals(1, effectNum); } } } }
运行单元测试
日志信息:
JDBC Connection [com.mchange.v2.c3p0.impl.NewProxyConnection@7fb95505] will not be managed by Spring ==> Preparing: INSERT INTO tb_product_category( product_category_name, product_category_desc, priority, create_time, last_edit_time, shop_id) VALUES ( ?, ?, ?, ?, ?, ? ) , ( ?, ?, ?, ?, ?, ? ) ==> Parameters: product1(String), product1_desc(String), 99(Integer), 2018-06-22 00:17:25.611(Timestamp), 2018-06-22 00:17:25.611(Timestamp), 5(Long), product2(String), product2_desc(String), 98(Integer), 2018-06-22 00:17:25.612(Timestamp), 2018-06-22 00:17:25.612(Timestamp), 5(Long) <== Updates: 2 Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@38b27cdc] Creating a new SqlSession SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@336f1079] was not registered for synchronization because synchronization is not active JDBC Connection [com.mchange.v2.c3p0.impl.NewProxyConnection@21fd5faa] will not be managed by Spring ==> Preparing: SELECT tpc.product_category_id, tpc.product_category_name, tpc.product_category_desc, tpc.priority, tpc.create_time, tpc.last_edit_time, tpc.shop_id FROM tb_product_category tpc WHERE tpc.shop_id = ? ORDER BY priority DESC ==> Parameters: 5(Long) <== Columns: product_category_id, product_category_name, product_category_desc, priority, create_time, last_edit_time, shop_id <== Row: 24, product1, product1_desc, 99, 2018-06-22 00:17:26.0, 2018-06-22 00:17:26.0, 5 <== Row: 25, product2, product2_desc, 98, 2018-06-22 00:17:26.0, 2018-06-22 00:17:26.0, 5 <== Total: 2 Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@336f1079] ProductCategory [productCategoryId=24, shopId=5, productCategoryName=product1, productCategoryDesc=product1_desc, priority=99, createTime=Fri Jun 22 00:17:26 BOT 2018, lastEditTime=Fri Jun 22 00:17:26 BOT 2018] ProductCategory [productCategoryId=25, shopId=5, productCategoryName=product2, productCategoryDesc=product2_desc, priority=98, createTime=Fri Jun 22 00:17:26 BOT 2018, lastEditTime=Fri Jun 22 00:17:26 BOT 2018] Creating a new SqlSession SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@19b93fa8] was not registered for synchronization because synchronization is not active JDBC Connection [com.mchange.v2.c3p0.impl.NewProxyConnection@1f010bf0] will not be managed by Spring ==> Preparing: SELECT tpc.product_category_id, tpc.product_category_name, tpc.product_category_desc, tpc.priority, tpc.create_time, tpc.last_edit_time, tpc.shop_id FROM tb_product_category tpc WHERE tpc.shop_id = ? ORDER BY priority DESC ==> Parameters: 6(Long) <== Total: 0 Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@19b93fa8] Creating a new SqlSession SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7f132176] was not registered for synchronization because synchronization is not active JDBC Connection [com.mchange.v2.c3p0.impl.NewProxyConnection@2631f68c] will not be managed by Spring ==> Preparing: SELECT tpc.product_category_id, tpc.product_category_name, tpc.product_category_desc, tpc.priority, tpc.create_time, tpc.last_edit_time, tpc.shop_id FROM tb_product_category tpc WHERE tpc.shop_id = ? ORDER BY priority DESC ==> Parameters: 5(Long) <== Columns: product_category_id, product_category_name, product_category_desc, priority, create_time, last_edit_time, shop_id <== Row: 24, product1, product1_desc, 99, 2018-06-22 00:17:26.0, 2018-06-22 00:17:26.0, 5 <== Row: 25, product2, product2_desc, 98, 2018-06-22 00:17:26.0, 2018-06-22 00:17:26.0, 5 <== Total: 2 Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7f132176] Creating a new SqlSession SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5443d039] was not registered for synchronization because synchronization is not active JDBC Connection [com.mchange.v2.c3p0.impl.NewProxyConnection@7d1cfb8b] will not be managed by Spring ==> Preparing: DELETE FROM tb_product_category WHERE product_category_id = ? and shop_id = ? ==> Parameters: 24(Long), 5(Long) <== Updates: 1 Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5443d039] Creating a new SqlSession SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6e4566f1] was not registered for synchronization because synchronization is not active JDBC Connection [com.mchange.v2.c3p0.impl.NewProxyConnection@344f4dea] will not be managed by Spring ==> Preparing: DELETE FROM tb_product_category WHERE product_category_id = ? and shop_id = ? ==> Parameters: 25(Long), 5(Long) <== Updates: 1 Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6e4566f1]
Servie层
接口
/** * * * @Title: deleteProductCategory * * @Description: TODO 需要先将该商品目录下的商品的类别Id置为空,然后再删除该商品目录, 因此需要事务控制 * * @param productCategoryId * @param shopId * @throws ProductCategoryOperationException * * @return: ProductCategoryExecution */ ProductCategoryExecution deleteProductCategory(long productCategoryId, long shopId) throws ProductCategoryOperationException;
接口实现
/** * TODO 需要先将该商品目录下的商品的类别Id置为空,然后再删除该商品目录, 因此需要事务控制@Transactional */ @Override @Transactional public ProductCategoryExecution deleteProductCategory(long productCategoryId, long shopId) throws ProductCategoryOperationException { // TODO 第一步 需要先将该商品目录下的商品的类别Id置为空 // 第二步 删除该商品目录 try { int effectNum = productCategoryDao.deleteProductCategory(productCategoryId, shopId); if (effectNum > 0) { return new ProductCategoryExecution(ProductCategoryStateEnum.SUCCESS); } else { return new ProductCategoryExecution(ProductCategoryStateEnum.INNER_ERROR); } } catch (Exception e) { throw new ProductCategoryOperationException(e.getMessage()); } }
单元测试
@Test public void testDeleteProductCategory() { ProductCategoryExecution productCategoryExecution = productCategoryService.deleteProductCategory(26, 5); Assert.assertEquals(1, productCategoryExecution.getState()); ProductCategoryExecution productCategoryExecution2 = productCategoryService.deleteProductCategory(27, 5); Assert.assertEquals(1, productCategoryExecution2.getState()); }
Controller层
路由方法
/** * * * @Title: remooveProductCategory * * @Description: 删除商品目录 * * @param productCategoryId * @param request * * @return: Map<String,Object> */ @RequestMapping(value = "/removeproductcategory", method = RequestMethod.POST) @ResponseBody public Map<String, Object> remooveProductCategory(Long productCategoryId, HttpServletRequest request) { Map<String, Object> modelMap = new HashMap<String, Object>(); if (productCategoryId != null && productCategoryId > 0) { // 从session中获取shop的信息 Shop currentShop = (Shop) request.getSession().getAttribute("currentShop"); if (currentShop != null && currentShop.getShopId() != null) { try { // 删除 Long shopId = currentShop.getShopId(); ProductCategoryExecution pce = productCategoryService.deleteProductCategory(productCategoryId, shopId); if (pce.getState() == ProductCategoryStateEnum.SUCCESS.getState()) { modelMap.put("success", true); } else { modelMap.put("success", false); modelMap.put("errMsg", pce.getStateInfo()); } } catch (ProductCategoryOperationException e) { e.printStackTrace(); modelMap.put("success", false); modelMap.put("errMsg", e.getMessage()); return modelMap; } } else { modelMap.put("success", false); modelMap.put("errMsg", ProductCategoryStateEnum.NULL_SHOP.getStateInfo()); } } else { modelMap.put("success", false); modelMap.put("errMsg", "请选择商品类别"); } return modelMap; }
单元测试
前端完成后,一起测试
View层
productcategorymanage.js
增加如下代码
var deleteProductCategoryUrl = '/o2o/shopadmin/removeproductcategory'; // 一种是需要提交到后台的删除 now ,另外一种是 新增但未提交到数据库中的删除 temp $('.product-categroy-wrap').on('click', '.row-product-category.now .delete', function(e) { var target = e.currentTarget; $.confirm('确定么?', function() { $.ajax({ url : deleteProductCategoryUrl, type : 'POST', data : { productCategoryId : target.dataset.id, }, dataType : 'json', success : function(data) { if (data.success) { $.toast('删除成功!'); // 重新加载数据 getProductCategoryList(); } else { $.toast('删除失败!'); } } }); }); }); $('.product-categroy-wrap').on('click', '.row-product-category.temp .delete', function(e) { $(this).parent().parent().remove(); });
联调
前端页面debug, 后端也可以加入断点,以debug的方式开启tomcat,逐步调测
效果如下:
Github地址
代码地址: https://github.com/yangshangwei/o2o