• 校园商铺-8商品模块-2商品添加之Service层的实现


    1. 创建ProductService接口使用的操作类、枚举类、异常类

    1.1 枚举类

    package com.csj2018.o2o.enums;
    
    public enum ProductStateEnum {
    	SUCCESS(1,"创建成功"),INNER_ERROR(-1001,"操作失败"),EMPTY_LIST(-1002,"添加数少于1");
    	
    	private int state;
    	
    	private String stateInfo;
    	
    	private ProductStateEnum(int state,String stateInfo) {
    		this.state = state;
    		this.stateInfo = stateInfo;
    	}
    	public int getState() {
    		return state;
    	}
    	public String getStateInfo() {
    		return stateInfo;
    	}
    	public static ProductStateEnum stateOf(int index) {
    		for(ProductStateEnum state:values()) {
    			if(state.getState() == index) {
    				return state;
    			}
    		}
    		return null;
    	}
    }
    

    1.2 异常类

    package com.csj2018.o2o.exceptions;
    
    public class ProductOperationException extends RuntimeException{
    	
    	
    	/**
    	 * add generated serial verisonID
    	 */
    	private static final long serialVersionUID = -5157230159775214912L;
    
    	public ProductOperationException(String msg) {
    		super(msg);
    	}
    }
    

    1.3 执行结果类

    package com.csj2018.o2o.dto;
    
    import java.util.List;
    
    import com.csj2018.o2o.entity.Product;
    import com.csj2018.o2o.enums.ProductStateEnum;
    
    public class ProductExecution {
    	//结果状态
    	private int state;
    	//状态标识
    	private String stateInfo;
    	//商品数量
    	private int count;
    	//操作的product(增删改商品的时候用)
    	private Product product;
    	//获取到饿product列表(查询商品列表的时候用)
    	private List<Product> productList;
    	
    	public ProductExecution() {}
    	//失败的构造器
    	public ProductExecution(ProductStateEnum stateEnum) {
    		this.state = stateEnum.getState();
    		this.stateInfo = stateEnum.getStateInfo();
    	}
    	//成功的构造器
    	public ProductExecution(ProductStateEnum stateEnum,Product product) {
    		this.state = stateEnum.getState();
    		this.stateInfo = stateEnum.getStateInfo();
    		this.product = product;
    	}
    	//成功的构造器
    	public ProductExecution(ProductStateEnum stateEnum,List<Product> productList) {
    		this.state = stateEnum.getState();
    		this.stateInfo = stateEnum.getStateInfo();
    		this.productList = productList;
    	}
    	public int getState() {
    		return state;
    	}
    	public void setState(int state) {
    		this.state = state;
    	}
    	public String getStateInfo() {
    		return stateInfo;
    	}
    	public void setStateInfo(String stateInfo) {
    		this.stateInfo = stateInfo;
    	}
    	public int getCount() {
    		return count;
    	}
    	public void setCount(int count) {
    		this.count = count;
    	}
    	public Product getProduct() {
    		return product;
    	}
    	public void setProduct(Product product) {
    		this.product = product;
    	}
    	public List<Product> getProductList() {
    		return productList;
    	}
    	public void setProductList(List<Product> productList) {
    		this.productList = productList;
    	}
    }
    

    2.ProductService接口

    package com.csj2018.o2o.service;
    
    import java.io.InputStream;
    import java.util.List;
    
    import com.csj2018.o2o.dto.ProductExecution;
    import com.csj2018.o2o.entity.Product;
    import com.csj2018.o2o.exceptions.ProductOperationException;
    
    public interface ProductService {
    	/**
    	 * 添加商品信息以及图片处理
    	 * @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;
    }
    

    缩略图和详情图参数是相似的,因此可以封装一个类让方法更清晰。

    3重构

    3.1 封装图片和流

    package com.csj2018.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.2 修改Service层

    package com.csj2018.o2o.service;
    
    import java.util.List;
    
    import com.csj2018.o2o.dto.ImageHolder;
    import com.csj2018.o2o.dto.ProductExecution;
    import com.csj2018.o2o.entity.Product;
    import com.csj2018.o2o.exceptions.ProductOperationException;
    
    public interface ProductService {
    	/**
    	 * 添加商品信息以及图片处理
    	 * @param product
    	 * @param thumbnail 缩略图
    	 * @param productImgList 详情图
    	 * @return
    	 * @throws ProductOperationException
    	 */
    	ProductExecution addProduct(Product product, ImageHolder thumbnail,List<ImageHolder> productImgList) throws ProductOperationException;
    }
    

    4.实现Service

    package com.csj2018.o2o.service.impl;
    
    import java.util.ArrayList;
    import java.util.Date;
    import java.util.List;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;
    
    import com.csj2018.o2o.dao.ProductDao;
    import com.csj2018.o2o.dao.ProductImgDao;
    import com.csj2018.o2o.dto.ImageHolder;
    import com.csj2018.o2o.dto.ProductExecution;
    import com.csj2018.o2o.entity.Product;
    import com.csj2018.o2o.entity.ProductImg;
    import com.csj2018.o2o.enums.ProductStateEnum;
    import com.csj2018.o2o.exceptions.ProductOperationException;
    import com.csj2018.o2o.service.ProductService;
    import com.csj2018.o2o.util.*;
    
    @Service
    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中
    	 * 通过spring的事务管理去执行这4不操作,任何一步出错就回滚,不会往表里写入
    	 */
    	@Override
    	@Transactional
    	public ProductExecution addProduct(Product product, ImageHolder thumbnail, List<ImageHolder> productImgHolderList)
    			throws ProductOperationException {
    		//空值判断
    		if(product != null && product.getShop() != null && product.getShop().getShopId() != null) {
    			//给商品设置默认属性
    			product.setCreateTime(new Date());
    			product.setLastEditTime(new Date());
    			//默认为上架的状态
    			product.setEnableStatus(1);
    			//若商品缩略图不为空,则添加缩略图信息到商品
    			if(thumbnail != null) {
    				addThumbnail(product,thumbnail);
    			}
    			try {
    				int effectedNum = productDao.insertProduct(product);
    				if(effectedNum <= 0) {
    					throw new ProductOperationException("创建商品失败");
    				}
    			}catch (Exception e) {
    				throw new ProductOperationException("创建商品失败:"+e.toString());
    			}
    			//若商品详情图不为空,则向tb_product_img添加商品详情图
    			if(productImgHolderList != null && productImgHolderList.size() >0) {
    				addProductImgList(product,productImgHolderList);
    			}
    			return new ProductExecution(ProductStateEnum.SUCCESS,product);
    		}else {
    			//传参为空,则返回控制错误信息
    			return new ProductExecution(ProductStateEnum.EMPTY);
    		}
    	}
    	/**
    	 * 向product对象添加缩略图
    	 * @param product
    	 * @param thumbnail
    	 */
    	private void addThumbnail(Product product, ImageHolder thumbnail) {
    		String dest = PathUtil.getShopImagePath(product.getShop().getShopId());
    		String thumbnailAddr = ImageUtil.generateThumbnail(thumbnail, dest);
    		product.setImgAddr(thumbnailAddr);
    	}
    	private void addProductImgList(Product product, List<ImageHolder> productImgHolderList) {
    		//获取图片存储路径,这里直接存放到相应店铺的文件夹下,同缩略图
    		String dest = PathUtil.getShopImagePath(product.getShop().getShopId());
    		List<ProductImg> productImgList = new ArrayList<ProductImg>();
    		//遍历,获得详情图片列表
    		for(ImageHolder productImgHolder:productImgHolderList) {
    			String imgAddr = ImageUtil.generateNormalImg(productImgHolder, 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.toString());
    			}
    		}
    	}
    }
    

    5.Image工具类

    package com.csj2018.o2o.util;
    
    import java.io.File;
    import java.io.InputStream;
    import java.io.IOException;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.Random;
    
    import javax.imageio.ImageIO;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.web.multipart.commons.CommonsMultipartFile;
    
    import com.csj2018.o2o.dto.ImageHolder;
    
    import net.coobird.thumbnailator.Thumbnails;
    import net.coobird.thumbnailator.geometry.Positions;
    
    public class ImageUtil {
    	private static String basePath = Thread.currentThread().getContextClassLoader().getResource("").getPath();
    	private static final SimpleDateFormat sDateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
    	private static final Random r = new Random();
    	private static Logger logger = LoggerFactory.getLogger(ImageUtil.class);
    	/**
    	 * 将文件流CommonsMultipartFile转换成File
    	 * @param cFile
    	 * @return
    	 */
    	public static File transferCommonsMultipartFileToFile(CommonsMultipartFile cFile) {
    		File newFile = new File(cFile.getOriginalFilename());
    		try {
    			cFile.transferTo(newFile);
    		}catch(IllegalStateException e) {
    			logger.error(e.toString());
    			e.printStackTrace();;
    		}catch (IOException e) {
    			logger.error(e.toString());
    			e.printStackTrace();
    		}
    		return newFile;
    	}
    	/**
    	 * 根据输入流,处理缩略图,并返回新生成图片的相对路径
    	 * @param thumbnailInputStream
    	 * @param targetAddr
    	 * @return
    	 */
    	public static String generateThumbnail(ImageHolder thumbnail ,String targetAddr) {
    		//获取不重复的随机名
    		String realFileName = getRandomFileName();
    		//获取文件的扩展名如png,jpg等
    		String extension = getFileExtension(thumbnail.getImageName());
    		//如果目标路径不存在,即自动创建
    		makeDirPath(targetAddr);
    		//获取文件存储的相对路径(带文件名)
    		String relativeAddr = targetAddr + realFileName + extension;
    		logger.debug("current relativeAddr is:" + relativeAddr);
    		//获取文件要保存到的目标路径
    		File dest = new File(PathUtil.getImgBasePath()+relativeAddr);
    		logger.debug("current complete addr is:" + PathUtil.getImgBasePath()+relativeAddr);
    		//调用Thumbnails生成带有水印的图片
    		try {
    			Thumbnails.of(thumbnail.getImage()).size(200,200).watermark(Positions.BOTTOM_RIGHT,ImageIO.read(new File(basePath+"/newwater.png")),0.8f)
    				.outputQuality(0.8f).toFile(dest);
    		}catch (IOException e) {
    			logger.error(e.toString());
    			throw new RuntimeException("创建缩略图失败:"+e.toString());
    		}
    		return relativeAddr;
    	}
    	/**
    	 * 根据输入流,生成详情图片,并返回新生成图片的相对地址
    	 * @param thumbnail
    	 * @param targetAddr
    	 * @return
    	 */
    	public static String generateNormalImg(ImageHolder thumbnail ,String targetAddr) {
    		//获取不重复的随机名
    		String realFileName = getRandomFileName();
    		//获取文件的扩展名如png,jpg等
    		String extension = getFileExtension(thumbnail.getImageName());
    		//如果目标路径不存在,即自动创建
    		makeDirPath(targetAddr);
    		//获取文件存储的相对路径(带文件名)
    		String relativeAddr = targetAddr + realFileName + extension;
    		logger.debug("current relativeAddr is:" + relativeAddr);
    		//获取文件要保存到的目标路径
    		File dest = new File(PathUtil.getImgBasePath()+relativeAddr);
    		logger.debug("current complete addr is:" + PathUtil.getImgBasePath()+relativeAddr);
    		//调用Thumbnails生成带有水印的图片
    		try {
    			Thumbnails.of(thumbnail.getImage()).size(337,640).watermark(Positions.BOTTOM_RIGHT,ImageIO.read(new File(basePath+"/newwater.png")),0.8f)
    				.outputQuality(0.9f).toFile(dest);
    		}catch (IOException e) {
    			logger.error(e.toString());
    			throw new RuntimeException("创建详情图片失败:"+e.toString());
    		}
    		return relativeAddr;
    	}
    	/**
    	 * 创建目标路径所设计的目录,即/a/b/c/xxx.jpg
    	 * 那么a b c 这三个文件夹都得自动创建
    	 * @param targetAddr
    	 */
    	private static void makeDirPath(String targetAddr) {
    		String realFileParentPath = PathUtil.getImgBasePath()+targetAddr;
    		File dirPath = new File(realFileParentPath);
    		if(!dirPath.exists()) {
    			dirPath.mkdirs();//上级目录不存在,也一并创建,同mkdir -p
    		}
    	}
    	/**
    	 * 获取输入文件流的扩展名
    	 * @param thumbnail
    	 * @return
    	 */
    	private static String getFileExtension(String fileName) {
    		//输入的图片,只需或获取最后一个 . 后面的字符即可
    		
    		return fileName.substring(fileName.lastIndexOf("."));
    	}
    	/**
    	 * 生成随机文件名,当前年月日时分秒+5位随机数
    	 * @param args
    	 * @throws Exception
    	 */
    	public static String getRandomFileName() {
    		//获取随机的5位数:10000-99999
    		int rannum = r.nextInt(89999)+10000;
    		String nowTimeStr = sDateFormat.format(new Date());
    		return nowTimeStr + rannum;
    	}
    	public static void main(String[] args) throws Exception {
    
    		Thumbnails.of(new File(basePath + "/water.png")).size(30, 30).toFile(new File(basePath + "/newwater.png"));
    //		Thumbnails.of(new File("/Users/chenshanju/Downloads/cat.jpg")).size(200, 200)
    //				.watermark(Positions.BOTTOM_RIGHT, ImageIO.read(new File(basePath + "newwater.png")), 1.0f)
    //				.outputQuality(0.8).toFile("/Users/chenshanju/Downloads/newcat.jpg");
    	}
    	/**
    	 * storePath是文件的路径还是目录的路径
    	 * 如果storePath是文件路径则删除该文件;
    	 * 如果storePath是目录路径则删除该目录下的所有文件
    	 * @param storePath
    	 */
    	public static void deleteFileOfPath(String storePath) {
    		File fileOrPath = new File(PathUtil.getImgBasePath() + storePath);
    		if(fileOrPath.exists()) {
    			if(fileOrPath.isDirectory()) {
    				File[] files = fileOrPath.listFiles();
    				for(int i=0;i<files.length;i++) {
    					files[i].delete();
    				}
    			}
    			fileOrPath.delete();
    		}
    	}
    }
    

    6.service层单元测试

    package com.csj2018.o2o.service;
    
    import static org.junit.Assert.assertEquals;
    
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.InputStream;
    import java.util.ArrayList;
    import java.util.Date;
    import java.util.List;
    
    import org.junit.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    
    import com.csj2018.o2o.BaseTest;
    import com.csj2018.o2o.dto.ImageHolder;
    import com.csj2018.o2o.dto.ProductExecution;
    import com.csj2018.o2o.entity.Product;
    import com.csj2018.o2o.entity.ProductCategory;
    import com.csj2018.o2o.entity.Shop;
    import com.csj2018.o2o.enums.ProductStateEnum;
    import com.csj2018.o2o.exceptions.ProductOperationException;
    
    public class ProductServiceTest extends BaseTest{
    	@Autowired
    	private ProductService productService;
    	@Test
    	public void testAddProduct() throws ProductOperationException,FileNotFoundException{
    		//创建shopID为1且productCategory为1的商品实例,并给其成员变量赋值
    		Product product = new Product();
    		Shop shop = new Shop();
    		shop.setShopId(1L);
    		ProductCategory pc = new ProductCategory();
    		pc.setProductCategoryId(10L);
    		product.setShop(shop);
    		product.setProductCategory(pc);
    		product.setProductName("测试商品1");
    		product.setProductDesc("测试商品1");
    		product.setPriority(20);
    		product.setCreateTime(new Date());
    		product.setEnableStatus(1);
    		//创建缩略图
    		File thumbnailFile = new File("/Users/chenshanju/Downloads/Y61.jpeg");
    		InputStream is = new FileInputStream(thumbnailFile);
    		ImageHolder thumbnail = new ImageHolder(thumbnailFile.getName(),is);
    		//创建2个详情图片
    		File productImg1 = new File("/Users/chenshanju/Downloads/Prado.jpg");
    		InputStream is1 = new FileInputStream(thumbnailFile);
    		File productImg2 = new File("/Users/chenshanju/Downloads/Pajero.jpg");
    		InputStream is2 = new FileInputStream(thumbnailFile);
    		List<ImageHolder> productImgList = new ArrayList<ImageHolder>();
    		productImgList.add(new ImageHolder(productImg1.getName(),is1));
    		productImgList.add(new ImageHolder(productImg2.getName(),is2));
    		
    		ProductExecution pe = productService.addProduct(product, thumbnail, productImgList);
    		assertEquals(ProductStateEnum.SUCCESS.getState(),pe.getState());
    	}
    }
    
  • 相关阅读:
    ORA-12520: TNS:监听程序无法为请求的服务器类型找到可用的处理程序解
    Django2.1.2创建默认管理后台
    堡垒机实例以及数据库操作
    pycharm常用快捷键
    Linux命令之sftp
    oracle收集ash和awr性能报告方法
    linux-php5.6-安装sftp扩展
    linux系统安全设置策略
    Openssh版本升级修复漏洞
    Android Studio下HierarchyViewer的使用
  • 原文地址:https://www.cnblogs.com/csj2018/p/12448553.html
Copyright © 2020-2023  润新知