2019-10-25 23:18:59 wxwsfl 阅读数 47
  • MUI+HTML5plus混合应用开发视频教程(微信APP实战)

    MUI+HTML5plus混合应用开发(微信APP实战)的课程主要介绍了如何使用移动端框架(mui)完成移动端混合应用开发,课程以移动端框架MUI为基础,以微信app项目为目标,介绍MUI框架的使用,包含移动端排版布局,借助HTML5Plus来手机摄像头调用、手机相册调用、手机重力感应调用,并终完成微信案例项目。

    1545 人正在学习 去看看 张鹏

今天编写一个网页授权接口开发的实例,希望对大家的工作有所帮助

微信公众号开发文档地址:https://developers.weixin.qq.com/doc/offiaccount/Getting_Started/Overview.html

网页授权文档地址:https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html

准备工作:

 微信平台测试号配置:

找到网页服务 --  网页账号 -- 授权接口的配置

点击修改, 添加内网映射的域名

注意, 前方有坑,请注意躲避----------此处的填写的是域名,不是URL,无需添加 http:// 协议

 

公众号配置完成后,开始上代码:

1.创建实体类

/**
 * @author:         diego
 * @date:           2019/2/20 15:57
 * @description:    微信常用属性定义
 * @version:        1.0
 */
public class WeChat {

    //自定义Token
    private String token = "token";

    //微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。
    private String signature;

    //时间戳
    private String timestamp;

    //随机数
    private String nonce;

    //随机字符串
    private String echostr;

    //用户同意授权返回code
    private String code;

    public String getToken() {
        return token;
    }

    public void setToken(String token) {
        this.token = token;
    }

    public String getSignature() {
        return signature;
    }

    public void setSignature(String signature) {
        this.signature = signature;
    }

    public String getTimestamp() {
        return timestamp;
    }

    public void setTimestamp(String timestamp) {
        this.timestamp = timestamp;
    }

    public String getNonce() {
        return nonce;
    }

    public void setNonce(String nonce) {
        this.nonce = nonce;
    }

    public String getEchostr() {
        return echostr;
    }

    public void setEchostr(String echostr) {
        this.echostr = echostr;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }
}

2.常量定义


public class WeChatConstDefine {

    /*------------------------------------------- 常量 -------------------------------------------*/

    public static final Boolean TRUE = true;

    public static final Boolean FALSE = false;

    public static final String GET = "GET";

    public static final String POST = "POST";

    public static final String ENCODE_UTF_8 = "UTF-8";

    public static final String ENCODE_GBK = "GBK";


    /*---------------------------------------- 微信请求地址 ----------------------------------------*/

    //用户同意授权,获取code
    public static final String authorize = "https://open.weixin.qq.com/connect/oauth2/authorize";

    //通过code换取网页授权access_token
    public static final String access_token = "https://api.weixin.qq.com/sns/oauth2/access_token";

    //刷新access_token(如果需要)
    public static final String refresh_token = "https://api.weixin.qq.com/sns/oauth2/refresh_token";

    //拉取用户信息(需scope为 snsapi_userinfo)
    public static final String userInfo = "https://api.weixin.qq.com/sns/userinfo";

    //检验授权凭证(access_token)是否有效
    public static final String auth = "https://api.weixin.qq.com/sns/auth";

    //重定向后缀参数
    public static final String weChat_redirect = "#wechat_redirect";

}

3.自定义异常类

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class MyException extends RuntimeException {


    public MyException(String message) {
        super(message);
        log.info("/************************My Exception************************/");
        log.info("");
        log.info("");
        log.info(message);
        log.info("");
        log.info("");
        log.info("/************************My Exception************************/");
    }

    public MyException(Exception e) {
        super(e);
        log.info("/************************My Exception************************/");
        log.info("");
        log.info("");
        log.info(e.getMessage());
        log.info("");
        log.info("");
        log.info("/************************My Exception************************/");
    }

    public MyException(String message, Exception e) {
        super(message, e);
        log.info("/************************My Exception************************/");
        log.info("");
        log.info("");
        log.info("My Message:" + message);
        log.info("System Message:" + e.getMessage());
        log.info("");
        log.info("");
        log.info("/************************My Exception************************/");
    }
}

4.编码-解码工具类

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;

/**
 * @author:         diego
 * @date:           2019/1/29 10:39
 * @description:    编码-解码工具类
 * @version:        1.0
 */
public class EncodeUtils {

	/**
	 * URL 编码
	 */
	public static String urlEncode(String url,String encode) {
		if(null == url || "".equals(url) || null == encode && "".equals(encode)){
			throw new MyException("The url or encode is not null.");
		}else{
			try {
				return URLEncoder.encode(url, WeChatConstDefine.ENCODE_UTF_8);
			} catch (UnsupportedEncodingException e) {
				throw new MyException(e);
			}
		}
	}

	/**
	 * URL 解码
	 */
	public static String urlDecode(String url,String encode) {
		if(null == url || "".equals(url) || null == encode && "".equals(encode)){
			throw new MyException("The url or encode is not null.");
		}else{
			try {
				return URLDecoder.decode(url, WeChatConstDefine.ENCODE_UTF_8);
			} catch (UnsupportedEncodingException e) {
				throw new MyException(e);
			}
		}
	}
}

5.http工具类

import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Iterator;
import java.util.Map;

/**
 * @author:         diego
 * @date:           2019/1/29 10:39
 * @description:    Http请求工具类
 * @version:        1.0
 */
public class HttpConnectionUtils {

    public static HttpConnectionUtils getHttp() {
        return new HttpConnectionUtils();
    }


    // url发送请求
    public String sendRequest(String url, String method, Map<String, Object> map,String suffix) throws MyException{
        String result = "";
        if (null == url || url.equals("")) {
            throw new MyException("The url is null.");
        }else if (null == method || method.equals("")) {
            method = WeChatConstDefine.GET;
        }else{
            if(!WeChatConstDefine.GET.equals(method) && !WeChatConstDefine.POST.equals(method)){
                throw new MyException("request method is error. you only use 'POST' or 'GET'.");
            }else{
                if(WeChatConstDefine.GET.equals(method)){
                    return sendByGetMethod(url, map,suffix);
                }else if(WeChatConstDefine.POST.equals(method)){
                    HttpURLConnection connection = getConnection(url, WeChatConstDefine.POST);
                    return sendByPostMethod(url,connection, map,suffix);
                }
            }
        }
        return result;
    }


    // url 拼接 参数
    public String analyticParams(String url,Map<String,Object> map,String suffix) throws MyException{
        StringBuffer params = new StringBuffer(url+"?");
        if(map != null && map.size() > 0){
            Iterator<String> it = map.keySet().iterator();
            do{
                String param = it.next();
                if(it.hasNext()){
                    params.append(param + "=" + map.get(param) + "&");
                }else{
                    params.append(param + "=" + map.get(param));
                }
            }while (it.hasNext());
        }else{
            throw new MyException("url parameter resolution failed.");
        }

        String httpUrl = "";
        if(null != suffix){
            httpUrl = params.toString() + suffix;
        }else{
            httpUrl = params.toString();
        }
        return httpUrl;
    }


    // get HttpURLConnection
    private HttpURLConnection getConnection(String urlString, String method) throws MyException {
        URL url = null;
        HttpURLConnection result = null;
        try {
            url = new URL(urlString);
            result = (HttpURLConnection) url.openConnection();
            result.setRequestMethod(method);
        } catch (Exception e) {
            throw new MyException(e);
        }

        if (null == result) {
            throw new MyException("HttpURLConnection is null.");
        }
        return result;
    }


    // get request method
    private String sendByGetMethod(String url, Map<String, Object> params,String suffix) throws MyException {
        // 拼接url
        String urlParams = this.analyticParams(url,params,suffix);

        HttpURLConnection connection = this.getConnection(urlParams, WeChatConstDefine.GET);
        try {
            connection.connect();
        } catch (IOException e) {
            throw new MyException(e);
        }

        return  getResponseResult(connection);
    }


    // post request method
    private String sendByPostMethod(String url,HttpURLConnection connection, Map<String, Object> params,String suffix) throws MyException {
        // 初始化post请求属性
        this.initPostProperties(connection);
        // 发送参数
        this.sendParams(url,connection, params,suffix);

        return  getResponseResult(connection);
    }


    // 初始化post请求属性
    private void initPostProperties(HttpURLConnection connection) {
        connection.setUseCaches(false);
        connection.setInstanceFollowRedirects(true);
        connection.setDoOutput(true);
        connection.setDoInput(true);
        connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
    }


    // 发送参数
    private void sendParams(String url,HttpURLConnection connection, Map<String, Object> params,String suffix) throws MyException {
        DataOutputStream out = null;
        try {
            connection.connect();
            out = new DataOutputStream(connection.getOutputStream());
            String stringParam = this.analyticParams(url,params,suffix);
            out.writeBytes(stringParam);
            out.flush();
        } catch (IOException e) {
            throw new MyException("Send param error : " + e);
        } finally {
            close(out);
        }
    }


    // 获取服务器返回结果
    private String getResponseResult(HttpURLConnection connection) throws MyException {
        StringBuilder result = new StringBuilder();
        InputStream in = null;
        try {
            in = connection.getInputStream();
            byte[] buff = new byte[1024];
            int flag = -1;

            while ((flag = in.read(buff)) != -1) {
                result.append(new String(buff, 0, flag, WeChatConstDefine.ENCODE_UTF_8));
            }
            in.close();
        } catch (IOException e) {
            throw new MyException(e);
        } finally {
            close(in);
        }
        return result.toString();
    }


    // close input stream
    private void close(InputStream in) {
        if (null != in) {
            try {
                in.close();
            } catch (IOException e) {
                throw new MyException(e);
            }
        }
    }


    // close output stream
    private void close(OutputStream out) {
        if (null != out) {
            try {
                out.close();
            } catch (IOException e) {
                throw new MyException(e);
            }
        }
    }

}

6.QR码工具类

import com.google.zxing.*;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.Hashtable;


/**
 * @author:         diego
 * @date:           2019/1/29 10:42
 * @description:    二维码工具类
 * @version:        1.0
 */
public class QRCodeUtils {

    private static final String CHARSET = "utf-8";
    private static final String FORMAT_NAME = "JPG";
    // 二维码尺寸
    private static final int QRCODE_SIZE = 300;
    // LOGO宽度
    private static final int WIDTH = 60;
    // LOGO高度
    private static final int HEIGHT = 60;

    /** 生成二维码 */
    private static BufferedImage createImage(String content,InputStream logo)throws Exception {
        Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>();
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        hints.put(EncodeHintType.CHARACTER_SET, CHARSET);
        hints.put(EncodeHintType.MARGIN, 1);
        BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE,QRCODE_SIZE, QRCODE_SIZE, hints);
        int width = bitMatrix.getWidth();
        int height = bitMatrix.getHeight();
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
            }
        }
        // 插入图片
        QRCodeUtils.insertImage(image, logo, true);
        return image;
    }


    /** 在二维码中间插入logo图片 */
    private static void insertImage(BufferedImage source, InputStream logo, boolean needCompress)throws Exception {
        if(logo==null)return;
        Image src = ImageIO.read(logo);
        int width = src.getWidth(null);
        int height = src.getHeight(null);
        if (needCompress) { // 压缩LOGO
            if (width > WIDTH) {
                width = WIDTH;
            }
            if (height > HEIGHT) {
                height = HEIGHT;
            }
            Image image = src.getScaledInstance(width, height, Image.SCALE_SMOOTH);
            BufferedImage tag = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            Graphics g = tag.getGraphics();
            g.drawImage(image, 0, 0, null); // 绘制缩小后的图
            g.dispose();
            src = image;
        }
        // 插入LOGO
        Graphics2D graph = source.createGraphics();
        int x = (QRCODE_SIZE - width) / 2;
        int y = (QRCODE_SIZE - height) / 2;
        graph.drawImage(src, x, y, width, height, null);
        Shape shape = new RoundRectangle2D.Float(x, y, width, width, 6, 6);
        graph.setStroke(new BasicStroke(3f));
        graph.draw(shape);
        graph.dispose();
    }


    /**
     * 生成二维码
     * @param content 文本内容
     * @param logo 内嵌图标
     * @param output 输出流
     * @throws Exception
     */
    public static void encode(String content, InputStream logo, OutputStream output) throws Exception {
        BufferedImage image = QRCodeUtils.createImage(content, logo);
        ImageIO.write(image, FORMAT_NAME, output);
    }
    public static void encode(String content, InputStream logo, File out)throws Exception {
        if(!out.getParentFile().exists()){
            out.getParentFile().mkdirs();
        }
        out.createNewFile();
        QRCodeUtils.encode(content, logo, new FileOutputStream(out));
    }
    public static void encode(String content, File logo, OutputStream out)throws Exception {
        if(logo.exists()){
            QRCodeUtils.encode(content, new FileInputStream(logo), out);
        }else{
            QRCodeUtils.encode(content,(InputStream)null, out);
        }
    }
    public static void encode(String content, File logo, File out)throws Exception {
        if(!out.getParentFile().exists()){
            out.getParentFile().mkdirs();
        }
        out.createNewFile();
        if(logo.exists()){
            QRCodeUtils.encode(content, new FileInputStream(logo), out);
        }else{
            QRCodeUtils.encode(content,(InputStream)null, out);
        }
    }
    public static void encode(String content, InputStream logo, String out)throws Exception {
        QRCodeUtils.encode(content, logo, new File(out));
    }
    public static void encode(String content, String logo, String out) throws Exception {
        QRCodeUtils.encode(content, new File(logo), new File(out));
    }
    public static void encode(String content, OutputStream out) throws Exception {
        QRCodeUtils.encode(content, (InputStream)null, out);
    }
    public static void encode(String content, String out)throws Exception {
        QRCodeUtils.encode(content,(InputStream)null, new File(out));
    }




    /**
     * 解析二维码,input是二维码图片流
     */
    public static String decode(InputStream input) throws Exception {
        BufferedImage image = ImageIO.read(input);
        if (image == null) {
            return null;
        }
        BufferedImageLuminanceSource source = new BufferedImageLuminanceSource(image);
        BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
        Result result;
        Hashtable<DecodeHintType, Object> hints = new Hashtable<DecodeHintType, Object>();
        hints.put(DecodeHintType.CHARACTER_SET, CHARSET);
        result = new MultiFormatReader().decode(bitmap, hints);
        String resultStr = result.getText();
        return resultStr;
    }
    /**
     * 解析二维码,file是二维码图片
     */
    public static String decode(File file) throws Exception{
        return decode(new FileInputStream(file));
    }
    /**
     * 解析二维码,path是二维码图片路径
     */
    public static String decode(String path) throws Exception {
        return QRCodeUtils.decode(new File(path));
    }

    private static class BufferedImageLuminanceSource extends LuminanceSource {
        private final BufferedImage image;
        private final int left;
        private final int top;

        public BufferedImageLuminanceSource(BufferedImage image) {
            this(image, 0, 0, image.getWidth(), image.getHeight());
        }

        public BufferedImageLuminanceSource(BufferedImage image, int left, int top, int width,
                                            int height) {
            super(width, height);

            int sourceWidth = image.getWidth();
            int sourceHeight = image.getHeight();
            if (left + width > sourceWidth || top + height > sourceHeight) {
                throw new IllegalArgumentException("Crop rectangle does not fit within image data.");
            }

            for (int y = top; y < top + height; y++) {
                for (int x = left; x < left + width; x++) {
                    if ((image.getRGB(x, y) & 0xFF000000) == 0) {
                        image.setRGB(x, y, 0xFFFFFFFF); // = white
                    }
                }
            }

            this.image = new BufferedImage(sourceWidth, sourceHeight, BufferedImage.TYPE_BYTE_GRAY);
            this.image.getGraphics().drawImage(image, 0, 0, null);
            this.left = left;
            this.top = top;
        }

        public byte[] getRow(int y, byte[] row) {
            if (y < 0 || y >= getHeight()) {
                throw new IllegalArgumentException("Requested row is outside the image: " + y);
            }
            int width = getWidth();
            if (row == null || row.length < width) {
                row = new byte[width];
            }
            image.getRaster().getDataElements(left, top + y, width, 1, row);
            return row;
        }

        public byte[] getMatrix() {
            int width = getWidth();
            int height = getHeight();
            int area = width * height;
            byte[] matrix = new byte[area];
            image.getRaster().getDataElements(left, top, width, height, matrix);
            return matrix;
        }

        public boolean isCropSupported() {
            return true;
        }

        public LuminanceSource crop(int left, int top, int width, int height) {
            return new BufferedImageLuminanceSource(image, this.left + left, this.top + top, width,
                    height);
        }

        public boolean isRotateSupported() {
            return true;
        }

        public LuminanceSource rotateCounterClockwise() {
            int sourceWidth = image.getWidth();
            int sourceHeight = image.getHeight();
            AffineTransform transform = new AffineTransform(0.0, -1.0, 1.0, 0.0, 0.0, sourceWidth);
            BufferedImage rotatedImage = new BufferedImage(sourceHeight, sourceWidth,
                    BufferedImage.TYPE_BYTE_GRAY);
            Graphics2D g = rotatedImage.createGraphics();
            g.drawImage(image, transform, null);
            g.dispose();
            int width = getWidth();
            return new BufferedImageLuminanceSource(rotatedImage, top,
                    sourceWidth - (left + width), getHeight(), width);
        }
    }


    public static void main(String[] args) throws Exception {
        QRCodeUtils.encode("https://baike.xsoftlab.net","", "D:/abc/qr/1.jpg");
        String data = QRCodeUtils.decode("D:/abc/qr/1.jpg");
        System.out.println(data);
    }
}

7.请求接口

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class WeChatController {

    /**
     * 授权后重定向的回调链接地址
     */
    @RequestMapping("/index")
    @ResponseBody
    public String getCode(WeChat weChat){

        /* 根据需求编写逻辑代码 */

        return weChat.getCode();
    }
}

打死都不会遗漏的pom:

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>


        <!-- QRCode二维码工具包 -->
        <dependency>
            <groupId>com.google.zxing</groupId>
            <artifactId>core</artifactId>
            <version>3.3.3</version>
        </dependency>

        <dependency>
            <groupId>com.google.zxing</groupId>
            <artifactId>javase</artifactId>
            <version>3.3.3</version>
        </dependency>

        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.6</version>
        </dependency>

测试:

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 *
 * @author: lsg
 * @create: 2019/10/25 13:33
 */
public class WeChatTest {

    public static void main(String[] args) {
        //参数详情请查看接口文档
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("appid", "测试账号中的appID");
        map.put("response_type", "code");
        map.put("scope", "snsapi_userinfo");
        map.put("state", "ABC");
        map.put("redirect_uri", EncodeUtils.urlEncode("http://内网穿透的域名/index", WeChatConstDefine.ENCODE_UTF_8));

        //用户通过扫码获取授权信息
        String url = HttpConnectionUtils.getHttp().analyticParams(WeChatConstDefine.authorize, map, WeChatConstDefine.weChat_redirect);
        try {
            System.out.println(url);
            //二维码
            QRCodeUtils.encode(url, "D:/WeChat.jpg");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

执行main方法,控制台输出URL,在微信中访问此URL或者找到D盘下 WeChat.jpg 文件进行扫码
 

 

点击允许,微信会调用redirect_uri定义的URL,访问了Controller中的 index 接口,页面输出用户授权 code。

 

此处预留一下 个人logo 位置,以后填充................

 

2019-01-07 15:25:38 AndroidO2O 阅读数 42
  • MUI+HTML5plus混合应用开发视频教程(微信APP实战)

    MUI+HTML5plus混合应用开发(微信APP实战)的课程主要介绍了如何使用移动端框架(mui)完成移动端混合应用开发,课程以移动端框架MUI为基础,以微信app项目为目标,介绍MUI框架的使用,包含移动端排版布局,借助HTML5Plus来手机摄像头调用、手机相册调用、手机重力感应调用,并终完成微信案例项目。

    1545 人正在学习 去看看 张鹏

最近一个月都在写Android NDK开发, 从C语言基础到JNI再到NDK , 一路写下来 , 都是在写C代码 , 有些枯燥乏味 , 故新开一个系列微信开发系列 。

前言

微信是一个非常好的产品 , 几亿人用的产品 , 依托于微信的产品更加多 , 如多如牛毛的微信公众号 , 有各类公众号应用 , O2O 、外卖、企业官网 等等 。微信开发主要由后端与前端组合开发, 本系列使用到的技术栈是,html5 + css + javascript + php 。

微信开发模式

做微信开发的时候 , 需要一个公众号帐号 , 个人的话 , 目前只能申请订阅号 ,需要实名认证 。

基本配置

注册完微信公众平台帐号,在微信公众平台左下角 , 找到开发,进行基本配置

base config

配置服务器环境
点击修改配置

config server

在修改配置页面 ,可以看到接入指南

接入指南

 

进入接入指南

 

Paste_Image.png

 

下载PHP示例代码

示例代码

 

修改代码

配置Token

 

修改完之后 , 上传到服务器。

微信公众平台,服务器配置

服务器配置

配置完成 , 点击启用

启用服务器配置

启动成功之后 , 这样我们的微信配置服务器就完成了 。

修改服务器端代码

将.php文件中的验证代码注释掉 , 调用responseMsg()方法

//define your token
define("TOKEN", "zenoWecaht");
$wechatObj = new wechatCallbackapiTest();
//$wechatObj->valid();

$wechatObj->responseMsg();

微信消息响应机制

Paste_Image.png

响应代码分析

responseMsg()这个方法名称就可以看出 , 这个是响应消息的一个方法 , 将微信服务器传递过来的消息进行解析 , 并进行处理 , 然后按照一定的格式返回 。

public function responseMsg()
    {
        //get post data, May be due to the different environments
        $postStr = $GLOBALS["HTTP_RAW_POST_DATA"];

        //extract post data
        if (!empty($postStr)){
                /* libxml_disable_entity_loader is to prevent XML eXternal Entity Injection,
                   the best way is to check the validity of xml by yourself */
                libxml_disable_entity_loader(true);
                $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
                $fromUsername = $postObj->FromUserName;
                $toUsername = $postObj->ToUserName;
                $keyword = trim($postObj->Content);
                $time = time();
                $textTpl = "<xml>
                            <ToUserName><![CDATA[%s]]></ToUserName>
                            <FromUserName><![CDATA[%s]]></FromUserName>
                            <CreateTime>%s</CreateTime>
                            <MsgType><![CDATA[%s]]></MsgType>
                            <Content><![CDATA[%s]]></Content>
                            <FuncFlag>0</FuncFlag>
                            </xml>";             
                if(!empty( $keyword ))
                {
                    $msgType = "text";
                    $contentStr = "Welcome to wechat world!";
                    $resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $msgType, $contentStr);
                    echo $resultStr;
                }else{
                    echo "Input something...";
                }

        }else {
            echo "";
            exit;
        }
    }

从上述代码可以看出 , $keyword这个变量就是微信服务器传给我们用户输入的内容的值了 。我们可以将他进行一些改造 。

public function responseMsg()
    {
        //get post data, May be due to the different environments
        $postStr = $GLOBALS["HTTP_RAW_POST_DATA"];

        //extract post data
        if (!empty($postStr)){
                /* libxml_disable_entity_loader is to prevent XML eXternal Entity Injection,
                   the best way is to check the validity of xml by yourself */
                libxml_disable_entity_loader(true);
                $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
                $fromUsername = $postObj->FromUserName;
                $toUsername = $postObj->ToUserName;
                $keyword = trim($postObj->Content);
                $time = time();
                $textTpl = "<xml>
                            <ToUserName><![CDATA[%s]]></ToUserName>
                            <FromUserName><![CDATA[%s]]></FromUserName>
                            <CreateTime>%s</CreateTime>
                            <MsgType><![CDATA[%s]]></MsgType>
                            <Content><![CDATA[%s]]></Content>
                            <FuncFlag>0</FuncFlag>
                            </xml>";             
                if(!empty( $keyword ))
                {

                    if($keyword == "zeno"){
                        $contentStr = "简单的微信开发";
                    }else{
                        $contentStr = "sorry ! 未能识别您的指令";
                    }
                    $msgType = "text";
                    $resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $msgType, $contentStr);
                    echo $resultStr;
                }else{
                    echo "Input something...";
                }

        }else {
            echo "";
            exit;
        }
    }

我们自定义了一个指令消息 , 当用户在聊天界面输入zeno就会返回简单的微信开发 , 我们通过简单的字符指令进行判断 , 然后返回响应的结果 。

响应代码分析

得到微信传递过来的消息对象,解析xml格式。

libxml_disable_entity_loader(true);
$postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);

得到消息解析的内容。

                $fromUsername = $postObj->FromUserName;
                $toUsername = $postObj->ToUserName;
                $keyword = trim($postObj->Content);

构建响应消息的模版,$textTpl是微信消息响应的消息格式 , 按照这个模版 , 然后将

                $textTpl = "<xml>
                            <ToUserName><![CDATA[%s]]></ToUserName>
                            <FromUserName><![CDATA[%s]]></FromUserName>
                            <CreateTime>%s</CreateTime>
                            <MsgType><![CDATA[%s]]></MsgType>
                            <Content><![CDATA[%s]]></Content>
                            <FuncFlag>0</FuncFlag>
                            </xml>";                                                  

判断用户输入的指令 , 并作出指令处理 , 响应消息 。

                if(!empty( $keyword ))
                {

                    if($keyword == "zeno"){
                        $contentStr = "简单的微信开发";
                    }else{
                        $contentStr = "sorry ! 未能识别您的指令";
                    }
                    $msgType = "text";
                    $resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $msgType, $contentStr);
                    echo $resultStr;
                }else{
                    echo "Input something...";
                }

结语

微信开发结合了服务器端开发前端开发 , 微信开发本身比较简单 , 就是微信提供的一些接口的调用 , 复杂之处在于 , 在微信外部 , 也就是我们服务器上搭建的web系统 , 和一般的web应用开发没什么区别 。 微信开发系列 , 属于闲暇之作 , 不定期更新 。

参考

微信开发文档

欢迎加入Android开发技术交流QQ群:150923287,本群可免费获取Flutter、Gradle、RxJava、小程序、Hybrid、移动架构、NDK、React Native、性能优化等技术教程!

 

2018-12-07 13:24:20 qq_31001889 阅读数 72
  • MUI+HTML5plus混合应用开发视频教程(微信APP实战)

    MUI+HTML5plus混合应用开发(微信APP实战)的课程主要介绍了如何使用移动端框架(mui)完成移动端混合应用开发,课程以移动端框架MUI为基础,以微信app项目为目标,介绍MUI框架的使用,包含移动端排版布局,借助HTML5Plus来手机摄像头调用、手机相册调用、手机重力感应调用,并终完成微信案例项目。

    1545 人正在学习 去看看 张鹏

转自:https://www.cnblogs.com/xdp-gacl/p/5151857.html

  上一篇《微信开发学习总结(一)——微信开发环境搭建》我们已经完成了微信开发的准备工作,准备工作完成之后,就要开始步入正题了。

一、微信公众平台的基本原理

  在开始做之前,先简单介绍了微信公众平台的基本原理。

  微信服务器就相当于一个转发服务器,终端(手机、Pad等)发起请求至微信服务器,微信服务器然后将请求转发给我们的应用服务器。应用服务器处理完毕后,将响应数据回发给微信服务器,微信服务器再将具体响应信息回复到微信App终端。

  通信协议为:HTTP

  数据传输格式为:XML

  具体的流程如下图所示:

  

  来一张更加直观的图吧:

  

  我们需要做的事情,就是对微信服务器转发的HTTP请求做出响应。具体的请求内容,我们按照特定的XML格式去解析,处理完毕后,也要按照特定的XML格式返回。

二、微信公众号接入

  在微信公众平台开发者文档上,关于公众号接入这一节内容在接入指南上写的比较详细的,文档中说接入公众号需要3个步骤,分别是:

  1、填写服务器配置
  2、验证服务器地址的有效性
  3、依据接口文档实现业务逻辑

  其实,第3步已经不能算做公众号接入的步骤,而是接入之后,开发人员可以根据微信公众号提供的接口所能做的一些开发。

  第1步中服务器配置包含服务器地址(URL)、Token和EncodingAESKey。

  服务器地址即公众号后台提供业务逻辑的入口地址,目前只支持80端口,之后包括接入验证以及任何其它的操作的请求(例如消息的发送、菜单管理、素材管理等)都要从这个地址进入。接入验证和其它请求的区别就是,接入验证时是get请求,其它时候是post请求;

  Token可由开发者可以任意填写,用作生成签名(该Token会和接口URL中包含的Token进行比对,从而验证安全性);

  EncodingAESKey由开发者手动填写或随机生成,将用作消息体加解密密钥。本例中全部以未加密的明文消息方式,不涉及此配置项。

  第2步,验证服务器地址的有效性,当点击“提交”按钮后,微信服务器将发送一个http的get请求到刚刚填写的服务器地址,并且携带四个参数:

  

  接到请求后,我们需要做如下三步,若确认此次GET请求来自微信服务器,原样返回echostr参数内容,则接入生效,否则接入失败。

  1. 将token、timestamp、nonce三个参数进行字典序排序
  2. 将三个参数字符串拼接成一个字符串进行sha1加密
  3. 开发者获得加密后的字符串可与signature对比,标识该请求来源于微信

  下面我们用Java代码来演示一下这个验证过程

  使用IDE(Eclipse或者IntelliJ IDEA)创建一个JavaWeb项目,这里我使用的是IntelliJ IDEA,项目目录结构如下图所示:

  

  编写一个servlevt,在其中的doGet方法中定义校验方法,具体代码如下:

复制代码
  1 package me.gacl.wx.web.servlet;
  2 
  3 import javax.servlet.ServletException;
  4 import javax.servlet.annotation.WebServlet;
  5 import javax.servlet.http.HttpServlet;
  6 import javax.servlet.http.HttpServletRequest;
  7 import javax.servlet.http.HttpServletResponse;
  8 import java.io.IOException;
  9 import java.security.MessageDigest;
 10 import java.security.NoSuchAlgorithmException;
 11 import java.util.Arrays;
 12 
 13 /**
 14  * Created by xdp on 2016/1/25.
 15  * 使用@WebServlet注解配置WxServlet,urlPatterns属性指明了WxServlet的访问路径
 16  */
 17 @WebServlet(urlPatterns="/WxServlet")
 18 public class WxServlet extends HttpServlet {
 19 
 20     /**
 21      * Token可由开发者可以任意填写,用作生成签名(该Token会和接口URL中包含的Token进行比对,从而验证安全性)
 22      * 比如这里我将Token设置为gacl
 23      */
 24     private final String TOKEN = "gacl";
 25 
 26     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 27 
 28     }
 29 
 30     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 31         System.out.println("开始校验签名");
 32         /**
 33          * 接收微信服务器发送请求时传递过来的4个参数
 34          */
 35         String signature = request.getParameter("signature");//微信加密签名signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。
 36         String timestamp = request.getParameter("timestamp");//时间戳
 37         String nonce = request.getParameter("nonce");//随机数
 38         String echostr = request.getParameter("echostr");//随机字符串
 39         //排序
 40         String sortString = sort(TOKEN, timestamp, nonce);
 41         //加密
 42         String mySignature = sha1(sortString);
 43         //校验签名
 44         if (mySignature != null && mySignature != "" && mySignature.equals(signature)) {
 45             System.out.println("签名校验通过。");
 46             //如果检验成功输出echostr,微信服务器接收到此输出,才会确认检验完成。
 47             //response.getWriter().println(echostr);
 48             response.getWriter().write(echostr);
 49         } else {
 50             System.out.println("签名校验失败.");
 51         }
 52 
 53     }
 54 
 55     /**
 56      * 排序方法
 57      *
 58      * @param token
 59      * @param timestamp
 60      * @param nonce
 61      * @return
 62      */
 63     public String sort(String token, String timestamp, String nonce) {
 64         String[] strArray = {token, timestamp, nonce};
 65         Arrays.sort(strArray);
 66         StringBuilder sb = new StringBuilder();
 67         for (String str : strArray) {
 68             sb.append(str);
 69         }
 70 
 71         return sb.toString();
 72     }
 73 
 74     /**
 75      * 将字符串进行sha1加密
 76      *
 77      * @param str 需要加密的字符串
 78      * @return 加密后的内容
 79      */
 80     public String sha1(String str) {
 81         try {
 82             MessageDigest digest = MessageDigest.getInstance("SHA-1");
 83             digest.update(str.getBytes());
 84             byte messageDigest[] = digest.digest();
 85             // Create Hex String
 86             StringBuffer hexString = new StringBuffer();
 87             // 字节数组转换为 十六进制 数
 88             for (int i = 0; i < messageDigest.length; i++) {
 89                 String shaHex = Integer.toHexString(messageDigest[i] & 0xFF);
 90                 if (shaHex.length() < 2) {
 91                     hexString.append(0);
 92                 }
 93                 hexString.append(shaHex);
 94             }
 95             return hexString.toString();
 96 
 97         } catch (NoSuchAlgorithmException e) {
 98             e.printStackTrace();
 99         }
100         return "";
101     }
102 }
复制代码

  我这里用的Servlet3.0,使用Servlet3.0的好处就是可以直接使用@WebServlet注解映射Servlet的访问路径,不再需要在web.xml文件中进行配置.

  将WxStudy项目部署到Tomcat服务器中运行,直接启动项目,然后用ngrok将本地8080端口映射到外网(如何使用ngrok请参考博客《微信开发学习总结(一)——微信开发环境搭建》)。如下图所示:

  

  测试是否可以通过http://xdp.ngrok.natapp.cn地址正常访问,测试结果如下:

  

  可以看到,我们的项目已经可以被外网正常访问到了。

  进入微信测试公众号管理界面,在接口配置信息中填入映射的外网地址和token,如下图所示:

 

  点击提交按钮,页面会提示配置成功,

  

  IDE的控制台中输出了校验通过的信息,如下图所示:

  

  到此,我们的公众号应用已经能够和微信服务器正常通信了,也就是说我们的公众号已经接入到微信公众平台了。

三、access_token管理

3.1、access_token介绍

  我们的公众号和微信服务器对接成功之后,接下来要做的就是根据我们的业务需求调用微信公众号提供的接口来实现相应的逻辑了。在使用微信公众号接口中都需要一个access_token。

  关于access_token,在微信公众平台开发者文档上的获取接口调用凭据有比较详细的介绍:access_token是公众号的全局唯一票据,公众号调用各接口时都需使用access_token,开发者需要妥善保存access_token的存储至少要保留512个字符空间。access_token的有效期目前为2个小时,需定时刷新,重复获取将导致上次获取的access_token失效。并且每天调用获取access_token接口的上限是2000次。

  总结以上说明,access_token需要做到以下两点:

  1.因为access_token有2个小时的时效性,要有一个机制保证最长2个小时重新获取一次。

  2.因为接口调用上限每天2000次,所以不能调用太频繁。

3.2、微信公众平台提供的获取access_token的接口

  关于access_token的获取方式,在微信公众平台开发者文档上有说明,公众号可以调用一个叫"获取access token"的接口来获取access_token。

  获取access token接口调用请求说明

    http请求方式: GET

    请求的URL地址:https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
    

2016-06-15 08:18:22 u011461420 阅读数 539
  • MUI+HTML5plus混合应用开发视频教程(微信APP实战)

    MUI+HTML5plus混合应用开发(微信APP实战)的课程主要介绍了如何使用移动端框架(mui)完成移动端混合应用开发,课程以移动端框架MUI为基础,以微信app项目为目标,介绍MUI框架的使用,包含移动端排版布局,借助HTML5Plus来手机摄像头调用、手机相册调用、手机重力感应调用,并终完成微信案例项目。

    1545 人正在学习 去看看 张鹏
2018-12-07 11:38:12 qq_31001889 阅读数 70
  • MUI+HTML5plus混合应用开发视频教程(微信APP实战)

    MUI+HTML5plus混合应用开发(微信APP实战)的课程主要介绍了如何使用移动端框架(mui)完成移动端混合应用开发,课程以移动端框架MUI为基础,以微信app项目为目标,介绍MUI框架的使用,包含移动端排版布局,借助HTML5Plus来手机摄像头调用、手机相册调用、手机重力感应调用,并终完成微信案例项目。

    1545 人正在学习 去看看 张鹏

转自:https://www.cnblogs.com/xdp-gacl/p/5149171.html

  目前移动开发处于比较火的的趋势,很多的开发者都跃跃欲试,目前移动App开发领域主要分为以下几种类型

  

  我在平时的工作中接触得比较多的就是基于Android的Native App开发和基于微信公众号的Light App开发,今天就来带领大家快速进入微信公众号的开发领域.

一、微信开发环境搭建

  工欲善其事,必先利其器。要做微信公众号开发,那么要先准备好两样必不可少的东西:

  1、要有一个用来测试的公众号。

  2、用来调式代码的开发环境

1.1、注册测试公众号

  微信公众号分为服务号、订阅号、企业号,订阅号可以个人申请,服务号和企业号要有企业资质才可以。

  

  我们所说的微信公众号开发指的是订阅号和服务号。

  关于订阅号和服务器的区别,官方是这样解释的

  服务号:主要偏向于服务交互(功能类似12315,114,银行,提供绑定信息,服务交互),每月可群发4条消息;服务号适用人群:媒体、企业、政府或其他组织。

  订阅号:主要偏向于为用户传达资讯,(功能类似报纸杂志,为用户提供新闻信息或娱乐趣事),每天可群发1条消息;订阅号适用人群:个人、媒体、企业、政府或其他组织。

  个人订阅号有一些接口是没有权限的,也就是说个人订阅号无法调用一些高级的权限接口,下图就是一个我的个人订阅号所具备权限列表,如下图所示:

  

  而一些高级接口,如生成二维码、网页授权、自定义菜单、微信支付这样的接口权限个人订阅号是没有调用权限的,如上图红色框起来的那些接口,个人订阅号都无法调用。

  幸运的是,微信公众平台提供了测试公众账号,测试公众号的注册地址为:http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login,只需要到这个页面,点击登录,并用自己的微信客户端扫码,并授权登录,就可以获得属于自己的测试公众号。测试公众号具备几乎所有的接口,所以平时学习微信公众号开发时,就可以去注册一个测试公众号,然后使用这个测试公众号做开发就可以了。不废话了,还是先注册一个测试公众号吧

  访问http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login,注册一个测试公众号。

  注册测试公众号的步骤如下图所示:

  

 

  

  用微信扫描上述的二维码进行登录,登录成功后,就可以看到腾讯分配给我们的测试公众号的信息了,如下图所示:

  

  测试公众号的所拥有的接口权限如下:

  

  可以看到,测试公众号拥有大部分的接口调用权限,因此用测试公众号来学习微信开发是完全可以的

1.2、搭建微信本地调试环境

  开发基于微信公众号的应用最大的痛苦之处就是调试问题,每次实现一个功能后都需要部署到一个公网服务器进行测试,因为微信用户每次向公众号发起请求时,微信服务器会先接收到用户的请求,然后再转发到我们的服务器上,也就是说,微信服务器是要和我们的服务器进行网络交互,所以我们必须保证我们的服务器外网可以访问到,这种部署到公网服务器进行测试的做法对于我们开发者来说简直是噩梦。所以我们要想一个办法可以做到本地部署,本地调试代码,而要做到这一点,那么我们要解决的问题就是将内网的部署服务器映射到外网,让微信服务器可以正常访问到,幸运的是,借助于第三方软件Ngrok,我们就可以做得到。Ngrok是一个免费的软件Ngrok,使用Ngrok后,我们就可以实现内网穿透,也就是说我们可以将内网的服务器映射到外网给别人访问,这对于我们在本地开发环境中调试微信代码是以及给用户演示一些东西非常快速和有帮助的,因为可以直接使用我们自己的内网的电脑作为服务器。

  国内提供Ngrok服务比较好的网站是:http://natapp.cn/,如下图所示:

  

微信卡券开发流程

阅读数 3010

http://www.thinkphp.cn/extend/863.html

博文 来自: qq_42440562
没有更多推荐了,返回首页