【做微信平台开发需要以下步骤,wx.zip示例可以参考,修改配置即可】
1.申请一个公众号(订阅号或者服务号)
2.需要有自己的服务器(建议使用花生壳做内网映射)
3.配置微信服务器
4.编写后台代码
*微信入口
package com.wx.controller; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.ServletInputStream; import javax.servlet.ServletOutputStream; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.code.util.WeixinHanlder; import com.code.util.WeixinHanlder.TextMsg; @WebServlet("/weixin_service") public class WxServlet extends HttpServlet{ private static final long serialVersionUID = 1L; /** * 验证微信信息 */ @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String signature,timestamp,nonce,echostr; signature = req.getParameter("signature"); timestamp = req.getParameter("timestamp"); nonce = req.getParameter("nonce"); echostr = req.getParameter("echostr"); try { if(WeixinHanlder.checkSgin(signature, timestamp, nonce)){ ServletOutputStream out = resp.getOutputStream(); out.print(echostr); out.close(); }else{ System.out.println("error invoke method failure "); } } catch (Exception e) { e.printStackTrace(); } } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletInputStream in = req.getInputStream(); try { Object obj = WeixinHanlder.XML.getMessage(in); System.out.println(obj); if(obj instanceof WeixinHanlder.TextMsg){ TextMsg msg = (TextMsg)obj; System.out.println(msg.getContent()); } } catch (Exception e) { e.printStackTrace(); } } }
* 微信加密工具类
package com.code.util; import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.text.MessageFormat; import java.util.Arrays; import java.util.Formatter; import java.util.HashMap; import java.util.Map; import java.util.Properties; import java.util.UUID; import javax.servlet.ServletContext; import net.sf.json.JSONObject; import org.dom4j.Document; import org.dom4j.DocumentHelper; import org.dom4j.Element; import org.dom4j.io.SAXReader; /** * 微信开发工具类 * @author LGF * */ public class WeixinHanlder { public static Integer CHANGE_TOKEN_TIME = 7000; public static String TOKEN = "weixin"; public static String OPENID = "gh_d97c8ce11b95"; public static String APPID = "wx1d80f7014b33404b"; public static String APPSECRET = "7eb7a1f207e905c41b7c7bb56221e3df"; public static String URL_ACCESS_TOKEN = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=wx1d80f7014b33404b&secret=7eb7a1f207e905c41b7c7bb56221e3df"; public static String URL_JS_TICKET = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token={0}&type=jsapi"; static{ Properties props = new Properties(); try { props.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("weixin.properties")); OPENID = props.get("open_id").toString(); APPID = props.get("app_id").toString(); APPSECRET = props.get("app_secret").toString(); TOKEN = props.get("token").toString(); URL_ACCESS_TOKEN = props.get("url_access_token").toString(); URL_JS_TICKET = props.get("url_js_ticket").toString(); CHANGE_TOKEN_TIME = Integer.parseInt(props.get("change_token_time").toString()); } catch (IOException e) { e.printStackTrace(); } } /** * 检查是否是微信发送的请求 * @param signature 签名 * @param timestamp 时间戳 * @param nonce 随机数 * @return * @throws Exception */ public static boolean checkSgin(String signature,String timestamp,String nonce) throws Exception{ String[] strs = new String[]{timestamp,nonce,TOKEN}; Arrays.sort(strs); StringBuffer sb = new StringBuffer(); for (String string : strs) { sb.append(string); } String sha1 = SecurityHanlder.sha1(sb.toString()); if(sha1.equals(signature)){ return true; } return false; } /** * 获取系统默认时间 * @return */ public static Long getTime(){ return System.currentTimeMillis(); } /** * 关键字检索,默认逗号分隔 * @param source * @param kws * @return */ public static boolean keywordCheck(String source,String kws,String splitor){ if(source!=null){ String[] split = kws.split(splitor); for (Object kw : split) { if(source.indexOf(kw.toString())!=-1||(kw!=null&&kw.toString().indexOf(source)!=-1)){ return true; } } } return false; } /** * 关键字检索,默认逗号分隔 * @param source * @param kws * @return */ public static boolean keywordCheck(String source,String kws){ return keywordCheck(source,kws,","); } /** * 读取字符串 * @param input * @return * @throws IOException */ public static String readString(InputStream input) throws IOException{ BufferedInputStream bis = new BufferedInputStream(input); byte[] bs = new byte[1024]; StringBuffer sb = new StringBuffer(); while(bis.read(bs)!=-1){ sb.append(new String(bs)); } input.close(); bis.close(); return sb.toString(); } /** * JS 签名验证 * @param jsapi_ticket * @param url * @return */ public static Map<String, String> sign(String jsapi_ticket, String url) { Map<String, String> ret = new HashMap<String, String>(); String nonce_str = create_nonce_str(); String timestamp = create_timestamp(); String signature = ""; String string1; //注意这里参数名必须全部小写,且必须有序 //注意这里参数名必须全部小写,且必须有序 string1 = "jsapi_ticket=" + jsapi_ticket + "&noncestr=" + nonce_str + "×tamp=" + timestamp + "&url=" + url; System.out.println("************"+string1); try { MessageDigest crypt = MessageDigest.getInstance("SHA-1"); crypt.reset(); crypt.update(string1.toString().getBytes("UTF-8")); signature = byteToHex(crypt.digest()); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } ret.put("url", url); ret.put("jsapi_ticket", jsapi_ticket); ret.put("nonceStr", nonce_str); ret.put("timestamp", timestamp); ret.put("signature", signature); return ret; } /** * 转换成十六进制 * @param hash * @return */ private static String byteToHex(final byte[] hash) { Formatter formatter = new Formatter(); for (byte b : hash) { formatter.format("%02x", b); } String result = formatter.toString(); formatter.close(); return result; } /** * 随机字符串 * @return */ private static String create_nonce_str() { return UUID.randomUUID().toString(); } /** * 随机时间 * @return */ private static String create_timestamp() { return Long.toString(System.currentTimeMillis() / 1000); } /** * XML 文件处理,获取XML文件 * @author LGF * */ public static class XML { public static String XML = "xml"; public static String TOUSERNAME = "ToUserName"; public static String FROMUSERNAME = "FromUserName"; public static String CREATETIME = "CreateTime"; public static String MSGTYPE = "MsgType"; public static String CONTENT = "Content"; public static String VIDEO = "video"; public static String MEDIAID = "MediaId"; public static String TITLE = "Title"; public static String DESCRIPTION = "Description"; public static String MUSICURL = "MusicURL"; public static String HQMUSICURL = "HQMusicUrl"; public static String THUMBMEDIAID = "ThumbMediaId"; public static String ARTICLES = "Articles"; public static String ITEM = "item"; public static String PICURL = "PicUrl"; public static String URL = "URL"; //消息类型 public static String MSGTYPE_TEXT = "text"; public static String MSGTYPE_IMAGE = "image"; public static String MSGTYPE_VIDO = "video"; public static String MSGTYPE_VOICE = "voice"; /** * 传入输入流获取Document对象 * @param input * @return * @throws Exception */ public static Document getDocuemnt(InputStream input) throws Exception{ return new SAXReader().read(input); } /** * XML输入流获取一个对象 * @param <T> * @param input * @return * @throws Exception */ @SuppressWarnings("unchecked") public static <T> T getMessage(InputStream input,Class<T> clazz) throws Exception{ Document d = getDocuemnt(input); Element root = d.getRootElement(); String type = root.element(MSGTYPE).getText(); String to = root.element(TOUSERNAME).getText(); String from = root.element(FROMUSERNAME).getText(); String time = root.element(CREATETIME).getText(); if(MSGTYPE_TEXT.equals(type)){ String content = root.element(CONTENT).getText(); return (T) new TextMsg(to,from,time==null||time.isEmpty()?null:Long.parseLong(time),type,content); }else if(MSGTYPE_IMAGE.equals(type)){ }else if(MSGTYPE_VIDO.equals(type)){ }else if(MSGTYPE_VOICE.equals(type)){ } return (T) d.asXML(); } /** * XML输入流获取一个对象 * @param input * @return * @throws Exception */ public static Object getMessage(InputStream input) throws Exception{ return getMessage(input,Object.class); } /** * 回复文本消息 * @param to * @param from * @param time * @param type * @param content * @return */ public static String getSendTextMessage(String to,Long time,String content){ Element r = getBaseMessageElement(to,time); r.addElement(CONTENT).addCDATA(content); return r.getDocument().asXML(); } /** * 设置基本回复消息 * @param to * @param from * @param time * @param type * @param content * @return */ private static Element getBaseMessageElement(String to,Long time){ Document d = DocumentHelper.createDocument(); Element r = d.addElement(XML); r.addElement(TOUSERNAME).addCDATA(to); r.addElement(FROMUSERNAME).addCDATA(WeixinHanlder.OPENID); r.addElement(CREATETIME).addCDATA(time.toString()); r.addElement(MSGTYPE).addCDATA(MSGTYPE_TEXT); return r; } /** * 回复文本消息 * @param to * @param content * @return */ public static String getSendTextMessage(String to,String content){ return getSendTextMessage(to,WeixinHanlder.getTime(),content); } } /** * 微信消息父类实体 * @author LGF * */ public static class Msg{ private String toUserName; private String fromUserName; private Long createTime; private String msgType; public Msg(String toUserName, String fromUserName, Long createTime, String msgType) { this.toUserName = toUserName; this.fromUserName = fromUserName; this.createTime = createTime; this.msgType = msgType; } public Msg() { } public String getToUserName() { return toUserName; } public void setToUserName(String toUserName) { this.toUserName = toUserName; } public String getFromUserName() { return fromUserName; } public void setFromUserName(String fromUserName) { this.fromUserName = fromUserName; } public Long getCreateTime() { return createTime; } public void setCreateTime(Long createTime) { this.createTime = createTime; } public String getMsgType() { return msgType; } public void setMsgType(String msgType) { this.msgType = msgType; } } /** * 文本消息实体类 * @author LGF * */ public static class TextMsg extends Msg { private String content; public TextMsg() { } public TextMsg(String toUserName, String fromUserName, Long createTime, String msgType, String content) { super(toUserName,fromUserName,createTime,msgType); this.content = content; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } } /** * 获取微信 access_token 线程 * @author LGF * */ public static class ThreadAccessToken implements Runnable{ private ServletContext servletContext; //实例化后启动线程 public ThreadAccessToken(ServletContext servletContext) { this.servletContext = servletContext; servletContext.setAttribute("wx_openId", OPENID); servletContext.setAttribute("wx_appId", APPID); servletContext.setAttribute("wx_appSecret", APPSECRET); setToken(); new Thread(this).start(); } @Override public void run() { while(true){ try { //两小时刷新一次签名 Thread.sleep(60*1000); setToken(); } catch (InterruptedException e) { e.printStackTrace(); new ThreadAccessToken(servletContext); } } } /** * 设置 access_token */ private synchronized void setToken(){ try { InputStream input = URLHanlder.getInputStream(URL_ACCESS_TOKEN); JSONObject json = JSONObject.fromObject(readString(input)); String wx_access_token = json.get(Const.ACCESS_TOKEN).toString(); servletContext.setAttribute("wx_access_token", wx_access_token); System.out.println("get access access_token success " + wx_access_token); InputStream input1 = URLHanlder.getInputStream(MessageFormat.format(URL_JS_TICKET, wx_access_token)); JSONObject json1 = JSONObject.fromObject(readString(input1)); String wx_ticket = json1.get(Const.TICKET).toString(); servletContext.setAttribute("wx_ticket", wx_ticket); System.out.println("get access ticket success " + wx_ticket); } catch (Exception e) { e.printStackTrace(); } } } } /** * 常量 * @author LGF * */ interface Const{ public static String ACCESS_TOKEN = "access_token"; public static String TICKET = "ticket"; }
* JS安全域名验证
package com.wx.controller; import java.io.IOException; import java.util.Map; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.code.util.JSONHanlder; import com.code.util.WeixinHanlder; @WebServlet("/weixin_sign") public class WXSign extends HttpServlet{ private static final long serialVersionUID = 1L; @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding("UTF-8"); resp.setCharacterEncoding("UTF-8"); String url = req.getParameter("url"); String jsapi_ticket = req.getServletContext().getAttribute("wx_ticket").toString(); String appid = req.getServletContext().getAttribute("wx_appId").toString(); Map<String, String> sign = WeixinHanlder.sign(jsapi_ticket, url); sign.put("appId", appid); String string = JSONHanlder.getObjectAsString(sign); ServletOutputStream out = resp.getOutputStream(); out.print(string); System.out.println(sign); out.close(); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { } }
* JSON 工具类
package com.code.util; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.Iterator; import java.util.List; import net.sf.json.JSONObject; import net.sf.json.JsonConfig; import net.sf.json.processors.JsonValueProcessor; public class JSONHanlder { /** * 获取JSON数据 * @param key * @param source * @return */ public static String getVal(String key,String json){ if(key!=null&&key.trim().isEmpty()==false&&key.indexOf(".")!=-1&&json!=null&&json.trim().isEmpty()==false){ String[] ks = key.split("[.]"); List<String> list = Arrays.asList(ks); return getVal(json,list.iterator()); }else if(key!=null&&key.trim().isEmpty()==false){ return JSONObject.fromObject(json).get(key).toString(); } return null; } /** * 将对象转换成 JSON * @param obj * @return */ public static String getObjectAsString(Object obj){ return getObjectAsString(null,null,obj); } /** * 将对象转换成 JSON * @param obj * @return */ public static String getObjectAsString(Object ... obj){ return getObjectAsString(null,null,obj); } /** * 将对象转换成 JSON * @param parrent 时间格式 * @param excludes 不包含的字段 * @param obj * @return */ public static String getObjectAsString(String parrent,String excludes,Object... obj){ if(obj==null||obj.length==0){ return "{}"; } if(obj.length==1){ return JSONObject.fromObject(obj[0],Config.getInstance(parrent,excludes)).toString(); } Data data = new Data(); data.getRecords().addAll(Arrays.asList(obj)); return JSONObject.fromObject(data,Config.getInstance(parrent,excludes)).toString(); } /** * 将对象转换成 JSON * @param excludes * @param obj * @return */ public static String getObjectAsString(String excludes,Object... obj){ return getObjectAsString(null,excludes,obj); } /** * 将对象转换成 JSON * @param parrent * @param obj * @return */ public static String getObjectAsString(Object parrent,Object... obj){ if(parrent!=null){ return getObjectAsString(parrent.toString(),null,obj); } return getObjectAsString(null,null,obj); } /** * 获取JSON数据 * @param source * @param ks * @return */ private static String getVal(Object source,Iterator<String> ks){ if(ks.hasNext()){ source = JSONObject.fromObject(source).get(ks.next()); if(source==null){ return null; } return getVal(source,ks); } return source.toString(); } /** * JSON 配置 * @author LGF * */ public static class Config extends JsonConfig implements JsonValueProcessor { /** * 日期格式化 */ private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); /** * 默认实例 */ private static Config config = new Config(); /** * 默认构造方法 */ private Config() { this.registerJsonValueProcessor(Date.class, this); } /** * 构造方法 * @param parrent 日期格式化 * @param excludes 不包含的字段 */ private Config(String parrent,String excludes) { if(parrent!=null){ sdf = new SimpleDateFormat(parrent); } if(excludes!=null){ this.setExcludes(excludes.split(",")); } this.registerJsonValueProcessor(Date.class, this); } @Override public Object processArrayValue(Object date, JsonConfig cfg) { if(date instanceof Date){ return sdf.format(date); } return null; } @Override public Object processObjectValue(String name, Object date, JsonConfig cfg) { if(date instanceof Date){ return sdf.format(date); } return null; } /** * 获取默认实例 * @return */ public static Config getDefaultInstance(){ return config; } /** * 日期格式化实例 * @param parrent * @return */ public static Config getInstance(String parrent,String excludes){ return new Config(parrent,excludes); } } /** * JSON 数据储存实体 * @author LGF * */ public static class Data{ private List<Object> records = new ArrayList<Object>(); public List<Object> getRecords() { return records; } public void setRecords(List<Object> records) { this.records = records; } } }
* 加密工具类
package com.code.util; import java.security.MessageDigest; import java.util.Formatter; import java.util.UUID; public class SecurityHanlder { private static final String uuid = "4c7a37a8-b8d7-442f-b9df-31ec4bcacebc"; /** * 获取 md5 加密字符串 * @param str * @return * @throws Exception */ public static String md5(String str) throws Exception { return getSign(str,"MD5"); } /** * 获取 md5 加密字符串 * 规则 str+uuid * @param str * @return * @throws Exception */ public static String md5x(String str) throws Exception { return getSign(str+uuid,"MD5"); } /** * 获取 sha1 加密字符串 * @param str * @return * @throws Exception */ public static String sha1(String str) throws Exception { return getSign(str,"SHA-1"); } /** * 获取 sha1 加密字符串 * 二次加密 * 规则 str+uuid * @param str * @return * @throws Exception */ public static String sha1x(String str) throws Exception { return getSign(str+uuid,"SHA-1"); } /** * 获取 sha1进行加密的字符后再进行 md5 加密字符串 * 二次加密 * @param str * @return * @throws Exception */ public static String md5_sha1(String str) throws Exception { return getSign(getSign(str,"MD5"),"SHA-1"); } /** * 获取 md5 进行加密的字符后再进行 sha1加密字符串 * @param str * @return * @throws Exception */ public static String sha1_md5(String str) throws Exception { return getSign(getSign(str,"SHA-1"),"MD5"); } /** * 创建随机字符 * @return */ public static String createNonceStr() { return UUID.randomUUID().toString(); } /** * 获取加密签名 * @param str 字符 * @param type 加密类型 * @return * @throws Exception */ public static String getSign(String str, String type) throws Exception { MessageDigest crypt = MessageDigest.getInstance(type); crypt.reset(); crypt.update(str.getBytes("UTF-8")); return str = byteToHex(crypt.digest()); } /** * 创建时间戳 * @return */ public static String createTimestamp() { return Long.toString(System.currentTimeMillis() / 1000); } /** * 字节转换 16 进制 * @param hash * @return */ private static String byteToHex(final byte[] hash) { Formatter formatter = new Formatter(); for (byte b : hash) { formatter.format("%02x", b); } String result = formatter.toString(); formatter.close(); return result; } }
* URL 工具类
package com.code.util; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import java.util.Map; public class URLHanlder { /** * 发送 HTTP 请求获取输入流 * @param str * @param params * @return */ public static InputStream getInputStream(String str,Map<String,String> params){ URL url = null; try { if(params!=null&¶ms.size()!=0){ StringBuffer sb = new StringBuffer(); int index = 0; if(str.indexOf("?")!=-1){ sb.append("&"); }else{ sb.append("?"); } for (String s : params.keySet()) { sb.append(s); sb.append("="); sb.append(params.get(s)); if(params.size()-1!=index){ sb.append("&"); } index++; } str+=sb.toString(); } url = new URL(str); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); return conn.getInputStream(); } catch (Exception e) { e.printStackTrace(); } return null; } /** * 发送 HTTP 请求获取输入流 * @param str * @return */ public static InputStream getInputStream(String str){ return getInputStream(str,null); } }
* 微信监听类(获取 token)
package com.code.util; import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import javax.servlet.annotation.WebListener; @WebListener public class WXListener implements ServletContextListener { public WXListener() { System.out.println("start com.code.util.WXListener.WXListener()"); } public void contextInitialized(ServletContextEvent e) { ServletContext servletContext = e.getServletContext(); new WeixinHanlder.ThreadAccessToken(servletContext); } public void contextDestroyed(ServletContextEvent e) { System.out.println("destory com.code.util.WXListener.WXListener()"); } }
* 微信 properties 配置
open_id=gh_08d0a8f58b1fsssgf app_id=wxe0faf281eed31f38899 app_secret=dcc59f91d76ea35a05a56fdc0bf16aa7dfh token=weixin url_access_token=https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=wxe0faf281eed31f38&secret=dcc59f91d76ea35a05a56fdc0bf16aa7 url_js_ticket=https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token={0}&type=jsapi change_token_time=7200
* web.xml 配置
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1"> <display-name>wx</display-name> <welcome-file-list> <welcome-file>index.html</welcome-file> </welcome-file-list> <listener> <listener-class>com.code.util.WXListener</listener-class> </listener> </web-app>
* index.jsp 示例
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=0"> <title>index</title> </head> <body> <input type="submit" id="onMenuShareAppMessage" value="submit"> <br/> <input type="file" /> <br/> <input type="button" value="reload" onclick="location.reload(true)"> </body> <script type="text/javascript" src="js/jquery-1.9.0.min.js"></script> <script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script> <script type="text/javascript"> $(function() { $.ajax({ type : "GET", url : "weixin_sign", async: false, data:{url:location.href.split("#")[0]}, dataType: "JSON", success : function(msg) { console.debug(msg); var params = { //url,jsapi_ticket,nonceStr,timestamp,signature debug: true, appId:msg.appId, timestamp:msg.timestamp, nonceStr:msg.nonceStr, signature:msg.signature, jsApiList: ['checkJsApi', 'onMenuShareTimeline', 'onMenuShareAppMessage', 'onMenuShareQQ', 'onMenuShareWeibo', 'hideMenuItems', 'showMenuItems', 'hideAllNonBaseMenuItem', 'showAllNonBaseMenuItem', 'translateVoice', 'startRecord', 'stopRecord', 'onRecordEnd', 'playVoice', 'pauseVoice', 'stopVoice', 'uploadVoice', 'downloadVoice', 'chooseImage', 'previewImage', 'uploadImage', 'downloadImage', 'getNetworkType', 'openLocation', 'getLocation', 'hideOptionMenu', 'showOptionMenu', 'closeWindow', 'scanQRCode', 'chooseWXPay', 'openProductSpecificView', 'addCard', 'chooseCard', 'openCard'] } wx.config(params); } }); }); wx.ready(function(){ $("#onMenuShareAppMessage").click(function(){ wx.openLocation({ latitude: 23.099994, longitude: 113.324520, name: 'TIT 创意园', address: '广州市海珠区新港中路 397 号', scale: 14, infoUrl: 'http://weixin.qq.com' }); }); }); wx.error(function(res){ alert("not success"); }); </script> </html>
相关推荐
翻倍工作室全能版微信开发入门教程代码
1. 微信开发概述 微信开发是指在微信平台上开发应用程序的过程。微信是一个以社交为主的移动应用程序,拥有庞大的用户群体和广泛的使用场景。微信开发可以帮助企业、个人或组织在微信平台上实现自己的业务需求,...
微信小程序开发入门教程&深入浅出,从理论到实践 微信小程序开发入门教程&深入浅出,从理论到实践 微信小程序开发入门教程&深入浅出,从理论到实践 微信小程序开发入门教程&深入浅出,从理论到实践 微信小程序开发...
本资源包括ppt开发说明文档和详细的C#代码实现,借此代码可以迅速搭建一个可用的微信开发框架,并在此基础上进行具体业务逻辑的开发。 微信公众平台开发入门的入门知识,包括 : 1 公众账号的申请和配置; 2 公众平台...
包括官方资源和支持第三方开发的框架或库
收集网上的开发例子 整理起来可以运行的项目,可以为刚入门的人 进行参考,当时为了整理 也下载了不少文档 故此此地需要积分。还有两个 单独java 项目 可以提供 模拟登陆 实现主动发送消息,和调用api实现客户接口
微信公众平台开发入门教程
2020微信小程序开发入门期末真题期末复习题.docx2020微信小程序开发入门期末真题期末复习题.docx2020微信小程序开发入门期末真题期末复习题.docx2020微信小程序开发入门期末真题期末复习题.docx2020微信小程序开发...
Java微信开发入门,主要介绍大微信公众号介绍、开发这环境的一个搭建、发送消息自定回复、企业实战中的微信开发
C#微信公众平台开发基础教程教程里附源码对微信开发入门者很有帮助,欢迎下载使用。 文中指导怎样申请微信开发的环境及部分源码可作为参考。
本资料包含微信小程序开发入门学习资料和小程序开发实战操作。
主要为大家详细介绍了python tornado微信开发入门代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
内容简介: 本视频由《微信公众平台应用开发:方法、技巧与案例》的作者刘运强(网名:柳峰)讲解微信公众平台开发入门级相关知识的系列视频之一。内容涵盖:1.微信公众平台基础知识(服务号/订阅号、公众账号注册的...
以Orange Can项目为主线,深入浅出地介绍微信小程序的基本结构、开发模式、组件应用、数据绑定方法、微信API使用、微信与设备硬件交互、微信支付等内容根据微信小程序公开上线新版本编写,总结小程序开发中踩过的“坑...
微信开发入门教程 jssdk,通过config接口注入权限验证配置java+jsp微信开发教程,功能:扫描二维码,拍照、本地选图,图片预览,上传图片,下载图片,获取当前网络状态,查看地理位置,获取当前地理位置打开地图,...
java 微信公众号开发入门 DEMO 可直接跑起来的 大家可以直接下载,然后练习一下。java 微信公众号开发入门 DEMO 可直接跑起来的 大家可以直接下载,然后练习一下。
以Orange Can项目为主线,深入浅出地介绍微信小程序的基本结构、开发模式、组件应用、数据绑定方法、微信API使用、微信与设备硬件交互、微信支付等内容 根据微信小程序公开上线新版本编写,总结小程序开发中踩过的...