微光集市-基于Redis购物车的实现(版本2.0)


基于Redis的购物车实现

1 向购物车中添加商品

1.1服务端

1.1.1 公共类-处理结果类
/**
 * 结果处理类
 */
@Getter
public class Result {
    private Boolean success;
    private Integer code;
    private String message;
    private Object data;

    private Result(Boolean success, Integer code, String message, Object data) {
        this.success = success;
        this.code = code;
        this.message = message;
        this.data = data;
    }
    public static Result success() {
        return new Result(true,200,null,null);
    }
    public static Result success(String message) {
        return new Result(true,200,message,null);
    }
    public static Result success(String message,Object data) {
        return new Result(true,200,message,data);
    }
    public static Result fail(Integer code,String message,Object data) {
        return new Result(false,code,message,data);
    }
    public static Result fail(Integer code,String message) {
        return new Result(false,code,message,null);
    }
    public static Result fail(Integer code) {
        return new Result(false,code,null,null);
    }
}
1.1.2 创建CarContoller
@RestController
@RequestMapping("/car")
public class CarController {
    @Resource
    private CarService carService;
    @PostMapping("/addCar")
	   public Result addCar(@RequestBody Car car) {
    	 try {
         //设置当前登录的用户编号
         car.setUser_id(93);
         carService.addCar(car);
         return Result.success();
    	 } catch (Exception e) {
         e.printStackTrace();
         return Result.fail(500,"商品添加失败!!!");
     }
 }
}
1.1.3 创建CarService
  • CarService接口

    public interface CarService {
        void addCar(Car car) throws Exception;
    }
    
    • CarServcieImpl类
      • 采用hash存储添加购物车信息
    @Service
    public class CarServiceImpl implements CarService {
        private RedisTemplate redisTemplate;
        private HashOperations hashOperations;
        //构造器注入RedisTemplate,并且序列化
        @Autowired
        public CarServiceImpl(RedisTemplate redisTemplate) {
            this.redisTemplate = redisTemplate;
            redisTemplate.setKeySerializer(new StringRedisSerializer());
            redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
            //获得Redis对象
            hashOperations = redisTemplate.opsForHash();
        }
        @Override
        public void addCar(Car car) throws Exception{        
            //向Redis中添加一个商品
            Car[] cars ={car};
            //向Redis中添加购物车信息
            hashOperations.put("cars","user:"+car.getUser_id(),cars);
        }
    }
    
1.1.4 购物车版本升级-添加多个商品-Service层修改对应方法

思路:

  • 购物车是否存在该商品
    • 若存在,给该商品数量+1,总价进行更新,存入carList集合中
    • 若不存在,添加该商品,总价进行更新,存入carList集合中
  • 购物车不存在该商品
    • 将该商品直接存入carList集合中
  • 将carList存入redis
    @Override
    public void addCar(Car car) throws Exception {
        List<Car> carList;
        //是否存在购物车
        Boolean bool = redisTemplate.hasKey("cars");
        if (bool) {//购物车存在
            //获取redis中的数据
            carList = (List<Car>) hashOperations.get("cars", "user:" + car.getUser_id());
            Boolean exists = false;//redis是否存在新要添加的商品,默认不存在
            for (Car car1 : carList) {
                if (car1.getBook_id().equals(car.getBook_id())) {//判断redis是否存在新添加的商品
                    //如果存在数量则增加
                    car1.setCar_count(car1.getCar_count() + car.getCar_count());
                    //更新总价格
                    car1.setTotal(car1.getCar_count()*car1.getBook_price());
                    exists=true;
                    break;
                }
            }
            if (!exists){//如果不存在商品
                car.setTotal(car.getCar_count()*car.getBook_price());
                //直接添加新商品
                carList.add(car);            
            }
        }else{//不存在购物车
           //创建购物车集合
            carList =new ArrayList<>();
            car.setTotal(car.getCar_count()*car.getBook_price());
            carList.add(car);
        }
        hashOperations.put("cars","user:"+car.getUser_id(),carList);
    }

1.2客户端

1.2.1 前端添加UI
<p class="buyCar">
    <el-input-number size="medium" v-model="car.car_count" :min="1"></el-input-number>
    <el-button type="warning" style="margin-left: 20px;" @click="addCar">
        <span class="el-icon-shopping-cart-full">加入购物车</span>
    </el-button>    
</p>
1.2.2 前端向后端传递数据
export default {
    data() {
        return {
            car:{
                car_count: 1,//加入购物车数量                
            },   
            book: {},//图书对象
    },
    methods: {
          addCar(){
            //将book_id添加到car对象中
            this.car.book_id=this.book.book_id;
            this.$axios
                .post('car/addCar',this.car)
                .then(response=>{
                    let result=response.data;
                    if(result.success){//添加成功

                    }else{//添加失败

                    }
                })
                .catch(error=>{
                    alert(error);
                })
          },  
    }      
1.2.3 测试Redis是否传入数据
127.0.0.1:6379> keys *
1) "bookList"
2) "cars"

