java开发微信公众号接受并回复消息[工程代码+图片全解]

news/2024/11/18 0:47:53/

写这篇博客时犹豫了好久,因为步骤太多了,上班了也没时间,但是我依然记得当时实现公众号自动回复时的场景,找个案例好

难,也没有一个完整的案例,想了想还是写出来吧,希望能让实现这功能的人少走弯路。

微信公众号平台也有自定义回复消息,比如我在公众号里发送关注你,我们在微信公众号平台设置关键字关注你(就是

有人发送这个关键字就要回复什么内容)设置成回复:**你好,java!**适用于这种固定信息,如果我发送 获取个人信息、我的积

分这种内容就需要动态的数据了,所以要使用我们自己的接口往数据库中进行查询信息。

这个项目实现了简单的回复文字消息,没有 图片、音频等类型的发送、推荐看微信API文档实现,我这也有实现的案例需要的可加我QQ 930496909

首先:

先整理一下大致流程

1.编写java代码,要按照微信公众号提供的API文档来做。

2.下载ngrok工具,假设编写的Java都不会部署到网上(本地运行项目),那我们要想微信能访问我们的java接口我们需要一个工

具(就是将我们本地电脑变成服务器,让别人能来访问我们本地运行的项目说的比较通俗具体可百度~),如果编写的java程序

部署到服务器上就不用啦。

3.在微信公众号平台注册服务号或者订阅号[两者的区别在于服务号收钱功能多,其他区别可自行百度~]我注册的是订阅号,然

后在微信平台进行一些配置,(其实就是让关注公众号的人发送消息后能够对接我们的java接口)

