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"),在mapper使文件中通过#{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文件所对应的接口类为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)
}
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值