Commit a7892caa by lixiaozhong

添加actionMapping,将websocket的服务写法模仿springmvc。

parent 49239792
...@@ -15,9 +15,9 @@ spring-boot-plus: ...@@ -15,9 +15,9 @@ spring-boot-plus:
spring: spring:
datasource: datasource:
url: jdbc:mysql://localhost:3306/wecloud_im?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true url: jdbc:mysql://192.168.1.51:3306/wecloud-im?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true
username: root username: mysql
password: 123 password: mysql
#//测试外网 #//测试外网
# url: jdbc:mysql://18.136.207.16:3306/wecloud_im?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true # url: jdbc:mysql://18.136.207.16:3306/wecloud_im?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true
...@@ -27,14 +27,14 @@ spring: ...@@ -27,14 +27,14 @@ spring:
# Redis配置 # Redis配置
redis: redis:
database: 0 database: 0
host: localhost host: 192.168.1.51
password: password:
port: 6379 port: 6379
cloud: cloud:
nacos: nacos:
discovery: discovery:
server-addr: localhost:8848 server-addr: 192.168.1.51:8848
dubbo: dubbo:
...@@ -42,7 +42,9 @@ dubbo: ...@@ -42,7 +42,9 @@ dubbo:
port: 20881 port: 20881
name: dubbo name: dubbo
registry: registry:
address: nacos://localhost:8848?username=nacos&password=nacos address: nacos://192.168.1.51:8848?username=nacos&password=nacos
provider:
cluster: channelRouterCluster
# 打印SQL语句和结果集,本地开发环境可开启,线上注释掉 # 打印SQL语句和结果集,本地开发环境可开启,线上注释掉
mybatis-plus: mybatis-plus:
......
...@@ -396,3 +396,6 @@ info: ...@@ -396,3 +396,6 @@ info:
project-knife4j: http://${spring-boot-plus.server-ip}:${server.port}${server.servlet.context-path}/doc.html project-knife4j: http://${spring-boot-plus.server-ip}:${server.port}${server.servlet.context-path}/doc.html
############################## Spring boot admin end ############################### ############################## Spring boot admin end ###############################
websocket:
action:
scan-package: com.wecloud
package com.wecloud.dispatch;
import com.wecloud.dispatch.annotation.ActionMapping;
import com.wecloud.dispatch.config.ActionConfigurer;
import com.wecloud.dispatch.extend.ActionBox;
import com.wecloud.dispatch.extend.impl.DefaultActionBox;
import com.wecloud.dispatch.registry.ActionBoxRegistry;
import com.wecloud.dispatch.registry.ActionInterceptorRegistry;
import com.wecloud.dispatch.registry.ActionMethodInterceptorRegistry;
import com.wecloud.dispatch.registry.ActionRegistry;
import com.wecloud.dispatch.registry.ArgumentDefaultValueBuilderRegistry;
import com.wecloud.dispatch.registry.MethodArgumentResolverRegistry;
import com.wecloud.dispatch.util.ClassScaner;
import lombok.extern.slf4j.Slf4j;
import java.util.Set;
/**
* @author lixiaozhong
*/
@Slf4j
public class ActionContext {
private final ActionRegistry actionRegistry = new ActionRegistry();
private final ActionBoxRegistry actionBoxRegistry = new ActionBoxRegistry();
private final ActionMethodInterceptorRegistry actionMethodInterceptorRegistry = new ActionMethodInterceptorRegistry();
private final MethodArgumentResolverRegistry methodArgumentResolverRegistry = new MethodArgumentResolverRegistry();
private final ActionInterceptorRegistry actionInterceptorRegistry = new ActionInterceptorRegistry();
private final ActionBox actionBox = new DefaultActionBox();
private final ArgumentDefaultValueBuilderRegistry argumentDefaultValueBuilderRegistry = new ArgumentDefaultValueBuilderRegistry();
private final ActionDispatcher actionDispatcher;
public ActionContext(ActionDispatcher actionDispatcher) {
super();
this.actionDispatcher = actionDispatcher;
}
@SuppressWarnings("unchecked")
public void scan(String... path) {
// 扫描包下面的所有被注解ActionMapping的类
Set<Class<?>> classSet = ClassScaner.scan(path, ActionMapping.class);
for (Class<?> classType : classSet) {
log.info("ActionMapping scan, find: {}", classType.getTypeName());
actionRegistry.add(classType);
}
}
@SuppressWarnings("unchecked")
public void cover(String... path) {
// 扫描xxx包下面的所有被注解ActionMapping的类
Set<Class<?>> classSet = ClassScaner.scan(path, ActionMapping.class);
for (Class<?> classType : classSet) {
actionRegistry.cover(classType);
}
}
public void cover(Class<?> classType) {
actionRegistry.cover(classType);
}
public void addConfig(ActionConfigurer actionConfigurer) {
actionConfigurer.addConfig(this);
}
public ActionRegistry getActionRegistry() {
return actionRegistry;
}
public ActionBoxRegistry getActionBoxRegistry() {
return actionBoxRegistry;
}
public MethodArgumentResolverRegistry getMethodArgumentResolverRegistry() {
return methodArgumentResolverRegistry;
}
public ActionInterceptorRegistry getActionInterceptorRegistry() {
return actionInterceptorRegistry;
}
public ActionBox getActionBox() {
return actionBox;
}
public ActionMethodInterceptorRegistry getActionMethodInterceptorRegistry() {
return actionMethodInterceptorRegistry;
}
public ArgumentDefaultValueBuilderRegistry getArgumentDefaultValueBuilderRegistry() {
return argumentDefaultValueBuilderRegistry;
}
public ActionDispatcher getActionDispatcher() {
return actionDispatcher;
}
}
package com.wecloud.dispatch;
import com.wecloud.dispatch.annotation.ActionMapping;
import com.wecloud.im.ws.model.WsResponse;
import com.wecloud.im.ws.model.request.PushVO;
import com.wecloud.utils.JsonUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* @author lixiaozhong
*/
@Component
@ActionMapping(value = "sendtest")
@Slf4j
public class WsTestAction {
/**
* test
* @param reqId
* @param nihao
* @param push
* @param pList
* @param pSet
* @param pMap
*/
@ActionMapping(value = "gogo")
public WsResponse<Boolean> groupChat(String reqId,
@RequestParam("hello") String nihao,
PushVO push,
ArrayList<PushVO> pList,
Set<PushVO> pSet,
Map<String, String> pMap) {
log.info(reqId);
log.info(nihao);
log.info(JsonUtils.encodeJson(push));
log.info(JsonUtils.encodeJson(pList));
log.info(JsonUtils.encodeJson(pSet));
log.info(JsonUtils.encodeJson(pMap));
WsResponse<Boolean> wsResponse = new WsResponse<>();
wsResponse.setCmd(0).setData(true).setCode(0).setMsg("msg").setReqId(reqId);
return wsResponse;
}
}
package com.wecloud.dispatch.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author lixiaozhong
*/
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface ActionMapping {
/**
* Mapping映射字段
* @return
*/
String[] value() default "";
/**
*
* @return
*/
int order() default 10;
}
package com.wecloud.dispatch.common;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.SynthesizingMethodParameter;
import java.lang.reflect.Method;
/**
* @author lixiaozhong
*/
public class ActionMethod {
private Class<?> actionClass;
private Method method;
private MethodParameter[] methodParameters;
private String methodPath;
// public ActionMethod(Class<?> actionClass, Method method) {
// this.actionClass = actionClass;
// this.method = method;
// initialize(method);
// }
public ActionMethod(Method method, String methodPath) {
this.actionClass = method.getDeclaringClass();
this.method = method;
this.methodPath = methodPath;
initialize(method);
}
private void initialize(Method method) {
methodParameters = initMethodParameters(method);
}
private MethodParameter[] initMethodParameters(Method method) {
int count = method.getParameterCount();
MethodParameter[] result = new MethodParameter[count];
for (int i = 0; i < count; i++) {
SynthesizingMethodParameter parameter = SynthesizingMethodParameter.forExecutable(method, i);
parameter.withContainingClass(this.actionClass);
parameter.initParameterNameDiscovery(new DefaultParameterNameDiscoverer());
result[i] = parameter;
}
return result;
}
public Class<?> getActionClass() {
return actionClass;
}
public Method getMethod() {
return method;
}
public MethodParameter[] getMethodParameters() {
return methodParameters;
}
public String getMethodPath() {
return methodPath;
}
public void setMethodPath(String methodPath) {
this.methodPath = methodPath;
}
}
package com.wecloud.dispatch.common;
/**
* @author lixiaozhong
*/
public class ApplyInfo {
private boolean approve;
private Object value;
public boolean isApprove() {
return approve;
}
public void setApprove(boolean approve) {
this.approve = approve;
}
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
}
package com.wecloud.dispatch.common;
import lombok.NoArgsConstructor;
import java.util.HashMap;
/**
* @author lixiaozhong
*/
@NoArgsConstructor
public class RequestVO extends HashMap<String, Object> {
/**
* 请求的参数 action,用来寻找action类的path
*/
private String action;
/**
* 请求id, 以判空是否请求成功, 服务端处理完成后 返回此id
* 由前端生成,可以用uuid,也可以用时间戳
*/
private String reqId;
public String getAction() {
return (String)this.get("action");
}
public void setAction(String action) {
this.put("action", action);
}
public String getReqId() {
return (String)this.get("reqId");
}
public void setReqId(String reqId) {
this.put("reqId", reqId);
}
}
package com.wecloud.dispatch.config;
import com.wecloud.dispatch.ActionContext;
/**
* @author lixiaozhong
*/
public interface ActionConfigurer {
/**
* 为了方便将配置项写入actionContext
* @param actionContext
*/
public void addConfig(ActionContext actionContext);
}
package com.wecloud.dispatch.exception;
/**
* @author lixiaozhong
*/
public class ActionNotFoundException extends RuntimeException {
private static final long serialVersionUID = 1L;
public ActionNotFoundException() {
super();
}
public ActionNotFoundException(String message) {
super(message);
}
}
package com.wecloud.dispatch.exception;
/**
* @author lixiaozhong
*/
public class MappingException extends RuntimeException {
private static final long serialVersionUID = 1L;
public MappingException() {
super();
}
public MappingException(String message) {
super(message);
}
}
package com.wecloud.dispatch.extend;
/**
* @author lixiaozhong
*/
public interface ActionBox {
/**
* 获取action对象
* @param type
* @return
*/
public Object getAction(Class<?> type);
/**
* 获取action对象
* @param className
* @return
*/
public Object getAction(String className);
}
package com.wecloud.dispatch.extend;
import com.wecloud.dispatch.ActionContext;
import com.wecloud.dispatch.common.ApplyInfo;
/**
* @author lixiaozhong
*/
public interface ActionInterceptor {
/**
*
* 执行前拦截
*
* @param actionContext
* @param request
* @param argumentBox
* @return
*/
public ApplyInfo previous(ActionContext actionContext, ActionRequest request, ArgumentBox argumentBox);
}
package com.wecloud.dispatch.extend;
import com.wecloud.dispatch.common.RequestVO;
/**
* @author lixiaozhong
*/
public interface ActionMessage {
void setMessage(RequestVO message);
RequestVO getMessage();
String getAction();
void setAction(String action);
}
package com.wecloud.dispatch.extend;
import com.wecloud.dispatch.ActionContext;
import com.wecloud.dispatch.common.ApplyInfo;
import org.springframework.core.MethodParameter;
import java.lang.reflect.Method;
/**
* 切面
* @author lixiaozhong
*/
public interface ActionMethodInterceptor {
/**
*
* 方法切面
*
* @param actionContext
* @param object
* @param method
* @param array
* @param parameter
* @param request
* @param argumentBox
* @return
*/
ApplyInfo intercept(ActionContext actionContext, Object object, Method method, Object[] array, MethodParameter[] parameter, ActionRequest request, ArgumentBox argumentBox);
}
package com.wecloud.dispatch.extend;
import com.wecloud.dispatch.common.ActionMethod;
import com.wecloud.dispatch.common.RequestVO;
/**
* @author lixiaozhong
*/
public interface ActionRequest {
String getPath();
Object getAction();
RequestVO getData();
ActionMethod getActionMethod();
}
package com.wecloud.dispatch.extend;
/**
* @author lixiaozhong
*/
public interface ActionResponse {
void write(Object data);
}
package com.wecloud.dispatch.extend;
import java.util.Set;
/**
* @author lixiaozhong
*/
public interface ArgumentBox {
<T> T get(Object key);
void put(Object key, Object object);
Set<Object> keySet();
}
package com.wecloud.dispatch.extend;
/**
* @author lixiaozhong
*/
public interface ArgumentDefaultValueBuilder {
/**
*
* 参数默认值创建
*
* @param classType
* @return
*/
Object build(Class<?> classType);
}
package com.wecloud.dispatch.extend;
import com.wecloud.dispatch.ActionContext;
import org.springframework.core.MethodParameter;
/**
* @author lixiaozhong
*/
public interface MethodArgumentResolver {
/**
*
* 是否支持<br>
*
* @param parameter
* @return
*/
boolean supportsParameter(MethodParameter parameter);
/**
*
* 解析参数<br>
*
* @param actionContext
* @param parameter
* @param request
* @param argumentBox
* @return
*/
Object resolveArgument(ActionContext actionContext, MethodParameter parameter, ActionRequest request, ArgumentBox argumentBox);
}
package com.wecloud.dispatch.extend.impl;
import com.wecloud.dispatch.extend.ActionBox;
import com.wecloud.dispatch.factory.ObjectFactory;
import java.util.HashMap;
import java.util.Map;
/**
* @author lixiaozhong
*/
public class DefaultActionBox implements ActionBox {
Map<String, Class<?>> classMap = new HashMap<>();
ObjectFactory objectFactory = new ObjectFactory();
@Override
public Object getAction(Class<?> type) {
return objectFactory.getObject(type);
}
@Override
public Object getAction(String className) {
Class<?> type = null;
if (classMap.containsKey(className)) {
type = classMap.get(className);
} else {
try {
type = Class.forName(className);
classMap.put(className, type);
} catch (Exception e) {
classMap.put(className, null);
}
}
if (null == type) {
return null;
} else {
return getAction(type);
}
}
}
package com.wecloud.dispatch.extend.impl;
import com.wecloud.dispatch.common.RequestVO;
import com.wecloud.dispatch.extend.ActionMessage;
/**
* @author lixiaozhong
*/
public class DefaultActionMessage implements ActionMessage {
String action;
RequestVO message;
public DefaultActionMessage() {
}
public DefaultActionMessage(String action, RequestVO message) {
this.message = message;
this.action = action;
}
@Override
public RequestVO getMessage() {
return message;
}
@Override
public void setMessage(RequestVO message) {
this.message = message;
}
@Override
public String getAction() {
return action;
}
@Override
public void setAction(String action) {
this.action = action;
}
}
package com.wecloud.dispatch.extend.impl;
import com.wecloud.dispatch.extend.ArgumentBox;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* @author lixiaozhong
*/
public class DefaultArgumentBox implements ArgumentBox {
Map<Object, Object> map = new HashMap<>();
@SuppressWarnings("unchecked")
@Override
public <T> T get(Object key) {
return (T) map.get(key);
}
@Override
public void put(Object key, Object object) {
map.put(key, object);
}
@Override
public Set<Object> keySet() {
return map.keySet();
}
}
package com.wecloud.dispatch.extend.impl;
import com.wecloud.dispatch.extend.ArgumentDefaultValueBuilder;
import com.wecloud.dispatch.util.ClassUtil;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* @author lixiaozhong
*/
public class DefaultArgumentDefaultValueBuilder implements ArgumentDefaultValueBuilder {
Map<Class<?>, Boolean> canNotInstanceMap = new HashMap<>();
@Override
public Object build(Class<?> classType) {
return getValue(classType);
}
private Object getValue(Class<?> clazz) {
Object value = null;
if (null == value) {
value = getDefaultValue(clazz);
}
if (null == value && ClassUtil.isCanInstance(clazz) && !canNotInstanceMap.containsKey(clazz)) {
value = getObject(clazz);
}
return value;
}
private <T> Object getObject(Class<T> clazz) {
Object object = null;
if (ClassUtil.isCanInstance(clazz) && !canNotInstanceMap.containsKey(clazz)) {
try {
object = clazz.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
canNotInstanceMap.put(clazz, false);
}
}
return object;
}
/**
* 对象给默认值
*
*/
@SuppressWarnings("unchecked")
public <T> T getDefaultValue(Class<T> clazz) {
Object object = null;
if (List.class.isAssignableFrom(clazz)) {
object = new ArrayList<Object>(0);
} else if (Map.class.isAssignableFrom(clazz)) {
object = new HashMap<Object, Object>(0);
} else if (Set.class.isAssignableFrom(clazz)) {
object = new HashSet<Object>(0);
} else if (clazz.isArray()) {
Class<?> componentType = clazz.getComponentType();
object = Array.newInstance(componentType, 0);
} else if (clazz == int.class) {
object = 0;
} else if (clazz == long.class) {
object = 0L;
} else if (clazz == float.class) {
object = 0.0F;
} else if (clazz == double.class) {
object = 0.00D;
} else if (clazz == byte.class) {
object = (byte) 0;
} else if (clazz == char.class) {
object = '\u0000';
} else if (clazz == short.class) {
object = 0;
} else if (clazz == boolean.class) {
object = false;
}
return ((T) object);
}
}
package com.wecloud.dispatch.extend.impl;
import com.wecloud.dispatch.ActionContext;
import com.wecloud.dispatch.extend.ActionRequest;
import com.wecloud.dispatch.extend.ArgumentBox;
import com.wecloud.dispatch.extend.MethodArgumentResolver;
import org.springframework.core.MethodParameter;
import java.util.Set;
/**
* @author lixiaozhong
*/
public class DefaultMethodArgumentResolver implements MethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return true;
}
@Override
public Object resolveArgument(ActionContext actionContext, MethodParameter parameter, ActionRequest request, ArgumentBox argumentBox) {
// Type type = parameter.getGenericParameterType();
Class<?> clazz = parameter.getParameterType();
Object data = null;
if (null != clazz) {
if (clazz.isAssignableFrom(ActionContext.class)) {
data = actionContext;
} else if (clazz.isAssignableFrom(ActionRequest.class)) {
data = request;
} else if (clazz.isAssignableFrom(ArgumentBox.class)) {
data = argumentBox;
} else {
data = argumentBox.get(clazz);
if (null == data) {
Set<Object> keys = argumentBox.keySet();
if (null != keys) {
for (Object o : keys) {
if (o instanceof Class) {
Class<?> classKey = (Class<?>) o;
if (clazz.isAssignableFrom(classKey)) {
data = argumentBox.get(o);
break;
}
}
}
}
}
if (null == data) {
data = getValue(actionContext, clazz);
}
}
}
return data;
}
private Object getValue(ActionContext actionContext, Class<?> clazz) {
return actionContext.getArgumentDefaultValueBuilderRegistry().getValue(clazz);
}
}
package com.wecloud.dispatch.factory;
import com.wecloud.dispatch.util.ClassUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Array;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author lixiaozhong
*/
public abstract class AbstractFactory {
protected final Logger logger = LoggerFactory.getLogger(this.getClass());
private Map<Class<?>, Object> objectMap = new ConcurrentHashMap<>();
private Map<Class<?>, Boolean> canNotInstanceMap = new ConcurrentHashMap<>();
private ReentrantLock lock = new ReentrantLock();
public <T> void put(Class<T> defineClass, T object) {
objectMap.put(defineClass, object);
}
/**
* 根据class获取对象,均为单列(有待验证😂)
*
* @param classType
* @return T
*/
public <T> T getObject(Class<T> classType) {
return getObject(classType, false, false);
}
/**
*
* @param classType
* @param createNew
* @return T
*/
public <T> T getObject(Class<T> classType, boolean createNew) {
return getObject(classType, createNew, false);
}
/**
*
* @param classType :被实例化的class对象
* @param createNew :true:不管对象是否存在,都新创建对象;false:如果对象已经存在就不新建对象
* @param cover :true:如果新建了对象,则覆盖原来的对象。false:不执行覆盖操作
* @return T
*/
@SuppressWarnings("unchecked")
public <T> T getObject(Class<T> classType, boolean createNew, boolean cover) {
Object object = null;
if (null != classType) {
object = objectMap.get(classType);
if (createNew) {
object = createObject(classType);
if ((cover) && null != object) {
objectMap.put(classType, object);
}
} else if (null == object) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
boolean has = objectMap.containsKey(classType);
object = objectMap.get(classType);
if (!has) {
object = createObject(classType);
// 原来对象不存在,或者覆盖,并且新创建的对象不能为空
if ((cover) && null != object) {
objectMap.put(classType, object);
}
}
} finally {
lock.unlock();
}
}
}
return (T) object;
}
/**
* 根据class反射创建对象
*
* @param clazz
* @return
*/
public Object createObject(Class<?> clazz) {
Object object = null;
if (!canNotInstanceMap.containsKey(clazz)) {
try {
if (ClassUtil.isCanInstance(clazz)) {
object = clazz.newInstance();
} else if (clazz.isArray()) {
Class<?> componentType = clazz.getComponentType();
object = Array.newInstance(componentType, 0);
}
} catch (Exception e) {
canNotInstanceMap.put(clazz, false);
logger.error("初始化对象失败!", e);
}
}
return object;
}
}
package com.wecloud.dispatch.factory;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 管理存放系统对象
*
* @author lixiaozhong
*/
public class ObjectFactory extends AbstractFactory {
private Map<Class<?>, Class<?>> map = new ConcurrentHashMap<Class<?>, Class<?>>();
private Map<Class<?>, Map<String, Object>> multipleMap = new ConcurrentHashMap<Class<?>, Map<String, Object>>();
private Lock lock = new ReentrantLock();
/**
* 注册定义类和实现类的关系<br>
*
* @param defineClass
* @param instanceClass
*/
public <T> void register(Class<T> defineClass, Class<? extends T> instanceClass) {
map.put(defineClass, instanceClass);
}
@Override
public <T> T getObject(Class<T> classType) {
return getObject(classType, false, false);
}
@Override
public <T> T getObject(Class<T> classType, boolean createNew) {
return getObject(classType, createNew, false);
}
@Override
@SuppressWarnings("unchecked")
public <T> T getObject(Class<T> classType, boolean createNew, boolean cover) {
T o = null;
Class<T> clazz = (Class<T>) map.get(classType);
if (null != clazz) {
o = super.getObject(clazz, createNew, cover);
} else {
o = super.getObject(classType, createNew, cover);
}
return o;
}
@SuppressWarnings("unchecked")
public <T> T getObject(String key, Class<T> classType) {
Object o = null;
lock.lock();
try {
Map<String, Object> objectMap = multipleMap.get(classType);
if (null == objectMap) {
objectMap = new ConcurrentHashMap<String, Object>(16);
multipleMap.put(classType, objectMap);
}
o = objectMap.get(key);
if (null == o) {
o = super.createObject(classType);
if (null != o) {
objectMap.put(key, o);
}
}
} finally {
lock.unlock();
}
return (T) o;
}
}
package com.wecloud.dispatch.general;
import com.wecloud.dispatch.common.RequestVO;
import com.wecloud.dispatch.extend.ActionMessage;
import com.wecloud.dispatch.extend.ArgumentBox;
import com.wecloud.dispatch.extend.impl.DefaultArgumentBox;
import com.wecloud.dispatch.general.config.GeneralActionDispatcher;
import com.wecloud.dispatch.general.extend.ActionMessageResolver;
import com.wecloud.im.ws.sender.ChannelSender;
import com.wecloud.utils.JsonUtils;
import io.geekidea.springbootplus.framework.common.exception.BusinessException;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.socket.nio.NioSocketChannel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* @author lixiaozhong
*/
@Component
@Slf4j
public class GeneralMessageHandler {
@Autowired
private GeneralActionDispatcher generalActionDispatcher;
@Autowired
private ActionMessageResolver actionMessageResolver;
@Autowired
private ChannelSender channelSender;
public void doMessage(Long senderClientId, ChannelHandlerContext ctx, String data) {
if(log.isDebugEnabled()) {
log.debug("appWS收到data: {}\n senderClientId:{}, channelId:{}", data, senderClientId, ctx.channel().id().asLongText());
}
// 解析jsonO
RequestVO requestVO = JsonUtils.decodeJson(data, RequestVO.class);
if (null == requestVO || null == requestVO.getAction()) {
throw new BusinessException("null == requestVO || null == requestVO.getAction()");
}
ActionMessage am = actionMessageResolver.resolver(generalActionDispatcher, requestVO);
Object res = generalActionDispatcher.action(am);
channelSender.sendMsgLocal((NioSocketChannel)ctx.channel(), res);
}
public ArgumentBox getArgumentBox() {
ArgumentBox beanBox = new DefaultArgumentBox();
return beanBox;
}
}
package com.wecloud.dispatch.general.config;
import com.wecloud.dispatch.general.impl.GeneralActionBox;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Set;
/**
* @author lixiaozhong
*/
@Configuration
@EnableConfigurationProperties(GeneralActionDispatcherProperties.class)
public class DispatcherConfig {
@Autowired
private GeneralActionDispatcherProperties generalActionDispatcherProperties;
@Bean
public GeneralActionDispatcher generalActionDispatcher(GeneralActionBox generalActionBox) {
Set<String> actionPackages = generalActionDispatcherProperties.getScanPackage();
GeneralActionDispatcher bean = new GeneralActionDispatcher();
bean.add(generalActionBox);
if (null != actionPackages && !actionPackages.isEmpty()) {
for (String path : actionPackages) {
bean.scan(path);
}
} else {
bean.scan("com.wecloud");
}
return bean;
}
@Bean
public GeneralActionBox generalActionBox() {
GeneralActionBox bean = new GeneralActionBox();
return bean;
}
}
package com.wecloud.dispatch.general.config;
import com.wecloud.dispatch.ActionContext;
import com.wecloud.dispatch.config.ActionConfigurer;
/**
* @author lixiaozhong
*/
public class GeneralActionConfigurerAdapter implements ActionConfigurer {
@Override
public void addConfig(ActionContext actionContext) {
// TODO Auto-generated method stub
}
}
package com.wecloud.dispatch.general.config;
import com.wecloud.dispatch.ActionContext;
import com.wecloud.dispatch.general.impl.GeneralActionMethodValidInterceptor;
import com.wecloud.dispatch.general.impl.GeneralMethodArgumentResolver;
/**
* @author lixiaozhong
*/
public class GeneralActionDefaultConfigurer extends GeneralActionConfigurerAdapter {
@Override
public void addConfig(ActionContext actionContext) {
actionContext.getMethodArgumentResolverRegistry().add(new GeneralMethodArgumentResolver());
actionContext.getActionMethodInterceptorRegistry().add(new GeneralActionMethodValidInterceptor());
}
}
package com.wecloud.dispatch.general.config;
import com.wecloud.dispatch.ActionContext;
import com.wecloud.dispatch.ActionDispatcher;
import com.wecloud.dispatch.config.ActionConfigurer;
import com.wecloud.dispatch.extend.ActionBox;
import com.wecloud.dispatch.general.impl.GeneralActionInterceptor;
/**
* @author lixiaozhong
*/
public class GeneralActionDispatcher extends ActionDispatcher {
private GeneralActionDefaultConfigurer handlerActionConfigurer = new GeneralActionDefaultConfigurer();
private GeneralActionInterceptor handlerActionInterceptor = new GeneralActionInterceptor();
public GeneralActionDispatcher() {
this.initialize();
}
public GeneralActionDispatcher(ActionBox actionBox) {
this.initialize();
this.add(actionBox);
}
public GeneralActionDispatcher(ActionBox actionBox, String... actionLocations) {
this.initialize();
this.add(actionBox);
this.scan(actionLocations);
}
@Override
public void addConfig(ActionConfigurer actionConfigurer) {
super.addConfig(actionConfigurer);
}
private void initialize() {
this.addConfig(handlerActionConfigurer);
this.addConfig(new GeneralActionConfigurerAdapter() {
@Override
public void addConfig(ActionContext actionContext) {
actionContext.getActionInterceptorRegistry().add(handlerActionInterceptor);
}
});
}
public void add(ActionBox actionBox) {
// "com.*.action"
this.addConfig(new GeneralActionConfigurerAdapter() {
@Override
public void addConfig(ActionContext actionContext) {
actionContext.getActionBoxRegistry().add(actionBox);
}
});
}
}
package com.wecloud.dispatch.general.extend;
import com.wecloud.dispatch.ActionDispatcher;
import com.wecloud.dispatch.common.RequestVO;
import com.wecloud.dispatch.extend.ActionMessage;
/**
* @author lixiaozhong
*/
public interface ActionMessageResolver {
/**
*
* 解析消息<br>
*
* @param actionDispatcher
* @param data
* @return
*/
ActionMessage resolver(ActionDispatcher actionDispatcher, RequestVO data);
}
package com.wecloud.dispatch.general.extend.impl;
import com.wecloud.dispatch.ActionDispatcher;
import com.wecloud.dispatch.common.RequestVO;
import com.wecloud.dispatch.extend.ActionMessage;
import com.wecloud.dispatch.extend.impl.DefaultActionMessage;
import com.wecloud.dispatch.general.extend.ActionMessageResolver;
import org.springframework.stereotype.Component;
/**
* @author lixiaozhong
*/
@Component
public class ActionMessageResolverImpl implements ActionMessageResolver {
@Override
public ActionMessage resolver(ActionDispatcher actionDispatcher, RequestVO data) {
ActionMessage am = new DefaultActionMessage();
am.setAction("");
if (data == null) {
return am;
}
String action = data.getAction();
String path = actionDispatcher.getActionRegistry().getPath(action, null);
am.setMessage(data);
am.setAction(path);
return am;
}
}
package com.wecloud.dispatch.general.impl;
import com.wecloud.dispatch.extend.ActionBox;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
/**
* @author lixiaozhong
*/
public class GeneralActionBox implements ActionBox, ApplicationContextAware {
private ApplicationContext applicationContext = null;
@Override
public Object getAction(Class<?> type) {
Object o = null;
if (null != applicationContext) {
o = applicationContext.getBean(type);
}
return o;
}
@Override
public Object getAction(String className) {
Object o = null;
if (null != applicationContext) {
o = applicationContext.getBean(className);
}
return o;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
package com.wecloud.dispatch.general.impl;
import com.wecloud.dispatch.ActionContext;
import com.wecloud.dispatch.common.ApplyInfo;
import com.wecloud.dispatch.extend.ActionInterceptor;
import com.wecloud.dispatch.extend.ActionRequest;
import com.wecloud.dispatch.extend.ArgumentBox;
/**
* @author lixiaozhong
*/
public class GeneralActionInterceptor implements ActionInterceptor {
@Override
public ApplyInfo previous(ActionContext actionContext, ActionRequest request, ArgumentBox argumentBox) {
ApplyInfo applyInfo = new ApplyInfo();
applyInfo.setApprove(true);
return applyInfo;
}
}
package com.wecloud.dispatch.general.impl;
import com.wecloud.dispatch.ActionContext;
import com.wecloud.dispatch.common.ApplyInfo;
import com.wecloud.dispatch.extend.ActionMethodInterceptor;
import com.wecloud.dispatch.extend.ActionRequest;
import com.wecloud.dispatch.extend.ArgumentBox;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.SmartFactoryBean;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.core.BridgeMethodResolver;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.ClassUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.validation.beanvalidation.OptionalValidatorFactoryBean;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Validator;
import javax.validation.executable.ExecutableValidator;
import java.lang.reflect.Method;
import java.util.Set;
/**
* @author lixiaozhong
*/
public class GeneralActionMethodValidInterceptor implements ActionMethodInterceptor {
Validator validator;
public GeneralActionMethodValidInterceptor() {
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
// messageSource.setBasename("classpath:i18n/ValidationMessages");
OptionalValidatorFactoryBean optionalValidatorFactoryBean = new OptionalValidatorFactoryBean();
optionalValidatorFactoryBean.setValidationMessageSource(messageSource);
optionalValidatorFactoryBean.afterPropertiesSet();
validator = optionalValidatorFactoryBean;
}
@Override
public ApplyInfo intercept(ActionContext actionContext, Object object, Method method, Object[] array, MethodParameter[] parameter, ActionRequest request, ArgumentBox argumentBox) {
// TODO Auto-generated method stub
boolean approve = true;
Object value = null;
if (!isFactoryBeanMetadataMethod(method)) {
Class<?>[] groups = determineValidationGroups(object, method);
// Standard Bean Validation 1.1 API
ExecutableValidator execVal = this.validator.forExecutables();
Method methodToValidate = method;
Set<ConstraintViolation<Object>> result;
try {
result = execVal.validateParameters(object, methodToValidate, array, groups);
} catch (IllegalArgumentException ex) {
// Probably a generic type mismatch between interface and impl as reported in
// SPR-12237 / HV-1011
// Let's try to find the bridged method on the implementation class...
methodToValidate = BridgeMethodResolver.findBridgedMethod(ClassUtils.getMostSpecificMethod(method, object.getClass()));
result = execVal.validateParameters(object, methodToValidate, array, groups);
}
if (!result.isEmpty()) {
throw new ConstraintViolationException(result);
}
if (null != array) {
int size = array.length;
for (int i = 0; i < size; i++) {
Validated validatedAnn = parameter[i].getParameterAnnotation(Validated.class);
if (validatedAnn != null) {
Class<?>[] gs = validatedAnn.value();
result = validator.validate(array[i], gs);
if (!result.isEmpty()) {
throw new ConstraintViolationException(result);
}
}
}
}
}
ApplyInfo applyInfo = new ApplyInfo();
applyInfo.setApprove(approve);
applyInfo.setValue(value);
return applyInfo;
}
private boolean isFactoryBeanMetadataMethod(Method method) {
Class<?> clazz = method.getDeclaringClass();
// Call from interface-based proxy handle, allowing for an efficient check?
if (clazz.isInterface()) {
return ((clazz == FactoryBean.class || clazz == SmartFactoryBean.class) &&
!"getObject".equals(method.getName()));
}
// Call from CGLIB proxy handle, potentially implementing a FactoryBean method?
Class<?> factoryBeanType = null;
if (SmartFactoryBean.class.isAssignableFrom(clazz)) {
factoryBeanType = SmartFactoryBean.class;
} else if (FactoryBean.class.isAssignableFrom(clazz)) {
factoryBeanType = FactoryBean.class;
}
return (factoryBeanType != null && !method.getName().equals("getObject") &&
ClassUtils.hasMethod(factoryBeanType, method.getName(), method.getParameterTypes()));
}
/**
* Determine the validation groups to validate against for the given method
* invocation.
* <p>
* Default are the validation groups as specified in the {@link Validated}
* annotation on the containing target class of the method.
*
* @param method the current MethodInvocation
* @return the applicable validation groups as a Class array
*/
protected Class<?>[] determineValidationGroups(Object bean, Method method) {
Validated validatedAnn = AnnotationUtils.findAnnotation(method, Validated.class);
if (validatedAnn == null) {
validatedAnn = AnnotationUtils.findAnnotation(bean.getClass(), Validated.class);
}
return (validatedAnn != null ? validatedAnn.value() : new Class<?>[0]);
}
}
package com.wecloud.dispatch.general.impl;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.wecloud.dispatch.ActionContext;
import com.wecloud.dispatch.extend.ActionRequest;
import com.wecloud.dispatch.extend.ArgumentBox;
import com.wecloud.dispatch.extend.MethodArgumentResolver;
import com.wecloud.utils.JsonUtils;
import org.springframework.core.MethodParameter;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.web.bind.annotation.RequestParam;
import java.lang.reflect.Array;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* @author lixiaozhong
*/
public class GeneralMethodArgumentResolver implements MethodArgumentResolver {
protected final DefaultConversionService conversionService = new DefaultConversionService();
Map<Class<?>, Boolean> canNotInstanceMap = new HashMap<>();
@Override
public boolean supportsParameter(MethodParameter parameter) {
// return parameter.hasParameterAnnotation(RequestParam.class);
return true;
}
@Override
public Object resolveArgument(
ActionContext actionContext,
MethodParameter parameter,
ActionRequest request,
ArgumentBox argumentBox) {
Object object = null;
RequestParam define = parameter.getParameterAnnotation(RequestParam.class);
// 获取属定义的名称
String name = null == define ? parameter.getParameterName() : define.value();
Type t = parameter.getGenericParameterType();
Class<?> clazz = parameter.getParameterType();
Object value = request.getData().get(name);
if (value instanceof JSONObject) {
JSONObject jo = (JSONObject) value;
if (isCustomMap(clazz)) {
object = JSONObject.parseObject(jo.toJSONString(), clazz);
} else {
object = jo.toJavaObject(t);
}
} else if (value instanceof JSONArray) {
JSONArray ja = (JSONArray) value;
object = ja.toJavaObject(t);
}
else if (value instanceof Map) {
if(clazz.isInstance(value)) {
object = value;
} else {
object = JsonUtils.mapToBean((Map) value, getObject(clazz));
}
}
else if (value instanceof List) {
if(clazz.isInstance(value)) {
object = value;
} else if(Set.class.isAssignableFrom(clazz)) {
Set objectSet = new HashSet();
Type actualTypeArgument = ((ParameterizedType) parameter.getGenericParameterType()).getActualTypeArguments()[0];
((List<Map<String, Object>>) value).forEach(p -> objectSet.add(JsonUtils.mapToBean(p, getObject((Class)actualTypeArgument))));
object = objectSet;
} else {
List objectList = new ArrayList();
Type actualTypeArgument = ((ParameterizedType) parameter.getGenericParameterType()).getActualTypeArguments()[0];
((List<Map<String, Object>>) value).forEach(p -> objectList.add(JsonUtils.mapToBean(p, getObject((Class)actualTypeArgument))));
object = objectList;
}
}
else if (null != value) {
if (clazz.isInstance(value)) {
object = value;
} else {
if (conversionService.canConvert(value.getClass(), clazz)) {
object = conversionService.convert(value, clazz);
}
}
}
if (null == object) {
object = getDefaultValue(clazz);
}
if (null == object && isCanInstance(clazz) && !canNotInstanceMap.containsKey(clazz)) {
object = getObject(clazz);
}
return object;
}
/**
*
* 是否可以被实例化
*
* @param classType
* @return
*/
private boolean isCanInstance(Class<?> classType) {
boolean isAbstract = Modifier.isAbstract(classType.getModifiers());
boolean can = true;
if (classType.isAnnotation()) {
can = false;
} else if (classType.isArray()) {
can = false;
} else if (classType.isEnum()) {
can = false;
} else if (classType.isInterface()) {
can = false;
} else if (isAbstract) {
can = false;
}
return can;
}
private <T> Object getObject(Class<T> clazz) {
Object object = null;
if (isCanInstance(clazz) && !canNotInstanceMap.containsKey(clazz)) {
try {
object = clazz.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
canNotInstanceMap.put(clazz, false);
}
}
return object;
}
/**
* @param clazz
* @return
*/
@SuppressWarnings("unchecked")
public <T> T getDefaultValue(Class<T> clazz) {
Object object = null;
if (List.class.isAssignableFrom(clazz)) {
if (isCanInstance(clazz)) {
object = getObject(clazz);
} else {
object = new ArrayList<Object>(0);
}
} else if (Map.class.isAssignableFrom(clazz)) {
if (isCanInstance(clazz)) {
object = getObject(clazz);
} else {
object = new HashMap<Object, Object>(0);
}
} else if (Set.class.isAssignableFrom(clazz)) {
if (isCanInstance(clazz)) {
object = getObject(clazz);
} else {
object = new HashSet<Object>(0);
}
} else if (clazz.isArray()) {
Class<?> componentType = clazz.getComponentType();
object = Array.newInstance(componentType, 0);
} else if (clazz == int.class) {
object = 0;
} else if (clazz == long.class) {
object = 0L;
} else if (clazz == float.class) {
object = 0.0F;
} else if (clazz == double.class) {
object = 0.00D;
} else if (clazz == byte.class) {
object = (byte) 0;
} else if (clazz == char.class) {
object = '\u0000';
} else if (clazz == short.class) {
object = 0;
} else if (clazz == boolean.class) {
object = false;
}
return ((T) object);
}
/**
* 是否自定义实现Map
*
* @param clazz
* @return
*/
boolean isCustomMap(Class<?> clazz) {
boolean isMap = Map.class.isAssignableFrom(clazz);
boolean isSubMap = java.util.HashMap.class == clazz
|| java.util.Hashtable.class == clazz
|| java.util.TreeMap.class == clazz
|| java.util.IdentityHashMap.class == clazz
|| java.util.WeakHashMap.class == clazz
|| java.util.LinkedHashMap.class == clazz;
return isMap && !isSubMap;
}
boolean isCollection(Class<?> clazz) {
return Collection.class.isAssignableFrom(clazz);
}
}
package com.wecloud.dispatch.registry;
import com.wecloud.dispatch.extend.ActionBox;
import java.util.ArrayList;
import java.util.List;
/**
* @author lixiaozhong
*/
public class ActionBoxRegistry {
List<ActionBox> list = new ArrayList<>();
public void add(ActionBox actionBox) {
list.add(actionBox);
}
public Object getAction(Class<?> type) {
Object o = null;
for (ActionBox ab : list) {
o = ab.getAction(type);
if (null != o) {
return o;
}
}
return null;
}
}
package com.wecloud.dispatch.registry;
import com.wecloud.dispatch.extend.ActionInterceptor;
import java.util.ArrayList;
import java.util.List;
/**
* @author lixiaozhong
*/
public class ActionInterceptorRegistry {
List<ActionInterceptor> list = new ArrayList<>();
public void add(ActionInterceptor actionInterceptor) {
list.add(actionInterceptor);
}
public List<ActionInterceptor> getActionInterceptorList() {
return list;
};
}
package com.wecloud.dispatch.registry;
import com.wecloud.dispatch.extend.ActionMethodInterceptor;
import java.util.ArrayList;
import java.util.List;
/**
* @author lixiaozhong
*/
public class ActionMethodInterceptorRegistry {
List<ActionMethodInterceptor> list = new ArrayList<>();
public void add(ActionMethodInterceptor actionInterceptor) {
list.add(actionInterceptor);
}
public List<ActionMethodInterceptor> getList() {
return list;
};
}
package com.wecloud.dispatch.registry;
import com.wecloud.dispatch.annotation.ActionMapping;
import com.wecloud.dispatch.common.ActionMethod;
import com.wecloud.dispatch.exception.MappingException;
import org.springframework.http.server.PathContainer;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.StringUtils;
import org.springframework.web.util.pattern.PathPattern;
import org.springframework.web.util.pattern.PathPatternParser;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
/**
* @author lixiaozhong
*/
public class ActionRegistry {
private final Map<PathPattern, ActionMethod> actionMethodMap = new ConcurrentHashMap<>(16);
private String separator = AntPathMatcher.DEFAULT_PATH_SEPARATOR;
private AntPathMatcher pathMatcher = new AntPathMatcher();
private final PathPatternParser patternParser = new PathPatternParser();;
/**
* 为了更快获取要执行的action,将要执行的action加入Map进行缓存
*
* @param classType
* @throws MappingException
*/
public void add(Class<?> classType) {
Annotation[] as = classType.getAnnotations();
ActionMapping am = null;
for (Annotation annotation : as) {
if (annotation instanceof ActionMapping) {
am = ((ActionMapping) annotation);
break;
}
}
String[] codes = null == am ? new String[] { "" } : am.value();
add(codes, classType);
}
/**
* 获取要执行的action的方法,并且缓存
*
* @param classType
* @return
* @throws MappingException
*/
public void add(String[] codes, Class<?> classType) {
Method[] methods = classType.getMethods();
if (null != methods && methods.length > 0) {
for (Method method : methods) {
add(codes, method);
}
}
}
public void add(Method method) {
if (null != method) {
Annotation[] as = method.getDeclaringClass().getAnnotations();
ActionMapping am = null;
for (Annotation annotation : as) {
if (annotation instanceof ActionMapping) {
am = ((ActionMapping) annotation);
break;
}
}
String[] codes = null == am ? new String[] { "" } : am.value();
add(codes, method);
}
}
public void add(String[] codes, Method method) {
if (null != method) {
codes = (null == codes) ? new String[] { "" } : codes;
Annotation[] as = method.getAnnotations();
for (Annotation a : as) {
if (a instanceof ActionMapping) {
ActionMapping actionMapping = (ActionMapping) a;
String[] values = actionMapping.value();
int order = actionMapping.order();
List<String> paths = getPaths(codes, values);
if (null != paths) {
for (String path : paths) {
ActionMethod am = getActionMethod(path);
boolean equals = false;
if (null != am) {
equals = null != am.getMethodPath() && am.getMethodPath().equals(path);
}
if (null != am && equals) {
Method lastMethod = am.getMethod();
if (method.equals(lastMethod)) {
continue;
}
ActionMapping lastMapping = am.getMethod().getAnnotation(ActionMapping.class);
int lastOrder = lastMapping.order();
if (order == lastOrder) {
StringBuilder sb = new StringBuilder();
sb.append("\n");
sb.append("ActionMapping:");
sb.append("\n");
sb.append("[");
sb.append(am.getActionClass().getName());
sb.append("]");
sb.append(".");
sb.append("[");
sb.append(am.getMethod().getName());
sb.append("]");
sb.append("\n");
sb.append("与");
sb.append("\n");
sb.append("[");
sb.append(method.getDeclaringClass().getName());
sb.append("]");
sb.append(".");
sb.append("[");
sb.append(method.getName());
sb.append("]");
sb.append("\n");
sb.append("存在重复");
sb.append("[");
sb.append(path);
sb.append("]!");
throw new MappingException(sb.toString());
} else if (order < lastOrder) {
put(path, new ActionMethod(method, path));
}
} else {
put(path, new ActionMethod(method, path));
}
}
}
break;
}
}
}
}
public void cover(Class<?> classType) {
Annotation[] as = classType.getAnnotations();
ActionMapping am = null;
for (Annotation annotation : as) {
if (annotation instanceof ActionMapping) {
am = ((ActionMapping) annotation);
break;
}
}
String[] value = null == am ? new String[] { "" } : am.value();
cover(value, classType);
}
public void cover(String[] codes, Class<?> classType) {
Method[] methods = classType.getMethods();
if (null != methods && methods.length > 0) {
for (Method method : methods) {
Annotation[] as = method.getAnnotations();
for (Annotation a : as) {
if (a instanceof ActionMapping) {
String[] values = ((ActionMapping) a).value();
List<String> paths = getPaths(codes, values);
cover(paths, method);
break;
}
}
}
}
}
public void cover(List<String> paths, Method method) {
if (null != paths && null != method) {
for (String path : paths) {
cover(path, method);
}
}
}
public void cover(String path, Method method) {
if (null != path && null != method) {
put(path, new ActionMethod(method, path));
}
}
public void put(String path, ActionMethod am) {
PathPattern pattern = patternParser.parse(path);
actionMethodMap.put(pattern, am);
}
public boolean has(String path) {
ActionMethod method = path == null || path.isEmpty() ? null : lookupHandler(PathContainer.parsePath(path));
return null != method;
}
public ActionMethod lookupHandler(PathContainer lookupPath) {
ActionMethod am = null;
List<PathPattern> matches = this.actionMethodMap.keySet().stream()
.filter(key -> key.matches(lookupPath))
.collect(Collectors.toList());
if (matches.isEmpty()) {
return null;
}
if (matches.size() > 1) {
matches.sort(PathPattern.SPECIFICITY_COMPARATOR);
}
PathPattern pattern = matches.get(0);
am = this.actionMethodMap.get(pattern);
return am;
}
/**
* 截取不包含包名,和小写首字母的类名
*
* @param classType
* @return
*/
public String getSimpleNameAsProperty(Class<?> classType) {
String valueName = classType.getSimpleName();
return valueName = valueName.substring(0, 1).toLowerCase() + valueName.substring(1);
}
public Class<?> getClass(String path) {
ActionMethod am = getActionMethod(path);
return null == am ? null : am.getActionClass();
}
public ActionMethod getActionMethod(String path) {
// ActionMethod method = actionMethodMap.get(path == null ? "" : path);
ActionMethod method = path == null || path.isEmpty() ? null : lookupHandler(PathContainer.parsePath(path));
return method;
}
public ActionMethod getActionMethod(String classCode, String methodCode) {
String path = getPath(classCode, methodCode);
return getActionMethod(path);
}
public List<String> getPaths(String[] classCodes, String[] methodCodes) {
classCodes = (null == classCodes || classCodes.length == 0) ? new String[] { "" } : classCodes;
methodCodes = (null == methodCodes || methodCodes.length == 0) ? new String[] { "" } : methodCodes;
List<String> list = new ArrayList<>();
for (String classCode : classCodes) {
for (String methodCode : methodCodes) {
list.add(getPath(classCode, methodCode));
}
}
return list;
}
public String getPath(String classCode, String methodCode) {
// StringBuilder sb = new StringBuilder();
String path = pathMatcher.combine(classCode, methodCode);
// if (isSeparateAlways()) {
// sb.append(getSeparator());
// } else if (null != classCode && !classCode.isEmpty() && !classCode.startsWith(getSeparator())) {
// sb.append(getSeparator());
// }
// sb.append(classCode);
// if (isSeparateAlways()) {
// sb.append(getSeparator());
// } else if (!methodCode.startsWith(getSeparator())) {
// sb.append(getSeparator());
// }
// sb.append(methodCode);
path = prependLeadingSlash(path);
return path;
}
private static String prependLeadingSlash(String pattern) {
String pre = "/";
if (StringUtils.hasLength(pattern) && !pattern.startsWith(pre)) {
return pre + pattern;
} else {
return pattern;
}
}
public Map<PathPattern, ActionMethod> getActionMethodMap() {
return actionMethodMap;
}
public String getSeparator() {
return separator;
}
public void setSeparator(String separator) {
this.separator = separator;
pathMatcher.setPathSeparator(separator);
}
// public boolean isSeparateAlways() {
// return separateAlways;
// }
//
// public void setSeparateAlways(boolean separateAlways) {
// this.separateAlways = separateAlways;
// }
//
// public void setSeparator(String separator, boolean separateAlways) {
// this.separator = separator;
// this.separateAlways = separateAlways;
// pathMatcher.setPathSeparator(separator);
// }
}
package com.wecloud.dispatch.registry;
import com.wecloud.dispatch.extend.ArgumentDefaultValueBuilder;
import com.wecloud.dispatch.extend.impl.DefaultArgumentDefaultValueBuilder;
import java.util.ArrayList;
import java.util.List;
/**
* @author lixiaozhong
*/
public class ArgumentDefaultValueBuilderRegistry {
List<ArgumentDefaultValueBuilder> list = new ArrayList<>();
ArgumentDefaultValueBuilder b = new DefaultArgumentDefaultValueBuilder();
public void add(ArgumentDefaultValueBuilder builder) {
list.add(builder);
}
public Object getValue(Class<?> type) {
Object o = null;
for (ArgumentDefaultValueBuilder ab : list) {
o = ab.build(type);
if (null != o) {
return o;
}
}
o = b.build(type);
return o;
}
}
package com.wecloud.dispatch.registry;
import com.wecloud.dispatch.ActionContext;
import com.wecloud.dispatch.extend.ActionRequest;
import com.wecloud.dispatch.extend.ArgumentBox;
import com.wecloud.dispatch.extend.MethodArgumentResolver;
import org.springframework.core.MethodParameter;
import java.util.LinkedList;
import java.util.List;
/**
* @author lixiaozhong
*/
public class MethodArgumentResolverRegistry {
List<MethodArgumentResolver> list = new LinkedList<>();
public void add(MethodArgumentResolver mar) {
list.add(mar);
}
public boolean supportsParameter(MethodParameter parameter) {
return (getArgumentResolver(parameter) != null);
}
public Object resolveArgument(ActionContext actionContext, MethodParameter parameter, ActionRequest request, ArgumentBox argumentBox) {
MethodArgumentResolver resolver = getArgumentResolver(parameter);
if (resolver == null) {
throw new IllegalArgumentException("Unknown parameter type [" + parameter.getParameterType().getName() + "]");
}
return resolver.resolveArgument(actionContext, parameter, request, argumentBox);
}
private MethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
MethodArgumentResolver result = null;
for (MethodArgumentResolver methodArgumentResolver : this.list) {
if (methodArgumentResolver.supportsParameter(parameter)) {
result = methodArgumentResolver;
break;
}
}
return result;
}
}
package com.wecloud.dispatch.util;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.core.type.filter.TypeFilter;
import org.springframework.util.ClassUtils;
import org.springframework.util.SystemPropertyUtils;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
/**
* @author lixiaozhong
*/
public class ClassScaner {
private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
private final List<TypeFilter> includeFilters = new LinkedList<TypeFilter>();
private final List<TypeFilter> excludeFilters = new LinkedList<TypeFilter>();
private MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(this.resourcePatternResolver);
public ClassScaner() {
}
public final ResourceLoader getResourceLoader() {
return this.resourcePatternResolver;
}
public void addIncludeFilter(TypeFilter includeFilter) {
this.includeFilters.add(includeFilter);
}
public void addExcludeFilter(TypeFilter excludeFilter) {
this.excludeFilters.add(0, excludeFilter);
}
public void resetFilters() {
this.includeFilters.clear();
this.excludeFilters.clear();
}
public Set<Class<?>> doScan(String basePackage) {
Set<Class<?>> classes = new HashSet<Class<?>>();
try {
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + org.springframework.util.ClassUtils.convertClassNameToResourcePath(SystemPropertyUtils.resolvePlaceholders(basePackage))
+ "/**/*.class";
Resource[] resources = this.resourcePatternResolver.getResources(packageSearchPath);
for (int i = 0; i < resources.length; i++) {
Resource resource = resources[i];
if (resource.isReadable()) {
MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource);
// boolean isEmpty = (includeFilters.size() == 0 && excludeFilters.size() == 0);
// if (isEmpty || matches(metadataReader)) {
if (matches(metadataReader)) {
String className = metadataReader.getClassMetadata().getClassName();
boolean isPresent = ClassUtils.isPresent(className, ClassScaner.class.getClassLoader());
if (isPresent) {
Class<?> classType = getClassByName(className);
if (null != classType) {
classes.add(classType);
}
}
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
return classes;
}
public Class<?> getClassByName(String className) {
try {
return Class.forName(className);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
public boolean matches(MetadataReader metadataReader) {
for (TypeFilter tf : this.excludeFilters) {
try {
if (tf.match(metadataReader, this.metadataReaderFactory)) {
return false;
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (includeFilters.isEmpty()) {
return true;
}
for (TypeFilter tf : this.includeFilters) {
try {
if (tf.match(metadataReader, this.metadataReaderFactory)) {
return true;
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return false;
}
public static Set<Class<?>> scan(String... basePackages) {
ClassScaner cs = new ClassScaner();
Set<Class<?>> classes = new HashSet<Class<?>>();
for (String s : basePackages) {
classes.addAll(cs.doScan(s));
}
return classes;
}
public static Set<Class<?>> scan(List<String> basePackages) {
ClassScaner cs = new ClassScaner();
Set<Class<?>> classes = new HashSet<Class<?>>();
for (String s : basePackages) {
classes.addAll(cs.doScan(s));
}
return classes;
}
public static Set<Class<?>> scan(String basePackage) {
ClassScaner cs = new ClassScaner();
return cs.doScan(basePackage);
}
@SuppressWarnings("unchecked")
public static Set<Class<?>> scan(String basePackage, Class<? extends Annotation>... annotations) {
ClassScaner cs = new ClassScaner();
for (Class<? extends Annotation> anno : annotations) {
cs.addIncludeFilter(new AnnotationTypeFilter(anno));
}
return cs.doScan(basePackage);
}
@SuppressWarnings({ "unchecked" })
public static Set<Class<?>> scan(String[] basePackages, Class<? extends Annotation>... annotations) {
ClassScaner cs = new ClassScaner();
for (Class<? extends Annotation> anno : annotations) {
cs.addIncludeFilter(new AnnotationTypeFilter(anno));
}
Set<Class<?>> classes = new HashSet<Class<?>>();
for (String s : basePackages) {
classes.addAll(cs.doScan(s));
}
return classes;
}
}
package com.wecloud.dispatch.util;
import java.lang.reflect.Modifier;
/**
* @author lixiaozhong
*/
public class ClassUtil {
/**
* 是否可被实例化
*
* @param classType
* @return
*/
public static boolean isCanInstance(Class<?> classType) {
boolean can = true;
boolean isAbstract = Modifier.isAbstract(classType.getModifiers());
if (classType.isAnnotation()) {
can = false;
} else if (classType.isEnum()) {
can = false;
} else if (classType.isInterface()) {
can = false;
} else if (isAbstract) {
can = false;
} else if (classType.isArray()) {
can = false;
}
return can;
}
}
package com.wecloud.im.netty.core; package com.wecloud.im.netty.core;
import com.wecloud.dispatch.general.GeneralMessageHandler;
import com.wecloud.im.executor.BusinessThreadPool; import com.wecloud.im.executor.BusinessThreadPool;
import com.wecloud.im.ws.manager.ChannelManager; import com.wecloud.im.ws.manager.ChannelManager;
import com.wecloud.im.ws.strategy.AbstractImCmdStrategy; import com.wecloud.im.ws.strategy.AbstractImCmdStrategy;
...@@ -30,6 +31,9 @@ public class WsReadHandler extends SimpleChannelInboundHandler<TextWebSocketFram ...@@ -30,6 +31,9 @@ public class WsReadHandler extends SimpleChannelInboundHandler<TextWebSocketFram
@Resource @Resource
private ChannelManager channelManager; private ChannelManager channelManager;
@Resource
private GeneralMessageHandler generalMessageHandler;
@Override @Override
protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) { protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) {
// 读空闲的计数清零 // 读空闲的计数清零
...@@ -70,6 +74,8 @@ public class WsReadHandler extends SimpleChannelInboundHandler<TextWebSocketFram ...@@ -70,6 +74,8 @@ public class WsReadHandler extends SimpleChannelInboundHandler<TextWebSocketFram
} }
AbstractImCmdStrategy.process(clientId, ctx, data); AbstractImCmdStrategy.process(clientId, ctx, data);
generalMessageHandler.doMessage(clientId, ctx, data);
} catch (Exception e) { } catch (Exception e) {
log.error("系统繁忙data:" + data + ",clientId:" + clientId + log.error("系统繁忙data:" + data + ",clientId:" + clientId +
......
...@@ -64,4 +64,6 @@ public class ImConstant implements Serializable { ...@@ -64,4 +64,6 @@ public class ImConstant implements Serializable {
*/ */
public static final String MSG_TYPE = "type"; public static final String MSG_TYPE = "type";
public static final String CMD = "cmd";
} }
...@@ -153,6 +153,20 @@ public class ChannelSender { ...@@ -153,6 +153,20 @@ public class ChannelSender {
* @param nioSocketChannel * @param nioSocketChannel
* @param responseModel * @param responseModel
*/ */
public void sendMsgLocal(NioSocketChannel nioSocketChannel, Object responseModel) {
String msgJson = JsonUtils.encodeJson(responseModel);
// 本地直接下发
nioSocketChannel.writeAndFlush(new TextWebSocketFrame(msgJson));
}
/**
* 本地直接下发,限定本机有的channel
*
* @param nioSocketChannel
* @param responseModel
*/
public void sendMsgLocal(NioSocketChannel nioSocketChannel, WsResponse responseModel) { public void sendMsgLocal(NioSocketChannel nioSocketChannel, WsResponse responseModel) {
String msgJson = JsonUtils.encodeJson(responseModel); String msgJson = JsonUtils.encodeJson(responseModel);
......
package com.wecloud.utils; package com.wecloud.utils;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.wecloud.im.ws.model.request.ReceiveVO;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.cglib.beans.BeanMap;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* fasterxml 的json工具类 * fasterxml 的json工具类
...@@ -21,6 +25,9 @@ import java.util.List; ...@@ -21,6 +25,9 @@ import java.util.List;
public class JsonUtils { public class JsonUtils {
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
static {
OBJECT_MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
}
/** /**
* Json格式的字符串向JavaBean转换,传入空串将返回null * Json格式的字符串向JavaBean转换,传入空串将返回null
...@@ -179,4 +186,49 @@ public class JsonUtils { ...@@ -179,4 +186,49 @@ public class JsonUtils {
return null; return null;
} }
} }
/**
* 判断字符也许是JSON
*
* @param string
* @return
*/
public static boolean maybeJson(String string) {
return maybeJsonArray(string) || maybeJsonObject(string);
}
/**
* 判断字符也许是JSONArray
*
* @param string
* @return
*/
public static boolean maybeJsonArray(String string) {
string = (null == string) ? string : string.trim();
return string != null && ("null".equals(string) || (string.startsWith("[") && string.endsWith("]")));
}
/**
* 判断字符也许是JSONObject
*
* @param string
* @return
*/
public static boolean maybeJsonObject(String string) {
string = (null == string) ? string : string.trim();
return string != null && ("null".equals(string) || (string.startsWith("{") && string.endsWith("}")));
}
/**
* 将map装换为javabean对象
*
* @param map
* @param bean
* @return
*/
public static <T> T mapToBean(Map<String, Object> map, T bean) {
BeanMap beanMap = BeanMap.create(bean);
beanMap.putAll(map);
return bean;
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment