[업무기능 97장] 마이크로서비스-springcloud-springboot-전자상거래 장바구니 모듈-현재 로그인된 사용자의 장바구니 정보 얻기

장바구니 기능

1. 장바구니 모듈

1.카트 서비스 생성

  먼저 카트 마이크로서비스를 생성한 다음 관련 종속성을 추가하고 구성을 설정하고 주석을 릴리스해야 합니다.

<dependencies>
        <dependency>
            <groupId>com.msb.mall</groupId>
            <artifactId>mall-commons</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

그런 다음 속성 파일의 구성

server.port=40000
spring.application.name=mall-cart

spring.cloud.nacos.discovery.server-addr=192.168.56.100:8848
spring.thymeleaf.cache=false

그런 다음 구성 센터의 구성을 추가합니다: bootstrap.yml 파일

spring.application.name=mall-cart
spring.cloud.nacos.config.server-addr=192.168.56.100:8848

등록 센터의 주석을 공개합니다.

이미지.png

2.Nginx 구성

  먼저 Windows의 호스트에 해당 도메인 이름을 지정하십시오.

이미지.png

해당 정적 리소스를 Nginx의 static/cart 디렉터리에 복사합니다.

이미지.png

그런 다음 Nginx 구성 파일을 수정합니다.

이미지.png

그런 다음 nginx 서비스를 다시 시작하십시오.

docker restart nginx

3. 게이트웨이 서비스 구성

  Nginx가 이 도메인 이름에 대한 액세스를 받으면 cart.msb.com서비스를 게이트웨이 서비스로 역방향 프록시합니다. 이때 게이트웨이 서비스는 요청을 장바구니 서비스로 라우팅해야 합니다. 게이트웨이 서비스의 구성을 수정해야 합니다.

이미지.png

마지막으로 템플릿 페이지에서 정적 리소스의 경로를 조정하면 됩니다.

이미지.png

그런 다음 서비스 액세스를 시작하십시오.

이미지.png

2. 장바구니 기능

1. 장바구니 모드 처리

  데이터가 장바구니에 어떻게 저장되는지 토론해 보세요. 장바구니에 있는 여러 항목을 볼 수 있습니다.

이미지.png

그런 다음 해당 데이터를 Redis에 저장하도록 선택할 수 있습니다. 레코드가 많기 때문에 해당 데이터 저장 구조를 신중하게 고려해야 합니다. List를 사용하여 저장하는 경우

[

{
    
    skuId:1,subTile:'华为',price:666}

,{
    
    skuId:1,subTile:'华为',price:666}

,{
    
    skuId:1,subTile:'华为',price:666}

]

그러면 나중에 제품 개수를 추가, 삭제, 수정할 때 더 번거로워지는데요, List에 있는 전체 데이터를 다 꺼낸 뒤, 연산하고 싶은 데이터를 찾아 Redis에 다시 써야 합니다. 이 방법은 분명히 바람직하지 않습니다. 현재로서는 다음을 저장하기 위해 해싱을 고려할 수 있습니다.

이미지.png

이런 식으로 하나씩 처리할 수 있는데, 이는 위의 방법보다 더 유연할 것입니다. 그런 다음 백엔드 서비스에 저장하는 구조는 다음과 같습니다.

Map<String,Map<String,CartItemVo>>

2. 장바구니 VO

  장바구니의 정보 저장을 위해 두 개의 해당 VO 객체를 생성합니다.

package com.msb.mall.vo;

import java.math.BigDecimal;
import java.util.List;

/**
 * 购物车中的商品信息
 */
public class CartItem {
    
    

    // 商品的编号 SkuId
    private Long skuId;
    // 商品的图片
    private String image;
    // 商品的标题
    private String title;
    // 是否选中
    private boolean check = true;
    // 商品的销售属性
    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 String getImage() {
    
    
        return image;
    }

    public void setImage(String image) {
    
    
        this.image = image;
    }

    public String getTitle() {
    
    
        return title;
    }

    public void setTitle(String title) {
    
    
        this.title = title;
    }

    public boolean isCheck() {
    
    
        return check;
    }

    public void setCheck(boolean check) {
    
    
        this.check = check;
    }

    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() {
    
    
        // 商品的总价  price * count
        return price.multiply(new BigDecimal(count));
    }

}

카트

package com.msb.mall.vo;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.List;

/**
 * 购物车
 */
public class Cart {
    
    
    // 购物车中的商品种类
    private Integer countType;

    // 选中的商品数量
    private Integer checkCountNum;

    // 选中商品的总价
    private BigDecimal totalAmount;

    // 购物中存储的商品信息
    private List<CartItem> items;

    public Integer getCountType() {
    
    
        return items.size();
    }


    public Integer getCheckCountNum() {
    
    
        Integer count = 0;
        for (CartItem item : items) {
    
    
            if (item.isCheck()){
    
    
                count += item.getCount();
            }
        }
        return count;
    }


    public BigDecimal getTotalAmount() {
    
    
        BigDecimal amount = new BigDecimal(0);
        for (CartItem item : items) {
    
    
            if (item.isCheck()){
    
    
                amount = amount.add(item.getTotalPrice());
            }
        }
        return amount;
    }


    public List<CartItem> getItems() {
    
    
        return items;
    }

    public void setItems(List<CartItem> items) {
    
    
        this.items = items;
    }
}

3. 인증정보

  장바구니 서비스의 현재 로그인 사용자 정보를 기반으로 Redis에서 해당 장바구니 정보를 쿼리해야 합니다. 먼저 Redis의 관련 종속성을 가져와야 하며 동시에 앞서 설명한 SpringSession을 사용하여 인증된 Session 정보를 공유해야 합니다.

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.session</groupId>
            <artifactId>spring-session-data-redis</artifactId>
        </dependency>

