Java Web商城開發--從DAO層到前端頁面實現店鋪註冊功能

之前已經創建了商店的數據表tb_shop和對應的實體類Shop:https://blog.csdn.net/theVicTory/article/details/105739461
那麼如何將商店信息傳遞到前端展示頁面,並且前端的用戶操作又作用於數據呢?
數據在Spring中的流動如下

數據庫
DAO層
DTO層
Service層
Controller層
前端頁面

DAO層

首先實現Shop對象的DAO層,DAO(Data Access Object)主要用來封裝對數據庫的訪問操作。由於使用Mybatis,所以在ShopDao類中只需要定義DAO接口,具體的數據庫操作在mapper文件ShopCategory.xml中實現,如下所示定義了Shop類的新增、更改、查詢操作的接口。在定義接口時將Shop對象作爲參數傳入,其屬性名可以在mapper文件中通過#{}的方式獲取到。如果需要傳入多個參數,要使用註解@Param("pageSize"),在使用#{pageSize}獲得參數。

public interface ShopDao {
    //新增店鋪
    int insertShop(Shop shop);

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

    //根據Id查詢指定店鋪
    Shop queryShopById(int shopId);

    //根據條件查詢店鋪列表
    List<Shop> queryShop(@Param("conditionShop") Shop conditionShop,
                         @Param("offset") int offset, @Param("pageSize") int pageSize);
}

mapper文件定義如下,首先在<mapper>標籤的namespace屬性中指明mapper文件所對應的Dao接口類爲ShopDao。

接着定義數據庫返回結果和Shop對象之間的映射<resultMap>,它定義了數據庫的字段如何映射爲Shop對象。主鍵字段用<id>標籤,普通字段用<result>property屬性代表類屬性,column代表數據庫中的字段。值得注意的是,如果數據庫字段是一個連接到其他對象的外鍵,例如通過外鍵area_id連接到另一張表,那麼可以通過<association>將類屬性area映射爲一個Area對象,並從外鍵連接的表中取出數據填充對象屬性areaId和areaName。

接着實現在接口中定義的insertShop、updateShop、queryShopById、queryShop方法,parameterType爲傳入參數的類型,resultMap爲返回結果的類型,如果返回多組結果Mybatis會自動轉爲List。在queryShop中根據傳入的conditionShop對象來匹配符合條件的結果,通過<where>標籤將Sql條件語句包裹起來,在其中首先通過<if>判斷conditionShop中的條件是否爲空,若不爲空,則用AND將查詢語句拼接起來。最後使用ORDER BY進行排序,LIMIT返回指定偏移和個數的數據。

