Skip to content

Commit

Permalink
支持使用redis缓存文章,优化速度。
Browse files Browse the repository at this point in the history
  • Loading branch information
zeekling committed Apr 10, 2023
1 parent ad8b2b4 commit 1f5eb32
Show file tree
Hide file tree
Showing 16 changed files with 172 additions and 33 deletions.
19 changes: 18 additions & 1 deletion src/main/java/org/b3log/solo/model/Article.java
Expand Up @@ -18,8 +18,10 @@
package org.b3log.solo.model;

import org.apache.commons.lang.StringUtils;
import org.b3log.latke.Keys;
import org.b3log.solo.util.Images;
import org.b3log.solo.util.Markdowns;
import org.b3log.solo.util.RedisCacheUtils;
import org.json.JSONObject;
import org.jsoup.Jsoup;
import org.jsoup.safety.Whitelist;
Expand Down Expand Up @@ -240,6 +242,15 @@ public static String getArticleImg1URL(final JSONObject article) {
* @param content the specified content
* @return the abstract plain text
*/
public static String getAbstractText(final String content, String articleId) {
final String ret = Jsoup.clean(Markdowns.toHTML(content, "abstractContent_" + articleId), Whitelist.none());
if (ret.length() > ARTICLE_ABSTRACT_LENGTH) {
return ret.substring(0, ARTICLE_ABSTRACT_LENGTH) + "....";
}

return ret;
}

public static String getAbstractText(final String content) {
final String ret = Jsoup.clean(Markdowns.toHTML(content), Whitelist.none());
if (ret.length() > ARTICLE_ABSTRACT_LENGTH) {
Expand All @@ -264,7 +275,13 @@ public static String getAbstractText(final JSONObject article) {

content = article.optString(Article.ARTICLE_CONTENT);
}
String articleId = article.getString(Keys.OBJECT_ID);
return getAbstractText(content, articleId);
}

return getAbstractText(content);
public static void cleanCache(String articleId) {
RedisCacheUtils.cleanCache("content_" + articleId,
"abstractContent_" + articleId,
"description_" + articleId);
}
}
7 changes: 0 additions & 7 deletions src/main/java/org/b3log/solo/processor/ArticleProcessor.java
Expand Up @@ -176,13 +176,6 @@ public void markdown2HTML(final RequestContext context) {
return;
}

/* if (!Solos.isLoggedIn(context)) {
result.put(Keys.CODE, -1);
result.put(Keys.MSG, langPropsService.get("getFailLabel"));
return;
} */

try {
final String html = Markdowns.toHTML(markdownText);
result.put(Common.DATA, html);
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/org/b3log/solo/processor/B3Receiver.java
Expand Up @@ -183,7 +183,7 @@ public void postArticle(final RequestContext context) {
put(Article.ARTICLE_TAGS_REF, symArticle.optString("tags"));
article.put(Article.ARTICLE_AUTHOR_ID, articleAuthor.getString(Keys.OBJECT_ID));
final String articleContent = article.optString(Article.ARTICLE_CONTENT);
article.put(Article.ARTICLE_ABSTRACT, Article.getAbstractText(articleContent));
article.put(Article.ARTICLE_ABSTRACT, Article.getAbstractText(articleContent, articleId));
article.put(Article.ARTICLE_STATUS, Article.ARTICLE_STATUS_C_PUBLISHED);
article.put(Common.POST_TO_COMMUNITY, false); // Do not send to rhythm
article.put(Article.ARTICLE_COMMENTABLE, true);
Expand All @@ -198,7 +198,7 @@ public void postArticle(final RequestContext context) {
}

final String articleContent = symArticle.optString("content");
oldArticle.put(Article.ARTICLE_ABSTRACT, Article.getAbstractText(articleContent));
oldArticle.put(Article.ARTICLE_ABSTRACT, Article.getAbstractText(articleContent, articleId));
oldArticle.put(Article.ARTICLE_CONTENT, articleContent);
oldArticle.put(Article.ARTICLE_TITLE, symArticle.optString("title"));
oldArticle.put(Article.ARTICLE_TAGS_REF, symArticle.optString("tags"));
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/org/b3log/solo/processor/FeedProcessor.java
Expand Up @@ -229,7 +229,8 @@ private Item getItem(final JSONArray articles, final boolean isFullContent, int
? article.getString(Article.ARTICLE_CONTENT)
: article.optString(Article.ARTICLE_ABSTRACT);
description = EmojiParser.parseToAliases(description);
description = Markdowns.toHTML(description);
String articleId = article.optString(Keys.OBJECT_ID);
description = Markdowns.toHTML(description, "description_" + articleId);
ret.setDescription(description);
final long pubDate = article.getLong(Article.ARTICLE_UPDATED);
ret.setPubDate(new Date(pubDate));
Expand Down
Expand Up @@ -514,6 +514,7 @@ public void updateArticle(final JSONObject requestJSONObject) throws ServiceExce
}

transaction.commit();
Article.cleanCache(articleId);
} catch (final ServiceException e) {
if (transaction.isActive()) {
transaction.rollback();
Expand Down
9 changes: 5 additions & 4 deletions src/main/java/org/b3log/solo/service/ArticleQueryService.java
Expand Up @@ -953,7 +953,7 @@ public String getArticleContent(final RequestContext context, final String artic
// Markdown to HTML for content and abstract
Stopwatchs.start("Get Article Content [Markdown]");
String content = article.optString(Article.ARTICLE_CONTENT);
content = Markdowns.toHTML(content);
content = Markdowns.toHTML(content, "content_" + articleId);
article.put(Article.ARTICLE_CONTENT, content);
Stopwatchs.end();
}
Expand Down Expand Up @@ -983,16 +983,17 @@ public void markdowns(final List<JSONObject> articles) {
* @param article the specified article
*/
public void markdown(final JSONObject article) {
Stopwatchs.start("Markdown Article [id=" + article.optString(Keys.OBJECT_ID) + "]");
final String articleId = article.optString(Keys.OBJECT_ID);
Stopwatchs.start("Markdown Article [id=" + articleId + "]");

String content = article.optString(Article.ARTICLE_CONTENT);
content = Markdowns.toHTML(content);
content = Markdowns.toHTML(content, "content_" + articleId);
article.put(Article.ARTICLE_CONTENT, content);

String abstractContent = article.optString(Article.ARTICLE_ABSTRACT);
if (StringUtils.isNotBlank(abstractContent)) {
Stopwatchs.start("Abstract");
abstractContent = Markdowns.toHTML(abstractContent);
abstractContent = Markdowns.toHTML(abstractContent, "abstractContent_" + articleId);
article.put(Article.ARTICLE_ABSTRACT, abstractContent);
Stopwatchs.end();
}
Expand Down
Expand Up @@ -284,7 +284,7 @@ public JSONObject addArticleComment(final JSONObject requestJSONObject) throws S
ret.put(Common.COMMENTABLE, preference.getBoolean(Option.ID_C_COMMENTABLE) && article.getBoolean(Article.ARTICLE_COMMENTABLE));
ret.put(Common.PERMALINK, article.getString(Article.ARTICLE_PERMALINK));
ret.put(Comment.COMMENT_NAME, commentName);
String cmtContent = Markdowns.toHTML(commentContent);
String cmtContent = Markdowns.toHTML(commentContent, "comment_" + commentName + "_" + articleId);
cmtContent = Markdowns.clean(cmtContent);
ret.put(Comment.COMMENT_CONTENT, cmtContent);
ret.put(Comment.COMMENT_URL, commentURL);
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/org/b3log/solo/service/CommentQueryService.java
Expand Up @@ -186,7 +186,7 @@ public JSONObject getComments(final JSONObject requestJSONObject) throws Service
comment.put(Common.COMMENT_TITLE, title);

String commentContent = comment.optString(Comment.COMMENT_CONTENT);
commentContent = Markdowns.toHTML(commentContent);
commentContent = Markdowns.toHTML(commentContent, "common_" + title + "_" + article.getString(Keys.OBJECT_ID));
commentContent = Markdowns.clean(commentContent);
comment.put(Comment.COMMENT_CONTENT, commentContent);

Expand Down Expand Up @@ -231,6 +231,7 @@ public List<JSONObject> getComments(final String onId) throws ServiceException {
comment.put(Comment.COMMENT_TIME, comment.optLong(Comment.COMMENT_CREATED));
comment.put(Comment.COMMENT_T_DATE, new Date(comment.optLong(Comment.COMMENT_CREATED)));
comment.put("commentDate2", new Date(comment.optLong(Comment.COMMENT_CREATED))); // 1.9.0 向后兼容
String commentName = comment.getString(Comment.COMMENT_NAME);
comment.put(Comment.COMMENT_NAME, comment.getString(Comment.COMMENT_NAME));
String url = comment.getString(Comment.COMMENT_URL);
if (StringUtils.contains(url, "<")) { // legacy issue https://github.com/b3log/solo/issues/12091
Expand All @@ -245,11 +246,10 @@ public List<JSONObject> getComments(final String onId) throws ServiceException {
}

String commentContent = comment.optString(Comment.COMMENT_CONTENT);
commentContent = Markdowns.toHTML(commentContent);
commentContent = Markdowns.toHTML(commentContent, "common_" + commentName + "_" + onId);
commentContent = Markdowns.clean(commentContent);
comment.put(Comment.COMMENT_CONTENT, commentContent);

String commentName = comment.optString(Comment.COMMENT_NAME);
commentName = Jsoup.clean(commentName, Whitelist.none());
comment.put(Comment.COMMENT_NAME, commentName);

Expand Down
6 changes: 4 additions & 2 deletions src/main/java/org/b3log/solo/service/DataModelService.java
Expand Up @@ -543,10 +543,12 @@ public void fillRecentComments(final Map<String, Object> dataModel, final JSONOb
final List<JSONObject> recentComments = commentRepository.getRecentComments(recentCommentDisplayCnt);
for (final JSONObject comment : recentComments) {
String commentContent = comment.optString(Comment.COMMENT_CONTENT);
commentContent = Markdowns.toHTML(commentContent);
String commentName = comment.getString(Comment.COMMENT_NAME);
commentContent = Markdowns.toHTML(commentContent, "comment_" + commentName +
"_" + comment.getString(Comment.COMMENT_ON_ID));
commentContent = Markdowns.clean(commentContent);
comment.put(Comment.COMMENT_CONTENT, commentContent);
comment.put(Comment.COMMENT_NAME, comment.getString(Comment.COMMENT_NAME));
comment.put(Comment.COMMENT_NAME, commentName);
comment.put(Comment.COMMENT_URL, comment.getString(Comment.COMMENT_URL));
comment.put(Common.IS_REPLY, false);
comment.put(Comment.COMMENT_T_DATE, new Date(comment.optLong(Comment.COMMENT_CREATED)));
Expand Down
10 changes: 10 additions & 0 deletions src/main/java/org/b3log/solo/util/Markdowns.java
Expand Up @@ -157,6 +157,16 @@ public static String clean(final String html) {
return Jsoup.clean(html, Latkes.getServePath(), whitelist, outputSettings);
}

public static String toHTML(final String markdownText, String cacheKey) {
String cache = RedisCacheUtils.getCache(cacheKey);
if (!StringUtils.isEmpty(cache)) {
return cache;
}
cache = toHTML(markdownText);
RedisCacheUtils.cacheValue(cacheKey, cache);
return cache;
}

/**
* Converts the specified markdown text to HTML.
*
Expand Down
109 changes: 109 additions & 0 deletions src/main/java/org/b3log/solo/util/RedisCacheUtils.java
@@ -0,0 +1,109 @@
/*
* Bolo - A stable and beautiful blogging system based in Solo.
* Copyright (c) 2020, https://github.com/adlered
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.b3log.solo.util;

import org.b3log.latke.logging.Logger;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

import java.util.ResourceBundle;

/**
* @author zeekling
*/
public class RedisCacheUtils {

private static final Logger LOGGER = Logger.getLogger(Markdowns.class);

public static String REDIS_CACHE_ADDRESS = "127.0.0.1:6379";

public static String REDIS_MODE = "single";

public static boolean REDIS_ENABLE = false;

private static final Object LOCK = new Object();

private static JedisPool jedisPool = null;

public static void initRedis(ResourceBundle solo) {
boolean redisEnable = Boolean.parseBoolean(solo.getString("redisEnable"));
RedisCacheUtils.REDIS_ENABLE = redisEnable;
if (!redisEnable) {
LOGGER.info("redis cache is not enable.");
return;
}
LOGGER.info("redis cache enable.");
String mode = solo.getString("redisMode");
if ("single".equals(mode)) {
RedisCacheUtils.REDIS_MODE = mode;
RedisCacheUtils.REDIS_CACHE_ADDRESS = solo.getString("redisAddress");
RedisCacheUtils.initJedis();
} else {
LOGGER.error("Only support single mode.");
}
}

private static void initJedis() {
if (jedisPool != null) {
return;
}
synchronized (LOCK) {
if (jedisPool != null) {
return;
}
String[] ipInfo = REDIS_CACHE_ADDRESS.split(":");
if (ipInfo.length != 2) {
LOGGER.warn("redisAddress is invalid");
REDIS_ENABLE = false;
return;
}
JedisPoolConfig config = new JedisPoolConfig();
jedisPool = new JedisPool(config, ipInfo[0], Integer.parseInt(ipInfo[1]));
}
}

public static String getCache(String cacheKey) {
if (!REDIS_ENABLE) {
return null;
}
try (Jedis jedis = jedisPool.getResource()) {
return jedis.get(cacheKey);
}
}

public static void cacheValue(String cacheKey, String cache) {
if (!REDIS_ENABLE) {
return ;
}
try (Jedis jedis = jedisPool.getResource()) {
jedis.set(cacheKey, cache);
}
}

public static void cleanCache(String... cacheKey) {
if (!REDIS_ENABLE) {
return ;
}
try (Jedis jedis = jedisPool.getResource()) {
jedis.unlink(cacheKey);
}
}


}
18 changes: 10 additions & 8 deletions src/main/java/org/b3log/solo/util/Solos.java
Expand Up @@ -107,15 +107,23 @@ public final class Solos {
private static String uploadMsg = "";

static {
ResourceBundle solo = getResourceBundle();
FAVICON_API = solo.getString("faviconAPI");
initMarkDown(solo);
RedisCacheUtils.initRedis(solo);
}

private static ResourceBundle getResourceBundle() {
ResourceBundle solo;
try {
solo = ResourceBundle.getBundle("solo");
} catch (final MissingResourceException e) {
solo = ResourceBundle.getBundle("b3log"); // 2.8.0 向后兼容
}
return solo;
}

FAVICON_API = solo.getString("faviconAPI");

private static void initMarkDown(ResourceBundle solo) {
if (!Markdowns.LUTE_AVAILABLE) {
try {
Markdowns.LUTE_ENGINE_URL = solo.getString("luteHttp");
Expand Down Expand Up @@ -163,12 +171,6 @@ private Solos() {
}

public static void enableWelfareLuteService() {
ResourceBundle solo;
try {
solo = ResourceBundle.getBundle("solo");
} catch (final MissingResourceException e) {
solo = ResourceBundle.getBundle("b3log"); // 2.8.0 向后兼容
}
boolean status = Boolean.parseBoolean(Options.get(Option.ID_C_WELFARE_LUTE_SERVICE));
// 使用公益Lute-Http服务(Bolo专享)
final String LUTE_URL = "http://lute.stackoverflow.wiki:8249";
Expand Down
4 changes: 2 additions & 2 deletions src/main/resources/latke.properties
Expand Up @@ -25,8 +25,8 @@
#### Server ####
# Browser visit protocol
serverScheme=http
#serverHost=localhost
#serverPort=
serverHost=zeekling
serverPort=8080

#### Runtime Mode ####
#runtimeMode=DEVELOPMENT
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/local.properties
Expand Up @@ -27,7 +27,7 @@ runtimeDatabase=MYSQL
jdbc.username=root
jdbc.password=123456
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.URL=jdbc:mysql://localhost:3306/solo?useUnicode=yes&characterEncoding=UTF-8&useSSL=false&serverTimezone=UTC
jdbc.URL=jdbc:mysql://127.0.0.1:3306/solo?useUnicode=yes&characterEncoding=UTF-8&useSSL=false&serverTimezone=UTC

#### H2 runtime ####
#runtimeDatabase=H2
Expand Down
5 changes: 4 additions & 1 deletion src/main/resources/solo.properties
Expand Up @@ -23,4 +23,7 @@
#

faviconAPI=https://api.byi.pw/favicon?url=
luteHttp=http://localhost:8249
luteHttp=http://localhost:8249
redisEnable=false
redisMode=single
redisAddress=127.0.0.1:6379
Empty file removed ssh
Empty file.

0 comments on commit 1f5eb32

Please sign in to comment.