----添加流程测试demo

This commit is contained in:
2025-12-02 10:21:46 +08:00
parent db1dd23743
commit a5b65b4f38
46 changed files with 2611 additions and 11 deletions

View File

@ -0,0 +1,29 @@
package com.pictc.config;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
import com.pictc.listener.PEventListenerPublisher;
import com.pictc.listener.TNacosManager;
@Configuration
public class PEventListenerConfig {
@Bean
public PEventListenerPublisher pEventListenerPublisher() {
return new PEventListenerPublisher();
}
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
@Bean
public TNacosManager nacosManager() {
return new TNacosManager();
}
}

View File

@ -0,0 +1,31 @@
package com.pictc.listener;
import java.io.Serializable;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class ListenerParameterContext implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
/**
* 发送源
*/
private String source;
/**
* 数据
*/
private Object data;
/**
* 单个监听器执行成功,就算成功
*/
private boolean single;
}

View File

@ -0,0 +1,27 @@
package com.pictc.listener;
import java.lang.reflect.Method;
import lombok.Data;
@Data
public class MethodInfo {
private Object bean;
private Method method;
private PEventListener annotation;
public MethodInfo(Object bean, Method method, PEventListener annotation) {
super();
this.bean = bean;
this.method = method;
this.annotation = annotation;
}
public Object invoke(Object[] args) throws Exception {
return method.invoke(bean, args);
}
}

View File

@ -0,0 +1,19 @@
package com.pictc.listener;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD) // 标注在方法上
@Retention(RetentionPolicy.RUNTIME) // 运行时保留,反射可获取
public @interface PEventListener {
/**
* EL表达式内容
*/
String value() default "";
}

View File

@ -0,0 +1,62 @@
package com.pictc.listener;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;
import com.pictc.utils.CollectionUtils;
import com.pictc.utils.ObjectUtils;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class PEventListenerPublisher {
private static RestTemplate rest;
@Autowired
public void setRest(RestTemplate rest) {
PEventListenerPublisher.rest = rest;
}
public static boolean publish(Object source,Object data) {
return publish(source, data, false);
}
public static boolean publish(Object source,Object data,boolean single) {
ListenerParameterContext conetext = new ListenerParameterContext();
conetext.setSource(TNacosManager.getAppName()+":"+source.getClass().getCanonicalName());
conetext.setData(data);
conetext.setSingle(single);
Set<String> services = TNacosManager.getNotSelfServices();
boolean flag = single?false:true;
if(CollectionUtils.isNotEmpty(services)) {
for (String serviceId : services) {
try {
URI uri = TNacosManager.getServiceURI(serviceId);
if(uri!=null) {
HttpHeaders headers = TNacosManager.createNewHeaders();
byte[] bytes = ObjectUtils.toBytes(conetext);
RequestEntity<byte[]> request = new RequestEntity<byte[]>(bytes,headers,HttpMethod.POST,uri);
ResponseEntity<Boolean> responseEntity = rest.exchange(request,boolean.class);
if(single && responseEntity.hasBody() && responseEntity.getBody()) {
return true;
}
}
} catch (URISyntaxException e) {
e.printStackTrace();
log.info("客户端:{}调用失败!",serviceId);
}
}
}
return flag;
}
}

View File