4.进行测试。(我会把源码贴到码云上,可以下载源码https://gitee.com/it_qin/weixintest.git)

接下来就是步骤了。

看一下java结构目录

jar包(因为当时在学校做的还不太会用MAVEN管理,无奈啊,jar包主要就是ssm框架jar包和微信的几个包,我把截图发下,上面

我提供的码云链接上也有jar包)
这里写图片描述
下面就是每个文件了

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"><!--  配置编码(解决中文乱码)过滤器 --><filter><filter-name>encodingFilter</filter-name><filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class><init-param><param-name>encoding</param-name><param-value>UTF-8</param-value></init-param><init-param><param-name>forceEncoding</param-name><param-value>true</param-value></init-param></filter><filter-mapping><filter-name>encodingFilter</filter-name><url-pattern>/*</url-pattern>  </filter-mapping>
<!-- log4j日志文件 --><context-param><param-name>log4jConfigLocation</param-name><param-value>classpath:log4j.properties</param-value></context-param> <listener><listener-class>org.springframework.web.util.Log4jConfigListener</listener-class></listener><!-- 创建springMvc的  dispathServlet  --><servlet><servlet-name>springMvc</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:springmvc-servlet.xml</param-value></init-param><load-on-startup>1</load-on-startup><!-- 服务器一启动就加载 --></servlet><!--拦截后缀是.do--><servlet-mapping><servlet-name>springMvc</servlet-name><url-pattern>*.do</url-pattern></servlet-mapping><!-- 启动spring容器  spring配置文件的位置--><context-param><param-name>contextConfigLocation</param-name><param-value>classpath:applicationContext-mybatis.xml</param-value></context-param> <!-- 监听spring容器的启动 --><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener>
</web-app>

springmvc-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:mvc="http://www.springframework.org/schema/mvc"xmlns:p="http://www.springframework.org/schema/p"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc.xsd"><context:component-scan base-package="com.qhk.controller"/><mvc:annotation-driven><mvc:message-converters><bean class="org.springframework.http.converter.StringHttpMessageConverter"><property name="supportedMediaTypes"><list><value>application/json;charset=UTF-8</value></list></property></bean><bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter"><property name="supportedMediaTypes"><list><value>text/html;charset=UTF-8</value><value>application/json</value></list></property><property name="features"><list><value>WriteDateUseDateFormat</value></list></property></bean></mvc:message-converters></mvc:annotation-driven><!-- 配置多视图解析器 --><bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver"><property name="favorParameter" value="true"/> <property name="defaultContentType" value="text/html" /> <property name="mediaTypes"><map><entry key="html" value="text/html; charset=UTF-8"/><entry key="json" value="application/json; charset=UTF-8"/><entry key="xml" value="application/xml; charset=UTF-8"/></map></property><property name="viewResolvers"><list><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="/"/><property name="suffix" value=".jsp"/></bean></list></property></bean><!-- 配置interceptors --><!-- <mvc:interceptors><mvc:interceptor><mvc:mapping path="/main/**"/><bean class="com.ktv.interceptor.SysInterceptor"/></mvc:interceptor> </mvc:interceptors> --><!-- 配置文件上传  MultipartResolver--><bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"><property name="maxUploadSize" value="500000000"/><property name="defaultEncoding" value="UTF-8"/></bean> 
</beans>   

applicationContext-mybatis.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"xmlns:p="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/tx"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="   http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd   http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd   http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><context:component-scan base-package="com.qhk.service" /><context:annotation-config /><context:property-placeholder location="classpath:database.properties" /><!-- JNDI获取数据源(使用dbcp连接池) --><bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"destroy-method="close" scope="singleton"><property name="driverClassName" value="${driver}" /><property name="url" value="${url}" /><property name="username" value="${user}" /><property name="password" value="${password}" /><property name="initialSize" value="${initialSize}" /><property name="maxActive" value="${maxActive}" /><property name="maxIdle" value="${maxIdle}" /><property name="minIdle" value="${minIdle}" /><property name="maxWait" value="${maxWait}" /><property name="removeAbandoned" value="${removeAbandoned}" /><property name="removeAbandonedTimeout" value="${removeAbandonedTimeout}" /><property name="testWhileIdle" value="true" /><property name="timeBetweenEvictionRunsMillis" value="60000" /><property name="testOnBorrow" value="false" /><property name="testOnReturn" value="false" /><property name="validationQuery" value="select 1" /><property name="numTestsPerEvictionRun" value="${maxActive}" /></bean><!-- 事务管理 --><bean id="txManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource" /></bean><!-- 配置mybatis SqlSessionFactoryBean --><bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean"><property name="dataSource" ref="dataSource" /><property name="configLocation" value="classpath:mybatis-config.xml" /></bean><aop:aspectj-autoproxy /><aop:config proxy-target-class="true"><aop:pointcut expression="execution(* *com.qhk.service..*(..))"id="transService" /><aop:advisor advice-ref="myAdvice" pointcut-ref="transService" /></aop:config><tx:advice id="myAdvice" transaction-manager="txManager"><tx:attributes><tx:method name="find*" read-only="true" propagation="SUPPORTS" /><tx:method name="add*" propagation="REQUIRED" /><tx:method name="update*"  propagation="REQUIRED" /><tx:method name="del*"  propagation="REQUIRED" /><tx:method name="*" /></tx:attributes></tx:advice><bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"  ><property name="basePackage" value="com.qhk.dao" /></bean></beans>

mybatis-config.xml

<?xml version="1.0" encoding="UTF-8"?>  
<!DOCTYPE configuration   PUBLIC "-//mybatis.org//DTD Config 3.0//EN"   "http://mybatis.org/dtd/mybatis-3-config.dtd">  
<configuration>  <settings>  <!-- changes from the defaults -->  <setting name="lazyLoadingEnabled" value="false" />  </settings>  <typeAliases>  <!--这里给实体类取别名,方便在mapper配置文件中使用--> <package name="com.qhk.entity"/></typeAliases> 
</configuration>  

database.properties

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/ktvsystem?useUnicode=true&characterEncoding=utf-8
user=root
password=admin
minIdle=45
maxIdle=50
initialSize=5
maxActive=100
maxWait=100
removeAbandonedTimeout=240
removeAbandoned=true

log4j.properties

log4j.rootLogger=debug,CONSOLE,file
#log4j.rootLogger=ERROR,ROLLING_FILElog4j.logger.cn.smbms=debug
log4j.logger.org.apache.ibatis=debug
log4j.logger.org.mybatis.spring=debug
log4j.logger.java.sql.Connection=debug
log4j.logger.java.sql.Statement=debug
log4j.logger.java.sql.PreparedStatement=debug
log4j.logger.java.sql.ResultSet=debug######################################################################################
# Console Appender  \u65e5\u5fd7\u5728\u63a7\u5236\u8f93\u51fa\u914d\u7f6e
######################################################################################
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.Threshold=debug
log4j.appender.CONSOLE.DatePattern=yyyy-MM-dd
log4j.appender.CONSOLE.Target=System.out
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern= - (%r ms) - %d{yyyy-M-d HH:mm:ss}%x[%5p](%F:%L) %m%n######################################################################################
# Rolling File  \u6587\u4ef6\u5927\u5c0f\u5230\u8fbe\u6307\u5b9a\u5c3a\u5bf8\u7684\u65f6\u5019\u4ea7\u751f\u4e00\u4e2a\u65b0\u7684\u6587\u4ef6
######################################################################################
#log4j.appender.ROLLING_FILE=org.apache.log4j.RollingFileAppender
#log4j.appender.ROLLING_FILE.Threshold=INFO
#log4j.appender.ROLLING_FILE.File=${baojia.root}/logs/log.log
#log4j.appender.ROLLING_FILE.Append=true
#log4j.appender.ROLLING_FILE.MaxFileSize=5000KB
#log4j.appender.ROLLING_FILE.MaxBackupIndex=100
#log4j.appender.ROLLING_FILE.layout=org.apache.log4j.PatternLayout
#log4j.appender.ROLLING_FILE.layout.ConversionPattern=%d{yyyy-M-d HH:mm:ss}%x[%5p](%F:%L) %m%n######################################################################################
# DailyRolling File  \u6bcf\u5929\u4ea7\u751f\u4e00\u4e2a\u65e5\u5fd7\u6587\u4ef6\uff0c\u6587\u4ef6\u540d\u683c\u5f0f:log2009-09-11
######################################################################################
log4j.appender.file=org.apache.log4j.DailyRollingFileAppender
log4j.appender.file.DatePattern=yyyy-MM-dd
log4j.appender.file.File=${AppInfoSystem.root}/logs/log.log
log4j.appender.file.Append=true
log4j.appender.file.Threshold=debug
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern= - (%r ms) - %d{yyyy-M-d HH:mm:ss}%x[%5p](%F:%L) %m%n#DWR \u65e5\u5fd7
#log4j.logger.org.directwebremoting = ERROR#\u663e\u793aHibernate\u5360\u4f4d\u7b26\u7ed1\u5b9a\u503c\u53ca\u8fd4\u56de\u503c
#log4j.logger.org.hibernate.type=DEBUG,CONSOLE #log4j.logger.org.springframework.transaction=DEBUG
#log4j.logger.org.hibernate=DEBUG
#log4j.logger.org.acegisecurity=DEBUG
#log4j.logger.org.apache.myfaces=TRACE
#log4j.logger.org.quartz=DEBUG#log4j.logger.com.opensymphony=INFO  
#log4j.logger.org.apache.struts2=DEBUG  
log4j.logger.com.opensymphony.xwork2=debug

WeiXinController.java

package com.qhk.controller;import java.util.Map;
import java.util.Random;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;import com.qhk.util.CheckUtil;
import com.qhk.util.MessageFormat;
import com.qhk.util.MessageUtil;@Controller
@RequestMapping("/weixin")
public class WeiXinController {/*** <h4>功能:[微信验证 ][2018年2月9日 下午10:01:14][创建人: HongKun.Qin]</h4>* <h4></h4>* @param request* @param response* @return*/@ResponseBody@RequestMapping(value = "/message.do",method =RequestMethod.GET)public String getMessageValidate(HttpServletRequest request, HttpServletResponse response){String signature = request.getParameter("signature");//微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。String timestamp = request.getParameter("timestamp");//	时间戳String nonce = request.getParameter("nonce");//	随机数String echostr = request.getParameter("echostr");//	随机字符串if(CheckUtil.checkSignature(signature, timestamp, nonce)){return echostr;}return "";}/*** <h4>功能:[接受消息,并返回消息 ][2018年2月9日 下午10:02:00][创建人: HongKun.Qin]</h4>* <h4></h4>* @param request* @param response* @return* @throws Exception*/@ResponseBody@RequestMapping(value = "/message.do",method =RequestMethod.POST)public String getMessage(HttpServletRequest request, HttpServletResponse response) throws Exception{Map<String,String> map = new MessageFormat().xmlToMap(request);String fromUserName = map.get("FromUserName");//公众号String toUserName = map.get("ToUserName");//粉丝号String msgType = map.get("MsgType");//发送的消息类型[比如 文字,图片,语音。。。]String content = map.get("Content");//发送的消息内容String message = null;System.out.println("fromUserName:"+fromUserName+"   ToUserName:"+toUserName+"  MsgType:"+msgType+"  "+content);//判断发送的类型是文本if(MessageUtil.MESSAGE_TEXT.equals(msgType)){//发送的内容为???时if("0".equals(content)){message = MessageFormat.initText(toUserName, fromUserName, MessageUtil.menuText());}else if("1".equals(content)) {Random random = new Random();message = MessageFormat.initText(toUserName, fromUserName, String.format("您本次的验证码为:%s%s%s%s", random.nextInt(10),random.nextInt(10),random.nextInt(10),random.nextInt(10)));//模拟验证码}else{message  = MessageFormat.initText(toUserName, fromUserName, "功能正在完善中,请按提示信息操作[回复'0'显示主菜单]。");}}else if(MessageUtil.MESSAGE_EVENT.equals(msgType)){//验证是关注/取消事件String eventType = map.get("Event");//获取是关注还是取消//关注if(MessageUtil.MESSAGE_SUBSCRIBE.equals(eventType)){message = MessageFormat.initText(toUserName, fromUserName, "欢迎关注青鸟ktv,回复[0]即可调出功能菜单");}}return message;}}

AccessToken.java

package com.qhk.entity;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;}
}

