2016-07-15 10:34:41 u013292160 阅读数 6381
  • 微信支付开发-微信公众号开发12-微信开发php

    微信公众平台开发之微信支付开发是子恒老师《微信公众平台开发》视频教程的第12部。详细讲解了用php进行微信支付的开发。内容包含获取支付密钥,微信公众号支付开发,扫码支付,微信刷卡支付,异步处理支付结果等等。欢迎反馈,微信/QQ:68183131

    27832 人正在学习 去看看 秦子恒

微信分享功能开发

用了一天时间,把微信发送给朋友和分享到朋友圈功能开发出来,在这里给大家分享一下,避免大家走弯路。

一.服务器端程序

package com.wiimedia.controller;


import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

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

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import com.google.gson.Gson;
import com.wiimedia.model.Ticket;
import com.wiimedia.service.ArticleSolrService;
import com.wiimedia.service.TicketRepository;
import com.wiimedia.service.TicketRepositorySolr;
import com.wiimedia.utils.GetRandomStr;
import com.wiimedia.utils.SignatureBean;
import com.wiimedia.utils.weixin.WeixinUtil;
/**
 * 
 * 
 *<p>Project:mryl_phone_v2</p> 
 * 
 *<p>Package:com.wiimedia.controller</p> 
 * 
 *<p>Description:微信分享Controller</p>
 *
 *<p>Company:Wiimedia</p>
 *
 *@Athor:SongJia
 *
 *@Date:2016-7-15 上午09:34:10
 *
 */

@Controller
@RequestMapping("/WeixinshareController/Api/Inteface")
public class WeixinshareController {
    @Autowired
    private TicketRepositorySolr ticketRepositorySolr;

    @RequestMapping("/getSignature")
    public String getSignature( HttpServletRequest request,
            HttpServletResponse response) throws IOException, ParseException{
        //获取签名页面链接
        String url = request.getParameter("url");
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //从数据库中获取标签,并检查标签是否过期
        Ticket oldticket = ticketRepositorySolr.getTicketById("20160114wiimediamrylsong1152");
        if(oldticket==null){//第一次访问,标签不存在。
            executeTicket(response,"1",url,format);
            return null;
        }else{//标签存在,判断标签是否超时
            String oldAcquiretime = oldticket.getAcquiretime();
            long difference=format.parse(format.format(new Date())).getTime()-format.parse(oldAcquiretime).getTime();
            if(difference>7100000){//标签超时,重新到微信服务器请求标签超时时间为7200秒(7200000毫秒)
                executeTicket(response,"2",url,format);
                return null;    
            }else{//标签未超时
                /** 
                 * 注意事项                                           
                 * 1.签名用的noncestr和timestamp必须与wx.config中的nonceStr和timestamp相同。
                 * 2.签名用的url必须是调用JS接口页面的完整URL。                      
                 * 3.出于安全考虑,开发者必须在服务器端实现签名的逻辑。    
                 * 
                 ****根据第1点要求          signature  配置的时候很容易出错,需要把生成  Ticket的  noncestr和 timestamp传给客户端***
                 */
                String signature = signature(oldticket.getTicket(),oldticket.getTimestamp(),oldticket.getNoncestr(),url);
                SignatureBean signatureBean = new SignatureBean();
                signatureBean.setNoncestr(oldticket.getNoncestr());
                signatureBean.setSignature(signature);
                signatureBean.setTimestamp(oldticket.getTimestamp());
                signatureBean.setUrl(url);
                response.setContentType("text/html;charset=UTF-8");
                response.getWriter().print(new Gson().toJson(signatureBean));
                return null;    
            } 
        }


    }
    /**
     * 
     *<p>Project:mryl_phone_v2</p> 
     * 
     *<p>:mryl_phone_v2</p> 
     * 
     *<p>Description:更新和获取ticket的方法,因为用的solr所以更新和新增是一样的ID无则添加,有责更新</p>
     *
     *<p>Company:Wiimedia</p>
     *
     *@Athor:SongJia
     *
     *@Date:2016-7-15 上午09:45:00 
     *
     */
    public void executeTicket(HttpServletResponse response,String flag,String url,SimpleDateFormat format) throws IOException{

        //获取签名随即字符串
        GetRandomStr randomStr = new GetRandomStr();
        String noncestr = randomStr.getRandomString(15);
        //获取签名时间戳
        String timestamp = Long.toString(System.currentTimeMillis());
        //请求accessToken
        String accessTokenUrl ="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=您的APPID&secret=您的密匙";
        String tokenJson = WeixinUtil.httpRequest(accessTokenUrl, "GET", null);
        Gson gson = new Gson();
        ShareAccess_Token token = gson.fromJson(tokenJson, ShareAccess_Token.class);
        String to= token.getAccess_token();
        //获取标签
        String urlTicket ="https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token="+to+"&type=jsapi";
        String ticketJson = WeixinUtil.httpRequest(urlTicket, "GET", null);
        Ticket ticket = gson.fromJson(ticketJson, Ticket.class);
        String t = ticket.getTicket();
        //String uuid = UUID.randomUUID().toString().trim().replaceAll("-", "");
        //我的Ticket ID是写死的
        String acquiretime = format.format(new Date());
        ticket.setTid("20160114wiimediamrylsong1152");
        ticket.setAcquiretime(acquiretime);
        ticket.setTimestamp(timestamp);
        ticket.setNoncestr(noncestr);
        //因为用的SOLR所以更新和添加的方法是一样的,可以根据自己具体需求进行修改,本文不再贴出代码.
        if(flag.equals("2")){
            ticketRepositorySolr.addTicketToSolr(ticket);   
        }else{
            ticketRepositorySolr.addTicketToSolr(ticket);
        }
        /** 
         * 注意事项                                           
         * 1.签名用的noncestr和timestamp必须与wx.config中的nonceStr和timestamp相同。
         * 2.签名用的url必须是调用JS接口页面的完整URL。                      
         * 3.出于安全考虑,开发者必须在服务器端实现签名的逻辑。    
         * 
         *根据第1点要求          signature  配置的时候很容易出错,需要把生成  Ticket的  noncestr和 timestamp传给客户端*
         */
        String signature = signature(t,timestamp,noncestr,url);
        SignatureBean signatureBean = new SignatureBean();
        signatureBean.setNoncestr(noncestr);
        signatureBean.setSignature(signature);
        signatureBean.setTimestamp(timestamp);
        signatureBean.setUrl(url);
        response.setContentType("text/html;charset=UTF-8");
        response.getWriter().print(new Gson().toJson(signatureBean));
    }

    /**
     * 
     *<p>Project:mryl_phone_v2</p> 
     * 
     *<p>:mryl_phone_v2</p> 
     * 
     *<p>Description:根据标签,时间戳,密匙,URL进行签名</p>
     *
     *<p>Company:Wiimedia</p>
     *
     *@Athor:SongJia
     *
     *@Date:2016-7-15 上午09:37:13 
     *
     */
    private String signature(String jsapi_ticket, String timestamp, String noncestr, String url) {
        jsapi_ticket = "jsapi_ticket=" + jsapi_ticket;
        timestamp = "timestamp=" + timestamp;
        noncestr = "noncestr=" + noncestr;
        url = "url=" + url;
        String[] arr = new String[] { jsapi_ticket, timestamp, noncestr, url };
        // 将token、timestamp、nonce,url参数进行字典序排序
        Arrays.sort(arr);
        StringBuilder content = new StringBuilder();
        for (int i = 0; i < arr.length; i++) {
            content.append(arr[i]);
            if (i != arr.length - 1) {
                content.append("&");
            }
        }
        MessageDigest md = null;
        String tmpStr = null;

        try {
            md = MessageDigest.getInstance("SHA-1");
            // 将三个参数字符串拼接成一个字符串进行sha1加密
            byte[] digest = md.digest(content.toString().getBytes());
            tmpStr = byteToStr(digest);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }

        content = null;
        return tmpStr;
    }
    /**
     * 将字节转换为十六进制字符串
     * 
     * @param mByte
     * @return
     */
    private static String byteToHexStr(byte mByte) {

        char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
        char[] tempArr = new char[2];
        tempArr[0] = Digit[(mByte >>> 4) & 0X0F];
        tempArr[1] = Digit[mByte & 0X0F];

        String s = new String(tempArr);
        return s;
    }
    /**
     * 将字节数组转换为十六进制字符串
     * 
     * @param byteArray
     * @return
     */
    private static String byteToStr(byte[] byteArray) {
        String strDigest = "";
        for (int i = 0; i < byteArray.length; i++) {
            strDigest += byteToHexStr(byteArray[i]);
        }
        return strDigest;
    }



    class ShareAccess_Token{
        private  String access_token;
        private  String expires_in;
        public String getAccess_token() {
            return access_token;
        }
        public void setAccess_token(String accessToken) {
            access_token = accessToken;
        }
        public String getExpires_in() {
            return expires_in;
        }
        public void setExpires_in(String expiresIn) {
            expires_in = expiresIn;
        }

    }
}


二.客户端代码.

