文章目录
概述
上篇博客 实战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地址