商铺项目(商品类别模块一)

<?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.ouyan.o2o.dao.ProductCategoryDao">
    <!-- 目的:为dao接口方法提供sql语句配置 -->
    <select id="queryProductCategoryList" resultType="com.ouyan.o2o.entity.ProductCategory"
        parameterType="Long">
        <!-- 具体的sql -->
        SELECT
        product_category_id,
        product_category_name,
        priority,
        create_time,
        shop_id
        FROM
        tb_product_category
        WHERE
        shop_id = #{shopId}
        ORDER BY
        priority DESC
    </select>
</mapper>    

package com.ouyan.o2o.dao;

import java.util.List;

import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;

import com.ouyan.o2o.BaseTest;
import com.ouyan.o2o.entity.ProductCategory;

public class ProductCategoryDaoTest extends BaseTest {
    @Autowired
    private ProductCategoryDao productCategoryDao;

    @Test
    public void testBQueryByShopId() throws Exception {
        long shopId = 62;
        List<ProductCategory> productCategoryList = productCategoryDao.queryProductCategoryList(shopId);
        System.out.println("该店铺自定义类别数为:" + productCategoryList.size());
    }

    
}

package com.ouyan.o2o.web.shopadmin;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
@RequestMapping(value="shopadmin",method={RequestMethod.GET})
public class ShopAdminController {
    @RequestMapping(value="/shopoperate")
    public String shopOperation(){
        return "shop/shopoperation";
    }
    
    @RequestMapping(value="/shoplist")
    public String shopList(){
        return "shop/shoplist";
    }
    
    @RequestMapping(value="/shopmanagement")
    public String shopManagement(){
        return "shop/shopmanagement";
    }
    
    @RequestMapping(value="/productcategorymanagement")
    public String peoductCategoryManagement(){
        return "shop/productcategorymanagement";
    }
}

package com.ouyan.o2o.dao;

import java.util.List;

import com.ouyan.o2o.entity.ProductCategory;

public interface ProductCategoryDao {
    /**
     * 通过shop id 查询店铺商品类别
     * 
     * @param long
     *            shopId
     * @return List<ProductCategory>
     */
    List<ProductCategory> queryProductCategoryList(long shopId);

}

package com.ouyan.o2o.entity;

import java.util.Date;

/**
 * 商品类别实体类
 * 
 * @author xiangze
 *
 */
public class ProductCategory {
    // 主键ID
    private Long productCategoryId;
    // 该类别是属于哪个店铺的
    private Long shopId;
    // 类别名
    private String productCategoryName;
    // 权重,越大越排前显示
    private Integer priority;
    // 创建时间
    private Date createTime;

    public Long getProductCategoryId() {
        return productCategoryId;
    }

    public void setProductCategoryId(Long productCategoryId) {
        this.productCategoryId = productCategoryId;
    }

    public Long getShopId() {
        return shopId;
    }

    public void setShopId(Long shopId) {
        this.shopId = shopId;
    }

    public String getProductCategoryName() {
        return productCategoryName;
    }

    public void setProductCategoryName(String productCategoryName) {
        this.productCategoryName = productCategoryName;
    }

    public Integer getPriority() {
        return priority;
    }

    public void setPriority(Integer priority) {
        this.priority = priority;
    }

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

}

package com.ouyan.o2o.service;

import java.util.List;

import com.ouyan.o2o.entity.ProductCategory;

public interface ProductCategoryService {
    /**
     * 查询指定某个店铺下的所有商品类别信息
     * 
     * @param long
     *            shopId
     * @return List<ProductCategory>
     */
    List<ProductCategory> getProductCategoryList(long shopId);

    
}

package com.ouyan.o2o.service.impl;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.ouyan.o2o.dao.ProductCategoryDao;
import com.ouyan.o2o.entity.ProductCategory;
import com.ouyan.o2o.service.ProductCategoryService;

@Service
public class ProductCategoryServiceImpl implements ProductCategoryService {
    @Autowired ProductCategoryDao productCategoryDao;
    @Override
    public List<ProductCategory> getProductCategoryList(long shopId) {
        return productCategoryDao.queryProductCategoryList(shopId);
    }
    
}

package com.ouyan.o2o.web.shopadmin;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.ouyan.o2o.dto.Result;
import com.ouyan.o2o.entity.ProductCategory;
import com.ouyan.o2o.entity.Shop;
import com.ouyan.o2o.enums.ProductCategoryStateEnum;
import com.ouyan.o2o.service.ProductCategoryService;

@Controller
@RequestMapping("/shopadmin")
public class ProductCategoryManagementController {
    @Autowired
    private ProductCategoryService productCategoryService;

    @RequestMapping(value = "/getproductcategorylist", method = RequestMethod.GET)
    @ResponseBody
    private Result<List<ProductCategory>> getProductCategoryList(HttpServletRequest request) {
        Shop currentShop = (Shop) request.getSession().getAttribute("currentShop");
        List<ProductCategory> list = null;
        if (currentShop != null && currentShop.getShopId() > 0) {
            list = productCategoryService.getProductCategoryList(currentShop.getShopId());
            return new Result<List<ProductCategory>>(true, list);
        } else {
            ProductCategoryStateEnum ps = ProductCategoryStateEnum.INNER_ERROR;
            return new Result<List<ProductCategory>>(false, ps.getState(), ps.getStateInfo());
        }
    }
}

package com.ouyan.o2o.dto;

/**
 * 封装json对象,所有返回结果都使用它
 */
public class Result<T> {

    private boolean success;// 是否成功标志

    private T data;// 成功时返回的数据

    private String errorMsg;// 错误信息

    private int errorCode;

    public Result() {
    }

    // 成功时的构造器
    public Result(boolean success, T data) {
        this.success = success;
        this.data = data;
    }

    // 错误时的构造器
    public Result(boolean success, int errorCode, String errorMsg) {
        this.success = success;
        this.errorMsg = errorMsg;
        this.errorCode = errorCode;
    }

    public boolean isSuccess() {
        return success;
    }

    public void setSuccess(boolean success) {
        this.success = success;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    public String getErrorMsg() {
        return errorMsg;
    }

    public void setErrorMsg(String errorMsg) {
        this.errorMsg = errorMsg;
    }

    public int getErrorCode() {
        return errorCode;
    }

    public void setErrorCode(int errorCode) {
        this.errorCode = errorCode;
    }

}

package com.ouyan.o2o.enums;

/**
 * 使用枚举表述常量数据字典
 */
public enum ShopStateEnum {

    CHECK(0, "审核中"), OFFLINE(-1, "非法商铺"), SUCCESS(1, "操作成功"), PASS(2, "通过认证"), INNER_ERROR(
            -1001, "操作失败"), NULL_SHOPID(-1002, "ShopId为空"), NULL_SHOP_INFO(
            -1003, "传入了空的信息");

    private int state;

    private String stateInfo;

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

    public int getState() {
        return state;
    }

    public String getStateInfo() {
        return stateInfo;
    }

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

}

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>商品分类管理</title>
<meta name="viewport" content="initial-scale=1, maximum-scale=1">
<link rel="shortcut icon" href="/favicon.ico">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<link rel="stylesheet"
    href="//g.alicdn.com/msui/sm/0.6.2/css/sm.min.css">
<link rel="stylesheet"
    href="//g.alicdn.com/msui/sm/0.6.2/css/sm-extend.min.css">
<link rel="stylesheet"
    href="../resources/css/shop/productcategorymanagement.css">
</head>
<body>
    <header class="bar bar-nav">
        <a class="button button-link button-nav pull-left back"
            href="javascript:history.back(-1)"> <span class="icon icon-left"></span> 返回
        </a>
        <h1 class="title">商品分类管理</h1>
    </header>
    <div class="content">
        <div class="content-block">
            <div class="row row-product-category">
                <div class="col-33">类别</div>
                <div class="col-33">优先级</div>
                <div class="col-33">操作</div>
            </div>
            <div class="category-wrap"></div>
        </div>
        <div class="content-block">
            <div class="row">
                <div class="col-50">
                    <a href="#" class="button button-big button-fill button-success"
                        id="new">新增</a>
                </div>
                <div class="col-50">
                    <a href="#" class="button button-big button-fill" id="submit">提交</a>
                </div>
            </div>
        </div>
    </div>



    <script type='text/javascript'
        src='//g.alicdn.com/sj/lib/zepto/zepto.min.js' charset='utf-8'></script>
    <script type='text/javascript'
        src='//g.alicdn.com/msui/sm/0.6.2/js/sm.min.js' charset='utf-8'></script>
    <script type='text/javascript'
        src='//g.alicdn.com/msui/sm/0.6.2/js/sm-extend.min.js' charset='utf-8'></script>
    <script type='text/javascript'
        src='../resources/js/shop/productcategorymanagement.js'
        charset='utf-8'></script>
</body>
</html>

$(function() {
    var listUrl = '/o2o/shopadmin/getproductcategorylist';
    var addUrl = '/o2o/shopadmin/addproductcategorys';
    var deleteUrl = '/o2o/shopadmin/removeproductcategory';
    getList();
    function getList() {
        $
                .getJSON(
                        listUrl,
                        function(data) {
                            if (data.success) {
                                var dataList = data.data;
                                $('.category-wrap').html('');
                                var tempHtml = '';
                                dataList
                                        .map(function(item, index) {
                                            tempHtml += ''
                                                    + '<div class="row row-product-category now">'
                                                    + '<div class="col-33 product-category-name">'
                                                    + item.productCategoryName
                                                    + '</div>'
                                                    + '<div class="col-33">'
                                                    + item.priority
                                                    + '</div>'
                                                    + '<div class="col-33"><a href="#" class="button delete" data-id="'
                                                    + item.productCategoryId
                                                    + '">删除</a></div>'
                                                    + '</div>';
                                        });
                                $('.category-wrap').append(tempHtml);
                            }
                        });
    }
    $('#new')
            .click(
                    function() {
                        var tempHtml = '<div class="row row-product-category temp">'
                                + '<div class="col-33"><input class="category-input category" type="text" placeholder="分类名"></div>'
                                + '<div class="col-33"><input class="category-input priority" type="number" placeholder="优先级"></div>'
                                + '<div class="col-33"><a href="#" class="button delete">删除</a></div>'
                                + '</div>';
                        $('.category-wrap').append(tempHtml);
                    });
    $('#submit').click(function() {
        var tempArr = $('.temp');
        var productCategoryList = [];
        tempArr.map(function(index, item) {
            var tempObj = {};
            tempObj.productCategoryName = $(item).find('.category').val();
            tempObj.priority = $(item).find('.priority').val();
            if (tempObj.productCategoryName && tempObj.priority) {
                productCategoryList.push(tempObj);
            }
        });
        $.ajax({
            url : addUrl,
            type : 'POST',
            data : JSON.stringify(productCategoryList),
            contentType : 'application/json',
            success : function(data) {
                if (data.success) {
                    $.toast('提交成功!');
                    getList();
                } else {
                    $.toast('提交失败!');
                }
            }
        });
    });

    $('.category-wrap').on('click', '.row-product-category.temp .delete',
            function(e) {
                console.log($(this).parent().parent());
                $(this).parent().parent().remove();

            });
    $('.category-wrap').on('click', '.row-product-category.now .delete',
            function(e) {
                var target = e.currentTarget;
                $.confirm('确定么?', function() {
                    $.ajax({
                        url : deleteUrl,
                        type : 'POST',
                        data : {
                            productCategoryId : target.dataset.id
                        },
                        dataType : 'json',
                        success : function(data) {
                            if (data.success) {
                                $.toast('删除成功!');
                                getList();
                            } else {
                                $.toast('删除失败!');
                            }
                        }
                    });
                });
            });
});

 访问:http://localhost:8080/o2o/shopadmin/shoplist,点击进入,然后点击类别管理。

接下来做商品类别批量添加后端开发:

 

package com.ouyan.o2o.exceptions;

public class ProductCategoryOperationException extends RuntimeException {

    /**
     * 
     */
    private static final long serialVersionUID = 1182563719599527969L;

    public ProductCategoryOperationException(String msg) {
        super(msg);
    }
}

package com.ouyan.o2o.service;

import java.util.List;

import com.ouyan.o2o.dto.ProductCategoryExecution;
import com.ouyan.o2o.entity.ProductCategory;
import com.ouyan.o2o.exceptions.ProductCategoryOperationException;

public interface ProductCategoryService {
    /**
     * 查询指定某个店铺下的所有商品类别信息
     * 
     * @param long
     *            shopId
     * @return List<ProductCategory>
     */
    List<ProductCategory> getProductCategoryList(long shopId);

    /**
     * 
     * @param productCategory
     * @return
     * @throws ProductCategoryOperationException
     */
    ProductCategoryExecution batchAddProductCategory(List<ProductCategory> productCategoryList)
            throws ProductCategoryOperationException;
}

package com.ouyan.o2o.dto;

import java.util.List;

import com.ouyan.o2o.entity.ProductCategory;
import com.ouyan.o2o.enums.ProductCategoryStateEnum;

public class ProductCategoryExecution {
    // 结果状态
    private int state;
    // 状态标识
    private String stateInfo;

    private List<ProductCategory> productCategoryList;

    public ProductCategoryExecution() {

    }

    // 操作失败的时候使用的构造器
    public ProductCategoryExecution(ProductCategoryStateEnum stateEnum) {
        this.state = stateEnum.getState();
        this.stateInfo = stateEnum.getStateInfo();
    }

    // 操作成功的时候使用的构造器
    public ProductCategoryExecution(ProductCategoryStateEnum stateEnum, List<ProductCategory> productCategoryList) {
        this.state = stateEnum.getState();
        this.stateInfo = stateEnum.getStateInfo();
        this.productCategoryList = productCategoryList;
    }

    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 List<ProductCategory> getProductCategoryList() {
        return productCategoryList;
    }

    public void setProductCategoryList(List<ProductCategory> productCategoryList) {
        this.productCategoryList = productCategoryList;
    }

}

package com.ouyan.o2o.service.impl;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.ouyan.o2o.dao.ProductDao;
import com.ouyan.o2o.dao.ProductCategoryDao;
import com.ouyan.o2o.dto.ProductCategoryExecution;
import com.ouyan.o2o.entity.ProductCategory;
import com.ouyan.o2o.enums.ProductCategoryStateEnum;
import com.ouyan.o2o.exceptions.ProductCategoryOperationException;
import com.ouyan.o2o.service.ProductCategoryService;

@Service
public class ProductCategoryServiceImpl implements ProductCategoryService {
    @Autowired
    ProductCategoryDao productCategoryDao;
    @Autowired
    private ProductDao productDao;
    @Override
    public List<ProductCategory> getProductCategoryList(long shopId) {
        return productCategoryDao.queryProductCategoryList(shopId);
    }

    @Override
    @Transactional
    public ProductCategoryExecution batchAddProductCategory(List<ProductCategory> productCategoryList)
            throws ProductCategoryOperationException {
        if (productCategoryList != null && productCategoryList.size() > 0) {
            try {
                int effectedNum = productCategoryDao.batchInsertProductCategory(productCategoryList);
                if (effectedNum <= 0) {
                    throw new ProductCategoryOperationException("店铺类别创建失败");
                } else {
                    return new ProductCategoryExecution(ProductCategoryStateEnum.SUCCESS);
                }

            } catch (Exception e) {
                throw new ProductCategoryOperationException("batchAddProductCategory error: " + e.getMessage());
            }
        } else {
            return new ProductCategoryExecution(ProductCategoryStateEnum.EMPTY_LIST);
        }
    }
    
    @Override
    @Transactional
    public ProductCategoryExecution deleteProductCategory(long productCategoryId, long shopId)
            throws ProductCategoryOperationException {
        // 删除该productCategory
        try {
            int effectedNum = productCategoryDao.deleteProductCategory(productCategoryId, shopId);
            if (effectedNum <= 0) {
                throw new ProductCategoryOperationException("商品类别删除失败");
            } else {
                return new ProductCategoryExecution(ProductCategoryStateEnum.SUCCESS);
            }
        } catch (Exception e) {
            throw new ProductCategoryOperationException("deleteProductCategory error:" + e.getMessage());
        }
    }
    
    

}

 

package com.ouyan.o2o.web.shopadmin;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.ouyan.o2o.dto.ProductCategoryExecution;
import com.ouyan.o2o.dto.Result;
import com.ouyan.o2o.entity.ProductCategory;
import com.ouyan.o2o.entity.Shop;
import com.ouyan.o2o.enums.ProductCategoryStateEnum;
import com.ouyan.o2o.exceptions.ProductCategoryOperationException;
import com.ouyan.o2o.service.ProductCategoryService;

@Controller
@RequestMapping("/shopadmin")
public class ProductCategoryManagementController {
    @Autowired
    private ProductCategoryService productCategoryService;

    @RequestMapping(value = "/getproductcategorylist", method = RequestMethod.GET)
    @ResponseBody
    private Result<List<ProductCategory>> getProductCategoryList(HttpServletRequest request) {
        Shop currentShop = (Shop) request.getSession().getAttribute("currentShop");
        List<ProductCategory> list = null;
        if (currentShop != null && currentShop.getShopId() > 0) {
            list = productCategoryService.getProductCategoryList(currentShop.getShopId());
            return new Result<List<ProductCategory>>(true, list);
        } else {
            ProductCategoryStateEnum ps = ProductCategoryStateEnum.INNER_ERROR;
            return new Result<List<ProductCategory>>(false, ps.getState(), ps.getStateInfo());
        }
    }
    
    @RequestMapping(value = "/addproductcategorys", method = RequestMethod.POST)
    @ResponseBody
    private Map<String, Object> addProductCategorys(@RequestBody List<ProductCategory> productCategoryList,
            HttpServletRequest request) {
        Map<String, Object> modelMap = new HashMap<String, Object>();
        Shop currentShop = (Shop) request.getSession().getAttribute("currentShop");
        for (ProductCategory pc : productCategoryList) {
            pc.setShopId(currentShop.getShopId());
        }
        if (productCategoryList != null && productCategoryList.size() > 0) {
            try {
                ProductCategoryExecution pe = productCategoryService.batchAddProductCategory(productCategoryList);
                if (pe.getState() == ProductCategoryStateEnum.SUCCESS.getState()) {
                    modelMap.put("success", true);
                } else {
                    modelMap.put("success", false);
                    modelMap.put("errMsg", pe.getStateInfo());
                }
            } catch (ProductCategoryOperationException e) {
                modelMap.put("success", false);
                modelMap.put("errMsg", e.toString());
                return modelMap;
            }

        } else {
            modelMap.put("success", false);
            modelMap.put("errMsg", "请至少输入一个商品类别");
        }
        return modelMap;
    }
}

商品类别删除后台开发:

<?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.ouyan.o2o.dao.ProductCategoryDao">
    <!-- 目的:为dao接口方法提供sql语句配置 -->
    <select id="queryProductCategoryList" resultType="com.ouyan.o2o.entity.ProductCategory"
        parameterType="Long">
        <!-- 具体的sql -->
        SELECT
        product_category_id,
        product_category_name,
        priority,
        create_time,
        shop_id
        FROM
        tb_product_category
        WHERE
        shop_id = #{shopId}
        ORDER BY
        priority DESC
    </select>
    <insert id="batchInsertProductCategory" parameterType="java.util.List">
        INSERT INTO
        tb_product_category(product_category_name, priority,
        create_time, shop_id)
        VALUES
        <foreach collection="list" item="productCategory" index="index"
            separator=",">
            (
            #{productCategory.productCategoryName},
            #{productCategory.priority},
            #{productCategory.createTime},
            #{productCategory.shopId}
            )
        </foreach>
    </insert>
    <delete id="deleteProductCategory">
        DELETE FROM
        tb_product_category
        WHERE
        product_category_id = #{productCategoryId}
        AND shop_id = #{shopId}
    </delete>
</mapper>    

package com.ouyan.o2o.dao;

import static org.junit.Assert.assertEquals;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runners.MethodSorters;
import org.springframework.beans.factory.annotation.Autowired;

import com.ouyan.o2o.BaseTest;
import com.ouyan.o2o.entity.ProductCategory;
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class ProductCategoryDaoTest extends BaseTest {
    @Autowired
    private ProductCategoryDao productCategoryDao;

    @Test
    public void testBQueryByShopId() throws Exception {
        long shopId = 62;
        List<ProductCategory> productCategoryList = productCategoryDao.queryProductCategoryList(shopId);
        System.out.println("该店铺自定义类别数为:" + productCategoryList.size());
    }
    
    @Test
    public void testABatchInsertProductCategory(){
        ProductCategory productCategory = new ProductCategory();
        productCategory.setProductCategoryName("商品类别1");
        productCategory.setPriority(1);
        productCategory.setCreateTime(new Date());
        productCategory.setShopId(62L);
        ProductCategory productCategory2 = new ProductCategory();
        productCategory2.setProductCategoryName("商品类别2");
        productCategory2.setPriority(2);
        productCategory2.setCreateTime(new Date());
        productCategory2.setShopId(62L);
        List<ProductCategory> productCategoryList = new ArrayList<ProductCategory>();
        productCategoryList.add(productCategory);
        productCategoryList.add(productCategory2);
        int effectedNum = productCategoryDao.batchInsertProductCategory(productCategoryList);
        assertEquals(2, effectedNum);
    }
    
    @Test
    public void testCDeleteProductCategory() throws Exception {
        long shopId = 1;
        List<ProductCategory> productCategoryList = productCategoryDao.queryProductCategoryList(shopId);
        for (ProductCategory pc : productCategoryList) {
            if ("商品类别1".equals(pc.getProductCategoryName()) || "商品类别2".equals(pc.getProductCategoryName())) {
                int effectedNum = productCategoryDao.deleteProductCategory(pc.getProductCategoryId(),
                        shopId);
                assertEquals(1, effectedNum);
            }
        }
    }
    
}

package com.ouyan.o2o.dao;

import java.util.List;

import org.apache.ibatis.annotations.Param;

import com.ouyan.o2o.entity.ProductCategory;

public interface ProductCategoryDao {
    /**
     * 通过shop id 查询店铺商品类别
     * 
     * @param long
     *            shopId
     * @return List<ProductCategory>
     */
    List<ProductCategory> queryProductCategoryList(long shopId);

    /**
     * 批量新增商品类别
     * 
     * @param productCategoryList
     * @return
     */
    int batchInsertProductCategory(List<ProductCategory> productCategoryList);
    
    /**
     * 删除指定商品类别
     * 
     * @param productCategoryId
     * @param shopId
     * @return effectedNum
     */
    int deleteProductCategory(@Param("productCategoryId") long productCategoryId, @Param("shopId") long shopId);
}

测试一下。

下面来做商品添加模块:

商品添加之Service层的实现:

<?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.ouyan.o2o.dao.ProductDao">
    <resultMap id="productMap" type="com.ouyan.o2o.entity.Product">
        <id column="product_id" property="productId" />
        <result column="product_name" property="productName" />
        <result column="product_desc" property="productDesc" />
        <result column="img_addr" property="imgAddr" />
        <result column="normal_price" property="normalPrice" />
        <result column="promotion_price" property="promotionPrice" />
        <result column="priority" property="priority" />
        <result column="create_time" property="createTime" />
        <result column="last_edit_time" property="lastEditTime" />
        <result column="enable_status" property="enableStatus" />
        <association property="productCategory" column="product_category_id"
            javaType="com.ouyan.o2o.entity.ProductCategory">
            <id column="product_category_id" property="productCategoryId" />
            <result column="product_category_name" property="productCategoryName" />
        </association>
        <association property="shop" column="shop_id"
            javaType="com.ouyan.o2o.entity.Shop">
            <id column="shop_id" property="shopId" />
            <result column="owner_id" property="ownerId" />
            <result column="shop_name" property="shopName" />
        </association>
        <collection property="productImgList" column="product_id"
            ofType="com.ouyan.o2o.entity.ProductImg">
            <id column="product_img_id" property="productImgId" />
            <result column="detail_img" property="imgAddr" />
            <result column="img_desc" property="imgDesc" />
            <result column="priority" property="priority" />
            <result column="create_time" property="createTime" />
            <result column="product_id" property="productId" />
        </collection>
    </resultMap>
    <select id="queryProductList" resultType="com.ouyan.o2o.entity.Product">
        SELECT
        product_id,
        product_name,
        product_desc,
        img_addr,
        normal_price,
        promotion_price,
        priority,
        create_time,
        last_edit_time,
        enable_status,
        product_category_id,
        shop_id
        FROM
        tb_product
        <where>
            <if
                test="productCondition.shop!=null
                 and productCondition.shop.shopId!=null">
                and shop_id = #{productCondition.shop.shopId}
            </if>
            <if
                test="productCondition.productCategory!=null
                 and productCondition.productCategory.productCategoryId!=null">
                and product_category_id =
                #{productCondition.productCategory.productCategoryId}
            </if>
            <!-- 写like语句的时候 一般都会写成 like '% %' 在mybatis里面写就是应该是 like '%${name} %' 而不是 
                '%#{name} %' ${name} 是不带单引号的,而#{name} 是带单引号的 -->
            <if test="productCondition.productName!=null">
                and product_name like '%${productCondition.productName}%'
            </if>
            <if test="productCondition.enableStatus!=null">
                and enable_status = #{productCondition.enableStatus}
            </if>
        </where>
        ORDER BY
        priority DESC
        LIMIT #{rowIndex},#{pageSize};
    </select>

