|
|
@@ -2,6 +2,7 @@ package com.cnd3b.common.websocket;
|
|
|
|
|
|
import com.alibaba.fastjson.JSONObject;
|
|
|
import com.cnd3b.common.BaseClass;
|
|
|
+import com.cnd3b.common.D3BReturnObject_Err;
|
|
|
import com.cnd3b.common.data.Row;
|
|
|
import com.cnd3b.common.parameter.parameter;
|
|
|
|
|
|
@@ -9,37 +10,50 @@ import javax.websocket.*;
|
|
|
import javax.websocket.server.PathParam;
|
|
|
import javax.websocket.server.ServerEndpoint;
|
|
|
import java.io.IOException;
|
|
|
+import java.lang.reflect.Constructor;
|
|
|
+import java.lang.reflect.InvocationTargetException;
|
|
|
+import java.lang.reflect.Method;
|
|
|
import java.util.Arrays;
|
|
|
import java.util.Calendar;
|
|
|
-import java.util.Map;
|
|
|
-import java.util.concurrent.ConcurrentHashMap;
|
|
|
|
|
|
//ws://127.0.0.1:8080/samex/webSocket/829fef9884bbf7f9fb9c51499d7b332f
|
|
|
@ServerEndpoint("/webSocket/{accesstoken}")
|
|
|
public class WebClientSocket extends BaseClass {
|
|
|
|
|
|
- //websocket连接池
|
|
|
- public static Map<Long, WebClientSocket> websocketClients = new ConcurrentHashMap<Long, WebClientSocket>();
|
|
|
private Session session;
|
|
|
//当前连接对象的账号ID
|
|
|
private long userid;
|
|
|
private Row userRow;
|
|
|
+ private String accesstoken;
|
|
|
|
|
|
+ /**
|
|
|
+ * 连接开启
|
|
|
+ *
|
|
|
+ * @param accesstoken
|
|
|
+ * @param session
|
|
|
+ * @throws IOException
|
|
|
+ */
|
|
|
@OnOpen
|
|
|
private void onOpen(@PathParam("accesstoken") String accesstoken, Session session) throws IOException {
|
|
|
this.session = session;
|
|
|
+ this.accesstoken = accesstoken;
|
|
|
if (parameter.tokenlist.containsKey(accesstoken)) {
|
|
|
userid = parameter.tokenlist.get(accesstoken);
|
|
|
userRow = parameter.userIdList.get(userid);
|
|
|
} else {
|
|
|
- sendMessage("请登陆!");
|
|
|
+ return;
|
|
|
}
|
|
|
- websocketClients.put(userid, this);
|
|
|
+ parameter.websocketClients.put(userid, this);
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 连接关闭
|
|
|
+ *
|
|
|
+ * @throws IOException
|
|
|
+ */
|
|
|
@OnClose
|
|
|
private void onClose() throws IOException {
|
|
|
- websocketClients.remove(userid);
|
|
|
+ parameter.websocketClients.remove(userid);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -80,111 +94,150 @@ public class WebClientSocket extends BaseClass {
|
|
|
* @param messageObject
|
|
|
* @throws IOException
|
|
|
*/
|
|
|
+ /**
|
|
|
+ * 消息接收
|
|
|
+ *
|
|
|
+ * @param RequestContent
|
|
|
+ * @throws IOException
|
|
|
+ */
|
|
|
@OnMessage
|
|
|
- private void onMessage(String messageObject) throws IOException {
|
|
|
- JSONObject mesageObj = messageCheck(messageObject);
|
|
|
- if (mesageObj == null) {
|
|
|
+ private void onMessage(String RequestContent) throws IOException {
|
|
|
+ /**
|
|
|
+ * 验证请求正文是否为规范的SONObject格式
|
|
|
+ */
|
|
|
+ JSONObject requestcontent = null;
|
|
|
+ try {
|
|
|
+ requestcontent = JSONObject.parseObject(RequestContent);
|
|
|
+ } catch (Exception e) {
|
|
|
return;
|
|
|
}
|
|
|
- long dialogid = mesageObj.getLong("dialogid");//对话框ID
|
|
|
/**
|
|
|
- * 消息处理
|
|
|
+ * 验证请求正文中是否包含必填的键值
|
|
|
*/
|
|
|
- mesageObj = messageProcessing(mesageObj);
|
|
|
+ String[] mustkeys = {"classname", "method", "content"};
|
|
|
+ for (String mustkey : mustkeys) {
|
|
|
+ if (!requestcontent.containsKey(mustkey)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
/**
|
|
|
- * 消息发送
|
|
|
+ * 验证请求正文中的content是否为规范的SONObject格式
|
|
|
*/
|
|
|
- sendMessageToDialog(mesageObj.toJSONString(), dialogid);
|
|
|
- }
|
|
|
+ JSONObject content = new JSONObject();
|
|
|
+ try {
|
|
|
+ content = requestcontent.getJSONObject("content");
|
|
|
+ } catch (Exception e) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- public JSONObject messageProcessing(JSONObject mesageObj) {
|
|
|
- mesageObj.put("datetime", getDateTime_Str());
|
|
|
- mesageObj.put("messageid", String.valueOf(userid) + Calendar.getInstance().getTimeInMillis());
|
|
|
/**
|
|
|
- * 创建发送方信息
|
|
|
+ * 验证正文中的token是否有效
|
|
|
*/
|
|
|
- JSONObject sendfromObject = new JSONObject();
|
|
|
- sendfromObject.put("userid", userid);
|
|
|
- sendfromObject.put("siteid", userRow.getString("siteid"));
|
|
|
- sendfromObject.put("username", userRow.getString("fname"));
|
|
|
- mesageObj.put("sendfrom", sendfromObject);
|
|
|
+ String className = requestcontent.getString("classname");
|
|
|
|
|
|
- /**
|
|
|
- * 消息持久化,保存消息体mesageObj,字段:siteid,dialogid,userid,messageid,datetime,description,messagetype,mesageObj
|
|
|
- */
|
|
|
+ parameter.requesttime.put(accesstoken, Calendar.getInstance().getTime());
|
|
|
|
|
|
- return mesageObj;
|
|
|
- }
|
|
|
+ String methodName = requestcontent.getString("method");
|
|
|
+ if (content.isEmpty()) {
|
|
|
+ content = new JSONObject();
|
|
|
+ }
|
|
|
+ content.put("$classname", className);
|
|
|
+ content.put("$method", methodName);
|
|
|
+ content.put("$accesstoken", accesstoken);
|
|
|
|
|
|
- /**
|
|
|
- * 消息格式检查
|
|
|
- *
|
|
|
- * @param messageObject
|
|
|
- * @throws Exception
|
|
|
- */
|
|
|
- public JSONObject messageCheck(String messageObject) {
|
|
|
- JSONObject mesageObj = null;
|
|
|
- String errmsg = "";
|
|
|
+ String key = className + "." + methodName;
|
|
|
+ String result;
|
|
|
+ Object obj = null;
|
|
|
try {
|
|
|
- mesageObj = JSONObject.parseObject(messageObject);
|
|
|
+
|
|
|
+ long starttimes = Calendar.getInstance().getTimeInMillis();
|
|
|
+ /**
|
|
|
+ * 执行请求方法
|
|
|
+ */
|
|
|
+ Class clz = Class.forName("com.cnd3b.websocketcontroller." + className);
|
|
|
+ Constructor cla = clz.getDeclaredConstructor(JSONObject.class);
|
|
|
+ obj = cla.newInstance(content);
|
|
|
+ Method method = obj.getClass().getDeclaredMethod(methodName);
|
|
|
+ result = (String) method.invoke(obj);
|
|
|
+ long endtimes = Calendar.getInstance().getTimeInMillis();
|
|
|
+ saveCallMethodMsg(key, true, endtimes - starttimes);
|
|
|
+ } catch (ClassNotFoundException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ result = new D3BReturnObject_Err().setErrMsg("找不到指定的类" + className).toString();
|
|
|
+ } catch (InstantiationException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ result = new D3BReturnObject_Err().setErrMsg("类" + className + "实例化异常").toString();
|
|
|
+ } catch (IllegalAccessException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ result = new D3BReturnObject_Err().setErrMsg("类" + className + "安全权限异常,可能该类为非public类").toString();
|
|
|
+ } catch (NoSuchMethodException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ result = new D3BReturnObject_Err().setErrMsg("找不到指定的类" + className + "的" + methodName + "方法").toString();
|
|
|
+ } catch (IllegalArgumentException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ result = new D3BReturnObject_Err().setErrMsg("类" + className + "的" + methodName + "方法参数不合法").toString();
|
|
|
+ } catch (InvocationTargetException e) {
|
|
|
+ Throwable targetException = e.getTargetException();
|
|
|
+ D3BReturnObject_Err d3BReturnObject_err = new D3BReturnObject_Err();
|
|
|
+ d3BReturnObject_err.setErrMsg(targetException.getMessage());
|
|
|
+ result = d3BReturnObject_err.toString();
|
|
|
} catch (Exception e) {
|
|
|
- errmsg = "不是有效的JSONObject消息格式";
|
|
|
- }
|
|
|
- if (!mesageObj.containsKey("dialogid") || mesageObj.getLongValue("dialogid") <= 0) {
|
|
|
- errmsg = "dialogid缺失";
|
|
|
- }
|
|
|
- if (!mesageObj.containsKey("messagetype")) {
|
|
|
- errmsg = "messagetype缺失";
|
|
|
- }
|
|
|
- String messagetype = mesageObj.getString("messagetype");
|
|
|
- if (!Arrays.asList(new String[]{"text", "file", "data"}).contains(messagetype)) {
|
|
|
- errmsg = "无效的messagetype";
|
|
|
- }
|
|
|
- if (!mesageObj.containsKey("description") || "".equals(mesageObj.getString("description"))) {
|
|
|
- errmsg = "description缺失";
|
|
|
- }
|
|
|
- if (!mesageObj.containsKey("data")) {
|
|
|
- errmsg = "data缺失";
|
|
|
- }
|
|
|
- JSONObject data = mesageObj.getJSONObject("data");
|
|
|
- if ("text".equals(messagetype)) {
|
|
|
- if (!data.containsKey("message") || "".equals(mesageObj.getString("message"))) {
|
|
|
- errmsg = "text消息必须包含message";
|
|
|
- }
|
|
|
- } else if ("file".equals(messagetype)) {
|
|
|
- if (!data.containsKey("ownertable") || "".equals(mesageObj.getString("ownertable"))) {
|
|
|
- errmsg = "file消息必须包含ownertable";
|
|
|
- }
|
|
|
- if (!data.containsKey("ownerid") || "".equals(mesageObj.getString("ownerid"))) {
|
|
|
- errmsg = "file消息必须包含ownerid";
|
|
|
- }
|
|
|
- if (!data.containsKey("serialnumber") || "".equals(mesageObj.getString("serialnumber"))) {
|
|
|
- errmsg = "file消息必须包含serialnumber";
|
|
|
- }
|
|
|
- if (!data.containsKey("fobsurl") || "".equals(mesageObj.getString("fobsurl"))) {
|
|
|
- errmsg = "file消息必须包含fobsurl";
|
|
|
- }
|
|
|
- if (!data.containsKey("fdocument") || "".equals(mesageObj.getString("fdocument"))) {
|
|
|
- errmsg = "file消息必须包含fdocument";
|
|
|
- }
|
|
|
- } else if ("data".equals(messagetype)) {
|
|
|
- if (!data.containsKey("type") || "".equals(mesageObj.getString("type"))) {
|
|
|
- errmsg = "data消息必须包含type";
|
|
|
- }
|
|
|
- if (!data.containsKey("ownertable") || "".equals(mesageObj.getString("ownertable"))) {
|
|
|
- errmsg = "data消息必须包含ownertable";
|
|
|
- }
|
|
|
- if (!data.containsKey("ownerid") || "".equals(mesageObj.getString("ownerid"))) {
|
|
|
- errmsg = "data消息必须包含ownerid";
|
|
|
+ e.printStackTrace();
|
|
|
+ result = new D3BReturnObject_Err().setErrMsg("发生未知异常" + e.getMessage()).toString();
|
|
|
+ } finally {
|
|
|
+ if (obj != null) {
|
|
|
+ try {
|
|
|
+ obj.getClass().getMethod("p2ServerSystemPaoSetClose").invoke(obj);
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
- if (!"".equals(errmsg)) {
|
|
|
- sendMessage(errmsg);
|
|
|
- return null;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 记录请求数
|
|
|
+ *
|
|
|
+ * @param key
|
|
|
+ * @param fromdb
|
|
|
+ * @param time
|
|
|
+ */
|
|
|
+ private void saveCallMethodMsg(String key, boolean fromdb, long time) {
|
|
|
+ long callmethodTimes = parameter.callmethodTimes.containsKey(key) ? parameter.callmethodTimes.get(key) : 0L;
|
|
|
+
|
|
|
+ //更新请求总数
|
|
|
+ parameter.callmethodTimes.put(key, callmethodTimes + 1L);
|
|
|
+
|
|
|
+ //最新请求时间
|
|
|
+ parameter.lastcallmethodtime.put(key, Calendar.getInstance().getTime());
|
|
|
+
|
|
|
+ //从缓存获取的次数
|
|
|
+ long callmethod_fromcacheTimes = parameter.callmethod_fromcacheTimes.containsKey(key) ? parameter.callmethod_fromcacheTimes.get(key) : 0L;
|
|
|
+ if (!fromdb) {
|
|
|
+ /**
|
|
|
+ * 方法请求从缓存获取次数
|
|
|
+ */
|
|
|
+ parameter.callmethod_fromcacheTimes.put(key, callmethod_fromcacheTimes + 1L);
|
|
|
+ } else {
|
|
|
+ /**
|
|
|
+ * 方法请求查询最新耗时
|
|
|
+ */
|
|
|
+ parameter.callmethodLastTimeLong.put(key, time);
|
|
|
+
|
|
|
+
|
|
|
+ long totaltimes = callmethodTimes - callmethod_fromcacheTimes;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 方法请求查询平均时间
|
|
|
+ */
|
|
|
+ long callmethodTimeLong = parameter.callmethodTimeLong.containsKey(key) ? parameter.callmethodTimeLong.get(key) : 0L;
|
|
|
+
|
|
|
+ parameter.callmethodTimeLong.put(key, (callmethodTimeLong * totaltimes + time) / (totaltimes + 1));
|
|
|
}
|
|
|
- return mesageObj;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
@OnError
|
|
|
private void onError(Session session, Throwable error) {
|
|
|
error.printStackTrace();
|
|
|
@@ -192,38 +245,27 @@ public class WebClientSocket extends BaseClass {
|
|
|
|
|
|
|
|
|
/**
|
|
|
- * 对当前连接发送消息
|
|
|
+ * 对当前连接发送对话框消息
|
|
|
*
|
|
|
* @param message
|
|
|
*/
|
|
|
- public void sendMessage(String message) {
|
|
|
- session.getAsyncRemote().sendText(message);
|
|
|
+ public void sendDialogMessage(JSONObject message) {
|
|
|
+ JSONObject object = new JSONObject();
|
|
|
+ object.put("msgtype", "imdialog");
|
|
|
+ object.put("message", message);
|
|
|
+ session.getAsyncRemote().sendText(object.toJSONString());
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 向指定的对象发送消息
|
|
|
+ * 对当前连接发送系统消息
|
|
|
*
|
|
|
* @param message
|
|
|
- * @param toUserid
|
|
|
- * @throws IOException
|
|
|
*/
|
|
|
- public void sendMessageToUser(String message, long toUserid) throws IOException {
|
|
|
- if (websocketClients.containsKey(toUserid)) {
|
|
|
- websocketClients.get(toUserid).session.getAsyncRemote().sendText(message);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 向指定的d对话框发送消息
|
|
|
- *
|
|
|
- * @param message
|
|
|
- * @param dialogid
|
|
|
- * @throws IOException
|
|
|
- */
|
|
|
- public void sendMessageToDialog(String message, long dialogid) throws IOException {
|
|
|
- for (WebClientSocket item : websocketClients.values()) {
|
|
|
- item.session.getAsyncRemote().sendText(message);
|
|
|
- }
|
|
|
+ public void sendSystemMessage(JSONObject message) {
|
|
|
+ JSONObject object = new JSONObject();
|
|
|
+ object.put("msgtype", "system");
|
|
|
+ object.put("message", message);
|
|
|
+ session.getAsyncRemote().sendText(object.toJSONString());
|
|
|
}
|
|
|
|
|
|
|