购物车(登录后)

添加商品sku到购物车,我们需要用fegin调用商品微服务完成根据商品id查询商品sku的操作
**
【商品微服务】把根据商品id查询商品sku的操作定义出来
用fegin对外暴露
【订单微服务】操作添加购物车
**
数据结构:

1)前端浏览器发送携带skuId,num(cookie)的请求
--------------------网关gateway-web-------------------
2)网关拦截请求&请求参数,判断书否拦截请求,拦截请求后根据请求cookie获得jwt,并将令牌添加的请求头和请求放行,路由到对应微服务(web-order)
--------------------前端web-order---------------------
3)前端工程接收到网关转发到的请求&请求参数,校验用户携带的jwt,校验通过则访问controller
controller中会根据需要调用对应的微服务工程(service-order里在order-api中定义的的cart fegin),获取数据或者执行增删改操作。
--------------------远程调用接口service-order-api-----------
--------------------后端微服务service-order-----------
4)controller控制层接收前台请求&请求参数,获取登录人的用户名,把skuId,num,username传递给service,调用service完成业务逻辑处理,返回给前端浏览器。
5)service业务层,根据用户名name,skuId查询redis,获取当前用户购物车信息cart中指定的orderitem的信息,
如果orderitem没有就把skuId转换为orderitem并存入购物车
如果orderitem已经存在,就只需要对orderitem做数量增减和金额变动。

fegin功能接口:

fegin的调用

购物车接口

购物车实现

@Service
public class CartServiceImpl implements CartService {

    private static final String CART="cart_";

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private SkuFeign skuFeign;

    @Autowired
    private SpuFeign spuFeign;


    @Override
    public void addCart(String skuId, Integer num, String username) {
        //1.查询redis中相对应的商品信息
        OrderItem orderItem = (OrderItem) redisTemplate.boundHashOps(CART+username).get(skuId);
        if (orderItem != null){
            //2.如果当前商品在redis中的存在,则更新商品的数量与价钱
            orderItem.setNum(orderItem.getNum()+num);
            if (orderItem.getNum()<=0){
                //删除该商品
                redisTemplate.boundHashOps(CART+username).delete(skuId);
                return;
            }
            orderItem.setMoney(orderItem.getNum()*orderItem.getPrice());
            orderItem.setPayMoney(orderItem.getNum()*orderItem.getPrice());
        }else {
            //3.如果当前商品在redis中不存在,将商品添加到redis中
            Sku sku = skuFeign.findById(skuId).getData();
            Spu spu = spuFeign.findSpuById(sku.getSpuId()).getData();

            //封装orderItem
           orderItem = this.sku2OrderItem(sku,spu,num);
        }

        //3.将orderitem添加到redis中
        redisTemplate.boundHashOps(CART+username).put(skuId,orderItem);
    }

    //查询购物车列表数据
    @Override
    public Map list(String username) {
        Map map = new HashMap();

        List<OrderItem> orderItemList = redisTemplate.boundHashOps(CART + username).values();
        map.put("orderItemList",orderItemList);

        //商品的总数量与总价格
        Integer totalNum = 0;
        Integer totalMoney = 0;

        for (OrderItem orderItem : orderItemList) {
            totalNum+=orderItem.getNum();
            totalMoney+=orderItem.getMoney();
        }

        map.put("totalNum",totalNum);
        map.put("totalMoney",totalMoney);

        return map;
    }

    private OrderItem sku2OrderItem(Sku sku, Spu spu, Integer num) {
        OrderItem orderItem = new OrderItem();
        orderItem.setSpuId(sku.getSpuId());
        orderItem.setSkuId(sku.getId());
        orderItem.setName(sku.getName());
        orderItem.setPrice(sku.getPrice());
        orderItem.setNum(num);
        orderItem.setMoney(orderItem.getPrice()*num);
        orderItem.setPayMoney(orderItem.getPrice()*num);
        orderItem.setImage(sku.getImage());
        orderItem.setWeight(sku.getWeight()*num);
        //分类信息
        orderItem.setCategoryId1(spu.getCategory1Id());
        orderItem.setCategoryId2(spu.getCategory2Id());
        orderItem.setCategoryId3(spu.getCategory3Id());
        return orderItem;
    }
}

购物车渲染 web

用户想获得购物车列表- 请求前端网关
前端网关把用户请求转发到【订单购物车渲染服务】
【订单购物车渲染服务】调用【购物车订单微服务】获取购物车列表数据
【订单购物车渲染服务】得到了购物车列表数据,进行thymeleaf进行页面渲染
页面渲染后返回页面给用户

配置文件:

server:
  port: 9011
spring:
  application:
    name: order-web
  main:
    allow-bean-definition-overriding: true   #当遇到同样名字的时候,是否允许覆盖注册
  thymeleaf:
    cache: false
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:6868/eureka
  instance:
    prefer-ip-address: true
feign:
  hystrix:
    enabled: true
  client:
    config:
      default:   #配置全局的feign的调用超时时间  如果 有指定的服务配置 默认的配置不会生效
        connectTimeout: 60000 # 指定的是 消费者 连接服务提供者的连接超时时间 是否能连接  单位是毫秒
        readTimeout: 80000  # 指定的是调用服务提供者的 服务 的超时时间()  单位是毫秒
#hystrix 配置
hystrix:
  command:
    default:
      execution:
        timeout:
          #如果enabled设置为false,则请求超时交给ribbon控制
          enabled: true
        isolation:
          strategy: SEMAPHORE
          thread:
            # 熔断器超时时间,默认:1000/毫秒
            timeoutInMilliseconds: 80000
#请求处理的超时时间
ribbon:
  ReadTimeout: 4000
  #请求连接的超时时间
  ConnectTimeout: 3000

使用方法:

实现方法

以fegin形式暴露方法:

前端:

    <li class="yui3-u-1-8">
	<a href="javascript:void(0)" class="increment mins" @click="add(item.skuId,-1)">-</a>
	<input autocomplete="off" type="text" v-model="item.num" @blur="add(item.skuId,item.num)" minnum="1" class="itxt" />
	<a href="javascript:void(0)" class="increment plus" @click="add(item.skuId,1)">+</a>
    </li>

... 

	<script th:inline="javascript">
		var app = new Vue({
			el:"#app",
			data:{
				items:[[${items}]]
			},
			methods:{
				add:function (skuId,num) {
					axios.get("/api/wcart/add?id="+skuId+"&num="+num).then(function (response) {
						if (response.data.flag){
							app.items=response.data.data;
						}
					})
				}
			}
		})
	</script>

订单服务对接Oauth:
公钥:

配置类:

@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)//激活方法上的PreAuthorize注解
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

    //公钥
    private static final String PUBLIC_KEY = "public.key";

    /***
     * 定义JwtTokenStore
     * @param jwtAccessTokenConverter
     * @return
     */
    @Bean
    public TokenStore tokenStore(JwtAccessTokenConverter jwtAccessTokenConverter) {
        return new JwtTokenStore(jwtAccessTokenConverter);
    }

    /***
     * 定义JJwtAccessTokenConverter
     * @return
     */
    @Bean
    public JwtAccessTokenConverter jwtAccessTokenConverter() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        converter.setVerifierKey(getPubKey());
        return converter;
    }
    /**
     * 获取非对称加密公钥 Key
     * @return 公钥 Key
     */
    private String getPubKey() {
        Resource resource = new ClassPathResource(PUBLIC_KEY);
        try {
            InputStreamReader inputStreamReader = new InputStreamReader(resource.getInputStream());
            BufferedReader br = new BufferedReader(inputStreamReader);
            return br.lines().collect(Collectors.joining("\n"));
        } catch (IOException ioe) {
            return null;
        }
    }

    /***
     * Http安全配置,对每个到达系统的http请求链接进行校验
     * @param http
     * @throws Exception
     */
    @Override
    public void configure(HttpSecurity http) throws Exception {
        //所有请求必须认证通过
        http.authorizeRequests()
                //下边的路径放行
                .antMatchers(
                        "/user/add","/user/load/**"). //配置地址放行
                permitAll()
                .anyRequest().
                authenticated();    //其他地址需要认证授权
    }
}

posted @ 2020-04-22 04:49  卯毛  阅读(425)  评论(0编辑  收藏  举报