    <select id="queryProductCount" resultType="int">
        SELECT count(1) FROM tb_product
        <where>
            <if
                test="productCondition.shop!=null
                 and productCondition.shop.shopId!=null">
                and shop_id = #{productCondition.shop.shopId}
            </if>
            <if
                test="productCondition.productCategory!=null
                 and productCondition.productCategory.productCategoryId!=null">
                and product_category_id =
                #{productCondition.productCategory.productCategoryId}
            </if>
            <if test="productCondition.productName!=null">
                and product_name like '%${productCondition.productName}%'
            </if>
            <if test="productCondition.enableStatus!=null">
                and enable_status = #{productCondition.enableStatus}
            </if>
        </where>
    </select>
    <select id="queryProductById" resultMap="productMap"
        parameterType="Long">
        <!-- 具体的sql -->
        SELECT
        p.product_id,
        p.product_name,
        p.product_desc,
        p.img_addr,
        p.normal_price,
        p.promotion_price,
        p.priority,
        p.create_time,
        p.last_edit_time,
        p.enable_status,
        p.product_category_id,
        p.shop_id,
        pm.product_img_id,
        pm.img_addr AS detail_img,
        pm.img_desc,
        pm.priority,
        pm.create_time
        FROM
        tb_product p
        LEFT JOIN
        tb_product_img pm
        ON
        p.product_id =
        pm.product_id
        WHERE
        p.product_id =
        #{productId}
        ORDER BY
        pm.priority DESC
    </select>
    <insert id="insertProduct" parameterType="com.ouyan.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>
    <update id="updateProduct" parameterType="com.ouyan.o2o.entity.Product"
        keyProperty="product_id" useGeneratedKeys="true">
        UPDATE tb_product
        <set>
            <if test="productName != null">product_name=#{productName},</if>
            <if test="productDesc != null">product_desc=#{productDesc},</if>
            <if test="imgAddr != null">img_addr=#{imgAddr},</if>
            <if test="normalPrice != null">normal_price=#{normalPrice},</if>
            <if test="promotionPrice != null">promotion_price=#{promotionPrice},</if>
            <if test="priority != null">priority=#{priority},</if>
            <if test="lastEditTime != null">last_edit_time=#{lastEditTime},</if>
            <if test="enableStatus != null">enable_status=#{enableStatus},</if>
            <if
                test="productCategory != null
                 and productCategory.productCategoryId != null">
                product_category_id=#{productCategory.productCategoryId}
            </if>
        </set>
        WHERE product_id = #{productId}
        AND shop_id=#{shop.shopId}
    </update>
    <update id="updateProductCategoryToNull" parameterType="Long">
        UPDATE
        tb_product
        SET
        product_category_id = null
        WHERE product_category_id =
        #{productCategoryId}
    </update>
    <delete id="deleteProduct">
        DELETE FROM
        tb_product
        WHERE
        product_id = #{productId}
        AND shop_id=#{shopId}
    </delete>
</mapper>

package com.ouyan.o2o.dao;

import java.util.List;

import org.apache.ibatis.annotations.Param;

import com.ouyan.o2o.entity.Product;

public interface ProductDao {
    /**
     * 查询商品列表并分页,可输入的条件有: 商品名(模糊),商品状态,店铺Id,商品类别
     * 
     * @param productCondition
     * @param beginIndex
     * @param pageSize
     * @return
     */
    List<Product> queryProductList(@Param("productCondition") Product productCondition, @Param("rowIndex") int rowIndex,
            @Param("pageSize") int pageSize);

    /**
     * 查询对应的商品总数
     * 
     * @param productCondition
     * @return
     */
    int queryProductCount(@Param("productCondition") Product productCondition);

    /**
     * 通过productId查询唯一的商品信息
     * 
     * @param productId
     * @return
     */
    Product queryProductById(long productId);

    /**
     * 插入商品
     * 
     * @param product
     * @return
     */
    int insertProduct(Product product);

    /**
     * 更新商品信息
     * 
     * @param product
     * @return
     */
    int updateProduct(Product product);

    /**
     * 删除商品类别之前,将商品类别ID置为空
     * 
     * @param productCategoryId
     * @return
     */
    int updateProductCategoryToNull(long productCategoryId);

    /**
     * 删除商品
     * 
     * @param productId
     * @return
     */
    int deleteProduct(@Param("productId") long productId, @Param("shopId") long shopId);
}

package com.ouyan.o2o.dao;

import java.util.List;

import com.ouyan.o2o.entity.ProductImg;

public interface ProductImgDao {

    /**
     * 列出某个商品的详情图列表
     * 
     * @param productId
     * @return
     */
    List<ProductImg> queryProductImgList(long productId);

    /**
     * 批量添加商品详情图片
     * 
     * @param productImgList
     * @return
     */
    int batchInsertProductImg(List<ProductImg> productImgList);

    /**
     * 删除指定商品下的所有详情图
     * 
     * @param productId
     * @return
     */
    int deleteProductImgByProductId(long productId);
}

<?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.ouyan.o2o.dao.ProductImgDao">
    <select id="queryProductImgList" resultType="com.ouyan.o2o.entity.ProductImg">
        SELECT
        product_img_id,
        img_addr,
        img_desc,
        priority,
        create_time,
        product_id
        FROM tb_product_img
        WHERE product_id=#{productId}
        ORDER BY
        product_img_id ASC
    </select>
    <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>

    <delete id="deleteProductImgByProductId">
        <!-- 具体的sql -->
        DELETE FROM
        tb_product_img
        WHERE
        product_id =
        #{productId}
    </delete>

</mapper>

package com.ouyan.o2o.dao;

import static org.junit.Assert.assertEquals;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runners.MethodSorters;
import org.springframework.beans.factory.annotation.Autowired;

import com.ouyan.o2o.BaseTest;
import com.ouyan.o2o.entity.ProductImg;

@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class ProductImgDaoTest extends BaseTest {
    @Autowired
    private ProductImgDao productImgDao;

    @Test
    public void testABatchInsertProductImg() throws Exception {
        // productId为1的商品里添加两个详情图片记录
        ProductImg productImg1 = new ProductImg();
        productImg1.setImgAddr("图片1");
        productImg1.setImgDesc("测试图片1");
        productImg1.setPriority(1);
        productImg1.setCreateTime(new Date());
        productImg1.setProductId(16L);
        ProductImg productImg2 = new ProductImg();
        productImg2.setImgAddr("图片2");
        productImg2.setPriority(1);
        productImg2.setCreateTime(new Date());
        productImg2.setProductId(16L);
        List<ProductImg> productImgList = new ArrayList<ProductImg>();
        productImgList.add(productImg1);
        productImgList.add(productImg2);
        int effectedNum = productImgDao.batchInsertProductImg(productImgList);
        assertEquals(2, effectedNum);
    }

    @Test
    public void testBQueryProductImgList() {
        // 检查productId为1的商品是否有且仅有两张商品详情图片
        List<ProductImg> productImgList = productImgDao.queryProductImgList(1L);
        assertEquals(2, productImgList.size());
    }

    @Test
    public void testCDeleteProductImgByProductId() throws Exception {
        // 删除新增的两条商品详情图片记录
        long productId = 1;
        int effectedNum = productImgDao.deleteProductImgByProductId(productId);
        assertEquals(2, effectedNum);
    }
}
package com.ouyan.o2o.service;

import java.util.List;

import com.ouyan.o2o.dto.ImageHolder;
import com.ouyan.o2o.dto.ProductExecution;
import com.ouyan.o2o.entity.Product;
import com.ouyan.o2o.exceptions.ProductOperationException;

public interface ProductService {


    /**
     * 添加商品信息以及图片处理
     * 
     * @param product
     * @param thumbnail
     * @param productImgs
     * @return
     * @throws ProductOperationException
     */
    ProductExecution addProduct(Product product, ImageHolder thumbnail, List<ImageHolder> productImgList)
            throws ProductOperationException;

    
}
package com.ouyan.o2o.exceptions;

public class ProductOperationException extends RuntimeException {

    /**
     * 
     */
    private static final long serialVersionUID = 5076172298827469013L;

    public ProductOperationException(String msg) {
        super(msg);
    }
}
package com.ouyan.o2o.dto;

import java.util.List;

import com.ouyan.o2o.entity.Product;
import com.ouyan.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;
    }

}
package com.ouyan.o2o.enums;

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 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;
    }

}
package com.ouyan.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;
    }

}
package com.ouyan.o2o.service;

import com.ouyan.o2o.dto.ImageHolder;
import com.ouyan.o2o.dto.ShopExecution;
import com.ouyan.o2o.entity.Shop;
import com.ouyan.o2o.exceptions.ShopOperationException;

public interface ShopService {
    /**
     * 根据shopCondition分页返回相应店铺列表
     * 
     * @param shopCondition
     * @param pageIndex
     * @param pageSize
     * @return
     */
    public ShopExecution getShopList(Shop shopCondition, int pageIndex, int pageSize);

    /**
     * 通过店铺Id获取店铺信息
     * 
     * @param shopId
     * @return
     */
    Shop getByShopId(long shopId);

    /**
     * 更新店铺信息,包括对图片的处理
     * 
     * @param shop
     * @param shopImg
     * @return
     * @throws ShopOperationException
     */
    ShopExecution modifyShop(Shop shop, ImageHolder thumbnail) throws ShopOperationException;

    /**
     * 注册店铺信息,包括图片处理
     * 
     * @param shop
     * @param shopImgInputStream
     * @param fileName
     * @return
     * @throws ShopOperationException
     */
    ShopExecution addShop(Shop shop, ImageHolder thumbnail) throws ShopOperationException;
}
package com.ouyan.o2o.service.impl;

import java.io.IOException;
import java.io.InputStream;
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.ouyan.o2o.dao.ShopDao;
import com.ouyan.o2o.dto.ImageHolder;
import com.ouyan.o2o.dto.ShopExecution;
import com.ouyan.o2o.entity.Shop;
import com.ouyan.o2o.enums.ShopStateEnum;
import com.ouyan.o2o.exceptions.ShopOperationException;
import com.ouyan.o2o.service.ShopService;
import com.ouyan.o2o.util.PageCalculator;
import com.ouyan.o2o.util.PathUtil;
import com.ouyan.o2o.util.imageUtil;
@Service
public class ShopServiceImpl implements ShopService{
    @Autowired
    private ShopDao shopDao;
    
    @Override
    @Transactional
    public ShopExecution addShop(Shop shop, ImageHolder thumbnail) {
        //空值判断
        if(shop==null){
            return new ShopExecution(ShopStateEnum.NULL_SHOP_INFO);
        }
        try {
            //给店铺信息赋值初始值
            shop.setEnableStatus(0);
            shop.setCreateTime(new Date());
            shop.setLastEditTime(new Date());
            //添加店铺信息
            int effectedNum = shopDao.insertShop(shop);
            if(effectedNum<=0){
                throw new ShopOperationException("店铺创建失败");
            }else{
                if(thumbnail.getImage()!=null){
                    //存储图片
                    try {
                        addShopImg(shop,thumbnail);
                    } catch (Exception e) {
                        throw new ShopOperationException("addShopImg error:"+e.getMessage());
                    }
                    effectedNum = shopDao.updateShop(shop);
                    if(effectedNum<=0){
                        throw new ShopOperationException("更新图片地址失败");
                    }
                }
            }
        } catch (Exception e) {
            throw new ShopOperationException("addShop error: "+ e.getMessage());
        }
        return new ShopExecution(ShopStateEnum.CHECK,shop);
    }

