SSM到Spring Boot-從零開發校園商鋪平臺四(店鋪註冊功能模塊)

這裏寫圖片描述

Dao層新增店鋪

src/main/java/com.imooc.o2o.dao 目錄下新建 ShopDao.java接口。

package com.imooc.o2o.dao;

import com.imooc.o2o.entity.Shop;

public interface ShopDao {

    /**
     * 新增店鋪
     * @param shop
     * @return
     */
    int insertShop(Shop shop);
}

src/main/resources/mapper路徑下創建ShopDao.xml文件

<?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.imooc.o2o.dao.ShopDao">
    <insert id="insertShop" useGeneratedKeys="true" keyColumn="shop_id"
        keyProperty="shopId">
        INSERT INTO
        tb_shop(owner_id,area_id,shop_category_id,shop_name,shop_desc,shop_addr,
        phone,shop_img,priority,create_time,last_edit_time,enable_status,advice)
        VALUSE
        (#{owner.userId},#{area.areaId},#{shopCategory.shopCategoryId},#{shopName},
        #{shopDesc},#{shopAddr},#{phone},#{shopImg},#{priority},#{createTime},
        #{lastEditTime},#{enableStatus},#{advice})
    </insert>
</mapper>

數據庫添加測試數據

insert into `o2o`.`tb_shop_category` ( `shop_category_name`, `shop_category_desc`, `shop_category_img`, `priority`) values ( '咖啡奶茶', '咖啡奶茶', 'test', '1')

insert into `o2o`.`tb_person_info` ( `name`, `profile_img`, `email`, `gender`, `enable_status`, `user_type`) values ( '測試', 'test', 'test', '1', '1', '2')

com.imooc.o2o.dao目錄下創建ShopDaoTest.java進行單元測試

package com.imooc.o2o.dao;

import static org.junit.Assert.assertEquals;

import java.util.Date;

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

import com.imooc.o2o.BaseTest;
import com.imooc.o2o.entity.Area;
import com.imooc.o2o.entity.PersonInfo;
import com.imooc.o2o.entity.Shop;
import com.imooc.o2o.entity.ShopCategory;

public class ShopDaoTest extends BaseTest{

    @Autowired
    private ShopDao shopDao;
    @Test
    public void testInsertShop() {
        Shop shop = new Shop();
        PersonInfo owner = new PersonInfo();
        Area area = new Area();
        ShopCategory shopCategory = new ShopCategory();
        owner.setUserId(1L);
        area.setAreaId(2);
        shopCategory.setShopCategoryId(1L);
        shop.setOwner(owner);
        shop.setArea(area);
        shop.setShopCategory(shopCategory);
        shop.setShopName("測試的店鋪");
        shop.setShopDesc("test");
        shop.setShopAddr("test");
        shop.setPhone("test");
        shop.setShopImg("test");
        shop.setCreateTime(new Date());
        shop.setEnableStatus(1);
        shop.setAdvice("審覈中");
        int effectedNum = shopDao.insertShop(shop);
        assertEquals(1, effectedNum);

    }
}

Dao層之更新店鋪

src/main/java/com.imooc.o2o.dao目錄下ShopDao.java新增代碼

/**
 * 更新店鋪信息
 */
int updateShop(Shop shop);

src/main/resources/mapper目錄下ShopDao.xml新增代碼

<update id="updateShop" parameterType="com.imooc.o2o.entity.Shop">
      update tb_shop
      <set>
        <if test="shopName != null">shop_name=#{shopName},</if>
        <if test="shopDesc != null">shop_desc=#{shopDesc},</if>
        <if test="shopAddr != null">shop_addr=#{shopAddr},</if>
        <if test="phone != null">phone=#{phone},</if>
        <if test="shopImg != null">shop_img=#{shopImg},</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="advice != null">advice=#{advice},</if>
        <if test="area != null">area_id=#{area.areaId},</if>
        <if test="shopCategory != null">shop_category_id=#{shopCategory.shopCategoryId}</if>
      </set>
      where shop_id=#{shopId}
    </update>

src/test/java/com.imooc.o2o.dao目錄下ShopDaoTest.java添加代碼

@Test
    public void testUpdateShop() {
        Shop shop = new Shop();
        shop.setShopId(1L);
        shop.setShopDesc("測試描述");
        shop.setShopAddr("測試地址");
        int effectedNum = shopDao.updateShop(shop);
        assertEquals(1, effectedNum);   
    }

testInsertShop方法上面添加@Ignore標籤,JUnit則不會觸發testInsertShop方法了。

Run As執行測試。沒發現錯誤就ok了。

Thumbnailator圖片處理和封裝Util

<!-- https://mvnrepository.com/artifact/net.coobird/thumbnailator -->
<dependency>
    <groupId>net.coobird</groupId>
    <artifactId>thumbnailator</artifactId>
    <version>0.4.8</version>
</dependency>

在src/main/java/com.imooc.o2o.util路徑下新建ImageUtil.java類

在src/main/resources路徑下放置一張圖片

在/Users/mac/Downloads/luoto.png 存入另外一張圖片。爲此圖片添加上面圖片的水印。

package com.imooc.o2o.util;

import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

import net.coobird.thumbnailator.Thumbnails;
import net.coobird.thumbnailator.geometry.Positions;

public class ImageUtil {

    public static void main(String[] args) throws IOException {
        String basePath = Thread.currentThread().getContextClassLoader().getResource("").getPath();
        Thumbnails.of(new File("/Users/mac/Downloads/luoto.png")).size(200, 200)
                .watermark(Positions.BOTTOM_RIGHT, ImageIO.read(new File(basePath + "/jingyu.png")), 0.25f)
                .outputQuality(0.8f).toFile("/Users/mac/Downloads/luotonew.png");
    }
}

運行main函數,我們發現在/Users/mac/Downloads路徑下多出一張luotonew.png的水印圖片。

src/main/java/com.imooc.o2o.util路徑下創建PathUtil.java類

package com.imooc.o2o.util;

public class PathUtil {

    /*
     * 根據不同的操作系統,設置儲存圖片文件不同的根目錄
     */
    private static String seperator = System.getProperty("file.separator");
    public static String getImgBasePath() {

        String os =System.getProperty("os.name");
        String basePath = "";
        if(os.toLowerCase().startsWith("win")) {
          basePath = "D:/projectdev/image/";    //根據自己的實際路徑進行設置
        }else {
            basePath = "/home/o2o/image/";//根據自己的實際路徑進行設置
        }
        basePath = basePath.replace("/", seperator);
        return basePath;
    }

    //根據不同的業務需求返回不同的子路徑
    public static String getShopImagePath(long shopId) {
        String imagePath = "/upkoad/item/shop/"+ shopId + "/";
        return imagePath.replace("/", seperator);
    }
}

修改ImageUtil.java類

package com.imooc.o2o.util;

import net.coobird.thumbnailator.Thumbnails;
import net.coobird.thumbnailator.geometry.Positions;

import javax.imageio.ImageIO;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;

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();

    /**
     * 處理縮略圖,並返回新生成圖片的相對值路徑
     */
    public static String generateThumbnail(File thumbnail,
                                           String targetAddr) {
        //隨機文件名,當前年月日小時分鐘秒+五位隨機數
        String realFileName = getRandomFileName();
        //文件的擴展名
        String extension = getFileExtension(thumbnail);
        //創建目標路徑所涉及到的目錄
        makeDirPath(targetAddr);
        String relativeAddr = targetAddr + realFileName + extension;
        File dest = new File(PathUtil.getImgBasePath() + relativeAddr);
        //給縮略圖上水印
        try {
            Thumbnails.of(thumbnail).size(200, 200)
                    .watermark(Positions.BOTTOM_RIGHT, ImageIO.read(new File(basePath + "watermark.png")), 0.25f)
                    .outputQuality(0.8f).toFile(dest);
        } catch (IOException e) {
            // TODO: handle exception
            e.printStackTrace();
        }
        //返回圖片存儲路徑
        return relativeAddr;
    }

    /**
     * 創建目標路徑所涉及到的目錄,即/home/work/o2o/xxx.jpg,
     * 那麼 home work o2o 這三個文件夾都得自動創建
     *
     * @param targetAddr
     */
    private static void makeDirPath(String targetAddr) {
        // TODO Auto-generated method stub
        String realFileParentPath = PathUtil.getImgBasePath() + targetAddr;
        File dirPath = new File(realFileParentPath);
        if (!dirPath.exists()) {
            dirPath.mkdirs();
        }
    }


    /**
     * 生成隨機文件名,當前年月日小時分鐘秒+五位隨機數
     */
    private static String getRandomFileName() {
        //獲取隨機的五位數
        int rannum = r.nextInt(89999) + 10000;
        String nowTimeStr = sDateFormat.format(new Date());
        return nowTimeStr + rannum;
    }

    /**
     * 獲取輸入文件流的擴展名
     */
    private static String getFileExtension(File thumbnail) {
        String originalFileName = thumbnail.getName();
        return originalFileName.substring(originalFileName.lastIndexOf("."));
    }

    public static void main(String[] args) throws IOException {

        Thumbnails.of(new File("/Users/mac/Downloads/luoto.png")).size(200, 200)
                .watermark(Positions.BOTTOM_RIGHT, ImageIO.read(new File(basePath + "/jingyu.png")), 0.25f)
                .outputQuality(0.8f).toFile("/Users/mac/Downloads/luotonew.png");
    }
}

