前言
使用java实现公众号消息模板推送,都是经过成功测试了的。
推荐:个人比较推荐实现方式一,因为简单简洁就把hutool用起来就行了,而且一般现在项目都有引入这个工具的;方式二的话相对来讲比较原始一点,代码量又多。
解决:如下使用不会出现44002/47001等错误码直接返回ok。
效果图
准备模板
微信公众号平台官网:https://mp.weixin.qq.com/cgi-bin/loginpage
点击模板的详情可以参考对应字段填充
java实现
下面的实现方法通用相关的代码
通用-依赖
<!-- 阿里巴巴json依赖包-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.1.41</version>
</dependency>
通用-代码
/**
* 给返回消息模板文字上色(但是:2023-05-04 取消了自定义文字颜色)
* @param value
* @return
*/
public JSONObject getJson(String value) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("value", value);
jsonObject.put("color", "#173177");
return jsonObject;
}
实现一(推荐)
使用hutool工具请求调用
<!-- hutool工具 -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.7</version>
</dependency>
引用
import cn.hutool.http.HttpRequest;
import com.alibaba.fastjson.JSONObject;
实现
public void sendMsg() {
JSONObject obj = new JSONObject();
obj.put("touser", ""); // 用户微信openId
obj.put("template_id", ""); // 消息模板ID
obj.put("url", ""); // 点击详情跳转的路径
JSONObject data = new JSONObject();
data.put("first", new JSONObject()); // {{first.DATA}} 如:您有一条通知(但是:2023-05-04 取消了这一行显示)
data.put("keyword1", getJson("张三")); // {{keyword1.DATA}} 1~5都是对应模板上面的
data.put("keyword2", new JSONObject()); // ....
data.put("keyword3", new JSONObject());
data.put("keyword4", new JSONObject());
data.put("keyword5", new JSONObject());
data.put("remark", new JSONObject());// {{remark.DATA}} 如:备注(但是:2023-05-04 取消了这一行显示)
obj.put("data", data);
String tk= ""; // 参考官网微信公众号token获取:https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Get_access_token.html
// 如token获取路径(get请求两个参数):https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+appid+"&secret="+secret
// 这两个参数appId和secret在:公众号平台->设置与开发->基本配置 中可以看到
String url = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" + tk;
String result = HttpRequest.post(url).body(obj.toString(), "application/json;charset=UTF-8").timeout(100000).execute().body();
JSONObject resultObject = JSONObject.parseObject(result);
Integer code = resultObject.getInteger("errcode");
int errcode = code == null ? -1 : code;
if (errcode == 0) {// 消息发送成功,看是否记录推送记录
System.out.println("推送成功");
} else{
System.out.println("推送失败");
}
}
方式二(不推荐)
使用apache.http.client依赖
<!-- httpclient依赖 -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<!-- httpclient缓存 -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient-cache</artifactId>
</dependency>
引用
import com.alibaba.fastjson.JSONObject;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
实现
public void sendMsg() {
JSONObject obj = new JSONObject();
obj.put("touser", ""); // 用户微信openId
obj.put("template_id", ""); // 消息模板ID
obj.put("url", ""); // 点击详情跳转的路径
JSONObject data = new JSONObject();
data.put("first", new JSONObject()); // {{first.DATA}} 如:您有一条通知(但是:2023-05-04 取消了这一行显示)
data.put("keyword1", getJson("张三")); // {{keyword1.DATA}} 1~5都是对应模板上面的
data.put("keyword2", new JSONObject()); // ....
data.put("keyword3", new JSONObject());
data.put("keyword4", new JSONObject());
data.put("keyword5", new JSONObject());
data.put("remark", new JSONObject());// {{remark.DATA}} 如:备注(但是:2023-05-04 取消了这一行显示)
obj.put("data", data);
String tk= ""; // 参考官网微信公众号token获取:https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Get_access_token.html
// 如token获取路径(get请求两个参数):https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+appid+"&secret="+secret
// 这两个参数appId和secret在:公众号平台->设置与开发->基本配置 中可以看到
HttpPost httpost = new HttpPost("https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" + tk);
MyHttpUtil http = new MyHttpUtil();
StringEntity entity = new StringEntity(obj.toString(), "UTF-8");
httpost.setEntity(entity);
String result = http.postHttp(httpost);// 返回的结果
JSONObject resultObject = JSONObject.parseObject(result);
Integer code = resultObject.getInteger("errcode");
int errcode = code == null ? -1 : code;
if (errcode == 0) {// 消息发送成功,看是否记录推送记录
System.out.println("推送成功");
} else{
System.out.println("推送失败");
}
}
其中 MyHttpUtil 是自己封装的,如下
package com.common.util;
import org.apache.http.*;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.CoreConnectionPNames;
import org.apache.http.util.EntityUtils;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.Date;
@SuppressWarnings("deprecation")
public class MyHttpUtil {
private DefaultHttpClient httpclient = new DefaultHttpClient(new ThreadSafeClientConnManager());
private HttpResponse response;
public MyHttpUtil() {
super();
httpclient.setHttpRequestRetryHandler(new DefaultHttpRequestRetryHandler(0, false));
}
/**
* 发送get请求,返回界面代码
*
* @param url
* @return
*/
public String getHttp(String url) {
HttpGet get = new HttpGet(url);
String result = "";
try {
response = httpclient.execute(get);
httpclient.getParams().setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 5000);
httpclient.getParams().setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 5000);
int statusCode = response.getStatusLine().getStatusCode();//
if (statusCode == HttpStatus.SC_OK) {
result = EntityUtils.toString(response.getEntity());
} else {
result = "返回码:" + statusCode;
}
} catch (ClientProtocolException e) {
e.printStackTrace();
get.abort();
} catch (IOException e) {
e.printStackTrace();
get.abort();
} finally {
get.abort();
}
return result;
}
/**
* 发送get请求,返回界面代码
*
* @return
*/
public String postHttp(HttpPost httpost) {
String result = "";
try {
httpclient.getParams().setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 5000);
httpclient.getParams().setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 5000);
response = httpclient.execute(httpost);
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == HttpStatus.SC_OK) {
result = EntityUtils.toString(response.getEntity());
} else {
result = "返回码:" + statusCode;
}
} catch (ClientProtocolException e) {
e.printStackTrace();
httpost.abort();
} catch (IOException e) {
e.printStackTrace();
httpost.abort();
} finally {
httpost.abort();
}
return result;
}
/**
* 设置浏览器的状态(必须带上)
*/
public HttpPost setPostHeader(HttpPost httpost, String Referer) {
// 必须模拟浏览器的配置,不然登录无效
httpost.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; rv:48.0) Gecko/20100101 Firefox/48.0");
httpost.setHeader("Origin", "http://www.baidu.com");
httpost.setHeader("Cache-Control", "max-age=0");
httpost.setHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
httpost.setHeader("Accept-Encoding", "gzip,deflate");
httpost.setHeader("Accept-Language", "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3");
httpost.setHeader("Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.3");
httpost.setHeader("Referer", "www.baidu.com");
httpost.setHeader("Host", "www.baidu.com");
return httpost;
}
/**
* 发送get请求, 下载文件存储
*
* @param url
* @return
*/
public String downFile(String url, String filePath, String fileName) {
HttpGet get = new HttpGet(url);
String result = "";
try {
response = httpclient.execute(get);
httpclient.getParams().setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 5000);
httpclient.getParams().setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 5000);
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == HttpStatus.SC_OK) {
HttpEntity entity = response.getEntity();
InputStream is = entity.getContent();
if (fileName.equals("")) {
fileName = new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date()) + getFileName(response);
}
saveToFile(filePath + "/" + fileName, is);
if (entity != null) {
entity.consumeContent();
}
if (new File(filePath + "/" + fileName).exists()) {
result = fileName;
}
}
} catch (ClientProtocolException e) {
e.printStackTrace();
get.abort();
} catch (IOException e) {
e.printStackTrace();
get.abort();
} finally {
get.abort();
}
return result;
}
public static boolean saveToFile(String fileDir, InputStream input) {
File file = new File(fileDir);
FileOutputStream output;
try {
output = new FileOutputStream(file);
byte b[] = new byte[1024];
int j = 0;
while ((j = input.read(b)) != -1) {
output.write(b, 0, j);
}
output.flush();
output.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
return false;
} catch (IOException e) {
e.printStackTrace();
return false;
} finally {
try {
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return true;
}
/**
* 5. 获取response header中Content-Disposition中的filename值
*
* @param response 响应
* @return String
* @desc :
*/
public static String getFileName(HttpResponse response) {
Header contentHeader = response.getFirstHeader("Content-Disposition");
String filename = null;
if (contentHeader != null) {
HeaderElement[] values = contentHeader.getElements();
if (values.length == 1) {
NameValuePair param = values[0].getParameterByName("filename");
if (param != null) {
try {
// filename = new String(param.getValue().toString().getBytes(), "utf-8");
// filename = URLDecoder.decode(param.getValue(), "utf-8");
String fname = param.getValue();
filename = fname.substring(fname.lastIndexOf("."), fname.length());
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
return filename;
}
}
以上就是微信公众号消息推送的实现了!