1)、安装RabbitMQ
docker run -d --name rabbitmq -p 5671:5671 -p 5672:5672 -p 4369:4369 -p 25672:25672 -p 15671:15671 -p 15672:15672 rabbitmq:management
2)、访问15672端口登录后台管理界面
默认的用户名和密码都是guest
3)、为order订单访问引入RabbitMQ服务
1.引入依赖
org.springframework.boot
spring-boot-starter-amqp
2.配置环境
spring:
rabbitmq:
host: 自己的地址
port: 5672
virtual-host: /
publisher-confirm-type: correlated
publisher-returns: true
template:
mandatory: true
listener:
simple:
acknowledge-mode: manual
3.添加@EnableRabbit注解
和前面一样,这里省略
使登录信息同步
1)、引入session的依赖
org.springframework.boot
spring-boot-starter-data-redis
io.lettuce
lettuce-core
redis.clients
jedis
org.springframework.session
spring-session-data-redis
2)、引入session配置和线程池配置
spring.session.store-type=redis
gulimall.thread.core-size=20
gulimall.thread.max-size=200
gulimall.thread.keep-alive-time=10
spring.redis.host=101.43.79.94
3)、开启注解
@EnableRedisHttpSession
1)、拦截order项目所有请求
@Configuration
public class OrderWebConfiguration implements WebMvcConfigurer {
@Autowired
LoginUserInterceptor interceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(interceptor).addPathPatterns("/**");
}
}
2)、设置拦截没登录的请求
@Component
public class LoginUserInterceptor implements HandlerInterceptor {
public static ThreadLocal loginUser = new ThreadLocal<>();
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// /order/order/status/2948294820984028420
String uri = request.getRequestURI();
AntPathMatcher antPathMatcher = new AntPathMatcher();
boolean match = antPathMatcher.match("/order/order/status/**", uri);
boolean match1 = antPathMatcher.match("/payed/notify", uri);
if(match || match1){
return true;
}
MemberRespVo attribute = (MemberRespVo) request.getSession().getAttribute(AuthServerConstant.LOGIN_USER);
if(attribute!=null){
loginUser.set(attribute);
return true;
}else {
//没登录就去登录
request.getSession().setAttribute("msg","请先进行登录");
response.sendRedirect("http://auth.gulimall.com/login.html");
return false;
}
}
}
1)、封装vo
//订单确认页需要用的数据
public class OrderConfirmVo {
收货地址,ums_member_receive_address表
@Setter @Getter
List address;
//所有选中的购物项
@Setter @Getter
List items;
//发票记录....
//优惠券信息...
@Setter @Getter
Integer integration;
@Setter @Getter
Map stocks;
//防重令牌
@Setter @Getter
String orderToken;
public Integer getCount(){
Integer i = 0 ;
if(items!=null){
for (OrderItemVo item : items) {
i+=item.getCount();
}
}
return i;
}
// BigDecimal total;//订单总额
public BigDecimal getTotal() {
BigDecimal sum = new BigDecimal("0");
if(items!=null){
for (OrderItemVo item : items) {
BigDecimal multiply = item.getPrice().multiply(new BigDecimal(item.getCount().toString()));
sum = sum.add(multiply);
}
}
return sum;
}
// BigDecimal payPrice;
public BigDecimal getPayPrice() {
return getTotal();
}
//应付价格
}
2)、获取member的收货地址
@GetMapping("/{memeberId}/addresses")
public List getAddress(@PathVariable("memeberId") Long memberId){
return memberReceiveAddressService.getAddress(memberId);
}
3)、获取购物项
@GetMapping("/currentUserCartItems")
@ResponseBody
public List getCurrentUserCartItems(){
return cartService.getUserCartItems();
}
4)、查询用户积分
//3、查询用户积分
Integer integration = memberRespVo.getIntegration();
confirmVo.setIntegration(integration);
5)、请求头问题
feign远程调用丢失请求头问题:
远程调用新创建的请求会丢失cookie等请求头,需要为其添加请求头
@Configuration
public class GuliFeignConfig {
@Bean("requestInterceptor")
public RequestInterceptor requestInterceptor(){
return new RequestInterceptor(){
@Override
public void apply(RequestTemplate template) {
//1、RequestContextHolder拿到刚进来的这个请求
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if(attributes!=null){
System.out.println("RequestInterceptor线程...."+Thread.currentThread().getId());
HttpServletRequest request = attributes.getRequest(); //老请求
if(request != null){
//同步请求头数据,Cookie
String cookie = request.getHeader("Cookie");
//给新请求同步了老请求的cookie
template.header("Cookie",cookie);
}
}
}
};
}
}
6)、异步编排
CompletableFuture getAddressFuture = CompletableFuture.runAsync(() -> {
//1、远程查询所有的收货地址列表
System.out.println("member线程...." + Thread.currentThread().getId());
//每一个线程都来共享之前的请求数据
RequestContextHolder.setRequestAttributes(requestAttributes);
List address = memberFeignService.getAddress(memberRespVo.getId());
confirmVo.setAddress(address);
}, executor);
7)、查询库存
CompletableFuture cartFuture = CompletableFuture.runAsync(() -> {
//2、远程查询购物车所有选中的购物项
System.out.println("cart线程...." + Thread.currentThread().getId());
//每一个线程都来共享之前的请求数据
RequestContextHolder.setRequestAttributes(requestAttributes);
List items = cartFeignService.getCurrentUserCartItems();
confirmVo.setItems(items);
//feign在远程调用之前要构造请求,调用很多的拦截器
//RequestInterceptor interceptor : requestInterceptors
}, executor).thenRunAsync(() -> {
List items = confirmVo.getItems();
List collect = items.stream().map(item -> item.getSkuId()).collect(Collectors.toList());
//TODO 一定要启动库存服务,否则库存查不出。
R hasStock = wmsFeignService.getSkusHasStock(collect);
List