|
|
package com.yoho.unions.server.mqconsumer;
|
|
|
|
|
|
import com.alibaba.fastjson.JSON;
|
|
|
import com.alibaba.fastjson.JSONArray;
|
|
|
import com.alibaba.fastjson.JSONObject;
|
|
|
import com.yoho.core.common.utils.MD5;
|
|
|
import com.yoho.unions.dal.IArticleBlockDao;
|
|
|
import com.yoho.unions.dal.IArticleDAO;
|
|
|
import com.yoho.unions.dal.model.Article;
|
|
|
import com.yoho.unions.dal.model.ArticleBlock;
|
|
|
import com.yoho.unions.message.CommonMessageConsumer;
|
|
|
import com.yoho.unions.utils.HttpUtils;
|
|
|
import org.apache.commons.collections.CollectionUtils;
|
|
|
import org.apache.commons.lang.StringUtils;
|
|
|
import org.apache.commons.lang3.tuple.ImmutablePair;
|
|
|
import org.apache.commons.lang3.tuple.Pair;
|
|
|
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.stereotype.Component;
|
|
|
|
|
|
import java.io.UnsupportedEncodingException;
|
|
|
import java.util.*;
|
|
|
|
|
|
/**
|
|
|
* Created by lenovo on 2017/6/15.
|
|
|
*/
|
|
|
@Component
|
|
|
public class ArticlePushConsumer implements CommonMessageConsumer {
|
|
|
|
|
|
private Logger logger = LoggerFactory.getLogger(ArticlePushConsumer.class);
|
|
|
|
|
|
private final static String ARTICLE_PUSH_TOPIC = "guang.article_push";
|
|
|
|
|
|
private final static String ARTICLE_BASE_URL = "guang.m.yohobuy.com/guang/info/";
|
|
|
|
|
|
//可推送的文章一级分类id
|
|
|
private final static Integer[] PUSH_ARTICLE_SORT_ID = {1,2,3,4,22};
|
|
|
|
|
|
@Value("${baidu.tp.push.url}")
|
|
|
private String baiduTPPushUrl;
|
|
|
|
|
|
@Value("${baidu.app.id}")
|
|
|
private String appId;
|
|
|
|
|
|
@Value("${baidu.app.token}")
|
|
|
private String token;
|
|
|
|
|
|
@Autowired
|
|
|
private IArticleDAO articleDAO;
|
|
|
|
|
|
@Autowired
|
|
|
private IArticleBlockDao articleBlockDao;
|
|
|
|
|
|
@Override
|
|
|
public String getMessageTopic() {
|
|
|
return ARTICLE_PUSH_TOPIC;
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public void handleMessage(Object message) {
|
|
|
logger.info("article push message {}", message);
|
|
|
try {
|
|
|
if (null == message) {
|
|
|
return;
|
|
|
}
|
|
|
JSONObject jsonObj = JSON.parseObject((String) message);
|
|
|
Integer articleId = jsonObj.getInteger("articleId");
|
|
|
if(articleId == null || articleId < 1){
|
|
|
return;
|
|
|
}
|
|
|
Article article = articleDAO.selectByPrimaryKey(articleId);
|
|
|
//(1) 检查文章是否满足要求
|
|
|
if(!checkArticle(article)){
|
|
|
return;
|
|
|
}
|
|
|
List<ArticleBlock> articleBlockList = articleBlockDao.selectListByArticleId(articleId);
|
|
|
//(2) 检查文章内容是否满足要求
|
|
|
if(!checkArticleBlock(articleId, articleBlockList)){
|
|
|
return;
|
|
|
}
|
|
|
//(3) 获取文章内容和挂接商品
|
|
|
Pair<StringBuilder,JSONArray> content = getArticleContent(articleBlockList);
|
|
|
//(4) 组装推送参数
|
|
|
Map<String, Object> pushParam = getArticlePushParam(article, content);
|
|
|
//(5) 推送文章到百度TP
|
|
|
String response = HttpUtils.httpPost(baiduTPPushUrl, pushParam).getRight();
|
|
|
JSONObject rspMessage = JSONObject.parseObject(response);
|
|
|
if(0 == rspMessage.getInteger("errno")){
|
|
|
JSONObject data = rspMessage.getJSONObject("data");
|
|
|
logger.info("push article to baidu success, articleId is {}, feed_id is {}", articleId, data.getString("id"));
|
|
|
}else{
|
|
|
logger.warn("push article to baidu failed, articleId is {}, return message is {}", articleId, rspMessage.toJSONString());
|
|
|
}
|
|
|
} catch (Exception e) {
|
|
|
logger.warn("ArticlePushConsumer.handleMessage fail: message is {}, error is {}", message, e);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
private Pair<StringBuilder,JSONArray> getArticleContent(List<ArticleBlock> articleBlockList){
|
|
|
StringBuilder contentBuilder = new StringBuilder("<div class=\"p-text\" style=\"margin: 0px;\">");
|
|
|
JSONArray goodsInfoArr = new JSONArray();
|
|
|
Pair<StringBuilder, JSONArray> res = new ImmutablePair<>(contentBuilder, goodsInfoArr);
|
|
|
if(CollectionUtils.isEmpty(articleBlockList)){
|
|
|
return res;
|
|
|
}
|
|
|
|
|
|
int goodsIndex = 0;
|
|
|
for(ArticleBlock articleBlock : articleBlockList){
|
|
|
String templeteKey = articleBlock.getTemplateKey();
|
|
|
String contentData = articleBlock.getContentData();
|
|
|
JSONObject contentObj = JSONObject.parseObject(contentData);
|
|
|
JSONObject data = contentObj.getJSONObject("data");
|
|
|
if("text".equals(templeteKey)){
|
|
|
String text = data.getString("text");
|
|
|
contentBuilder.append(text);
|
|
|
contentBuilder.append("<br/>");
|
|
|
}else if("singleImage".equals(templeteKey)){
|
|
|
JSONObject imageObj = data.getJSONObject("0");
|
|
|
String imageSrc = imageObj.getString("src");
|
|
|
int index = imageSrc.indexOf("?");
|
|
|
imageSrc = index > 0 ? imageSrc.substring(0, index) : imageSrc;
|
|
|
//百度暂不支持gif图片
|
|
|
if(imageSrc.endsWith(".gif")){
|
|
|
continue;
|
|
|
}
|
|
|
contentBuilder.append("<img src= \"");
|
|
|
contentBuilder.append(imageSrc);
|
|
|
contentBuilder.append("\"/>");
|
|
|
}else if("goods".equals(templeteKey)){
|
|
|
JSONArray dataArray = phpArrayToJSONArray(data);
|
|
|
if(dataArray.size() == 0){
|
|
|
continue;
|
|
|
}
|
|
|
for(int i = 0; i < dataArray.size(); i++){
|
|
|
//图文最多支持5个商品
|
|
|
if(goodsInfoArr.size() > 4){
|
|
|
continue;
|
|
|
}
|
|
|
JSONObject element = dataArray.getJSONObject(i);
|
|
|
if(null == element || null == element.getInteger("id") || "Y".equals(element.getString("is_global"))){
|
|
|
continue;
|
|
|
}
|
|
|
contentBuilder.append("<iframe class=\"spd-faked-goods\" data-pos=\"").append(goodsIndex++).append("\"></iframe>");
|
|
|
JSONObject goodInfo = new JSONObject();
|
|
|
goodInfo.put("sku_id", element.getInteger("id"));
|
|
|
goodInfo.put("tpl_id", "BdrainrwSpdGoodsHasPic");
|
|
|
goodsInfoArr.add(goodInfo);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
contentBuilder.append("</div>");
|
|
|
return res;
|
|
|
}
|
|
|
|
|
|
private Map<String, Object> getArticlePushParam(Article article, Pair<StringBuilder,JSONArray> content){
|
|
|
SortedMap<String, Object> paramMap = new TreeMap<>();
|
|
|
JSONArray coverImageArr = new JSONArray();
|
|
|
String articleUrl = ARTICLE_BASE_URL + article.getId() + ".html";
|
|
|
String coverImage = article.getCoverImage();
|
|
|
int index = coverImage.indexOf("?");
|
|
|
coverImage = index > 0 ? coverImage.substring(0, index) : coverImage;
|
|
|
coverImageArr.add(coverImage);
|
|
|
paramMap.put("app_id", appId);
|
|
|
paramMap.put("tp_src", "yoho");
|
|
|
paramMap.put("v", "1.0");
|
|
|
paramMap.put("domain", "12");
|
|
|
paramMap.put("origin_url", articleUrl);
|
|
|
paramMap.put("title", article.getArticleTitle());
|
|
|
paramMap.put("abstract", article.getArticleSummary());
|
|
|
paramMap.put("content", content.getLeft().toString());
|
|
|
paramMap.put("cover_layout", "one");
|
|
|
paramMap.put("cover_images", coverImageArr);
|
|
|
paramMap.put("publish_time", article.getPublishTime() == null ? "0": String.valueOf(article.getPublishTime()));
|
|
|
paramMap.put("publish_type", "immediate");
|
|
|
paramMap.put("source_type", "creation");
|
|
|
paramMap.put("service_type", content.getRight().size() > 0 ? 1 : 0);
|
|
|
paramMap.put("goods_info", content.getRight());
|
|
|
List<String> array = new LinkedList<>();
|
|
|
for(Map.Entry<String, Object> entry : paramMap.entrySet()){
|
|
|
if(entry.getValue() == null){
|
|
|
continue;
|
|
|
}
|
|
|
array.add(String.valueOf(entry.getValue()));
|
|
|
}
|
|
|
String signStr = String.join("", array);
|
|
|
String sign = MD5.md5(signStr + token);
|
|
|
paramMap.put("sign", sign);
|
|
|
|
|
|
return paramMap;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 检查文章是否满足推送要求
|
|
|
* @param article
|
|
|
* @return Boolean
|
|
|
*/
|
|
|
private Boolean checkArticle(Article article){
|
|
|
//(1) 文章标题, 摘要不能为空
|
|
|
if(article == null || StringUtils.isEmpty(article.getArticleTitle()) || StringUtils.isEmpty(article.getArticleSummary())){
|
|
|
return false;
|
|
|
}
|
|
|
int maxSortId = article.getMaxSortId();
|
|
|
String title = article.getArticleTitle();
|
|
|
String coverImage = article.getCoverImage();
|
|
|
int index = coverImage.indexOf("?");
|
|
|
coverImage = index > 0 ? coverImage.substring(0, index) : coverImage;
|
|
|
List<Integer> sortIdList = Arrays.asList(PUSH_ARTICLE_SORT_ID);
|
|
|
//(2) 只推送指定文章分类
|
|
|
if(!sortIdList.contains(maxSortId)){
|
|
|
logger.info("checkArticle: article sort id {} not support", maxSortId);
|
|
|
return false;
|
|
|
}
|
|
|
//(3) 封面图是gif格式的不支持
|
|
|
if(coverImage.endsWith(".gif")){
|
|
|
return false;
|
|
|
}
|
|
|
//(4) 文章标题必须大于16个字节,小于80个字节
|
|
|
try {
|
|
|
int len = title.getBytes("GBK").length;
|
|
|
if(len < 16 || len > 80){
|
|
|
logger.info("checkArticle: article title not support, article id {}, title is {}", article.getId(), title);
|
|
|
return false;
|
|
|
}
|
|
|
} catch (UnsupportedEncodingException e) {
|
|
|
logger.warn("checkArticle: get title bytes failed: article id is {}, error is {}", article.getId(), e);
|
|
|
}
|
|
|
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 检查文章内容是否满足推送要求
|
|
|
* @param articleBlockList
|
|
|
* @return Boolean
|
|
|
*/
|
|
|
private Boolean checkArticleBlock(Integer articleId, List<ArticleBlock> articleBlockList){
|
|
|
if(CollectionUtils.isEmpty(articleBlockList)){
|
|
|
return false;
|
|
|
}
|
|
|
List<String> templeteKeyList = new ArrayList<>();
|
|
|
int contentLen = 0;
|
|
|
for(ArticleBlock articleBlock : articleBlockList){
|
|
|
if(articleBlock == null || articleBlock.getTemplateKey() == null){
|
|
|
continue;
|
|
|
}
|
|
|
String templeteKey = articleBlock.getTemplateKey();
|
|
|
if("text".equals(templeteKey)){
|
|
|
try {
|
|
|
String contentData = articleBlock.getContentData();
|
|
|
JSONObject contentObj = JSONObject.parseObject(contentData);
|
|
|
JSONObject data = contentObj.getJSONObject("data");
|
|
|
String text = data.getString("text");
|
|
|
contentLen += text.getBytes("GBK").length;
|
|
|
} catch (UnsupportedEncodingException e) {
|
|
|
logger.warn("checkArticleBlock: get text bytes failed: articleBlock id is {}, error is {}", articleBlock.getId(), e);
|
|
|
}
|
|
|
}else if("singleImage".equals(templeteKey)){
|
|
|
//一张图片算100字节
|
|
|
contentLen += 100;
|
|
|
}
|
|
|
templeteKeyList.add(articleBlock.getTemplateKey());
|
|
|
}
|
|
|
//推送文章必须包含文字
|
|
|
if(!templeteKeyList.contains("text")){
|
|
|
return false;
|
|
|
}
|
|
|
//文章内容必须大于400个字节,小于40000个字节
|
|
|
if(contentLen < 400 || contentLen > 40000){
|
|
|
logger.info("checkArticleBlock: article block not support, articleId is {}", articleId);
|
|
|
return false;
|
|
|
}
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* php数组转成json数组
|
|
|
* @param dataObject
|
|
|
* @return JSONArray
|
|
|
*/
|
|
|
private JSONArray phpArrayToJSONArray(JSONObject dataObject) {
|
|
|
JSONArray dataToArray = new JSONArray();
|
|
|
if (dataObject == null || dataObject.isEmpty()) {
|
|
|
return new JSONArray();
|
|
|
}
|
|
|
for (int i = 0; i < dataObject.size(); i++) {
|
|
|
JSONObject object = dataObject.getJSONObject("" + i);
|
|
|
dataToArray.add(object);
|
|
|
}
|
|
|
return dataToArray;
|
|
|
}
|
|
|
} |
...
|
...
|
|