diff --git a/.gitignore b/.gitignore index acbf00b..ab4d0ee 100644 --- a/.gitignore +++ b/.gitignore @@ -48,3 +48,4 @@ tags target *.iml gradle +logs \ No newline at end of file diff --git a/pom.xml b/pom.xml index 0c09d38..42a1f83 100644 --- a/pom.xml +++ b/pom.xml @@ -44,6 +44,13 @@ test + + com.rometools + rome + 1.6.0 + + + diff --git a/src/main/java/com/zeekling/Main.java b/src/main/java/com/zeekling/Main.java new file mode 100644 index 0000000..6936392 --- /dev/null +++ b/src/main/java/com/zeekling/Main.java @@ -0,0 +1,20 @@ +package com.zeekling; + +import com.zeekling.blog.BlogUpdateService; +import com.zeekling.blog.BlogUpdateServiceImpl; + +/** + * @author zeekling [lingzhaohui@zeekling.cn] + * @version 1.0 + * @apiNote + * @since 2020-07-26 + */ +public class Main { + + public static void main(String[] args) { + BlogUpdateService updateService = new BlogUpdateServiceImpl("/home/zeek/project/github_zeekling/src/main/resources/blog.properties"); + int res = updateService.update(); + System.out.println(res); + } + +} diff --git a/src/main/java/com/zeekling/blog/BlogUpdate.java b/src/main/java/com/zeekling/blog/BlogUpdateService.java similarity index 71% rename from src/main/java/com/zeekling/blog/BlogUpdate.java rename to src/main/java/com/zeekling/blog/BlogUpdateService.java index ad72f3a..553fda3 100644 --- a/src/main/java/com/zeekling/blog/BlogUpdate.java +++ b/src/main/java/com/zeekling/blog/BlogUpdateService.java @@ -6,9 +6,9 @@ package com.zeekling.blog; * @apiNote * @since 2020-07-25 */ -public class BlogUpdate { - +public interface BlogUpdateService { + int update(); } diff --git a/src/main/java/com/zeekling/blog/BlogUpdateServiceImpl.java b/src/main/java/com/zeekling/blog/BlogUpdateServiceImpl.java new file mode 100644 index 0000000..17993eb --- /dev/null +++ b/src/main/java/com/zeekling/blog/BlogUpdateServiceImpl.java @@ -0,0 +1,102 @@ +package com.zeekling.blog; + +import com.rometools.rome.feed.synd.SyndEntry; +import com.rometools.rome.io.FeedException; +import com.zeekling.conf.BlogConfigure; +import com.zeekling.util.ConfigureUtil; +import com.zeekling.util.FeedXmlUtil; +import com.zeekling.util.GitHubs; +import org.apache.log4j.Level; +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; +import org.json.JSONObject; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.nio.charset.StandardCharsets; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * @author zeekling [lingzhaohui@zeekling.cn] + * @version 1.0 + * @apiNote + * @since 2020-07-26 + */ +public class BlogUpdateServiceImpl implements BlogUpdateService { + + private static final Logger LOGGER = LogManager.getLogger(BlogUpdateServiceImpl.class); + + private BlogConfigure blogConfigure = null; + + public BlogUpdateServiceImpl(String confPath) { + // init blogConfigure + try { + blogConfigure = ConfigureUtil.getNewInstants(confPath, BlogConfigure.class); + } catch (IllegalAccessException | InstantiationException | IOException e) { + e.printStackTrace(); + } + } + + @Override + public int update() { + if (blogConfigure == null) { + return -1; + } + final JSONObject gitHubUser = GitHubs.getGitHubUser(blogConfigure.getPat()); + if (null == gitHubUser) { + LOGGER.error("login failed"); + return -1; + } + LOGGER.info("login success"); + final String loginName = gitHubUser.optString("login"); + boolean ok = GitHubs.createOrUpdateGitHubRepo(blogConfigure.getPat(), loginName, blogConfigure.getRepoName(), "跟新主页", blogConfigure.getHome()); + if (!ok) { + LOGGER.error("get " + blogConfigure.getRepoName() + " failed"); + return -1; + } + final String readme = genSoloBlogReadme(loginName + "/" + blogConfigure.getRepoName()); + ok = GitHubs.updateFile(blogConfigure.getPat(), loginName, blogConfigure.getRepoName(), "README.md", readme.getBytes(StandardCharsets.UTF_8)); + if (ok) { + LOGGER.log(Level.INFO, "Exported public articles to your repo [" + blogConfigure.getRepoName() + "]"); + } + return 0; + } + + private String genSoloBlogReadme(final String repoFullName) { + final StringBuilder bodyBuilder = new StringBuilder("### 最新\n"); + try { + List entries = FeedXmlUtil.parseXml(blogConfigure.getRss()); + for (SyndEntry syndEntry: entries){ + bodyBuilder.append("\n* [").append(syndEntry.getTitle()).append("](").append(syndEntry.getLink()).append(")"); + } + } catch (FeedException | MalformedURLException e) { + e.printStackTrace(); + } + bodyBuilder.append("\n\n"); + + String ret = "

\"${title}\"

\n" + + "${title}\n" + + "

\n" + + "\n" + + "

${subtitle}

\n" + + "

" + + "\n" + + "\n" + + "" + + "

\n" + + "\n" + + "${body}\n\n" + + "---\n" + + "\n" + + "本仓库通过 [github_zeekling](https://git.zeekling.cn/zeekling/github_zeekling) 自动进行同步更新 ❤️ "; + ret = ret.replace("${title}", blogConfigure.getClientTitle()). + replace("${subtitle}", blogConfigure.getClientSubtitle()). + replace("${favicon}", blogConfigure.getFavicon()). + replace("${repoFullName}", repoFullName). + replace("${body}", bodyBuilder.toString()); + return ret; + } + +} diff --git a/src/main/java/com/zeekling/conf/BlogConfigure.java b/src/main/java/com/zeekling/conf/BlogConfigure.java new file mode 100644 index 0000000..395c428 --- /dev/null +++ b/src/main/java/com/zeekling/conf/BlogConfigure.java @@ -0,0 +1,87 @@ +package com.zeekling.conf; + +/** + * @author zeekling [lingzhaohui@zeekling.cn] + * @version 1.0 + * @apiNote 博客信息配置 + * @since 2020-07-26 + */ +public final class BlogConfigure { + + @Value(name = "blog.title") + private String clientTitle; + + @Value(name = "blog.subTitle") + private String clientSubtitle; + + @Value(name = "blog.favicon") + private String favicon; + + @Value(name = "github.pat") + private String pat; + + @Value(name = "github.repoName") + private String repoName; + + @Value(name = "blog.home") + private String home; + + @Value(name = "blog.rss") + private String rss; + + public String getClientTitle() { + return clientTitle; + } + + public void setClientTitle(String clientTitle) { + this.clientTitle = clientTitle; + } + + public String getClientSubtitle() { + return clientSubtitle; + } + + public void setClientSubtitle(String clientSubtitle) { + this.clientSubtitle = clientSubtitle; + } + + public String getFavicon() { + return favicon; + } + + public void setFavicon(String favicon) { + this.favicon = favicon; + } + + public String getPat() { + return pat; + } + + public void setPat(String pat) { + this.pat = pat; + } + + public String getRepoName() { + return repoName; + } + + public void setRepoName(String repoName) { + this.repoName = repoName; + } + + public String getHome() { + return home; + } + + public void setHome(String home) { + this.home = home; + } + + public String getRss() { + return rss; + } + + public void setRss(String rss) { + this.rss = rss; + } +} diff --git a/src/main/java/com/zeekling/conf/Value.java b/src/main/java/com/zeekling/conf/Value.java new file mode 100644 index 0000000..1e0f888 --- /dev/null +++ b/src/main/java/com/zeekling/conf/Value.java @@ -0,0 +1,20 @@ +package com.zeekling.conf; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * @author zeekling [lingzhaohui@zeekling.cn] + * @version 1.0 + * @apiNote + * @since 2020-07-26 + */ +@Target(value={ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface Value { + + String name(); + +} diff --git a/src/main/java/com/zeekling/util/ConfigureUtil.java b/src/main/java/com/zeekling/util/ConfigureUtil.java new file mode 100644 index 0000000..57f4a7c --- /dev/null +++ b/src/main/java/com/zeekling/util/ConfigureUtil.java @@ -0,0 +1,54 @@ +package com.zeekling.util; + +import com.zeekling.conf.Value; +import org.apache.commons.lang.StringUtils; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Field; +import java.util.Properties; + +/** + * @author zeekling [lingzhaohui@zeekling.cn] + * @version 1.0 + * @apiNote 读取配置文件 + * @since 2020-07-26 + */ +public final class ConfigureUtil { + + private ConfigureUtil() { + } + + public static Properties readProperties(String filePath) throws IOException { + Properties properties = new Properties(); + BufferedReader bufferedReader = new BufferedReader(new FileReader(filePath)); + properties.load(bufferedReader); + return properties; + } + + @SuppressWarnings("ReflectionForUnavailableAnnotation") + public static T getNewInstants(String filePath, Class tClass) + throws IllegalAccessException, InstantiationException, IOException { + T t = tClass.newInstance(); + Properties properties = readProperties(filePath); + + Field[] fields = tClass.getDeclaredFields(); + for (Field field : fields) { + Value value = field.getAnnotation(Value.class); + if (value == null || StringUtils.isEmpty(value.name())){ + continue; + } + String realValue = properties.getProperty(value.name()); + if (realValue == null){ + continue; + } + field.setAccessible(true); + field.set(t, realValue); + } + return t; + } + + +} diff --git a/src/main/java/com/zeekling/util/FeedXmlUtil.java b/src/main/java/com/zeekling/util/FeedXmlUtil.java new file mode 100644 index 0000000..99f9464 --- /dev/null +++ b/src/main/java/com/zeekling/util/FeedXmlUtil.java @@ -0,0 +1,59 @@ +package com.zeekling.util; + +import com.rometools.rome.feed.synd.SyndEntry; +import com.rometools.rome.feed.synd.SyndFeed; +import com.rometools.rome.io.FeedException; +import com.rometools.rome.io.SyndFeedInput; +import com.rometools.rome.io.XmlReader; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; +import java.util.List; +import java.util.zip.GZIPInputStream; + +/** + * @author zeekling [lingzhaohui@zeekling.cn] + * @version 1.0 + * @apiNote + * @since 2020-07-26 + */ +public final class FeedXmlUtil { + + private FeedXmlUtil(){} + + public static List parseXml(String urlStr) + throws IllegalArgumentException, FeedException, MalformedURLException { + URL url = new URL(urlStr); + return parseXml(url); + } + + /** + * 根据链接地址得到数据 + */ + public static List parseXml(URL url) + throws IllegalArgumentException, FeedException { + List entries = null; + try { + SyndFeedInput input = new SyndFeedInput(); + SyndFeed feed = null; + URLConnection conn; + conn = url.openConnection(); + String content_encoding = conn.getHeaderField("Content-Encoding"); + if (content_encoding != null && content_encoding.contains("gzip")) { + System.out.println("conent encoding is gzip"); + GZIPInputStream gzin = new GZIPInputStream(conn.getInputStream()); + feed = input.build(new XmlReader(gzin)); + } else { + feed = input.build(new XmlReader(conn.getInputStream())); + } + + entries = feed.getEntries();// 得到所有的标题 + } catch (IOException e) { + e.printStackTrace(); + } + return entries; + + } +} diff --git a/src/main/resources/blog.properties b/src/main/resources/blog.properties new file mode 100644 index 0000000..4eff79d --- /dev/null +++ b/src/main/resources/blog.properties @@ -0,0 +1,7 @@ +blog.title=小令童鞋 +blog.subTitle=梅干菜你个小酥饼哦。 +blog.home=https://www/zeekling.cn +blog.rss=https://www.zeekling.cn/rss.xml +blog.favicon=https://img.zeekling.cn/images/2020/02/23/logo.th.png +github.pat=068783457fa6e084aad1342ed2730f33a0255b97 +github.repoName=zeekling diff --git a/src/main/resources/log4j.properties b/src/main/resources/log4j.properties new file mode 100644 index 0000000..8306a46 --- /dev/null +++ b/src/main/resources/log4j.properties @@ -0,0 +1,24 @@ +### 设置### +log4j.rootLogger = debug,stdout,D,E + +### 输出信息到控制抬 ### +log4j.appender.stdout = org.apache.log4j.ConsoleAppender +log4j.appender.stdout.Target = System.out +log4j.appender.stdout.layout = org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n + +### 输出DEBUG 级别以上的日志到=./logs/debug.log ### +log4j.appender.D = org.apache.log4j.DailyRollingFileAppender +log4j.appender.D.File = ./logs/debug.log +log4j.appender.D.Append = true +log4j.appender.D.Threshold = DEBUG +log4j.appender.D.layout = org.apache.log4j.PatternLayout +log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n + +### 输出ERROR 级别以上的日志到=./logs/error.log ### +log4j.appender.E = org.apache.log4j.DailyRollingFileAppender +log4j.appender.E.File =./logs/error.log +log4j.appender.E.Append = true +log4j.appender.E.Threshold = ERROR +log4j.appender.E.layout = org.apache.log4j.PatternLayout +log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n \ No newline at end of file diff --git a/src/test/java/com/zeekling/blog/BlogUpdateTest.java b/src/test/java/com/zeekling/blog/BlogUpdateTest.java index 349069e..364131f 100644 --- a/src/test/java/com/zeekling/blog/BlogUpdateTest.java +++ b/src/test/java/com/zeekling/blog/BlogUpdateTest.java @@ -1,5 +1,9 @@ package com.zeekling.blog; +import com.zeekling.util.GitHubs; +import org.json.JSONObject; +import org.testng.annotations.Test; + /** * @author zeekling [lingzhaohui@zeekling.cn] * @version 1.0 @@ -7,4 +11,22 @@ package com.zeekling.blog; * @since 2020-07-25 */ public class BlogUpdateTest { + + @Test + public void updateGitHub(){ + String pat = "068783457fa6e084aad1342ed2730f33a0255b97"; + final JSONObject gitHubUser = GitHubs.getGitHubUser(pat); + if (null == gitHubUser) { + return; + } + + final String loginName = gitHubUser.optString("login"); + final String repoName = "zeekling"; + boolean ok = GitHubs.createOrUpdateGitHubRepo(pat, loginName, repoName, "跟新主页", "https://www.zeekling.cn/"); + if (!ok) { + return; + } +// final String readme = genSoloBlogReadme(clientTitle, clientSubtitle, preference.optString(Option.ID_C_FAVICON_URL), loginName + "/" + repoName); + } + } diff --git a/src/test/java/com/zeekling/util/ConfigureUtilTest.java b/src/test/java/com/zeekling/util/ConfigureUtilTest.java new file mode 100644 index 0000000..a2db52b --- /dev/null +++ b/src/test/java/com/zeekling/util/ConfigureUtilTest.java @@ -0,0 +1,31 @@ +package com.zeekling.util; + +import com.zeekling.conf.BlogConfigure; +import org.json.JSONObject; +import org.testng.annotations.Test; + +import java.io.IOException; + +/** + * @author zeekling [lingzhaohui@zeekling.cn] + * @version 1.0 + * @apiNote + * @since 2020-07-26 + */ +public class ConfigureUtilTest { + + @Test + public void getNewInstants(){ + try { + BlogConfigure blogConfigure = ConfigureUtil.getNewInstants("/home/zeek/project/github_zeekling/src/main/resources/blog.properties", BlogConfigure.class); + System.out.println(new JSONObject(blogConfigure)); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } catch (InstantiationException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + } + +} diff --git a/src/test/java/com/zeekling/util/FeedXmlUtilTest.java b/src/test/java/com/zeekling/util/FeedXmlUtilTest.java new file mode 100644 index 0000000..daece49 --- /dev/null +++ b/src/test/java/com/zeekling/util/FeedXmlUtilTest.java @@ -0,0 +1,31 @@ +package com.zeekling.util; + +import com.rometools.rome.feed.synd.SyndEntry; +import com.rometools.rome.io.FeedException; +import org.json.JSONObject; +import org.testng.annotations.Test; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.List; + +/** + * @author zeekling [lingzhaohui@zeekling.cn] + * @version 1.0 + * @apiNote + * @since 2020-07-26 + */ +public class FeedXmlUtilTest { + + @Test + public void parseXml(){ + URL url = null; + try { + url = new URL("https://www.zeekling.cn/rss.xml"); + List entries = FeedXmlUtil.parseXml(url); + } catch (MalformedURLException | FeedException e) { + e.printStackTrace(); + } + } + +}