Java微信公众号开发

article/2025/9/12 10:45:24

本文从本人博客搬运,原文格式更加美观,可以移步原文阅读:Java微信公众号开发

微信公众号介绍

1.公众号的分类

我们平常在微信应用上会看到有很多的公众号,但是各自并不一样,公众号也分很多种类型,不过最常见的就是服务号和订阅号了。下面我们来看一下他们的区别:

  • 订阅号:为媒体和个人提供一种信息传播方式,主要偏于为用户传达资讯(类似报纸杂志),主要的定位是阅读,每天可以群发1条消息
  • 服务号:为企业,政府或组织提供对用户进行服务,主要偏于服务交互(类似银行提供服务查询),每个月只可群发4条消息
  • 企业微信:为企业,政府,事业单位,实现生产管理和协作运营的移动化,主要用于公司内部通讯使用,旨在为用户提供移动办公,需要先有成员的通讯信息验证才可以关注成功企业微信

订阅号和服务号有一个比较明显的区别就是:订阅号都是存放在一个名叫订阅号的文件夹中,点开才能看到所有关注过的订阅号,但是服务号却和好友一样直接就显示在聊天列表中。这个大家打开微信客户端便能看到

2.公众号注册流程

以注册订阅号为例,访问注册地址:https://mp.weixin.qq.com/cgi-bin/registermidpage?action=index&lang=zh_CN&token=

填写基本信息,验证邮箱

选择账号类型

账号主体类型选择个人,填写信息

填写公众号信息

创建成功后,可以进入公众号的管理界面

3.公众号的管理模式

3.1 编辑模式

主要针对非编程人员及信息发布类公众帐号使用。开启该模式后,可以方便地通过界面配置“自定义菜单”和“自动回复的消息”。好处是可视化界面配置,操作简单,快捷,但是功能有限

我们可以给自己的公众号设置关键词回复,收到已关注用户发送的消息,匹配到你好时回复一个你好~~

编辑模式只能预先自定义一些固定的规则和数据,这些数据会保存在微信服务器,只能完成一些简单的功能。如果要完成更复杂的功能,比如根据用户输入信息动态获取数据返回,则需要使用开发模式

3.2 开发模式

主要针对具备开发能力的人使用。开启该模式后,能够使用微信公众平台开放的接口,但是编辑模式的设置会失效,比如“自定义菜单”和“自动回复的消息”功能。通过编程方式可以实现更多复杂的功能,提供个性化服务。

总的来说,编辑模式就是为所有人提供的,如果你的需求仅仅只是最常见的菜单,自动回复等,使用编辑模式已经满足,但是如果你需求的功能比较复杂,比如需要从自己的业务系统数据库中查询数据返回给微信用户,就需要使用到开发模式。

接下来我们介绍开发模式的各种功能使用步骤。出于安全考虑,普通的订阅号权限非常有限,可以调用的接口非常有限,不便于测试

所以,为了帮助开发者快速了解和上手微信公众号开发,熟悉各个接口的调用,微信推出了公众帐号测试号,无需公众帐号、快速申请接口测试号,通过手机微信扫描二维码即可获得,利用测试号我们可以体验和测试更多高级功能。测试号申请地址:https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login

但测试号也不是万能的,部分高级功能,如微信支付,卡券功能等也是不开放的。如果要实现支付功能还是得去注册个正式的公众号。本文后续所有测试都基于测试公众号

接入开发模式

我们首先了解下微信与我们的服务器交互的过程:

当我们在微信app上,给公众号发送一条内容的时候,实际会发送到微信的服务器上,此时微信的服务器就会对内容进行封装成某种格式的数据比如xml格式,再转发到我们配置好的某个URL上,所以该URL实际就是我们处理数据的一个请求路径。所以该URL必须是能暴露给外界访问的一个公网地址,不能使用内网地址,生产环境可以申请腾讯云,阿里云服务器等,但是在开发环境中可以暂时利用一些软件来完成内网穿透

在进行和微信公众号服务器交互之前,需要进行接入验证。接入验证涉及的2个关键参数如下:

  • URL:就是指我们自己的服务器地址。该URL是开发者用来接收和响应微信消息和事件的接口URL(必须以http://或https://开头,分别支持80端口和443端口)
  • Token:可任意填写,用作生成签名(必须为英文或数字,长度为3-32字符)

接入验证的大致流程如下:

  1. 开发者提交URL和token信息后,微信服务器将发送GET请求到填写的服务器地址URL上,GET请求携带参数如下表所示:
参数描述
signature微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。
timestamp时间戳
nonce随机数
echostr随机字符串
  1. 开发者通过检验signature对请求进行校验(下面有校验方式)。若确认此次GET请求来自微信服务器,请原样返回echostr参数内容,则接入生效,成为开发者成功,否则接入失败。加密/校验流程如下:

    1. 将token、timestamp、nonce三个参数进行字典序排序
    2. 将三个参数字符串拼接成一个字符串进行sha1加密
    3. 开发者获得加密后的字符串可与signature对比,标识该请求来源于微信

    注意到微信发送的GET请求中并没有携带我们填写的token,而签名signature的生成过程中token是一个入参,所以我们填写的url处理程序中,校验signature时也需要token,这就要求我们在url对应的后端程序中定义token,要和通过微信页面填写的token一致。这样做是为了安全性,只有知道token才可以接入成功,避免了他人盗用公众号做操作

根据上述验证流程,我们创建一个Springboot应用,编写验证接口

@RestController
@RequestMapping("wechat/publicAccount")
public class WechatPublicAccountController {// 微信页面填写的token,必须保密private static final String TOKEN = "";@GetMapping("validate")public String validate(String signature,String timestamp,String nonce,String echostr){// 1. 将token、timestamp、nonce三个参数进行字典序排序String[] arr = {timestamp, nonce, TOKEN};Arrays.sort(arr);// 2. 将三个参数字符串拼接成一个字符串进行sha1加密StringBuilder sb = new StringBuilder();for (String temp : arr) {sb.append(temp);}// 这里利用了hutool的加密工具类String sha1 = SecureUtil.sha1(sb.toString());// 3. 加密后的字符串与signature对比,如果相同则该请求来源于微信,原样返回echostrif (sha1.equals(signature)){return echostr;}// 接入失败return null;}
}

利用内网穿透工具,将我们的本地应用地址映射到公网域名

然后在测试号页面填写回调url和正确的token,即可接入成功。如果token填错,将接入失败

特别注意:

  • 在接入成功后,后续所有微信发送过来的消息都会携带signaturetimestampnonce这3个参数,我们每次接收微信消息时都要跟初始接入一样去校验signature,以确保接收到的消息是微信发过来的,而不是其他人发过来的
  • 仅接入消息会携带echostr,后续所有微信发过来的消息不会携带echostr,所以可以根据请求是否携带了echostr来判断是否是接入消息。接入消息除了校验signature外要原样返回echostr,其他后续消息只需校验signature即可

消息接收与响应

1.接收消息

接入成功以后,我们就可以利用微信提供的接口实现各种功能。首先来看一下基本的消息接收和回复,官方文档位置如下

当关注了公众号的用户向公众号发送消息时,微信服务器将POST消息的XML数据包到开发者填写的URL上。所以我们要在Controller中新建一个处理方法

微信会将用户发送的消息信息封装到请求体的xml中,根据消息类型的不同,xml的格式也有所不同:

  • 文本消息
<xml><ToUserName><![CDATA[toUser]]></ToUserName><FromUserName><![CDATA[fromUser]]></FromUserName><CreateTime>1348831860</CreateTime><MsgType><![CDATA[text]]></MsgType><Content><![CDATA[this is a test]]></Content><MsgId>1234567890123456</MsgId>
</xml>
参数描述
ToUserName开发者微信号
FromUserName发送方帐号(一个OpenID)
CreateTime消息创建时间 (整型)
MsgType消息类型,文本为text
Content文本消息内容
MsgId消息id,64位整型
  • 图片消息
<xml><ToUserName><![CDATA[toUser]]></ToUserName><FromUserName><![CDATA[fromUser]]></FromUserName><CreateTime>1348831860</CreateTime><MsgType><![CDATA[image]]></MsgType><PicUrl><![CDATA[this is a url]]></PicUrl><MediaId><![CDATA[media_id]]></MediaId><MsgId>1234567890123456</MsgId>
</xml>
参数描述
ToUserName开发者微信号
FromUserName发送方帐号(一个OpenID)
CreateTime消息创建时间 (整型)
MsgType消息类型,图片为image
PicUrl图片链接(由系统生成)
MediaId图片消息媒体id,可以调用获取临时素材接口拉取数据。
MsgId消息id,64位整型
  • 语音消息
<xml><ToUserName><![CDATA[toUser]]></ToUserName><FromUserName><![CDATA[fromUser]]></FromUserName><CreateTime>1357290913</CreateTime><MsgType><![CDATA[voice]]></MsgType><MediaId><![CDATA[media_id]]></MediaId><Format><![CDATA[Format]]></Format><MsgId>1234567890123456</MsgId>
</xml>
参数描述
ToUserName开发者微信号
FromUserName发送方帐号(一个OpenID)
CreateTime消息创建时间 (整型)
MsgType语音为voice
MediaId语音消息媒体id,可以调用获取临时素材接口拉取数据。
Format语音格式,如amr,speex等
MsgId消息id,64位整型
  • 视频消息
<xml><ToUserName><![CDATA[toUser]]></ToUserName><FromUserName><![CDATA[fromUser]]></FromUserName><CreateTime>1357290913</CreateTime><MsgType><![CDATA[video]]></MsgType><MediaId><![CDATA[media_id]]></MediaId><ThumbMediaId><![CDATA[thumb_media_id]]></ThumbMediaId><MsgId>1234567890123456</MsgId>
</xml>
参数描述
ToUserName开发者微信号
FromUserName发送方帐号(一个OpenID)
CreateTime消息创建时间 (整型)
MsgType视频为video
MediaId视频消息媒体id,可以调用获取临时素材接口拉取数据。
ThumbMediaId视频消息缩略图的媒体id,可以调用多媒体文件下载接口拉取数据。
MsgId消息id,64位整型
  • 小视频消息
<xml><ToUserName><![CDATA[toUser]]></ToUserName><FromUserName><![CDATA[fromUser]]></FromUserName><CreateTime>1357290913</CreateTime><MsgType><![CDATA[shortvideo]]></MsgType><MediaId><![CDATA[media_id]]></MediaId><ThumbMediaId><![CDATA[thumb_media_id]]></ThumbMediaId><MsgId>1234567890123456</MsgId>
</xml>
参数描述
ToUserName开发者微信号
FromUserName发送方帐号(一个OpenID)
CreateTime消息创建时间 (整型)
MsgType小视频为shortvideo
MediaId视频消息媒体id,可以调用获取临时素材接口拉取数据。
ThumbMediaId视频消息缩略图的媒体id,可以调用获取临时素材接口拉取数据。
MsgId消息id,64位整型
  • 地理位置消息
<xml><ToUserName><![CDATA[toUser]]></ToUserName><FromUserName><![CDATA[fromUser]]></FromUserName><CreateTime>1351776360</CreateTime><MsgType><![CDATA[location]]></MsgType><Location_X>23.134521</Location_X><Location_Y>113.358803</Location_Y><Scale>20</Scale><Label><![CDATA[位置信息]]></Label><MsgId>1234567890123456</MsgId>
</xml>
参数描述
ToUserName开发者微信号
FromUserName发送方帐号(一个OpenID)
CreateTime消息创建时间 (整型)
MsgType消息类型,地理位置为location
Location_X地理位置纬度
Location_Y地理位置经度
Scale地图缩放大小
Label地理位置信息
MsgId消息id,64位整型
  • 链接消息
<xml><ToUserName><![CDATA[toUser]]></ToUserName><FromUserName><![CDATA[fromUser]]></FromUserName><CreateTime>1351776360</CreateTime><MsgType><![CDATA[link]]></MsgType><Title><![CDATA[公众平台官网链接]]></Title><Description><![CDATA[公众平台官网链接]]></Description><Url><![CDATA[url]]></Url><MsgId>1234567890123456</MsgId>
</xml>
参数描述
ToUserName接收方微信号
FromUserName发送方微信号,若为普通用户,则是一个OpenID
CreateTime消息创建时间
MsgType消息类型,链接为link
Title消息标题
Description消息描述
Url消息链接
MsgId消息id,64位整型

我们对比一下不同类型的xml数据包中的参数,ToUserNameFromUserNameCreateTimeMsgTypeMsgId这五个是公共的,所有类型都会带上这些参数。接下来,我们需要来了解这5个参数的具体意义:

  • ToUserName:文档上描述的是开发者微信号,实际上,直接把它当做你的公众号的微信号即可,表示的是发到那个公众号的意思。
  • FromUserName:与ToUserName相反,这是代表是由哪个用户发过来的,同一个用户发多条信息过来,FromUserName都是不变的。但这并不是用户的微信号,而是一个OpenID。那什么是OpenID呢:当用户和公众号发生了交互,微信服务器会为每个用户针对每个公众号产生一个OpenID(也就是指该OpenID是利用两个因素:用户和公众号来产生的,也就意味着如果该用户跟另外一个公众号交互,产生的OpenID也是不同的,这样安全性会比较高),如果一个公司有多个公众号,并且需要在多公众号、移动应用之间做用户共通,则需要使用UnionID,前往微信开放平台,将这些公众号和应用绑定到一个开放平台账号下,绑定后,一个用户虽然对多个公众号和应用有多个不同的OpenID,但他对所有这些同一开放平台账号下的公众号和应用,只有一个UnionID,可以在用户管理-获取用户基本信息(UnionID机制)文档了解详情。
  • CreateTime:消息创建时间
  • MsgType:用户发送的消息的类型,如text代表文本消息,image代表图片消息等。
  • MsgId:用户发送的每个消息都有自己的id,可以用于消息排重,比如微信服务器把xml消息包发送到URL了,但是五秒内微信服务器没有收到我们的响应,则会重新发起请求,总共重试三次。如果不做消息排重,那么用户可能就收到多条相同的响应消息了。

微信服务器在五秒内收不到响应会断掉连接,并且重新发起请求,总共重试三次。假如服务器无法保证在五秒内处理并回复,可以直接回复空串,微信服务器不会对此作任何处理,并且不会发起重试

接下来,我们可以创建一个封装消息的实体类,把所有可接收到的参数都放进入,其他类型的暂时不演示,所以只在最后加入了文本和图片的参数。

@Data
@AllArgsConstructor
@NoArgsConstructor
public class InMessage {// 开发者微信号protected String FromUserName;// 发送方帐号(一个OpenID)protected String ToUserName;// 消息创建时间protected Long CreateTime;/*** 消息类型* text 文本消息* image 图片消息* voice 语音消息* video 视频消息* music 音乐消息*/protected String MsgType;// 消息idprotected Long MsgId;// 文本内容private String Content;// 图片链接(由系统生成)private String PicUrl;// 图片消息媒体id,可以调用多媒体文件下载接口拉取数据private String MediaId;
}

这时候大家可能会有个疑问,为什么字段名称都是大写开头呢?因为微信服务器传过来的xml数据包中的xml元素都是大写开头的,如下所示:

<xml><ToUserName><![CDATA[toUser]]></ToUserName><FromUserName><![CDATA[fromUser]]></FromUserName><CreateTime>1348831860</CreateTime><MsgType><![CDATA[text]]></MsgType><Content><![CDATA[this is a test]]></Content><MsgId>1234567890123456</MsgId>
</xml>

因为xml解析是大小写敏感的,所以为了方便封装,我直接把字段名设置为大写开头。当然,如果还是想要小写开头的字段,也是可以的,我们待会再说处理方式。

实体已经建好之后,我们就可以开始接收微信传过来的xml数据了。

第1步:在handleMessage方法的形参上添加消息实体类型的参数:

第2步:需要配合JAXB的注解来解析xml。在消息实体类上添加以下两个注解:

这2个注解的含义如下:

  • @XmlRootElement:是一个类级别注解,主要属性为name,意为指定根节点的名字。往上面看前面举了个微信传过来的xml数据的例子里,里面的根节点就是"xml",所以这里就直接设置name=“xml”
  • @XmlAccessorType:用于定义这个类中的何种类型需要映射到XML中
    • XmlAccessType.PROPERTY:代表映射这个类中的属性(get/set方法)到XML
    • XmlAccessType.FIELD:代表映射这个类中的所有字段到XML

之前我们为了方便解析,将消息实体类的属性命名成和xml中的节点一样都是大写开头,现在我们优化一下,按照java规范命名属性小写开头,然后利用@XmlElement给每个属性标注对应的xml节点名称

@Data
@AllArgsConstructor
@NoArgsConstructor
@XmlRootElement(name = "xml")
@XmlAccessorType(XmlAccessType.FIELD)
public class InMessage {/*** 开发者微信号*/@XmlElement(name="FromUserName")protected String fromUserName;/*** 发送方帐号(一个OpenID)*/@XmlElement(name="ToUserName")protected String toUserName;/*** 消息创建时间*/@XmlElement(name="CreateTime")protected Long createTime;/*** 消息类型* text 文本消息* image 图片消息* voice 语音消息* video 视频消息* music 音乐消息*/@XmlElement(name="MsgType")protected String msgType;/*** 消息id*/@XmlElement(name="MsgId")protected Long msgId;/*** 文本内容*/@XmlElement(name="Content")private String content;/*** 图片链接(由系统生成)*/@XmlElement(name="PicUrl")private String picUrl;/*** 图片消息媒体id,可以调用多媒体文件下载接口拉取数据*/@XmlElement(name="MediaId")private String mediaId;
}

然后我们在Controller接收消息的方法中设置断点,关注测试公众号,给它发送一个文本消息"你好",就可以接收到了

2.响应消息

官方文档:https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Passive_user_reply_message.html

当用户发送消息给公众号时(或某些特定的用户操作引发的事件推送时),会产生一个POST请求,开发者可以在响应包(Get)中返回特定XML结构,来对该消息进行响应(现支持回复文本、图片、图文、语音、视频、音乐)。严格来说,发送被动响应消息其实并不是一种接口,而是对微信服务器发过来消息的一次回复

微信服务器在将用户的消息发给公众号的开发者服务器地址(开发者中心处配置)后,微信服务器在五秒内收不到响应会断掉连接,并且重新发起请求,总共重试三次,如果在调试中,发现用户无法收到响应的消息,可以检查是否消息处理超时。关于重试的消息排重,有msgid的消息推荐使用msgid排重。事件类型消息推荐使用FromUserName + CreateTime 排重。

如果开发者希望增强安全性,可以在开发者中心处开启消息加密,这样,用户发给公众号的消息以及公众号被动回复用户消息都会继续加密。

假如服务器无法保证在五秒内处理并回复,必须做出下述回复,这样微信服务器才不会对此作任何处理,并且不会发起重试(这种情况下,可以使用客服消息接口进行异步回复),否则,将出现严重的错误提示:

  1. 直接回复success(推荐方式)
  2. 直接回复空串(指字节长度为0的空字符串,而不是XML结构体中content字段的内容为空)

一旦遇到以下情况,微信都会在公众号会话中,向用户下发系统提示“该公众号暂时无法提供服务,请稍后再试”:

  1. 开发者在5秒内未回复任何内容
  2. 开发者回复了异常数据,比如JSON数据等

另外,请注意,回复图片(不支持gif动图)等多媒体消息时需要预先通过素材管理接口上传临时素材到微信服务器,可以使用素材管理中的临时素材,也可以使用永久素材。

各种类型的响应消息格式如下:

  • 回复文本消息
<xml><ToUserName><![CDATA[toUser]]></ToUserName><FromUserName><![CDATA[fromUser]]></FromUserName><CreateTime>12345678</CreateTime><MsgType><![CDATA[text]]></MsgType><Content><![CDATA[你好]]></Content>
</xml>
参数是否必须描述
ToUserName接收方帐号(收到的OpenID)
FromUserName开发者微信号
CreateTime消息创建时间 (整型)
MsgType消息类型,文本为text
Content回复的消息内容(换行:在content中能够换行,微信客户端就支持换行显示)
  • 回复图片消息
<xml><ToUserName><![CDATA[toUser]]></ToUserName><FromUserName><![CDATA[fromUser]]></FromUserName><CreateTime>12345678</CreateTime><MsgType><![CDATA[image]]></MsgType><Image><MediaId><![CDATA[media_id]]></MediaId></Image>
</xml>
参数是否必须说明
ToUserName接收方帐号(收到的OpenID)
FromUserName开发者微信号
CreateTime消息创建时间 (整型)
MsgType消息类型,图片为image
MediaId通过素材管理中的接口上传多媒体文件,得到的id。
  • 回复语音消息
<xml><ToUserName><![CDATA[toUser]]></ToUserName><FromUserName><![CDATA[fromUser]]></FromUserName><CreateTime>12345678</CreateTime><MsgType><![CDATA[voice]]></MsgType><Voice><MediaId><![CDATA[media_id]]></MediaId></Voice>
</xml>
参数是否必须说明
ToUserName接收方帐号(收到的OpenID)
FromUserName开发者微信号
CreateTime消息创建时间戳 (整型)
MsgType消息类型,语音为voice
MediaId通过素材管理中的接口上传多媒体文件,得到的id
  • 回复视频消息
<xml><ToUserName><![CDATA[toUser]]></ToUserName><FromUserName><![CDATA[fromUser]]></FromUserName><CreateTime>12345678</CreateTime><MsgType><![CDATA[video]]></MsgType><Video><MediaId><![CDATA[media_id]]></MediaId><Title><![CDATA[title]]></Title><Description><![CDATA[description]]></Description></Video>
</xml>
参数是否必须说明
ToUserName接收方帐号(收到的OpenID)
FromUserName开发者微信号
CreateTime消息创建时间 (整型)
MsgType消息类型,视频为video
MediaId通过素材管理中的接口上传多媒体文件,得到的id
Title视频消息的标题
Description视频消息的描述
  • 回复音乐消息
<xml><ToUserName><![CDATA[toUser]]></ToUserName><FromUserName><![CDATA[fromUser]]></FromUserName><CreateTime>12345678</CreateTime><MsgType><![CDATA[music]]></MsgType><Music><Title><![CDATA[TITLE]]></Title><Description><![CDATA[DESCRIPTION]]></Description><MusicUrl><![CDATA[MUSIC_Url]]></MusicUrl><HQMusicUrl><![CDATA[HQ_MUSIC_Url]]></HQMusicUrl><ThumbMediaId><![CDATA[media_id]]></ThumbMediaId></Music>
</xml>
参数是否必须说明
ToUserName接收方帐号(收到的OpenID)
FromUserName开发者微信号
CreateTime消息创建时间 (整型)
MsgType消息类型,音乐为music
Title音乐标题
Description音乐描述
MusicURL音乐链接
HQMusicUrl高质量音乐链接,WIFI环境优先使用该链接播放音乐
ThumbMediaId缩略图的媒体id,通过素材管理中的接口上传多媒体文件,得到的id
  • 回复图文消息
<xml><ToUserName><![CDATA[toUser]]></ToUserName><FromUserName><![CDATA[fromUser]]></FromUserName><CreateTime>12345678</CreateTime><MsgType><![CDATA[news]]></MsgType><ArticleCount>1</ArticleCount><Articles><item><Title><![CDATA[title1]]></Title><Description><![CDATA[description1]]></Description><PicUrl><![CDATA[picurl]]></PicUrl><Url><![CDATA[url]]></Url></item></Articles>
</xml>
参数是否必须说明
ToUserName接收方帐号(收到的OpenID)
FromUserName开发者微信号
CreateTime消息创建时间 (整型)
MsgType消息类型,图文为news
ArticleCount图文消息个数;当用户发送文本、图片、语音、视频、图文、地理位置这六种消息时,开发者只能回复1条图文消息;其余场景最多可回复8条图文消息
Articles图文消息信息,注意,如果图文数超过限制,则将只发限制内的条数
Title图文消息标题
Description图文消息描述
PicUrl图片链接,支持JPG、PNG格式,较好的效果为大图360*200,小图200*200
Url点击图文消息跳转链接

我们可以看到回复的格式中除了都没有MsgId,只有普通文本和接收的格式基本是一样的,图片消息或其他类型的消息与接收到的格式相比,多了xml元素的嵌套,所以原先定义的接收消息实体类无法复用,我们再封装一个响应消息的实体类,这里暂时只考虑文本和图片类型

@Data
@AllArgsConstructor
@NoArgsConstructor
@XmlRootElement(name = "xml")
@XmlAccessorType(XmlAccessType.FIELD)
public class OutMessage {/*** 开发者微信号*/@XmlElement(name="FromUserName")protected String fromUserName;/*** 发送方帐号(一个OpenID)*/@XmlElement(name="ToUserName")protected String toUserName;/*** 消息创建时间*/@XmlElement(name="CreateTime")protected Long createTime;/*** 消息类型* text 文本消息* image 图片消息* voice 语音消息* video 视频消息* music 音乐消息*/@XmlElement(name="MsgType")protected String msgType;/*** 文本内容*/@XmlElement(name="Content")private String content;/*** 图片的媒体id列表*/@XmlElementWrapper(name="Image") // 表示MediaId属性内嵌于<Image>标签@XmlElement(name = "MediaId")private String[] mediaId;
}

@XmlElementWrapper注解可以在原xml结点上再包装一层xml,但仅允许出现在数组或集合属性上

现在我们来实现一下简单的回复消息:用户给我们发什么,我们就回复什么,只需要把接收到InMessage的内容设置到OutMessage上,并且把ToUserNameFromUserName的值设置为相反即可

@PostMapping(value = "validate", produces = "application/xml;charset=UTF-8")
public Object handleMessage(@RequestBody InMessage inMessage){// 创建响应消息实体对象OutMessage outMessage = new OutMessage();// 把原来的接收方设置为发送方outMessage.setFromUserName(inMessage.getToUserName());// 把原来的发送方设置为接收方outMessage.setToUserName(inMessage.getFromUserName());// 设置消息类型outMessage.setMsgType(inMessage.getMsgType());// 设置消息时间outMessage.setCreateTime(System.currentTimeMillis());// 根据接收到消息类型,响应对应的消息内容if ("text".equals(inMessage.getMsgType())){// 文本outMessage.setContent(inMessage.getContent());}else if ("image".equals(inMessage.getMsgType())){// 图片outMessage.setMediaId(new String[]{inMessage.getMediaId()});}return outMessage;
}

注意:这里要在接口的@PostMapping中指定produces = "application/xml;charset=UTF-8",表示返回的数据格式是xml,否则将默认以json格式返回

测试效果如下

关键字回复

在开发模式下要实现关键字回复非常简单,只要判断发送过来的文本消息中是否包含关键字,然后给予相应的回复即可

@PostMapping(value = "validate", produces = "application/xml;charset=UTF-8")
public Object handleMessage(@RequestBody InMessage inMessage){// 创建响应消息实体对象OutMessage outMessage = new OutMessage();// 把原来的接收方设置为发送方outMessage.setFromUserName(inMessage.getToUserName());// 把原来的发送方设置为接收方outMessage.setToUserName(inMessage.getFromUserName());// 设置消息类型outMessage.setMsgType(inMessage.getMsgType());// 设置消息时间outMessage.setCreateTime(System.currentTimeMillis() / 1000);// 根据接收到消息类型,响应对应的消息内容if ("text".equals(inMessage.getMsgType())){// 根据不同的关键字回复消息String inContent = inMessage.getContent();if (inContent.contains("游戏")){outMessage.setContent("仙剑");}else if (inContent.contains("动漫")){outMessage.setContent("进击的巨人");}else {outMessage.setContent(inContent);}}else if ("image".equals(inMessage.getMsgType())){// 图片outMessage.setMediaId(new String[]{inMessage.getMediaId()});}return outMessage;
}

事件推送

官方文档:https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Receiving_event_pushes.html

我们之前的案例都是用户发送信息过来,我们才回复的。但是,如果是关注的时候需要马上回复,就要使用到事件消息,实际上,微信已经提供给我们很多的事件

在微信用户和公众号产生交互的过程中,用户的某些操作会使得微信服务器通过事件推送的形式通知到开发者在开发者中心处设置的服务器地址,从而开发者可以获取到该信息。其中,某些事件推送在发生后,是允许开发者回复用户的,某些则不允许

1.关注/取消关注事件

用户在关注与取消关注公众号时,微信会把这个事件推送到开发者填写的URL。方便开发者给用户下发欢迎消息或者做帐号的解绑。为保护用户数据隐私,开发者收到用户取消关注事件时需要删除该用户的所有信息。

微信服务器在五秒内收不到响应会断掉连接,并且重新发起请求,总共重试三次。

关于重试的消息排重,推荐使用FromUserName + CreateTime 排重。

假如服务器无法保证在五秒内处理并回复,可以直接回复空串,微信服务器不会对此作任何处理,并且不会发起重试。

推送XML数据包示例:

<xml><ToUserName><![CDATA[toUser]]></ToUserName><FromUserName><![CDATA[FromUser]]></FromUserName><CreateTime>123456789</CreateTime><MsgType><![CDATA[event]]></MsgType><Event><![CDATA[subscribe]]></Event>
</xml>
参数描述
ToUserName开发者微信号
FromUserName发送方帐号(一个OpenID)
CreateTime消息创建时间 (整型)
MsgType消息类型,event
Event事件类型,subscribe(订阅)、unsubscribe(取消订阅)

2.扫描带参数二维码事件

用户扫描带场景值二维码时,可能推送以下两种事件:

  1. 如果用户还未关注公众号,则用户可以关注公众号,关注后微信会将带场景值关注事件推送给开发者。
<xml><ToUserName><![CDATA[toUser]]></ToUserName><FromUserName><![CDATA[FromUser]]></FromUserName><CreateTime>123456789</CreateTime><MsgType><![CDATA[event]]></MsgType><Event><![CDATA[subscribe]]></Event><EventKey><![CDATA[qrscene_123123]]></EventKey><Ticket><![CDATA[TICKET]]></Ticket>
</xml>
参数描述
ToUserName开发者微信号
FromUserName发送方帐号(一个OpenID)
CreateTime消息创建时间 (整型)
MsgType消息类型,event
Event事件类型,subscribe
EventKey事件KEY值,qrscene_为前缀,后面为二维码的参数值
Ticket二维码的ticket,可用来换取二维码图片
  1. 如果用户已经关注公众号,则微信会将带场景值扫描事件推送给开发者。
<xml><ToUserName><![CDATA[toUser]]></ToUserName><FromUserName><![CDATA[FromUser]]></FromUserName><CreateTime>123456789</CreateTime><MsgType><![CDATA[event]]></MsgType><Event><![CDATA[SCAN]]></Event><EventKey><![CDATA[SCENE_VALUE]]></EventKey><Ticket><![CDATA[TICKET]]></Ticket>
</xml> 
参数描述
ToUserName开发者微信号
FromUserName发送方帐号(一个OpenID)
CreateTime消息创建时间 (整型)
MsgType消息类型,event
Event事件类型,SCAN
EventKey事件KEY值,是一个32位无符号整数,即创建二维码时的二维码scene_id
Ticket二维码的ticket,可用来换取二维码图片

3.上报地理位置事件

这个事件仅用于服务号,订阅号不行。用户同意上报地理位置后,每次进入公众号会话时,都会在进入时上报地理位置,或在进入会话后每5秒上报一次地理位置,公众号可以在公众平台网站中修改以上设置。上报地理位置时,微信会将上报地理位置事件推送到开发者填写的URL。

推送XML数据包示例:

<xml><ToUserName><![CDATA[toUser]]></ToUserName><FromUserName><![CDATA[fromUser]]></FromUserName><CreateTime>123456789</CreateTime><MsgType><![CDATA[event]]></MsgType><Event><![CDATA[LOCATION]]></Event><Latitude>23.137466</Latitude><Longitude>113.352425</Longitude><Precision>119.385040</Precision>
</xml>
参数描述
ToUserName开发者微信号
FromUserName发送方帐号(一个OpenID)
CreateTime消息创建时间 (整型)
MsgType消息类型,event
Event事件类型,LOCATION
Latitude地理位置纬度
Longitude地理位置经度
Precision地理位置精度

4.自定义菜单事件

用户点击自定义菜单后,微信会把点击事件推送给开发者,请注意,点击菜单弹出子菜单,不会产生上报

点击菜单拉取消息时的事件推送

<xml><ToUserName><![CDATA[toUser]]></ToUserName><FromUserName><![CDATA[FromUser]]></FromUserName><CreateTime>123456789</CreateTime><MsgType><![CDATA[event]]></MsgType><Event><![CDATA[CLICK]]></Event><EventKey><![CDATA[EVENTKEY]]></EventKey>
</xml>
参数描述
ToUserName开发者微信号
FromUserName发送方帐号(一个OpenID)
CreateTime消息创建时间 (整型)
MsgType消息类型,event
Event事件类型,CLICK
EventKey事件KEY值,与自定义菜单接口中KEY值对应

点击菜单跳转链接时的事件推送

<xml><ToUserName><![CDATA[toUser]]></ToUserName><FromUserName><![CDATA[FromUser]]></FromUserName><CreateTime>123456789</CreateTime><MsgType><![CDATA[event]]></MsgType><Event><![CDATA[VIEW]]></Event><EventKey><![CDATA[www.qq.com]]></EventKey>
</xml>
参数描述
ToUserName开发者微信号
FromUserName发送方帐号(一个OpenID)
CreateTime消息创建时间 (整型)
MsgType消息类型,event
Event事件类型,VIEW
EventKey事件KEY值,设置的跳转URL

事件推送案例演示

我们来实现一下用户关注公众号时接收推送消息并自动回复的功能

事件和消息都是推送到我们的URL上,怎么区分他们也很简单,通过MsgType这个属性,那么进一步再区分是关注还是取消关注,根据Event属性即可。所以,我们在原来的InMessage类,再添加一个Event属性

然后在Controller处理方法中添加对应逻辑

然后取消关注后再关注,即可展现效果

自定义菜单

1.自定义菜单简介

官方文档:https://developers.weixin.qq.com/doc/offiaccount/Custom_Menus/Creating_Custom-Defined_Menu.html

自定义菜单能够帮助公众号丰富界面,让用户更好更快地理解公众号的功能。开启自定义菜单后,公众号界面如图所示:

请注意:

  • 自定义菜单最多包括3个一级菜单,每个一级菜单最多包含5个二级菜单。
  • 一级菜单最多4个汉字,二级菜单最多7个汉字,多出来的部分将会以“…”代替。
  • 创建自定义菜单后,菜单的刷新策略是,在用户进入公众号会话页或公众号profile页时,如果发现上一次拉取菜单的请求在5分钟以前,就会拉取一下菜单,如果菜单有更新,就会刷新客户端的菜单。测试时可以尝试取消关注公众账号后再次关注,则可以看到创建后的效果。

自定义菜单接口可实现多种类型按钮,如下:

  1. click:点击推事件用户点击click类型按钮后,微信服务器会通过消息接口推送消息类型为event的结构给开发者(参考消息接口指南),并且带上按钮中开发者填写的key值,开发者可以通过自定义的key值与用户进行交互;
  2. view:跳转URL用户点击view类型按钮后,微信客户端将会打开开发者在按钮中填写的网页URL,可与网页授权获取用户基本信息接口结合,获得用户基本信息。
  3. scancode_push:扫码推事件用户点击按钮后,微信客户端将调起扫一扫工具,完成扫码操作后显示扫描结果(如果是URL,将进入URL),且会将扫码的结果传给开发者,开发者可以下发消息。
  4. scancode_waitmsg:扫码推事件且弹出“消息接收中”提示框用户点击按钮后,微信客户端将调起扫一扫工具,完成扫码操作后,将扫码的结果传给开发者,同时收起扫一扫工具,然后弹出“消息接收中”提示框,随后可能会收到开发者下发的消息。
  5. pic_sysphoto:弹出系统拍照发图用户点击按钮后,微信客户端将调起系统相机,完成拍照操作后,会将拍摄的相片发送给开发者,并推送事件给开发者,同时收起系统相机,随后可能会收到开发者下发的消息。
  6. pic_photo_or_album:弹出拍照或者相册发图用户点击按钮后,微信客户端将弹出选择器供用户选择“拍照”或者“从手机相册选择”。用户选择后即走其他两种流程。
  7. pic_weixin:弹出微信相册发图器用户点击按钮后,微信客户端将调起微信相册,完成选择操作后,将选择的相片发送给开发者的服务器,并推送事件给开发者,同时收起相册,随后可能会收到开发者下发的消息。
  8. location_select:弹出地理位置选择器用户点击按钮后,微信客户端将调起地理位置选择工具,完成选择操作后,将选择的地理位置发送给开发者的服务器,同时收起位置选择工具,随后可能会收到开发者下发的消息。
  9. media_id:下发消息(除文本消息)用户点击media_id类型按钮后,微信服务器会将开发者填写的永久素材id对应的素材下发给用户,永久素材类型可以是图片、音频、视频、图文消息。请注意:永久素材id必须是在“素材管理/新增永久素材”接口上传后获得的合法id。
  10. view_limited:跳转图文消息URL用户点击view_limited类型按钮后,微信客户端将打开开发者在按钮中填写的永久素材id对应的图文消息URL,永久素材类型只支持图文消息。请注意:永久素材id必须是在“素材管理/新增永久素材”接口上传后获得的合法id。

请注意,3到8的所有事件,仅支持微信iPhone5.4.1以上版本,和Android5.4以上版本的微信用户,旧版本微信用户点击后将没有回应,开发者也不能正常接收到事件推送。9和10,是专门给第三方平台旗下未微信认证(具体而言,是资质认证未通过)的订阅号准备的事件类型,它们是没有事件推送的,能力相对受限,其他类型的公众号不必使用。

如果我们要给公众号创建自定义菜单,需要发送下列请求

http请求方式:POST(请使用https协议) https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN

请求体示例如下:

{"button":[{	"type":"click","name":"今日歌曲","key":"V1001_TODAY_MUSIC"},{"name":"菜单","sub_button":[{	"type":"view","name":"搜索","url":"http://www.soso.com/"},{"type":"miniprogram","name":"wxa","url":"http://mp.weixin.qq.com","appid":"wx286b93c14bbf93aa","pagepath":"pages/lunar/index"},{"type":"click","name":"赞一下我们","key":"V1001_GOOD"}]}]}
参数是否必须说明
button一级菜单数组,个数应为1~3个
sub_button二级菜单数组,个数应为1~5个
type菜单的响应动作类型,view表示网页类型,click表示点击类型,miniprogram表示小程序类型
name菜单标题,不超过16个字节,子菜单不超过60个字节
keyclick等点击类型必须菜单KEY值,用于消息接口推送,不超过128字节
urlview、miniprogram类型必须网页 链接,用户点击菜单可打开链接,不超过1024字节。 type为miniprogram时,不支持小程序的老版本客户端将打开本url。
media_idmedia_id类型和view_limited类型必须调用新增永久素材接口返回的合法media_id
appidminiprogram类型必须小程序的appid(仅认证公众号可配置)
pagepathminiprogram类型必须小程序的页面路径

正确时的返回JSON数据包如下:

{"errcode":0,"errmsg":"ok"}

错误时的返回JSON数据包如下(示例为无效菜单名长度):

{"errcode":40018,"errmsg":"invalid button name size"}

其他类型的菜单示例如下

{"button": [{"name": "扫码", "sub_button": [{"type": "scancode_waitmsg", "name": "扫码带提示", "key": "rselfmenu_0_0", "sub_button": [ ]}, {"type": "scancode_push", "name": "扫码推事件", "key": "rselfmenu_0_1", "sub_button": [ ]}]}, {"name": "发图", "sub_button": [{"type": "pic_sysphoto", "name": "系统拍照发图", "key": "rselfmenu_1_0", "sub_button": [ ]}, {"type": "pic_photo_or_album", "name": "拍照或者相册发图", "key": "rselfmenu_1_1", "sub_button": [ ]}, {"type": "pic_weixin", "name": "微信相册发图", "key": "rselfmenu_1_2", "sub_button": [ ]}]}, {"name": "发送位置", "type": "location_select", "key": "rselfmenu_2_0"},{"type": "media_id", "name": "图片", "media_id": "MEDIA_ID1"}, {"type": "view_limited", "name": "图文消息", "media_id": "MEDIA_ID2"}]
}

2.获取access_token

在我们调用创建菜单接口之前,必须先获取调用微信接口的access_tokenaccess_token是公众号的全局唯一接口调用凭据,公众号调用各接口时都需使用access_token。开发者需要进行妥善保存。access_token的存储至少要保留512个字符空间。access_token的有效期目前为2个小时,需定时刷新,重复获取将导致上次获取的access_token失效

公众平台的API调用所需的access_token的使用及生成方式说明:

  • 建议公众号开发者使用中控服务器统一获取和刷新access_token,其他业务逻辑服务器所使用的access_token均来自于该中控服务器,不应该各自去刷新,否则容易造成冲突,导致access_token覆盖而影响业务;
  • 目前access_token的有效期通过返回的expire_in来传达,目前是7200秒之内的值。中控服务器需要根据这个有效时间提前去刷新新access_token。在刷新过程中,中控服务器可对外继续输出的老access_token,此时公众平台后台会保证在5分钟内,新老access_token都可用,这保证了第三方业务的平滑过渡;
  • access_token的有效时间可能会在未来有调整,所以中控服务器不仅需要内部定时主动刷新,还需要提供被动刷新access_token的接口,这样便于业务服务器在API调用获知access_token已超时的情况下,可以触发access_token的刷新流程。
  • 对于可能存在风险的调用,在开发者进行获取 access_token调用时进入风险调用确认流程,需要用户管理员确认后才可以成功获取。具体流程为:开发者通过某IP发起调用->平台返回错误码[89503]并同时下发模板消息给公众号管理员->公众号管理员确认该IP可以调用->开发者使用该IP再次发起调用->调用成功。如公众号管理员第一次拒绝该IP调用,用户在1个小时内将无法使用该IP再次发起调用,如公众号管理员多次拒绝该IP调用,该IP将可能长期无法发起调用。平台建议开发者在发起调用前主动与管理员沟通确认调用需求,或请求管理员开启IP白名单功能并将该IP加入IP白名单列表。

公众号和小程序均可以使用AppID和AppSecret调用本接口来获取access_token。AppID和AppSecret可在“微信公众平台-开发-基本配置”页中获得(需要已经成为开发者,且帐号没有异常状态)。**调用接口时,请登录“微信公众平台-开发-基本配置”提前将服务器IP地址添加到IP白名单中,否则将无法调用成功。**小程序无需配置IP白名单。

获取access_token需要调用的接口如下

https请求方式: GET https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET

参数是否必须说明
grant_type获取access_token填写client_credential
appid公众号唯一凭证,注册成功后由微信提供
secret公众号唯一凭证密钥,注册成功后由微信提供

正常情况下,微信会返回下述JSON数据包给公众号:

{"access_token":"ACCESS_TOKEN","expires_in":7200}
参数说明
access_token获取到的凭证
expires_in凭证有效时间,单位:秒

错误时微信会返回错误码等信息,JSON数据包示例如下(该示例为AppID无效错误):

{"errcode":40013,"errmsg":"invalid appid"}
返回码说明
-1系统繁忙,此时请开发者稍候再试
0请求成功
40001AppSecret错误或者AppSecret不属于这个公众号,请开发者确认AppSecret的正确性
40002请确保grant_type字段值为client_credential
40164调用接口的IP地址不在白名单中,请在接口IP白名单中进行设置。(小程序及小游戏调用不要求IP地址在白名单内。)
89503此IP调用需要管理员确认,请联系管理员
89501此IP正在等待管理员确认,请联系管理员
8950624小时内该IP被管理员拒绝调用两次,24小时内不可再使用该IP调用
895071小时内该IP被管理员拒绝调用一次,1小时内不可再使用该IP调用

在Controller中创建获取access_token的方法,获取成功后将其保存到redis中

@GetMapping("getAccessToken")
public String getAccessToken(){String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + APPID +"&secret=" + APPSECRET;// 利用hutool的http工具类请求获取access_tokenString result = HttpUtil.get(url);// 将结果解析为jsonJSONObject jsonObject = JSONUtil.parseObj(result);// 获取access_tokenString accessToken = jsonObject.getStr("access_token");if (!StringUtils.isEmpty(accessToken)){// 将access_token存入redisstringRedisTemplate.opsForValue().set("access_token", accessToken);}return accessToken;
}

3.创建自定义菜单

在Controller中新增方法,发送创建菜单的请求

@GetMapping("createMenu")
public String createMenu(){// 从redis中取出access_tokenString accessToken = stringRedisTemplate.opsForValue().get("access_token");String url = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=" + accessToken;// 创建菜单的请求体String body = "{\n" +"     \"button\":[\n" +"     {\t\n" +"          \"type\":\"click\",\n" +"          \"name\":\"位置\",\n" +"          \"key\":\"button_location\"\n" +"      }]}";return HttpUtil.post(url, body);
}

发送请求后返回结果

{"errcode":0,"errmsg":"ok"}

创建菜单后效果如下

发送模板消息

官方文档:https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Template_Message_Interface.html

在我们的生活中,无论是微商城消费,还是日常生活消费,都可能收到这种提示,比如订单通知,快递状态通知,银行卡支付通知,都属于业务通知,很多公众号也都实现了这种功能,当触发了某种行为或状态改变,就会发送这么一个消息给你,因为这种消息都是按照一定的的格式来编辑,所以也叫模板消息

认证后的服务号才可以申请模板消息的使用权限并获得该权限,否则就只能使用测试号

我们要发送模板消息,第一步是需要创建一个模板,有了模板之后,我们才能填充内容来进行发送。创建模板不需要调用接口,在公众号后台即可设置

现在我们来按照下面案例来新建一个模板。但是模板的内容是有一定的规则的,不能随便添加:

  • 测试模板的模板ID仅用于测试,不能用来给正式帐号发送模板消息
  • 为方便测试,测试模板可任意指定内容,但实际上正式帐号的模板消息,只能从模板库中获得
  • 需为正式帐号申请新增符合要求的模板,需使用正式号登录公众平台,按指引申请
  • 模板内容可设置参数(模板标题不可),供接口调用时使用,参数需以{{开头,以.DATA}}结尾

保存之后,微信会给该模板分配一个ID,待我们要发送模板消息的时候就需要用到这个ID了

发送模板消息需要如下请求:

http请求方式: POST https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN

请求体示例如下

{"touser":"OPENID","template_id":"ngqIpbwh8bUfcSsECmogfXcV14J0tQlEpBO27izEYtY","url":"http://weixin.qq.com/download",  "miniprogram":{"appid":"xiaochengxuappid12345","pagepath":"index?foo=bar"},          "data":{"goodsName":{"value":"巧克力","color":"#173177"},"price": {"value":"39.8元","color":"#173177"},"time": {"value":"2014年9月22日","color":"#173177"},"remark":{"value":"欢迎再次购买!","color":"#173177"}}
}
参数是否必填说明
touser接收者openid
template_id模板ID
url模板跳转链接(海外帐号没有跳转能力)
miniprogram跳小程序所需数据,不需跳小程序可不用传该数据
appid所需跳转到的小程序appid(该小程序appid必须与发模板消息的公众号是绑定关联关系,暂不支持小游戏)
pagepath所需跳转到小程序的具体页面路径,支持带参数,(示例index?foo=bar),要求该小程序已发布,暂不支持小游戏
data模板数据
color模板内容字体颜色,不填默认为黑色

在调用模板消息接口后,会返回JSON数据包。正常时的返回JSON数据包示例:

{"errcode":0,"errmsg":"ok","msgid":200228332
}

http://chatgpt.dhexx.cn/article/t8bZrvtx.shtml

相关文章

如何建立一个微信公众号

如何建立一个微信公众号 一、定位 首先你要对公众号有定位&#xff0c;比如美妆&#xff0c;时尚&#xff0c;校园生活&#xff0c;好物分享等&#xff0c;每日推荐适合大学生的电影&#xff0c;连续剧&#xff0c;推荐大学生日常会做的好事。 二、准备工作 在建立一个微信…

公众号 菜单 代码 php,如何使用Vue.js实现微信公众号菜单编辑器(案例代码)

这次给大家带来如何使用Vue.js实现微信公众号菜单编辑器(案例代码)&#xff0c;使用Vue.js实现微信公众号菜单编辑器的注意事项有哪些&#xff0c;下面就是实战案例&#xff0c;一起来看一下。 实现菜单删除方法 在vue实例中添加删除菜单方法&#xff0c;根据选中的菜单级别和索…

在微信公众号中写html代码吗,微信公众号内容如何利用html编辑?

微信公众号内容如何利用html编辑?以下是小编整理的怎么利用html代码去更换微信公众号里的内容&#xff0c;有需要的朋友们请往下看具体怎么去操作的。以下内容供大家参考。 登录微信公众号 点击左侧分类的“素材管理”&#xff0c;在出现的页面中选择“图片” 点击右侧的“本地…

微信公众号使用Chrome插件:Markdown Nice优化微信公众号排版教程

Markdown Nice 是一个为了解决微信公众号排版而生的 Markdown 编辑器&#xff0c;当前有在线编辑器和 Chrome 插件 2 种产品形态。 下面介绍Chrome 插件&#xff1a;Markdown Nice 一、下载和安装Markdown Nice 1.从 墨滴 网站下载mdnice谷歌浏览器插件&#xff0c;如下图&a…

微信公众号的html5界面用什么软件,微信公众号编辑排版用什么软件(推荐这4款编辑器)...

做 但是市面上的公众号排版编辑器层出不穷&#xff0c;到底哪一款最好用呢&#xff1f;下面就带来主流公众号排版编辑器的对比&#xff0c;看下最受欢迎的编辑器中&#xff0c;哪款最好用吧。 1、秀米编辑器 秀米编辑器可以说是一款比较受欢迎的公众号排版编辑器了&#xff0c;…

java微信公众号图文消息编辑器,如何使用微信公众号自带的编辑器做出简洁舒适的图文排版...

所谓云想衣裳花想容&#xff0c;写文章也讲内容与形式&#xff0c;做微信公众号、新媒体、自媒体&#xff0c;光生产内容还不够&#xff0c;编辑排版也非常重要。 一个简洁、美观、使读者看起来舒适的排版能更好地抓住读者的眼球&#xff0c;愉悦读者的眼睛&#xff0c;才能更好…

微信公众平台菜单编辑php,Vue.js实现微信公众号菜单编辑器步骤详解(上)

这次给大家带来Vue.js实现微信公众号菜单编辑器步骤详解(上)&#xff0c;Vue.js实现微信公众号菜单编辑器的注意事项有哪些&#xff0c;下面就是实战案例&#xff0c;一起来看一下。 学习一段时间Vue.js&#xff0c;于是想尝试着做一个像微信平台里那样的菜单编辑器&#xff0c…

微信文章编辑的html在哪里,微信公众号的文章编辑界面在哪里?怎么编辑排版? | 微信公众号指南...

今天给大家介绍公众号文章编辑页面在哪里&#xff0c;怎么编辑排版&#xff0c;怎么推送文章。 申请了微信公众号后怎么发布文章&#xff1f;公众号的文章编辑页面在哪里?部分刚接触公众号运营的小伙伴是不太了解公众号后台功能的&#xff0c;今天就给大家介绍公众号文章编辑页…

微信公众号编辑底部自定义菜单解决方案

微信公众号编辑底部自定义菜单解决方案 1.需求背景 最近开发公众号项目&#xff0c;关于公众号里面底部的菜单栏设置一般常用有两种方法。 1&#xff0c;是进入公众号后台&#xff0c;找到自定义菜单&#xff0c;点击后进入编辑页面&#xff0c;进行编辑即可。2&#xff0c;是…

如何在微信公众号编辑器发布免费好看的排版内容

闲谈 最近很久没更新硬核的技术内容&#xff0c;也没发布最近人工智能的大动作文章&#xff0c;总感觉有点跟这个社区脱节的样子&#xff0c;不过没关系&#xff0c;经历了痛苦的一个月找工作冲刺后&#xff0c;我悟了&#xff0c;还是混吃等死水文章舒服。 爪巴的知乎文章 …

markdown转微信公众号编辑器

Foxmd&#xff5c;markdown微信公众号编辑器 https://foxmd.cn 支持两端对齐可以调整字间距、行间距、段间距以及文字大小可以设置图片圆角和图片阴影可以设置自动在中英文之间插入一个空格

php+仿微信公众号样式,仿微信公众号富文本编辑器

微信公众号富文本编辑器使用百度ueditor插件为基础加以封装 百度ueditor配置提供替换皮肤,只要添加相应的样式即可(码云代码链接) TIM截图20190404150153.png 以下处理富文本编辑器里面内容是别处复制粘贴而来(如果是微信或者百度的图片资源,有些图片不会显示出来),此时需要我…

程序员的专属微信公众号编辑器:定制 Markdown 转 HTML

原文地址&#xff1a; https://www.fang1688.cn/study-code/3158.html 今天介绍的这款开源项目&#xff1a;cdk8s-markdown-to-html-master 平时我们用微信公众号的编辑器写文章功能比较简陋&#xff0c;主题样式也不美观&#xff0c;最近小编方包找到一款实用的可一键转换&…

微信公众号 Markdown 编辑器

微信公众号文章 Markdown 在线编辑器&#xff0c;使用 markdown 语法创建一篇简介美观大方的微信公众号图文。由于发版本麻烦&#xff0c;和一些功能无法扩展停滞开发了&#xff0c;未来不再开发 Chrome 的插件(暂存在 chrome 分支)&#xff0c;通过 web 版本定制更丰富的功能。…

4款微信公众号编辑器,哪个最好用?

微信公众号的文案编辑一定都有这样的感受&#xff1a;微信后台的编辑器功能太少了&#xff0c;想要做出一篇样式精美、内容丰富的文章&#xff0c;非常有必要找到一款好用的微信编辑器。 市面上的微信编辑器那么多&#xff0c;哪一款最好用呢&#xff1f;今天我们就一起来对比分…

人工智能语音如何实现?

语音识别是以语音为研究对象,通过语音信号处理和模式识别让机器自动识别和理解人类口述的语言。语音识别技术就是让机器通过识别和理解过程把语音信号转变为相应的文本或命令的高技术。语音识别是一门涉及面很广的交叉学科,它与声学、语音学、语言学、信息理论、模式识别理论…

人工智能之语音识别技术(四)

1. 语音信号基础 1.1 语音信号处理的目的 语音信号处理是一门新兴的边缘科学&#xff0c;它是语音学与数字信号处理两个学科相结合的产物。它和认知科学、心理学、语音学、计算机科学、模式识别和人工智能等学科有着紧密的联系。语音信号处理的目的是要得到某些语音特征参数以…

【第2篇】人工智能(AI)语音测试原理和实践

第1章第1节 人工智能语音测试介绍 本章首先介绍语音的基本概念及语音的产生原理&#xff0c;然后介绍什么是人工智能语音、人工智能语音交互和人工智能语音测试&#xff0c;最后阐述人工智能语音测试的目的和意义&#xff0c;引领大家走入人工智能语音测试的世界。 目录 第1章…

人工智能之语音合成,语音识别

人工智能 此篇是人工智能应用的重点,只用现成的技术不做底层算法,也是让初级程序员快速进入人工智能行业的捷径 目前市面上主流的AI技术提供公司有很多,比如百度,阿里,腾讯,主做语音的科大讯飞,做只能问答的图灵机器人等等 这些公司投入了很大一部分财力物力人力将底层封装,提供…

人工智能:语音合成技术介绍

❤️作者主页&#xff1a;IT技术分享社区 ❤️作者简介&#xff1a;大家好,我是IT技术分享社区的博主&#xff0c;从事C#、Java开发九年&#xff0c;对数据库、C#、Java、前端、运维、电脑技巧等经验丰富。 ❤️个人荣誉&#xff1a; 数据库领域优质创作者&#x1f3c6;&#x…