精华内容
下载资源
问答
  • 微信公众号开发者原生态的servlet  如果想要成功成为微信公众号开发者,那么首先就是要服务器与微信公众号接入 查询公众号开发文档:https://mp.weixin.qq.com/wiki?t=...

                                                微信公众号开发者原生态的servlet                                                      

    如果想要成功成为微信公众号开发者,那么首先就是要服务器与微信公众号接入

    查询公众号开发文档:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421135319

    1. 根据微信的API来编写servlet,请求获取四个字段(signature、timestamp、nonce、echostr)这些参数的表示什么意义自己查询公众号的API。
    2. 对这三个字段进行list排序处理,通过SHA1加密算法返回密文,与第一个参数signature进行比较,hashcode如果一致,接入成功,原样返回echostr参数内容,则接入生效,成为开发者成功。
    3. 这个工程部署到Linux上。
    4. 微信公众号上的url写,部署工程的action请求地址。

    值得注意的是上述接入公众号是servlet的doGet( )请求 ,直接上代码

    编写JoinChatServlet.java文件的get请求方法:

    package com.eastrobot.robotdev.wechat;
    
    import java.io.IOException;
    import java.io.PrintWriter;
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.Comparator;
    import java.util.List;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import com.eastrobot.robotdev.Constants;
    import com.eastrobot.robotdev.util.HttpUtils;
    import com.eastrobot.robotdev.wechat.entity.AccessToken;
    import com.eastrobot.robotdev.wechat.util.SHA1Utils;
    
    
    /**
     * 接入微信公众号平台
     * 
     * @author han.sun
     * 
     */
    public class JoinChatServlet extends HttpServlet {
    
    	private static final long serialVersionUID = 1L;
    	private static Logger log = LoggerFactory.getLogger(JoinChatServlet.class);
    	// private static ReceiveXmlUtils receiveXmlUtils;
    	// 微信上填写的Token数据
    	private static String Token = "sunhan";
    
    	public void doGet(HttpServletRequest request, HttpServletResponse response)
    			throws ServletException, IOException {
    		request.setCharacterEncoding(Constants.CHARSET);
    		response.setCharacterEncoding(Constants.CHARSET);
    		log.debug("GEt请求成功");
    		// 微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。
    		String signature = request.getParameter("signature");
    		// 时间戳
    		String timestamp = request.getParameter("timestamp");
    		// 随机数
    		String nonce = request.getParameter("nonce");
    		// 随机字符串
    		String echostr = request.getParameter("echostr");
    
    		List<String> params = new ArrayList<String>();
    		params.add(Token);
    		params.add(timestamp);
    		params.add(nonce);
    		// 1. 将token、timestamp、nonce三个参数进行字典排序
    		Collections.sort(params, new Comparator<String>() {
    			@Override
    			public int compare(String o1, String o2) {
    				return o1.compareTo(o2);
    			}
    		});
    
    		// 2. 将三个参数拼接成一个字符串进行SHA1进行加密
    		String temp = SHA1Utils.encode(params.get(0) + params.get(1)
    				+ params.get(2));
    		// 3. 加密后的字符串与signature比较,标识该请求是来自微信
    		if (temp.equals(signature)) {
    			// 原样返回echostr参数内容,则接入成功
    			response.getWriter().write(echostr);
    			log.debug("echostr传回微信后台成功...");
    		} else {
    			log.debug("echostr传回微信后台失败...");
    		}
    	}
    }

    SHA1Utils.java

    package com.eastrobot.robotdev.wechat.util;
    
    import java.security.MessageDigest;
    
    /**
     * SHA1算法
     * @author han.sun
     *
     */
    public class SHA1Utils {
    
    	private SHA1Utils() {
    	}
    	private static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5',
    			'6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
    
    	public static String getFormattedText(byte[] bytes) {
    		int len = bytes.length;
    		StringBuffer buffer = new StringBuffer(len * 2);
    		// 把密文转换成十六进制的字符串形式
    		for (int i = 0; i < bytes.length; i++) {
    			buffer.append(HEX_DIGITS[(bytes[i] >> 4) & 0x0f]);
    			buffer.append(HEX_DIGITS[bytes[i] & 0x0f]);
    		}
    		return buffer.toString();
    	}
    	
    	public static String encode(String str){
    		if (str==null) {
    			return null;
    		}
    		try {
    			MessageDigest messageDigest = MessageDigest.getInstance("SHA1");
    			messageDigest.update(str.getBytes());
    			return getFormattedText(messageDigest.digest());
    		} catch (Exception e) {
    			throw new RuntimeException(e);
    		}
    	}
    }
    

    此时如果微信公众号后台的URL、秘钥、token等填写无误,用微信公众号调试接口:https://mp.weixin.qq.com/debug?token=233128916&lang=zh_CN进行测试服务器是否已经接入,会返回json数据状态为200 OK那么恭喜你已经成功接入开发者模式

    二、实现公众号被动回复消息

    可以回复文本、图片、语音、图文等等众多多谋体文件。创建这些文件消息实体。发送与回复消息都是通过Xml格式进行传输

    创建一个消息实体基类,供它的子类继承,不论是文本还是图片都有4个共有的属性,ToUserName、FromUserName、CreateTime、MsgType,分别是接收方、来自方、会话创建时间、会话类型。

    BaseMessage.java

    package com.eastrobot.robotdev.wechat.entity;
    
    import java.io.Serializable;
    
    import com.thoughtworks.xstream.annotations.XStreamAlias;
    
    /**
     * 请求消息基类
     * @author han.sun
     *
     */
    public class BaseMessage implements Serializable{
    
    	private static final long serialVersionUID = 1L;
    
    	@XStreamAlias("ToUserName")
    	public String ToUserName;
    
    	@XStreamAlias("FromUserName")
    	public String FromUserName;
    
    	@XStreamAlias("CreateTime")
    	public Long CreateTime;
    
    	@XStreamAlias("MsgType")
    	public String MsgType;
    
    	public String getToUserName() {
    		return ToUserName;
    	}
    
    	public void setToUserName(String toUserName) {
    		ToUserName = toUserName;
    	}
    
    	public String getFromUserName() {
    		return FromUserName;
    	}
    
    	public void setFromUserName(String fromUserName) {
    		FromUserName = fromUserName;
    	}
    
    	public Long getCreateTime() {
    		return CreateTime;
    	}
    
    	public void setCreateTime(Long createTime) {
    		CreateTime = createTime;
    	}
    
    	public String getMsgType() {
    		return MsgType;
    	}
    
    	public void setMsgType(String msgType) {
    		MsgType = msgType;
    	}
    
    }
    

    文本消息类

    package com.eastrobot.robotdev.wechat.entity;
    
    /**
     * 文本消息类
     * @author han.sun
     *
     */
    public class TextMessage extends BaseMessage {
    
    	private static final long serialVersionUID = 1L;
    
    	private String Content;
    
    	private String MsgId;
    
    	public String getContent() {
    		return Content;
    	}
    
    	public void setContent(String content) {
    		Content = content;
    	}
    
    	public String getMsgId() {
    		return MsgId;
    	}
    
    	public void setMsgId(String msgId) {
    		MsgId = msgId;
    	}
    
    }
    

    图片消息类

    package com.eastrobot.robotdev.wechat.entity;
    
    import com.thoughtworks.xstream.annotations.XStreamAlias;
    
    /**
     * 图片消息类
     * @author han.sun
     *
     */
    @XStreamAlias("xml")
    public class ImageMessage extends BaseMessage {
    
    	private static final long serialVersionUID = 1L;
    	
    	@XStreamAlias("Image")
    	private Image Image;
    
    
    	public Image getImage() {
    		return Image;
    	}
    
    
    	public void setImage(Image image) {
    		Image = image;
    	}
    
    
    }
    

    ImageMessage的图片消息类下的子属性Image类

    package com.eastrobot.robotdev.wechat.entity;
    
    /**
     * 图片消息类的Image
     * @author han.sun
     *
     */
    public class Image {
    
    	/**
    	 * 图片的临时文件Id
    	 */
    	private String MediaId;
    
    	public String getMediaId() {
    		return MediaId;
    	}
    
    	public void setMediaId(String mediaId) {
    		MediaId = mediaId;
    	}
    
    }
    

    我还实现了很多的类型,图文消息实体就不附加上来了

    下面就是消息回复所用到的工具类啦,Message消息处理工具类(最重要的工具类)

    1. 此工具类是为了,把请求的Xml格式数据转换成Map集合类型,这样才好处理,用到消息实体时候,我们使用map.get()方法就可以获取出想要的xml标签中的数据
    2. 在servlet处理好数据准备回复的时候,也要把数据进行输出xml形式返回给微信后台
    package com.eastrobot.robotdev.wechat.util;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.ArrayList;
    import java.util.Date;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    import javax.servlet.http.HttpServletRequest;
    
    import org.dom4j.Document;
    import org.dom4j.DocumentException;
    import org.dom4j.Element;
    import org.dom4j.io.SAXReader;
    
    import com.eastrobot.robotdev.wechat.entity.ArticlesItem;
    import com.eastrobot.robotdev.wechat.entity.ArticlesMessage;
    import com.eastrobot.robotdev.wechat.entity.Image;
    import com.eastrobot.robotdev.wechat.entity.ImageMessage;
    import com.eastrobot.robotdev.wechat.entity.TextMessage;
    import com.thoughtworks.xstream.XStream;
    
    /**
     * 处理Xml消息工具类
     * @author han.sun
     *
     */
    public class MessageUtils {
    
    	public static final String MESSAGE_SCAN = "SCAN";// 未关注公众号扫描二维码
    	public static final String MESSAGE_TEXT = "text";// 文本
    	public static final String MESSAGE_IMAGE = "image";// 图片
    	public static final String MESSAGE_VOICE = "voice";// 语音
    	public static final String MESSAGE_VIDEO = "video";// 视频
    	public static final String MESSAGE_LINK = "link";// 连接
    	public static final String MESSAGE_LOCATION = "location";// 地理位置事件
    	public static final String MESSAGE_EVENT = "event";// 事件
    	public static final String MESSAGE_SUBSCRIBE = "subscribe";// 关注
    	public static final String MESSAGE_UNSUBSCRIBE = "unsubscribe";// 取消关注
    	public static final String MESSAGE_CLICK = "CLICK";// 点击
    	public static final String MESSAGE_VIEW = "VIEW";// t跳转链接url
    	public static final String MESSAGE_NEWS = "news";
    
    	private MessageUtils() {
    	}
    
    	/**
    	 * 将接受到的xml转换成Map集合
    	 * @param request
    	 * @return	Map集合
    	 */
    	public static Map<String, String> xmlToMap(HttpServletRequest request)
    			throws IOException, DocumentException {
    		Map<String, String> map = new HashMap<String, String>();
    		SAXReader reader = new SAXReader();
    		InputStream in = request.getInputStream();
    		Document document = reader.read(in);
    		Element root = document.getRootElement();
    		@SuppressWarnings("unchecked")
    		List<Element> list = root.elements();
    		for (Element e : list) {
    			map.put(e.getName(), e.getText());
    		}
    		in.close();
    		return map;
    	}
    
    	/**
    	 * 将文本信息转换成Xml
    	 * @param textMessage	文本消息实体
    	 * @return	准备返回的xml字符串
    	 */
    	private static String textMessageToXml(TextMessage textMessage) {
    		XStream stream = new XStream();
    		stream.alias("xml", textMessage.getClass());
    		return stream.toXML(textMessage);
    	}
    
    	/**
    	 * 将图片消息转换成xml
    	 * @param imageMessage	图片消息实体
    	 * @return	准备返回的xml字符串
    	 */
    	private static String imageMessageToXml(ImageMessage imageMessage) {
    		XStream stream = new XStream();
    		stream.alias("xml", imageMessage.getClass());
    		return stream.toXML(imageMessage);
    	}
    
    	/**
    	 * 图文消息转为xml
    	 * @param newsMessage
    	 * @return
    	 */
    	public static String articlesMessageToXml(ArticlesMessage articlesMessage){
    		XStream xstream = new XStream();
    		xstream.alias("xml", articlesMessage.getClass());
    		xstream.alias("item", new ArticlesItem().getClass());
    		return xstream.toXML(articlesMessage);
    	}
    	
    	/**
    	 * 图文消息的组装(类型为news)
    	 * @param toUserName
    	 * @param fromUserName
    	 * @return
    	 */
    	public static String initArticlesMessage(String toUserName,String fromUserName){
    		String message = null;
    		List<ArticlesItem> newsList = new ArrayList<ArticlesItem>();
    		ArticlesMessage newsMessage = new ArticlesMessage();
    		
    		ArticlesItem article = new ArticlesItem();
    		article.setTitle("图文消息");
    		article.setDescription("你,在或者不在;这些年风里,雨里;无论,快乐还是哀愁;我都将终点,等你 。");
    		article.setPicUrl("http://ctr.demo.xiaoi.com/robot-dev/image/028.jpg");
    		article.setUrl("https://www.baidu.com");
    		
    		newsList.add(article);
    		
    		newsMessage.setToUserName(fromUserName);
    		newsMessage.setFromUserName(toUserName);
    		newsMessage.setCreateTime(new Date().getTime());
    		newsMessage.setMsgType(MESSAGE_NEWS);
    		newsMessage.setArticles(newsList);
    		newsMessage.setArticleCount(newsList.size());
    		
    		message = articlesMessageToXml(newsMessage);
    		return message;
    	}
    
    	
    	/**
    	 * 文本消息的组装
    	 * @param content
    	 * @param toUserName
    	 * @param fromUserName
    	 * @return	发送给客户端
    	 */
    	public static String initTextMessage(String content, String toUserName,
    			String fromUserName) {
    		String message = null;
    		TextMessage textMessage = new TextMessage();
    		textMessage.setContent(content);
    		textMessage.setCreateTime(new Date().getTime());
    		textMessage.setFromUserName(toUserName);
    		textMessage.setToUserName(fromUserName);
    		textMessage.setMsgType(MESSAGE_TEXT);
    		message = textMessageToXml(textMessage);
    		return message;
    	}
    
    	/**
    	 * 图片消息的组装
    	 * @param mediaId
    	 * @param toUserName
    	 * @param fromUsername
    	 * @return	发送给客户端
    	 */
    	public static String initImageMessage(String mediaId, String toUserName,
    			String fromUserName) {
    		String message = null;
    		ImageMessage imageMessage = new ImageMessage();
    		Image image = new Image();
    		image.setMediaId(mediaId);
    		imageMessage.setImage(image);
    		imageMessage.setFromUserName(toUserName);
    		imageMessage.setToUserName(fromUserName);
    		imageMessage.setCreateTime(new Date().getTime());
    		imageMessage.setMsgType(MESSAGE_IMAGE);
    		message = imageMessageToXml(imageMessage);
    		return message;
    	}
    
    	public static String initMuenMessage() {
    		StringBuffer bf = new StringBuffer();
    		bf.append("你,在或者不在\n");
    		bf.append("这些年风里,雨里\n");
    		bf.append("无论是快乐,哀愁\n");
    		bf.append("我都将终点,等你\n");
    		return bf.toString();
    	}
    }
    

    实现图片回复的功能,因为图片不是在微信后台的,所以必要我们提供的服务器来进行预上传到公众号的临时素材库中(失效是三天吧)。公众号的API中提供的接口中要求必须有一个MediaId,这就是此类的作用

    package com.eastrobot.robotdev.wechat.util;
    
    import java.io.BufferedReader;
    import java.io.DataInputStream;
    import java.io.DataOutputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.OutputStream;
    import java.net.HttpURLConnection;
    import java.net.URL;
    import java.security.KeyManagementException;
    import java.security.NoSuchAlgorithmException;
    import java.security.NoSuchProviderException;
    
    import net.sf.json.JSONObject;
    
    import com.eastrobot.robotdev.Constants;
    import com.eastrobot.robotdev.util.HttpUtils;
    import com.eastrobot.robotdev.wechat.entity.AccessToken;
    
    /**
     * 上传图片到临时素材库类
     * @author han.sun
     *
     */
    public class WechatUtils {
    
    	private static final String APPID = "wx7eea4228e2073fb8";
    	private static final String APPSECRET = "13f608d28a4d2cefedb790fa321766fb";
    	private static final String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
    	private static final String UPLOAD_URL = "https://api.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE";
    
    	private WechatUtils(){
    	}
    	
    	/**
    	 * doGet形式的HttpClient请求
    	 * @param url	接口地址
    	 * @return	返回Json对象
    	 */
    	public static JSONObject doGetStr(String url) {
    		JSONObject jsonObject = null;
    		String result = HttpUtils.get(url, Constants.CHARSET);
    		jsonObject = JSONObject.fromObject(result);
    		return jsonObject;
    	}
    
    	/**
    	 * 获取AccessToken
    	 * @return AccessToken
    	 * @author han.sun
    	 */
    	public static AccessToken getAccessToken() {
    		AccessToken token = new AccessToken();
    		String url = ACCESS_TOKEN_URL.replace("APPID", APPID).replace(
    				"APPSECRET", APPSECRET);
    		JSONObject jsonObject = doGetStr(url);
    		if (jsonObject != null) {
    			token.setToken(jsonObject.getString("access_token"));
    			token.setExpiresIn(jsonObject.getInt("expires_in"));
    		}
    		return token;
    	}
    
    	/**
    	 * 上传本地文件到微信获取mediaId
    	 * @param filePath	文件路径
    	 * @param accessToken	令牌
    	 * @param type	消息类型
    	 * @return 返回mediaId
    	 */
    	public static String upload(String filePath, String accessToken, String type)
    			throws IOException, NoSuchAlgorithmException,
    			NoSuchProviderException, KeyManagementException {
    		System.out.println("filePath:" + filePath);
    		File file = new File(filePath);
    		if (!file.exists() || !file.isFile()) {
    			throw new IOException("文件不存在");
    		}
    
    		String url = UPLOAD_URL.replace("ACCESS_TOKEN", accessToken).replace(
    				"TYPE", type);
    
    		URL urlObj = new URL(url);
    		// 连接
    		HttpURLConnection con = (HttpURLConnection) urlObj.openConnection();
    
    		con.setRequestMethod("POST");
    		con.setDoInput(true);
    		con.setDoOutput(true);
    		con.setUseCaches(false);
    
    		// 设置请求头信息
    		con.setRequestProperty("Connection", "Keep-Alive");
    		con.setRequestProperty("Charset", "UTF-8");
    
    		// 设置边界
    		String BOUNDARY = "----------" + System.currentTimeMillis();
    		con.setRequestProperty("Content-Type", "multipart/form-data; boundary="
    				+ BOUNDARY);
    
    		StringBuilder sb = new StringBuilder();
    		sb.append("--");
    		sb.append(BOUNDARY);
    		sb.append("\r\n");
    		sb.append("Content-Disposition: form-data;name=\"file\";filename=\""
    				+ file.getName() + "\"\r\n");
    		sb.append("Content-Type:application/octet-stream\r\n\r\n");
    
    		byte[] head = sb.toString().getBytes("utf-8");
    
    		// 获得输出流
    		OutputStream out = new DataOutputStream(con.getOutputStream());
    		// 输出表头
    		out.write(head);
    
    		// 文件正文部分
    		// 把文件已流文件的方式 推入到url中
    		DataInputStream in = new DataInputStream(new FileInputStream(file));
    		int bytes = 0;
    		byte[] bufferOut = new byte[1024];
    		while ((bytes = in.read(bufferOut)) != -1) {
    			out.write(bufferOut, 0, bytes);
    		}
    		in.close();
    
    		// 结尾部分
    		byte[] foot = ("\r\n--" + BOUNDARY + "--\r\n").getBytes("utf-8");// 定义最后数据分隔线
    
    		out.write(foot);
    		out.flush();
    		out.close();
    
    		StringBuffer buffer = new StringBuffer();
    		BufferedReader reader = null;
    		String result = null;
    		try {
    			// 定义BufferedReader输入流来读取URL的响应
    			reader = new BufferedReader(new InputStreamReader(
    					con.getInputStream()));
    			String line = null;
    			while ((line = reader.readLine()) != null) {
    				buffer.append(line);
    			}
    			if (result == null) {
    				result = buffer.toString();
    			}
    		} catch (IOException e) {
    			e.printStackTrace();
    		} finally {
    			if (reader != null) {
    				reader.close();
    			}
    		}
    
    		JSONObject jsonObj = JSONObject.fromObject(result);
    		System.out.println(jsonObj);
    		String typeName = "media_id";
    		if (!"image".equals(type)) {
    			typeName = type + "_media_id";
    		}
    		String mediaId = jsonObj.getString(typeName);
    		return mediaId;
    	}
    
    }
    

    三、实现查询天气的功能

    根据天气的接口,来定义查询出来的天气实体类。进行查询天气并且处理我们场景实用的信息

    package com.eastrobot.robotdev.wechat.weather;
    
    import java.io.UnsupportedEncodingException;
    import java.net.URLEncoder;
    import java.util.List;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import com.eastrobot.robotdev.Constants;
    import com.eastrobot.robotdev.util.HttpUtils;
    import com.google.gson.Gson;
    
    /**
     * 拼接查询天气接口所需的URL,查询天气
     * @author han.sun
     *
     */
    public class BaiduWeather {
    
    	public static final Logger log = LoggerFactory
    			.getLogger(BaiduWeather.class);
    	private static final String API = "http://api.map.baidu.com/telematics/v3/weather?";
    	private static final String AK = "81218080E79C9685b35e757566d8cbe5";
    	private static final String OUTPUT = "json";
    
    	/**
    	 * 获取天气的结果
    	 * @param location	地点
    	 * @return	该地点的天气信息
    	 */
    	public static String getResult(String location) {
    		try {
    			URLEncoder.encode(location, Constants.CHARSET);
    		} catch (UnsupportedEncodingException e) {
    			e.printStackTrace();
    		}
    		// 拼接url
    		StringBuffer sb = new StringBuffer();
    		sb.append("location=");
    		sb.append(location);
    		sb.append("&output=");
    		sb.append(OUTPUT);
    		sb.append("&ak=");
    		sb.append(AK);
    		String url = API + sb.toString();
    		// 百度天气返回的内容
    		String result = "";
    		result = HttpUtils.get(url, Constants.CHARSET);
    		// 去解析查询回来的json字符串
    		String message = handleResult(result);
    		// 如果返回的不是Json那么还需要进行处理....
    		return message;
    	}
    	
    	/**
    	 * 处理查询出来的天气结果
    	 * @param result	原始的Json字符串
    	 * @return	真正返回给用户的字符串
    	 */
    	private static String handleResult(String result){
    		Gson gson = new Gson();
    		Status status = gson.fromJson(result, Status.class);
    		List<Results> list = status.getResults();
    		StringBuffer buffer = new StringBuffer();
    		for (int i = 0; i < list.size(); i++) {
    			Results results = list.get(i);
    			List<Weather> weather_data = results.getWeather_data();
    			for (int j = 0; j < weather_data.size(); j++) {
    				Weather weather = weather_data.get(j);
    				String date = weather.getDate();
    				String weath= weather.getWeather();
    				String temperature = weather.getTemperature();
    				buffer.append(date+" ");
    				buffer.append(weath+" ");
    				buffer.append(temperature+" ");
    				buffer.append("\n");
    			}
    		}
    		return buffer.toString();
    		
    	} 
    	
    }
    

    最后编写我们最核心的大脑系统servlet,编写JoinChatServlet中doPost()方法,接入公众号是get请求,粉丝与公众号之间进行消息回复是Post请求

    最终的servlet程序代码:

    package com.eastrobot.robotdev.wechat;
    
    import java.io.IOException;
    import java.io.PrintWriter;
    import java.io.UnsupportedEncodingException;
    import java.net.URLEncoder;
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.Comparator;
    import java.util.List;
    import java.util.Map;
    import java.util.Random;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.dom4j.DocumentException;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import com.eastrobot.robotdev.Constants;
    import com.eastrobot.robotdev.util.HttpUtils;
    import com.eastrobot.robotdev.wechat.entity.AccessToken;
    import com.eastrobot.robotdev.wechat.util.MessageUtils;
    import com.eastrobot.robotdev.wechat.util.SHA1Utils;
    import com.eastrobot.robotdev.wechat.util.WechatUtils;
    
    /**
     * 接入微信公众号平台
     * 
     * @author han.sun
     * 
     */
    public class JoinChatServlet extends HttpServlet {
    
    	private static final long serialVersionUID = 1L;
    	private static Logger log = LoggerFactory.getLogger(JoinChatServlet.class);
    	// private static ReceiveXmlUtils receiveXmlUtils;
    	// 微信上填写的Token数据
    	private static String Token = "sunhan";
    
    	public void doGet(HttpServletRequest request, HttpServletResponse response)
    			throws ServletException, IOException {
    		request.setCharacterEncoding(Constants.CHARSET);
    		response.setCharacterEncoding(Constants.CHARSET);
    		log.debug("GEt请求成功");
    		// 微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。
    		String signature = request.getParameter("signature");
    		// 时间戳
    		String timestamp = request.getParameter("timestamp");
    		// 随机数
    		String nonce = request.getParameter("nonce");
    		// 随机字符串
    		String echostr = request.getParameter("echostr");
    
    		List<String> params = new ArrayList<String>();
    		params.add(Token);
    		params.add(timestamp);
    		params.add(nonce);
    		// 1. 将token、timestamp、nonce三个参数进行字典排序
    		Collections.sort(params, new Comparator<String>() {
    			@Override
    			public int compare(String o1, String o2) {
    				return o1.compareTo(o2);
    			}
    		});
    
    		// 2. 将三个参数拼接成一个字符串进行SHA1进行加密
    		String temp = SHA1Utils.encode(params.get(0) + params.get(1)
    				+ params.get(2));
    		// 3. 加密后的字符串与signature比较,标识该请求是来自微信
    		if (temp.equals(signature)) {
    			// 原样返回echostr参数内容,则接入成功
    			response.getWriter().write(echostr);
    			log.debug("echostr传回微信后台成功...");
    		} else {
    			log.debug("echostr传回微信后台失败...");
    		}
    	}
    
    	public void doPost(HttpServletRequest request, HttpServletResponse response)
    			throws ServletException, IOException {
    		request.setCharacterEncoding(Constants.CHARSET);
    		response.setCharacterEncoding(Constants.CHARSET);
    		PrintWriter out = response.getWriter();
    
    		String result = null;
    		Map<String, String> map = null;
    		try {
    			map = MessageUtils.xmlToMap(request);
    		} catch (DocumentException e1) {
    			e1.printStackTrace();
    		}
    		String toUserName = map.get("ToUserName");
    		String fromUserName = map.get("FromUserName");
    		String msgType = map.get("MsgType");
    		String content = map.get("Content");
    
    		String echostr = request.getParameter("echostr");
    		// 判断是否是微信接入激活验证,只有首次接入验证时才会收到echostr参数,此时需要把它直接返回
    		if (echostr != null && echostr.length() > 1) {
    			result = echostr;
    		} else {
    
    			// 判断请求是是否是文本类型 text
    			if (MessageUtils.MESSAGE_TEXT.equals(msgType)) {
    				if ("文艺".equals(content)) {
    					result = imageProcess(toUserName, fromUserName);
    					// String mediaId =
    					// "7u19uWKlh-Nfpm8dAEpkhgxr0u5y0H5hxARQKsqtv3FjcMOV9dtFGxpYU4RvaV4t";
    					// result = MessageUtils.initImageMessage(mediaId,
    					// toUserName,fromUserName);
    				} else if ("图文".equals(content)) {
    					result = MessageUtils.initArticlesMessage(toUserName,
    							fromUserName);
    				} else {
    					String api = "http://ctr.demo.xiaoi.com/robot/ask.action?";
    					try {
    						URLEncoder.encode(content, Constants.CHARSET);
    					} catch (UnsupportedEncodingException e) {
    						e.printStackTrace();
    					}
    					// 拼接url
    					StringBuffer bf = new StringBuffer();
    					bf.append("question=");
    					bf.append(content);
    					bf.append("&paltform=weixin");
    					String url = api + bf.toString();
    					String message = HttpUtils.get(url, Constants.CHARSET);
    					message = message.substring(
    							message.indexOf("<Content>") + 9,
    							message.indexOf("</Content>"));
    					result = MessageUtils.initTextMessage(message, toUserName,
    							fromUserName);
    				}
    			}
    
    		}
    		out.write(result);
    		out.close();
    	}
    
    	private String imageProcess(String toUserName, String fromUserName) {
    		String message = null;
    		AccessToken token = WechatUtils.getAccessToken();
    		String mediaId = null;
    		Random ran = new Random();
    		int i = ran.nextInt(28);
    
    		String filePath = "/app/ibot-odin-robot-8005/webapps/robot-dev/image/0" + (i+1) + ".jpg";
    		try {
    			
    			mediaId = WechatUtils.upload(filePath, token.getToken(),
    					MessageUtils.MESSAGE_IMAGE);
    			// mediaId =
    			// "7u19uWKlh-Nfpm8dAEpkhgxr0u5y0H5hxARQKsqtv3FjcMOV9dtFGxpYU4RvaV4t";
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    		message = MessageUtils.initImageMessage(mediaId, toUserName,
    				fromUserName);
    		return message;
    	}
    }
    

    当然了还有一个常用类HttpUtils工具类,进行各种接口的调用。但凡遇见Constant.CHARSET全部改成UTF-8就行啦。

    展开全文
  • 微信验证开发者服务器接口 微信验证开发者服务器接口 如图所示,开发者可填写自己...流程图如下(不知道博客园怎么显示md流程图,有知道的仁兄告知):(取自微信公众平台技术文档) st=>start: 开启服务 ipop1=...

    微信验证开发者服务器接口

    微信验证开发者服务器接口

    1199621-20171227232815972-359054158.png

    • 如图所示,开发者可填写自己服务器的验证token的接口地址,以及自定义的token(博主申请的测试号,使用natapp来进行内网穿透)
    • 目的:帮助微信服务器和开发者服务器互相识别,以防恶意攻击
    • 流程图如下(不知道博客园怎么显示md流程图,有知道的仁兄告知):(取自微信公众平台技术文档)


    st=>start: 开启服务
    ipop1=>inputoutput: 接收到数据【不确定是谁发来的】
    op1=>operation: 尝试提取出signature字段,timestamp字段,nonce字段,echostr字段
    cd1=>condition: 字段均提取成功?
    op2=>operation: token赋值为基本配置中的信息
    op3=>operation: token,timestamp,nonce字段排序得到字符串list
    op4=>operation: 哈希算法加密list得到hashcode
    cd2=>condition: hashcode == signature?
    op5=>operation: 确定该数据源是微信后台
    ipop2=>inputoutput: 把echostr返回给微信后台,供微信后台认证Token
    ed=>end: 继续其他服务
    op6=>operation: 确定该数据源不是微信后台
    ipop3=>inputoutput: 不处理
    st->ipop1->op1->cd1->op2->op3->op4->cd2->op5->ipop2->ed
    cd1(yes)->op2
    cd1(no)->op6->ipop3->ed
    cd2(yes)->op5
    cd2(no)->op6


    • java代码实现如下:
        @GetMapping("/getToken")
        @ResponseBody
        public String getToken(TokenDTO tokenDTO, HttpServletResponse response){
            if ((StringUtils.isBlank(tokenDTO.getSignature()) || StringUtils.isBlank(tokenDTO.getTimestamp()) || StringUtils.isBlank(tokenDTO.getNonce()) || StringUtils.isBlank(tokenDTO.getEchostr()))) {
                return "";
            }
            String[] arr = new String[]{tokenDTO.getTimestamp(), WeixinConstant.token, tokenDTO.getNonce()};
            Arrays.sort(arr);
            StringBuffer sb = new StringBuffer();
            sb.append(arr[0]).append(arr[1]).append(arr[2]);
            String hash = null;
            try {
                hash = new String(Hex.encodeHex(MessageDigest.getInstance("SHA-1").
                        digest(sb.toString().getBytes(Constant.charset))));
            } catch (UnsupportedEncodingException | NoSuchAlgorithmException e) {
                e.printStackTrace();
            }
            return (StringUtils.isNoneBlank(hash) && hash.equals(tokenDTO.getSignature()))
                    ? tokenDTO.getEchostr() : "";
        }

    转载于:https://www.cnblogs.com/tswhq/p/8157795.html

    展开全文
  • 认识微信公众号1.微信账号类型2.微信公众号开发需求3.微信公众号开发原理 1.微信账号类型 个人号 公众号 订阅号 服务号 企业号 这里要讲的就是订阅号 前往注册微信公众号 ...前往微信公众号开发者文档 ...

    1.微信账号类型

    • 个人号
    • 公众号
      • 订阅号
      • 服务号
    • 企业号

    这里要讲的就是订阅号
    前往注册微信公众号

    2.微信公众号开发需求

    • 内嵌功能
      • 被动回复
      • 主动告知
      • 内嵌网页
    • 高级需求需编程实现如
      在这里插入图片描述

    3.微信公众号开发原理

    在这里插入图片描述
    编程人员要做的就是完成开发者服务器或者说是网页服务器
    前往微信公众号开发者文档

    展开全文
  • 如何接入公众号开发者模式的资料网上很多,也有许多成熟的SDK可以直接使用。为什么会有本文,主要的原因是最近自己刚刚申请了一个个人订阅号,由于无法认证,因而只需要接入开发者模式能够自动回复一些内容即可。...
    357a088b266bfa4d06b471cfe15b696b.gif


    如何接入公众号开发者模式的资料网上很多,也有许多成熟的SDK可以直接使用。为什么会有本文,主要的原因是最近自己刚刚申请了一个个人订阅号,由于无法认证,因而只需要接入开发者模式能够自动回复一些内容即可。因此本人特意花几个小时写了一个PHP脚本来实现该功能。


    单一PHP脚本的好处在于部署方便、性能足、代码量少、扩展性好。本文主要讲解整个实现流程。

    第一步、阅读官方开发文档


    对于程序开发者来说,学会和善于阅读官方开发文档,会让自己少走很多弯路。要接入开发者模式只需要阅读以下五篇文档即可。

    e076893cd3e20b8689002da800ad99a0.png

    第二步、开发代码


    代码主要分成两部分类:(1). 响应消息类 (2). 处理消息接入类。


    1.1、 创建一个响应消息类接口

    class MessageInterface{    // 获取消息体    public function getMessage(): array;}

    1.2、 创建文本响应消息类

    class TextMessage implements MessageInterface{    public function __construct($content)    {        $this->content = $content;    }    public function getMessage(): array    {        return [            "MsgType" => "text",            "Content" => $this->content        ];    }    protected $content;}

    1.3、创建其他类型响应消息类
    ​ 分别为: ImageMessage(图片)、VoiceMessage(语音)、VideoMessage(视频)、MusicMessage(音乐)、NewsMessage(图文)
    ​ 语法与TextMessage类类似,具体实现下载附件代码。


    2、处理消息接入类

    class Handler{  /**   * 处理请求   * @param array $get_params  $_GET参数     * @param null|callable $join_in_callback 接入回调函数,     *         原型:callback($echostr)     * @param string $raw_param HTTP POST RAW值     * @param null|callable $handle_message_callback 消息处理回调函数,     *         原型 array|string|true callback($request)     * @return string     * @throw Exception   */    public static function handle($get_params, $join_in_callback = null,        $raw_param = "", $handle_message_callback = null)    {            // 以下代码为功能备注,具体实现下载附件代码        // 0. 记录请求参数,$get_params、$raw_param        // 1. 校验参数,signature、timestamp、nonce        // 2. 校验微信加密签名signature是否合法        // 3. 若带参数echostr则判断为第一次接入        // 4. 非第一次接入,则将XML字符串转数组        // 5. 若带参数encrypt_type则将Encrypt值解密        // 6. 判断ToUserName是否为合法公众号ID        // 7. 设置来源用户OpenID为FromUserName        // 8. 使用handler_message_callback处理请求参数        // 9. 判断回调函数返回结果类型,并返回响应XML字符串    }    /**     * 记录日志     */    public static function log($message)    {    }  // 具体实现下载附件代码 ...}

    3、程序主流程(实现自问自答)

    4471251a33042ba39afa2eec5ed56cf4.png

    第三步、部署代码


    代码开发完之后,比较简单的部署方式有两种:(1). 云虚拟主机 (2). 新浪SAE


    1、云虚拟主机部署
    建站常用的三件套:域名、程序、空间。如果你已经拥有域名和空间,则可以直接将该程序上传到空间即可。


    2、新浪SAE部署
    新浪SAE是中国最早、最大的PaaS服务商,对于不想购买域名的人来说,将程序部署到SAE上是最便捷、便宜的一种方式。


    购买新浪云应用(PHP版本)

    220139cf0cbc8cd3357e5082b28528b1.png


    进入云应用控制台


    控制台 > 运行环境管理 > PHP版本管理 > 切换为PHP 7.4版本

    0bae8f2683646d9b1da8cdb1a6e5712a.png


    控制台 > 运行环境管理 > 代码管理 > 上传代码(ZIP包)

    a6a7c94834236a0de45a66f5ee585820.png

    第四步、微信公众号中配置开发者模式


    微信公众号后台 > 开发 > 基本配置 > 服务器配置

    d1b9cb9134a5d7ba009224c759aea3f2.png

    第五步、测试公众号开发者模式


    微信 > 搜索/扫一扫添加公众号 > 加关注/发送消息测试

    【源码点击下面链接下载】

    展开全文
  • 如何接入公众号开发者模式的资料网上很多,也有许多成熟的SDK可以直接使用。为什么会有本文,主要的原因是最近自己刚刚申请了一个个人订阅号,由于无法认证,因而只需要接入开发者模式能够自动回复一些内容即可。...
  • 如何接入公众号开发者模式的资料网上很多,也有许多成熟的SDK可以直接使用。为什么会有本文,主要的原因是最近自己刚刚申请了一个个人订阅号,由于无法认证,因而只需要接入开发者模式能够自动回复一些内容即可。...
  • 如何接入公众号开发者模式的资料网上很多,也有许多成熟的SDK可以直接使用。为什么会有本文,主要的原因是最近自己刚刚申请了一个个人订阅号,由于无法认证,因而只需要接入开发者模式能够自动回复一些内容即可。...
  • 相关文档微信公众号开发-实现服务端回复消息为空   xstream简单使用(wx消息体处理)   XStream-bean转换为xml是,携带CDATA  controller中直接...首先,按照微信公众号开发文档提示,进行公众号申请: ...
  • 在要做微信项目开发前,大家都会去了解微信公众号的类型和注册流程,以及不同公众号的功能使用权限,这个我前面文章也有过介绍,做微信开发公众号最起码得是一个已认证的服务号,这里我是指企业项目哈,当然如果是...
  • 要搭建加密传输的微信公众号消息传输,首先要在开发这平台下载一下微信加密的相关jar包,并做一些准备。准备的步骤如下: 1.打开开发者文档,找到消息加减密--->接入指引,如下图所示: 2.在页面底部...
  • 公众号平台 网址 ...id=mp1445241432 1..开发者首先浏览 微信公众号平台开发文档:https://mp.weixin.qq.com/wiki 2..注册微信公众号 进入微信公众号注册页面https://m...
  • 要搭建加密传输的微信公众号消息传输,首先要在开发这平台下载一下微信加密的相关jar包,并做一些准备。准备的步骤如下: 1.打开开发者文档,找到消息加减密--->接入指引,如下图所示: 2.在页面...
  • WeRoBot 是一个微信公众号开发框架,采用MIT协议发布。 Werobot文档:链接 我原本是打算在个人订阅号玩一玩自定义开发,因为可以实现很多有趣的功能。 结果弄到自定义菜单的时候居然发现: 个人订阅号无法...
  • 最近一个项目是在微信公众号内二次开发,涉及到微信公众号支付,根据文档要求想要支付就必须要获取到用户的openid。官方流程网页授权流程分为四步:1、引导用户进入授权页面同意授权,获取code2、通过code换取网页...
  • 要知道公众号开启开发者模式后,公众号自带的功能就不能使用了。 那么如何自定义菜单呢? 此时,我们要通过接口来配置微信自定义菜单,微信自定义菜单接口链接 先查看官方文档的自定义菜单: 然后,我们打开微信...
  • 公众号每次调用接口时,可能获得正确或错误的返回码, 开发者可以根据返回码信息调试接口,排查错误 全局返回码说明如下: 返回码 说明 -1 系统繁忙,此时请开发者稍候再试 0 请求成功 40001 ...
  • 微信公众号

    2017-09-08 16:37:10
    一份官方文档:微信公众平台开发者文档;里面有很多的代码demo一本书:微信公众平台应用开发 (豆瓣)一系列视频:初识Java微信公众号开发;Java微信公众号开发进阶GitHub有很多开源的代码可以学习。
  • 微信公众号开发基本流程

    万次阅读 多人点赞 2019-04-07 16:46:18
    过年前后做了个微信公众号项目,已经过去一段时间了,抽空回忆总结下基本流程吧,不然很快估计自己就忘了。。 微信公众平台官网:https://mp.weixin.qq.com 文章目录一、注册公众号二、了解公众号管理页面三、必备...
  • 微信的开发者文档真的有点丈二和尚摸不着头脑,有点让人迷糊。 做微信公众号开发,先注册微信公众号,最好有一个服务器和一个备过案的域名,不然很多jsapi接口无法调试。 一般情况下,个人注册订阅号,企业注册...
  • Go 学习之路:Go 开发者博客、Go 微信公众号、Go 学习资料(文档、书籍、视频)
  • java实现微信公众号推送消息

    万次阅读 2019-07-09 15:15:40
    微信公众号开发文档 基本信息 AppID:开发者ID,微信公众号的唯一标识 AppSecret:开发者密码,操作微信公众号的验证 IP白名单:获取access_token时,需要IP白名单才可以获取 OpenID:微信用户在当前公众号的唯一...
  • 新浪微博与微信公众号开发总结

    千次阅读 2018-07-18 15:47:18
    微信公众号开发者文档地址: https://mp.weixin.qq.com/wiki?t=resource/res_main&amp;id=mp1445241432 可根据文档开始微信者公众号开发: 以下说明一些注意点: 微信公众号的每个接口都需要传入access_...
  • 没有公众号的可以使用微信测试号进行开发 申请测试号地址:https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login 微信开发文档:https://mp.weixin.qq.com/wiki?t=resource/res_main&amp;id=mp...
  • JAVA对接微信公众号

    2020-06-04 18:20:26
    微信公众号开发文档 对接别人的东西,肯定需要文档 第二步 搭建微信公众号环境。 如果有公司资源可以利用最好,没有的话,需要本地外网映射 原文链接:初识微信公众号以及环境搭建 该文章介绍几个免费的可以将我们本地...
  • 一、开通现金红包权限注意: ...操作路径:【登录微信支付商户平台——>产品中心——>现金红包——>开通】。说明:在开通时请如实选择你的使用场景,且在红包的发放过程中如实上报你的场景,如有作假,微信...
  • 微信公众号开发教程

    2019-11-17 02:04:42
    微信开发者文档 文章目录微信公众号开发教程1. 开发须知1.1 相关概念1.1.1 AppID1.1.2 AppSecret1.1.3 access_token1.1.4 jsapi_ticket1.1.5 JS_SDK网页签名1.2 开发主要配置1.2.1 JS安全域名1.2.2 IP白名单设置1......
  • 微信公众号开发

    2018-10-17 11:05:48
    微信公众号开发微信公众号开发1.自定义菜单代码2....开发者文档将一级菜单与二级菜单以json数据格式封装好; { &amp;quot;button&amp;quot;:[ { &amp;quot;type&amp;quot;:&
  • 微信公众号启用了开发者模式,自定义菜单需要链接一个其他开发者的小程序时,我们该怎么办? 0.需要提前准备的工具 首先你得有一个微信公众平台的公众号并且你是管理员 然后你注册了微信公众平台小程序并且能够...
  • (一)接入流程解析 在我们的开发过程中无论如何最好的参考...通过上面我们可以看出其中接入微信公众平台开发,开发者需要按照如下步骤完成: 填写服务器配置 验证服务器地址的有效性 依据接口文档实现业务逻
  • 微信JS-SDK Demo https://www.weixinsxy.com/jssdk/ jQuery WEUI 旧版 http://old.jqweui.com/components#navbar jQuery WEUI 新版 ...微信JSSDK说明文档-微信公众号开发者平台 http://caibaojian.com/wxw...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,010
精华内容 404
关键字:

微信公众号开发者文档