谷粒P193线程池&异步&分布式session&单点登录

p193 异步 异步复习

多线程几种方式
1.继承Thread
在这里插入图片描述
2.实现runable接口在这里插入图片描述3.实现callable接口在这里插入图片描述
在这里插入图片描述
4.线程池

public class ThreadTest {
    public static ExecutorService executorService = Executors.newFixedThreadPool(10);

    public static void main(String[] args) {
        executorService.execute(()->{
            System.out.println(Thread.currentThread().getId());
        });
        System.out.println("main结束");
    }
}

在这里插入图片描述

p194 线程池详解

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
原始构造方法
在这里插入图片描述
快速构建线程池

在这里插入图片描述

p195 completableFuture异步编排

在这里插入图片描述

p196 completableFuture启动异步任务

在这里插入图片描述

com
无返回值

public static ExecutorService executorService = Executors.newFixedThreadPool(10);

    public static void main(String[] args) {
        System.out.println("main start---");
        CompletableFuture<Void> voidCompletableFuture = CompletableFuture.runAsync(() -> {
            System.out.println("当前线程:" + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果:" + i);
        }, executorService);

        System.out.println("main end---");
    }

有返回值

 public static ExecutorService executorService = Executors.newFixedThreadPool(10);

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("main start---");
        //可以获取结果
        CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程:" + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果:" + i);
            return i;
        }, executorService);
        Integer result = completableFuture.get();
        System.out.println(result);
        System.out.println("main end---");
    }

p197completableFuture完成回调与异常感知

在这里插入图片描述
在这里插入图片描述

 public static ExecutorService executorService = Executors.newFixedThreadPool(10);

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("main start---");
        //可以获取结果
        CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程:" + Thread.currentThread().getId());
            int i = 10 / 0;
            System.out.println("运行结果:" + i);
            return i;
        }, executorService).whenComplete(new BiConsumer<Integer, Throwable>() {
            //可以获取到结果 或者异常信息
            @Override
            public void accept(Integer integer, Throwable throwable) {
                System.out.println("异步任务完成,结果为:"+integer+",异常为:"+throwable);
            }
        }).exceptionally( (throwable)->{//如果出现异常,可以自定义返回结果
            return 10;
        });
        Integer result = completableFuture.get();
        System.out.println(result);
        System.out.println("main end---");
    }

结果:
在这里插入图片描述

p198 handler最终处理

在这里插入图片描述

 public static ExecutorService executorService = Executors.newFixedThreadPool(10);


    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("main start---");
        //可以获取结果
        CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程:" + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果:" + i);
            return i;
        }, executorService).handle((res,throwable)->{
            if (res!=null){
                return res*2;
            }
            if (throwable!=null){
                return 0;
            }
            return 0;
        });
        System.out.println("结果:"+completableFuture.get());
        System.out.println("main end---");
    }

p199线程串行化方法

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

p200 两任务组合

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

p201 两任务组合 一个完成

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

p202多任务组合

在这里插入图片描述
等待多个任务全部结束
在这里插入图片描述
只需要任意一个任务执行结束
在这里插入图片描述

p203商品详情

在这里插入图片描述
在这里插入图片描述

p204模型抽取

在这里插入图片描述

p205商品规格参数

在这里插入图片描述
在这里插入图片描述

p206 销售属性组合

在这里插入图片描述

在这里插入图片描述

p207 详情页面渲染

在这里插入图片描述

p208 商品详情 销售属性渲染

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
属性设置边框 回显当前sku的属性
在这里插入图片描述

在这里插入图片描述

p209sku组合切换

点击属性时,会跳转到具有该属性的sku商品页面
在这里插入图片描述

在这里插入图片描述

p210 异步编排优化

yml配置

gulimall:
  thread:
    core-size: 20  # 20-50
    max-size: 200
    keep-alive-time: 10  # 10s

建立配置属性类(使用@Component会加入容器)

@ConfigurationProperties(prefix = "gulimall.thread")
//@Component
@Data
public class ThreadPoolConfigProperties {

	private Integer coreSize;

	private Integer maxSize;

	private Integer keepAliveTime;
}

有了@EnableConfigurationProperties,上面配置属性类的注解@Component取消掉

// 开启这个属性配置
@EnableConfigurationProperties(ThreadPoolConfigProperties.class)
@Configuration
public class MyThreadConfig {

	@Bean
	public ThreadPoolExecutor threadPoolExecutor(ThreadPoolConfigProperties threadPoolConfigProperties){

		return new ThreadPoolExecutor(threadPoolConfigProperties.getCoreSize(),
				threadPoolConfigProperties.getMaxSize(),
				threadPoolConfigProperties.getKeepAliveTime() ,TimeUnit.SECONDS,
				new LinkedBlockingDeque<>(10000), Executors.defaultThreadFactory(),
				new ThreadPoolExecutor.AbortPolicy());
	}
}

优化商品详情为异步编排

 @Override
    public SkuItemVo item(Long skuId) throws ExecutionException, InterruptedException {
        SkuItemVo skuItemVo = new SkuItemVo();
        //sku基本信息 开启一个异步任务
        CompletableFuture<SkuInfoEntity> infoFuture = CompletableFuture.supplyAsync(() -> {
            SkuInfoEntity skuInfoEntity = getById(skuId);
            skuItemVo.setInfo(skuInfoEntity);
            return skuInfoEntity;
        }, executor);
        //Long spuId = skuInfoEntity.getSpuId();
        //图片信息 开启另一个异步任务
        CompletableFuture<Void> imgFuture = CompletableFuture.runAsync(() -> {
            List<SkuImagesEntity> images = imagesService.getImagesBySkuId(skuId);
            skuItemVo.setImages(images);
        }, executor);

        //spu销售属性信息 res就是infoFuture任务的返回结果 infoFuture完成后就行下面的任务
        CompletableFuture<Void> future1 = infoFuture.thenAcceptAsync((res) -> {
            List<ItemSaleAttrVo> saleAttrVos = skuSaleAttrValueService.getSaleAttrsBuSpuId(res.getSpuId());
            skuItemVo.setSaleAttr(saleAttrVos);
        }, executor);
        //spu介绍
        CompletableFuture<Void> future2 = infoFuture.thenAcceptAsync((res)->{
            SpuInfoDescEntity spuInfo = spuInfoDescService.getById(res.getSpuId());
            skuItemVo.setDesc(spuInfo);
        },executor);
        //获取spu规格参数信息
        CompletableFuture<Void> future3 =infoFuture.thenAcceptAsync((res)->{
            List<SpuItemAttrGroup> attrGroups = attrGroupService.getAttrGroupWithAttrsBySpuId(res.getSpuId(),res.getCatalogId());
            skuItemVo.setGroupAttrs(attrGroups);
        },executor);

        //等待所有任务完成
        CompletableFuture.allOf(imgFuture,future1,future2,future3).get();
        return skuItemVo;
    }

p211 认证服务环境搭建

输入域名时,先通过ip到linux服务器,找到nginx,nginx再路由到网关,网关再路由到具体的服务
在这里插入图片描述

在这里插入图片描述
网关配置
在这里插入图片描述

p212 验证码倒计时

在这里插入图片描述
在这里插入图片描述

p213 短信验证码

在这里插入图片描述

@Data
@ConfigurationProperties(prefix = "spring.cloud.alicloud.sms")
@Component
public class SmsComponent {

	private String host;

	private String path;

	private String appCode;

	public void sendSmsCode(String phone, String code){
//		String host = "https://dfsns.market.alicloudapi.com";
//		String path = "/data/send_sms";
		String method = "POST";
//		String appcode = "764d82d28f354f028122ca6450114cb6";
		Map<String, String> headers = new HashMap<String, String>();
		//最后在header中的格式(中间是英文空格)为Authorization:APPCODE 83359fd73fe94948385f570e3c139105
		headers.put("Authorization", "APPCODE " + appCode);
		//根据API的要求,定义相对应的Content-Type
		headers.put("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
		Map<String, String> querys = new HashMap<String, String>();
		Map<String, String> bodys = new HashMap<String, String>();
		bodys.put("content", "code:"+code);
		bodys.put("phone_number", phone);
		bodys.put("template_id", "TPL_0000");


		try {
			/**
			 * 重要提示如下:
			 * HttpUtils请从
			 * https://github.com/aliyun/api-gateway-demo-sign-java/blob/master/src/main/java/com/aliyun/api/gateway/demo/util/HttpUtils.java
			 * 下载
			 *
			 * 相应的依赖请参照
			 * https://github.com/aliyun/api-gateway-demo-sign-java/blob/master/pom.xml
			 */
			HttpResponse response = HttpUtils.doPost(host, path, method, headers, querys, bodys);
			System.out.println(response.toString());
			//获取response的body
			//System.out.println(EntityUtils.toString(response.getEntity()));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

p214 验证码防刷校验

@ResponseBody
    @RequestMapping("/sms/sendcode")
    public R sendCode(@RequestParam("param")String phone){
        //1接口防刷
        String oldCode = redisTemplate.opsForValue().get(AuthServerConstant.SMS_CODE_CACHE_PREFIX + phone);
        //如果之前有验证码
        if (StringUtils.isNotEmpty(oldCode)){
            String lastTime = oldCode.split("_")[1];
            //60s内防刷
            if(System.currentTimeMillis()-Long.valueOf(lastTime)<60000){
                return R.error(BizCodeEnum.SMS_CODE_EXCEPTION.getCode(),BizCodeEnum.SMS_CODE_EXCEPTION.getMsg());
            }
        }
        //2存储验证码后面注册再次校验
        String code = UUID.randomUUID().toString().substring(0, 5)+"_"+System.currentTimeMillis();
        //缓存验证码
        redisTemplate.opsForValue().set(AuthServerConstant.SMS_CODE_CACHE_PREFIX+phone,code,10,TimeUnit.MINUTES);
        service.sendCode(phone,code);
        return R.ok();
    }

p215 注册页

@PostMapping("register")
    public String register(@Valid UserRegisterVo userRegisterVo,
                           BindingResult result,
//                           Model model
                            RedirectAttributes redirectAttributes){
        if (result.hasErrors()){
            //获取错误信息
            Map<String, String> errors = result.getFieldErrors().stream().collect(
                    Collectors.toMap(FieldError::getField, fieldError -> fieldError.getDefaultMessage())
            );
//            model.addAttribute("errors",errors);
            //视图转发会有浏览器刷新重复提交的问题(因为浏览器地址栏没有变化) 改用重定向
//            return "reg";
            //但是重定向会有问题,使用model无法在重定向使用,解决:用RedirectAttributes(原理session)
            //todo 用RedirectAttributes有分布式session问题
            redirectAttributes.addFlashAttribute("errors",errors);//Flash代表取了就删除了
            return "redirect:http://auth.gulimall.com/reg.html";//这里加上域名 不加的时候有个坑 会使用ip
        }
        return "redirect:/login.html";
    }

在这里插入图片描述

p216 注册逻辑和远程注册

在这里插入图片描述
远程会员服务注册
在这里插入图片描述

p217 认证服务 MD5&盐值&BCrypt

不可逆加密算法
在这里插入图片描述
直接使用md5容易被彩虹表破解,加盐能提高安全性
在这里插入图片描述
在这里插入图片描述

p218 注册完成

 @PostMapping("register")
    public String register(@Valid UserRegisterVo userRegisterVo,
                           BindingResult result,
//                           Model model
                            RedirectAttributes redirectAttributes){
        //jsr303校验
        if (result.hasErrors()){
            //获取错误信息
            Map<String, String> errors = result.getFieldErrors().stream().collect(
                    Collectors.toMap(FieldError::getField, fieldError -> fieldError.getDefaultMessage())
            );
//            model.addAttribute("errors",errors);
            //视图转发会有浏览器刷新重复提交的问题(因为浏览器地址栏没有变化) 改用重定向
//            return "reg";
            //但是重定向会有问题,使用model无法在重定向使用,解决:用RedirectAttributes(原理session)
            //todo 用RedirectAttributes有分布式session问题
            redirectAttributes.addFlashAttribute("errors",errors);//Flash代表取了就删除了
            return "redirect:http://auth.gulimall.com/reg.html";//这里加上域名 不加的时候有个坑 会使用ip
        }

        //远程调用注册
        // 1.校验验证码
        String code = userRegisterVo.getCode();

        String redis_code = redisTemplate.opsForValue().get(AuthServerConstant.SMS_CODE_CACHE_PREFIX + userRegisterVo.getPhone());
        //如果验证码不为空
        if(!org.springframework.util.StringUtils.isEmpty(redis_code)){
            // 验证码通过
            if(code.equals(redis_code.split("_")[0])){
                // 删除验证码
                redisTemplate.delete(AuthServerConstant.SMS_CODE_CACHE_PREFIX + userRegisterVo.getPhone());
                // 调用远程服务进行注册
                R r = memberFeignService.register(userRegisterVo);
                if(r.getCode() == 0){
                    // 注册成功,去登录
                    return "redirect:http://auth.gulimall.com/login.html";
                }else{
                    Map<String, String> errors = new HashMap<>();
                    errors.put("msg",r.getData("msg",new TypeReference<String>(){}));
                    // 数据只需要取一次
                    redirectAttributes.addFlashAttribute("errors",errors);
                    return "redirect:http://auth.gulimall.com/reg.html";
                }
            }else{//验证码不通过
                Map<String, String> errors = new HashMap<>();
                errors.put("code", "验证码错误");
                // addFlashAttribute 这个数据只取一次
                redirectAttributes.addFlashAttribute("errors", errors);
                return "redirect:http://auth.gulimall.com/reg.html";
            }
        }else{//如果验证码为空
            Map<String, String> errors = new HashMap<>();
            errors.put("code", "验证码错误");
            // addFlashAttribute 这个数据只取一次
            redirectAttributes.addFlashAttribute("errors", errors);
            return "redirect:http://auth.gulimall.com/reg.html";
        }

        //注册成功跳转到登录页
    }

p219 登录功能 账号密码登录

在这里插入图片描述
调用远程用户服务 登录
在这里插入图片描述

p220 认证服务 oauth2简介

在这里插入图片描述
在这里插入图片描述

p221微博登录

在这里插入图片描述
拿code换取token
在这里插入图片描述
拿到token可以去访问微博用户信息
在这里插入图片描述

在这里插入图片描述

p222 社交登陆回调


拿到code去换取token,跳转到首页
在这里插入图片描述

p223 社交登陆完成

在这里插入图片描述

@Override // 已经用code生成了token
    public MemberEntity login(SocialUser socialUser) {

        // 微博的uid
        String uid = socialUser.getUid();
        // 1.判断社交用户登录过系统
        MemberDao dao = this.baseMapper;
        MemberEntity entity = dao.selectOne(new QueryWrapper<MemberEntity>().eq("social_uid", uid));

        MemberEntity memberEntity = new MemberEntity();
        if(entity != null){ // 注册过
            // 说明这个用户注册过, 修改它的资料
            // 更新令牌
            memberEntity.setId(entity.getId());
            memberEntity.setAccessToken(socialUser.getAccessToken());
            memberEntity.setExpiresIn(socialUser.getExpiresIn());
            // 更新
            dao.updateById(memberEntity);

            entity.setAccessToken(socialUser.getAccessToken());
            entity.setExpiresIn(socialUser.getExpiresIn());
            entity.setPassword(null);
            return entity;
        }else{ // 没有注册过
            // 2. 没有查到当前社交用户对应的记录 我们就需要注册一个
            HashMap<String, String> map = new HashMap<>();
            map.put("access_token", socialUser.getAccessToken());
            map.put("uid", socialUser.getUid());
            try {
                // 3. 查询当前社交用户账号信息(昵称、性别、头像等)
                HttpResponse response = HttpUtils.doGet("https://api.weibo.com", "/2/users/show.json", "get", new HashMap<>(), map);
                if(response.getStatusLine().getStatusCode() == 200){
                    // 查询成功
                    String json = EntityUtils.toString(response.getEntity());
                    // 这个JSON对象什么样的数据都可以直接获取
                    JSONObject jsonObject = JSON.parseObject(json);
                    memberEntity.setNickname(jsonObject.getString("name"));
                    memberEntity.setUsername(jsonObject.getString("name"));
                    memberEntity.setGender("m".equals(jsonObject.getString("gender"))?1:0);
                    memberEntity.setCity(jsonObject.getString("location"));
                    memberEntity.setJob("自媒体");
                    memberEntity.setEmail(jsonObject.getString("email"));
                }
            } catch (Exception e) {
                log.warn("社交登录时远程调用出错 [尝试修复]");
            }
            memberEntity.setStatus(0);
            memberEntity.setCreateTime(new Date());
            memberEntity.setBirth(new Date());
            memberEntity.setLevelId(1L);
            memberEntity.setSocialUid(socialUser.getUid());
            memberEntity.setAccessToken(socialUser.getAccessToken());
            memberEntity.setExpiresIn(socialUser.getExpiresIn());

            // 注册 -- 登录成功
            dao.insert(memberEntity);
            memberEntity.setPassword(null);
            return memberEntity;
        }
    }

p224社交登陆测试

p225 分布式session

在这里插入图片描述
2个问题
在这里插入图片描述

p226分布式session解决方案原理

多个相同服务分布式下解决办法

在这里插入图片描述
在这里插入图片描述
采用redis存储方案
在这里插入图片描述

不同服务session同步办法

解决了多个相同服务的问题,还有不同服务之间域名不同导致的cookie的domain不一样,session不能共享问题,修改cookie作用域名
在这里插入图片描述

p227整合springsession

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

配置

#分布式session
spring.session.store-type=redis
server.servlet.session.timeout=30m

注解
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

p228完成session子域共享

// TODO 1.默认发的当前域的session (需要解决子域session共享问题)
// TODO 2.使用JSON序列化后保存到redis 自动完成

@Configuration
public class AuthSessionConfig {

	@Bean
	public CookieSerializer cookieSerializer(){
		DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer();
		// 明确的指定Cookie的作用域
		cookieSerializer.setDomainName("gulimall.com");
		cookieSerializer.setCookieName(AuthServerConstant.SESSION);
		return cookieSerializer;
	}

	/**
	 * 自定义序列化机制
	 * 这里方法名必须是:springSessionDefaultRedisSerializer
	 */
	@Bean
	public RedisSerializer<Object> springSessionDefaultRedisSerializer(){
		return new GenericJackson2JsonRedisSerializer();
	}
}

在这里插入图片描述

p229springsession原理

在这里插入图片描述

在这里插入图片描述

p230页面效果完成

搜索服务也引入springsession
各个服务修改前端页面
在这里插入图片描述

p231单点登录

在这里插入图片描述

p232 xxl-sso 单点登录

在一个服务器上登录.其他服务器都不用再登录
在这里插入图片描述
在这里插入图片描述

p233-234 单点登录流程

登录client1

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

p235登录流程

登录client2

上一步登录client1和ssoserver了,但是在登录client2还不能直接免登录,需要修改之前的流程
在这里插入图片描述
client1登陆时 即第一次访问sso时,添加相应的cookie
在这里插入图片描述
后面浏览器只要没关闭,访问ssoserver就会携带相关的cookie

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

p236 购物车服务 环境搭建

搭建购物车
在这里插入图片描述

p237购物车 数据模型分析

在这里插入图片描述

p238 编写vo

在这里插入图片描述

在这里插入图片描述

p239 购物车 ThreadLocal 用户身份识别

springsession配置
在这里插入图片描述
引入依赖

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

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

p240 页面环境修改

主要是修改html相关链接的跳转路径

p241

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值