<?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.tory.shop.dao.ShopDao">
    <resultMap id="shopMap" type="com.tory.shop.entity.Shop">
        <id property="shopId" column="shop_id"/>
        <result property="shopName" column="shop_name"/>
        <result property="shopAddr" column="shop_addr"/>
        <result property="shopDescribe" column="shop_describe"/>
        <result property="shopPhone" column="shop_phone"/>
        <result property="shopImg" column="shop_img"/>
        <result property="enableStatus" column="enable_status"/>
        <result property="priority" column="priority"/>
        <result property="createTime" column="create_time"/>
        <result property="lastEditTime" column="last_edit_time"/>
        <result property="adviceMessage" column="advice_message"/>
        <association property="area" column="area_id" javaType="com.tory.shop.entity.Area">
            <id property="areaId" column="area_id"/>
            <result property="areaName" column="area_name"/>
        </association>
        <association property="shopCategory" column="shop_category" javaType="com.tory.shop.entity.ShopCategory">
            <id property="categoryId" column="category_id"/>
            <result property="categoryName" column="category_name"/>
        </association>
        <association property="owner" column="owner_id" javaType="com.tory.shop.entity.PersonInfo">
            <id property="userId" column="user_id"/>
            <result property="name" column="name"/>
        </association>
    </resultMap>

    <insert id="insertShop" useGeneratedKeys="true" keyColumn="shop_id" keyProperty="shopId">
        INSERT INTO tb_shop
        (owner_id, area_id, shop_category,
         shop_name, shop_describe, shop_addr, shop_phone, shop_img,
         create_time, last_edit_time, enable_status, advice_message)
        VALUES (#{owner.userId}, #{area.areaId}, #{shopCategory.categoryId},
                #{shopName}, #{shopDescribe}, #{shopAddr}, #{shopPhone}, #{shopImg},
                #{createTime}, #{lastEditTime}, #{enableStatus}, #{adviceMessage})
    </insert>

    <update id="updateShop" parameterType="com.tory.shop.entity.Shop">
        UPDATE tb_shop
        <set>
            <if test="shopName != null">shop_name=#{shopName},</if>
            <if test="shopDescribe != null">shop_describe=#{shopDescribe},</if>
            <if test="shopAddr != null">shop_addr=#{shopAddr},</if>
            <if test="shopPhone != null">shop_phone=#{shopPhone},</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="adviceMessage != null">advice_message=#{adviceMessage},</if>
            <if test="area != null">area_id=#{area.areaId},</if>
            <if test="shopCategory != null">shop_category=#{shopCategory.categoryId},</if>
        </set>
        WHERE shop_id=#{shopId}
    </update>

    <select id="queryShopById" resultMap="shopMap" parameterType="int">
        SELECT s.shop_id,s.shop_name,s.shop_describe,s.advice_message,s.shop_addr,s.shop_phone,
               s.shop_img,s.priority,s.create_time,s.last_edit_time,s.enable_status,
               a.area_id,a.area_name,c.category_id,c.category_name
        FROM tb_shop s,tb_area a,tb_shop_category c
        WHERE shop_id = #{_parameter}
          AND s.area_id = a.area_id
          AND s.shop_category = c.category_id
    </select>

    <select id="queryShop" resultMap="shopMap">
        SELECT
        s.shop_id,s.shop_name,s.shop_describe,s.advice_message,s.
        shop_addr,s.shop_phone,s.shop_img,s.priority,s.create_time,s.last_edit_time,s.enable_status,
        a.area_id,a.area_name,c.category_id,c.category_name
        FROM
        tb_shop s,tb_area a,tb_shop_category c
        <where>
            <if test="conditionShop.shopCategory!=null and conditionShop.shopCategory.categoryId!=null">
                AND s.shop_category=#{conditionShop.shopCategory.categoryId}
            </if>
            <if test="conditionShop.area!=null and conditionShop.area.areaId!=null">
                AND s.area_id=#{conditionshop.area.areaId}
            </if>
            <if test="conditionShop.shopName!=null">
                AND s.shop_name like '% ${conditionShop.shopName} %'
            </if>
            <if test="conditionShop.enableStatus !=null">
                AND s.enable_status=#{conditionShop.enableStatus}
            </if>
            <if test="conditionShop.owner!=null and conditionShop.owner.userId !=null">
                AND s.owner_id=#{conditionShop.owner.userId}
            </if>
            AND s.area_id=a.area_id AND s.shop_category=c.category_id
        </where>
        ORDER BY s.priority DESC
        LIMIT #{offset},#{pageSize}
    </select>
</mapper>

DTO層

Data Transfer Object數據傳輸對象,該層負責屏蔽後端的實體層,用於將DAO取到的數據進行再次處理加工後返回給Service層。在實際的業務場景下,後端存儲的數據遠比用戶需要的數據要龐大和複雜,因此需要進行處理、組合之後再返回。

如下所示爲Shop的DTO類,在其中保存商鋪操作結果狀態及信息,以及返回的Shop對象。

public class ShopExecution {
    private int state;              //結果狀態
    private String stateInfo;       //結果信息
    private Shop shop;              //操作的商鋪
    private int shopCount;          //返回商鋪的數量
    private List<Shop> shopList;    //返回的商鋪列表

    //執行失敗時的構造器,只有狀態枚舉作爲參數
    public ShopExecution(ShopStateEnum stateEnum){
        this.state=stateEnum.getState();
        this.stateInfo=stateEnum.getStateInfo();
    }
    //執行增刪改成功時的構造器,傳入狀態枚舉和Shop對象
    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;
    }
    ......getter/setter

其中用枚舉類型來儲存結果狀態,如下所示爲枚舉類ShopStateEnum的定義

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;

    //枚舉類的構造函數
    ShopStateEnum(int state, String stateInfo) {
        this.state=state;
        this.stateInfo=stateInfo;
    }

    //根據狀態值返回狀態枚舉對象
    public static ShopStateEnum stateOf(int index){
        for (ShopStateEnum state : values()){
            if (state.getState()==index)
                return state;
        }
        return null;
    }
    ......getter/setter

Service層

在Service層,首先在接口中定義了添加、更新、查詢商店的四個方法

public interface ShopService {
    //添加商店
    ShopExecution addShop(Shop shop, CommonsMultipartFile shopImg);
    //更新商店
    ShopExecution updateShop(Shop shop, CommonsMultipartFile shopImg);
    //根據id查詢商店
    Shop getShopById(int shopId);
    //根據條件查詢商店列表
    ShopExecution getShopList(Shop conditionShop,int pageIndex,int pageSize);
}

接着實現service層。首先實現店鋪添加的操作addShop(),該方法傳入shop對象和shopImg圖片,首先進行判空操作,若shop對象爲空,則返回插入失敗的ShopExecution對象。否則爲shop增加一些初始屬性後調用Dao層將店鋪信息存入數據庫。然後調用saveImg()方法將圖片保存到服務器並返回圖片地址,最後將圖片地址信息更新到shop對象的數據庫中。saveImg()中調用ImageUtil類進行的圖片操作,實現記錄在:https://blog.csdn.net/theVicTory/article/details/106007111

updateShop()用於更新店鋪,若傳入的shopImg不爲空,則更新圖片。接着調用shopDao的updateShop()方法更新shop對象的信息

在查詢商鋪列表的getShopList()方法中,首先根據傳入的pageIndexpageSize計算出所需數據在數據庫中的偏移量offset,然後傳入shopDao.queryShop()中得到Shop列表。若shopList不爲空,則將其傳入構造ShopExecution對象,否則構造錯誤的ShopExecution,最後將其返回。

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

    @Override
    public ShopExecution addShop(Shop shop, CommonsMultipartFile shopImg) {
        //如果傳入shop對象爲空,則返回失敗的ShopExecution
        if (shop==null)
            return new  ShopExecution(ShopStateEnum.NULL_SHOP_INFO);
        //爲shop設置一些初始值屬性
        shop.setEnableStatus(0);
        shop.setCreateTime(new Date());
        shop.setLastEditTime(new Date());
        //存入店鋪信息
        int affectedRows=shopDao.insertShop(shop);
        if (affectedRows<=0)
            throw new RuntimeException("插入數據庫失敗!");
        else {
            if (shopImg!=null){
                saveShopImg(shop,shopImg);
                //更新店鋪的圖片地址
                affectedRows= shopDao.updateShop(shop);
                if (affectedRows<=0)
                    throw new RuntimeException("更新數據庫失敗!");
            }
        }
        return new ShopExecution(ShopStateEnum.CHECK,shop);
    }

    @Override
    public ShopExecution updateShop(Shop shop, CommonsMultipartFile shopImg) {
        if (shop ==null)
            return new ShopExecution(ShopStateEnum.NULL_SHOP_INFO);
        //更新圖片
        if (shopImg!=null){
            String tempShopImg=shopDao.queryShopById(shop.getShopId()).getShopImg();
            if (tempShopImg !=null)     //如果原來Shop的圖片不爲空,則刪除
                FileUtil.deleteFile(tempShopImg);
            saveShopImg(shop,shopImg);
        }
        //更新Shop信息
        shop.setLastEditTime(new Date());
        int influenceNum=shopDao.updateShop(shop);
        if (influenceNum<=0)
            return new ShopExecution(ShopStateEnum.INNER_ERROR);
        else
            return new ShopExecution(ShopStateEnum.SUCCESS,shop);
    }

    @Override
    public Shop getShopById(int shopId) {
        return shopDao.queryShopById(shopId);
    }

    @Override
    public ShopExecution getShopList(Shop conditionShop, int pageIndex, int pageSize) {
        int offset=pageIndex>1?(pageIndex-1)*pageSize:0;        //根據頁碼計算在數據庫中對應的偏移量
        List<Shop> shopList=shopDao.queryShop(conditionShop,offset,pageSize);
        ShopExecution shopExecution;
        if (shopList!=null){
            shopExecution=new ShopExecution(ShopStateEnum.SUCCESS,shopList);
            shopExecution.setShopCount(shopList.size());
        }else {
            shopExecution=new ShopExecution(ShopStateEnum.INNER_ERROR);
        }
        return shopExecution;
    }

    public void saveShopImg(Shop shop, CommonsMultipartFile shopImg) {
        String imgPath= FileUtil.getShopImagePath(shop.getShopId());
        String shopImgAddr= ImageUtil.generateThumbnail(shopImg,imgPath);
        shop.setShopImg(shopImgAddr);
    }
}