<script type="text/javascript">
            var url = window.location.href;
            var articleId = "";
            var shareTitle="明日医疗资讯";
            var shareImgUrl="";
            var userinfo = localStorage.getItem("_userinfo");
            var timestamp;
            var noncestr;
            var signature;
            //获取签名
             $.ajax({
                     type: "GET",
                     url: "WeixinshareController/Api/Inteface/getSignature",
                     //data:{timestamp:timestamp,noncestr:noncestr,url:url},
                     data:{url:url},
                     success: function(data){
                                var objData=JSON.parse(data); 
                                timestamp=objData.timestamp;    
                                noncestr=objData.noncestr;  
                                signature=objData.signature;
                                 console.log(objData);
                                 wxShare();
                     }
                 });
            function wxShare(){
            wx.config({
                debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
                appId: '您的appid', // 和获取Ticke的必须一样------必填,公众号的唯一标识
                timestamp:timestamp, // 必填,生成签名的时间戳
                nonceStr: noncestr, // 必填,生成签名的随机串
                signature: signature,// 必填,签名,见附录1
                jsApiList: [
                'onMenuShareAppMessage'
                ] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
            });
            }
            wx.ready(function(){
                 //config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,
                 //config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关
                 //接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。

                //----------“分享给朋友”
                wx.onMenuShareAppMessage({
                    title: "明日医疗资讯", // 分享标题
                    desc: shareTitle, // 分享描述
                    link: url, // 分享链接
                    imgUrl: shareImgUrl, // 分享图标
                    type: '', // 分享类型,music、video或link,不填默认为link
                    dataUrl: '', // 如果type是music或video,则要提供数据链接,默认为空
                    success: function () { 
                        // 用户确认分享后执行的回调函数、
                    },
                    cancel: function () { 
                        // 用户取消分享后执行的回调函数
                    }
                });
                //------------"分享到朋友圈"
                wx.onMenuShareTimeline({
                    title: '明日医疗资讯', // 分享标题
                    link: '', // 分享链接
                    imgUrl: shareImgUrl, // 分享图标
                    success: function () { 
                        // 用户确认分享后执行的回调函数
                    },
                    cancel: function () { 
                        // 用户取消分享后执行的回调函数
                    }
                });
                //-------------分享到QQ
                wx.onMenuShareQQ({
                    title: '明日医疗资讯', // 分享标题
                    desc: shareTitle, // 分享描述
                    link: '', // 分享链接
                    imgUrl: shareImgUrl, // 分享图标
                    success: function () { 
                       // 用户确认分享后执行的回调函数
                    },
                    cancel: function () { 
                       // 用户取消分享后执行的回调函数
                    }
                });
                //-------------分享到QQ空间
                wx.onMenuShareQZone({
                    title: '明日医疗资讯', // 分享标题
                    desc: shareTitle, // 分享描述
                    link: '', // 分享链接
                    imgUrl: shareImgUrl, // 分享图标
                    success: function () { 
                       // 用户确认分享后执行的回调函数
                    },
                    cancel: function () { 
                        // 用户取消分享后执行的回调函数
                    }
                });

            });

三.服务器需要的工具类和Model

① Ticket

package com.wiimedia.model;


public class Ticket{
    private String tid;
    private String ticket;   
    private String errcode;
    private String errmsg; 
    private String expires_in;
    private String acquiretime;
    private String noncestr;
    private String timestamp;

    public Ticket(String tid, String ticket, String errcode, String errmsg,
            String expiresIn, String acquiretime, String noncestr,
            String timestamp) {
        super();
        this.tid = tid;
        this.ticket = ticket;
        this.errcode = errcode;
        this.errmsg = errmsg;
        expires_in = expiresIn;
        this.acquiretime = acquiretime;
        this.noncestr = noncestr;
        this.timestamp = timestamp;
    }
    public String getTid() {
        return tid;
    }
    public void setTid(String tid) {
        this.tid = tid;
    }
    public String getTicket() {
        return ticket;
    }
    public void setTicket(String ticket) {
        this.ticket = ticket;
    }
    public String getErrcode() {
        return errcode;
    }
    public void setErrcode(String errcode) {
        this.errcode = errcode;
    }
    public String getErrmsg() {
        return errmsg;
    }
    public void setErrmsg(String errmsg) {
        this.errmsg = errmsg;
    }
    public String getExpires_in() {
        return expires_in;
    }
    public void setExpires_in(String expiresIn) {
        expires_in = expiresIn;
    }
    public String getAcquiretime() {
        return acquiretime;
    }
    public void setAcquiretime(String acquiretime) {
        this.acquiretime = acquiretime;
    }
    public String getNoncestr() {
        return noncestr;
    }
    public void setNoncestr(String noncestr) {
        this.noncestr = noncestr;
    }
    public String getTimestamp() {
        return timestamp;
    }
    public void setTimestamp(String timestamp) {
        this.timestamp = timestamp;
    }



}

② 添加到数据库的业务根据自己需要进行实现.
③ GetRandomStr

package com.wiimedia.utils;

import java.util.Random;

public class GetRandomStr {
    /**
     * 
     *<p>Project:mryl_phone_v2</p> 
     * 
     *<p>:mryl_phone_v2</p> 
     * 
     *<p>Description:生成随即字符串 </p>
     *
     *<p>Company:Wiimedia</p>
     *
     *@Athor:SongJia
     *
     *@Date:2016-7-14 上午11:14:46 
     *
     */
    public  String getRandomString(int length) {
        String base = "abcdefghijklmnopqrstuvwxyz0123456789";   
        Random random = new Random();   
        StringBuffer sb = new StringBuffer();   
        for (int i = 0; i < length; i++) {   
            int number = random.nextInt(base.length());   
            sb.append(base.charAt(number));   
        }   
        return sb.toString();   
     }
}

④ SignatureBean

package com.wiimedia.utils;

public class SignatureBean {
    private String noncestr;
    private String url;
    private String timestamp;
    private String signature;
    public String getNoncestr() {
        return noncestr;
    }
    public void setNoncestr(String noncestr) {
        this.noncestr = noncestr;
    }
    public String getUrl() {
        return url;
    }
    public void setUrl(String url) {
        this.url = url;
    }
    public String getTimestamp() {
        return timestamp;
    }
    public void setTimestamp(String timestamp) {
        this.timestamp = timestamp;
    }
    public String getSignature() {
        return signature;
    }
    public void setSignature(String signature) {
        this.signature = signature;
    }

}

⑤ WeixinUtil

package com.wiimedia.utils.weixin;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ConnectException;
import java.net.URL;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;

/**
     * 
     *<p>Project:mryl_phone_v2</p> 
     * 
     *<p>:mryl_phone_v2</p> 
     * 
     *<p>Description:公众平台接口工具类</p>
     *
     *<p>Company:Wiimedia</p>
     *
     *@Athor:SongJia
     *
     *@Date:2016-7-15 上午09:37:13 
     *
     */
public class WeixinUtil {

    /** 
     * 发起https请求并获取结果 
     *  
     * @param requestUrl 请求地址 
     * @param requestMethod 请求方式(GET、POST) 
     * @param outputStr 提交的数据 
     * @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值) 
     */  
    public static String httpRequest(String requestUrl, String requestMethod, String outputStr) {  

        StringBuffer buffer = new StringBuffer();  
        try {  
            // 创建SSLContext对象,并使用我们指定的信任管理器初始化  
            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 httpUrlConn = (HttpsURLConnection) url.openConnection();  
            httpUrlConn.setSSLSocketFactory(ssf);  

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

            if ("GET".equalsIgnoreCase(requestMethod))  
                httpUrlConn.connect();  

            // 当有数据需要提交时  
            if (null != outputStr) {  
                OutputStream outputStream = httpUrlConn.getOutputStream();  
                // 注意编码格式,防止中文乱码  
                outputStream.write(outputStr.getBytes("UTF-8"));  
                outputStream.close();  
            }  

            // 将返回的输入流转换成字符串  
            InputStream inputStream = httpUrlConn.getInputStream();  
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");  
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);  

            String str = null;  
            while ((str = bufferedReader.readLine()) != null) {  
                buffer.append(str);  
            }  
            bufferedReader.close();  
            inputStreamReader.close();  
            // 释放资源  
            inputStream.close();  
            inputStream = null;  
            httpUrlConn.disconnect();  
            return buffer.toString();  
        } catch (ConnectException ce) {  
            ce.printStackTrace(); 
        } catch (Exception e) {  
            e.printStackTrace();
        }  
        return "";  
    }
}

四 至此,分享功能已经开发完成,但是,在生成signature的时候会遇到很多问题,这里提供一些wx.config失败的排错方法.

① 确认自己的生成的signature是否正确
在微信提供的http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign进行校验

② wx.config中使用的noncestr, timestamp与用以签名中的对应noncestr, timestamp是否一致一致…如上面(一.服务器代码)
(有可能因为JS页面加载顺序问题,服务器生成的signature,noncestr,timestamp在wx.config中没有获取到)。

③ 确认url是页面完整的url,包括GET参数部分
需要去掉#后面的部分

④ config 中的 appid 与用来获取 jsapi_ticket 的 appid 是否一致

⑤ 报错{errmsg:config:ok}是debug的正常返回把调试模式关掉就OK
wx.config debug: false,



能力有限,希望有问题及时邮箱或留言,谢谢.

Email:358106209@qq.com

2015-12-10 20:24:26 qq_16558621 阅读数 1131
  • 微信支付开发-微信公众号开发12-微信开发php

    微信公众平台开发之微信支付开发是子恒老师《微信公众平台开发》视频教程的第12部。详细讲解了用php进行微信支付的开发。内容包含获取支付密钥,微信公众号支付开发,扫码支付,微信刷卡支付,异步处理支付结果等等。欢迎反馈,微信/QQ:68183131

    27832 人正在学习 去看看 秦子恒

这几天做微信开发,深一脚浅一脚,总算摸出来一些门道和一些小小的感悟。

今天给大家分享一个在微信平台php发送HTTP GET请求的方法:

public function get_request($url)
		{
		$curl = curl_init();
		curl_setopt($curl, CURLOPT_URL, $url);
		curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
		curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
		curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
		$data = curl_exec($curl);
		if (curl_errno($curl)) {return 'ERROR '.curl_error($curl);}
		curl_close($curl);
		return $data;
	   }

2016-12-23 16:53:57 u013248535 阅读数 29150
  • 微信支付开发-微信公众号开发12-微信开发php

    微信公众平台开发之微信支付开发是子恒老师《微信公众平台开发》视频教程的第12部。详细讲解了用php进行微信支付的开发。内容包含获取支付密钥,微信公众号支付开发,扫码支付,微信刷卡支付,异步处理支付结果等等。欢迎反馈,微信/QQ:68183131

    27832 人正在学习 去看看 秦子恒

发送消息,是指用户公众号向用户发送相应形式的消息。根据微信开发文档,由以下四种形式:被动回复,群发接口,客服消息接口以及模板消息接口。本文将基于Java语言以及个人微信测试号,说明被动回复、客服消息接口以及模板消息接口的使用实现,群发接口并未涉及。
1. 被动回复
被动回复只能应用于在接收到用户的互动数据之后,才能向用户发送消息。这一部分较为简单,正式进行微信开发的第一步就是,在公众号中基本配置->服务器配置中设置URL(服务器地址)时,这时该URL链接指定的地址就是对应着Java Web下的一个Servlet,配置好对应的Token及相关参数之后,则微信服务器将会将所有的用户与公众号的互动信息都转发到该Servlet,然后开发者根据接收到的用户互动数据,再进行处理。所谓的被动回复,就是在该Servlet中判断接收到你指定的消息时(例如某个字眼),则直接将想要回复的消息打包成官方指定的XML数据格式,写回到输出流中即可。在这里不过过多解释,如下示例代码:

response.getWriter().write( MessageUtil.MessageToXML(new TextMessage.Builder(fromUserName,toUserName,new Date().getTime(),"最新资讯请查看下方微信菜单栏,谢谢您的关注").build()));

2.客服消息接口
客服消息接口,应用于公众号主动向特定用户(必须满足该用户在48小时内与公众号有交互)发送特定格式的消息,应用场景例如:用户在微页面上完成了抽奖,而这时候公众号主动向用户推送中奖信息。所回复的不同消息的格式,参见开发者文档,下面以回复文本消息作为示例,需要注意的是推送的消息data必须满足json格式,请求类型为post。返回的json数据中,若errorcode为0,则代表推送成功。

 //推送中奖消息
        String data = "{"+
                "\"touser\":\""+openid+"\","+
                "\"msgtype\":\"text\","+
                "\"text\":"+
                "{"+
                "\"content\":\""+content+"\""+
                "}"+
                "}";
        System.out.println(data);
        String reMsg0 = UrlReqUtil.post("https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token="+access_token,data);
        JSONObject jsonObject = JSONObject.fromObject(reMsg0);
        if(0 != (Integer) jsonObject.get("errcode")) throw new RuntimeException("通知用户失败");

3.模板消息接口
模板消息接口的使用场景大体与客服消息接口一致,只是不需要证明对象用户“在线”,即48小时内与当前公众号有交互记录,因而应用范围更为广泛。在具有权限的服务号中使用该接口时,需要向系统申请对应模板,并得到模板号,作为调用凭据。在测试号环境下,则需要自定义模板。例如:
这里写图片描述
其中模板内容需要严格遵循指定的格式,即在需要调用才填入的变量值的定义方式为:{{xxxx.DATA}},其中“xxxx”为调用时对应的字段名。
以下是调用代码:jsonData数据部分遵循json数据格式。
其中touser:为用户在该公众号下的openid
template_id:为模板id
对于每个字段,包含两个值,一是value,即填入模板的具体值;二是color,即对应的字体颜色。
请求方式为post,判断是否成功同样是依据errcode字段,为0则成功。

        //推送模板消息
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        String jsonData = "{" +
                "\"touser\":\""+openid+"\"," +
                "\"template_id\":\"maD2W1yaTvkXmh1dRjXEsMHUc9dDP8Xh1eANP***ig\"," +
                "\"topcolor\":\"#FF0000\"," +
                "\"data\":{" +
                "\"title\":{\"value\":\"恭喜您中奖啦\",\"color\":\"#173177\"}," +
                "\"nickname\":{\"value\":\""+nickname+"\",\"color\":\"#173177\"}," +
                "\"prizeLevel\":{\"value\":\""+rewardLevel+"\",\"color\":\"#173177\"}," +
                "\"prizeContent\":{\"value\":\""+ ConfigParamUtil.PRIZE_CONTENT.split(",")[rewardLevel]+"\",\"color\":\"#173177\"}," +
                "\"time\":{\"value\":\""+dateFormat.format(new Date())+"\",\"color\":\"#173177\"}," +
                "\"bonus\":{\"value\":\"10积分\",\"color\":\"#173177\"}}}";
        String reMsg1 = UrlReqUtil.post("https://api.weixin.qq.com/cgi-bin/message/template/send?access_token="+access_token,jsonData);
        JSONObject jsonObject = JSONObject.fromObject(reMsg1);
        if(0 != (Integer) jsonObject.get("errcode")) throw new RuntimeException("通知用户失败");
2019-05-16 14:03:49 weixin_43278947 阅读数 101
  • 微信支付开发-微信公众号开发12-微信开发php

    微信公众平台开发之微信支付开发是子恒老师《微信公众平台开发》视频教程的第12部。详细讲解了用php进行微信支付的开发。内容包含获取支付密钥,微信公众号支付开发,扫码支付,微信刷卡支付,异步处理支付结果等等。欢迎反馈,微信/QQ:68183131

    27832 人正在学习 去看看 秦子恒

微信开发-关于分享朋友&朋友圈以及录音功能
两天刚整理了一个关于微信开发录音功能的开发步骤,网上这方面资料已经很多了,写下来就当作自己的笔记。

一. 首先需要在微信公众号中进行配置(其中Token为自定义项)
在这里插入图片描述
二. 在配置的域名文件夹下放置checkwei.php文件,用来验证配置是否成功。如下:

<?php
header('Content-type:text');
define("TOKEN", "weixin");
$wechatObj = new wechatCallbackapiTest();
if (isset($_GET['echostr'])) {
    $wechatObj->valid();
}else{
    $wechatObj->responseMsg();
}
 
class wechatCallbackapiTest
{
    public function valid()
    {
        $echoStr = $_GET["echostr"];
        if($this->checkSignature()){
            header('content-type:text');
            echo $echoStr;
            exit;
        }
    }
 
    private function checkSignature()
    {
        $signature = $_GET["signature"];
        $timestamp = $_GET["timestamp"];
        $nonce = $_GET["nonce"];
 
        $token = TOKEN;
        $tmpArr = array($token, $timestamp, $nonce);
        sort($tmpArr, SORT_STRING);
        $tmpStr = implode( $tmpArr );
        $tmpStr = sha1( $tmpStr );
 
        if( $tmpStr == $signature ){
            return true;
        }else{
            return false;
        }
    }
}

三.配置js接口安全域名,配置后公众号开发者可在该域名下调用微信开放的JS接口
在这里插入图片描述
按照提示进行第三部操作:
在这里插入图片描述
四.准备jssdk文件,现已经整理出一个分享的js_sdk包,所以前端同事在做的项目中直接引入这个封装好的包就行,jssdk包无需做任何修改!

(1)前端同事写的页面后缀多为.html或.shtml文件,需将页面的后缀改为.php ,因为在页面中需要嵌入PHP的代码,若是.html,.shtml后缀则无法解析。(该方法比较笨,因为我做的时候用的就是简单的一个页面所以就这样做了)

(2)引入一小段php文件,必须在文件开头引入,因为php规定require一个文件前面不能有任何输出。代码实例如下:

<?php
require_once "jssdk.php";
$jssdk=new JSSDK
 ("wx****************a","86****************************67");
$signPackage =$jssdk->GetSignPackage();
?>

五.这次主要做的是一个关于微信录音,将录音资源从微信服务器下载到本地服务器的一个过程。不过先将获取用户信息这个步骤代码贴出来:
1.

	https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx***********************291&redirect_uri=http://www.demo.com/index.php/Ch/Cms/Uploadwxvoice/index&response_type=code&scope=snsapi_userinfo&state=1#wechat_redirect

2.//通过授权获取用户的信息
public function index(){
$appid = “wx*********291”;
$secret = “eb************************23eb2”;
$code = $_GET[“code”];

		//使用code换取oauth2的授权access_token
		$token_obj = json_decode(file_get_contents('https://api.weixin.qq.com/sns/oauth2/access_token?appid=’.$appid.’ &secret=’.$secret.’ &code='.$code.'&grant_type=authorization_code'));
		$access_token = $token_obj->access_token;
		$openid = $token_obj->openid;
		
		//使用授权Access Token和openid获取用户信息`
		$user_obj = json_decode(file_get_contents('https://api.weixin.qq.com/sns/userinfo?access_token='.$access_token.'&openid='.$openid.'&lang=zh_CN'));
		
		//将相关信息存储进session
		$_SESSION['openid'] = $user_obj->openid;
		$_SESSION['nickname'] = $user_obj->nickname;
		$_SESSION['headimgurl'] = $user_obj->headimgurl;
	
		$this->display();
		
}

六.接下来可以进行调用接口开发。首先配置config项,注册需要调用的接口,
注意:需要先引入微信js文件
在这里插入图片描述

<script>
    //微信分享
    // var share_image = "";
    // var share_link = "";
    // var share_desc = '';
    // var share_title = '部落PK联盟';
    wx.config({
        debug: false,
        appId: '<?php echo $signPackage["appId"];?>',
        timestamp: <?php echo $signPackage["timestamp"];?>,
        nonceStr: '<?php echo $signPackage["nonceStr"];?>',
            signature: '<?php echo $signPackage["signature"];?>',
            jsApiList: [
        // 所有要调用的 API 都要加到这个列表中
        'onMenuShareAppMessage',//分享朋友
        'onMenuShareTimeline',///分享朋友圈
        'startRecord',//开始录音
		'stopRecord',//停止录音
		'onVoiceRecordEnd',//监听录音自动停止接口
		'playVoice',//播放录音
		'pauseVoice',//暂停云隐接口
		'stopVoice',//停止播放
		'onVoicePlayEnd',//
		'uploadVoice',//上传语音
		'downloadVoice'//下载语音
    ]
    });
    wx.ready(function () {
	
	
		//朋友圈
		wx.onMenuShareTimeline({
			title:' ',//标题
			link:'',//链接
			imgUrl:'',//图片
			success:function(){
 
			},
			cancle:function(){
 
			}
 
 
 
		});
 
		//朋友
		wx.onMenuShareAppMessage({
			title:' ',
			desc:' ',//描述
			link:'',
			imgUrl:'',
			type:'',//分享类型music  不填默认是link
			dataUrl:'',//如过类型是music  video  需要填写链接  默认为空
			success:function(){
 
			},
			cancle:function(){
 
			}
 
 
 
		});
	if(!localStorage.rainAllowRecord || localStorage.rainAllowRecord !== 'true'){
    wx.startRecord({
        success: function(){
            localStorage.rainAllowRecord = 'true';
            wx.stopRecord();
        },
        cancel: function () {
            alert('用户拒绝授权录音');
        }
    });
}
 
        // 4 音频接口
  // 4.2 开始录音
  document.querySelector('#startRecord').onclick = function () {
	 START = new Date().getTime();
 
    recordTimer = setTimeout(function(){
        wx.startRecord({
            success: function(){
                localStorage.rainAllowRecord = 'true';
				alert('true');
            },
            cancel: function () {
                alert('用户拒绝授权录音');
            }
        });
    },300);
  };
var voice = {
localId: '',
serverId: ''
};
  // 4.3 停止录音
  document.querySelector('#stopRecord').onclick = function () {
   END = new Date().getTime();
    
    if((END - START) < 300){
        END = 0;
        START = 0;
        //小于300ms,不录音
        clearTimeout(recordTimer);
    }else{
        wx.stopRecord({
          success: function (res) {  
          voice.localId = res.localId;
          //uploadVoice();	
          },
          fail: function (res) {
            alert(JSON.stringify(res));
          }
        });
    }
  };
  
  // 4.4 监听录音自动停止
  wx.onVoiceRecordEnd({
    complete: function (res) {
      voice.localId = res.localId;
      alert('录音时间已超过一分钟');
    }
  });
  // 4.5 播放音频
  document.querySelector('#playVoice').onclick = function () {
    if (voice.localId == '') {
      alert('请先使用 startRecord 接口录制一段声音');
      return;
    }
    wx.playVoice({
      localId: voice.localId
    });
  };
  // 4.6 暂停播放音频
  document.querySelector('#pauseVoice').onclick = function () {
    wx.pauseVoice({
      localId: voice.localId
    });
  };
  // 4.7 停止播放音频
  document.querySelector('#stopVoice').onclick = function () {
    wx.stopVoice({
      localId: voice.localId
    });
  };
  // 4.8 监听录音播放停止
  wx.onVoicePlayEnd({
    complete: function (res) {
      alert('录音(' + res.localId + ')播放结束');
    }
  });
  // 4.8 上传语音
  document.querySelector('#uploadVoice').onclick = function () {
    if (voice.localId == '') {
      alert('请先使用 startRecord 接口录制一段声音');
      return;
    }
   wx.uploadVoice({
    localId: voice.localId, // 需要上传的音频的本地ID,由stopRecord接口获得
    isShowProgressTips: 1, // 默认为1,显示进度提示
        success: function (res) {
        var serverId = res.serverId; // 返回音频的服务器端ID
		alert(serverId);
		 $.ajax({
                url: '/index.php/Ch/Cms/Uploadwxvoice/upload',//通过ajax请求后台进行语音资源向本地服务器下载的操作
                type: 'POST',
               data : { serverId : serverId },
                dataType: "html",
                success: function (data) {
                    alert('OK');
					console.log(data);
                },
                error: function (xhr, errorType, error) {
                    console.log(error);
                }
            });
    }
	});
  };
  // 4.9 下载语音
  document.querySelector('#downloadVoice').onclick = function () {
    if (voice.serverId == '') {
      alert('请先使用 uploadVoice 上传声音');
      return;
    }
    wx.downloadVoice({
      serverId: voice.serverId,
      success: function (res) {
        alert('下载语音成功,localId 为' + res.localId);
        voice.localId = res.localId;
      }
    });
  };
    });
wx.error(function (res) {
  alert(res.errMsg);
});
</script>

七.第六步中的 Uploadwxvoice() 方法代码如下:

//上传操作,将微信服务器上的文件下载到本地服务器
    public function upload(){
		$model = M('wxly');
		//media_id(serverId)为微信jssdk接口上传后返回的媒体id
        $media_id = $_POST['serverId'];
		
		$token_data = json_decode(file_get_contents("./luyin/access_token.json"));
        $access_token = $token_data->access_token;
 
		$path = "./Wxupload/";   //保存路径,相对当前文件的路径
		 if(!is_dir($path)){
			mkdir($path);
		}
			
		//微 信上传下载媒体文件
		$url = "http://file.api.weixin.qq.com/cgi-bin/media/get?access_token={$access_token}&media_id={$media_id}";
		
		
		$filename = $media_id.".amr";//下载下来的文件名字,前缀可自定义,在此步骤后可将下载的资源上传七牛云进行转码为 .MP3 再次下载操作,功能不需要可忽略
			
		$filepath = $path.$filename;
	
		
		ob_start();
		readfile($url);
		$img  = ob_get_contents();
		ob_end_clean();
		$size = strlen($img);
		$fp = fopen($path."/".$filename, 'a');
		fwrite($fp, $img);
		fclose($fp);
			
		 
		
		$data['name'] = $name;
		$data['phone'] = $phone;
		$data['source'] = $biaoti;
		$data['attachment'] = $filename;
		$data['zattachment'] = $zfilename;
		$data['openid'] = $_SESSION['openid'];
		$data['nickname'] = $_SESSION['nickname'];
		$data['headimgurl'] = $_SESSION['headimgurl'];
		$data['status'] = 0;
		$data['writetime'] = time();
 
 
		// 保存当前数据对象
		if ($result = $model->add($data)) { //保存成功
			echo 'uploadok';
		} else {
			echo 'uploaderror';
		} 
		//echo json_encode($arr);
	}
2018-02-03 09:43:54 yji534123343 阅读数 913
  • 微信支付开发-微信公众号开发12-微信开发php

    微信公众平台开发之微信支付开发是子恒老师《微信公众平台开发》视频教程的第12部。详细讲解了用php进行微信支付的开发。内容包含获取支付密钥,微信公众号支付开发,扫码支付,微信刷卡支付,异步处理支付结果等等。欢迎反馈,微信/QQ:68183131

    27832 人正在学习 去看看 秦子恒
一、微信开发的整体介绍
开放平台:https://open.weixin.qq.com/
公众平台:https://mp.weixin.qq.com/
1、微信开发的种类
①移动应用开发
支持微信的分享、收藏、支付三大功能,原生开发的人员去使用的开发类别
②网站应用开发
网站支持使用微信账号进行注册和登录,从而来实现:提高用户的留存率,方便不同账号的统一(结合unionId)
③公众账号开发


④公众账号第三方平台
优势在于免繁琐设置,方便小白用户去使用。


2、公众账号开发
①服务号
主要偏向于给用户提供查询服务(招商银行、麦当劳。。)
显示在好友列表,每个月只能群发4条消息


②订阅号
主要偏向于给用户提供资讯(朝闻天下、Web前端。。)
显示在订阅号文件夹内,每天都可以群发1条消息


③小程序
2017年1月9号 (2007年1月9号 推出iphone)
基于微信的平台,ui提供了很多组件,js提供了很多接口


(微信官方的小程序:小程序示例,包含了微信官方封装好的组件、以及封装好的接口)


目标:万物互联 (IOT),  二维码
开放范围:(不包含个人)
http://www.wxapp-union.com/forum.php?mod=viewthread&tid=495


https://mp.weixin.qq.com/debug/wxadoc/dev/index.html


数据存储和服务器:
两种解决方案 ①腾讯云(不到100) ②godaddy


④企业号
主要是建立起 企业与人的关系,提供信息、和企业相关的定制功能


温馨提示:
1)如果想简单的发送消息,达到宣传效果,建议可选择订阅号;
2)如果想进行商品销售,进行商品售卖,建议可申请服务号;
3)如果想用来管理内部企业员工、团队,对内使用,可申请企业号。
4)订阅号可通过微信认证资质审核通过后有一次升级为服务号的入口,升级成功后类型不可再变。
5)服务号不可变更成订阅号。


3、九大类高级接口


语音识别接口
客服接口
OAuth2.0 网页授权接口
生成带参数的二维码接口
获取用户地理位置接口
获取用户基本信息接口
获取关注者列表接口
用户分组接口
上传下载多媒体文件接口


+ 微信支付
(十大类接口的使用,必须是认证过的服务号和订阅号才能使用)




4、正式环境的搭建
(公众账号-》订阅号)


购买自己的域名(万网、dnsPod、godaddy)
购买申请主机空间(新浪云、阿里云、腾讯云、大米云、godaddy、aws)
注册订阅号
登录到订阅号管理接口、服务器的配置、调用10大类接口


5、测试环境的搭建
(公众账号-》订阅号)


主机空间(新浪云)
注册订阅号
登录到订阅号管理接口、服务器的配置、调用10大类接口


6、注册订阅号
①填写邮箱、密码
②到邮箱中激活账号
③选择类型
④登记信息(个人、组织、媒体、企业。。)
⑤填写公众号的信息(名称、介绍、头像)






二、个人订阅号(jssdk)


1、实现功能:统计页面被访问的次数


分析:
①存储需要持久保存的数据
数据库、文件系统、内存中:fileSystem
②读写过程
读:file_get_contents($fileUrl);
写:file_put_contents($fileUrl,$content);


需要apache启动


2、新浪云storage


通过bucket管理我们的文件,如何访问?
saestor:// testbucket/count.txt




3、jsSDK的使用步骤
①绑定域名
②引入js文件
③注入接口(将使用接口的名称,写在config方法中jsAPIList这个数组中)
④在ready中调用接口
⑤在error中处理失败的异常情况






sample.zip有4个文件,
前两个文件都是用来存储数据的,jssdk.php进行网络请求以及数据的读写操作,sample.php文件主要完成接口的注入和调用


jssdk.php封装了2个方法get_php_file、set_php_file,如果部署在服务端,写文件会出现权限拒绝的问题。
①将存储文件 放到新浪云的bucket中
②修改读写文件的路径为 saestor://bucketName/**.php




require subscribe 需要订阅测试账号。




三、版本控制工具(git)


1、版本控制
记录一个或者多个文件内容变化,以便于未来查询指定的版本信息。


svn 集中式/git  分布式
①防止代码的丢失
②团队协作
③版本还原
④更好的管理代码


2、git介绍
用于代码的版本控制,使用方式:命令行/图形化


git(分布式版本控制工具)与github(托管开源项目的网站,托管项目的方式采用的是git)


3、自己使用git将项目上传到github


①申请github的账号 
https://github.com/
注册账号,在选择计划的时候选择continue,在编辑经验时选择skip跳过。
②去邮件激活账号
③start project 只需要指定repository的名称,点击create去创建。


④安装git
一路next,最后点击install安装 取消所有的勾选就可以了。
⑤启动git
到所有程序中,找到git,找到gitbash,点击启动


⑥基础命令
ls (list) 查看当前目录下的文件
clear 清除当前的屏幕信息
pwd (print the work directory)显示当前目录
mkdir web1609 在当前的路径中创建一个叫做web1609的目录
cd web1609 (change directory)
touch a.txt 创建一个叫做a.txt的一个文件


通过电脑中的文件系统找到文件,写上了hello git.


git的用法


git init 初始化仓库
git status 查看仓库的状态
git add a.txt 将a.txt添加到代码仓库
git commit -m '第一次提交'     添加到缓存区


配置上传到github上的用户信息:
git config --global user.name "web1609best"
git config --global user.email "web1609@vip.163.com"


设置完账号之后,重新提交到缓存区:
git commit -m '第一次提交'     添加到缓存区


将本地的代码设置它推送到github上的地址:
git remote add origin https://github.com/web1609best/web1609.git


将当前目录的git仓库推送到github对应的origin地址的master分支
git push origin master

















微信开发之JSSDK调用

阅读数 20068

没有更多推荐了,返回首页