SSM分布式项目之淘淘商城-第十二天(IDEA)

文章大纲
一、购物车流程
二、购物车系统的搭建
三、购物车系统实现分析
四、购物车系统实现的准备工作
五、添加商品到购物车
六、展示购物车列表
七、更新购物车的商品数量
八、删除购物车中的商品
九、参考博客

淘淘商城课程大纲

课程大纲
一共14天课程
(1)第一天:电商介绍–互联网术语-SOA-分布式-集群介绍-环境配置-框架搭建
(2)第二天:Dubbo介绍_dubbo框架整合_商品列表查询实现_分页_逆向工程
(3)第三天:Git&.Nginx,类目选择,新增商品
(4)第四天:门户网站介绍&商城首页搭建&内容系统创建&CMS实现
(5)第五天:首页轮播图显示实现,Redis环境搭建,Redis实现缓存
(6)第六天:solr索引库搭建&solr搜索功能实现&图片显示问题解决
(7)第七天:solr集群搭建_全局异常处理
(8)第八天:activeMQ介绍_搭建_解决同步索引库问题
(9)第九天:FreeMark入门_静态化页面标签介绍_静态化页面实现
(10)第十天:Nginx代理详解…单点登录系统工程搭建_接口文档讲解
(11)第十一天:SSO系统的搭建&单点登录系统实现_用户名回显_cookie跨域问题
(12)第十二天:购物车订单系统的实现。
(13)第十三天:订单提交的功能实现&项目的部署&服务器的域名规划。
(14)项目总结。

1. 购物车流程

1.1 以前的购物车流程

用户将商品添加到购物车时,判断用户是否登录,如果已经登录将购物车放入session中。

存在的问题:
  购物车使用了session,而session是存在于内存资源中,消耗了大量的内存资源。非常不好。
  购物车存在session当中,如果session销毁(浏览器关闭),购物车就没有了。
  session无法共享,无法进行水平扩展。
    解决方案:给购物车做持久化。
    持久化,需要用到数据库(把数据存储到服务端,较安全)。
    a、mysql数据库(数据完整性比较好)
    b、redis数据库(读写速度快)

用户未登录的时候不能添加购物车。
    解决方案:未登录的状态下,可以把购物车放在cookie中。
  在不登陆的情况下添加购物车。把购物车信息写入cookie。(数据保存在客户端,数据完整性差)。
  优点:
    1、不占用服务端存储空间。
    2、用户体验好。
    3、代码实现简单。
  缺点:
    1、cookie中保存的容量有限。最大4k。
    2、把购物车信息保存在cookie中,更换设备购物车信息不能同步。
  这里我们不使用这种方法。

1.2 现在的购物车流程

对于未登陆用户,将购物车放到cookie中。对于已登陆用户将购物车放入redis缓存中。可以实现,用户未登录或者登录状况下的添加购物车(并进行购物车的增删查改)。

2. 商城购物车系统的搭建

2.1 购物车系统的架构

购物车系统架构:

taotao-cart(pom聚合工程)
  |–taotao-cart-interface(jar)
  |–taotao-cart-Service(war)
taotao-cart-web(war)

可以参考taotao-manager、taotao-manager-web创建。

2.2 服务层工程搭建

taotao-cart

taotao-cart打包方式pom。
可以参考taotao-manager工程的创建。
New --> Maven Project --> 不使用骨架创建工程 --> Next

pom.xml

<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>
    <modules>
        <module>taotao-cart-interface</module>
        <module>taotao-cart-service</module>
    </modules>
    <parent>
        <groupId>com.taotao</groupId>
        <artifactId>taotao-parent</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <groupId>com.taotao</groupId>
    <artifactId>taotao-cart</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>pom</packaging>
    <dependencies>
        <!-- 依赖taotao-manager-common -->
        <dependency>
            <groupId>com.taotao</groupId>
            <artifactId>taotao-common</artifactId>
            <version>1.0-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>

taotao-cart-interface

New --> Other–> Maven Module --> 不使用骨架创建
千万不要创建成Maven Project。
taotao-cart-interface打包方式jar。
pom.xml

<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>1.0-SNAPSHOT</version>
    </parent>
    <artifactId>taotao-cart-interface</artifactId>
    <dependencies>
        <!-- 依赖taotao-manager-pojo -->
        <dependency>
            <groupId>com.taotao</groupId>
            <artifactId>taotao-manager-pojo</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>
</project>

taotao-cart-service

New --> Other–> Maven Module --> 不使用骨架创建
千万不要创建成Maven Project。
taotao-cart-service打包方式war。
pom.xml

<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>1.0-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>1.0-SNAPSHOT</version>
        </dependency>
        <!-- 配置对taotao-cart-interface的依赖:服务层发布服务要通过该接口 -->
        <dependency>
            <groupId>com.taotao</groupId>
            <artifactId>taotao-cart-interface</artifactId>
            <version>1.0-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中配置spring的监听器,内容如下:
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-service</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
  <!-- 初始化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中

删除或清空与数据库相关的配置文件,因为购物车主要使用redis缓存,所以需要将redis的工具类添加进来:

修改applicationContext-service.xml中spring注解包扫描的类与dubbo暴露服务的端口:

在taotao-cart-interface工程的src/main/java中创建com.taotao.cart.service包;
在taotao-cart-service工程的src/main/java中创建com.taotao.cart.service.impl包。

在这里插入图片描述

2.3 表现层工程搭建

taotao-cart-web

表现层为一个单独的工程,所以需要创建Maven Project。
New --> Maven Project
千万不要创建成Maven Module。
taotao-cart-web的打包方式是war。

pom.xml

	<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>1.0-SNAPSHOT</version>
    </parent>
    <groupId>com.taotao</groupId>
    <artifactId>taotao-cart-web</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>
    <dependencies>
        <dependency>
            <groupId>com.taotao</groupId>
            <artifactId>taotao-cart-interface</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>com.taotao</groupId>
            <artifactId>taotao-sso-interface</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>com.taotao</groupId>
            <artifactId>taotao-manager-interface</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <!-- 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>
        <!-- dubbo相关 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>dubbo</artifactId>
            <!-- 排除依赖 -->
            <exclusions>
                <exclusion>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.jboss.netty</groupId>
                    <artifactId>netty</artifactId>
                </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>
            <scope>test</scope>
        </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.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.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>
    <!-- SEO :搜索引擎优化   伪静态化-->
    <url-pattern>*.html</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>taotao-cart-web</servlet-name>
    <!-- SEO :搜索引擎优化   伪静态化-->
    <url-pattern>*.action</url-pattern>
  </servlet-mapping>
</web-app>

框架整合

将表现层taotao-manager-web工程下的src/main/resources下面的配置文件复制到taotao-cart-web下的src/main/resources中
删除或清空相关的配置文件:

修改springmvc.xml中controller注解扫描的位置:

在taotao-manager-web工程下创建com.taotao.cart.controller包。
在这里插入图片描述

3. 商城购物车系统的实现分析

3.1 购物车如何表示

由于购物车中的商品属性与TbItem类似,所以可以将TbItem当做购买的商品。TbItem中的num属性原用作后台管理系统的商品库存数量,在这里可以将num属性用作购买商品的数量,所以List就是一个购物车。一个用户对应一个购物车,一个购物车对应多个商品。

3.2 怎么将购物车存入cookie中

对于存入cookie中,我们可以自定义key,然后将购物车List转为json串,存到cookie。

3.3 使用哪种redis数据结构存放购物车

由于一个用户对应一个购物车,一个购物车购买多个商品。相当于一个用户可以购买多个商品。
对于存入redis中,我们有两种实现方案:
1.方案一:
  使用String类型,将用户userId作为key,将购物List转为json串作为value。

2.方案二:
  使用hash类型,将用户userId作为key,将商品itemId作为filed,将购物车List转为json串作为value。

推荐使用hash,可以提高修改的效率(性能的提升),如果是String存储大数据量的时候速度较慢。redis是单线程。
分析需要存储的商品的信息的属性有:
  商品的ID、商品的名称、商品的价格、购买商品的数量、商品的图片(取一张即可)。

