All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.javaclub.addons.service.impl.ConfluenceApiServiceImpl Maven / Gradle / Ivy

/*
 * @(#)ConfluenceApiServiceImpl.java	2024-03-11 16:50:50
 *
 * Copyright (c) 2024 - 2099. All Rights Reserved.
 *
 */

package com.github.javaclub.addons.service.impl;

import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.github.javaclub.BizException;
import com.github.javaclub.addons.domain.ConfluencePageDO;
import com.github.javaclub.addons.domain.model.HtmlArticleFetchConfig;
import com.github.javaclub.addons.service.ConfluenceApiService;
import com.github.javaclub.addons.service.spider.WikiArticleSpider;
import com.github.javaclub.monitor.component.alarm.AlarmMonitor;
import com.github.javaclub.monitor.entity.HttpInvokeResult;
import com.github.javaclub.monitor.util.HttpClientUtils;
import com.github.javaclub.ossclient.OSS;
import com.github.javaclub.toolbox.ToolBox.Files;
import com.github.javaclub.toolbox.ToolBox.Maps;
import com.github.javaclub.toolbox.ToolBox.Objects;
import com.github.javaclub.toolbox.ToolBox.Strings;
import com.github.javaclub.toolbox.ToolBox.UUID;
import com.github.javaclub.toolbox.conf.CompositeAppConfigProperties;
import com.github.javaclub.toolbox.URL;
import com.github.javaclub.toolbox.spring.BeanFactory;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;


/**
 * ConfluenceApiServiceImpl
 *
 * @author Gerald Chen
 * @version $Id: ConfluenceApiServiceImpl.java 2024-03-11 16:50:50 Exp $
 */
@Service
@Slf4j
public class ConfluenceApiServiceImpl implements ConfluenceApiService {
	
	@Value("${system.configs.confluence.rest-api-key:cm9ib3Q6Szl5RHBnV2M4enY=}")
	private String restApiKey = "cm9ib3Q6Szl5RHBnV2M4enY=";
	
	@Value("${system.configs.confluence.rest-api-url:http://wiki.idev.vip/rest/api}")
	private String restApiUrl = "http://wiki.idev.vip/rest/api";
	
	private AlarmMonitor alarmMonitor;
	
	AlarmMonitor getAlarmMonitor() {
		if (null != alarmMonitor) {
			return alarmMonitor;
		}
		alarmMonitor = BeanFactory.getInstance().getBean(AlarmMonitor.class);
		return alarmMonitor;
	}

	@Override
	public boolean createPage(String accessKey, ConfluencePageDO page) {
		String authToken = Strings.concat("Basic ", Strings.noneBlank(accessKey, restApiKey));
		if (null == page) {
			return false;
		}
		Objects.requireNotEmpty(page.getPageTitle(), "获取到文章标题为空");
		Objects.requireNotEmpty(page.getPageHtml(), "获取到文章内容为空");
		String payload = page.payload();
		String api = Strings.concat(restApiUrl, "/content");
		Map headerMap = Maps.createStringMap(
	        "Authorization", authToken,
	        "Origin", "http://wiki.idev.vip",
	        "Referer", "http://wiki.idev.vip/display/collects"
	    );
		HttpInvokeResult result = HttpClientUtils.postJsonWithAnyEcho(api, payload, headerMap);
		if (null == result) {
			return false;
		}
		if (!result.isHttpOK() && Strings.isNotBlank(result.getResponseText())) {
			throw new BizException(result.getResponseText());
		}
		return result.isHttpOK();
	}

	
	@Override
	public Map createPageByFetchArticleUrl(String url) throws Exception {
		if (Strings.isBlank(url)) {
			throw new BizException("链接地址不能为空!");
		}
		URL thisUrl = URL.valueOf(url);
		if (null == thisUrl) {
			throw new BizException("请输入正确的链接地址!");
		}
		ConfluencePageDO page = this.buildPageContent(url);
		boolean flag = createPage(null, page);
		if (!flag) {
			throw new BizException("提交保存文章失败!");
		}
		
		return page.fetchResult();
	}

