1 salesforce 配置site
2 微信公众平台根据site 的信息 配置url 以及token, token 需要与代码中验证的 token 一致 微信 配置url 需要是https
3 doget 只是与微信进行 链接验证 测试的 话需要自己拼接值 进行验证
4 不加http
public with sharing class WechatNews {
public WechatNews() {
}
public String title;
public String description;
public String picUrl;
public String url;
public WeChatNews(String t, String d, String p, String u){
this.title = t;
this.description = d;
this.picUrl = p;
this.url = u;
}
}
public with sharing class ResponseMessage {
public String title;
public String url;
public ResponseMessage(String title,String url) {
this.title = title;
this.url = url;
}
}
public with sharing class RequestMessage {
public String toUserName;
public String fromUserName;
public String msgType;
public String content;
public String Ticket;
public String EventKey;
public RequestMessage(String toUserName,String fromUserName,String msgType,String content,String Ticket,String EventKey) {
this.toUserName = toUserName;
this.fromUserName = fromUserName;
this.msgType = msgType;
this.content = content;
this.Ticket = Ticket;
this.EventKey = EventKey;
}
}
public with sharing class IncomingMsg {
public IncomingMsg() {
}
public String toUserName;
public String fromUserName;
public String msgType;
public String picURL;
public String mediaID;
public String locationX;
public String locationY;
public String URL;
public String content;
public String event;
public String eventKey;
public String recognition;
public String Ticket;
public IncomingMsg(String tUN, String fUN, String mT, String pU, String mI, String lX, String lY, String u, String c, String e, String eK, String r,String ti){
this.toUserName = tUN;
this.fromUserName = fUN;
this.msgType = mT;
this.picURL = pU;
this.mediaID = mI;
this.locationX = lX;
this.locationY = lY;
this.URL = u;
this.content = c;
this.event = e;
this.eventKey = eK;
this.recognition = r;
this.Ticket = ti;
}
}
@RestResource(urlMapping = '/WeChatRest/*')
global without sharing class IntegrateWechat {
public static List<String> strList;
public static List<String> openIdList;
public IntegrateWechat() {
}
@HttpGet
global static void doGet() {
String signature = RestContext.request.params.get('signature');
String timestamp = RestContext.request.params.get('timestamp');
String nonce = RestContext.request.params.get('nonce');
String echostr = RestContext.request.params.get('echostr');
System.debug(echostr + ' ------------ timestamp------------' + timestamp);
if (checkSignature(signature, timestamp, nonce)) {
RestContext.response.addHeader('Content-Type', 'text/plain');
RestContext.response.responseBody = Blob.valueOf(echostr);
}
}
public static Boolean checkSignature(String signature, String timestamp, String nonce) {
String[] arr = new String[] {'richDemo', timestamp, nonce};
arr.sort();
String content = '';
for (Integer i = 0; i < arr.size(); i++) {
content += arr[i];
}
Blob hash = Crypto.generateDigest('SHA1', Blob.valueOf(content));
String hexDigest = EncodingUtil.convertToHex(hash);
String singUpperCase = hexDigest.toUpperCase();
System.debug(singUpperCase + '===============');
// 将sha1加密后的字符串可与signature对比,标识该请求来源于微信
Boolean flag = singUpperCase != null ? singUpperCase .equals(signature.toUpperCase()) : false;
system.debug(flag + '==============');
return flag;
}
@HttpPost
global static void doPost() {
//Receive message from user;
RestRequest req = RestContext.request;
RestResponse res = RestContext.response;
string strMsg = req.requestBody.toString();
System.debug('Request Contents' + strMsg);
XmlStreamReader reader = new XmlStreamReader(strMsg);
String toUserName = '';
String fromUserName = '';
String msgType = '';
String picURL = '';
String mediaID = '';
String locationX = '';
String locationY = '';
String URL = '';
String content = '';
String msgID = '';
String event = '';
String eventKey = '';
String recognition = '';
String Ticket = '';
while (reader.hasNext()) {
if (reader.getLocalName() == 'ToUserName') {
reader.next();
if (String.isNotBlank(reader.getText())) {
toUserName = reader.getText();
}
} else if (reader.getLocalName() == 'FromUserName') {
reader.next();
if (String.isNotBlank(reader.getText())) {
fromUserName = reader.getText();
}
} else if (reader.getLocalName() == 'MsgType') {
reader.next();
if (String.isNotBlank(reader.getText())) {
msgType = reader.getText();
}
} else if (reader.getLocalName() == 'PicURL') {
reader.next();
if (String.isNotBlank(reader.getText())) {
picURL = reader.getText();
}
} else if (reader.getLocalName() == 'MediaId') {
reader.next();
if (String.isNotBlank(reader.getText())) {
mediaID = reader.getText();
}
} else if (reader.getLocalName() == 'Location_X') {
reader.next();
if (String.isNotBlank(reader.getText())) {
locationX = reader.getText();
}
} else if (reader.getLocalName() == 'Location_Y') {
reader.next();
if (String.isNotBlank(reader.getText())) {
locationY = reader.getText();
}
} else if (reader.getLocalName() == 'Url') {
reader.next();
if (String.isNotBlank(reader.getText())) {
URL = reader.getText();
}
} else if (reader.getLocalName() == 'MsgId') {
reader.next();
if (String.isNotBlank(reader.getText())) {
msgID = reader.getText();
}
} else if (reader.getLocalName() == 'Content') {
reader.next();
if (String.isNotBlank(reader.getText())) {
content = reader.getText();
}
} else if (reader.getLocalName() == 'Event') {
reader.next();
if (String.isNotBlank(reader.getText())) {
event = reader.getText();
}
} else if (reader.getLocalName() == 'EventKey') {
reader.next();
if (String.isNotBlank(reader.getText())) {
eventKey = reader.getText();
}
} else if (reader.getLocalName() == 'Recognition') {
reader.next();
if (String.isNotBlank(reader.getText())) {
recognition = reader.getText();
}
}else if (reader.getLocalName() == 'Ticket') {
System.debug('ticket---->');
reader.next();
if (String.isNotBlank(reader.getText())) {
Ticket = reader.getText();
}
}
reader.next();
}
System.debug('toUserName===>' + toUserName);
System.debug('fromUserName===>' + fromUserName);
System.debug('msgType===>' + msgType);
IncomingMsg inMsg = new IncomingMsg(toUserName, fromUserName, msgType, picURL, mediaID, locationX, locationY, URL, content, event, eventKey, recognition,Ticket);
String rtnMsg = '';
String resultXML;
RequestMessage receiveMsg = new RequestMessage(toUserName,fromUserName,msgType,content,Ticket,eventKey);
//回复消息
if (msgType.equals('text')) {
rtnMsg = handleText(inMsg);
} else if (msgType.equals('event')) {
rtnMsg = handleEvent(inMsg);
System.debug(fromUserName);
System.debug(eventKey);
List<CampaignMember> cmList = [
SELECT Id, Contact.WechatId__c, CampaignId, Arrived__c
FROM CampaignMember
WHERE Contact.WechatId__c = :fromUserName
AND CampaignId = :eventKey.split(':')[0]
];
if (cmList.size() > 0) {
if (eventKey.split(':')[1] == 'register') {
for (CampaignMember cm : cmList) {
cm.Arrived__c = true;
WechatPageController.sendRegisterMessage(cm.Contact.WechatId__c, 'Welcome', 'Have fun!', cm.CampaignId);
// resultXML = buildResponseXMLByContent(receiveMsg);
// System.debug('resultXML--->'+resultXML);
// RestContext.response.addHeader('Content-Type', 'text/plain');
// RestContext.response.responseBody = Blob.valueOf(resultXML);
// System.debug('RestContext.response.responseBody------>'+RestContext.response.responseBody);
}
update cmList;
} else if (eventKey.split(':')[1] == 'feedback') {
for (CampaignMember cm : cmList) {
WechatPageController.sendMessage1(cm.Contact.WechatId__c, 'Feedback', 'Please tell us about your feeling.', cm.CampaignId);
}
}
} else {
// 原先没有添加到Campaign Member
List<Contact> contactList=[
SELECT Id,WechatId__c
FROM Contact
WHERE WechatId__c=:fromUserName];
List<CampaignMember> campaignMemberList=new List<CampaignMember>();
for(Contact contact:contactList ){
CampaignMember campaignMember=new CampaignMember();
campaignMember.ContactId=contact.Id;
campaignMember.Arrived__c=true;
campaignMember.CampaignId=eventKey.split(':')[0];
campaignMemberList.add(campaignMember);
}
insert campaignMemberList;
}
}
RestResponse response = RestContext.response;
response.statusCode = 200;
response.responseBody = Blob.valueOf('success');
}
public static String buildResponseXMLByContent(RequestMessage message) {
//用于作为XML拼装的返回结果
String buildXMLString;
//对搜索出来的结果集进行封装,然后加工处理XML作为微信返回内容
List<ResponseMessage> responseMessageList = new List<ResponseMessage>();
buildXMLString = buildResponseXML(message, responseMessageList);
System.debug(LoggingLevel.INFO, '*** buildXMLString: ' + buildXMLString);
return buildXMLString;
}
public static String buildResponseXML(RequestMessage message,List<ResponseMessage> responseMessageList) {
String currentDateTime = System.now().format('YYYY-MM-dd HH:mm:ss');
//根据微信公众号规则拼装XML模板
String responseMessageTemplate = '<xml><ToUserName><![CDATA[{0}]]></ToUserName><FromUserName><![CDATA[{1}]]></FromUserName><CreateTime>'
+ currentDateTime +
'</CreateTime><MsgType><![CDATA[event]]></MsgType>'+
'<Event><![CDATA[subscribe]]></Event>'+
'<EventKey><![CDATA[qrscene_'+message.eventKey.split(':')[0]+']]></EventKey>'+
'<Ticket><![CDATA['+message.Ticket+']]></Ticket>'+
'</xml>';
//XML模板中对应的Placeholder的值
String[] arguments;
arguments = new String[]{message.fromUserName, message.toUserName, 'Sign in succeeded'};
//非文本输入提示
// if(!message.msgType.equalsIgnoreCase('text')) {
// arguments = new String[]{message.fromUserName, message.toUserName, '该公众号目前支支持文字输入'};
// } else {
// //没有搜索出记录提示
// if(responseMessageList.isEmpty()) {
// arguments = new String[]{message.fromUserName, message.toUserName, '没有匹配的数据,请重新尝试其他的关键字'};
// } else {
// String messageStringBuffer = '';
// for(ResponseMessage responseItem : responseMessageList) {
// messageStringBuffer += '<a href="' + responseItem.url + '">' + responseItem.title + '"></a>\n';
// }
// messageStringBuffer = messageStringBuffer.removeEnd('\n');
// arguments = new String[]{message.fromUserName, message.toUserName, messageStringBuffer};
// }
// }
String results = String.format(responseMessageTemplate, arguments);
return results;
}
private static String handleText(IncomingMsg msg) {
String keyword = msg.content;
String strReply;
String strResult;
if (keyword.equals('1')) {
strReply = '这是个文本消息';
strResult = composeTextReply(msg, strReply);
} else if (keyword.equals('2') || keyword.equals('单图文')) {
WeChatNews news = new WeChatNews('图文图文图文图文图文图文', '2020图文图文图文图文', 'http://a.36krcnd.com/photo/2014/4e3ae0dac4884bb91934a689b72f8f8b.png',
'https://richs-wechat-developer-edition.ap16.force.com/WechatPage');
List<WeChatNews> newsList = new List<WeChatNews>();
newsList.add(news);
strResult = composeNewsReply(msg, newsList);
} else if (keyword.equals('3')) {
WeChatNews news1 = new WeChatNews('图文1图文1图文1图文1图文1图文1', '2020图文1图文1图文1图文1图文1图文1', 'http://a.36krcnd.com/photo/2014/4e3ae0dac4884bb91934a689b72f8f8b.png',
'http://www.36kr.com/p/212479.html');
WeChatNews news2 = new WeChatNews('图文2图文2图文2图文2图文2图文2', '2020图文2图文2图文2图文2图文2图文2', 'http://a.36krcnd.com/photo/2014/e64d647389bfda39131e12fa9d606bb6.jpg',
'http://www.36kr.com/p/212476.html');
WeChatNews news3 = new WeChatNews('图文3图文3图文3图文3图文3图文3', '2020图文3图文3图文3图文3图文3图文3', 'http://a.36krcnd.com/photo/2014/25490e2b8e63ced9586f0a432eebb972.jpg',
'http://www.36kr.com/p/212484.html');
List<WeChatNews> newsList = new List<WeChatNews>();
newsList.add(news1);
newsList.add(news2);
newsList.add(news3);
strResult = composeNewsReply(msg, newsList);
} else if (keyword.equals('4')) {
Map<String, String> music = new Map<String, String>();
music.put('title', '爱你的宿命');
music.put('description', '张信哲');
music.put('musicUrl',
'http://zhangmenshiting.baidu.com/data2/music/119826740/1197655931401552061128.mp3?xcode=80587c819993d49621a8dce05e5bb8c9e36664380262dc7e&song_id=119765593');
music.put('musicHQUrl',
'http://zhangmenshiting.baidu.com/data2/music/119826740/1197655931401552061128.mp3?xcode=80587c819993d49621a8dce05e5bb8c9e36664380262dc7e&song_id=119765593');
strResult = composeMusicReply(msg, music);
} else {
WeChatNews newsS = new WeChatNews('test,test......', 'shdiswanghsiankgi....', 'http://a.36krcnd.com/photo/2014/4e3ae0dac4884bb91934a689b72f8f8b.png',
'https://richs-wechat-developer-edition.ap16.force.com/WechatPage');
List<WeChatNews> newsListS = new List<WeChatNews>();
newsListS.add(newsS);
strResult = composeNewsReply(msg, newsListS);
}
return strResult;
}
private static String composeNewsReply(IncomingMsg msg, List<WeChatNews> newsList) {
String strNews = '';
String newsTpl = '<item><Title><![CDATA[{0}]]></Title><Description><![CDATA[{1}]]></Description><PicUrl><![CDATA[{2}]]></PicUrl><Url><![CDATA[{3}]]></Url></item>';
for (WeChatNews news : newsList) {
String[] arguments = new String[]{news.title, news.description, news.picUrl, news.url};
strNews += String.format(newsTpl, arguments);
}
String strTmp =
'<xml><ToUserName><![CDATA[{0}]]></ToUserName><FromUserName><![CDATA[{1}]]></FromUserName><CreateTime>1234567890</CreateTime><MsgType><![CDATA[news]]></MsgType><ArticleCount><![CDATA[{2}]]></ArticleCount><Articles>' +
strNews + '</Articles></xml>';
String[] arguments = new String[]{msg.fromUserName, msg.toUserName, String.valueOf(newsList.size())};
String results = String.format(strTmp, arguments);
return results;
}
private static String composeMusicReply(IncomingMsg msg, Map<String, String> music) {
String strTitle = music.get('title');
String strDesc = music.get('description');
String strURL = music.get('musicUrl');
String strHQURL = music.get('musicHQUrl');
String musicTpl =
'<xml><ToUserName><![CDATA[{0}]]></ToUserName><FromUserName><![CDATA[{1}]]></FromUserName><CreateTime>12345678</CreateTime><MsgType><![CDATA[music]]></MsgType><Music><Title><![CDATA[{2}]]></Title><Description><![CDATA[{3}]]></Description><MusicUrl><![CDATA[{4}]]></MusicUrl><HQMusicUrl><![CDATA[{5}]]></HQMusicUrl></Music></xml>';
String[] arguments = new String[]{msg.fromUserName, msg.toUserName, strTitle, strDesc, strURL, strHQURL};
String results = String.format(musicTpl, arguments);
return results;
}
private static String composeTextReply(IncomingMsg msg, String content) {
String strTmp =
'<xml><ToUserName><![CDATA[{0}]]></ToUserName><FromUserName><![CDATA[{1}]]></FromUserName><CreateTime>12345678</CreateTime><MsgType><![CDATA[text]]></MsgType><Content><![CDATA[{2}]]></Content></xml>';
String[] arguments = new String[]{msg.fromUserName, msg.toUserName, content};
String strReply = String.format(strTmp, arguments);
return strReply;
}
public static String handleEvent(IncomingMsg msg) {
strList = new List<String>();
String event = msg.event;
String strTmp = '';
if (event.equals('subscribe')) {
WechatPageController.getAccessToken();
} else if (event.equals('unsubscribe')) {
strTmp = '';
} else if (event.equals('CLICK')) {
//strTmp = '您点击了' + msg.eventKey;
if (msg.eventKey.equals('最新展销')) {
WeChatNews newsS = new WeChatNews('test,test......', 'shdiswanghsiankgi....', 'http://a.36krcnd.com/photo/2014/4e3ae0dac4884bb91934a689b72f8f8b.png',
'http://www.36kr.com/p/212479.html');
List<WeChatNews> newsListS = new List<WeChatNews>();
newsListS.add(newsS);
String strResult = composeNewsReply(msg, newsListS);
return strResult;
}
}
String result = composeTextReply(msg, strTmp);
return result;
}
}
<apex:page standardstylesheets="false" showHeader="false" sidebar="false" Controller="WechatCampaignConfirmController"
docType="html-5.0">
<head>
<meta name="viewport"
content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no"/>
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/4.5.0/css/bootstrap.min.css" rel="stylesheet"/>
</head>
<body
style=" background-repeat:no-repeat;
margin-left: 1rem;
margin-bottom: 1rem;
margin-right: 1rem;
margin-top: 1rem;
background-size:100% 100%;
background-attachment: fixed;
background: url(https://help.salesforce.com/resource/1591233462000/HelpStaticResource/assets/images/EmailTemplatebg.jpg);">
<div class="container">
<div class="row">
</div>
<div class="row">
<div class="jumbotron" style="width: 100%">
<h2 class="display-4">Hello</h2>
<p class="lead"> Please fill in the relevant information and confirm</p>
<hr class="my-4"/>
<apex:image url="{! $Resource.test01 }" style="width: 100%;"/>
</div>
</div>
<div class="row" id="formdiv">
<form style="width: 100%" id="form1">
<div class="form-group">
<label>Rating</label>
<input type="number" class="form-control" required="required" value="{!Rating}" id="Rating" oninput="if(value.length>1)value=value.slice(0,1)"/>
</div>
<div class="form-group">
<label>Feedback</label>
<textarea class="form-control" required="true" value="{!Feedback}" id="Feedback"></textarea>
</div>
<div class="form-group ">
</div>
<input Id="campaignId" value="{!campaignId}" type="hidden"/>
<input Id="code" value="{!code}" type="hidden"/>
</form>
<input type="button" class="btn btn-primary" onclick="submit();" value="Submit"/>
</div>
</div>
<script>
function submit() {
//window.alert(111);
const campaignId = document.getElementById('campaignId').value;
const code = document.getElementById('code').value;
const Rating = document.getElementById('Rating').value;
const Feedback = document.getElementById('Feedback').value;
Visualforce.remoting.Manager.invokeAction(
'{!$RemoteAction.WechatCampaignConfirmController.doSave}',
campaignId,Rating,Feedback,code,
function(result, event){
if (event.status) {
console.log(event);
document.getElementById("formdiv").style.display = 'none';
window.alert('You have successfully submitted');
} else if (event.type === 'exception') {
document.getElementById("responseErrors").innerHTML =
event.message + "<br/>\n<pre>" + event.where + "</pre>";
} else {
document.getElementById("responseErrors").innerHTML = event.message;
}
},
{escape: true}
);
}
</script>
</body>
</apex:page>
/*
* Created by leal on 2020/6/15.
*/
public class WechatCampaignConfirmController {
Public Campaign campaign{
get;set;
}
public String description{
get;set;
}
public String code {
get; set;
}
public String Result {
get; set;
}
public Integer Rating {
get; set;
}
public String Feedback {
get; set;
}
public String campaignId {
get; set;
}
public static String openId { get; set; }
public class JSONApex{
public String access_token;
public Integer expires_in;
public String refresh_token;
public String openid;
public String scope;
}
public WechatCampaignConfirmController() {
code = ApexPages.currentPage().getParameters().get('code');
String campaignId = ApexPages.currentPage().getParameters().get('strId');
System.debug('campaignId---->'+campaignId);
System.debug('code---->'+code);
//getAuthAcessToken();
Campaign campaign = [select id, name, Type, StartDate, EndDate, Description,ExpectedRevenue from campaign where id=:campaignId];
this.campaign = campaign;
this.campaignId=campaign.Id;
}
@RemoteAction
public static String doSave(String campaignid,String Rating,String Feedback,String code) {
Http h = new Http();
HttpRequest req = new HttpRequest();
req.setMethod('GET');
req.setHeader('Content-Type', 'text/xml;charset=UTF-8');
req.setEndpoint('https://api.weixin.qq.com/sns/oauth2/access_token?' +
'appid=wxa16c53b4e1de217b&' +
'secret=8ce3a2fede0c6b9be9f87542843d25ab&' +
'code=' + code + '&grant_type=authorization_code');
//ApexPages.currentPage().getParameters().get('code')
HttpResponse res = h.send(req);
String Result = res.getBody();
Result = '[' + Result;
Result += ']';
System.debug('Result--->'+Result);
List<JSONApex> openIdList = (List<JSONApex>)JSON.deserialize(Result, List<JSONApex>.class);
System.debug('openIdss' + openIdList[0].openid);
openId = openIdList[0].openid;
Contact contact=[select id from contact where WechatId__c=:openId];
Campaign_Feedback__c CampaignFeedback=new Campaign_Feedback__c();
CampaignFeedback.Campaign__c=campaignid;
CampaignFeedback.Rating__c=Integer.valueOf(Rating);
CampaignFeedback.Feedback__c=Feedback;
CampaignFeedback.Contact__c=contact.id;
System.debug('CampaignFeedback---->'+CampaignFeedback);
insert CampaignFeedback;
return campaignid;
}
}