商城业务--> 购物车 - ThreadLocal用户身份鉴别

This commit is contained in:
Kirk Lin 2021-07-10 15:57:02 +08:00
parent 5782c0679a
commit c0eabe572b
9 changed files with 378 additions and 7 deletions

View file

@ -4,9 +4,11 @@ import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
@SpringBootApplication
@EnableDiscoveryClient
@EnableRedisHttpSession
@EnableFeignClients("name.lkk.kkmall.cart.feign")
public class KkmallCartApplication {

View file

@ -0,0 +1,22 @@
package name.lkk.kkmall.cart.config;
import name.lkk.kkmall.cart.interceptor.CartInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @author: kirklin
* @date: 2021/7/10 3:33 下午
* @description: 添加拦截器
*/
@Configuration
public class CartWebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
WebMvcConfigurer.super.addInterceptors(registry);
registry.addInterceptor(new CartInterceptor()).addPathPatterns("/**");
}
}

View file

@ -0,0 +1,38 @@
package name.lkk.kkmall.cart.controller;
import lombok.extern.slf4j.Slf4j;
import name.lkk.kkmall.cart.interceptor.CartInterceptor;
import name.lkk.kkmall.cart.to.UserInfoTo;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
/**
* @author: kirklin
* @date: 2021/7/10 3:39 下午
* @description:
*/
@Slf4j
@Controller
public class CartController {
/**
* 去购物车页面的请求
* 浏览器有一个cookie:user-key 标识用户的身份一个月过期
* 如果第一次使用jd的购物车功能都会给一个临时的用户身份:
* 浏览器以后保存每次访问都会带上这个cookie
* <p>
* 登录session有
* 没登录按照cookie里面带来user-key来做
* 第一次如果没有临时用户自动创建一个临时用户
*
* @return
*/
@GetMapping({"/", "/cart.html"})
public String carListPage() {
//快速得到用户信息id,user-key
UserInfoTo userInfoTo = CartInterceptor.userInfoToThreadLocal.get();
log.info(userInfoTo.toString());
return "cartList";
}
}

View file

@ -0,0 +1,70 @@
package name.lkk.kkmall.cart.interceptor;
import name.lkk.common.constant.AuthServerConstant;
import name.lkk.common.constant.CartConstant;
import name.lkk.common.constant.DomainConstant;
import name.lkk.common.vo.MemberRsepVo;
import name.lkk.kkmall.cart.to.UserInfoTo;
import org.springframework.util.ObjectUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.UUID;
/**
* @author: kirklin
* @date: 2021/7/10 3:12 下午
* @description: 购物车拦截器在执行业务之前 判断用户是否登录,并使用ThreadLocal封装UserInfoTo
*/
public class CartInterceptor implements HandlerInterceptor {
public static ThreadLocal<UserInfoTo> userInfoToThreadLocal = new InheritableThreadLocal<>();
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
UserInfoTo userInfoTo = new UserInfoTo();
HttpSession session = request.getSession();
MemberRsepVo user = (MemberRsepVo) session.getAttribute(AuthServerConstant.LOGIN_USER);
if (user != null) {
//用户已经登陆了
userInfoTo.setUsername(user.getUsername());
userInfoTo.setUserId(user.getId());
}
Cookie[] cookies = request.getCookies();
if (cookies != null && cookies.length > 0) {
for (Cookie cookie : cookies) {
String name = cookie.getName();
if (name.equals(CartConstant.TEMP_USER_COOKIE_NAME)) {
userInfoTo.setUserKey(cookie.getValue());
userInfoTo.setTempUser(true);
}
}
}
if (ObjectUtils.isEmpty(userInfoTo.getUserKey())) {
String uuid = UUID.randomUUID().toString().replace("-", "");
userInfoTo.setUserKey(uuid);
}
userInfoToThreadLocal.set(userInfoTo);
return HandlerInterceptor.super.preHandle(request, response, handler);
}
/**
* 执行完毕之后分配临时用户让浏览器保存
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
UserInfoTo userInfoTo = userInfoToThreadLocal.get();
userInfoToThreadLocal.remove();
if (!userInfoTo.isTempUser()) {
Cookie cookie = new Cookie(CartConstant.TEMP_USER_COOKIE_NAME, userInfoTo.getUserKey());
// 设置这个cookie作用域 过期时间
cookie.setDomain(DomainConstant.MALL_DOMAIN);
cookie.setMaxAge(CartConstant.TEMP_USER_COOKIE_TIME_OUT);
response.addCookie(cookie);
}
}
}

View file

@ -0,0 +1,32 @@
package name.lkk.kkmall.cart.to;
import lombok.Data;
import lombok.ToString;
/**
* @author kirklin
*/
@ToString
@Data
public class UserInfoTo {
/**
* 存储已登录用户在数据库中的ID
*/
private Long userId;
/**
* 存储用户名
*/
private String username;
/**
* 配分一个临时的user-key
*/
private String userKey;
/**
* 判断是否是临时用户
*/
private boolean tempUser = false;
}

