六,购物⻋
6.1购物⻋
购物⻋分为⽤户登录购物⻋和未登录购物⻋操作,国内知名电商京东⽤户登录和不登录都可以操作购物⻋,如果⽤户不登录,操作购物⻋可以将数据存储到Cookie或者WebSQL或者SessionStorage中,⽤户登录后购物⻋数据可以存储到Redis中,再将之前未登录加⼊的购物⻋合并到Redis中即可。
京东购物⻋⽅案:
天猫则采⽤了另外⼀种实现⽅案,⽤户要想将商品加⼊购物⻋,必须先登录才能操作购物⻋。我们今天实现的购物⻋是天猫解决⽅案,即⽤户必须先登录才能使⽤购物⻋功能。
6.1.1 购物⻋分析
(1)需求分析
⽤户在商品详细⻚点击加⼊购物⻋,提交商品SKU编号和购买数量,添加到购物⻋。购物⻋展示⻚⾯如下:
(2)购物⻋实现思路
我们实现的是⽤户登录后的购物⻋,⽤户将商品加⼊购物⻋的时候,直接将要加⼊购物⻋的详情存⼊到Redis即可。每次查看购物⻋的时候直接从Redis中获取。
(3)表结构分析
⽤户登录后将商品加⼊购物⻋,需要存储商品详情以及购买数量,购物⻋详情表如下:数据中order_item_表:
CREATE TABLE `order_item_` (
`id` varchar(20) COLLATE utf8_bin NOT NULL COMMENT 'ID',
`category_id1` int(11) DEFAULT NULL COMMENT '1级分类',
`category_id2` int(11) DEFAULT NULL COMMENT '2级分类',
`category_id3` int(11) DEFAULT NULL COMMENT '3级分类',
`spu_id` varchar(20) COLLATE utf8_bin DEFAULT NULL COMMENT 'SPU_ID',
`sku_id` bigint(20) NOT NULL COMMENT 'SKU_ID',
`order_id` bigint(20) NOT NULL COMMENT '订单ID',
`name` varchar(200) COLLATE utf8_bin DEFAULT NULL COMMENT '商品名称',
`price` int(20) DEFAULT NULL COMMENT '单价',
`num` int(10) DEFAULT NULL COMMENT '数量',
`money` int(20) DEFAULT NULL COMMENT '总⾦额',
`pay_money` int(11) DEFAULT NULL COMMENT '实付⾦额',
`image` varchar(200) COLLATE utf8_bin DEFAULT NULL COMMENT '图⽚地址',
`weight` int(11) DEFAULT NULL COMMENT '重量',
`post_fee` int(11) DEFAULT NULL COMMENT '运费',
`is_return` char(1) COLLATE utf8_bin DEFAULT NULL COMMENT '是否退货',
PRIMARY KEY (`id`),
KEY `item_id` (`sku_id`),
KEY `order_id` (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
购物⻋详情表其实就是订单详情表结构,只是⽬前临时存储数据到Redis,等⽤户下单后才将数据从Redis取出存⼊到MySQL中。
6.1.2 搭建订单购物⻋微服务
因为购物⻋功能⽐较简单,这⾥我们把订单和购物⻋微服务放在⼀个⼯程下
(1) pom.xml
legou-order/pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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">
<parent>
<artifactId>legou-parent</artifactId>
<groupId>com.lxs</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>legou-order</artifactId>
<packaging>pom</packaging>
<modules>
<module>legou-order-interface</module>
<module>legou-order-service</module>
</modules>
</project>
legou-order/legou-order-interface/pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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">
<parent>
<artifactId>legou-order</artifactId>
<groupId>com.lxs</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>legou-order-interface</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>com.lxs</groupId>
<artifactId>legou-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.core.Starter</mainClass>
<layout>ZIP</layout>
<classifier>exec</classifier>
<includeSystemScope>true</includeSystemScope>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
legou-order/legou-order-service/pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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">
<parent>
<artifactId>legou-order</artifactId>
<groupId>com.lxs</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>legou-order-service</artifactId>
<dependencies>
<!-- redis 使⽤-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</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-netflix-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
<dependency>
<groupId>com.lxs</groupId>
<artifactId>legou-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.46</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.lxs</groupId>
<artifactId>legou-order-interface</artifactId>
<version>${project.version}</version>
</dependency>
<!--商品微服务-->
<dependency>
<groupId>com.lxs</groupId>
<artifactId>legou-item-instance</artifactId>
<version>${project.version}</version>
</dependency>
<!-- swagger -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
<!--oauth2-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
</dependencies>
</project>
(2) 启动器配置⽂件
public.key 拷⻉即可
legou-order/legou-order-service/src/main/resources/bootstrap.yml
spring:
application:
name: order-service
# 多个接⼝上的@FeignClient(“相同服务名”)会报错,overriding is disabled。
# 设置 为true ,即 允许 同名
main:
allow-bean-definition-overriding: true
config-repo/order-service.yml
server:
port: 9009
spring:
redis:
host: 192.168.220.110
port: 6379
mybatis-plus:
mapper-locations: classpath*:mybatis/*/*.xml
type-aliases-package: com.lxs.legou.*.po
configuration:
# 下划线驼峰转换
map-underscore-to-camel-case: true
lazy-loading-enabled: true
aggressive-lazy-loading: false
logging:
#file: demo.log
pattern:
console: "%d - %msg%n"
level:
org.springframework.web: debug
com.lxs: debug
security:
oauth2:
resource:
jwt:
key-uri: http://localhost:9098/oauth/token_key #如果使⽤JWT,可以获取公钥⽤于 token 的验签
legou-order/legou-order-service/src/main/java/com/legou/order/OrderApplication.java
package com.legou.order;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
/**
* @author
* @version 1.0
* @description 订单微服务
* @createDate 2022/6/20 16:50
**/
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
@EnableCircuitBreaker
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class, args);
}
}
(3)配置类
配置类和其他资源微服务⼯程类似,拷⻉修改即可
legou-order/legou-order-service/src/main/java/com/legou/order/config/MybatisPlusConfig.java
package com.legou.order.config;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.pagination.optimize.JsqlParserCountOptimize;
import com.github.pagehelper.PageInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author
* @version 1.0
* @description
* @createDate 2022/6/20 16:52
**/
@Configuration
@MapperScan("com.lxs.legou.order.dao")
public class MybatisPlusConfig {
/**
* 分⻚插件
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
// 开启 count 的 join 优化,只针对 left join !!!
return new PaginationInterceptor().setCountSqlParser(new JsqlParserCountOptimize(true));
}
@Bean
public PageInterceptor pageInterceptor() {
return new PageInterceptor();
}
}
legou-order/legou-order-
service/src/main/java/com/legou/order/config/JwtConfig.java
package com.legou.order.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
import org.springframework.util.FileCopyUtils;
import java.io.IOException;
/**
* @author
* @version 1.0
* @description
* @createDate 2022/6/20 16:54
**/
@Configuration
public class JwtConfig {
public static final String public_cert = "mickey_public.key";
@Autowired
private JwtAccessTokenConverter jwtAccessTokenConverter;
@Bean
@Qualifier("tokenStore"