去除 fastjson2 依赖

This commit is contained in:
2025-12-31 00:50:33 +08:00
parent a731d0c996
commit 24323e246f
20 changed files with 176 additions and 179 deletions

14
pom.xml
View File

@@ -178,20 +178,6 @@
</exclusion>
</exclusions>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba.fastjson2/fastjson2 -->
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>2.0.23</version>
</dependency>
<!--
https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.14.1</version><!--$NO-MVN-MAN-VER$-->
</dependency>
<!-- https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15to18 -->
<!-- sha224 哈希套件 -->

View File

@@ -186,7 +186,7 @@ public class Rk {
* @return
*/
public static String prepareDogHash(String email) {
if (email == null) email = "";
email = email.toLowerCase(Locale.ENGLISH);
RBucket<String> gravatarHashBucket = redisson.getBucket(getGravatarKey(EMAIL_HASH_PREFIX + email));

View File

@@ -3,6 +3,7 @@ package me.qwq.doghouse.config;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.cache.CacheProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
@@ -21,11 +22,13 @@ import me.qwq.doghouse.service.ConfigService;
/**
* Doghouse 配置项
* <p>
* 指定 RedisCacheManager 序列化器后需要重新指定启用 CacheProperties 的自动装配
* @author Doghole
*
*/
@Configuration
@EnableConfigurationProperties(DoghouseProperties.class)
@EnableConfigurationProperties({DoghouseProperties.class, CacheProperties.class})
@Import(ConfigAutoRegistrar.class)
public class DoghouseConfig implements WebMvcConfigurer {
@@ -90,4 +93,5 @@ public class DoghouseConfig implements WebMvcConfigurer {
resolver.setCheckExistence(true); // 文件不存在就跳过,交给下一个 resolver
return resolver;
}
}

View File

@@ -1,6 +1,5 @@
package me.qwq.doghouse.controller.admin;
import com.alibaba.fastjson2.util.DateUtils;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
@@ -18,6 +17,8 @@ import me.qwq.doghouse.pojo.dto.LayPageReq;
import me.qwq.doghouse.pojo.dto.LayPageResp;
import me.qwq.doghouse.pojo.dto.R;
import me.qwq.doghouse.service.AssetService;
import me.qwq.doghouse.util.DateUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

View File

@@ -1,10 +1,11 @@
package me.qwq.doghouse.controller.admin.post;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import jakarta.validation.Valid;
@@ -56,13 +57,19 @@ public abstract class AbstractAdminPostController<C extends IPostTypeConfig<C>,
@Autowired
AssetService assetService;
@Autowired
MetaService metaService;
@Autowired
RelationshipService relationshipService;
@Autowired
PostTypeComponent postTypeComponent;
@Autowired
ObjectMapper objectMapper;
C postTypeConfig;
/**
@@ -136,9 +143,10 @@ public abstract class AbstractAdminPostController<C extends IPostTypeConfig<C>,
/**
* 编辑
* @throws JsonProcessingException
*/
@GetMapping("/edit")
public String edit(@RequestParam(required = false) Long postId) {
public String edit(@RequestParam(required = false) Long postId) throws JsonProcessingException {
PostTypeEnum postType = getPostTypeConfig().getPostType();
@@ -148,7 +156,7 @@ public abstract class AbstractAdminPostController<C extends IPostTypeConfig<C>,
request.setAttribute("title", "编辑 - " + post.getPostTitle());
List<Asset> assets = assetService.list(
new LambdaQueryWrapper<Asset>().eq(Asset::getFromPostId, postId));
request.setAttribute("assets", StringEscapeUtils.escapeEcmaScript(JSONObject.toJSONString(assets)));
request.setAttribute("assets", StringEscapeUtils.escapeEcmaScript(objectMapper.writeValueAsString(assets)));
}
else {
request.setAttribute("title", "新增" + postType.getNote());

View File

@@ -20,14 +20,13 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.alibaba.fastjson2.JSONObject;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import me.qwq.dogface.Dogface;
import me.qwq.doghouse.component.Rk;
import me.qwq.doghouse.exception.PageNotFoundException;
import me.qwq.doghouse.pojo.dto.DailyPostCommentStats;
import me.qwq.doghouse.pojo.dto.R;
import me.qwq.doghouse.service.CommentService;
import me.qwq.doghouse.service.StatisticsService;
@@ -132,7 +131,7 @@ public class ApiControllerV1 {
}
@GetMapping(path="/getPassDaysStatistics", produces="application/json")
public JSONObject getPassDaysStatistics(Integer passDays) {
public DailyPostCommentStats getPassDaysStatistics(Integer passDays) {
return statisticsService.getPostAndCommentCountsWithDates(passDays, null);
}
@@ -163,11 +162,11 @@ public class ApiControllerV1 {
svgRoot.setAttribute("viewBox", String.format("0 0 %d %d", w, h));
// 获取 n 日以来的文章和评论统计
JSONObject jo = statisticsService.getPostAndCommentCountsWithDates(total, null);
DailyPostCommentStats s = statisticsService.getPostAndCommentCountsWithDates(total, null);
List<String> dates = jo.getList("dates", String.class);
List<Integer> postCounts = jo.getList("postCounts", Integer.class);
List<Integer> commentCounts = jo.getList("commentCounts", Integer.class);
List<String> dates = s.dates();
List<Integer> postCounts = s.postCounts();
List<Integer> commentCounts = s.commentCounts();
for (int col = 0; col < cols; col++) {
for (int row = 0; row < rows; row++) {

View File

@@ -1,5 +1,8 @@
package me.qwq.doghouse.controller.api.v2;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@@ -8,7 +11,7 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.alibaba.fastjson2.JSONObject;
import com.fasterxml.jackson.databind.JsonNode;
import me.qwq.dogface.Dogface;
import me.qwq.doghouse.controller.common.BaseController;
@@ -38,8 +41,8 @@ public class CommentApiControllerV2 extends BaseController {
Dogface dogface;
@PostMapping("/preview")
public R<?> preview(@RequestBody JSONObject jo) {
String markDown = MarkDownUtils.commentToHtml(jo.getString("content"));
public R<?> preview(@RequestBody JsonNode jo) {
String markDown = MarkDownUtils.commentToHtml(jo.get("content").asText());
return R.ok(markDown);
}
@@ -54,16 +57,16 @@ public class CommentApiControllerV2 extends BaseController {
throw RException.badRequest("非法请求");
}
JSONObject jo = new JSONObject();
jo.put("author", commentForEdit.getAuthor());
jo.put("isMarkdown", commentForEdit.isMarkdown());
jo.put("email", commentForEdit.getEmail());
jo.put("url", commentForEdit.getUrl());
jo.put("content", commentForEdit.getContent());
jo.put("subscribeReply", commentForEdit.isSubscribeReply());
jo.put("commentStatu", commentForEdit.getCommentStatus());
jo.put("id", commentForEdit.getId());
Map<String, Object> dto = new HashMap<>();
dto.put("author", commentForEdit.getAuthor());
dto.put("isMarkdown", commentForEdit.isMarkdown());
dto.put("email", commentForEdit.getEmail());
dto.put("url", commentForEdit.getUrl());
dto.put("content", commentForEdit.getContent());
dto.put("subscribeReply", commentForEdit.isSubscribeReply());
dto.put("commentStatu", commentForEdit.getCommentStatus());
dto.put("id", commentForEdit.getId());
return R.ok(jo);
return R.ok(dto);
}
}

View File

@@ -1,7 +1,6 @@
package me.qwq.doghouse.controller.blog;
import com.alibaba.fastjson2.util.DateUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
@@ -18,6 +17,7 @@ import me.qwq.doghouse.interfaces.IPostTypeConfig;
import me.qwq.doghouse.pojo.dto.PageQuery;
import me.qwq.doghouse.service.*;
import me.qwq.doghouse.service.post.PostService;
import me.qwq.doghouse.util.DateUtils;
import org.apache.commons.lang3.StringUtils;
import org.jdom2.Document;

View File

@@ -1,7 +1,9 @@
package me.qwq.doghouse.controller.blog.post;
import com.alibaba.fastjson2.JSON;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import me.qwq.doghouse.entity.config.WikiConfig;
import me.qwq.doghouse.entity.Post;
@@ -9,6 +11,7 @@ import me.qwq.doghouse.pojo.bo.PostPassJar;
import me.qwq.doghouse.service.post.WikiService;
import me.qwq.doghouse.util.EscapeUnescapeUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@@ -28,6 +31,9 @@ import java.util.List;
@RequestMapping("/wiki")
public class WikiPaginationController extends AbstractPaginationController<WikiConfig, WikiService> {
@Autowired
ObjectMapper objectMapper;
/**
* 首页
*/
@@ -44,9 +50,10 @@ public class WikiPaginationController extends AbstractPaginationController<WikiC
* Wiki 树形菜单点击
* @param postId
* @return
* @throws JsonProcessingException
*/
@GetMapping({"/list", "/list/", "/list/{postId}"})
public String listFrontWikisOnly(@PathVariable(name="postId", required=false) Long postId) {
public String listFrontWikisOnly(@PathVariable(name="postId", required=false) Long postId) throws JsonProcessingException {
request.setAttribute("wikis", listFrontWikis(postId));
return postTypeComponent.getTemplatePath(getPostType(), "side-only");
}
@@ -56,10 +63,11 @@ public class WikiPaginationController extends AbstractPaginationController<WikiC
* 放在控制器这里只是方便前端模板调用,并且能获得 service 的缓存能力
* @param postId
* @return
* @throws JsonProcessingException
*/
public List<Post> listFrontWikis(Long postId) {
public List<Post> listFrontWikis(Long postId) throws JsonProcessingException {
List<Long> unfolded = WikiService.getUnfoldedWikis(request);
String unfoldedStr = unfolded == null ? "[]" : JSON.toJSONString(unfolded);
String unfoldedStr = unfolded == null ? "[]" : objectMapper.writeValueAsString(unfolded);
unfoldedStr = EscapeUnescapeUtils.escape(unfoldedStr);
Cookie unfoldedCookie = new Cookie(WikiService.UNFOLDED_WIKIS, unfoldedStr);
unfoldedCookie.setPath("/");

View File

@@ -27,7 +27,6 @@ import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import me.qwq.doghouse.enums.PostStatusEnum;
import me.qwq.doghouse.enums.PostTypeEnum;
import me.qwq.doghouse.interfaces.IAvatarUrl;
import me.qwq.doghouse.interfaces.IFriendlyName;
import me.qwq.doghouse.interfaces.IPostPassMess;
import me.qwq.doghouse.validator.FriendlyNameValid;
@@ -41,7 +40,7 @@ import me.qwq.doghouse.validator.FriendlyNameValid;
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@FriendlyNameValid
public class Post extends Model<Post> implements Serializable, IPostPassMess<Post>, ITreeView<Post>, IAvatarUrl, IFriendlyName {
public class Post extends Model<Post> implements Serializable, IPostPassMess<Post>, ITreeView<Post>, IFriendlyName {
private static final long serialVersionUID = 1L;

View File

@@ -1,39 +0,0 @@
package me.qwq.doghouse.entity.config;
import java.io.Serializable;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import jodd.io.FileUtil;
import lombok.Data;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;
import me.qwq.doghouse.annotation.ConfigInfo;
import me.qwq.doghouse.interfaces.IConfig;
@SuppressWarnings("serial")
@Data
@Accessors(chain=true)
@ConfigInfo(field="markdown", name="Markdown 设置", initDefault=true)
@Slf4j
public class MarkdownConfig implements Serializable, IConfig<MarkdownConfig> {
private static final String DEFAULT_MERMAID_CONFIG = "";
private String mermaidConfig = DEFAULT_MERMAID_CONFIG;
public MarkdownConfig afterSaving() {
if (StringUtils.isNotBlank(mermaidConfig)) {
try {
JSONObject jo = JSONObject.parse(mermaidConfig);
FileUtil.writeString("./conf/mermaid/config.json", jo.toJSONString());
} catch (Exception e) {
log.warn("Save mermaid self-defined css failed", e);
}
}
return this;
}
}

View File

@@ -0,0 +1,10 @@
package me.qwq.doghouse.pojo.dto;
import java.io.Serializable;
import java.util.List;
public record DailyPostCommentStats(
List<String> dates,
List<Integer> postCounts,
List<Integer> commentCounts
) implements Serializable {}

View File

@@ -7,7 +7,8 @@ import me.qwq.doghouse.entity.RawConfig;
import me.qwq.doghouse.interfaces.IConfig;
import me.qwq.doghouse.util.SpringContextHolder;
import com.alibaba.fastjson2.JSONObject;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
@@ -40,6 +41,9 @@ public class ConfigService extends BaseServiceImpl<ConfigMapper, RawConfig> {
@Autowired
Reflections reflections;
@Autowired
private ObjectMapper objectMapper;
/**
* 从
* <b><code> field </code></b>
@@ -198,8 +202,15 @@ public class ConfigService extends BaseServiceImpl<ConfigMapper, RawConfig> {
}
return null;
}
T iConfig =
JSONObject.parseObject(rawConfig.getConfigValue(), clazz);
T iConfig;
try {
iConfig = objectMapper.readValue(rawConfig.getConfigValue(), clazz);
}
catch (JsonProcessingException e) {
throw new IllegalStateException(
"Failed to deserialize config: " + info.field(), e
);
}
setCache(iConfig);
return iConfig;
}
@@ -222,7 +233,15 @@ public class ConfigService extends BaseServiceImpl<ConfigMapper, RawConfig> {
else {
rawConfig.setUpdateTime(LocalDateTime.now());
}
rawConfig.setConfigValue(JSONObject.toJSONString(iConfig));
try {
rawConfig.setConfigValue(
objectMapper.writeValueAsString(iConfig)
);
} catch (JsonProcessingException e) {
throw new IllegalStateException(
"Failed to serialize config: " + info.field(), e
);
}
iConfig.beforeSaving();
if (saveOrUpdate(rawConfig)) {

View File

@@ -4,15 +4,13 @@ import java.text.DecimalFormat;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import com.alibaba.fastjson2.JSONObject;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import lombok.Getter;
@@ -25,6 +23,7 @@ import me.qwq.doghouse.entity.Post;
import me.qwq.doghouse.enums.CommentStatusEnum;
import me.qwq.doghouse.enums.PostStatusEnum;
import me.qwq.doghouse.enums.PostTypeEnum;
import me.qwq.doghouse.pojo.dto.DailyPostCommentStats;
import me.qwq.doghouse.service.post.PostService;
@Service
@@ -86,15 +85,24 @@ public class StatisticsService {
*/
@CacheEvictionTask
@Cacheable(value=CacheConstants.Statistics.DAILY_POST_AND_COMMENT_COUNTS)
public JSONObject getPostAndCommentCountsWithDates(Integer passDays, PostTypeEnum postType) {
JSONObject jo = new JSONObject();
Map<String, String> map = mapper.getPostAndCommentCountsWithDates(passDays, postType);
jo.put("dates", map.get("dates").split(","));
jo.put("postCounts", Arrays.asList(map.get("postCounts").split(",")).stream()
.map(s -> Integer.valueOf(s)).collect(Collectors.toList()));
jo.put("commentCounts", Arrays.asList(map.get("commentCounts").split(",")).stream()
.map(s -> Integer.valueOf(s)).collect(Collectors.toList()));
return jo;
public DailyPostCommentStats getPostAndCommentCountsWithDates(Integer passDays, PostTypeEnum postType) {
Map<String, String> map =
mapper.getPostAndCommentCountsWithDates(passDays, postType);
List<String> dates =
Arrays.asList(map.get("dates").split(","));
List<Integer> postCounts =
Arrays.stream(map.get("postCounts").split(","))
.map(Integer::valueOf)
.toList();
List<Integer> commentCounts =
Arrays.stream(map.get("commentCounts").split(","))
.map(Integer::valueOf)
.toList();
return new DailyPostCommentStats(dates, postCounts, commentCounts);
}
public PostStatistic getPostStatistic(Post post) {

View File

@@ -25,7 +25,8 @@ import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.stereotype.Service;
import org.springframework.util.function.ThrowingSupplier;
import com.alibaba.fastjson2.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import me.qwq.doghouse.config.DoghouseProperties;
@@ -43,6 +44,8 @@ public class ThemeService {
private volatile List<ThemeInfo> cachedThemes = Collections.emptyList();
private List<ThemeInfo> internalThemes = new ArrayList<>();
@Autowired
private ObjectMapper objectMapper;
@Autowired
DoghouseProperties doghouseProperties;
@@ -294,7 +297,7 @@ public class ThemeService {
*/
private ThemeInfo getThemeInfo(Resource config) throws IOException {
String json = config.getContentAsString(StandardCharsets.UTF_8);
ThemeInfo themeInfo = JSONObject.parseObject(json, ThemeInfo.class);
ThemeInfo themeInfo = objectMapper.readValue(json, ThemeInfo.class);
// uri: .../templates/blog/bleaching/config.json
// folderName: bleaching
@@ -331,7 +334,7 @@ public class ThemeService {
*/
private ThemeInfo getThemeInfo(Path configPath) throws IOException {
String json = Files.readString(configPath);
ThemeInfo themeInfo = JSONObject.parseObject(json, ThemeInfo.class);
ThemeInfo themeInfo = objectMapper.readValue(json, ThemeInfo.class);
Path path = configPath.getParent();
themeInfo.setDirectory(path.toString());

View File

@@ -13,10 +13,11 @@ import me.qwq.doghouse.pojo.dto.LayPageReq;
import me.qwq.doghouse.util.CookieUtils;
import me.qwq.doghouse.util.SessionUtils;
import com.alibaba.fastjson2.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.github.yulichang.wrapper.enums.DefaultFuncEnum;
@@ -669,8 +670,10 @@ public class WikiService extends AbstractPostService<WikiService, WikiConfig> {
Cookie cookie = CookieUtils.getCookie(request, UNFOLDED_WIKIS);
if (cookie == null) new ArrayList<>();
try {
JSONArray ja = JSONArray.parse(cookie.getValue());
return ja.toJavaList(Long.class);
return new ObjectMapper().readValue(
cookie.getValue(),
new TypeReference<List<Long>>() {}
);
}
catch (Exception e) {
return null;

View File

@@ -0,0 +1,37 @@
package me.qwq.doghouse.util;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public final class DateUtils {
// 缓存 formatter行为接近 fastjson2
private static final Map<String, DateTimeFormatter> FORMATTER_CACHE =
new ConcurrentHashMap<>();
private DateUtils() {
}
/**
* 格式化 LocalDateTime
*
* @param dateTime LocalDateTime
* @param pattern 日期格式,如 yyyy-MM-dd HH:mm:ss
* @return 格式化后的字符串
*/
public static String format(LocalDateTime dateTime, String pattern) {
if (dateTime == null) {
return null;
}
if (pattern == null || pattern.isEmpty()) {
throw new IllegalArgumentException("pattern must not be null or empty");
}
DateTimeFormatter formatter =
FORMATTER_CACHE.computeIfAbsent(pattern, DateTimeFormatter::ofPattern);
return dateTime.format(formatter);
}
}

View File

@@ -1,70 +0,0 @@
package me.qwq.doghouse.util;
import java.io.*;
import java.nio.file.*;
import java.util.Base64;
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.StreamUtils;
public class ImageBase64Utils {
/**
* 从文件系统路径读取图片并转 base64
*/
public static String fromFileSystem(Path imagePath) throws IOException {
if (imagePath == null || !Files.exists(imagePath)) {
return null;
}
byte[] bytes = Files.readAllBytes(imagePath);
String mimeType = Files.probeContentType(imagePath);
return toDataUrl(bytes, mimeType);
}
/**
* 从 classpath 读取图片并转 base64支持 jar 内)
*/
public static String fromClasspath(String classpathLocation) throws IOException {
ClassPathResource resource = new ClassPathResource(classpathLocation);
if (!resource.exists()) {
return null;
}
byte[] bytes;
try (InputStream is = resource.getInputStream()) {
bytes = StreamUtils.copyToByteArray(is);
}
String mimeType = guessMimeType(classpathLocation);
return toDataUrl(bytes, mimeType);
}
/**
* 生成 data:image/...;base64,...
*/
private static String toDataUrl(byte[] bytes, String mimeType) {
if (bytes == null || bytes.length == 0) {
return null;
}
if (mimeType == null) {
mimeType = "image/png"; // 兜底
}
String base64 = Base64.getEncoder().encodeToString(bytes);
return "data:" + mimeType + ";base64," + base64;
}
/**
* 根据文件名猜测 MIME
*/
private static String guessMimeType(String filename) {
String lower = filename.toLowerCase();
if (lower.endsWith(".png")) return "image/png";
if (lower.endsWith(".jpg") || lower.endsWith(".jpeg")) return "image/jpeg";
if (lower.endsWith(".gif")) return "image/gif";
if (lower.endsWith(".webp")) return "image/webp";
return "image/png";
}
}

View File

@@ -0,0 +1,18 @@
package me.qwq.doghouse.util;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import me.qwq.doghouse.annotation.StaticAttribute;
@StaticAttribute
public final class JsonUtils {
private static final ObjectMapper MAPPER = new ObjectMapper();
public static String toJson(Object o) {
try {
return MAPPER.writeValueAsString(o);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
}

View File

@@ -80,7 +80,7 @@
<ul class="tags-ul">
<th:block th:each="tag, i : ${@metaService.listMetaCount(MetaTypeEnum.TAG, null)}">
<li
th:with="tagJson=${T(com.alibaba.fastjson2.JSONObject).toJSONString(tag)}"
th:with="tagJson=${JsonUtils.toJson(tag)}"
th:attr="mid=${tag.mid},tag=${tagJson}">
<a
th:href="@{${'/admin/v2/post/?tagId=' + tag.mid}}"