View file

@ -0,0 +1,87 @@
package name.lkk.kkmall.cart.vo;
import java.math.BigDecimal;
import java.util.List;
/**
* 购物车本VO的GETSET方法非默认实现
*/
public class Cart {
private List<CartItem> items;
/**
* 商品的数量
*/
private Integer countNum;
/**
* 商品的类型数量
*/
private Integer countType;
/**
* 整个购物车的总价
*/
private BigDecimal totalAmount;
/**
* 减免的价格
*/
private BigDecimal reduce = new BigDecimal("0.00");
public List<CartItem> getItems() {
return items;
}
public void setItems(List<CartItem> items) {
this.items = items;
}
/**
* 计算商品的总量
*
* @return
*/
public Integer getCountNum() {
int count = 0;
if (this.items != null && this.items.size() > 0) {
for (CartItem item : this.items) {
count += item.getCount();
}
}
return count;
}
public Integer getCountType() {
int count = 0;
if (this.items != null && this.items.size() > 0) {
for (CartItem item : this.items) {
count += 1;
}
}
return count;
}
public BigDecimal getTotalAmount() {
BigDecimal amount = new BigDecimal("0");
if (this.items != null && this.items.size() > 0) {
for (CartItem item : this.items) {
if (item.getCheck()) {
BigDecimal totalPrice = item.getTotalPrice();
amount = amount.add(totalPrice);
}
}
}
return amount.subtract(this.getReduce());
}
public BigDecimal getReduce() {
return reduce;
}
public void setReduce(BigDecimal reduce) {
this.reduce = reduce;
}
}

View file

@ -0,0 +1,102 @@
package name.lkk.kkmall.cart.vo;
import java.math.BigDecimal;
import java.util.List;
/**
* 购物车商品项本VO的GETSET方法非默认实现
*/
public class CartItem {
private Long skuId;
/**
* 是否被选中
*/
private Boolean check = true;
private String title;
private String image;
private List<String> skuAttr;
/**
* 价格
*/
private BigDecimal price;
/**
* 数量
*/
private Integer count;
private BigDecimal totalPrice;
public Long getSkuId() {
return skuId;
}
public void setSkuId(Long skuId) {
this.skuId = skuId;
}
public Boolean getCheck() {
return check;
}
public void setCheck(Boolean check) {
this.check = check;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getImage() {
return image;
}
public void setImage(String image) {
this.image = image;
}
public List<String> getSkuAttr() {
return skuAttr;
}
public void setSkuAttr(List<String> skuAttr) {
this.skuAttr = skuAttr;
}
public BigDecimal getPrice() {
return price;
}
public void setPrice(BigDecimal price) {
this.price = price;
}
public Integer getCount() {
return count;
}
public void setCount(Integer count) {
this.count = count;
}
/**
* 手动计算总价
*/
public BigDecimal getTotalPrice() {
return this.price.multiply(new BigDecimal("" + this.count));
}
public void setTotalPrice(BigDecimal totalPrice) {
this.totalPrice = totalPrice;
}
}

View file

@ -1,13 +1,17 @@
package name.lkk.common.constant;
/**
* <p>Title: CartConstant</p>
* Description
* date2020/6/27 22:37
* 购物车常量
*
* @author kirklin
*/
public class CartConstant {
public static final String TEMP_USER_COOKIE_NAME = "user-key";
public static final int TEMP_USER_COOKIE_TIME_OUT = 60 * 60 * 24 * 30;
/**
* 购物车临时用户COOKIE
*/
public static final String TEMP_USER_COOKIE_NAME = "user-key";
/**
* 购物车临时用户COOKIE过期时间
*/
public static final int TEMP_USER_COOKIE_TIME_OUT = 60 * 60 * 24 * 30;
}

View file

@ -0,0 +1,14 @@
package name.lkk.common.constant;
/**
* @author: kirklin
* @date: 2021/7/10 3:29 下午
* @description: 域名常量
*/
public class DomainConstant {
public static final String MALL_DOMAIN = "kkmall.com";
public static final String MALL_HTTP_DOMAIN = "http://kkmall.com";
public static final String MALL_HTTPS_DOMAIN = "https://kkmall.com";
}