五. 商品模块的开发
1. 后台新增商品的接口以及图片上传接口的开发
先来了解一下图片上传,图片名我们采用的是UUID(Universally Unique Identifier),中文名为通用唯一识别码。使用UUID可以防止图片重名的问题,以及可以防止别人爬图。他的生成规则:日期和时间、MAC地址、HashCode 、随机数等。
相关代码如下:
controller:
package com.haiexijun.mall.controller; import com.haiexijun.mall.common.ApiRestResponse; import com.haiexijun.mall.common.Constant; import com.haiexijun.mall.exception.MallException; import com.haiexijun.mall.exception.MallExceptionEnum; import com.haiexijun.mall.model.pojo.Product; import com.haiexijun.mall.model.request.addProductReq; import com.haiexijun.mall.service.ProductService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import javax.validation.Valid; import java.io.File; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.util.UUID; /** * 描述: 后台商品管理Controller */ @Controller @Api(tags = "后台商品管理相关接口",description = "有后台添加商品的接口、图片上传的接口、更新和删除商品的接口、批量上下架商品的接口、后台商品列表和商品详情的接口") public class ProductAdminController { @Autowired ProductService productService; @PostMapping("/admin/product/add") @ApiOperation("后台添加商品") @ResponseBody public ApiRestResponse addProduct(@Valid @RequestBody addProductReq addProductReq) throws MallException { productService.add(addProductReq); return ApiRestResponse.success(); } @PostMapping("/admin/product/file") @ResponseBody @ApiOperation("商品图片上传") public ApiRestResponse upload(HttpServletRequest httpServletRequest,@RequestParam("file") MultipartFile file) throws MallException { // 获取图片的原始名字 String fileName= file.getOriginalFilename(); //获取图片的后缀 String suffixName= fileName.substring(fileName.lastIndexOf(".")); //生成图片的UUID名称 UUID uuid=UUID.randomUUID(); String newFileName=uuid.toString()+suffixName; //创建文件夹 File fileDirectory= new File(Constant.FILE_UPLOAD_DIR); // 创建文件 File destFile= new File(Constant.FILE_UPLOAD_DIR+newFileName); //判断文件夹是否存在 if (!fileDirectory.exists()){ //如果不存在,就创建这个文件夹 if (!fileDirectory.mkdir()){ //如果没有建立成功,抛出异常 throw new MallException(MallExceptionEnum.MKDIR_FAILED); } } try { file.transferTo(destFile); } catch (IOException e) { e.printStackTrace(); } //把地址给返回回去 try { return ApiRestResponse.success(getHost(new URI(httpServletRequest.getRequestURL()+""))+"/images/"+newFileName); } catch (URISyntaxException e) { return ApiRestResponse.error(MallExceptionEnum.UPLOAD_FAILED); } } private URI getHost(URI uri){ URI effectiveURI; try { effectiveURI=new URI(uri.getScheme(),uri.getUserInfo(),uri.getHost(),uri.getPort(),null,null,null); } catch (URISyntaxException e) { effectiveURI=null; } return effectiveURI; } }
service层:
package com.haiexijun.mall.service.impl; import com.haiexijun.mall.exception.MallException; import com.haiexijun.mall.exception.MallExceptionEnum; import com.haiexijun.mall.model.dao.ProductMapper; import com.haiexijun.mall.model.pojo.Product; import com.haiexijun.mall.model.request.addProductReq; import com.haiexijun.mall.service.ProductService; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** *描述: 商品服务实现类 */ @Service public class ProductServiceImpl implements ProductService { @Autowired ProductMapper productMapper; @Override public void add(addProductReq addProductReq) throws MallException { Product product=new Product(); BeanUtils.copyProperties(addProductReq,product); Product productOld=productMapper.selectByName(addProductReq.getName()); if (productOld!=null){ throw new MallException(MallExceptionEnum.NAME_EXISTED); } int count= productMapper.insertSelective(product); if (count==0){ throw new MallException(MallExceptionEnum.CREATE_FAILED); } } }
其他层这里不多写了。
图片上传的地址我们要在application.properties配置文件中进行配置:
# 上传图片的路径,根据部署情况,可自行修改 file.upload_dir=D:\\
然后还要在MallWebMvcConfig这个配置类中对图片的资源映射配置,addResourceHandlers方法里面添加代码:
registry.addResourceHandler("/images/**").addResourceLocations( "file:"+ Constant.FILE_UPLOAD_DIR);
2.更新和删除商品的接口
controller层:
@PostMapping("/admin/product/update") @ResponseBody @ApiOperation("后台更新商品信息") public ApiRestResponse updateProduct(@Valid @RequestBody UpdateProductReq updateProductReq) throws MallException { Product product = new Product(); BeanUtils.copyProperties(updateProductReq,product); productService.update(product); return ApiRestResponse.success(); } @PostMapping("/admin/product/delete") @ResponseBody @ApiOperation("后台删除商品信息") public ApiRestResponse deleteProduct(@RequestParam Integer id) throws MallException { productService.delete(id); return ApiRestResponse.success(); }
service层:
@Override public void update(Product updateProduct) throws MallException { Product productOld=productMapper.selectByName(updateProduct.getName()); //如果同名不同id,不能进行修改 if (productOld!=null&&!productOld.getId().equals(updateProduct.getId())){ throw new MallException(MallExceptionEnum.NAME_EXISTED) ; } int count=productMapper.updateByPrimaryKeySelective(updateProduct); if (count==0){ throw new MallException(MallExceptionEnum.UPDATE_FAILED); } } @Override public void delete(Integer id) throws MallException { Product productOld=productMapper.selectByPrimaryKey(id); //如果查不到该记录,无法删除 if (productOld==null){ throw new MallException(MallExceptionEnum.DELETE_FAILED) ; } int count=productMapper.deleteByPrimaryKey(id); if (count==0){ throw new MallException(MallExceptionEnum.DELETE_FAILED); } }
3. 批量上下架商品的接口
对于Mybatis而言,它的一个能力就是遍历List。比如说我们传进去一个列表,那想把这里面的所有符合这个列表Id的都进行上下架状态的更新。我们要实现的话,就要在where语句中进行拼接。
controller层:
@PostMapping("/admin/product/batchUpdateSellStatus") @ResponseBody @ApiOperation("后台批量上下架") public ApiRestResponse batchUpdateSellStatus(@RequestParam Integer[] ids,@RequestParam Integer sellStatus){ productService.batchUpdateSellStatus(ids, sellStatus); return ApiRestResponse.success(); }
service层:
@Override public void batchUpdateSellStatus(Integer[] ids,Integer sellStatus){ productMapper.batchUpdateSellStatus(ids,sellStatus); }
mapper.xml:
<update id="batchUpdateSellStatus"> update mall_product set status=#{sellStatus} where id in <foreach collection="ids" close=")" item="id" open="(" separator=","> #{id} </foreach> </update>
六.购物车模块
1.部分业务流程
2. 核心代码
controller层:
package com.haiexijun.mall.controller; import com.haiexijun.mall.common.ApiRestResponse; import com.haiexijun.mall.exception.MallException; import com.haiexijun.mall.filter.UserFilter; import com.haiexijun.mall.service.CartService; import com.haiexijun.mall.vo.CartVO; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import java.util.List; /** * 描述: 购物车Controller */ @RestController @Api(tags = "购物车相关的接口") @RequestMapping("/cart") public class CartController { @Autowired CartService cartService; @PostMapping("/add") @ApiOperation("商品加入购物车") public ApiRestResponse add(@RequestParam Integer productId,@RequestParam Integer count) throws MallException { //内部获取用户id防止越权操作别人的 Integer userId= UserFilter.currentUser.getId(); List<CartVO> cartVOList= cartService.add(userId,productId,count); return ApiRestResponse.success(cartVOList); } @ApiOperation("获取购物车列表") @GetMapping("/list") public ApiRestResponse list(){ //内部获取用户id防止越权操作别人的 Integer userId= UserFilter.currentUser.getId(); List<CartVO> carList =cartService.list(userId); return ApiRestResponse.success(carList); } @ApiOperation("更新购物车") @PostMapping("/update") public ApiRestResponse update(@RequestParam Integer productId,@RequestParam Integer count) throws MallException { //内部获取用户id防止越权操作别人的 Integer userId= UserFilter.currentUser.getId(); List<CartVO> cartVOList=cartService.update(userId,productId,count); return ApiRestResponse.success(cartVOList); } @ApiOperation("删除购物车") @PostMapping("/delete") public ApiRestResponse update(@RequestParam Integer productId) throws MallException { //内部获取用户id防止越权操作别人的 Integer userId= UserFilter.currentUser.getId(); List<CartVO> cartVOList=cartService.delete(userId,productId); return ApiRestResponse.success(cartVOList); } @ApiOperation("单个选中/不选中购物车的商品") @PostMapping("/select") public ApiRestResponse select(@RequestParam Integer productId,@RequestParam Integer selected) throws MallException { //内部获取用户id防止越权操作别人的 Integer userId= UserFilter.currentUser.getId(); List<CartVO> cartVOList=cartService.selectOrNot(userId,productId,selected); return ApiRestResponse.success(cartVOList); } @ApiOperation("全部选中/不选中购物车的商品") @PostMapping("/selectAll") public ApiRestResponse selectAll(@RequestParam Integer selected) throws MallException { //内部获取用户id防止越权操作别人的 Integer userId= UserFilter.currentUser.getId(); List<CartVO> cartVOList=cartService.selectAll(userId,selected); return ApiRestResponse.success(cartVOList); } }
service层:
package com.haiexijun.mall.service.impl; import com.haiexijun.mall.common.Constant; import com.haiexijun.mall.exception.MallException; import com.haiexijun.mall.exception.MallExceptionEnum; import com.haiexijun.mall.model.dao.CartMapper; import com.haiexijun.mall.model.dao.ProductMapper; import com.haiexijun.mall.model.pojo.Cart; import com.haiexijun.mall.model.pojo.Product; import com.haiexijun.mall.service.CartService; import com.haiexijun.mall.vo.CartVO; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; /** * 购物车Service的实现类 */ @Service public class CartServiceImpl implements CartService { @Autowired ProductMapper productMapper; @Autowired CartMapper cartMapper; @Override public List<CartVO> add(Integer userId, Integer productId, Integer count) throws MallException { validProduct(productId,count); Cart cart=cartMapper.selectCartByUserIdAndProductId(userId,productId); if (cart==null){ //如果这个商品之前不在购物车里面,就要新增一个记录 cart=new Cart(); cart.setProductId(productId); cart.setUserId(userId); cart.setQuantity(count); cart.setSelected(Constant.Cart.CHECKED); cartMapper.insertSelective(cart); }else { //如果这个商品之前在购物车里面,则数量增加 count=count+cart.getQuantity(); Cart cartNew=new Cart(); cartNew.setQuantity(count); cartNew.setId(cart.getId()); cartNew.setProductId(cart.getProductId()); cartNew.setUserId(cart.getUserId()); cartNew.setSelected(Constant.Cart.CHECKED); cartMapper.updateByPrimaryKeySelective(cartNew); } return this.list(userId); } private void validProduct(Integer productId,Integer count) throws MallException { Product product=productMapper.selectByPrimaryKey(productId); // 判断商品是否存在,是否上架 if (product==null||product.getStatus().equals(Constant.SaleStatus.NOT_SELL)){ throw new MallException(MallExceptionEnum.NOT_SELL); } //判断商品库存,如果库存不足够也不行 if (count>product.getStock()){ throw new MallException(MallExceptionEnum.NOT_ENOUGH); } } @Override public List<CartVO> list(Integer userId){ List<CartVO> cartVOS= cartMapper.selectList(userId); for (int i = 0; i < cartVOS.size(); i++) { CartVO cartVO=cartVOS.get(i); cartVO.setTotalPrice(cartVO.getPrice()*cartVO.getQuantity()); } return cartVOS; } @Override public List<CartVO> update(Integer userId, Integer productId, Integer count) throws MallException { validProduct(productId,count); Cart cart=cartMapper.selectCartByUserIdAndProductId(userId,productId); if (cart==null){ //如果这个商品之前不在购物车里面,要报错的,无法更新 throw new MallException(MallExceptionEnum.UPDATE_FAILED); }else { //如果这个商品之前在购物车里面,则更新数量 Cart cartNew=new Cart(); cartNew.setQuantity(count); cartNew.setId(cart.getId()); cartNew.setProductId(cart.getProductId()); cartNew.setUserId(cart.getUserId()); cartNew.setSelected(Constant.Cart.CHECKED); cartMapper.updateByPrimaryKeySelective(cartNew); } return this.list(userId); } @Override public List<CartVO> delete(Integer userId, Integer productId) throws MallException { Cart cart=cartMapper.selectCartByUserIdAndProductId(userId,productId); if (cart==null){ //如果这个商品之前不在购物车里面,要报错的,无法删除 throw new MallException(MallExceptionEnum.DELETE_FAILED); }else { //如果这个商品之前在购物车里面,则更新数量 cartMapper.deleteByPrimaryKey(cart.getId()); } return this.list(userId); } @Override public List<CartVO> selectOrNot(Integer userId, Integer productId, Integer selected) throws MallException { Cart cart=cartMapper.selectCartByUserIdAndProductId(userId,productId); if (cart==null){ throw new MallException(MallExceptionEnum.UPDATE_FAILED); }else { cartMapper.selectOrNot(userId,productId,selected); } return this.list(userId); } @Override public List<CartVO> selectAll(Integer userId,Integer selected){ cartMapper.selectOrNot(userId,null,selected); return this.list(userId); } }
dao层:
package com.haiexijun.mall.model.dao; import com.haiexijun.mall.model.pojo.Cart; import com.haiexijun.mall.vo.CartVO; import org.apache.ibatis.annotations.Param; import org.springframework.stereotype.Repository; import java.util.List; @Repository public interface CartMapper { int deleteByPrimaryKey(Integer id); int insert(Cart record); int insertSelective(Cart record); Cart selectByPrimaryKey(Integer id); int updateByPrimaryKeySelective(Cart record); int updateByPrimaryKey(Cart record); Cart selectCartByUserIdAndProductId(@Param("userId") Integer userId,@Param("productId") Integer productId); List<CartVO> selectList(@Param("userId") Integer userId); Integer selectOrNot(@Param("userId") Integer userId,@Param("productId") Integer productId,@Param("selected") Integer selected); }
<?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.haiexijun.mall.model.dao.CartMapper"> <resultMap id="BaseResultMap" type="com.haiexijun.mall.model.pojo.Cart"> <id column="id" jdbcType="INTEGER" property="id" /> <result column="product_id" jdbcType="INTEGER" property="productId" /> <result column="user_id" jdbcType="INTEGER" property="userId" /> <result column="quantity" jdbcType="INTEGER" property="quantity" /> <result column="selected" jdbcType="INTEGER" property="selected" /> <result column="create_time" jdbcType="TIMESTAMP" property="createTime" /> <result column="update_time" jdbcType="TIMESTAMP" property="updateTime" /> </resultMap> <sql id="Base_Column_List"> id, product_id, user_id, quantity, selected, create_time, update_time </sql> <select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap"> select <include refid="Base_Column_List" /> from mall_cart where id = #{id,jdbcType=INTEGER} </select> <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer"> delete from mall_cart where id = #{id,jdbcType=INTEGER} </delete> <insert id="insert" parameterType="com.haiexijun.mall.model.pojo.Cart"> insert into mall_cart (id, product_id, user_id, quantity, selected, create_time, update_time) values (#{id,jdbcType=INTEGER}, #{productId,jdbcType=INTEGER}, #{userId,jdbcType=INTEGER}, #{quantity,jdbcType=INTEGER}, #{selected,jdbcType=INTEGER}, #{createTime,jdbcType=TIMESTAMP}, #{updateTime,jdbcType=TIMESTAMP}) </insert> <insert id="insertSelective" parameterType="com.haiexijun.mall.model.pojo.Cart"> insert into mall_cart <trim prefix="(" suffix=")" suffixOverrides=","> <if test="id != null"> id, </if> <if test="productId != null"> product_id, </if> <if test="userId != null"> user_id, </if> <if test="quantity != null"> quantity, </if> <if test="selected != null"> selected, </if> <if test="createTime != null"> create_time, </if> <if test="updateTime != null"> update_time, </if> </trim> <trim prefix="values (" suffix=")" suffixOverrides=","> <if test="id != null"> #{id,jdbcType=INTEGER}, </if> <if test="productId != null"> #{productId,jdbcType=INTEGER}, </if> <if test="userId != null"> #{userId,jdbcType=INTEGER}, </if> <if test="quantity != null"> #{quantity,jdbcType=INTEGER}, </if> <if test="selected != null"> #{selected,jdbcType=INTEGER}, </if> <if test="createTime != null"> #{createTime,jdbcType=TIMESTAMP}, </if> <if test="updateTime != null"> #{updateTime,jdbcType=TIMESTAMP}, </if> </trim> </insert> <update id="updateByPrimaryKeySelective" parameterType="com.haiexijun.mall.model.pojo.Cart"> update mall_cart <set> <if test="productId != null"> product_id = #{productId,jdbcType=INTEGER}, </if> <if test="userId != null"> user_id = #{userId,jdbcType=INTEGER}, </if> <if test="quantity != null"> quantity = #{quantity,jdbcType=INTEGER}, </if> <if test="selected != null"> selected = #{selected,jdbcType=INTEGER}, </if> <if test="createTime != null"> create_time = #{createTime,jdbcType=TIMESTAMP}, </if> <if test="updateTime != null"> update_time = #{updateTime,jdbcType=TIMESTAMP}, </if> </set> where id = #{id,jdbcType=INTEGER} </update> <update id="updateByPrimaryKey" parameterType="com.haiexijun.mall.model.pojo.Cart"> update mall_cart set product_id = #{productId,jdbcType=INTEGER}, user_id = #{userId,jdbcType=INTEGER}, quantity = #{quantity,jdbcType=INTEGER}, selected = #{selected,jdbcType=INTEGER}, create_time = #{createTime,jdbcType=TIMESTAMP}, update_time = #{updateTime,jdbcType=TIMESTAMP} where id = #{id,jdbcType=INTEGER} </update> <select id="selectCartByUserIdAndProductId" parameterType="map" resultMap="BaseResultMap"> select <include refid="Base_Column_List"/> from mall_cart where user_id=#{userId} and product_id=#{productId} </select> <select id="selectList" resultType="com.haiexijun.mall.vo.CartVO" parameterType="java.lang.Integer"> select c.id as id, p.id as productId, c.user_id as userId, c.selected as selected, c.quantity as quantity, p.price as price, p.name as productName, p.image as productImage from mall_cart c left join mall_product p on p.id =c.product_id where c.user_id=#{userId} and p.status=1 </select> <update id="selectOrNot" parameterType="map"> update mall_cart set selected=#{selected} where user_id=#{userId} <if test="productId!=null"> and product_id=#{productId} </if> </update> </mapper>
七.订单模块的开发
1.下单流程