Controller層

首先定義ShopRouteController類用於返回關於頁面的請求,這裏主要有三個頁面,比如getRegisterView()方法映射爲/ShopView下的/edit的GET請求,返回店鋪的註冊頁面。

@Controller
@RequestMapping("ShopView")
public class ShopRouteController {
    //店鋪註冊頁面
    @RequestMapping("edit")
    public String getRegisterView() {
        return "shop/shop-edit";
    }

    //返回店鋪列表頁面
    @RequestMapping("list")
    public String getShopListView() {
        return "shop/shop-list";
    }

    //店鋪管理頁面
    @RequestMapping("manage")
    public String getManageView() {
        return "shop/shop-manage";
    }
}

定義ShopManagementController類用於處理店鋪相關數據操作的請求。

getInitInfo()用於返回註冊頁面所需要的初始化信息–店鋪類別列表categoryList和區域列表areaList。這裏使用Map<String, Object>來儲存返回的數據,之後由於添加了@ResponseBody註解,返回的內容會被轉換爲JSON格式。

registerShop()方法映射爲/shop下的/register的POST請求,用於接收店鋪的信息並完成註冊。首先調用checkCode()方法比對驗證碼是否輸入正確。然後通過request.getParameter()取出shopStr,前端以JSON字符串的形式將Shop對象放在了字符串shopStr中,通過JSON的ObjectMapper.readValue()方法將其轉換爲Shop對象。接着提取POST請求中的圖片文件,首先將request轉換爲MultipartHttpServletRequest類型,然後調用getFile()獲取圖片對象shopImg。最後調用shopService儲存shop、shopImg對象,根據Service層返回的ShopExecution判斷儲存操作是否成功,若成功則設置modelMap中的success字段爲true,否則設爲false並將錯誤信息保存在errMsg字段中。最後將儲存結果信息的modelMap返回給客戶端。

initUpdateShop()方法用於返回店鋪信息,當用戶修改店鋪時,需要將店鋪原來的信息渲染到頁面,在初始化頁面時請求/shop/updateInit到達這個方法,通過request.getParameter()獲取到請求中的shopId,調用service層根據shopId查詢到shop對象的信息返回給客戶端。

updateShop()方法用於更新店鋪信息,和registerShop()類似,首先比對驗證碼,然後獲取到前端傳回的shop和shopImg對象,最後調用Service層進行保存操作,最後返回操作結果。

getShopList()方法用於根據條件查詢商店並返回結果列表,由於這裏沒有登錄,所以先手動將用戶信息存入session。然後從session中取出用戶user信息,以此作爲條件設置到conditionShop中,然後將其傳給service層的getShopList獲得查詢結果並返回給客戶端。

最後一個getCurrentShop()方法用於設置/獲取當前操作店鋪的shopId,如果請求中帶有shopId,則將其保存到session中,否則從session中查找是否有shopId,若也沒有,則未選擇店鋪,頁面跳轉到店鋪列表頁面。

package com.tory.shop.controller.shop;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.tory.shop.dto.ShopExecution;
import com.tory.shop.entity.Area;
import com.tory.shop.entity.PersonInfo;
import com.tory.shop.entity.Shop;
import com.tory.shop.entity.ShopCategory;
import com.tory.shop.enums.ShopStateEnum;
import com.tory.shop.service.AreaService;
import com.tory.shop.service.ShopCategoryService;
import com.tory.shop.service.ShopService;
import com.tory.shop.util.CodeUtil;
import com.tory.shop.util.RequestUtil;
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 javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Controller
@RequestMapping("shop")
public class ShopManagementController {
    @Autowired
    ShopService shopService;
    @Autowired
    ShopCategoryService shopCategoryService;
    @Autowired
    AreaService areaService;


    //返回註冊頁面的初始化信息
    @RequestMapping("init")
    @ResponseBody
    public Map<String, Object> getInitInfo() {
        Map<String, Object> modelMap = new HashMap<>();
        try {
            List<Area> areaList = areaService.getAreaList();
            List<ShopCategory> categoryList = shopCategoryService.getCategoryList(new ShopCategory());
            modelMap.put("categoryList", categoryList);
            modelMap.put("areaList", areaList);
            modelMap.put("success", true);
        } catch (Exception e) {
            modelMap.put("success", false);
            modelMap.put("errMsg", e.getMessage());
        }
        return modelMap;
    }

    //接收註冊店鋪的POST請求
    @RequestMapping(value = "register", method = RequestMethod.POST)
    @ResponseBody
    public Map<String, Object> registerShop(HttpServletRequest request) {
        Map<String, Object> modelMap = new HashMap<>();
        //校驗驗證碼是否正確
        if (!CodeUtil.checkCode(request)) {
            modelMap.put("success", false);
            modelMap.put("errMsg", "驗證碼錯誤");
            return modelMap;
        }
        //將前端傳回的json字符串的shop數據轉爲shop對象
        String shopStr = request.getParameter("shopStr");
        ObjectMapper jsonMapper = new ObjectMapper();
        Shop shop;
        try {
            shop = jsonMapper.readValue(shopStr, Shop.class);
        } catch (JsonProcessingException e) {
            modelMap.put("success", false);
            modelMap.put("errMsg", e.getMessage());
            return modelMap;
        }
        //接收前端傳回的圖片文件
        MultipartHttpServletRequest mRequest = (MultipartHttpServletRequest) request;
        CommonsMultipartFile shopImg = (CommonsMultipartFile) mRequest.getFile("shopImg");
        //存儲shop和shopImg對象
        if (shop != null && shopImg != null) {
            //從session中獲取用戶信息
            PersonInfo owner = (PersonInfo) request.getSession().getAttribute("user");
            shop.setOwner(owner);
            ShopExecution shopExecution = shopService.addShop(shop, shopImg);
            //如果存儲成功將"success"設爲true,否則設爲false並返回錯誤信息
            if (shopExecution.getState() == ShopStateEnum.CHECK.getState()) {
                modelMap.put("success", true);
                //將用戶對應的商店列表存入Session
                List<Shop> shopList = (List<Shop>) request.getSession().getAttribute("shopList");
                if (shopList == null)
                    shopList = new ArrayList<>();
                shopList.add(shopExecution.getShop());
                request.getSession().setAttribute("shopList", shopList);
            } else {
                modelMap.put("success", false);
                modelMap.put("errMsg", shopExecution.getStateInfo());
            }
        } else {
            modelMap.put("success", false);
            modelMap.put("errMsg", "店鋪信息不能爲空");
        }
        return modelMap;
    }

    //店鋪的初始化信息
    @RequestMapping(value = "updateInit", method = RequestMethod.GET)
    @ResponseBody
    public Map<String, Object> initUpdateShop(HttpServletRequest request) {
        Map<String, Object> modelMap = new HashMap<>();
        int shopId = Integer.parseInt(request.getParameter("shopId"));
        if (shopId > 0) {
            //根據shopId查詢shop信息
            Shop shop = shopService.getShopById(shopId);
            modelMap.put("shop", shop);
            List areaList = areaService.getAreaList();
            modelMap.put("areaList", areaList);
            modelMap.put("success", true);
        } else {
            modelMap.put("success", false);
            modelMap.put("errMsg", "shopId is null");
        }
        return modelMap;
    }