Dto之ShopExecution的實現

src/main/java/com.imooc.o2o.dto路徑下創建ShopExecution.java類

package com.imooc.o2o.dto;

import java.util.List;

import com.imooc.o2o.entity.Shop;
import com.imooc.o2o.enums.ShopStateEnum;

public class ShopExecution {

    // 結果狀態
    private int state;

    // 狀態標識
    private String stateInfo;

    // 店鋪數量
    private int count;

    // 操作的shop(增刪改店鋪的時候用到)
    private Shop shop;

    // shop列表(查詢店鋪列表的時候使用)
    private List<Shop> shopList;

    public ShopExecution() {

    }

    // 店鋪操作失敗的時候使用的構造器
    public ShopExecution(ShopStateEnum stateEnum) {
        this.state = stateEnum.getState();
        this.stateInfo = stateEnum.getStateInfo();
    }

    // 店鋪操作成功的時候使用的構造器
    public ShopExecution(ShopStateEnum stateEnum, Shop shop) {
        this.state = stateEnum.getState();
        this.stateInfo = stateEnum.getStateInfo();
        this.shop = shop;
    }

    // 店鋪操作成功的時候使用的構造器
    public ShopExecution(ShopStateEnum stateEnum, List<Shop> shopList) {
        this.state = stateEnum.getState();
        this.stateInfo = stateEnum.getStateInfo();
        this.shopList = shopList;
    }

    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 Shop getShop() {
        return shop;
    }

