/* ==================================================================
* Created [2009-4-27 下午11:32:55] by Jon.King
* ==================================================================
* TSS
* ==================================================================
* mailTo:jinpujun@hotmail.com
* Copyright (c) Jon.King, 2009-2012
* ==================================================================
*/
package com.jinhe.tss.cms.service.impl;
import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.log4j.Logger;
import org.apache.lucene.search.Hit;
import org.apache.lucene.search.Hits;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.SortField;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.springframework.beans.factory.annotation.Autowired;
import com.jinhe.tss.cms.AttachmentDTO;
import com.jinhe.tss.cms.CMSConstants;
import com.jinhe.tss.cms.dao.IArticleDao;
import com.jinhe.tss.cms.dao.IChannelDao;
import com.jinhe.tss.cms.entity.Article;
import com.jinhe.tss.cms.entity.ArticleType;
import com.jinhe.tss.cms.entity.Attachment;
import com.jinhe.tss.cms.entity.AttachmentId;
import com.jinhe.tss.cms.entity.Channel;
import com.jinhe.tss.cms.entity.ChannelArticle;
import com.jinhe.tss.cms.entity.ChannelArticleId;
import com.jinhe.tss.cms.entity.TimerStrategy;
import com.jinhe.tss.cms.helper.ArticleHelper;
import com.jinhe.tss.cms.helper.ArticleQueryCondition;
import com.jinhe.tss.cms.helper.HitRateManager;
import com.jinhe.tss.cms.lucene.executor.IndexExecutorFactory;
import com.jinhe.tss.cms.service.IRemoteArticleService;
import com.jinhe.tss.component.support.persistence.pagequery.PageInfo;
import com.jinhe.tss.core.exception.BusinessException;
import com.jinhe.tss.core.sso.Environment;
import com.jinhe.tss.core.util.BeanUtil;
import com.jinhe.tss.core.util.DateUtil;
import com.jinhe.tss.core.util.EasyUtils;
import com.jinhe.tss.core.util.FileHelper;
import com.jinhe.tss.core.util.MacrocodeCompiler;
import com.jinhe.tss.core.util.XMLDocUtil;
import com.jinhe.tss.core.util.XmlUtil;
import com.jinhe.tss.core.web.dispaly.tree.LevelTreeParser;
import com.jinhe.tss.core.web.dispaly.tree.TreeEncoder;
public class RemoteArticleService implements IRemoteArticleService {
protected Logger log = Logger.getLogger(this.getClass());
@Autowired protected IArticleDao articleDao;
@Autowired protected IChannelDao channelDao;
public String getArticleListByChannel4Rss(Long channelId, Integer page, Integer pageSize) {
Channel channel = channelDao.getEntity(channelId);
if(channel == null) {
throw new BusinessException("ID为:" + channelId + " 的栏目不存在!");
}
if( !channelDao.checkBrowsePermission(channelId) ) {
log.error("用户【" + Environment.getOperatorName() + "】试图访问没有文章浏览权限的栏目【" + channelId + "】");
channelId = channelId * -1; // 置反channelId值,使查询不到结果
}
ArticleQueryCondition condition = new ArticleQueryCondition();
condition.setChannelId(channelId);
condition.getPage().setPageNum(page);
condition.getPage().setPageSize(pageSize);
condition.setStatus(CMSConstants.XML_STATUS);
PageInfo pageInfo = articleDao.getChannelPageArticleList(condition);
Document doc = org.dom4j.DocumentHelper.createDocument();
Element rssElement = doc.addElement("rss").addAttribute("version", "2.0");
Element channelElement = rssElement.addElement("channel");
channelElement.addElement("title").setText(channel.getName());
channelElement.addElement("link").setText("http://192.168.0.31:9081/index.portal");
channelElement.addElement("description").setText(channel.getName() + "栏目文章列表");
channelElement.addElement("language").setText("zh");
channelElement.addElement("copyright").setText("Copyright (c) JinHe S&T Co.ltd ZJ, 2012-2020 ");
List<?> articleList = pageInfo.getItems();
if (articleList != null) {
for (int i = 0; i < articleList.size(); i++) {
Object[] fields = (Object[]) articleList.get(i);
Long articleId = (Long) fields[0];
Element itemElement = channelElement.addElement("item");
itemElement.addElement("id").setText(articleId == null ? "" : articleId.toString());
itemElement.addElement("title").setText(fields[2] == null ? "" : fields[2].toString());
itemElement.addElement("pubDate").setText(fields[5] == null ? "" : DateUtil.format((Date) fields[5]));
itemElement.addElement("link").setText("http://localhost:8088/article.portal?isRobot=true&articleId=" + articleId);
}
}
doc.setXMLEncoding("GBK");
return doc.asXML();
}
public String getArticleListXMLByChannel(Long channelId, Integer page, Integer pageSize) {
String rssXML = getArticleListByChannel(channelId, page, pageSize, false);
return "<Response><ArticleList>" + rssXML + "</ArticleList></Response>";
}
public String getPicArticleListByChannel(Long channelId, Integer page, Integer pageSize) {
String rssXML = getArticleListByChannel(channelId, page, pageSize, true);
return "<Response><ArticleList>" + rssXML + "</ArticleList></Response>";
}
private String getArticleListByChannel(Long channelId, Integer page, Integer pageSize, boolean isNeedPic) {
Channel channel = channelDao.getEntity(channelId);
if(channel == null) {
throw new BusinessException("ID为:" + channelId + " 的栏目不存在!");
}
if( !channelDao.checkBrowsePermission(channelId) ) {
log.error("用户【" + Environment.getOperatorName() + "】试图访问没有文章浏览权限的栏目【" + channelId + "】");
channelId = channelId * -1; // 置反channelId值,使查询不到结果
}
ArticleQueryCondition condition = new ArticleQueryCondition();
condition.setChannelId(channelId);
condition.getPage().setPageNum(page);
condition.getPage().setPageSize(pageSize);
condition.setStatus(CMSConstants.XML_STATUS);
PageInfo pageInfo = articleDao.getChannelPageArticleList(condition);
Document doc = org.dom4j.DocumentHelper.createDocument();
Element channelElement = doc.addElement("rss").addAttribute("version", "2.0");
channelElement.addElement("channelName").setText(channel.getName());
channelElement.addElement("totalPageNum").setText(String.valueOf(pageInfo.getTotalPages()));
channelElement.addElement("totalRows").setText(String.valueOf(pageInfo.getTotalRows()));
channelElement.addElement("currentPage").setText(page.toString());
List<?> articleList = pageInfo.getItems();
if (articleList != null) {
for (int i = 0; i < articleList.size(); i++) {
Object[] fields = (Object[]) articleList.get(i);
Long articleId = (Long) fields[0];
Element itemElement = createArticleElement(channelElement, articleId, (String) fields[2], (String) fields[3],
(Date) fields[5], (Date) fields[6], (String) fields[4], (Integer) fields[8]);
if(isNeedPic){
Map<String, Attachment> attachments = articleDao.getArticleAttachments(articleId);
ArticleHelper.addPicListInfo(itemElement, attachments.values());
}
}
}
return channelElement.asXML();
}
public String queryArticlesByChannelIds(String channelIdStr, Integer page, Integer pageSize){
ArticleQueryCondition condition = new ArticleQueryCondition();
condition.getPage().setPageNum(page);
condition.getPage().setPageSize(pageSize);
condition.setStatus(CMSConstants.XML_STATUS);
List<Long> channelIds = new ArrayList<Long>();
String[] strIdArray = channelIdStr.split(",");
for( String temp : strIdArray) {
Long channelId = Long.valueOf(temp);
if( channelDao.checkBrowsePermission(channelId) ) {
channelIds.add(channelId);
}
}
condition.setChannelIds(channelIds);
PageInfo pageInfo = articleDao.getArticlesByChannelIds(condition);
return "<Response><ArticleList>" + createReturnXML(pageInfo, channelIds.get(0)) + "</ArticleList></Response>";
}
public String queryArticlesDeeplyByChannelId(Long channelId, Integer page, Integer pageSize){
ArticleQueryCondition condition = new ArticleQueryCondition();
condition.getPage().setPageNum(page);
condition.getPage().setPageSize(pageSize);
condition.setStatus(CMSConstants.XML_STATUS);
List<Channel> subChannels = channelDao.getChildrenById(channelId, CMSConstants.OPERATION_BROWSE);
List<Long> channelIds = new ArrayList<Long>();
for(Channel temp : subChannels) {
if( channelDao.checkBrowsePermission(temp.getId()) ) {
channelIds.add(temp.getId());
}
}
condition.setChannelIds(channelIds);
PageInfo pageInfo = articleDao.getArticlesByChannelIds(condition);
return "<Response><ArticleList>" + createReturnXML(pageInfo, channelId) + "</ArticleList></Response>";
}
private String createReturnXML(PageInfo pageInfo, Long channelId){
Channel channel = channelDao.getEntity(channelId);
List<?> articleList = pageInfo.getItems();
Document doc = DocumentHelper.createDocument();
Element channelElement = doc.addElement("rss").addAttribute("version", "2.0");
channelElement.addElement("channelName").setText(channel == null ? "栏目" : channel.getName()); //多个栏目一起查找,取第一个栏目
channelElement.addElement("totalRows").setText(String.valueOf(pageInfo.getTotalRows()));
channelElement.addElement("totalPageNum").setText(String.valueOf(pageInfo.getTotalPages()));
channelElement.addElement("currentPage").setText(String.valueOf(pageInfo.getPageNum()));
if (articleList != null) {
for (int i = 0; i < articleList.size(); i++) {
Object[] fields = (Object[]) articleList.get(i);
createArticleElement(channelElement, (Long) fields[0], (String) fields[1], (String) fields[2],
(Date) fields[3], (Date) fields[4], (String) fields[6], (Integer) fields[7]);
}
}
return channelElement.asXML();
}
public String getRelationArticles(Long articleId, Integer pageSize) {
if (articleId == null) {
throw new NullPointerException("读取相关文章时候文章ID为空!");
}
Document doc = org.dom4j.DocumentHelper.createDocument();
Element articleListElement = doc.addElement("Response").addElement("ArticleList");
Element channelElement = articleListElement.addElement("rss").addAttribute("version", "2.0");
List<?> articleList = articleDao.getRelationArticles(articleId);
for (int i = 0; i < articleList.size(); i++) {
Article article = (Article) articleList.get(i);
createArticleElement(channelElement, article.getId(), article.getTitle(), article.getAuthor(),
article.getIssueDate(), article.getWzrq(), article.getSummary(), article.getHitCount());
}
return doc.asXML();
}
private Element createArticleElement(Element channelElement, Object articleId, String title, String author,
Date issueDate, Date wzrq, String summary, Integer hitCount){
Element itemElement = channelElement.addElement("item");
itemElement.addElement("id").setText(articleId == null ? "" : articleId.toString());
itemElement.addElement("title").setText(title == null ? "" : title);
itemElement.addElement("author").setText(author == null ? "空" : author);
itemElement.addElement("issueDate").setText(issueDate == null ? "" : DateUtil.format(issueDate));
itemElement.addElement("wzrq").setText(wzrq == null ? "" : DateUtil.format(wzrq));
itemElement.addElement("summary").setText(summary == null ? "无" : summary);
itemElement.addElement("hitCount").setText(hitCount == null ? "" : hitCount.toString());
return itemElement;
}
public String getChannelTree4Portlet(Long channelId) {
List<Channel> list = channelDao.getChildrenById(channelId, CMSConstants.OPERATION_BROWSE);
TreeEncoder encoder = new TreeEncoder(list, new LevelTreeParser());
encoder.setNeedRootNode(false);
return encoder.toXml();
}
public String getArticleXML(Long articleId) {
Article article = articleDao.fetchArticleById(articleId);
Document articleDoc;
String pubUrl = article.getPubUrl();
try{
articleDoc = XMLDocUtil.createDocByAbsolutePath(pubUrl);
} catch(Exception e){
String fileContent = FileHelper.readFile(new File(pubUrl), "UTF-8");
articleDoc = XMLDocUtil.dataXml2Doc(XmlUtil.stripNonValidXMLCharacters(fileContent));
}
Element articleElement = articleDoc.getRootElement();
Element hitRateNode = (Element) articleElement.selectSingleNode("//hitCount");
hitRateNode.setText(article.getHitCount().toString()); // 更新点击率
// 进行文章portlet的修饰(只是对文章的基本属性进行处理)
Long articleTypeId = new Long(article.getArticleTypeId().longValue());
ArticleType articleType = (ArticleType) articleDao.getEntity(ArticleType.class, articleTypeId);
String articleTemplate = articleType.getArticleTemplate();
if ( !EasyUtils.isNullOrEmpty(articleTemplate) ) {
decorateArticleContentByTemplate(articleElement, articleId, articleTemplate);
}
Document doc = org.dom4j.DocumentHelper.createDocument();
Element articleInfoElement = doc.addElement("Response").addElement("ArticleInfo");
articleInfoElement.addElement("rss").addAttribute("version", "2.0").add(articleElement);
//添加文章点击率;
HitRateManager.getInstanse().output(articleId);
return doc.asXML();
}
private void decorateArticleContentByTemplate(Element articleElement, Long articleId, String articleTemplate){
Map<String, String> macro = new HashMap<String, String>();
List<?> list = articleElement.elements();
//遍历文章的基本属性
for (int j = 0; j < list.size(); j++) {
Element attributeNode = (Element) list.get(j);
if (attributeNode.getName().equals("Attachments")) {
// 加入相关附件
StringBuffer attachmentsInfo = new StringBuffer();
List<?> attachs = attributeNode.selectNodes("Attachment");
for(Iterator<?> it = attachs.iterator(); it.hasNext();){
Element node = (Element) it.next();
String name = node.selectSingleNode("name").getText();
String url = node.selectSingleNode("url").getText();
attachmentsInfo.append("<a href=\"" + url + "\">" + name + "</a><br/>");
}
macro.put("${Attachments}", attachmentsInfo.toString());
} else {
String code = attributeNode.getName();
macro.put("${" + code + "}", attributeNode.getTextTrim());
}
}
// 加入相关文章
List<?> relations = articleDao.getRelationArticles(articleId);
StringBuffer relationsInfo = new StringBuffer();
for(Iterator<?> it = relations.iterator(); it.hasNext();){
Article temp = (Article) it.next();
relationsInfo.append("<a href=\"articlePage.portal?articleId=" + temp.getId() + "\">" + temp.getName() + "</a><br/>");
}
macro.put("${Lations}", relationsInfo.toString());
String contentXml = MacrocodeCompiler.run(articleTemplate, macro);
articleElement.selectSingleNode("content").setText(contentXml);
}
public void addArticle(String articleXml){
Document doc = XMLDocUtil.dataXml2Doc(articleXml);
Element articleNode = (Element) doc.selectSingleNode("//ArticleInfo/Article");
Article article = new Article();
BeanUtil.setDataToBean(article, XMLDocUtil.dataNodes2Map(articleNode));
Long channelId = article.getChannelId();
Channel channel = channelDao.getEntity(channelId);
//设置过期时间
Date calculateOverDate = ArticleHelper.calculateOverDate(article, channel);
if(calculateOverDate != null) {
article.setOverdueDate(calculateOverDate);
}
articleDao.saveArticle(article);
// 栏目文章关系
ChannelArticle ca = new ChannelArticle();
ca.setId(new ChannelArticleId(channelId, article.getId()));
ca.setSeqNo(articleDao.getChannelArticleNextOrder(channelId));
articleDao.createObject(ca);
}
protected static final Date DEFAULT_START_DATE = DateUtil.parse("2000-1-1");
protected static final Date DEFAULT_END_DATE = DateUtil.parse("2099-12-31");
public String search(Long tacticId, String searchStr, Integer pageNum, Integer pagesize) {
Date startDate = DEFAULT_START_DATE;
Date endDate = DEFAULT_END_DATE;
boolean filterByTime = false; // 是否需要对查询结果集进行按时间段过滤,高级查询的时候用到
String[] field = null;
if(searchStr != null && searchStr.indexOf("@advancedSearch") >= 0){
// 查询条件(searchStr)格式为 : + 杭州 + 零售信贷 , 2000-1-1, 2099-12-31, @advancedSearch, title:杭州&author:零售信贷&
String[] condition = searchStr.split(",");
try {
searchStr = condition[0];
startDate = DateUtil.parse(condition[1].trim());
endDate = DateUtil.parse(condition[2].trim());
filterByTime = !DEFAULT_START_DATE.equals(startDate) || !DEFAULT_END_DATE.equals(endDate);
if(condition[4] != null){
field = condition[4].split("&");
}
} catch (Exception e) {
// do nothing
filterByTime = false;
}
}
TimerStrategy tacticIndex = getStrategyById(tacticId);
TimerStrategy parent = getStrategyById(tacticIndex.getParentId());
tacticIndex.setIndexPath(parent.getIndexPath());
String indexPath = tacticIndex.createIndexPath();
if (!new File(indexPath).exists() || searchStr == null || "".equals(searchStr.trim()))
return "<Response><ArticleList><rss version=\"2.0\"><channel/></rss></ArticleList></Response>";
org.dom4j.Document doc = DocumentHelper.createDocument();
// 生成rss格式的xml文件的Head部分
Element channelElement = doc.addElement("rss").addAttribute("version", "2.0");
try {
IndexSearcher searcher = new IndexSearcher(indexPath);
Query query = IndexExecutorFactory.create(tacticIndex.getIndexExecutorClass()).createIndexQuery(searchStr);
Hits hits = searcher.search(query, new Sort(new SortField("createTime", SortField.STRING, true))); // 按创建时间排序
// 先遍历一边查询结果集,对其按时间段以及权限进行过滤,将过滤后的结果集放入到一个临时list中。
List<org.apache.lucene.document.Document> list = new ArrayList<org.apache.lucene.document.Document>();
for (Iterator<?> it = hits.iterator(); it.hasNext(); ) {
Hit hit = (Hit) it.next();
org.apache.lucene.document.Document document = hit.getDocument();
// 按时间段对查询结果集进行过滤
if(filterByTime){
Date createTime = document.get("createTime") == null ? null : DateUtil.parse(document.get("createTime"));
startDate = startDate == null ? DEFAULT_START_DATE : startDate;
endDate = endDate == null ? DEFAULT_END_DATE : endDate;
if(createTime == null || createTime.before(startDate) || createTime.after(endDate)){
continue;
}
}
boolean checkByField = true;
if(field != null){
for(int i = 0; i < field.length; i++){
String nv = field[i];
try {
String fieldName = nv.substring(0, nv.indexOf(":")).trim();
String fieldValue = nv.substring(nv.indexOf(":") + 1).trim();
// 如果搜索的字段在索引里没有,或者没有包含搜索字段的关键字,则过滤掉
if(document.get(fieldName) == null || document.get(fieldName).indexOf(fieldValue) == -1){
checkByField = false;
break;
}
}catch(Exception e){
}
}
}
if(!checkByField){
continue;
}
// TODO 如果需要对结果集进行权限过滤等操作,则在此处进行
list.add(document);
}
int page = pageNum.intValue();
int pageSize = pagesize.intValue();
int totalRows = list.size();
int totalPage = totalRows % pageSize != 0 ? totalRows / pageSize + 1 : totalRows / pageSize;
channelElement.addElement("totalPageNum").setText(String.valueOf(totalPage));
channelElement.addElement("totalRows").setText(totalRows + "");
channelElement.addElement("currentPage").setText(pageNum.toString());
for (int i = (page - 1) * pageSize; i < totalRows && i < page * pageSize; i++) {
org.apache.lucene.document.Document document = list.get(i);
// 生成rss格式的xml文件的搜索出来的内容
Long articleId = document.get("id") == null ? null : Long.valueOf(document.get("id"));
Date issueDate = document.get("issueDate") == null ? null : DateUtil.parse(document.get("issueDate"));
Date wzrq = document.get("createTime") == null ? null : DateUtil.parse(document.get("createTime"));
createArticleElement(channelElement, articleId, document.get("title"), document.get("author"),
issueDate, wzrq, document.get("summary"), new Integer(0));
}
searcher.close();
} catch (Exception e) {
throw new BusinessException("搜索出错!", e);
}
return "<Response><ArticleList>" + channelElement.asXML() + "</ArticleList></Response>";
}
protected TimerStrategy getStrategyById(Long strategyId) {
Object tacticIndex = articleDao.getEntity(TimerStrategy.class, strategyId);
if (tacticIndex == null) {
throw new BusinessException("策略ID(" + strategyId + ")在数据库中不存在!");
}
return (TimerStrategy) tacticIndex;
}
public AttachmentDTO getAttachmentInfo(Long articleId, Integer seqNo) {
AttachmentId attachmentId = new AttachmentId(articleId, seqNo);
Attachment att = (Attachment) articleDao.getEntity(Attachment.class, attachmentId);
if (att == null) {
log.error("数据库中没有相应的附件信息!文章ID:" + attachmentId.getArticleId() + ", 序号:" + attachmentId.getSeqNo());
return null;
}
// 通过文章id获取栏目id
Long channelId = articleDao.getChannelIdByArticleId(articleId);
Channel site = channelDao.getSiteByChannel(channelId);
AttachmentDTO dto = new AttachmentDTO(att.getType(), att.getName(), att.getFileName(), att.getFileExt(),
att.getLocalPath(), new String[]{site.getPath(), site.getDocPath(), site.getImagePath()});
return dto;
}
public String getArticleListByChannelAndTime(Long channelId, String year, String month) {
if(channelId == null){
throw new BusinessException("栏目ID不能为空!");
}
if(year == null || month == null){
throw new BusinessException("年度或月份不能为空!");
}
Channel channel = channelDao.getEntity(channelId);
if(channel == null) {
throw new BusinessException("栏目不存在!");
}
Channel site = channelDao.getEntity(channel.getSiteId());
String publishBaseDir = site.getPath();
month = (month.length() == 1 ? "0" + month : month);
String publishDir = publishBaseDir + "/" + year + "/" + month;
List<File> xmlFiles = FileHelper.listFilesByTypeDeeply(".xml", new File(publishDir));
Document doc = org.dom4j.DocumentHelper.createDocument();
Element channelElement = doc.addElement("rss").addAttribute("version", "2.0");
channelElement.addElement("channelName").setText(channel.getName());
channelElement.addElement("totalPageNum").setText("1");
channelElement.addElement("totalRows").setText("100");
channelElement.addElement("currentPage").setText("1");
for( File xmlFile : xmlFiles ){
if(xmlFile.getName().startsWith(channelId + "_")){
Document articleDoc;
try{
articleDoc = XMLDocUtil.createDocByAbsolutePath(xmlFile.getPath());
}
catch(Exception e){
String fileContent = FileHelper.readFile(xmlFile, "UTF-8");
articleDoc = XMLDocUtil.dataXml2Doc(XmlUtil.stripNonValidXMLCharacters(fileContent));
}
Element articleElement = articleDoc.getRootElement();
Element idNode = (Element) articleElement.selectSingleNode("//id");
Element titleNode = (Element) articleElement.selectSingleNode("//title");
Element authorNode = (Element) articleElement.selectSingleNode("//author");
Element issueDateNode = (Element) articleElement.selectSingleNode("//issueDate");
Element summaryNode = (Element) articleElement.selectSingleNode("//summary");
createArticleElement(channelElement,
idNode == null ? null : idNode.getText(),
titleNode == null ? null : titleNode.getText(),
authorNode == null ? null : authorNode.getText(),
issueDateNode == null ? null : DateUtil.parse(issueDateNode.getText()),
null,
summaryNode == null ? null : summaryNode.getText(),
null);
}
}
return "<Response><ArticleList>" + channelElement.asXML() + "</ArticleList></Response>";
}
}