    //修改店鋪信息
    @RequestMapping(value = "update", method = RequestMethod.POST)
    @ResponseBody
    public Map<String, Object> updateShop(HttpServletRequest request) {
        Map<String, Object> modelMap = new HashMap<>();
        //校驗驗證碼是否正確
        if (!CodeUtil.checkCode(request)) {
            modelMap.put("success", false);
            modelMap.put("errMsg", "驗證碼錯誤");
            return modelMap;
        }
        //將前端傳回的json字符串的shop數據轉爲shop對象
        String shopStr = request.getParameter("shopStr");
        ObjectMapper jsonMapper = new ObjectMapper();
        Shop shop;
        try {
            shop = jsonMapper.readValue(shopStr, Shop.class);
        } catch (JsonProcessingException e) {
            modelMap.put("success", false);
            modelMap.put("errMsg", e.getMessage());
            return modelMap;
        }
        //接收前端傳回的圖片文件
        MultipartHttpServletRequest mRequest = (MultipartHttpServletRequest) request;
        CommonsMultipartFile shopImg = (CommonsMultipartFile) mRequest.getFile("shopImg");
        //更新shop和shopImg對象
        if (shop.getShopId() != null) {
            ShopExecution shopExecution = shopService.updateShop(shop, shopImg);
            //如果存儲成功將"success"設爲true,否則設爲false並返回錯誤信息
            if (shopExecution.getState() == ShopStateEnum.SUCCESS.getState())
                modelMap.put("success", true);
            else {
                modelMap.put("success", false);
                modelMap.put("errMsg", shopExecution.getStateInfo());
            }
        } else {
            modelMap.put("success", false);
            modelMap.put("errMsg", "未找到店鋪Id");
        }
        return modelMap;
    }

    //按條件查詢店鋪列表
    @RequestMapping(value = "getList", method = RequestMethod.GET)
    @ResponseBody
    public Map<String, Object> getShopList(HttpServletRequest request) {
        Map<String, Object> modelMap = new HashMap<>();
        //手動設置用戶session
        PersonInfo user = new PersonInfo();
        user.setUserId(1);
        request.getSession().setAttribute("user", user);
        //從session中獲取用戶信息
        user = (PersonInfo) request.getSession().getAttribute("user");
        Shop conditionShop = new Shop();
        conditionShop.setOwner(user);

        //調用Service層按conditionShop條件進行查詢
        ShopExecution shopExecution = shopService.getShopList(conditionShop, 1, 10);
        if (shopExecution.getState() == ShopStateEnum.SUCCESS.getState()) {
            modelMap.put("shopList", shopExecution.getShopList());
            modelMap.put("user", user);
            modelMap.put("success", true);
        } else {
            modelMap.put("success", false);
            modelMap.put("errMsg", shopExecution.getStateInfo());
        }
        return modelMap;
    }

    //獲取當前shop
    @RequestMapping("getCurrentShop")
    @ResponseBody
    public Map<String, Object> getCurrentShop(HttpServletRequest request) {
        Map<String, Object> modelMap = new HashMap<>();
        int shopId = RequestUtil.getInt(request, "shopId");
        if (shopId < 0) {      //如果請求中沒有shopId參數,則從session中查找
            Shop currentShop = (Shop) request.getSession().getAttribute("currentShop");
            if (currentShop == null) {     //如果session中也沒有,則重定向到商店列表頁面
                modelMap.put("redirect", true);
                modelMap.put("url", "/ShopDemo/ShopView/list");
            } else {
                modelMap.put("redirect", false);
                modelMap.put("shopId", currentShop.getShopId());
            }
        } else {	//若請求中帶有shopId,將其保存到session中
            Shop currentShop = new Shop();
            currentShop.setShopId(shopId);
            request.getSession().setAttribute("currentShop", currentShop);
            modelMap.put("redirect", false);
        }
        return modelMap;
    }
}

值得注意的是這裏使用multipartResolver來接收混合字符串和圖片文件的FormData類型POST請求,因此需要在spring-mvc.xml配置文件中註冊該bean,否則使用request.getParameter()接收FormData會爲空值null。而且bean的id必須爲multipartResolver。記得在POM中引入該類的依賴庫commons-fileupload:commons-fileupload

    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="maxUploadSize" value="10485760"/>   <!--文件最大10M=10485760字節-->
        <property name="defaultEncoding" value="UTF-8"/>
        <property name="resolveLazily" value="true"/>       <!--開啓文件延遲解析-->
    </bean>

CodeUtil.checkCode()實現如下,就是分別獲取request中傳來的用戶輸入的內容和session中儲存的內容進行比較,如果相同返回true

package com.tory.shop.util;

import com.google.code.kaptcha.Constants;

import javax.servlet.http.HttpServletRequest;