@ -0,0 +1,214 @@
package com.pictc.listener;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.http.HttpHeaders;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.NacosServiceManager;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.ListView;
import com.alibaba.nacos.client.naming.event.InstancesChangeEvent;
import com.alibaba.nacos.common.notify.Event;
import com.alibaba.nacos.common.notify.NotifyCenter;
import com.alibaba.nacos.common.notify.listener.Subscriber;
import com.pictc.utils.CollectionUtils;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Getter
public class TNacosManager extends Subscriber<InstancesChangeEvent> implements InitializingBean{
private static Set<String> services = CollectionUtils.newConcurrentSet();
private static Object lock = new Object();
private static NacosServiceManager nacosServiceManager;
private static NacosDiscoveryProperties properties;
private static NamingService nacos;
private static String appName;
private static String group;
private static LoadBalancerClient loadba;
@Autowired
public void setLoadbalancerClient(LoadBalancerClient loadbalancerClient) {
TNacosManager.loadba = loadbalancerClient;
}
@Value("${spring.application.name}")
public void setAppName(String appName) {
TNacosManager.appName = appName;
}
public static String getAppName() {
return appName;
}
public static boolean isSelf(String serviceId) {
return appName.equals(serviceId);
}
@Autowired
public void setNacosServiceManager(NacosServiceManager nacosServiceManager) {
TNacosManager.nacosServiceManager = nacosServiceManager;
}
@Autowired
public void setProperties(NacosDiscoveryProperties properties) {
TNacosManager.properties = properties;
}
public static Set<String> getServices() {
synchronized (lock) {
initServices();
return services;
}
}
public static Set<String> getNotSelfServices() {
return getServices().stream().filter(it->it.equals(appName)).collect(Collectors.toSet());
}
public static URI getServiceURI(String serviceId) throws URISyntaxException {
ServiceInstance instance = loadba.choose(serviceId);
if(instance==null) return null;
String url = instance.getUri().toString();
if(url.endsWith("/")) {
url = url.substring(0, url.length()-1);
}
return new URI(url+"/reception/listener");
}
public static HttpHeaders createNewHeaders() {
HttpHeaders source = getHeaders();
HttpHeaders headers = new HttpHeaders();
if(source!=null) {
for (String name : source.keySet()) {
if(HttpHeaders.CONTENT_TYPE.equalsIgnoreCase(name)
|| HttpHeaders.CONTENT_LENGTH.equalsIgnoreCase(name)
|| HttpHeaders.CONTENT_DISPOSITION.equalsIgnoreCase(name)
|| HttpHeaders.CONTENT_ENCODING.equalsIgnoreCase(name)
|| HttpHeaders.CONTENT_LANGUAGE.equalsIgnoreCase(name)
|| HttpHeaders.CONTENT_LOCATION.equalsIgnoreCase(name)
|| HttpHeaders.CONTENT_RANGE.equalsIgnoreCase(name)
) {
continue;
}
headers.addAll(name,source.get(name));
}
}
return headers;
}
@Override
public void afterPropertiesSet() throws Exception {
init();
NotifyCenter.registerSubscriber(this);
initServices();
}
@Override
public Class<? extends Event> subscribeType() {
return InstancesChangeEvent.class;
}
@Override
public void onEvent(InstancesChangeEvent event) {
String serviceName = event.getServiceName();
String split = Constants.SERVICE_INFO_SPLITER;
if (serviceName.contains(split)) {
serviceName = serviceName.substring(serviceName.indexOf(split) + split.length());
}
initServices();
}
private static void init() {
if(nacos==null) {
nacos = nacosServiceManager.getNamingService();
group = properties.getGroup();
}
}
private static void initServices() {
try {
init();
services.clear();
int index = 1;
while (true) {
ListView<String> listView = nacos.getServicesOfServer(index,20,group);
if(CollectionUtils.isEmpty(listView.getData())) {
break;
}else {
for (String name : listView.getData()) {
if(!services.contains(name)) {
services.add(name);
}
}
}
index++;
}
} catch (NacosException e) {
log.error("初始化服务名异常",e);
}
}
public static HttpHeaders getHeaders() {
HttpServletRequest request = getRequest();
HttpHeaders headers = null;
if(request!=null) {
headers = new HttpHeaders();
Enumeration<String> headerNames = request.getHeaderNames();
if (headerNames != null) {
while (headerNames.hasMoreElements()) {
String name = headerNames.nextElement();
headers.addAll(name, getValues(request.getHeaders(name)));
}
}
}
return headers;
}
private static List<String> getValues(Enumeration<String> sourcs){
List<String> values = new ArrayList<String>();
if (sourcs != null) {
while (sourcs.hasMoreElements()) {
values.add(sourcs.nextElement());
}
}
return values;
}
private static HttpServletRequest getRequest() {
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
if(servletRequestAttributes!=null) {
return servletRequestAttributes.getRequest();
}
return null;
}
}

View File

@ -777,7 +777,6 @@ public class DataLogTools {
change.setNewValue(parseValue(BeanUtils.getFieldValue(item.getField(),entity),item.getField().getType()));
datalog.addFiledChnage(change);
}
}
}
@ -891,7 +890,9 @@ public class DataLogTools {
// }
// executeBatch(sql, batchParams);
for (DataChangeLog item : logs) {
logDbService.insertDataLog(tableName,item);
if(item.hasFieldChanges()) {
logDbService.insertDataLog(tableName,item);
}
}
}

View File

@ -0,0 +1,70 @@
package com.pictc.utils;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
public class MethodUtils {
private static ParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer();
private MethodUtils() {
super();
}
public static String toString(Method method) {
StringBuilder builder = new StringBuilder(method.getName());
builder.append("(");
String[] names = getArgNames(method);
Parameter[] parameters = method.getParameters();
if(parameters!=null) {
for (int i = 0; i < parameters.length; i++) {
if(i>0) {
builder.append(",");
}
if(names!=null) {
builder.append(names[i]);
}else {
builder.append("arg"+i);
}
Parameter parameter = parameters[i];
builder.append(":");
builder.append(typeToString(parameter.getParameterizedType()));
}
}
builder.append("):");
if(Void.class.equals(method.getReturnType())) {
builder.append("void");
}else {
builder.append(method.getReturnType().getName());
}
return builder.toString();
}
public static String[] getArgNames(Method method) {
return discoverer.getParameterNames(method);
}
public static String typeToString(Type type) {
if(type instanceof ParameterizedType) {
ParameterizedType gtype = ((ParameterizedType)type);
StringBuilder builder = new StringBuilder();
builder.append(gtype.getRawType().getTypeName());
Type[] generics = gtype.getActualTypeArguments();
builder.append("<");
for (int i = 0; i < generics.length; i++) {
if(i>0) {
builder.append(",");
}
builder.append(typeToString(generics[i]));
}
builder.append(">");
return builder.toString();
}
return type.getTypeName();
}
}

View File

@ -0,0 +1,96 @@
package com.pictc.utils;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Serializable;
/**
* @Description TODO(这里用一句话描述这个类的作用)
* @author zhangfucai
* @Date 2023年4月25日 上午12:49:14
* @version 1.0.0
*/
public class ObjectUtils {
private ObjectUtils() {
super();
}
public static byte[] toBytes(Object obj){
if(obj!=null) {
if(!(obj instanceof Serializable)) {
throw new RuntimeException(obj+"没有实现 Serializable");
}
ByteArrayOutputStream out = new ByteArrayOutputStream();
ObjectOutputStream oo=null;
try {
oo = new ObjectOutputStream(out);
oo.writeObject(obj);
oo.flush();
return out.toByteArray();
} catch (Exception e) {
throw new RuntimeException("对象序列化失败!",e);
}finally {
closeQuietly(oo,out);
}
}
return null;
}
public static void write(OutputStream out,Object obj) {
if(obj!=null) {
if(!(obj instanceof Serializable)) {
throw new RuntimeException(obj+"没有实现 Serializable");
}
ObjectOutputStream oo=null;
try {
oo = new ObjectOutputStream(out);
oo.writeObject(obj);
oo.flush();
} catch (Exception e) {
throw new RuntimeException("对象序列化失败!",e);
}finally {
closeQuietly(oo,out);
}
}
}
@SuppressWarnings("unchecked")
public static <T>T reader(InputStream in){
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(in);
return (T) ois.readObject();
} catch (Exception e) {
throw new RuntimeException("对象反序列化失败!",e);
}finally {
closeQuietly(ois,in);
}
}
public static <T>T reader(byte[] bytes){
return reader(new ByteArrayInputStream(bytes));
}
public static void closeQuietly(Closeable... closeables) {
if (closeables == null)
return;
for (Closeable closeable : closeables) {
if (closeable == null)
return;
try {
closeable.close();
} catch (IOException ignored) {
}
}
}
}