BaseMessage.java

package com.qhk.entity;public class BaseMessage {private String ToUserName;private String FromUserName;private long CreateTime;private 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;}
}

TextMessage.java

package com.qhk.entity;public class TextMessage extends BaseMessage{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;}
}

CheckUtil.java(token注意,我现在是qhk后面微信公众号平台配置也要用这个,自己改了的话就填自己改的)

package com.qhk.util;import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;public class CheckUtil {public static final String token = "qhk";//这个地方也要注意public static boolean checkSignature(String signature,String timestamp,String nonce){String[] arr=new String[]{token,timestamp,nonce};//排序Arrays.sort(arr);//生成字符串StringBuffer content = new StringBuffer();for (int i = 0; i < arr.length; i++) {content.append(arr[i]);}//sha1加密String temp = getSha1(content.toString());return temp.equals(signature);}public static String getSha1(String str){if (null == str || 0 == str.length()){return null;}char[] hexDigits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};try {MessageDigest mdTemp = MessageDigest.getInstance("SHA1");mdTemp.update(str.getBytes("UTF-8"));byte[] md = mdTemp.digest();int j = md.length;char[] buf = new char[j * 2];int k = 0;for (int i = 0; i < j; i++) {byte byte0 = md[i];buf[k++] = hexDigits[byte0 >>> 4 & 0xf];buf[k++] = hexDigits[byte0 & 0xf];}return new String(buf);} catch (NoSuchAlgorithmException e) {e.printStackTrace();} catch (UnsupportedEncodingException e) {e.printStackTrace();}return null;}}

MessageFormat.java

package com.qhk.util;import java.io.IOException;
import java.io.InputStream;
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.qhk.entity.TextMessage;
import com.thoughtworks.xstream.XStream;/*** <p>将发送的消息进行转换</p>* @author HongKun.Qin*/
public class MessageFormat {/*** 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<String, String>();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;}/*** 将文本消息转换为xml* * @param textMessage* @return*/public static String textMessageToXml(TextMessage textMessage) {XStream xStream = new XStream();xStream.alias("xml", textMessage.getClass());return xStream.toXML(textMessage);}public static String initText(String toUserName, String fromUserName,String content) {TextMessage text = new TextMessage();text.setFromUserName(toUserName);text.setToUserName(fromUserName);text.setMsgType(MessageUtil.MESSAGE_TEXT);text.setCreateTime(new Date().getTime());text.setContent(content);return textMessageToXml(text);}
}

MessageUtil.java

package com.qhk.util;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_MUSIC = "music";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";public static final String MESSAGE_SCANCODE = "scancode_push";/*** <h4>功能:[显示的主菜单 ][2018年2月9日 下午9:37:56][创建人: HongKun.Qin]</h4>* <h4></h4>* @return*/public static String menuText() {StringBuffer sb = new StringBuffer();sb.append("欢迎您关注青鸟KTV,请按照菜单提示进行操作:\n\n");sb.append("[1].显示短信验证码\n");sb.append("[2].显示个人信息\n");sb.append("[3].关于青鸟KTV\n");sb.append("[4].关于注册成为会员\n\n");sb.append("回复 \"[0]\" 调出此菜单。");return sb.toString();}
}

