(JAVA)自建应用调用企业微信API接口,实现消息推送

建议先简单了解企业微信开发者中心文档:开发前必读 - 文档 - 企业微信开发者中心

了解一下企业微信调用接口的基础参数:基本概念介绍 - 文档 - 企业微信开发者中心

本篇每个步骤都会跟着官网文档走,都会贴上相关链接,看完本篇文章,可以获得技能:

1、学会查看各应用的开发文档

2、学会调用接口,对接口的处理

3、学会redis和redisson的使用

4、学会封装数据传输对象(DTO)来调用接口和获取返回值

5、学会使用Spring WebFlux的非阻塞HTTP客户端的使用

实现所需以下步骤:

1、获取企业的IDSecretID

2、根据ID和SecretID从而获取access_token

3、对access_token进行缓存

4、调用接口发送信息

1、获取企业的ID和SecretID

操作:先注册好你的企业 -> 点击头像 -> 管理企业

进入管理企业页面后

操作:应用管理 - > 创建应用

进入创建应用后

填写你的企业信息,点击创建应用

创建应用完成后

操作:返回应用管理 - > 点击你新创建的应用

1.1、获取到企业的SecretID

操作:点击查看就能获取SecretID(会发送到你的企业微信)

1.2、获取到企业的ID

操作 :我的企业 - > 企业信息 - > 拉到最底下能看到企业ID

2、根据ID和SecretID从而获取access_token

文档对应位置:获取access_token - 文档 - 企业微信开发者中心

注意点:

请求方式: GET(HTTPS
请求地址: https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=ID&corpsecret=SECRET

参数必须说明
corpid企业ID,获取方式参考:术语说明-corpid
corpsecret应用的凭证密钥,注意应用需要是启用状态,获取方式参考:术语说明-secret

2.1、获取access_token

1、使用postman获取

返回结果:

{ "errcode": 0, "errmsg": "ok", "access_token": "accesstoken000001", "expires_in": 7200 }

翻译:

errcode出错返回码,为0表示成功,非0表示调用失败
errmsg返回码提示语
access_token获取到的凭证,最长为512字节
expires_in凭证的有效时间(秒)

注意事项:(在文中第3点会贴出代码,来实现如何通过redis来对access_token进行缓存
开发者需要缓存access_token,用于后续接口的调用(注意:不能频繁调用gettoken接口,否则会受到频率拦截)。当access_token失效或过期时,需要重新获取。

access_token的有效期通过返回的expires_in来传达,正常情况下为7200秒(2小时)。
由于企业微信每个应用的access_token是彼此独立的,所以进行缓存时需要区分应用来进行存储。
access_token至少保留512字节的存储空间。
企业微信可能会出于运营需要,提前使access_token失效,开发者应实现access_token失效时重新获取的逻辑。

2、springboot单元测试获取

wxService代码在后面讲到redis缓存access_token时会贴上

2.2、获取失败解决 - 新版本需要加入企业可信IP

意思是不允许你当前的ip进行访问(你的ip不可信)

新版本企业微信需要配置企业可信IP才能使用

配置IP地址:

如果出现以下情况:配置企业可信IP前,请先 设置可信域名 或 设置接收消息服务器URL

详情解决办法请看我另外一篇文章:

(JAVA)自建应用调用企业微信API接口,设置企业可信IP-CSDN博客

3、对access_token进行缓存

使用redis+redisson分布式锁,对access_token进行相关缓存操作。

代码实现:(思路逻辑都已经备注在代码里)

public String getAccessTokenByRedis() {//从redis中获取wx_access_tokenObject cacheObject = redisCache.getCacheObject("wx_access_token");//如果存在,直接返回access_tokenif(cacheObject != null){return cacheObject.toString();}//如果不存在,获取分布式锁RLock lock = redissonClient.getLock("wx_access_token_lock");//默认未上锁boolean locked = false;try {//尝试获取锁,最多等待3秒,上锁后10秒自动释放locked = lock.tryLock(3,10, TimeUnit.SECONDS);//如果获取到锁,再次从redis中获取access_token,防止在上锁期间,其他线程已经获取到锁并更新了access_token。if (locked) {cacheObject = redisCache.getCacheObject("wx_access_token");if(cacheObject != null){return cacheObject.toString();}String accessToken = getAccessTokenByApi();//企业微信接口的返回值access_token有效期为7200秒,这里存入redis设置为7000秒,防止临界值过期问题。redisCache.setCacheObject("wx_access_token", accessToken,7000, TimeUnit.SECONDS);return accessToken;}else{//未取到锁throw new RuntimeException("获取 access_token 超时,请稍后再试");}}catch (Exception e){throw new RuntimeException("Redisson 锁被中断", e);}finally {if(locked && lock.isHeldByCurrentThread()){lock.unlock();}}}

代码中的:redisCache是ruoyi框架封装好的redis工具类,调用的是redis的redisTemplate,可自行封装。

getCacheObject:

setCacheObject:

4、调用接口发送信息

了解调用消息推送的传输过程:概述 - 文档 - 企业微信开发者中心

4.1、查看发送应用消息接口文档

发送应用消息 - 文档 - 企业微信开发者中心

4.2、接口地址与请求方式

请求方式:POST(HTTPS
请求地址: https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=ACCESS_TOKEN

参数是否必须说明
access_token调用接口凭证

4.3、返回示例

{
  "errcode" : 0,
  "errmsg" : "ok",
  "invaliduser" : "userid1|userid2",
  "invalidparty" : "partyid1|partyid2",
  "invalidtag": "tagid1|tagid2",
  "unlicenseduser" : "userid3|userid4",
  "msgid": "xxxx",
  "response_code": "xyzxyz"
}

返回结果说明:

参数说明
errcode返回码
errmsg对返回码的文本描述内容
invaliduser不合法的userid,不区分大小写,统一转为小写
invalidparty不合法的partyid
invalidtag不合法的标签id
unlicenseduser没有基础接口许可(包含已过期)的userid
msgid消息id,用于撤回应用消息
response_code仅消息类型为“按钮交互型”,“投票选择型”和“多项选择型”的模板卡片消息返回,应用可使用response_code调用更新模版卡片消息接口,72小时内有效,且只能使用一次/4、

4.4、请求示例

4.4.1请求消息类型(文本

{
   "touser" : "UserID1|UserID2|UserID3",
   "toparty" : "PartyID1|PartyID2",
   "totag" : "TagID1 | TagID2",
   "msgtype" : "text",
   "agentid" : 1,
   "text" : {
       "content" : "你的快递已到,请携带工卡前往邮件中心领取。\n出发前可查看<a href=\"https://work.weixin.qq.com\">邮件中心视频实况</a>,聪明避开排队。"
   },
   "safe":0,
   "enable_id_trans": 0,
   "enable_duplicate_check": 0,
   "duplicate_check_interval": 1800
}

参数说明:

参数是否必须说明
touser指定接收消息的成员,成员ID列表(多个接收者用‘|’分隔,最多支持1000个)。
特殊情况:指定为"@all",则向该企业应用的全部成员发送
toparty指定接收消息的部门,部门ID列表,多个接收者用‘|’分隔,最多支持100个。
当touser为"@all"时忽略本参数
totag指定接收消息的标签,标签ID列表,多个接收者用‘|’分隔,最多支持100个。
当touser为"@all"时忽略本参数
msgtype消息类型,此时固定为:text
agentid企业应用的id,整型。企业内部开发,可在应用的设置页面查看;第三方服务商,可通过接口 获取企业授权信息 获取该参数值
content消息内容,最长不超过2048个字节,超过将截断(支持id转译)
safe表示是否是保密消息,0表示可对外分享,1表示不能分享且内容显示水印,默认为0
enable_id_trans表示是否开启id转译,0表示否,1表示是,默认0。
enable_duplicate_check表示是否开启重复消息检查,0表示否,1表示是,默认0
duplicate_check_interval表示是否重复消息检查的时间间隔,默认1800s,最大不超过4小时

注意:touser、toparty、totag不能同时为空,后面不再强调。

注意:成员ID是企业微信的唯一标识,查看方式如下:

注意:可以进行编辑修改,只有一次机会

修改建议:企业微信成员的企业邮箱作为账号成员ID

样式如下:

4.4.2请求消息类型(文本卡片

{
   "touser" : "UserID1|UserID2|UserID3",
   "toparty" : "PartyID1 | PartyID2",
   "totag" : "TagID1 | TagID2",
   "msgtype" : "textcard",
   "agentid" : 1,
   "textcard" : {
            "title" : "领奖通知",
            "description" : "<div class=\"gray\">2016年9月26日</div> <div class=\"normal\">恭喜你抽中iPhone 7一台,领奖码:xxxx</div><div class=\"highlight\">请于2016年10月10日前联系行政同事领取</div>",
            "url" : "URL",
                        "btntxt":"更多"
   },
   "enable_id_trans": 0,
   "enable_duplicate_check": 0,
   "duplicate_check_interval": 1800
}

参数是否必须说明
touser成员ID列表(消息接收者,多个接收者用‘|’分隔,最多支持1000个)。特殊情况:指定为@all,则向关注该企业应用的全部成员发送
toparty部门ID列表,多个接收者用‘|’分隔,最多支持100个。当touser为@all时忽略本参数
totag标签ID列表,多个接收者用‘|’分隔,最多支持100个。当touser为@all时忽略本参数
msgtype消息类型,此时固定为:textcard
agentid企业应用的id,整型。企业内部开发,可在应用的设置页面查看;第三方服务商,可通过接口 获取企业授权信息 获取该参数值
title标题,不超过128个字符,超过会自动截断(支持id转译)
description描述,不超过512个字符,超过会自动截断(支持id转译)
url点击后跳转的链接。最长2048字节,请确保包含了协议头(http/https)
btntxt按钮文字。 默认为“详情”, 不超过4个文字,超过自动截断。
enable_id_trans表示是否开启id转译,0表示否,1表示是,默认0
enable_duplicate_check表示是否开启重复消息检查,0表示否,1表示是,默认0
duplicate_check_interval表示是否重复消息检查的时间间隔,默认1800s,最大不超过4小时

样式如下:

4.5接口工具测试(postman)

4.5.1、带上请求参数param

4.5.2、带上请求体

4.5.3、结果

5、使用springboot整合Spring-WebFlux开发发送消息接口

5.1、maven导入Spring-WebFlux

        <!-- webflux--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId></dependency>

5.2、配置WebClient(我们只需要用到webflux的http客户端)

@Configuration
public class WebClientConfig {@Beanpublic WebClient webClient() {return WebClient.builder().defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE).build();}
}

5.3、新增数据传输对象(DTO)

根据第4节的请求示例新建DTO

5.3.1 WeChatMessageDTO
@Data
public class WeChatMessageDTO {/*** 指定接收消息的成员,成员ID列表(多个接收者用‘|’分隔,最多支持1000个)。* 特殊情况:指定为"@all",则向该企业应用的全部成员发送*/private String touser;/*** 指定接收消息的部门,部门ID列表,多个接收者用‘|’分隔,最多支持100个。* 当touser为"@all"时忽略本参数*/private String toparty;/*** 指定接收消息的标签,标签ID列表,多个接收者用‘|’分隔,最多支持100个。* 当touser为"@all"时忽略本参数*/private String totag;/*** 消息类型,text为返回的文本*/private String msgtype;/*** 企业应用的id,整型。企业内部开发,可在应用的设置页面查看;第三方服务商,可通过接口 获取企业授权信息 获取该参数值*/private Integer agentid;/*** 	消息内容,最长不超过2048个字节,超过将截断(支持id转译)*/private WeChatTextDTO text;/*** 	卡片消息的展现形式非常灵活,支持使用br标签或者空格来进行换行处理,也支持使用div标签来使用不同的字体颜色,目前内置了3种文字颜色:灰色(gray)、高亮(highlight)、默认黑色(normal),将其作为div标签的class属性即可,具体用法请参考上面的示例。*/private WeChatTextDTO textcard;/*** 表示是否是保密消息,0表示可对外分享,1表示不能分享且内容显示水印,默认为0*/private Integer safe;/*** 表示是否开启id转译,0表示否,1表示是,默认0。*/private Integer enable_id_trans;/*** 表示是否开启重复消息检查,0表示否,1表示是,默认0*/private Integer enable_duplicate_check;/*** 表示是否重复消息检查的时间间隔,默认1800s,最大不超过4小时*/private Integer duplicate_check_interval;//touser、toparty、totag不能同时为空,后面不再强调。
}
5.3.2 WeChatTextDTO
@Data
public class WeChatTextDTO {//text专用private String content;//消息内容,最长不超过2048个字节,超过将截断(支持id转译)//textcard专用private String title;//标题,不超过128个字符,超过会自动截断(支持id转译)private String description;//描述,不超过512个字符,超过会自动截断(支持id转译)private String url;//点击后跳转的链接。最长2048字节,请确保包含了协议头(http/https)private String btntxt;//按钮文字。 默认为“详情”, 不超过4个文字,超过自动截断。//图文、语音、视频等...}

5.4 WxService

@Service
public class WxService {@Autowiredprivate WebClient webClient;@Autowiredprivate RedisCache redisCache;@Autowiredprivate RedissonClient redissonClient;private static final Logger logger = LoggerFactory.getLogger(WxService.class);//企业微信所需凭证private static final String corpid = "在第一节的1.2获取到的企业ID";private static final String corpsecret = "在一节的1.1获取到的企业SecretID";private String getAccessTokenByApi(){String url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=" + corpid + "&corpsecret=" + corpsecret;Map<String, Object> response = webClient.get().uri(url).retrieve().bodyToMono(new ParameterizedTypeReference<Map<String, Object>>() {}).block();if (response == null || !response.containsKey("access_token")) {throw new RuntimeException("获取 access_token 失败:" + response);}return response.get("access_token").toString();}public String getAccessTokenByRedis() {//从redis中获取wx_access_tokenObject cacheObject = redisCache.getCacheObject("wx_access_token");//如果存在,直接返回access_tokenif(cacheObject != null){return cacheObject.toString();}//如果不存在,获取分布式锁RLock lock = redissonClient.getLock("wx_access_token_lock");//默认未上锁boolean locked = false;try {//尝试获取锁,最多等待3秒,上锁后10秒自动释放locked = lock.tryLock(3,10, TimeUnit.SECONDS);//如果获取到锁,再次从redis中获取access_token,防止在上锁期间,其他线程已经获取到锁并更新了access_token。if (locked) {cacheObject = redisCache.getCacheObject("wx_access_token");if(cacheObject != null){return cacheObject.toString();}String accessToken = getAccessTokenByApi();//企业微信接口的返回值access_token有效期为7200秒,这里设置为7000秒,防止临界值过期问题。//将access_token存入redis,有效期7000秒。redisCache.setCacheObject("wx_access_token", accessToken,7000, TimeUnit.SECONDS);return accessToken;}else{//未取到锁throw new RuntimeException("获取 access_token 超时,请稍后再试");}}catch (Exception e){throw new RuntimeException("Redisson 锁被中断", e);}finally {if(locked && lock.isHeldByCurrentThread()){lock.unlock();}}}public Map<String,Object> pushMessage(WeChatMessageDTO weChatMessageDTO){String accessToken = getAccessTokenByRedis();String url = "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token="+accessToken;return webClient.post().uri(url).contentType(MediaType.APPLICATION_JSON).bodyValue(weChatMessageDTO).retrieve().bodyToMono(new ParameterizedTypeReference<Map<String, Object>>() {}).block(); // 阻塞获取响应(适用于同步调用场景)}/*** 推送企业微信通知*/public void sendWeChatNotification(String title, String content, String receiverWxId) {try {WeChatTextDTO textDTO = new WeChatTextDTO();textDTO.setTitle(title);textDTO.setDescription(content);textDTO.setUrl("填写你要跳转的URL");textDTO.setBtntxt("点击查看");WeChatMessageDTO messageDTO = new WeChatMessageDTO();messageDTO.setTouser(receiverWxId);messageDTO.setMsgtype("textcard");messageDTO.setAgentid(1000002);messageDTO.setTextcard(textDTO);Map<String, Object> result = pushMessage(messageDTO);logger.info("企业微信推送结果: {}", result);} catch (Exception e) {logger.error("企业微信推送失败", e);}}}

5.5 WxTest

使用springboot的单元测试来测试。

@SpringBootTest
@DisplayName("单元测试案例")
public class WxTest {@Autowiredprivate WxService wxService;@DisplayName("获取accessToken")@Testpublic void test1(){//获取accessTokenString accessToken = wxService.getAccessTokenByRedis();System.out.println("accessToken:"+accessToken);}@DisplayName("推送信息-文本")@Testpublic void test2(){WeChatTextDTO weChatTextDTO = new WeChatTextDTO();weChatTextDTO.setContent("私聊测试");WeChatMessageDTO weChatMessageDTO = new WeChatMessageDTO();weChatMessageDTO.setTouser("ChenPengWei");//填入企业ID则是私聊weChatMessageDTO.setMsgtype("text");weChatMessageDTO.setAgentid(1000002);weChatMessageDTO.setText(weChatTextDTO);Map<String,Object> map = wxService.pushMessage(weChatMessageDTO);System.out.println(map);}@DisplayName("推送信息-文本卡片")@Testpublic void test3(){WeChatTextDTO weChatTextDTO = new WeChatTextDTO();weChatTextDTO.setTitle("CRM系统通知");weChatTextDTO.setDescription("<div class=\"gray\">2025年07月01日</div> <div class=\"normal\">天气不错</div><div class=\"highlight\">在一个阳光明媚的下午....</div>");weChatTextDTO.setUrl("https://www.baidu.com");weChatTextDTO.setBtntxt("点击查看");WeChatMessageDTO weChatMessageDTO = new WeChatMessageDTO();weChatMessageDTO.setTouser("@all");//@all是公告,群广播weChatMessageDTO.setMsgtype("textcard");weChatMessageDTO.setAgentid(1000002);weChatMessageDTO.setTextcard(weChatTextDTO);//textcardMap<String,Object> map = wxService.pushMessage(weChatMessageDTO);System.out.println(map);}}

效果图:

小弹窗:

窗口:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/87593.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/87593.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

P/Invoke 在默认封送(marshalling)规则下,常见托管 ⇄ 非托管类型的对应关系

下表整理了 P/Invoke 在默认封送&#xff08;marshalling&#xff09;规则下&#xff0c;常见托管 ⇄ 非托管类型的对应关系。 内容主要依据微软官方 Marshalling Data with Platform Invoke 文档&#xff0c;并补充了常见指针&#xff0f;句柄用法与字符串缓冲区&#xff…

2.isaacsim4.2 教程-初识OmniGraph

1. OmniGraph&#xff08;视觉编程&#xff09; OmniGraph 是 Omniverse 的可视化编程框架。它提供了一个图状结构&#xff0c;将 Omniverse 内多个系统的功能节点串联起来&#xff1b;同时也是一个计算框架&#xff0c;允许你编写高度自定义的节点&#xff0c;将自己的功能无…

MonoGame 游戏开发框架日记 -03

第三章&#xff1a;创建类库 内容介绍 主要内容&#xff1a;创建Core类并编写 创建这个类主要是为了后续开发方便&#xff0c;并介绍游戏开发中的一种非常重要编程模式 单例模式&#xff0c;以及了解MonoGame基本图形渲染知识单例模式&#xff1a; 第一步我们得先了解什么是单例…

AES 256 CBC加密和解密

AES-256-CBC 是一种对称加密算法&#xff0c;使用 256位密钥 和 CBC&#xff08;Cipher Block Chaining&#xff09;模式。它的典型使用场景包括对敏感信息进行加密存储或传输。下面是 AES-256-CBC 的加密与解密的 Python 示例&#xff0c;使用 pycryptodome 库&#xff1a; &a…

Git 版本控制完全指南:从入门到精通

Git 版本控制完全指南&#xff1a;从入门到精通 作为当今最流行的分布式版本控制系统&#xff0c;Git 已经成为开发者必备的技能之一。无论你是独立开发者还是团队协作&#xff0c;Git 都能帮助你高效管理代码版本。本文将带你从零开始&#xff0c;逐步掌握 Git 的核心概念和常…

408第三季part2 - 计算机网络 - 计算机网络分层结构

理解 PCI会放一些控制信息&#xff0c;源地址目的地址都在里面 SDU是放的数据 整个加起来是PDU 每一层的SDU都是上一层的PDU 看一看 也是简单看一看就行 网络层有时候也叫IP数据报 这里断点下载的意思就是&#xff0c;你下载东西的时候网络断了&#xff0c;再连回来的时候会接…

打开摄像头,服务器和客户端传输摄像头图像数据

1&#xff1a;Camera Server 主要功能&#xff0c;打开摄像头&#xff0c;接收客户端请求 接收到客户端请求“R”字符后开始传输摄像头图像。 #include "mainwindow.h" #include "ui_mainwindow.h"#include<QDebug>MainWindow::MainWindow(QWidget…

Android实现获取前台应用信息

Android实现获取前台应用信息 1.前言&#xff1a; 之前需要获取在后台运行的App信息&#xff0c;比如包名、版本这些常规的&#xff0c;今天是讲解获取在前台的App信息&#xff0c;虽然App在前台&#xff0c;但是具体的信息可能不知道&#xff0c;今天就尝试获取一下&#xf…

快讯|美团即时零售日订单已突破1.2亿,餐饮订单占比过亿

据美团内网公布信息显示&#xff0c;截至22时54分&#xff0c;美团即时零售当日订单已经突破了1.2亿单&#xff0c;其中&#xff0c;餐饮订单已超过1亿单。 值得注意的是&#xff0c;就在当晚20时45分&#xff0c;美团内网曾显示即时零售日订单突破了1亿。这也意味着&#xff…

pycharm2018配置gitee操作

一、gitee介绍及下载安装 gitee介绍&#xff1a; gitee别名码云&#xff0c;是中国的一个代码托管平台&#xff0c;类似于GitHub&#xff0c;基于Git技术&#xff0c;提供远程仓库托管、协作功能和开源社区服务&#xff0c;优势包括访问速度快、本地化服务和政策合规git和gite…

数据结构——栈的讲解(超详细)

数据结构——栈的讲解&#xff08;超详细&#xff09;-腾讯云开发者社区-腾讯云 #include"Stack.h" void STInit(ST* ps) {ps->arr NULL;ps->capacity ps->top 0; //总空间个数和有用空间个数都初始化为0 }void STDestroy(ST* ps) {if (ps -> arr) …

MySQL允许root用户远程连接

注意&#xff1a;在实际生产环境中&#xff0c;允许root用户从任意主机&#xff08;‘%’&#xff09;连接存在安全风险&#xff0c;建议使用强密码并限制访问IP&#xff0c;或者创建具有必要权限的单独用户用于远程连接。MySQL 配置远程连接指南 1. 登录 MySQL 服务器 mysql -…

STM32的 syscalls.c 和 sysmem.c

syscalls.c 是 STM32CubeIDE 自动生成的标准系统调用适配文件&#xff0c;用于裸机环境下支持 newlib 标准库&#xff08;如 printf, scanf, malloc&#xff09;的运行。这份文件提供了标准库运行所需的最小系统调用实现。现在我来逐段解析其作用&#xff0c;并补充你可能需要修…

Java零基础笔记01(JKD及开发工具IDEA安装配置)

1.Java简介 Java是一种广泛使用的计算机编程语言&#xff0c;由美国的Sun Microsystems公司&#xff08;Stanford University Network&#xff09;在1995年推出。Java以其跨平台、面向对象、安全性高等特点&#xff0c;广泛应用于企业级应用开发、移动应用开发等领域。2009年&a…

Spark SQL架构及高级用法

Spark SQL 架构概述 架构核心组件 API层&#xff08;用户接口&#xff09; 输入方式&#xff1a;SQL查询&#xff1b;DataFrame/Dataset API。统一性&#xff1a; 所有接口最终转换为逻辑计划树&#xff08;Logical Plan&#xff09;&#xff0c;进入优化流程。 编译器层&…

【机器学习深度学习】什么是下游任务模型?

目录 前言 一、什么是下游任务模型&#xff1f; 二、为什么需要下游任务模型&#xff1f; 三、下游任务模型都在干嘛&#xff1f; 四、下游模型怎么训练出来的&#xff1f; 五、图解理解&#xff1a;上游 vs 下游 六、一个现实案例&#xff1a;BERT做情感分析 原始数据…

补充:问题:CORS ,前后端访问跨域问题

补充&#xff1a;问题&#xff1a;CORS &#xff0c;前后端访问跨域问题 我这边的解决方法是&#xff1a; myAxios.defaults.withCredentials true; // 配置为true&#xff0c;表示前端向后端发送请求的时候&#xff0c;需要携带上凭证cookie整体的&#xff1a; import axio…

洛谷 P13014 [GESP202506 五级] 最大公因数-普及-

题目描述 对于两个正整数 a,ba,ba,b&#xff0c;他们的最大公因数记为 gcd⁡(a,b)\gcd(a,b)gcd(a,b)。对于 k>3k > 3k>3 个正整数 c1,c2,…,ckc_1,c_2,\dots,c_kc1​,c2​,…,ck​&#xff0c;他们的最大公因数为&#xff1a; gcd⁡(c1,c2,…,ck)gcd⁡(gcd⁡(c1,c2,……

前端-CSS-day1

目录 1、初识CSS 2、CSS引入方式 3、标签选择器 4、类选择器 5、id选择器 6、通配符选择器 7、画盒子 8、字体大小 9、字体粗细 10、字体倾斜 11、行高 12、行高-垂直居中 13、字体族 14、font属性 15、文本缩进 16、文本对齐方式 17、图片对齐方式 18、文本…

解锁万能文件内容提取器:Apache Tika

01 引言 在日常工作中&#xff0c;你是否曾为这些场景头疼过&#xff1f; 堆积如山的PDF、Word、Excel文档&#xff0c;如何快速提取关键信息&#xff1f;用户上传的文件五花八门&#xff0c;如何自动识别类型并安全处理&#xff1f;构建搜索引擎时&#xff0c;如何让系统“读懂…