View File

@ -0,0 +1,119 @@
package com.xjrsoft.common;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.util.List;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.BeansException;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import com.alibaba.fastjson.JSON;
import com.pictc.listener.ListenerParameterContext;
import com.pictc.listener.MethodInfo;
import com.pictc.listener.PEventListener;
import com.pictc.utils.CollectionUtils;
import com.pictc.utils.ObjectUtils;
import com.pictc.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import springfox.documentation.annotations.ApiIgnore;
@Slf4j
@ApiIgnore
@RequestMapping("/reception")
public class ServiceListenerProvider implements ApplicationContextAware,ApplicationRunner{
private ApplicationContext context;
private List<MethodInfo> cmethods = CollectionUtils.newArrayList();
// SpEL解析器
private final ExpressionParser parser = new SpelExpressionParser();
private static byte[] FALSE;
private static byte[] TRUE;
static {
try {
FALSE = "false".getBytes("UTF-8");
TRUE = "true".getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.context = applicationContext;
}
@PostMapping("/listener")
public void reception(HttpServletRequest request,HttpServletResponse response) throws Exception {
boolean flag = false;
if(!cmethods.isEmpty()) {
ListenerParameterContext context = ObjectUtils.reader(request.getInputStream());
log.info("监听服务:{},调用{}->{},是否单例:{}",context.getSource(),JSON.toJSONString(context.getData()),context.isSingle());
StandardEvaluationContext elEContext = new StandardEvaluationContext();
elEContext.setVariable("source", context.getSource());
elEContext.setVariable("data", context.getData());
for (MethodInfo info : cmethods) {
PEventListener annotation = info.getAnnotation();
if(StringUtils.isNotEmpty(annotation.value())) {
Object result = parser.parseExpression(annotation.value()).getValue(elEContext);
System.out.println("EL表达式执行结果" + result);
if(result!=null && (boolean)result == false) {
continue;
}
}
flag = parseResult(info.invoke(new Object[] {context.getSource(),context.getData()}));
if(context.isSingle() && flag) {
break;
}
}
ServletOutputStream stream = response.getOutputStream();
stream.write(flag?TRUE:FALSE);
stream.flush();
}else {
log.info("没有注册监听器");
}
}
private boolean parseResult(Object val) {
if(val==null) return false;
if(Boolean.class.equals(val.getClass())) {
return Boolean.class.cast(val).booleanValue();
}else if(boolean.class.equals(val.getClass())) {
return (boolean)val;
}
return true;
}
// 项目启动后执行扫描
@Override
public void run(ApplicationArguments args) throws Exception {
String[] beanNames = context.getBeanDefinitionNames();
for (String beanName : beanNames) {
Object bean = context.getBean(beanName);
Method[] methods = bean.getClass().getDeclaredMethods();
for (Method method : methods) {
if (method.isAnnotationPresent(PEventListener.class)) {
cmethods.add(new MethodInfo(bean, method, method.getAnnotation(PEventListener.class)));
}
}
}
log.info("监听器客户端:{}",cmethods);
}
}

View File

@ -1,4 +1,5 @@
# src/main/resources/META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.pictc.config.PcitcAutoConfig,\
com.pictc.config.JdbcConfig
com.pictc.config.JdbcConfig,\
com.pictc.config.PEventListenerConfig

View File

@ -1,4 +1,5 @@
# src/main/resources/META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.pictc.config.PcitcAutoConfig,\
com.pictc.config.JdbcConfig
com.pictc.config.JdbcConfig,\
com.pictc.config.PEventListenerConfig