目录
报错信息:Caused by: java.lang.IllegalStateException: No typehandler found for property xxx
一、自定义的参数解析器
footer.html
-
function
check
() {
-
$.get(
'/shopCar/check',{},function(rs){
-
if(rs.code!=
200){
-
alert(
'请先登录后再购买商品!');
-
}
else
-
location.href=
'/shopCar/queryShopCar';
-
},
'json');
-
}
ShopCarController
-
package com.xiaokun.spbootpro.controller;
-
-
import com.xiaokun.spbootpro.exception.BusinessException;
-
import com.xiaokun.spbootpro.model.User;
-
import com.xiaokun.spbootpro.service.IRedisService;
-
import com.xiaokun.spbootpro.utils.JsonResponseBody;
-
import com.xiaokun.spbootpro.utils.JsonResponseStatus;
-
import org.springframework.beans.factory.annotation.Autowired;
-
import org.springframework.web.bind.annotation.CookieValue;
-
import org.springframework.web.bind.annotation.RequestMapping;
-
import org.springframework.web.bind.annotation.RestController;
-
-
/**
-
* @author 小坤
-
* @create 2022-11-09-10:19
-
*/
-
@RestController
-
@RequestMapping("/shopCar")
-
public
class
ShopCarController {
-
@Autowired
-
private IRedisService redisService;
-
-
@RequestMapping("/check")
-
public JsonResponseBody
check
(@CookieValue("token") String token){
-
if(token ==
null)
-
throw
new
BusinessException(JsonResponseStatus.TOKEN_EEROR);
-
User user=redisService.getUserToRedis(token);
-
if(user ==
null)
-
throw
new
BusinessException(JsonResponseStatus.TOKEN_EEROR);
-
return
new
JsonResponseBody();
-
}
-
-
}
关于Mybatis-plus时间字段代码生成问题
org.springframework.data.redis.serializer.SerializationException: Could not read JSON: Cannot construct instance of `java.time.LocalDateTime` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
at [Source: (byte[])"{"@class":"com.zking.testspbootpro.model.User","nickname":"小胖","password":"6502cbf0ac7d357831536b119ff26d28","salt":"7ceff545c6944e5cb7da355ae6243939","registerDate":{"month":"DECEMBER","year":2021,"dayOfMonth":11,"hour":2,"minute":36,"monthValue":12,"nano":0,"second":56,"dayOfWeek":"SATURDAY","dayOfYear":345,"chronology":{"@class":"java.time.chrono.IsoChronology","id":"ISO","calendarType":"iso8601"}},"lastLoginDate":null,"loginCount":0}"; line: 1, column: 172] (through reference chain: com.zking.testspbootpro.model.User["registerDate"]); nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `java.time.LocalDateTime` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
at [Source: (byte[])"{"@class":"com.zking.testspbootpro.model.User","nickname":"小胖","password":"6502cbf0ac7d357831536b119ff26d28","salt":"7ceff545c6944e5cb7da355ae6243939","registerDate":{"month":"DECEMBER","year":2021,"dayOfMonth":11,"hour":2,"minute":36,"monthValue":12,"nano":0,"second":56,"dayOfWeek":"SATURDAY","dayOfYear":345,"chronology":{"@class":"java.time.chrono.IsoChronology","id":"ISO","calendarType":"iso8601"}},"lastLoginDate":null,"loginCount":0}"; line: 1, column: 172] (through reference chain: com.zking.testspbootpro.model.User["registerDate"])
出现上述错误,原因是使用了lastLoginDate,改成java.util.Date;改完之后为了避免干扰将redis中的数据以及cookie(浏览器缓存)中的数据清空,再次登录测试;
小编还遇到了一个错,可以看一下
报错信息:Caused by: java.lang.IllegalStateException: No typehandler found for property xxx
原因:
在相应的xml里的resultMap标签里的result标签里的property属性的值没有在实体类里找到,即property的值没有和实体类的属性名相对应,原因可能是写错了
解决办法:
进入相应的xml文件里,把该报错的值与实体类的属性对照,看是否写错了,如果写错则改成实体类有的属性
ShopCarController使用参数解析器之前的做法弊端 在每一个需要登录之后才能操作的功能,都需要做用户登录验证,即以下代码都需要写一遍
更改后的ShopCarController
-
package com.xiaokun.spbootpro.controller;
-
-
import com.xiaokun.spbootpro.exception.BusinessException;
-
import com.xiaokun.spbootpro.model.User;
-
import com.xiaokun.spbootpro.service.IRedisService;
-
import com.xiaokun.spbootpro.utils.JsonResponseBody;
-
import com.xiaokun.spbootpro.utils.JsonResponseStatus;
-
import org.springframework.beans.factory.annotation.Autowired;
-
import org.springframework.web.bind.annotation.CookieValue;
-
import org.springframework.web.bind.annotation.RequestMapping;
-
import org.springframework.web.bind.annotation.RestController;
-
-
/**
-
* @author 小坤
-
* @create 2022-11-09-10:19
-
*/
-
@RestController
-
@RequestMapping("/shopCar")
-
public
class
ShopCarController {
-
@Autowired
-
private IRedisService redisService;
-
-
/**
-
* 使用参数解析器之前的做法弊端
-
* 在每一个需要登录之后才能操作的功能,都需要做用户登录验证,即以下代码都需要写一遍
-
* @param token
-
* @return
-
*/
-
// @RequestMapping("/check")
-
// public JsonResponseBody check(@CookieValue("token") String token){
-
// if(token == null)
-
// throw new BusinessException(JsonResponseStatus.TOKEN_EEROR);
-
// User user=redisService.getUserToRedis(token);
-
// if(user == null)
-
// throw new BusinessException(JsonResponseStatus.TOKEN_EEROR);
-
// return new JsonResponseBody();
-
// }
-
-
/**
-
* 带了user,会自动进入参数解析器supportsParameter
-
* @param user
-
* @return
-
*/
-
@RequestMapping("/check")
-
public JsonResponseBody
check
(User user){
-
-
return
new
JsonResponseBody();
-
}
-
-
}
参数解析器类
-
package com.xiaokun.spbootpro.config;
-
-
import com.xiaokun.spbootpro.exception.BusinessException;
-
import com.xiaokun.spbootpro.model.User;
-
import com.xiaokun.spbootpro.service.IRedisService;
-
import com.xiaokun.spbootpro.utils.CookieUtils;
-
import com.xiaokun.spbootpro.utils.JsonResponseStatus;
-
import org.springframework.beans.factory.annotation.Autowired;
-
import org.springframework.core.MethodParameter;
-
import org.springframework.stereotype.Component;
-
import org.springframework.stereotype.Controller;
-
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 org.springframework.web.servlet.HandlerExceptionResolver;
-
-
import javax.servlet.http.HttpServletRequest;
-
-
/**
-
* @author 小坤
-
* @create 2022-11-09-16:14
-
*
-
* 凡是实现HandlerMethodArgumentResolver接口的类都是参数解析器类
-
*/
-
@Component
-
public
class
UserArgumentResovler
implements
HandlerMethodArgumentResolver {
-
-
@Autowired
-
private IRedisService redisService;
-
-
/**
-
* supportsParameter的方法的返回值,true:则会调用下面resolveArgument
-
* false:不调用
-
* @param methodParameter
-
* @return
-
*/
-
@Override
-
public
boolean
supportsParameter
(MethodParameter methodParameter) {
-
return methodParameter.getParameterType() == User.class;
-
}
-
-
/**
-
* resolveArgument:具体的业务代码处理
-
* @param methodParameter
-
* @param modelAndViewContainer
-
* @param nativeWebRequest
-
* @param webDataBinderFactory
-
* @return
-
* @throws Exception
-
*/
-
@Override
-
public Object
resolveArgument
(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory)
throws Exception {
-
HttpServletRequest request=(HttpServletRequest)nativeWebRequest.getNativeRequest();
-
String token=CookieUtils.getCookieValue(request,
"token");
-
if(token ==
null)
-
throw
new
BusinessException(JsonResponseStatus.TOKEN_EEROR);
-
User user=redisService.getUserToRedis(token);
-
if(user ==
null)
-
throw
new
BusinessException(JsonResponseStatus.TOKEN_EEROR);
-
return user;
-
}
-
}
WebMvcConfigurer 资源映射器、相当于web.xml
WebMvcConfigurer添加之后,会覆盖application.yml中的静态资源映射⬇⬇
所以需要重新去添加配置,固定配置,按需拷贝咯
-
package com.xiaokun.spbootpro.config;
-
-
import org.springframework.beans.factory.annotation.Autowired;
-
import org.springframework.context.annotation.Configuration;
-
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;
-
-
/**
-
* @author 小坤
-
* @create 2022-11-09-16:41
-
*
-
* WebMvcConfigurer添加之后,会覆盖application.yml中的静态资源映射
-
*/
-
@Configuration
-
public
class
WebConfig
implements
WebMvcConfigurer {
-
-
@Autowired
-
private UserArgumentResovler userArgumentResovler;
-
-
/**
-
* 配置静态资源访问映射,使用了WebMvcConfigurer会覆盖原有的application.yml文件中的静态资源配置
-
* @param registry
-
*/
-
@Override
-
public
void
addResourceHandlers
(ResourceHandlerRegistry registry) {
-
registry.addResourceHandler(
"/static/**")
-
.addResourceLocations(
"classpath:/static/");
-
}
-
-
/**
-
* 添加自定义的参数解析器
-
* @param resolvers
-
*/
-
@Override
-
public
void
addArgumentResolvers
(List<HandlerMethodArgumentResolver> resolvers) {
-
resolvers.add(userArgumentResovler);
-
}
-
}
凡是controller中的方法中包含参数User,都会进参数解析器UserArgumentResovler中的resolveArgument方法;这样一定程度下可以减少用户信息登录检验;
当然,我们也可以通过拦截器、过滤器、aop等方式,来解决这一类问题
修改配置类后建议重启一下项目 !!!
我在user中加了一个id字段
二、购物车后台
定义购物车对象ShopCar
1.1购物车中商品集合
定义购物车商品详情对象ShopCarItem
商品ID/商品名称/商品单价/商品图片/商品数量/小计计算方法
1.2加入购物车
1.3删除购物车中指定商品
1.4更新购物车中商品数量
1.5清空购物车
1.6总价计算
-
package com.xiaokun.spbootpro.model.vo;
-
-
import java.util.ArrayList;
-
import java.util.Arrays;
-
import java.util.List;
-
import java.util.ListIterator;
-
-
/**
-
* @author 小坤
-
* @create 2022-11-10-14:49
-
*
-
* 购物车对象 vo:view object
-
*
-
*/
-
public
class
ShopCar {
-
// 1.1购物车中商品集合
-
private List<ShopCarItem> items=
new
ArrayList<>();
-
-
//set get方法
-
public List<ShopCarItem>
getItems
() {
-
return items;
-
}
-
-
public
void
setItems
(List<ShopCarItem> items) {
-
this.items = items;
-
}
-
-
//增加
-
//1.2加入购物车
-
public
void
add
(ShopCarItem shopCarItem){
-
//循环遍历购物车集合
-
for (ShopCarItem item : items) {
-
//判断加入购物车中的商品ID与购物车中的商品ID是否一致
-
if (item.getGid().equals(shopCarItem.getGid())) {
-
//获取购物车中原有商品的数量,再进行+1
-
Integer
num
= item.getQuantity();
-
item.setQuantity(num +
1);
-
return;
-
}
-
}
-
//加入购物车
-
items.add(shopCarItem);
-
}
-
-
//删除
-
//1.3删除购物车中指定商品
-
public
void
delete
(String gids) {
-
//将gids分割后转换成List集合
-
List<String> ids = Arrays.asList(gids.split(
","));
-
//获取商品集合迭代器对象
-
ListIterator<ShopCarItem> it = items.listIterator();
-
//循环遍历迭代器
-
while (it.hasNext()) {
-
//获取迭代器元素并移动下标
-
ShopCarItem
shopCarItem
= it.next();
-
//判断购物车中的商品ID是否在被删除商品的ID集合中
-
if (ids.contains(shopCarItem.getGid() +
"")) {
-
//删除商品
-
it.remove();
-
}
-
}
-
}
-
-
//修改
-
//1.4更新购物车中商品数量
-
public
void
update
(ShopCarItem shopCarItem){
-
//循环遍历购物车集合
-
for (ShopCarItem item : items) {
-
if (shopCarItem.getGid().equals(item.getGid())){
-
item.setQuantity(shopCarItem.getQuantity());
-
}
-
}
-
}
-
-
// 1.5清空购物车
-
public
void
clear
() {
-
items.clear();
-
}
-
-
-
// 1.6总价计算
-
// public BigDecimal total() {
-
// BigDecimal total = new BigDecimal(0);
-
// for (ShopCarItem item : items) {
-
// total = total.add(item.smalltotal());
-
// }
-
// return total;
-
// }
-
-
}
-
package com.xiaokun.spbootpro.model.vo;
-
-
import lombok.AllArgsConstructor;
-
import lombok.Data;
-
import lombok.NoArgsConstructor;
-
-
import java.awt.*;
-
import java.math.BigDecimal;
-
import java.util.ArrayList;
-
import java.util.List;
-
-
/**
-
* @author 小坤
-
* @create 2022-11-10-14:50
-
*
-
* 购物车明细
-
*/
-
@Data
-
@NoArgsConstructor
-
@AllArgsConstructor
-
public
class
ShopCarItem {
-
//商品id、商品名称、商品单价、商品数量、商品图片
-
private Long gid;
-
private String goodsName;
-
private String goodsImg;
-
private BigDecimal goodsPrice;
-
private Integer quantity;
-
-
/**
-
* 这是个虚拟方法,用于计算商品的小计
-
* 公式:商品的单价*数量=小计
-
* @return
-
*/
-
public BigDecimal
smalltotal
(){
-
BigDecimal num=
new
BigDecimal(quantity);
-
return goodsPrice.multiply(num);
-
}
-
-
}
web层定义 ShopCarController
1) 从session中获取购物车对象ShopCar
注:根据当前登陆用户ID绑定购物车,确保一人一车
2) 加入购物车方法
3) 查询购物车商品方法
4) 删除购物车指定商品方法
5) 更新购物车商品数量方法
-
package com.xiaokun.spbootpro.controller;
-
-
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-
import com.xiaokun.spbootpro.exception.BusinessException;
-
import com.xiaokun.spbootpro.model.Goods;
-
import com.xiaokun.spbootpro.model.User;
-
import com.xiaokun.spbootpro.model.vo.ShopCar;
-
import com.xiaokun.spbootpro.model.vo.ShopCarItem;
-
import com.xiaokun.spbootpro.service.IGoodsService;
-
import com.xiaokun.spbootpro.service.IRedisService;
-
import com.xiaokun.spbootpro.utils.JsonResponseBody;
-
import com.xiaokun.spbootpro.utils.JsonResponseStatus;
-
import org.springframework.beans.factory.annotation.Autowired;
-
import org.springframework.stereotype.Controller;
-
import org.springframework.web.bind.annotation.CookieValue;
-
import org.springframework.web.bind.annotation.RequestMapping;
-
import org.springframework.web.bind.annotation.ResponseBody;
-
import org.springframework.web.bind.annotation.RestController;
-
import org.springframework.web.servlet.ModelAndView;
-
-
import javax.servlet.http.HttpServletRequest;
-
import javax.servlet.http.HttpServletResponse;
-
import javax.servlet.http.HttpSession;
-
-
/**
-
* @author 小坤
-
* @create 2022-11-09-10:19
-
*/
-
@Controller
-
@RequestMapping("/shopCar")
-
public
class
ShopCarController {
-
@Autowired
-
private IRedisService redisService;
-
-
@Autowired
-
private IGoodsService goodsService;
-
-
/**
-
* 使用参数解析器之前的做法弊端
-
* 在每一个需要登录之后才能操作的功能,都需要做用户登录验证,即以下代码都需要写一遍
-
* @param token
-
* @return
-
*/
-
// @RequestMapping("/check")
-
// public JsonResponseBody check(@CookieValue("token") String token){
-
// if(token == null)
-
// throw new BusinessException(JsonResponseStatus.TOKEN_EEROR);
-
// User user=redisService.getUserToRedis(token);
-
// if(user == null)
-
// throw new BusinessException(JsonResponseStatus.TOKEN_EEROR);
-
// return new JsonResponseBody();
-
// }
-
-
/**
-
* 带了user,会自动进入参数解析器supportsParameter
-
* @param user
-
* @return
-
*/
-
@RequestMapping("/check")
-
@ResponseBody
-
public JsonResponseBody
check
(User user){
-
-
return
new
JsonResponseBody();
-
}
-
-
//私有方法 从session获取购物对象
-
private ShopCar
getShopCar
(User user,HttpServletRequest request){
-
HttpSession session=request.getSession();
-
ShopCar
shopCar
= (ShopCar) session.getAttribute(user.getId() +
"_shopCar");
-
if (shopCar==
null){
-
shopCar=
new
ShopCar();
-
session.setAttribute(user.getId() +
"_shopCar",shopCar);
-
}
-
return shopCar;
-
}
-
-
//查询
-
@RequestMapping("/queryShopCar")
-
public ModelAndView
queryShopCar
(User user,
-
HttpServletRequest request,
-
HttpServletResponse response){
-
ModelAndView mv=
new
ModelAndView();
-
ShopCar shopCar=getShopCar(user,request);
-
mv.addObject(
"shopCar",shopCar);
-
mv.setViewName(
"cart.html");
-
return mv;
-
}
-
-
//增加
-
@RequestMapping("/add")
-
@ResponseBody
-
public JsonResponseBody
add
(User user,
-
HttpServletRequest request,
-
HttpServletResponse response,long gid){
-
ModelAndView mv=
new
ModelAndView();
-
ShopCar shopCar=getShopCar(user,request);
-
Goods
goods
= goodsService.getOne(
new
QueryWrapper<Goods>().eq(
"gid", gid));
-
//初始化商品详情ShopCarItem
-
ShopCarItem item=
new
ShopCarItem();
-
item.setQuantity(
1);
-
item.setGid(goods.getGid());
-
item.setGoodsImg(goods.getGoodsImg());
-
item.setGoodsName(goods.getGoodsName());
-
item.setGoodsPrice(goods.getGoodsPrice());
-
//加入购物车
-
shopCar.add(item);
-
return
new
JsonResponseBody();
-
}
-
-
//修改
-
@RequestMapping("/update")
-
@ResponseBody
-
public JsonResponseBody
update
(User user,
-
HttpServletRequest request,
-
HttpServletResponse response,ShopCarItem shopCarItem){
-
ModelAndView mv=
new
ModelAndView();
-
ShopCar shopCar=getShopCar(user,request);
-
shopCar.update(shopCarItem);
-
return
new
JsonResponseBody();
-
}
-
-
//删除
-
@RequestMapping("/delete")
-
@ResponseBody
-
public JsonResponseBody
delete
(User user,
-
HttpServletRequest request,
-
HttpServletResponse response,String gids){
-
ModelAndView mv=
new
ModelAndView();
-
ShopCar shopCar=getShopCar(user,request);
-
shopCar.delete(gids);
-
return
new
JsonResponseBody();
-
}
-
-
}
三、商品详情页
修改index.html
商品详情页的模板跳转地址如下
${ctx}/page/proDetail.html 先使用这个跳转地址,看是否可以跳转
index.html
-
<!DOCTYPE html>
-
<html>
-
<head lang="en">
-
<#include "common/head.html">
-
<link rel="stylesheet" type="text/css" href="css/public.css"/>
-
<link rel="stylesheet" type="text/css" href="css/index.css" />
-
</head>
-
<body>
-
<!------------------------------head------------------------------>
-
<#include "common/top.html">
-
-
<!-------------------------banner--------------------------->
-
<div class="block_home_slider">
-
<div id="home_slider" class="flexslider">
-
<ul class="slides">
-
<li>
-
<div class="slide">
-
<img src="img/banner2.jpg"/>
-
</div>
-
</li>
-
<li>
-
<div class="slide">
-
<img src="img/banner1.jpg"/>
-
</div>
-
</li>
-
</ul>
-
</div>
-
</div>
-
-
<!------------------------------thImg------------------------------>
-
<div class="thImg">
-
<div class="clearfix">
-
<a href="${ctx}/page/vase_proList.html">
<img src="img/i1.jpg"/>
</a>
-
<a href="${ctx}/page/proList.html">
<img src="img/i2.jpg"/>
</a>
-
<a href="#2">
<img src="img/i3.jpg"/>
</a>
-
</div>
-
</div>
-
-
<!------------------------------news------------------------------>
-
<div class="news">
-
<div class="wrapper">
-
<h2>
<img src="img/ih1.jpg"/>
</h2>
-
<div class="top clearfix">
-
<a href="${ctx}/page/proDetail.html">
<img src="img/n1.jpg"/>
<p>
</p>
</a>
-
<a href="${ctx}/page/proDetail.html">
<img src="img/n2.jpg"/>
<p>
</p>
</a>
-
<a href="${ctx}/page/proDetail.html">
<img src="img/n3.jpg"/>
<p>
</p>
</a>
-
</div>
-
<div class="bott clearfix">
-
<a href="${ctx}/page/proDetail.html">
<img src="img/n4.jpg"/>
<p>
</p>
</a>
-
<a href="${ctx}/page/proDetail.html">
<img src="img/n5.jpg"/>
<p>
</p>
</a>
-
<a href="${ctx}/page/proDetail.html">
<img src="img/n6.jpg"/>
<p>
</p>
</a>
-
</div>
-
<h2>
<img src="img/ih2.jpg"/>
</h2>
-
<#if gt01?? && gt01?size gt 0>
-
<#list gt01?keys as key>
-
<div class="flower clearfix tran">
-
<!--遍历gt01中所有的key,是为了该key中的数组对象-->
-
<#list gt01[key] as g>
-
<a href="${ctx}/page/proDetail.html" class="clearfix">
-
<dl>
-
<dt>
-
<span class="abl">
</span>
-
<img src="${g.goodsImg}"/>
-
<span class="abr">
</span>
-
</dt>
-
<dd>${g.goodsName}
</dd>
-
<dd>
<span>¥ ${g.goodsPrice}
</span>
</dd>
-
</dl>
-
</a>
-
</#list>
-
</div>
-
</#list>
-
</#if>
-
-
</div>
-
</div>
-
-
<!------------------------------ad------------------------------>
-
<a href="#" class="ad">
<img src="img/ib1.jpg"/>
</a>
-
-
<!------------------------------people------------------------------>
-
<div class="people">
-
<div class="wrapper">
-
<h2>
<img src="img/ih3.jpg"/>
</h2>
-
<#if gt07?? && gt07?size gt 0>
-
<#list gt07?keys as key>
-
<div class="pList clearfix tran">
-
<#list gt07[key] as g>
-
<a href="${ctx}/page/proDetail.html">
-
<dl>
-
<dt>
-
<span class="abl">
</span>
-
<img src="${g.goodsImg}"/>
-
<span class="abr">
</span>
-
</dt>
-
<dd>${g.goodsName}
</dd>
-
<dd>
<span>¥${g.goodsPrice}
</span>
</dd>
-
</dl>
-
</a>
-
</#list>
-
</div>
-
</#list>
-
</#if>
-
-
</div>
-
</div>
-
-
<#include "common/footer.html"/>
-
-
<script src="js/public.js" type="text/javascript" charset="utf-8">
</script>
-
<script src="js/nav.js" type="text/javascript" charset="utf-8">
</script>
-
<script src="js/jquery.flexslider-min.js" type="text/javascript" charset="utf-8">
</script>
-
<script type="text/javascript">
-
$(
function(
) {
-
$(
'#home_slider').
flexslider({
-
animation:
'slide',
-
controlNav:
true,
-
directionNav:
true,
-
animationLoop:
true,
-
slideshow:
true,
-
slideshowSpeed:
2000,
-
useCSS:
false
-
});
-
-
});
-
</script>
-
</body>
-
</html>
可以跳转后,我们需要跳转后台controller加载数据
将对应controller层的代码编写好后,修改index.html中详情页的模板跳转地址${ctx}/goods/detail/${g.gid}
controller代码在下面
-
<#if gt01?? && gt01?size gt 0>
-
<#list gt01?keys as key>
-
<div class="flower clearfix tran">
-
<#list gt01[key] as g>
-
<a href="${ctx}/goods/detail/${g.gid}" class="clearfix">
-
<dl>
-
<dt>
-
<span class="abl">
</span>
-
<img src="${g.goodsImg}"/>
-
<span class="abr">
</span>
-
</dt>
-
<dd>${g.goodsName}
</dd>
-
<dd>
<span>¥ ${g.goodsPrice}
</span>
</dd>
-
</dl>
-
</a>
-
</#list>
-
</div>
-
</#list>
-
</#if>
-
<#if gt07?? && gt01?size gt 0>
-
<#list gt07?keys as key>
-
<div class="pList clearfix tran">
-
<#list gt07[key] as g>
-
<a href="${ctx}/goods/detail/${g.gid}">
-
<dl>
-
<dt>
-
<span class="abl">
</span>
-
<img src="${g.goodsImg}"/>
-
<span class="abr">
</span>
-
</dt>
-
<dd>${g.goodsName}
</dd>
-
<dd>
<span>¥${g.goodsPrice}
</span>
</dd>
-
</dl>
-
</a>
-
</#list>
-
</div>
-
</#list>
-
</#if>
proDetail.html 商品详情页
跳转详情页不能返回RestController 使用ModelAndView所以必须换成Controller
GoodsController
-
package com.xiaokun.spbootpro.controller;
-
-
-
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-
import com.xiaokun.spbootpro.model.Goods;
-
import com.xiaokun.spbootpro.service.IGoodsService;
-
import org.springframework.beans.factory.annotation.Autowired;
-
import org.springframework.stereotype.Controller;
-
import org.springframework.web.bind.annotation.PathVariable;
-
import org.springframework.web.bind.annotation.RequestMapping;
-
-
import org.springframework.web.bind.annotation.RestController;
-
import org.springframework.web.servlet.ModelAndView;
-
-
/**
-
* <p>
-
* 商品信息表 前端控制器
-
* </p>
-
*
-
* @author xiaokun
-
* @since 2022-11-09
-
*/
-
@Controller
-
@RequestMapping("/goods")
-
public
class
GoodsController {
-
@Autowired
-
private IGoodsService goodsService;
-
-
@RequestMapping("/detail/{gid}")
-
public ModelAndView
detail
(@PathVariable("gid") long gid){
-
//根据商品ID查询单个商品信息
-
Goods
goods
= goodsService.getOne(
new
QueryWrapper<Goods>().eq(
"gid", gid));
-
//将商品存入model带入前端展示
-
ModelAndView mv=
new
ModelAndView();
-
mv.addObject(
"goods",goods);
-
//设置跳转页面,商品详情页
-
mv.setViewName(
"proDetail.html");
-
return mv;
-
}
-
-
-
}
四、商品详情页加入购物车
点击加入购物车,商品详情页跳转到购物车页面并商品显示在购物车中
加入并展示购物车
-
$(function () {
-
$(
".cart").click(function () {
-
$.get(
'/shopCar/add',{gid:$(
"#gids").val()},function(rs){
-
if(rs.code!=
200){
-
alert(
'请先登录后再加购商品!');
-
}
else
-
location.href=
'/page/cart.html';
-
},
'json');
-
});
-
})
添加这行
这样点击商品,就跳转到购物车了,接下来把加入购物车中的商品变活
-
<#if shopCar??>
-
<#list shopCar.items as g>
-
<div class="th">
-
<div class="pro clearfix">
-
<label class="fl">
-
<input type="hidden" value="${g.gid!}"/>
-
<input type="checkbox"/>
-
<span>
</span>
-
</label>
-
<a class="fl" href="#">
-
<dl class="clearfix">
-
<dt class="fl">
<img style="width: 120px;height: 120px;" src="${g.goodsImg}">
</dt>
-
<dd class="fl">
-
<p>${g.goodsName}
</p>
-
<p>颜色分类:
</p>
-
<p>白色瓷瓶+白色串枚
</p>
-
</dd>
-
</dl>
-
</a>
-
</div>
-
<div class="price">¥${g.goodsPrice}
</div>
-
<div class="number">
-
<p class="num clearfix">
-
<img class="fl sub" src="img/temp/sub.jpg">
-
<span class="fl">${g.quantity}
</span>
-
<img class="fl add" src="img/temp/add.jpg">
-
</p>
-
</div>
-
<div class="price sAll">¥${g.smalltotal()}
</div>
-
<div class="price">
<a class="del" href="javascript:void(0)">删除
</a>
</div>
-
</div>
-
</#list>
-
</#if>
即增加又查询
这是我刚刚加入购物车的商品,数据变活ok
五、购物车删除功能
删除购物车中指定商品
1)点击删除按钮删除单个商品
2)全选商品删除部分或者全部商品
原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<len1){
-
$(
'.checkAll').attr(
"checked",
false);
-
}
-
zg();
-
jisuan();
-
}
-
}
-
-
});
-
/****************************proDetail 加入购物车*******************************/
-
$(
".btns .cart").click(function(){
-
if($(
".categ p").hasClass(
"on")){
-
var
num
= parseInt($(
".num span").text());
-
var
num1
= parseInt($(
".goCart span").text());
-
$(
".goCart span").text(num+num1);
-
}
-
});
-
-
//删除购物车商品
-
$(
'.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='<span class="edit">修改</span>';
-
// $(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();
-
// })
-
})
cart.js进行整改
-
//删除购物车商品
-
$(
'.del').click(function(){
-
let
gids
=
"";
-
//单个删除
-
if($(
this).parent().parent().hasClass(
"th")){
-
$(
".mask").show();
-
$(
".tipDel").show();
-
index = $(
this).parents(
".th").index()-
1;
-
//TODO 获取当前的checkbox中设置的隐藏域(包含了商品ID)
-
gids=$(
".th").eq(index).find(
'div:eq(0) input[type=hidden]').val();
-
console.log(gids);
-
-
$(
'.cer').click(function(){
-
$(
".mask").hide();
-
$(
".tipDel").hide();
-
$(
".th").eq(index).remove();
-
$(
'.cer').off(
'click');
-
if($(
".th").length==
0){
-
$(
".table .goOn").show();
-
}
-
//TODO
-
del(gids);
-
})
-
}
else{
-
//选中多个一起删除
-
if($(
".th input[type='checkbox']:checked").length==
0){
-
$(
".mask").show();
-
$(
".pleaseC").show();
-
}
-
else{
-
$(
".mask").show();
-
$(
".tipDel").show();
-
-
//TODO 先获取所有即将被删除的商品ID
-
let
gidArr
=
new
Array();
-
$(
".th input[type='checkbox']:checked").each(function(j) {
-
index = $(
this).parents(
'.th').index() -
1;
-
//在这里需要获取当前行商品的商品ID
-
gidArr.push($(
".th").eq(index).find(
"div:eq(0) input[type='hidden']").val());
-
});
-
gids = gidArr.join(
",");
-
console.log(gids);
-
-
$(
'.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();
-
-
//TODO
-
del(gids);
-
})
-
}
-
}
-
})
-
-
#在页面初始化事件外添加删除方法
-
//删除商品
-
function
del
(gids){
-
$.post(
'/shopCar/delete',{
-
'gids':gids
-
},function(rs){
-
if(rs.code!=
200)
-
alert(rs.msg);
-
else
-
location.href=
'/shopCar/queryShopCar';
-
},
'json');
-
}
六、购物车修改功能
修改购物车中商品数量
cart.js进行整改
-
$(
".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();
-
-
//TODO 获取当前行的行索引
-
let
index
= $(
this).parents(
".th").index()-
1;
-
//获取当前的checkbox中设置的隐藏域(包含了商品ID)
-
let gid=$(
".th").eq(index).find(
'div:eq(0) input[type=hidden]').val();
-
update(num,gid);
-
}
-
});
-
$(
".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();
-
-
//TODO 获取当前行的行索引
-
let
index
= $(
this).parents(
".th").index()-
1;
-
//获取当前的checkbox中设置的隐藏域(包含了商品ID)
-
let gid=$(
".th").eq(index).find(
'div:eq(0) input[type=hidden]').val();
-
update(num,gid);
-
}
-
});
-
-
#在页面初始化事件外添加修改方法
-
//更新商品数量
-
function
update
(num,gid){
-
$.post(
'/shopCar/update',{
-
'gid':gid,
-
'quantity':num
-
},function(rs){
-
if(rs.code!=
200)
-
alert(rs.msg);
-
else
-
location.href=
'/shopCar/queryShopCar';
-
},
'json');
-
}
最终版
-
$(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();
-
-
//TODO 获取当前行的行索引
-
let
index
= $(
this).parents(
".th").index()-
1;
-
//获取当前的checkbox中设置的隐藏域(包含了商品ID)
-
let gid=$(
".th").eq(index).find(
'div:eq(0) input[type=hidden]').val();
-
update(num,gid);
-
}
-
});
-
$(
".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();
-
-
//TODO 获取当前行的行索引
-
let
index
= $(
this).parents(
".th").index()-
1;
-
//获取当前的checkbox中设置的隐藏域(包含了商品ID)
-
let gid=$(
".th").eq(index).find(
'div:eq(0) input[type=hidden]').val();
-
update(num,gid);
-
}
-
});
-
//计算总价
-
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<len1){
-
$(
'.checkAll').attr(
"checked",
false);
-
}
-
zg();
-
jisuan();
-
}
-
}
-
-
});
-
/****************************proDetail 加入购物车*******************************/
-
$(
".btns .cart").click(function(){
-
if($(
".categ p").hasClass(
"on")){
-
var
num
= parseInt($(
".num span").text());
-
var
num1
= parseInt($(
".goCart span").text());
-
$(
".goCart span").text(num+num1);
-
}
-
});
-
-
//删除购物车商品
-
$(
'.del').click(function(){
-
//定义商品id 比如:1,2,3,4,5
-
let
gids
=
"";
-
//单个删除
-
if($(
this).parent().parent().hasClass(
"th")){
-
$(
".mask").show();
-
$(
".tipDel").show();
-
index = $(
this).parents(
".th").index()-
1;
-
-
//TODO 获取当前的checkbox中设置的隐藏域(包含了商品ID)
-
gids=$(
".th").eq(index).find(
'div:eq(0) input[type=hidden]').val();
-
console.log(gids);
-
-
$(
'.cer').click(function(){
-
$(
".mask").hide();
-
$(
".tipDel").hide();
-
$(
".th").eq(index).remove();
-
$(
'.cer').off(
'click');
-
if($(
".th").length==
0){
-
$(
".table .goOn").show();
-
}
-
del(gids);
-
})
-
}
else{
-
//选中多个一起删除
-
if($(
".th input[type='checkbox']:checked").length==
0){
-
$(
".mask").show();
-
$(
".pleaseC").show();
-
}
-
else{
-
$(
".mask").show();
-
$(
".tipDel").show();
-
-
//TODO 先获取所有即将被删除的商品ID
-
let
gidarr
=
new
Array();
-
$(
".th input[type='checkbox']:checked").each(function(j){
-
gidarr.push($(
".th").eq(index).find(
'div:eq(0) input[type=hidden]').val());
-
// gids += $(".th").eq(index).find('div:eq(0) input[type=hidden]').val(); 很容易报数据下标越界异常
-
});
-
gids = gidarr.join(
",");
-
-
$(
'.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();
-
-
del(gids);
-
})
-
}
-
}
-
})
-
$(
'.cancel').click(function(){
-
$(
".mask").hide();
-
$(
".tipDel").hide();
-
})
-
//改变商品规格
-
// $(".pro dd").hover(function(){
-
// var html='';
-
// html='<span class="edit">修改</span>';
-
// $(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();
-
// })
-
})
-
//删除商品
-
function
del
(gids) {
-
$.post(
'/shopCar/delete',{
-
'gids':gids
-
},function(rs){
-
if(rs.code!=
200)
-
alert(rs.msg);
-
else
-
location.href=
'/shopCar/queryShopCar';
-
},
'json');
-
}
-
-
//修改商品数量
-
function
update
(num,gid){
-
$.post(
'/shopCar/update',{
-
'gid':gid,
-
'quantity':num
-
},function(rs){
-
if(rs.code!=
200)
-
alert(rs.msg);
-
else
-
location.href=
'/shopCar/queryShopCar';
-
},
'json');
-
}
转载:https://blog.csdn.net/weixin_67450855/article/details/127765226