点击指定的商品去到指定的商品详情页面:点击加入购物车,会将指定的商品加入该账号的购物车中去:
前台传递商品id
后台接收:
GoodsController
package com.lya.lyaspshop.controller; import com.lya.lyaspshop.pojo.Goods; import com.lya.lyaspshop.service.impl.GoodsServiceImpl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.List; /** *
* 商品信息表 前端控制器 *
* * @author lya * @since 2023-12-27 */ @RequestMapping("/goods") @Controller//跳页面 //@RestController//显示数据 public class GoodsController { @Autowired private GoodsServiceImpl goodsService; // 首页商品 @RequestMapping("/list") public Object index() { Listg1 = goodsService.list(); return g1; } @RequestMapping("/query") public String query(Goods goods , Model model) { // 前台带一个gid,我们来查询 Goods g = goodsService.getById(goods.getGid()); model.addAttribute("g",g); return "proDetail" ; } }
购物车界面:
<#include "common/head.html"> <#include "common/top.html">
首页 / 装饰摆件 / 干花花艺 / <#-- 注意: 1)${goods.goodsTitle!}:只能判断goodsTitle属性是否为空,不能判断goods对象是否为空 2)${(goods.goodsTitle)!}:既可以判断goods对象是否为空,也可以判断goodsTitle属性是否为空 --> 【最家】非洲菊仿真花干花<#include "common/footer.html">馨***呀
不好意思评价晚了,产品很好,价格比玻璃品便宜,没有我担心的杂色,发货快,包装好,全5分
2016年12月27日08:31颜色分类:大中小三件套(不含花)
么***周
花瓶超级棒,我看图以为是光面的,收货发现是磨砂,但感觉也超有质感,很喜欢。磨砂上面还有点纹路,不过觉得挺自然的,不影响美观。包装也很好,绝对不会磕碎碰坏,好评!
2016年12月27日08:31颜色分类:大中小三件套(不含花)
馨***呀
不好意思评价晚了,产品很好,价格比玻璃品便宜,没有我担心的杂色,发货快,包装好,全5分
2016年12月27日08:31颜色分类:大中小三件套(不含花)
么***周
花瓶超级棒,我看图以为是光面的,收货发现是磨砂,但感觉也超有质感,很喜欢。磨砂上面还有点纹路,不过觉得挺自然的,不影响美观。包装也很好,绝对不会磕碎碰坏,好评!
2016年12月27日08:31颜色分类:大中小三件套(不含花)
馨***呀
不好意思评价晚了,产品很好,价格比玻璃品便宜,没有我担心的杂色,发货快,包装好,全5分
2016年12月27日08:31颜色分类:大中小三件套(不含花)
么***周
花瓶超级棒,我看图以为是光面的,收货发现是磨砂,但感觉也超有质感,很喜欢。磨砂上面还有点纹路,不过觉得挺自然的,不影响美观。包装也很好,绝对不会磕碎碰坏,好评!
2016年12月27日08:31颜色分类:大中小三件套(不含花)
馨***呀
不好意思评价晚了,产品很好,价格比玻璃品便宜,没有我担心的杂色,发货快,包装好,全5分
2016年12月27日08:31颜色分类:大中小三件套(不含花)
么***周
花瓶超级棒,我看图以为是光面的,收货发现是磨砂,但感觉也超有质感,很喜欢。磨砂上面还有点纹路,不过觉得挺自然的,不影响美观。包装也很好,绝对不会磕碎碰坏,好评!
2016年12月27日08:31颜色分类:大中小三件套(不含花)
馨***呀
不好意思评价晚了,产品很好,价格比玻璃品便宜,没有我担心的杂色,发货快,包装好,全5分
2016年12月27日08:31颜色分类:大中小三件套(不含花)
么***周
花瓶超级棒,我看图以为是光面的,收货发现是磨砂,但感觉也超有质感,很喜欢。磨砂上面还有点纹路,不过觉得挺自然的,不影响美观。包装也很好,绝对不会磕碎碰坏,好评!
2016年12月27日08:31颜色分类:大中小三件套(不含花)
将商品id绑定到data-gid属性上面去:
为其设置点击事件:
/****************************proDetail 加入购物车*******************************/ $(".btns .cart").click(function(){ //获得添加购物车的id data-gid let gid = this.dataset.gid //发送添加购物车的数量 let num = $("div.num span.fl").text() //发起请求添加购物车 $.post('/cart/add',{gid,num},resp=>{ if(resp.code===200){ alert('增加成功') } },"json") });
这里我们后端要思考:购物车的东西我们因该放在哪里?
Redis 可以作为缓存系统,将热点数据存储在内存中,提高读写性能和响应速度,减少对后端数据存储的压力。
@RequestMapping("/add") @ResponseBody public JsonResponseBody> add(User user, CartItemVo vo, HttpServletRequest request){ String token = CookieUtils.getCookieValue(request, "userToken"); User userByToken = redisService.getUserByToken(token); //将购物车的商品放到缓存数据库中 redisService.saveCart(userByToken,vo); return JsonResponseBody.success(); }
这里写一个类用来放入保存到redis中去:
注意这个类要实现实现Serializable接口!!!
在Java中,实现Serializable接口是为了让一个对象可以被序列化和反序列化。序列化指的是将对象转换成字节流,以便可以在网络上传输或者保存在磁盘上;而反序列化则是将字节流重新转换成对象。
CartItemVo:
package com.lya.lyaspshop.vo; import lombok.Data; import java.io.Serializable; import java.math.BigDecimal; @Data public class CartItemVo implements Serializable { private Long gid; private String goodsName; private String goodsTitle; private BigDecimal goodsPrice; private String goodsImg; private String goodsType; private Integer num; public BigDecimal cartprice(){ return goodsPrice.multiply(BigDecimal.valueOf(num.doubleValue())); } }
redis中有许多的数据结构:
- String(字符串类型)常见使用场景是:存储 Session 信息、存储缓存信息(如详情页的缓存)、存储整数信息,可使用 incr 实现整数+1,和使用 decr 实现整数 -1;
- List(列表类型)常见使用场景是:实现简单的消息队列、存储某项列表数据;
- Hash(哈希表类型)常见使用场景是:存储 Session 信息、存储商品的购物车,购物车非常适合用哈希字典表示,使用人员唯一编号作为字典的 key,value 值可以存储商品的 id 和数量等信息、存储详情页信息;
- Set(集合类型)是一个无序并唯一的键值集合,它的常见使用场景是:关注功能,比如关注我的人和我关注的人,使用集合存储,可以保证人员不会重复;
- Sorted Set(有序集合类型)相比于 Set 集合类型多了一个排序属性 score(分值),它的常见使用场景是:可以用来存储排名信息、关注列表功能,这样就可以根据关注实现排序展示了。
@Override public void saveCart(User user, CartItemVo vo) { HashOperations
operations = redisTemplate.opsForHash(); //获取购物车key String bigKey=REDIS_CART_PREFIX + user.getId(); //获取购物车中商品的gid String hashKey=vo.getGid().toString(); //判断购物车中是否有该商品 Boolean has = operations.hasKey(bigKey, hashKey); //如果有数据 修改购物车 if(has){ CartItemVo item = operations.get(bigKey, hashKey); vo.setNum(item.getNum()+vo.getNum()); } //添加缓存 operations.put(bigKey, hashKey,vo); }
展示购物车:
@Override public List
loadCart(User user) { //获取购物车中的商品 HashOperations operations = redisTemplate.opsForHash(); String bigKey=REDIS_CART_PREFIX + user.getId(); //根据用户id获取购物车数据 List values = operations.values(bigKey); return values; }
前台:
后台:
清除缓存就行:
@RequestMapping("/userLogout") // 指定返回JsonResponseBody格式 public String logout (UserVo userVo , HttpServletRequest request, HttpServletResponse response){ String userToken = CookieUtils.getCookieValue(request, "userToken"); redisService.removeUser(userToken); CookieUtils.deleteCookie(request,response,"userToken"); CookieUtils.deleteCookie(request,response,"nickname"); return "redirect:/"; }
调用redis内置方法delete
HandlerMethodArgumentResolver
是Spring框架中的一个接口,用于解析处理方法参数。在Spring MVC中,当一个请求到达时,框架会尝试将请求参数映射到控制器方法的参数上。
HandlerMethodArgumentResolver
接口定义了一组方法,用于解析不同类型的方法参数。实现
HandlerMethodArgumentResolver
接口的类可以自定义参数解析逻辑,并告诉Spring如何将请求参数转换为方法参数。通常,开发人员可以根据业务需求实现自己的
HandlerMethodArgumentResolver
,以支持自定义的请求参数类型或者处理逻辑。使用
HandlerMethodArgumentResolver
可以帮助简化控制器方法的参数处理过程,提高代码的可读性和可维护性。
当您使用参数解析器时,您可以将输入的参数进行解析,并根据解析后的结果执行相应的操作。参数解析器可以帮助您从输入中提取所需的信息,并对其进行处理。
package com.lya.lyaspshop.core; import com.lya.lyaspshop.exception.BusinessException; import com.lya.lyaspshop.pojo.User; import com.lya.lyaspshop.service.impl.RedisServiceImpl; import com.lya.lyaspshop.utils.CookieUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.MethodParameter; import org.springframework.stereotype.Component; import org.springframework.web.bind.support.WebDataBinderFactory; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.method.support.ModelAndViewContainer; import javax.servlet.http.HttpServletRequest; import static com.lya.lyaspshop.core.Constants.USER_CACHE_TOKEN; import static com.lya.lyaspshop.resp.JsonResponseStatus.NO_LOGIN; @Component public class UserArgumentResolver implements HandlerMethodArgumentResolver { @Autowired private RedisServiceImpl redisService; @Override public boolean supportsParameter(MethodParameter parameter) { return parameter.getParameterType() == User.class; } @Override public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { HttpServletRequest request = (HttpServletRequest) webRequest.getNativeRequest(); String token = CookieUtils.getCookieValue(request, USER_CACHE_TOKEN); if (token == null) throw new BusinessException(NO_LOGIN); return redisService.getUserByToken(token); } }
配置:配置类才能使用
package com.lya.lyaspshop.core; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import java.util.List; @Component public class WebConfig implements WebMvcConfigurer { @Autowired private UserArgumentResolver userArgumentResolver; @Override public void addArgumentResolvers(List
resolvers) { resolvers.add(userArgumentResolver); } }
使用解析类: