微信公众平台开发

1.开启微信回调模式(servlet doGet):
1)使用微信的加密解密包验证url,url参数为corpid、timpstamp、nonceStr


2.截获用户发送的消息(serlvet doPost):
用户向微信服务器发送消息、微信服务器截获消息后进行加密、微信服务器将加密后的消息发送到我们的应用服务器
1)按微信消息格式封装消息对象;
2)解密消息
3)使用dom4j解析消息
4)根据messageType处理消息


3.微信定时推送个人待办事项:
1)使用spring quartz实现定时。
SchedulerFactoryBean、CronTriggerFactoryBean、
JobDetailFactoryBean
2)根据权限组corpid、secret获取微信令牌
注:①、此处需实现X509TrustManager接口
因为客户端要信任服务器端证书有两种方式,一是将服务器端的证书导入到客户端TrustStroe文件中,二是实现X509TrustManager接口即可;
②、封装了一个方法,调用微信url返回jsonObject或向微信写入信息
3)xml、JSONObject、Object的相互转换
获取所有已关注成员列表xml,并转化为用户对象
Object转换为xml后调用微信发送消息接口url


4.微信菜单链接
1)OAuth2.0鉴权实现
原因:click只能返回图文消息后传递用户信息,直接链接无法传递用户信息,OAuth直接跳转页面并返回用户信息
①配置微信鉴权链接,链接包含跳转链接地址,该地址需经过一次encode
②通过配置的servlet得到code,根据code和token获得用户信息
③跳转页面

 

coreServlet:

package weixin.qy.servlet;


import java.io.IOException;
import java.io.PrintWriter;
import java.util.Map;


import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


import org.apache.log4j.Logger;
import org.dom4j.DocumentException;


import com.thoughtworks.xstream.XStream;


import weixin.common.util.AesException;
import weixin.common.util.SingletonObject;
import weixin.common.util.WXBizMsgCrypt;
import weixin.common.util.WeiXinParam;
import weixin.core.busi.CoreService;
import weixin.message.Util.BackMessage;
import weixin.message.Util.EncryptMessage;
import weixin.message.Util.MessageUtil;
import weixin.common.util.XMLParse;
public class CoreServlet extends HttpServlet{


private static final long serialVersionUID = 1L;
private Logger log=Logger.getLogger(CoreServlet.class);
public void doGet(HttpServletRequest request,HttpServletResponse response) throws IOException{
String msgSignature=request.getParameter("msg_signature");
String timeStamp=request.getParameter("timestamp");
String nonce=request.getParameter("nonce");
String echoStr=request.getParameter("echostr");
PrintWriter out=response.getWriter();
String decryptStr;
try {
WXBizMsgCrypt wXBizMsgCrypt=SingletonObject.getWXBizMsgCryptInstance();
log.info("************msg_signature:"+msgSignature+";timeStamp:"+timeStamp+";nonce:"+nonce+";echoStr:"+echoStr+"************");
decryptStr = wXBizMsgCrypt.VerifyURL(msgSignature, timeStamp, nonce, echoStr);
log.info("************decryptStr:"+decryptStr+"************");
out.print(decryptStr);
} catch (AesException e) {
log.info("************开启回调模式失败************");
e.printStackTrace();
}
out.close();
out=null;
}
public void doPost(HttpServletRequest request,HttpServletResponse response) throws IOException{
//将请求、响应编码均设置为UTF-8,防止中文乱码
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
//接收参数:微信加密签名、时间戳、随机数
String msgSignature=request.getParameter("msg_signature");
String timeStamp=request.getParameter("timestamp");
String nonce=request.getParameter("nonce");
String echoStr=request.getParameter("echostr");
WXBizMsgCrypt wXBizMsgCrypt;
PrintWriter out=response.getWriter();
try {
wXBizMsgCrypt = SingletonObject.getWXBizMsgCryptInstance();
Map<String,String> requestMap=MessageUtil.parseXml(request);
//企业号id
String toUserName=requestMap.get("ToUserName");
//应用id
String agentID=requestMap.get("AgentID");
//加密消息
String encryptMessage=requestMap.get("Encrypt");
BackMessage backMessage=new BackMessage();
backMessage.setAgentID(agentID);
backMessage.setEncrypt(encryptMessage);
backMessage.setToUserName(toUserName);
XStream xStream=new XStream();
xStream.alias("xml", BackMessage.class);
String postData=xStream.toXML(backMessage);
log.info("============加密的postData:"+postData+"============");
log.info("============加密消息:"+encryptMessage+"============");
//解密后的消息
String decryptMessage=wXBizMsgCrypt.DecryptMsg(msgSignature, timeStamp, nonce, postData);
log.info("============解密后的消息:"+decryptMessage+"============");
String respXml=CoreService.processRequest(msgSignature, timeStamp, nonce,decryptMessage);
log.info("============返回的消息:"+respXml+"============");
// out.print(respXml);
} catch (AesException e) {
log.error("************aes解密失败************");
e.printStackTrace();
} catch (DocumentException e) {
e.printStackTrace();
}
out.close();
out=null;
}
}

 

 

