1 用户模块
1.1 用户登出操作(SSO)
要达成的效果就是:
用户在jt-web主页面点击了退出之后,跳转回jt-web主页面,并且不再显示用户的名称。
隐含的过程是:
浏览器:要删除用户上次登录时的cookie信息(即作废ticket);
服务器:要删除用户上次登录存入的登录的redis缓存信息(因为redis中的记录是根据ticket来记录的,ticket的value就是redis中的key。ticket作废了,redis中这条数据也就作废了)
1.1.1 当前情况分析
点击了“退出”后,浏览器地址栏中的地址变成了:
可见,这是一个同域请求。
所以需要在自家的jt-web的controller中写一个方法,来接收
1.1.2 编辑jt-web中的UserController
去处理登出请求。
有两种方式:
/**
* 方式1:用最原始的手敲一行行代码的方式 (没用用Cookie工具API)
* 用户在点击“退出”时,要重定向到jt-web的首页,并删除这个用户的cookie和redis中这个用户的数据
* 步骤:通过cookie获取ticket信息。根据cookie中的cookie的name,获取到这个name对应的value(就是ticket的信息)。
* 这个ticket就是redis中的key
* url:http://www.jt.com/user/logout.html
* 返回值:重定向到jt-web首页
* 同时要做的:删除用户cookie,并在redis中删除这个用户的数据
* 思路:要先获取到他的cookie中的key和value(value就是ticket)
*/
@RequestMapping("/logout")
public String logout(HttpServletRequest request,HttpServletResponse response){
//1.request.getCookies()获取到的目前还存活的所有的cookies。
Cookie[] cookies = request.getCookies();
//2.校验Cookie[] 中是否有数据(是否为null)
//cookies不是空的,并且 cookies中确实存的是cookie的信息
if(cookies !=null && cookies.length>0){
//3 从cookies中获取到当前这个用户的cookie
for (Cookie cookie: cookies ) {
if("JT_TICKET".equals(cookie.getName())){ //在之前用户注册时,服务器把cookie给用户时,就规定了,这个cookie的名字是JT_TICKET
//4 删除redis中这个用户的登录的数据
String ticket = cookie.getValue();
//打个桩===看看ticket中是什么样的数据
//System.out.println(ticket); //8b80e3adaaeb44b896e2ffbc50540026
//根据ticket的值,就是redis中的key,去删除redis中的数据
jedisCluster.del(ticket);
//5 删除cookie
cookie.setMaxAge(0);
//由于通过request对象获取的cookie中只有name和value,而cookie的其他属性值(path和domain需要自己赋值)
cookie.setPath("/"); //cookie要设置成与用户原来的cookie中的这个属性值一致
cookie.setDomain("jt.com"); //cookie要设置成与用户原来的cook
response.addCookie(cookie);
//当cookies都被遍历完了,就break跳出
break;
}
}
}
return "redirect:/"; //重定向到jt-web的首页
}
/**
* 方式2:通过工具API 见1.1.2.1
* 用户在点击“退出”时,要重定向到jt-web的首页,并删除这个用户的cookie和redis中这个用户的数据
* 步骤:通过cookie获取ticket信息。根据cookie中的cookie的name,获取到这个name对应的value(就是ticket的信息)。
* 这个ticket就是redis中的key
* url:http://www.jt.com/user/logout.html
* 返回值:重定向到jt-web首页
* 同时要做的:删除用户cookie,并在redis中删除这个用户的数据
* 思路:要先获取到他的cookie中的key(就是ticket)和value
*/
@RequestMapping("/logout")
public String logout(HttpServletRequest request,HttpServletResponse response){
//1.通过工具API获取cookie的值,也就是ticket
String ticket = CookieUtil.getCookieValueByName("JT_TICKET",request);
//2.判断ticket中是否有值
if(!StringUtils.isEmpty(ticket)){
//3.根据ticket,删除redis
jedisCluster.del(ticket);
//4.删除cookie
CookieUtil.deleteCookie("JT_TICKET","/","jt.com",response);
}
//5.跳转到jt-web首页
return "redirect:/";
}
既然要用工具API,就我就得先写一个工具API
1.1.2.1 自编一个关于操作cookie的工具util----CookieUtil
写在jt-common的util中
注意,这个util中包含:
1.根据cookie的名称 返回cookie对象
2.根据cookie的名称 返回value的值
3.新增cookie的方法
4.删除cookie的方法
public class CookieUtil {
/**
* 该工具API的主要作用:
* 1.根据cookie的名称 返回cookie对象
* 2.根据cookie的名称 返回value的值
* 3.新增cookie的方法
* 4.删除cookie的方法
*/
//1.根据cookie的name 获取这个cookie对象 (在调用这个方法时,我得事先知道cookie的name,比如JT_TICKET)
public static Cookie getCookieByName(String cookieName,HttpServletRequest request){
//一个网页中可能含有很多个cookie,它们都可以通过request对象获取到
Cookie[] cookies = request.getCookies();
//判断一个数组是否有值的标准写法:先判断它是不是null,并且 ,这个数组的长度要>0
if(cookies !=null && cookies.length>0){
for(Cookie cookie : cookies){
//从这一堆cookie中挑选出跟这个用户的cookie的name匹配的那个cookie,上交这个cookie
//如果方法参数中的name与cookie的真实的name相同
if(cookieName.equalsIgnoreCase(cookie.getName())){
//就把这个cookie上交给调用getCookieByName()这个方法的对象
return cookie;
}//否则,啥也不做
}
}
//如果cookie数组是空的,就返回null
return null;
}
//2.根据cookie的name 获取这个cookie的value
public static String getCookieValueByName(String cookieName,HttpServletRequest request){
//调用上面那个方法 获取cookie对象
Cookie cookie = getCookieByName(cookieName,request);
//cookie为空吗? 如果是null,就返回null。如果不为null,就返回cookie的value
return (cookie==null)?null:cookie.getValue();
}
//3.addCookie()的作用就是 new出一个新的空的cookie
public static void addCookie(String cookieName, String cookieValue, String path, String domain, int maxAge, HttpServletResponse response){
//一个cookie身上最常用的5个属性:name,value,path,domain,maxAge
Cookie cookie = new Cookie(cookieName,cookieValue);
cookie.setPath(path);
cookie.setDomain(domain);
cookie.setMaxAge(maxAge);
//通过response对象,将cookie返回给浏览器
response.addCookie(cookie);
}
//4.deleteCookie()的作用:删除Cookie
public static void deleteCookie(String cookieName,String path,String domain,HttpServletResponse response){
//删除的思路就是:再新建一个cookie。并且把maxAge设置为0,value设置为空串,其余3项的值与原cookie保持一致。否则某些浏览器可能不能成功删除。
Cookie cookie = new Cookie(cookieName, "");
cookie.setPath(path);
cookie.setDomain(domain);
cookie.setMaxAge(0); //!!!!!
//cookie的maxAge如果为-1,意思是关闭浏览器后这个cookie就失效了
//通过response对象,将cookie返回给浏览器
response.addCookie(cookie);
}
}
2 商品详情页的展现(MANAGE)
目的:用户在jt-web的页面上点击一个商品,能展现出这个商品的详情信息
是jt-web服务器向jt-manage服务器请求数据信息,又是RPC远程调用。所以要将jt-manage配置上dubbo框架。
跳转到的页面url
而商品的详情信息要去jt-manage服务器中请求获取。
所以要将jt-manage改造为Dubbo项目
2.1 将jt-manage改造为Dubbo项目
2.1.1 在jt-manage中新增DubboItemServiceImpl实现类
在jt-manage中新增DubboItemServiceImpl实现类,用来实现展现商品详情数据的业务逻辑。
2.1.2 修改jt-manage的yml文件
只需要在最下面添加上dubbo框架的配置即可
2.2 实现商品详情的展现
2.2.1 页面请求url分析
说明:当用户点击某个商品时,需要跳转到商品的详情页面中.根据itemId展现商品信息.并且在item.jsp中展现数据.
2.2.2 前台页面是怎么取值的?
商品Item的pojo身上有title和sellpoint这两个属性
展现的就是这的数据
别的item的信息以此类推
2.2.3 编辑ItemController
由请求的url可知,这个controller要写在jt-web中。
所以在jt-web中的controller文件夹中,新增一个ItemController类,里面写一个方法,用来根据itemId展现这个item的具体信息
@Controller //由于要返回页面 所以这里要写@Controller
public class ItemController {
@Reference(check = false,timeout = 3000) //A发送请求后,等B服务器3秒钟,如果B还不接收请求,A再回去
private DubboItemService dubboItemService;
/** 在jt-web主页 点击一个商品后,展现这个商品的介绍页面
* 根据itemId查询商品信息:1、商品信息 2、商品详情信息
* url地址:http://www.jt.com/items/562379.html
* 参数:是从url中传过来的,restful风格
* 返回值:页面 item.jsp
* 前端js是怎么取值的:${item.title} ${itemDesc.itemDesc},它就可以从域中取到值了
*/
@RequestMapping("/items/{itemId}")
public String findItemById(@PathVariable Long itemId, Model model){
//查询到商品信息item
Item item = dubboItemService.findItemById(itemId);
//查询到商品详情信息itemDesc
ItemDesc itemDesc = dubboItemService.findItemDescById(itemId);
//把商品信息item放到作用域中,来让前端获取 (其实是放到item.jsp中的指定位置)
model.addAttribute("item",item);
//把商品详情信息itemDesc放到域中,来让前端获取(其实是放到item.jsp中的指定位置)
model.addAttribute("itemDesc",itemDesc);
//返回有了数据的item.jsp
return "item";
}
}
2.2.4 编辑ItemService
在jt-common的service中新建一个DubboItemService接口,用来生成上面controller中的两个方法
package com.jt.service;
import com.jt.pojo.Item;
import com.jt.pojo.ItemDesc;
//商品
public interface DubboItemService {
Item findItemById(Long itemId);
ItemDesc findItemDescById(Long itemId);
}
2.2.5 编辑DubboItemServiceImpl
在jt-manage中的web文件夹下,新建一个service文件夹,用来存放DubboItemServiceImpl.java
@Service //dubbo框架的@Service注解
public class DubboItemServiceImpl implements DubboItemService {
@Autowired
private ItemMapper itemMapper; //商品信息
@Autowired
private ItemDescMapper itemDescMapper; //商品详情信息
/**
* 在jt-web主页点击一个商品后,根据itemId,查询这个商品的item信息和itemDesc信息
* @param itemId
* @return item信息 itemDesc信息
*/
@Override
public Item findItemById(Long itemId) {
//根据itemId查询item信息
return itemMapper.selectById(itemId);
}
@Override
public ItemDesc findItemDescById(Long itemId) {
//根据itemId查询itemDesc信息
//由于都是同一个商品,所以它的itemDesc的id和itemId是一样的
return itemDescMapper.selectById(itemId);
}
}
2.2.6 展现效果
3 购物车模块业务的实现(CART)
3.1 创建jt-cart项目
3.1.1 新建项目
3.1.2 添加基础/依赖/插件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>jt-cart</artifactId>
<parent>
<artifactId>jt</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<!--添加依赖项-->
<dependencies>
<dependency>
<groupId>org.example</groupId>
<artifactId>jt-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
<!--添加插件-->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
3.1.3 编辑jt-cart的pojo
在jt-common的pojo文件夹中,新建一个Cart.java
@TableName("tb_cart")
@Data
@Accessors(chain = true)
public class Cart extends BasePojo {
@TableId(type = IdType.AUTO) //主键自增
private Long id; //购物车id
private Long userId; //用户id
private Long itemId; //商品id
private String itemTitle; //商品标题
private String itemImage; //商品主图
private Long itemPrice; //商品价格
private Integer num; //购买数量
}
3.1.4 jt-cart项目的文件结构
3.1.5 编辑jt-cart的yml文件
tomcat服务器端口号:8094
dubbo的服务名称:provider-cart
dubbo的服务端口号:20881
server:
port: 8094
servlet:
context-path: /
spring:
datasource:
#引入druid数据源
#type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/jtdb?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true
username: root
password: root
#提供了MVC的支持
mvc:
view:
prefix: /WEB-INF/views/
suffix: .jsp
#mybatis-plush配置
mybatis-plus:
type-aliases-package: com.jt.pojo
mapper-locations: classpath:/mybatis/mappers/*.xml
configuration:
map-underscore-to-camel-case: true
logging:
level:
com.jt.mapper: debug
#关于Dubbo配置
dubbo:
scan:
basePackages: com.jt #指定dubbo的包路径
application: #应用名称
name: provider-cart #一个接口对应一个服务名称
registry: #zk集群 主机中的信息与从机中的信息一致的 从zk中获取数据的时候链接的从机 主机的作用就是监控集群
address: zookeeper://192.168.126.129:2181?backup=192.168.126.129:2182,192.168.126.129:2183
protocol: #指定协议
name: dubbo #使用dubbo协议(tcp-ip) web-controller直接调用sso-Service
port: 20881 #每一个服务都有自己特定的端口 不能重复.
3.1.6 修改IDEA在启动启动类时的名称
3.2 购物车页面的展现
3.2.1 页面分析
1.分析客户端请求的url
2.业务说明
用户只能看自己的购物车信息,所以用户得先登录,才能进行购物车的操作。
当用户登录了后,就能获取到userId,当他点击“加入购物车”按钮后,就应该跳转到他的购物车页面。
根据userId查询这个用户的购物车数据信息,然后在cart.jsp中展现这个用户的购物车中的信息。
由于购物车中可以放这个用户想买的很多很多item,不止一条信息。
所以根据userId查到的是一个cartList集合
3.2.2 编辑CartController
由于 “想要 跳转到 购物车” 这个请求是 在jt-web页面中发过来的。所以CartController.java要写在jt-web的controller中
在jt-web的controller中增加“CartController”
@Controller
@RequestMapping("/cart")
public class CartController {
@Reference(check = false,timeout = 3000)
private DubboCartService cartService;
/**
* 1.购物车列表数据展现
* url地址: http://www.jt.com/cart/show.html
* 参数: 暂时没有
* 返回值: 页面逻辑名称 cart.jsp
* 页面取值: ${cartList}
* 应该将数据添加到域对象中 Request域 model工具API操作request对象
*
*/
@RequestMapping("/show")
public String show(Model model){
//1.暂时将userId写死 7L
Long userId = 7L;
List<Cart> cartList = cartService.findCartListByUserId(userId);
model.addAttribute("cartList",cartList);
return "cart";
}
}
3.2.3 编辑DubboCartService接口
通过controller中我自定义的方法中的提示,IDEA会帮我在DubboCartService接口中新建findCartListByUserId()方法
3.2.4 编辑DubboCartServiceImpl
由于购物车页面到底展现啥,是jt-cart的活,所以要在jt-cart的service文件夹下新建DubboCartServiceImpl.java
@Service
public class DubboCartServiceImpl implements DubboCartService{
@Autowired
private CartMapper cartMapper;
/**
* 根据jt-web的controller中传过来的用户的userId,查询他的购物车的信息
*/
@Override
public List<Cart> findCartListByUserId(Long userId) {
QueryWrapper<Cart> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("user_id",userId);
List<Cart> cartList = cartMapper.selectList(queryWrapper);
return cartList;
}
}
3.2.5 页面效果展现
3.3 实现购物车中修改商品数量的操作,并且总计的费用同时变化
业务要求:
点击“-”或者“+”,商品的数量要随之变化。
并且总价要随之动态变化。
3.3.1 页面分析
3.3.2 页面JS分析
3.3.3 编辑CartController
在jt-web的controller中添加“修改购物车中商品数量”的方法updateCartNum()
/**
* 在购物车中,点击“+”“-”修改购物车中这个商品的数量
* url:http://www.jt.com/cart/update/num/562379/10 (当我把商品数量想改成 10 时,就显示这个)
* 参数: itemId/num (比如:562379/10)
* 返回值类型: void
*/
@RequestMapping("/update/num/{itemId}/{num}")
@ResponseBody //这个注解的作用是,将返回值对象转化为json串
//为的是满足前端调用的要求
//而前端是靠发ajax请求,所以这个注解也可以看做是ajax请求的结束
public void updateCartNum(Cart cart){ //restful风格中,如果{ }中的名字 与 对象的属性名称一致,则可以自动赋值
//1.获取itemId
Long userId = 7L; //暂时写死
cart.setUserId(userId); //将7号用户的userId 放进cart对象中,就表明我要修改的是7号的这人的购物车信息、
/**
* cart身上共有7个属性,传过来的这个cart身上哪些属性有值?哪些属性为null?
* cart.getUserId 为 7L 在上边那句代码中传过来的
* cart.getItemId 为 562379 是因为用户在点击“+”“-”时,肯定操作的是1个item,这个itemId就得到了
* cart.getNum 有值,改之前 是 几就是几
* 其余的都为null
*/
dubboCartService.updateCartNum(cart);
}
3.3.4 编辑DubboCartService接口
jt-common中的DubboCartService接口中又多了一个方法
3.3.5 编辑DubboCartServiceImpl实现类
在jt-cart的service中的DubboCartServiceImpl实现类中,实现上面接口中多出来的接口方法:
注意:点击“+”“-”修改数量这个操作,需求是只修改cart的num属性的值,别的属性要是有值的话,不要去变。
而如果直接传controller中的cart对象进来,因为人家身上有4个属性都有值,修改的就太多了,并且itemId和userId,它俩的值在修改前和修改后,值是一样的,那岂不是做了无用功。
uodated时间的修改我已经写了一个MyMetaObjectHandler.java方法,可以实现自动修改。
所以我只需要修改num这个属性的值即可。
所以我就要new出一个cartTemp对象,让它只有num这个属性有值。
/**
* 根据cart对象身上的信息,去修改他购物车中,这个商品的数量
* 注意:要新new一个cartTemp对象,让其身上只有num属性有值。
*/
@Override
public void updateCartNum(Cart cart) {
//构建一个购物车,把传过来的购物车的信息放到这个新车上
//传过来的cart对象身上的哪些属性有值,哪些为空???
// System.out.println("cartId==="+cart.getId()); //null
// System.out.println("userId==="+cart.getUserId()); //7
// System.out.println("itemId==="+cart.getItemId()); //562379
// System.out.println("itemTitle=="+cart.getItemTitle());//null
// System.out.println("itemImage==="+cart.getItemImage());//null
// System.out.println("itemPrice=="+cart.getItemPrice());//null
// System.out.println("itemNum=="+cart.getNum()); //9
Cart cartTemp = new Cart();
cartTemp.setNum(cart.getNum()); //cartTemp身上 只有num这一个属性有值
UpdateWrapper<Cart> updateWrapper = new UpdateWrapper<>();
updateWrapper.eq("user_id",cart.getUserId());
updateWrapper.eq("item_id",cart.getItemId());
/**
* 为什么要new一个cartTemp传进来,而不用原来的cart?
* 1.当我用原来的cart传进来时,update的sql语句如下:
* UPDATE tb_cart SET item_id=?,num=?,user_id=?,updated=? WHERE (user_id=? AND item_id=?)
* 这是因为cart身上有4个属性有值,所以修改时 要这4个属性的值都要修改。
* 2.当我再new一个cartTemp出来,只让它身上的num属性有值时,update的sql语句如下:
* UPDATE tb_cart SET num=?,updated=? WHERE (user_id=? AND item_id=?)
* (由于我之前写了一个时间自动填充的方法:jt-common中MyMetaObjectHandler.java,所以这个updated不算)
* 可见,这种情况下,我只修改了购物车中的num。
* 而实际上,我需要的效果就是:在购物车页面,点击“+”“-”只修改num即可,与第2种情况是吻合的。
* 我只想修改num,不需要修改itemId和userId。
* 并且第一种情况下,itemId和userId的值在修改前和修改后都是一样,没修改一丁点,岂不是很多余的操作。
* 所以这里要传的就是(身上只有num这一个属性有值的)cartTemp对象
*/
cartMapper.update(cartTemp,updateWrapper);
}
3.3.6 效果验证
我将下面商品的数量由8 增加到 10,总价也跟着变了
3.4 购物车中商品的删除
目的:在购物车页面,点击 商品后面的删除,能将这个商品的信息,从购物车中删除。
并且重定向到购物车列表页面。
3.4.1 页面请求的url分析
根据userId(用户登录了就有)和itemId(购物车页面有),这两个属性作为where条件,删除购物车中此条item数据
3.4.2 编辑CartController
由上图可知,这个请求是jt-web中的请求,所以还是要往jt-web中的controller中添加方法
/**
* 在购物车页面,点击“删除”后,删除此条商品的信息,并重定向到购物车页面
* url:http://www.jt.com/cart/delete/562379.html
* 参数: 562379 (就是我这次选的商品的itemId)
* 返回值: 跳转到购物车列表页面
*/
@RequestMapping("/delete/{itemId}")
public String deleteCart(Cart cart){
Long userId = 7L;
cart.setUserId(userId); //规定了这是7号人物的 他那台购物车
dubboCartService.deleteCart(cart); //这个cart只有userId和itemId这两个属性有值
return "redirect:/cart/show.html"; //参考上面的展现页面的方法
}
3.4.3 编辑DubboCartService
通过CartController中的提示,就可以在jt-common中的DubboCartService接口中新增出deleteCart()接口方法
3.4.4 编辑DubboCartServiceImpl
在jt-cart中,DubboCartServiceImpl去实现上面的接口方法
cart对象身上只有userId和itemId有值,就根据这两个条件去删除购物车中的这条信息
/**
* 在购物车页面中,点击“删除”,删除此条商品信息
* @param cart
*/
@Override
public void deleteCart(Cart cart) { //这个cart只有userId和itemId这两个属性有值
// //方法1:麻烦写法:
// QueryWrapper<Cart> queryWrapper = new QueryWrapper<>();
// queryWrapper.eq("item_id",cart.getItemId());
// queryWrapper.eq("user_id",cart.getUserId());
// cartMapper.delete(queryWrapper);
//方法2:简单写法 根据对象中不为null的元素,充当where条件
cartMapper.delete(new QueryWrapper<>(cart));
}
3.5 往购物车中添加商品
目的:
用户在商品详情页点击“加入购物车”后,有2种情况:
1.这个商品之前已经在购物车里有了,那么这次用户想要再增加几个,就在购物车中这个商品的数量上新增就可以,并且重定向到购物车列表页面.
2.这个商品在购物车里没有,就将这个商品的信息,按照购物车信息展现的形式,添加到购物车中。(其实后台的操作是,将用户提交的数据以购物车商品的pojo的形式存到tb_cart表中)并且重定向到购物车列表页面.
要是实现这个功能,首先要实现商品详情页面的展现。这个功能在上面“2 商品详情页的展现”中已经实现了。
开发者工具中显示:
还有一个需要注意的点:
每个商品一般都有多张图片:
点击“加入购物车”后,购物车页面只会显示一个简图:
那就是介绍页的第一个图
<form id="cartForm" method="post">
<input class="text" id="buy-num" name="num" value="1" onkeyup="setAmount.modify('#buy-num');"/>
<input type="hidden" class="text" name="itemTitle" value="${item.title }"/>
<input type="hidden" class="text" name="itemImage" value="${item.images[0]}"/>
<input type="hidden" class="text" name="itemPrice" value="${item.price}"/>
</form>
3.5.1 编辑CartController
由上面的请求的url可知,这个CartController应该是在jt-web服务器中
所以在jt-web的controller中新增方法
/**
* 在商品详情页面,点击“加入购物车”,将用户提交的数据(这个商品,和商品的数量)插入到tb_cart表中,实现购物车页面呈现该商品的信息
* 注意事项:
* 如果用户提交的这个商品,购物车中已经有了,就把购物车中的这个商品的数量更新。
* url:http://www.jt.com/cart/add/562379.html
* 参数:form表单提交的数据 和 itemId
* 返回值:重定向到更新后的购物车页面
*/
@RequestMapping("/add/{itemId}")
public String addCart(Cart cart){
//暂时先将将登陆的用户固定死 7号用户
Long userId = 7L;
//addCart方法的参数是cart,是为了简化代码
//用户在点击“加入购物车”后,通过form表单提交了很多数据,从中提取一些就能封装成一个Cart对象
//将用户的userId插入到这个cart对象中
cart.setUserId(userId);
//将这个封装了新数据的cart对象通过addCart()方法,加入到购物车页面中。(至于是新增一条数据,还是在原有数据上增加num,就要在serviceImpl中进行判断处理了)
dubboCartService.addCart(cart);
//重定向到购物车页面
return "redirect:/cart/show.html";
}
3.5.2 编辑DubboCartService
在jt-common的DubboCartService接口中,新建接口方法
3.5.3 编辑DubboCartServiceImpl
在jt-cart的DubboCartServiceImpl中添加方法addCart()
/**
* 在商品详情页面,点击“加入购物车”,将用户提交的数据(这个商品,和商品的数量)插入到tb_cart表中,实现购物车页面呈现该商品的信息
* 思路:
* 查询数据库,根据user_id和item_id这两个条件 去查tb_cart表,看表里是不是已经有这条数据了。
* 如果有,则只需要 将购物页面该商品的数量 增加。 如果没有,则把这条信息写入到tb_cart表中,即在购物车页面新增这条信息。
*/
@Override
public void addCart(Cart cart) {
//第2步:构造查询的条件,要要满足,同时匹配上userId和itemId
QueryWrapper<Cart> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("user_id",cart.getUserId());
queryWrapper.eq("item_id",cart.getItemId());
//第1步:让cartMapper对象去查表,根据userId和itemId,查查看有没有满足条件的这个Cart对象(取名为cartDB)
Cart cartDB = cartMapper.selectOne(queryWrapper);
//第3步:进行判断,查询出的结果是否有值
if(cartDB == null){
//情况1:tb_cart表中没有这条数据,需要新增,到购物车页面
//cart对象的7个属性都能有值:id没有传值,但它是主键,入库后就有了;userId,只要用户登录了,就有了;itemId,用户点击“加入购物车”时就有了;
//itemTitle,itemImage,itemPrice,num 这4个都是用户在点击“加入购物车”时,通过表单提交的
//所以可以放心地把cart对象传进去,入库
cartMapper.insert(cart);
}else {
//情况2:购物车页面已有这条数据了,只需增加num 。
//最后商品的总数量 = 我这次要买的 + 之前我已经加入到购物车的(即我之前已经写入tb_cart表中的)
int num = cart.getNum() + cartDB.getNum();
//这种情况下,我只需将总的num更新进数据库就行了
//方式1.用MP写的话,代码很多====不推荐
// Cart cartTemp = new Cart();
// cartTemp.setNum(num);
// UpdateWrapper<Cart> updateWrapper = new UpdateWrapper<>();
// updateWrapper.eq("user_id",cart.getUserId());
// updateWrapper.eq("item_id",cart.getItemId());
// cartMapper.update(cartTemp,updateWrapper);
// //方式2.手写sql
//1.将新的商品的总数传入cartDB对象 数据库中购物车的数据都是这个cartDB身上的
cartDB.setNum(num).setUpdated(new Date());
//2.updateCartNum()方法是自定义的,
//由于sql语句为update tb_cart set num=#{num},updated=now() where user_id=#{userId} and item_id=#{itemId}
//可知需要num,updated,userId,itemId这几个属性的值,而cartDB身上,这几个属性正好都有值,所以直接传cartDB对象即可
cartMapper.updateCartNum(cartDB);
}
}
3.5.3.1 如果是用方法2,还需编辑CartMapper
在jt-cart的CartMapper中添加方法,并填写sql语句
package com.jt.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.jt.pojo.Cart;
import org.apache.ibatis.annotations.Update;
public interface CartMapper extends BaseMapper<Cart> {
@Update("update tb_cart set num=#{num},updated=now() where user_id=#{userId} and item_id=#{itemId}")
void updateCartNum(Cart cartDB);
}
3.5.4 效果验证
之前购物车中没有这个商品,我想先加入1台
点击“加入购物车”后,购物车页面多了这个商品的信息:
当我在商品详情页面 再选择5台 点击“加入购物车”后,
购物车中由于之前已经有这个商品了,所以只把这个商品的num加了5