    private void addShopImg(Shop shop, ImageHolder thumnail) throws ShopOperationException, IOException {
        //获取shop图片的相对路径
        String dest = PathUtil.getShopImagePath(shop.getShopId());
        String shopImgAddr = imageUtil.generateThumbnail(thumnail,dest);
        shop.setShopImg(shopImgAddr);
    }

    @Override
    public Shop getByShopId(long shopId) {
        return shopDao.queryByShopId(shopId);
    }

    @Override
    public ShopExecution modifyShop(Shop shop,ImageHolder thumbnail)
            throws ShopOperationException {
        if(shop==null||shop.getShopId()==null){
            return new ShopExecution(ShopStateEnum.NULL_SHOP_INFO);
        }else{
            //判断是否需要处理图片
            try{
            if(thumbnail.getImage()!=null&&thumbnail.getImageName()!=null&&!"".equals(thumbnail.getImageName())){
                Shop tempShop = shopDao.queryByShopId(shop.getShopId());
                if(tempShop.getShopImg()!=null){
                    imageUtil.deleteFileOrPath(tempShop.getShopImg());
                }
                try {
                    addShopImg(shop,thumbnail);
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            //更新店铺信息
            shop.setLastEditTime(new Date());
            int effectedNum = shopDao.updateShop(shop);
            if(effectedNum<=0){
                return new ShopExecution(ShopStateEnum.INNER_ERROR);
            }else{
                shop=shopDao.queryByShopId(shop.getShopId());
                return new ShopExecution(ShopStateEnum.SUCCESS,shop);
            }}catch(Exception e){
                throw new ShopOperationException("modifyShop error: "+e.getMessage());
            }
        }
    }

    @Override
    public ShopExecution getShopList(Shop shopCondition, int pageIndex, int pageSize) {
        int rowIndex = PageCalculator.calculateRowIndex(pageIndex,pageSize);
        List<Shop> shopList = shopDao.queryShopList(shopCondition, rowIndex, pageSize);
        int count = shopDao.queryShopCount(shopCondition);
        ShopExecution se = new ShopExecution();
        if(shopList!=null){
            se.setShopList(shopList);
            se.setCount(count);
        }else{
            se.setState(ShopStateEnum.INNER_ERROR.getState());
        }
        return se;
    }
}
package com.ouyan.o2o.util;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
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.ouyan.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 thumbnail
     * @param targetAddr
     * @return
     * @throws IOException
     */
    public static String generateThumbnail(ImageHolder thumnail , String targetAddr) throws IOException
             {
        String realFileName = getRandomFileName();
        String extension = getFileExtesion(thumnail.getImageName());
        makeDirPath(targetAddr);
        String relativeAddr = targetAddr + realFileName + extension;
        logger.error("current relativeAddr is:" + relativeAddr);
        File dest = new File(PathUtil.getImgBasePath() + relativeAddr);
        logger.debug("current complete addr is :" + PathUtil.getImgBasePath() + relativeAddr);
        Thumbnails.of(thumnail.getImage()).size(200, 200)
                .watermark(Positions.BOTTOM_RIGHT, ImageIO.read(new File(basePath + "/watermark.jpg")), 0.25f)
                .outputQuality(0.8).toFile(dest);
        return relativeAddr;
    }

    /**
     * 创建目标路径涉及的目录
     * 
     * @param targetAddr
     */
    private static void makeDirPath(String targetAddr) {
        String realFileParentPath = PathUtil.getImgBasePath() + targetAddr;
        File dirPath = new File(realFileParentPath);
        if (!dirPath.exists()) {
            dirPath.mkdirs();
        }
    }

    /**
     * 获取输入文件的扩展名
     * 
     * @param thumbnail
     * @return
     */
    private static String getFileExtesion(String fileName) {
        return fileName.substring(fileName.lastIndexOf("."));
    }

    /**
     * 生成随机文件名,当前年月是小时分钟秒钟+五位随机数
     * 
     * @return
     */
    public static String getRandomFileName() {
        // 获取随机的五位数
        int rannum = r.nextInt(89999) + 10000;
        String nowTimeStr = sDateFormat.format(new Date());
        return nowTimeStr + rannum;
    }

    public static void main(String[] args) throws IOException {
        Thumbnails.of(new File("d:\\timg.jpg")).size(2000, 2000)
                .watermark(Positions.BOTTOM_RIGHT, ImageIO.read(new File(basePath + "/watermark.jpg")), 0.25f)
                .outputQuality(0.8f).toFile("d:\\timgnew.jpg");
    }

    /**
     * 删除图片或者目录下的所有图片
     * 
     * @param storePath
     */
    public static void deleteFileOrPath(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();
        }
    }
}
package com.ouyan.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.Date;

import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.ouyan.o2o.BaseTest;
import com.ouyan.o2o.dto.ImageHolder;
import com.ouyan.o2o.dto.ShopExecution;
import com.ouyan.o2o.entity.Area;
import com.ouyan.o2o.entity.PersonInfo;
import com.ouyan.o2o.entity.Shop;
import com.ouyan.o2o.entity.ShopCategory;
import com.ouyan.o2o.enums.ShopStateEnum;

@Service
public class ShopServiceTest extends BaseTest {
    @Autowired
    private ShopService shopService;
    
    @Test
    public void testGetShopList(){
        Shop shopCondition = new Shop();
        ShopCategory sc = new ShopCategory();
        sc.setShopCategoryId(33L);
        shopCondition.setShopCategory(sc);
        ShopExecution se=shopService.getShopList(shopCondition, 2, 5);
        System.out.println(se.getShopList().size());
        System.out.println(se.getCount());
    }
    
    @Test
    public void testModifyShop() throws FileNotFoundException {
        Shop shop = new Shop();
        shop.setShopId(62L);
        shop.setShopName("修改后的店铺名称");
        File shopImg = new File("d:/haha.jpg");
        InputStream is = new FileInputStream(shopImg);
        ImageHolder imageHolder = new ImageHolder("haha1.jpg",is);
        ShopExecution shopExecution = shopService.modifyShop(shop,imageHolder);
        System.out.println("新地址是: "+shopExecution.getShop().getShopImg());
    }

    @Test
    public void testAddShop() throws FileNotFoundException {
        Shop shop = new Shop();
        PersonInfo owner = new PersonInfo();
        Area area = new Area();
        ShopCategory shopCategory = new ShopCategory();
        owner.setUserId(1L);
        area.setAreaId(2L);
        shopCategory.setShopCategoryId(33L);
        shop.setOwner(owner);
        shop.setArea(area);
        shop.setShopCategory(shopCategory);
        shop.setShopName("测试的店铺3");
        shop.setShopDesc("test3");
        shop.setShopAddr("test3");
        shop.setPhone("test3");
        shop.setCreateTime(new Date());
        shop.setEnableStatus(ShopStateEnum.CHECK.getState());
        shop.setAdvice("审核中");
        File shopImg = new File("d:/timg.jpg");
        InputStream is = new FileInputStream(shopImg);
        ImageHolder imageHolder = new ImageHolder("haha1.jpg",is);
        ShopExecution se = shopService.addShop(shop, imageHolder);
        assertEquals(ShopStateEnum.CHECK.getState(), se.getState());
    }
}
package com.ouyan.o2o.web.shopadmin;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.ouyan.o2o.dto.ImageHolder;
import com.ouyan.o2o.dto.ShopExecution;
import com.ouyan.o2o.entity.Area;
import com.ouyan.o2o.entity.PersonInfo;
import com.ouyan.o2o.entity.Shop;
import com.ouyan.o2o.entity.ShopCategory;
import com.ouyan.o2o.enums.ShopStateEnum;
import com.ouyan.o2o.exceptions.ShopOperationException;
import com.ouyan.o2o.service.AreaService;
import com.ouyan.o2o.service.ShopCategoryService;
import com.ouyan.o2o.service.ShopService;
import com.ouyan.o2o.util.CodeUtil;
import com.ouyan.o2o.util.HttpServletRequestUtil;

@Controller
@RequestMapping("/shopadmin")
public class ShopManagementController {
    @Autowired
    private ShopService shopService;
    @Autowired
    private ShopCategoryService ShopCategoryService;
    @Autowired
    private AreaService areaService;

    @RequestMapping(value = "/getshopmanagementinfo", method = RequestMethod.GET)
    @ResponseBody
    private Map<String,Object> getShopManagementInfo(HttpServletRequest request){
        Map<String,Object> modelMap = new HashMap<String,Object>();
        long shopId=HttpServletRequestUtil.getLong(request, "shopId");
        if(shopId<=0){
            Object currentShopObj = request.getSession().getAttribute("currentShop");
            if(currentShopObj==null){
                modelMap.put("redirect", true);
                modelMap.put("url", "/o2o/shopadmin/shoplist");
            }else{
                Shop currentShop = (Shop) currentShopObj;
                modelMap.put("redirect", false);
                modelMap.put("shopId", currentShop.getShopId());
            }
        }else{
            Shop currentShop = new Shop();
            currentShop.setShopId(shopId);
            request.getSession().setAttribute("currentShop", currentShop);
            modelMap.put("redirect", false);
        }
        return modelMap;
    }
    
    
    @RequestMapping(value = "/getshoplist", method = RequestMethod.GET)
    @ResponseBody
    private Map<String,Object> getShopList(HttpServletRequest request){
        Map<String,Object> modelMap=new HashMap<String,Object>();
        PersonInfo user =new PersonInfo();
        user.setUserId(1L);
        user.setName("Poker");
        request.getSession().setAttribute("user", user);
        user = (PersonInfo)request.getSession().getAttribute("user");
        try {
            Shop shopCondition = new Shop();
            shopCondition.setOwner(user);
            ShopExecution se = shopService.getShopList(shopCondition, 0, 100);
            modelMap.put("shopList", se.getShopList());
            modelMap.put("user", user);
            modelMap.put("success", true);
        } catch (Exception e) {
            modelMap.put("success", false);
            modelMap.put("errMsg", e.getMessage());
        }
        return modelMap;
    }
    
    @RequestMapping(value = "/getshopbyid", method = RequestMethod.GET)
    @ResponseBody
    private Map<String, Object> getShopById(HttpServletRequest request) {
        Map<String, Object> modelMap = new HashMap<String, Object>();
        Long shopId = HttpServletRequestUtil.getLong(request, "shopId");
        if (shopId > -1) {
            try {
                Shop shop = shopService.getByShopId(shopId);
                List<Area> areaList = areaService.getAreaList();
                modelMap.put("shop", shop);
                modelMap.put("areaList", areaList);
                modelMap.put("success", true);
            } catch (Exception e) {
                modelMap.put("success", false);
                modelMap.put("errMsg", e.toString());
            }
        } else {
            modelMap.put("success", false);
            modelMap.put("errMsg", "empty shopId");
        }
        return modelMap;
    }

    @RequestMapping(value = "/getshopinitinfo", method = RequestMethod.GET)
    @ResponseBody
    private Map<String, Object> getShopInitInfo() {
        Map<String, Object> modelMap = new HashMap<String, Object>();
        List<ShopCategory> shopCategoryList = new ArrayList<ShopCategory>();
        List<Area> areaList = new ArrayList<Area>();
        try {
            shopCategoryList = ShopCategoryService.getShopCategoryList(new ShopCategory());
            areaList = areaService.getAreaList();
            modelMap.put("shopCategoryList", shopCategoryList);
            modelMap.put("areaList", areaList);
            modelMap.put("success", true);
        } catch (Exception e) {
            modelMap.put("success", false);
            modelMap.put("errMsg", e.getMessage());
        }
        return modelMap;

    }

    @SuppressWarnings("unchecked")
    @RequestMapping(value = "/registershop", method = RequestMethod.POST)
    @ResponseBody
    public Map<String, Object> registerShop(HttpServletRequest request) {
        Map<String, Object> modelMap = new HashMap<String, Object>();
        if (!CodeUtil.checkVerifyCode(request)) {
            modelMap.put("success", false);
            modelMap.put("errMsg", "输入了错误的验证码");
            return modelMap;
        }
        // 接受并转化相应参数
        String shopStr = HttpServletRequestUtil.getString(request, "shopStr");
        ObjectMapper mapper = new ObjectMapper();
        Shop shop = null;
        try {
            shop = mapper.readValue(shopStr, Shop.class);
        } catch (Exception e) {
            modelMap.put("success", false);
            modelMap.put("errMsg", e.getMessage());
            return modelMap;
        }
        CommonsMultipartFile shopImg = null;
        CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver(
                request.getSession().getServletContext());
        if (commonsMultipartResolver.isMultipart(request)) {
            MultipartHttpServletRequest multipartHttpServletRequest = (MultipartHttpServletRequest) request;
            shopImg = (CommonsMultipartFile) multipartHttpServletRequest.getFile("shopImg");
        } else {
            modelMap.put("success", false);
            modelMap.put("errMsg", "上传文件不能为空");
            return modelMap;
        }
        // 注册店铺
        if (shop != null && shopImg != null) {
            PersonInfo owner = (PersonInfo) request.getSession().getAttribute("user");
            shop.setOwner(owner);
            ShopExecution se;
            try {
                ImageHolder imageHolder = new ImageHolder(shopImg.getOriginalFilename(),shopImg.getInputStream());
                se = shopService.addShop(shop,imageHolder );
                if (se.getState() == ShopStateEnum.CHECK.getState()) {
                    modelMap.put("success", true);
                    // 该用户可操作的店铺列表
                    List<Shop> shopList = (List<Shop>) request.getAttribute("shopList");
                    if (shopList == null || shopList.size() == 0) {
                        shopList = new ArrayList<Shop>();
                    }
                    shopList.add(se.getShop());
                    request.getSession().setAttribute("shopList", shopList);
                } else {
                    modelMap.put("success", false);
                    modelMap.put("errMsg", se.getStateInfo());
                }
            } catch (ShopOperationException e) {
                modelMap.put("success", false);
                modelMap.put("errMsg", e.getMessage());
            } catch (IOException e) {
                modelMap.put("success", false);
                modelMap.put("errMsg", e.getMessage());
            }
            return modelMap;
        } else {
            modelMap.put("success", false);
            modelMap.put("errMsg", "请输入店铺信息");
            return modelMap;
        }
    }

    @RequestMapping(value = "/modifyshop", method = RequestMethod.POST)
    @ResponseBody
    public Map<String, Object> modifyshop(HttpServletRequest request) {
        Map<String, Object> modelMap = new HashMap<String, Object>();
        if (!CodeUtil.checkVerifyCode(request)) {
            modelMap.put("success", false);
            modelMap.put("errMsg", "输入了错误的验证码");
            return modelMap;
        }
        // 接受并转化相应参数
        String shopStr = HttpServletRequestUtil.getString(request, "shopStr");
        ObjectMapper mapper = new ObjectMapper();
        Shop shop = null;
        try {
            shop = mapper.readValue(shopStr, Shop.class);
        } catch (Exception e) {
            modelMap.put("success", false);
            modelMap.put("errMsg", e.getMessage());
            return modelMap;
        }
        CommonsMultipartFile shopImg = null;
        CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver(
                request.getSession().getServletContext());
        if (commonsMultipartResolver.isMultipart(request)) {
            MultipartHttpServletRequest multipartHttpServletRequest = (MultipartHttpServletRequest) request;
            shopImg = (CommonsMultipartFile) multipartHttpServletRequest.getFile("shopImg");
        }
        // 修改店铺
        if (shop != null && shop.getShopId() != null) {
            ShopExecution se;
            try {
                if (shopImg == null) {
                    se = shopService.modifyShop(shop, null);
                } else {
                    ImageHolder imageHolder = new ImageHolder(shopImg.getOriginalFilename(),shopImg.getInputStream());
                    se = shopService.modifyShop(shop, imageHolder);
                }
                if (se.getState() == ShopStateEnum.SUCCESS.getState()) {
                    modelMap.put("success", true);
                } else {
                    modelMap.put("success", false);
                    modelMap.put("errMsg", se.getStateInfo());
                }
            } catch (ShopOperationException e) {
                modelMap.put("success", false);
                modelMap.put("errMsg", e.getMessage());
            } catch (IOException e) {
                modelMap.put("success", false);
                modelMap.put("errMsg", e.getMessage());
            }
            return modelMap;
        } else {
            modelMap.put("success", false);
            modelMap.put("errMsg", "请输入店铺id");
            return modelMap;
        }
    }
}
package com.ouyan.o2o.service.impl;

import java.io.IOException;
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.ouyan.o2o.dao.ProductDao;
import com.ouyan.o2o.dao.ProductImgDao;
import com.ouyan.o2o.dto.ImageHolder;
import com.ouyan.o2o.dto.ProductExecution;
import com.ouyan.o2o.entity.Product;
import com.ouyan.o2o.entity.ProductImg;
import com.ouyan.o2o.enums.ProductStateEnum;
import com.ouyan.o2o.exceptions.ProductOperationException;
import com.ouyan.o2o.service.ProductService;
import com.ouyan.o2o.util.ImageUtil;
import com.ouyan.o2o.util.PathUtil;

@Service
public class ProductServiceImpl implements ProductService {
    @Autowired
    private ProductDao productDao;
    @Autowired
    private ProductImgDao productImgDao;

    

    @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) {
                try {
                    addThumbnail(product, thumbnail);
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            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);
        }
    }
    

    /**
     * 批量添加图片
     * 
     * @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());
            }
        }
    }

    /**
     * 添加缩略图
     * 
     * @param product
     * @param thumbnail
     * @throws IOException 
     */
    private void addThumbnail(Product product, ImageHolder thumbnail) throws IOException {
        String dest = PathUtil.getShopImagePath(product.getShop().getShopId());
        String thumbnailAddr = ImageUtil.generateThumbnail(thumbnail, dest);
        product.setImgAddr(thumbnailAddr);
    }



    @Override
    public Product getProductById(long productId) {
        // TODO Auto-generated method stub
        return null;
    }



    @Override
    public ProductExecution getProductList(Product productCondition, int pageIndex, int pageSize) {
        // TODO Auto-generated method stub
        return null;
    }



    @Override
    public ProductExecution modifyProduct(Product product, ImageHolder thumbnail,
            List<ImageHolder> productImgHolderList) throws ProductOperationException {
        // TODO Auto-generated method stub
        return null;
    }

}
package com.ouyan.o2o.service;

import java.util.List;

import com.ouyan.o2o.dto.ImageHolder;
import com.ouyan.o2o.dto.ProductExecution;
import com.ouyan.o2o.entity.Product;
import com.ouyan.o2o.exceptions.ProductOperationException;

public interface ProductService {


    /**
     * 添加商品信息以及图片处理
     * 
     * @param product
     * @param thumbnail
     * @param productImgs
     * @return
     * @throws ProductOperationException
     */
    ProductExecution addProduct(Product product, ImageHolder thumbnail, List<ImageHolder> productImgList)
            throws ProductOperationException;

    Product getProductById(long productId);

    ProductExecution getProductList(Product productCondition, int pageIndex, int pageSize);

    ProductExecution modifyProduct(Product product, ImageHolder thumbnail, List<ImageHolder> productImgHolderList)
            throws ProductOperationException;

    
}
package com.ouyan.o2o.util;

import java.io.File;
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.ouyan.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 thumbnail
     * @param targetAddr
     * @return
     * @throws IOException
     */
    public static String generateThumbnail(ImageHolder thumnail , String targetAddr) throws IOException
             {
        String realFileName = getRandomFileName();
        String extension = getFileExtesion(thumnail.getImageName());
        makeDirPath(targetAddr);
        String relativeAddr = targetAddr + realFileName + extension;
        logger.error("current relativeAddr is:" + relativeAddr);
        File dest = new File(PathUtil.getImgBasePath() + relativeAddr);
        logger.debug("current complete addr is :" + PathUtil.getImgBasePath() + relativeAddr);
        Thumbnails.of(thumnail.getImage()).size(200, 200)
                .watermark(Positions.BOTTOM_RIGHT, ImageIO.read(new File(basePath + "/watermark.jpg")), 0.25f)
                .outputQuality(0.8).toFile(dest);
        return relativeAddr;
    }

    /**
     * 创建目标路径涉及的目录
     * 
     * @param targetAddr
     */
    private static void makeDirPath(String targetAddr) {
        String realFileParentPath = PathUtil.getImgBasePath() + targetAddr;
        File dirPath = new File(realFileParentPath);
        if (!dirPath.exists()) {
            dirPath.mkdirs();
        }
    }

    /**
     * 获取输入文件的扩展名
     * 
     * @param thumbnail
     * @return
     */
    private static String getFileExtesion(String fileName) {
        return fileName.substring(fileName.lastIndexOf("."));
    }

    /**
     * 生成随机文件名,当前年月是小时分钟秒钟+五位随机数
     * 
     * @return
     */
    public static String getRandomFileName() {
        // 获取随机的五位数
        int rannum = r.nextInt(89999) + 10000;
        String nowTimeStr = sDateFormat.format(new Date());
        return nowTimeStr + rannum;
    }

    public static void main(String[] args) throws IOException {
        Thumbnails.of(new File("d:\\timg.jpg")).size(2000, 2000)
                .watermark(Positions.BOTTOM_RIGHT, ImageIO.read(new File(basePath + "/watermark.jpg")), 0.25f)
                .outputQuality(0.8f).toFile("d:\\timgnew.jpg");
    }

    /**
     * 删除图片或者目录下的所有图片
     * 
     * @param storePath
     */
    public static void deleteFileOrPath(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();
        }
    }

    /**
     * 处理详情图,并返回新生成图片的相对值路径
     * 
     * @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 + "/watermark.jpg")), 0.25f)
                    .outputQuality(0.9f).toFile(dest);
        } catch (IOException e) {
            logger.error(e.toString());
            throw new RuntimeException("创建缩图片失败:" + e.toString());
        }
        // 返回图片相对路径地址
        return relativeAddr;
    }
    
    /**
     * 获取输入文件流的扩展名
     * 
     * @param thumbnail
     * @return
     */
    private static String getFileExtension(String fileName) {
        return fileName.substring(fileName.lastIndexOf("."));
    }

}
package com.ouyan.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.Ignore;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;

import com.ouyan.o2o.BaseTest;
import com.ouyan.o2o.dto.ImageHolder;
import com.ouyan.o2o.dto.ProductExecution;
import com.ouyan.o2o.entity.Product;
import com.ouyan.o2o.entity.ProductCategory;
import com.ouyan.o2o.entity.Shop;
import com.ouyan.o2o.enums.ProductStateEnum;
import com.ouyan.o2o.exceptions.ShopOperationException;

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(62L);
        ProductCategory pc = new ProductCategory();
        pc.setProductCategoryId(21L);
        product.setShop(shop);
        product.setProductCategory(pc);
        product.setProductName("测试商品1");
        product.setProductDesc("测试商品1");
        product.setPriority(20);
        product.setCreateTime(new Date());
        product.setEnableStatus(ProductStateEnum.SUCCESS.getState());
        // 创建缩略图文件流
        File thumbnailFile = new File("D:/haha.jpg");
        InputStream is = new FileInputStream(thumbnailFile);
        ImageHolder thumbnail = new ImageHolder(thumbnailFile.getName(), is);
        // 创建两个商品详情图文件流并将他们添加到详情图列表中
        File productImg1 = new File("/D:/haha.jpg");
        InputStream is1 = new FileInputStream(productImg1);
        File productImg2 = new File("D:/haha.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());
    }

    @Test
    public void testModifyProduct() 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.setProductId(1L);
        product.setShop(shop);
        product.setProductCategory(pc);
        product.setProductName("正式的商品");
        product.setProductDesc("正式的商品");
        // 创建缩略图文件流
        File thumbnailFile = new File("/Users/baidu/work/image/ercode.jpg");
        InputStream is = new FileInputStream(thumbnailFile);
        ImageHolder thumbnail = new ImageHolder(thumbnailFile.getName(), is);
        // 创建两个商品详情图文件流并将他们添加到详情图列表中
        File productImg1 = new File("/Users/baidu/work/image/xiaohuangren.jpg");
        InputStream is1 = new FileInputStream(productImg1);
        File productImg2 = new File("/Users/baidu/work/image/dabai.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.modifyProduct(product, thumbnail, productImgList);
        assertEquals(ProductStateEnum.SUCCESS.getState(), pe.getState());
    }

}