coreService:

package weixin.core.busi;


import java.net.URLEncoder;
import java.util.Date;
import java.util.List;
import java.util.Map;




import org.apache.log4j.Logger;
import org.dom4j.DocumentException;


import weixin.access.token.AccessToken;
import weixin.access.token.MisApp;
import weixin.addressbook.util.AddressBookUtil;
import weixin.addressbook.util.WeixinDepartment;
import weixin.common.util.AesException;
import weixin.common.util.SingletonObject;
import weixin.common.util.WXBizMsgCrypt;
import weixin.common.util.WeiXinParam;
import weixin.message.Util.EncryptMessage;
import weixin.message.Util.MessageUtil;
import weixin.response.message.TextMessage;
import weixin.response.message.ViewMenu;
public class CoreService {
public static Logger log=Logger.getLogger(CoreService.class);
public static String processRequest(String msgSignature,String timeStamp,String nonce,String xmltext) throws AesException{
//加密后的xml消息
String respXmlEnc=null;
//XML格式的消息数据
String respXml=null;
//默认返回的文本消息内容
String respContent="未知的消息类型!";
//解析接收到的消息
try {
Map<String,String> requestMap=SingletonObject.getXMLParseDom4jInstance().parseXML(xmltext);
//发送方的账号
String fromUserName=requestMap.get("FromUserName");
//开发者微信号
String toUserName=requestMap.get("ToUserName");
//消息类型
String msgType=requestMap.get("MsgType");


 
log.info("============消息类型:MsgType:"+msgType+"============");
//根据消息类型返回消息
if(msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_TEXT)){
String requestContent=requestMap.get("Content");
log.info("============消息内容:"+requestContent+"============");
StringBuffer stringBuffer=new StringBuffer();
if(requestContent.equals("部门")){
log.info("============进入部门列表解析程序:"+"============");
//获取accessToken
MisApp misApp=new MisApp();
log.info("============MisApp应用的相关值:corpid:"+misApp.getCorpid()+";corpSecret:"+misApp.getCorpsecret());
AccessToken accessToken=MessageUtil.getAccessToken(misApp);
log.info("============service accessToken:"+accessToken+"============");
log.info("============access_token:"+accessToken.getAccess_token()+"============");
List<WeixinDepartment> weixinDepList=AddressBookUtil.getAllWeinxinDep(accessToken.getAccess_token());

if(weixinDepList!=null){
for(WeixinDepartment dep:weixinDepList){
stringBuffer.append("部门id:"+dep.getId()+",部门名称:"+dep.getName()+",父部门id:"+dep.getParentid()+",部门排序:"+dep.getOrder()+"\n");
}
}
}
if(!stringBuffer.toString().equals("")){
respContent=stringBuffer.toString();
}else{
respContent="您发送的是文本消息!";
}
}else if(msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_IMAGE)){
respContent="您发送的是图片消息!";
}else if(msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_VOICE)){
respContent="您发送的是语音消息!";
}else if(msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_VIDEO)){
respContent="您发送的是视频消息!";
}else if(msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_LOCATION)){
respContent="您发送的是地理位置消息!";
}else if(msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_LINK)){
respContent="您发送的是链接消息!";
}else if(msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_EVENT)){
//事件类型
String eventType=requestMap.get("Event");
log.info("============事件响应eventType"+eventType+"==========");
if(eventType.equals(MessageUtil.EVENT_TYPE_SUBSCRIBE)){
respContent="感谢您的关注!";
}else if(eventType.equals(MessageUtil.EVENT_TYPE_CLICK)){
//自定义菜单
respContent="自定义菜单click!";
respContent="自定义菜单view!";
//获取菜单EventKey
String eventKey=requestMap.get("EventKey");
//获取AgentID
String agentID=requestMap.get("AgentID");
ViewMenu viewMenu=new ViewMenu();

viewMenu.setToUserName(fromUserName);
viewMenu.setFromUserName(toUserName);
viewMenu.setCreateTime(new Date().getTime());
viewMenu.setMsgType(MessageUtil.REQ_MESSAGE_TYPE_EVENT);
viewMenu.setEvent(eventType.toUpperCase());
viewMenu.setEventKey(eventKey);
viewMenu.setAgentID(Integer.parseInt(agentID));
respXml=MessageUtil.messageToXml(viewMenu);
}else if(eventType.equals(MessageUtil.EVENT_TYPE_VIEW)){
//菜单链接事件
//获取菜单EventKey
String eventKey=requestMap.get("EventKey");
//获取应用id
String agentId=requestMap.get("AgentID");

}else if(eventType.equals(MessageUtil.EVENT_TYPE_UNSUBSCRIBE)){

}else if(eventType.equals(MessageUtil.EVENT_TYPE_UNSUBSCRIBE)){

}
}
// //以文本消息回复
// TextMessage textMessage=new TextMessage();
// textMessage.setToUserName(fromUserName);
// textMessage.setFromUserName(toUserName);
// textMessage.setCreateTime(new Date().getTime());
// textMessage.setMsgType(MessageUtil.RESP_MESSAGE_TYPE_TEXT);
// textMessage.setContent(respContent);
//
// respXml=MessageUtil.messageToXml(textMessage);