public class CodeUtil {
    public static boolean checkCode(HttpServletRequest request) {
        String expectedCode = (String) request.getSession().getAttribute(Constants.KAPTCHA_SESSION_KEY);
        String inputCode = (String) request.getParameter("inputCode");
        if (inputCode == null || !expectedCode.equals(inputCode))
            return false;
        else return true;
    }
}

前端頁面

在前端頁面實現簡單的店鋪信息註冊如下所示,這裏使用的是一個輕量級的UI庫:SUI
在這裏插入圖片描述使用CDN的方式引入SUI的相關文件,css文件在頁面加載之前,js文件在頁面加載之後。最後引入用於加載信息和提交Ajax請求的shopedit.js文件

<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>
<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/shopedit.js' charset='utf-8'></script>
</body>

如下所示爲頁面的Javascript代碼,這裏使用的是zepto.js,它是一個和jQuery語法類似但更爲輕量的js庫。首先通過$.getJSON()從服務器獲取categoryList和areaList信息並填充到頁面中。之後爲#submit添加點擊事件,提交商店的信息。首先獲取頁面中的信息構建shop對象,並且獲取圖片文件shopImg。然後通過JSON.stringify()將shop對象序列化爲json字符串,並和shopImg一起放到formData對象中。最後通過$.ajax()將formData發送給服務器。值得注意的是contentType指定發送數據的形式,默認爲application/x-www-form-urlencoded,即一般的表格將數據編碼爲urlenconded的方式,但是如果需要傳輸文件則需要FormData的方式而不是默認。這裏可以指定contentType爲false即不採用默認值,而是根據實際內容自動調整爲FormData。

$(function () {
    registerShop();

    function registerShop() {
        //獲取初始化信息並填充到頁面
        $.getJSON("/ShopDemo/shop/init", function (data) {
            if (data.success) {          //獲取店鋪分類和區域信息填充到頁面
                var categoryHtml = '';
                var areaHtml = '';
                data.categoryList.map(function (item, index) {
                    categoryHtml += '<option data-id="' + item.categoryId + '">' + item.categoryName + '</option>';
                });
                data.areaList.map(function (item, index) {
                    areaHtml += '<option data-id="' + item.areaId + '">' + item.areaName + '</option>';
                });
                $('#shop-category').html(categoryHtml);
                $('#area').html(areaHtml);
            }
        });

        //提交註冊信息
        $('#submit').click(function () {
            //獲取頁面shop的信息與圖片
            var shop = {};
            shop.shopName = $('#shop-name').val();
            shop.shopAddr = $('#shop-addr').val();
            shop.shopPhone = $('#shop-phone').val();
            shop.shopDescribe = $('#shop-desc').val();
            shop.shopCategory = {
                categoryId: $('#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];

            //將shop信息和圖片封裝爲FormData並上傳給服務器
            var formData = new FormData();
            formData.append('shopStr', JSON.stringify(shop));
            formData.append('shopImg', shopImg);
            $.ajax({
                url: '/ShopDemo/shop/register',
                type: 'POST',
                data: formData,
                contentType: false,
                processData: false,
                cache: false,
                success: function (data) {
                    if (data.success) {
                        $.toast('註冊成功!');
                    } else {
                        $.toast('註冊失敗' + data.errMsg);
                    }
                }
            })
        })
    }
});

頁面中驗證碼的實現使用的是com.github.penggle:kaptcha庫,在pom.xml文件中引入該依賴後需要在web.xml文件中配置servlet如下,

<!--配置驗證碼生成工具kaptcha  -->
  <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>

其中<servlet-mapping>映射路徑爲/Kaptcha,即請求該路徑會生成驗證碼並返回圖片,如下所示在html頁面中設置驗證碼圖片的src爲…/Kaptcha

<div class="item-inner">
    <label for="kaptcha-code" class="item-title label">驗證碼</label>
    <input id="kaptcha-code" name="kaptcha-code" type="text"
            class="form-control in" placeholder="驗證碼"/>
    <div class="item-input">
        <img id="kaptcha_img" alt="點擊更換" title="點擊更換"
             onclick="changeCode(this)" src="../Kaptcha"/>
    </div>
</div>

點擊更換驗證碼即更改圖片的src,向/Kaptcha請求一個新的圖片,並且請求的參數附帶隨機數作爲參數

function changeCode(img) {
    img.src="../Kaptcha?"+Math.floor(Math.random()*100)
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章