第六章 架构核心技术-池化思想-异步结合 性能优化最佳实践
第1集 RestTemplate里面的存在的问题你知道多少- Broken pipe错误
项目就更新到第六章了,剩下的内容 放百度网盘里面了,需要的来取。
链接:https://pan.baidu.com/s/19LHPw36dsxPB75z_FHS64Q?pwd=8h89
提取码:8h89
简介: RestTemplate里面的存在的问题你知道多少
-
还原代码(暂时不用异步)
- 异步-里面是用线程池-是池化思想的一种应用
-
同步发送+resttemplate未池化
-
压测结果 几百吞吐量
-
错误Caused by: java.io.IOException: Broken pipe
- 服务端向前端socket连接管道写返回数据时 链接(pipe)却断开了
- 从应用角度分析,这是因为客户端等待返回超时了,主动断开了与服务端链接
- 连接数设置太小,并发量增加后,造成大量请求排队等待
- 网络延迟,是否有丢包
- 内存是否足够多支持对应的并发量
- 服务端向前端socket连接管道写返回数据时 链接(pipe)却断开了
-
-
问题分析
- resttemplate底层是怎样的?
- 基于之前的认知-池化思想,联想到是否使用了http连接池?
-
重新认识RestTemplate
- RestTemplate是Spring提供的用于访问Rest服务的客户端
- 底层通过使用java.net包下的实现创建HTTP 请求
- 通过使用ClientHttpRequestFactory指定不同的HTTP请求方式,主要提供了两种实现方式
- SimpleClientHttpRequestFactory(默认)
- 底层使用J2SE提供的方式,既java.net包提供的方式,创建底层的Http请求连接
- 主要createRequest 方法( 断点调试),每次都会创建一个新的连接,每次都创建连接会造成极大的资源浪费,而且若连接不能及时释放,会因为无法建立新的连接导致后面的请求阻塞
- HttpComponentsClientHttpRequestFactory
- 底层使用HttpClient访问远程的Http服务
- SimpleClientHttpRequestFactory(默认)
-
问题解决
- 客户端每次请求都要和服务端建立新的连接,即三次握手将会非常耗时
- 通过http连接池可以减少连接建立与释放的时间,提升http请求的性能
- Spring的restTemplate是对httpclient进行了封装, 而httpclient是支持池化机制
- 拓展
- 对httpclient进行封装的有:Apache的Fluent、es的restHighLevelClient、spring的restTemplate等
第2集 高性能RestTemplate连接池封装配置实战
简介: 高性能RestTemplate封装配置实战
- 配置RestTemplate连接池实战
@Beanpublic RestTemplate restTemplate(ClientHttpRequestFactory factory) {return new RestTemplate(factory);}@Beanpublic ClientHttpRequestFactory httpRequestFactory() {return new HttpComponentsClientHttpRequestFactory(httpClient());}/*** @return*/@Beanpublic HttpClient httpClient() {Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create().register("http", PlainConnectionSocketFactory.getSocketFactory()).register("https", SSLConnectionSocketFactory.getSocketFactory()).build();PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry);//设置整个连接池最大连接数connectionManager.setMaxTotal(500);//MaxPerRoute路由是对maxTotal的细分,每个主机的并发,这里route指的是域名connectionManager.setDefaultMaxPerRoute(200);RequestConfig requestConfig = RequestConfig.custom()//返回数据的超时时间.setSocketTimeout(20000)//连接上服务器的超时时间.setConnectTimeout(10000)//从连接池中获取连接的超时时间.setConnectionRequestTimeout(1000).build();return HttpClientBuilder.create().setDefaultRequestConfig(requestConfig).setConnectionManager(connectionManager).build();}
第3集 【10倍+QPS提升】Jmeter5.x压测 优化后RestTemplate前后性能对比
简介: 【10倍+提升】Jmeter5.x压测 优化后RestTemplate前后性能对比
-
同步发送+resttemplate未池化
- 压测结果 几百 吞吐量
-
同步发送+resttemplate池化
- 压测结果
-
检查你自己公司的项目,是否存在对应的问题
第七章 账号微服务-发送短信验证码-池化+异步结合最佳实践
第1集 调用第三方短信验证码组件性能优化实战
简介:调用第三方短信验证码组件性能优化实战
-
调整代码
-
采用异步调用方式
-
采用 resttemplate池化方式
第2集 说说一些薅羊毛的事情+防范解决方案
- 抢票
- 稀缺的酒、鞋等
-
短信邮箱轰炸机
- 什么是短信-邮箱轰炸机:
手机短信轰炸机是批量、循环给手机无限发送各种网站的注册验证码短信的方法。
- 美好的初衷-发明的由来
最早发明是用来整治街头广告电话号泛滥的一种手段,采用“手机短信轰炸机”软件可无限发送垃圾短信到牛皮癣小广告的手机号码上,使对方的手机快速消耗电量,变成高频率振动棒,且无法正常使用。“短信轰炸机”可严厉打击城市“牛皮癣”,还城市明净容颜。
- 灰色产业的目光-也就是部分不法分子利用
某次大型程序员相亲现场-老王得罪了小王, 小王不爽,就道听途说知道了”短信轰炸机“,1天50元,轰炸了5天还打折300元。一天内接到来自全国各地数千个陌生电话短信的轰炸骚扰,导致个人通讯中断,被工作生活受到严重影响,连刚相亲到的女友没没法联系上了。
-
原理
很多人都用手机注册一些网站的验证了,比如手机验证码。先填手机号,然后发一条验证码过去,输入验证码,完成验证,注册成功。* 寻找大量肉鸡网站,寻找发送验证码的请求接口* 如果找不到接口,也可以使用自动化UI工具触发* 编写程序和调度任务,相关脚本录入数据库* 输入目标手机号或者邮箱,触发攻击
-
公司带来的损失
- 短信一条5分钱,如果被大量盗刷大家自己计算
- 邮箱通知不用钱,但被大量盗刷,带宽、连接等都被占用,导致无法正常使用
-
如何避免自己的网站成为”肉鸡“或者被刷呢
- 增加图形验证码(开发人员)
- 单IP请求次数限制(开发人员)
- 限制号码发送(一般短信提供商会做)
-
是否可以一劳永逸???
-
没有百分百的安全,验证码是可以破解的,ip也是可以租用代理ip的
-
攻防永远是有的,只过加大了攻击者的成本,ROI划不过来自然就放弃了
-
第3集 图形验证码开发之谷歌kaptcha引入
简介:谷歌开源kaptcha图形验证码开发
-
Kaptcha 框架介绍 谷歌开源的一个可高度配置的实用验证码生成工具
- 验证码的字体/大小/颜色
- 验证码内容的范围(数字,字母,中文汉字!)
- 验证码图片的大小,边框,边框粗细,边框颜色
- 验证码的干扰线
- 验证码的样式(鱼眼样式、3D、普通模糊)
-
聚合工程依赖添加(使用国内baomidou二次封装的springboot整合starter)
<!--kaptcha依赖包--><dependency><groupId>com.baomidou</groupId><artifactId>kaptcha-spring-boot-starter</artifactId><version>1.1.0</version></dependency>
- 账号微服务添加
<dependency><groupId>com.baomidou</groupId><artifactId>kaptcha-spring-boot-starter</artifactId></dependency>
- 开发配置(任何框架和springboot整合基本都是)
@Configuration
public class CaptchaConfig {/*** 验证码配置* Kaptcha配置类名* * @return*/@Bean@Qualifier("captchaProducer")public DefaultKaptcha kaptcha() {DefaultKaptcha kaptcha = new DefaultKaptcha();Properties properties = new Properties();
// properties.setProperty(Constants.KAPTCHA_BORDER, "yes");
// properties.setProperty(Constants.KAPTCHA_BORDER_COLOR, "220,220,220");
// //properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_FONT_COLOR, "38,29,12");
// properties.setProperty(Constants.KAPTCHA_IMAGE_WIDTH, "147");
// properties.setProperty(Constants.KAPTCHA_IMAGE_HEIGHT, "34");
// properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_FONT_SIZE, "25");
// //properties.setProperty(Constants.KAPTCHA_SESSION_KEY, "code");//验证码个数properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "4");
// properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Courier");//字体间隔properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_CHAR_SPACE,"8");//干扰线颜色
// properties.setProperty(Constants.KAPTCHA_NOISE_COLOR, "white");//干扰实现类properties.setProperty(Constants.KAPTCHA_NOISE_IMPL, "com.google.code.kaptcha.impl.NoNoise");//图片样式properties.setProperty(Constants.KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.WaterRipple");//文字来源properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_CHAR_STRING, "0123456789");Config config = new Config(properties);kaptcha.setConfig(config);return kaptcha;}
}
- 开发一个Controller使用测试
第4集 池化思想应用-Redis6.X配置连接池实战
简介:池化思想应用-Redis6.X配置连接池实战
-
连接池好处
- 使用连接池不用每次都走三次握手、每次都关闭Jedis
- 相对于直连,使用相对麻烦,在资源管理上需要很多参数来保证,规划不合理也会出现问题
- 如果pool已经分配了maxActive个jedis实例,则此时pool的状态就成exhausted了
-
连接池配置 common项目
<!--redis客户端--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId><exclusions><exclusion><groupId>io.lettuce</groupId><artifactId>lettuce-core</artifactId></exclusion></exclusions></dependency><dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId></dependency>
-
配置Redis连接
redis:client-type: jedishost: 120.79.150.146password: class.netport: 6379jedis:pool:# 连接池最大连接数(使用负值表示没有限制)max-active: 100# 连接池中的最大空闲连接max-idle: 100# 连接池中的最小空闲连接min-idle: 100# 连接池最大阻塞等待时间(使用负值表示没有限制)max-wait: 60000
-
序列化配置
@Configuration public class RedisTemplateConfiguration {/*** @param redisConnectionFactory* @return*/@Beanpublic RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();redisTemplate.setConnectionFactory(redisConnectionFactory);// 使用Jackson2JsonRedisSerialize 替换默认序列化Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);ObjectMapper objectMapper = new ObjectMapper();objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);jackson2JsonRedisSerializer.setObjectMapper(objectMapper);// 设置key和value的序列化规则redisTemplate.setKeySerializer(new StringRedisSerializer());redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);// 设置hashKey和hashValue的序列化规则redisTemplate.setHashKeySerializer(new StringRedisSerializer());redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);return redisTemplate;} }
第5集 账号微服务开发图形验证码加入缓存+Try-with-resource
简介:账号微服务开发图形验证码接口+Try-with-resource
-
redis做隔离, 多集群:核心集群和非核心集群,高并发集群和非高并发集群
- 资源隔离
- 数据保护
- 提高性能
- key规范:业务划分,冒号隔离
- account-service:captcha:xxxx
- 长度不能过长
-
验证码接口开发
/***临时使用10分钟有效,方便测试*/private static final long CAPTCHA_CODE_EXPIRED = 60 * 1000 * 10;/*** 获取图形验证码* @param request* @param response*/@GetMapping("captcha")public void getCaptcha(HttpServletRequest request, HttpServletResponse response) {String captchaText = captchaProducer.createText();log.info("图形验证码:{}", captchaText);//存储redisTemplate.opsForValue().set(getCaptchaKey(request),captchaText, CAPTCHA_CODE_EXPIRED, TimeUnit.MILLISECONDS);BufferedImage bufferedImage = captchaProducer.createImage(captchaText);try (ServletOutputStream outputStream = response.getOutputStream()){ImageIO.write(bufferedImage, "jpg", outputStream);outputStream.flush();} catch (IOException e) {log.error("获取图形验证码异常:{}", e);}}
- 什么是try-with-resources
- 资源的关闭很多⼈停留在旧的流程上,jdk7新特性就有, 但是很多⼈以为是jdk8的
- 在try( …)⾥声 明的资源,会在try-catch代码块结束后⾃动关闭掉
- 注意点
- 实现了AutoCloseable接⼝的类,在try()⾥声明该类实例的时候,try结束后⾃动调⽤的 close⽅法,这个动作会早于finally⾥调⽤的⽅法
- 不管是否出现异常,try()⾥的实例都会被调⽤close⽅法
- try⾥⾯可以声明多个⾃动关闭的对象,越早声明的对象,会越晚被close掉
第6集 账号微服务之注册短信验证码接口开发
简介:注册短信验证码接口开发
- service层
@Overridepublic JsonData sendCode(SendCodeEnum sendCodeType, String to) {if(CheckUtil.isEmail(to)){//邮箱验证码}else if(CheckUtil.isPhone(to)){//短信验证码}return JsonData.buildResult(BizCodeEnum.CODE_TO_ERROR);}
- 邮箱工具类正则
public class CheckUtil {/*** 邮箱正则*/private static final Pattern MAIL_PATTERN = Pattern.compile("^([a-z0-9A-Z]+[-|\\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,}$");/*** 手机号正则*/private static final Pattern PHONE_PATTERN = Pattern.compile("^((13[0-9])|(14[0-9])|(15[0-9])|(17[0-9])|(18[0-9]))\\d{8}$");/*** @param email* @return*/public static boolean isEmail(String email) {if (null == email || "".equals(email)) {return false;}Matcher m = MAIL_PATTERN.matcher(email);return m.matches();}/*** * @param phone* @return*/public static boolean isPhone(String phone) {if (null == phone || "".equals(phone)) {return false;}Matcher m = PHONE_PATTERN.matcher(phone);boolean result = m.matches();return result;}
}
第7集 关于注册短信验证码防刷设计方案你能想到几个
简介:注册短信验证码防刷方案你能想到几个
-
需求:一定时间内禁止重复发送短信,大家想下有哪几种实现方式
- 两个时间要求
- 60秒后才可以重新发送短信验证码
- 发送的短信验证码10分钟内有效
- 两个时间要求
-
-
方式一:前端增加校验倒计时,不到60秒按钮不给点击
- 简单
- 不安全,存在绕过的情况
-
方式二:增加Redis存储,发送的时候设置下额外的key,并且60秒后过期
-
非原子操作,存在不一致性
-
增加的额外的key - value存储,浪费空间
-
/*** 前置:判断是否重复发送** 1、存储验证码到缓存** 2、发送短信验证码** 后置:存储发送记录**/
-
-
方式三:基于原先的key拼装时间戳
- 好处:满足了当前节点内的原子性,也满足业务需求
-
第8集 【重要】注册邮箱验证码防刷代码落地+整体测试
简介:注册邮箱验证码防刷落地和整体测试
@Overridepublic JsonData sendCode(SendCodeEnum sendCodeEnum, String to) {String cacheKey = String.format(RedisKey.CHECK_CODE_KEY,sendCodeEnum.name(),to);String cacheValue = redisTemplate.opsForValue().get(cacheKey);//如果不为空,再判断是否是60秒内重复发送 0122_232131321314132if(StringUtils.isNotBlank(cacheValue)){long ttl = Long.parseLong(cacheValue.split("_")[1]);//当前时间戳-验证码发送的时间戳,如果小于60秒,则不给重复发送long leftTime = CommonUtil.getCurrentTimestamp() - ttl;if( leftTime < (1000*60)){log.info("重复发送短信验证码,时间间隔:{}秒",leftTime);return JsonData.buildResult(BizCodeEnum.CODE_LIMITED);}}String code = CommonUtil.getRandomCode(6);//生成拼接好验证码String value = code+"_"+CommonUtil.getCurrentTimestamp();redisTemplate.opsForValue().set(cacheKey,value,CODE_EXPIRED,TimeUnit.MILLISECONDS);if(CheckUtil.isEmail(to)){//发送邮箱验证码 TODO}else if(CheckUtil.isPhone(to)){//发送手机验证码smsComponent.send(to,smsConfig.getTemplateId(),code);}return JsonData.buildSuccess();}
第八章 账号微服务-阿里云OSS接入实战
第1集 分布式文件存储业界常见解决方案介绍
简介:分布式文件存储常见解决方案介绍
-
目前业界比较多这个解决方案,这边就挑选几个介绍下
- MinIO
是在 Apache License v2.0 下发布的对象存储服务器,学习成本低,安装运维简单,主流语言的客户端整合都有, 号称最强的对象存储文件服务器,且可以和容器化技术docker/k8s等结合,社区活跃但不够成熟,业界参考资料较少官网:https://docs.min.io/cn/
- FastDFS
一个开源的轻量级分布式文件系统,比较少的客户端可以整合,目前主要是C和java客户端,在一些互联网创业公司中有应用比较多,没有官方文档,社区不怎么活跃. 架构+部署结构复杂,出问题定位比较难定位,可以说是fastdfs零件的组装过程,需要去理解fastDFS的架构设计,才能够正确的安装部署
-
云厂商
-
阿里云OSS
-
七牛云
-
腾讯云
-
亚马逊云
-
CDN最强:Akamai https://www.akamai.com/cn
-
-
选云厂商理由
- 优点:开发简单,功能强大,容易维护(不同网络下图片质量、水印、加密策略、扩容、加速)
- 缺点:要钱, 个性化处理,未来转移比较复杂,不排除有些厂商会提供一键迁移工具
-
选开源MinIO的理由
- 优点:功能强大、可以根据业务做二次的定制,新一代分布式文件存储系统,容器化结合强大,更重要的是免费(购买磁盘、内存、带宽)
- 缺点:自己需要有专门的团队进行维护、扩容等
-
文件上传流程
- web控制台
- 前端->后端程序->阿里云OSS
第2集 阿里云OSS分布式对象存储介绍开通
简介:阿里云OSS对象存储介绍和开通
- 阿里云OSS介绍
对象存储OSS(Object Storage Service)是阿里云提供的海量、安全、低成本、高持久的云存储服务。其数据设计持久性不低于99.9999999999%(12个9),服务设计可用性不低于99.995%。OSS具有与平台无关的RESTful API接口,您可以在任何应用、任何时间、任何地点存储和访问任意类型的数据。提供标准、低频访问、归档和冷归档四种存储类型,全面覆盖从热到冷的各种数据存储场景:
标准存储类型 | 高持久、高可用、高性能的对象存储服务,支持频繁的数据访问。是各种社交、分享类的图片、音视频应用、大型网站、大数据分析的合适选择。 |
---|---|
低频访问存储类型 | 适合长期保存不经常访问的数据(平均每月访问频率1到2次)。存储单价低于标准类型,适合各类移动应用、智能设备、企业数据的长期备份,支持实时数据访问。 |
归档存储类型 | 适合需要长期保存(建议半年以上)的归档数据,在存储周期内极少被访问,数据进入到可读取状态需要1分钟的解冻时间。适合需要长期保存的档案数据、医疗影像、科学资料、影视素材。 |
冷归档存储类型 | 适合需要超长时间存放的极冷数据。例如因合规要求需要长期留存的数据、大数据及人工智能领域长期积累的原始数据、影视行业长期留存的媒体资源、在线教育行业的归档视频等。 |
-
开通阿里云OSS
-
有阿里云账号、实名认证
-
OSS介绍:https://www.aliyun.com/product/oss
-
OSS控制台:https://oss.console.aliyun.com/bucket
-
学习路径:https://help.aliyun.com/learn/learningpath/oss.html
-
-
开通后的操作
- 创建Bucket
- 上传文件
- 访问文件
第3集 权限知识 RBAC-ACL模式应用之阿里云RAM访问控制
简介:权限知识 RBAC-ACL模式应用之阿里云RAM访问控制
-
ACL: Access Control List 访问控制列表
- 以前盛行的一种权限设计,它的核心在于用户直接和权限挂钩
- 优点:简单易用,开发便捷
- 缺点:用户和权限直接挂钩,导致在授予时的复杂性,比较分散,不便于管理
- 例子:常见的文件系统权限设计, 直接给用户加权限
-
RBAC: Role Based Access Control
- 基于角色的访问控制系统。权限与角色相关联,用户通过成为适当角色的成员而得到这些角色的权限
- 优点:简化了用户与权限的管理,通过对用户进行分类,使得角色与权限关联起来
- 缺点:开发对比ACL相对复杂
- 例子:基于RBAC模型的权限验证框架与应用 Apache Shiro、spring Security
-
总结:不能过于复杂,规则过多,维护性和性能会下降, 更多分类 ABAC、PBAC等
-
RAM权限介绍
-
阿里云用于各个产品的权限,基于RBAC、ACL模型都有,进行简单管理账号、统一分配权限、集中管控资源,从而建立安全、完善的资源控制体系。
-
众多产品,一般采用子账号进行分配权限,防止越权攻击
-
建立用户,勾选编程访问(保存accessKey和accessSecret,只出现一次)
- 用户登录名称 dcloud_link@1701673122790560.onaliyun.com AccessKey ID : LTAI5tHVGvYw7twoVFyruB1H AccessKey Secret : r4d0EudzSvPfVMb9Zp0TfmsE32RXmN
-
为新建用户授权OSS全部权限
-
第4集 阿里云OSS客户端SDK集成和上传组件功能开发
简介:阿里云OSS对象存储客户端集成和测试服务
-
添加阿里云OSS的SDK
-
地址:https://help.aliyun.com/document_detail/32008.html
-
添加maven依赖
- 底层聚合工程添加版本
<!-- OSS各个项目单独加依赖,根据需要进行添加--><dependency><groupId>com.aliyun.oss</groupId><artifactId>aliyun-sdk-oss</artifactId><version>3.10.2</version></dependency>
- 账号微服务添加
<!-- OSS各个项目单独加依赖,根据需要进行添加--><dependency><groupId>com.aliyun.oss</groupId><artifactId>aliyun-sdk-oss</artifactId></dependency>
-
-
账号微服务配置OSS
#阿里云OSS配置
aliyun:oss:endpoint: oss-cn-guangzhou.aliyuncs.comaccess-key-id: LTAI5tHVGvYw7twoVFyruB1Haccess-key-secret: r4d0EudzSvPfVMb9Zp0TfmsE32RXmNbucketname: dcloud-link
- 新建配置类 (配置里面的横杠会,自动转驼峰)
@ConfigurationProperties(prefix = "aliyun.oss")
@Configuration
@Data
public class OSSConfig {private String endpoint;private String accessKeyId;private String accessKeySecret;private String bucketname;
}
-
开发controller
-
开发service
@Service
@Slf4j
public class FileServiceImpl implements FileService {@Autowiredprivate OSSConfig ossConfig;@Overridepublic String uploadUserImg(MultipartFile file) {//获取相关配置String bucketname = ossConfig.getBucketname();String endpoint = ossConfig.getEndpoint();String accessKeyId = ossConfig.getAccessKeyId();String accessKeySecret = ossConfig.getAccessKeySecret();//创建OSS对象OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);//获取原生文件名 xxx.jpgString originalFileName = file.getOriginalFilename();//JDK8的日期格式LocalDateTime ldt = LocalDateTime.now();DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy/MM/dd");//拼装路径,oss上存储的路径 user/2022/12/1/sdfdsafsdfdsf.jpgString folder = dtf.format(ldt);String fileName = CommonUtil.generateUUID();String extension = originalFileName.substring(originalFileName.lastIndexOf("."));// 在OSS上的bucket下创建 user 这个文件夹String newFileName = "user/"+folder+"/"+fileName+ extension;try {PutObjectResult putObjectResult = ossClient.putObject(bucketname,newFileName,file.getInputStream());//拼装返回路径if(putObjectResult != null){String imgUrl = "https://"+bucketname+"."+endpoint+"/"+newFileName;return imgUrl;}} catch (IOException e) {log.error("文件上传失败:{}",e);} finally {//oss关闭服务,不然会造成OOMossClient.shutdown();}return null;}
}
第5集 账号微服务头像上传阿里云OSS接口和PostMan测试
简介: 账号微服务头像上传阿里云OSS接口和PostMan测试
- 文件上传流程
- 先上传文件,返回url地址,再和普通表单一并提交(推荐这种,更加灵活,失败率低)
- 文件和普通表单一并提交(设计流程比较多,容易超时和失败)
- 注意:默认SpringBoot最大文件上传是1M,大家测试的时候记得关注下
- 开发controller
- @requestPart注解 接收文件以及其他更为复杂的数据类型
/*** 上传用户头像** 默认文件大小 1M,超过会报错** @param file* @return*/@PostMapping(value = "upload")public JsonData uploadHeaderImg(@RequestPart("file") MultipartFile file){String result = fileService.uploadUserHeadImg(file);return result != null?JsonData.buildSuccess(result):JsonData.buildResult(BizCodeEnum.FILE_UPLOAD_USER_IMG_FAIL);}
} catch (IOException e) {log.error("文件上传失败:{}",e);} finally {//oss关闭服务,不然会造成OOMossClient.shutdown();}return null;
}
}
#### 第5集 账号微服务头像上传阿里云OSS接口和PostMan测试**简介: 账号微服务头像上传阿里云OSS接口和PostMan测试**- 文件上传流程- 先上传文件,返回url地址,再和普通表单一并提交(推荐这种,更加灵活,失败率低)- 文件和普通表单一并提交(设计流程比较多,容易超时和失败)
- 注意:默认SpringBoot最大文件上传是1M,大家测试的时候记得关注下
- 开发controller- @requestPart注解 接收文件以及其他更为复杂的数据类型```java/*** 上传用户头像** 默认文件大小 1M,超过会报错** @param file* @return*/@PostMapping(value = "upload")public JsonData uploadHeaderImg(@RequestPart("file") MultipartFile file){String result = fileService.uploadUserHeadImg(file);return result != null?JsonData.buildSuccess(result):JsonData.buildResult(BizCodeEnum.FILE_UPLOAD_USER_IMG_FAIL);}