	ConfluencePageDO buildPageContent(String url) {
		// 新的文章抓取实现逻辑
		WikiArticleSpider spider = this.parseSpider(url);
		ConfluencePageDO page = spider.fetch(url);
		
		if (null == page || Strings.isBlank(page.getPageHtml())) {
			throw new BizException("抓取文章内容为空!");
		}
		String pageHtml = Strings.cleanEmoji(page.getPageHtml());
		page.setPageHtml(pageHtml);
		page.setFetchUrl(url);
		String imgTagWiki = "";
		String img1024WidthTagWiki = "";
		
		// 替换img标签,使其符合confluence最佳展示效果
		Pattern pattern = Pattern.compile("");
		Matcher matcher = pattern.matcher(page.getPageHtml());
		StringBuffer sb = new StringBuffer();
		int imageNum = 0;
		while (matcher.find()) {
		    String imgUrl = matcher.group(1);
		    try {
				Map params = Maps.newHashMap(3);
				String fetchUrl = getFetchUrl(url, imgUrl);
				if (Strings.isBlank(fetchUrl)) {
					String imgTag = Strings.format(imgTagWiki, imgUrl, imgUrl);
					matcher.appendReplacement(sb, Matcher.quoteReplacement(imgTag));
					continue;
				}
				byte[] bytes = Files.fetchUrlAsBytes(fetchUrl);
				params.put("total", bytes.length);
				String filename = Strings.concat(UUID.randomUUID(), getImageExtention(fetchUrl));
				String imageUrl = OSS.get().upload(bytes, filename, params);
				if (Strings.isNotBlank(imageUrl)) {
					int[] widthAndHeight = Files.getWidthAndHeightByImageBytes(bytes);
					boolean widthGt1024 = null != widthAndHeight && widthAndHeight.length > 0 && widthAndHeight[0] > 1024;
				    String imgTagFormat = widthGt1024 ? img1024WidthTagWiki : imgTagWiki;
				    String imgTag = Strings.format(imgTagFormat, imageUrl, imageUrl);
				    matcher.appendReplacement(sb, Matcher.quoteReplacement(imgTag));
				    imageNum++;
				}
			} catch (Exception e) {
				String imgTag = Strings.format(imgTagWiki, imgUrl, imgUrl);
				matcher.appendReplacement(sb, Matcher.quoteReplacement(imgTag));
				continue;
			}
		}
		matcher.appendTail(sb);
		page.setImagesNum(imageNum);
		page.setPageHtml(cleanInvalidHtml4Editor(sb.toString()));
		if (log.isInfoEnabled()) {
			log.info("Page HTML: {}", page.getPageHtml());
		}
		return page;
	}

	String getFetchUrl(String url, String imgUrl) {
		if (imgUrl.startsWith("http://") || imgUrl.startsWith("https://")) {
			return imgUrl;
		}
		if (imgUrl.startsWith("//")) {
			URL _tURL = URL.valueOf(url);
			return Strings.concat(_tURL.getProtocol(), ":", imgUrl);
		}
		return imgUrl;
	}
	
	String getImageExtention(String url) {
		String ext = Files.getExtension(url);
		if (Strings.endsWith(ext, new String[] {".jpg", ".jpeg", ".png", ".gif"})) {
			return ext.toLowerCase();
		}
		return ".jpg";
	}
	
	String cleanInvalidHtml4Editor(String content) {
		String text = content.replaceAll("", Strings.EMPTY);
		text = text.replaceAll("
", "
"); text = text.replaceAll("]*>", "
"); text = text.replaceAll("
", "
"); text = text.replaceAll("]*>", "
"); text = text.replaceAll("]*>", Strings.EMPTY); text = text.replaceAll("", Strings.EMPTY); text = Strings.cleanEmoji(text); // log.warn("Cleaned HTML: {}", text); return text; } @SuppressWarnings("unchecked") @SneakyThrows WikiArticleSpider parseSpider(String url) { Map confMap = parseFetchRulesMap(); for (Map.Entry e : confMap.entrySet()) { if (!url.contains(e.getValue().getUrlMatchSegment())) { continue; } Class fetcherClass = Objects.forName(e.getValue().getHtmlFetcherClass()); WikiArticleSpider spider = BeanFactory.getInstance().getBean(fetcherClass); spider.setConfigKey(e.getKey()); return spider; } throw new BizException("No matched WikiArticleSpider"); } Map parseFetchRulesMap() { String json = CompositeAppConfigProperties.getInstance().getValue("wiki-article-spider.json"); Map map = JSONObject.parseObject(json, new TypeReference>(){}); Objects.requireTrue(null != map && 0 < map.size(), "Spider规则配置为空!"); return map; } public static void main(String[] args) { try { ConfluenceApiServiceImpl api = new ConfluenceApiServiceImpl(); String url = "https://www.jb51.net/article/34888.htm"; Map map = api.createPageByFetchArticleUrl(url); System.out.println(JSON.toJSONString(map)); } catch (Exception e) { e.printStackTrace(); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy