• 淘淘商城_day09_课堂笔记


    1. 今日大纲

    1. 实现购物车
    2. 基于Mysql实现读写分离
    1. 购物车

      1. 需求描述

    1. 用户可以在登录状态下将商品添加到购物车
    2. 用户可以在未登录状态下将商品添加到购物车
    3. 用户可以使用购物车一起结算下单
    4. 用户可以查询自己的购物车
    5. 用户可以在购物车中可以修改购买商品的数量。
    6. 用户可以在购物车中删除商品。

    开发模式:敏捷开发

    2个核心:

    1. 用户故事
    2. 周期迭代
    1. 业务流程

    1. 搭建购物车系统(taotao-cart)

      1. 创建工程

    1. 导入依赖

    <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.parent</groupId>

            <artifactId>taotao-parent</artifactId>

            <version>0.0.1-SNAPSHOT</version>

        </parent>

        <groupId>com.taotao.cart</groupId>

        <artifactId>taotao-cart</artifactId>

        <version>1.0.0-SNAPSHOT</version>

        <packaging>war</packaging>

     

        <dependencies>

            <dependency>

                <groupId>com.taotao.common</groupId>

                <artifactId>taotao-common</artifactId>

                <version>1.0.0-SNAPSHOT</version>

            </dependency>

            <!-- 单元测试 -->

            <dependency>

                <groupId>junit</groupId>

                <artifactId>junit</artifactId>

                <scope>test</scope>

            </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>

     

            <!-- Mybatis -->

            <dependency>

                <groupId>org.mybatis</groupId>

                <artifactId>mybatis</artifactId>

            </dependency>

            <dependency>

                <groupId>org.mybatis</groupId>

                <artifactId>mybatis-spring</artifactId>

            </dependency>

            <!-- 分页助手 -->

            <dependency>

                <groupId>com.github.pagehelper</groupId>

                <artifactId>pagehelper</artifactId>

            </dependency>

            <dependency>

                <groupId>com.github.jsqlparser</groupId>

                <artifactId>jsqlparser</artifactId>

            </dependency>

     

            <!-- 通用Mapper -->

            <dependency>

                <groupId>com.github.abel533</groupId>

                <artifactId>mapper</artifactId>

            </dependency>

     

            <!-- MySql -->

            <dependency>

                <groupId>mysql</groupId>

                <artifactId>mysql-connector-java</artifactId>

            </dependency>

     

            <dependency>

                <groupId>org.slf4j</groupId>

                <artifactId>slf4j-log4j12</artifactId>

            </dependency>

     

            <!-- Jackson Json处理工具包 -->

            <dependency>

                <groupId>com.fasterxml.jackson.core</groupId>

                <artifactId>jackson-databind</artifactId>

            </dependency>

     

            <!-- 连接池 -->

            <dependency>

                <groupId>com.jolbox</groupId>

                <artifactId>bonecp-spring</artifactId>

                <version>0.8.0.RELEASE</version>

            </dependency>

     

            <!-- httpclient -->

            <dependency>

                <groupId>org.apache.httpcomponents</groupId>

                <artifactId>httpclient</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>

     

            <!-- Apache工具组件 -->

            <dependency>

                <groupId>org.apache.commons</groupId>

                <artifactId>commons-lang3</artifactId>

            </dependency>

            <dependency>

                <groupId>org.apache.commons</groupId>

                <artifactId>commons-io</artifactId>

            </dependency>

     

        </dependencies>

        <build>

            <plugins>

                <!-- 配置Tomcat插件 -->

                <plugin>

                    <groupId>org.apache.tomcat.maven</groupId>

                    <artifactId>tomcat7-maven-plugin</artifactId>

                    <configuration>

                        <port>8086</port>

                        <path>/</path>

                    </configuration>

                </plugin>

            </plugins>

        </build>

    </project>

    1. 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"

        id="WebApp_ID" version="2.5">

        <display-name>taotao-cart</display-name>

     

        <context-param>

            <param-name>contextConfigLocation</param-name>

            <param-value>classpath:spring/applicationContext*.xml</param-value>

        </context-param>

     

        <!--SpringApplicationContext 载入 -->

        <listener>

            <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>

        </listener>

     

        <!-- 编码过滤器,以UTF8编码 -->

        <filter>

            <filter-name>encodingFilter</filter-name>

            <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>

            <init-param>

                <param-name>encoding</param-name>

                <param-value>UTF8</param-value>

            </init-param>

        </filter>

        <filter-mapping>

            <filter-name>encodingFilter</filter-name>

            <url-pattern>/*</url-pattern>

        </filter-mapping>

     

        <!-- 配置SpringMVC框架入口 -->

        <servlet>

            <servlet-name>taotao-cart</servlet-name>

            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

            <init-param>

                <param-name>contextConfigLocation</param-name>

                <param-value>classpath:spring/taotao-cart-servlet.xml</param-value>

            </init-param>

            <load-on-startup>1</load-on-startup>

        </servlet>

     

        <servlet-mapping>

            <servlet-name>taotao-cart</servlet-name>

            <url-pattern>*.html</url-pattern>

        </servlet-mapping>

     

        <welcome-file-list>

            <welcome-file>index.jsp</welcome-file>

        </welcome-file-list>

     

    </web-app>

    1. 其他配置文件

    1. 配置nginx和hosts

    Hosts:

    1. 导入页面

    1. 表结构

    使用联合索引,一定要注意索引字段的顺序

    1. 加入商品到购物车的地址

    http://cart.taotao.com/cart/{itemId}.html

    1. 通过拦截器判断用户是否登录

      1. 编写拦截器

    1. 配置拦截器

    1. 商品加入购物车

      1. Controller

    1. Service

    加入商品到购物车:

    public void addItemToCart(Long itemId) {

    // 判断该商品在购物车中是否存在

    User user = UserThreadLocal.get();

    Cart record = new Cart();

    record.setItemId(itemId);

    record.setUserId(user.getId());

    Cart cart = this.cartMapper.selectOne(record);

     

    if (null == cart) {

    // 购物车中不存在该商品

    cart = new Cart();

    cart.setItemId(itemId);

    cart.setUserId(user.getId());

    cart.setNum(1); // TODO先默认为1

    cart.setCreated(new Date());

    cart.setUpdated(cart.getCreated());

     

    Item item = this.itemService.queryItemById(itemId);

    cart.setItemImage(item.getImages()[0]);

    cart.setItemPrice(item.getPrice());

    cart.setItemTitle(item.getTitle());

     

    // Cart保存到数据库

    this.cartMapper.insert(cart);

    } else {

    // 该商品已经存在购物车中

    cart.setNum(cart.getNum() + 1); // TODO先默认为1

    cart.setUpdated(new Date());

    this.cartMapper.updateByPrimaryKey(cart);

    }

    }

     

    1. 查询购物车列表

      1. Controller

    1. Service

    按照加入购物车时间倒序排序。

    1. 测试

    1. 计算总价

    计算总价:

    显示总价:

    效果:

    1. 修改购买数量

      1. JS

        1. 限制用户输入

    解释:http://www.cnblogs.com/PeunZhang/archive/2012/08/16/2642084.html

    使用:

    1. 后台实现

      1. Controller

    1. Service

    1. 格式化价格

    格式化压缩的js:

     

    1. 删除购物车中商品

      1. Controller

    1. Service

    1. 分页插件

     

    1. 未登录状态下的购物车

      1. 以什么样数据格式保存购物车数据到cookie?

    可以使用json数据格式。

     

    [

    {

    itemId:1001

    itemTitle:"小米手机手机中的战斗机,欧耶"

    ……

    }

    ]

     

    1. Service实现

    package com.taotao.cart.service;

     

    import java.util.ArrayList;

    import java.util.Collections;

    import java.util.Comparator;

    import java.util.Date;

    import java.util.List;

     

    import javax.servlet.http.HttpServletRequest;

    import javax.servlet.http.HttpServletResponse;

     

    import org.apache.commons.lang3.StringUtils;

    import org.springframework.beans.factory.annotation.Autowired;

    import org.springframework.stereotype.Service;

     

    import com.fasterxml.jackson.databind.ObjectMapper;

    import com.taotao.cart.bean.Item;

    import com.taotao.cart.pojo.Cart;

    import com.taotao.common.utils.CookieUtils;

     

    @Service

    public class CartCookieService {

     

    private static final String COOKIE_NAME = "TT_CART";

     

    private static final Integer COOKIE_TIME = 60 * 60 * 24 * 30 * 12;

     

    private static final ObjectMapper MAPPER = new ObjectMapper();

     

    @Autowired

    private ItemService itemService;

     

    public void addItemToCart(Long itemId, HttpServletRequest request, HttpServletResponse response) {

    // 判断该商品在购物车中是否存在,如果存在数量相加,如果不存在,直接添加

    List<Cart> carts = this.queryCartList(request);

    // 判断该商品是否存在

    Cart cart = null;

    for (Cart c : carts) {

    if (c.getItemId().longValue() == itemId.longValue()) {

    cart = c;

    break;

    }

    }

     

    if (null == cart) {

    // 不存在

    cart = new Cart();

    cart.setItemId(itemId);

    cart.setCreated(new Date());

    cart.setUpdated(cart.getCreated());

    cart.setNum(1); // TODO未完成

     

    Item item = this.itemService.queryItemById(itemId);

    String[] images = StringUtils.split(item.getImage(), ',');

    if (null != images && images.length > 0) {

    cart.setItemImage(images[0]);

    }

    cart.setItemPrice(item.getPrice());

    cart.setItemTitle(item.getTitle());

    carts.add(cart);

    } else {

    // 存在

    cart.setNum(cart.getNum() + 1); // TODO未完成

    cart.setUpdated(new Date());

    }

     

    try {

    // 将购物车数据写入到cookie

    CookieUtils.setCookie(request, response, COOKIE_NAME, MAPPER.writeValueAsString(carts),

    COOKIE_TIME, true);

    } catch (Exception e) {

    e.printStackTrace();

    }

    }

     

    public List<Cart> queryCartList(HttpServletRequest request) {

    String jsonData = CookieUtils.getCookieValue(request, COOKIE_NAME, true);

    List<Cart> carts = null;

    if (StringUtils.isNotEmpty(jsonData)) {

    // 反序列化为List集合对象

    try {

    carts = MAPPER.readValue(jsonData,

    MAPPER.getTypeFactory().constructCollectionType(List.class, Cart.class));

    } catch (Exception e) {

    e.printStackTrace();

    carts = new ArrayList<Cart>();

    }

    } else {

    carts = new ArrayList<Cart>();

    }

     

    // 按照创建时间倒序排序

    Collections.sort(carts, new Comparator<Cart>() {

    @Override

    public int compare(Cart o1, Cart o2) {

    return (int) (o2.getCreated().getTime() - o1.getCreated().getTime());

    }

    });

     

    return carts;

    }

     

    public void updateNum(Long itemId, Integer num, HttpServletRequest request, HttpServletResponse response) {

    List<Cart> carts = this.queryCartList(request);

    // 判断该商品是否存在

    Cart cart = null;

    for (Cart c : carts) {

    if (c.getItemId().longValue() == itemId.longValue()) {

    cart = c;

    break;

    }

    }

    if (cart == null) {

    return;

    }

    cart.setNum(num);

    cart.setUpdated(new Date());

     

    try {

    // 将购物车数据写入到cookie

    CookieUtils.setCookie(request, response, COOKIE_NAME, MAPPER.writeValueAsString(carts),

    COOKIE_TIME, true);

    } catch (Exception e) {

    e.printStackTrace();

    }

    }

     

    public void delete(Long itemId, HttpServletRequest request, HttpServletResponse response) {

    List<Cart> carts = this.queryCartList(request);

    // 判断该商品是否存在

    for (Cart c : carts) {

    if (c.getItemId().longValue() == itemId.longValue()) {

    carts.remove(c);

    break;

    }

    }

    try {

    // 将购物车数据写入到cookie

    CookieUtils.setCookie(request, response, COOKIE_NAME, MAPPER.writeValueAsString(carts),

    COOKIE_TIME, true);

    } catch (Exception e) {

    e.printStackTrace();

    }

    }

    }

     

     

    1. 基于购物车实现下单功能

      1. 分析

    1. 购物车页面中跳转到前端的订单确认页

    1. 前端系统的中实现

     

    通过购物车系统提供的接口查询数据:

     

     

    购物车系统中开发接口,根据用户id查询购物车列表:

     

    订单确认页:

     

    关键点:form表单

     

    下单成功:

     

    数据:

    1. 购物车的优化改进

      1. 未登录状态的数据存储的优化

        1. 现在有什么问题?

    现在,将未登录状态下的购物车数据保存在cookie中,存在问题,因为,浏览器对cookie的大小是有限制的,意味着,我们不可能一直向cookie中存数据,限制了用户的使用。

     

     

    1. 如何改造、优化?

    未登录状态下的购物车数据已经不能保存在客户端(cookie),只能保存在服务端:

     

    1. 数据库
      1. 数据库的读写压力比较大
      2. 容易产生垃圾数据,需要定期去清理它
    2. 文件中
      1. 还不如保存在数据库
      2. IO(读写)问题
    3. Redis
      1. 可行的
      2. 内存存储,读写速度快
      3. 有生存时间,可以自动清理垃圾数据
      4. 但是,要考虑到一个问题,容量问题?
        1. Redis的集群
        2. 一种:分片式集群
        3. 一种:Redis3.0的新功能,集群
    4. 其他
      1. 。。。。
      1. 使用Redis的什么数据结构?

    方案一:

    将原有的cookie中字符串数据,按照字符串的数据结构保存到Redis中。

     

    该方案存在的问题:

    对于每一个Cart对象的操作,都需要经历,字符串 è List<Cart> è 字符串,假如,购物车中1000个商品,问题就更为突出了。

     

    方案二:

    使用Redis的hash结构。

     

    结构: key field value

    实现:

    1. key : 为每一个人都生成一个唯一的key,可以使用md5
    2. field :商品id
    3. value: Cart对象序列化之后的json字符串

     

    显然,我们采用方案二。

    1. 扩展RedisService

     

    /**

    * 保存数据到hash结构中(指定生存时间)

    *

    * @param key

    * @param field

    * @param value

    * @param seconds

    * @return

    */

    public Long hset(final String key, final String field, final String value, final Integer seconds) {

    return this.execute(new Function<Long, ShardedJedis>() {

    @Override

    public Long callback(ShardedJedis e) {

    Long _long = e.hset(key, field, value);

    e.expire(key, seconds);

    return _long;

    }

    });

    }

     

    /**

    * 保存数据到hash结构中

    *

    * @param key

    * @param field

    * @param value

    * @return

    */

    public Long hset(final String key, final String field, final String value) {

    return this.execute(new Function<Long, ShardedJedis>() {

    @Override

    public Long callback(ShardedJedis e) {

    return e.hset(key, field, value);

    }

    });

    }

     

    /**

    * 获取hash中的数据

    *

    * @param key

    * @param field

    * @return

    */

    public String hget(final String key, final String field) {

    return this.execute(new Function<String, ShardedJedis>() {

    @Override

    public String callback(ShardedJedis e) {

    return e.hget(key, field);

    }

    });

    }

     

    /**

    * 获取hash结构中所有的数据

    *

    * @param key

    * @return

    */

    public Map<String, String> hgetAll(final String key) {

    return this.execute(new Function<Map<String, String>, ShardedJedis>() {

    @Override

    public Map<String, String> callback(ShardedJedis e) {

    return e.hgetAll(key);

    }

    });

    }

     

    /**

    * 删除hash中的数据

    *

    * @param key

    * @param field

    * @return

    */

    public Long hdel(final String key, final String field) {

    return this.execute(new Function<Long, ShardedJedis>() {

    @Override

    public Long callback(ShardedJedis e) {

    return e.hdel(key, field);

    }

    });

    }

    1. 实现RedisService

    import java.util.ArrayList;

    import java.util.Collections;

    import java.util.Comparator;

    import java.util.Date;

    import java.util.List;

    import java.util.Map;

     

    import javax.servlet.http.HttpServletRequest;

    import javax.servlet.http.HttpServletResponse;

     

    import org.apache.commons.codec.digest.DigestUtils;

    import org.apache.commons.lang3.RandomUtils;

    import org.apache.commons.lang3.StringUtils;

    import org.springframework.beans.factory.annotation.Autowired;

    import org.springframework.stereotype.Service;

     

    import com.fasterxml.jackson.databind.ObjectMapper;

    import com.taotao.cart.bean.Item;

    import com.taotao.cart.pojo.Cart;

    import com.taotao.common.service.RedisService;

    import com.taotao.common.utils.CookieUtils;

     

    @Service

    public class CartRedisService {

     

    private static final String COOKIE_NAME = "TT_CART";

     

    private static final Integer TIME = 60 * 60 * 24 * 30;

     

    @Autowired

    private ItemService itemService;

     

    @Autowired

    private RedisService redisService;

     

    private static final ObjectMapper MAPPER = new ObjectMapper();

     

    public void addItemToCart(Long itemId, HttpServletRequest request, HttpServletResponse response) {

    String key = CookieUtils.getCookieValue(request, COOKIE_NAME);

    if (StringUtils.isEmpty(key)) {

    // 生存一个key

    key = DigestUtils.md5Hex("" + System.currentTimeMillis() + itemId

    + RandomUtils.nextInt(1000, 9999));

    // 写入到cookie

    CookieUtils.setCookie(request, response, COOKIE_NAME, key, TIME);

    }

    // 判断该商品在购物车中是否存在,如果存在数量相加,如果不存在,直接添加

    String redisKey = "CART_" + key;

    String cartStr = this.redisService.hget(redisKey, String.valueOf(itemId));

    Cart cart = null;

    if (StringUtils.isNotEmpty(cartStr)) {

    try {

    cart = MAPPER.readValue(cartStr, Cart.class);

    } catch (Exception e) {

    e.printStackTrace();

    }

    }

     

    if (null == cart) {

    // 不存在

    cart = new Cart();

    cart.setItemId(itemId);

    cart.setCreated(new Date());

    cart.setUpdated(cart.getCreated());

    cart.setNum(1); // TODO未完成

     

    Item item = this.itemService.queryItemById(itemId);

    String[] images = StringUtils.split(item.getImage(), ',');

    if (null != images && images.length > 0) {

    cart.setItemImage(images[0]);

    }

    cart.setItemPrice(item.getPrice());

    cart.setItemTitle(item.getTitle());

    } else {

    // 存在

    cart.setNum(cart.getNum() + 1); // TODO未完成

    cart.setUpdated(new Date());

    }

     

    try {

    this.redisService.hset(redisKey, String.valueOf(itemId), MAPPER.writeValueAsString(cart), TIME);

    } catch (Exception e) {

    e.printStackTrace();

    }

    }

     

    public List<Cart> queryCartList(HttpServletRequest request, HttpServletResponse response) {

    String key = CookieUtils.getCookieValue(request, COOKIE_NAME);

    String redisKey = "CART_" + key;

    Map<String, String> map = this.redisService.hgetAll(redisKey);

    if (null == map || map.isEmpty()) {

    return new ArrayList<Cart>();

    }

    List<Cart> carts = new ArrayList<Cart>();

    for (String k : map.keySet()) {

    String json = map.get(k);

    Cart cart;

    try {

    cart = MAPPER.readValue(json, Cart.class);

    carts.add(cart);

    } catch (Exception e) {

    // 如果有异常,就忽略该数据

    e.printStackTrace();

    }

    }

     

    // 按照创建时间倒序排序

    Collections.sort(carts, new Comparator<Cart>() {

    @Override

    public int compare(Cart o1, Cart o2) {

    return (int) (o2.getCreated().getTime() - o1.getCreated().getTime());

    }

    });

     

    // 刷新数据的生存时间

    this.redisService.expire(redisKey, TIME);

    CookieUtils.setCookie(request, response, COOKIE_NAME, key, TIME);

     

    return carts;

    }

     

    public void updateNum(Long itemId, Integer num, HttpServletRequest request) {

    String key = CookieUtils.getCookieValue(request, COOKIE_NAME);

    String redisKey = "CART_" + key;

    String cartStr = this.redisService.hget(redisKey, String.valueOf(itemId));

    if (StringUtils.isEmpty(cartStr)) {

    return;

    }

    Cart cart = null;

    if (StringUtils.isNotEmpty(cartStr)) {

    try {

    cart = MAPPER.readValue(cartStr, Cart.class);

    } catch (Exception e) {

    e.printStackTrace();

    }

    }

     

    if (null != cart) {

    cart.setNum(num);

    cart.setUpdated(new Date());

     

    try {

    this.redisService.hset(redisKey, String.valueOf(itemId), MAPPER.writeValueAsString(cart),

    TIME);

    } catch (Exception e) {

    e.printStackTrace();

    }

    }

    }

     

    public void delete(Long itemId, HttpServletRequest request) {

    String key = CookieUtils.getCookieValue(request, COOKIE_NAME);

    String redisKey = "CART_" + key;

    this.redisService.hdel(redisKey, String.valueOf(itemId));

    }

     

    }

     

    1. 登录成功后,合并未登录和登录状态下的数据

      1. 合并的动作在哪个系统中完成?

    1. 实现分析

    1. 用户在登录成功时,需要发送消息到交换机
      1. 发送消息时,携带cookie中的购物车key的值
    2. 购物车系统创建队列,绑定到该交换机
    3. 购物车系统接收到消息之后,读取未登录状态下的购物车数据,和数据库中的数据进行合并,清空未登录状态下的数据
      1. Sso系统中发送登录成功的消息

    4. 导入依赖
    5. RabbitMQ的配置文件
    6. 在UserService中,登录成功后发送消息
      1. 购物车系统中接收消息

    7. 导入依赖
    8. 配置文件
    9. 处理消息

     

    @Service

    public class CartRedisService {

     

    private static final String COOKIE_NAME = "TT_CART";

     

    private static final Integer TIME = 60 * 60 * 24 * 30;

     

    @Autowired

    private ItemService itemService;

     

    @Autowired

    private RedisService redisService;

     

    private static final ObjectMapper MAPPER = new ObjectMapper();

     

    public void addItemToCart(Long itemId, HttpServletRequest request, HttpServletResponse response) {

    String key = CookieUtils.getCookieValue(request, COOKIE_NAME);

    if (StringUtils.isEmpty(key)) {

    // 生存一个key

    key = DigestUtils.md5Hex("" + System.currentTimeMillis() + itemId

    + RandomUtils.nextInt(1000, 9999));

    // 写入到cookie

    CookieUtils.setCookie(request, response, COOKIE_NAME, key, TIME);

    }

    // 判断该商品在购物车中是否存在,如果存在数量相加,如果不存在,直接添加

    String redisKey = getRedisKey(key);

    String cartStr = this.redisService.hget(redisKey, String.valueOf(itemId));

    Cart cart = null;

    if (StringUtils.isNotEmpty(cartStr)) {

    try {

    cart = MAPPER.readValue(cartStr, Cart.class);

    } catch (Exception e) {

    e.printStackTrace();

    }

    }

     

    if (null == cart) {

    // 不存在

    cart = new Cart();

    cart.setItemId(itemId);

    cart.setCreated(new Date());

    cart.setUpdated(cart.getCreated());

    cart.setNum(1); // TODO未完成

     

    Item item = this.itemService.queryItemById(itemId);

    String[] images = StringUtils.split(item.getImage(), ',');

    if (null != images && images.length > 0) {

    cart.setItemImage(images[0]);

    }

    cart.setItemPrice(item.getPrice());

    cart.setItemTitle(item.getTitle());

    } else {

    // 存在

    cart.setNum(cart.getNum() + 1); // TODO未完成

    cart.setUpdated(new Date());

    }

     

    try {

    this.redisService.hset(redisKey, String.valueOf(itemId), MAPPER.writeValueAsString(cart), TIME);

    } catch (Exception e) {

    e.printStackTrace();

    }

    }

     

    public List<Cart> queryCartList(String cookieCart) {

    String redisKey = getRedisKey(cookieCart);

    Map<String, String> map = this.redisService.hgetAll(redisKey);

    if (null == map || map.isEmpty()) {

    return new ArrayList<Cart>();

    }

    List<Cart> carts = new ArrayList<Cart>();

    for (String k : map.keySet()) {

    String json = map.get(k);

    Cart cart;

    try {

    cart = MAPPER.readValue(json, Cart.class);

    carts.add(cart);

    } catch (Exception e) {

    // 如果有异常,就忽略该数据

    e.printStackTrace();

    }

    }

    // 刷新数据的生存时间

    this.redisService.expire(redisKey, TIME);

    return carts;

    }

     

    public List<Cart> queryCartList(HttpServletRequest request, HttpServletResponse response) {

    String key = CookieUtils.getCookieValue(request, COOKIE_NAME);

    List<Cart> carts = this.queryCartList(key);

    // 按照创建时间倒序排序

    Collections.sort(carts, new Comparator<Cart>() {

    @Override

    public int compare(Cart o1, Cart o2) {

    return (int) (o2.getCreated().getTime() - o1.getCreated().getTime());

    }

    });

     

    CookieUtils.setCookie(request, response, COOKIE_NAME, key, TIME);

    return carts;

    }

     

    public void updateNum(Long itemId, Integer num, HttpServletRequest request) {

    String key = CookieUtils.getCookieValue(request, COOKIE_NAME);

    String redisKey = getRedisKey(key);

    String cartStr = this.redisService.hget(redisKey, String.valueOf(itemId));

    if (StringUtils.isEmpty(cartStr)) {

    return;

    }

    Cart cart = null;

    if (StringUtils.isNotEmpty(cartStr)) {

    try {

    cart = MAPPER.readValue(cartStr, Cart.class);

    } catch (Exception e) {

    e.printStackTrace();

    }

    }

     

    if (null != cart) {

    cart.setNum(num);

    cart.setUpdated(new Date());

     

    try {

    this.redisService.hset(redisKey, String.valueOf(itemId), MAPPER.writeValueAsString(cart),

    TIME);

    } catch (Exception e) {

    e.printStackTrace();

    }

    }

    }

     

    private String getRedisKey(String cookieKey){

    return "CART_" + cookieKey;

    }

     

    public void delete(Long itemId, HttpServletRequest request) {

    String key = CookieUtils.getCookieValue(request, COOKIE_NAME);

    String redisKey = getRedisKey(key);

    this.redisService.hdel(redisKey, String.valueOf(itemId));

    }

     

    public void clear(String cookieCart) {

    String redisKey = getRedisKey(cookieCart);

    this.redisService.del(redisKey);

    }

     

    }

    1. 下单成功后,删除成功下单的商品

      1. 分析

    订单系统中,下单成功后发送消息。

     

    1. 订单系统发消息
    2. 购物车系统监听消息
    3. 处理消息
      1. 实现

    4. 导入Spring-rabbit依赖
    5. 编写配置文件
    6. 发送消息
    7. 处理消息(taotao-cart)

      1. 读写分离

    《使用Spring实现读写分离(MySQL实现主从复制).docx》

    1. 主从设置失败

     

    如何定位问题?

     

    查看3381的日志:

     

    问题:

     

    如何设置Mysql的UUID?

     

     

    问题解决:

     

  • 相关阅读:
    Redis集群的搭建
    CAS部署在Windows上
    Loadrunner中Error-26612HTTP Status-Cod
    Coneroller执行时候的-26374及-26377错误
    Loadrunner 26377错误
    歌名也好笑
    loadrunner 中Error和failed transaction 的区别
    loadrunner 性能测试报error-27796的解决
    lr11.0负载测试 real-world schedule 与basic schedule的区别是什么
    LR中错误代号为27796的一个解决方法
  • 原文地址:https://www.cnblogs.com/beyondcj/p/6272738.html
Copyright © 2020-2023  润新知