成功…

2 查看购物车

2.1 客户端

2.1.1创建Show.vue
<template>
    <div class="showCar-Container"> 
        <div class="car_list">
            <el-table
                :data="carList"
                border
                style="width: 100%"
                empty-text="暂无商品">
                <el-table-column
                align="center"
                type="selection">
                </el-table-column>

                <el-table-column
                    align="center"
                    type="index"
                    label="序号">
                </el-table-column> 

                <el-table-column
                    align="center"
                    prop="book_name"
                    label="商品名称">
                </el-table-column>

                <el-table-column
                    align="center"
                    label="商品照片">
                    <template slot-scope="scope">
                        <img :src="require('@/assets/images/books/' + scope.row.book_image)" class="image">
                    </template>    
                </el-table-column>

                <el-table-column
                    align="center"
                    prop="book_price"
                    label="单价">
                </el-table-column>
                
                <el-table-column
                    align="center"
                    prop="car_count"
                    label="购买数量">
                    <template slot-scope="scope">
                        <el-input-number size="small" v-model="scope.row.car_count" :min="1" @change="updateCarCount(scope.row.book_id,scope.row.car_count)"></el-input-number>
                    </template>
                </el-table-column>            

                <el-table-column
                    align="center" 
                    label="总计">
                    <template slot-scope="scope">
                        {{ scope.row.car_count* scope.row.book_price }}
                    </template>
                </el-table-column>  
                
                <el-table-column
                    align="center"
                    label="操作">
                    <template slot-scope="scope">
                        <el-popconfirm
                            confirm-button-text='确认'
                            cancel-button-text='取消'
                            icon="el-icon-info"
                            icon-color="red"
                            title="确定删除购物车内该商品吗?"
                            @confirm="delCarByBookId(scope.row.book_id)">
                            <el-button type="danger" icon="el-icon-delete" slot="reference">删除</el-button>
                        </el-popconfirm>
                    </template>
                </el-table-column>  
            </el-table>
        </div>
    </div>
</template>

<script>
export default {
}
</script>

<style scoped>
 .image{
    width: 80px;
    height: 80px;
 }
</style>
2.2.2 路由配置
import ShowCar from "../views/ShowCar.vue"
const routes = [
  {
    path: "/showCar",
    name: "showCar",
    component: ShowCar,
  },
];
2.2.3 前端对后端传来的数据进行处理
export default {
    data(){
        return{
            carList:[],//购物车列表
        }
    },methods:{
        /**
         * 获得购物车信息
         */
          queryCars(){
            this.$axios
                .get('car/queryCarInfo')
                .then(response=>{
                    this.carList=response.data;
                })
                .catch(error=>{
                    alert(error)
                })
          },
    },created(){
           this.queryCars();
    }
}

2.2 服务端

2.2.1 创建前端所用数据的model-view-CarView
@Data
@AllArgsConstructor
@NoArgsConstructor
public class CarView implements Serializable {
    private Integer book_id;       //图书编号
    private String book_name;        
    private Double book_price;
    private String book_message;       
    private Integer car_count;     //加入购物车数量  
    private Double total;         //总价
}
2.2.2 CarController添加该功能
   @GetMapping("/queryCarInfo")
    public List<CarView> queryCarInfo(){
        //当前登陆者的编号
        int userId=93;
        return carService.queryCarInfo(userId);
    }
2.2.3 CarService增加该功能
  • CarService
List<CarView> queryCarInfo(int userId);
  • CarServiceImpl
    @Override
    public List<CarView> queryCarInfo(int user_id) {
        //从redis中获取去购物车信息
        List<Car> carList = (List<Car>) hashOperations.get("cars", "user:" + user_id);
        //将carList中的book_id封装到list集合中
        List<Integer> bookIdList = new ArrayList<>();
        for (Car car : carList) {
            bookIdList.add(car.getBook_id());
        }
        //根据book_id获得对应商品数据
        List<Book> books = bookMapper.queryBookById(bookIdList.toArray(new Integer[bookIdList.size()]));
        List<CarView> carViewList = new ArrayList<>();
        for (Car car : carList) {
            CarView carView = new CarView();
            //购买数量
            carView.setCar_count(car.getCar_count());
            carView.setBook_id(car.getBook_id());
            //获得商品数据
            for (Book book : books) {
                if (book.getBook_id().equals(car.getCar_count())) {
                     carView.setBook_image(book.getBook_image());
                     carView.setBook_name(book.getBook_name());
                     carView.setBook_price(book.getBook_price());
                     carView.setTotal(car.getCar_count()*book.getBook_price());
                     break;
                }
            }
            carViewList.add(carView);
        }
        return carViewList;
    }