log.info("============文本回复消息内容:"+respXml+"============");
/*EncryptMessage encryptObj=new EncryptMessage();
encryptObj.setMsgSignature(msgSignature);
encryptObj.setNonce(nonce);
encryptObj.setTimeStamp(timeStamp);
encryptObj.setEncrypt(respXml);

respXml=MessageUtil.messageToXml(encryptObj);
log.info("============被动响应消息加密前:"+respXml+"============");*/
WXBizMsgCrypt wXBizMsgCrypt = SingletonObject.getWXBizMsgCryptInstance();
respXmlEnc=wXBizMsgCrypt.EncryptMsg(respXml, timeStamp, nonce);
} catch (DocumentException e) {
e.printStackTrace();
}
return respXmlEnc;
}
public static void main(String args[]){
String redirect_uri=WeiXinParam.REDIRECT_URI;
redirect_uri=URLEncoder.encode(redirect_uri);
System.out.println(redirect_uri);
}
}

 

//从微信服务器获取数据等

package weixin.message.Util;


import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Writer;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.servlet.http.HttpServletRequest;


import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.json.JSONObject;


import org.apache.log4j.Logger;
import org.dom4j.*;
import org.dom4j.io.SAXReader;


import weixin.access.token.AccessToken;
import weixin.access.token.PrivilegeStr;
import weixin.common.util.MyX509TrustManager;
import weixin.response.message.Article;
import weixin.response.message.NewsMessage;
import weixin.response.message.SendTextMessage;
import weixin.response.message.TextContent;
import weixin.response.message.TextMessage;




import javax.net.ssl.SSLContext;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.io.xml.*;
import com.thoughtworks.xstream.core.util.QuickWriter;


