SSM框架学习——8.2/8.3 商品添加之Service层的实现

商品添加Service层的实现

本节主要是开发Product和ProductImg的添加Service方法。有异议的地方在于:Product类中的List< ProductImg >属性的存在是否必要。

接口定义:ProductService.java

public interface ProductService {
    /**
     * 
     * @param product 前端传入的Product对象,里面的信息不包括创建时间、商品状态、缩略图、详细图、productId,这些需要在方法内部进行赋值(详细图未赋值)
     * @param thumbnail 缩略图封装
     * @param productImgHolderList 详细图列表封装
     * @return
     * @throws ProductOperationException
     */
    ProductExecution addProduct(Product product, ImageHolder thumbnail,
                                List<ImageHolder> productImgHolderList)
            throws ProductOperationException;
}

新定义了ProductExecutionImageHolder以及ProductOperationException

ProcutExecution:Product服务层的返回类。
ImageHolder:利用ImageHolder对前面开发的ShopService层的add和modify,以及ImageUtil工具类中的generateThumbnail方法进行了重构。
ProductOperationException:继承RuntimeException类,以支持Service层的事务回滚。


dto/ProductExecution.java

//setter/getter省略
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;
    }
}

ProductExecution类专门用于Service层的返回值,这个返回值里包括了操作的状态码、信息以及需要返回的实体对象。
那么最好要有一个Enum枚举类定义和存储多个状态状态码和状态信息。

ProductStateEnum.java

//setter/getter省略
public enum ProductStateEnum {
    OFFLINE(-1, "非法商品"), DOWN(0, "下架"), SUCCESS(1, "操作成功"), INNER_ERROR(-1001, "操作失败"), EMPTY(-1002, "商品为空");

    private int state;

    private String stateInfo;

    private ProductStateEnum(int state, String stateInfo) {
        this.state = state;
        this.stateInfo = stateInfo;
    }

    public static ProductStateEnum stateOf(int index) {
        for (ProductStateEnum state : values()) {
            if (state.getState() == index) {
                return state;
            }
        }
        return null;
    }
}

定义好枚举类之后,Service层就可以很方便的利用枚举名( 例如ProductStateEnum.SUCCESS)将当前的状态存储到Execution中返回给上一层调用,不需要记录很多的状态码和状态信息。


ImageHolder.java

//setter/getter省略
public class ImageHolder {

    private String imageName;
    private InputStream image;
}

ImageHolder很简单,它只是将文件的输入流和名字封装在一个类中,减少了方法的参数数量。


ProductOperationException.java

public class ProductOperationException extends RuntimeException {
    public ProductOperationException(String msg){
        super(msg);
    }
}

接口实现:ProductServiceImpl.java

    @Override
    @Transactional
    // 1.处理缩略图,获取缩略图相对路径并赋值给product
    // 2.往tb_product写入商品信息,获取productId
    // 3.结合productId批量处理商品详情图
    // 4.将商品详情图列表批量插入tb_product_img中
    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());`
            }
            // 若商品详情图不为空则添加
            if (productImgHolderList != null && productImgHolderList.size() > 0) {
                addProductImgList(product, productImgHolderList);
            }
            return new ProductExecution(ProductStateEnum.SUCCESS, product);
        } else {
            // 传参为空则返回空值错误信息
            return new ProductExecution(ProductStateEnum.EMPTY);
        }

    }

Service内部实现主要做了什么工作呢?

首先确保前端js表单封装传入的Product对象以及类中的Shop对象以及Shop对象中的shopid值是否为空,如果为空,直接向Controller层抛出ProductStateEnum.EMPTY空值状态异常。(也说明应用允许店主创建商品时,不上传缩略图和详细图)

接着,向Product对象中添加商品创建时间、修改时间、商品上架状态,接着判断用户是否已上传商品的缩略图。

如果上传则调用addThumbnail方法(见下面),利用工具类Util的方法getShopImagePath获得该商品所属店铺的图片目录相对路径,然后调用工具类Util的方法generateThumbnail将缩略图放在服务器对应店铺的图片目录下,并把缩略图的相对地址放到传入的Product对象的imgAddr属性中。

然后调用DAO层的insertProduct方法,将Product对象传入,由于Dao层的配置(商品添加之Dao层实现),Dao层SQL语句执行完毕后,会将数据库中获得的product_id的主键赋值给Product对象中的productId。获得productId是因为,接下来添加的商品的详细图的数据库表依赖于商品id号(外键),所以在添加详细图之前,一定要获得商品的id号。

接下来便进行添加商品详情图操作,首先判断详情图是否存在,然后调用addProductImgList方法(见下面),通过商品的店铺Id获得店铺的图片相对路径,通过循环的方式,将图片存入到图片路径中,并且封装ProductImg对象,不断地加入到List中,最后调用Dao层的batchInsertProductImg(productImgList)方法将详细图的相对路径存入到数据库中。

最后返回给Controller层ProductExecution类型的操作结果。

总结

总的来说,进行了两次Dao操作,一次是Product表信息,一次是Product_img表信息。Product_img表依赖于Product的id号,所以在后面操作。

特殊的是Product表信息处理时需要将缩略图存入到服务器后,获得相对路径存入到数据库中。所以使用了Util工具类中的方法。Product_img表同理。

    /**
     * 添加缩略图
     * @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);
    }
    /**
     * 批量添加图片
     *
     * @param product
     * @param productImgHolderList
     */
    private void addProductImgList(Product product, List<ImageHolder> productImgHolderList) {
        // 获取图片存储路径,这里直接存放到相应店铺的文件夹底下
        String dest = PathUtil.getShopImagePath(product.getShop().getShopId());
        List<ProductImg> productImgList = new ArrayList<ProductImg>();
        // 遍历图片一次去处理,并添加进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());
            }
        }
    }

单元测试

ProductServiceTest.java

public class ProductServiceTest extends BaseTest {
    @Autowired
    private ProductService productService;

    @Test
    public void testAddProduct() throws ShopOperationException, FileNotFoundException {
        // 创建shopId为1且productCategoryId为1的商品实例并给其成员变量赋值
        Product product = new Product();
        Shop shop = new Shop();
        shop.setShopId(1L);
        ProductCategory pc = new ProductCategory();
        pc.setProductCategoryId(1L);
        product.setShop(shop);
        product.setProductCategory(pc);
        product.setProductName("测试商品1");
        product.setProductDesc("测试商品1");
        product.setPriority(20);
        product.setCreateTime(new Date());
        // 创建缩略图文件流
        File thumbnailFile = new File("/home/zjc/xiaohuangren.jpg");
        InputStream is = new FileInputStream(thumbnailFile);
        ImageHolder thumbnail = new ImageHolder(thumbnailFile.getName(), is);
        // 创建两个商品详情图文件流并将他们添加到详情图列表中
        File productImg1 = new File("/home/zjc/xiaohuangren.jpg");
        InputStream is1 = new FileInputStream(productImg1);
        File productImg2 = new File("/home/zjc/xiaohuangren.jpg");
        InputStream is2 = new FileInputStream(productImg2);
        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());
    }
}

你可能感兴趣的:(SSM框架学习——8.2/8.3 商品添加之Service层的实现)