    public void setShop(Shop shop) {
        this.shop = shop;
    }

    public List<Shop> getShopList() {
        return shopList;
    }

    public void setShopList(List<Shop> shopList) {
        this.shopList = shopList;
    }


}

創建枚舉類型文件

package com.imooc.o2o.enums;

public enum ShopStateEnum {

    CHECK(0, "審覈中"), OFFLINE(-1, "非法店鋪"), SUCCESS(1, "操作成功"), PASS(2, "通過認證"), INNER_ERROR(-1001, "內部系統錯誤"),
    NULL_SHOPID(-1002,"ShopId爲空"),
    ULL_SHOP(-1003,"shop信息爲空");
    private int state;
    private String stateInfo;

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

    /*
     *依據傳入的state返回相應的enum值 
     */
    public static ShopStateEnum stateOf(int state) {
        for(ShopStateEnum stateEnum:values()) {
            if(stateEnum.getState() == state) {
                return stateEnum;
            }
        }
        return null;
    }

    public int getState() {
        return state;
    }

    public String getStateInfo() {
        return stateInfo;
    }

}

店鋪註冊之Service層的實現

Service層需要事務的管理

創建com.imooc.o2o.exceptions包,ShopOperationException.java類文件

package com.imooc.o2o.exceptions;

public class ShopOperationException extends RuntimeException{

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

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

ShopServiceImpl.java

@Service
public class ShopServiceImpl implements ShopService{

    @Autowired
    private ShopDao shopDao;
    @Override
    @Transactional
    public ShopExecution addShop(Shop shop, File shopImg) {
        //空值判斷
        if(shop == null) {
            return new ShopExecution(ShopStateEnum.NULL_SHOP);
        }
        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(shopImg !=null) {
                    //存儲圖片
                    try {
                        addShopImg(shop, shopImg);
                    }catch (Exception e) {
                        // TODO: handle exception
                        throw new ShopOperationException("addShopImg error"+e.getMessage());
                    }
                    //更新店鋪的圖片地址
                    effectedNum = shopDao.updateShop(shop);
                    if(effectedNum <=0) {
                        throw new  ShopOperationException("更新圖片地址失敗");
                    }

                }
            }
        }catch (Exception e) {
            // TODO: handle exception
            throw new ShopOperationException("addShop error:"+e.getMessage());
        }
        return new ShopExecution(ShopStateEnum.CHECK,shop);
    }
    private void addShopImg(Shop shop, File shopImg) {
        // 獲取shop圖片目錄的相對值路徑
                String dest = PathUtil.getShopImagePath(shop.getShopId());
                String shopImgAddr = ImageUtil.generateThumbnail(shopImg,dest);
                shop.setShopImg(shopImgAddr);
    }
}

src/test/java/com.imooc.o2o.service目錄下創建ShopServiceTest.java文件

public class ShopServiceTest extends BaseTest{

    @Autowired
    private ShopService shopService;