속성 파일 정보 추가

server.port=40000
spring.application.name=mall-cart

spring.cloud.nacos.discovery.server-addr=192.168.56.100:8848
spring.thymeleaf.cache=false

spring.redis.host=192.168.56.100
spring.redis.port=6379
spring.thymeleaf.enabled=false

spring.session.store-type=redis
server.servlet.session.timeout=30m
spring.session.redis.namespace=spring:session

쿠키 구성 정보 추가

@Configuration
public class MySessionConfig {
    
    

    /**
     * 自定义Cookie的配置
     * @return
     */
    @Bean
    public CookieSerializer cookieSerializer(){
    
    
        DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer();
        cookieSerializer.setDomainName("msb.com"); // 设置session对应的一级域名
        cookieSerializer.setCookieName("msbsession");
        return cookieSerializer;
    }

    /**
     * 对存储在Redis中的数据指定序列化的方式
     * @return
     */
    @Bean
    public RedisSerializer<Object> redisSerializer(){
    
    
        return new GenericJackson2JsonRedisSerializer();
    }
}

사용자 정의 인터셉터 추가

/**
 * 我们自定义的拦截器:帮助我们获取当前登录的用户信息
 *     通过Session共享获取的
 */
public class AuthInterceptor implements HandlerInterceptor {
    
    
    // 本地线程对象  Map<thread,Object>
    public static ThreadLocal<MemberVO> threadLocal = new ThreadLocal();

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    
    
        // 通过HttpSession获取当前登录的用户信息
        HttpSession session = request.getSession();
        Object attribute = session.getAttribute(AuthConstant.AUTH_SESSION_REDIS);
        if(attribute != null){
    
    
            MemberVO memberVO = (MemberVO) attribute;
            threadLocal.set(memberVO);
        }
        return true;
    }
}

인터셉터 등록

@Configuration
public class MyWebInterceptorConfig implements WebMvcConfigurer {
    
    
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
    
    
        registry.addInterceptor(new AuthInterceptor()).addPathPatterns("/**");
    }
}

그런 다음 로그인하고 컨트롤러 서비스 테스트에 액세스하십시오.

이미지.png

4. 페이지 점프

  제품 세부 정보 페이지에서 장바구니 추가를 클릭하면 장바구니 추가 로직이 완료됩니다.

이미지.png

5. 장바구니 로직 추가

  장바구니를 추가하는 논리와 서비스에서 제품의 SKUId 및 수량을 얻은 후 구현하려는 논리를 구체적으로 완료합니다.

이미지.png

특정 핵심 코드


    /**
     * 把商品添加到购物车中
     * @param skuId
     * @param num
     * @return
     */
    @Override
    public CartItem addCart(Long skuId, Integer num) throws Exception {
    
    
        BoundHashOperations<String, Object, Object> hashOperations = getCartKeyOperation();
        // 如果Redis存储在商品的信息,那么我们只需要修改商品的数量就可以了
        Object o = hashOperations.get(skuId.toString());
        if(o != null){
    
    
            // 说明已经存在了这个商品那么修改商品的数量即可
            String json = (String) o;
            CartItem item = JSON.parseObject(json, CartItem.class);
            item.setCount(item.getCount()+num);
            hashOperations.put(skuId.toString(),JSON.toJSONString(item));
            return item;
        }
        CartItem item = new CartItem();
        CompletableFuture future1 = CompletableFuture.runAsync(()->{
    
    
            // 1.远程调用获取 商品信息
            R r = productFeignService.info(skuId);
            String skuInfoJSON = (String) r.get("skuInfoJSON");
            SkuInfoVo vo = JSON.parseObject(skuInfoJSON,SkuInfoVo.class);
            item.setCheck(true);
            item.setCount(num);
            item.setPrice(vo.getPrice());
            item.setImage(vo.getSkuDefaultImg());
            item.setSkuId(skuId);
            item.setTitle(vo.getSkuTitle());
        },executor);

        CompletableFuture future2 = CompletableFuture.runAsync(()->{
    
    
            // 2.获取商品的销售属性
            List<String> skuSaleAttrs = productFeignService.getSkuSaleAttrs(skuId);
            item.setSkuAttr(skuSaleAttrs);
        },executor);

        CompletableFuture.allOf(future1,future2).get();
        // 3.把数据存储在Redis中
        String json = JSON.toJSONString(item);
        hashOperations.put(skuId.toString(),json);

        return item;
    }
        private BoundHashOperations<String, Object, Object> getCartKeyOperation() {
    
    
        // hash key: cart:1   skuId:cartItem
        MemberVO memberVO = AuthInterceptor.threadLocal.get();
        String cartKey = CartConstant.CART_PERFIX + memberVO.getId();
        BoundHashOperations<String, Object, Object> hashOperations = redisTemplate.boundHashOps(cartKey);
        return hashOperations;
    }

6. 장바구니 홈페이지

  장바구니에 상품을 담은 후 Checkout을 클릭하여 장바구니 페이지로 진입한 후 백그라운드에서 현재 로그인된 모든 사용자의 장바구니 상품 정보를 조회하여 페이지에 표시해야 합니다.

이미지.png

이미지.png

그런 다음 페이지의 데이터를 처리합니다.

이미지.png

이미지.png

Supongo que te gusta

Origin blog.csdn.net/studyday1/article/details/132676376
Recomendado
Clasificación