3.4 创建POJO

可以直接使用TbItem。

4 购物车系统实现的准备工作

由于购物车系统的运行,依赖很多其他系统,为了防止登录注册等其他情况,url错误报404导致不好测试,需要修改整个淘淘商城系统中的url为正确的url。
4.1、修改所有登录注册的url

Ctrl+H,搜索所有的:http://localhost:8084/page,将8084改为8088

搜索结果如下:
在这里插入图片描述我已经全部改好了
现在搜索8088,看看
在这里插入图片描述
8084的地方都改成这样的

5. 添加商品到购物车

5.1 导入静态资源

将参考资料中的购物车静态页面下的js、css、images导入webapp下,将jsp导入WEB-INF下:

5.2 修改商品详情页

商品详情在taotao-item-web系统的item.jsp中,给加入购物车添加一个事件javascript:addCartItem();
注意一定要修改这个,要不然到后面购物车列表会有一个很大的坑,在计算数量的时候,num=null,我就因为这个找了一上午的BUG

在这里插入图片描述

在前端点击添加购物车,就会触发addCartItem函数,跳转url:cart/add/itemId.html?num=123,我们需要接收itemId与num,同步到redis或者cookie中。
添加购物车功能的分析:
  url:/cart/add/{itemId}?num=2
  参数:商品的id以及num
  另外:用户的id(因为要保证redis中存储数据的正确性,必须要求要存放于哪一个用户的购物车数据)
  返回值:逻辑视图,cartSuccess.jsp 。

实际上,是搜索加入购物车,前面跳转的地方加上端口号
在这里插入图片描述

5.3 添加购物车

Dao层

直接通过JedisClient对象操作redis数据库。
  
Service层

业务逻辑:
  1、根据商品的ID查询商品的信息。
  2、设置商品的数量和图片(只需要设置图片的一张即可,数量使用num字段来表示,因为原来的num存放的是库存,所以需要重新设置一下)。
  3、根据商品id和用户id从redis数据库中查询用户的购物车的商品的列表,看是否存在(需要将JSON转成java对象)。
  4、如果没有存在,则直接添加到redis中(需要将java对象转成JSON)。
  5、如果存在,则更新商品购买的数量即可。
首先在taotao-cart-interface下创建接口包com.taotao.cart.service,在接口包下创建接口CartService.java。

package com.taotao.cart.service;

import com.taotao.common.pojo.TaotaoResult;
import com.taotao.pojo.TbItem;

import java.util.List;

public interface CartService {
	/**
	 * 添加购物车
	 * @param itemId
	 * @param num
	 * @param userId
	 * @return
	 */
	public TaotaoResult addItemCart(TbItem item, Integer num, Long userId);
	

使用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:

	@Autowired
	private JedisClient client;
	
	@Value("${TT_CART_REDIS_PRE_KEY}")
	private String TT_CART_REDIS_PRE_KEY;
	

	// 登录状态下的添加购物车  hash
	@Override
	public TaotaoResult addItemCart(TbItem item, Integer num, Long userId) {
		// 1.查询  可以根据 key 和field获取某一个商品
		TbItem itemtem = queryItemByItemIdAndUserId(item.getId(), userId);
		// 2.判断要添加的商品是否存在于列表中
		if(itemtem!=null){
			// 3.如果存在,直接数量相加
			itemtem.setNum(itemtem.getNum()+num);
			//图片只取一张
			//设置到redis
			client.hset(TT_CART_REDIS_PRE_KEY+":"+userId+"", itemtem.getId()+"", JsonUtils.objectToJson(itemtem));
		}else{
			// 4.如果不存在,直接添加到redis中
				//查询商品的数据 (商品的名称商品的价格,商品的图片。。) 调用商品的服务  直接从controller中传递
				//.设置商品的数量
			item.setNum(num);
				//.设置商品的图片为一张
			if(item.getImage()!=null){
				item.setImage(item.getImage().split(",")[0]);
			}
			//.设置到redis中
			client.hset(TT_CART_REDIS_PRE_KEY+":"+userId+"", item.getId()+"", JsonUtils.objectToJson(item));
		}
		return TaotaoResult.ok();
	}

	private TbItem queryItemByItemIdAndUserId(Long itemId, Long userId) {
		String string = client.hget(TT_CART_REDIS_PRE_KEY+":"+userId+"", itemId+"");
		if(StringUtils.isNoneBlank(string)){
			TbItem tbItem = JsonUtils.jsonToPojo(string, TbItem.class);
			return tbItem;
		}
		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文件中引用服务

Controller

url: /cart/add/{itemId}
参数:itemId, num
返回值:添加购物车成功页面。
业务逻辑:
  1、调用SSO的服务,获取用户相关的信息。
  2、调用商品(manage)的服务,获取商品的相关的信息。
  3、判断如果是登录的状态,则调用登录的添加购物车的service。
  4、如果是未登录的状态,则调用的是未登录的添加购物车的方法。

在taotao-cart-web下创建controller的包com.taotao.cart.controller,在包controller中创建CartController.java:

@Controller
public class CartController {
	@Autowired
	private CartService cartservice;
	@Autowired
	private UserLoginService loginservice;
	@Autowired
	private ItemService itemservice;

	@Value("${TT_TOKEN_KEY}")
	private String TT_TOKEN_KEY;
	@Value("${TT_CART_KEY}")
	private String TT_CART_KEY;

	/**
	 * url:/cart/add/{itemId}?num=2 参数:商品的id 以及num 返回值:jsp页面
	 * 
	 */
	@RequestMapping("/cart/add/{itemId}")
	public String addItemCart(@PathVariable Long itemId, Integer num, HttpServletRequest request,
			HttpServletResponse response) {
		// 1.引入服务
		// 2.注入服务

		// 3.判断用户是否登录
		// 从cookie中获取用户的token信息
		String token = CookieUtils.getCookieValue(request, TT_TOKEN_KEY);
		// 调用SSO的服务查询用户的信息
		TaotaoResult result = loginservice.getUserByToken(token);

		// 获取商品的数据
		TbItem tbItem = itemservice.getItemById(itemId);
		if (result.getStatus() == 200) {
			// 4.如果已登录,调用service的方法
			TbUser user = (TbUser) result.getData();
			cartservice.addItemCart(tbItem, num, user.getId());
		} else {
			// 5.如果没有登录 调用设置到cookie的方法
			// 先根据cookie获取购物车的列表
			List<TbItem> cartList = getCookieCartList(request);
			boolean flag = false;
			// 判断如果购物车中有包含要添加的商品 商品数量相加
			for (TbItem tbItem2 : cartList) {
				if (tbItem2.getId() == itemId.longValue()) {
					// 找到列表中的商品 更新数量
					tbItem2.setNum(tbItem2.getNum() + num);
					flag = true;
					break;
				}
			}
			if (flag == true) {
				// 如果找到对应的商品,更新数量后,还需要设置回cookie中
				CookieUtils.setCookie(request, response, TT_CART_KEY, JsonUtils.objectToJson(cartList), 7 * 24 * 3600,
						true);
			} else {
				// 如果没有就直接添加到购物车
				// 调用商品服务
				// 设置数量
				tbItem.setNum(num);
				// 设置图片为一张
				if (tbItem.getImage() != null) {
					tbItem.setImage(tbItem.getImage().split(",")[0]);
				}
				// 添加商品到购物车中
				cartList.add(tbItem);
				// 设置到cookie中
				CookieUtils.setCookie(request, response, TT_CART_KEY, JsonUtils.objectToJson(cartList), 7 * 24 * 3600,
						true);
			}
		}
		return "cartSuccess";
	}
}
	// 获取购物车的列表
	private List<TbItem> getCookieCartList(HttpServletRequest request) {
		// 从cookie中获取商品的列表
		String jsonstr = CookieUtils.getCookieValue(request, TT_CART_KEY, true);// 商品的列表的JSON
		// 讲商品的列表的JSON转成 对象
		if (StringUtils.isNotBlank(jsonstr)) {
			List<TbItem> list = JsonUtils.jsonToList(jsonstr, TbItem.class);
			return list;
		}
		return new ArrayList<>();

	}

5.4 访问测试

首先退出用户登录状态,使用我们已经做好的查看购物车列表的功能,查看cookie中是否存入了购物车,可以看到未登录的情况下,添加购物车成功。

在这里插入图片描述

6. 展示购物车列表

如果用户登录状态,展示购物车列表以redis为准。如果未登录,以cookie为准。

6.1 功能分析

添加商品到购物车后,会提示【去购物车结算】,点击【去购物车结算】,会跳转到http://localhost:8089/cart/cart.html页面,可以看到购物车中商品列表。
在cart.jsp,我们可以看到需要准备一个cartList商品集合到model中。需要修改 c a r t . i m a g e s [ 0 ] 为 {cart.images[0]}为 cart.images[0]{cart.image}。

url: /cart/cart
参数:用户id
返回值:购物车页面,需要传递模型数据list

6.2 Dao层

直接通过JedisClient对象操作redis数据库。

6.3 Service层

在taotao-cart-interface创建接口

	/**
	 * 根据用户的ID查询用户的购物车的列表
	 * @param userId
	 * @return
	 */
	public List<TbItem> getCartList(Long userId);

在taotao-cart-service编写实现类
业务逻辑:
  1、根据用户的ID查询redis中所有的field的值(map)。
  2、遍历map对象,将其添加到List中。
  3、返回一个List。

// 获取购物车的商品的列表
	public List<TbItem> getCartList(Long userId) {
		Map<String, String> map = client.hgetAll(TT_CART_REDIS_PRE_KEY+":"+userId + "");
		//
		List<TbItem> list = new ArrayList<>();
		if (map != null) {
			for (Map.Entry<String, String> entry : map.entrySet()) {
				String value = entry.getValue();// 商品的jSON数据
				// 转成POJO
				TbItem item = JsonUtils.jsonToPojo(value, TbItem.class);
				list.add(item);
			}
		}
		return list;
	}

发布服务与引用服务

6.4 Controller

url: /cart/cart
参数:无
返回值:购物车展示列表的页面
业务逻辑:
  1、根据token调用SSO的服务,获取用户的信息。
  2、判断,如果有用户的信息,说明用户已登录,调用CartService服务中查询购物车的商品列表的方法。
  3、如果没有用户信息,说明用户未登录,调用从cookie中获取购物车商品列表的方法。
  4、将购物车对象放入request域。
  5、返回逻辑页面cart.jsp。

代码如下:

// 展示购物车的列表
	@RequestMapping("/cart/cart")
	public String getCartList(HttpServletRequest request) {
		// 1.引入服务
		// 2.注入服务

		// 3.判断用户是否登录
		// 从cookie中获取用户的token信息
		String token = CookieUtils.getCookieValue(request, TT_TOKEN_KEY);
		// 调用SSO的服务查询用户的信息
		TaotaoResult result = loginservice.getUserByToken(token);

		System.out.println(result.getData());
		// 获取商品的数据
		if (result.getStatus() == 200) {
			// 4.如果已登录,调用service的方法
			TbUser user = (TbUser) result.getData();
			List<TbItem> cartList = cartservice.getCartList(user.getId());
			System.out.println(cartList.size());
			request.setAttribute("cartList", cartList);
		} else {
			// 5.如果没有登录 调用cookie的方法 获取商品的列表
			List<TbItem> cartList = getCookieCartList(request);
			// 将数据传递到页面中
			request.setAttribute("cartList", cartList);
		}
		return "cart";
	}

6.5 访问测试

安装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也要启动。

在这里插入图片描述

7. 更新购物车的商品数量

7.1 更新购物车的商品数量的js分析

在taotao-cart-web的cart.js中有更新商品时js事件处理。
商品数量加一、减一时会触发对应的事件,修改dom,从而修改前端展示的商品价格。
然后会异步请求url:/cart/update/num/" + _thisInput.attr(“itemId”) + “/” + _thisInput.val()
也就是url:/cart/update/num/itemId/num,修改服务端的数据。
refreshTotalPrice函数用于重新计算总价。

注意:我们的请求是以.action结尾的。为什么呢?
答:因为在springmvc.xml中拦截*.html结尾的请求不可以返回json数据。

7.2 Dao层

直接通过JedisClient对象操作redis数据库。

7.3 Service层

在taotao-cart-interface创建接口

	/**
	 * 根据商品的ID 更新数量
	 * @param itemId 商品的ID
	 * @param num 更新后的数量
	 * @param userId 用户的id  购物车的id
	 * @return
	 */
	public TaotaoResult updateItemCartByItemId(Long userId, Long itemId, Integer num);

在taotao-cart-service创建实现类
业务逻辑:
从redis中获取到对应的商品的对象,设置对象的商品数量,转成JSON,存入redis中。

	@Override
	public TaotaoResult updateItemCartByItemId(Long userId, Long itemId, Integer num) {
		//1.根据用户id和商品的id获取商品的对象
		TbItem tbItem = queryItemByItemIdAndUserId(itemId,userId);
		//判断是否存在
		if(tbItem!=null){
			//2.更新数量
			tbItem.setNum(num);
			//设置回redis中
			client.hset(TT_CART_REDIS_PRE_KEY+":"+userId, itemId+"", JsonUtils.objectToJson(tbItem));
		}else{
			//不管啦
		}
		return TaotaoResult.ok();
	}
	
	private TbItem queryItemByItemIdAndUserId(Long itemId, Long userId) {
		String string = client.hget(TT_CART_REDIS_PRE_KEY+":"+userId+"", itemId+"");
		if(StringUtils.isNoneBlank(string)){
			TbItem tbItem = JsonUtils.jsonToPojo(string, TbItem.class);
			return tbItem;
		}
		return null;
	}

发布服务与引用服务

7.4 Controller

url:/cart/update/num/{itemId}/{num}
参数:itemId、num
从cookie中获取token,根据token查询redis,判断用户是否登录,已登录更新购物车到redis中,未登录更新到cookie中。
更新cookie中的购物车思路比较简单:从cookie中获取所有购物车,遍历购物车找到对应商品更新数量,重新存入cookie即可。

	/**
	 * url:/cart/update/num/{itemId}/{num} 参数:商品的id 和更新后的数量 还有用户的id 返回值:json
	 */
	@RequestMapping("/cart/update/num/{itemId}/{num}")
	@ResponseBody
	public TaotaoResult updateItemCartByItemId(@PathVariable Long itemId, @PathVariable Integer num,
			HttpServletRequest request, HttpServletResponse response) {
		// 1.引入服务
		// 2.注入服务

		// 3.判断用户是否登录
		// 从cookie中获取用户的token信息
		String token = CookieUtils.getCookieValue(request, TT_TOKEN_KEY);
		// 调用SSO的服务查询用户的信息
		TaotaoResult result = loginservice.getUserByToken(token);

		// 获取商品的数据
		if (result.getStatus() == 200) {
			// 4.如果已登录,调用service的方法
			TbUser user = (TbUser) result.getData();
			// 更新商品的数量
			cartservice.updateItemCartByItemId(user.getId(), itemId, num);
		} else {
			// 5.如果没有登录 调用cookie的方法 更新cookie中的商品的数量的方法
			updateCookieItemCart(itemId, num, request, response);
		}
		return TaotaoResult.ok();
	}

	/**
	 * 更新商品的数量
	 * 
	 * @param itemId
	 * @param num
	 */
	private void updateCookieItemCart(Long itemId, Integer num, HttpServletRequest request,
			HttpServletResponse response) {
		// 1.获取cookie中的购物车的商品列表
		List<TbItem> cartList = getCookieCartList(request);
		// 2.判断修改的商品是否在购物车的列表中
		boolean flag = false;
		for (TbItem tbItem : cartList) {
			// 表示找到了要修改的商品
			if (tbItem.getId() == itemId.longValue()) {
				tbItem.setNum(num);
				flag = true;
				break;
			}
		}
		if (flag == true) {
			// 3.如果存在 更新数量
			CookieUtils.setCookie(request, response, TT_CART_KEY, JsonUtils.objectToJson(cartList), 7 * 24 * 3600,
					true);
		} else {
			// 4.如果不存在 不管啦。
		}
	}

7.5 访问测试

解决请求*.html后缀无法返回json格式的数据的问题:
问题原因:因为在springmvc.xml中拦截*.html结尾的请求不可以返回json数据。
解决方式:由于我们的请求是以.action结尾的,所以我们修改web.xml,添加url拦截格式。

在这里插入图片描述

8. 删除购物车中的商品

8.1 功能分析

用户点击删除,未登录从cookie中删除该商品、已登录从redis中删除该商品。
url:/cart/delete/${cart.id}.html
参数:cartid,其实是就是itemId
根据商品id,从cookie或者redis中删除商品。
返回值:展示购物车列表页面。url需要做redirect跳转(重定向)。

8.2 Dao层

直接通过JedisClient对象操作redis数据库。

8.3 Service层

在taotao-cart-interface创建接口

	public TaotaoResult deleteItemCartByItemId(Long userId, Long itemId);

在taotao-cart-service创建实现类
业务逻辑:
根据userid、itemid删除redis中购物车列表的商品


```java
@Override
	public TaotaoResult deleteItemCartByItemId(Long userId, Long itemId) {
		client.hdel(TT_CART_REDIS_PRE_KEY+":"+userId, itemId+"");
		return TaotaoResult.ok();
	}

8.4 Controller

url:/cart/delete/${cart.id}.html
参数:cartid,其实是就是itemId
根据商品id,从cookie或者redis中删除商品
返回值:展示购物车列表页面。url需要做redirect跳转到商品列表展示的controller。

	/**
	 * url:/cart/delete/{itemId} 参数:用户的ID 还有商品的ID 返回值:string 逻辑视图
	 */
	// 删除购物车中的商品
	@RequestMapping("/cart/delete/{itemId}")
	public String deleteItemCartByItemId(@PathVariable Long itemId, HttpServletRequest request,
			HttpServletResponse response) {
		// 1.引入服务
		// 2.注入服务

		// 3.判断用户是否登录
		// 从cookie中获取用户的token信息
		String token = CookieUtils.getCookieValue(request, TT_TOKEN_KEY);
		// 调用SSO的服务查询用户的信息
		TaotaoResult result = loginservice.getUserByToken(token);

		// 获取商品的数据
		if (result.getStatus() == 200) {
			// 4.如果已登录,调用service的方法
			TbUser user = (TbUser) result.getData();
			// 删除
			cartservice.deleteItemCartByItemId(user.getId(), itemId);
		} else {
			// 5.如果没有登录 调用cookie的方法 删除cookie中的商品
			deleteCookieItemCartByItemId(itemId, request, response);
		}
		return "redirect:/cart/cart.html";// 重定向
	}
	
	/**
	 * 删除cookie中的购物车的商品
	 * 
	 * @param itemId
	 * @param request
	 * @param response
	 */
	private void deleteCookieItemCartByItemId(Long itemId, HttpServletRequest request, HttpServletResponse response) {
		// 1.从cookie中获取商品的列表
		List<TbItem> cartList = getCookieCartList(request);
		// 2.判断 商品是否存在于商品的列表中
		boolean flag = false;
		for (TbItem tbItem : cartList) {
			if (tbItem.getId() == itemId.longValue()) {
				// 找到要删除的商品
				cartList.remove(tbItem);
				flag = true;
				// break;
			}
		}
		if (flag == true) {
			// 3.如果存在,删除
			CookieUtils.setCookie(request, response, TT_CART_KEY, JsonUtils.objectToJson(cartList), 7 * 24 * 3600,
					true);
		}
		// 4.如果不存在,不管
	}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值