微信公众平台开发教程Java版.docx
《微信公众平台开发教程Java版.docx》由会员分享,可在线阅读,更多相关《微信公众平台开发教程Java版.docx(70页珍藏版)》请在冰点文库上搜索。
微信公众平台开发教程Java版
微信公众平台开发教程Java版
一、环境准备篇
准备写系列博客,记录下我的微信公众平台学习记录,也为那些摸索中的开发者提供点参考。
希望与大家共同进步。
微信3.0的时候我开始做微信公众账号,那时候没时间研究开发,先用的是编辑者模式,后用开发者模式,托管于第三方。
一直想自己写个服务端来实现个人定制化的需求。
废话不多说,进入正题。
想要开发微信公众平台需要一些环境
一、申请微信公众账号
这个就不用废话了。
附上地址:
现在申请好严格的说,3.0的时候申请都不需要拍照什么的。
友情提示:
1、微信公众账号的名字一旦申请,则不能更改。
取名请慎重!
2、一个身份证只能申请两个公众号
3、公众号分两种:
订阅号和服务号
订阅号可一天群发一次消息,目前不能申请自定义菜单。
发送的消息将显示在“订阅号”文件夹中,适合媒体等提供咨询服务的公众号。
服务号一个月只能群发一条消息,能申请自定义菜单,发送的消息会显示在用户的聊天列表中,并会提醒用户新消息。
适合为用户提供服务的公众号
二、外网服务器
你需要一台外网服务器,来发布你的代码,用于接收处理用户发送的请求。
如果没有的话,也不用担心。
可以使用XXBAE,或者是sinasae,国外比较多的是用google的gae。
googlegae支持的语言很多。
但是在国内经常访问不了,不推荐使用。
XXBae支持java和php(完全免费,XX对于资源方面还是一向很大方的,赞一个,哈哈)
sinasae支持java,php,python(可免费使用半年,收费的,但很便宜)
三、至少会一种语言
java,php,asp,python等,至少得会一样!
接下来的文章中我会用java做事例来做微信公众平台的开发
二、接口配置
微信公众账号申请完成后,默认开启的是编辑模式。
我们需要修改为开发模式。
登陆微信公众平台》功能》高级功能
先关闭编辑模式,再开启开发模式。
申请成为开发者,如果是服务号,需要则会有开发者凭证信息
如图
如果是订阅号,则只显示服务器配置。
下一步就是配置接口服务器了。
在公众平台网站的高级功能–开发模式页,点击“成为开发者”按钮,填写URL和Token,其中URL是开发者用来接收微信服务器数据的接口URL。
(这就是我们开发的程序,并部署到公网上了)
Token官网描述:
可由开发者任意填写,用作生成签名(该Token会和接口URL中包含的Token进行比对,从而验证安全性)。
总之就是你的程序里面写的token和这里填入的token要一致。
还没有url和token?
首先需要新建一个javaweb工程。
接下来就要看看验证url和token了。
下面是官网的描述,已经写的很清楚了
核心实现方式就是将三个参数排序,拼接成字符串进行sha1加密,然后与signature比较
官网也给了实例,是php的,我们只需要装换成java就可以了。
privatefunctioncheckSignature()
{
$signature=$_GET["signature"];
$timestamp=$_GET["timestamp"];
$nonce=$_GET["nonce"];
$token=TOKEN;
$tmpArr=array($token,$timestamp,$nonce);
sort($tmpArr);
$tmpStr=implode($tmpArr);
$tmpStr=sha1($tmpStr);
if($tmpStr==$signature){
returntrue;
}else{
returnfalse;
}
}
java代码我的WeixinController类
我的项目架构是基于spring3.0的,用到了注解。
当get请求的时候会执行get方法,post请求的时候会执行post方法,分别来处理不同的请求,各位也可用servlet等去实现,原理都一样
packagecom.ifp.weixin.controller;
importjava.io.IOException;
importjava.io.PrintWriter;
importjava.io.UnsupportedEncodingException;
importjavax.annotation.Resource;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
importorg.springframework.stereotype.Controller;
importorg.springframework.web.bind.annotation.RequestMapping;
importorg.springframework.web.bind.annotation.RequestMethod;
importcom.ifp.weixin.biz.core.CoreService;
importcom.ifp.weixin.util.SignUtil;
@Controller
@RequestMapping("/weixinCore")
publicclassWeixinController{
@Resource(name="coreService")
privateCoreServicecoreService;
@RequestMapping(method=RequestMethod.GET)
publicvoidget(HttpServletRequestrequest,HttpServletResponseresponse){
//微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。
Stringsignature=request.getParameter("signature");
//时间戳
Stringtimestamp=request.getParameter("timestamp");
//随机数
Stringnonce=request.getParameter("nonce");
//随机字符串
Stringechostr=request.getParameter("echostr");
PrintWriterout=null;
try{
out=response.getWriter();
//通过检验signature对请求进行校验,若校验成功则原样返回echostr,否则接入失败
if(SignUtil.checkSignature(signature,timestamp,nonce)){
out.print(echostr);
}
}catch(IOExceptione){
e.printStackTrace();
}finally{
out.close();
out=null;
}
}
@RequestMapping(method=RequestMethod.POST)
publicvoidpost(HttpServletRequestrequest,HttpServletResponseresponse){
//暂时空着,在这里可处理用户请求
}
}
上面类中用到了SignUtil类
packagecom.ifp.weixin.util;
importjava.security.MessageDigest;
importjava.security.NoSuchAlgorithmException;
importjava.util.Arrays;
importcom.ifp.weixin.constant.Constant;
/**
*验证签名
*
*/
publicclassSignUtil{
/**
*验证签名
*@paramsignature
*@paramtimestamp
*@paramnonce
*@return
*/
publicstaticbooleancheckSignature(Stringsignature,Stringtimestamp,Stringnonce){
String[]arr=newString[]{Constant.TOKEN,timestamp,nonce};
//将token、timestamp、nonce三个参数进行字典排序
Arrays.sort(arr);
StringBuildercontent=newStringBuilder();
for(inti=0;icontent.append(arr[i]);
}
MessageDigestmd=null;
StringtmpStr=null;
try{
md=MessageDigest.getInstance("SHA-1");
//将三个参数字符串拼接成一个字符串进行sha1加密
byte[]digest=md.digest(content.toString().getBytes());
tmpStr=byteToStr(digest);
}catch(NoSuchAlgorithmExceptione){
e.printStackTrace();
}
content=null;
//将sha1加密后的字符串可与signature对比
returntmpStr!
=null?
tmpStr.equals(signature.toUpperCase()):
false;
}
/**
*将字节数组转换为十六进制字符串
*
*@parambyteArray
*@return
*/
privatestaticStringbyteToStr(byte[]byteArray){
StringstrDigest="";
for(inti=0;istrDigest+=byteToHexStr(byteArray[i]);
}
returnstrDigest;
}
/**
*将字节转换为十六进制字符串
*
*@parammByte
*@return
*/
privatestaticStringbyteToHexStr(bytemByte){
char[]Digit={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
char[]tempArr=newchar[2];
tempArr[0]=Digit[(mByte>>>4)&0X0F];
tempArr[1]=Digit[mByte&0X0F];
Strings=newString(tempArr);
returns;
}
}
我们看到 checkSignature这个方法里使用到了Constant.TOKEN,这个token,我声明的一个常量。
要与微信配置接口里面的token值一样
/**
*与接口配置信息中的Token要一致
*/
publicstaticStringTOKEN="infopower";
也贴上web.xml的配置,我的后缀是.html的请求都交给DispatcherServlet了。
xmlversion="1.0"encoding="UTF-8"?
>
xmlns:
xsi="http:
//www.w3.org/2001/XMLSchema-instance"
xsi:
schemaLocation="
weixinHelp
contextConfigLocation
classpath:
/applicationContext.xml
log4jConfigLocation
classpath:
/properties/log4j.properties
org.springframework.web.util.Log4jConfigListener
encodingFilter
org.springframework.web.filter.CharacterEncodingFilter
encoding
UTF-8
encodingFilter
/*
spring容器的监听器
org.springframework.web.context.ContextLoaderListener
action
org.springframework.web.servlet.DispatcherServlet
action
*.html
index.jsp
我们的代码已经写完了,访问请求地址试试
什么都没有显示,看看后台
报空指针异常
别担心,我们的代码没问题。
因为直接访问地址,默认是get请求,而什么参数都没有传给后台,当然会报空指针
前台没有异常,是因为我做了异常处理。
ok
接下来就是把代码打成war包发布到外网。
然后填入相应的url和token,接口的配置就完成了。
注意1:
一定要发布war包到外网,配置外网的url,有些开发者配置的是ip是localhost,那肯定是不行的啦。
如果没有外网环境,请看我的第一篇,环境准备,里面有介绍可以使用XXbae
注意2:
开发模式一定要开启,不然配置了url和token也没用,我犯过这个错,嘿嘿。
三、消息接收和发送
前面两章已经介绍了如何接入微信公众平台,这一章说说消息的接收和发送
可以先了解公众平台的消息api接口(接收消息,发送消息)
接收消息
当普通微信用户向公众账号发消息时,微信服务器将POST消息的XML数据包到开发者填写的URL上。
接收的消息类型有6种,分别为:
∙1 文本消息
∙2 图片消息
∙3 语音消息
∙4 视频消息
∙5 地理位置消息
∙6 链接消息
可以根据官方的api提供的字段建立对应的实体类
如:
文本消息
有很多属性是所有消息类型都需要的,可以把这些信息提取出来建立一个基类
packagecom.ifp.weixin.entity.Message.req;
/**
*消息基类(用户->公众帐号)
*
*/
publicclassBaseMessage{
/**
*开发者微信号
*/
privateStringToUserName;
/**
*发送方帐号(一个OpenID)
*/
privateStringFromUserName;
/**
*消息创建时间(整型)
*/
privatelongCreateTime;
/**
*消息类型text、image、location、link
*/
privateStringMsgType;
/**
*消息id,64位整型
*/
privatelongMsgId;
publicStringgetToUserName(){
returnToUserName;
}
publicvoidsetToUserName(StringtoUserName){
ToUserName=toUserName;
}
publicStringgetFromUserName(){
returnFromUserName;
}
publicvoidsetFromUserName(StringfromUserName){
FromUserName=fromUserName;
}
publiclonggetCreateTime(){
returnCreateTime;
}
publicvoidsetCreateTime(longcreateTime){
CreateTime=createTime;
}
publicStringgetMsgType(){
returnMsgType;
}
publicvoidsetMsgType(StringmsgType){
MsgType=msgType;
}
publiclonggetMsgId(){
returnMsgId;
}
publicvoidsetMsgId(longmsgId){
MsgId=msgId;
}
}
接收的文本消息
packagecom.ifp.weixin.entity.Message.req;
/**
*文本消息
*/
publicclassTextMessageextendsBaseMessage{
/**
*回复的消息内容
*/
privateStringContent;
publicStringgetContent(){
returnContent;
}
publicvoidsetContent(Stringcontent){
Content=content;
}
}
接收的图片消息
packagecom.ifp.weixin.entity.Message.req;
publicclassImageMessageextendsBaseMessage{
privateStringpicUrl;
publicStringgetPicUrl(){
returnpicUrl;
}
publicvoidsetPicUrl(StringpicUrl){
this.picUrl=picUrl;
}
}
接收的链接消息
packagecom.ifp.weixin.entity.Message.req;
publicclassLinkMessageextendsBaseMessage{
/**
*消息标题
*/
privateStringTitle;
/**
*消息描述
*/
privateStringDescription;
/**
*消息链接
*/
privateStrin