3 修改版-查看购物车基于redis

上文中,Redis中存储的数据只是[book_id(图书编号),user_id(用户id),car_count(购买数量)],需要用图书编号查询其他图书信息,是基于redis和mysql共同实现的。

  • 该修改是把购物车所需的数据全部存储在Redis中不需要和mysql配合

3.1 客户端

3.1.1 将购物车所需的数据都添加到car对象中
addCar(){
            //将数据动态添加到car对象中
            this.car.book_id=this.book.book_id;
            this.car.book_name=this.book.book_name;
            this.car.book_image=this.book.book_image;
            this.car.book_price=this.book.book_price;
            this.$axios
                .post('car/addCar',this.car)
                .then(response=>{
                    let result=response.data;
                    if(result.success){//添加成功
                        this.$notify({
                            title: '成功',
                            message: '添加成功',
                            type: 'success'
                        })
                    }else{//添加失败
                        this.$notify.error({
                            title: '错误',
                            message: '添加失败'
                        });
                    }
                })
                .catch(error=>{
                    alert(error);
                })
          }

3.2 服务端

3.2.1 服务端实体类Car的修改
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Car implements Serializable {
    private Integer book_id;
    private Integer car_count;
    private Integer user_id;
    private String book_name;
    private Double book_price;
    private String book_image;
    private Double total;
}
3.2.2 CarController对应方法的修改
@GetMapping("/queryCarInfo")
    public List<Car> queryCarInfo() {
        //当前登陆者的编号
        int userId = 93;
        return carService.queryCarInfo(userId);
    }
3.2.3 CarService中的对应方法修改
  • addCar方法
    @Override
    public void addCar(Car car) throws Exception {
        //向Redis中添加一个商品
        List<Car> cars = new ArrayList<>();
        //设置合计
        car.setTotal(car.getCar_count()*car.getBook_price());
        cars.add(car);
        //向Redis中添加购物车信息
        hashOperations.put("cars", "user:" + car.getUser_id(), cars);
    }
  • CarService接口
List<Car> queryCarInfo(int userId);
  • queryCarInfo方法
 @Override
    public List<Car> queryCarInfo(int user_id) {
        return (List<Car>) hashOperations.get("cars","user:"+user_id);
    }

4 修改购物车中商品的数量及删除商品

4.1 客户端

4.1.1 前端UI的修改
  • 商品数量
<el-table-column
  align="center"
  prop="car_count"
  label="购买数量">
   <template slot-scope="scope">
      <el-input-number size="small" v-model="scope.row.car_count" :min="1" @change="updateCarCount(scope.row.book_id,scope.row.car_count)"></el-input-number>          </template>
</el-table-column>  
  • 删除商品
<el-table-column
    align="center"
    label="操作">
  <template slot-scope="scope">
      <el-popconfirm
           confirm-button-text='确认'
           cancel-button-text='取消'
           icon="el-icon-info"
           icon-color="red"
           title="确定删除购物车内该商品吗?"
           @confirm="delCarByBookId(scope.row.book_id)">
          <el-button type="danger" icon="el-icon-delete" slot="reference">删除</el-button>
      </el-popconfirm>
   </template>
</el-table-column>
4.1.2 前端向后端传递数据
  • 商品数量
  		/**
           * 修改购物车商品数量
           */
          updateCarCount(book_id,car_count){
            this.$axios
                .put('car/updateCarCount',
                {"book_id":book_id,
                "car_count": car_count})
                .then(response => {
                    let result=response.data;
                    if(result.success){
                        this.queryCars();
                    }else{
                         this.$notify.error({
                            title: '错误',
                            message: '请输入有效数字'
                        });
                    }
                })
                .catch(error => {
                    alert(error)
                })
          },
  • 删除商品
 			/**
           * 根据id删除对应商品
           */
          delCarByBookId(book_id){
            this.$axios
                .delete('car/delCarByBookId?book_id='+book_id)
                .then(response => {
                    let result = response.data;
                    if (result.success) {
                        this.queryCars();
                    } else {
                        this.$notify.error({
                            title: '错误',
                            message: '删除失败'
                        });
                    }
                })
                .catch(error => {
                    alert(error)
                })
          }

4.2 服务端

4.2.1 CarController添加对应方法
  • 修改数量
   @PutMapping("/updateCarCount")
    public Result updateCarCount(@RequestBody Car car){
       try {
           car.setUser_id(93);
           carService.updateCarCount(car);
           return Result.success();
       } catch (Exception e) {
           e.printStackTrace();
           return Result.fail(500, "数字不能为0");
       }
   }
  • 删除商品
   @DeleteMapping("/delCarByBookId")
   public Result delCarByBookId(Integer book_id){
       try {
           carService.delCarByBookId(93,book_id);
           return Result.success();
       } catch (Exception e) {
           e.printStackTrace();
           return Result.fail(500, "删除失败!!");
       }
   }
4.2.2 CarService添加对应方法
  • 修改数量

    • CarService接口
        void updateCarCount(Car car);	
    
    • CarServiceImpl
    @Override
    public void updateCarCount(Car car) {
        //获取当前用户购物车
       List<Car> carList = (List<Car>) hashOperations.get("cars", "user:" +car.getUser_id());
        for (Car car1 : carList) {//查找要修改的商品,并修改数量
            if (car1.getBook_id().equals(car.getBook_id())) {
                //如果存在数量则修改
                car1.setCar_count(car.getCar_count());
                //更新总价格
                car1.setTotal(car1.getCar_count() * car1.getBook_price());
                break;
            }
        }
        //修改redis中数据
        hashOperations.put("cars", "user:" + car.getUser_id(), carList);
    }
    
  • 删除商品

    • CarService接口
    	void delCarByBookId(int user_id, Integer book_id);
    
    • CarServiceImpl
    @Override
    public void delCarByBookId(int user_id, Integer book_id) {
        List<Car> carList = (List<Car>) hashOperations.get("cars", "user:" + user_id);
        for (Car car :carList){
            if (car.getBook_id().equals(book_id)) {
                //如果存在则从carList中删除
                carList.remove(car);
                break;
            }
        }
        //修改redis中数据
        hashOperations.put("cars", "user:" + user_id, carList);
    }
    

5 使用Map集合重构购物车

之前存出购物车里商品用的是List列表,操作不是很容易,此修改我们用Map集合来存储购物车商品信息,Map中Key用来存储商品id,Value存储购物车对应商品信息

5.1 添加购物车

5.1.1 服务端Service层-CarService
    /**
     * 版本3:使用Map解存储购物车内信息
     * @param car
     * @throws Exception
     */
    @Override
    public void addCar(Car car) throws Exception {
        //声明Map集合存储购物车信息
        Map<Integer, Car> carMap = null;
        //是否存在购物车
        Boolean bool = redisTemplate.hasKey("cars");
        if (bool) {//购物车存在
            //获取redis中的数据
            carMap = (Map<Integer, Car>) hashOperations.get("cars", "user:" + car.getUser_id());
            //判断当前用户购物车是否存在
            if (carMap == null) {//如果不存在创建Map对象
                carMap = new HashMap<>();

            } else {//当前用户购物车存在
                //判断当前商品是否在购物车
                if (carMap.containsKey(car.getBook_id())) {
                    //更新数量
                    Car updateCar = carMap.get(car.getBook_id());
                    updateCar.setCar_count(updateCar.getCar_count() + car.getCar_count());
                } else {//当前商品不存在
                    //直接加入map集合
                    carMap.put(car.getBook_id(), car);
                }
            }
        } else {//当前购物车不存在
            carMap = new HashMap<>();
            carMap.put(car.getBook_id(), car);
        }
        hashOperations.put("cars", "user:" + car.getUser_id(), carMap);
    }
5.1.2 价格总计在前端处理
<el-table-column
     align="center" 
     label="总计">
     <template slot-scope="scope">
         {{ scope.row.car_count* scope.row.book_price }}
     </template>
 </el-table-column>  

5.2 查询购物车信息

  • Service层-CarService
    @Override
    public List<Car> queryCarInfo(int user_id) {
        Map<Integer, Car> carMap = (Map<Integer, Car>) hashOperations.get("cars", "user:" + user_id);
        if (carMap == null) {
            return null;
        }
        List<Car> carList =new ArrayList<>();
        Collection<Car> carInfo = carMap.values();
        carList.addAll(carInfo);
        return carList;
    }

5.3 修改购物车商品数量和删除商品

  • Service层-CarService
@Override
public void updateCarCount(Car car) {
        //获取当前用户购物车
    Map<Integer, Car> carMap = (Map<Integer, Car>) hashOperations.get("cars", "user:" + car.getUser_id());
    if (carMap.containsKey(car.getBook_id())){//存在该书
        Car updateCar = carMap.get(car.getBook_id());
        updateCar.setCar_count(car.getCar_count());
        carMap.put(updateCar.getBook_id(),updateCar);
    }
        //修改redis中数据
    hashOperations.put("cars", "user:" + car.getUser_id(), carMap);
}

@Override public void delCarByBookId(int user_id, Integer book_id) {
    Map<Integer, Car> carMap = (Map<Integer, Car>) hashOperations.get("cars", "user:" + user_id);

    if (carMap.containsKey(book_id)){//购物车是否存在该书,存在即删除
            carMap.remove(book_id);
    }
    //修改redis中数据
    hashOperations.put("cars", "user:" + user_id, carMap);
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@活着笑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值