做了一个简单的微信公众号文章拉取功能,做个简单记录
Http请求工具类
package com.asiainfo.vehicle.modules.community.util;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
/**
*
* @Description: Http请求工具类
* @author [ Wenfeng.Huang ] on [2018年10月10日下午7:44:50]
* @Modified By: [修改人] on [修改日期] for [修改说明]
*
*/
public class HttpClientUtil {
private static Logger logger = LoggerFactory.getLogger(HttpClientUtil.class);
public static JSONObject doGet(String url) {
// 指定get请求
HttpGet httpGet = new HttpGet(url);
// 创建httpclient
@SuppressWarnings("resource")
HttpClient httpClient = new DefaultHttpClient();
// 发送请求
HttpResponse httpResponse;
//返回的json
JSONObject jsonObject = null;
try {
httpResponse = httpClient.execute(httpGet);
// 验证请求是否成功
if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
// 得到请求响应信息
String str = EntityUtils.toString(httpResponse.getEntity(),
"utf-8");
// 返回json
jsonObject = JSON.parseObject(str);
}
} catch (ClientProtocolException e) {
logger.error("HttpClientUtil =====get请求微信失败!");
} catch (Exception e) {
logger.error("HttpClientUtil =====get请求微信失败!");
}
return jsonObject;
}
public static JSONObject doPost(String url, JSONObject jsonData) {
// 指定Post请求
HttpPost httpPost = new HttpPost(url);
// 创建httpclient
@SuppressWarnings("resource")
HttpClient httpClient = new DefaultHttpClient();
// 发送请求
HttpResponse httpResponse;
// 返回的json
JSONObject jsonObject = null;
// 封装post请求数据
StringEntity entity = new StringEntity(jsonData.toString(), "utf-8");
httpPost.setEntity(entity);
try {
// 发送请求
httpResponse = httpClient.execute(httpPost);
// 判断请求是否成功
if(httpResponse.getStatusLine().getStatusCode()==HttpStatus.SC_OK){
// 得到请求响应信息
String str = EntityUtils.toString(httpResponse.getEntity(), "utf-8");
// 返回json
jsonObject = JSON.parseObject(str);
}
} catch (ClientProtocolException e) {
logger.error("HttpClientUtil =====post请求微信失败!");
} catch (Exception e) {
logger.error("HttpClientUtil =====post请求微信失败!");
}
return jsonObject;
}
}
请求微信接口工具类
package com.asiainfo.vehicle.modules.community.util;
import org.springframework.stereotype.Component;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
/**
*
* @Description: 请求微信接口工具类
*
* @author [ Wenfeng.Huang ] on [2018年10月10日下午7:46:05]
* @Modified By: [修改人] on [修改日期] for [修改说明]
*
*/
@Component
public class WeixinUtil {
private static final String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APP_ID&secret=APP_SECRET";
private static final String CRATE_QRCODE_URL = "https://api.weixin.qq.com/device/getqrcode?access_token=accessToken&product_id=productId";
private static final String COMPEL_BIND_URL = "https://api.weixin.qq.com/device/compel_bind?access_token=accessToken";
private static final String COMPEL_UNBIND_URL = "https://api.weixin.qq.com/device/compel_unbind?access_token=accessToken";
private static final String BIND_STATUS_URL = "https://api.weixin.qq.com/device/get_stat?access_token=accessToken&device_id=deviceId";
private static final String GETCALLBACKIP_URL = "https://api.weixin.qq.com/cgi-bin/getcallbackip?access_token=accessToken";
private static final String GETUSERINFO_URL = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=accessToken&openid=openId&lang=zh_CN";
private static final String GET_MATERIALCOUNT = "https://api.weixin.qq.com/cgi-bin/material/get_materialcount?access_token=accessToken";
private static final String GET_BATCHGET_MATERIAL = "https://api.weixin.qq.com/cgi-bin/material/batchget_material?access_token=accessToken";
/**
* 获取token
*
* @return
*/
public static String getAccessToken(String appId, String appSecret) {
String url = ACCESS_TOKEN_URL.replace("APP_ID", appId).replace("APP_SECRET", appSecret);
JSONObject result = HttpClientUtil.doGet(url);
return result.getString("access_token");
}
/**
* 验证token是否有效
*
* @param token
* @return
*
* {"errcode":40001,"errmsg":"invalid credential, access_token is
* invalid or not latest hint: [TCmz5a03344694!]"}
*/
public static boolean validateAccessToken(String token) {
String url = GETCALLBACKIP_URL.replace("accessToken", token);
JSONObject result = HttpClientUtil.doGet(url);
if (result.toJSONString().contains("ip_list") && !result.toJSONString().contains("errmsg")) {
return true;
} else {
return false;
}
}
/**
* 创建绑定二维码
*
* @param token
* @return
*/
public static JSONObject createQrcode(String token, String productId) {
String url = CRATE_QRCODE_URL.replace("accessToken", token).replace("productId", productId);
JSONObject result = HttpClientUtil.doGet(url);
return result;
}
/**
* 强制绑定用户和设备
*
* @param token
* @param deviceId
* @param openId
* @return {base_resp:{"errcode": 0,"errmsg":"ok"}} {base_resp:{"errcode":
* -1,"errmsg":"system error"}}
*/
public static JSONObject compelBind(String token, String deviceId, String openId) {
JSONObject jsonData = new JSONObject();
String url = COMPEL_BIND_URL.replace("accessToken", token);
jsonData.put("device_id", deviceId);
jsonData.put("openid", openId);
JSONObject json = HttpClientUtil.doPost(url, jsonData);
JSONObject result = JSON.parseObject(json.getString("base_resp"));
return result;
}
/**
* 强制解绑用户和设备
*
* @param token
* @param deviceId
* @param openId
* @return
*/
public static JSONObject compelUnbind(String token, String deviceId, String openId) {
JSONObject jsonData = new JSONObject();
String url = COMPEL_UNBIND_URL.replace("accessToken", token);
jsonData.put("device_id", deviceId);
jsonData.put("openid", openId);
JSONObject json = HttpClientUtil.doPost(url, jsonData);
JSONObject result = JSON.parseObject(json.getString("base_resp"));
return result;
}
/**
* 设备状态查询 status 0:未授权 1:已经授权(尚未被用户绑定) 2:已经被用户绑定 3:属性未设置
*
* @param token
* @param deviceId
* @return
*/
public static JSONObject getBingStatus(String token, String deviceId) {
String url = BIND_STATUS_URL.replace("accessToken", token).replace("deviceId", deviceId);
JSONObject result = HttpClientUtil.doGet(url);
return result;
}
/**
* 通过openId获取微信用户信息
* @param token
* @param openId
* @return
*/
public static JSONObject getUserInfo(String token, String openId) {
String url = GETUSERINFO_URL.replace("accessToken", token).replace("openId", openId);
JSONObject result = HttpClientUtil.doGet(url);
return result;
}
/**
* 获取公众号素材总数
* @param token
* @return
*/
public static Integer getMaterialCount(String token) {
String url = GET_MATERIALCOUNT.replace("accessToken", token);
JSONObject result = HttpClientUtil.doGet(url);
if(result.toJSONString().contains("errcode")) {
return null;
}
int count = result.getInteger("news_count");
return count;
}
/**
* 获取微信素材文章
* @param token
* @param pageIndex
* @param pageCount
* @return
*/
public static JSONObject getBatchgetMaterial(String token,int pageIndex, int pageCount) {
JSONObject jsonData = new JSONObject();
String url = GET_BATCHGET_MATERIAL.replace("accessToken", token);
jsonData.put("type", "news");
jsonData.put("offset", pageIndex);
jsonData.put("count", pageCount);
JSONObject result = HttpClientUtil.doPost(url, jsonData);
return result;
}
}
package com.asiainfo.vehicle.modules.community.web;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import javax.servlet.http.HttpServletRequest;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.asiainfo.common.IDataResult;
import com.asiainfo.vehicle.common.utils.CommonsService;
import com.asiainfo.vehicle.common.web.controller.BaseController;
import com.asiainfo.vehicle.modules.community.util.WeixinUtil;
import com.ibm.icu.text.SimpleDateFormat;
/**
*
* @Description: 微信公众号文章功能
*
* @author [ Wenfeng.Huang ] on [2019年2月20日下午4:07:13]
* @Modified By: [修改人] on [修改日期] for [修改说明]
*
*/
@Controller
public class ArticleManagementController extends BaseController {
private static final Logger LOGGER = LoggerFactory.getLogger(ArticleManagementController.class);
@Value("${appId}")
private String appId;
@Value("${appSecret}")
private String appSecret;
private static final String WEIXIN_REQUEST_TOKEN_KEY = "WEIXIN_REQUEST_ARTICLE_TOKEN_KEY";
private static final int WEIXIN_MATERIAL_PAGECOUNT = 15;
@Autowired
private RedisTemplate<String, String> redisTemplate;
@Autowired
private ArticleDao articleDao;
/**
* 下载素材文章
*
* @param request
* @return
* @throws IOException
*/
@GetMapping(value = "/community/article/downArticle")
@ResponseBody
public Map<String, Object> downArticle(HttpServletRequest request) throws IOException {
boolean flag = false;
String token = getWeixinToken();
// 公众号文章总数
Integer weixinArticleCount = WeixinUtil.getMaterialCount(token);
Map<String, Object> result = new HashMap<String, Object>();
if (weixinArticleCount == null) {
result.put("code", 100);
result.put("msg", "查询失败!");
return result;
}
if (weixinArticleCount == 0) {
result.put("code", 101);
result.put("msg", "没有更新的文章!");
return result;
}
Integer dbArticleCount = queryDbArticleCount();
if (dbArticleCount == null) {
result.put("code", 102);
result.put("msg", "查询数据库文章总数失败!");
return result;
}
if (weixinArticleCount <= dbArticleCount) {
result.put("code", 101);
result.put("msg", "没有最新的文章!");
return result;
}
/**
* 计算需要从微信公众号拉取多少次
*/
int pageNumber = getPageNumber((weixinArticleCount - dbArticleCount), WEIXIN_MATERIAL_PAGECOUNT);
for (int i = 0; i < pageNumber; i++) {
int offset = dbArticleCount + i * WEIXIN_MATERIAL_PAGECOUNT;
flag = downArticle(token, offset);
}
if (flag) {
result.put("code", 0);
result.put("msg", "下载成功!");
return result;
} else {
result.put("code", 100);
result.put("msg", "下载失败!");
return result;
}
}
/**
* 记录素材
*
* @param param
* @return
*/
public boolean recordArticleHeader(Map<String, Object> param) {
//recordArticleHeader,存入数据库
return true;
}
/**
* 记录文章
*
* @param param
* @return
*/
public boolean recordArticleTrailer(JSONArray jsonArticles, String pId, Date updateTime) {
Map<String, Object> params = new HashMap<String, Object>();
List<Map<String, Object>> paramList = new ArrayList<Map<String, Object>>();
for (int i = 0; i < jsonArticles.size(); i++) {
JSONObject article = (JSONObject) jsonArticles.get(i);
Map<String, Object> param = new HashMap<String, Object>();
String id = get18UUIDString();
param.put("ID", id);
param.put("PARENT_ID", pId);
param.put("AUTHOR", article.getString("author"));
param.put("DIGEST", article.getString("digest"));
param.put("TITLE", article.getString("title"));
param.put("URL", article.getString("url"));
param.put("CONTENT_SOURCE_URL", article.getString("content_source_url"));
param.put("SHOW_COVER_PIC", article.getInteger("show_cover_pic"));
param.put("THUMB_MEDIA_ID", article.getString("thumb_media_id"));
param.put("THUMB_URL", article.getString("thumb_url"));
param.put("UPDATE_TIME", updateTime);
param.put("FILE_NAME", "");
if(i == 0) {
param.put("IS_HEAD", 1);
}else {
param.put("IS_HEAD", 0);
}
paramList.add(param);
}
params.put("resultList", paramList);
//recordArticleTrailer,存入数据库
return true;
}
/**
* 处理更新素材文章逻辑
*
* @return
*/
public boolean downArticle(String token, int offset) {
JSONObject materialObject = WeixinUtil.getBatchgetMaterial(token, offset,
WEIXIN_MATERIAL_PAGECOUNT);
JSONArray jsonMaterials = materialObject.getJSONArray("item");
for (int i = 0; i < jsonMaterials.size(); i++) {
JSONObject material = (JSONObject) jsonMaterials.get(i);
Map<String, Object> param = new HashMap<String, Object>();
JSONObject content = (JSONObject) material.getJSONObject("content");
String id = get18UUIDString();
param.put("ID", id);
param.put("MEDIA_ID", material.getString("media_id"));
param.put("CREATE_TIME", new Date(content.getLong("create_time") * 1000L));
param.put("UPDATE_TIME", new Date(material.getLong("update_time") * 1000L));
param.put("IS_DISPLAY", 0);
boolean recordArticleHeaderFlag = recordArticleHeader(param);
if (!recordArticleHeaderFlag) {
return false;
}
JSONArray jsonArticles = content.getJSONArray("news_item");
Date updateTime = new Date(content.getLong("update_time") * 1000L);
boolean recordArticleTrailerFlag = recordArticleTrailer(jsonArticles, id, updateTime);
if (!recordArticleTrailerFlag) {
return false;
}
}
return true;
}
/**
* 查询数据库文章数量
*
* @param request
* @return
* @throws IOException
*/
public Integer queryDbArticleCount() throws IOException {
Map<String, Object> resultMap = articleDao.queryDbArticleCount();//查询数据里的文章总数
Object count = resultMap.get("ARTICLE_COUNT");
return Integer.valueOf(count.toString());
}
/**
* 计算查询页数
*
* @param total
* @param pageCount
* @return
*/
public static int getPageNumber(int total, int pageCount) {
if(total <= 0) {
return 0;
}
int pageNumber = total / pageCount;
if ((total % pageCount) == 0) {
return pageNumber;
}
return pageNumber + 1;
}
/**
* 获取微信token
*
* @return
*/
public String getWeixinToken() {
ValueOperations<String, String> opsForValue = redisTemplate.opsForValue();
String token = opsForValue.get(WEIXIN_REQUEST_TOKEN_KEY);
if (!"".equals(token) && token != null) {
boolean flag = WeixinUtil.validateAccessToken(token);
if (!flag) {
String accessToken = WeixinUtil.getAccessToken(appId, appSecret);
opsForValue.set(WEIXIN_REQUEST_TOKEN_KEY, accessToken);
}
} else {
String accessToken = WeixinUtil.getAccessToken(appId, appSecret);
opsForValue.set(WEIXIN_REQUEST_TOKEN_KEY, accessToken);
}
return opsForValue.get(WEIXIN_REQUEST_TOKEN_KEY);
}
/**
* 生成主键
*
* @return
* @throws Exception
*/
public String get18UUIDString() {
Date date = new Date();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
String dateStr = dateFormat.format(date);
StringBuffer result = new StringBuffer(dateStr);
Random random = new Random();
String num_4 = "";
int randomNum;
do {
randomNum = Math.abs(random.nextInt()) % 10 + 48;
char randomChar = (char) randomNum;
String randomStr = Character.toString(randomChar);
num_4 += randomStr;
} while (num_4.length() < 4);
result.append(num_4);
return result.toString();
}
}
附:
将微信公众号文章拉取下来之后,如果要在HTML上显示文章内容,会发现微信的图片会加载不出来。
解决办法:
在HTML页面加上 <meta name="referrer" content="never">