欢迎来到我的CSDN主页!
我是Java方文山,一个在CSDN分享笔记的博主。
推荐给大家我的专栏《电商项目实战》。
点击这里,就可以查看我的主页啦!
Java方文山的个人主页
如果感觉还不错的话请给我点赞吧!
期待你的加入,一起学习,一起进步!
当我们点击商品的时候需要展示对应的商品详情,首先在首页商品页写入后端的接口
controller代码
@Controller
@RequestMapping("/goods")
public class GoodsController {
@Autowired
private IGoodsService goodsService;
@RequestMapping("/ByIdSelect")
public String ByIdSelect(GoodsVo vo, Model model){
Goods g = goodsService.getById(vo.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属性是否为空
-->
${(g.goodsTitle)!}
馨***呀
不好意思评价晚了,产品很好,价格比玻璃品便宜,没有我担心的杂色,发货快,包装好,全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颜色分类:大中小三件套(不含花)
<#include "common/footer.html">
效果展示
商品详情页面引入了一个cart.js,里面是有关该所有的点击事件方法
$(function(){
/**************数量加减***************/
$(".num .sub").click(function(){
var num = parseInt($(this).siblings("span").text());
if(num<=1){
$(this).attr("disabled","disabled");
}else{
num--;
$(this).siblings("span").text(num);
//获取除了货币符号以外的数字
var price = $(this).parents(".number").prev().text().substring(1);
//单价和数量相乘并保留两位小数
$(this).parents(".th").find(".sAll").text('¥'+(num*price).toFixed(2));
jisuan();
zg();
}
});
$(".num .add").click(function(){
var num = parseInt($(this).siblings("span").text());
if(num>=5){
confirm("限购5件");
}else{
num++;
$(this).siblings("span").text(num);
var price = $(this).parents(".number").prev().text().substring(1);
$(this).parents(".th").find(".sAll").text('¥'+(num*price).toFixed(2));
jisuan();
zg();
}
});
//计算总价
function jisuan(){
var all=0;
var len =$(".th input[type='checkbox']:checked").length;
if(len==0){
$("#all").text('¥'+parseFloat(0).toFixed(2));
}else{
$(".th input[type='checkbox']:checked").each(function(){
//获取小计里的数值
var sAll = $(this).parents(".pro").siblings('.sAll').text().substring(1);
//累加
all+=parseFloat(sAll);
//赋值
$("#all").text('¥'+all.toFixed(2));
})
}
}
//计算总共几件商品
function zg(){
var zsl = 0;
var index = $(".th input[type='checkbox']:checked").parents(".th").find(".num span");
var len =index.length;
if(len==0){
$("#sl").text(0);
}else{
index.each(function(){
zsl+=parseInt($(this).text());
$("#sl").text(zsl);
})
}
if($("#sl").text()>0){
$(".count").css("background","#c10000");
}else{
$(".count").css("background","#8e8e8e");
}
}
/*****************商品全选***********************/
$("input[type='checkbox']").on('click',function(){
var sf = $(this).is(":checked");
var sc= $(this).hasClass("checkAll");
if(sf){
if(sc){
$("input[type='checkbox']").each(function(){
this.checked=true;
});
zg();
jisuan();
}else{
$(this).checked=true;
var len = $("input[type='checkbox']:checked").length;
var len1 = $("input").length-1;
if(len==len1){
$("input[type='checkbox']").each(function(){
this.checked=true;
});
}
zg();
jisuan();
}
}else{
if(sc){
$("input[type='checkbox']").each(function(){
this.checked=false;
});
zg();
jisuan();
}else{
$(this).checked=false;
var len = $(".th input[type='checkbox']:checked").length;
var len1 = $("input").length-1;
if(len{
},"json")
});
//删除购物车商品
$('.del').click(function(){
//单个删除
if($(this).parent().parent().hasClass("th")){
$(".mask").show();
$(".tipDel").show();
index = $(this).parents(".th").index()-1;
$('.cer').click(function(){
$(".mask").hide();
$(".tipDel").hide();
$(".th").eq(index).remove();
$('.cer').off('click');
if($(".th").length==0){
$(".table .goOn").show();
}
})
}else{
//选中多个一起删除
if($(".th input[type='checkbox']:checked").length==0){
$(".mask").show();
$(".pleaseC").show();
}
else{
$(".mask").show();
$(".tipDel").show();
$('.cer').click(function(){
$(".th input[type='checkbox']:checked").each(function(j){
index = $(this).parents('.th').index()-1;
$(".th").eq(index).remove();
if($(".th").length==0){
$(".table .goOn").show();
}
})
$(".mask").hide();
$(".tipDel").hide();
zg();
jisuan();
})
}
}
})
$('.cancel').click(function(){
$(".mask").hide();
$(".tipDel").hide();
})
//改变商品规格
// $(".pro dd").hover(function(){
// var html='';
// html='修改';
// $(this).addClass("on").append(html).parents(".th").siblings(".th").find(".pro dd").removeClass("on").find('.edit').remove();
// $(".edit").each(function(i){
// $(this).attr("id",'edit'+i);
// $("#edit"+i).click(function(){
// $(".proDets").show();
// $(".mask").show();
// $(".changeBtn .buy").attr("data-id",i);
// })
// })
// },function(){
// $(this).removeClass("on");
// })
// $(".changeBtn .buy").click(function(){
// var index = $(this).attr("data-id");
// var result = $(".smallImg .on").find("img").attr("alt");
// $("#edit"+index).prev().text(result);
// $(".proDets").hide();
// $(".mask").hide();
// $("#edit"+index).parent("dd").removeClass("on").find(".edit").remove();
// });
// $(".changeBtn .cart").click(function(){
// $(".proDets").hide();
// $(".mask").hide();
// })
})
我们的用户购物车数据放在数据库太耗费数据库的资源了,我们可以将数据放入redis,进行一个时限判断,如果一周内没有进行数据访问就加入数据库并清除缓存。
我们需要编写新增和查询Redis中购物车数据方法
IRedisService
// 保存用户购物车信息
void saveCart(User user, GoodsVo vo);
// 查询用户购物车信息
List loadCart(User user);
IRedisService实现类
@Override
public List loadCart(User user) {
HashOperations operations=redisTemplate.opsForHash();
String bigKey=Constants.REDIS_CART_PREFIX + user.getId();
//根据用户Id查询所有的购物车信息
List values = operations.values(bigKey);
return values;
}
controller
@RequestMapping("/getCart")
public String getCart(GoodsVo vo, HttpServletRequest request, Model model) {
//根据键获取token
String token = CookieUtils.getCookieValue(request, "userToken");
//根据token获取用户
User user = redisService.loadUser(token);
//获取用户购物车商品信息
List goodsVos = redisService.loadCart(user);
//根据商品Id查询对应商品
List ids = goodsVos.stream().map(GoodsVo::getGid).collect(Collectors.toList());
List goods = goodsService.listByIds(ids);
// 进行遍历筛选合适的数据
for (Goods g : goods) {
//找到对应属性的商品
GoodsVo gv = goodsVos.stream()
.filter(v -> Objects.equals(v.getGid(), g.getGid()))
.findFirst()
.orElse(null);
if (gv != null) {
//将该商品g的属性赋值给GoodsVos
BeanUtils.copyProperties(g, gv);
}
}
System.out.println(goodsVos);
model.addAttribute("item", goodsVos);
return "cart";
}
因为我们redis中只有商品的id所以需要将所有商品的id拿到数据库中查询,将该商品的图片信息标题等查询出来利用BeanUtils将属性加入到goodsVos中,方便前端页面显示
<#include "common/head.html">
购物车
继续购物>
<#include "common/footer.html">
请选择宝贝
这里直接将我们后端所拿到的数据进行判断遍历展示即可
首先我们不止需要清除浏览器上的cookie还需要清除redis中保存的用户信息,所以在Redis的service层定义一个删除的方法
// 清除用户数据
void logout(String token);
实现类编写相应代码
@Override
public void logout(String token) {
//根据token删除对应的键
redisTemplate.delete(Constants.REDIS_USER_PREFIX +token);
}
这时候,我们就可以编写退出的controller代码了
@RequestMapping("/logout")
public String login( HttpServletRequest request, HttpServletResponse response){
//清除redis缓存
String token = CookieUtils.getCookieValue(request, "userToken");
redisService.logout(token);
//清除cookie
CookieUtils.deleteCookie(request,response,"userToken");
CookieUtils.deleteCookie(request,response,"nickname");
return "redirect:/";
}
清除浏览器cookie的同时也清除redis中的数据避免资源浪费
通过这几天的编写,不知道大家发现没有,我们很多方法中都有获取用户的token信息,可以说这段代码是重复的,我们可以将其优化掉
UserArgumentResolver
@Component
public class UserArgumentResolver implements HandlerMethodArgumentResolver {
@Autowired
private IRedisService redisService;
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.getGenericParameterType()== User.class;
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
HttpServletRequest request = (HttpServletRequest) webRequest.getNativeRequest();
//从请求中获取cookie
String token = CookieUtils.getCookieValue(request, "userToken");
User user = redisService.loadUser(token);
return user;
}
}
这个解析器的作用是判断控制器方法的参数是否为User类型,如果是,则会在处理请求之前执行resolveArgument方法。在resolveArgument方法中,它会通过HttpServletRequest获取请求中的cookie,然后调用redisService的loadUser方法根据cookie中的token加载对应的用户信息。最后,返回解析得到的User对象作为控制器方法的参数。
这里还需要一个config配置类,用于加载自定义解析器
WebConfig
@Component
public class WebConfig implements WebMvcConfigurer {
@Autowired
private UserArgumentResolver userArgumentResolver;
@Override
public void addArgumentResolvers(List resolvers) {
resolvers.add(userArgumentResolver);
}
}
到这里我的分享就结束了,欢迎到评论区探讨交流!!
如果觉得有用的话还请点个赞吧