LAPTOP-SB56SG4Q\86185
3 years ago
18 changed files with 990 additions and 1 deletions
Binary file not shown.
Binary file not shown.
@ -1,3 +1,6 @@
|
||||
# open-JSD-8001 |
||||
|
||||
JSD-8001 多门户单点 |
||||
JSD-8001 多门户单点\ |
||||
免责说明:该源码为第三方爱好者提供,不保证源码和方案的可靠性,也不提供任何形式的源码教学指导和协助!\ |
||||
仅作为开发者学习参考使用!禁止用于任何商业用途!\ |
||||
为保护开发者隐私,开发者信息已隐去!若原开发者希望公开自己的信息,可联系hugh处理。 |
Binary file not shown.
Binary file not shown.
@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<plugin> |
||||
<id>com.fr.plugin.hjta.sso</id> |
||||
<name><![CDATA[单点登陆用户同步jsd8001]]></name> |
||||
<active>yes</active> |
||||
<version>1.1.1</version> |
||||
<env-version>10.0</env-version> |
||||
<jartime>2018-07-31</jartime> |
||||
<vendor>fr.open</vendor> |
||||
<description><![CDATA[单点登陆用户同步jsd8001]]></description> |
||||
<change-notes><![CDATA[单点登陆用户同步jsd8001]]></change-notes> |
||||
<main-package>com.fr.plugin.hjta</main-package> |
||||
<prefer-packages> |
||||
<prefer-package>com.fanruan.api</prefer-package> |
||||
</prefer-packages> |
||||
<lifecycle-monitor class="com.fr.plugin.hjta.PluginMonitor"/> |
||||
<extra-core> |
||||
<LocaleFinder class="com.fr.plugin.hjta.LocaleFinder"/> |
||||
</extra-core> |
||||
<extra-decision> |
||||
<GlobalRequestFilterProvider class="com.fr.plugin.hjta.request.OAuthLogin"/> |
||||
<HttpHandlerProvider class="com.fr.plugin.hjta.user.ProcessHttpHandlerProvider"/> |
||||
<URLAliasProvider class="com.fr.plugin.hjta.user.ProcessURLAliasProvider"/> |
||||
</extra-decision> |
||||
<function-recorder class="com.fr.plugin.hjta.LocaleFinder"/> |
||||
</plugin> |
@ -0,0 +1,37 @@
|
||||
/* |
||||
* Copyright (C), 2018-2020 |
||||
* Project: starter |
||||
* FileName: LocaleFinder |
||||
* Author: Louis |
||||
* Date: 2020/8/31 22:19 |
||||
*/ |
||||
package com.fr.plugin.hjta; |
||||
|
||||
import com.fr.intelli.record.Focus; |
||||
import com.fr.intelli.record.Original; |
||||
import com.fr.record.analyzer.EnableMetrics; |
||||
import com.fr.stable.fun.impl.AbstractLocaleFinder; |
||||
|
||||
import static com.fr.plugin.hjta.config.SsoConfig.PLUGIN_ID; |
||||
|
||||
/** |
||||
* <Function Description><br> |
||||
* <LocaleFinder> |
||||
* |
||||
* @author fr.open |
||||
* @since 1.0.0 |
||||
*/ |
||||
@EnableMetrics |
||||
public class LocaleFinder extends AbstractLocaleFinder { |
||||
|
||||
@Override |
||||
@Focus(id = PLUGIN_ID, text = "Plugin-hjta", source = Original.PLUGIN) |
||||
public String find() { |
||||
return "com/fr/plugin/hjta/locale/lang"; |
||||
} |
||||
|
||||
@Override |
||||
public int currentAPILevel() { |
||||
return CURRENT_LEVEL; |
||||
} |
||||
} |
@ -0,0 +1,34 @@
|
||||
/* |
||||
* Copyright (C), 2018-2021 |
||||
* Project: starter |
||||
* FileName: PluginMonitor |
||||
* Author: Louis |
||||
* Date: 2021/3/30 15:10 |
||||
*/ |
||||
package com.fr.plugin.hjta; |
||||
|
||||
import com.fr.plugin.context.PluginContext; |
||||
import com.fr.plugin.hjta.config.SsoConfig; |
||||
import com.fr.plugin.observer.inner.AbstractPluginLifecycleMonitor; |
||||
|
||||
|
||||
/** |
||||
* <Function Description><br> |
||||
* <PluginMonitor> |
||||
* |
||||
* @author fr.open |
||||
* @since 1.0.0 |
||||
*/ |
||||
public class PluginMonitor extends AbstractPluginLifecycleMonitor { |
||||
public PluginMonitor() { |
||||
} |
||||
|
||||
@Override |
||||
public void afterRun(PluginContext pluginContext) { |
||||
SsoConfig.getInstance(); |
||||
} |
||||
|
||||
@Override |
||||
public void beforeStop(PluginContext pluginContext) { |
||||
} |
||||
} |
@ -0,0 +1,119 @@
|
||||
/* |
||||
* Copyright (C), 2018-2021 |
||||
* Project: starter |
||||
* FileName: SsoConfig |
||||
* Author: Louis |
||||
* Date: 2021/3/30 9:38 |
||||
*/ |
||||
package com.fr.plugin.hjta.config; |
||||
|
||||
import com.fanruan.api.util.StringKit; |
||||
import com.fr.config.*; |
||||
import com.fr.config.holder.Conf; |
||||
import com.fr.config.holder.factory.Holders; |
||||
import com.fr.intelli.record.Focus; |
||||
import com.fr.intelli.record.Original; |
||||
|
||||
/** |
||||
* <Function Description><br> |
||||
* <SsoConfig> |
||||
* |
||||
* @author fr.open |
||||
* @since 1.0.0 |
||||
*/ |
||||
@Visualization(category = "Plugin-hjta_Group") |
||||
public class SsoConfig extends DefaultConfiguration { |
||||
public static final String PLUGIN_ID = "com.fr.plugin.hjta.sso"; |
||||
public static final String BASE_URI = "http://xxxx/aweb-api/sso/ssoauthority"; |
||||
|
||||
private static volatile SsoConfig config = null; |
||||
|
||||
@Focus(id = PLUGIN_ID, text = "Plugin-hjta", source = Original.PLUGIN) |
||||
public static SsoConfig getInstance() { |
||||
if (config == null) { |
||||
config = ConfigContext.getConfigInstance(SsoConfig.class); |
||||
} |
||||
return config; |
||||
} |
||||
|
||||
@Identifier(value = "homePage", name = "Plugin-hjta_Config_HomePage", description = "Plugin-hjta_Config_HomePage_Description", status = Status.SHOW) |
||||
private Conf<String> homePage = Holders.simple(StringKit.EMPTY); |
||||
@Identifier(value = "uriBase", name = "Plugin-hjta_Config_UriBase", description = "Plugin-hjta_Config_UriBase_Description", status = Status.SHOW) |
||||
private Conf<String> uriBase = Holders.simple(BASE_URI); |
||||
@Identifier(value = "serverIp", name = "Plugin-hjta_Config_ServerIp", description = "Plugin-hjta_Config_ServerIp_Description", status = Status.SHOW) |
||||
private Conf<String> serverIp = Holders.simple(StringKit.EMPTY); |
||||
@Identifier(value = "serverPort", name = "Plugin-hjta_Config_ServerPort", description = "Plugin-hjta_Config_ServerPort_Description", status = Status.SHOW) |
||||
private Conf<Integer> serverPort = Holders.simple(30015); |
||||
@Identifier(value = "userMsgCd", name = "Plugin-hjta_Config_UserMsgCd", description = "Plugin-hjta_Config_UserMsgCd_Description", status = Status.SHOW) |
||||
private Conf<String> userMsgCd = Holders.simple("BI.1000000020.01"); |
||||
@Identifier(value = "instMsgCd", name = "Plugin-hjta_Config_InstMsgCd", description = "Plugin-hjta_Config_InstMsgCd_Description", status = Status.SHOW) |
||||
private Conf<String> instMsgCd = Holders.simple("BI.1000000010.01"); |
||||
@Identifier(value = "userOutput", name = "Plugin-hjta_Config_UserOutput", description = "Plugin-hjta_Config_UserOutput_Description", status = Status.SHOW) |
||||
private Conf<String> userOutput = Holders.simple("/reportlets/userinfo.xml"); |
||||
@Identifier(value = "instOutput", name = "Plugin-hjta_Config_InstOutput", description = "Plugin-hjta_Config_InstOutput_Description", status = Status.SHOW) |
||||
private Conf<String> instOutput = Holders.simple("/reportlets/instinfo.xml"); |
||||
|
||||
public String getHomePage() { |
||||
return homePage.get(); |
||||
} |
||||
|
||||
public void setHomePage(String homePage) { |
||||
this.homePage.set(homePage); |
||||
} |
||||
|
||||
public String getUriBase() { |
||||
return uriBase.get(); |
||||
} |
||||
|
||||
public void setUriBase(String uriBase) { |
||||
this.uriBase.set(uriBase); |
||||
} |
||||
|
||||
public String getServerIp() { |
||||
return serverIp.get(); |
||||
} |
||||
|
||||
public void setServerIp(String serverIp) { |
||||
this.serverIp.set(serverIp); |
||||
} |
||||
|
||||
public int getServerPort() { |
||||
return serverPort.get(); |
||||
} |
||||
|
||||
public void setServerPort(int serverPort) { |
||||
this.serverPort.set(serverPort); |
||||
} |
||||
|
||||
public String getUserMsgCd() { |
||||
return userMsgCd.get(); |
||||
} |
||||
|
||||
public void setUserMsgCd(String userMsgCd) { |
||||
this.userMsgCd.set(userMsgCd); |
||||
} |
||||
|
||||
public String getInstMsgCd() { |
||||
return instMsgCd.get(); |
||||
} |
||||
|
||||
public void setInstMsgCd(String instMsgCd) { |
||||
this.instMsgCd.set(instMsgCd); |
||||
} |
||||
|
||||
public String getUserOutput() { |
||||
return userOutput.get(); |
||||
} |
||||
|
||||
public void setUserOutput(String userOutput) { |
||||
this.userOutput.set(userOutput); |
||||
} |
||||
|
||||
public String getInstOutput() { |
||||
return instOutput.get(); |
||||
} |
||||
|
||||
public void setInstOutput(String instOutput) { |
||||
this.instOutput.set(instOutput); |
||||
} |
||||
} |
@ -0,0 +1,175 @@
|
||||
/* |
||||
* Copyright (C), 2018-2021 |
||||
* Project: starter |
||||
* FileName: OAuthLogin |
||||
* Author: Louis |
||||
* Date: 2021/3/30 22:09 |
||||
*/ |
||||
package com.fr.plugin.hjta.request; |
||||
|
||||
import com.fanruan.api.decision.login.LoginKit; |
||||
import com.fanruan.api.decision.user.UserKit; |
||||
import com.fanruan.api.json.JSONKit; |
||||
import com.fanruan.api.log.LogKit; |
||||
import com.fanruan.api.net.NetworkKit; |
||||
import com.fanruan.api.net.http.HttpKit; |
||||
import com.fanruan.api.util.StringKit; |
||||
import com.fr.decision.fun.impl.AbstractGlobalRequestFilterProvider; |
||||
import com.fr.decision.webservice.utils.DecisionServiceConstants; |
||||
import com.fr.decision.webservice.v10.login.LoginService; |
||||
import com.fr.json.JSONObject; |
||||
import com.fr.plugin.context.PluginContexts; |
||||
import com.fr.plugin.hjta.config.SsoConfig; |
||||
import com.fr.stable.fun.Authorize; |
||||
import com.fr.third.org.apache.http.entity.StringEntity; |
||||
|
||||
import javax.servlet.FilterChain; |
||||
import javax.servlet.FilterConfig; |
||||
import javax.servlet.http.HttpServletRequest; |
||||
import javax.servlet.http.HttpServletResponse; |
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
|
||||
import static com.fr.plugin.hjta.config.SsoConfig.PLUGIN_ID; |
||||
|
||||
/** |
||||
* <Function Description><br> |
||||
* <OAuthLogin> |
||||
* |
||||
* @author fr.open |
||||
* @since 1.0.0 |
||||
*/ |
||||
@Authorize(callSignKey = PLUGIN_ID) |
||||
public class OAuthLogin extends AbstractGlobalRequestFilterProvider { |
||||
public static final String REMOTE_DESIGN = "/remote/design"; |
||||
public static final String RESOURCES_PATH = "/resources"; |
||||
public static final String FILE_PATH = "/file"; |
||||
public static final String SYSTEM_INFO = "/system/info"; |
||||
public static final String MATERIALS_MIN_JS_MAP = "/materials.min.js.map"; |
||||
public static final String LOGIN_PATH = "/login"; |
||||
public static final String LOGIN_OTHER = "/login/"; |
||||
public static final String LOGOUT_PATH = "/logout"; |
||||
public static final String USER_LANGUAGE = "/v10/user/language"; |
||||
public static final String SYSTEM_HEALTH = "/system/health"; |
||||
|
||||
public static final String CODE = "uid"; |
||||
public static final String USER_IDENTITY = "userIdentity"; |
||||
|
||||
private SsoConfig config; |
||||
|
||||
/** |
||||
* 过滤器名称 |
||||
* |
||||
* @return |
||||
*/ |
||||
@Override |
||||
public String filterName() { |
||||
return "hjtaFilter"; |
||||
} |
||||
|
||||
/** |
||||
* 过滤规则 |
||||
* |
||||
* @return |
||||
*/ |
||||
@Override |
||||
public String[] urlPatterns() { |
||||
return new String[]{"/*"}; |
||||
} |
||||
|
||||
/** |
||||
* 过滤器初始化 |
||||
* |
||||
* @param filterConfig |
||||
*/ |
||||
@Override |
||||
public void init(FilterConfig filterConfig) { |
||||
this.config = SsoConfig.getInstance(); |
||||
super.init(filterConfig); |
||||
} |
||||
|
||||
/** |
||||
* 过滤器处理 |
||||
* |
||||
* @param request |
||||
* @param response |
||||
* @param filterChain |
||||
*/ |
||||
@Override |
||||
public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) { |
||||
try { |
||||
if (operation(request, response)) { |
||||
filterChain.doFilter(request, response); |
||||
} |
||||
} catch (Exception e) { |
||||
LogKit.error(e.getMessage(), e); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 用户验证登陆操作 |
||||
* |
||||
* @param req |
||||
* @param res |
||||
* @throws Exception |
||||
*/ |
||||
private boolean operation(HttpServletRequest req, HttpServletResponse res) throws Exception { |
||||
String pathInfo = (req.getPathInfo() != null) ? req.getPathInfo() : StringKit.EMPTY; |
||||
if (pathInfo.startsWith(REMOTE_DESIGN) || pathInfo.startsWith(LOGIN_OTHER) |
||||
|| StringKit.equals(LOGIN_PATH, pathInfo) |
||||
|| pathInfo.startsWith(RESOURCES_PATH) || pathInfo.startsWith(LOGOUT_PATH) |
||||
|| pathInfo.startsWith(SYSTEM_INFO) || pathInfo.startsWith(MATERIALS_MIN_JS_MAP) || pathInfo.startsWith(SYSTEM_HEALTH) |
||||
|| pathInfo.startsWith(USER_LANGUAGE) || pathInfo.startsWith(FILE_PATH)) { |
||||
return true; |
||||
} |
||||
String code = NetworkKit.getHTTPRequestParameter(req, CODE); |
||||
String userIdentity = NetworkKit.getHTTPRequestParameter(req, USER_IDENTITY); |
||||
if (StringKit.isBlank(code) && StringKit.isBlank(userIdentity)) { |
||||
return true; |
||||
} |
||||
// 已登录
|
||||
if (LoginService.getInstance().isLogged(req)) { |
||||
return true; |
||||
} |
||||
String username = StringKit.EMPTY; |
||||
if (StringKit.isNotBlank(code)) { |
||||
username = getUsername(code); |
||||
} |
||||
if (StringKit.isNotBlank(userIdentity)) { |
||||
username = userIdentity; |
||||
} |
||||
if (StringKit.isEmpty(username) || !UserKit.existUsername(username)) { |
||||
return true; |
||||
} |
||||
// 验证插件授权
|
||||
if (!PluginContexts.currentContext().isAvailable()) { |
||||
return true; |
||||
} |
||||
String tokenFR = LoginKit.login(req, res, username); |
||||
req.setAttribute(DecisionServiceConstants.FINE_AUTH_TOKEN_NAME, tokenFR); |
||||
if (StringKit.isNotBlank(this.config.getHomePage())) { |
||||
res.sendRedirect(this.config.getHomePage()); |
||||
return false; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* 通过凭证获得username |
||||
* |
||||
* @param accessToken |
||||
* @return |
||||
*/ |
||||
private String getUsername(String accessToken) throws Exception { |
||||
JSONObject params = JSONKit.create(); |
||||
params.put("token", accessToken); |
||||
LogKit.info("hjta-OAuthLogin-getUsername-params:{}", params); |
||||
Map<String, String> headers = new HashMap<>(); |
||||
headers.put("Content-Type", "application/json"); |
||||
StringEntity stringEntity = new StringEntity(params.encode(), "UTF-8"); |
||||
String userRes = HttpKit.executeAndParse(com.fanruan.api.net.http.rs.HttpRequest.custom() |
||||
.url(this.config.getUriBase()).post(stringEntity).headers(headers).build()); |
||||
LogKit.info("hjta-OAuthLogin-getUsername-userRes:{}", userRes); |
||||
return new JSONObject(userRes).getJSONObject("obj").getString("username"); |
||||
} |
||||
} |
@ -0,0 +1,33 @@
|
||||
/* |
||||
* Copyright (C), 2018-2020 |
||||
* Project: starter |
||||
* FileName: ProcessHttpHandlerProvider |
||||
* Author: Louis |
||||
* Date: 2020/9/11 8:41 |
||||
*/ |
||||
package com.fr.plugin.hjta.user; |
||||
|
||||
import com.fr.decision.fun.impl.AbstractHttpHandlerProvider; |
||||
import com.fr.decision.fun.impl.BaseHttpHandler; |
||||
import com.fr.record.analyzer.EnableMetrics; |
||||
|
||||
/** |
||||
* <Function Description><br> |
||||
* <ProcessHttpHandlerProvider> |
||||
* |
||||
* @author fr.open |
||||
* @since 1.0.0 |
||||
*/ |
||||
@EnableMetrics |
||||
public class ProcessHttpHandlerProvider extends AbstractHttpHandlerProvider { |
||||
|
||||
public ProcessHttpHandlerProvider() { |
||||
} |
||||
|
||||
@Override |
||||
public BaseHttpHandler[] registerHandlers() { |
||||
return new BaseHttpHandler[]{ |
||||
new StartProcessHandler() |
||||
}; |
||||
} |
||||
} |
@ -0,0 +1,34 @@
|
||||
/* |
||||
* Copyright (C), 2018-2020 |
||||
* Project: starter |
||||
* FileName: ProcessURLAliasProvider |
||||
* Author: Louis |
||||
* Date: 2020/9/11 8:47 |
||||
*/ |
||||
package com.fr.plugin.hjta.user; |
||||
|
||||
import com.fr.decision.fun.impl.AbstractURLAliasProvider; |
||||
import com.fr.decision.webservice.url.alias.URLAlias; |
||||
import com.fr.decision.webservice.url.alias.URLAliasFactory; |
||||
|
||||
import static com.fr.plugin.hjta.user.StartProcessHandler.START_PROCESS; |
||||
|
||||
/** |
||||
* <Function Description><br> |
||||
* <ProcessURLAliasProvider> |
||||
* |
||||
* @author fr.open |
||||
* @since 1.0.0 |
||||
*/ |
||||
public class ProcessURLAliasProvider extends AbstractURLAliasProvider { |
||||
|
||||
public ProcessURLAliasProvider() { |
||||
} |
||||
|
||||
@Override |
||||
public URLAlias[] registerAlias() { |
||||
return new URLAlias[]{ |
||||
URLAliasFactory.createPluginAlias(START_PROCESS, START_PROCESS, true) |
||||
}; |
||||
} |
||||
} |
@ -0,0 +1,113 @@
|
||||
/* |
||||
* Copyright (C), 2018-2020 |
||||
* Project: starter |
||||
* FileName: StartProcessHandler |
||||
* Author: Louis |
||||
* Date: 2020/9/11 8:51 |
||||
*/ |
||||
package com.fr.plugin.hjta.user; |
||||
|
||||
import com.fanruan.api.json.JSONKit; |
||||
import com.fanruan.api.log.LogKit; |
||||
import com.fr.decision.fun.impl.BaseHttpHandler; |
||||
import com.fr.json.JSONObject; |
||||
import com.fr.plugin.context.PluginContexts; |
||||
import com.fr.plugin.hjta.config.SsoConfig; |
||||
import com.fr.plugin.hjta.user.xsocket.server.ServerHandler; |
||||
import com.fr.stable.fun.Authorize; |
||||
import com.fr.third.springframework.web.bind.annotation.RequestMethod; |
||||
import com.fr.web.utils.WebUtils; |
||||
import org.xsocket.connection.IConnection; |
||||
import org.xsocket.connection.IServer; |
||||
import org.xsocket.connection.Server; |
||||
|
||||
import javax.servlet.http.HttpServletRequest; |
||||
import javax.servlet.http.HttpServletResponse; |
||||
import java.net.InetAddress; |
||||
import java.util.Map; |
||||
|
||||
import static com.fr.plugin.hjta.config.SsoConfig.PLUGIN_ID; |
||||
|
||||
/** |
||||
* <Function Description><br> |
||||
* <StartProcessHandler> |
||||
* |
||||
* @author fr.open |
||||
* @since 1.0.0 |
||||
*/ |
||||
@Authorize(callSignKey = PLUGIN_ID) |
||||
public class StartProcessHandler extends BaseHttpHandler { |
||||
|
||||
public static final String START_PROCESS = "/server/start"; |
||||
|
||||
private SsoConfig config; |
||||
|
||||
public StartProcessHandler() { |
||||
this.config = SsoConfig.getInstance(); |
||||
} |
||||
|
||||
@Override |
||||
public RequestMethod getMethod() { |
||||
return RequestMethod.GET; |
||||
} |
||||
|
||||
@Override |
||||
public String getPath() { |
||||
return START_PROCESS; |
||||
} |
||||
|
||||
@Override |
||||
public boolean isPublic() { |
||||
return true; |
||||
} |
||||
|
||||
@Override |
||||
public void handle(HttpServletRequest request, HttpServletResponse response) throws Exception { |
||||
JSONObject data = JSONKit.create(); |
||||
if (!PluginContexts.currentContext().isAvailable()) { |
||||
data.put("status", "Plugin License is expired."); |
||||
WebUtils.flushSuccessMessageAutoClose(request, response, data); |
||||
return; |
||||
} |
||||
try { |
||||
startSocketServer(); |
||||
data.put("status", "socket server running"); |
||||
WebUtils.flushSuccessMessageAutoClose(request, response, data); |
||||
} catch (Exception e) { |
||||
LogKit.error(e.getMessage(), e); |
||||
data.put("status", "socket server already running"); |
||||
WebUtils.flushSuccessMessageAutoClose(request, response, data); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 采用XSocket通讯的服务端 |
||||
*/ |
||||
private void startSocketServer() throws Exception { |
||||
// 注意其构造方法有多个。一般是使用这种构造方法出来的!
|
||||
// 不过要注意一下java.net.InetAddress这个类的使用在初始化的时候需要捕获异常
|
||||
// 可能是这个绑定的主机可能不存在之类的异常即UnknowHostNameException
|
||||
InetAddress address = InetAddress.getByName(this.config.getServerIp()); |
||||
//InetAddress address = InetAddress.getLocalHost();
|
||||
// 创建一个服务端的对象
|
||||
IServer srv = new Server(address, this.config.getServerPort(), new ServerHandler()); |
||||
// 设置当前的采用的异步模式
|
||||
srv.setFlushmode(IConnection.FlushMode.ASYNC); |
||||
try { |
||||
// srv.run();
|
||||
// the call will not return
|
||||
// ... or start it by using a dedicated thread
|
||||
srv.start(); // returns after the server has been started
|
||||
LogKit.info("hjta-UserPluginMonitor-Server:" + srv.getLocalAddress() + ":" + this.config.getServerPort()); |
||||
Map<String, Class> maps = srv.getOptions(); |
||||
if (maps != null) { |
||||
for (Map.Entry<String, Class> entry : maps.entrySet()) { |
||||
LogKit.info("hjta-UserPluginMonitor-key= " + entry.getKey() + " value =" + entry.getValue().getName()); |
||||
} |
||||
} |
||||
//System.out.println("版本: " + srv.getStartUpLogMessage());
|
||||
} catch (Exception e) { |
||||
LogKit.error(e.getMessage(), e); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,143 @@
|
||||
package com.fr.plugin.hjta.user.xsocket.server; |
||||
|
||||
import com.fanruan.api.log.LogKit; |
||||
import com.fr.base.TemplateUtils; |
||||
import com.fr.general.ComparatorUtils; |
||||
import com.fr.io.utils.ResourceIOUtils; |
||||
import com.fr.plugin.hjta.config.SsoConfig; |
||||
import com.fr.stable.StringUtils; |
||||
import com.fr.workspace.WorkContext; |
||||
|
||||
import java.io.InputStream; |
||||
import java.text.SimpleDateFormat; |
||||
import java.util.Date; |
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
|
||||
public class BizMessage { |
||||
public static final String USER_RESPONSE = "<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?><transaction><header><msg><msgCd>BI.1000000020.01</msgCd><seqNb>UCA20200929094246976</seqNb><sndAppCd>UCA</sndAppCd><sndDt>20200929</sndDt><sndTm>094246976</sndTm><rcvAppCd>BRD</rcvAppCd><srcAppCd>UCA</srcAppCd><srcNb>GUCA-202009290094246976</srcNb></msg><status><desc>OK</desc><appCd>ESB</appCd><retCd>000000</retCd><ip>${serverIp}</ip></status></header><body><response><info>${dt}</info></response></body></transaction>"; |
||||
public static final String INST_RESPONSE = "<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?><transaction><header><msg><msgCd>BI.1000000010.01</msgCd><seqNb>UCA20200929094722390</seqNb><sndAppCd>UCA</sndAppCd><sndDt>20200929</sndDt><sndTm>094722390</sndTm><rcvAppCd>BRD</rcvAppCd><srcAppCd>UCA</srcAppCd><srcNb>GUCA-202009290094722390</srcNb></msg><status><desc>OK</desc><appCd>ESB</appCd><retCd>000000</retCd><ip>${serverIp}</ip></status></header><body><response><info>${dt}</info></response></body></transaction>"; |
||||
public static final String USER_BEAN_ARRAY_START = "<request>"; |
||||
public static final String USER_BEAN_ARRAY_END = "</request>"; |
||||
public static final String USER_BEAN_START = "<RvlNode>"; |
||||
public static final String USER_BEAN_END = "</RvlNode>"; |
||||
public static final String INST_BEAN_ARRAY_START = "<request>"; |
||||
public static final String INST_BEAN_ARRAY_END = "</request>"; |
||||
public static final String INST_BEAN_START = "<RvlNode>"; |
||||
public static final String INST_BEAN_END = "</RvlNode>"; |
||||
|
||||
// 测试超时服务
|
||||
public String responseMsg(String request) throws Exception { |
||||
LogKit.info("hjta-BizMessage-responseMsg-request:{}", request); |
||||
String msgCd = parseMsgCd(request); |
||||
if (StringUtils.isEmpty(msgCd)) { |
||||
return null; |
||||
} |
||||
String responseType = StringUtils.EMPTY; |
||||
if (ComparatorUtils.equals(msgCd, SsoConfig.getInstance().getUserMsgCd())) { |
||||
responseType = USER_RESPONSE; |
||||
operationUser(request); |
||||
} else if (ComparatorUtils.equals(msgCd, SsoConfig.getInstance().getInstMsgCd())) { |
||||
responseType = INST_RESPONSE; |
||||
operationInstitution(request); |
||||
} |
||||
String dt = new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date()); |
||||
Map<String, Object> params = new HashMap<String, Object>(); |
||||
params.put("dt", dt); |
||||
String msg = TemplateUtils.renderTemplate(responseType, params); |
||||
LogKit.info("hjta-BizMessage-responseMsg-response:{}", msg); |
||||
return msg; |
||||
} |
||||
|
||||
/** |
||||
* 用户变更广播处理 |
||||
* |
||||
* @param request |
||||
* @throws Exception |
||||
*/ |
||||
private void operationUser(String request) { |
||||
int start = request.indexOf(USER_BEAN_ARRAY_START) + USER_BEAN_ARRAY_START.length(); |
||||
int end = request.indexOf(USER_BEAN_ARRAY_END); |
||||
String[] users = request.substring(start, end).split(USER_BEAN_END); |
||||
for (String user : users) { |
||||
if (!StringUtils.contains(user, USER_BEAN_START)) { |
||||
continue; |
||||
} |
||||
int beanStart = user.indexOf(USER_BEAN_START) + USER_BEAN_START.length(); |
||||
String userBean = user.substring(beanStart); |
||||
write2xml("<userInfo>\n" + userBean + "\n</userInfo>\n", SsoConfig.getInstance().getUserOutput()); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 机构变更广播 |
||||
* |
||||
* @param request |
||||
* @throws Exception |
||||
*/ |
||||
private void operationInstitution(String request) { |
||||
int start = request.indexOf(INST_BEAN_ARRAY_START) + INST_BEAN_ARRAY_START.length(); |
||||
int end = request.indexOf(INST_BEAN_ARRAY_END); |
||||
String[] insts = request.substring(start, end).split(INST_BEAN_END); |
||||
for (String inst : insts) { |
||||
if (!StringUtils.contains(inst, INST_BEAN_START)) { |
||||
continue; |
||||
} |
||||
int beanStart = inst.indexOf(INST_BEAN_START) + INST_BEAN_START.length(); |
||||
String instBean = inst.substring(beanStart); |
||||
write2xml("<instInfo>\n" + instBean + "\n</instInfo>\n", SsoConfig.getInstance().getInstOutput()); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 解析获得msgCd |
||||
* |
||||
* @param request |
||||
* @return |
||||
*/ |
||||
private String parseMsgCd(String request) { |
||||
String labelStart = "<msgCd>"; |
||||
String labelEnd = "</msgCd>"; |
||||
int startIndex; |
||||
int endIndex; |
||||
startIndex = request.indexOf(labelStart) + labelStart.length(); |
||||
endIndex = request.indexOf(labelEnd); |
||||
return request.substring(startIndex, endIndex); |
||||
} |
||||
|
||||
/** |
||||
* 报文输出到xml |
||||
* |
||||
* @param data |
||||
* @param path |
||||
*/ |
||||
private void write2xml(String data, String path) { |
||||
String fileContent; |
||||
if (WorkContext.getWorkResource().createFile(path)) { |
||||
fileContent = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" + data; |
||||
} else { |
||||
InputStream fileInputStream = WorkContext.getWorkResource().openStream(path); |
||||
fileContent = ResourceIOUtils.inputStream2String(fileInputStream) + data; |
||||
} |
||||
WorkContext.getWorkResource().write(path, fileContent.getBytes()); |
||||
} |
||||
|
||||
// /**
|
||||
// * 报文输出到xml
|
||||
// *
|
||||
// * @param data
|
||||
// * @param path
|
||||
// */
|
||||
// private void write2xml(String data, String path) {
|
||||
// API.LOG.info("sso-BizMessage-write2xml-before-getUnderlying:{}", ResourceIOUtils.getUnderlying().toString());
|
||||
// if (ResourceIOUtils.createFile(path)) {
|
||||
// String xmlHead = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n";
|
||||
// ResourceIOUtils.write(path, xmlHead + data);
|
||||
// } else {
|
||||
// InputStream fileInputStream = ResourceIOUtils.read(path);
|
||||
// String fileContent = ResourceIOUtils.inputStream2String(fileInputStream);
|
||||
// ResourceIOUtils.write(path, fileContent + data);
|
||||
// }
|
||||
// API.LOG.info("sso-BizMessage-write2xml-after-getUnderlying:{}", ResourceIOUtils.getUnderlying().toString());
|
||||
// }
|
||||
} |
@ -0,0 +1,236 @@
|
||||
package com.fr.plugin.hjta.user.xsocket.server; |
||||
|
||||
import com.fanruan.api.log.LogKit; |
||||
import org.xsocket.MaxReadSizeExceededException; |
||||
import org.xsocket.connection.*; |
||||
|
||||
import java.io.IOException; |
||||
import java.nio.BufferUnderflowException; |
||||
import java.nio.channels.ClosedChannelException; |
||||
|
||||
|
||||
/** |
||||
* 服务端定义数据的处理类 |
||||
* |
||||
* @author fr.open |
||||
*/ |
||||
public class ServerHandler |
||||
implements IDataHandler, IConnectHandler, IIdleTimeoutHandler, IConnectionTimeoutHandler, IDisconnectHandler { |
||||
|
||||
/** |
||||
* 即当建立完连接之后可以进行的一些相关操作处理。包括修改连接属性、准备资源、等! 连接的成功时的操作 |
||||
*/ |
||||
@Override |
||||
public boolean onConnect(INonBlockingConnection nbc) |
||||
throws IOException, BufferUnderflowException, MaxReadSizeExceededException { |
||||
|
||||
String remoteName = nbc.getRemoteAddress().getHostName(); |
||||
System.out.println("remoteName " + remoteName + " has connected !"); |
||||
|
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* 即如果失去连接应当如何处理? 需要实现 IDisconnectHandler 这个接口 连接断开时的操作 |
||||
*/ |
||||
@Override |
||||
public boolean onDisconnect(INonBlockingConnection nbc) throws IOException { |
||||
System.out.println("remote close !"); |
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* 即这个方法不光是说当接收到一个新的网络包的时候会调用而且如果有新的缓存存在的时候也会被调用。而且 The onData will also be called, if the connection is |
||||
* closed当连接被关闭的时候也会被调用的! |
||||
*/ |
||||
@Override |
||||
public boolean onData(INonBlockingConnection nbc) |
||||
throws IOException, BufferUnderflowException, ClosedChannelException, MaxReadSizeExceededException { |
||||
|
||||
// 无报文头获取报文
|
||||
// return rcvData(nbc,"ok");
|
||||
// 报文头获取文
|
||||
|
||||
return rcvDataByHrdLen(nbc, 8); |
||||
// return rcvDataByHrdLenTest(nbc, 8);
|
||||
} |
||||
|
||||
// 无报文头接收
|
||||
public boolean rcvData(INonBlockingConnection nbc, String delimiterStr) |
||||
throws IOException, BufferUnderflowException, ClosedChannelException, MaxReadSizeExceededException { |
||||
// 接收请求报文体
|
||||
byte[] rcvMsgByte = nbc.readBytesByDelimiter(delimiterStr); |
||||
String rcvMsg = new String(rcvMsgByte, "UTF-8"); |
||||
|
||||
// 输出请求
|
||||
LogKit.info("hjta-ServerHandler-rcvData-rcvMsgByte size:" + rcvMsgByte.length); |
||||
LogKit.info("hjta-ServerHandler-rcvData-rcvMsgBody:" + rcvMsg); |
||||
|
||||
BizMessage bizMessage = new BizMessage(); |
||||
String rspMsg = ""; |
||||
try { |
||||
rspMsg = bizMessage.responseMsg(rcvMsg);// 获取应答报文
|
||||
|
||||
} catch (Exception ex) { |
||||
ex.printStackTrace(); |
||||
} |
||||
|
||||
String rspHdrLen = String.format("%08d", rspMsg.getBytes("UTF-8").length); |
||||
byte[] rspMsgByte = (rspHdrLen + rspMsg).getBytes("utf-8"); |
||||
|
||||
// 输出应答报文
|
||||
nbc.write(rspMsgByte); |
||||
nbc.flush(); |
||||
// 不输出应答报文
|
||||
|
||||
LogKit.info("hjta-ServerHandler-rcvData-rspHdrLen:" + rspHdrLen + ",rspMsgByte:" + rspMsg); |
||||
return true; |
||||
} |
||||
|
||||
public boolean rcvDataByHrdLen(INonBlockingConnection nbc, int hrdLen) |
||||
throws IOException, BufferUnderflowException, ClosedChannelException, MaxReadSizeExceededException { |
||||
|
||||
// 接收请求报文头
|
||||
byte[] rcvHdr = nbc.readBytesByLength(hrdLen); |
||||
String rcvHdrLen = new String(rcvHdr, "UTF-8"); |
||||
|
||||
// 接收请求报文体
|
||||
byte[] rcvMsgByte = nbc.readBytesByLength(Integer.parseInt(rcvHdrLen)); |
||||
String rcvMsg = new String(rcvMsgByte, "UTF-8"); |
||||
|
||||
// 输出请求
|
||||
LogKit.info("hjta-ServerHandler-rcvDataByHrdLen-rcvMsgHdrLen:" + rcvHdrLen); |
||||
// System.out.println("rcvMsgBody:" + rcvMsg);
|
||||
|
||||
// try {
|
||||
// //阻塞69秒
|
||||
// Thread.sleep(10000);
|
||||
// }catch (Exception ex){
|
||||
// ex.printStackTrace();
|
||||
// }
|
||||
|
||||
BizMessage bizMessage = new BizMessage(); |
||||
String rspMsg = ""; |
||||
try { |
||||
rspMsg = bizMessage.responseMsg(rcvMsg);// 获取应答报文
|
||||
} catch (Exception ex) { |
||||
ex.printStackTrace(); |
||||
} |
||||
|
||||
String rspHdrLen = String.format("%08d", rspMsg.getBytes("UTF-8").length); |
||||
byte[] rspMsgByte = (rspHdrLen + rspMsg).getBytes("utf-8"); |
||||
|
||||
nbc.close(); |
||||
// 输出应答报文
|
||||
nbc.write(rspMsgByte); |
||||
nbc.flush(); |
||||
|
||||
LogKit.info("hjta-ServerHandler-rcvDataByHrdLen-rspHdrLen:" + rspHdrLen + "\n\n"); |
||||
return true; |
||||
} |
||||
|
||||
public boolean rcvDataByHrdLenTest(INonBlockingConnection nbc, int hrdLen) |
||||
throws IOException, BufferUnderflowException, ClosedChannelException, MaxReadSizeExceededException { |
||||
// test user
|
||||
String rcvMsg = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?><transaction><header><ver>1.0</ver><msg><msgCd>BI.1000000020.01</msgCd><seqNb>UCA20200929094246976</seqNb><sndAppCd>UCA</sndAppCd><sndDt>20200929</sndDt><sndTm>094246976</sndTm><rcvAppCd>BRD</rcvAppCd><srcAppCd>UCA</srcAppCd><srcNb>GUCA-202009290094246976</srcNb></msg></header><body><request><ReqBaseHdr><ChnlCD>999999</ChnlCD><InsNo>0001</InsNo><TlrNo>UCA9000001</TlrNo><BrNo>0001</BrNo><LglPsnID>001</LglPsnID></ReqBaseHdr><RvlNode><EmpID>4259</EmpID><CtcPsnNm>张三</CtcPsnNm><Sex>1</Sex><IDNo>130732199106240854</IDNo><MblPhNo>13831314787</MblPhNo><EmailAdr>278178879@qq.com</EmailAdr><CtcPsnAdr>张家口市桥西区六</CtcPsnAdr><CustSt>01</CustSt><MbrStCD>2</MbrStCD><InsID>0000</InsID><DeptId>5</DeptId><Duty>科员8</Duty><Dept2>000017</Dept2><RgstSt>1</RgstSt><CrtDt>20200929</CrtDt></RvlNode></request></body></transaction>"; |
||||
// test inist
|
||||
// String rcvMsg = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?><transaction><header><ver>1.0</ver><msg><msgCd>BI.1000000010.01</msgCd><seqNb>UCA20200929094722390</seqNb><sndAppCd>UCA</sndAppCd><sndDt>20200929</sndDt><sndTm>094722390</sndTm><rcvAppCd>BRD</rcvAppCd><srcAppCd>UCA</srcAppCd><srcNb>GUCA-202009290094722390</srcNb></msg></header><body><request><ReqBaseHdr><ChnlCD>999999</ChnlCD><InsNo>0001</InsNo><TlrNo>UCA9000001</TlrNo><BrNo>0001</BrNo><LglPsnID>001</LglPsnID></ReqBaseHdr><RvlNode><UUID>BYpQl1Mg1eOKHgFKeT6MLA</UUID><InsID>5605</InsID><InstNm>5605涿州支行</InstNm><PuuID>x3r1KEVrVO9YIAFKeT5FoA</PuuID><PrnInsID>5600</PrnInsID><WrkUnitAdr>河北省保定市涿州市平安北街123号</WrkUnitAdr><TelCtcModWrkNo>0312-5455123</TelCtcModWrkNo><InstPnp>1187</InstPnp><MbrStCD>2</MbrStCD><InstEngNm>涿州支行</InstEngNm><BlngRgonCD>130600</BlngRgonCD><EstbDt>20180314</EstbDt><CustSt>00</CustSt><ZipECD>071000</ZipECD><LglPsnID>001</LglPsnID><InstTpCD>0</InstTpCD><Prov>河北省</Prov><City>保定市</City><Cnty>涿州</Cnty><DtlAdr>河北省保定市涿州市平安北街123号</DtlAdr><Lgt>116.024739</Lgt><Ltt>39.502208</Ltt><BrID>C1</BrID><ClrgBnkNo>313134002017</ClrgBnkNo><ProvCityZonCD>1352</ProvCityZonCD><FncInstIDCD></FncInstIDCD><BlngExOffCD>130600</BlngExOffCD><FTAZonID>0</FTAZonID><InstMgtList>5605|5600|0000|</InstMgtList><CrtDt>20200929</CrtDt><IsCashBusiness>1</IsCashBusiness><TownID>130681</TownID></RvlNode></request></body></transaction>";
|
||||
BizMessage bizMessage = new BizMessage(); |
||||
String rspMsg = ""; |
||||
try { |
||||
rspMsg = bizMessage.responseMsg(rcvMsg);// 获取应答报文
|
||||
} catch (Exception ex) { |
||||
ex.printStackTrace(); |
||||
} |
||||
|
||||
String rspHdrLen = String.format("%08d", rspMsg.getBytes("UTF-8").length); |
||||
byte[] rspMsgByte = (rspHdrLen + rspMsg).getBytes("utf-8"); |
||||
|
||||
nbc.close(); |
||||
// 输出应答报文
|
||||
nbc.write(rspMsgByte); |
||||
nbc.flush(); |
||||
|
||||
LogKit.info("hjta-ServerHandler-rcvDataByHrdLen-rspHdrLen:" + rspHdrLen + "\n\n"); |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* 请求处理超时的处理事件 Handles idle timeout. The timeouts will be defined by the server. To modify the timeouts the proper |
||||
* server methods has to be called. E.g.<br> |
||||
* |
||||
* <pre> |
||||
* ... |
||||
* IServer server = new Server(new MyHandler()); |
||||
* server.setIdleTimeoutMillis(60 * 1000); |
||||
* ConnectionUtils.start(server); |
||||
* ... |
||||
* |
||||
* |
||||
* class MyHandler implements IIdleTimeoutHandler { |
||||
* |
||||
* public boolean onIdleTimeout(INonBlockingConnection connection) throws IOException { |
||||
* ... |
||||
* connection.close(); |
||||
* return true; // true -> event has been handled (by returning false xSocket will close the connection)
|
||||
* } |
||||
* } |
||||
* </pre> |
||||
* |
||||
* @author grro@xsocket.org |
||||
*/ |
||||
|
||||
/** |
||||
* handles the idle timeout. |
||||
* |
||||
* @param connection the underlying connection |
||||
* @return true if the timeout event has been handled (in case of false the connection will be closed by the server) |
||||
* @throws IOException if an error occurs. Throwing this exception causes that the underlying connection will be closed. |
||||
*/ |
||||
@Override |
||||
public boolean onIdleTimeout(INonBlockingConnection connection) throws IOException { |
||||
// TODO Auto-generated method stub
|
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* Handles connection timeout. The timeouts will be defined by the server. To modify the timeouts the proper server |
||||
* methods has to be called. E.g.<br> |
||||
* |
||||
* <pre> |
||||
* ... |
||||
* IServer server = new Server(new MyHandler()); |
||||
* server.setConnectionTimeoutMillis(60 * 1000); |
||||
* ConnectionUtils.start(server); |
||||
* ... |
||||
* |
||||
* |
||||
* class MyHandler implements IConnectionTimeoutHandler { |
||||
* |
||||
* public boolean onConnectionTimeout(INonBlockingConnection connection) throws IOException { |
||||
* ... |
||||
* connection.close(); |
||||
* return true; // true -> event has been handled (by returning false xSocket will close the connection)
|
||||
* } |
||||
* } |
||||
* </pre> |
||||
* |
||||
* @author grro@xsocket.org |
||||
*/ |
||||
|
||||
/** |
||||
* handles the connection timeout. |
||||
* |
||||
* @param connection the underlying connection |
||||
* @return true if the timeout event has been handled (in case of false the connection will be closed by the server) |
||||
* @throws IOException if an error occurs. Throwing this exception causes that the underlying connection will be closed. |
||||
*/ |
||||
/** |
||||
* 连接超时处理事件 |
||||
*/ |
||||
@Override |
||||
public boolean onConnectionTimeout(INonBlockingConnection connection) throws IOException { |
||||
// TODO Auto-generated method stub
|
||||
return false; |
||||
} |
||||
} |
@ -0,0 +1,18 @@
|
||||
Plugin-hjta=Sso Plugin |
||||
Plugin-hjta_Group=Sso Plugin |
||||
Plugin-hjta_Config_HomePage=Home Page |
||||
Plugin-hjta_Config_HomePage_Description=Home Page |
||||
Plugin-hjta_Config_UriBase=Uri Base |
||||
Plugin-hjta_Config_UriBase_Description=Uri Base |
||||
Plugin-hjta_Config_ServerIp=Server Ip |
||||
Plugin-hjta_Config_ServerIp_Description=Server Ip |
||||
Plugin-hjta_Config_ServerPort=Server Port |
||||
Plugin-hjta_Config_ServerPort_Description=Server Port |
||||
Plugin-hjta_Config_UserMsgCd=UserMsgCd |
||||
Plugin-hjta_Config_UserMsgCd_Description=UserMsgCd |
||||
Plugin-hjta_Config_InstMsgCd=InstMsgCd |
||||
Plugin-hjta_Config_InstMsgCd_Description=InstMsgCd |
||||
Plugin-hjta_Config_UserOutput=UserOutput |
||||
Plugin-hjta_Config_UserOutput_Description=UserOutput |
||||
Plugin-hjta_Config_InstOutput=Inst Output |
||||
Plugin-hjta_Config_InstOutput_Description=Inst Output |
@ -0,0 +1,18 @@
|
||||
Plugin-hjta=\u5355\u70B9\u767B\u9646\u63D2\u4EF6 |
||||
Plugin-hjta_Group=\u5355\u70B9\u767B\u9646\u63D2\u4EF6 |
||||
Plugin-hjta_Config_HomePage=\u6307\u5B9A\u9996\u9875 |
||||
Plugin-hjta_Config_HomePage_Description=\u6307\u5B9A\u9996\u9875 |
||||
Plugin-hjta_Config_UriBase=\u7EDF\u4E00\u8BA4\u8BC1\u63A5\u53E3 |
||||
Plugin-hjta_Config_UriBase_Description=\u7EDF\u4E00\u8BA4\u8BC1\u63A5\u53E3 |
||||
Plugin-hjta_Config_ServerIp=\u672C\u5730\u670D\u52A1IP |
||||
Plugin-hjta_Config_ServerIp_Description=\u672C\u5730\u670D\u52A1IP |
||||
Plugin-hjta_Config_ServerPort=\u672C\u5730\u670D\u52A1\u7AEF\u53E3 |
||||
Plugin-hjta_Config_ServerPort_Description=\u672C\u5730\u670D\u52A1\u7AEF\u53E3 |
||||
Plugin-hjta_Config_UserMsgCd=\u7528\u6237MsgCd |
||||
Plugin-hjta_Config_UserMsgCd_Description=\u7528\u6237MsgCd |
||||
Plugin-hjta_Config_InstMsgCd=\u673A\u6784MsgCd |
||||
Plugin-hjta_Config_InstMsgCd_Description=\u673A\u6784MsgCd |
||||
Plugin-hjta_Config_UserOutput=\u7528\u6237\u4FE1\u606Fxml\u6587\u4EF6 |
||||
Plugin-hjta_Config_UserOutput_Description=\u7528\u6237\u4FE1\u606Fxml\u6587\u4EF6 |
||||
Plugin-hjta_Config_InstOutput=\u673A\u6784\u4FE1\u606Fxml\u6587\u4EF6 |
||||
Plugin-hjta_Config_InstOutput_Description=\u673A\u6784\u4FE1\u606Fxml\u6587\u4EF6 |
Binary file not shown.
Loading…
Reference in new issue