课程计划javascript
用户将商品添加到购物车时,判断用户是否登陆,若是已经登陆将购物车放入session中。
php
用户未登陆的时候不能添加购物车。
解决方案:未登陆的状态下,能够把购物车放在cookie中。
在不登录的状况下添加购物车。把购物车信息写入cookie。(数据保存在客户端,数据完整性差)。
优势:
一、不占用服务端存储空间。
二、用户体验好。
三、代码实现简单。
缺点:
一、cookie中保存的容量有限。最大4k
。
二、把购物车信息保存在cookie中,更换设备购物车信息不能同步。
这里咱们不使用这种方法。css
对于未登录用户,将购物车放到cookie中。对于已登录用户将购物车放入redis缓存中
。能够实现,用户未登陆或者登陆情况下的添加购物车(并进行购物车的增删查改)。
购物车系统架构:
taotao-cart(pom聚合工程)
|--taotao-cart-interface(jar)
|--taotao-cart-Service(war)
taotao-cart-web(war)
能够参考taotao-manager、taotao-manager-web建立。html
taotao-cart打包方式pom。
能够参考taotao-manager工程的建立。
New --> Maven Project --> 不使用骨架建立工程 --> Next前端
<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>
<parent>
<groupId>com.taotao</groupId>
<artifactId>taotao-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>taotao-cart</artifactId>
<packaging>pom</packaging>
<dependencies>
<!-- 配置对taotao-common的依赖-->
<dependency>
<groupId>com.taotao</groupId>
<artifactId>taotao-common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- 配置Tomcat插件 -->
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<configuration>
<port>8089</port>
<path>/</path>
</configuration>
</plugin>
</plugins>
</build>
</project>
New --> Other--> Maven Module --> 不使用骨架建立
千万不要建立成Maven Project。
taotao-cart-interface打包方式jar。
pom.xmljava
<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>
<parent>
<groupId>com.taotao</groupId>
<artifactId>taotao-cart</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>taotao-cart-interface</artifactId>
<dependencies>
<!-- 配置对taotao-manager-pojo的依赖 -->
<dependency>
<groupId>com.taotao</groupId>
<artifactId>taotao-manager-pojo</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
New --> Other--> Maven Module --> 不使用骨架建立
千万不要建立成Maven Project。
taotao-cart-service打包方式war。
pom.xmlmysql
<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>
<parent>
<groupId>com.taotao</groupId>
<artifactId>taotao-cart</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>taotao-cart-service</artifactId>
<packaging>war</packaging>
<dependencies>
<!-- 配置对taotao-manager-dao的依赖 -->
<dependency>
<groupId>com.taotao</groupId>
<artifactId>taotao-manager-dao</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!-- 配置对taotao-cart-interface的依赖:服务层发布服务要经过该接口 -->
<dependency>
<groupId>com.taotao</groupId>
<artifactId>taotao-cart-interface</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!-- 配置对spring的依赖 -->
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
<!-- 配置对dubbo的依赖 -->
<!-- dubbo相关 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<!-- 排除对低版本jar包的依赖 -->
<exclusions>
<exclusion>
<artifactId>spring</artifactId>
<groupId>org.springframework</groupId>
</exclusion>
<exclusion>
<artifactId>netty</artifactId>
<groupId>org.jboss.netty</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
</dependency>
<dependency>
<groupId>com.github.sgroschupf</groupId>
<artifactId>zkclient</artifactId>
</dependency>
<!-- 配置对Redis的Java客户端jedis的依赖 -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
</dependencies>
</project>
因为没有web.xml,打包方式为war的项目会报错。
右键项目taotao-cart-service --> Java EE Tools --> Generate … xxx,会自动帮咱们生成web.xml,
在web.xml中配置spring的监听器,内容以下:
web.xmlgit
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<display-name>taotao-cart-service</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<!-- 初始化spring容器:也即加载spring容器 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/applicationContext*.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
将taotao-manager-service的src/main/resources下的配置文件所有复制到taotao-cart-service的src/main/resources中github
表现层为一个单独的工程,因此须要建立Maven Project。
New --> Maven Project
千万不要建立成Maven Module。
taotao-cart-web的打包方式是war。web
<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>
<parent>
<groupId>com.taotao</groupId>
<artifactId>taotao-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>taotao-cart-web</artifactId>
<packaging>war</packaging>
<dependencies>
<!-- 配置对taotao-common的依赖 -->
<dependency>
<groupId>com.taotao</groupId>
<artifactId>taotao-common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!-- 配置对taotao-manager-interface的依赖:表现层调用服务要经过该接口 -->
<dependency>
<groupId>com.taotao</groupId>
<artifactId>taotao-manager-interface</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!-- 配置对spring的依赖 -->
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
<!-- JSP相关 -->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jsp-api</artifactId>
<scope>provided</scope>
</dependency>
<!-- 文件上传组件 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
</dependency>
<!-- 配置对分页插件pagehelper的依赖 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
</dependency>
<!-- 配置对dubbo的依赖 -->
<!-- dubbo相关 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<!-- 排除对低版本jar包的依赖 -->
<exclusions>
<exclusion>
<artifactId>spring</artifactId>
<groupId>org.springframework</groupId>
</exclusion>
<exclusion>
<artifactId>netty</artifactId>
<groupId>org.jboss.netty</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
</dependency>
<dependency>
<groupId>com.github.sgroschupf</groupId>
<artifactId>zkclient</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<!-- 配置Tomcat插件 -->
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<configuration>
<port>8090</port>
<path>/</path>
</configuration>
</plugin>
</plugins>
</build>
</project>
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<display-name>taotao-cart-web</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<!-- 配置解决post乱码的过滤器 -->
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 配置springmvc的前端控制器 -->
<servlet>
<servlet-name>taotao-cart-web</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- contextConfigLocation不是必须的, 若是不配置contextConfigLocation, springmvc的配置文件默认在:WEB-INF/servlet的name+"-servlet.xml" -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>taotao-cart-web</servlet-name>
<!-- 拦截以(*.html)请求,jsp除外 -->
<url-pattern>*.html</url-pattern>
</servlet-mapping>
</web-app>
将表现层taotao-manager-web工程下的src/main/resources下面的配置文件复制到taotao-cart-web下的src/main/resources中
删除或清空相关的配置文件:
因为购物车中的商品属性与TbItem相似,因此能够将TbItem
当作购买的商品。TbItem
中的num属性
原用做后台管理系统的商品库存数量
,在这里能够将num属性
用做购买商品的数量
,因此List<TbItem>
就是一个购物车
。一个用户对应一个购物车,一个购物车对应多个商品。
对于存入cookie
中,咱们能够自定义key
,而后将购物车List<TbItem>转为json串
,存到cookie。
因为一个用户对应一个购物车,一个购物车购买多个商品。至关于一个用户能够购买多个商品。
对于存入redis中,咱们有两种实现方案:
1.方案一:
使用String类型,将用户userId做为key
,将购物List<TbItem>转为json串做为value
。
用户userId做为key
,将
商品itemId做为filed
,将
购物车List<TbItem>转为json串做为value
。
能够直接使用TbItem。
因为购物车系统的运行,依赖不少其余系统,为了防止登陆注册等其余状况,url错误报404致使很差测试,须要修改整个淘淘商城系统中的url为正确的url。
将全部的$.cookie()
取值的name
改成本身定义的值。
将ajax跨域请求的url改成本身的。
Ctrl+H,搜索全部的:<a href=\"http://www.taotao.com/user/logout.html\" class=\"link-logout\">[退出]</a>
,
改成:<a href=\"http://localhost:8088/user/logout.html\" class=\"link-logout\">[退出]</a>
。
将参考资料中的购物车静态页面
下的js、css、images导入webapp下,将jsp导入WEB-INF下:
商品详情在taotao-item-web系统的item.jsp中,给加入购物车添加一个事件javascript:addCartItem();
直接经过JedisClient对象操做redis数据库。
业务逻辑:
一、根据商品的ID查询商品的信息。
二、设置商品的数量和图片(只须要设置图片的一张便可,数量使用num字段来表示,由于原来的num存放的是库存,因此须要从新设置一下)。
三、根据商品id和用户id从redis数据库中查询用户的购物车的商品的列表,看是否存在(须要将JSON转成java对象)。
四、若是没有存在,则直接添加到redis中(须要将java对象转成JSON)。
五、若是存在,则更新商品购买的数量便可。
首先在taotao-cart-interface下建立接口包com.taotao.cart.service,在接口包下建立接口CartService.java。
/**
* 购物车管理接口
* @author chenmingjun
* @date 2018年12月5日 下午11:21:43
* @version V1.0
*/
public interface CartService {
/**
* 添加商品至redis购物车或者cookie购物车
* @param userId 购物车所属的用户
* @param item 添加的商品
* @param num 添加商品的数量
* @return
*/
TaotaoResult addItemCart(Long userId, TbItem tbItem, Integer num);
/**
* 根据用户ID和商品的ID查询购物车是否存储在redis中
* @param userId
* @param itemId
* @return null 说明购物车不存在,若是不为空说明购物车存在
*/
TbItem queryTbItemByUserIdAndItemId(Long userId, Long itemId);
}
使用hash类型,能够给key设置一个前缀用于分类。在taotao-cart-service的src/main/resources下建立resource.properties文件,文件内容以下:
#购物车的前缀
TT_CART_REDIS_PRE_KEY=TT_CART_REDIS_PRE_KEY
在taotao-cart-service下建立实现类包com.taotao.cart.service.impl,在实现类包下建立CartServiceImpl实现CartService:
/**
* 购物车管理Service
* @author chenmingjun
* @date 2018年12月5日 下午11:23:46
* @version V1.0
*/
@Service
public class CartServiceImpl implements CartService {
// 注入jedisClient对象
@Autowired
private JedisClient jedisClient;
// 获取redis中购物车的前缀
@Value("${TT_CART_REDIS_PRE_KEY}")
private String TT_CART_REDIS_PRE_KEY;
@Override
public TaotaoResult addItemCart(Long userId, TbItem tbItem, Integer num) {
// 一、从redis数据库中查询该用户的购物车中的某一个商品
TbItem tbItem2 = queryTbItemByUserIdAndItemId(userId, tbItem.getId());
// 利用了redis中hash类型赋值的特性:当字段不存在时赋值
// 二、判断要添加的商品是否存在于列表中
if (tbItem2 != null) {
// 三、说明存在,则将商品的数量取出后相加再设置回去(将修改过的java对象转为JSON)
tbItem2.setNum(tbItem2.getNum() + num);
// 存入redis
jedisClient.hset(TT_CART_REDIS_PRE_KEY + ":" + userId, tbItem.getId() + "", JsonUtils.objectToJson(tbItem2));
} else {
// 四、说明不存在,则设置商品数量,并设置照片(只须要设置图片的一张便可)
tbItem.setNum(num);
String image = tbItem.getImage();
if (StringUtils.isNotBlank(image)) {
tbItem.setImage(image.split(",")[0]);
}
// 存入redis
jedisClient.hset(TT_CART_REDIS_PRE_KEY + ":" + userId, tbItem.getId() + "", JsonUtils.objectToJson(tbItem));
}
return TaotaoResult.ok();
}
@Override
public TbItem queryTbItemByUserIdAndItemId(Long userId, Long itemId) {
// 经过用户id和商品的id查询redis数据库所对应的商品的数据,若是存在则不为空
String string = jedisClient.hget(TT_CART_REDIS_PRE_KEY + ":" + userId, itemId + "");
if (StringUtils.isNotBlank(string)) {
// 将JSON转成java对象
TbItem tbItem = JsonUtils.jsonToPojo(string, TbItem.class);
return tbItem;
} else {
return null;
}
}
}
先在taotao-cart-service工程中的pom.xml文件中配置对taotao-cart-interface的依赖,由于服务层发布服务要经过该接口,
再在taotao-cart-service工程中的applicationContext-service.xml文件中发布服务:要注意图中标注的地方
先在taotao-cart-web工程中的pom.xml文件中配置对taotao-cart-interface的依赖,由于表现层引用服务要经过该接口,
再在taotao-cart-web工程中的springmvc.xml文件中引用服务:要注意图中标注的地方
url: /cart/add/{itemId}
参数:itemId, num
返回值:添加购物车成功页面。
业务逻辑:
一、调用SSO的服务,获取用户相关的信息。
二、调用商品(manage)的服务,获取商品的相关的信息。
三、判断若是是登陆的状态,则调用登陆的添加购物车的service。
四、若是是未登陆的状态,则调用的是未登陆的添加购物车的方法。
一、因为要表现层taotao-cart-web要调用taotao-sso与taotao-manager的服务,因此须要在该工程的pom.xml中添加依赖:
<!-- 配置对taotao-cart-interface的依赖:表现层调用服务要经过该接口 -->
<dependency>
<groupId>com.taotao</groupId>
<artifactId>taotao-cart-interface</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!-- 配置对taotao-manager-interface的依赖:表现层调用服务要经过该接口 -->
<dependency>
<groupId>com.taotao</groupId>
<artifactId>taotao-manager-interface</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!-- 配置对taotao-sso-interface的依赖:表现层调用服务要经过该接口 -->
<dependency>
<groupId>com.taotao</groupId>
<artifactId>taotao-sso-interface</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
二、因为要将购物车存入cookie中,因此须要给购物车存入cookie时设置一个name,获取token时正好也须要一个name,能够将这两个name放在resource.properties文件中,咱们还须要设置cookie中存放token的key的过时时间,代码截图以下:
#cookie中存放token的key
COOKIE_TOKEN_KEY=COOKIE_TOKEN_KEY
#cookie中存放购物车的key
COOKIE_CART_KEY=COOKIE_CART_KEY
#cookie中存放token的key的过时时间,7天
COOKIE_CART_EXPIRE_TIME=604800
在taotao-cart-web下建立controller的包com.taotao.cart.controller,在包controller中建立CartController.java:
@Controller
public class CartController {
// 引入服务 ,注入依赖
@Autowired
private CartService cartService;
@Autowired
private ItemService itemService;
@Autowired
private UserLoginService userLoginService;
// cookie中存放token的key
@Value("${COOKIE_TOKEN_KEY}")
private String COOKIE_TOKEN_KEY;
// cookie中存放购物车的key
@Value("${COOKIE_CART_KEY}")
private String COOKIE_CART_KEY;
@RequestMapping("/cart/add/{itemId}") // /cart/add/149204693130763.html?num=4
public String addItemCart(@PathVariable Long itemId, Integer num, HttpServletRequest request, HttpServletResponse response) {
// 一、从cookie中获取token
String token = CookieUtils.getCookieValue(request, COOKIE_TOKEN_KEY);
// 二、根据token调用SSO的服务,获取用户的信息
TaotaoResult result = userLoginService.getUserByToken(token);
// 三、判断
// 3.一、首先根据商品id调用商品(manager)服务的方法,获取商品的数据TbItem
TbItem tbItem = itemService.getItemById(itemId);
if (result.getStatus() == 200) { // 若是用户存在,说明已经登陆
// 3.二、调用添加购物车的方法,将商品数据添加到redis中
TbUser tbUser = (TbUser) result.getData();
cartService.addItemCart(tbUser.getId(), tbItem, num);
} else {
// 四、判断,若是用户不存在,说明未登陆,将商品数据添加到cookie中,并设置过时时间
// 4.一、首先根据cookie获取购物车的列表
}
return "cartSuccess";
}
}
安装taotao-cart。
因为要调用taotao-sso与taotao-manager查询用户与商品信息,因此须要启动taotao-sso、taotao-manager。
须要登陆在cookie中写入toekn,因此要启动taotao-sso-web。
须要搜索商品,因此要启动taotao-search、taotao-search-web。(若是手动输入url进入商品详情页,能够不启动。)
须要将商品详情页加入购物车,因此须要启动taotao-item-web。
最后购物车的taotao-cart、taotao-cart-web也要启动。
服务层不变,存入cookie,须要要使用servlet原生response对象,跟service没什么关系,因此放在controller中。
在addItemCart判断用户没登陆中添加以下,须要判断cookie中是否已存在该商品,存在的话商品数量须要相加,不存在的话直接设置商品数量,还须要设置图片为第一张图片,最后设置cookie存放时间为一个星期(7243600)。
@Controller
public class CartController {
// 引入服务 ,注入依赖
@Autowired
private CartService cartService;
@Autowired
private ItemService itemService;
@Autowired
private UserLoginService userLoginService;
// cookie中存放token的key
@Value("${COOKIE_TOKEN_KEY}")
private String COOKIE_TOKEN_KEY;
// cookie中存放购物车的key
@Value("${COOKIE_CART_KEY}")
private String COOKIE_CART_KEY;
// cookie中存放token的key的过时时间
@Value("${COOKIE_CART_EXPIRE_TIME}")
private Integer COOKIE_CART_EXPIRE_TIME;
@RequestMapping("/cart/add/{itemId}") // /cart/add/149204693130763.html?num=4
public String addItemCart(@PathVariable Long itemId, Integer num, HttpServletRequest request, HttpServletResponse response) {
// 一、从cookie中获取token
String token = CookieUtils.getCookieValue(request, COOKIE_TOKEN_KEY);
// 二、根据token调用SSO的服务,获取用户的信息
TaotaoResult result = userLoginService.getUserByToken(token);
// 三、判断
// 3.一、首先根据商品id调用商品(manager)服务的方法,获取商品的数据TbItem
TbItem tbItem = itemService.getItemById(itemId);
if (result.getStatus() == 200) { // 若是用户存在,说明已经登陆
// 3.二、调用添加购物车的方法,将商品数据添加到redis中
TbUser tbUser = (TbUser) result.getData();
cartService.addItemCart(tbUser.getId(), tbItem, num);
} else {
// 四、判断,若是用户不存在,说明未登陆,将商品数据添加到cookie中,并设置过时时间
// 4.一、首先根据cookie获取购物车的列表
List<TbItem> cartList = getCartListFromCookie(request);
boolean flag = false;
for (TbItem tbItem2 : cartList) {
// 4.二、说明购物车cookie上有该商品,就获取购物车列表中的商品,更新商品数量
if (tbItem2.getId() == itemId.longValue()) { // 两个对象比的是内存地址值,longValue()取出的是基本类型的值
tbItem2.setNum(tbItem2.getNum() + num);
flag = true;
break;
}
}
if (!flag) {
// 4.三、说明购物车cookie中没有该商品,就设置该商品数量和图片
tbItem.setNum(num);
if (tbItem.getImage() != null) {
tbItem.setImage(tbItem.getImage().split(",")[0]);
}
// 把商品添加至购物车列表
cartList.add(tbItem);
}
// 五、将商品添加至购物车cookie,并设置过时时间
CookieUtils.setCookie(request, response, COOKIE_CART_KEY, JsonUtils.objectToJson(cartList), COOKIE_CART_EXPIRE_TIME, true);
}
return "cartSuccess";
}
/**
* 从cookie中获取购物车列表
* @param request
* @return
*/
private List<TbItem> getCartListFromCookie(HttpServletRequest request) {
// 从cookie中获取购物车商品列表
String cartJson = CookieUtils.getCookieValue(request, COOKIE_CART_KEY, true);
// 将cartJson转换为List<TbItem>
if (StringUtils.isNotBlank(cartJson)) {
List<TbItem> list = JsonUtils.jsonToList(cartJson, TbItem.class);
return list;
}
return new ArrayList<>();
}
}
注意:因为从cookie中获取购物车方法会常用,因此单独抽取成一个私有方法。
首先退出用户登陆状态,使用咱们已经作好的查看购物车列表的功能(在下节),查看cookie中是否存入了购物车,能够看到未登陆的状况下,添加购物车成功。
在 5.三、登陆状态下添加购物车
和 5.四、未登陆状态下添加购物车
准备工做已经作完的状况下。
若是用户登陆状态,展现购物车列表以redis为准。若是未登陆,以cookie为准。
添加商品到购物车后,会提示【去购物车结算】,点击【去购物车结算】,会跳转到http://localhost:8090/cart/cart.html页面,能够看到购物车中商品列表。
在cart.jsp,咱们能够看到须要准备一个cartList商品集合到model中。须要修改${cart.images[0]}
为${cart.image}
。
List<Tbitem>
直接经过JedisClient对象操做redis数据库。
在taotao-cart-interface建立接口
/**
* 根据用户的ID查询redis数据库中用户的购物车的商品列表
* @param userId
* @return
*/
List<TbItem> queryCartListByUserId(Long userId);
在taotao-cart-service编写实现类
业务逻辑:
一、根据用户的ID查询redis中全部的field的值(map)。
二、遍历map对象,将其添加到List中。
三、返回一个List<tbitem>
。
@Override
public List<TbItem> queryCartListByUserId(Long userId) {
// 一、根据用户的ID查询redis中全部的field的值(map)
Map<String, String> map = jedisClient.hgetAll(TT_CART_REDIS_PRE_KEY + ":" + userId);
Set<Entry<String, String>> set = map.entrySet(); // map.entrySet() 是把Map类型的数据转换成集合类型
// Map.Entry是Map声明的一个内部接口,此接口为泛型,定义为Entry<K,V>。它表示Map中的一个实体(一个key-value对)。接口中有getKey()、getValue()方法。
// 二、遍历map对象,将其添加到List中
if (set != null) { // 判断是否为空
List<TbItem> list = new ArrayList<>();
// 迭代器只针对集合类型的数据,所以map类型的必须先转换成集合类型才能使用迭代器去获取元素
for (Entry<String, String> entry : set) {
TbItem tbItem = JsonUtils.jsonToPojo(entry.getValue(), TbItem.class);
list.add(tbItem);
}
// 三、返回一个List<tbitem>
return list;
}
return null;
}
同上5.4.二、发布服务
和 5.4.三、引用服务
,这里再也不赘图!
url: /cart/cart
参数:无
返回值:购物车展现列表的页面
业务逻辑:
一、根据token调用SSO的服务,获取用户的信息。
二、判断,若是有用户的信息,说明用户已登陆,调用CartService服务中查询购物车的商品列表的方法。
三、若是没有用户信息,说明用户未登陆,调用从cookie中获取购物车商品列表的方法。
四、将购物车对象放入request域。
五、返回逻辑页面cart.jsp。
@RequestMapping("/cart/cart") // http://localhost:8090/cart/cart.html
public String showCart(HttpServletRequest request) {
// 一、从cookie中获取token
String token = CookieUtils.getCookieValue(request, COOKIE_TOKEN_KEY);
// 二、根据token调用SSO的服务,获取用户的信息
TaotaoResult result = userLoginService.getUserByToken(token);
// 三、判断,若是用户存在,说明已经登陆
if (result.getStatus() == 200) {
// 若是用户已经登陆,从redis中查询购物车列表
TbUser tbUser = (TbUser) result.getData();
List<TbItem> redisCartlist = cartService.queryCartListByUserId(tbUser.getId());
request.setAttribute("cartList", redisCartlist);
} else {
// 若是用户未登陆,从cookie中查询购物车列表
List<TbItem> cookieCartList = getCartListFromCookie(request);
request.setAttribute("cartList", cookieCartList);
}
return "cart";
}
安装taotao-cart。
因为要调用taotao-sso与taotao-manager查询用户与商品信息,因此须要启动taotao-sso、taotao-manager。
须要登陆在cookie中写入toekn,因此要启动taotao-sso-web。
须要搜索商品,因此要启动taotao-search、taotao-search-web。(若是手动输入url进入商品详情页,能够不启动)
须要将商品详情页加入购物车,因此须要启动taotao-item-web。
最后购物车的taotao-cart、taotao-cart-web也要启动。
在taotao-cart-web的cart.js中有更新商品时js事件处理。
商品数量加1、减一时会触发对应的事件,修改dom,从而修改前端展现的商品价格。
而后会异步请求url:/cart/update/num/" + _thisInput.attr("itemId") + "/" + _thisInput.val()
也就是url:/cart/update/num/itemId/num,修改服务端的数据。
refreshTotalPrice函数用于从新计算总价。
.action
结尾的。为何呢?
*.html
结尾的请求不能够返回json数据。
直接经过JedisClient对象操做redis数据库。
在taotao-cart-interface建立接口
/**
* 根据用户ID和商品的ID更新redis购物车中商品的数量
* @param userId
* @param itemId
* @param num
* @return
*/
TaotaoResult updateTbItemCartByUserIdAndItemId(Long userId, Long itemId, Integer num);
在taotao-cart-service建立实现类
业务逻辑:
从redis中获取到对应的商品的对象,设置对象的商品数量,转成JSON,存入redis中。
@Override
public TbItem queryTbItemByUserIdAndItemId(Long userId, Long itemId) {
// 经过用户id和商品的id查询redis数据库所对应的商品的数据,若是存在则不为空
String string = jedisClient.hget(TT_CART_REDIS_PRE_KEY + ":" + userId, itemId + "");
if (StringUtils.isNotBlank(string)) {
// 将JSON转成java对象
TbItem tbItem = JsonUtils.jsonToPojo(string, TbItem.class);
return tbItem;
} else {
return null;
}
}
@Override
public TaotaoResult updateTbItemCartByUserIdAndItemId(Long userId, Long itemId, Integer num) {
// 经过用户id和商品的id查询redis数据库所对应的商品的数据,若是存在则不为空
TbItem tbItem = queryTbItemByUserIdAndItemId(userId, itemId);
if (tbItem != null) {
tbItem.setNum(num);
jedisClient.hset(TT_CART_REDIS_PRE_KEY + ":" + userId, itemId + "", JsonUtils.objectToJson(tbItem));
}
return TaotaoResult.ok();
}
同上5.4.二、发布服务
和 5.4.三、引用服务
,这里再也不赘图!
url:/cart/update/num/{itemId}/{num}
参数:itemId、num
从cookie中获取token,根据token查询redis,判断用户是否登陆,已登陆更新购物车到redis中,未登陆更新到cookie中。
更新cookie中的购物车思路比较简单:从cookie中获取全部购物车,遍历购物车找到对应商品更新数量,从新存入cookie便可。
@RequestMapping("/cart/update/num/{itemId}/{num}")
@ResponseBody // 响应json
public TaotaoResult updateTbItemCartByUserIdAndItemId(@PathVariable Long itemId, @PathVariable Integer num,
HttpServletRequest request, HttpServletResponse response) {
// 一、从cookie中获取token
String token = CookieUtils.getCookieValue(request, COOKIE_TOKEN_KEY);
// 二、根据token调用SSO的服务,获取用户的信息
TaotaoResult result = userLoginService.getUserByToken(token);
// 三、判断用户是否登陆
if (result.getStatus() == 200) {
// 用户已登陆,在redis中更新数据
TbUser tbUser = (TbUser) result.getData();
cartService.updateTbItemCartByUserIdAndItemId(tbUser.getId(), itemId, num);
} else {
// 用户没有登陆,在cookie中更新数据
updateCookieItemCart(itemId, num, request, response);
}
// 四、返回TaotaoResult.ok()
return TaotaoResult.ok();
}
/**
* 从cookie中获取购物车列表的方法
* @param request
* @return
*/
private List<TbItem> getCartListFromCookie(HttpServletRequest request) {
// 从cookie中获取购物车列表
String cartJson = CookieUtils.getCookieValue(request, COOKIE_CART_KEY, true);
// 将cartJson转换为List<TbItem>
if (StringUtils.isNotBlank(cartJson)) {
List<TbItem> list = JsonUtils.jsonToList(cartJson, TbItem.class);
return list;
}
return new ArrayList<>();
}
/**
* 更新购物车cookie中的商品数量的方法
* @param itemId
* @param num
* @param request
* @param response
*/
private void updateCookieItemCart(Long itemId, Integer num,
HttpServletRequest request, HttpServletResponse response) {
// 一、从cookie中获取商品的列表
List<TbItem> cartList = getCartListFromCookie(request);
// 二、判断,若是列表中有商品的id和传递过来的itemId一致 ,说明商品找到,更新商品的数量
for (TbItem tbItem : cartList) {
if (tbItem.getId() == itemId.longValue()) { // 两个对象比的是内存地址值,longValue()取出的是基本类型的值
tbItem.setNum(num); // 设置新的商品数量
break;
}
}
// 三、从新设置cookie,将商品的列表转换成JSON设置回cookie中
CookieUtils.setCookie(request, response, COOKIE_CART_KEY, JsonUtils.objectToJson(cartList), COOKIE_CART_EXPIRE_TIME, true);
// 四、找不到什么不处理
}
解决请求*.html后缀
没法返回json格式的数据
的问题:
问题缘由:由于在springmvc.xml中拦截*.html
结尾的请求不能够返回json数据。
解决方式:因为咱们的请求是以.action
结尾的,因此咱们修改web.xml,添加url拦截格式。
用户点击删除,未登陆从cookie中删除该商品、已登陆从redis中删除该商品。url:/cart/delete/${cart.id}.html
参数:cartid,实际上是就是itemId
根据商品id,从cookie或者redis中删除商品。
返回值:展现购物车列表页面。url须要作redirect跳转(重定向)
。
直接经过JedisClient对象操做redis数据库。
在taotao-cart-interface建立接口
/**
* 根据用户ID和商品的ID删除redis购物车中的商品
* @param userId
* @param itemId
* @param num
* @return
*/
TaotaoResult deleteTbItemCartByUserIdAndItemId(Long userId, Long itemId);
在taotao-cart-service建立实现类
业务逻辑:
根据userid、itemid删除redis中购物车列表的商品
@Override
public TaotaoResult deleteTbItemCartByUserIdAndItemId(Long userId, Long itemId) {
jedisClient.hdel(TT_CART_REDIS_PRE_KEY + ":" + userId, itemId + "");
return TaotaoResult.ok();
}
同上5.4.二、发布服务
和 5.4.三、引用服务
,这里再也不赘图!
url:/cart/delete/${cart.id}.html
参数:cartid,实际上是就是itemId
根据商品id,从cookie或者redis中删除商品
返回值:展现购物车列表页面。url须要作redirect跳转到商品列表展现的controller。
@RequestMapping("/cart/delete/{itemId}")
public String deleteTbItemCartByUserIdAndItemId(@PathVariable Long itemId,
HttpServletRequest request, HttpServletResponse response) {
// 一、从cookie中获取token
String token = CookieUtils.getCookieValue(request, COOKIE_TOKEN_KEY);
// 二、根据token调用SSO的服务,获取用户的信息
TaotaoResult result = userLoginService.getUserByToken(token);
if (result.getStatus() == 200) {
// 三、若是用户已经登陆,则删除redis中对应商品
TbUser tbUser = (TbUser) result.getData();
cartService.deleteTbItemCartByUserIdAndItemId(tbUser.getId(), itemId);
} else {
// 4.若是用户没登陆,则删除cookie中对应商品
deleteCookieCartItem(itemId, request, response);
}
return "redirect:/cart/cart.html"; // 重定向
}
/**
* 从cookie中删除购物车中的商品的方法
* @param itemId
* @param request
* @param response
*/
private void deleteCookieCartItem(Long itemId,
HttpServletRequest request, HttpServletResponse response) {
// 一、 从cookie中获取商品的列表
List<TbItem> cartList = getCartListFromCookie(request);
// 二、判断是否商品在列表中,若是列表中有商品的id和传递过来的itemId一致 ,说明商品找到,刪除商品
for (TbItem tbItem : cartList) {
if (tbItem.getId() == itemId.longValue()) { // 两个对象比的是内存地址值,longValue()取出的是基本类型的值
// 删除商品
cartList.remove(tbItem); // 在循环中删除,再遍历的话会有问题,因此咱们删除完后应当即跳出循环
break;
}
}
// 三、从新设置购物车列表到cookie中
CookieUtils.setCookie(request, response, COOKIE_CART_KEY, JsonUtils.objectToJson(cartList), COOKIE_CART_EXPIRE_TIME, true);
// 四、若是不在不处理
}
省略。。。