public class MessageUtil {
//请求消息类型:文本
public static final String REQ_MESSAGE_TYPE_TEXT="text";
//请求消息类型:图片
public static final String REQ_MESSAGE_TYPE_IMAGE="image";
//请求消息类型:语音
public static final String REQ_MESSAGE_TYPE_VOICE="voice";
//请求消息类型:视频
public static final String REQ_MESSAGE_TYPE_VIDEO="video";
//请求消息类型:地理位置
public static final String REQ_MESSAGE_TYPE_LOCATION="location";
//请求消息类型:链接
public static final String REQ_MESSAGE_TYPE_LINK="link";

//请求消息类型:事件推送
public static final String REQ_MESSAGE_TYPE_EVENT="event";

//事件类型:订阅
public static final String EVENT_TYPE_SUBSCRIBE="subscribe";
//事件类型:取消订阅
public static final String EVENT_TYPE_UNSUBSCRIBE="unsubscribe";
//事件类型:扫描带参数二维码
public static final String EVENT_TYPE_SCAN="scan";
//事件类型:上报地理位置
public static final String EVENT_TYPE_LOCATION="location";
//事件类型:自定义菜单
public static final String EVENT_TYPE_CLICK="click";
public static final String EVENT_TYPE_VIEW="view";
//响应消息类型:文本
public static final String RESP_MESSAGE_TYPE_TEXT="text";
//响应消息类型:图片
public static final String RESP_MESSAGE_TYPE_IMAGE="image";
//响应消息类型:语音
public static final String RESP_MESSAGE_TYPE_VOICE="voice";
//响应消息类型:视频
public static final String RESP_MESSAGE_TYPE_VIDEO="video";
//响应消息类型:音乐
public static final String RESP_MESSAGE_TYPE_MUSIC="music";
//响应消息类型:图文
public static final String RESP_MESSAGE_TYPE_NEWS="news";
//token url
public static String token_url="https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=MyCorpid&corpsecret=MySecrect";
public static Logger log=Logger.getLogger(MessageUtil.class);
//解析消息
public static Map<String ,String> parseXml(HttpServletRequest request) throws IOException, DocumentException{
Map<String,String> map=new HashMap<String,String>();
InputStream inputStream=request.getInputStream();
SAXReader reader=new SAXReader();
Document document=reader.read(inputStream);
Element root=document.getRootElement();
@SuppressWarnings("unchecked")
List<Element> elementList=root.elements();
for(Element e:elementList){
map.put(e.getName(), e.getText());
}
inputStream.close();
inputStream=null;
return map;
}
//扩展xstream使其支持CDATA
private static XStream xstream=new XStream(new XppDriver(){
public HierarchicalStreamWriter createWriter(Writer out){
return new PrettyPrintWriter(out){
boolean cdata=true;
public void startNode(String name,Class clazz){
super.startNode(name,clazz);
}
protected void writeText(QuickWriter writer,String text){
if(cdata){
writer.write("<![CDATA[");
writer.write(text);
writer.write("]]>");
}else{
writer.write(text);
}
}
};
}
});
//封装消息
public static String messageToXml(Object obj){
xstream.alias("xml", obj.getClass());
return xstream.toXML(obj);
}
//封装图文消息
public static String messageToXml(NewsMessage newsMessage){
xstream.alias("xml",newsMessage.getClass());
xstream.alias("item", new Article().getClass());
return xstream.toXML(newsMessage);
}
//封装图文消息
public static String sendMessageToXml(SendTextMessage sendTextMessage){
xstream.alias("xml",sendTextMessage.getClass());
xstream.aliasField("text", sendTextMessage.getClass(),"textContent");
return xstream.toXML(sendTextMessage);
}
//获取应用access_token
public static AccessToken getAccessToken(PrivilegeStr privilegeStr){
AccessToken accessToken=null;
//先从内存读取accessToken,如果没有找到则从微信服务器获取
AccessToken ehcacheAccessToken=getEhcacheAccessToken();
if(ehcacheAccessToken==null){
log.info("============privilegeStr.corpid:"+privilegeStr.getCorpid()+";privilegeStr.corpsecret:"+privilegeStr.getCorpsecret()+"============");
String requestUrl=token_url.replace("MyCorpid", privilegeStr.getCorpid()).replace("MySecrect", privilegeStr.getCorpsecret());
log.info("============requestUrl:"+requestUrl+"============");
JSONObject jsonObject=httpsRequest(requestUrl,"GET",null);
accessToken=new AccessToken();
log.info("============jsonObject.getString(\"access_token\"):"+jsonObject.getString("access_token")+";jsonObject.getInt(\"expires_in\"):"+jsonObject.getInt("expires_in")+"============");
accessToken.setAccess_token(jsonObject.getString("access_token"));
accessToken.setExpires_in(jsonObject.getInt("expires_in"));
log.info("============accessToken:"+accessToken.getAccess_token()+";expires:"+accessToken.getExpires_in()+"==========");
Cache cache=getEhcacheCache("weixinCache");
net.sf.ehcache.Element element=new net.sf.ehcache.Element("AccessToken",accessToken);
cache.put(element);
}else{
accessToken=ehcacheAccessToken;
log.info("============从内存获取的accessToken:"+accessToken.getAccess_token()+"============");
}
return accessToken;
}
//获取JSONObject对象
public static JSONObject httpsRequest(String requestUrl,String requestMethod,String outputStr){
JSONObject jsonObject=null;
try {
TrustManager[] tm={new MyX509TrustManager()};
SSLContext sslContext=SSLContext.getInstance("SSL","SunJSSE");
sslContext.init(null,  tm, new java.security.SecureRandom());
//从SSLContext中得到SSLSocketFactory
SSLSocketFactory ssf=sslContext.getSocketFactory();
URL url=new URL(requestUrl);
HttpsURLConnection conn=(HttpsURLConnection) url.openConnection();
conn.setSSLSocketFactory(ssf);

conn.setDoInput(true);
conn.setDoOutput(true);
conn.setUseCaches(false);
//设置请求方式
conn.setRequestMethod(requestMethod);

//当outputStr不为null时,向输出流写数据
if(null!=outputStr){
OutputStream outputStream=conn.getOutputStream();
outputStream.write(outputStr.getBytes("UTF-8"));
outputStream.close();
}
//从输入流读取返回内容
InputStream inputStream =conn.getInputStream();
InputStreamReader inputStreamReader=new InputStreamReader(inputStream,"UTF-8");
BufferedReader bufferReader=new BufferedReader(inputStreamReader);
String str=null;
StringBuffer buffer=new StringBuffer();
while ((str=bufferReader.readLine())!=null){
buffer.append(str);
}
//释放资源
bufferReader.close();
inputStreamReader.close();
inputStream.close();
conn.disconnect();
log.info("============jsonString:"+buffer.toString()+"============");
jsonObject=JSONObject.fromObject(buffer.toString());
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchProviderException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return jsonObject;
}
/**
* 从内存获取accessToken
* 2015-9-15下午3:39:30,huangjuan,微信V1.0
*/
public static AccessToken getEhcacheAccessToken(){
AccessToken token=null;
Cache cache=getEhcacheCache("weixinCache");
net.sf.ehcache.Element accessTokenE=cache.get("AccessToken");
if(accessTokenE!=null){
token=new AccessToken();
token=(AccessToken) accessTokenE.getObjectValue();
}
return token;
}
/**
* 获取微信的ehcache
* 2015-9-15下午4:13:54,huangjuan,微信V1.0
*/
public static Cache getEhcacheCache(String cacheName){
CacheManager cacheManager=CacheManager.create();
Cache cache=cacheManager.getCache(cacheName);
return cache;
}
/**
* 获取微信jsapi_ticket
* 2015-9-15下午4:14:59,huangjuan,微信V1.0
*/
public static String getCachedJsapi_ticket(){
String jsapi_ticket="";
Cache cache=getEhcacheCache("weixinCache");
net.sf.ehcache.Element jsapi_ticket_e=cache.get("jsapi_ticket");
if(jsapi_ticket_e!=null) jsapi_ticket=(String)jsapi_ticket_e.getObjectValue();
return jsapi_ticket;
}
public static void main(String args[]){
String str="{\"access_token\":\"iRH_DuNHSDgs6iH6pcO-0NEZfHjAH94rWZb-Tm5otJnp1uRiQ22mEnWQBnJu-8KO\",\"expires_in\":7200}";
JSONObject obj=JSONObject.fromObject(str);
System.out.println(obj.get("access_token"));
}
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值