.
This commit is contained in:
commit
e2f4e82323
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/out/
|
||||
*.iml
|
0
.idea/.gitignore
vendored
Normal file
0
.idea/.gitignore
vendored
Normal file
8
.idea/artifacts/z_im_jar.xml
Normal file
8
.idea/artifacts/z_im_jar.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<component name="ArtifactManager">
|
||||
<artifact type="jar" name="z-im:jar">
|
||||
<output-path>$PROJECT_DIR$/out/artifacts/z_im_jar</output-path>
|
||||
<root id="archive" name="HaoSportProject.jar">
|
||||
<element id="module-output" name="HaoSportProject" />
|
||||
</root>
|
||||
</artifact>
|
||||
</component>
|
8
.idea/compiler.xml
Normal file
8
.idea/compiler.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<annotationProcessing>
|
||||
<profile default="true" name="Default" enabled="true" />
|
||||
</annotationProcessing>
|
||||
</component>
|
||||
</project>
|
12
.idea/libraries/lib.xml
Normal file
12
.idea/libraries/lib.xml
Normal file
@ -0,0 +1,12 @@
|
||||
<component name="libraryTable">
|
||||
<library name="lib">
|
||||
<CLASSES>
|
||||
<root url="jar://D:/wk/libs/z-core.jar!/" />
|
||||
<root url="jar://D:/wk/libs/redkale.jar!/" />
|
||||
<root url="jar://D:/wk/libs/mysql-connector-java-8.0.18.jar!/" />
|
||||
<root url="jar://D:/wk/libs/lombok-1.18.20.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
6
.idea/misc.xml
Normal file
6
.idea/misc.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" project-jdk-name="17" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
8
.idea/modules.xml
Normal file
8
.idea/modules.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/ZimPlatfProject.iml" filepath="$PROJECT_DIR$/ZimPlatfProject.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
6
.idea/vcs.xml
Normal file
6
.idea/vcs.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
138
.idea/workspace.xml
Normal file
138
.idea/workspace.xml
Normal file
@ -0,0 +1,138 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ArtifactsWorkspaceSettings">
|
||||
<artifacts-to-build>
|
||||
<artifact name="z-im:jar" />
|
||||
</artifacts-to-build>
|
||||
</component>
|
||||
<component name="AutoImportSettings">
|
||||
<option name="autoReloadType" value="SELECTIVE" />
|
||||
</component>
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="22feb48f-4d0d-4bc6-b200-bfc5d6a85040" name="变更" comment=".">
|
||||
<change beforePath="$PROJECT_DIR$/conf/_conf/_config.properties" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/conf/_conf/application.xml" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/conf/application.xml" beforeDir="false" afterPath="$PROJECT_DIR$/conf/application.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/com/zchd/base/BaseEntity.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/com/zchd/base/BaseService.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/com/zchd/base/BaseService.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/com/zchd/base/info/SwearWordService.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/com/zchd/base/info/SwearWordService.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/com/zchd/base/util/FileKit.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/com/zchd/base/util/FileKit.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/com/zchd/base/util/PSubBean.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/com/zchd/base/util/QiniuUtils.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/com/zchd/zim/ImAccountService.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/com/zchd/zim/ImAccountService.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/com/zchd/zim/ImChatWebSocket.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/com/zchd/zim/ImChatWebSocket.java" afterDir="false" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||
</component>
|
||||
<component name="MarkdownSettingsMigration">
|
||||
<option name="stateVersion" value="1" />
|
||||
</component>
|
||||
<component name="ProjectId" id="2Hk3V13tpwIzPYUs3ORxKq2da8n" />
|
||||
<component name="ProjectLevelVcsManager">
|
||||
<OptionsSetting value="false" id="Update" />
|
||||
</component>
|
||||
<component name="ProjectViewState">
|
||||
<option name="hideEmptyMiddlePackages" value="true" />
|
||||
<option name="showLibraryContents" value="true" />
|
||||
</component>
|
||||
<component name="PropertiesComponent"><![CDATA[{
|
||||
"keyToString": {
|
||||
"RunOnceActivity.OpenProjectViewOnStart": "true",
|
||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||
"last_opened_file_path": "D:/wk/libs/lombok-1.18.20.jar",
|
||||
"project.structure.last.edited": "Problems",
|
||||
"project.structure.proportion": "0.15",
|
||||
"project.structure.side.proportion": "0.3137931",
|
||||
"settings.editor.selected.configurable": "preferences.pluginManager"
|
||||
}
|
||||
}]]></component>
|
||||
<component name="RecentsManager">
|
||||
<key name="CopyFile.RECENT_KEYS">
|
||||
<recent name="E:\wk-hao\HaoSportProject\out\artifacts\zim" />
|
||||
<recent name="E:\wk-hao\HaoSportProject\out\artifacts\libs" />
|
||||
</key>
|
||||
</component>
|
||||
<component name="RunManager">
|
||||
<configuration name="Unnamed" type="Application" factoryName="Application" nameIsGenerated="true">
|
||||
<option name="MAIN_CLASS_NAME" value="org.redkale.boot.Application" />
|
||||
<module name="ZimPlatfProject" />
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="应用程序级" UseSingleDictionary="true" transferred="true" />
|
||||
<component name="TaskManager">
|
||||
<task active="true" id="Default" summary="默认任务">
|
||||
<changelist id="22feb48f-4d0d-4bc6-b200-bfc5d6a85040" name="变更" comment="" />
|
||||
<created>1668815275339</created>
|
||||
<option name="number" value="Default" />
|
||||
<option name="presentableId" value="Default" />
|
||||
<updated>1668815275339</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00001" summary=".">
|
||||
<created>1668826741516</created>
|
||||
<option name="number" value="00001" />
|
||||
<option name="presentableId" value="LOCAL-00001" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1668826741516</updated>
|
||||
</task>
|
||||
<option name="localTasksCounter" value="2" />
|
||||
<servers />
|
||||
</component>
|
||||
<component name="Vcs.Log.Tabs.Properties">
|
||||
<option name="TAB_STATES">
|
||||
<map>
|
||||
<entry key="MAIN">
|
||||
<value>
|
||||
<State>
|
||||
<option name="FILTERS">
|
||||
<map>
|
||||
<entry key="user">
|
||||
<value>
|
||||
<list>
|
||||
<option value="*" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
</map>
|
||||
</option>
|
||||
</State>
|
||||
</value>
|
||||
</entry>
|
||||
</map>
|
||||
</option>
|
||||
<option name="RECENT_FILTERS">
|
||||
<map>
|
||||
<entry key="User">
|
||||
<value>
|
||||
<list>
|
||||
<RecentGroup>
|
||||
<option name="FILTER_VALUES">
|
||||
<option value="*" />
|
||||
</option>
|
||||
</RecentGroup>
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
</map>
|
||||
</option>
|
||||
</component>
|
||||
<component name="VcsManagerConfiguration">
|
||||
<MESSAGE value="." />
|
||||
<option name="LAST_COMMIT_MESSAGE" value="." />
|
||||
</component>
|
||||
<component name="XDebuggerManager">
|
||||
<breakpoint-manager>
|
||||
<breakpoints>
|
||||
<breakpoint enabled="true" type="java-exception">
|
||||
<properties class="java.nio.channels.AsynchronousCloseException" package="java.nio.channels" />
|
||||
<option name="timeStamp" value="2" />
|
||||
</breakpoint>
|
||||
</breakpoints>
|
||||
</breakpoint-manager>
|
||||
</component>
|
||||
</project>
|
44
conf/application.xml
Normal file
44
conf/application.xml
Normal file
@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<application port="2091" name="ZIM_LOCAL">
|
||||
<zhubs>
|
||||
<zhub name="zhub" addr="47.111.150.118:6066" groupid="zim-zhub" auth="zchd@123456"/>
|
||||
</zhubs>
|
||||
|
||||
<resources>
|
||||
<properties load="config.properties"></properties>
|
||||
<listener value="com.zdemo.ZhubListener"/>
|
||||
<listener value="com.zchd.base.AppListener"/>
|
||||
|
||||
<source name="int_cache" value="com.zdemo.cachex.MyRedisCacheSource">
|
||||
<node addr="47.111.150.118" password="*Zhong9307!" port="6064" db="0"/>
|
||||
</source>
|
||||
<source name="str_cache" value="com.zdemo.cachex.MyRedisCacheSource">
|
||||
<node addr="47.111.150.118" password="*Zhong9307!" port="6064" db="0"/>
|
||||
</source>
|
||||
<source name="long_cache" value="com.zdemo.cachex.MyRedisCacheSource">
|
||||
<node addr="47.111.150.118" password="*Zhong9307!" port="6064" db="0"/>
|
||||
</source>
|
||||
</resources>
|
||||
|
||||
<server protocol="HTTP" port="8091" maxbody="2m">
|
||||
<request>
|
||||
<remoteaddr value="request.headers.X-Real-IP"/>
|
||||
</request>
|
||||
|
||||
<rest autoload="true" base="com.zchd.base.BaseServlet" path="/"/>
|
||||
|
||||
<response>
|
||||
<addheader name="X-Node" value="system.property.APP_NODE"/>
|
||||
<addheader name="Access-Control-Allow-Methods" value="*"/>
|
||||
<addheader name="Access-Control-Max-Age" value="3600"/>
|
||||
<addheader name="Access-Control-Allow-Headers" value="*"/>
|
||||
<addheader name="Access-Control-Allow-Credentials" value="true"/>
|
||||
<addheader name="Access-Control-Allow-Origin" value="*"/>
|
||||
</response>
|
||||
|
||||
<services autoload="true"/>
|
||||
<servlets path="/"/>
|
||||
</server>
|
||||
|
||||
</application>
|
2
conf/config.properties
Normal file
2
conf/config.properties
Normal file
@ -0,0 +1,2 @@
|
||||
# swear
|
||||
# swearbasepath=/opt/swear
|
16
conf/logging.properties
Normal file
16
conf/logging.properties
Normal file
@ -0,0 +1,16 @@
|
||||
handlers=java.util.logging.ConsoleHandler
|
||||
############################################################
|
||||
.level=FINEST
|
||||
java.level=INFO
|
||||
javax.level=INFO
|
||||
com.sun.level=INFO
|
||||
sun.level=INFO
|
||||
jdk.level=INFO
|
||||
java.util.logging.FileHandler.level=FINE
|
||||
#10M
|
||||
java.util.logging.FileHandler.limit=10485760
|
||||
java.util.logging.FileHandler.count=10000
|
||||
java.util.logging.FileHandler.encoding=UTF-8
|
||||
java.util.logging.FileHandler.pattern=${APP_HOME}/logs-%m/log-%d.log
|
||||
java.util.logging.FileHandler.append=true
|
||||
java.util.logging.ConsoleHandler.level=FINEST
|
15
conf/persistence.xml
Normal file
15
conf/persistence.xml
Normal file
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
|
||||
|
||||
<persistence-unit name="z_im">
|
||||
<shared-cache-mode>ALL</shared-cache-mode>
|
||||
<properties>
|
||||
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://47.111.150.118:6063/z_im"/>
|
||||
<property name="javax.persistence.jdbc.user" value="vsport"/>
|
||||
<property name="javax.persistence.jdbc.password" value="*Zhong123098!"/>
|
||||
</properties>
|
||||
</persistence-unit>
|
||||
|
||||
</persistence>
|
32
src/com/zchd/base/AppListener.java
Normal file
32
src/com/zchd/base/AppListener.java
Normal file
@ -0,0 +1,32 @@
|
||||
package com.zchd.base;
|
||||
|
||||
import com.zchd.base.util.QueueTask;
|
||||
import org.redkale.boot.Application;
|
||||
import org.redkale.boot.ApplicationListener;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.File;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* 服务监听
|
||||
*
|
||||
* @author: liangxy.
|
||||
*/
|
||||
public class AppListener implements ApplicationListener {
|
||||
|
||||
private Logger logger = Logger.getLogger(this.getClass().getSimpleName());
|
||||
|
||||
@Resource(name = "APP_HOME")
|
||||
protected File APP_HOME;
|
||||
|
||||
@Override
|
||||
public void preStart(Application application) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preShutdown(Application application) {
|
||||
QueueTask.destroys();
|
||||
}
|
||||
}
|
24
src/com/zchd/base/BaseBean.java
Normal file
24
src/com/zchd/base/BaseBean.java
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package com.zchd.base;
|
||||
|
||||
import org.redkale.convert.json.JsonConvert;
|
||||
import org.redkale.service.RetResult;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author zhangjx
|
||||
*/
|
||||
public abstract class BaseBean implements Serializable {
|
||||
|
||||
public final static RetResult RESULT_SUCCESS = RetResult.success();
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JsonConvert.root().convertTo(this);
|
||||
}
|
||||
}
|
52
src/com/zchd/base/BaseService.java
Normal file
52
src/com/zchd/base/BaseService.java
Normal file
@ -0,0 +1,52 @@
|
||||
package com.zchd.base;
|
||||
|
||||
import com.zdemo.cachex.MyRedisCacheSource;
|
||||
import com.zdemo.zhub.ZHubClient;
|
||||
import org.redkale.convert.json.JsonConvert;
|
||||
import org.redkale.service.AbstractService;
|
||||
import org.redkale.service.RetResult;
|
||||
import org.redkale.source.DataSource;
|
||||
import org.redkale.util.Sheet;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class BaseService extends AbstractService {
|
||||
|
||||
protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName());
|
||||
protected final static RetResult RET_SUCCESS = RetResult.success();
|
||||
protected final static RetResult RET_EMPTY_SHEET = RetResult.success(new Sheet<>(0, List.of()));
|
||||
protected final static RetResult RET_EMPTY_LIST = RetResult.success(List.of());
|
||||
protected final JsonConvert convert = JsonConvert.root();
|
||||
|
||||
@Resource(name = "zhub")
|
||||
protected ZHubClient zhub;
|
||||
|
||||
@Resource(name = "int_cache")
|
||||
protected MyRedisCacheSource<Integer> intCache;
|
||||
|
||||
@Resource(name = "long_cache")
|
||||
protected MyRedisCacheSource<Long> longCache;
|
||||
|
||||
@Resource(name = "str_cache")
|
||||
protected MyRedisCacheSource<String> strCache;
|
||||
|
||||
@Resource(name = "z_im")
|
||||
protected DataSource zimSource;
|
||||
|
||||
@Resource(name = "APP_HOME")
|
||||
protected File APP_HOME;
|
||||
|
||||
@Resource(name = "APP_NAME")
|
||||
protected String APP_NAME = "";
|
||||
|
||||
protected RetResult retError(String info) {
|
||||
return new RetResult<>(100, info);
|
||||
}
|
||||
|
||||
protected RetResult retError(int code, String info) {
|
||||
return new RetResult<>(code, info);
|
||||
}
|
||||
}
|
49
src/com/zchd/base/BaseServlet.java
Normal file
49
src/com/zchd/base/BaseServlet.java
Normal file
@ -0,0 +1,49 @@
|
||||
package com.zchd.base;
|
||||
|
||||
import org.redkale.convert.json.JsonConvert;
|
||||
import org.redkale.net.http.HttpRequest;
|
||||
import org.redkale.net.http.HttpResponse;
|
||||
import org.redkale.net.http.HttpServlet;
|
||||
import org.redkale.service.RetResult;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.IOException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class BaseServlet extends HttpServlet {
|
||||
|
||||
protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName());
|
||||
|
||||
@Resource(name = "APP_NAME")
|
||||
protected String APP_NAME = "";
|
||||
|
||||
@Resource
|
||||
protected JsonConvert convert;
|
||||
|
||||
@Override
|
||||
protected void preExecute(HttpRequest request, HttpResponse response) throws IOException {
|
||||
|
||||
super.preExecute(request, response);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void authenticate(HttpRequest request, HttpResponse response) throws IOException {
|
||||
response.nextEvent();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void execute(HttpRequest request, HttpResponse response) throws IOException {
|
||||
try {
|
||||
super.execute(request, response);
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.WARNING, "", e);
|
||||
RetResult result = RetResult.success();
|
||||
result.setRetcode(100);
|
||||
result.setRetinfo("操作失败");
|
||||
response.finishJson(result);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
477
src/com/zchd/base/RetCodes.java
Normal file
477
src/com/zchd/base/RetCodes.java
Normal file
@ -0,0 +1,477 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package com.zchd.base;
|
||||
|
||||
import com.zchd.base.util.Utils;
|
||||
import org.redkale.service.RetLabel;
|
||||
import org.redkale.service.RetResult;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
/**
|
||||
* @author zhangjx
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public abstract class RetCodes {
|
||||
|
||||
//2000_0001 - 2999_9999 预留给 Redkale的扩展包redkalex使用
|
||||
//3000_0001 - 7999_9999 为平台系统使用
|
||||
//8000_0001 - 9999_9999 为OSS系统使用
|
||||
//------------------------------------- 通用模块 -----------------------------------------
|
||||
@RetLabel("参数无效")
|
||||
public static final int RET_PARAMS_ILLEGAL = 30010001;
|
||||
|
||||
@RetLabel("无上传文件")
|
||||
public static final int RET_UPLOAD_NOFILE = 30010002;
|
||||
|
||||
@RetLabel("上传文件过大")
|
||||
public static final int RET_UPLOAD_FILETOOBIG = 30010003;
|
||||
|
||||
@RetLabel("上传文件不是图片")
|
||||
public static final int RET_UPLOAD_NOTIMAGE = 30010004;
|
||||
|
||||
@RetLabel("文件写入失败")
|
||||
public static final int RET_FILE_WRITE_ERROR = 30010005;
|
||||
|
||||
@RetLabel("系统内部异常")
|
||||
public static final int RET_INNER_ILLEGAL = 30010006;
|
||||
|
||||
@RetLabel("调用远程接口异常")
|
||||
public static final int RET_REMOTE_ILLEGAL = 30010007;
|
||||
|
||||
@RetLabel("调用远程接口超时")
|
||||
public static final int RET_REMOTE_TIMEOUT = 30010008;
|
||||
|
||||
@RetLabel("重复操作")
|
||||
public static final int RET_REPEAT_ILLEGAL = 30010009;
|
||||
|
||||
@RetLabel("操作失败")
|
||||
public static final int RET_UNKNOWN_ERROR = 30010010;
|
||||
|
||||
@RetLabel("操作失败,包含敏感词")
|
||||
public static final int RET_SWEAR_ERROR = 30010011;
|
||||
|
||||
@RetLabel("网络繁忙,请稍后再试")
|
||||
public static final int RET_FREQUENCY_ERROR = 30010012;
|
||||
|
||||
@RetLabel("不在白名单内")
|
||||
public static final int RET_FREQUENCY_NOT_WHITE = 30010013;
|
||||
|
||||
@RetLabel("您操作速度太快,请稍后再试")
|
||||
public static final int RET_FREQUENCY_SPEED_FAST = 30010014;
|
||||
|
||||
@RetLabel("权限不足")
|
||||
public static final int RET_AUTH_ILLEGAL = 30010015;
|
||||
|
||||
@RetLabel("请求参数长度超出限制(2M)")
|
||||
public static final int RET_REQUEST_PARAM_LENGTH_OUT = 30010016;
|
||||
|
||||
@RetLabel("手速太快,请稍后再试")
|
||||
public static final int RET_REQUEST_UNIQUE = 30010017;
|
||||
|
||||
//------------------------------------- 用户模块 -----------------------------------------
|
||||
@RetLabel("未登陆")
|
||||
public static final int RET_USER_UNLOGIN = 30020001;
|
||||
|
||||
@RetLabel("用户登录失败")
|
||||
public static final int RET_USER_LOGIN_FAIL = 30020002;
|
||||
|
||||
@RetLabel("用户被禁用")
|
||||
public static final int RET_USER_FREEZED = 30020005;
|
||||
|
||||
@RetLabel("用户权限不够")
|
||||
public static final int RET_USER_AUTH_ILLEGAL = 30020006;
|
||||
|
||||
@RetLabel("用户不存在")
|
||||
public static final int RET_USER_NOTEXISTS = 30020007;
|
||||
|
||||
@RetLabel("用户状态异常")
|
||||
public static final int RET_USER_STATUS_ILLEGAL = 30020008;
|
||||
|
||||
@RetLabel("用户注册参数无效")
|
||||
public static final int RET_USER_SIGNUP_ILLEGAL = 30020009;
|
||||
|
||||
@RetLabel("用户性别参数无效")
|
||||
public static final int RET_USER_GENDER_ILLEGAL = 30020010;
|
||||
|
||||
@RetLabel("用户名无效")
|
||||
public static final int RET_USER_USERNAME_ILLEGAL = 30020011;
|
||||
|
||||
@RetLabel("用户账号无效")
|
||||
public static final int RET_USER_ACCOUNT_ILLEGAL = 30020012;
|
||||
|
||||
@RetLabel("手机号已存在")
|
||||
public static final int RET_USER_ACCOUNT_EXISTS = 30020013;
|
||||
|
||||
@RetLabel("手机号码无效")
|
||||
public static final int RET_USER_MOBILE_ILLEGAL = 30020014;
|
||||
|
||||
@RetLabel("手机号码已存在")
|
||||
public static final int RET_USER_MOBILE_EXISTS = 30020015;
|
||||
|
||||
@RetLabel("手机验证码发送过于频繁")
|
||||
public static final int RET_USER_MOBILE_SMSFREQUENT = 30020016;
|
||||
|
||||
@RetLabel("邮箱地址无效")
|
||||
public static final int RET_USER_EMAIL_ILLEGAL = 30020017;
|
||||
|
||||
@RetLabel("邮箱地址已存在")
|
||||
public static final int RET_USER_EMAIL_EXISTS = 30020018;
|
||||
|
||||
@RetLabel("微信绑定号无效")
|
||||
public static final int RET_USER_WXID_ILLEGAL = 30020019;
|
||||
|
||||
@RetLabel("微信绑定号已存在")
|
||||
public static final int RET_USER_WXID_EXISTS = 30020020;
|
||||
|
||||
@RetLabel("绑定微信号失败")
|
||||
public static final int RET_USER_WXID_BIND_FAIL = 30020021;
|
||||
|
||||
@RetLabel("QQ绑定号无效")
|
||||
public static final int RET_USER_QQID_ILLEGAL = 30020022;
|
||||
|
||||
@RetLabel("QQ绑定号已存在")
|
||||
public static final int RET_USER_QQID_EXISTS = 30020023;
|
||||
|
||||
@RetLabel("绑定QQ号失败")
|
||||
public static final int RET_USER_QQID_BIND_FAIL = 30020024;
|
||||
|
||||
@RetLabel("获取绑定QQ信息失败")
|
||||
public static final int RET_USER_QQID_INFO_FAIL = 30020025;
|
||||
|
||||
@RetLabel("验证码无效")
|
||||
public static final int RET_USER_RANDCODE_ILLEGAL = 30020026; //邮件或者短信验证码
|
||||
|
||||
@RetLabel("验证码已过期")
|
||||
public static final int RET_USER_RANDCODE_EXPIRED = 30020027; //邮件或者短信验证码
|
||||
|
||||
@RetLabel("验证码错误或失效")
|
||||
public static final int RET_USER_CAPTCHA_ILLEGAL = 30020028; //图片验证码
|
||||
|
||||
@RetLabel("用户类型无效")
|
||||
public static final int RET_USER_TYPE_ILLEGAL = 30020029;
|
||||
|
||||
@RetLabel("账号已在其他设备登录")
|
||||
public static final int RET_USER_LOGIN_ILLEGAL = 30020030;
|
||||
|
||||
@RetLabel("今日已签到")
|
||||
public static final int RET_QUESTS_DUTY_EXISTS = 30020031;
|
||||
|
||||
@RetLabel("父账号不存在")
|
||||
public static final int RET_USER_PARENT_ILLEGAL = 30020032;
|
||||
|
||||
@RetLabel("手机号码所在运营商不存在")
|
||||
public static final int RET_USER_MOBILE_NONET = 30020033;
|
||||
|
||||
@RetLabel("用户等级不够")
|
||||
public static final int RET_USER_LEVEL_ILLEGAL = 30020036;
|
||||
|
||||
@RetLabel("银行密码错误")
|
||||
public static final int RET_USER_BANKPWD_ILLEGAL = 30020037;
|
||||
|
||||
@RetLabel("用户已绑定在其他设备上了")
|
||||
public static final int RET_USER_APPTOKEN_BINDED = 30020039;
|
||||
|
||||
@RetLabel("短信发送失败")
|
||||
public static final int RET_SMS_SEND_ERROR = 30020041;
|
||||
|
||||
@RetLabel("同一设备注册次数达到上限")
|
||||
public static final int RET_USER_REG_APPSAME_LIMIT = 30020042;
|
||||
|
||||
@RetLabel("您的账号已被限制登录")
|
||||
public static final int RET_USER_LOGINORREG_LIMIT = 30020043;
|
||||
|
||||
@RetLabel("城信APP绑定号已存在")
|
||||
public static final int RET_USER_CXID_EXISTS = 30020044;
|
||||
|
||||
@RetLabel("禁止循环代理")
|
||||
public static final int RET_USER_AGENCY_REPEAT = 30020045;
|
||||
|
||||
@RetLabel("没有可提取的奖励")
|
||||
public static final int RET_USER_PROFIT_MONEY_ILLEGAL = 30020046;
|
||||
|
||||
@RetLabel("收款资料不全")
|
||||
public static final int RET_USER_PROFIT_CARD_ILLEGAL = 30020047;
|
||||
|
||||
@RetLabel("用户生日无效")
|
||||
public static final int RET_USER_BIRTHDAY_ILLEGAL = 30020048;
|
||||
|
||||
@RetLabel("举报参数无效")
|
||||
public static final int RET_USER_REPORT_ILLEGAL = 30020049;
|
||||
|
||||
@RetLabel("邀请码无效")
|
||||
public static final int RET_USER_INVITE_ILLEGAL = 30020050;
|
||||
|
||||
@RetLabel("此用户昵称已存在")
|
||||
public static final int RET_USERNAME_EXISTS = 30020051;
|
||||
|
||||
@RetLabel("昵称不可用")
|
||||
public static final int RET_USERNAME_ILLEGAL = 30020052;
|
||||
|
||||
@RetLabel("用户地址无效")
|
||||
public static final int RET_ADDR_ILLEGAL = 30020053;
|
||||
|
||||
@RetLabel("用户头像无效")
|
||||
public static final int RET_FACE_ILLEGAL = 30020054;
|
||||
|
||||
@RetLabel("用户封面无效")
|
||||
public static final int RET_USERCOVER_ILLEGAL = 30020055;
|
||||
|
||||
@RetLabel("第三方用户信息获取失败")
|
||||
public static final int RET_JTOKEN_ILLEGAL = 30020056;
|
||||
|
||||
@RetLabel("用户年龄参数无效")
|
||||
public static final int RET_USER_AGE_ILLEGAL = 30020057;
|
||||
|
||||
@RetLabel("接口调用Token无效")
|
||||
public static final int RET_USERCREATE_TOKEN_ILLEGAL = 30020057;
|
||||
|
||||
@RetLabel("抽奖券不足")
|
||||
public static final int RET_LUCK_DRAW_TICKET_ILLEGAL = 30020058;
|
||||
|
||||
@RetLabel("您的账号已被冻结")
|
||||
public static final int RET_USER_STATUS_FROZEN = 30020059;
|
||||
|
||||
@RetLabel("您已被禁言")
|
||||
public static final int RET_USER_STATUS_FREEZE = 30020060;
|
||||
|
||||
@RetLabel("邀请码已达到使用上限")
|
||||
public static final int RET_USER_INVITE_UPPER = 30020061;
|
||||
|
||||
@RetLabel("用户未激活")
|
||||
public static final int RET_USER_STATUS_PENDING = 30020062;
|
||||
|
||||
@RetLabel("用户未进行身份认证")
|
||||
public static final int RET_USER_IDENTITY_NOT_PROVED = 30020063;
|
||||
|
||||
@RetLabel("解绑后没有其它登录方式,不允许解绑")
|
||||
public static final int RET_USER_NOT_UNBIND = 30020065;
|
||||
|
||||
@RetLabel("已是推广员,请勿重复申请")
|
||||
public static final int RET_USER_ALREADY_PROMOTER = 30020066;
|
||||
|
||||
@RetLabel("请充值会员")
|
||||
public static final int RET_USER_VIP_ERROR = 30020067;
|
||||
|
||||
@RetLabel("已举报过,请勿重复举报")
|
||||
public static final int RET_USER_ALREADY_REPORT = 30020068;
|
||||
|
||||
@RetLabel("Apple Id绑定号已存在")
|
||||
public static final int RET_USER_APPLEID_EXISTS = 30020069;
|
||||
|
||||
@RetLabel("您的登录状态已过期")
|
||||
public static final int RET_USER_LOGIN_EXPIRE = 30020070;
|
||||
|
||||
@RetLabel("手机号已绑定其它第三方账号")
|
||||
public static final int RET_USER_MOBILE_BINDED = 30020071;
|
||||
|
||||
@RetLabel("名片背景图无效")
|
||||
public static final int RET_USER_CARD_IMG_ERROR = 30020072;
|
||||
|
||||
@RetLabel("未查询到用户收货地址")
|
||||
public static final int RET_USER_ADDRESS_NOT_EXISTS = 30020073;
|
||||
|
||||
@RetLabel("7天内只能修改1次,请稍后再试~")
|
||||
public static final int RET_USER_CHANGE_NAME_COUNT = 30020074;
|
||||
|
||||
@RetLabel("开通VIP解锁多张封面特权")
|
||||
public static final int RET_USER_BATCH_COVER_NO_VIP = 30020075;
|
||||
|
||||
@RetLabel("手机号已绑定其它账号")
|
||||
public static final int RET_MOBILE_BIND_OTHER = 30020076;
|
||||
|
||||
@RetLabel("手机号已注册V运动账号,是否确认绑定")
|
||||
public static final int RET_MOBILE_EXISTS_CONFIRM = 30020077;
|
||||
|
||||
@RetLabel("您的账号长时间未登录,为保证账号安全,请重新输入账号密码")
|
||||
public static final int RET_ACCOUNT_LOGIN_EXPIRE = 30020078;
|
||||
|
||||
|
||||
//----------------------------------------头衔认证-------------------------------------------------------------------
|
||||
@RetLabel("已申请或拥有此头衔")
|
||||
public static final int RET_IDENTITY_ALREADY_APPLY = 40100001;
|
||||
@RetLabel("不满足申请条件")
|
||||
public static final int RET_IDENTITY_CANNOT_APPLY = 40100002;
|
||||
@RetLabel("佩戴头衔超出限制")
|
||||
public static final int RET_IDENTITY_WEAR_ERROR = 40100003;
|
||||
@RetLabel("自定义头衔昵称为空")
|
||||
public static final int RET_IDENTITY_CUSTOM_NAME_ERROR = 40100004;
|
||||
@RetLabel("自定义头衔名称不能与提供的名称重复")
|
||||
public static final int RET_IDENTITY_NAME_REPEAT = 40100005;
|
||||
@RetLabel("未获得头衔")
|
||||
public static final int RET_IDENTITY_NOT_HAD = 40100006;
|
||||
@RetLabel("文件大小超过限制(3M)")
|
||||
public static final int RET_IDENTITY_FILE_LENGTH_OUT = 40100007;
|
||||
@RetLabel("文件类型超出限制(jpeg,jpg,png)")
|
||||
public static final int RET_IDENTITY_FILE_SUFFIX_OUT = 40100008;
|
||||
@RetLabel("未获取到身份证图片")
|
||||
public static final int RET_IDENTITY_FILE_NOTEXIST = 40100009;
|
||||
@RetLabel("填写信息与照片不符")
|
||||
public static final int RET_IDENTITY_FILE_NOTOK = 40100010;
|
||||
@RetLabel("上送人脸核身信息失败")
|
||||
public static final int RET_IDENTITY_FILE_UPLOADFACEID = 40100011;
|
||||
@RetLabel("身份证人像面信息读取失败")
|
||||
public static final int RET_IDENTITY_FACEID_FRONT_ERROR = 40100012;
|
||||
@RetLabel("身份证国徽面信息读取失败")
|
||||
public static final int RET_IDENTITY_FACEID_BACK_ERROR = 40100013;
|
||||
@RetLabel("未查询到实名认证申请记录")
|
||||
public static final int RET_IDENTITY_FACEID_INFO_ERROR = 40100014;
|
||||
@RetLabel("人脸核身识别失败")
|
||||
public static final int RET_IDENTITY_FACEID_IERROR = 40100015;
|
||||
@RetLabel("人脸核身返回名称或身份证号码不匹配")
|
||||
public static final int RET_IDENTITY_FACEID_NOTOK = 40100016;
|
||||
@RetLabel("Base64转文件失败")
|
||||
public static final int RET_IDENTITY_FILE_CREATE_ERROR = 40100017;
|
||||
@RetLabel("该身份证已与其他彩虹号绑定,如有疑问,请联系客服")
|
||||
public static final int RET_IDENTITY_REPEAT_ERROR = 40100018;
|
||||
@RetLabel("申请材料无效")
|
||||
public static final int RET_IDENTITY_APPLY_FILE_ERROR = 40100019;
|
||||
|
||||
//----------------------------------------------消息-------------------------------------------------------------
|
||||
|
||||
@RetLabel("消息参数不正确")
|
||||
public static final int RET_MESSAGE_ILLEGAL = 40150001;
|
||||
|
||||
@RetLabel("空白消息")
|
||||
public static final int RET_MESSAGE_EMPTY = 40150002;
|
||||
|
||||
@RetLabel("消息内容超长")
|
||||
public static final int RET_MESSAGE_TOO_LONG = 40150003;
|
||||
|
||||
@RetLabel("还不是好友关系")
|
||||
public static final int RET_MESSAGE_NOT_FRIEND = 40150004;
|
||||
|
||||
@RetLabel("消息含有敏感词")
|
||||
public static final int RET_MESSAGE_HAS_SENSITIVE_WORD = 40150005;
|
||||
|
||||
@RetLabel("图片信息有误")
|
||||
public static final int RET_MESSAGE_PICTURE_ERROR = 40150006;
|
||||
|
||||
@RetLabel("用户已被禁言")
|
||||
public static final int RET_MESSAGE_ACCOUNT_BANNED = 40150007;
|
||||
|
||||
//-----------------------------------------push-----------------------------------------------------
|
||||
@RetLabel("通知未开启")
|
||||
public static final int RET_PUSH_NOT_OPEN = 40160001;
|
||||
|
||||
//-----------------------------------------通用-----------------------------------------------------
|
||||
@RetLabel("访问内容不存在")
|
||||
public static final int RES_NON_EXISTENT = 40180001;
|
||||
|
||||
//-----------------------------------------其他临时-----------------------------------------------------
|
||||
@RetLabel("内容已被锁定")
|
||||
public static final int RET_ARTICLE_LOCKED = 40400001;
|
||||
|
||||
@RetLabel("身份证信息已存在")
|
||||
public static final int RET_IDCARD_EXISTS = 40400002;
|
||||
|
||||
protected static final Map<String, Map<Integer, String>> rets = RetLabel.RetLoader.loadMap(RetCodes.class);
|
||||
|
||||
protected static final Map<Integer, String> defret = rets.get("");
|
||||
public static final RetResult RET_SUCCESS = RetResult.success();
|
||||
|
||||
public static <T> RetResult<T> retResult(int retcode) {
|
||||
if (retcode == 0) {
|
||||
return RET_SUCCESS;
|
||||
}
|
||||
return new RetResult(retcode, retInfo(retcode));
|
||||
}
|
||||
|
||||
public static <T> RetResult<T> retResult(String locale, int retcode) {
|
||||
if (retcode == 0) {
|
||||
return RET_SUCCESS;
|
||||
}
|
||||
return new RetResult(retcode, retInfo(locale, retcode));
|
||||
}
|
||||
|
||||
public static <T> RetResult<T> retResult(int retcode, Object... args) {
|
||||
if (retcode == 0) {
|
||||
return RET_SUCCESS;
|
||||
}
|
||||
if (args == null || args.length < 1) {
|
||||
return new RetResult(retcode, retInfo(retcode));
|
||||
}
|
||||
String info = MessageFormat.format(retInfo(retcode), args);
|
||||
return new RetResult(retcode, info);
|
||||
}
|
||||
|
||||
public static <T> RetResult<T> retResult(String locale, int retcode, Object... args) {
|
||||
if (retcode == 0) {
|
||||
return RET_SUCCESS;
|
||||
}
|
||||
if (args == null || args.length < 1) {
|
||||
return new RetResult(retcode, retInfo(locale, retcode));
|
||||
}
|
||||
String info = MessageFormat.format(retInfo(locale, retcode), args);
|
||||
return new RetResult(retcode, info);
|
||||
}
|
||||
|
||||
public static <T> CompletableFuture<RetResult<T>> retResultFuture(int retcode) {
|
||||
return CompletableFuture.completedFuture(retResult(retcode));
|
||||
}
|
||||
|
||||
public static <T> CompletableFuture<RetResult<T>> retResultFuture(String locale, int retcode) {
|
||||
return CompletableFuture.completedFuture(retResult(locale, retcode));
|
||||
}
|
||||
|
||||
public static <T> CompletableFuture<RetResult<T>> retResultFuture(int retcode, Object... args) {
|
||||
return CompletableFuture.completedFuture(retResult(retcode, args));
|
||||
}
|
||||
|
||||
public static <T> CompletableFuture<RetResult<T>> retResultFuture(String locale, int retcode, Object... args) {
|
||||
return CompletableFuture.completedFuture(retResult(locale, retcode, args));
|
||||
}
|
||||
|
||||
public static RetResult set(RetResult result, int retcode, Object... args) {
|
||||
if (retcode == 0) {
|
||||
return result.retcode(0).retinfo("");
|
||||
}
|
||||
if (args == null || args.length < 1) {
|
||||
return result.retcode(retcode).retinfo(retInfo(retcode));
|
||||
}
|
||||
String info = MessageFormat.format(retInfo(retcode), args);
|
||||
return result.retcode(retcode).retinfo(info);
|
||||
}
|
||||
|
||||
public static RetResult set(RetResult result, String locale, int retcode, Object... args) {
|
||||
if (retcode == 0) {
|
||||
return result.retcode(0).retinfo("");
|
||||
}
|
||||
if (args == null || args.length < 1) {
|
||||
return result.retcode(retcode).retinfo(retInfo(locale, retcode));
|
||||
}
|
||||
String info = MessageFormat.format(retInfo(locale, retcode), args);
|
||||
return result.retcode(retcode).retinfo(info);
|
||||
}
|
||||
|
||||
public static String retInfo(int retcode) {
|
||||
if (retcode == 0) {
|
||||
return "Success";
|
||||
}
|
||||
return defret.getOrDefault(retcode, "Error");
|
||||
}
|
||||
|
||||
public static String retInfo(String locale, int retcode) {
|
||||
if (locale == null || locale.isEmpty()) {
|
||||
return retInfo(retcode);
|
||||
}
|
||||
if (retcode == 0) {
|
||||
return "Success";
|
||||
}
|
||||
String key = locale == null ? "" : locale;
|
||||
Map<Integer, String> map = rets.get(key);
|
||||
if (map == null) {
|
||||
return "Error";
|
||||
}
|
||||
return map.getOrDefault(retcode, "Error");
|
||||
}
|
||||
|
||||
public static RetResult retResult(RetResult codeRet) {
|
||||
return Utils.copy(new RetResult<>(), codeRet);
|
||||
}
|
||||
}
|
16
src/com/zchd/base/info/Swear.java
Normal file
16
src/com/zchd/base/info/Swear.java
Normal file
@ -0,0 +1,16 @@
|
||||
package com.zchd.base.info;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import static java.lang.annotation.ElementType.FIELD;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
/**
|
||||
* 敏感词配置检查
|
||||
*/
|
||||
@Target(FIELD)
|
||||
@Retention(RUNTIME)
|
||||
public @interface Swear {
|
||||
String name() default "";
|
||||
}
|
33
src/com/zchd/base/info/SwearRpcReq.java
Normal file
33
src/com/zchd/base/info/SwearRpcReq.java
Normal file
@ -0,0 +1,33 @@
|
||||
package com.zchd.base.info;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.redkale.util.Comment;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author YLZ FUTURE MADE
|
||||
* @date 2021/10/15 10:42
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class SwearRpcReq implements Serializable {
|
||||
|
||||
@Comment("敏感词内容")
|
||||
private String content;
|
||||
@Comment("敏感词检测类型 MinMatchTYpe:最小匹配规则,如:敏感词库[\"中国\",\"中国人\"],语句:\"我是中国人\",匹配结果:我是[中国]人\n" +
|
||||
" * MaxMatchType:最大匹配规则,如:敏感词库[\"中国\",\"中国人\"],语句:\"我是中国人\",匹配结果:我是[中国人]")
|
||||
private int matchType = 1;
|
||||
@Comment("替换的敏感字")
|
||||
private char replaceChar = '*';
|
||||
@Comment("替换的敏感词")
|
||||
private String replace = "";
|
||||
|
||||
public static SwearRpcReq build(String content) {
|
||||
SwearRpcReq bean = new SwearRpcReq();
|
||||
bean.setContent(content);
|
||||
return bean;
|
||||
}
|
||||
|
||||
}
|
168
src/com/zchd/base/info/SwearWordService.java
Normal file
168
src/com/zchd/base/info/SwearWordService.java
Normal file
@ -0,0 +1,168 @@
|
||||
package com.zchd.base.info;
|
||||
|
||||
import com.zchd.base.BaseService;
|
||||
import com.zchd.base.RetCodes;
|
||||
import com.zchd.base.util.FileKit;
|
||||
import com.zchd.base.util.QueueTasks;
|
||||
import com.zchd.base.util.Utils;
|
||||
import org.redkale.net.http.RestMapping;
|
||||
import org.redkale.net.http.RestService;
|
||||
import org.redkale.service.RetResult;
|
||||
import org.redkale.util.AnyValue;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
|
||||
@RestService(name = "swearword", comment = "敏感词服务")
|
||||
public class SwearWordService extends BaseService {
|
||||
|
||||
protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName());
|
||||
|
||||
@Resource(name = "APP_HOME")
|
||||
protected File APP_HOME;
|
||||
|
||||
@Resource(name = "property.swearbasepath")
|
||||
private String swearbasepath;
|
||||
|
||||
private Set<String> words = new HashSet<>();
|
||||
|
||||
@Override
|
||||
public void init(AnyValue config) {
|
||||
QueueTasks.add(() -> {
|
||||
reload();
|
||||
zhub.subscribe("sport:swearword-reload", x -> {
|
||||
reload();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@RestMapping(name = "reload", comment = "加载敏感词")
|
||||
public RetResult reload() {
|
||||
if (Utils.isEmpty(swearbasepath)) {
|
||||
return RET_SUCCESS;
|
||||
}
|
||||
String swearpath = swearbasepath.replace("${APP_HOME}", APP_HOME.getPath());
|
||||
File dir = new File(swearpath);
|
||||
if (!dir.exists()) {
|
||||
return null;
|
||||
}
|
||||
words.clear();
|
||||
for (File file : dir.listFiles()) {
|
||||
if (!file.isFile()) continue;
|
||||
try {
|
||||
FileInputStream in = new FileInputStream(file);
|
||||
LineNumberReader reader = new LineNumberReader(new InputStreamReader(in, "UTF-8"));
|
||||
String line;
|
||||
int n = words.size();
|
||||
while ((line = reader.readLine()) != null) {
|
||||
words.add(Utils.unicodeToCn(line).trim());
|
||||
}
|
||||
words.remove("");
|
||||
words.remove("null");
|
||||
words.remove("9");
|
||||
logger.log(Level.INFO, String.format("loaded swear file :%s, add new words: %d", file.getName(), words.size() - n));
|
||||
reader.close();
|
||||
} catch (FileNotFoundException | UnsupportedEncodingException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
return RET_SUCCESS;
|
||||
}
|
||||
|
||||
@RestMapping(name = "check", auth = false)
|
||||
public RetResult check(String str) {
|
||||
for (String word : words) {
|
||||
if (str.contains(word)) {
|
||||
RetResult<Object> result = new RetResult<>();
|
||||
result.setRetcode(RetCodes.RET_SWEAR_ERROR);
|
||||
result.setRetinfo(word);
|
||||
FileKit.append(result.getRetinfo(), new File("/tmp/swearword.txt"));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return RET_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* 实体中属性敏感词 检查
|
||||
* 调用前需配置实体属性 @Swear
|
||||
*
|
||||
* @param obj
|
||||
* @return
|
||||
*/
|
||||
public RetResult _checkBean(Object obj) {
|
||||
if (obj == null) {
|
||||
return RET_SUCCESS;
|
||||
}
|
||||
|
||||
Class clazz = obj.getClass();
|
||||
Field[] fields = clazz.getDeclaredFields();
|
||||
for (Field field : fields) {
|
||||
Swear swear = field.getAnnotation(Swear.class);
|
||||
if (swear != null) {
|
||||
try {
|
||||
field.setAccessible(true);
|
||||
Object str = field.get(obj);
|
||||
RetResult result = str instanceof String ? check((String) str) : RetResult.success();
|
||||
if (!result.isSuccess()) {
|
||||
String name = swear.name();
|
||||
if (!Utils.isEmpty(name)) {
|
||||
result.setRetinfo(name + "包含敏感词[" + result.getRetinfo() + "]");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return RET_SUCCESS;
|
||||
}
|
||||
|
||||
public RetResult checkBean(Object obj) {
|
||||
if (obj == null) {
|
||||
return RET_SUCCESS;
|
||||
}
|
||||
|
||||
Class clazz = obj.getClass();
|
||||
Field[] fields = clazz.getDeclaredFields();
|
||||
for (Field field : fields) {
|
||||
Swear swear = field.getAnnotation(Swear.class);
|
||||
if (swear != null) {
|
||||
try {
|
||||
field.setAccessible(true);
|
||||
String str = (String) field.get(obj);
|
||||
|
||||
RetResult result;
|
||||
do {
|
||||
result = str instanceof String ? check(str) : RetResult.success();
|
||||
if (!result.isSuccess()) {
|
||||
FileKit.append(result.getRetinfo(), new File("/tmp/swearword.txt"));
|
||||
str = str.replace(result.getRetinfo(), "*");
|
||||
} else {
|
||||
field.set(obj, str);
|
||||
}
|
||||
} while (!result.isSuccess());
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return RET_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
}
|
160
src/com/zchd/base/util/FileKit.java
Normal file
160
src/com/zchd/base/util/FileKit.java
Normal file
@ -0,0 +1,160 @@
|
||||
package com.zchd.base.util;
|
||||
|
||||
|
||||
import org.redkale.convert.json.JsonConvert;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Type;
|
||||
import java.net.URL;
|
||||
import java.net.URLDecoder;
|
||||
import java.nio.file.Files;
|
||||
|
||||
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
/**
|
||||
* Created by liangxianyou at 2018/5/31 10:23.
|
||||
*/
|
||||
public final class FileKit {
|
||||
|
||||
private FileKit() {
|
||||
}
|
||||
|
||||
public static void strToFile(String entityBody, File file) {
|
||||
strToFile(entityBody, file, true);
|
||||
}
|
||||
|
||||
public static void strToFile(String entityBody, File file, boolean existDel) {
|
||||
if (file.exists()) {
|
||||
if (existDel) {
|
||||
file.delete();
|
||||
} else {
|
||||
throw new RuntimeException(file.getPath() + "已经存在");
|
||||
}
|
||||
}
|
||||
|
||||
if (!file.getParentFile().exists()) {
|
||||
file.getParentFile().mkdirs();
|
||||
}
|
||||
try (FileOutputStream out = new FileOutputStream(file)) {
|
||||
out.write(entityBody.getBytes("UTF-8"));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void append(String str, File file) {
|
||||
if (!file.getParentFile().exists()) {
|
||||
file.getParentFile().mkdirs();
|
||||
}
|
||||
|
||||
try (FileOutputStream out = new FileOutputStream(file, true)) {
|
||||
out.write(str.getBytes("UTF-8"));
|
||||
if (!str.endsWith("\n")) {
|
||||
out.write("\n".getBytes("UTF-8"));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 拷贝文件/文件目录
|
||||
*
|
||||
* @param source 源文件目录
|
||||
* @param target 目标目录
|
||||
*/
|
||||
private static void copyFiles(File source, File target) {
|
||||
copyFiles(source, target, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* 拷贝文件/文件目录
|
||||
*
|
||||
* @param source
|
||||
* @param target
|
||||
* @param linkPath
|
||||
*/
|
||||
public static void copyFiles(File source, File target, String linkPath) {
|
||||
if (source.isDirectory()) {
|
||||
final String _linkPath = linkPath + File.separator + source.getName();
|
||||
asList(source.listFiles()).forEach(f -> {
|
||||
copyFiles(f, target, _linkPath);
|
||||
});
|
||||
} else if (source.isFile()) {
|
||||
try {
|
||||
String _linkPath = "";
|
||||
int index = linkPath.indexOf(File.separator, 1);
|
||||
if (index > 0) {
|
||||
_linkPath = linkPath.substring(index);
|
||||
}
|
||||
File targetFile = new File(target.toPath() + _linkPath + File.separator + source.getName());
|
||||
if (!targetFile.getParentFile().exists()) {
|
||||
targetFile.getParentFile().mkdirs();
|
||||
}
|
||||
|
||||
Files.copy(source.toPath(), targetFile.toPath(), REPLACE_EXISTING);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 clazz的路径,如果是jar里面的文件得到jar存放的目录,如:lib
|
||||
*
|
||||
* @param clazz
|
||||
* @return
|
||||
*/
|
||||
public static String rootPath(Class clazz) {
|
||||
//return clazz.getClassLoader().getResource("").getPath();
|
||||
URL url = clazz.getProtectionDomain().getCodeSource().getLocation();
|
||||
try {
|
||||
String filePath = URLDecoder.decode(url.getPath(), "utf-8");
|
||||
if (filePath.endsWith(".jar")) {
|
||||
return filePath.substring(0, filePath.lastIndexOf("/") + 1);
|
||||
}
|
||||
return filePath;
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
public static String rootPath() {
|
||||
return rootPath(FileKit.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取流内的所有内容
|
||||
*
|
||||
* @param inputStream
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
public static String readAll(InputStream inputStream) {
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
|
||||
StringBuffer buf = new StringBuffer();
|
||||
String str;
|
||||
try {
|
||||
while ((str = reader.readLine()) != null) {
|
||||
buf.append(str + "\n");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
public static <T> T readAs(File file, Type typeToken) throws IOException {
|
||||
try (
|
||||
FileInputStream inputStream = new FileInputStream(file)
|
||||
) {
|
||||
return JsonConvert.root().convertFrom(typeToken, inputStream);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
325
src/com/zchd/base/util/Kv.java
Normal file
325
src/com/zchd/base/util/Kv.java
Normal file
@ -0,0 +1,325 @@
|
||||
package com.zchd.base.util;
|
||||
|
||||
import org.redkale.convert.json.JsonConvert;
|
||||
|
||||
import javax.persistence.Id;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* Created by liangxianyou@eversec.cn at 2018/3/12 14:17.
|
||||
*/
|
||||
public class Kv<K, V> extends LinkedHashMap<K, V> {
|
||||
public static Kv of() {
|
||||
return new Kv();
|
||||
}
|
||||
|
||||
public static Kv of(Object k, Object v) {
|
||||
return new Kv().set(k, v);
|
||||
}
|
||||
|
||||
public static Kv filter(Map<String, String> map, String... fields) {
|
||||
Kv kv = Kv.of();
|
||||
if (fields == null || fields.length == 0 || map == null) {
|
||||
return kv;
|
||||
}
|
||||
|
||||
for (String field : fields) {
|
||||
if (field.contains("->")) {
|
||||
String[] arr = field.split("->");
|
||||
kv.put(arr[1], map.get(arr[0]));
|
||||
continue;
|
||||
}
|
||||
|
||||
kv.put(field, map.get(field));
|
||||
}
|
||||
return kv;
|
||||
}
|
||||
|
||||
public Kv<K, V> set(K k, V v) {
|
||||
put(k, v);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Kv<K, V> putAll(Kv<K, V> kv) {
|
||||
kv.forEach((k, v) -> put(k, v));
|
||||
return this;
|
||||
}
|
||||
|
||||
// 将obj 属性映射到Kv 中
|
||||
public static Kv toKv(Object m, String... fields) {
|
||||
Kv kv = Kv.of();
|
||||
if (m == null) {
|
||||
return kv;
|
||||
}
|
||||
Stream.of(fields).forEach(field -> {
|
||||
String filedT = field;
|
||||
String filedS = field;
|
||||
|
||||
try {
|
||||
if (field.contains("=")) {
|
||||
String[] arr = field.split("=");
|
||||
filedT = arr[0];
|
||||
filedS = arr[1];
|
||||
}
|
||||
|
||||
Method method = m.getClass().getMethod("get" + Utils.toUpperCaseFirst(filedS));
|
||||
if (method != null) {
|
||||
kv.set(filedT, method.invoke(m));
|
||||
}
|
||||
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
|
||||
new IllegalArgumentException(String.format("Kv.toKv获取 获取参数[]失败", field), e);
|
||||
}
|
||||
});
|
||||
|
||||
return kv;
|
||||
}
|
||||
|
||||
public static <T> List<Kv> toKv(Collection<T> datas, String... fields) {
|
||||
return datas.stream().map(x -> toKv(x, fields)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static Kv toKv(Object m) {
|
||||
return toKv(m, Kv.of(), m.getClass());
|
||||
}
|
||||
|
||||
private static Kv toKv(Object m, Kv kv, Class clazz) {
|
||||
Method[] methods = clazz.getMethods();
|
||||
for (Method method : methods) {
|
||||
if (!method.getName().startsWith("get") || method.getParameterCount() > 0 || "getClass".equals(method.getName()))
|
||||
continue;
|
||||
|
||||
String k = Utils.toLowerCaseFirst(method.getName().replaceFirst("get", ""));
|
||||
if (!kv.containsKey(k) || Utils.isEmpty(kv.get(k))) {
|
||||
try {
|
||||
kv.set(k, method.invoke(m));
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (Field field : clazz.getDeclaredFields()) {
|
||||
if (field.getAnnotation(Id.class) != null) {
|
||||
try {
|
||||
field.setAccessible(true);
|
||||
kv.set("_id", field.get(m));
|
||||
break;
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Class superclass = clazz.getSuperclass();
|
||||
if (superclass != null) {
|
||||
kv = toKv(m, kv, superclass);
|
||||
}
|
||||
return kv;
|
||||
}
|
||||
|
||||
public <T> T toBean(Class<T> type) {
|
||||
return toBean(this, type);
|
||||
}
|
||||
|
||||
// 首字母大写
|
||||
private static Function<String, String> upFirst = (s) -> {
|
||||
return s.substring(0, 1).toUpperCase() + s.substring(1);
|
||||
};
|
||||
|
||||
private static Predicate<Class> isNumber = (t) -> {
|
||||
return t == Integer.class || t == int.class
|
||||
|| t == Long.class || t == long.class
|
||||
|| t == Float.class || t == float.class
|
||||
|| t == Double.class || t == double.class
|
||||
|| t == Short.class || t == short.class
|
||||
|| t == Byte.class || t == byte.class
|
||||
;
|
||||
};
|
||||
|
||||
public static <T> T toAs(Object v, Class<T> clazz) {
|
||||
if (v == null) {
|
||||
return null;
|
||||
} else if (v.getClass() == clazz) {
|
||||
return (T) v;
|
||||
} else if (clazz == String.class) {
|
||||
return (T) String.valueOf(v);
|
||||
}
|
||||
|
||||
Object v1 = v;
|
||||
try {
|
||||
|
||||
if (v.getClass() == Long.class) {//多种数值类型的处理: Long => x
|
||||
switch (clazz.getSimpleName()) {
|
||||
case "int", "Integer" -> v1 = (int) (long) v;
|
||||
case "short", "Short" -> v1 = (short) (long) v;
|
||||
case "float", "Float" -> v1 = (float) (long) v;
|
||||
case "byte", "Byte" -> v1 = (byte) (long) v;
|
||||
}
|
||||
} else if (v.getClass() == Double.class) {
|
||||
if (isNumber.test(clazz)) {
|
||||
switch (clazz.getSimpleName()) {
|
||||
case "long", "Long" -> v1 = (long) (double) v;
|
||||
case "int", "Integer" -> v1 = (int) (double) v;
|
||||
case "short", "Short" -> v1 = (short) (double) v;
|
||||
case "float", "Float" -> v1 = (float) (double) v;
|
||||
case "byte", "Byte" -> v1 = (byte) (double) v;
|
||||
}
|
||||
} else if (clazz == String.class) {
|
||||
v1 = String.valueOf(v);
|
||||
}
|
||||
} else if (v.getClass() == String.class) {
|
||||
switch (clazz.getSimpleName()) {
|
||||
case "Date" -> v1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse((String) v);
|
||||
case "short", "Short" -> v1 = (short) Double.parseDouble((String) v);
|
||||
case "float", "Float" -> v1 = (float) Double.parseDouble((String) v);
|
||||
case "int", "Integer" -> v1 = (int) Double.parseDouble((String) v);
|
||||
case "long", "Long" -> v1 = (long) Double.parseDouble((String) v);
|
||||
case "double", "Double" -> v1 = Double.parseDouble((String) v);
|
||||
case "byte", "Byte" -> v1 = Byte.parseByte((String) v);
|
||||
}
|
||||
} else if (v.getClass() == Integer.class) {
|
||||
switch (clazz.getSimpleName()) {
|
||||
case "long", "Long" -> v1 = (long) (int) v;
|
||||
case "short", "Short" -> v1 = (short) (int) v;
|
||||
case "float", "Float" -> v1 = (float) (int) v;
|
||||
case "byte", "Byte" -> v1 = (byte) (int) v;
|
||||
}
|
||||
} else if (v.getClass() == Float.class) {
|
||||
switch (clazz.getSimpleName()) {
|
||||
case "long", "Long" -> v1 = (long) (float) v;
|
||||
case "int", "Integer" -> v1 = (int) (float) v;
|
||||
case "short", "Short" -> v1 = (short) (float) v;
|
||||
case "byte", "Byte" -> v1 = (byte) (float) v;
|
||||
}
|
||||
} else {
|
||||
v1 = v;
|
||||
}
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return (T) v1;
|
||||
}
|
||||
|
||||
public static <T> T toBean(Map map, Class<T> clazz) {
|
||||
//按照方法名 + 类型寻找,
|
||||
//按照方法名 寻找
|
||||
//+
|
||||
Object obj = null;
|
||||
try {
|
||||
obj = clazz.getDeclaredConstructor().newInstance();
|
||||
} catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
|
||||
new IllegalArgumentException("创建对象实列失败", e); // 检查clazz是否有无参构造
|
||||
}
|
||||
|
||||
for (String k : (Set<String>) map.keySet()) {
|
||||
Object v = map.get(k);
|
||||
if (v == null) continue;
|
||||
//寻找method
|
||||
try {
|
||||
String methodName = "set" + upFirst.apply(k);
|
||||
Class tClazz = null;
|
||||
Method method = null;
|
||||
try {
|
||||
method = clazz.getMethod(methodName, tClazz = v.getClass());
|
||||
} catch (NoSuchMethodException e) {
|
||||
//e.printStackTrace();
|
||||
}
|
||||
if (method == null) {
|
||||
for (Method _method : clazz.getMethods()) {
|
||||
if (methodName.equals(_method.getName()) && _method.getParameterCount() == 1) {
|
||||
method = _method;
|
||||
tClazz = _method.getParameterTypes()[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (method == null) {
|
||||
for (Method _method : clazz.getMethods()) {
|
||||
if (methodName.equalsIgnoreCase(_method.getName()) && _method.getParameterCount() == 1) {
|
||||
method = _method;
|
||||
tClazz = _method.getParameterTypes()[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (method != null) {
|
||||
method.invoke(obj, toAs(v, tClazz));
|
||||
}
|
||||
|
||||
//没有方法,找属性注解
|
||||
/*if (method == null) {
|
||||
Field field = null;
|
||||
Field[] fields = clazz.getDeclaredFields();
|
||||
for (Field _field : fields) {
|
||||
To to = _field.getAnnotation(To.class);
|
||||
if (to != null && k.equals(to.value())) {
|
||||
field = _field;
|
||||
tClazz = _field.getType();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (field != null) {
|
||||
field.setAccessible(true);
|
||||
field.set(obj, toAs(v, tClazz));
|
||||
}
|
||||
}*/
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
return (T) obj;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return JsonConvert.root().convertTo(this);
|
||||
}
|
||||
|
||||
public int getInt(String key) {
|
||||
return getInt(key, 0);
|
||||
}
|
||||
|
||||
public int getInt(String key, int defaultValue) {
|
||||
V v = get(key);
|
||||
if (v == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
return toAs(v, int.class);
|
||||
}
|
||||
|
||||
public long getLong(String key) {
|
||||
return getLong(key, 0);
|
||||
}
|
||||
|
||||
public long getLong(String key, long defaultValue) {
|
||||
V v = get(key);
|
||||
if (v == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
return toAs(v, long.class);
|
||||
}
|
||||
|
||||
public String getStr(String key) {
|
||||
return toAs(get(key), String.class);
|
||||
}
|
||||
|
||||
public String getStr(String key, String defaultValue) {
|
||||
V v = get(key);
|
||||
if (v == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
return toAs(v, String.class);
|
||||
}
|
||||
}
|
146
src/com/zchd/base/util/QueueTask.java
Normal file
146
src/com/zchd/base/util/QueueTask.java
Normal file
@ -0,0 +1,146 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package com.zchd.base.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* @param <T> 泛型
|
||||
* @author zhangjx
|
||||
*/
|
||||
public class QueueTask<T> {
|
||||
private static List<QueueTask> queueTasks = new ArrayList<>(); // queueTask 实例引用
|
||||
private static final AtomicInteger counter = new AtomicInteger();
|
||||
|
||||
protected final BlockingQueue<T> queue;
|
||||
|
||||
protected final int threads;
|
||||
|
||||
protected Consumer<T> consumer;
|
||||
|
||||
protected Logger logger;
|
||||
|
||||
public QueueTask(int threads) {
|
||||
this.threads = threads;
|
||||
this.queue = new LinkedBlockingQueue<>();
|
||||
}
|
||||
|
||||
public QueueTask(int threads, int queueSize) {
|
||||
this.threads = threads;
|
||||
this.queue = new LinkedBlockingQueue<>(queueSize);
|
||||
}
|
||||
|
||||
public QueueTask(int threads, Logger logger, Consumer<T> consumer) {
|
||||
this.threads = threads;
|
||||
this.queue = new LinkedBlockingQueue<>();
|
||||
this.init(logger, consumer);
|
||||
}
|
||||
|
||||
public T poll() {
|
||||
return this.queue.poll();
|
||||
}
|
||||
|
||||
public T task() throws InterruptedException {
|
||||
return this.queue.take();
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return this.queue.size();
|
||||
}
|
||||
|
||||
public boolean add(T data) {
|
||||
return this.queue.add(data);
|
||||
}
|
||||
|
||||
public boolean remove(T data) {
|
||||
return this.queue.remove(data);
|
||||
}
|
||||
|
||||
public void put(T data) throws InterruptedException {
|
||||
this.queue.put(data);
|
||||
}
|
||||
|
||||
public void init(Logger logger, Consumer<T> consumer) {
|
||||
this.logger = logger;
|
||||
this.consumer = consumer;
|
||||
Runnable task = () -> {
|
||||
T data;
|
||||
try {
|
||||
while ((data = queue.take()) != null) {
|
||||
try {
|
||||
consumer.accept(data);
|
||||
} catch (Throwable e) {
|
||||
if (logger != null) logger.log(Level.SEVERE, "QueueTask Data["
|
||||
+ (data == null ? null : data.getClass().getSimpleName()) + "](" + data + ") consume error", e);
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException ex) {
|
||||
}
|
||||
};
|
||||
for (int i = 0; i < threads; i++) {
|
||||
Thread thread = new Thread(task);
|
||||
thread.setName("QueueTask-" + i + "-Thread");
|
||||
thread.setDaemon(true);
|
||||
thread.start();
|
||||
}
|
||||
counter.addAndGet(threads);
|
||||
queueTasks.add(this);
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
int count = 0;
|
||||
while (count < 50) {
|
||||
if (queue.size() > 0) {
|
||||
try {
|
||||
Thread.sleep(200);
|
||||
} catch (Exception e) {
|
||||
break;
|
||||
}
|
||||
count++;
|
||||
} else {
|
||||
count = Integer.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
counter.addAndGet(-threads);
|
||||
}
|
||||
|
||||
public static int runningThreads() {
|
||||
return counter.get();
|
||||
}
|
||||
|
||||
// 队列堆叠信息获取
|
||||
public static List<Kv> pileup() {
|
||||
Map map = new HashMap();
|
||||
for (QueueTask queueTask : queueTasks) {
|
||||
map.put(queueTask.logger.getName(), queueTask.queue.size());
|
||||
}
|
||||
|
||||
List<Kv> kvs = Utils.toList(queueTasks, x -> {
|
||||
Kv kv = Kv.of();
|
||||
kv.set("name", x.logger.getName().replace("_DynLocal", ""));
|
||||
kv.set("threadcount", x.threads);
|
||||
kv.set("stack", x.queue.size());
|
||||
return kv;
|
||||
});
|
||||
|
||||
return kvs;
|
||||
}
|
||||
|
||||
public static void destroys() {
|
||||
for (QueueTask queueTask : queueTasks) {
|
||||
queueTask.destroy();
|
||||
}
|
||||
}
|
||||
}
|
38
src/com/zchd/base/util/QueueTasks.java
Normal file
38
src/com/zchd/base/util/QueueTasks.java
Normal file
@ -0,0 +1,38 @@
|
||||
package com.zchd.base.util;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* 公共异步队列
|
||||
*
|
||||
* @author: liangxy.
|
||||
*/
|
||||
public class QueueTasks {
|
||||
|
||||
private static final QueueTask<Runnable> queueTask = new QueueTask<>(1);
|
||||
|
||||
static {
|
||||
queueTask.init(Logger.getLogger(QueueTasks.class.getSimpleName()), Runnable::run);
|
||||
}
|
||||
|
||||
public static void add(Runnable runnable) {
|
||||
queueTask.queue.add(runnable);
|
||||
}
|
||||
|
||||
// -------------------------- 支持返回结果的任务队列 -----------------------------
|
||||
private static ExecutorService executor = Executors.newFixedThreadPool(1);
|
||||
|
||||
public static CompletableFuture submit(Runnable task) {
|
||||
return CompletableFuture.runAsync(() -> {
|
||||
try {
|
||||
executor.submit(task).get();
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
1282
src/com/zchd/base/util/Utils.java
Normal file
1282
src/com/zchd/base/util/Utils.java
Normal file
File diff suppressed because it is too large
Load Diff
269
src/com/zchd/zim/ImAccountService.java
Normal file
269
src/com/zchd/zim/ImAccountService.java
Normal file
@ -0,0 +1,269 @@
|
||||
package com.zchd.zim;
|
||||
|
||||
import com.zchd.base.BaseService;
|
||||
import com.zchd.base.util.Kv;
|
||||
import com.zchd.zim.bean.ImBean;
|
||||
import com.zchd.zim.bean.SubscribeBean;
|
||||
import com.zchd.zim.entity.AppInfo;
|
||||
import com.zchd.zim.entity.ChannelUser;
|
||||
import com.zchd.zim.entity.ImUser;
|
||||
import com.zdemo.cachex.MyRedisCacheSource;
|
||||
import com.zdemo.zhub.RpcResult;
|
||||
import org.redkale.convert.json.JsonConvert;
|
||||
import org.redkale.net.http.RestMapping;
|
||||
import org.redkale.net.http.RestService;
|
||||
import org.redkale.service.RetResult;
|
||||
import org.redkale.source.*;
|
||||
import org.redkale.util.AnyValue;
|
||||
import org.redkale.util.Comment;
|
||||
import org.redkale.util.TypeToken;
|
||||
import org.redkale.util.Utility;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
|
||||
@RestService(name = "im_account", comment = "账号服务")
|
||||
public class ImAccountService extends BaseService {
|
||||
|
||||
|
||||
@Resource(name = "str_cache")
|
||||
protected MyRedisCacheSource<String> strCache;
|
||||
@Resource
|
||||
protected ImMessageMonitor messageMonitor;
|
||||
@Resource
|
||||
protected ImAccountService accountService;
|
||||
|
||||
@Override
|
||||
public void init(AnyValue config) {
|
||||
|
||||
CompletableFuture.runAsync(() -> {
|
||||
List<Serializable> list = zimSource.queryColumnList("userid", ImUser.class, new Flipper(1, "userid DESC"), (FilterBean) null);
|
||||
int userid = 10000;
|
||||
if (!list.isEmpty()) {
|
||||
userid = Kv.toAs(list.get(0), int.class);
|
||||
}
|
||||
intCache.set("im:max-userid", userid);
|
||||
});
|
||||
|
||||
// 游戏用户注册
|
||||
zhub.rpcSubscribe("im:account-register", new TypeToken<ImBean>() {
|
||||
}, r -> {
|
||||
ImBean bean = r.getValue();
|
||||
RetResult<Kv> result = register(bean);
|
||||
if (!result.isSuccess()) {
|
||||
return r.buildError(result.getRetinfo());
|
||||
}
|
||||
return r.buildResp(result.getResult());
|
||||
});
|
||||
|
||||
// 获取游戏用户 IM-TOKEN
|
||||
zhub.rpcSubscribe("im:account-token", new TypeToken<ImBean>() {
|
||||
}, r -> {
|
||||
ImBean bean = r.getValue();
|
||||
RetResult<Kv> result = getToken(bean);
|
||||
if (!result.isSuccess()) {
|
||||
return r.buildError(result.getRetinfo());
|
||||
}
|
||||
return r.buildResp(result.getResult());
|
||||
});
|
||||
|
||||
// 为用户新增订阅频道
|
||||
zhub.rpcSubscribe("im:subscribe", new TypeToken<SubscribeBean>() {
|
||||
}, r -> {
|
||||
SubscribeBean bean = r.getValue();
|
||||
RetResult result = subscribe(bean);
|
||||
return r.buildResp(result.getResult());
|
||||
});
|
||||
|
||||
// 为用户取消订阅频道
|
||||
zhub.rpcSubscribe("im:unsubscribe", new TypeToken<SubscribeBean>() {
|
||||
}, r -> {
|
||||
SubscribeBean bean = r.getValue();
|
||||
RetResult result = unsubscribe(bean);
|
||||
return r.buildResp(result.getResult());
|
||||
});
|
||||
|
||||
// 禁言 todo: ①禁言时长 ②禁言指定频道
|
||||
zhub.rpcSubscribe("im:banned-talk", new TypeToken<SubscribeBean>() {
|
||||
}, r -> {
|
||||
SubscribeBean bean = r.getValue();
|
||||
String imtoken = bean.getImtoken();
|
||||
|
||||
ImUser user = accountService.currentImUser(imtoken);
|
||||
int userid = user.getUserid();
|
||||
zimSource.updateColumn(ImUser.class, userid, ColumnValue.create("status", ImUser.STATUS_FREEZE_ACTIVE));
|
||||
intCache.setBit("im:banned-talk", userid, true);
|
||||
return r.buildResp();
|
||||
});
|
||||
|
||||
// 取消禁言
|
||||
zhub.rpcSubscribe("im:unbanned-talk", new TypeToken<SubscribeBean>() {
|
||||
}, r -> {
|
||||
SubscribeBean bean = r.getValue();
|
||||
String imtoken = bean.getImtoken();
|
||||
|
||||
ImUser user = accountService.currentImUser(imtoken);
|
||||
int userid = user.getUserid();
|
||||
zimSource.updateColumn(ImUser.class, userid, ColumnValue.create("status", 10));
|
||||
intCache.setBit("im:banned-talk", userid, false);
|
||||
return r.buildResp();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@Comment("获取当前用户ID")
|
||||
public ImUser currentImUser(String token) {
|
||||
|
||||
ImUser user = strCache.hget("im:user-token", token, new TypeToken<ImUser>() {
|
||||
}.getType());
|
||||
if (user == null) {
|
||||
user = zimSource.find(ImUser.class, FilterNode.create("imtoken", token));
|
||||
strCache.hset("im:user-token", token, JsonConvert.root(), user);
|
||||
}
|
||||
return user;
|
||||
}
|
||||
|
||||
/*@Comment("获取当前用户ID")
|
||||
public int currentImUserId(String token) {
|
||||
return currentImUser(token).getUserid();
|
||||
}*/
|
||||
|
||||
|
||||
/*
|
||||
Url: http://127.0.0.1:8021/im_account/register
|
||||
Body: {"appid":"krlq07sx","appsecret":"79eb45ebdabc4d90bfb69949b8fd767e","guserid":"S_C_01_R0001","gender":10,"nickname":"M","face":"http://xxxxxx/xxx"}
|
||||
Body: {"appid":"krlq07sx","appsecret":"79eb45ebdabc4d90bfb69949b8fd767e","guserid":"S_C_01_R0002","gender":20,"nickname":"V","face":"http://xxxxxx/xxx"}
|
||||
*/
|
||||
@RestMapping(name = "register", auth = false, comment = "获取当前登录用户ID")
|
||||
public RetResult<Kv> register(ImBean bean) {
|
||||
RetResult<Kv> result = check(bean);
|
||||
if (!result.isSuccess()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// 检查有无当前用户
|
||||
FilterNode node = FilterNode.create("guserid", bean.getGuserid()).and("appid", bean.getAppid());
|
||||
ImUser user = zimSource.find(ImUser.class, node);
|
||||
|
||||
if (user == null) {
|
||||
user = ImUser.buildImUser(bean.getGuserid(), bean.getAppid());
|
||||
int userid = (int) intCache.incr("im:max-userid");
|
||||
user.setUserid(userid);
|
||||
|
||||
user.setImtoken(Utility.uuid()); // 生成IM-TOKEN
|
||||
zimSource.insert(user);
|
||||
|
||||
// intCache.set("im:account-user-token:" + user.getImtoken(), userid);
|
||||
strCache.hset("im:user-token", user.getImtoken(), JsonConvert.root(), user);
|
||||
|
||||
}
|
||||
|
||||
return RetResult.success(Kv.of("token", user.getImtoken()));
|
||||
}
|
||||
|
||||
/*
|
||||
Url: http://127.0.0.1:8021/im_account/register
|
||||
Body: {"appid":"krlq07sx","appsecret":"79eb45ebdabc4d90bfb69949b8fd767e","guserid":"S_C_01_R0001"}
|
||||
Body: {"appid":"krlq07sx","appsecret":"79eb45ebdabc4d90bfb69949b8fd767e","guserid":"S_C_01_R0002"}
|
||||
*/
|
||||
@RestMapping(name = "get_token", auth = false, comment = "获取平台识别Token")
|
||||
public RetResult<Kv> getToken(ImBean bean) {
|
||||
RetResult<Kv> result = check(bean);
|
||||
if (!result.isSuccess()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
FilterNode node = FilterNode.create("appid", bean.getAppid()).and("guserid", bean.getGuserid());
|
||||
Serializable imtoken = zimSource.findColumn(ImUser.class, "imtoken", node);
|
||||
|
||||
return RetResult.success(Kv.of("token", imtoken));
|
||||
}
|
||||
|
||||
/*
|
||||
Url: http://127.0.0.1:8021/im_app/subscribe
|
||||
Body: {"imtoken":"krlq07sxS_C_01_R00011627473704040","channeltype":"Word","channelvalue":"W_C_01_001"}
|
||||
Body: {"imtoken":"krlq07sxS_C_01_R00021627474715105","channeltype":"Word","channelvalue":"W_C_01_001"}
|
||||
*/
|
||||
@RestMapping(name = "subscribe", auth = false, comment = "给用户订阅频道信息")
|
||||
public RetResult subscribe(SubscribeBean bean) {
|
||||
ImUser user = accountService.currentImUser(bean.getImtoken());
|
||||
int userid = user.getUserid();
|
||||
try {
|
||||
// 添加数据库订阅关系
|
||||
intCache.tryLock("im:channel-create:" + userid, 500);
|
||||
FilterNode node1 = FilterNode.create("appid", user.getAppid())
|
||||
.and("channeltype", bean.getChanneltype())
|
||||
.and("channelvalue", bean.getChannelvalue())
|
||||
.and("userid", userid);
|
||||
if (!zimSource.exists(ChannelUser.class, node1)) {
|
||||
ChannelUser record = ChannelUser.buildChannelUser(userid, user.getAppid(), bean);
|
||||
zimSource.insert(record);
|
||||
|
||||
// 确保写入库后,再发送订阅事件
|
||||
messageMonitor.subscribeChannel(userid, record.buildChannelid(), true);
|
||||
}
|
||||
} finally {
|
||||
intCache.unlock("im:channel-create:" + userid);
|
||||
}
|
||||
return RET_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Url: http://127.0.0.1:8021/im_app/unsubscribe
|
||||
Body: {"imtoken":"krlq07sxS_C_01_R00011627473704040","channeltype":"Word","channelvalue":"W_C_01_001"}
|
||||
Body: {"imtoken":"krlq07sxS_C_01_R00021627474715105","channeltype":"Word","channelvalue":"W_C_01_001"}
|
||||
*/
|
||||
@RestMapping(name = "unsubscribe", auth = false, comment = "取消频道订阅")
|
||||
public RetResult unsubscribe(SubscribeBean bean) {
|
||||
ImUser user = accountService.currentImUser(bean.getImtoken());
|
||||
int userid = user.getUserid();
|
||||
|
||||
|
||||
String channelid = user.getAppid() + "-" + bean.getChanneltype() + "-" + bean.getChannelvalue();
|
||||
messageMonitor.subscribeChannel(userid, channelid, false);
|
||||
|
||||
// 删除数据库订阅关系
|
||||
FilterNode node1 = FilterNode.create("appid", user.getAppid())
|
||||
.and("channeltype", bean.getChanneltype())
|
||||
.and("channelvalue", bean.getChannelvalue())
|
||||
.and("userid", userid);
|
||||
zimSource.delete(ChannelUser.class, node1);
|
||||
return RET_SUCCESS;
|
||||
}
|
||||
|
||||
@Comment("平台安全校验")
|
||||
public RetResult check(ImBean bean) {
|
||||
FilterNode node = FilterNode.create("appid", bean.getAppid()).and("appsecret", bean.getAppsecret()).and("status", 10);
|
||||
if (!zimSource.exists(AppInfo.class, node)) {
|
||||
return retError("平台信息校验失败");
|
||||
}
|
||||
return RET_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------- 测试 ----------------------------------
|
||||
|
||||
@RestMapping(name = "test_account_register", auth = false, comment = "rpc测试")
|
||||
public RpcResult testAccountRegister(ImBean bean) {
|
||||
return zhub.rpc("im:account-register", bean);
|
||||
}
|
||||
|
||||
@RestMapping(name = "test_account_token", auth = false, comment = "rpc测试")
|
||||
public RpcResult testAccountToken(ImBean bean) {
|
||||
return zhub.rpc("im:account-token", bean);
|
||||
}
|
||||
|
||||
@RestMapping(name = "test_subscribe", auth = false, comment = "rpc测试")
|
||||
public RpcResult testSubscribe(SubscribeBean bean) {
|
||||
return zhub.rpc("im:subscribe", bean);
|
||||
}
|
||||
|
||||
@RestMapping(name = "test_unsubscribe", auth = false, comment = "rpc测试")
|
||||
public RpcResult testUnsubscribe(SubscribeBean bean) {
|
||||
return zhub.rpc("im:unsubscribe", bean);
|
||||
}
|
||||
}
|
193
src/com/zchd/zim/ImChatService.java
Normal file
193
src/com/zchd/zim/ImChatService.java
Normal file
@ -0,0 +1,193 @@
|
||||
package com.zchd.zim;
|
||||
|
||||
import com.zchd.base.BaseService;
|
||||
import com.zchd.base.util.Kv;
|
||||
import com.zchd.base.util.QueueTask;
|
||||
import com.zchd.zim.entity.ChannelMessage;
|
||||
import com.zchd.zim.entity.ChannelUser;
|
||||
import com.zchd.zim.entity.FriendMessage;
|
||||
import com.zchd.zim.entity.ImUser;
|
||||
import com.zdemo.zhub.ZHubClient;
|
||||
import net.tccn.timer.Timers;
|
||||
import org.redkale.net.http.RestService;
|
||||
import org.redkale.net.http.WebSocketNode;
|
||||
import org.redkale.source.ColumnValue;
|
||||
import org.redkale.source.DataSource;
|
||||
import org.redkale.source.FilterNode;
|
||||
import org.redkale.source.Flipper;
|
||||
import org.redkale.util.AnyValue;
|
||||
import org.redkale.util.Comment;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.persistence.Transient;
|
||||
import java.util.List;
|
||||
|
||||
import static org.redkale.source.FilterExpress.*;
|
||||
|
||||
@RestService(name = "im_chat_x", comment = "IM消息总线")
|
||||
public class ImChatService extends BaseService {
|
||||
|
||||
@Resource(name = "im_chat")
|
||||
protected WebSocketNode wsnode;
|
||||
@Resource(name = "z_im")
|
||||
protected DataSource zimSource;
|
||||
@Resource(name = "zhub")
|
||||
protected ZHubClient zhub;
|
||||
|
||||
@Transient //消息发送
|
||||
protected QueueTask<Runnable> msgQueue = new QueueTask<>(20);
|
||||
@Transient //消息存储
|
||||
protected QueueTask<Runnable> dbQueue = new QueueTask<>(1);
|
||||
|
||||
|
||||
@Override
|
||||
public void init(AnyValue config) {
|
||||
msgQueue.init(logger, Runnable::run);
|
||||
dbQueue.init(logger, Runnable::run);
|
||||
}
|
||||
|
||||
@Comment("发送私聊消息")
|
||||
public void sendMsg(FriendMessage bean, int uid) {
|
||||
wsnode.sendMessage(buildFriendMessageDeail(bean), uid).thenAccept(x -> {
|
||||
if (x != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// intCache.incrHm("im:heartbeat:" + uid, "messagecount", -1);
|
||||
// 更新状态失败, 200ms 后重试(当数据未写入的时候,更新失败)
|
||||
Timers.tryDelay(() -> {
|
||||
FilterNode node = FilterNode.create("senduserid", bean.getSenduserid()).and("receiveuserid", uid);
|
||||
int updateColumn = zimSource.updateColumn(FriendMessage.class, node, ColumnValue.create("status", 10));
|
||||
|
||||
return updateColumn != 0;
|
||||
}, 200, 3);
|
||||
});
|
||||
}
|
||||
|
||||
@Comment("拉取离线消息")
|
||||
public void pullOfflineMsg(int userid) {
|
||||
msgQueue.add(() -> {
|
||||
// 拉取私聊离线消息
|
||||
List<FriendMessage> list = zimSource.queryList(FriendMessage.class, new Flipper(0, "createtime"),
|
||||
FilterNode.create("receiveuserid", userid).and("status", 20));
|
||||
|
||||
list.forEach(x -> {
|
||||
Integer join = wsnode.sendMessage(buildFriendMessageDeail(x), userid).join();
|
||||
if (join == 0) {
|
||||
zimSource.updateColumn(FriendMessage.class, x.getMessageid(), ColumnValue.create("status", 10));
|
||||
}
|
||||
});
|
||||
|
||||
// 拉取频道离线消息
|
||||
List<ChannelUser> userGroups = userChannels(userid);
|
||||
for (ChannelUser userGroup : userGroups) {
|
||||
Long lastAcceptTime = longCache.getHm("im:channel:" + userGroup.buildChannelid(), userGroup.getUserid());
|
||||
if (lastAcceptTime == null || lastAcceptTime == 0) {
|
||||
lastAcceptTime = userGroup.getCreatetime();
|
||||
}
|
||||
|
||||
// 获取当前频道的数据列表
|
||||
FilterNode node1 = FilterNode.create("appid", userGroup.getAppid())
|
||||
.and("channeltype", userGroup.getChanneltype())
|
||||
.and("channelvalue", userGroup.getChannelvalue())
|
||||
.and("senduserid", NOTEQUAL, userid)
|
||||
.and("createtime", GREATERTHAN, lastAcceptTime)
|
||||
.and("createtime", LESSTHAN, System.currentTimeMillis())
|
||||
.and("status", NOTEQUAL, 80);
|
||||
try {
|
||||
List<ChannelMessage> messages = zimSource.queryList(ChannelMessage.class, new Flipper(50, "createtime desc"), node1);
|
||||
|
||||
// 获取最新的消息集合后,从时间最早的开始推送
|
||||
for (int i = messages.size() - 1; i > -1; i--) {
|
||||
ChannelMessage message = messages.get(i);
|
||||
int status = wsnode.sendMessage(buildMessageDetail(message), userid).join();
|
||||
if (status != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 每次推完一个消息后将拉取时间修改为当前消息的发送时间
|
||||
lastAcceptTime = message.getCreatetime();
|
||||
}
|
||||
} finally {
|
||||
|
||||
longCache.setHm("im:channel:" + userGroup.buildChannelid(), userGroup.getUserid(), lastAcceptTime);
|
||||
// 变更最后拉取时间
|
||||
/*FilterNode node = FilterNode.create("appid", userGroup.getAppid())
|
||||
.and("channeltype", userGroup.getChanneltype())
|
||||
.and("channelvalue", userGroup.getChannelvalue()).and("userid", userid);
|
||||
zimSource.updateColumn(ChannelUser.class, node, ColumnValue.create("lastaccepttime", lastAcceptTime)); // todo 中途失败时间有问题*/
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public List<ChannelUser> userChannels(int userid) {
|
||||
FilterNode node = FilterNode.create("userid", userid)
|
||||
.and(FilterNode.create("status", 10).or("status", 40));
|
||||
return zimSource.queryList(ChannelUser.class, node);
|
||||
}
|
||||
|
||||
@Comment("用户IM是否在线")
|
||||
public boolean userOnline(int userid) {
|
||||
return intCache.getBit("im:user", userid);
|
||||
}
|
||||
|
||||
@Comment("用户在线直接发送, 如果不在线先记录到数据库")
|
||||
public void sendFriendMessage(FriendMessage message) {
|
||||
dbQueue.add(() -> {
|
||||
zimSource.insert(message);
|
||||
});
|
||||
|
||||
int receiveuserid = message.getReceiveuserid();
|
||||
if (userOnline(receiveuserid)) {
|
||||
zhub.publish("im:friend:" + receiveuserid, message);
|
||||
}
|
||||
}
|
||||
|
||||
public void sendChannelMessage(ChannelMessage message) {
|
||||
// 记录消息,发送群消息
|
||||
dbQueue.add(() -> {
|
||||
zimSource.insert(message);
|
||||
});
|
||||
|
||||
zhub.broadcast("im:channel:" + message.buildChannelid(), message);
|
||||
}
|
||||
|
||||
private String getGuserid(int userid) {
|
||||
ImUser user = zimSource.find(ImUser.class, userid);
|
||||
return user.getGuserid();
|
||||
}
|
||||
|
||||
public int getUserid(String appid, String guserid) {
|
||||
ImUser user = zimSource.find(ImUser.class, FilterNode.create("appid", appid).and("guserid", guserid));
|
||||
return user.getUserid();
|
||||
}
|
||||
|
||||
public Kv buildFriendMessageDeail(FriendMessage message) {
|
||||
Kv detail = Kv.toKv(message, "content", "messageid", "sendtime");
|
||||
detail.set("sendguserid", getGuserid(message.getSenduserid()));
|
||||
Kv data = Kv.of("detail", detail).set("type", "friend-text");
|
||||
return data;
|
||||
}
|
||||
|
||||
public Kv buildBackMessage(FriendMessage message, String mck) {
|
||||
Kv detail = Kv.toKv(message, "content", "messageid", "sendtime");
|
||||
detail.set("sendguserid", getGuserid(message.getSenduserid()));
|
||||
Kv data = Kv.of("detail", detail).set("type", "friend-text").set("mck", mck);
|
||||
return data;
|
||||
}
|
||||
|
||||
public Kv buildMessageDetail(ChannelMessage message) {
|
||||
Kv detail = Kv.toKv(message, "content", "messageid", "sendtime", "channeltype", "channelvalue");
|
||||
detail.set("sendguserid", getGuserid(message.getSenduserid()));
|
||||
Kv data = Kv.of("detail", detail).set("type", "channel-text");
|
||||
return data;
|
||||
}
|
||||
|
||||
public Kv buildBackMessage(ChannelMessage message, String mck) {
|
||||
Kv detail = Kv.toKv(message, "content", "messageid", "sendtime", "channeltype", "channelvalue");
|
||||
detail.set("sendguserid", getGuserid(message.getSenduserid()));
|
||||
Kv data = Kv.of("detail", detail).set("type", "channel-text").set("mck", mck);
|
||||
return data;
|
||||
}
|
||||
}
|
182
src/com/zchd/zim/ImChatWebSocket.java
Normal file
182
src/com/zchd/zim/ImChatWebSocket.java
Normal file
@ -0,0 +1,182 @@
|
||||
package com.zchd.zim;
|
||||
|
||||
import com.zchd.base.info.SwearWordService;
|
||||
import com.zchd.base.util.Kv;
|
||||
import com.zchd.base.util.Utils;
|
||||
import com.zchd.zim.entity.ChannelMessage;
|
||||
import com.zchd.zim.entity.FriendMessage;
|
||||
import com.zchd.zim.entity.ImUser;
|
||||
import com.zdemo.cachex.MyRedisCacheSource;
|
||||
import org.redkale.net.http.HttpRequest;
|
||||
import org.redkale.net.http.RestOnMessage;
|
||||
import org.redkale.net.http.RestWebSocket;
|
||||
import org.redkale.net.http.WebSocket;
|
||||
import org.redkale.service.RetResult;
|
||||
import org.redkale.source.DataSource;
|
||||
import org.redkale.util.Comment;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
/*
|
||||
* ws://127.0.0.1:8091/im_chat?imtoken=xx
|
||||
* */
|
||||
@RestWebSocket(name = "im_chat", comment = "IM即使通讯", anyuser = true)
|
||||
public class ImChatWebSocket extends WebSocket {
|
||||
|
||||
@Resource(name = "z_im")
|
||||
protected DataSource zimSource;
|
||||
|
||||
@Resource(name = "int_cache")
|
||||
protected MyRedisCacheSource<Integer> intCache;
|
||||
|
||||
@Resource
|
||||
protected ImAccountService accountService;
|
||||
@Resource
|
||||
protected ImChatService chatService;
|
||||
@Resource
|
||||
protected ImMessageMonitor messageMonitor;
|
||||
@Resource
|
||||
protected SwearWordService swearWordService;
|
||||
|
||||
@Override
|
||||
protected CompletableFuture<String> onOpen(HttpRequest request) {
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
String token = request.getHeader("imtoken", request.getParameter("imtoken"));
|
||||
return token;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CompletableFuture createUserid() {
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
ImUser user = accountService.currentImUser(getSessionid());
|
||||
int userid = user.getUserid();
|
||||
|
||||
|
||||
if (userid > 0) {
|
||||
WebSocket socket = findLocalWebSocket(userid);
|
||||
if (socket != null) {
|
||||
forceCloseWebSocket(userid);
|
||||
}
|
||||
|
||||
setAttribute("appid", user.getAppid());
|
||||
setAttribute("guserid", user.getGuserid());
|
||||
}
|
||||
|
||||
return userid;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture onConnected() {
|
||||
return CompletableFuture.runAsync(() -> {
|
||||
final int userid = (int) getUserid();
|
||||
getLogger().info("im:state-change:" + userid + "---ws connected---");
|
||||
intCache.setBit("im:user", userid, true);
|
||||
// 上线开启订阅
|
||||
messageMonitor.online(userid);
|
||||
// 拉取离线消息
|
||||
chatService.pullOfflineMsg(userid);
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
{friend:{bean:{"type": "friend-text","content": "发给V的私聊"},extmap:{"mck":"11001and1234567860","guserid": "S_C_01_R0002"}}}
|
||||
{friend:{bean:{"type": "friend-text","content": "发给M的私聊"},extmap:{"mck":"11001and1234567861","guserid": "S_C_01_R0001"}}}
|
||||
*/
|
||||
@RestOnMessage(name = "friend", comment = "私聊消息")
|
||||
public void friend(@Comment("content、type") Map<String, String> bean,
|
||||
@Comment("mck、guserid") Map<String, String> extmap) {
|
||||
int userid = (int) getUserid();
|
||||
String guserid = extmap.get("guserid");
|
||||
String appid = (String) getAttribute("appid");
|
||||
String mck = extmap.get("mck");
|
||||
|
||||
int targetguserid = chatService.getUserid(appid, guserid);
|
||||
FriendMessage message = FriendMessage.buildFriendMessage(bean.get("content"), userid, targetguserid);
|
||||
|
||||
// 禁言检查
|
||||
if (intCache.getBit("im:banned-talk", userid)) {
|
||||
sendTip("发送失败,你已被禁言", mck, 3002);
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查敏感词 :若加入消息撤回,可使用延时检查(后置审核),检查到违禁词 撤回消息
|
||||
RetResult check = swearWordService.check(message.getContent());
|
||||
if (!check.isSuccess()) {
|
||||
sendTip("发送消息含有敏感词", mck, 3001);
|
||||
return;
|
||||
}
|
||||
|
||||
// 发送消息
|
||||
chatService.sendFriendMessage(message);
|
||||
|
||||
// 回执
|
||||
Kv kv = chatService.buildBackMessage(message, mck);
|
||||
send(kv);
|
||||
}
|
||||
|
||||
/*
|
||||
{channel:{bean:{"type": "channel-test","content": "asfsafasfsaf"},extmap:{"mck":"11001and1234567860","channeltype": "world","channelvalue": "2"}}}
|
||||
{channel:{bean:{"type": "channel-test","content": "这是世界频道消息V"},extmap:{"mck":"11001and1234567860","channeltype": "Word","channelvalue": "W_C_01_001"}}}
|
||||
*/
|
||||
@RestOnMessage(name = "channel", comment = "频道消息")
|
||||
public void channel(@Comment("content、type") Map<String, String> bean,
|
||||
@Comment("mck、channeltype、channelvalue") Map<String, String> extmap) {
|
||||
int userid = (int) getUserid();
|
||||
String appid = (String) getAttribute("appid");
|
||||
|
||||
String channeltype = extmap.get("channeltype");
|
||||
String channelvalue = extmap.get("channelvalue");
|
||||
String mck = extmap.get("mck");
|
||||
|
||||
// 禁言检查
|
||||
if (intCache.getBit("im:banned-talk", userid)) {
|
||||
sendTip("发送失败,你已被禁言", mck, 3002);
|
||||
return;
|
||||
}
|
||||
// 检查敏感词 :若加入消息撤回,可使用延时检查(后置审核),检查到违禁词 撤回消息
|
||||
RetResult check = swearWordService.check(bean.get("content"));
|
||||
if (!check.isSuccess()) {
|
||||
sendTip("发送消息含有敏感词", mck, 3001);
|
||||
return;
|
||||
}
|
||||
|
||||
ChannelMessage message = new ChannelMessage();
|
||||
message.setContent(bean.get("content"));
|
||||
message.setAppid(appid);
|
||||
message.setSenduserid(userid);
|
||||
message.setChanneltype(channeltype);
|
||||
message.setChannelvalue(channelvalue);
|
||||
message.setCreatetime(System.currentTimeMillis());
|
||||
message.setStatus((short) 20);
|
||||
message.setMessageid(Utils.fmt36(message.getSenduserid()) + "-" + Utils.fmt36(message.getCreatetime()));
|
||||
|
||||
// 发送
|
||||
chatService.sendChannelMessage(message);
|
||||
|
||||
// 回执
|
||||
Kv kv = chatService.buildBackMessage(message, mck);
|
||||
send(kv);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture onClose(int code, String reason) {
|
||||
final int userid = (int) getUserid();
|
||||
getLogger().info("im:state-change:" + userid + "---close---" + code + "---" + reason);
|
||||
intCache.setBit("im:user:", userid, false);
|
||||
// 取消用户订阅
|
||||
messageMonitor.offline(userid);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Comment("发送提示信息")
|
||||
public void sendTip(String tipinfo, String mck, int code) {
|
||||
Kv tip = Kv.of("type", "tip")
|
||||
.set("mck", mck).set("code", code)
|
||||
.set("info", tipinfo);
|
||||
send(tip);
|
||||
}
|
||||
}
|
166
src/com/zchd/zim/ImMessageMonitor.java
Normal file
166
src/com/zchd/zim/ImMessageMonitor.java
Normal file
@ -0,0 +1,166 @@
|
||||
package com.zchd.zim;
|
||||
|
||||
import com.zchd.base.BaseService;
|
||||
import com.zchd.base.util.Kv;
|
||||
import com.zchd.base.util.QueueTask;
|
||||
import com.zchd.base.util.Utils;
|
||||
import com.zchd.zim.entity.ChannelMessage;
|
||||
import com.zchd.zim.entity.ChannelUser;
|
||||
import com.zchd.zim.entity.FriendMessage;
|
||||
import com.zdemo.cachex.MyRedisCacheSource;
|
||||
import org.redkale.net.http.RestService;
|
||||
import org.redkale.net.http.WebSocketNode;
|
||||
import org.redkale.util.AnyValue;
|
||||
import org.redkale.util.Comment;
|
||||
import org.redkale.util.TypeToken;
|
||||
import org.redkale.util.Utility;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.BitSet;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@RestService(name = "im_message_monitor", comment = "总线消息订阅管理")
|
||||
public class ImMessageMonitor extends BaseService {
|
||||
|
||||
@Resource
|
||||
protected ImChatService chatService;
|
||||
|
||||
@Resource(name = "im_chat")
|
||||
protected WebSocketNode wsnode;
|
||||
|
||||
@Resource(name = "int_cache")
|
||||
protected MyRedisCacheSource<Integer> intCache;
|
||||
@Resource(name = "long_cache")
|
||||
protected MyRedisCacheSource<Long> longCache;
|
||||
|
||||
protected BitSet bitSet = new BitSet(); // IM用户连接当前实例记录
|
||||
|
||||
protected ConcurrentHashMap<String, Set<Integer>> channelSubscribe = new ConcurrentHashMap<>();
|
||||
|
||||
protected final QueueTask<Runnable> messageQueue = new QueueTask<>(1);
|
||||
|
||||
@Override
|
||||
public void init(AnyValue config) {
|
||||
messageQueue.init(Logger.getLogger(this.getClass().getSimpleName()), Runnable::run);
|
||||
|
||||
// 订阅用户动态广播消息, 用户未连接当前IM 服务实例,不做通道订阅
|
||||
zhub.subscribe("im:channel", new TypeToken<Kv<String, String>>() {
|
||||
}, para -> {
|
||||
int userid = para.getInt("userid");
|
||||
if (!bitSet.get(userid)) {
|
||||
return;
|
||||
}
|
||||
|
||||
String channelid = para.get("channelid");
|
||||
String type = para.get("type");
|
||||
switch (type) {
|
||||
case "subscribe" -> subscribeChannel(userid, channelid);
|
||||
case "unsubscribe" -> unsubscribeChannel(userid, channelid);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Comment("用户上线")
|
||||
public void online(int userid) {
|
||||
// 设置用户在当前实例标记
|
||||
bitSet.set(userid);
|
||||
|
||||
// 开启频道订阅
|
||||
List<ChannelUser> list = chatService.userChannels(userid);
|
||||
list.forEach(x -> {
|
||||
subscribeChannel(userid, x.buildChannelid());
|
||||
});
|
||||
|
||||
// 开启对点订阅
|
||||
zhub.subscribe("im:friend:" + userid, new TypeToken<FriendMessage>() {
|
||||
}, x -> {
|
||||
messageQueue.add(() -> {
|
||||
chatService.sendMsg(x, userid);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@Comment("用户下线")
|
||||
public void offline(int userid) {
|
||||
// 设置用户在当前实例标记
|
||||
bitSet.clear(userid);
|
||||
|
||||
// 取消点对点订阅
|
||||
zhub.unsubscribe("im:friend:" + userid);
|
||||
|
||||
// 取消频道订阅
|
||||
List<ChannelUser> list = chatService.userChannels(userid);
|
||||
list.forEach(x -> {
|
||||
unsubscribeChannel(userid, x.buildChannelid());
|
||||
});
|
||||
}
|
||||
|
||||
@Comment("订阅频道")
|
||||
private void subscribeChannel(int userid, String channelid) {
|
||||
Set<Integer> uids = channelSubscribe.get(channelid);
|
||||
if (uids == null) {
|
||||
uids = new HashSet<>();
|
||||
|
||||
zhub.subscribe("im:channel:" + channelid, new TypeToken<ChannelMessage>() {
|
||||
}, x -> {
|
||||
messageQueue.add(() -> {
|
||||
Set<Integer> _uids = channelSubscribe.get(channelid);
|
||||
_uids.forEach(uid -> {
|
||||
// 自己发的频道消息 不发送给自己
|
||||
if (x.getSenduserid() == uid) {
|
||||
return;
|
||||
}
|
||||
|
||||
wsnode.sendMessage(chatService.buildMessageDetail(x), uid).thenAccept(status -> {
|
||||
// 完成群发消息同步
|
||||
if (status != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// todo:并发场景下,会影响拉取离线消息
|
||||
longCache.setHm("im:channel:" + x.buildChannelid(), uid, System.currentTimeMillis());
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
uids.add(userid);
|
||||
channelSubscribe.put(channelid, uids);
|
||||
}
|
||||
|
||||
@Comment("取消订阅频道")
|
||||
private void unsubscribeChannel(int userid, String channelid) {
|
||||
Set<Integer> uids = channelSubscribe.get(channelid);
|
||||
if (uids == null) {
|
||||
return;
|
||||
}
|
||||
// 先移除用户
|
||||
uids.remove(userid);
|
||||
// 当主题订阅没有人在线,取消总线订阅
|
||||
if (uids.isEmpty()) {
|
||||
channelSubscribe.remove(channelid);
|
||||
zhub.unsubscribe("im:channel:" + channelid);
|
||||
return;
|
||||
}
|
||||
channelSubscribe.put(channelid, uids);
|
||||
}
|
||||
|
||||
public void subscribeChannel(int userid, String channelid, boolean subscribe) {
|
||||
Kv kv = Kv.of("userid", userid)
|
||||
.set("channelid", channelid)
|
||||
.set("type", subscribe ? "subscribe" : "unsubscribe");
|
||||
zhub.broadcast("im:channel", kv);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
long millis = System.currentTimeMillis();
|
||||
System.out.println(Utils.fmt36(millis));
|
||||
System.out.println(millis);
|
||||
System.out.println(Utility.uuid());
|
||||
}
|
||||
}
|
17
src/com/zchd/zim/bean/ImBean.java
Normal file
17
src/com/zchd/zim/bean/ImBean.java
Normal file
@ -0,0 +1,17 @@
|
||||
package com.zchd.zim.bean;
|
||||
|
||||
import com.zchd.base.BaseBean;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
public class ImBean extends BaseBean {
|
||||
|
||||
private String appid;
|
||||
|
||||
private String appsecret;
|
||||
|
||||
private String guserid;
|
||||
|
||||
}
|
17
src/com/zchd/zim/bean/SubscribeBean.java
Normal file
17
src/com/zchd/zim/bean/SubscribeBean.java
Normal file
@ -0,0 +1,17 @@
|
||||
package com.zchd.zim.bean;
|
||||
|
||||
import com.zchd.base.BaseBean;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
public class SubscribeBean extends BaseBean {
|
||||
|
||||
private String imtoken = "";
|
||||
|
||||
private String channeltype = "";
|
||||
|
||||
private String channelvalue = "";
|
||||
|
||||
}
|
34
src/com/zchd/zim/entity/AppInfo.java
Normal file
34
src/com/zchd/zim/entity/AppInfo.java
Normal file
@ -0,0 +1,34 @@
|
||||
package com.zchd.zim.entity;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
@Table(comment = "平台信息表")
|
||||
public class AppInfo {
|
||||
|
||||
@Id
|
||||
@Column(comment = "[平台标识]")
|
||||
private String appid = "";
|
||||
|
||||
@Column(comment = "[平台名称]")
|
||||
private String appname = "";
|
||||
|
||||
@Column(comment = "[校验码]")
|
||||
private String appsecret = "";
|
||||
|
||||
@Column(comment = "[创建时间]")
|
||||
private long createtime;
|
||||
|
||||
@Column(comment = "[修改时间]")
|
||||
private long updatetime;
|
||||
|
||||
@Column(comment = "[状态]10正常, 40停用,80删除")
|
||||
private short status;
|
||||
|
||||
}
|
44
src/com/zchd/zim/entity/ChannelMessage.java
Normal file
44
src/com/zchd/zim/entity/ChannelMessage.java
Normal file
@ -0,0 +1,44 @@
|
||||
package com.zchd.zim.entity;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
@Table(comment = "频道内容表")
|
||||
public class ChannelMessage {
|
||||
|
||||
@Id
|
||||
@Column(comment = "[消息ID]")
|
||||
private String messageid;
|
||||
|
||||
@Column(comment = "[频道内容]")
|
||||
private String content = "";
|
||||
|
||||
@Column(comment = "[平台ID]")
|
||||
private String appid;
|
||||
|
||||
@Column(comment = "[平台频道类型]")
|
||||
private String channeltype;
|
||||
|
||||
@Column(comment = "[平台频道ID]")
|
||||
private String channelvalue;
|
||||
|
||||
@Column(comment = "[发送人]")
|
||||
private int senduserid;
|
||||
|
||||
@Column(comment = "[创建时间]")
|
||||
private long createtime;
|
||||
|
||||
@Column(comment = "[状态]10正常,40发送失败,80屏蔽")
|
||||
private short status;
|
||||
|
||||
public String buildChannelid() {
|
||||
return appid + "-" + channeltype + "-" + channelvalue;
|
||||
}
|
||||
|
||||
}
|
63
src/com/zchd/zim/entity/ChannelUser.java
Normal file
63
src/com/zchd/zim/entity/ChannelUser.java
Normal file
@ -0,0 +1,63 @@
|
||||
package com.zchd.zim.entity;
|
||||
|
||||
import com.zchd.zim.bean.SubscribeBean;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.redkale.util.Utility;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
@Table(comment = "用户组信息表")
|
||||
public class ChannelUser {
|
||||
|
||||
@Id
|
||||
@Column(comment = "[记录ID]")
|
||||
private String cuid;
|
||||
|
||||
@Column(comment = "[平台ID]")
|
||||
private String appid = "";
|
||||
|
||||
@Column(comment = "[平台频道ID]")
|
||||
private String channelvalue = "";
|
||||
|
||||
@Column(comment = "[平台频道类型]")
|
||||
private String channeltype = "";
|
||||
|
||||
@Column(comment = "[订阅用户]")
|
||||
private int userid;
|
||||
|
||||
@Column(comment = "[创建时间]")
|
||||
private long createtime;
|
||||
|
||||
@Column(comment = "[最后接收时间]")
|
||||
private long lastaccepttime;
|
||||
|
||||
@Column(comment = "[状态]10正常,40禁言,41踢除")
|
||||
private short status;
|
||||
|
||||
public ChannelUser() {
|
||||
}
|
||||
|
||||
// 频道的订阅唯一KEY
|
||||
public String buildChannelid() {
|
||||
return appid + '-' + channeltype + '-' + channelvalue;
|
||||
}
|
||||
|
||||
public static ChannelUser buildChannelUser(int userid, String appid, SubscribeBean bean) {
|
||||
ChannelUser record = new ChannelUser();
|
||||
record.userid = userid;
|
||||
record.appid = appid;
|
||||
record.channeltype = bean.getChanneltype();
|
||||
record.channelvalue = bean.getChannelvalue();
|
||||
record.createtime = System.currentTimeMillis();
|
||||
record.lastaccepttime = record.getCreatetime();
|
||||
record.cuid = Utility.uuid();
|
||||
record.status = 10;
|
||||
|
||||
return record;
|
||||
}
|
||||
}
|
47
src/com/zchd/zim/entity/FriendMessage.java
Normal file
47
src/com/zchd/zim/entity/FriendMessage.java
Normal file
@ -0,0 +1,47 @@
|
||||
package com.zchd.zim.entity;
|
||||
|
||||
import com.zchd.base.util.Utils;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
@Table(comment = "私聊内容表")
|
||||
public class FriendMessage {
|
||||
|
||||
@Id
|
||||
@Column(comment = "[私聊ID]发送人-时间戳")
|
||||
private String messageid = "";
|
||||
|
||||
@Column(comment = "[私聊内容]")
|
||||
private String content = "";
|
||||
|
||||
@Column(comment = "[发送人]")
|
||||
private int senduserid;
|
||||
|
||||
@Column(comment = "[接收人]")
|
||||
private int receiveuserid;
|
||||
|
||||
@Column(comment = "[创建时间]")
|
||||
private long createtime;
|
||||
|
||||
@Column(comment = "[状态]10已发送,20未发送")
|
||||
private short status;
|
||||
|
||||
public static FriendMessage buildFriendMessage(String content, int senduserid, int receiveuserid) {
|
||||
FriendMessage message = new FriendMessage();
|
||||
message.content = content;
|
||||
message.senduserid = senduserid;
|
||||
message.receiveuserid = receiveuserid;
|
||||
|
||||
message.createtime = System.currentTimeMillis();
|
||||
message.status = 20;
|
||||
message.messageid = Utils.fmt36(senduserid) + "-" + Utils.fmt36(message.createtime);
|
||||
return message;
|
||||
}
|
||||
|
||||
}
|
50
src/com/zchd/zim/entity/ImUser.java
Normal file
50
src/com/zchd/zim/entity/ImUser.java
Normal file
@ -0,0 +1,50 @@
|
||||
package com.zchd.zim.entity;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
import java.io.Serializable;
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
@Table(comment = "IM用户")
|
||||
public class ImUser implements Serializable {
|
||||
|
||||
public static final short STATUS_FREEZE_ACTIVE = 41;//禁言
|
||||
|
||||
@Id
|
||||
@Column(comment = "[用户标识]")
|
||||
private int userid;
|
||||
|
||||
@Column(comment = "[平台自用用户标识]")
|
||||
private String guserid = "";
|
||||
|
||||
@Column(comment = "[关联平台标识]")
|
||||
private String appid = "";
|
||||
|
||||
@Column(comment = "[创建时间]")
|
||||
private long createtime;
|
||||
|
||||
@Column(comment = "[修改时间]")
|
||||
private long updatetime;
|
||||
|
||||
@Column(comment = "[接收时间]")
|
||||
private long lastaccepttime;
|
||||
|
||||
private String imtoken;
|
||||
|
||||
@Column(comment = "[状态]10正常,40停用,80删除")
|
||||
private short status;
|
||||
|
||||
public static ImUser buildImUser(String guserid, String appid) {
|
||||
ImUser user = new ImUser();
|
||||
user.guserid = guserid;
|
||||
user.appid = appid;
|
||||
user.status = 10;
|
||||
user.createtime = System.currentTimeMillis();
|
||||
return user;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user