java開發微信公眾號接受並回復訊息[工程程式碼 圖片全解]

java開發微信公眾號接受並回復訊息[工程程式碼 圖片全解]

寫這篇部落格時猶豫了好久,因為步驟太多了,上班了也沒時間,但是我依然記得當時實現公眾號自動回覆時的場景,找個案例好

難,也沒有一個完整的案例,想了想還是寫出來吧,希望能讓實現這功能的人少走彎路。

微信公眾號平臺也有自定義回覆訊息,比如我在公眾號裡傳送關注你,我們在微信公眾號平臺設定關鍵字關注你(就是

有人傳送這個關鍵字就要回復什麼內容)設定成回覆:你好,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/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://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_FILE
log4j.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="";//在基礎配置中可檢視自己APPID
private static final String APPSECRET="";//在基礎配置中可檢視自己APPSECRET
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";
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.

現在去你的公眾號測試一下就行了,有什麼問題或者建議歡迎評論,確保一天之內回覆,不算星期天哦。