商品添加dao层
1 /** 2 * 插入商品 3 * 4 * @param product 5 * @return 6 */ 7 int insertProduct(Product product);
商品添加映射文件
<?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.ryanxu.o2o.dao.ProductDao"> <insert id="insertProduct" parameterType="com.ryanxu.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> </mapper>
批量添加商品图片dao层
/** * 批量添加商品详情图片 * @param productImgList * @return */ int batchInsertProductImg(List<ProductImg> productImgList);
批量添加商品图片映射文件
<?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.ryanxu.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.imgDesc}, #{productImg.priority}, #{productImg.createTime}, #{productImg.productId} ) </foreach> </insert> </mapper>
在做单元测试的时候需要继承BaseTest
Service层
步骤如下:
-
1.处理商品的缩略图,获取相对路径,为了调用dao层的时候写入 tb_product中的 img_addr字段有值
-
2.写入tb_product ,得到product_id(Mybatis自动映射进去的)
-
3.集合product_id 批量处理商品详情图片
-
4.将商品详情图片 批量更新到 tb_proudct_img表
1 /** 2 * 添加商品信息以及图片处理 3 * 4 * @param product 5 * @param thumbnail 缩略图 6 * @param productImgs 详情图 7 * @return 8 * @throws ProductCategoryOperationException 9 */ 10 ProductExecution addProduct(Product product,ImageHolder thumbanil,List<ImageHolder> productImgList) throws ProductCategoryOperationException;
因为每次都需要传入文件流和文件名 所以使用ImageHolder来专门包装这两个属性 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; } }
Service层的实现类
1 @Service 2 public class ProductServiceImpl implements ProductService{ 3 @Autowired 4 private ProductDao productDao; 5 @Autowired 6 private ProductImgDao productImgDao; 7 8 @Override 9 @Transactional 10 //1.处理缩略图,获取缩略图相对路径并赋值给product 11 //2.往tb_product写入商品信息,获取productId 12 //3.结合productId批量处理商品详情图 13 //4.将商品详情图列表批量插入tb_product_img中 14 public ProductExecution addProduct(Product product, ImageHolder thumbanil, List<ImageHolder> productImgList) 15 throws ProductCategoryOperationException { 16 //空值判断 17 if(product!=null&&product.getShop()!=null&&product.getShop().getShopId()!=null) { 18 //给商品设置默认属性 19 product.setCreateTime(new Date()); 20 product.setLastEditTime(new Date()); 21 //默认为上架的状态 22 product.setEnableStatus(1); 23 //若商品缩略图不为空则添加 24 if(thumbanil!=null) { 25 addThumbnail(product,thumbanil); 26 } 27 try { 28 //创建商品信息 29 int effectedNum = productDao.insertProduct(product); 30 if(effectedNum<=0) { 31 throw new ProductOperationException("创建商品失败"); 32 } 33 }catch (Exception e) { 34 throw new ProductOperationException("创建商品失败 :" +e.toString()); 35 } 36 //若商品详情图不为空则添加 37 if(productImgList != null && productImgList.size() >0) { 38 addProductImgList(product,productImgList); 39 } 40 return new ProductExecution(ProductStateEnum.SUCCESS,product); 41 }else { 42 //传参为空则返回空值错误信息 43 return new ProductExecution(ProductStateEnum.NULL_PRODUCT); 44 } 45 } 46 47 48 /** 49 * 将商品缩略图添加到用户相对的文件夹下,并将店铺信息中的商品图片信息更新 50 * 51 * @param product 52 * @param imageHolder 53 */ 54 private void addThumbnail(Product product,ImageHolder imageHolder) { 55 //获取缩略图的存储途径,直接存储在店铺的文件夹下 56 String dest = PathUtil.getShopImagePath(product.getShop().getShopId()); 57 //返回相对路径 58 String thumbnailAddr = ImageUtil.generateThumbnail(imageHolder, dest); 59 product.setImgAddr(thumbnailAddr); 60 } 61 62 /** 63 * 批量添加商品详情图片到用户相对的文件夹下,并将其批量插入到数据库中 64 * 65 * @param product 66 * @param productImgHolderList 67 */ 68 private void addProductImgList(Product product, List<ImageHolder> productImgHolderList) { 69 //获取图片存储路径,这里直接存放到相应店铺的文件夹底下 70 String dest = PathUtil.getShopImagePath(product.getShop().getShopId()); 71 List<ProductImg> productImgList = new ArrayList<>(); 72 //遍历图片一次去处理,并添加进productImg实体类里 73 for(ImageHolder productImgHolder:productImgHolderList) { 74 String imgAddr = ImageUtil.generateNormalImg(productImgHolder,dest); 75 ProductImg productImg = new ProductImg(); 76 productImg.setImgAddr(imgAddr); 77 productImg.setProductId(product.getProductId()); 78 productImg.setCreateTime(new Date()); 79 productImgList.add(productImg); 80 } 81 //如果确实是有图片需要添加的,就执行批量添加操作 82 if(productImgList.size() > 0) { 83 try { 84 int effectedNum = productImgDao.batchInsertProductImg(productImgList); 85 if(effectedNum <= 0) { 86 throw new ProductOperationException("创建商品详情图片失败"); 87 } 88 }catch (Exception e) { 89 throw new ProductOperationException("创建商品详情图片失败: "+e.toString()); 90 } 91 } 92 } 93 }
Controller层
步骤如下:
- 获取前端传递过来的Product对象,通过FastJson提供的api将其转换为Product对象
- 获取前端传递过来的商品缩略图以及商品详情图片,通过CommonsMultipartResolver来处理
- 调用Service层的服务来持久化数据及图片的操作
1 @Controller 2 @RequestMapping("/shopadmin") 3 public class ProductManagementController { 4 @Autowired 5 private ProductService productService; 6 7 //支持上传商品详情图的最大数量 8 private static final int IMAGEMAXCOUNT=6; 9 10 /** 11 * 前端页面通过post方式传递一个包含文件上传的Form会以multipart/form-data请求发送给服务器, 12 * 13 * 需要告诉DispatcherServlet如何处理MultipartRequest,我们在spring-web. 14 * xml中定义了multipartResolver。 15 * 16 * 如果某个Request是一个MultipartRequest,它就会首先被MultipartResolver处理, 17 * 然后再转发相应的Controller。 18 * 19 * 在Controller中, 20 * 将HttpServletRequest转型为MultipartHttpServletRequest 21 * ,可以非常方便的得到文件名和文件内容 22 * @param request 23 * @return 24 * @throws IOException 25 */ 26 @RequestMapping(value="/addproduct",method=RequestMethod.POST) 27 @ResponseBody 28 private Map<String, Object> addproduct(HttpServletRequest request) throws IOException{ 29 Map<String, Object> modelMap = new HashMap<>(); 30 31 //初始化各种参数!!!! 32 //接收前端传递过来的product 33 Product product = null; 34 String productStr = HttpServletRequestUtil.getString(request, "productStr"); 35 //处理文件流 36 MultipartHttpServletRequest multipartHttpServletRequest = null; 37 //接收前端传递过来的product 38 ImageHolder thumbnail = null; 39 // 接收商品详情图片 40 List<ImageHolder> productImgList = new ArrayList<>(); 41 //在本次会话的上下文获取上传的文件 42 CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver(request.getSession().getServletContext()); 43 44 //步骤1:验证码校验 45 if(!CodeUtil.checkVerifyCode(request)) { 46 modelMap.put("success", false); 47 modelMap.put("errMsg", "验证码错误"); 48 return modelMap; 49 } 50 //步骤2:使用FastJson提供的api,实例化Product 构造调用service层的第一个参数 51 //接受前端参数变量的初始化,商品,缩略图,详情图列表实体类 52 ObjectMapper objectMapper = new ObjectMapper(); 53 // 获取前端传递过来的product,约定好使用productStr 54 try { 55 product = objectMapper.readValue(productStr, Product.class); 56 } catch (Exception e) { 57 modelMap.put("success", false); 58 modelMap.put("errMsg", e.toString()); 59 return modelMap; 60 } 61 //步骤3: 商品缩略图 和 商品详情图 构造调用service层的第二个参数和第三个参数 62 try { 63 //若请求中存在文件流,则取出相关的文件(包括缩略图和详情图) 64 if(commonsMultipartResolver.isMultipart(request)) { 65 // 将HttpServletRequest转型为MultipartHttpServletRequest,可以很方便地得到文件名和文件内容 66 multipartHttpServletRequest = (MultipartHttpServletRequest) request; 67 68 //1.接收商品缩略图 取出缩略图并构建ImageHolder对象 69 CommonsMultipartFile thumbnailFile = (CommonsMultipartFile) multipartHttpServletRequest.getFile("thumbnail"); 70 //2.转化为ImageHolder,使用service层的参数类型要求 71 thumbnail = new ImageHolder(thumbnailFile.getOriginalFilename(), thumbnailFile.getInputStream()); 72 //3.取出详情图列表并构建List<ImageHolder>列表对象,最多支持六张图上传 73 for(int i = 0; i < IMAGEMAXCOUNT; i++){ 74 CommonsMultipartFile commonsMultipartFile = (CommonsMultipartFile) multipartHttpServletRequest.getFile("productImg" + i); 75 if(commonsMultipartFile != null){ 76 //若取出的第i个详情图片文件流不为空,则将其加入详情图列表 77 ImageHolder productImg = new ImageHolder(commonsMultipartFile.getOriginalFilename(), commonsMultipartFile.getInputStream()); 78 productImgList.add(productImg); 79 } else { 80 //若取出的第i个详情图片文件流为空,则终止循环 81 break; 82 } 83 } 84 85 } else{ 86 modelMap.put( "success", false ); 87 modelMap.put( "errMsg", "上传图片不能为空" ); 88 } 89 } catch (Exception e){ 90 modelMap.put( "success", false ); 91 modelMap.put( "errMsg", e.toString() ); 92 return modelMap; 93 } 94 95 //步骤4:调用service层 96 //若product,thumbnail(缩略图),productImgList(商品详情图片列表)不为空,则进行商品添加 97 if(product != null && thumbnail != null && productImgList.size() > 0){ 98 try{ 99 //从session中获取当前shop的id赋值给product,减少对前端数据的依赖 100 Shop currentShop = (Shop) request.getSession().getAttribute( "currentShop" ); 101 102 /* Shop currentShop = new Shop(); 103 currentShop.setShopId( 1L );*/ 104 Shop shop = new Shop(); 105 shop.setShopId(currentShop.getShopId()); 106 product.setShop(shop); 107 //执行添加操作 108 ProductExecution productExecution = productService.addProduct( product, thumbnail, productImgList ); 109 if(productExecution.getState() == ProductStateEnum.SUCCESS.getState()){ 110 modelMap.put( "success", true ); 111 }else{ 112 modelMap.put( "success", false ); 113 modelMap.put( "errMsg", productExecution.getStateInfo() ); 114 } 115 } catch(ProductOperationException e){ 116 modelMap.put( "success", false ); 117 modelMap.put( "errMsg", e.toString() ); 118 return modelMap; 119 } 120 }else{ 121 modelMap.put( "success", false ); 122 modelMap.put( "errMsg", "请输入商品信息" ); 123 } 124 return modelMap; 125 } 126 }