mirror of
https://github.com/blossom-editor/blossom.git
synced 2026-03-12 17:41:26 +08:00
(fixed & feat) 修复索引删除路径错误的问题, 修复事务导致的索引滞后问题。 新增支持spel表达式的自定义注解,用于索引维护,减少对业务代码侵入同时增加拓展性
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
package com.blossom.backend.base.search;
|
||||
|
||||
import com.blossom.backend.base.search.message.IndexMsgTypeEnum;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface EnableIndex {
|
||||
|
||||
/**
|
||||
* 索引操作类型, 默认值为追加
|
||||
* @return
|
||||
*/
|
||||
IndexMsgTypeEnum type();
|
||||
|
||||
/**
|
||||
* id字段表达式
|
||||
* @return
|
||||
*/
|
||||
String id();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
package com.blossom.backend.base.search;
|
||||
|
||||
import com.blossom.backend.base.auth.AuthContext;
|
||||
import com.blossom.backend.base.search.message.ArticleIndexMsg;
|
||||
import com.blossom.backend.base.search.message.IndexMsgTypeEnum;
|
||||
import com.blossom.backend.base.search.queue.IndexMsgQueue;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.aspectj.lang.Signature;
|
||||
import org.aspectj.lang.annotation.AfterReturning;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Pointcut;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.ExpressionParser;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
@Aspect
|
||||
@Component
|
||||
@Slf4j
|
||||
public class IndexAspect {
|
||||
|
||||
/**
|
||||
* 用于spl解析
|
||||
*/
|
||||
private static final LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();
|
||||
|
||||
@Pointcut("@annotation(com.blossom.backend.base.search.EnableIndex)")
|
||||
private void cutMethod(){
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 成功返回后调用该方法,维护索引。 使用after防止事务未提交导致的数据滞后
|
||||
*/
|
||||
@AfterReturning("cutMethod()")
|
||||
public void afterReturning(JoinPoint joinPoint) {
|
||||
// 此处进行索引处理, 降低索引维护代码侵入
|
||||
// 获取注解对象
|
||||
EnableIndex annotation = getAnnotation(joinPoint);
|
||||
if (annotation == null){
|
||||
// 记录问题, 并结束逻辑
|
||||
log.error("索引切面获取注解失败!");
|
||||
return;
|
||||
}
|
||||
|
||||
IndexMsgTypeEnum indexMsgTypeEnum = annotation.type();
|
||||
if (indexMsgTypeEnum == null){
|
||||
log.error("获取索引消息操作类型失败");
|
||||
return;
|
||||
}
|
||||
String idSpEL = annotation.id();
|
||||
if (!StringUtils.hasText(idSpEL)){
|
||||
log.error("获取id表达式失败");
|
||||
return;
|
||||
}
|
||||
Long customerId = parse(idSpEL, joinPoint, Long.class);
|
||||
if (customerId == null){
|
||||
return;
|
||||
}
|
||||
ArticleIndexMsg indexMsg = new ArticleIndexMsg(indexMsgTypeEnum, customerId, AuthContext.getUserId());
|
||||
try {
|
||||
IndexMsgQueue.add(indexMsg);
|
||||
} catch (InterruptedException e) {
|
||||
// 不抛出, 暂时先记录
|
||||
log.error("索引操作失败" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取method
|
||||
* @return method
|
||||
*/
|
||||
private Method getTargetMethod(JoinPoint joinPoint) {
|
||||
Signature signature = joinPoint.getSignature();
|
||||
MethodSignature methodSignature = (MethodSignature)signature;
|
||||
Method agentMethod = methodSignature.getMethod();
|
||||
try {
|
||||
return joinPoint.getTarget().getClass().getMethod(agentMethod.getName(),agentMethod.getParameterTypes());
|
||||
}catch (Exception e){
|
||||
// 只记录异常
|
||||
log.error("获取目标方法失败");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取注解声明对象
|
||||
* @param joinPoint
|
||||
* @return
|
||||
*/
|
||||
private EnableIndex getAnnotation(JoinPoint joinPoint){
|
||||
// 获取方法上的注解
|
||||
MethodSignature sign = (MethodSignature) joinPoint.getSignature();
|
||||
Method method = sign.getMethod();
|
||||
return method.getAnnotation(EnableIndex.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析SpEL表达式, 提供后续拓展的灵活性
|
||||
* @param spel
|
||||
* @param joinPoint
|
||||
* @param clazz
|
||||
* @return
|
||||
* @param <T>
|
||||
*/
|
||||
private <T> T parse(String spel, JoinPoint joinPoint, Class<T> clazz){
|
||||
ExpressionParser parser = new SpelExpressionParser();
|
||||
Method method = getTargetMethod(joinPoint);
|
||||
if (method == null){
|
||||
return null;
|
||||
}
|
||||
|
||||
String[] params = discoverer.getParameterNames(method);
|
||||
if (params == null || params.length == 0){
|
||||
log.error("获取参数列表失败");
|
||||
return null;
|
||||
}
|
||||
|
||||
Object[] args = joinPoint.getArgs();
|
||||
EvaluationContext context = new StandardEvaluationContext();
|
||||
for (int len = 0; len < params.length; len++) {
|
||||
context.setVariable(params[len], args[len]);
|
||||
}
|
||||
|
||||
Expression expression = parser.parseExpression(spel);
|
||||
return expression.getValue(context, clazz);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -21,7 +21,6 @@ import org.apache.lucene.store.FSDirectory;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
/**
|
||||
@@ -88,7 +87,7 @@ public class IndexMsgConsumer {
|
||||
}
|
||||
} else if (IndexMsgTypeEnum.DELETE.equals(indexMsg.getType())) {
|
||||
// 删除索引
|
||||
try (Directory directory = FSDirectory.open(new File(searchProperties.getPath()).toPath());
|
||||
try (Directory directory = FSDirectory.open(searchProperties.getUserIndexDirectory(userId));
|
||||
IndexWriter indexWriter = new IndexWriter(directory, new IndexWriterConfig(new StandardAnalyzer()));
|
||||
|
||||
) {
|
||||
|
||||
@@ -4,10 +4,8 @@ import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.blossom.backend.base.auth.AuthContext;
|
||||
import com.blossom.backend.base.search.message.ArticleIndexMsg;
|
||||
import com.blossom.backend.base.search.EnableIndex;
|
||||
import com.blossom.backend.base.search.message.IndexMsgTypeEnum;
|
||||
import com.blossom.backend.base.search.queue.IndexMsgQueue;
|
||||
import com.blossom.backend.server.article.TagEnum;
|
||||
import com.blossom.backend.server.article.draft.pojo.ArticleEntity;
|
||||
import com.blossom.backend.server.article.draft.pojo.ArticleQueryReq;
|
||||
@@ -151,16 +149,10 @@ public class ArticleService extends ServiceImpl<ArticleMapper, ArticleEntity> {
|
||||
/**
|
||||
* 新增
|
||||
*/
|
||||
@EnableIndex(type = IndexMsgTypeEnum.ADD, id = "#req.id")
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ArticleEntity insert(ArticleEntity req) {
|
||||
baseMapper.insert(req);
|
||||
ArticleIndexMsg articleIndexMsg = new ArticleIndexMsg(IndexMsgTypeEnum.ADD, req.getId(), AuthContext.getUserId());
|
||||
try {
|
||||
IndexMsgQueue.add(articleIndexMsg);
|
||||
} catch (InterruptedException e) {
|
||||
// 不抛出, 暂时先记录
|
||||
log.error("索引更新失败" + e.getMessage());
|
||||
}
|
||||
return req;
|
||||
}
|
||||
|
||||
@@ -168,17 +160,11 @@ public class ArticleService extends ServiceImpl<ArticleMapper, ArticleEntity> {
|
||||
* 修改
|
||||
* <p>该接口只能修改文章的基本信息, 正文及版本修改请使用 {@link ArticleService#updateContentById(ArticleEntity)}
|
||||
*/
|
||||
@EnableIndex(type = IndexMsgTypeEnum.ADD, id = "#req.id")
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Long update(ArticleEntity req) {
|
||||
XzException404.throwBy(req.getId() == null, "ID不得为空");
|
||||
baseMapper.updById(req);
|
||||
ArticleIndexMsg articleIndexMsg = new ArticleIndexMsg(IndexMsgTypeEnum.ADD, req.getId(),AuthContext.getUserId());
|
||||
try {
|
||||
IndexMsgQueue.add(articleIndexMsg);
|
||||
} catch (InterruptedException e) {
|
||||
// 不抛出, 暂时先记录
|
||||
log.error("索引更新失败" + e.getMessage());
|
||||
}
|
||||
return req.getId();
|
||||
}
|
||||
|
||||
@@ -187,6 +173,7 @@ public class ArticleService extends ServiceImpl<ArticleMapper, ArticleEntity> {
|
||||
*
|
||||
* @return 返回文章字数
|
||||
*/
|
||||
@EnableIndex(type = IndexMsgTypeEnum.ADD, id = "#req.id")
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Integer updateContentById(ArticleEntity req) {
|
||||
XzException404.throwBy(req.getId() == null, "ID不得为空");
|
||||
@@ -199,14 +186,6 @@ public class ArticleService extends ServiceImpl<ArticleMapper, ArticleEntity> {
|
||||
baseMapper.updContentById(req);
|
||||
referenceService.bind(req.getUserId(), req.getId(), req.getName(), req.getReferences());
|
||||
logService.insert(req.getId(), 0, req.getMarkdown());
|
||||
// 更新索引
|
||||
ArticleIndexMsg articleIndexMsg = new ArticleIndexMsg(IndexMsgTypeEnum.ADD, req.getId(), AuthContext.getUserId());
|
||||
try {
|
||||
IndexMsgQueue.add(articleIndexMsg);
|
||||
} catch (InterruptedException e) {
|
||||
// 不抛出, 暂时先记录
|
||||
log.error("索引更新失败" + e.getMessage());
|
||||
}
|
||||
return req.getWords();
|
||||
}
|
||||
|
||||
@@ -218,6 +197,7 @@ public class ArticleService extends ServiceImpl<ArticleMapper, ArticleEntity> {
|
||||
* @param id 文章ID
|
||||
* @since 1.10.0 删除时不校验文章内容, 被删除的文章会进入回收站, 可在回收站中查询
|
||||
*/
|
||||
@EnableIndex(type = IndexMsgTypeEnum.DELETE, id = "#id")
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void delete(Long id) {
|
||||
ArticleEntity article = selectById(id, false, true, true);
|
||||
@@ -235,14 +215,6 @@ public class ArticleService extends ServiceImpl<ArticleMapper, ArticleEntity> {
|
||||
referenceService.delete(id);
|
||||
// 删除访问记录
|
||||
viewService.delete(id);
|
||||
// 删除索引
|
||||
ArticleIndexMsg articleIndexMsg = new ArticleIndexMsg(IndexMsgTypeEnum.DELETE, id, AuthContext.getUserId());
|
||||
try {
|
||||
IndexMsgQueue.add(articleIndexMsg);
|
||||
} catch (InterruptedException e) {
|
||||
// 不抛出, 暂时先记录
|
||||
log.error("索引更新失败" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,13 +3,11 @@ package com.blossom.backend.server.article.recycle;
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.blossom.backend.base.auth.AuthContext;
|
||||
import com.blossom.backend.base.param.ParamEnum;
|
||||
import com.blossom.backend.base.param.ParamService;
|
||||
import com.blossom.backend.base.param.pojo.ParamEntity;
|
||||
import com.blossom.backend.base.search.message.ArticleIndexMsg;
|
||||
import com.blossom.backend.base.search.EnableIndex;
|
||||
import com.blossom.backend.base.search.message.IndexMsgTypeEnum;
|
||||
import com.blossom.backend.base.search.queue.IndexMsgQueue;
|
||||
import com.blossom.backend.server.article.recycle.pojo.ArticleRecycleEntity;
|
||||
import com.blossom.backend.server.folder.FolderService;
|
||||
import com.blossom.backend.server.folder.pojo.FolderEntity;
|
||||
@@ -52,6 +50,7 @@ public class ArticleRecycleService extends ServiceImpl<ArticleRecycleMapper, Art
|
||||
*
|
||||
* @param id 文章ID
|
||||
*/
|
||||
@EnableIndex(type = IndexMsgTypeEnum.ADD, id = "#id")
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void restore(Long id) {
|
||||
ArticleRecycleEntity article = baseMapper.selectById(id);
|
||||
@@ -62,13 +61,6 @@ public class ArticleRecycleService extends ServiceImpl<ArticleRecycleMapper, Art
|
||||
baseMapper.restore(id, folder.getId());
|
||||
}
|
||||
baseMapper.deleteById(id);
|
||||
ArticleIndexMsg articleIndexMsg = new ArticleIndexMsg(IndexMsgTypeEnum.ADD, article.getId(), AuthContext.getUserId());
|
||||
try {
|
||||
IndexMsgQueue.add(articleIndexMsg);
|
||||
} catch (InterruptedException e) {
|
||||
// 不抛出, 暂时先记录
|
||||
log.error("索引更新失败" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user