1.申请隧道
在开发之前我们先去申请一个隧道
https://natapp.cn/
注册完成后我们就可以申请隧道了
注:注意自己的本地端口号
这样我们就可以使用authtoken了
2.使用隧道
下载客户端
https://natapp.cn/#download
将下载好的安装包解压后即可
启动cmd
进入到安装包的目录文件
输入:natapp -authtoken [authtoken]
这个就是我们所需要的URL地址了。
注:不要关闭cmd。
3.测试项目
在com.wx.pojo包下
新建一个实体类AccessToken
public class AccessToken {
private String token;
private int expiresIn;
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
public int getExpiresIn() {
return expiresIn;
}
public void setExpiresIn(int expiresIn) {
this.expiresIn = expiresIn;
}
}
新建实体类TextMessage
public class TextMessage{
private String ToUserName;
private String FromUserName;
private long CreateTime;
private String MsgType;
private String Content;
private String MsgId;
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;
}
public String getContent() {
return Content;
}
public void setContent(String content) {
Content = content;
}
public String getMsgId() {
return MsgId;
}
public void setMsgId(String msgId) {
MsgId = msgId;
}
}
在com.wx.util包下
新建一个WeixinUtil类
public class WeixinUtil {
public static final String APPID = "***********";
public static final String APPSECRET = "***********";
private static final String UPLOAD_URL = "https://api.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE";
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 CREATE_MENU_URL = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN";
/**
* get请求
* @param url
* @return
*/
public static JSONObject doGetStr(String url){
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(url);
JSONObject jsonObject = null;
try {
HttpResponse response = httpClient.execute(httpGet);
HttpEntity httpEntity = response.getEntity();
if(httpEntity != null){
String result = EntityUtils.toString(httpEntity,"UTF-8");
jsonObject = JSONObject.fromObject(result);
}
} catch (IOException e) {
e.printStackTrace();
}
return jsonObject;
}
/**
* post请求
* @param url
* @param outStr
* @return
*/
public static JSONObject doPostStr(String url, String outStr){
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(url);
JSONObject jsonObject = null;
httpPost.setEntity(new StringEntity(outStr,"UTF-8"));
try {
HttpResponse response = httpClient.execute(httpPost);
String result = EntityUtils.toString(response.getEntity(),"UTF-8");
jsonObject = JSONObject.fromObject(result);
} catch (IOException e) {
e.printStackTrace();
}
return jsonObject;
}
/**
* 获取access_token
* @return
*/
public static AccessToken getAccessToken(){
AccessToken accessToken = new AccessToken();
String url = ACCESS_TOKEN_URL.replace("APPID",APPID).replace("APPSECRET",APPSECRET);
JSONObject jsonObject = doGetStr(url);
if(jsonObject != null){
accessToken.setToken(jsonObject.getString("access_token"));
accessToken.setExpiresIn(jsonObject.getInt("expires_in"));
}
return accessToken;
}
/**
* 图片上传
* @param filPpath
* @param accessToken
* @param type
* @return
*/
public static String upload(String filPpath,String accessToken,String type) throws IOException {
File file = new File(filPpath);
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;
//定义BudderedReader输入流来读取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();
}
JSONObject jsonObject = JSONObject.fromObject(result);
System.out.println(jsonObject);
String mediaId = jsonObject.getString("media_id");
return mediaId;
}
/**
* 组装菜单
* @return
*/
public static Menu initMenu() throws UnsupportedEncodingException {
Menu menu = new Menu();
ViewButton myButton = new ViewButton();
myButton.setName("我的");
myButton.setType("view");
myButton.setUrl("https://open.weixin.qq.com/connect/oauth2/authorize?appid=***********&redirect_uri="+ URLEncoder.encode("http://37n4ud.natappfree.cc/standard/user/toMy", "UTF-8") +"&response_type=code&scope=snsapi_base&state=123#wechat_redirect");
ViewButton viewButton1 = new ViewButton();
viewButton1.setName("班次查询");
viewButton1.setType("view");
viewButton1.setUrl("https://open.weixin.qq.com/connect/oauth2/authorize?appid=***********&redirect_uri="+ URLEncoder.encode("http://37n4ud.natappfree.cc/standard/user/toClasses", "UTF-8") +"&response_type=code&scope=snsapi_base&state=123#wechat_redirect");
ViewButton viewButton2 = new ViewButton();
viewButton2.setName("工资查询");
viewButton2.setType("view");
viewButton2.setUrl("https://open.weixin.qq.com/connect/oauth2/authorize?appid=***********&redirect_uri="+ URLEncoder.encode("http://37n4ud.natappfree.cc/standard/jsp/salary", "UTF-8") +"&response_type=code&scope=snsapi_base&state=123#wechat_redirect");
ViewButton viewButton3 = new ViewButton();
viewButton3.setName("违章查询");
viewButton3.setType("view");
viewButton3.setUrl("https://open.weixin.qq.com/connect/oauth2/authorize?appid=***********&redirect_uri="+ URLEncoder.encode("http://37n4ud.natappfree.cc/standard/jsp/outRules", "UTF-8") +"&response_type=code&scope=snsapi_base&state=123#wechat_redirect");
Button infoButton = new Button();
infoButton.setName("信息查询");
infoButton.setSub_button(new Button[]{viewButton1,viewButton2,viewButton3});
menu.setButton(new Button[]{infoButton,myButton});
return menu;
}
public static int createMenu(String token, String menu) throws ParseException,IOException {
int result = 0;
String url = CREATE_MENU_URL.replace("ACCESS_TOKEN",token);
JSONObject jsonObject = doPostStr(url,menu);
if(jsonObject != null){
result = jsonObject.getInt("errcode");
}
return result;
}
}
在com.wx.util包下
新建一个类MessageUtil
public class MessageUtil {
public static final String MESSAGE_TEXT = "text";
public static final String MESSAGE_NEWS = "news";
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";
/**
* xml转为map集合
* @param request
* @return
* @throws IOException
* @throws DocumentException
*/
public static Map<String,String> xmlToMap(HttpServletRequest request) throws IOException, DocumentException {
Map<String,String> map = new HashMap<>();
SAXReader reader = new SAXReader();
InputStream ins = request.getInputStream();
Document doc = reader.read(ins);
Element root = doc.getRootElement();
List<Element> list = root.elements();
for(Element e : list){
map.put(e.getName(),e.getText());
}
ins.close();
return map;
}
/**
* 文本对象
* @param toUserName
* @param fromUserName
* @param content
* @return
*/
public static String initText(String toUserName,String fromUserName,String content){
TextMessage textMessage = new TextMessage();
textMessage.setFromUserName(toUserName);
textMessage.setToUserName(fromUserName);
textMessage.setMsgType("text");
textMessage.setCreateTime(new Date().getTime());
textMessage.setContent(content);
return textMessageToXml(textMessage);
}
/**
* 将文本消息对象转为xml
* @param textMessage
* @return
*/
public static String textMessageToXml(TextMessage textMessage){
XStream xStream = new XStream();
xStream.alias("xml",textMessage.getClass());
return xStream.toXML(textMessage);
}
/**
* 组装菜单
* @return
*/
public static String menuText(){
StringBuffer sb = new StringBuffer();
sb.append("感谢您的关注~,请按照菜单提示进行操作:\n\n");
sb.append("1、请先点击我的绑定您的个人信息\n");
sb.append("2、绑定完成后可以查看您的明日班次、工资信息、违章信息以及个人信息\n");
sb.append("3、输入内容,获取您输入的内容\n\n");
sb.append("回复?调出此菜单");
return sb.toString();
}
}
在com.wx.weChatServlet包下
新建一个类weChatAccounts
/**
* Servlet implementation class weChatAccounts
*/
public class weChatAccounts extends HttpServlet {
@Override
public void init(ServletConfig config) throws ServletException
{
SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, config.getServletContext());
}
@Autowired
private WxService wxService;
/*
* 自定义token, 用作生成签名,从而验证安全性
* */
private final String TOKEN = "cherry";
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
resp.setCharacterEncoding("UTF-8");
PrintWriter out = resp.getWriter();
try {
Map<String,String> map = MessageUtil.xmlToMap(req);
String toUserName = map.get("ToUserName");
String fromUserName = map.get("FromUserName");
String msgType = map.get("MsgType");
String content = map.get("Content");
String message = null;
String a = wxService.query();
if(MessageUtil.MESSAGE_TEXT.equals(msgType)){
if("?".equals(content) || "?".equals(content)){
message = MessageUtil.initText(toUserName,fromUserName,MessageUtil.menuText());
}else if(content.contains("查询")){
String worknum = content.substring(2,content.length()).trim();
message = MessageUtil.initText(toUserName,fromUserName,"查询结果为:\n" + a);
}else {
message = MessageUtil.initText(toUserName,fromUserName,"您所输入的内容为:" + content);
}
}else if(MessageUtil.MESSAGE_EVENT.equals(msgType)){
if(map.get("EventKey").equals("11")){
message = MessageUtil.initText(toUserName,fromUserName,"您点击了click菜单");
}
String eventType = map.get("Event");
if(MessageUtil.MESSAGE_SUBSCRIBE.equals(eventType)){
message = MessageUtil.initText(toUserName,fromUserName,MessageUtil.menuText());
}
}
System.out.println(message);
out.print(message);
} catch (DocumentException e) {
e.printStackTrace();
}finally {
out.close();
}
}
@Override
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
try {
System.out.println("-----开始校验签名-----");
/**
* 接收微信服务器发送请求时传递过来的参数
*/
String signature = req.getParameter("signature");
String timestamp = req.getParameter("timestamp");
String nonce = req.getParameter("nonce"); //随机数
String echostr = req.getParameter("echostr");//随机字符串
/**
* 将token、timestamp、nonce三个参数进行字典序排序
* 并拼接为一个字符串
*/
String sortStr = sort(TOKEN,timestamp,nonce);
/**
* 字符串进行shal加密
*/
String mySignature = shal(sortStr);
/**
* 校验微信服务器传递过来的签名 和 加密后的字符串是否一致, 若一致则签名通过
*/
if(!"".equals(signature) && !"".equals(mySignature) && signature.equals(mySignature)){
System.out.println("-----签名校验通过-----");
resp.getWriter().write(echostr);
}else {
System.out.println("-----校验签名失败-----");
}
} catch (BeansException e) {
e.printStackTrace();
}
}
/**
* 参数排序
* @param token
* @param timestamp
* @param nonce
* @return
*/
public String sort(String token, String timestamp, String nonce) {
String[] strArray = {token, timestamp, nonce};
Arrays.sort(strArray);
StringBuilder sb = new StringBuilder();
for (String str : strArray) {
sb.append(str);
}
return sb.toString();
}
/**
* 字符串进行shal加密
* @param str
* @return
*/
public String shal(String str){
try {
MessageDigest digest = MessageDigest.getInstance("SHA-1");
digest.update(str.getBytes());
byte messageDigest[] = digest.digest();
StringBuffer hexString = new StringBuffer();
// 字节数组转换为 十六进制 数
for (int i = 0; i < messageDigest.length; i++) {
String shaHex = Integer.toHexString(messageDigest[i] & 0xFF);
if (shaHex.length() < 2) {
hexString.append(0);
}
hexString.append(shaHex);
}
return hexString.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return "";
}
}
新建测试类WeixinTest
public class WeixinTest {
public static void main(String[] args) throws IOException {
AccessToken token = WeixinUtil.getAccessToken();
System.out.println("票据:" + token.getToken());
System.out.println("有效时间:" + token.getExpiresIn());
String menu = JSONObject.fromObject(WeixinUtil.initMenu()).toString();
int result = WeixinUtil.createMenu(token.getToken(),menu);
if(result == 0){
System.out.println("创建菜单成功");
}else{
System.out.println("错误码:" + result);
}
}
}
4.配置微信公众平台
开发=>基本配置=>修改配置
URL已http开头跟上你的隧道authtoken接项目路径直接访问weChatServlet包
注:许启动项目后才可以通过
接着进入
开发=》开发者工具=》公众平台测试账号
往下拖
扫描二维码就可以访问了。