mirror of
https://github.com/kirklin/kkmall.git
synced 2024-09-20 06:46:15 +08:00
商城业务--> 购物车 - ThreadLocal用户身份鉴别
This commit is contained in:
parent
5782c0679a
commit
c0eabe572b
|
@ -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 {
|
||||
|
||||
|
|
|
@ -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("/**");
|
||||
|
||||
}
|
||||
}
|
|
@ -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";
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
87
kkmall-cart/src/main/java/name/lkk/kkmall/cart/vo/Cart.java
Normal file
87
kkmall-cart/src/main/java/name/lkk/kkmall/cart/vo/Cart.java
Normal file
|
@ -0,0 +1,87 @@
|
|||
package name.lkk.kkmall.cart.vo;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 购物车,!本VO的GET,SET方法非默认实现。
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
102
kkmall-cart/src/main/java/name/lkk/kkmall/cart/vo/CartItem.java
Normal file
102
kkmall-cart/src/main/java/name/lkk/kkmall/cart/vo/CartItem.java
Normal file
|
@ -0,0 +1,102 @@
|
|||
package name.lkk.kkmall.cart.vo;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 购物车商品项,!本VO的GET,SET方法非默认实现。
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
|
@ -1,13 +1,17 @@
|
|||
package name.lkk.common.constant;
|
||||
|
||||
/**
|
||||
* <p>Title: CartConstant</p>
|
||||
* Description:
|
||||
* date:2020/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;
|
||||
}
|
||||
|
|
|
@ -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";
|
||||
|
||||
}
|
Loading…
Reference in a new issue