接下來看Conreoller:

package com.ouyan.o2o.web.shopadmin;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.ouyan.o2o.dto.ImageHolder;
import com.ouyan.o2o.dto.ProductExecution;
import com.ouyan.o2o.entity.Product;
import com.ouyan.o2o.entity.ProductCategory;
import com.ouyan.o2o.entity.Shop;
import com.ouyan.o2o.enums.ProductStateEnum;
import com.ouyan.o2o.exceptions.ProductOperationException;
import com.ouyan.o2o.service.ProductCategoryService;
import com.ouyan.o2o.service.ProductService;
import com.ouyan.o2o.util.CodeUtil;
import com.ouyan.o2o.util.HttpServletRequestUtil;

@Controller
@RequestMapping("/shopadmin")
public class ProductManagementController {
    @Autowired
    private ProductService productService;
    @Autowired
    private ProductCategoryService productCategoryService;

    // 支持上传商品详情图的最大数量
    private static final int IMAGEMAXCOUNT = 6;

    /**
     * 通过店铺id获取该店铺下的商品列表
     * 
     * @param request
     * @return
     */
    @RequestMapping(value = "/getproductlistbyshop", method = RequestMethod.GET)
    @ResponseBody
    private Map<String, Object> getProductListByShop(HttpServletRequest request) {
        Map<String, Object> modelMap = new HashMap<String, Object>();
        // 获取前台传过来的页码
        int pageIndex = HttpServletRequestUtil.getInt(request, "pageIndex");
        // 获取前台传过来的每页要求返回的商品数上限
        int pageSize = HttpServletRequestUtil.getInt(request, "pageSize");
        // 从当前session中获取店铺信息,主要是获取shopId
        Shop currentShop = (Shop) request.getSession().getAttribute("currentShop");
        // 空值判断
        if ((pageIndex > -1) && (pageSize > -1) && (currentShop != null) && (currentShop.getShopId() != null)) {
            // 获取传入的需要检索的条件,包括是否需要从某个商品类别以及模糊查找商品名去筛选某个店铺下的商品列表
            // 筛选的条件可以进行排列组合
            long productCategoryId = HttpServletRequestUtil.getLong(request, "productCategoryId");
            String productName = HttpServletRequestUtil.getString(request, "productName");
            Product productCondition = compactProductCondition(currentShop.getShopId(), productCategoryId, productName);
            // 传入查询条件以及分页信息进行查询,返回相应商品列表以及总数
            ProductExecution pe = productService.getProductList(productCondition, pageIndex, pageSize);
            modelMap.put("productList", pe.getProductList());
            modelMap.put("count", pe.getCount());
            modelMap.put("success", true);
        } else {
            modelMap.put("success", false);
            modelMap.put("errMsg", "empty pageSize or pageIndex or shopId");
        }
        return modelMap;
    }

    /**
     * 通过商品id获取商品信息
     * 
     * @param productId
     * @return
     */
    @RequestMapping(value = "/getproductbyid", method = RequestMethod.GET)
    @ResponseBody
    private Map<String, Object> getProductById(@RequestParam Long productId) {
        Map<String, Object> modelMap = new HashMap<String, Object>();
        // 非空判断
        if (productId > -1) {
            // 获取商品信息
            Product product = productService.getProductById(productId);
            // 获取该店铺下的商品类别列表
            List<ProductCategory> productCategoryList = productCategoryService
                    .getProductCategoryList(product.getShop().getShopId());
            modelMap.put("product", product);
            modelMap.put("productCategoryList", productCategoryList);
            modelMap.put("success", true);
        } else {
            modelMap.put("success", false);
            modelMap.put("errMsg", "empty productId");
        }
        return modelMap;
    }

    @RequestMapping(value = "/addproduct", method = RequestMethod.POST)
    @ResponseBody
    private Map<String, Object> addProduct(HttpServletRequest request) {
        Map<String, Object> modelMap = new HashMap<String, Object>();
        // 验证码校验
        if (!CodeUtil.checkVerifyCode(request)) {
            modelMap.put("success", false);
            modelMap.put("errMsg", "输入了错误的验证码");
            return modelMap;
        }
        // 接收前端参数的变量的初始化,包括商品,缩略图,详情图列表实体类
        ObjectMapper mapper = new ObjectMapper();
        Product product = null;
        ImageHolder thumbnail = null;
        List<ImageHolder> productImgList = new ArrayList<ImageHolder>();
        CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(
                request.getSession().getServletContext());
        try {
            // 若请求中存在文件流,则取出相关的文件(包括缩略图和详情图)
            if (multipartResolver.isMultipart(request)) {
                thumbnail = handleImage(request, thumbnail, productImgList);
            } else {
                modelMap.put("success", false);
                modelMap.put("errMsg", "上传图片不能为空");
                return modelMap;
            }
        } catch (Exception e) {
            modelMap.put("success", false);
            modelMap.put("errMsg", e.toString());
            return modelMap;
        }
        try {
            String productStr = HttpServletRequestUtil.getString(request, "productStr");
            // 尝试获取前端传过来的表单string流并将其转换成Product实体类
            product = mapper.readValue(productStr, Product.class);
        } catch (Exception e) {
            modelMap.put("success", false);
            modelMap.put("errMsg", e.toString());
            return modelMap;
        }
        // 若Product信息,缩略图以及详情图列表为非空,则开始进行商品添加操作
        if (product != null && thumbnail != null && productImgList.size() > 0) {
            try {
                // 从session中获取当前店铺的Id并赋值给product,减少对前端数据的依赖
                Shop currentShop = (Shop) request.getSession().getAttribute("currentShop");
                product.setShop(currentShop);
                // 执行添加操作
                ProductExecution pe = productService.addProduct(product, thumbnail, productImgList);
                if (pe.getState() == ProductStateEnum.SUCCESS.getState()) {
                    modelMap.put("success", true);
                } else {
                    modelMap.put("success", false);
                    modelMap.put("errMsg", pe.getStateInfo());
                }
            } catch (ProductOperationException e) {
                modelMap.put("success", false);
                modelMap.put("errMsg", e.toString());
                return modelMap;
            }
        } else {
            modelMap.put("success", false);
            modelMap.put("errMsg", "请输入商品信息");
        }
        return modelMap;
    }

    private ImageHolder handleImage(HttpServletRequest request, ImageHolder thumbnail, List<ImageHolder> productImgList)
            throws IOException {
        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
        // 取出缩略图并构建ImageHolder对象
        CommonsMultipartFile thumbnailFile = (CommonsMultipartFile) multipartRequest.getFile("thumbnail");
        if (thumbnailFile != null) {
            thumbnail = new ImageHolder(thumbnailFile.getOriginalFilename(), thumbnailFile.getInputStream());
        }
        // 取出详情图列表并构建List<ImageHolder>列表对象,最多支持六张图片上传
        for (int i = 0; i < IMAGEMAXCOUNT; i++) {
            CommonsMultipartFile productImgFile = (CommonsMultipartFile) multipartRequest.getFile("productImg" + i);
            if (productImgFile != null) {
                // 若取出的第i个详情图片文件流不为空,则将其加入详情图列表
                ImageHolder productImg = new ImageHolder(productImgFile.getOriginalFilename(),
                        productImgFile.getInputStream());
                productImgList.add(productImg);
            } else {
                // 若取出的第i个详情图片文件流为空,则终止循环
                break;
            }
        }
        return thumbnail;
    }

    /**
     * 商品编辑
     * 
     * @param request
     * @return
     */
    @RequestMapping(value = "/modifyproduct", method = RequestMethod.POST)
    @ResponseBody
    private Map<String, Object> modifyProduct(HttpServletRequest request) {
        Map<String, Object> modelMap = new HashMap<String, Object>();
        // 是商品编辑时候调用还是上下架操作的时候调用
        // 若为前者则进行验证码判断,后者则跳过验证码判断
        boolean statusChange = HttpServletRequestUtil.getBoolean(request, "statusChange");
        // 验证码判断
        if (!statusChange && !CodeUtil.checkVerifyCode(request)) {
            modelMap.put("success", false);
            modelMap.put("errMsg", "输入了错误的验证码");
            return modelMap;
        }
        // 接收前端参数的变量的初始化,包括商品,缩略图,详情图列表实体类
        ObjectMapper mapper = new ObjectMapper();
        Product product = null;
        ImageHolder thumbnail = null;
        List<ImageHolder> productImgList = new ArrayList<ImageHolder>();
        CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(
                request.getSession().getServletContext());
        // 若请求中存在文件流,则取出相关的文件(包括缩略图和详情图)
        try {
            if (multipartResolver.isMultipart(request)) {
                thumbnail = handleImage(request, thumbnail, productImgList);
            }
        } catch (Exception e) {
            modelMap.put("success", false);
            modelMap.put("errMsg", e.toString());
            return modelMap;
        }
        try {
            String productStr = HttpServletRequestUtil.getString(request, "productStr");
            // 尝试获取前端传过来的表单string流并将其转换成Product实体类
            product = mapper.readValue(productStr, Product.class);
        } catch (Exception e) {
            modelMap.put("success", false);
            modelMap.put("errMsg", e.toString());
            return modelMap;
        }
        // 非空判断
        if (product != null) {
            try {
                // 从session中获取当前店铺的Id并赋值给product,减少对前端数据的依赖
                Shop currentShop = (Shop) request.getSession().getAttribute("currentShop");
                product.setShop(currentShop);
                // 开始进行商品信息变更操作
                ProductExecution pe = productService.modifyProduct(product, thumbnail, productImgList);
                if (pe.getState() == ProductStateEnum.SUCCESS.getState()) {
                    modelMap.put("success", true);
                } else {
                    modelMap.put("success", false);
                    modelMap.put("errMsg", pe.getStateInfo());
                }
            } catch (RuntimeException e) {
                modelMap.put("success", false);
                modelMap.put("errMsg", e.toString());
                return modelMap;
            }

        } else {
            modelMap.put("success", false);
            modelMap.put("errMsg", "请输入商品信息");
        }
        return modelMap;
    }

    /**
     * 封装商品查询条件到Product实例中
     * 
     * @param shopId(mandatory)
     * @param productCategoryId(optional)
     * @param productName(optional)
     * @return
     */
    private Product compactProductCondition(long shopId, long productCategoryId, String productName) {
        Product productCondition = new Product();
        Shop shop = new Shop();
        shop.setShopId(shopId);
        productCondition.setShop(shop);
        // 若有指定类别的要求则添加进去
        if (productCategoryId != -1L) {
            ProductCategory productCategory = new ProductCategory();
            productCategory.setProductCategoryId(productCategoryId);
            productCondition.setProductCategory(productCategory);
        }
        // 若有商品名模糊查询的要求则添加进去
        if (productName != null) {
            productCondition.setProductName(productName);
        }
        return productCondition;
    }
}

 

$(function() {
    // 从URL里获取productId参数的值
    var productId = getQueryString('productId');
    // 通过productId获取商品信息的URL
    var infoUrl = '/o2o/shopadmin/getproductbyid?productId=' + productId;
    // 获取当前店铺设定的商品类别列表的URL
    var categoryUrl = '/o2o/shopadmin/getproductcategorylist';
    // 更新商品信息的URL
    var productPostUrl = '/o2o/shopadmin/modifyproduct';
    // 由于商品添加和编辑使用的是同一个页面,
    // 该标识符用来标明本次是添加还是编辑操作
    var isEdit = false;
    if (productId) {
        // 若有productId则为编辑操作
        getInfo(productId);
        isEdit = true;
    } else {
        getCategory();
        productPostUrl = '/o2o/shopadmin/addproduct';
    }

    // 获取需要编辑的商品的商品信息,并赋值给表单
    function getInfo(id) {
        $
                .getJSON(
                        infoUrl,
                        function(data) {
                            if (data.success) {
                                // 从返回的JSON当中获取product对象的信息,并赋值给表单
                                var product = data.product;
                                $('#product-name').val(product.productName);
                                $('#product-desc').val(product.productDesc);
                                $('#priority').val(product.priority);
                                $('#normal-price').val(product.normalPrice);
                                $('#promotion-price').val(
                                        product.promotionPrice);
                                // 获取原本的商品类别以及该店铺的所有商品类别列表
                                var optionHtml = '';
                                var optionArr = data.productCategoryList;
                                var optionSelected = product.productCategory.productCategoryId;
                                // 生成前端的HTML商品类别列表,并默认选择编辑前的商品类别
                                optionArr
                                        .map(function(item, index) {
                                            var isSelect = optionSelected === item.productCategoryId ? 'selected'
                                                    : '';
                                            optionHtml += '<option data-value="'
                                                    + item.productCategoryId
                                                    + '"'
                                                    + isSelect
                                                    + '>'
                                                    + item.productCategoryName
                                                    + '</option>';
                                        });
                                $('#category').html(optionHtml);
                            }
                        });
    }

    // 为商品添加操作提供该店铺下的所有商品类别列表
    function getCategory() {
        $.getJSON(categoryUrl, function(data) {
            if (data.success) {
                var productCategoryList = data.data;
                var optionHtml = '';
                productCategoryList.map(function(item, index) {
                    optionHtml += '<option data-value="'
                            + item.productCategoryId + '">'
                            + item.productCategoryName + '</option>';
                });
                $('#category').html(optionHtml);
            }
        });
    }

    // 针对商品详情图控件组,若该控件组的最后一个元素发生变化(即上传了图片),
    // 且控件总数未达到6个,则生成新的一个文件上传控件
    $('.detail-img-div').on('change', '.detail-img:last-child', function() {
        if ($('.detail-img').length < 6) {
            $('#detail-img').append('<input type="file" class="detail-img">');
        }
    });

    // 提交按钮的事件响应,分别对商品添加和编辑操作做不同响应
    $('#submit').click(
            function() {
                // 创建商品json对象,并从表单里面获取对应的属性值
                var product = {};
                product.productName = $('#product-name').val();
                product.productDesc = $('#product-desc').val();
                product.priority = $('#priority').val();
                product.normalPrice = $('#normal-price').val();
                product.promotionPrice = $('#promotion-price').val();
                // 获取选定的商品类别值
                product.productCategory = {
                    productCategoryId : $('#category').find('option').not(
                            function() {
                                return !this.selected;
                            }).data('value')
                };
                product.productId = productId;

                // 获取缩略图文件流
                var thumbnail = $('#small-img')[0].files[0];
                // 生成表单对象,用于接收参数并传递给后台
                var formData = new FormData();
                formData.append('thumbnail', thumbnail);
                // 遍历商品详情图控件,获取里面的文件流
                $('.detail-img').map(
                        function(index, item) {
                            // 判断该控件是否已选择了文件
                            if ($('.detail-img')[index].files.length > 0) {
                                // 将第i个文件流赋值给key为productImgi的表单键值对里
                                formData.append('productImg' + index,
                                        $('.detail-img')[index].files[0]);
                            }
                        });
                // 将product json对象转成字符流保存至表单对象key为productStr的的键值对里
                formData.append('productStr', JSON.stringify(product));
                // 获取表单里输入的验证码
                var verifyCodeActual = $('#j_captcha').val();
                if (!verifyCodeActual) {
                    $.toast('请输入验证码!');
                    return;
                }
                formData.append("verifyCodeActual", verifyCodeActual);
                // 将数据提交至后台处理相关操作
                $.ajax({
                    url : productPostUrl,
                    type : 'POST',
                    data : formData,
                    contentType : false,
                    processData : false,
                    cache : false,
                    success : function(data) {
                        if (data.success) {
                            $.toast('提交成功!');
                            $('#captcha_img').click();
                        } else {
                            $.toast('提交失败!');
                            $('#captcha_img').click();
                        }
                    }
                });
            });

});

 

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>商品编辑</title>
<meta name="viewport" content="initial-scale=1, maximum-scale=1">
<link rel="shortcut icon" href="/favicon.ico">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<link rel="stylesheet"
    href="//g.alicdn.com/msui/sm/0.6.2/css/sm.min.css">
<link rel="stylesheet"
    href="//g.alicdn.com/msui/sm/0.6.2/css/sm-extend.min.css">
<link rel="stylesheet"
    href="../resources/css/shop/productmanagement.css">
</head>
<body>
    <header class="bar bar-nav">
        <h1 class="title">商品编辑</h1>
    </header>
    <div class="content">
        <div class="list-block">
            <ul>
                <li>
                    <div class="item-content">
                        <div class="item-media">
                            <i class="icon icon-form-name"></i>
                        </div>
                        <div class="item-inner">
                            <div class="item-title label">商品名称</div>
                            <div class="item-input">
                                <input type="text" id="product-name" placeholder="商品名称">
                            </div>
                        </div>
                    </div>
                </li>
                <li>
                    <div class="item-content">
                        <div class="item-media">
                            <i class="icon icon-form-email"></i>
                        </div>
                        <div class="item-inner">
                            <div class="item-title label">目录</div>
                            <div class="item-input">
                                <select id="category">
                                </select>
                            </div>
                        </div>
                    </div>
                </li>
                <li>
                    <div class="item-content">
                        <div class="item-media">
                            <i class="icon icon-form-email"></i>
                        </div>
                        <div class="item-inner">
                            <div class="item-title label">优先级</div>
                            <div class="item-input">
                                <input type="number" id="priority" placeholder="数字越大越排前面">
                            </div>
                        </div>
                    </div>
                </li>
                <li>
                    <div class="item-content">
                        <div class="item-media">
                            <i class="icon icon-form-email"></i>
                        </div>
                        <div class="item-inner">
                            <div class="item-title label">原价</div>
                            <div class="item-input">
                                <input type="number" id="normal-price" placeholder="可选">
                            </div>
                        </div>
                    </div>
                </li>
                <li>
                    <div class="item-content">
                        <div class="item-media">
                            <i class="icon icon-form-email"></i>
                        </div>
                        <div class="item-inner">
                            <div class="item-title label">现价</div>
                            <div class="item-input">
                                <input type="number" id="promotion-price" placeholder="可选">
                            </div>
                        </div>
                    </div>
                </li>
                <!--                 <li>
                    <div class="item-content">
                        <div class="item-media">
                            <i class="icon icon-form-email"></i>
                        </div>
                        <div class="item-inner">
                            <div class="item-title label">积分</div>
                            <div class="item-input">
                                <input type="number" id="point" placeholder="可选">
                            </div>
                        </div>
                    </div>
                </li> -->
                <li>
                    <div class="item-content">
                        <div class="item-media">
                            <i class="icon icon-form-email"></i>
                        </div>
                        <div class="item-inner">
                            <div class="item-title label">缩略图</div>
                            <div class="item-input">
                                <input type="file" id="small-img">
                            </div>
                        </div>
                    </div>
                </li>
                <li>
                    <div class="item-content">
                        <div class="item-media">
                            <i class="icon icon-form-email"></i>
                        </div>
                        <div class="item-inner detail-img-div">
                            <div class="item-title label">详情图片</div>
                            <div class="item-input" id="detail-img">
                                <input type="file" class="detail-img">
                                <!-- <input type="file" class="detail-img">
                                <input type="file" class="detail-img"> -->
                            </div>
                        </div>
                    </div>
                </li>
                <li>
                    <div class="item-content">
                        <div class="item-media">
                            <i class="icon icon-form-email"></i>
                        </div>
                        <div class="item-inner">
                            <div class="item-title label">商品描述</div>
                            <div class="item-input">
                                <textarea id="product-desc" placeholder="商品描述"></textarea>
                            </div>
                        </div>
                    </div>
                </li>
                <li>
                    <div class="item-content">
                        <div class="item-media">
                            <i class="icon icon-form-email"></i>
                        </div>
                        <div class="item-inner">
                            <label for="j_captcha" class="item-title label">验证码</label> <input
                                id="j_captcha" name="j_captcha" type="text"
                                class="form-control in" placeholder="验证码" />
                            <div class="item-input">
                                <img id="captcha_img" alt="点击更换" title="点击更换"
                                    onclick="changeVerifyCode(this)" src="../Kaptcha" />
                            </div>
                        </div>
                    </div>
                </li>

            </ul>
        </div>
        <div class="content-block">
            <div class="row">
                <div class="col-50">
                    <a href="/o2o/shopadmin/productmanagement"
                        class="button button-big button-fill button-danger" id="back">返回商品管理</a>
                </div>
                <div class="col-50">
                    <a href="#" class="button button-big button-fill" id="submit">提交</a>
                </div>
            </div>
        </div>
    </div>



    <script type='text/javascript'
        src='//g.alicdn.com/sj/lib/zepto/zepto.min.js' charset='utf-8'></script>
    <script type='text/javascript'
        src='//g.alicdn.com/msui/sm/0.6.2/js/sm.min.js' charset='utf-8'></script>
    <script type='text/javascript'
        src='//g.alicdn.com/msui/sm/0.6.2/js/sm-extend.min.js' charset='utf-8'></script>
    <script type='text/javascript' src='../resources/js/common/common.js'
        charset='utf-8'></script>
    <script type='text/javascript'
        src='../resources/js/shop/productoperation.js' charset='utf-8'></script>
</body>
</html>
package com.ouyan.o2o.web.shopadmin;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.ouyan.o2o.dto.ProductCategoryExecution;
import com.ouyan.o2o.dto.Result;
import com.ouyan.o2o.entity.ProductCategory;
import com.ouyan.o2o.entity.Shop;
import com.ouyan.o2o.enums.ProductCategoryStateEnum;
import com.ouyan.o2o.exceptions.ProductCategoryOperationException;
import com.ouyan.o2o.service.ProductCategoryService;

@Controller
@RequestMapping("/shopadmin")
public class ProductCategoryManagementController {
    @Autowired
    private ProductCategoryService productCategoryService;

    @RequestMapping(value = "/getproductcategorylist", method = RequestMethod.GET)
    @ResponseBody
    private Result<List<ProductCategory>> getProductCategoryList(HttpServletRequest request) {
        Shop currentShop = (Shop) request.getSession().getAttribute("currentShop");
        List<ProductCategory> list = null;
        if (currentShop != null && currentShop.getShopId() > 0) {
            list = productCategoryService.getProductCategoryList(currentShop.getShopId());
            return new Result<List<ProductCategory>>(true, list);
        } else {
            ProductCategoryStateEnum ps = ProductCategoryStateEnum.INNER_ERROR;
            return new Result<List<ProductCategory>>(false, ps.getState(), ps.getStateInfo());
        }
    }
    
    @RequestMapping(value = "/addproductcategorys", method = RequestMethod.POST)
    @ResponseBody
    private Map<String, Object> addProductCategorys(@RequestBody List<ProductCategory> productCategoryList,
            HttpServletRequest request) {
        Map<String, Object> modelMap = new HashMap<String, Object>();
        Shop currentShop = (Shop) request.getSession().getAttribute("currentShop");
        for (ProductCategory pc : productCategoryList) {
            pc.setShopId(currentShop.getShopId());
        }
        if (productCategoryList != null && productCategoryList.size() > 0) {
            try {
                ProductCategoryExecution pe = productCategoryService.batchAddProductCategory(productCategoryList);
                if (pe.getState() == ProductCategoryStateEnum.SUCCESS.getState()) {
                    modelMap.put("success", true);
                } else {
                    modelMap.put("success", false);
                    modelMap.put("errMsg", pe.getStateInfo());
                }
            } catch (ProductCategoryOperationException e) {
                modelMap.put("success", false);
                modelMap.put("errMsg", e.toString());
                return modelMap;
            }

        } else {
            modelMap.put("success", false);
            modelMap.put("errMsg", "请至少输入一个商品类别");
        }
        return modelMap;
    }
    
    @RequestMapping(value = "/removeproductcategory", method = RequestMethod.POST)
    @ResponseBody             
    private Map<String, Object> removeProductCategory(Long productCategoryId, HttpServletRequest request) {
        Map<String, Object> modelMap = new HashMap<String, Object>();
        if (productCategoryId != null && productCategoryId > 0) {
            try {
                Shop currentShop = (Shop) request.getSession().getAttribute("currentShop");
                ProductCategoryExecution pe = productCategoryService.deleteProductCategory(productCategoryId,currentShop.getShopId());
                if (pe.getState() == ProductCategoryStateEnum.SUCCESS.getState()) {
                    modelMap.put("success", true);
                } else {
                    modelMap.put("success", false);
                    modelMap.put("errMsg", pe.getStateInfo());
                }
            } catch (ProductCategoryOperationException e) {
                modelMap.put("success", false);
                modelMap.put("errMsg", e.toString());
                return modelMap;
            }

        } else {
            modelMap.put("success", false);
            modelMap.put("errMsg", "请至少选择一个商品类别");
        }
        return modelMap;
    }    

} 

package com.ouyan.o2o.web.shopadmin;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
@RequestMapping(value="shopadmin",method={RequestMethod.GET})
public class ShopAdminController {
    @RequestMapping(value="/shopoperate")
    public String shopOperation(){
        return "shop/shopoperation";
    }
    
    @RequestMapping(value="/shoplist")
    public String shopList(){
        return "shop/shoplist";
    }
    
    @RequestMapping(value="/shopmanagement")
    public String shopManagement(){
        return "shop/shopmanagement";
    }
    
    @RequestMapping(value="/productcategorymanagement")
    public String peoductCategoryManagement(){
        return "shop/productcategorymanagement";
    }

    @RequestMapping(value = "/productoperation")
    public String productOperation() {
        // 转发至商品添加/编辑页面
        return "shop/productoperation";
    }

    @RequestMapping(value = "/productmanagement")
    public String productManagement() {
        // 转发至商品管理页面
        return "shop/productmanagement";
    }
    
}

package com.ouyan.o2o.web.shopadmin;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.ouyan.o2o.dto.ImageHolder;
import com.ouyan.o2o.dto.ProductExecution;
import com.ouyan.o2o.entity.Product;
import com.ouyan.o2o.entity.ProductCategory;
import com.ouyan.o2o.entity.Shop;
import com.ouyan.o2o.enums.ProductStateEnum;
import com.ouyan.o2o.exceptions.ProductOperationException;
import com.ouyan.o2o.service.ProductCategoryService;
import com.ouyan.o2o.service.ProductService;
import com.ouyan.o2o.util.CodeUtil;
import com.ouyan.o2o.util.HttpServletRequestUtil;

@Controller
@RequestMapping("/shopadmin")
public class ProductManagementController {
    @Autowired
    private ProductService productService;
    @Autowired
    private ProductCategoryService productCategoryService;

    // 支持上传商品详情图的最大数量
    private static final int IMAGEMAXCOUNT = 6;

    /**
     * 通过店铺id获取该店铺下的商品列表
     * 
     * @param request
     * @return
     */
    @RequestMapping(value = "/getproductlistbyshop", method = RequestMethod.GET)
    @ResponseBody
    private Map<String, Object> getProductListByShop(HttpServletRequest request) {
        Map<String, Object> modelMap = new HashMap<String, Object>();
        // 获取前台传过来的页码
        int pageIndex = HttpServletRequestUtil.getInt(request, "pageIndex");
        // 获取前台传过来的每页要求返回的商品数上限
        int pageSize = HttpServletRequestUtil.getInt(request, "pageSize");
        // 从当前session中获取店铺信息,主要是获取shopId
        Shop currentShop = (Shop) request.getSession().getAttribute("currentShop");
        // 空值判断
        if ((pageIndex > -1) && (pageSize > -1) && (currentShop != null) && (currentShop.getShopId() != null)) {
            // 获取传入的需要检索的条件,包括是否需要从某个商品类别以及模糊查找商品名去筛选某个店铺下的商品列表
            // 筛选的条件可以进行排列组合
            long productCategoryId = HttpServletRequestUtil.getLong(request, "productCategoryId");
            String productName = HttpServletRequestUtil.getString(request, "productName");
            Product productCondition = compactProductCondition(currentShop.getShopId(), productCategoryId, productName);
            // 传入查询条件以及分页信息进行查询,返回相应商品列表以及总数
            ProductExecution pe = productService.getProductList(productCondition, pageIndex, pageSize);
            modelMap.put("productList", pe.getProductList());
            modelMap.put("count", pe.getCount());
            modelMap.put("success", true);
        } else {
            modelMap.put("success", false);
            modelMap.put("errMsg", "empty pageSize or pageIndex or shopId");
        }
        return modelMap;
    }

    /**
     * 通过商品id获取商品信息
     * 
     * @param productId
     * @return
     */
    @RequestMapping(value = "/getproductbyid", method = RequestMethod.GET)
    @ResponseBody
    private Map<String, Object> getProductById(@RequestParam Long productId) {
        Map<String, Object> modelMap = new HashMap<String, Object>();
        // 非空判断
        if (productId > -1) {
            // 获取商品信息
            Product product = productService.getProductById(productId);
            // 获取该店铺下的商品类别列表
            List<ProductCategory> productCategoryList = productCategoryService
                    .getProductCategoryList(product.getShop().getShopId());
            modelMap.put("product", product);
            modelMap.put("productCategoryList", productCategoryList);
            modelMap.put("success", true);
        } else {
            modelMap.put("success", false);
            modelMap.put("errMsg", "empty productId");
        }
        return modelMap;
    }

    @RequestMapping(value = "/addproduct", method = RequestMethod.POST)
    @ResponseBody
    private Map<String, Object> addProduct(HttpServletRequest request) {
        Map<String, Object> modelMap = new HashMap<String, Object>();
        // 验证码校验
        if (!CodeUtil.checkVerifyCode(request)) {
            modelMap.put("success", false);
            modelMap.put("errMsg", "输入了错误的验证码");
            return modelMap;
        }
        // 接收前端参数的变量的初始化,包括商品,缩略图,详情图列表实体类
        ObjectMapper mapper = new ObjectMapper();
        Product product = null;
        ImageHolder thumbnail = null;
        List<ImageHolder> productImgList = new ArrayList<ImageHolder>();
        CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(
                request.getSession().getServletContext());
        try {
            // 若请求中存在文件流,则取出相关的文件(包括缩略图和详情图)
            if (multipartResolver.isMultipart(request)) {
                thumbnail = handleImage(request, thumbnail, productImgList);
            } else {
                modelMap.put("success", false);
                modelMap.put("errMsg", "上传图片不能为空");
                return modelMap;
            }
        } catch (Exception e) {
            modelMap.put("success", false);
            modelMap.put("errMsg", e.toString());
            return modelMap;
        }
        try {
            String productStr = HttpServletRequestUtil.getString(request, "productStr");
            // 尝试获取前端传过来的表单string流并将其转换成Product实体类
            product = mapper.readValue(productStr, Product.class);
        } catch (Exception e) {
            modelMap.put("success", false);
            modelMap.put("errMsg", e.toString());
            return modelMap;
        }
        // 若Product信息,缩略图以及详情图列表为非空,则开始进行商品添加操作
        if (product != null && thumbnail != null && productImgList.size() > 0) {
            try {
                // 从session中获取当前店铺的Id并赋值给product,减少对前端数据的依赖
                Shop currentShop = (Shop) request.getSession().getAttribute("currentShop");
                product.setShop(currentShop);
                // 执行添加操作
                ProductExecution pe = productService.addProduct(product, thumbnail, productImgList);
                if (pe.getState() == ProductStateEnum.SUCCESS.getState()) {
                    modelMap.put("success", true);
                } else {
                    modelMap.put("success", false);
                    modelMap.put("errMsg", pe.getStateInfo());
                }
            } catch (ProductOperationException e) {
                modelMap.put("success", false);
                modelMap.put("errMsg", e.toString());
                return modelMap;
            }
        } else {
            modelMap.put("success", false);
            modelMap.put("errMsg", "请输入商品信息");
        }
        return modelMap;
    }

    private ImageHolder handleImage(HttpServletRequest request, ImageHolder thumbnail, List<ImageHolder> productImgList)
            throws IOException {
        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
        // 取出缩略图并构建ImageHolder对象
        CommonsMultipartFile thumbnailFile = (CommonsMultipartFile) multipartRequest.getFile("thumbnail");
        if (thumbnailFile != null) {
            thumbnail = new ImageHolder(thumbnailFile.getOriginalFilename(), thumbnailFile.getInputStream());
        }
        // 取出详情图列表并构建List<ImageHolder>列表对象,最多支持六张图片上传
        for (int i = 0; i < IMAGEMAXCOUNT; i++) {
            CommonsMultipartFile productImgFile = (CommonsMultipartFile) multipartRequest.getFile("productImg" + i);
            if (productImgFile != null) {
                // 若取出的第i个详情图片文件流不为空,则将其加入详情图列表
                ImageHolder productImg = new ImageHolder(productImgFile.getOriginalFilename(),
                        productImgFile.getInputStream());
                productImgList.add(productImg);
            } else {
                // 若取出的第i个详情图片文件流为空,则终止循环
                break;
            }
        }
        return thumbnail;
    }

    /**
     * 商品编辑
     * 
     * @param request
     * @return
     */
    @RequestMapping(value = "/modifyproduct", method = RequestMethod.POST)
    @ResponseBody
    private Map<String, Object> modifyProduct(HttpServletRequest request) {
        Map<String, Object> modelMap = new HashMap<String, Object>();
        // 是商品编辑时候调用还是上下架操作的时候调用
        // 若为前者则进行验证码判断,后者则跳过验证码判断
        boolean statusChange = HttpServletRequestUtil.getBoolean(request, "statusChange");
        // 验证码判断
        if (!statusChange && !CodeUtil.checkVerifyCode(request)) {
            modelMap.put("success", false);
            modelMap.put("errMsg", "输入了错误的验证码");
            return modelMap;
        }
        // 接收前端参数的变量的初始化,包括商品,缩略图,详情图列表实体类
        ObjectMapper mapper = new ObjectMapper();
        Product product = null;
        ImageHolder thumbnail = null;
        List<ImageHolder> productImgList = new ArrayList<ImageHolder>();
        CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(
                request.getSession().getServletContext());
        // 若请求中存在文件流,则取出相关的文件(包括缩略图和详情图)
        try {
            if (multipartResolver.isMultipart(request)) {
                thumbnail = handleImage(request, thumbnail, productImgList);
            }
        } catch (Exception e) {
            modelMap.put("success", false);
            modelMap.put("errMsg", e.toString());
            return modelMap;
        }
        try {
            String productStr = HttpServletRequestUtil.getString(request, "productStr");
            // 尝试获取前端传过来的表单string流并将其转换成Product实体类
            product = mapper.readValue(productStr, Product.class);
        } catch (Exception e) {
            modelMap.put("success", false);
            modelMap.put("errMsg", e.toString());
            return modelMap;
        }
        // 非空判断
        if (product != null) {
            try {
                // 从session中获取当前店铺的Id并赋值给product,减少对前端数据的依赖
                Shop currentShop = (Shop) request.getSession().getAttribute("currentShop");
                product.setShop(currentShop);
                // 开始进行商品信息变更操作
                ProductExecution pe = productService.modifyProduct(product, thumbnail, productImgList);
                if (pe.getState() == ProductStateEnum.SUCCESS.getState()) {
                    modelMap.put("success", true);
                } else {
                    modelMap.put("success", false);
                    modelMap.put("errMsg", pe.getStateInfo());
                }
            } catch (RuntimeException e) {
                modelMap.put("success", false);
                modelMap.put("errMsg", e.toString());
                return modelMap;
            }

        } else {
            modelMap.put("success", false);
            modelMap.put("errMsg", "请输入商品信息");
        }
        return modelMap;
    }

    /**
     * 封装商品查询条件到Product实例中
     * 
     * @param shopId(mandatory)
     * @param productCategoryId(optional)
     * @param productName(optional)
     * @return
     */
    private Product compactProductCondition(long shopId, long productCategoryId, String productName) {
        Product productCondition = new Product();
        Shop shop = new Shop();
        shop.setShopId(shopId);
        productCondition.setShop(shop);
        // 若有指定类别的要求则添加进去
        if (productCategoryId != -1L) {
            ProductCategory productCategory = new ProductCategory();
            productCategory.setProductCategoryId(productCategoryId);
            productCondition.setProductCategory(productCategory);
        }
        // 若有商品名模糊查询的要求则添加进去
        if (productName != null) {
            productCondition.setProductName(productName);
        }
        return productCondition;
    }
}

 

posted @ 2017-10-20 17:18  虚极静笃  Views(1301)  Comments(0Edit  收藏  举报