说明:

(1) 本篇博客内容:开发购物车模块的【购物车列表】接口;

(2)本篇博客需要注意的点:

          ● 本篇博客遇到了,mybatis多表关联查询,一种不太推荐的使用方式;虽然自己认为不推荐这种使用方式,但还是要知道的;

springboot 系统账号关联企业微信账号 springboot关联查询_ooc

          ● 这儿,恰巧,我们本来用来包装返回结果的CartVO,可以直接去承载多表查询的结果;(但是,能够感受到,这儿所谓的“恰巧”,在实际中,是可以广泛存在的)

(3)本篇博客出于安全考虑:而采用的一种广泛采用的做法:接口不能传入用户id,而是要在程序内部获取;否则,如果接口参数中有用户id的话,这很可能会被黑客利用,黑客就可以通过这个接口查看任何人的购物车信息了;

springboot 系统账号关联企业微信账号 springboot关联查询_数据_02

其实,由此,也能感受到【接口的设计能力】,这个能力也是需要慢慢锻炼的;

目录

一:【购物车列表】接口;

1.【购物车列表】接口文档;

(1)返回购物车列表时候,没有采用使用分页;

(2)购物车返回的数据:创建CartVO来包装返回给前端的数据,以符合接口对返回数据格式的要求;

(3)购物车返回的数据,横跨了cart表和product表,两个表的内容;所以,在SQL查询的时候,我们要做相应的处理;

2.【购物车列表】接口,在界面上的表现;

二:正式开发;

1.创建CartController类,并在CartController中,创建获取购物车列表的方法:list()方法;

 2.创建CartService接口,CartServiceImpl实现类;

3.在CartServiceImpl中编写获取购物车列表的方法:list()方法;

4.在CartServiceImpl中反向生成方法的声明;

5.在CartMapper中定义【根据userId,从cart表、product表中,查询购物车数据】的方法:selectList()方法;并在CartMapper.xml中编写实现SQL;

(1)在CartMapper中定义【根据userId,从cart表、product表中,查询购物车数据】的方法:selectList()方法;

(2)在CartMapper.xml中编写实现SQL;(重点!!!)

三:测试;


一:【购物车列表】接口;

1.【购物车列表】接口文档;

springboot 系统账号关联企业微信账号 springboot关联查询_spring boot_03

说明:

(1)返回购物车列表时候,没有采用使用分页;

          ● 这儿,我们默认购物车中的商品数量不多,而且就算购物车中的商品数量比较多,一次性返回购物车中的所有商品比分页获取购物车中的商品,体验也要好;所以,这儿请求购物车列表的时候,没有采用分页;自然,因为没有分页,所以这个接口也没有pageNum,pageSize这种参数;

(2)购物车返回的数据:创建CartVO来包装返回给前端的数据,以符合接口对返回数据格式的要求;

          ● 可以看到,【购物车列表】接口对返回数据的要求,其包括了cart表的内容、也包括了product表的内容、也有一个totalPrice;

springboot 系统账号关联企业微信账号 springboot关联查询_ooc_04

          ● 所以,很显然我们通过【mybatis-generator】创建的Cart和Product这两个pojo类,是不符合要求的; 

          ● 所以,我们为了符合接口对返回数据格式的要求,创建了CartVO来包装数据;

springboot 系统账号关联企业微信账号 springboot关联查询_数据_05

(3)购物车返回的数据,横跨了cart表和product表,两个表的内容;所以,在SQL查询的时候,我们要做相应的处理;

这儿,在后面介绍SQL的时候,会详细介绍;

2.【购物车列表】接口,在界面上的表现;

项目上线后,回来补……


二:正式开发;

1.创建CartController类,并在CartController中,创建获取购物车列表的方法:list()方法;

springboot 系统账号关联企业微信账号 springboot关联查询_数据_06

package com.imooc.mall.controller;

import com.imooc.mall.common.ApiRestResponse;
import com.imooc.mall.common.Constant;
import com.imooc.mall.filter.UserFilter;
import com.imooc.mall.model.pojo.User;
import com.imooc.mall.model.vo.CartVO;
import com.imooc.mall.service.CartService;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.List;

/**
 * 描述:【购物车】模块的Controller
 */

@RestController
//@Controller
@RequestMapping("/cart")
public class CartController {

    @Autowired
    CartService cartService;

    /**
     * 购物车模块:购物车列表
     * @return
     */
    @ApiOperation("购物车列表")
    @GetMapping("/list")
    public ApiRestResponse list() {
        List<CartVO> cartVOList = cartService.list(UserFilter.currentUser.getId());
        return ApiRestResponse.success(cartVOList);
    }

}

说明:

(1)url,请求方式,要符合接口文档要求;

springboot 系统账号关联企业微信账号 springboot关联查询_java_07

 (2)这儿我们使用了@RequestMapping,来统一指定CartController中方法的url前缀;很简单,就不啰嗦了;(PS:如有需要可以参考【SpringMVC入门与数据绑定4:Spring MVC数据绑定一:URL Mapping(URL映射);(@RequestMapping,@GetMapping、@PostMapping)】)

(3)因为,这儿接口的返回结果都要序列化为JSON,所以在前面我们在方法上都使用了@ResponseBody注解;这儿,我们直接在类上使用@RestController注解,这样就不用再在每个方法上使用@ResponseBody注解了;这儿也很简单,就不啰嗦了;(PS:如有需要可以参考【RESTful开发风格4:RESTful基本使用二:【@RestController注解】;【路径变量(uri中的变量)】(使用@PathVariable注解来获取路径变量值);】)

(4)因为,这个接口会被在【Spring Boot电商项目44:购物车模块二:统一校验当前是否有用户登录;】中编写的过滤器给处理;所以,我们可以通过UserFilter来获取当前登录用户;(PS:这儿用的add()方法中来阐述的,其实list()方法中,是一样的;就不再新写一个了) 

springboot 系统账号关联企业微信账号 springboot关联查询_后端_08

(5)另外,额外说一下,我们在调用service层的方法时候,需要传入当前登录用户的id,这其实也是为了防止横向越权;(横向越权:比如,A用户去操作B用户的东西;纵向越权:比如普通用户去操作管理员用户的东西)

springboot 系统账号关联企业微信账号 springboot关联查询_java_09

(6)service层的获取购物车列表的逻辑,在下一部分介绍; 

 2.创建CartService接口,CartServiceImpl实现类;

springboot 系统账号关联企业微信账号 springboot关联查询_java_10

3.在CartServiceImpl中编写获取购物车列表的方法:list()方法;

package com.imooc.mall.service.impl;

import com.imooc.mall.common.Constant;
import com.imooc.mall.exception.ImoocMallException;
import com.imooc.mall.exception.ImoocMallExceptionEnum;
import com.imooc.mall.model.dao.CartMapper;
import com.imooc.mall.model.dao.ProductMapper;
import com.imooc.mall.model.pojo.Cart;
import com.imooc.mall.model.pojo.Product;
import com.imooc.mall.model.vo.CartVO;
import com.imooc.mall.service.CartService;
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;


    /**
     * 根据前端要求,根据cart表和product表,获取并组织购物车列表数据
     * @return
     */
    @Override
    public List<CartVO> list(Integer userId) {
        List<CartVO> cartVOList = cartMapper.selectList(userId);
        for (int i = 0; i < cartVOList.size(); i++) {
            CartVO cartVO =  cartVOList.get(i);
            cartVO.setTotalPrice(cartVO.getPrice() * cartVO.getQuantity());
        }
        return cartVOList;
    }

}


说明:

(1)逻辑说明;

springboot 系统账号关联企业微信账号 springboot关联查询_数据_11

(2)Dao层的,根据用户id,查询购物车数据的方法selectList()方法,在下一部分介绍;

4.在CartServiceImpl中反向生成方法的声明;

springboot 系统账号关联企业微信账号 springboot关联查询_ooc_12

5.在CartMapper中定义【根据userId,从cart表、product表中,查询购物车数据】的方法:selectList()方法;并在CartMapper.xml中编写实现SQL;

(1)在CartMapper中定义【根据userId,从cart表、product表中,查询购物车数据】的方法:selectList()方法;

/** * 根据userId,从cart表和product表中,查询购物车数据 * @param userId * @return */ List<CartVO> selectList(@Param("userId") Integer userId);


(2)在CartMapper.xml中编写实现SQL;(重点!!!)

<select id="selectList" parameterType="java.lang.Integer" resultType="com.imooc.mall.model.vo.CartVO"> select c.id as id, p.id as productId, c.user_id as userId, c.quantity as quantity, c.selected as selected, p.price as price, p.name as productName, p.image as productImage from imooc_mall_cart c left join imooc_mall_product p on p.id=c.product_id where c.user_id = #{userId,jdbcType=INTEGER} and p.status=1 </select>


说明:

(1)首先,因为我们需要从cart表和product表,两个表中去查询;所以,这个查询是个多表查询;

springboot 系统账号关联企业微信账号 springboot关联查询_数据_13

(2)以前有关Mybatis的多表查询,可以参考:

          ● 首先,如果不是多表查询,即我们只查询一张表;那么,我们的做法是:根据表创建一个实体类,然后直接用这个实体类去承载查询结果;可以参考【MyBatis入门六:SQL传参一:SQL传参;(单参数传递【基本包装类型】和多参数传递【Map接口】)】;

springboot 系统账号关联企业微信账号 springboot关联查询_后端_14

          ● 然后,如果是多表查询,即我们查询的结果中包含多张表的字段;一种不推荐的做法,是使用Map去承载查询结果;可以参考【MyBatis入门七:多表关联查询一:获取多表关联查询结果;(查询结果包括多张表的字段,使用Map去承载存储查询结果)】;

springboot 系统账号关联企业微信账号 springboot关联查询_后端_15

springboot 系统账号关联企业微信账号 springboot关联查询_ooc_16

          ● 最后,如果是多表查询,即我们查询的结果中包含多张表的字段;一种推荐的标准做法是:【先创建一个实体类,这个实体类要包含多表关联查询中,所有将要查询的字段;;;我们下面是要用这个实体类去承载查询结果的】→【然后,通过<resultMap>去指定“属性”和“字段”的对应关系】→【然后,在SQL语句中,就可以直接引用我们定义的<resultMap>】;

springboot 系统账号关联企业微信账号 springboot关联查询_数据_17

springboot 系统账号关联企业微信账号 springboot关联查询_后端_18

(3)【购物车列表】接口:这儿的逻辑是:【我们本来创建CartVO的目的是,使用CartVO来包装返回给前端的数据,以符合接口对返回数据的格式要求】→【自然,这个接口,最终在Dao层,是需要查询多张表的;也就是说,这个底层是需要多表关联查询的】→【而,恰好,我们可以使用CartVO去直接承载多表关联查询的结果;(PS:自己能感觉到,这儿所谓的“恰巧”,在实际开发是可以广泛应用的)】;

(4)但是,和mybatis的标准的做法相比,这儿的多表查询的做法,有点图快、临时的感觉;不推荐这儿的用法;

springboot 系统账号关联企业微信账号 springboot关联查询_后端_19

springboot 系统账号关联企业微信账号 springboot关联查询_ooc

(5)其实,通过本篇博客的的案例,能够感觉到:在实际开中,尤其是比如多表关联查询、构建返回对象的时候,思想上没必要太死板,可以活泛点;


三:测试;

启动项目:

springboot 系统账号关联企业微信账号 springboot关联查询_ooc_21

springboot 系统账号关联企业微信账号 springboot关联查询_ooc_22