WeixinUtil.java(APPID、APPSECRET)别忘改成自己的,不然项目也没法运行

package com.qhk.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 org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;import com.qhk.entity.AccessToken;import net.sf.json.JSONObject;public class WeixinUtil {private static final String APPID="";//在基础配置中可查看自己APPIDprivate static final String APPSECRET="";//在基础配置中可查看自己APPSECRETprivate 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";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 entity = response.getEntity();if(entity!=null){String result = EntityUtils.toString(entity,"UTF-8");jsonObject = JSONObject.fromObject(result);}} catch (ClientProtocolException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}System.out.println(jsonObject);return jsonObject;}/*** * @Description: TODO 获取AccessToken* @param @return   * @return AccessToken  * @throws* @author qinhongkun* @date 2017-12-18*/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;}/** 文件上传*/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;}}

2.大家现在就是关心ngrok下载地址:https://ngrok.com/download

还有人会问:哎哟我靠,什么是ngrok?

其实不用纠结这是个啥,如果你作为一个Java开发人员是第一次接触微信公众号后台开发,我建议你千万别纠结这到底是个

啥,简单明了的告诉你:微信公众号开发文档中 要求 有服务器 (自己的域名、也可以理解为自己的空间 当然 不是QQ空

间),然后呢,那你就想百度一下了,怎么拥有自己的域名或者说空间,有人推荐你使用百度BEA(好像是,不知道名字有

没有记错),然后微信公众号的技术文档里面推荐你用腾讯的什么什么,总之,收费。诶,对 就是收费。

所以呢,这个ngrok就是免费的。而且运行极其简单,对,不费劲哈。

这个下载之后,暂时放那,别动。

3.注册订阅号 去微信公众号平台注册一个个人的订阅号就行,登录进去,三个箭头分别点击一下将最下面红箭头标出的地方进

行关闭
这里写图片描述
关闭后
这里写图片描述
看图操作
这里写图片描述这里写图片描述这里写图片描述
此时 我们还需要配置下图

配置你的服务器地址 (这是问题1)

配置你的token (这是问题2)

配置你的EncodingAESkey (这不是问题!!)
这里写图片描述
问题1:

然后你肯定进入了死胡同,想说URL怎么填呢?

你还记得你的ngrok吗?

首先我们先在本地启动项目,(注意代码中需要修改的地方上面我已经写出来,填写自己的APPID和密码)必须是tomcat的8080

端口

这时候就要用到ngrok了

打开你的ngrok文件夹,在包涵ngrok.exe文件的文件夹中运行cmd,然后输入指令:

ngrok -config ngrok.cfg -subdomain qinhongkun 8080

qinhongkun可以随便改,自己填写服务器地址别写错了就行。
这里写图片描述

如果没有什么问题的话下面这张图就是启动成功的(别关掉这dos窗口)
这里写图片描述
转回来微信公众号,你的URL就填写ngrok运行后的生成的网址(我已经用红色标记出来了用哪一个都行有两个)/项目名称/控

制器名 比如我的就是 https://qinhongkun.tunnel.echomod.cn/weixintest/weixin/message.do

至于为什么我的项目名是weixintest而不是weixin-demo 那是我之前在eclipse中改了项目名,而tomcat中没有修改过来,

weixin/message.do这控制器方法上面有。

问题2:

token 就要填我们在项目中写的那个,上面我也重点标记了,如果项目中更改了的话,这别忘了修改!

问题3:直接点击随机生成一个就ok了

如果没有问题现在已经能保存了。

我将项目上传到码云,https://gitee.com/it_qin/weixintest.git。

注:因为当时用作项目中有很多功能,所以这是个完整的ssm框架,只不过我把那些都删了,只留下一个简单的微信Demo.

现在去你的公众号测试一下就行了,有什么问题或者建议欢迎评论,确保一天之内回复,不算星期天哦。


http://www.ppmy.cn/news/472284.html

相关文章

A Survey of Recommender Systems Based on Deep Learning (1)

A Survey of Recommender Systems Based on Deep Learning (本文为同名paper的个人翻译版本&#xff0c;如有认知上的偏差&#xff0c;请谅解) 原文地址&#xff1a;https://www.researchgate.net/publication/328843931_A_Survey_of_Recommender_Systems_Based_on_Deep_Learn…

yolov5模型训练

本文将介绍yolov5从环境搭建到模型训练的整个过程。最后训练识别哆啦A梦的模型。 1.anconda环境搭建 2.yolov5下载 3.素材整理 4.模型训练 5.效果预测 - Anconda环境搭建 提醒&#xff1a;所有操作都是在anconda的yolo的环境下进行的&#xff0c;在创建yolo环境后&#xff0…

快速上手Opencv--图片输入的形式(计算机眼中的世界)

快速上手Opencv--图片输入的形式&#xff08;计算机眼中的世界&#xff09; 声明&#xff0c;这是一篇针对非计算机专业的科普性介绍。 我们常常通过深度学习的方法&#xff0c;利用神经网络去处理图像的识别问题。我们常用的做法就是首先输入图像数据&#xff0c;然后经过一系…

教程:超详细从零开始yolov5模型训练

本文将介绍yolov5从环境搭建到模型训练的整个过程。最后训练识别哆啦A梦的模型。 1.anconda环境搭建 2.yolov5下载 3.素材整理 4.模型训练 5.效果预测 - Anconda环境搭建 提醒&#xff1a;所有操作都是在anconda的yolo的环境下进行的&#xff0c;在创建yolo环境后&#xff0…

Java中的Spring Boot 2.0简介笔记

我相信这世界&#xff0c;不是每个人都有机会做自己想做的事情&#xff0c;但是我们应该尽量去做那些正确的事情。 专注才能专业&#xff0c;专业才有价值&#xff0c;写够两万行代码&#xff0c;就是合格程序员。个人为人真诚&#xff0c;有很强的责任心&#xff0c;学习能力与…

微博表情 文本与图片对照表

微博表情地址:https://weibo.com/aj/mblog/face?type=face&_wv=5&ajwvr=6&__rnd=1558005188908 (20190516有效) $faces = array([马到成功] => //img.t.sinajs.cn/t4/appstyle/expression/ext/normal/b0/mdcg_org.gif,[带着微博去旅行] => //img.t.sinaj…

2行Python给图片加水印,太强了!

大家好&#xff0c;我是菜鸟哥&#xff01; 今天给大家分享一个非常实用的招数&#xff0c;对于某张图片&#xff0c;可能是你精心制作的思维导图&#xff0c;或者你精心设计的某个logo。你可能花费好多时间来弄&#xff0c;最后却被别人直接搬运过去使用&#xff0c;好气哦&am…

如何用Python和深度神经网络寻找近似图片?

给你10万张图片&#xff0c;让你找出与其中某张图片最为近似的10张&#xff0c;你会怎么做&#xff1f;不要轻言放弃&#xff0c;也不用一张张浏览。使用Python&#xff0c;你也可以轻松搞定这个任务。 识别相同或相似的图像&#xff0c;有什么好的方法么&#xff1f; 加vx&…