mirror of https://github.com/halo-dev/halo
chore: remove useless code and dependencies. (#845)
* chore: remove useless code and dependencies. * Update build.gradlepull/832/head
parent
e7addd41f9
commit
ecc97c207f
|
@ -52,7 +52,7 @@ ext {
|
|||
upyunSdkVersion = "4.2.0"
|
||||
qiniuSdkVersion = "7.2.28"
|
||||
aliyunSdkVersion = "3.9.1"
|
||||
baiduSdkVersion = "0.10.106"
|
||||
baiduSdkVersion = "0.10.36"
|
||||
qcloudSdkVersion = "5.6.22"
|
||||
swaggerVersion = "2.9.2"
|
||||
commonsLangVersion = "3.10"
|
||||
|
@ -65,7 +65,6 @@ ext {
|
|||
flywayVersion = "6.4.1"
|
||||
h2Version = "1.4.196"
|
||||
levelDbVersion = "0.12"
|
||||
jsonVersion = "20190722"
|
||||
fastJsonVersion = "1.2.68"
|
||||
annotationsVersion = "3.0.1u2"
|
||||
jedisVersion= '3.3.0'
|
||||
|
@ -78,7 +77,6 @@ dependencies {
|
|||
implementation "org.springframework.boot:spring-boot-starter-data-jpa"
|
||||
implementation "org.springframework.boot:spring-boot-starter-web"
|
||||
implementation "org.springframework.boot:spring-boot-starter-undertow"
|
||||
implementation "redis.clients:jedis:$jedisVersion"
|
||||
implementation "org.springframework.boot:spring-boot-starter-freemarker"
|
||||
implementation "com.sun.mail:jakarta.mail"
|
||||
|
||||
|
@ -113,18 +111,17 @@ dependencies {
|
|||
implementation "com.vladsch.flexmark:flexmark-ext-superscript:$flexmarkVersion"
|
||||
implementation "com.vladsch.flexmark:flexmark-ext-yaml-front-matter:$flexmarkVersion"
|
||||
implementation "com.vladsch.flexmark:flexmark-ext-gitlab:$flexmarkVersion"
|
||||
// implementation "com.vladsch.flexmark:flexmark-html-parser:$flexmarkVersion"
|
||||
|
||||
implementation "net.coobird:thumbnailator:$thumbnailatorVersion"
|
||||
implementation "net.sf.image4j:image4j:$image4jVersion"
|
||||
implementation "org.flywaydb:flyway-core:$flywayVersion"
|
||||
|
||||
implementation "org.json:json:$jsonVersion"
|
||||
implementation "com.alibaba:fastjson:$fastJsonVersion"
|
||||
|
||||
implementation "com.google.zxing:core:$zxingVersion"
|
||||
|
||||
implementation "org.iq80.leveldb:leveldb:$levelDbVersion"
|
||||
implementation "redis.clients:jedis:$jedisVersion"
|
||||
runtimeOnly "com.h2database:h2:$h2Version"
|
||||
runtimeOnly "mysql:mysql-connector-java"
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package run.halo.app.model.annotation;
|
||||
package run.halo.app.annotation;
|
||||
|
||||
import org.springframework.core.annotation.AliasFor;
|
||||
import run.halo.app.model.enums.Mode;
|
|
@ -1,4 +1,4 @@
|
|||
package run.halo.app.handler.aspect;
|
||||
package run.halo.app.aspect;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
|
@ -6,9 +6,9 @@ import org.aspectj.lang.annotation.Around;
|
|||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Pointcut;
|
||||
import org.springframework.stereotype.Component;
|
||||
import run.halo.app.annotation.DisableOnCondition;
|
||||
import run.halo.app.config.properties.HaloProperties;
|
||||
import run.halo.app.exception.ForbiddenException;
|
||||
import run.halo.app.model.annotation.DisableOnCondition;
|
||||
import run.halo.app.model.enums.Mode;
|
||||
|
||||
/**
|
||||
|
@ -28,7 +28,7 @@ public class DisableOnConditionAspect {
|
|||
this.haloProperties = haloProperties;
|
||||
}
|
||||
|
||||
@Pointcut("@annotation(run.halo.app.model.annotation.DisableOnCondition)")
|
||||
@Pointcut("@annotation(run.halo.app.annotation.DisableOnCondition)")
|
||||
public void pointcut() {
|
||||
}
|
||||
|
|
@ -2,26 +2,24 @@ package run.halo.app.cache;
|
|||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
import redis.clients.jedis.HostAndPort;
|
||||
import redis.clients.jedis.JedisCluster;
|
||||
import redis.clients.jedis.JedisPoolConfig;
|
||||
import run.halo.app.config.properties.HaloProperties;
|
||||
import run.halo.app.utils.JsonUtils;
|
||||
|
||||
import javax.annotation.PreDestroy;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
import redis.clients.jedis.JedisCluster;
|
||||
import redis.clients.jedis.JedisPoolConfig;
|
||||
import redis.clients.jedis.HostAndPort;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
import java.util.Date;
|
||||
|
||||
import run.halo.app.config.properties.HaloProperties;
|
||||
import run.halo.app.utils.JsonUtils;
|
||||
|
||||
/**
|
||||
* Redis cache store.
|
||||
*
|
||||
|
@ -29,19 +27,22 @@ import run.halo.app.utils.JsonUtils;
|
|||
*/
|
||||
@Slf4j
|
||||
public class RedisCacheStore extends AbstractStringCacheStore {
|
||||
private volatile static JedisCluster REDIS;
|
||||
protected HaloProperties haloProperties;
|
||||
|
||||
/**
|
||||
* Cache container.
|
||||
*/
|
||||
private final static ConcurrentHashMap<String, CacheWrapper<String>> CACHE_CONTAINER = new ConcurrentHashMap<>();
|
||||
|
||||
private volatile static JedisCluster REDIS;
|
||||
protected HaloProperties haloProperties;
|
||||
/**
|
||||
* Lock.
|
||||
*/
|
||||
private Lock lock = new ReentrantLock();
|
||||
|
||||
public RedisCacheStore(HaloProperties haloProperties) {
|
||||
this.haloProperties = haloProperties;
|
||||
initRedis();
|
||||
}
|
||||
|
||||
private void initRedis() {
|
||||
JedisPoolConfig cfg = new JedisPoolConfig();
|
||||
cfg.setMaxIdle(2);
|
||||
|
@ -83,20 +84,16 @@ public class RedisCacheStore extends AbstractStringCacheStore {
|
|||
return REDIS;
|
||||
}
|
||||
|
||||
public RedisCacheStore(HaloProperties haloProperties) {
|
||||
this.haloProperties = haloProperties;
|
||||
initRedis();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
Optional<CacheWrapper<String>> getInternal(String key) {
|
||||
Optional<CacheWrapper<String>> getInternal(@NotNull String key) {
|
||||
Assert.hasText(key, "Cache key must not be blank");
|
||||
String v = REDIS.get(key);
|
||||
return StringUtils.isEmpty(v) ? Optional.empty() : jsonToCacheWrapper(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
void putInternal(String key, CacheWrapper<String> cacheWrapper) {
|
||||
void putInternal(@NotNull String key, @NotNull CacheWrapper<String> cacheWrapper) {
|
||||
putInternalIfAbsent(key, cacheWrapper);
|
||||
try {
|
||||
REDIS.set(key, JsonUtils.objectToJson(cacheWrapper));
|
||||
|
@ -110,7 +107,7 @@ public class RedisCacheStore extends AbstractStringCacheStore {
|
|||
}
|
||||
|
||||
@Override
|
||||
Boolean putInternalIfAbsent(String key, CacheWrapper<String> cacheWrapper) {
|
||||
Boolean putInternalIfAbsent(@NotNull String key, @NotNull CacheWrapper<String> cacheWrapper) {
|
||||
Assert.hasText(key, "Cache key must not be blank");
|
||||
Assert.notNull(cacheWrapper, "Cache wrapper must not be null");
|
||||
try {
|
||||
|
@ -131,7 +128,7 @@ public class RedisCacheStore extends AbstractStringCacheStore {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void delete(String key) {
|
||||
public void delete(@NotNull String key) {
|
||||
Assert.hasText(key, "Cache key must not be blank");
|
||||
REDIS.del(key);
|
||||
log.debug("Removed key: [{}]", key);
|
||||
|
|
|
@ -4,8 +4,8 @@ import lombok.Data;
|
|||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import run.halo.app.model.enums.Mode;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import static run.halo.app.model.support.HaloConst.*;
|
||||
import static run.halo.app.utils.HaloUtils.ensureSuffix;
|
||||
|
|
|
@ -5,8 +5,8 @@ import lombok.extern.slf4j.Slf4j;
|
|||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import run.halo.app.Application;
|
||||
import run.halo.app.annotation.DisableOnCondition;
|
||||
import run.halo.app.cache.lock.CacheLock;
|
||||
import run.halo.app.model.annotation.DisableOnCondition;
|
||||
import run.halo.app.model.dto.EnvironmentDTO;
|
||||
import run.halo.app.model.dto.LoginPreCheckDTO;
|
||||
import run.halo.app.model.dto.StatisticDTO;
|
||||
|
|
|
@ -8,8 +8,8 @@ import org.springframework.http.MediaType;
|
|||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import run.halo.app.annotation.DisableOnCondition;
|
||||
import run.halo.app.config.properties.HaloProperties;
|
||||
import run.halo.app.model.annotation.DisableOnCondition;
|
||||
import run.halo.app.model.dto.BackupDTO;
|
||||
import run.halo.app.model.dto.post.BasePostDetailDTO;
|
||||
import run.halo.app.service.BackupService;
|
||||
|
|
|
@ -5,8 +5,8 @@ import org.springframework.web.bind.annotation.PostMapping;
|
|||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import run.halo.app.annotation.DisableOnCondition;
|
||||
import run.halo.app.mail.MailService;
|
||||
import run.halo.app.model.annotation.DisableOnCondition;
|
||||
import run.halo.app.model.params.MailParam;
|
||||
import run.halo.app.model.support.BaseResponse;
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ import org.springframework.data.domain.Page;
|
|||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.web.PageableDefault;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import run.halo.app.model.annotation.DisableOnCondition;
|
||||
import run.halo.app.annotation.DisableOnCondition;
|
||||
import run.halo.app.model.dto.OptionDTO;
|
||||
import run.halo.app.model.dto.OptionSimpleDTO;
|
||||
import run.halo.app.model.entity.Option;
|
||||
|
|
|
@ -4,9 +4,9 @@ import io.swagger.annotations.ApiOperation;
|
|||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import run.halo.app.annotation.DisableOnCondition;
|
||||
import run.halo.app.handler.theme.config.support.Group;
|
||||
import run.halo.app.handler.theme.config.support.ThemeProperty;
|
||||
import run.halo.app.model.annotation.DisableOnCondition;
|
||||
import run.halo.app.model.params.ThemeContentParam;
|
||||
import run.halo.app.model.support.BaseResponse;
|
||||
import run.halo.app.model.support.ThemeFile;
|
||||
|
|
|
@ -5,9 +5,9 @@ import cn.hutool.core.util.StrUtil;
|
|||
import cn.hutool.extra.qrcode.QrCodeUtil;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import run.halo.app.annotation.DisableOnCondition;
|
||||
import run.halo.app.cache.lock.CacheLock;
|
||||
import run.halo.app.exception.BadRequestException;
|
||||
import run.halo.app.model.annotation.DisableOnCondition;
|
||||
import run.halo.app.model.dto.UserDTO;
|
||||
import run.halo.app.model.entity.User;
|
||||
import run.halo.app.model.enums.MFAType;
|
||||
|
@ -76,7 +76,7 @@ public class UserController {
|
|||
String mfaKey = TwoFactorAuthUtils.generateTFAKey();
|
||||
String optAuthUrl = TwoFactorAuthUtils.generateOtpAuthUrl(user.getNickname(), mfaKey);
|
||||
String qrImageBase64 = "data:image/png;base64," +
|
||||
Base64.encode(QrCodeUtil.generatePng(optAuthUrl, 128, 128));
|
||||
Base64.encode(QrCodeUtil.generatePng(optAuthUrl, 128, 128));
|
||||
return new MultiFactorAuthVO(qrImageBase64, optAuthUrl, mfaKey, MFAType.TFA_TOTP);
|
||||
} else {
|
||||
throw new BadRequestException("暂不支持的 MFA 认证的方式");
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
package run.halo.app.handler.migrate;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import run.halo.app.model.enums.MigrateType;
|
||||
|
||||
/**
|
||||
* Cnblogs(https://cnblogs.com) migrate handler.
|
||||
*
|
||||
* @author ryanwang
|
||||
* @date 2019-10-30
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class CnBlogsMigrateHandler implements MigrateHandler {
|
||||
|
||||
@Override
|
||||
public void migrate(MultipartFile file) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportType(MigrateType type) {
|
||||
return MigrateType.CNBLOGS.equals(type);
|
||||
}
|
||||
}
|
|
@ -1,693 +0,0 @@
|
|||
package run.halo.app.handler.migrate;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import run.halo.app.exception.ServiceException;
|
||||
import run.halo.app.model.entity.*;
|
||||
import run.halo.app.model.enums.AttachmentType;
|
||||
import run.halo.app.model.enums.CommentStatus;
|
||||
import run.halo.app.model.enums.MigrateType;
|
||||
import run.halo.app.model.enums.PostStatus;
|
||||
import run.halo.app.service.*;
|
||||
import run.halo.app.utils.BeanUtils;
|
||||
import run.halo.app.utils.JsonUtils;
|
||||
import run.halo.app.utils.ServiceUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Old version(0.4.4) migrate handler
|
||||
*
|
||||
* @author ryanwang
|
||||
* @author johnniang
|
||||
* @date 2019-10-28
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@SuppressWarnings("unchecked")
|
||||
public class OldVersionMigrateHandler implements MigrateHandler {
|
||||
|
||||
private final AttachmentService attachmentService;
|
||||
|
||||
private final PostService postService;
|
||||
|
||||
private final LinkService linkService;
|
||||
|
||||
private final MenuService menuService;
|
||||
|
||||
private final CategoryService categoryService;
|
||||
|
||||
private final TagService tagService;
|
||||
|
||||
private final PostCommentService postCommentService;
|
||||
|
||||
private final SheetCommentService sheetCommentService;
|
||||
|
||||
private final SheetService sheetService;
|
||||
|
||||
private final PhotoService photoService;
|
||||
|
||||
private final PostCategoryService postCategoryService;
|
||||
|
||||
private final PostTagService postTagService;
|
||||
|
||||
public OldVersionMigrateHandler(AttachmentService attachmentService,
|
||||
PostService postService,
|
||||
LinkService linkService,
|
||||
MenuService menuService,
|
||||
CategoryService categoryService,
|
||||
TagService tagService,
|
||||
PostCommentService postCommentService,
|
||||
SheetCommentService sheetCommentService,
|
||||
SheetService sheetService,
|
||||
PhotoService photoService,
|
||||
PostCategoryService postCategoryService,
|
||||
PostTagService postTagService) {
|
||||
this.attachmentService = attachmentService;
|
||||
this.postService = postService;
|
||||
this.linkService = linkService;
|
||||
this.menuService = menuService;
|
||||
this.categoryService = categoryService;
|
||||
this.tagService = tagService;
|
||||
this.postCommentService = postCommentService;
|
||||
this.sheetCommentService = sheetCommentService;
|
||||
this.sheetService = sheetService;
|
||||
this.photoService = photoService;
|
||||
this.postCategoryService = postCategoryService;
|
||||
this.postTagService = postTagService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void migrate(MultipartFile file) {
|
||||
// Get migration content
|
||||
try {
|
||||
String migrationContent = FileCopyUtils.copyToString(new InputStreamReader(file.getInputStream(), StandardCharsets.UTF_8));
|
||||
|
||||
Object migrationObject = JsonUtils.jsonToObject(migrationContent, Object.class);
|
||||
|
||||
if (migrationObject instanceof Map) {
|
||||
Map<String, Object> migrationMap = (Map<String, Object>) migrationObject;
|
||||
|
||||
// Handle attachments
|
||||
List<Attachment> attachments = handleAttachments(migrationMap.get("attachments"));
|
||||
|
||||
log.debug("Migrated attachments: [{}]", attachments);
|
||||
|
||||
// Handle links
|
||||
List<Link> links = handleLinks(migrationMap.get("links"));
|
||||
|
||||
log.debug("Migrated links: [{}]", links);
|
||||
|
||||
// Handle galleries
|
||||
List<Photo> photos = handleGalleries(migrationMap.get("galleries"));
|
||||
|
||||
log.debug("Migrated photos: [{}]", photos);
|
||||
|
||||
// Handle menus
|
||||
List<Menu> menus = handleMenus(migrationMap.get("menus"));
|
||||
|
||||
log.debug("Migrated menus: [{}]", menus);
|
||||
|
||||
// Handle posts
|
||||
List<BasePost> posts = handleBasePosts(migrationMap.get("posts"));
|
||||
|
||||
log.debug("Migrated posts: [{}]", posts);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new ServiceException("备份文件 " + file.getOriginalFilename() + " 读取失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@NonNull
|
||||
private List<BasePost> handleBasePosts(@Nullable Object postsObject) {
|
||||
if (!(postsObject instanceof List)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<Object> postObjectList = (List<Object>) postsObject;
|
||||
|
||||
List<BasePost> result = new LinkedList<>();
|
||||
|
||||
postObjectList.forEach(postObject -> {
|
||||
if (!(postObject instanceof Map)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Map<String, Object> postMap = (Map<String, Object>) postObject;
|
||||
|
||||
BasePost post = new BasePost();
|
||||
post.setTitle(postMap.getOrDefault("postTitle", "").toString());
|
||||
post.setSlug(postMap.getOrDefault("postUrl", "").toString());
|
||||
post.setOriginalContent(postMap.getOrDefault("postContentMd", "").toString());
|
||||
post.setFormatContent(postMap.getOrDefault("postContent", "").toString());
|
||||
post.setSummary(postMap.getOrDefault("postSummary", "").toString());
|
||||
post.setThumbnail(postMap.getOrDefault("postThumbnail", "").toString());
|
||||
post.setVisits(getLongOrDefault(postMap.getOrDefault("postViews", "").toString(), 0L));
|
||||
post.setDisallowComment(false);
|
||||
post.setTemplate(postMap.getOrDefault("customTpl", "").toString());
|
||||
|
||||
// Set disallow comment
|
||||
Integer allowComment = getIntegerOrDefault(postMap.getOrDefault("allowComment", "1").toString(), 1);
|
||||
if (allowComment != 1) {
|
||||
post.setDisallowComment(true);
|
||||
}
|
||||
|
||||
// Set create time
|
||||
Long createTime = getLongOrDefault(postMap.getOrDefault("postDate", "").toString(), 0L);
|
||||
if (createTime != 0L) {
|
||||
post.setCreateTime(new Date(createTime));
|
||||
}
|
||||
|
||||
// Set update time
|
||||
Long updateTime = getLongOrDefault(postMap.getOrDefault("postUpdate", "").toString(), 0L);
|
||||
if (updateTime != 0L) {
|
||||
post.setUpdateTime(new Date(updateTime));
|
||||
}
|
||||
|
||||
// Set status (default draft)
|
||||
Integer postStatus = getIntegerOrDefault(postMap.getOrDefault("postStatus", "").toString(), 1);
|
||||
if (postStatus == 0) {
|
||||
post.setStatus(PostStatus.PUBLISHED);
|
||||
} else if (postStatus == 1) {
|
||||
post.setStatus(PostStatus.DRAFT);
|
||||
} else {
|
||||
post.setStatus(PostStatus.RECYCLE);
|
||||
}
|
||||
|
||||
String postType = postMap.getOrDefault("postType", "post").toString();
|
||||
|
||||
try {
|
||||
if ("post".equalsIgnoreCase(postType)) {
|
||||
// Handle post
|
||||
result.add(handlePost(post, postMap));
|
||||
} else {
|
||||
// Handle page
|
||||
result.add(handleSheet(post, postMap));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("Failed to migrate a post or sheet", e);
|
||||
// Ignore this exception
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private Post handlePost(@NonNull BasePost basePost, @NonNull Map<String, Object> postMap) {
|
||||
Post post = BeanUtils.transformFrom(basePost, Post.class);
|
||||
|
||||
// Create it
|
||||
Post createdPost = postService.createOrUpdateBy(post);
|
||||
|
||||
Object commentsObject = postMap.get("comments");
|
||||
Object categoriesObject = postMap.get("categories");
|
||||
Object tagsObject = postMap.get("tags");
|
||||
// Handle comments
|
||||
List<BaseComment> baseComments = handleComment(commentsObject, createdPost.getId());
|
||||
|
||||
// Handle categories
|
||||
List<Category> categories = handleCategories(categoriesObject, createdPost.getId());
|
||||
|
||||
log.debug("Migrated categories of post [{}]: [{}]", categories, createdPost.getId());
|
||||
|
||||
// Handle tags
|
||||
List<Tag> tags = handleTags(tagsObject, createdPost.getId());
|
||||
|
||||
log.debug("Migrated tags of post [{}]: [{}]", tags, createdPost.getId());
|
||||
|
||||
List<PostComment> postComments = baseComments.stream()
|
||||
.map(baseComment -> BeanUtils.transformFrom(baseComment, PostComment.class))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
try {
|
||||
// Build virtual comment
|
||||
PostComment virtualPostComment = new PostComment();
|
||||
virtualPostComment.setId(0L);
|
||||
// Create comments
|
||||
createPostCommentRecursively(virtualPostComment, postComments);
|
||||
} catch (Exception e) {
|
||||
log.warn("Failed to create post comments for post with id " + createdPost.getId(), e);
|
||||
// Ignore this exception
|
||||
}
|
||||
|
||||
return createdPost;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private Sheet handleSheet(@NonNull BasePost basePost, @NonNull Map<String, Object> postMap) {
|
||||
Sheet sheet = BeanUtils.transformFrom(basePost, Sheet.class);
|
||||
|
||||
// Create it
|
||||
Sheet createdSheet = sheetService.createOrUpdateBy(sheet);
|
||||
|
||||
Object commentsObject = postMap.get("comments");
|
||||
// Handle comments
|
||||
List<BaseComment> baseComments = handleComment(commentsObject, createdSheet.getId());
|
||||
|
||||
List<SheetComment> sheetComments = baseComments.stream()
|
||||
.map(baseComment -> BeanUtils.transformFrom(baseComment, SheetComment.class))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// Create comments
|
||||
try {
|
||||
// Build virtual comment
|
||||
SheetComment virtualSheetComment = new SheetComment();
|
||||
virtualSheetComment.setId(0L);
|
||||
// Create comments
|
||||
createSheetCommentRecursively(virtualSheetComment, sheetComments);
|
||||
} catch (Exception e) {
|
||||
log.warn("Failed to create sheet comments for sheet with id " + createdSheet.getId(), e);
|
||||
// Ignore this exception
|
||||
}
|
||||
|
||||
return createdSheet;
|
||||
}
|
||||
|
||||
|
||||
private void createPostCommentRecursively(@NonNull final PostComment parentComment, List<PostComment> postComments) {
|
||||
Long oldParentId = parentComment.getId();
|
||||
|
||||
// Create parent
|
||||
if (!ServiceUtils.isEmptyId(parentComment.getId())) {
|
||||
PostComment createdComment = postCommentService.create(parentComment);
|
||||
log.debug("Created post comment: [{}]", createdComment);
|
||||
parentComment.setId(createdComment.getId());
|
||||
}
|
||||
|
||||
if (CollectionUtils.isEmpty(postComments)) {
|
||||
return;
|
||||
}
|
||||
// Get all children
|
||||
List<PostComment> children = postComments.stream()
|
||||
.filter(postComment -> Objects.equals(oldParentId, postComment.getParentId()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
|
||||
// Set parent id again
|
||||
children.forEach(postComment -> postComment.setParentId(parentComment.getId()));
|
||||
|
||||
// Remove children
|
||||
postComments.removeAll(children);
|
||||
|
||||
// Create children recursively
|
||||
children.forEach(childComment -> createPostCommentRecursively(childComment, postComments));
|
||||
}
|
||||
|
||||
private void createSheetCommentRecursively(@NonNull final SheetComment parentComment, List<SheetComment> sheetComments) {
|
||||
Long oldParentId = parentComment.getId();
|
||||
// Create parent
|
||||
if (!ServiceUtils.isEmptyId(parentComment.getId())) {
|
||||
SheetComment createComment = sheetCommentService.create(parentComment);
|
||||
parentComment.setId(createComment.getId());
|
||||
}
|
||||
|
||||
if (CollectionUtils.isEmpty(sheetComments)) {
|
||||
return;
|
||||
}
|
||||
// Get all children
|
||||
List<SheetComment> children = sheetComments.stream()
|
||||
.filter(sheetComment -> Objects.equals(oldParentId, sheetComment.getParentId()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// Set parent id again
|
||||
children.forEach(postComment -> postComment.setParentId(parentComment.getId()));
|
||||
|
||||
// Remove children
|
||||
sheetComments.removeAll(children);
|
||||
|
||||
// Create children recursively
|
||||
children.forEach(childComment -> createSheetCommentRecursively(childComment, sheetComments));
|
||||
}
|
||||
|
||||
private List<BaseComment> handleComment(@Nullable Object commentsObject, @NonNull Integer postId) {
|
||||
Assert.notNull(postId, "Post id must not be null");
|
||||
|
||||
if (!(commentsObject instanceof List)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<Object> commentObjectList = (List<Object>) commentsObject;
|
||||
|
||||
List<BaseComment> result = new LinkedList<>();
|
||||
|
||||
commentObjectList.forEach(commentObject -> {
|
||||
if (!(commentObject instanceof Map)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Map<String, Object> commentMap = (Map<String, Object>) commentObject;
|
||||
|
||||
BaseComment baseComment = new BaseComment();
|
||||
baseComment.setId(getLongOrDefault(commentMap.getOrDefault("commentId", "").toString(), null));
|
||||
baseComment.setAuthor(commentMap.getOrDefault("commentAuthor", "").toString());
|
||||
baseComment.setEmail(commentMap.getOrDefault("commentAuthorEmail", "").toString());
|
||||
baseComment.setIpAddress(commentMap.getOrDefault("commentAuthorIp", "").toString());
|
||||
baseComment.setAuthorUrl(commentMap.getOrDefault("commentAuthorUrl", "").toString());
|
||||
baseComment.setGravatarMd5(commentMap.getOrDefault("commentAuthorAvatarMd5", "").toString());
|
||||
baseComment.setContent(commentMap.getOrDefault("commentContent", "").toString());
|
||||
baseComment.setUserAgent(commentMap.getOrDefault("commentAgent", "").toString());
|
||||
baseComment.setIsAdmin(getBooleanOrDefault(commentMap.getOrDefault("isAdmin", "").toString(), false));
|
||||
baseComment.setPostId(postId);
|
||||
baseComment.setParentId(getLongOrDefault(commentMap.getOrDefault("commentParent", "").toString(), 0L));
|
||||
|
||||
// Set create date
|
||||
Long createTimestamp = getLongOrDefault(commentMap.getOrDefault("createDate", "").toString(), System.currentTimeMillis());
|
||||
baseComment.setCreateTime(new Date(createTimestamp));
|
||||
|
||||
Integer commentStatus = getIntegerOrDefault(commentMap.getOrDefault("commentStatus", "").toString(), 1);
|
||||
if (commentStatus == 0) {
|
||||
baseComment.setStatus(CommentStatus.PUBLISHED);
|
||||
} else if (commentStatus == 1) {
|
||||
baseComment.setStatus(CommentStatus.AUDITING);
|
||||
} else {
|
||||
baseComment.setStatus(CommentStatus.RECYCLE);
|
||||
}
|
||||
|
||||
result.add(baseComment);
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private List<Category> handleCategories(@Nullable Object categoriesObject, @NonNull Integer postId) {
|
||||
Assert.notNull(postId, "Post id must not be null");
|
||||
|
||||
if (!(categoriesObject instanceof List)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<Object> categoryObjectList = (List<Object>) categoriesObject;
|
||||
|
||||
List<Category> result = new LinkedList<>();
|
||||
|
||||
categoryObjectList.forEach(categoryObject -> {
|
||||
if (!(categoryObject instanceof Map)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Map<String, Object> categoryMap = (Map<String, Object>) categoryObject;
|
||||
|
||||
String slug = categoryMap.getOrDefault("cateUrl", "").toString();
|
||||
|
||||
Category category = categoryService.getBySlug(slug);
|
||||
|
||||
if (null == category) {
|
||||
category = new Category();
|
||||
category.setName(categoryMap.getOrDefault("cateName", "").toString());
|
||||
category.setSlug(slug);
|
||||
category.setDescription(categoryMap.getOrDefault("cateDesc", "").toString());
|
||||
category = categoryService.create(category);
|
||||
}
|
||||
|
||||
PostCategory postCategory = new PostCategory();
|
||||
postCategory.setCategoryId(category.getId());
|
||||
postCategory.setPostId(postId);
|
||||
postCategoryService.create(postCategory);
|
||||
|
||||
try {
|
||||
result.add(category);
|
||||
} catch (Exception e) {
|
||||
log.warn("Failed to migrate a category", e);
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private List<Tag> handleTags(@Nullable Object tagsObject, @NonNull Integer postId) {
|
||||
Assert.notNull(postId, "Post id must not be null");
|
||||
|
||||
if (!(tagsObject instanceof List)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<Object> tagObjectList = (List<Object>) tagsObject;
|
||||
|
||||
List<Tag> result = new LinkedList<>();
|
||||
|
||||
tagObjectList.forEach(tagObject -> {
|
||||
if (!(tagObject instanceof Map)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Map<String, Object> tagMap = (Map<String, Object>) tagObject;
|
||||
|
||||
String slug = tagMap.getOrDefault("tagUrl", "").toString();
|
||||
|
||||
Tag tag = tagService.getBySlug(slug);
|
||||
|
||||
if (null == tag) {
|
||||
tag = new Tag();
|
||||
tag.setName(tagMap.getOrDefault("tagName", "").toString());
|
||||
tag.setSlug(slug);
|
||||
tag = tagService.create(tag);
|
||||
}
|
||||
|
||||
PostTag postTag = new PostTag();
|
||||
postTag.setTagId(tag.getId());
|
||||
postTag.setPostId(postId);
|
||||
postTagService.create(postTag);
|
||||
|
||||
try {
|
||||
result.add(tag);
|
||||
} catch (Exception e) {
|
||||
log.warn("Failed to migrate a tag", e);
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private List<Menu> handleMenus(@Nullable Object menusObject) {
|
||||
if (!(menusObject instanceof List)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<Object> menuObjectList = (List<Object>) menusObject;
|
||||
|
||||
List<Menu> result = new LinkedList<>();
|
||||
|
||||
menuObjectList.forEach(menuObject -> {
|
||||
if (!(menuObject instanceof Map)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Map<String, Object> menuMap = (Map<String, Object>) menuObject;
|
||||
|
||||
Menu menu = new Menu();
|
||||
|
||||
menu.setName(menuMap.getOrDefault("menuName", "").toString());
|
||||
menu.setUrl(menuMap.getOrDefault("menuUrl", "").toString());
|
||||
// Set priority
|
||||
String sortString = menuMap.getOrDefault("menuSort", "0").toString();
|
||||
menu.setPriority(getIntegerOrDefault(sortString, 0));
|
||||
menu.setTarget(menuMap.getOrDefault("menuTarget", "_self").toString());
|
||||
menu.setIcon(menuMap.getOrDefault("menuIcon", "").toString());
|
||||
|
||||
try {
|
||||
// Create menu
|
||||
result.add(menuService.create(menu));
|
||||
} catch (Exception e) {
|
||||
log.warn("Failed to migrate a menu", e);
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private List<Photo> handleGalleries(@Nullable Object galleriesObject) {
|
||||
if (!(galleriesObject instanceof List)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<Object> galleryObjectList = (List<Object>) galleriesObject;
|
||||
|
||||
List<Photo> result = new LinkedList<>();
|
||||
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
|
||||
|
||||
galleryObjectList.forEach(galleryObject -> {
|
||||
if (!(galleriesObject instanceof Map)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Map<String, Object> galleryMap = (Map<String, Object>) galleryObject;
|
||||
|
||||
Photo photo = new Photo();
|
||||
photo.setName(galleryMap.getOrDefault("galleryName", "").toString());
|
||||
photo.setDescription(galleryMap.getOrDefault("galleryDesc", "").toString());
|
||||
photo.setLocation(galleryMap.getOrDefault("galleryLocation", "").toString());
|
||||
photo.setThumbnail(galleryMap.getOrDefault("galleryThumbnailUrl", "").toString());
|
||||
photo.setUrl(galleryMap.getOrDefault("galleryUrl", "").toString());
|
||||
|
||||
Object galleryDate = galleryMap.get("galleryDate");
|
||||
|
||||
try {
|
||||
if (galleryDate != null) {
|
||||
photo.setTakeTime(dateFormat.parse(galleryDate.toString()));
|
||||
}
|
||||
|
||||
// Create it
|
||||
result.add(photoService.create(photo));
|
||||
} catch (Exception e) {
|
||||
log.warn("Failed to create a photo", e);
|
||||
// Ignore this exception
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private List<Link> handleLinks(@Nullable Object linksObject) {
|
||||
if (!(linksObject instanceof List)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<Object> linkObjectList = (List<Object>) linksObject;
|
||||
|
||||
List<Link> result = new LinkedList<>();
|
||||
|
||||
linkObjectList.forEach(linkObject -> {
|
||||
if (!(linkObject instanceof Map)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Map<String, Object> linkMap = (Map<String, Object>) linkObject;
|
||||
|
||||
Link link = new Link();
|
||||
|
||||
link.setName(linkMap.getOrDefault("linkName", "").toString());
|
||||
link.setUrl(linkMap.getOrDefault("linkUrl", "").toString());
|
||||
link.setLogo(linkMap.getOrDefault("linkPic", "").toString());
|
||||
link.setDescription(linkMap.getOrDefault("linkDesc", "").toString());
|
||||
try {
|
||||
result.add(linkService.create(link));
|
||||
} catch (Exception e) {
|
||||
log.warn("Failed to migrate a link", e);
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private List<Attachment> handleAttachments(@Nullable Object attachmentsObject) {
|
||||
if (!(attachmentsObject instanceof List)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<Object> attachmentObjectList = (List<Object>) attachmentsObject;
|
||||
|
||||
List<Attachment> result = new LinkedList<>();
|
||||
|
||||
attachmentObjectList.forEach(attachmentObject -> {
|
||||
if (!(attachmentObject instanceof Map)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Map<String, Object> attachmentMap = (Map<String, Object>) attachmentObject;
|
||||
// Convert to attachment param
|
||||
Attachment attachment = new Attachment();
|
||||
|
||||
attachment.setName(attachmentMap.getOrDefault("attachName", "").toString());
|
||||
attachment.setPath(StringUtils.removeStart(attachmentMap.getOrDefault("attachPath", "").toString(), "/"));
|
||||
attachment.setThumbPath(attachmentMap.getOrDefault("attachSmallPath", "").toString());
|
||||
attachment.setMediaType(attachmentMap.getOrDefault("attachType", "").toString());
|
||||
attachment.setSuffix(StringUtils.removeStart(attachmentMap.getOrDefault("attachSuffix", "").toString(), "."));
|
||||
attachment.setSize(0L);
|
||||
|
||||
if (StringUtils.startsWith(attachment.getPath(), "/upload")) {
|
||||
// Set this key
|
||||
attachment.setFileKey(attachment.getPath());
|
||||
}
|
||||
|
||||
// Set location
|
||||
String attachLocation = attachmentMap.getOrDefault("attachLocation", "").toString();
|
||||
if (StringUtils.equalsIgnoreCase(attachLocation, "qiniu")) {
|
||||
attachment.setType(AttachmentType.QINIUOSS);
|
||||
} else if (StringUtils.equalsIgnoreCase(attachLocation, "upyun")) {
|
||||
attachment.setType(AttachmentType.UPOSS);
|
||||
} else {
|
||||
attachment.setType(AttachmentType.LOCAL);
|
||||
}
|
||||
|
||||
try {
|
||||
// Save to db
|
||||
Attachment createdAttachment = attachmentService.create(attachment);
|
||||
|
||||
result.add(createdAttachment);
|
||||
|
||||
} catch (Exception e) {
|
||||
// Ignore this exception
|
||||
log.warn("Failed to migrate an attachment " + attachment.getPath(), e);
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private Integer getIntegerOrDefault(@Nullable String numberString, @Nullable Integer defaultNumber) {
|
||||
try {
|
||||
return Integer.valueOf(numberString);
|
||||
} catch (Exception e) {
|
||||
// Ignore this exception
|
||||
return defaultNumber;
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private Long getLongOrDefault(@Nullable String numberString, @Nullable Long defaultNumber) {
|
||||
try {
|
||||
return Long.valueOf(numberString);
|
||||
} catch (Exception e) {
|
||||
// Ignore this exception
|
||||
return defaultNumber;
|
||||
}
|
||||
}
|
||||
|
||||
private Boolean getBooleanOrDefault(@Nullable String boolString, @Nullable Boolean defaultValue) {
|
||||
if (StringUtils.equalsIgnoreCase(boolString, "0")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (StringUtils.equalsIgnoreCase(boolString, "1")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (StringUtils.equalsIgnoreCase(boolString, "true")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (StringUtils.equalsIgnoreCase(boolString, "false")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportType(MigrateType type) {
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -1,106 +0,0 @@
|
|||
package run.halo.app.handler.migrate;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import run.halo.app.exception.ServiceException;
|
||||
import run.halo.app.handler.migrate.converter.Converter;
|
||||
import run.halo.app.handler.migrate.converter.WordPressConverter;
|
||||
import run.halo.app.handler.migrate.support.vo.PostVO;
|
||||
import run.halo.app.handler.migrate.support.wordpress.Rss;
|
||||
import run.halo.app.model.enums.MigrateType;
|
||||
import run.halo.app.service.*;
|
||||
import run.halo.app.utils.XmlMigrateUtils;
|
||||
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* WordPress migrate handler
|
||||
*
|
||||
* @author ryanwang
|
||||
* @author guqing
|
||||
* @date 2019-10-28
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@SuppressWarnings("unchecked")
|
||||
public class WordPressMigrateHandler implements MigrateHandler {
|
||||
|
||||
private final AttachmentService attachmentService;
|
||||
|
||||
private final PostService postService;
|
||||
|
||||
private final LinkService linkService;
|
||||
|
||||
private final MenuService menuService;
|
||||
|
||||
private final CategoryService categoryService;
|
||||
|
||||
private final TagService tagService;
|
||||
|
||||
private final PostCommentService postCommentService;
|
||||
|
||||
private final SheetCommentService sheetCommentService;
|
||||
|
||||
private final SheetService sheetService;
|
||||
|
||||
private final PhotoService photoService;
|
||||
|
||||
private final PostCategoryService postCategoryService;
|
||||
|
||||
private final PostTagService postTagService;
|
||||
|
||||
public WordPressMigrateHandler(AttachmentService attachmentService,
|
||||
PostService postService,
|
||||
LinkService linkService,
|
||||
MenuService menuService,
|
||||
CategoryService categoryService,
|
||||
TagService tagService,
|
||||
PostCommentService postCommentService,
|
||||
SheetCommentService sheetCommentService,
|
||||
SheetService sheetService,
|
||||
PhotoService photoService,
|
||||
PostCategoryService postCategoryService,
|
||||
PostTagService postTagService) {
|
||||
this.attachmentService = attachmentService;
|
||||
this.postService = postService;
|
||||
this.linkService = linkService;
|
||||
this.menuService = menuService;
|
||||
this.categoryService = categoryService;
|
||||
this.tagService = tagService;
|
||||
this.postCommentService = postCommentService;
|
||||
this.sheetCommentService = sheetCommentService;
|
||||
this.sheetService = sheetService;
|
||||
this.photoService = photoService;
|
||||
this.postCategoryService = postCategoryService;
|
||||
this.postTagService = postTagService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void migrate(MultipartFile file) {
|
||||
try {
|
||||
String migrationContent = FileCopyUtils.copyToString(new InputStreamReader(file.getInputStream(), StandardCharsets.UTF_8));
|
||||
String jsonString = XmlMigrateUtils.xml2jsonString(migrationContent);
|
||||
JSONObject json = JSONObject.parseObject(jsonString);
|
||||
Rss rss = json.getObject("rss", Rss.class);
|
||||
|
||||
// 转换
|
||||
Converter<Rss, List<PostVO>> converter = new WordPressConverter();
|
||||
|
||||
List<PostVO> postVoList = converter.convertFrom(rss);
|
||||
|
||||
log.debug("Migrated posts: [{}]", postVoList);
|
||||
} catch (Exception e) {
|
||||
throw new ServiceException("WordPress 入出文件 " + file.getOriginalFilename() + " 读取失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportType(MigrateType type) {
|
||||
return MigrateType.WORDPRESS.equals(type);
|
||||
}
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
package run.halo.app.handler.migrate.converter;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 博客迁移数据转换器,只定义从SOURCE转TARGET的单向转换
|
||||
*
|
||||
* @author guqing
|
||||
* @date 2020-01-18 16:45
|
||||
*/
|
||||
public interface Converter<SOURCE, TARGET> {
|
||||
|
||||
/**
|
||||
* 将source转换为target
|
||||
*
|
||||
* @param s 需要转换的源对象
|
||||
* @return 返回转换得到的结果对象
|
||||
*/
|
||||
TARGET convertFrom(SOURCE s);
|
||||
|
||||
/**
|
||||
* 从SOURCE转为TARGET
|
||||
*
|
||||
* @param s source,需要转换的原始SOURCE集合
|
||||
* @param function 具体转换逻辑
|
||||
* @return 返回转换得到的TARGET对象
|
||||
*/
|
||||
default TARGET convertFrom(SOURCE s, Function<SOURCE, TARGET> function) {
|
||||
return function.apply(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量从SOURCE转换得到TARGET
|
||||
*
|
||||
* @param list 需要转换的原始SOURCE集合
|
||||
* @param function 具体转换逻辑
|
||||
* @return 返回转换得到的TARGET集合结果
|
||||
*/
|
||||
default List<TARGET> batchConverterFromDto(List<SOURCE> list, Function<SOURCE, TARGET> function) {
|
||||
return list.stream().map(s -> convertFrom(s, function)).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
|
@ -1,138 +0,0 @@
|
|||
package run.halo.app.handler.migrate.converter;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import run.halo.app.handler.migrate.support.vo.PostVO;
|
||||
import run.halo.app.handler.migrate.support.wordpress.*;
|
||||
import run.halo.app.handler.migrate.utils.RelationMapperUtils;
|
||||
import run.halo.app.model.entity.BaseComment;
|
||||
import run.halo.app.model.entity.BasePost;
|
||||
import run.halo.app.model.entity.Category;
|
||||
import run.halo.app.model.entity.Tag;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* WordPress 博客数据迁移转换器
|
||||
*
|
||||
* @author guqing
|
||||
* @author ryanwang
|
||||
* @date 2020-01-18 16:50
|
||||
*/
|
||||
public class WordPressConverter implements Converter<Rss, List<PostVO>> {
|
||||
|
||||
@Override
|
||||
public List<PostVO> convertFrom(Rss rss) {
|
||||
return convertFrom(rss, this::apply);
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义转换规则
|
||||
*/
|
||||
public List<PostVO> apply(Rss rss) {
|
||||
if (Objects.isNull(rss) || Objects.isNull(rss.getChannel())) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
Channel channel = rss.getChannel();
|
||||
List<Item> items = channel.getItems();
|
||||
|
||||
if (items == null) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return getBasePost(items);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets post vo list from items.
|
||||
*
|
||||
* @param items wordpress items.
|
||||
* @return a list of post vo.
|
||||
*/
|
||||
private List<PostVO> getBasePost(List<Item> items) {
|
||||
List<PostVO> posts = new ArrayList<>();
|
||||
if (items == null) {
|
||||
return posts;
|
||||
}
|
||||
|
||||
for (Item item : items) {
|
||||
PostVO postVo = new PostVO();
|
||||
// 设置文章
|
||||
BasePost post = getBasePostFromItem(item);
|
||||
postVo.setBasePost(post);
|
||||
|
||||
// 获取标签和分类
|
||||
List<WpCategory> categories = item.getCategories();
|
||||
List<Category> categoryModelList = new ArrayList<>();
|
||||
List<Tag> tags = new ArrayList<>();
|
||||
if (categories != null) {
|
||||
categories.forEach(category -> {
|
||||
String domain = category.getDomain();
|
||||
if ("post_tag".equals(domain)) {
|
||||
Tag tag = RelationMapperUtils.convertFrom(category, Tag.class);
|
||||
tags.add(tag);
|
||||
} else if ("category".equals(domain)) {
|
||||
Category categoryModel = RelationMapperUtils.convertFrom(category, Category.class);
|
||||
categoryModelList.add(categoryModel);
|
||||
}
|
||||
});
|
||||
}
|
||||
// 设置标签和分类
|
||||
postVo.setCategories(categoryModelList);
|
||||
postVo.setTags(tags);
|
||||
|
||||
// 设置评论
|
||||
List<BaseComment> comments = getCommentsFromItem(item);
|
||||
postVo.setComments(comments);
|
||||
|
||||
posts.add(postVo);
|
||||
}
|
||||
|
||||
return posts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets item's comments.
|
||||
*
|
||||
* @param item wordpress item.
|
||||
* @return a list of baseComment.
|
||||
*/
|
||||
private List<BaseComment> getCommentsFromItem(Item item) {
|
||||
List<BaseComment> baseComments = new ArrayList<>();
|
||||
if (Objects.isNull(item) || Objects.isNull(item.getComments())) {
|
||||
return baseComments;
|
||||
}
|
||||
|
||||
List<Comment> comments = item.getComments();
|
||||
for (Comment comment : comments) {
|
||||
BaseComment baseComment = RelationMapperUtils.convertFrom(comment, BaseComment.class);
|
||||
Date commentDate = DateUtil.parseDateTime(comment.getCommentDate());
|
||||
baseComment.setCreateTime(commentDate);
|
||||
baseComment.setUpdateTime(commentDate);
|
||||
baseComments.add(baseComment);
|
||||
}
|
||||
|
||||
return baseComments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets base post from item.
|
||||
*
|
||||
* @param item wordpress item.
|
||||
* @return base post.
|
||||
*/
|
||||
private BasePost getBasePostFromItem(Item item) {
|
||||
BasePost post = RelationMapperUtils.convertFrom(item, BasePost.class);
|
||||
Date postDate = DateUtil.parseDateTime(item.getPostDate());
|
||||
if (StringUtils.isNoneEmpty(post.getFormatContent())) {
|
||||
post.setOriginalContent(post.getFormatContent());
|
||||
}
|
||||
post.setCreateTime(postDate);
|
||||
post.setUpdateTime(postDate);
|
||||
post.setEditTime(postDate);
|
||||
return post;
|
||||
}
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
package run.halo.app.handler.migrate.support.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import run.halo.app.model.entity.BaseComment;
|
||||
import run.halo.app.model.entity.BasePost;
|
||||
import run.halo.app.model.entity.Category;
|
||||
import run.halo.app.model.entity.Tag;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author guqing
|
||||
* @date 2020-01-18 16:52
|
||||
*/
|
||||
@Data
|
||||
public class PostVO {
|
||||
private BasePost basePost;
|
||||
private List<Tag> tags;
|
||||
private List<Category> categories;
|
||||
private List<BaseComment> comments;
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
package run.halo.app.handler.migrate.support.wordpress;
|
||||
|
||||
import com.alibaba.fastjson.annotation.JSONField;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* WordPress导出的xml中对应的channel节点下的子节点将被映射为该类的属性
|
||||
* </p>
|
||||
*
|
||||
* @author guqing
|
||||
* @date 2019-11-17 13:57
|
||||
*/
|
||||
@Data
|
||||
public class Channel {
|
||||
@JSONField(name = "title")
|
||||
private String title;
|
||||
private String link;
|
||||
private String description;
|
||||
private String pubDate;
|
||||
private String language;
|
||||
private String author;
|
||||
|
||||
@JSONField(name = "item")
|
||||
private List<Item> items;
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
package run.halo.app.handler.migrate.support.wordpress;
|
||||
|
||||
import com.alibaba.fastjson.annotation.JSONField;
|
||||
import lombok.Data;
|
||||
import run.halo.app.handler.migrate.utils.PropertyMappingTo;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* WordPress导出的xml中对于的comment节点下的子节点值将被映射为该类的属性,
|
||||
* 最终会被转换为{@link run.halo.app.model.entity.PostComment}
|
||||
* </p>
|
||||
*
|
||||
* @author guqing
|
||||
* @author ryanwang
|
||||
* @date 2019-11-17 14:01
|
||||
*/
|
||||
@Data
|
||||
public class Comment {
|
||||
|
||||
@JSONField(name = "wp:comment_id")
|
||||
@PropertyMappingTo("id")
|
||||
private String commentId;
|
||||
|
||||
@JSONField(name = "wp:comment_author")
|
||||
@PropertyMappingTo("author")
|
||||
private String commentAuthor;
|
||||
|
||||
@JSONField(name = "wp:comment_author_email")
|
||||
@PropertyMappingTo("email")
|
||||
private String commentAuthorEmail;
|
||||
|
||||
@JSONField(name = "wp:comment_author_url")
|
||||
@PropertyMappingTo("authorUrl")
|
||||
private String commentAuthorUrl;
|
||||
|
||||
@JSONField(name = "wp:comment_author_IP")
|
||||
@PropertyMappingTo("ipAddress")
|
||||
private String commentAuthorIp;
|
||||
|
||||
@JSONField(name = "wp:comment_date")
|
||||
private String commentDate;
|
||||
|
||||
@JSONField(name = "wp:comment_content")
|
||||
@PropertyMappingTo("content")
|
||||
private String commentContent;
|
||||
|
||||
@JSONField(name = "wp:comment_approved")
|
||||
private String commentApproved;
|
||||
|
||||
@JSONField(name = "wp:comment_parent")
|
||||
@PropertyMappingTo("parentId")
|
||||
private Long commentParent;
|
||||
|
||||
@JSONField(name = "wp:comment_user_id")
|
||||
private String commentUserId;
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
package run.halo.app.handler.migrate.support.wordpress;
|
||||
|
||||
import com.alibaba.fastjson.annotation.JSONField;
|
||||
import lombok.Data;
|
||||
import run.halo.app.handler.migrate.utils.PropertyMappingTo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p> WordPress导出的xml中对于的item子节点的值将会被映射到该类的属性上,最终被解析为文章属性{@link BasePost} </p>
|
||||
*
|
||||
* @author guqing
|
||||
* @author ryanwang
|
||||
* @date 2019-11-17 13:59
|
||||
*/
|
||||
@Data
|
||||
public class Item {
|
||||
|
||||
private String title;
|
||||
|
||||
private String pubDate;
|
||||
|
||||
private String description;
|
||||
|
||||
@JSONField(name = "content:encoded")
|
||||
@PropertyMappingTo("formatContent")
|
||||
private String content;
|
||||
|
||||
@JSONField(name = "excerpt:encoded")
|
||||
@PropertyMappingTo("summary")
|
||||
private String excerpt;
|
||||
|
||||
@JSONField(name = "wp:post_date")
|
||||
private String postDate;
|
||||
|
||||
@JSONField(name = "wp:comment_status")
|
||||
private String commentStatus;
|
||||
|
||||
@JSONField(name = "wp:post_name")
|
||||
@PropertyMappingTo("slug")
|
||||
private String postName;
|
||||
|
||||
@JSONField(name = "wp:status")
|
||||
private String status;
|
||||
|
||||
@JSONField(name = "wp:post_password")
|
||||
@PropertyMappingTo("password")
|
||||
private String postPassword;
|
||||
|
||||
@JSONField(name = "wp:is_sticky")
|
||||
@PropertyMappingTo("topPriority")
|
||||
private Integer isSticky;
|
||||
|
||||
@JSONField(name = "wp:comment")
|
||||
private List<Comment> comments;
|
||||
|
||||
@JSONField(name = "category")
|
||||
private List<WpCategory> categories;
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
package run.halo.app.handler.migrate.support.wordpress;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* WordPress导出的xml数据中对应的rss节点下的子节点channel将会被映射到该类属性
|
||||
* 如果不写这个Rss类包装想要的Channel,会无法解析到想要的结果
|
||||
*
|
||||
* @author guqing
|
||||
* @date 2020-01-17 00:45
|
||||
*/
|
||||
@Data
|
||||
public class Rss {
|
||||
private Channel channel;
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
package run.halo.app.handler.migrate.support.wordpress;
|
||||
|
||||
import lombok.Data;
|
||||
import run.halo.app.handler.migrate.utils.PropertyMappingTo;
|
||||
import run.halo.app.model.entity.PostCategory;
|
||||
|
||||
/**
|
||||
* WordPress导出的xml数据中对应的category的子节点将会被映射到该类属性,
|
||||
* 最终会被转换为文章分类{@link PostCategory}
|
||||
*
|
||||
* @author guqing
|
||||
* @date 2020-01-18 16:09
|
||||
*/
|
||||
@Data
|
||||
public class WpCategory {
|
||||
private String domain;
|
||||
|
||||
@PropertyMappingTo("slug")
|
||||
private String nicename;
|
||||
|
||||
@PropertyMappingTo("name")
|
||||
private String content;
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
package run.halo.app.handler.migrate.utils;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 该注解用于定义两个对象之间的属性映射关系
|
||||
*
|
||||
* @author guqing
|
||||
* @date 2020-1-19 13:51
|
||||
*/
|
||||
@Target(value = {ElementType.FIELD, ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface PropertyMappingTo {
|
||||
/**
|
||||
* value对应的是目标对象的属性名称
|
||||
*
|
||||
* @return 返回源对象属性对应的目标对象的属性名
|
||||
*/
|
||||
String value() default "";
|
||||
}
|
|
@ -1,128 +0,0 @@
|
|||
package run.halo.app.handler.migrate.utils;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 关系映射工具类,用于使用@PropertyMappingTo注解映射源对象与目标对象属性之间的关系
|
||||
*
|
||||
* @author guqing
|
||||
* @date 2020-01-19 01:47
|
||||
*/
|
||||
public class RelationMapperUtils {
|
||||
private RelationMapperUtils() {
|
||||
}
|
||||
|
||||
public static <SOURCE, TARGET> TARGET convertFrom(SOURCE source, Class<TARGET> targetClazz) {
|
||||
Map<String, Class> methodNameAndTypeMap = new HashMap<>(16);
|
||||
TARGET target;
|
||||
try {
|
||||
// 通过类的详情信息,创建目标对象 这一步等同于Hello target = new Hello();
|
||||
target = targetClazz.getConstructor().newInstance();
|
||||
Field[] targetFields = targetClazz.getDeclaredFields();
|
||||
for (Field field : targetFields) {
|
||||
methodNameAndTypeMap.put(field.getName(), field.getType());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("目标对象创建失败");
|
||||
}
|
||||
|
||||
return propertyMapper(source, target, methodNameAndTypeMap);
|
||||
}
|
||||
|
||||
private static <SOURCE, TARGET> TARGET propertyMapper(SOURCE source, TARGET target, Map<String, Class> methodNameAndTypeMap) {
|
||||
// 判断传入源数据是否为空,如果空,则抛自定义异常
|
||||
if (null == source) {
|
||||
throw new IllegalArgumentException("数据源不能为空");
|
||||
}
|
||||
// 获取源对象的类的详情信息
|
||||
Class<?> sourceClazz = source.getClass();
|
||||
// 获取源对象的所有属性
|
||||
Field[] sourceFields = sourceClazz.getDeclaredFields();
|
||||
|
||||
// 循环取到源对象的单个属性
|
||||
for (Field sourceField : sourceFields) {
|
||||
boolean sourceFieldHasAnnotation = sourceField.isAnnotationPresent(PropertyMappingTo.class);
|
||||
|
||||
String sourceFieldName = sourceField.getName();
|
||||
// 如果源对象没有添加注解则默认使用源对象属性名去寻找对于的目标对象属性名
|
||||
if (sourceFieldHasAnnotation) {
|
||||
PropertyMappingTo propertyMapping = sourceField.getAnnotation(PropertyMappingTo.class);
|
||||
String targetFieldName = propertyMapping.value();
|
||||
copyProperty(sourceFieldName, targetFieldName, source, target, sourceField.getType(), methodNameAndTypeMap);
|
||||
} else if (methodNameAndTypeMap.containsKey(sourceFieldName)) {
|
||||
// 如果源对象和目标对象的属性名相同则直接设置
|
||||
// 获取目标对象的属性名,将属性名首字母大写,拼接如:setUsername、setId的字符串
|
||||
// 判断源对象的属性名、属性类型是否和目标对象的属性名、属性类型一致
|
||||
copyProperty(sourceFieldName, sourceFieldName, source, target, sourceField.getType(), methodNameAndTypeMap);
|
||||
}
|
||||
}
|
||||
// 返回赋值得到的目标对象
|
||||
return target;
|
||||
}
|
||||
|
||||
private static <SOURCE, TARGET> void copyProperty(String sourceFieldName, String targetFieldName,
|
||||
SOURCE source, TARGET target, Class<?> sourceType,
|
||||
Map<String, Class> methodNameAndTypeMap) {
|
||||
try {
|
||||
Class<?> sourceClazz = source.getClass();
|
||||
Class<?> targetClazz = target.getClass();
|
||||
// 获取源对象的属性名,将属性名首字母大写,拼接如:getUsername、getId的字符串
|
||||
String sourceGetMethodName = getterName(sourceFieldName);
|
||||
// 获得属性的get方法
|
||||
Method sourceMethod = sourceClazz.getMethod(sourceGetMethodName);
|
||||
// 调用get方法
|
||||
Object sourceFieldValue = sourceMethod.invoke(source);
|
||||
|
||||
Class methodType = methodNameAndTypeMap.get(targetFieldName);
|
||||
// 通过字段名称得到set方法名称
|
||||
String targetSetMethodName = setterName(targetFieldName);
|
||||
if (methodType == sourceType) {
|
||||
// 调用方法,并将源对象get方法返回值作为参数传入
|
||||
Method targetSetMethod = targetClazz.getMethod(targetSetMethodName, sourceType);
|
||||
targetSetMethod.invoke(target, sourceFieldValue);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException("转换失败,请检查属性类型是否匹配");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过属性名称得到对于的get或set方法
|
||||
*
|
||||
* @param fieldName 属性名称
|
||||
* @param methodType 方法类型可选值为:get或set
|
||||
* @return 返回对象的get或set方法的名称
|
||||
*/
|
||||
private static String getMethodNameFromField(String fieldName, String methodType) {
|
||||
if (fieldName == null || fieldName.length() == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the second char is upper, make 'get' + field name as getter name. For example, eBlog -> getBlog
|
||||
*/
|
||||
if (fieldName.length() > 2) {
|
||||
String second = fieldName.substring(1, 2);
|
||||
if (second.equals(second.toUpperCase())) {
|
||||
return methodType + fieldName;
|
||||
}
|
||||
}
|
||||
|
||||
// Common situation
|
||||
fieldName = methodType + fieldName.substring(0, 1).toUpperCase() +
|
||||
fieldName.substring(1);
|
||||
return fieldName;
|
||||
}
|
||||
|
||||
private static String getterName(String fieldName) {
|
||||
return getMethodNameFromField(fieldName, "get");
|
||||
}
|
||||
|
||||
private static String setterName(String fieldName) {
|
||||
return getMethodNameFromField(fieldName, "set");
|
||||
}
|
||||
}
|
|
@ -24,12 +24,12 @@ public enum MFAType implements ValueEnum<Integer> {
|
|||
this.value = value;
|
||||
}
|
||||
|
||||
public static boolean useMFA(MFAType mfaType) {
|
||||
return mfaType != null && MFAType.NONE != mfaType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public static boolean useMFA(MFAType mfaType) {
|
||||
return mfaType != null && MFAType.NONE != mfaType;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -130,16 +130,14 @@ public class HaloConst {
|
|||
public final static String API_ACCESS_KEY_QUERY_NAME = "api_access_key";
|
||||
public final static String ONE_TIME_TOKEN_QUERY_NAME = "ott";
|
||||
public final static String ONE_TIME_TOKEN_HEADER_NAME = "ott";
|
||||
/**
|
||||
* Database product name.
|
||||
*/
|
||||
public static String DATABASE_PRODUCT_NAME = null;
|
||||
|
||||
/**
|
||||
* Version constant. (Available in production environment)
|
||||
*/
|
||||
public static final String HALO_VERSION;
|
||||
|
||||
/**
|
||||
* Database product name.
|
||||
*/
|
||||
public static String DATABASE_PRODUCT_NAME = null;
|
||||
/**
|
||||
* user_session
|
||||
*/
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
package run.halo.app.model.vo;
|
||||
|
||||
import lombok.*;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.ToString;
|
||||
import run.halo.app.model.enums.MFAType;
|
||||
|
||||
/**
|
||||
|
|
|
@ -55,14 +55,14 @@ public interface StaticStorageService {
|
|||
* Rename static file or folder.
|
||||
*
|
||||
* @param basePath base path must not be null
|
||||
* @param newName new name must not be null
|
||||
* @param newName new name must not be null
|
||||
*/
|
||||
void rename(@NonNull String basePath, @NonNull String newName);
|
||||
|
||||
/**
|
||||
* Save static file.
|
||||
*
|
||||
* @param path path must not be null
|
||||
* @param path path must not be null
|
||||
* @param content saved content
|
||||
*/
|
||||
void save(@NonNull String path, String content);
|
||||
|
|
|
@ -140,7 +140,7 @@ public class AdminServiceImpl implements AdminService {
|
|||
try {
|
||||
// Get user by username or email
|
||||
user = Validator.isEmail(username) ?
|
||||
userService.getByEmailOfNonNull(username) : userService.getByUsernameOfNonNull(username);
|
||||
userService.getByEmailOfNonNull(username) : userService.getByUsernameOfNonNull(username);
|
||||
} catch (NotFoundException e) {
|
||||
log.error("Failed to find user by name: " + username, e);
|
||||
eventPublisher.publishEvent(new LogEvent(this, loginParam.getUsername(), LogType.LOGIN_FAILED, loginParam.getUsername()));
|
||||
|
@ -163,7 +163,7 @@ public class AdminServiceImpl implements AdminService {
|
|||
@Override
|
||||
public AuthToken authCodeCheck(LoginParam loginParam) {
|
||||
// get user
|
||||
final User user = this.authenticate(loginParam);
|
||||
final User user = this.authenticate(loginParam);
|
||||
|
||||
// check authCode
|
||||
if (MFAType.useMFA(user.getMfaType())) {
|
||||
|
@ -322,14 +322,14 @@ public class AdminServiceImpl implements AdminService {
|
|||
Assert.hasText(refreshToken, "Refresh token must not be blank");
|
||||
|
||||
Integer userId = cacheStore.getAny(SecurityUtils.buildTokenRefreshKey(refreshToken), Integer.class)
|
||||
.orElseThrow(() -> new BadRequestException("登录状态已失效,请重新登录").setErrorData(refreshToken));
|
||||
.orElseThrow(() -> new BadRequestException("登录状态已失效,请重新登录").setErrorData(refreshToken));
|
||||
|
||||
// Get user info
|
||||
User user = userService.getById(userId);
|
||||
|
||||
// Remove all token
|
||||
cacheStore.getAny(SecurityUtils.buildAccessTokenKey(user), String.class)
|
||||
.ifPresent(accessToken -> cacheStore.delete(SecurityUtils.buildTokenAccessKey(accessToken)));
|
||||
.ifPresent(accessToken -> cacheStore.delete(SecurityUtils.buildTokenAccessKey(accessToken)));
|
||||
cacheStore.delete(SecurityUtils.buildTokenRefreshKey(refreshToken));
|
||||
cacheStore.delete(SecurityUtils.buildAccessTokenKey(user));
|
||||
cacheStore.delete(SecurityUtils.buildRefreshTokenKey(user));
|
||||
|
@ -344,8 +344,8 @@ public class AdminServiceImpl implements AdminService {
|
|||
ResponseEntity<Map> responseEntity = restTemplate.getForEntity(HaloConst.HALO_ADMIN_RELEASES_LATEST, Map.class);
|
||||
|
||||
if (responseEntity == null ||
|
||||
responseEntity.getStatusCode().isError() ||
|
||||
responseEntity.getBody() == null) {
|
||||
responseEntity.getStatusCode().isError() ||
|
||||
responseEntity.getBody() == null) {
|
||||
log.debug("Failed to request remote url: [{}]", HALO_ADMIN_RELEASES_LATEST);
|
||||
throw new ServiceException("系统无法访问到 Github 的 API").setErrorData(HALO_ADMIN_RELEASES_LATEST);
|
||||
}
|
||||
|
@ -359,17 +359,17 @@ public class AdminServiceImpl implements AdminService {
|
|||
try {
|
||||
List assets = (List) assetsObject;
|
||||
Map assetMap = (Map) assets.stream()
|
||||
.filter(assetPredicate())
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new ServiceException("Halo admin 最新版暂无资源文件,请稍后再试"));
|
||||
.filter(assetPredicate())
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new ServiceException("Halo admin 最新版暂无资源文件,请稍后再试"));
|
||||
|
||||
Object browserDownloadUrl = assetMap.getOrDefault("browser_download_url", "");
|
||||
// Download the assets
|
||||
ResponseEntity<byte[]> downloadResponseEntity = restTemplate.getForEntity(browserDownloadUrl.toString(), byte[].class);
|
||||
|
||||
if (downloadResponseEntity == null ||
|
||||
downloadResponseEntity.getStatusCode().isError() ||
|
||||
downloadResponseEntity.getBody() == null) {
|
||||
downloadResponseEntity.getStatusCode().isError() ||
|
||||
downloadResponseEntity.getBody() == null) {
|
||||
throw new ServiceException("Failed to request remote url: " + browserDownloadUrl.toString()).setErrorData(browserDownloadUrl.toString());
|
||||
}
|
||||
|
||||
|
@ -382,7 +382,7 @@ public class AdminServiceImpl implements AdminService {
|
|||
|
||||
// Create temp folder
|
||||
Path assetTempPath = FileUtils.createTempDirectory()
|
||||
.resolve(assetMap.getOrDefault("name", "halo-admin-latest.zip").toString());
|
||||
.resolve(assetMap.getOrDefault("name", "halo-admin-latest.zip").toString());
|
||||
|
||||
// Unzip
|
||||
FileUtils.unzip(downloadResponseEntity.getBody(), assetTempPath);
|
||||
|
@ -537,7 +537,7 @@ public class AdminServiceImpl implements AdminService {
|
|||
|
||||
linesArray.forEach(line -> {
|
||||
result.append(line)
|
||||
.append(StringUtils.LF);
|
||||
.append(StringUtils.LF);
|
||||
});
|
||||
|
||||
return result.toString();
|
||||
|
@ -550,7 +550,7 @@ public class AdminServiceImpl implements AdminService {
|
|||
boolean useMFA = true;
|
||||
try {
|
||||
final User user = Validator.isEmail(username) ?
|
||||
userService.getByEmailOfNonNull(username) : userService.getByUsernameOfNonNull(username);
|
||||
userService.getByEmailOfNonNull(username) : userService.getByUsernameOfNonNull(username);
|
||||
useMFA = MFAType.useMFA(user.getMfaType());
|
||||
} catch (NotFoundException e) {
|
||||
log.error("Failed to find user by name: " + username, e);
|
||||
|
|
|
@ -143,9 +143,9 @@ public class BackupServiceImpl implements BackupService {
|
|||
*/
|
||||
public static String sanitizeFilename(final String unSanitized) {
|
||||
return unSanitized.
|
||||
replaceAll("[^(a-zA-Z0-9\\u4e00-\\u9fa5\\.)]", "").
|
||||
replaceAll("[\\?\\\\/:|<>\\*\\[\\]\\(\\)\\$%\\{\\}@~\\.]", "").
|
||||
replaceAll("\\s", "");
|
||||
replaceAll("[^(a-zA-Z0-9\\u4e00-\\u9fa5\\.)]", "").
|
||||
replaceAll("[\\?\\\\/:|<>\\*\\[\\]\\(\\)\\$%\\{\\}@~\\.]", "").
|
||||
replaceAll("\\s", "");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -165,8 +165,8 @@ public class BackupServiceImpl implements BackupService {
|
|||
try {
|
||||
// Create zip path for halo zip
|
||||
String haloZipFileName = HaloConst.HALO_BACKUP_PREFIX +
|
||||
DateTimeUtils.format(LocalDateTime.now(), DateTimeUtils.HORIZONTAL_LINE_DATETIME_FORMATTER) +
|
||||
IdUtil.simpleUUID().hashCode() + ".zip";
|
||||
DateTimeUtils.format(LocalDateTime.now(), DateTimeUtils.HORIZONTAL_LINE_DATETIME_FORMATTER) +
|
||||
IdUtil.simpleUUID().hashCode() + ".zip";
|
||||
// Create halo zip file
|
||||
Path haloZipPath = Files.createFile(Paths.get(haloProperties.getBackupDir(), haloZipFileName));
|
||||
|
||||
|
@ -191,10 +191,10 @@ public class BackupServiceImpl implements BackupService {
|
|||
// Build backup dto
|
||||
try (Stream<Path> subPathStream = Files.list(backupParentPath)) {
|
||||
return subPathStream
|
||||
.filter(backupPath -> StringUtils.startsWithIgnoreCase(backupPath.getFileName().toString(), HaloConst.HALO_BACKUP_PREFIX))
|
||||
.map(backupPath -> buildBackupDto(BACKUP_RESOURCE_BASE_URI, backupPath))
|
||||
.sorted(Comparator.comparingLong(BackupDTO::getUpdateTime).reversed())
|
||||
.collect(Collectors.toList());
|
||||
.filter(backupPath -> StringUtils.startsWithIgnoreCase(backupPath.getFileName().toString(), HaloConst.HALO_BACKUP_PREFIX))
|
||||
.map(backupPath -> buildBackupDto(BACKUP_RESOURCE_BASE_URI, backupPath))
|
||||
.sorted(Comparator.comparingLong(BackupDTO::getUpdateTime).reversed())
|
||||
.collect(Collectors.toList());
|
||||
} catch (IOException e) {
|
||||
throw new ServiceException("Failed to fetch backups", e);
|
||||
}
|
||||
|
@ -285,8 +285,8 @@ public class BackupServiceImpl implements BackupService {
|
|||
|
||||
try {
|
||||
String haloDataFileName = HaloConst.HALO_DATA_EXPORT_PREFIX +
|
||||
DateTimeUtils.format(LocalDateTime.now(), DateTimeUtils.HORIZONTAL_LINE_DATETIME_FORMATTER) +
|
||||
IdUtil.simpleUUID().hashCode() + ".json";
|
||||
DateTimeUtils.format(LocalDateTime.now(), DateTimeUtils.HORIZONTAL_LINE_DATETIME_FORMATTER) +
|
||||
IdUtil.simpleUUID().hashCode() + ".json";
|
||||
|
||||
Path haloDataPath = Files.createFile(Paths.get(haloProperties.getDataExportDir(), haloDataFileName));
|
||||
|
||||
|
@ -309,10 +309,10 @@ public class BackupServiceImpl implements BackupService {
|
|||
|
||||
try (Stream<Path> subPathStream = Files.list(exportedDataParentPath)) {
|
||||
return subPathStream
|
||||
.filter(backupPath -> StringUtils.startsWithIgnoreCase(backupPath.getFileName().toString(), HaloConst.HALO_DATA_EXPORT_PREFIX))
|
||||
.map(backupPath -> buildBackupDto(DATA_EXPORT_BASE_URI, backupPath))
|
||||
.sorted(Comparator.comparingLong(BackupDTO::getUpdateTime).reversed())
|
||||
.collect(Collectors.toList());
|
||||
.filter(backupPath -> StringUtils.startsWithIgnoreCase(backupPath.getFileName().toString(), HaloConst.HALO_DATA_EXPORT_PREFIX))
|
||||
.map(backupPath -> buildBackupDto(DATA_EXPORT_BASE_URI, backupPath))
|
||||
.sorted(Comparator.comparingLong(BackupDTO::getUpdateTime).reversed())
|
||||
.collect(Collectors.toList());
|
||||
} catch (IOException e) {
|
||||
throw new ServiceException("Failed to fetch exported data", e);
|
||||
}
|
||||
|
@ -452,9 +452,9 @@ public class BackupServiceImpl implements BackupService {
|
|||
|
||||
// Build full url
|
||||
return HaloUtils.compositeHttpUrl(optionService.getBlogBaseUrl(), backupUri)
|
||||
+ "?"
|
||||
+ HaloConst.ONE_TIME_TOKEN_QUERY_NAME
|
||||
+ "=" + oneTimeToken;
|
||||
+ "?"
|
||||
+ HaloConst.ONE_TIME_TOKEN_QUERY_NAME
|
||||
+ "=" + oneTimeToken;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -59,10 +59,10 @@ public class CommentBlackListServiceImpl extends AbstractCrudService<CommentBlac
|
|||
return CommentViolationTypeEnum.FREQUENTLY;
|
||||
} else if (isPresent) {
|
||||
CommentBlackList commentBlackList = CommentBlackList
|
||||
.builder()
|
||||
.banTime(getBanTime(now, banTime))
|
||||
.ipAddress(ipAddress)
|
||||
.build();
|
||||
.builder()
|
||||
.banTime(getBanTime(now, banTime))
|
||||
.ipAddress(ipAddress)
|
||||
.build();
|
||||
super.create(commentBlackList);
|
||||
return CommentViolationTypeEnum.FREQUENTLY;
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ public class CommentBlackListServiceImpl extends AbstractCrudService<CommentBlac
|
|||
blackList.setBanTime(getBanTime(localDateTime, banTime));
|
||||
int updateResult = commentBlackListRepository.updateByIpAddress(blackList);
|
||||
Optional.of(updateResult)
|
||||
.filter(result -> result <= 0).ifPresent(result -> log.error("更新评论封禁时间失败"));
|
||||
.filter(result -> result <= 0).ifPresent(result -> log.error("更新评论封禁时间失败"));
|
||||
}
|
||||
|
||||
private Date getBanTime(LocalDateTime localDateTime, Integer banTime) {
|
||||
|
|
|
@ -168,8 +168,8 @@ public class StaticPageServiceImpl implements StaticPageService {
|
|||
public Path zipStaticPagesDirectory() {
|
||||
try {
|
||||
String staticPagePackName = HaloConst.STATIC_PAGE_PACK_PREFIX +
|
||||
DateTimeUtils.format(LocalDateTime.now(), DateTimeUtils.HORIZONTAL_LINE_DATETIME_FORMATTER) +
|
||||
IdUtil.simpleUUID().hashCode() + ".zip";
|
||||
DateTimeUtils.format(LocalDateTime.now(), DateTimeUtils.HORIZONTAL_LINE_DATETIME_FORMATTER) +
|
||||
IdUtil.simpleUUID().hashCode() + ".zip";
|
||||
Path staticPageZipPath = Files.createFile(Paths.get(STATIC_PAGE_PACK_DIR, staticPagePackName));
|
||||
|
||||
FileUtils.zip(pagesDir, staticPageZipPath);
|
||||
|
|
|
@ -22,7 +22,10 @@ import run.halo.app.utils.FileUtils;
|
|||
import javax.activation.MimetypesFileTypeMap;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.*;
|
||||
import java.nio.file.FileAlreadyExistsException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
|
|
@ -45,11 +45,11 @@ import java.nio.file.Files;
|
|||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.zip.ZipInputStream;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static run.halo.app.model.support.HaloConst.DEFAULT_THEME_ID;
|
||||
|
||||
|
@ -63,28 +63,20 @@ import static run.halo.app.model.support.HaloConst.DEFAULT_THEME_ID;
|
|||
@Service
|
||||
public class ThemeServiceImpl implements ThemeService {
|
||||
|
||||
/**
|
||||
* Theme work directory.
|
||||
*/
|
||||
private final Path themeWorkDir;
|
||||
|
||||
private final OptionService optionService;
|
||||
|
||||
private final AbstractStringCacheStore cacheStore;
|
||||
|
||||
private final ThemeConfigResolver themeConfigResolver;
|
||||
|
||||
private final ThemePropertyResolver themePropertyResolver;
|
||||
|
||||
private final RestTemplate restTemplate;
|
||||
|
||||
private final ApplicationEventPublisher eventPublisher;
|
||||
|
||||
/**
|
||||
* in seconds.
|
||||
*/
|
||||
protected static final long ACTIVATED_THEME_SYNC_INTERVAL = 5;
|
||||
|
||||
/**
|
||||
* Theme work directory.
|
||||
*/
|
||||
private final Path themeWorkDir;
|
||||
private final OptionService optionService;
|
||||
private final AbstractStringCacheStore cacheStore;
|
||||
private final ThemeConfigResolver themeConfigResolver;
|
||||
private final ThemePropertyResolver themePropertyResolver;
|
||||
private final RestTemplate restTemplate;
|
||||
private final ApplicationEventPublisher eventPublisher;
|
||||
/**
|
||||
* Activated theme id.
|
||||
*/
|
||||
|
|
|
@ -193,7 +193,7 @@ public class UserServiceImpl extends AbstractCrudService<User, Integer> implemen
|
|||
|
||||
@Override
|
||||
@NonNull
|
||||
public User updateMFA(@NonNull MFAType mfaType, String mfaKey,@NonNull Integer userId) {
|
||||
public User updateMFA(@NonNull MFAType mfaType, String mfaKey, @NonNull Integer userId) {
|
||||
Assert.notNull(mfaType, "MFA Type must not be null");
|
||||
|
||||
// get User
|
||||
|
|
|
@ -19,9 +19,9 @@ public class DateTimeUtils {
|
|||
* 标准日期格式 {@link DateTimeFormatter}:yyyyMMddHHmmssSSS
|
||||
*/
|
||||
public static final DateTimeFormatter PURE_DATETIME_MS_FORMATTER = new DateTimeFormatterBuilder()
|
||||
.appendPattern(PURE_DATETIME_PATTERN)
|
||||
.appendValue(ChronoField.MILLI_OF_SECOND, 3)
|
||||
.toFormatter();
|
||||
.appendPattern(PURE_DATETIME_PATTERN)
|
||||
.appendValue(ChronoField.MILLI_OF_SECOND, 3)
|
||||
.toFormatter();
|
||||
/**
|
||||
* 标准日期格式 {@link DateTimeFormatter}:yyyyMMdd
|
||||
*/
|
||||
|
|
|
@ -81,7 +81,7 @@ public class FileUtils {
|
|||
* Renames file or folder.
|
||||
*
|
||||
* @param pathToRename file path to rename must not be null
|
||||
* @param newName new name must not be null
|
||||
* @param newName new name must not be null
|
||||
*/
|
||||
public static void rename(@NonNull Path pathToRename, @NonNull String newName) throws IOException {
|
||||
Assert.notNull(pathToRename, "File path to rename must not be null");
|
||||
|
|
|
@ -82,13 +82,12 @@ class TimeBasedOneTimePasswordUtil {
|
|||
* default time-step which is part of the spec, 30 seconds is default
|
||||
*/
|
||||
public static final int DEFAULT_TIME_STEP_SECONDS = 30;
|
||||
private static final String BLOCK_OF_ZEROS;
|
||||
/**
|
||||
* set to the number of digits to control 0 prefix, set to 0 for no prefix
|
||||
*/
|
||||
private static int NUM_DIGITS_OUTPUT = 6;
|
||||
|
||||
private static final String BLOCK_OF_ZEROS;
|
||||
|
||||
static {
|
||||
char[] chars = new char[NUM_DIGITS_OUTPUT];
|
||||
Arrays.fill(chars, '0');
|
||||
|
@ -137,9 +136,9 @@ class TimeBasedOneTimePasswordUtil {
|
|||
* @return True if the authNumber matched the calculated number within the specified window.
|
||||
*/
|
||||
public static boolean validateCurrentNumber(String base32Secret, int authNumber, int windowMillis)
|
||||
throws GeneralSecurityException {
|
||||
throws GeneralSecurityException {
|
||||
return validateCurrentNumber(base32Secret, authNumber, windowMillis, System.currentTimeMillis(),
|
||||
DEFAULT_TIME_STEP_SECONDS);
|
||||
DEFAULT_TIME_STEP_SECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -196,7 +195,7 @@ class TimeBasedOneTimePasswordUtil {
|
|||
* output.
|
||||
*/
|
||||
public static String generateNumberString(String base32Secret, long timeMillis, int timeStepSeconds)
|
||||
throws GeneralSecurityException {
|
||||
throws GeneralSecurityException {
|
||||
int number = generateNumber(base32Secret, timeMillis, timeStepSeconds);
|
||||
return zeroPrepend(number, NUM_DIGITS_OUTPUT);
|
||||
}
|
||||
|
@ -216,7 +215,7 @@ class TimeBasedOneTimePasswordUtil {
|
|||
* @return A number which should match the user's authenticator application output.
|
||||
*/
|
||||
public static int generateNumber(String base32Secret, long timeMillis, int timeStepSeconds)
|
||||
throws GeneralSecurityException {
|
||||
throws GeneralSecurityException {
|
||||
|
||||
byte[] key = decodeBase32(base32Secret);
|
||||
|
||||
|
|
|
@ -1,142 +0,0 @@
|
|||
package run.halo.app.utils;
|
||||
|
||||
import org.dom4j.Document;
|
||||
import org.dom4j.Element;
|
||||
import org.dom4j.io.SAXReader;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author guqing
|
||||
* @date 2020-01-18 14:06
|
||||
*/
|
||||
public class WordPressMigrateUtils {
|
||||
/**
|
||||
* 存储在此集合中的节点名称都会被解析为一个List存储
|
||||
*/
|
||||
private static final List<String> ARRAY_PROPERTY = Arrays.asList("channel", "item", "wp:category", "wp:tag", "wp:term", "wp:postmeta", "wp:comment");
|
||||
|
||||
/**
|
||||
* 根据xml文件对象获取xml的根节点rootElement对象
|
||||
*
|
||||
* @param file xml的文件对象
|
||||
* @return 返回根节点元素
|
||||
*/
|
||||
public static Element getRootElement(File file) {
|
||||
try {
|
||||
SAXReader saxReader = new SAXReader();
|
||||
FileInputStream fileInputStream = new FileInputStream(file);
|
||||
Document document = saxReader.read(fileInputStream);
|
||||
|
||||
return document.getRootElement();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("can not get root element");
|
||||
}
|
||||
}
|
||||
|
||||
public static Element getRootElement(FileInputStream fileInputStream) {
|
||||
try {
|
||||
SAXReader saxReader = new SAXReader();
|
||||
Document document = saxReader.read(fileInputStream);
|
||||
saxReader.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
|
||||
return document.getRootElement();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("can not get root element");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 xml的 映射结果集对象
|
||||
*
|
||||
* @return 返回 xml 解析得到的 Map 映射结果集
|
||||
*/
|
||||
public static Map<String, Object> getResultSetMapping(File file) {
|
||||
Element rootElement = getRootElement(file);
|
||||
return getResultSetMapping(rootElement);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据根节点获取子节点元素集合递归遍历得到 Map 结果集
|
||||
*
|
||||
* @param root xml 的根节点元素对象
|
||||
* @return 返回解析 xml 得到的Map结果集
|
||||
*/
|
||||
public static Map<String, Object> getResultSetMapping(Element root) {
|
||||
Map<String, Object> result = new HashMap<String, Object>();
|
||||
|
||||
try {
|
||||
// 获取根元素的所有子元素
|
||||
List<Element> children = root.elements();
|
||||
|
||||
// 递归遍历将 xml 节点数据解析为 Map 结果集
|
||||
result = transfer2Map(children, null);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("can not transfer xml file to map." + e.getMessage());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归解析 xml,实现 N 层解析
|
||||
*
|
||||
* @param elements 所有子节点元素集,随着递归遍历而改变
|
||||
* @param list 存储中间遍历结果的容器
|
||||
* @return 返回递归完成后的Map结果集映射
|
||||
*/
|
||||
private static Map<String, Object> transfer2Map(List<Element> elements, List<Map<String, Object>> list) {
|
||||
Map<String, Object> map = new HashMap<String, Object>();
|
||||
|
||||
for (Element element : elements) {
|
||||
// getName 获取到的节点名称不带名称空间例如 <wp:content/> 获取到 name 为 content
|
||||
String nameWithoutPrefix = element.getName();
|
||||
|
||||
// 需要使用的真是 name 默认等于不带名称空间的,如果名称存在空间则 name 的形式为: 名称空间:名称
|
||||
String name = nameWithoutPrefix;
|
||||
String prefix = element.getNamespace().getPrefix();
|
||||
if (isNotBlack(prefix)) {
|
||||
name = prefix + ":" + nameWithoutPrefix;
|
||||
}
|
||||
|
||||
// 判断节点是否在定义的数组中,如果存在将其创建成 List 集合,否则作为文本
|
||||
if (ARRAY_PROPERTY.contains(name)) {
|
||||
//继续递归循环
|
||||
List<Map<String, Object>> sublist = new ArrayList<Map<String, Object>>();
|
||||
|
||||
Map<String, Object> subMap = transfer2Map(element.elements(), sublist);
|
||||
|
||||
// 根据 key 获取是否已经存在
|
||||
Object object = map.get(name);
|
||||
// 如果存在,合并
|
||||
if (object != null) {
|
||||
List<Map<String, Object>> olist = (List<Map<String, Object>>) object;
|
||||
olist.add(subMap);
|
||||
map.put(name, olist);
|
||||
} else {
|
||||
// 否则直接存入 map
|
||||
map.put(name, sublist);
|
||||
}
|
||||
} else {
|
||||
map.put(name, element.getTextTrim());
|
||||
}
|
||||
}
|
||||
|
||||
// 存入 list 中
|
||||
if (list != null) {
|
||||
list.add(map);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断字符串是否为空,如果是空串返回 {@code true},否则 {@code false}
|
||||
*
|
||||
* @param str 需要进行空串判断的字符串
|
||||
* @return 如果是空串返回 true, 否则返回 false
|
||||
*/
|
||||
private static boolean isNotBlack(String str) {
|
||||
return str != null && str.length() > 0 && str.trim().length() > 0;
|
||||
}
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
package run.halo.app.utils;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.json.XML;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* <p> 将xml解析为json </p>
|
||||
*
|
||||
* @author guqing
|
||||
* @author ryanwang
|
||||
* @date 2019-11-17 13:33
|
||||
*/
|
||||
public class XmlMigrateUtils {
|
||||
|
||||
/**
|
||||
* xml to json.
|
||||
*
|
||||
* @param in {@link java.io.FileInputStream}
|
||||
* @return json result
|
||||
* @throws JSONException throw JSONException
|
||||
* @throws IOException throw IOException
|
||||
*/
|
||||
public static String xml2jsonString(FileInputStream in) throws JSONException, IOException {
|
||||
String xml = IOUtils.toString(in, StandardCharsets.UTF_8);
|
||||
JSONObject jsonObject = XML.toJSONObject(xml);
|
||||
return jsonObject.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* xml to json.
|
||||
*
|
||||
* @param xml xml
|
||||
* @return json result
|
||||
*/
|
||||
public static String xml2jsonString(String xml) {
|
||||
JSONObject jsonObject = XML.toJSONObject(xml);
|
||||
return jsonObject.toString();
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package run.halo.app.handler.aspect;
|
||||
package run.halo.app.aspect;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
|
@ -3,7 +3,7 @@ package run.halo.app.controller;
|
|||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import run.halo.app.model.annotation.DisableOnCondition;
|
||||
import run.halo.app.annotation.DisableOnCondition;
|
||||
import run.halo.app.model.support.BaseResponse;
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,52 +0,0 @@
|
|||
package run.halo.app.utils;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.util.ResourceUtils;
|
||||
import run.halo.app.handler.migrate.converter.Converter;
|
||||
import run.halo.app.handler.migrate.converter.WordPressConverter;
|
||||
import run.halo.app.handler.migrate.support.vo.PostVO;
|
||||
import run.halo.app.handler.migrate.support.wordpress.Rss;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author guqing
|
||||
* @date 2020-01-18 14:02
|
||||
*/
|
||||
@Slf4j
|
||||
public class XmlMigrateUtilsTest {
|
||||
|
||||
@Test
|
||||
void testXmlMigrateUtils() throws IOException, URISyntaxException {
|
||||
JSONObject json = readXml();
|
||||
log.debug("WordPress blog json data:" + json);
|
||||
Rss rss = json.getObject("rss", Rss.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testWordPressConvert() throws IOException, URISyntaxException {
|
||||
JSONObject json = readXml();
|
||||
Rss rss = json.getObject("rss", Rss.class);
|
||||
Converter<Rss, List<PostVO>> converter = new WordPressConverter();
|
||||
List<PostVO> postVoList = converter.convertFrom(rss);
|
||||
|
||||
log.debug("{}", postVoList);
|
||||
}
|
||||
|
||||
private JSONObject readXml() throws IOException, URISyntaxException {
|
||||
URL migrationUrl = ResourceUtils.getURL(ResourceUtils.CLASSPATH_URL_PREFIX + "wordpressdemo.xml");
|
||||
URI wordpressUrl = migrationUrl.toURI();
|
||||
File file = new File(wordpressUrl);
|
||||
FileInputStream inputStream = new FileInputStream(file);
|
||||
String s = XmlMigrateUtils.xml2jsonString(inputStream);
|
||||
return JSONObject.parseObject(s);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue