微信公众号,我们都很熟悉。但是如何开一个属于自己的一个微信公众号,其实很简单。这边文章就给一个简单的例子。需要准备的环境:
1、域名,用于微信公众号访问我们的服务器,如没有域名,建议使用花生壳进行内网穿透来访问我们的项目(具体使用方法,不在这里讨论)
2、需要申请一个微信公众号:https://mp.weixin.qq.com/
3、需要一个Javaweb项目
万事俱备后,开始生路。
第一步,对微信公众号的一些配置:
登录微信公众平台,找到如图所示
填写如下的信息,url是我们项目的URL,token是我们自己定义的
此时,我们点提交会报错,是因为我们还没有校验,当我们点提交之后,会通过get方式发送一些校验的数据到我们的项目。然后我们需要进行校验
第二步,数据的检验,检验方式是SHA1算法,具体如下代码
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
System.out.println("进入get方法");
String str = request.getQueryString();
String echostr = check(str);
OutputStream out = response.getOutputStream();
if(str != null)
{
try
{
out.write(echostr.getBytes());
}finally{
out.close();
}
}
}
private String check(String text)
{
//解析发过来的参数:
//signature=2e334555ebb6e43ec2c975d6ad54f642d7c95252&echostr=9019000808531292887×tamp=1563681495&nonce=1882518168
/*
* 微信公众号会通过get请求发送如上的参数,然后我们验证是否是微信公众号的请求,
* timestamp nonce tokone 我们将这三个连起来进行加密,加密前要对他们进行按字母排序,
* 其中tokone是我们自己写的
* 如果密文匹配,我们返回echostr的值,此时微信公众化那边就认为匹配成功
*/
String[] content = text.split("&");
String signature = content[0].split("=")[1];
String echostr = content[1].split("=")[1];
String timestamp = content[2].split("=")[1];
String nonce = content[3].split("=")[1];
String token = "hello2019";//这个自己定义,单要与页面上的一致
String[] arr = {token , timestamp , nonce};
Arrays.sort(arr);//根据字符的顺序排序
//排序后将三个字符串连起来
String checkCode = arr[0] + arr[1] + arr[2];//将排序后字符串连接起来
MessageDigest md;
try
{
//进行SHA1加密
md = MessageDigest.getInstance("SHA1");
md.update(checkCode.getBytes());
byte[] code = md.digest();
//将加密后的字节数组转成十六 进制字符串
String ss = Hex.encodeHexString(code);
if(ss.endsWith(signature))//判断两个密文是否一致
{
return echostr;
}
} catch (NoSuchAlgorithmException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
校验通过之后,我点提交按钮就会提示校验成功。
第三步,处理文本信息。当我们检验成功之后,我们在公众号好发一条消息,微信公众号会通post方式以xml格式发送到我的项目,然后我们就对数据进行解析,具体各种字段的含义可以参考微信公众号的开发文档https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1472017492_58YV5
下面是我自己的处理方法,首先写一个工具类,用来xml与map之间的转换,其中用到dom4j的jar包,代码如下:
package my;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
public class TextUtils
{
/**
* 读取字符串
* @param input
* @return
* @throws IOException
*/
public static String readAsText(InputStream input , String charSet) throws IOException
{
ByteArrayOutputStream cache = new ByteArrayOutputStream();
byte[] buf = new byte[1024];
int count = -1;
while(true)
{
int n = input.read(buf);
if(n == 0)
{
try
{
Thread.sleep(3000);
count++;
} catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
if(count < 3)
{
continue;
}
else
{
break;
}
}
if(n < 0)
{
break;
}
cache.write(buf, 0, n);
}
return cache.toString(charSet);
}
/**
* 默认编码格式是UTF-8
* @param input
* @return
* @throws IOException
*/
public static String readAsText(InputStream input) throws IOException
{
return readAsText(input , "UTF-8");
}
/**
* 将xml格式转成map
* @return
* @throws DocumentException
*/
public static Map<String , String> xml2Map(InputStream input) throws DocumentException
{
Map<String , String> map = new HashMap<String , String>();
SAXReader xmlReader = new SAXReader();
Document x_doc = xmlReader.read(input);
Element x_root = x_doc.getRootElement();
List<Element> list = x_root.elements();
for(Element e : list)
{
String name = e.getName();
String value = e.getTextTrim();
map.put(name, value);
}
return map;
}
/**
*
* @param map
* @return
* @throws IOException
*/
public static String map2Xml(Map<String , String> map) throws IOException
{
//创建一个空的Document
Document x_doc = DocumentHelper.createDocument();
//添加跟元素
Element x_root = x_doc.addElement("xml");
Iterator<java.util.Map.Entry<String, String>> entries = map.entrySet().iterator();
while(entries.hasNext())
{
Entry<String, String> entry = entries.next();
String key = entry.getKey();
Object value = entry.getValue();
x_root.addElement(key).addCDATA((String) value);
}
OutputStream out = new ByteArrayOutputStream();
OutputFormat format = OutputFormat.createPrettyPrint();
format.setEncoding("UTF-8");
format.setSuppressDeclaration(true);
format.setIndent(true);
format.setNewlines(true);
XMLWriter xmlWriter = new XMLWriter(out,format);
xmlWriter.write(x_doc);
xmlWriter.close();
return out.toString();
}
}
消息的接收与回复:
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
System.out.println("用户发出信息");
InputStream input = request.getInputStream();
try
{
//将用户发过来的信息转成map
Map<String , String> map = TextUtils.xml2Map(input);
//获取消息内容
String content = (String) map.get("Content");
//构造返回的信息
Map<String , String> reply = new HashMap();
reply.put("ToUserName", map.get("FromUserName"));
reply.put("FromUserName", map.get("ToUserName"));
reply.put("CreateTime", String.valueOf(System.currentTimeMillis()));
reply.put("MsgType", "text");
reply.put("Content", "欢迎");
String str = TextUtils.map2Xml(reply);//将回复的信息转成xml格式的
//将信息发出去
OutputStream out = response.getOutputStream();
out.write(str.getBytes());
out.close();
} catch (DocumentException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
此例子只给出了文本信息的处理,其实对其他类型信息的处理也是大同小异,就不在累赘。具体的消息每个字段代表的含义可参考微信公众开发平台的开发文档。最后也提供源码:链接:https://pan.baidu.com/s/1dkRzEJqrn_MyVvz0RL2WAw
提取码:ssdv
有不足之处,希望多多提出宝贵意见。