mirror of
https://gitee.com/dromara/easy-es.git
synced 2025-12-06 17:18:57 +08:00
Merge branch 'develop' of https://gitee.com/easy-es/easy-es into develop
This commit is contained in:
commit
9d95764196
@ -90,14 +90,14 @@ Easy-Es是一款简化ElasticSearch搜索引擎操作的开源框架,简化`CRUD
|
||||
**Maven:**
|
||||
``` xml
|
||||
<dependency>
|
||||
<groupId>com.github.xpc1024</groupId>
|
||||
<groupId>io.github.xpc1024</groupId>
|
||||
<artifactId>easy-es-boot-starter</artifactId>
|
||||
<version>Latest Version</version>
|
||||
</dependency>
|
||||
```
|
||||
**Gradle:**
|
||||
```groovy
|
||||
compile group: 'com.github.xpc1024', name: 'easy-es-boot-starter', version: 'Latest Version'
|
||||
compile group: 'io.github.xpc1024', name: 'easy-es-boot-starter', version: 'Latest Version'
|
||||
```
|
||||
|
||||
# 其他开源项目 | Other Project
|
||||
|
||||
@ -85,14 +85,14 @@ String indexName = "document";
|
||||
- Maven:
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>com.github.xpc1024</groupId>
|
||||
<groupId>io.github.xpc1024</groupId>
|
||||
<artifactId>easy-es-boot-starter</artifactId>
|
||||
<version>Latest Version</version>
|
||||
</dependency>
|
||||
```
|
||||
- Gradle
|
||||
```groovy
|
||||
compile group: 'com.github.xpc1024', name: 'easy-es-boot-starter', version: 'Latest Version'
|
||||
compile group: 'io.github.xpc1024', name: 'easy-es-boot-starter', version: 'Latest Version'
|
||||
```
|
||||
- Add mapper file extends BaseEsMapper interface
|
||||
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
package com.xpc.easyes.autoconfig.config;
|
||||
|
||||
import com.xpc.easyes.core.plugin.interceptor.Interceptor;
|
||||
import com.xpc.easyes.core.plugin.interceptor.InterceptorChain;
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
@ -51,4 +53,22 @@ public class EsConfigProperties {
|
||||
* 连接请求超时时间
|
||||
*/
|
||||
private Integer connectionRequestTimeout;
|
||||
/**
|
||||
* 拦截器链
|
||||
*/
|
||||
protected InterceptorChain interceptorChain;
|
||||
|
||||
public void initInterceptorChain(){
|
||||
if(interceptorChain == null){
|
||||
interceptorChain = new InterceptorChain();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加拦截器
|
||||
* @param interceptor
|
||||
*/
|
||||
public void addInterceptor(Interceptor interceptor) {
|
||||
interceptorChain.addInterceptor(interceptor);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,12 +1,18 @@
|
||||
package com.xpc.easyes.autoconfig.register;
|
||||
|
||||
import com.xpc.easyes.autoconfig.config.EsConfigProperties;
|
||||
import com.xpc.easyes.core.cache.BaseCache;
|
||||
import com.xpc.easyes.core.plugin.interceptor.Interceptor;
|
||||
import com.xpc.easyes.core.plugin.interceptor.InterceptorChain;
|
||||
import com.xpc.easyes.core.plugin.interceptor.Intercepts;
|
||||
import com.xpc.easyes.core.proxy.EsMapperProxy;
|
||||
import org.elasticsearch.client.RestHighLevelClient;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 代理类
|
||||
@ -19,6 +25,12 @@ public class MapperFactoryBean<T> implements FactoryBean<T> {
|
||||
@Autowired
|
||||
private RestHighLevelClient client;
|
||||
|
||||
@Autowired
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
@Autowired
|
||||
private EsConfigProperties esConfigProperties;
|
||||
|
||||
public MapperFactoryBean() {
|
||||
}
|
||||
|
||||
@ -30,7 +42,9 @@ public class MapperFactoryBean<T> implements FactoryBean<T> {
|
||||
public T getObject() throws Exception {
|
||||
EsMapperProxy<T> esMapperProxy = new EsMapperProxy<>(mapperInterface);
|
||||
BaseCache.initCache(mapperInterface, client);
|
||||
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[]{mapperInterface}, esMapperProxy);
|
||||
T t = (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[]{mapperInterface}, esMapperProxy);
|
||||
InterceptorChain interceptorChain = this.initInterceptorChain();
|
||||
return interceptorChain.pluginAll(t);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -42,4 +56,24 @@ public class MapperFactoryBean<T> implements FactoryBean<T> {
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
private InterceptorChain initInterceptorChain(){
|
||||
InterceptorChain interceptorChain = esConfigProperties.getInterceptorChain();
|
||||
if(interceptorChain == null){
|
||||
synchronized (this){
|
||||
esConfigProperties.initInterceptorChain();
|
||||
Map<String, Object> beansWithAnnotation = this.applicationContext.getBeansWithAnnotation(Intercepts.class);
|
||||
if(beansWithAnnotation != null){
|
||||
beansWithAnnotation.forEach((key, val) ->{
|
||||
if(val instanceof Interceptor){
|
||||
Interceptor interceptor = (Interceptor) val;
|
||||
esConfigProperties.addInterceptor(interceptor);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return esConfigProperties.getInterceptorChain();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,25 @@
|
||||
package com.xpc.easyes.core.plugin.interceptor;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Interceptor
|
||||
* </p>
|
||||
*
|
||||
* @author lilu
|
||||
* @since 2022/3/4
|
||||
*/
|
||||
public interface Interceptor {
|
||||
|
||||
Object intercept(Invocation invocation) throws Throwable;
|
||||
|
||||
/**
|
||||
* 代理
|
||||
*
|
||||
* @param t 泛型
|
||||
* @return 泛型
|
||||
*/
|
||||
default <T> T plugin(T t) {
|
||||
return Plugin.wrap(t, this);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,53 @@
|
||||
package com.xpc.easyes.core.plugin.interceptor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 拦截器链
|
||||
* </p>
|
||||
*
|
||||
* @author lilu
|
||||
* @since 2022/3/4
|
||||
*/
|
||||
public class InterceptorChain {
|
||||
|
||||
/**
|
||||
* 拦截器集合
|
||||
*/
|
||||
private final List<Interceptor> interceptors = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* 装载拦截器
|
||||
*
|
||||
* @param t 泛型
|
||||
* @return 泛型
|
||||
*/
|
||||
public <T> T pluginAll(T t) {
|
||||
for (Interceptor interceptor : interceptors) {
|
||||
t = interceptor.plugin(t);
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加拦截器
|
||||
*
|
||||
* @param interceptor
|
||||
*/
|
||||
public void addInterceptor(Interceptor interceptor) {
|
||||
interceptors.add(interceptor);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取所有拦截器
|
||||
*
|
||||
* @return 拦截器集合
|
||||
*/
|
||||
public List<Interceptor> getInterceptors() {
|
||||
return Collections.unmodifiableList(interceptors);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
package com.xpc.easyes.core.plugin.interceptor;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 拦截器
|
||||
* </p>
|
||||
*
|
||||
* @author lilu
|
||||
* @since 2022/3/4
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface Intercepts {
|
||||
|
||||
Signature[] value();
|
||||
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
package com.xpc.easyes.core.plugin.interceptor;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 执行器
|
||||
* </p>
|
||||
*
|
||||
* @author lilu
|
||||
* @since 2022/3/4
|
||||
*/
|
||||
public class Invocation {
|
||||
|
||||
private final Object target;
|
||||
private final Method method;
|
||||
private final Object[] args;
|
||||
|
||||
public Invocation(Object target, Method method, Object[] args) {
|
||||
this.target = target;
|
||||
this.method = method;
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
public Object getTarget() {
|
||||
return target;
|
||||
}
|
||||
|
||||
public Method getMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
public Object[] getArgs() {
|
||||
return args;
|
||||
}
|
||||
|
||||
public Object proceed() throws InvocationTargetException, IllegalAccessException {
|
||||
return method.invoke(target, args);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,84 @@
|
||||
package com.xpc.easyes.core.plugin.interceptor;
|
||||
|
||||
|
||||
import com.xpc.easyes.core.exception.EasyEsException;
|
||||
import com.xpc.easyes.core.utils.ExceptionUtil;
|
||||
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 插件代理
|
||||
* </p>
|
||||
*
|
||||
* @author lilu
|
||||
* @since 2022/3/4
|
||||
*/
|
||||
public class Plugin implements InvocationHandler {
|
||||
|
||||
private final Object target;
|
||||
private final Interceptor interceptor;
|
||||
private final Map<Class<?>, Set<Method>> signatureMap;
|
||||
|
||||
private Plugin(Object target, Interceptor interceptor, Map<Class<?>, Set<Method>> signatureMap) {
|
||||
this.target = target;
|
||||
this.interceptor = interceptor;
|
||||
this.signatureMap = signatureMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 包装代理
|
||||
*
|
||||
* @param t 泛型
|
||||
* @param interceptor 拦截器
|
||||
* @return 泛型
|
||||
*/
|
||||
public static <T> T wrap(T t, Interceptor interceptor) {
|
||||
Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);
|
||||
return (T) Proxy.newProxyInstance(
|
||||
t.getClass().getClassLoader(),
|
||||
t.getClass().getInterfaces(),
|
||||
new Plugin(t, interceptor, signatureMap));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
try {
|
||||
Set<Method> methods = signatureMap.get(method.getDeclaringClass());
|
||||
if (methods != null && methods.contains(method)) {
|
||||
return interceptor.intercept(new Invocation(target, method, args));
|
||||
}
|
||||
return method.invoke(target, args);
|
||||
} catch (Exception e) {
|
||||
throw ExceptionUtil.unwrapThrowable(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static Map<Class<?>, Set<Method>> getSignatureMap(Interceptor interceptor) {
|
||||
Intercepts interceptsAnnotation = interceptor.getClass().getAnnotation(Intercepts.class);
|
||||
// 检查类是否被@Intercepts标记
|
||||
if (interceptsAnnotation == null) {
|
||||
throw new EasyEsException("No @Intercepts annotation was found in interceptor " + interceptor.getClass().getName());
|
||||
}
|
||||
Signature[] sigs = interceptsAnnotation.value();
|
||||
Map<Class<?>, Set<Method>> signatureMap = new HashMap<>();
|
||||
// 检查被@Signature标记的方法是否存在
|
||||
for (Signature sig : sigs) {
|
||||
Set<Method> methods = signatureMap.computeIfAbsent(sig.type(), k -> new HashSet<>());
|
||||
try {
|
||||
Method method = sig.type().getMethod(sig.method(), sig.args());
|
||||
methods.add(method);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new EasyEsException("Could not find method on " + sig.type() + " named " + sig.method() + ". Cause: " + e, e);
|
||||
}
|
||||
}
|
||||
return signatureMap;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
package com.xpc.easyes.core.plugin.interceptor;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 签名定义
|
||||
* </p>
|
||||
*
|
||||
* @author lilu
|
||||
* @since 2022/3/4
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({})
|
||||
public @interface Signature {
|
||||
|
||||
/**
|
||||
* Returns the java type.
|
||||
*
|
||||
* @return the java type
|
||||
*/
|
||||
Class<?> type();
|
||||
|
||||
/**
|
||||
* Returns the method name.
|
||||
*
|
||||
* @return the method name
|
||||
*/
|
||||
String method();
|
||||
|
||||
/**
|
||||
* Returns java types for method argument.
|
||||
*
|
||||
* @return java types for method argument
|
||||
*/
|
||||
Class<?>[] args();
|
||||
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
package com.xpc.easyes.core.utils;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.UndeclaredThrowableException;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* ExceptionUtil
|
||||
* </p>
|
||||
*
|
||||
* @author lilu
|
||||
* @since 2022/3/4
|
||||
*/
|
||||
public class ExceptionUtil {
|
||||
|
||||
private ExceptionUtil() {
|
||||
// Prevent Instantiation
|
||||
}
|
||||
|
||||
public static Throwable unwrapThrowable(Throwable wrapped) {
|
||||
Throwable unwrapped = wrapped;
|
||||
while (true) {
|
||||
if (unwrapped instanceof InvocationTargetException) {
|
||||
unwrapped = ((InvocationTargetException) unwrapped).getTargetException();
|
||||
} else if (unwrapped instanceof UndeclaredThrowableException) {
|
||||
unwrapped = ((UndeclaredThrowableException) unwrapped).getUndeclaredThrowable();
|
||||
} else {
|
||||
return unwrapped;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,18 +1,23 @@
|
||||
package com.xpc.easyes.sample;
|
||||
|
||||
import com.xpc.easyes.autoconfig.annotation.EsMapperScan;
|
||||
import org.elasticsearch.client.RestHighLevelClient;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
|
||||
/**
|
||||
* 启动类
|
||||
* <p>
|
||||
* Copyright © 2021 xpc1024 All Rights Reserved
|
||||
**/
|
||||
@SpringBootApplication
|
||||
@SpringBootApplication(scanBasePackages = {"com.xpc.easyes"})
|
||||
@EsMapperScan("com.xpc.easyes.sample.mapper")
|
||||
public class EasyEsApplication {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(EasyEsApplication.class, args);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -17,6 +17,7 @@ import java.util.List;
|
||||
**/
|
||||
@RestController
|
||||
public class TestController {
|
||||
|
||||
@Resource
|
||||
private DocumentMapper documentMapper;
|
||||
|
||||
@ -36,4 +37,19 @@ public class TestController {
|
||||
return documentMapper.selectList(wrapper);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 演示根据title删除文章,同时会被 DeleteInterceptor 拦截,执行逻辑删除
|
||||
*
|
||||
* @param title
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/deleteDocumentByTitle")
|
||||
public Integer deleteDocumentByTitle(@RequestParam String title) {
|
||||
// 实际开发中会把这些逻辑写进service层 这里为了演示方便就不创建service层了
|
||||
LambdaEsQueryWrapper<Document> wrapper = new LambdaEsQueryWrapper<>();
|
||||
wrapper.eq(Document::getTitle, title);
|
||||
return documentMapper.delete(wrapper);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,21 @@
|
||||
package com.xpc.easyes.sample.entity;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* GeneralBean
|
||||
* </p>
|
||||
*
|
||||
* @author lilu
|
||||
* @since 2022/3/4
|
||||
*/
|
||||
@Data
|
||||
public class GeneralBean {
|
||||
|
||||
/**
|
||||
* 删除状态
|
||||
*/
|
||||
private Boolean existStatus;
|
||||
|
||||
}
|
||||
@ -0,0 +1,37 @@
|
||||
package com.xpc.easyes.sample.interceptor;
|
||||
|
||||
import com.xpc.easyes.core.conditions.LambdaEsQueryWrapper;
|
||||
import com.xpc.easyes.core.conditions.interfaces.BaseEsMapper;
|
||||
import com.xpc.easyes.core.plugin.interceptor.Interceptor;
|
||||
import com.xpc.easyes.core.plugin.interceptor.Intercepts;
|
||||
import com.xpc.easyes.core.plugin.interceptor.Invocation;
|
||||
import com.xpc.easyes.core.plugin.interceptor.Signature;
|
||||
import com.xpc.easyes.sample.entity.GeneralBean;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 统一逻辑删除拦截器 demo
|
||||
* </p>
|
||||
*
|
||||
* @author lilu
|
||||
* @since 2022/3/4
|
||||
*/
|
||||
@Intercepts(
|
||||
{
|
||||
// 只是个例子,如果要实现这个功能还需要拦截更多的方法
|
||||
@Signature(type = BaseEsMapper.class, method = "delete", args = {LambdaEsQueryWrapper.class}),
|
||||
}
|
||||
)
|
||||
@Component
|
||||
public class DeleteInterceptor implements Interceptor {
|
||||
|
||||
@Override
|
||||
public Object intercept(Invocation invocation) throws Throwable {
|
||||
// 统一逻辑删除拦截
|
||||
System.out.println("啊啊啊,我拦截到了删除,禁止删除");
|
||||
// 这里直接改为update
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
package com.xpc.easyes.sample.interceptor;
|
||||
|
||||
import com.xpc.easyes.core.conditions.LambdaEsQueryWrapper;
|
||||
import com.xpc.easyes.core.conditions.interfaces.BaseEsMapper;
|
||||
import com.xpc.easyes.core.plugin.interceptor.Interceptor;
|
||||
import com.xpc.easyes.core.plugin.interceptor.Intercepts;
|
||||
import com.xpc.easyes.core.plugin.interceptor.Invocation;
|
||||
import com.xpc.easyes.core.plugin.interceptor.Signature;
|
||||
import com.xpc.easyes.sample.entity.GeneralBean;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 统一查询拦截器 demo
|
||||
* </p>
|
||||
*
|
||||
* @author lilu
|
||||
* @since 2022/3/4
|
||||
*/
|
||||
@Intercepts(
|
||||
{
|
||||
@Signature(type = BaseEsMapper.class, method = "selectList", args = {LambdaEsQueryWrapper.class}),
|
||||
}
|
||||
)
|
||||
@Component
|
||||
public class QueryInterceptor implements Interceptor {
|
||||
|
||||
@Override
|
||||
public Object intercept(Invocation invocation) throws Throwable {
|
||||
System.out.println("啊啊啊,我拦截到了查询,统一增加查询条件");
|
||||
// 统一逻辑删除拦截
|
||||
Object[] args = invocation.getArgs();
|
||||
LambdaEsQueryWrapper<GeneralBean> arg = (LambdaEsQueryWrapper) args[0];
|
||||
arg.eq(GeneralBean::getExistStatus, true);
|
||||
return invocation.proceed();
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user