淘淘商城_day09_课堂笔记
今日大纲
- 实现购物车
- 基于Mysql实现读写分离
购物车
需求描述
- 用户可以在登录状态下将商品添加到购物车
- 用户可以在未登录状态下将商品添加到购物车
- 用户可以使用购物车一起结算下单
- 用户可以查询自己的购物车
- 用户可以在购物车中可以修改购买商品的数量。
- 用户可以在购物车中删除商品。
开发模式:敏捷开发
2个核心:
- 用户故事
- 周期迭代
业务流程
搭建购物车系统(taotao-cart)
创建工程
导入依赖
<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>
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>
<!--Spring的ApplicationContext 载入 -->
<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>
其他配置文件
配置nginx和hosts
Hosts:
导入页面
表结构
使用联合索引,一定要注意索引字段的顺序。
加入商品到购物车的地址
http://cart.taotao.com/cart/{itemId}.html
通过拦截器判断用户是否登录
编写拦截器
配置拦截器
商品加入购物车
Controller
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.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.setUpdated(new Date());
this.cartMapper.updateByPrimaryKey(cart);
}
}
查询购物车列表
Controller
Service
按照加入购物车时间倒序排序。
测试
计算总价
计算总价:
显示总价:
效果:
修改购买数量
JS
限制用户输入
解释:http://www.cnblogs.com/PeunZhang/archive/2012/08/16/2642084.html
使用:
后台实现
Controller
Service
格式化价格
格式化压缩的js:
删除购物车中商品
Controller
Service
分页插件
未登录状态下的购物车
以什么样数据格式保存购物车数据到cookie?
可以使用json数据格式。
[
{
itemId:1001
itemTitle:"小米手机手机中的战斗机,欧耶"
……
}
]
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();
}
}
}
基于购物车实现下单功能
分析
购物车页面中跳转到前端的订单确认页
前端系统的中实现
通过购物车系统提供的接口查询数据:
购物车系统中开发接口,根据用户id查询购物车列表:
订单确认页:
关键点:form表单
下单成功:
数据:
购物车的优化改进
未登录状态的数据存储的优化
现在有什么问题?
现在,将未登录状态下的购物车数据保存在cookie中,存在问题,因为,浏览器对cookie的大小是有限制的,意味着,我们不可能一直向cookie中存数据,限制了用户的使用。
如何改造、优化?
未登录状态下的购物车数据已经不能保存在客户端(cookie),只能保存在服务端:
- 数据库
- 数据库的读写压力比较大
- 容易产生垃圾数据,需要定期去清理它
- 文件中
- 还不如保存在数据库
- IO(读写)问题
- Redis
- 可行的
- 内存存储,读写速度快
- 有生存时间,可以自动清理垃圾数据
- 但是,要考虑到一个问题,容量问题?
- Redis的集群
- 一种:分片式集群
- 一种:Redis3.0的新功能,集群
- 其他
- 。。。。
使用Redis的什么数据结构?
方案一:
将原有的cookie中字符串数据,按照字符串的数据结构保存到Redis中。
该方案存在的问题:
对于每一个Cart对象的操作,都需要经历,字符串 è List<Cart> è 字符串,假如,购物车中1000个商品,问题就更为突出了。
方案二:
使用Redis的hash结构。
结构: key field value
实现:
- key : 为每一个人都生成一个唯一的key,可以使用md5
- field :商品id
- value: Cart对象序列化之后的json字符串
显然,我们采用方案二。
扩展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);
}
});
}
实现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));
}
}
登录成功后,合并未登录和登录状态下的数据
合并的动作在哪个系统中完成?
实现分析
- 用户在登录成功时,需要发送消息到交换机
- 发送消息时,携带cookie中的购物车key的值
- 购物车系统创建队列,绑定到该交换机
- 购物车系统接收到消息之后,读取未登录状态下的购物车数据,和数据库中的数据进行合并,清空未登录状态下的数据
Sso系统中发送登录成功的消息
- 导入依赖
- RabbitMQ的配置文件
- 在UserService中,登录成功后发送消息
购物车系统中接收消息
- 导入依赖
- 配置文件
- 处理消息
@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);
}
}
下单成功后,删除成功下单的商品
分析
订单系统中,下单成功后发送消息。
- 订单系统发消息
- 购物车系统监听消息
- 处理消息
实现
- 导入Spring-rabbit依赖
- 编写配置文件
- 发送消息
- 处理消息(taotao-cart)
读写分离
《使用Spring实现读写分离(MySQL实现主从复制).docx》
主从设置失败
如何定位问题?
查看3381的日志:
问题:
如何设置Mysql的UUID?
问题解决:
淘淘商城_day09_课堂笔记的更多相关文章
- 淘淘商城_day11_课堂笔记
今日大纲 发布前的准备 实施发布 一部分是由我来发布 一部分是由你们来发布 讲解分布式部署架构 测试 功能测试 压力测试 项目实战的准备以及分组 分组 抽取功能 讲解所需要开发的功能 项目部署上线流程 ...
- 淘淘商城_day01_课堂笔记
今日大纲 聊聊电商行业 电商行业发展 11.11 2015双11: 2016年: 预测:2017年的双11交易额将达到:1400亿 电商行业技术特点 淘淘商城简介 淘淘商城的前身 电商行业的概念 B2 ...
- 淘淘商城_day04_课堂笔记
今日大纲 实现首页的大广告位功能 实现内容管理系统 首页的大广告 什么是大广告 JS效果: 点击下面的序号选择查询哪个广告 自动切换 点击图片查询具体的页面 以上是由前端团队来开发. 数据结构 说明: ...
- 淘淘商城_day02_课堂笔记
今日大纲 学习Nginx的使用 实现商品的管理 新增商品 查询商品列表 编辑商品 删除商品 上架和下架商品 学习nginx 开发阶段中的环境 开发环境:自己的电脑 测试环境:提供给测试人员使用的环境 ...
- 淘淘商城_day10_课堂笔记
今日大纲 Dubbo入门学习 使用dubbo优化单点登录系统 系统间服务调用方式 浏览器直接访问 浏览器发起请求,通过ajax或jsonp方式请求: Httpclient方式 系统与系统之间通过Htt ...
- 淘淘商城_day08_课堂笔记
今日大纲 问题,如何实现商品数据的同步? 学习MQ(消息队列) 搭建RabbitMQ的环境 学习RabbitMQ的队列 学习Spring-Rabbit 使用RabbitMQ完成商品数据的同步 如何实现 ...
- 淘淘商城_day07_课堂笔记
今日大纲 讲解订单系统 基于订单系统完成下单功能的开发 使用Solr完成商品的搜索功能 订单系统 说明:订单系统只是做讲解,不做开发. 导入taotao-order 表结构 订单表: 订单商品表: 疑 ...
- 淘淘商城_day05_课堂笔记
今日大纲 学习Redis 使用Redis完成项目中缓存需求 实现商品详情页功能 缓存的需求 大广告位数据无需每次查询后台系统的接口,可以在前台系统添加缓存,提高访问首页的速度. 商品类目的数据也可以缓 ...
- 淘淘商城_day06_课堂笔记
今日大纲 实现单点登录系统 基于单点登录系统实现,用户的注册和登录 商品数据同步问题 问题 后台系统中将商品修改,前台系统没有进行数据的同步,导致前端系统不能够实时显示最新的数据. 解决 后台系统中商 ...
随机推荐
- java基础(一)对象
对象的创建 Test test = new Test(); Test test = new Test("a"); 其实,对象被创建出来时,对象就是一个对象的引用,这个引用在内存中为 ...
- Vmware Vcenter6.0 全新安装及群集配置介绍
介绍如何安装vsphere ESxi主机及将vmware vsphere5.5升级到vmware vsphere6.0的介绍,而今天呢,主要介绍vsphere vcenter,说到vsphere vc ...
- Kattis - Aaah!
Aaah! Photo by Unknown Jon Marius shouted too much at the recent Justin Bieber concert, and now need ...
- 一个经典的js中关于块级作用域和声明提升的问题
function functions(flag) { if (flag) { function getValue() { return 'a'; } } else { function getValu ...
- sass---Sass混合宏、继承、占位符
混合宏-声明混合宏如果你的整个网站中有几处小样式类似,比如颜色,字体等,在 Sass 可以使用变量来统一处理,那么这种选择还是不错的.但当你的样式变得越来越复杂,需要重复使用大段的样式时,使用变量就无 ...
- 敏捷开发(十一)- Scrum Sprint评审会议
本文主要是为了检测你对SCRUM 评审会议的了解和使用程度, 通过本文你可以检测一下 1.你们的SCRUM 评审会议的过程和步骤 2.SCRUM 评审会议的输出结果一.会议目的 ...
- 更改系统相机UIImagePickerController导航栏的cancle为自定义按钮
有时候需要对系统相册里面的取消按钮进行自定义,并获取点击事件做一些操作,那么你可以这样做. 第一:实现navigationController代理 - (void)navigationControll ...
- 学习笔记_ADB常用指令
ADB 查看连接到计算机的Android设备或模拟器 adb devices 说明: 正常显示状态应该是IP:Port State. State=device说明设备已经连接到计算机, State=o ...
- 凭借5G研究优势,诺基亚将携手菲律宾将其应用于VR/AR领域
目前,很多人都在抱怨网速不行,影响视频的流畅播放,未来这些问题可以通过5G解决.近日,诺基亚和PLDT的全资子公司Smart首次在菲律宾一个"现场"网络演示上实现了5G速度,该网络 ...
- DUIlib使用Fastreport--报表简单使用
fastreport是一个简单优秀的报表,fastreport更多是和delphi联合使用预览和打印数据的.我在开始使用duilib做项目时,打印和数据预览都是自己绘制的,这样不仅绘制麻烦费事费事,而 ...