    @Test
    public void testAddShop() {
        Shop shop = new Shop();
        PersonInfo owner = new PersonInfo();
        Area area = new Area();
        ShopCategory shopCategory = new ShopCategory();
        owner.setUserId(1L);
        area.setAreaId(2);
        shopCategory.setShopCategoryId(1L);
        shop.setOwner(owner);
        shop.setArea(area);
        shop.setShopCategory(shopCategory);
        shop.setShopName("測試的店鋪1");
        shop.setShopDesc("test1");
        shop.setShopAddr("test1");
        shop.setPhone("test1");
        shop.setCreateTime(new Date());
        shop.setEnableStatus(ShopStateEnum.CHECK.getState());
        shop.setAdvice("審覈中");
        File shopImg = new File("/Users/mac/Downloads/luoto.png");
        ShopExecution se = shopService.addShop(shop, shopImg);
        assertEquals(ShopStateEnum.CHECK.getState(), se.getState());
    }
}

Controller層的實現

util/HttpServletRequestUtil


public class HttpServletRequestUtil {
    public static int getInt(HttpServletRequest request,String name){
        try {
            /*decode適合用來分析數字
             8進:010=>分析後爲 8 10進:10=>分析後爲 10 16進:#10|0X10|0x10=>分析後是 16
             而valueof    只能分析純數字的String
             像 010 這樣的8進制 他會解析成 =>10
             parseInt(s,int radix)
             若想獲得Integer:
             String 爲十進制. 採用valueof(String)合適. 非十進制,採用decode(String)
              想要獲得int
              String 爲十進制. 採用parseInt(String )合適. 非十進制,採用parseInt(String ,int)
            */
            return Integer.decode(request.getParameter(name));
        } catch (NumberFormatException e) {
            return -1;
        }
    }

    public static long getLong(HttpServletRequest request, String name){
        try {
            return Long.valueOf(request.getParameter(name));
        } catch (NumberFormatException e) {

            return -1;
        }
    }

    public static Double getDouble(HttpServletRequest request,String name){
        try {
            return Double.valueOf(request.getParameter(name));
        } catch (NumberFormatException e) {
            return -1d;
        }
    }

    public static Boolean getBoolean(HttpServletRequest request,String name){
        try {
            return Boolean.valueOf(request.getParameter(name));
        } catch (Exception e) {
            return false;
        }
    }

    public static String getString(HttpServletRequest request,String name){
        try {
            String result = request.getParameter(name);
            if (result!=null){
                result =result.trim();
            }
            if ("".equals(result)){
                result =null;
            }
            return result;
        } catch (Exception e) {
            return null;
        }
    }

}


ShopManagementController.java

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

    @RequestMapping(value = "/registershop", method = RequestMethod.POST)
    @ResponseBody
    private Map<String, Object> listShop(HttpServletRequest request) {
        Map<String, Object> modelMap = new HashMap<String, Object>();

        //1.接受並轉化相關的參數,包括店鋪信息以及圖片信息
        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());
        }
        //接受圖片信息
        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;
        }
        //2.註冊店鋪
        if(shop!=null&&shopImg!=null){
            PersonInfo owner = new PersonInfo();
            owner.setUserId(1L);
            shop.setOwner(owner);
            File shopImgFile =
                    new File(PathUtil.getImgBasePath()+ ImageUtil.getRandomFileName());
            try {
                shopImgFile.createNewFile();
            } catch (IOException e) {
                modelMap.put("success",false);
                modelMap.put("errMsg",e.getMessage());
                e.printStackTrace();
            }
            try {
                inputStreamToFile(shopImg.getInputStream(),shopImgFile);
            } catch (IOException e) {
                modelMap.put("success",false);
                modelMap.put("errMsg",e.getMessage());
                e.printStackTrace();
            }
            ShopExecution se = shopService.addShop(shop,shopImgFile);
            if(se.getState()== ShopStateEnum.CHECK.getState()){
                modelMap.put("success",true);
            }else {
                modelMap.put("success",false);
                modelMap.put("errMsg",se.getStateInfo());
            }
            return modelMap;
        }else {
            modelMap.put("success",false);
            modelMap.put("errMsg","請輸入店鋪信息");
            return modelMap;
        }

    }

    private static void inputStreamToFile(InputStream ins, File file){
        FileOutputStream os= null;
        try {
            os=new FileOutputStream(file);
            int bytesRead=0;
            byte[] buffer = new byte[1024];
            while ((bytesRead=ins.read(buffer))!=-1){
                os.write(buffer,0,bytesRead);
            }
        } catch (IOException e) {
            throw new RuntimeException("調用inputStreamToFile產生異常"+e.getMessage());
        }finally {
            try {
                if(os!=null){
                    os.close();
                }
                if(ins!=null){
                    ins.close();
                }
            } catch (IOException e) {
                throw new RuntimeException("調用inputStreamToFile關閉io產生異常"+e.getMessage());
            }
        }
    }

}

Controller層的改造

ShopManagementController

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

    @RequestMapping(value = "/registershop", method = RequestMethod.POST)
    @ResponseBody
    private Map<String, Object> listShop(HttpServletRequest request) {
        Map<String, Object> modelMap = new HashMap<String, Object>();

        //1.接受並轉化相關的參數,包括店鋪信息以及圖片信息
        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());
        }
        //接受圖片信息
        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;
        }
        //2.註冊店鋪
        if(shop!=null&&shopImg!=null){
            PersonInfo owner = new PersonInfo();
            //Session TODO
            owner.setUserId(1L);
            shop.setOwner(owner);
            ShopExecution se = null;
            try {
                se = shopService.addShop(shop,
                        shopImg.getInputStream(),shopImg.getOriginalFilename());
                if(se.getState()== ShopStateEnum.CHECK.getState()){
                    modelMap.put("success",true);
                }else {
                    modelMap.put("success",false);
                    modelMap.put("errMsg",se.getStateInfo());
                }
            } catch (IOException e) {
                modelMap.put("success",false);
                modelMap.put("errMsg",e.getMessage());
                e.printStackTrace();
            }

            return modelMap;
        }else {
            modelMap.put("success",false);
            modelMap.put("errMsg","請輸入店鋪信息");
            return modelMap;
        }

    }

}

更改shopService


public interface ShopService {
    public ShopExecution addShop(Shop shop, InputStream shopImgInputStream,
                                 String fieName);
}

更改shopServiceImpl

@Service
public class ShopServiceImpl implements ShopService {
    @Autowired
    private ShopDao shopDao;

    @Transactional //需要事務支持
    public ShopExecution addShop(Shop shop, InputStream shopImgInputStream,
                                 String fileName){
        //空值判斷
        if(shop == null){
            return new ShopExecution(ShopStateEnum.NULL_SHOP);
        }
        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(shopImgInputStream !=null) {
                    //存儲圖片
                    try {
                        addShopImg(shop, shopImgInputStream,fileName);
                    }catch (Exception e) {
                        // TODO: handle exception
                        throw new ShopOperationException("addShopImg error"+e.getMessage());
                    }
                    //更新店鋪的圖片地址
                    effectedNum = shopDao.updateShop(shop);
                    if(effectedNum <=0) {
                        throw new ShopOperationException("更新圖片地址失敗");
                    }

                }
            }
        }catch (Exception e) {
            // TODO: handle exception
            throw new ShopOperationException("addShop error:"+e.getMessage());
        }
        return new ShopExecution(ShopStateEnum.CHECK,shop);
    }

    private void addShopImg(Shop shop, InputStream shopImgInputStream,
                            String fileName) {
        // 獲取shop圖片目錄的相對值路徑
        String dest = PathUtil.getShopImagePath(shop.getShopId());
        String shopImgAddr = ImageUtil.generateThumbnail(shopImgInputStream,
                fileName,dest);
        shop.setShopImg(shopImgAddr);
    }

}

更改ImageUtil.java

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();

    /**
     * 處理縮略圖,並返回新生成圖片的相對值路徑
     */
    public static String generateThumbnail(InputStream thumbnailInputStream,
                                           String fileName,
                                           String targetAddr) {
        //隨機文件名,當前年月日小時分鐘秒+五位隨機數
        String realFileName = getRandomFileName();
        //文件的擴展名
        String extension = getFileExtension(fileName);
        //創建目標路徑所涉及到的目錄
        makeDirPath(targetAddr);
        String relativeAddr = targetAddr + realFileName + extension;
        File dest = new File(PathUtil.getImgBasePath() + relativeAddr);
        //給縮略圖上水印
        try {
            Thumbnails.of(thumbnailInputStream).size(200, 200)
                    .watermark(Positions.BOTTOM_RIGHT,
                            ImageIO.read(new File(basePath + "cat.jpg")),
                            0.25f)
                    .outputQuality(0.8f).toFile(dest);
        } catch (IOException e) {
            // TODO: handle exception
            e.printStackTrace();
        }
        //返回圖片存儲路徑
        return relativeAddr;
    }

    /**
     * 創建目標路徑所涉及到的目錄,即/home/work/o2o/xxx.jpg,
     * 那麼 home work o2o 這三個文件夾都得自動創建
     *
     * @param targetAddr
     */
    private static void makeDirPath(String targetAddr) {
        // TODO Auto-generated method stub
        String realFileParentPath = PathUtil.getImgBasePath() + targetAddr;
        File dirPath = new File(realFileParentPath);
        if (!dirPath.exists()) {
            dirPath.mkdirs();
        }
    }


    /**
     * 生成隨機文件名,當前年月日小時分鐘秒+五位隨機數
     */
    public static String getRandomFileName() {
        //獲取隨機的五位數
        int rannum = r.nextInt(89999) + 10000;
        String nowTimeStr = sDateFormat.format(new Date());
        return nowTimeStr + rannum;
    }

    /**
     * 獲取輸入文件流的擴展名
     */
    private static String getFileExtension(String fileName) {

        return fileName.substring(fileName.lastIndexOf("."));
    }
}

前端設計

使用SUI Mobile

官網地址:https://sui.ctolog.com/

使用模板改造shopoperation.html

<!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">
</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="shop-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="shop-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">
                            <select id="area">
                            </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="text" id="shop-addr"
                                   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="tel" id="shop-phone"
                                   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="shop-img" 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">
                            <textarea placeholder="店鋪簡介"
                                      id="shop-desc"></textarea>
                        </div>
                    </div>
                </div>
            </li>
        </ul>
    </div>
    <div class="content-block">
        <div class="row">
            <div class="col-50">
                <a href="/myo2o/shop/shopmanage"
                   class="button button-big button-fill button-danger">返回</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.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/shopoperation.js"></script>
</body>
</html>

店鋪註冊之js實現

resources/js/shop/shopoperation.js

$(function () {
    var initUrl='/o2o/shopadmin/getshopinitinfo';
    //註冊店鋪
    var regidterShopUrl ='/o2o/shopadmin/registershop';
    alert(initUrl);
    //調用getShopInitInfo
    getShopInitInfo();
    function getShopInitInfo() {
        $.getJSON(initUrl,function (data) {
            if(date.success){
                var tempHtml="";
                //獲取區域信息
                var tempAreaHtml="";
                //後臺獲取的店鋪分類列表,遍歷
                data.shopCategoryList.map(function (item,index) {
                    tempHtml+='<option data-id="'+item.shopCategoryId+'">'+item.shopCategoryName+'</option>'
                });
                //區域信息
                data.areaList.map(function (item,index) {
                    tempAreaHtml+='<option data-id="'+item.areaId+'">'+item.areaName+'</option>';
                });
                $('#shop-category').html(tempHtml);
                $('#area').html(tempAreaHtml);

            }
        });
        //點擊提交後的響應
        $('#submit').click(function () {
            var shop ={};
            //從控件中獲取信息
            shop.shopName=$('#shop-name').val();
            shop.shopAddr=$('#shop-addr').val();
            shop.phone=$('#shop-phone').val();
            shop.shopDesc=$('#shop-desc').val();
            //獲取列表中的數據
            shop.shopCategory={
                shopCategoryId:$('#shop-category').find('option').not(function(){
                    return !this.selected;
                }).data('id')
            };
            shop.area = {
                areaId:$('#area').find('option').not(function () {
                    return !this.selected;
                }).data('id')
            };
            var shopImg =$('#shop-img')[0].files[0];
            var formData = new FormData();
            formData.append('shopImg',shopImg);
            formData.append('shopStr',JSON.stringify(shop));
            $.ajax({
               url:regidterShopUrl,
               type:'POST',
               data:formData,
               contentType:false,
               proceesData:false,
               cache:false,
               success:function (data) {
                    if(data.success){
                        $.toast('提交成功');
                    }else{
                        $.toast('提交失敗'+data.errMsg);
                    }
               }
            });
        });
    }
})

店鋪類別區域信息的獲取

shopCategoryDao

public interface ShopCategoryDao {
    List<ShopCategory> queryShopCategory(@Param("shopCategoryCondition") ShopCategory shopCategoryCondition);
}

shopCategoryDao.xml

<?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.imooc.o2o.dao.ShopCategoryDao">
    <select id="queryShopCategory"
            resultType="com.imooc.o2o.entity.ShopCategory">
        select
        shop_category_id,
        shop_category_name,
        shop_category_desc,
        shop_category_img,
        priority,
		create_time,
		last_edit_time,
		parent_id
		FROM
		tb_shop_category
		<where>
            <if test="shopCategoryCondition!=null">
                and parent_id is not null
            </if>
            <if test="shopCategoryCondition.parent!=null">
                and parent_id = #{shopCategoryCondition.parent.shopCategoryId}
            </if>
        </where>
        order by
        priority desc
    </select>
</mapper>

測試

package com.imooc.o2o.dao;

import com.imooc.o2o.BaseTest;
import com.imooc.o2o.entity.ShopCategory;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;

import static org.junit.Assert.*;

public class ShopCategoryDaoTest extends BaseTest {

    @Autowired
    private ShopCategoryDao shopCategoryDao;

    @Test
    public void queryShopCategory() {
        List<ShopCategory> shopCategoryList=
                shopCategoryDao.queryShopCategory(new ShopCategory());
        assertEquals(2,shopCategoryList.size());
        ShopCategory testCategory = new ShopCategory();
        ShopCategory parentCategory = new ShopCategory();
        parentCategory.setShopCategoryId(1L);
        testCategory.setParent(parentCategory);
        shopCategoryList = shopCategoryDao.queryShopCategory(testCategory);
        assertEquals(1,shopCategoryList.size());
        System.out.println(shopCategoryList.get(0).getShopCategoryName());
    }
}

ShopCategoryService 

package com.imooc.o2o.service;

import com.imooc.o2o.entity.ShopCategory;

import java.io.IOException;
import java.util.List;

public interface ShopCategoryService {
    List<ShopCategory> getShopCategoryList(ShopCategory shopCategoryCondition) throws IOException;
}

ShopCategoryServiceImpl

package com.imooc.o2o.service.impl;

import com.imooc.o2o.dao.ShopCategoryDao;
import com.imooc.o2o.entity.ShopCategory;
import com.imooc.o2o.service.ShopCategoryService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.List;

@Service
public class ShopCategoryServiceImpl implements ShopCategoryService {

    @Autowired
    private ShopCategoryDao shopCategoryDao;

    @Override
    public List<ShopCategory> getShopCategoryList(ShopCategory shopCategoryCondition) throws IOException {
        return shopCategoryDao.queryShopCategory(shopCategoryCondition);
    }
}

在ShopManagementController中加入getShopInitInfo()

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

    @Autowired
    private ShopCategoryService shopCategoryService;

    @Autowired
    private AreaService areaService;

    @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 (IOException e) {
            modelMap.put("success",false);
            modelMap.put("errMsg",e.getMessage());
        }
        return modelMap;
    }
    ...
}

運行

引入kaptcha實現驗證碼

在pom中加入

    <dependency>
      <groupId>com.github.penggle</groupId>
      <artifactId>kaptcha</artifactId>
      <version>2.3.2</version>
    </dependency>

在web.xml中加入

	<servlet>
		<!-- 生成圖片的Servlet -->
		<servlet-name>Kaptcha</servlet-name>
		<servlet-class>com.google.code.kaptcha.servlet.KaptchaServlet</servlet-class>

		<!-- 是否有邊框 -->
		<init-param>
			<param-name>kaptcha.border</param-name>
			<param-value>no</param-value>
		</init-param>
		<!-- 字體顏色 -->
		<init-param>
			<param-name>kaptcha.textproducer.font.color</param-name>
			<param-value>red</param-value>
		</init-param>
		<!-- 圖片寬度 -->
		<init-param>
			<param-name>kaptcha.image.width</param-name>
			<param-value>135</param-value>
		</init-param>
		<!-- 使用哪些字符生成驗證碼 -->
		<init-param>
			<param-name>kaptcha.textproducer.char.string</param-name>
			<param-value>ACDEFHKPRSTWX345679</param-value>
		</init-param>
		<!-- 圖片高度 -->
		<init-param>
			<param-name>kaptcha.image.height</param-name>
			<param-value>50</param-value>
		</init-param>
		<!-- 字體大小 -->
		<init-param>
			<param-name>kaptcha.textproducer.font.size</param-name>
			<param-value>43</param-value>
		</init-param>
		<!-- 干擾線的顏色 -->
		<init-param>
			<param-name>kaptcha.noise.color</param-name>
			<param-value>black</param-value>
		</init-param>
		<!-- 字符個數 -->
		<init-param>
			<param-name>kaptcha.textproducer.char.length</param-name>
			<param-value>4</param-value>
		</init-param>
		<!-- 使用哪些字體 -->
		<init-param>
			<param-name>kaptcha.textproducer.font.names</param-name>
			<param-value>Arial</param-value>
		</init-param>
	</servlet>
	<!-- 映射的url -->
	<servlet-mapping>
		<servlet-name>Kaptcha</servlet-name>
		<url-pattern>/Kaptcha</url-pattern>
	</servlet-mapping>

引入驗證碼到html

            <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="點擊更換"
                                 οnclick="changeVerifyCode(this)" src="../Kaptcha" />
                        </div>
                    </div>
                </div>
            </li>

實現changeVerifyCode

在resources/js/common中創建commonutil.js

function changeVerifyCode(img) {
    img.src="../Kaptcha?"+Math.floor(Math.random()*100);
}

並在HTML引入

<script type='text/javascript'
        src='../resources/js/common/commonutil.js' charset='utf-8'></script>

shopoperation.js

$(function () {
    var initUrl='/shopadmin/getshopinitinfo';
    //註冊店鋪
    var regidterShopUrl ='/shopadmin/registershop';
    //調用getShopInitInfo
    getShopInitInfo();
    function getShopInitInfo() {
        $.getJSON(initUrl,function (data) {
            if(data.success){
                var tempHtml="";
                //獲取區域信息
                var tempAreaHtml="";
                //後臺獲取的店鋪分類列表,遍歷
                data.shopCategoryList.map(function (item,index) {
                    tempHtml+='<option data-id="'+item.shopCategoryId+'">'+item.shopCategoryName+'</option>'
                });
                //區域信息
                data.areaList.map(function (item,index) {
                    tempAreaHtml+='<option data-id="'+item.areaId+'">'+item.areaName+'</option>';
                });
                $('#shop-category').html(tempHtml);
                $('#area').html(tempAreaHtml);

            }
        });
        //點擊提交後的響應
        $('#submit').click(function () {
            var shop ={};
            //從控件中獲取信息
            shop.shopName=$('#shop-name').val();
            shop.shopAddr=$('#shop-addr').val();
            shop.phone=$('#shop-phone').val();
            shop.shopDesc=$('#shop-desc').val();
            //獲取列表中的數據
            shop.shopCategory={
                shopCategoryId:$('#shop-category').find('option').not(function(){
                    return !this.selected;
                }).data('id')
            };
            shop.area = {
                areaId:$('#area').find('option').not(function () {
                    return !this.selected;
                }).data('id')
            };
            var shopImg =$('#shop-img')[0].files[0];
            var formData = new FormData();
            formData.append('shopImg',shopImg);
            formData.append('shopStr',JSON.stringify(shop));
            var verifyCodeActual=$('#j_captcha').val();
            if(!verifyCodeActual){
                $.toast('請輸入驗證碼!');
                return;
            }
            formData.append('verifyCodeActual',verifyCodeActual);
            $.ajax({
               url:regidterShopUrl,
               type:'POST',
               data:formData,
               contentType:false,
               proceesData:false,
               cache:false,
               success:function (data) {
                    if(data.success){
                        $.toast('提交成功');
                    }else{
                        $.toast('提交失敗'+data.errMsg);
                    }
                    $('#captcha_img').click();
               }
            });
        });
    }
})

在util中創建CodeUtil.java

package com.imooc.o2o.util;

import com.google.code.kaptcha.Constants;

import javax.servlet.http.HttpServletRequest;

public class CodeUtil {
    public static boolean checkVerifyCode(HttpServletRequest request){
        String verifyCodeExpected =
                (String)request.getSession().getAttribute(Constants.KAPTCHA_SESSION_KEY);
        String verifyCodeActual= HttpServletRequestUtil.getString(request,
                "verifyCodeActual");
        if(verifyCodeActual==null||!verifyCodeActual.equals(verifyCodeExpected)){
            return false;
        }
        return true;
    }
}

shopManagementController.java中驗證驗證碼

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

    @RequestMapping(value = "/registershop", method = RequestMethod.POST)
    @ResponseBody
    private Map<String, Object> listShop(HttpServletRequest request) {
        Map<String, Object> modelMap = new HashMap<String, Object>();
        //驗證碼
        if(!CodeUtil.checkVerifyCode(request)){
            modelMap.put("success",false);
            modelMap.put("errMsg","輸入了錯誤的驗證碼");
            return modelMap;
        }
        //1.接受並轉化相關的參數,包括店鋪信息以及圖片信息
        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());
        }
        //接受圖片信息
        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;
        }
        //2.註冊店鋪
        if(shop!=null&&shopImg!=null){
            PersonInfo owner = new PersonInfo();
            //Session TODO
            owner.setUserId(1L);
            shop.setOwner(owner);
            ShopExecution se = null;
            try {
                se = shopService.addShop(shop,
                        shopImg.getInputStream(),shopImg.getOriginalFilename());
                if(se.getState()== ShopStateEnum.CHECK.getState()){
                    modelMap.put("success",true);
                }else {
                    modelMap.put("success",false);
                    modelMap.put("errMsg",se.getStateInfo());
                }
            } catch (IOException e) {
                modelMap.put("success",false);
                modelMap.put("errMsg",e.getMessage());
                e.printStackTrace();
            }

            return modelMap;
        }else {
            modelMap.put("success",false);
            modelMap.put("errMsg","請輸入店鋪信息");
            return modelMap;
        }

    }


}

前後端聯調驗證整體模塊功能

按F10一步一步調試

spring-web.xml加入

    <!-- 文件上傳解析器 -->
    <bean id="multipartResolver"
          class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="defaultEncoding" value="utf-8"></property>
        <!--1024x1024x20   20M-->
        <property name="maxUploadSize" value="10485760000"></property><!-- 最大上傳文件大小 -->
        <property name="maxInMemorySize" value="10960"></property>
    </bean>

pom.xml

引入文件上傳的jar包

    <dependency>
      <groupId>commons-fileupload</groupId>
      <artifactId>commons-fileupload</artifactId>
      <version>1.3.2</version>
    </dependency>

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章