Repository: bupt1987/JgFramework Branch: master Commit: 1bf38c4d7f4b Files: 76 Total size: 258.7 KB Directory structure: gitextract_g4i9k2tv/ ├── .gitignore ├── LICENSE ├── README.md ├── default_applicationContext.xml ├── default_jgframework.properties ├── pom.xml └── src/ └── main/ ├── java/ │ └── com/ │ └── zhaidaosi/ │ └── game/ │ └── jgframework/ │ ├── Boot.java │ ├── Router.java │ ├── common/ │ │ ├── BaseAvlTree.java │ │ ├── BaseDate.java │ │ ├── BaseFile.java │ │ ├── BaseGeneratePassword.java │ │ ├── BaseIp.java │ │ ├── BaseJson.java │ │ ├── BaseRunTimer.java │ │ ├── BaseSocket.java │ │ ├── BaseString.java │ │ ├── cache/ │ │ │ ├── BaseLocalCached.java │ │ │ └── BaseMemCached.java │ │ ├── encrpt/ │ │ │ ├── BaseDes.java │ │ │ ├── BaseMd5.java │ │ │ └── BaseRsa.java │ │ ├── excption/ │ │ │ ├── BaseException.java │ │ │ ├── HttpException.java │ │ │ ├── IBaseException.java │ │ │ └── MessageException.java │ │ ├── http/ │ │ │ ├── BaseCookie.java │ │ │ └── BaseHttp.java │ │ ├── queue/ │ │ │ ├── BaseQueue.java │ │ │ └── BaseQueueElement.java │ │ ├── sdm/ │ │ │ ├── BaseDao.java │ │ │ ├── BaseModel.java │ │ │ ├── BaseService.java │ │ │ ├── IBaseDao.java │ │ │ └── IBaseModel.java │ │ └── spring/ │ │ ├── AnnotationSessionFactoryBeanEx.java │ │ ├── DataSourceAdvice.java │ │ ├── DataSourceSwitcher.java │ │ ├── DynamicDataSource.java │ │ └── ServiceManager.java │ ├── connector/ │ │ ├── AuthConnector.java │ │ ├── IBaseConnector.java │ │ ├── ManagerConnector.java │ │ └── ServiceConnector.java │ ├── handler/ │ │ ├── BaseHandler.java │ │ ├── BaseHandlerChannel.java │ │ └── IBaseHandler.java │ ├── message/ │ │ ├── IBaseMessage.java │ │ ├── InMessage.java │ │ ├── MessageDecode.java │ │ ├── MessageEncode.java │ │ ├── OutMessage.java │ │ └── WebSocketEncode.java │ ├── model/ │ │ ├── BasePosition.java │ │ ├── action/ │ │ │ ├── ActionManager.java │ │ │ ├── BaseAction.java │ │ │ └── IBaseAction.java │ │ ├── area/ │ │ │ ├── AreaManager.java │ │ │ ├── BaseArea.java │ │ │ ├── BaseZone.java │ │ │ └── IBaseArea.java │ │ ├── entity/ │ │ │ ├── BaseEntity.java │ │ │ ├── BaseNpc.java │ │ │ ├── BasePlayer.java │ │ │ ├── BasePlayerFactory.java │ │ │ ├── IBaseCharacter.java │ │ │ ├── IBaseEntity.java │ │ │ └── IBasePlayerFactory.java │ │ └── map/ │ │ └── IBaseMap.java │ ├── rsync/ │ │ ├── BaseRsync.java │ │ ├── IBaseRsync.java │ │ └── RsyncManager.java │ └── session/ │ ├── BaseSecretFactory.java │ ├── IBaseSecretFactory.java │ └── SessionManager.java └── resources/ └── errorCode.properties ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ *.class # Package Files # *.jar *.war *.ear .svn /target *.svn-base .myeclipse/ .idea/ JgFramework.iml ================================================ FILE: LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright {yyyy} {name of copyright owner} Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: README.md ================================================ JgFramework =========== 基于Netty的强大的游戏服务器框架 特点 === ~~~ 1、使用netty作为底层,性能得到保障 2、支持socket和websocket2种连接模式,可以自由选择 3、简单实用的路由,方便handler开发 4、异步无锁的数据同步 5、spring+Hibernia的自动注入和事务管理 6、mysql数据库的读写分离以及对多数据库的读写支持 7、传输数据的多样化,可以自用实现接口来实现不同的传输数据类型,现在使用的是json 8、框架自带了认证服务和管理服务,有简单的管理命令,需要telnet连接到端口(默认38080) 9、方便的ip段限制功能 10、方便设置心跳检查 11、登录方和服务端之间的认证,可通过实际接口来完成,默认使用的rsa加密传输认证码 12、性能优良的排队系统 13、丰富的工具类:memcache、redis等 14、基本游戏模块的抽象 ~~~ 性能测试 ====== ##### *测试信息* ~~~ cpu : AMD A10 内存 : 8G 测试项目 : https://github.com/bupt1987/JgWeb 测试脚本 : src/test/java/client/TestWebSocket.java 测试方式 : 自压 ~~~ ##### *测试结果* ~~~ 在100个登录用户,每个用户在登录完成,再init操作之后,每个用户发送100000个请求, 得到每秒处理请求数在3.5W左右。 ~~~ 欢迎加入 ====== 如果对该系统有兴趣可以发邮件至 bupt1987@gmail.com 一起探讨,欢迎加入 例子 === 见:https://github.com/bupt1987/JgWeb ================================================ FILE: default_applicationContext.xml ================================================ org.hibernate.dialect.MySQLInnoDBDialect false none classpath*:com/zhaidaosi/game/server/sdm/model/*.class ================================================ FILE: default_jgframework.properties ================================================ #must input base.package.name=com.zhaidaosi.game.server #run mode : debug, product default : debug run.mode=debug #timezone time.zone=Asia/Shanghai #charset default : UTF-8 charset=UTF-8 #true or false default : true useSpring=true #memcache default : 127.0.0.1:11211,1 memcache.servers=127.0.0.1:11211,1 memcache.keyPrefix=jg- #manager default : 38080 manager.port=38080 #default : 127.0.0.1 manager.allowIps=127.0.0.1;10.10.2.1-10.10.2.254 #default : admin manager.user=admin #default : admin manager.password=admin #service #default : 127.0.0.1 service.ips=127.0.0.1 #default : 28080 service.port=28080 #syncPeriod need > 3 miao default : 60 service.syncPeriod=60 #default : 0 service.threadCount=0 #default : 60 service.heartbeatTime=60 #socket or websocket #default : websocket service.mode=websocket #max login user default : 0 service.maxLoginUser=0 #auth #default : 18080 auth.port=18080 #default : 0 auth.threadCount=0 auth.handler=auth. #des key #default : 1234567890!@#$qweasd des.key=1234567890!@#$qweasd #rsa keys rsa.publicKey=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCifAl6RlbG1PVOowZJ2niVlijq9FC19jEIaA2WVm+En64roRsTjlWpAKOfYBHIwEYWvI7rObyobTIPyOkBOCx5Sbopq2ME7FUQEwI2IeEBGHwnIBPzkhTEt9kMT88g8hZRBV6D/p6J8Z1u2WU0q88Xpd4o7VDxFRmGUTSePOGcjQIDAQAB rsa.privateKey=MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAKJ8CXpGVsbU9U6jBknaeJWWKOr0ULX2MQhoDZZWb4SfriuhGxOOVakAo59gEcjARha8jus5vKhtMg/I6QE4LHlJuimrYwTsVRATAjYh4QEYfCcgE/OSFMS32QxPzyDyFlEFXoP+nonxnW7ZZTSrzxel3ijtUPEVGYZRNJ484ZyNAgMBAAECgYA3SHCJE8mOmQJloP4Qvq5sZszBNCMJ5hvEunJ1Bi+nNhUybvwhaTon6DnDjhI+9XxjXABcdCaGP7DawgbVDWHDzjgQG0xQle2ryrZFa0thgQDYM4iraMgxMN/5kTXD9DlZcf871N0DeI8dTpxJhVMcM5d95sml6pJxxqwyzABiAQJBAO1rvTpHS6OgDVRpHV4HksyEcKETEayVknAIbTGP3VH3L4X50CpwOwPsvaHi5sENkSEA2JtKj0qF0CbP3sAdDcECQQCvMxhuq2V+dRyMkFLot3YZbMffr2dJi6o4XwxDtI/nhHzS5bQIzKX7L1m8ZJ0GR6CSjZ6X+LBRW6h3tLTsNdnNAkANsK+5o5DN/5WlL2Z9HIyvdFeWQiY7wGgwQ5wgRn5pkopP/Gave8c7Y7RPmGjb6u9aatUSp0r57hthkYzzoPlBAkBG6sfZBEfxCDamL0VgLeMAJ6hAQx/sBTzB1LeCMHSPonFkbNaTOUN2iZQpThDBmfzFVc38dg3o4NEwo1UYyDOBAkAsfnopb+Msp8pMBw7mcX/CeCXNIVpBNWSLtT0AssDf9ofaQ+bIsFIsy2GaPt/UuZmltXgTP5J3iWqFIKQDRstH ================================================ FILE: pom.xml ================================================ 4.0.0 JgFramework JgFramework 0.0.1-SNAPSHOT jar JgFramework http://maven.apache.org UTF-8 jboss-releases https://repository.jboss.org/nexus/content/repositories/releases/ org.apache.maven.plugins maven-compiler-plugin 2.3.2 1.7 1.7 io.netty netty-all compile com.alibaba fastjson compile org.jboss.marshalling jboss-marshalling compile true com.google.protobuf protobuf-java compile true javax.activation activation compile true org.apache.felix org.osgi.core compile true org.apache.felix org.osgi.compendium compile javax.servlet org.apache.felix org.osgi.foundation org.apache.felix true org.slf4j slf4j-api compile true commons-logging commons-logging compile true org.jboss.logging jboss-logging-spi compile true log4j log4j compile mail javax.mail jms javax.jms jmxtools com.sun.jdmk jmxri com.sun.jmx true org.hibernate hibernate-annotations org.hibernate hibernate-commons-annotations org.hibernate hibernate-entitymanager org.hibernate hibernate-validator javax.persistence persistence-api cglib cglib javassist javassist antlr antlr javax.transaction jta net.sf.ehcache ehcache dom4j dom4j c3p0 c3p0 jboss jboss-cache org.jboss.cache jbosscache-core opensymphony oscache proxool proxool swarmcache swarmcache commons-httpclient commons-httpclient org.springframework spring-core org.springframework spring-aop org.springframework spring-asm org.springframework spring-aspects org.springframework spring-beans org.springframework spring-context org.springframework spring-context-support org.springframework spring-expression org.springframework spring-instrument org.springframework spring-jdbc org.springframework spring-orm org.springframework spring-tx aopalliance aopalliance asm asm org.aspectj aspectjweaver cglib cglib-nodep commons-codec commons-codec commons-dbcp commons-dbcp commons-pool commons-pool com.jolbox bonecp-provider mysql mysql-connector-java commons-beanutils commons-beanutils commons-collections commons-collections com.whalin Memcached-Java-Client com.google.guava guava redis.clients jedis jar compile io.netty netty-all 4.0.33.Final org.jboss.marshalling jboss-marshalling 1.4.0.Final com.google.protobuf protobuf-java 2.5.0 javax.activation activation 1.1.1 org.apache.felix org.osgi.core 1.4.0 org.apache.felix org.osgi.compendium 1.4.0 org.slf4j slf4j-api 1.6.4 commons-logging commons-logging 1.1.1 org.jboss.logging jboss-logging-spi 2.1.2.GA log4j log4j 1.2.16 org.hibernate hibernate-annotations 3.4.0.GA org.hibernate hibernate-commons-annotations 3.1.0.GA org.hibernate hibernate-entitymanager 3.4.0.GA org.hibernate hibernate-validator 3.1.0.GA javax.persistence persistence-api 1.0 cglib cglib 2.2 javassist javassist 3.9.0.GA antlr antlr 2.7.6 javax.transaction jta 1.1 net.sf.ehcache ehcache 1.2.3 org.slf4j slf4j-log4j12 1.6.4 dom4j dom4j 1.6.1 c3p0 c3p0 0.9.1 jboss jboss-cache 1.4.1.GA org.jboss.cache jbosscache-core 3.1.0.GA opensymphony oscache 2.1 proxool proxool 0.8.3 swarmcache swarmcache 1.0RC2 commons-httpclient commons-httpclient 3.1 org.springframework spring-core 3.1.1.RELEASE org.springframework spring-aop 3.1.1.RELEASE org.springframework spring-asm 3.1.1.RELEASE org.springframework spring-aspects 3.1.1.RELEASE org.springframework spring-beans 3.1.1.RELEASE org.springframework spring-context 3.1.1.RELEASE org.springframework spring-context-support 3.1.1.RELEASE org.springframework spring-expression 3.1.1.RELEASE org.springframework spring-instrument 3.1.1.RELEASE org.springframework spring-jdbc 3.1.1.RELEASE org.springframework spring-orm 3.1.1.RELEASE org.springframework spring-tx 3.1.1.RELEASE aopalliance aopalliance 1.0 asm asm 3.1 org.aspectj aspectjweaver 1.6.9 cglib cglib-nodep 2.2 commons-codec commons-codec 1.8 commons-dbcp commons-dbcp 1.4 commons-pool commons-pool 1.5.3 com.jolbox bonecp-provider 0.7.1.RELEASE mysql mysql-connector-java 5.1.26 commons-beanutils commons-beanutils 1.7.0 commons-collections commons-collections 3.1 com.whalin Memcached-Java-Client 3.0.2 com.google.guava guava r09 com.alibaba fastjson 1.2.12 redis.clients jedis 2.0.0 ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/Boot.java ================================================ package com.zhaidaosi.game.jgframework; import com.zhaidaosi.game.jgframework.common.BaseIp; import com.zhaidaosi.game.jgframework.common.BaseRunTimer; import com.zhaidaosi.game.jgframework.common.BaseString; import com.zhaidaosi.game.jgframework.common.cache.BaseLocalCached; import com.zhaidaosi.game.jgframework.common.encrpt.BaseDes; import com.zhaidaosi.game.jgframework.common.encrpt.BaseRsa; import com.zhaidaosi.game.jgframework.common.spring.ServiceManager; import com.zhaidaosi.game.jgframework.connector.AuthConnector; import com.zhaidaosi.game.jgframework.connector.ManagerConnector; import com.zhaidaosi.game.jgframework.connector.ServiceConnector; import com.zhaidaosi.game.jgframework.model.action.ActionManager; import com.zhaidaosi.game.jgframework.model.area.AreaManager; import com.zhaidaosi.game.jgframework.model.entity.BasePlayerFactory; import com.zhaidaosi.game.jgframework.model.entity.IBasePlayerFactory; import com.zhaidaosi.game.jgframework.session.SessionManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Collections; import java.util.Properties; import java.util.TimeZone; public class Boot { public static String BASE_PACKAGE_NAME; public static String SDM_BASE_PACKAGE_NAME; public static String SERVER_RSYNC_PACKAGE_PATH; public static String SERVER_HANDLER_PACKAGE_PATH; private static final Logger log = LoggerFactory.getLogger(Boot.class); private final static String SERVER_PROPERTIES = "jgframework.properties"; private final static String ALL_STRING = "all"; private final static String SERVICE_STRING = "service"; private final static String AUTH_STRING = "auth"; private static String actionPackage; private static String areaPackage; private static int servicePort = 28080; private static String serviceMode = ServiceConnector.MODE_WEB_SOCKET; private static long serviceSyncPeriod = 60000; private static int serviceThreadCount = 0; private static int serviceHeartbeatTime = 60; private static int serviceMaxLoginUser = 0; private static ArrayList serviceIps = new ArrayList<>(); private static int authPort = 18080; private static int authThreadCount = 0; private static String authHandler; private static boolean debug = true; private static ArrayList memcacheServers = new ArrayList<>(); private static String memcacheKeyPrefix = "jg-"; private static Charset charset = Charset.forName("UTF-8"); private static int managerPort = 38080; private static ArrayList managerAllowIps = new ArrayList<>(); private static String managerUser = "admin"; private static String managerPassword = "admin"; private static ServiceConnector serviceConnector = null; private static ManagerConnector managerConnector = null; private static AuthConnector authConnector = null; private static String args = null; private static IBasePlayerFactory playerFactory = new BasePlayerFactory(); private static boolean useSpring = true; private static boolean init = false; /** * 初始化参数 * @return */ private static boolean init() { if (init) { return true; } boolean error = false; try { Properties pps = new Properties(); pps.load(Boot.class.getClassLoader().getResourceAsStream(SERVER_PROPERTIES)); BASE_PACKAGE_NAME = pps.getProperty("base.package.name"); if (BaseString.isEmpty(BASE_PACKAGE_NAME)) { error = true; log.error("base.package.name 必须填写"); } SDM_BASE_PACKAGE_NAME = BASE_PACKAGE_NAME + ".sdm"; SERVER_RSYNC_PACKAGE_PATH = BASE_PACKAGE_NAME + ".rsync"; SERVER_HANDLER_PACKAGE_PATH = BASE_PACKAGE_NAME + ".handler"; //设置默认时间 if (!BaseString.isEmpty(pps.getProperty("time.zone"))) { TimeZone.setDefault(TimeZone.getTimeZone(pps.getProperty("time.zone"))); } //是否使用spring if (!BaseString.isEmpty(pps.getProperty("useSpring"))) { useSpring = pps.getProperty("useSpring").equals("true"); } //设置运行模式 debug = "debug".equals(pps.getProperty("run.mode")); if (debug) { BaseRunTimer.toActive(); } if (ALL_STRING.equals(args) || SERVICE_STRING.equals(args)) { //service端 if (!BaseString.isEmpty(pps.getProperty("service.port"))) { servicePort = Integer.valueOf(pps.getProperty("service.port")); } if (!BaseString.isEmpty(pps.getProperty("service.mode"))) { serviceMode = pps.getProperty("service.mode"); } if (!BaseString.isEmpty(pps.getProperty("service.threadCount"))) { serviceThreadCount = Integer.valueOf(pps.getProperty("service.threadCount")); } if (!BaseString.isEmpty(pps.getProperty("service.syncPeriod"))) { serviceSyncPeriod = Integer.valueOf(pps.getProperty("service.syncPeriod")); if (serviceSyncPeriod < 3) { error = true; log.error("service.syncPeriod 必须大于3秒"); } serviceSyncPeriod = serviceSyncPeriod * 1000; } if (!BaseString.isEmpty(pps.getProperty("service.heartbeatTime"))) { serviceHeartbeatTime = Integer.valueOf(pps.getProperty("service.heartbeatTime")); } if (!BaseString.isEmpty(pps.getProperty("service.maxLoginUser"))) { serviceMaxLoginUser = Integer.valueOf(pps.getProperty("service.maxLoginUser")); } } if (ALL_STRING.equals(args) || AUTH_STRING.equals(args)) { //auth端 if (!BaseString.isEmpty(pps.getProperty("service.ips"))) { Collections.addAll(serviceIps, pps.getProperty("service.ips").split(";")); } else { error = true; log.error("service.ips 必须填写"); } if (!BaseString.isEmpty(pps.getProperty("auth.port"))) { authPort = Integer.valueOf(pps.getProperty("auth.port")); } if (!BaseString.isEmpty(pps.getProperty("auth.threadCount"))) { authThreadCount = Integer.valueOf(pps.getProperty("auth.threadCount")); } if (!BaseString.isEmpty(pps.getProperty("auth.handler"))) { authHandler = pps.getProperty("auth.handler"); } else { error = true; log.error("auth.handler 必须填写"); } } //manager端 if (!BaseString.isEmpty(pps.getProperty("manager.port"))) { managerPort = Integer.valueOf(pps.getProperty("manager.port")); } if (!BaseString.isEmpty(pps.getProperty("manager.user"))) { managerUser = pps.getProperty("manager.user"); } if (!BaseString.isEmpty(pps.getProperty("manager.password"))) { managerPassword = pps.getProperty("manager.password"); } String[] ips; if (!BaseString.isEmpty(pps.getProperty("manager.allowIps"))) { ips = pps.getProperty("manager.allowIps").split(";"); } else { ips = new String[]{"127.0.0.1"}; } setManagerAllowIps(ips); //memcache if (!BaseString.isEmpty(pps.getProperty("memcache.servers"))) { Collections.addAll(memcacheServers, pps.getProperty("memcache.servers").split(";")); } else { memcacheServers.add("127.0.0.1:11211,1"); } if (!BaseString.isEmpty(pps.getProperty("memcache.keyPrefix"))) { memcacheKeyPrefix = pps.getProperty("memcache.keyPrefix"); } //des密钥 if (!BaseString.isEmpty(pps.getProperty("des.key"))) { BaseDes.setDesKey(pps.getProperty("des.key")); } //rsa密钥 if (!BaseString.isEmpty(pps.getProperty("rsa.publicKey")) && !BaseString.isEmpty(pps.getProperty("rsa.privateKey"))) { BaseRsa.init(pps.getProperty("rsa.publicKey"), pps.getProperty("rsa.privateKey")); } //系统字符集 if (!BaseString.isEmpty(pps.getProperty("charset"))) { charset = Charset.forName(pps.getProperty("charset")); } } catch (Exception e) { error = true; log.error("系统启动失败", e); } if (!error) { init = true; } return init; } /** * 设置允许ip段 * @param ips */ private static void setManagerAllowIps(String[] ips) { for (String ip : ips) { managerAllowIps.add(BaseIp.stringToIp(ip)); } } /** * 设置扫描action的包路径,例如:com.zhaidaosi.game.server.model.action * @param actionPackage */ public static void setActionPackage(String actionPackage) { Boot.actionPackage = actionPackage; } /** * 设置扫描area的包路径,例如:com.zhaidaosi.game.server.model.area * @param areaPackage */ public static void setAreaPackage(String areaPackage) { Boot.areaPackage = areaPackage; } /** * 获取player的工厂,默认是BasePlayerFactory * @return */ public static IBasePlayerFactory getPlayerFactory() { return playerFactory; } /** * 设置player的工厂,默认是BasePlayerFactory * @param playerFactory */ public static void setPlayerFactory(IBasePlayerFactory playerFactory) { Boot.playerFactory = playerFactory; } /** * 设置mc的前缀 * @return */ public static String getMemcacheKeyPrefix() { return memcacheKeyPrefix; } /** * 获取service的连接对象 * @return */ public static ServiceConnector getServiceConnector() { return serviceConnector; } /** * 获取auth的连接对象 * @return */ public static AuthConnector getAuthConnector() { return authConnector; } /** * 获取manager服务端口 * @return */ public static int getManagerPort() { return managerPort; } /** * 获取manager允许访问的ip段 * @return */ public static ArrayList getManagerAllowIps() { return managerAllowIps; } /** * 获取manager的登录用户 * @return */ public static String getManagerUser() { return managerUser; } /** * 获取manager的用户密码 * @return */ public static String getManagerPassword() { return managerPassword; } /** * 获取默认字符集 * @return */ public static Charset getCharset() { return charset; } /** * service服务器工作线程数 * @return */ public static int getServiceThreadCount() { return serviceThreadCount; } /** * 认证服务器工作线程数 * @return */ public static int getAuthThreadCount() { return authThreadCount; } /** * 返回所有的memcache配置 * @return */ public static ArrayList getMemcacheServers() { return memcacheServers; } /** * 返回所有service服务器ip * @return */ public static ArrayList getServiceIps() { return serviceIps; } /** * 返回认证服务的所有handler * @return */ public static String getAuthHandler() { return authHandler; } /** * 返回服务器端口 * @return */ public static int getServicePort() { return servicePort; } /** * 返回service服务器个数 * @return */ public static int getServiceCount() { return serviceIps.size(); } /** * 返回service的同步间隔 * @return */ public static long getServiceSyncPeriod() { return serviceSyncPeriod; } /** * 获取心跳检查时间 * @return */ public static int getServiceHeartbeatTime() { return serviceHeartbeatTime; } /** * 通过ip返回service的连接地址 * @param ip * @return */ public static String getServiceAddress(String ip) { if (serviceMode.equals(ServiceConnector.MODE_SOCKET)) { return ip + ":" + servicePort; } else { return "ws://" + ip + ":" + servicePort + ServiceConnector.WEB_SOCKET_PATH; } } /** * 是否开启debug模式 * @return */ public static boolean getDebug() { return debug; } /** * 重启服务 */ public static void restart() { stop(); start(); } /** * 停止服务 */ public static void stop() { BaseLocalCached.cancelTimer(); if (authConnector != null) { authConnector.stop(); } if (serviceConnector != null) { serviceConnector.stop(); } if (managerConnector != null) { managerConnector.stop(); } } /** * 启动服务 */ public static void start() { start(Boot.args); } /** * 启动服务 * @param args ALL_STRING,SERVICE_STRING,AUTH_STRING */ public static void start(String args) { if (Boot.args == null) { Boot.args = args == null ? ALL_STRING : args; } if (!Boot.ALL_STRING.equals(Boot.args) && !Boot.SERVICE_STRING.equals(Boot.args) & !Boot.AUTH_STRING.equals(Boot.args)) { Boot.args = args = ALL_STRING; } //初始化参数 if (init()) { //加载spring if (useSpring) { ServiceManager.init(); } //开启本地缓存清理任务 BaseLocalCached.startTimer(); //加载路由 Router.init(); if (args == null || args.equals(ALL_STRING) || args.equals(SERVICE_STRING)) { //加载动作 ActionManager.initAction(actionPackage); //加载区域 AreaManager.initArea(areaPackage); if (serviceMaxLoginUser > 0) { SessionManager.setMaxUser(serviceMaxLoginUser); } else { serviceMaxLoginUser = 0; } if (serviceConnector == null) { serviceConnector = new ServiceConnector(servicePort, serviceSyncPeriod, serviceMode); } serviceConnector.start(); if (managerConnector == null) { managerConnector = new ManagerConnector(managerPort); } managerConnector.start(); } if (args == null || args.equals(ALL_STRING) || args.equals(AUTH_STRING)) { if (authConnector == null) { authConnector = new AuthConnector(authPort); } authConnector.start(); } } } } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/Router.java ================================================ package com.zhaidaosi.game.jgframework; import com.zhaidaosi.game.jgframework.common.BaseFile; import com.zhaidaosi.game.jgframework.common.BaseRunTimer; import com.zhaidaosi.game.jgframework.common.BaseString; import com.zhaidaosi.game.jgframework.handler.BaseHandler; import com.zhaidaosi.game.jgframework.handler.IBaseHandler; import com.zhaidaosi.game.jgframework.message.IBaseMessage; import com.zhaidaosi.game.jgframework.message.InMessage; import com.zhaidaosi.game.jgframework.message.OutMessage; import io.netty.channel.Channel; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.HashMap; import java.util.Set; public class Router { private static final Logger log = LoggerFactory.getLogger(Router.class); private static HashMap handlers = new HashMap<>(); private static final String classSuffix = "Handler"; public static final String ERROR_HANDLERNAME = "_error_"; public static final String HEART_HANDLERNAME = "_heart_"; public static final String WAIT_HANDLERNAME = "_wait_"; /** * 初始化handler */ public static void init() { Set> classes = BaseFile.getClasses(Boot.SERVER_HANDLER_PACKAGE_PATH, classSuffix, true); for (Class c : classes) { String className = c.getName(); IBaseHandler handler; try { handler = (IBaseHandler) c.newInstance(); // 只取Handler前面部分 String handlerName = className.replace(Boot.SERVER_HANDLER_PACKAGE_PATH + ".", "").replace(classSuffix, "").toLowerCase(); handler.setHandlerName(handlerName); handlers.put(handlerName, handler); log.info("handler类 : " + className + " 加载完成"); } catch (InstantiationException | IllegalAccessException e) { log.error("handler类 : " + className + " 加载失败", e); } } } /** * 运行handler * @param im * @param ch * @return * @throws Exception */ public static IBaseMessage run(InMessage im, Channel ch) throws Exception { long startTime = 0; if (BaseRunTimer.isActive()) { startTime = System.currentTimeMillis(); } IBaseMessage rs = null; String handlerName = im.getH(); if (!BaseString.isEmpty(handlerName)) { try { if (handlerName.equals(HEART_HANDLERNAME)) { rs = BaseHandler.doHeart(); rs.setH(HEART_HANDLERNAME); } else { IBaseHandler handler = handlers.get(handlerName); if (handler == null) { rs = OutMessage.showError("handler不存在", 21000); } else { rs = handler.run(im, ch); } if (rs != null) { rs.setH(handlerName); } } } finally { if (BaseRunTimer.isActive()) { long runningTime = System.currentTimeMillis() - startTime; BaseRunTimer.addTimer("Handler : " + handlerName + " run " + runningTime + " ms"); } } } else { rs = OutMessage.showError("handler不能为空", 20000); rs.setH(ERROR_HANDLERNAME); } return rs; } } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/common/BaseAvlTree.java ================================================ package com.zhaidaosi.game.jgframework.common; import java.util.AbstractSet; import java.util.Iterator; import java.util.Random; /** * 平衡二叉搜索(排序)树 */ public class BaseAvlTree> extends AbstractSet { private Entry root;//根节点 private int size;//树节点个数 private static class Entry { E elem;//数据域 Entry parent;//父节点 Entry left;//左节点 Entry right;//右节点 /* * 树的平衡因子,等号表示左子树和右子树有同样的高度。如果L,左子树比右子树高1。如果为R,则意味着右 * 子树比左高1。刚创建时是平衡的,所以为= * 50 * /R\ * 20 80 * /L /R\ * 10 70 100 * = = /=\ * 92 103 * = = */ char balanceFactor = '='; //构造函数只有两个参数,左右节点是调用add方法时设置 public Entry(E elem, Entry parent) { this.elem = elem; this.parent = parent; } } private class TreeIterator implements Iterator { private Entry lastReturned = null; private Entry next; TreeIterator() { next = root; if (next != null) while (next.left != null) next = next.left; } public boolean hasNext() { return next != null; } public E next() { lastReturned = next; next = successor(next); return lastReturned.elem; } public void remove() { if (lastReturned != null && lastReturned.left != null) next = lastReturned; deleteEntry(lastReturned); lastReturned = null; } } /** * 左旋转:结果就是将p移到它的左子节点的位置,而p的右子节点被移到该元素原来位置 * @param p 旋转元素 */ private void rotateLeft(Entry p) { /* * 围绕50左旋转: *p → 50 90 * \ /\ * r → 90 → 50 100 * \ * 100 * * 围绕80左旋转:r的左子树变成p的右子树。因为位于r的左子树上的任意一个元素值大于p且小于r,所以r的左子 * 树可以成为p的右子树这是没有问题的。其实上面也发生了同样的现象,只是r的左子树为空罢了 * p → 80 90 * /\ /\ * 60 90 ← r → 80 120 * /\ /\ / * 85 120 60 85 100 * / * 100 * * 围绕80在更大范围内旋转:元素不是围绕树的根旋转。旋转前后的树都是二叉搜索树。且被旋转元素80上的所 * 有元素在旋转中不移动(50、30、20、40这四个元素还是原来位置) * 50 50 * / \ / \ * 30 80 ← p 30 90 * /\ /\ /\ / \ * 20 40 60 90 ← r → 20 40 80 120 * /\ /\ / * 85 120 60 85 100 * / * 100 * * 节点数据结构: * +------------------+ * | elem | p | l | r | * +------------------+ * * +------------------+ * | 50 |NULL|NULL| r | * +------------------+ * ↖⑥ ↘④ * +---------------+ * |80| p | l | r | ← p * +---------------+ * ↗ ↙ ↖③ ↘① * +----------------+ +---------------+ * |60| p |NULL|NULL| |90| p | l | r | ← r * +----------------+ +---------------+ * ↗② ↙⑤ ↖↘ * +----------------+ +---------------+ * |85| p |NULL|NULL| |90| p | l |NULL| * +----------------+ +---------------+ * ↗ ↙ * +-----------------+ * |100| p |NULL|NULL| * +-----------------+ */ Entry r = p.right;//旋转元素的右子节点 //把旋转元素的右子节点的左子节点接到旋转元素的右子树 p.right = r.left;//① //如果旋转元素的右子节点存在左子节点的话,同时修改该节点的父节指针指向 if (r.left != null) { //把旋转元素的右子节点的左子节点的父设置成旋转元素 r.left.parent = p;//② } //将旋转元素的右子节点的父设置成旋转元素的父,这里有可以p为根节点,那么旋转后p就成根节点 r.parent = p.parent;//③ //如果旋转元素为根元素,则旋转后,旋转元素的右子节点r将成为根节点 if (p.parent == null) { root = r; }//否则p不是根节点,如果p是他父节点的左节点时 else if (p.parent.left == p) { //让p的父节点的左指针指向r p.parent.left = r; }//否则如果p是他父节点的右节点时 else { //让p的父节点的右指针指向r p.parent.right = r;//④ } //让旋转元素的左节点指向旋转元素p r.left = p;//⑤ //让旋转元素的父节点指向旋转元素右节点r p.parent = r;//⑥ } /** * 右旋转:结果就是将p移到它的右子节点的位置,而p的左子节点被移到该元素原来位置 * 与左旋转是完全对称的,将左旋转中的lef与rigth互换即可得到,这里就不详细解释了 * @param p 旋转元素 */ private void rotateRight(Entry p) { /* * 围绕100右旋转: * p → 100 90 * / /\ * l → 90 → 50 100 * / * 50 * * 围绕80右旋转:l的右子树变成p的左子树。因为位于l的右子树上的任意一个元素值小于p且小于l,所以l的右 * 子树可以成为p的左子树这是没有问题的。其实上面也发生了同样的现象,只是l的右子树为空罢了 * * p → 80 60 * /\ /\ * l → 60 90 → 50 80 * /\ \ /\ * 50 70 55 70 90 * \ * 55 */ Entry l = p.left; p.left = l.right; if (l.right != null) { l.right.parent = p; } l.parent = p.parent; if (p.parent == null) { root = l; } else if (p.parent.right == p) { p.parent.right = l; } else { p.parent.left = l; } l.right = p; p.parent = l; } /** * BaseAVLTree类的add方法类似于BinSerrchTree类的add方法,但是沿着根向下前进到插入点时,需记录这样一个被插 * 入Entry对象最近的祖先:该祖先的平衡因子balanceFactor值是L或R(即不歼),且让ancestor指向这个祖先节 * 点,该祖先节有什么用呢,从ancestor的子开始到新增节点路径上的所有祖先节点都是平衡,这些祖先节点会因为 * 新增节点而变得不平衡了,需要重新调整平衡因子,这个分界点在调整平衡因子时非常有用 * * @param elem 要新增元素的数据域 * @return boolean */ public boolean add(E elem) { //如果树为空,则直接插入 if (root == null) { root = new Entry(elem, null); size++; return true; } else { Entry tmp = root;//新增节点的父节点,从根节点下面开始找插入点 Entry ancestor = null;//平衡因子不为 = 的最近祖先节点 int comp; //比较结果 while (true) {//死循环,直接找到插入点退出循环 comp = elem.compareTo(tmp.elem); //如果已存在该元素,则直接返回失败 if (comp == 0) { return false; } //记录不平衡的祖先节点 if (tmp.balanceFactor != '=') { //如果哪个祖先节点不平衡,则记录,当循环完后,ancestor指向的就是最近一个 //不平衡的祖先节点 ancestor = tmp; } //如果小于当前比较节点,则在其左边插入 if (comp < 0) { //如果左子树不为空,继续循环在左边找插入点 if (tmp.left != null) { tmp = tmp.left; } else {//否则插入 tmp.left = new Entry(elem, tmp); //插入后要进行平衡调整 fixAfterInsertion(ancestor, tmp.left); size++; return true; } } else {//在右边插入 //如果右子树不为空,继续循环在右边找插入点 if (tmp.right != null) { tmp = tmp.right; } else {//否则插入 tmp.right = new Entry(elem, tmp); //插入后要进行平衡调整 fixAfterInsertion(ancestor, tmp.right); size++; return true; } } } } } /** * 当新增节点后,会改变某些节点的平衡因子,所以添加节点后需重新调整平衡因子 * * 根据前人们的分析与研究,可分为6种情况 * * @param ancestor 新增元素的最近一个不平衡的祖先节点 * @param inserted 新增元素 */ protected void fixAfterInsertion(Entry ancestor, Entry inserted) { E elem = inserted.elem; if (ancestor == null) { /* * 情况1:ancestor的值为null,即被插入Entry对象的每个祖先的平衡因子都是 =,此时新增节点后 * ,树的高度不会发生变化,所以不需要旋转,我们要作的就是调整从根节点到插入节点的路径上的所有 * 节点的平衡因子罢了 * * 新增55后调整 * 50 → 50 * /=\ /R\ * 25 70 25 70 * /=\ /=\ /=\ /L\ * 15 30 60 90 15 30 60 90 * = = = = = = /L = * 55 * = */ //根节点的平衡因子我们单独拿出来调整,因为adjustPath的参数好比是一个开区间,它不包括两头参数 //本身,而是从nserted.paraent开始到to的子节点为止,所以需单独调整,其他分支也一样 if (elem.compareTo(root.elem) < 0) { root.balanceFactor = 'L'; } else { root.balanceFactor = 'R'; } //再调用adjustPath方法调整新增节点的父节点到root的某子节点路径上的所有祖先节点的 //平衡因子 adjustPath(root, inserted); } else if ((ancestor.balanceFactor == 'L' && elem.compareTo(ancestor.elem) > 0) || (ancestor.balanceFactor == 'R' && elem.compareTo(ancestor.elem) < 0)) { /* * 情况2: * ancestor.balanceFactor的值为 L,且在ancestor对象的右子树插入,或ancestor.balanceFac * tor的值为 R,且在ancestor对象的左子树插入,这两插入方式都不会引起树的高度发生变化,所以我们 * 也不需要旋转,直接调整平衡因子即可 * 新增55后调整 * ancestor → 50 → 50 * /L\ /=\ * 25 70 25 70 * /R\ /=\ /R\ /L\ * 15 30 60 90 15 30 60 90 * /L /L /L * 28 28 55 * 新增28后调整 * ancestor → 50 → 50 * /R\ /=\ * 25 70 25 70 * /=\ /L\ /R\ /L\ * 15 30 60 90 15 30 60 90 * /L /L /L * 55 28 55 */ //先设置ancestor的平衡因子为 平衡 ancestor.balanceFactor = '='; //然后按照一般策略对inserted与ancestor间的元素进行调整 adjustPath(ancestor, inserted); } else if (ancestor.balanceFactor == 'R' && elem.compareTo(ancestor.right.elem) > 0) { /* * 情况3: * ancestor.balanceFactor的值为 R,并且被插入的Entry位于ancestor的右子树的右子树上, 此 * 种情况下会引起树的不平衡,所以先需绕ancestor进行旋转,再进行平衡因子的调整 * * 新增93 先调整因子再绕70左旋 * → 50 → 50 * /R\ /R\ * 25 70 ← ancestor 25 90 * /L /R\ /L /=\ * 15 60 90 15 70 98 * = = /=\ = /=\ /L * 80 98 60 80 93 * = /= = = = * 93 * = */ ancestor.balanceFactor = '='; //围绕ancestor执行一次左旋 rotateLeft(ancestor); //再调整ancestor.paraent(90)到新增节点路径上祖先节点平衡 adjustPath(ancestor.parent, inserted); } else if (ancestor.balanceFactor == 'L' && elem.compareTo(ancestor.left.elem) < 0) { /* * 情况4: * ancestor.balanceFactor的值为 L,并且被插入的Entry位于ancestor的左子树的左子树上, * 此种情况下会引起树的不平衡,所以先需绕ancestor进行旋转,再进行平衡因子的调整 * * 新增13 先调整因子再绕50右旋 * → 50 ← ancestor → 20 * /L\ /=\ * 20 70 10 50 * /=\ /=\ /R\ /=\ * 10 30 60 90 5 15 30 70 * /=\ /=\= = = /L /=\ /=\ * 5 15 25 35 13 25 35 60 90 * = /= = = = = = = = * 13 * = */ ancestor.balanceFactor = '='; //围绕ancestor执行一次右旋 rotateRight(ancestor); //再调整ancestor.paraent(20)到新增节点路径上祖先节点平衡 adjustPath(ancestor.parent, inserted); } else if (ancestor.balanceFactor == 'L' && elem.compareTo(ancestor.left.elem) > 0) { /* * 情况5: * ancestor.balanceFactor的值为 L,并且被插入的Entry位于ancestor的左子树的右子树上。此 * 种情况也会导致树不平衡,此种与第6种一样都需要执行两次旋转(执行一次绕ancestor的左子节点左 * 旋,接着执行一次绕ancestor执行一次右旋)后,树才平衡,最后还需调用 左-右旋 专有方法进行平衡 * 因子的调整 */ rotateLeft(ancestor.left); rotateRight(ancestor); //旋转后调用 左-右旋 专有方法进行平衡因子的调整 adjustLeftRigth(ancestor, inserted); } else if (ancestor.balanceFactor == 'R' && elem.compareTo(ancestor.right.elem) < 0) { /* * 情况6: * ancestor.balanceFactor的值为 R,并且被插入的Entry位于ancestor的右子树的 左子树上,此 * 种情况也会导致树不平衡,此种与第5种一样都需要执行两次旋转(执行一次绕ancestor的右子节点右旋 * ,接着执行一次绕ancestor执行一次左旋)后,树才平衡,最后还需调用 右-左旋 专有方法进行平衡因 * 子的调整 */ rotateRight(ancestor.right); rotateLeft(ancestor); //旋转后调用 右-左旋 专有方法进行平衡因子的调整 adjustRigthLeft(ancestor, inserted); } } /** * 调整指定路径上的节点的平衡因子 * * 注,指定的路径上的所有节点一定是平衡的,因此如果被插入元素小于某个祖先节点, * 则这个祖先节点新的平衡因子是 L,反之为 R。 * * @param inserted 从哪里元素开始向上调整,但不包括该,即从父开始) * @param to 直到哪个元素结束,但不包括该元素,一般传进来的为ancestor */ protected void adjustPath(Entry to, Entry inserted) { E elem = inserted.elem; Entry tmp = inserted.parent; //从新增节点的父节点开始向上回溯调整,直到结尾节点to止 while (tmp != to) { /* * 插入30,则在25右边插入,这样父节点平衡会被打破,右子树就会比左子树高1,所以平衡因子为R;祖 * 先节点50的平衡因子也被打破,因为在50的左子树上插入的,所以对50来说,左子树会比右子树高1,所 * 以其平衡因子为L * 50 50 * /=\ 插入30 /L\ * 25 70 → 25 70 * = = R\ = * 30 * = */ //如果新增元素比祖先节点小,则是在祖先节点的左边插入,则自然该祖先的左比右子树会高1 if (elem.compareTo(tmp.elem) < 0) { tmp.balanceFactor = 'L'; } else { //否则会插到右边,那么祖先节点的右就会比左子树高1 tmp.balanceFactor = 'R'; } tmp = tmp.parent;//再调整祖先的祖先 } } /** * 进行 左-右旋转 后平衡因子调整 * 分三种情况 * @param ancestor * @param inserted */ protected void adjustLeftRigth(Entry ancestor, Entry inserted) { E elem = inserted.elem; if (ancestor.parent == inserted) { /* * 第1种,新增的节点在旋转完成后为ancestor父节点情况: * * 新增40 绕30左旋 绕50右旋 * → 50 ← ancestor → 50 → * /L /L * 30 40 * =\ /= * 40 30 * = = * * 调整平衡因子 * 40 → 40 * /=\ /=\ * 30 50 30 50 * = L = = * * 注,这里的 左-右旋 是在fixAfterInsertion方法中的第5种情况中完成的,在这里只是平衡因子的 * 调整,图是为了好说明问题而放在这个方法中的,下面的两个分支也是一样 */ ancestor.balanceFactor = '='; } else if (elem.compareTo(ancestor.parent.elem) < 0) { /* * 第2种,新增的节点在旋转完成后为不为ancestor父节点,且新增节点比旋转后ancestor的父节点要小 * 的情况 * * 由于插入元素(35)比旋转后ancestor(50)的父节点(40)要小, 所以新增节点会在其左子树中 * * 新增35 绕20左旋 * → 50 ← ancestor → 50 * /L\ /L\ * 20 90 40 90 * /=\ /=\ /=\ /=\ * 10 40 70 100 20 45 70 100 * /=\ /=\= = /=\ * 5 15 30 45 10 30 * = = =\ = /=\ =\ * 35 5 15 35 * = = = = * * 绕50右旋 调整平衡因子 * → 40 → 40 * /=\ /=\ * 20 50 20 50 * /=\ /L\ /=\ /R\ * 10 30 45 90 10 30 45 90 * /=\ =\ /=\ /=\ R\ /=\ * 5 15 35 70 100 5 15 35 70 100 * = = = = = = = = = = * */ ancestor.balanceFactor = 'R'; //调整ancestor兄弟节点到插入点路径上节点平衡因子 adjustPath(ancestor.parent.left, inserted); } else { /* * 第2种,新增的节点在旋转完成后为不为ancestor父节点,且新增节点比旋转后ancestor的父节点要大的 * 情况 * * 由于插入元素(42)比旋转后ancestor(50)的父节点(40)要大,所以新增节点会在其右子树中 * * 新增42 绕20左旋 * → 50 ← ancestor → 50 * /L\ /L\ * 20 90 40 90 * /=\ /=\ /=\ /=\ * 10 40 70 100 20 45 70 100 * /=\ /=\= = /=\ /= * 5 15 30 45 10 30 42 * = = = /= /=\= = * 42 5 15 * = = = * * 绕50右旋 调整平衡因子 * → 40 → 40 * /=\ /=\ * 20 50 20 50 * /=\ /L\ /L\ /=\ * 10 30 45 90 10 30 45 90 * /=\ /= /=\ /=\ /L /=\ * 5 15 42 70 100 5 15 42 70 100 * = = = = = = = = = = * */ ancestor.parent.left.balanceFactor = 'L'; ancestor.balanceFactor = '='; //调整ancestor节点到插入点路径上节点平衡因子 adjustPath(ancestor, inserted); } } /** * 进行 右-左旋转 后平衡因子调整 * * 与adjustLeftRigth方法一样,也有三种情况,这两个方法是对称的 * @param ancestor * @param inserted */ protected void adjustRigthLeft(Entry ancestor, Entry inserted) { E elem = inserted.elem; if (ancestor.parent == inserted) { /* * 第1种,新增的节点在旋转完成后为ancestor父节点情况: * * 新增40 绕50右旋 绕30左旋 * → 30 ← ancestor → 30 → * R\ R\ * 50 40 * /= =\ * 40 50 * = = * * 40 调整平衡因子 40 * /=\ → /=\ * 30 50 30 50 * R = = = * * 注,这里的 右-左旋 是在fixAfterInsertion方法中的第6种情况中完成的,这里只是 平衡因子的调 * 整,图是为了好说明问题而放在这个方法中的,下面的两个分支也是一样 */ ancestor.balanceFactor = '='; } else if (elem.compareTo(ancestor.parent.elem) > 0) { /* * 第2种,新增的节点在旋转完成后为不为ancestor父节点,且新增节点比旋转后 * ancestor的父节点要大的情况 * * 由于插入元素(73)比旋转后ancestor(50)的父节点(70)要大, 所以新增节点会 * 在其右子树中 * * 新增73 绕90右旋 * → 50 ← ancestor → 50 * /R\ /R\ * 20 90 20 70 * /=\ /=\ /=\ /=\ * 10 40 70 95 10 40 65 90 * = = /=\ /=\ = = = /=\ * 65 75 93 97 75 95 * = /= = = /= /=\ * 73 73 93 97 * = * * 绕50左旋 调整平衡因子 * → 70 → 70 * /=\ /=\ * 50 90 50 90 * /R\ /=\ /L\ /=\ * 20 65 75 95 20 65 75 95 * /=\ = /= /=\ /=\ = /L /=\ * 10 40 73 93 97 10 40 73 93 97 * = = = = = = = = = = * */ ancestor.balanceFactor = 'L'; adjustPath(ancestor.parent.right, inserted); } else { /* * 第2种,新增的节点在旋转完成后为不为ancestor父节点,且新增节点比旋转后ancestor的父节点要小 * 的情况 * * 由于插入元素(73)比旋转后ancestor(50)的父节点(70)要大, 所以新增节点会在其右子树中 * * 新增63 绕90右旋 * → 50 ← ancestor → 50 * /R\ /R\ * 20 90 20 70 * /=\ /=\ /=\ /=\ * 10 40 70 95 10 40 65 90 * = = /=\ /=\ = = /= /=\ * 65 75 93 97 63 75 95 * /= = = = = = /=\ * 63 93 97 * = = = * * 绕50左旋 调整平衡因子 * → 70 → 70 * /=\ /=\ * 50 90 50 90 * /R\ /=\ /=\ /R\ * 20 65 75 95 20 65 75 95 * /=\ /= = /=\ /=\ /L /=\ * 10 40 63 93 97 10 40 63 93 97 * = = = = = = = = = = */ ancestor.parent.right.balanceFactor = 'R'; ancestor.balanceFactor = '='; adjustPath(ancestor, inserted); } } /** * 删除指定节点 * * @param elem * @return boolean */ public boolean remove(E elem) { Entry e = getEntry(elem); if (e == null) return false; deleteEntry(e); return true; } private Entry getEntry(E e) { Entry tmp = root; int c; while (tmp != null) { c = e.compareTo(tmp.elem); if (c == 0) { return tmp; } else if (c < 0) { tmp = tmp.left; } else { tmp = tmp.right; } } return null; } private void deleteEntry(Entry p) { if (p.left != null && p.right != null) { Entry s = successor(p); p.elem = s.elem; p = s; } if (p.left == null && p.right == null) { if (p.parent == null) { root = null; } else if (p == p.parent.left) { p.parent.left = null; } else { p.parent.right = null; } } else { Entry rep; if (p.left != null) { rep = p.left; } else { rep = p.right; } rep.parent = p.parent; if (p.parent == null) { root = rep; } else if (p == p.parent.left) { p.parent.left = rep; } else { p.parent.right = rep; } } fixAfterDeletion(p.elem, p.parent); p.parent = null; p.left = null; p.right = null; size--; } /** * 查找指定节点的中序遍历序列的直接后继节点,此方法的实现与二叉搜索树类(BinSearchTree.java)的此方法是 * 一样的,具体的思路请参考二叉搜索树类中的相应方法 * * @param e 需要查找哪个节点的直接后继节点 * @return Entry 直接后继节点 */ private Entry successor(Entry e) { if (e == null) { return null; }//如果待找的节点有右子树,则在右子树上查找 else if (e.right != null) { //默认后继节点为右子节点(如果右子节点没有左子树时即为该节点) Entry p = e.right; while (p.left != null) { //注,如果右子节点的左子树不为空,则在左子树中查找,且后面找时要一直向左拐 p = p.left; } return p; }//如果待查节点没有右子树,则要在祖宗节点中查找后继节点 else { //默认后继节点为父节点(如果待查节点为父节点的左子树,则后继为父节点) Entry p = e.parent; Entry c = e;//当前节点,如果其父不为后继,则下次指向父节点 //如果待查节点为父节点的右节点时,继续向上找,一直要找到c为左子节点,则p才是后继 while (p != null && c == p.right) { c = p; p = p.parent; } return p; } } /** * 删除节点后平衡调整实现 * * @param elem 被删除节点的数据域 * @param ancestor 被删除节点的祖先节点,从父节点向上迭代 */ protected void fixAfterDeletion(E elem, Entry ancestor) { boolean heightHasDecreased = true;//树的高度是否还需要减小 /* * 1、如果删除的是根节点,则ancestor为空,此时不需调整了,直接退出 * 2、如果删除的不是根节点,且根节点都已调整,则退出 * 3、如果删除的不是根节点,且树的高度不需再减小(heightHasDecreased为false),退出 */ while (ancestor != null && heightHasDecreased) { int comp = elem.compareTo(ancestor.elem); /* * 当要删除的节点有左右子树时,comp就会等于0,比如下面要删除33这个节点,删除方法deleteEntry * 会用36替换掉33节点中的数据的elem,删除后会调用fixAfterDeletion(p.elem, p.parent)方 * 法来调整平衡因子,p又是指向的36,所以p.elem与p.parent.elem是相等的,都是36 * * 82 * /L\ * 42 95 * /=\ R\ * 33 48 96 * /=\ /=\ * 29 36 43 75 */ //从ancestor的右子树中删除节点 if (comp >= 0) { // ancestor 的平衡因子为 '=' if (ancestor.balanceFactor == '=') { /* 删除15 调整因子 * 20 → 20 * /L\ /L\ * → 10 50 10 50 * /=\ /L * 5 15 5 */ ancestor.balanceFactor = 'L'; heightHasDecreased = false; } // ancestor 的平衡因子为 'R' else if (ancestor.balanceFactor == 'R') { /* 删除15 调整因子 下次循环调整20的因子 * 20 → → 20 ← ancestor → ... * /L\ /L\ * → 10 50 10 50 * /R\ R\ /=\ R\ * 5 15 60 5 18 60 * R\ * 18 */ ancestor.balanceFactor = '='; ancestor = ancestor.parent; }// ancestor 的平衡因子为 'L' else if (ancestor.balanceFactor == 'L') { // ancestor 的左子节点平衡因子为 '=' if (ancestor.left.balanceFactor == '=') { /* 删除60 调整因子 绕50右旋 * 20 → → 20 → 20 * /R\ / \ /R\ * 10 50 ← ancestor 10 50 ← 10 45 * /L /L\ / /L\ /L /R\ * 5 45 60 5 45 60 5 35 50 ← * /=\ /R\ /L * 35 48 35 48 48 */ ancestor.left.balanceFactor = 'R'; ancestor.balanceFactor = 'L'; rotateRight(ancestor); heightHasDecreased = false; }// ancestor 的左子节点平衡因子为 'L' else if (ancestor.left.balanceFactor == 'L') { /* 删除60 调整因子 绕50右旋 下次循环调整20的因子 * 20 → → 20 → 20 ← p → ... * /R\ / \ /R\ * 10 50 ← ancestor 10 50 ← 10 45 * /L /L\ / /=\ /L /=\ * 5 45 60 5 45 60 5 35 50 ← ancestor * /L /= = * 35 35 */ Entry p = ancestor.parent; ancestor.balanceFactor = '='; ancestor.left.balanceFactor = '='; rotateRight(ancestor); ancestor = p; } // ancestor 的左子节点平衡因子为 'R' else if (ancestor.left.balanceFactor == 'R') { Entry p = ancestor.parent; // ancestor 的左子节点的右子节点的平衡因子为 'L' if (ancestor.left.right.balanceFactor == 'L') { /* 删除60 调整因子 * 20 → 20 * /R\ / \ * 10 50 ← ancestor 10 50 ← ancestor * /L\ /L\ / \ /R\ * 5 12 45 60 5 12 45 70 * /L /R\ R\ / /=\ * 3 42 48 70 3 42 48 * /L /= * 46 46 * * 绕45左旋 绕50右旋 下次循环调整20的因子 * → 20 → 20 ← p → ... * /R\ /R\ * 10 50 ← 10 48 * /L\ /R\ /L\ /=\ * 5 12 48 70 5 12 45 50 ← ancestor * /L /= /L /=\ R\ * 3 45 3 42 46 70 * /=\ * 42 46 */ ancestor.balanceFactor = 'R'; ancestor.left.balanceFactor = '='; }// ancestor 的左子节点的右子节点的平衡因子为 'R' else if (ancestor.left.right.balanceFactor == 'R') { /* 删除60 调整因子 * 20 → 20 * /R\ / \ * 10 50 ← ancestor 10 50 ← * /L\ /L\ / \ /=\ * 5 12 45 60 5 12 45 70 * /L /R\ R\ / /L\ * 3 42 48 70 3 42 48 * R\ =\ * 49 49 * * 绕45左旋 绕50右旋 下次循环调整20的因子 * → 20 → 20 ← p → ... * /R\ /R\ * 10 50 ← 10 48 * /L\ /=\ /L\ /=\ * 5 12 48 70 5 12 45 50 ← ancestor * /L /=\ /L /L /=\ * 3 45 49 3 42 49 70 * /L * 42 */ ancestor.balanceFactor = '='; ancestor.left.balanceFactor = 'L'; }// ancestor 的左子节点的右子节点的平衡因子为 '=' else { /* 删除60 调整因子 * 20 → 20 * /R\ / \ * 10 50 ← ancestor 10 50 ← * /L\ /L\ / \ /=\ * 5 12 45 60 5 12 45 70 * /L /R\ R\ / /=\ * 3 42 48 70 3 42 48 * /=\ /=\ * 46 49 46 49 * * 绕45左旋 绕50右旋 下次循环调整20的因子 * → 20 → 20 ← p → ... * /R\ /R\ * 10 50 ← 10 48 * /L\ /=\ /L\ /=\ * 5 12 48 70 5 12 45 50 ← ancestor * /L /=\ /L /=\ /=\ * 3 45 49 3 42 46 49 70 * /=\ * 42 46 */ ancestor.balanceFactor = '='; ancestor.left.balanceFactor = '='; } ancestor.left.right.balanceFactor = '='; rotateLeft(ancestor.left); rotateRight(ancestor); ancestor = p; } } } //从ancestor的左子树中删除节点,与上面是对称的 else if (comp < 0) { if (ancestor.balanceFactor == '=') { ancestor.balanceFactor = 'R'; heightHasDecreased = false; } else if (ancestor.balanceFactor == 'L') { ancestor.balanceFactor = '='; ancestor = ancestor.parent; } else if (ancestor.balanceFactor == 'R') { if (ancestor.right.balanceFactor == '=') { ancestor.balanceFactor = 'R'; ancestor.right.balanceFactor = 'L'; rotateLeft(ancestor); heightHasDecreased = false; } else if (ancestor.right.balanceFactor == 'R') { Entry p = ancestor.parent; ancestor.balanceFactor = '='; ancestor.right.balanceFactor = '='; rotateLeft(ancestor); ancestor = p; } else if (ancestor.right.balanceFactor == 'L') { Entry p = ancestor.parent; if (ancestor.right.left.balanceFactor == 'R') { ancestor.balanceFactor = 'L'; ancestor.right.balanceFactor = '='; } else if (ancestor.right.left.balanceFactor == 'L') { ancestor.balanceFactor = '='; ancestor.right.balanceFactor = 'R'; } else { ancestor.balanceFactor = '='; ancestor.right.balanceFactor = '='; } ancestor.right.left.balanceFactor = '='; rotateRight(ancestor.right); rotateLeft(ancestor); ancestor = p; } } } } } public boolean contains(E o) { Entry e = root; int comp; while (e != null) { comp = o.compareTo(e.elem); if (comp == 0) return true; else if (comp < 0) e = e.left; else e = e.right; } return false; } //验证树是否是平衡二叉树 public boolean isAVL() { return checkAVL(root); } /** * 验证指定的树是否是平衡二叉树 * @param p * @return */ public static > boolean checkAVL(Entry p) { if (p == null) return true; //左子树与右子树绝对值不能超过 1,并且左右子树也是平衡二叉树 return (Math.abs(h(p.left) - h(p.right)) <= 1 && checkAVL(p.left) && checkAVL(p.right)); } /** * 求指定节点的高度 * @param * @param p * @return */ protected static > int h(Entry p) { if (p == null) return -1; return 1 + Math.max(h(p.left), h(p.right)); } /** * 树的高度 * @return */ public int height() { return h(root); } //树的高度非递归求法 public int heightIter() { int height = -1; for (Entry temp = root; temp != null; height++) if (temp.balanceFactor == 'L') temp = temp.left; else temp = temp.right; return height; } @Override public Iterator iterator() { return new TreeIterator(); } @Override public int size() { return size; } public static void main(String[] args) { BaseAvlTree myTree = new BaseAvlTree(); Random random = new Random(); System.out.print("随机产生的节点为:"); int num = 0; //直到树的节点数为n止 while (myTree.size() < 10) { num = new Integer(random.nextInt(100)); myTree.add(num); System.out.print(num + " "); } System.out.println(""); if (myTree.isAVL()) { System.out.println("这棵平衡二叉树的总节点数:" + myTree.size()); System.out.println("这棵平衡二叉树的高度是:" + myTree.height()); System.out.println("在树中查找 " + num + " 节点:" + myTree.contains(new Integer(num))); System.out.println("在树中查找 100 节点:" + myTree.contains(new Integer(100))); System.out.print("中序遍历:"); Iterator itr = myTree.iterator(); while (itr.hasNext()) { System.out.print(itr.next() + " "); } System.out.println(""); myTree.remove(num); System.out.print("删除节点 " + num + " 后遍历:"); itr = myTree.iterator(); while (itr.hasNext()) { System.out.print(itr.next() + " "); } System.out.println(""); System.out.println("使用迭代器删除所有节点"); itr = myTree.iterator(); while (itr.hasNext()) { itr.next(); itr.remove(); } System.out.println("删除后树的总节点数:" + myTree.size()); } else { System.out.println("failure"); } } } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/common/BaseDate.java ================================================ package com.zhaidaosi.game.jgframework.common; import java.sql.Timestamp; import java.text.SimpleDateFormat; import java.util.Date; public class BaseDate { public static String FORMAT_YY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss"; public static String FORMAT_YY_MM_DD = "yyyy-MM-dd"; /** * 转换时间to字符串 * @param String format * @param long time * @return String */ public static String time2String(String format, long time) { SimpleDateFormat formatter = new SimpleDateFormat(format); Date curDate = new Date(time); return formatter.format(curDate); } /** * 转换时间to字符串 * @param String format * @return String */ public static String time2String(String format) { return time2String(format, System.currentTimeMillis()); } /** * 字符时间到long * @param date * @return */ public static long string2Time(String date) { if (date != null && !date.equals("")) { return Timestamp.valueOf(date).getTime(); } return 0l; } } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/common/BaseFile.java ================================================ package com.zhaidaosi.game.jgframework.common; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.*; import java.net.URL; import java.net.URLDecoder; import java.util.*; import java.util.jar.JarEntry; import java.util.jar.JarFile; @SuppressWarnings("resource") public class BaseFile { private static final Logger log = LoggerFactory.getLogger(BaseFile.class); public static Set> getClasses(String pack, boolean recursive) { return getClasses(pack, "", recursive); } /** * 从包package中获取所有的Class * * @param pack String * @param suffix String * @param recursive 是迭代 * @return String */ public static Set> getClasses(String pack, String suffix, boolean recursive) { // 第一个class类的集合 Set> classes = new LinkedHashSet>(); // 获取包的名字 并进行替换 String packageName = pack; String packageDirName = packageName.replace('.', '/'); // 定义一个枚举的集合 并进行循环来处理这个目录下的things Enumeration dirs; try { dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName); // 循环迭代下去 while (dirs.hasMoreElements()) { // 获取下一个元素 URL url = dirs.nextElement(); // 得到协议的名称 String protocol = url.getProtocol(); // 如果是以文件的形式保存在服务器上 if ("file".equals(protocol)) { // 获取包的物理路径 String filePath = URLDecoder.decode(url.getFile(), "UTF-8"); // 以文件的方式扫描整个包下的文件 并添加到集合中 findAndAddClassesInPackageByFile(packageName, filePath, suffix, recursive, classes); } else if ("jar".equals(protocol)) { // 如果是jar包文件 // 定义一个JarFile JarFile jar; try { String jarPath = url.getPath(); if (jarPath.indexOf("file:") == 0) { jarPath = jarPath.substring(5); } int index = jarPath.lastIndexOf(".jar"); jarPath = jarPath.substring(0, index) + ".jar"; // 获取jar jar = new JarFile(jarPath); // 从此jar包 得到一个枚举类 Enumeration entries = jar.entries(); // 同样的进行循环迭代 while (entries.hasMoreElements()) { // 获取jar里的一个实体 可以是目录 和一些jar包里的其他文件 如META-INF等文件 JarEntry entry = entries.nextElement(); String name = entry.getName(); // 如果是以/开头的 if (name.charAt(0) == '/') { // 获取后面的字符串 name = name.substring(1); } // 如果前半部分和定义的包名相同 if (name.startsWith(packageDirName)) { int idx = name.lastIndexOf('/'); // 如果以"/"结尾 是一个包 if (idx != -1) { // 获取包名 把"/"替换成"." packageName = name.substring(0, idx).replace('/', '.'); } // 如果可以迭代下去 并且是一个包 if ((idx != -1) || recursive) { // 如果是一个.class文件 而且不是目录 if (name.endsWith(".class") && !entry.isDirectory()) { // 去掉后面的".class" 获取真正的类名 String className = name.substring(packageName.length() + 1, name.length() - 6); try { // 添加到classes classes.add(Class.forName(packageName + '.' + className)); } catch (ClassNotFoundException e) { log.error("添加用户自定义视图类错误 找不到此类的.class文件", e); } } } } } } catch (IOException e) { log.error("在扫描用户定义视图时从jar包获取文件出错", e); } } } } catch (IOException e) { } return classes; } /** * 以文件的形式来获取包下的所有Class * * @param packageName * @param packagePath * @param recursive * @param classes */ private static void findAndAddClassesInPackageByFile(String packageName, String packagePath, final String suffix, final boolean recursive, Set> classes) { // 获取此包的目录 建立一个File File dir = new File(packagePath); // 如果不存在或者 也不是目录就直接返回 if (!dir.exists() || !dir.isDirectory()) { // log.warn("用户定义包名 " + packageName + " 下没有任何文件"); return; } // 如果存在 就获取包下的所有文件 包括目录 File[] dirfiles = dir.listFiles(new FileFilter() { // 自定义过滤规则 如果可以循环(包含子目录) 或则是以.class结尾的文件(编译好的java类文件) public boolean accept(File file) { return (recursive && file.isDirectory()) || (file.getName().endsWith(suffix + ".class")); } }); // 循环所有文件 for (File file : dirfiles) { // 如果是目录 则继续扫描 if (file.isDirectory()) { findAndAddClassesInPackageByFile(packageName + "." + file.getName(), file.getAbsolutePath(), suffix, recursive, classes); } else { // 如果是java类文件 去掉后面的.class 只留下类名 String className = file.getName().substring(0, file.getName().length() - 6); try { // 添加到集合中去 // classes.add(Class.forName(packageName + '.' + // className)); // 经过回复同学的提醒,这里用forName有一些不好,会触发static方法,没有使用classLoader的load干净 classes.add(Thread.currentThread().getContextClassLoader().loadClass(packageName + '.' + className)); } catch (ClassNotFoundException e) { log.error("添加用户自定义视图类错误 找不到此类的.class文件", e); } } } } public static List fileList(String path) { return fileList(path, false); } public static List fileList(String path, boolean needDir) { List list = new ArrayList(); File file = new File(path); if (file.isDirectory()) { String[] filelist = file.list(); for (int i = 0; i < filelist.length; i++) { file = new File(path + "/" + filelist[i]); if (!file.isDirectory()) { list.add(file.getName()); } else { if (needDir) { list = fileList(list, path, file.getName()); } } } } return list; } private static List fileList(List list, String path, String dir) { File file = new File(path + "/" + dir); if (file.isDirectory()) { String[] filelist = file.list(); for (int i = 0; i < filelist.length; i++) { file = new File(path + "/" + dir + "/" + filelist[i]); if (!file.isDirectory()) { list.add(dir + "/" + file.getName()); } else { list = fileList(list, path, dir + "/" + file.getName()); } } } return list; } public static String readResourceByLines(String resourcePath) { // 返回读取指定资源的输入流 InputStream is = BaseFile.class.getClassLoader().getResourceAsStream(resourcePath); BufferedReader reader = new BufferedReader(new InputStreamReader(is)); StringBuffer buffer = new StringBuffer(""); try { String tempString = null; while ((tempString = reader.readLine()) != null) { buffer.append(tempString); buffer.append("\n"); } } catch (IOException e) { log.error("读取文件失败", e); } finally { if (reader != null) { try { reader.close(); } catch (IOException e1) { } } } return buffer.toString(); } /** * 以行为单位读取文件,常用于读面向行的格式化文件 */ public static String readFileByLines(String fileName) { File file = new File(fileName); return readFileByLines(file); } /** * 以行为单位读取文件,常用于读面向行的格式化文件 */ public static String readFileByLines(File file) { BufferedReader reader = null; StringBuffer buffer = new StringBuffer(""); try { reader = new BufferedReader(new FileReader(file)); String tempString = null; // 一次读入一行,直到读入null为文件结束 while ((tempString = reader.readLine()) != null) { buffer.append(tempString); buffer.append("\n"); } reader.close(); } catch (IOException e) { log.error("读取文件失败", e); } finally { if (reader != null) { try { reader.close(); } catch (IOException e1) { } } } return buffer.toString(); } public static String readFileLastByLine(String filePath, int lastStart, int limit) { File file = new File(filePath); String buffer = ""; if (!file.exists()) { return buffer; } RandomAccessFile raf; try { raf = new RandomAccessFile(file, "r"); long len = raf.length(); int line = 0; if (len != 0L) { long pos = len - 1; while (pos > 0) { raf.seek(pos); if (raf.readByte() == '\n') { if (lastStart <= line && line < lastStart + limit) { String temp = ""; // Windows下有乱码问题 String tempLine = raf.readLine(); if (tempLine == null) { pos--; continue; } temp += tempLine; temp += "\n"; buffer += temp; pos--; } line++; } else { pos--; } if (line >= lastStart + limit) { break; } } } raf.close(); } catch (IOException e) { log.error("读取文件失败", e); } return buffer; } /** * 判断文件的编码格式 * * @param fileName * :file * @return 文件编码格式 * @throws Exception */ public static String codeString(String fileName) throws Exception { BufferedInputStream bin = new BufferedInputStream(new FileInputStream(fileName)); int p = (bin.read() << 8) + bin.read(); String code = null; // 其中的 0xefbb、0xfffe、0xfeff、0x5c75这些都是这个文件的前面两个字节的16进制数 switch (p) { case 0xefbb: code = "UTF-8"; break; case 0xfffe: code = "Unicode"; break; case 0xfeff: code = "UTF-16BE"; break; case 0x5c75: code = "ANSI|ASCII"; break; default: code = "GBK"; } return code; } } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/common/BaseGeneratePassword.java ================================================ package com.zhaidaosi.game.jgframework.common; import java.util.Random; public class BaseGeneratePassword { private static char arrayString[] = new char[62]; // 候选字符数组 static { int j = 0; for (int i = 48; i <= 57; i++) { // 0-9 arrayString[j] = (char) i; j++; } for (int i = 65; i <= 90; i++) { // A-Z arrayString[j] = (char) i; j++; } for (int i = 97; i <= 122; i++) { // a-z arrayString[j] = (char) i; j++; } } /** * 生成密码 * @param intPassLength 密码长度 * @return String */ public static String doGenerate(final int intPassLength) { int intTemp; String strPassword = ""; Random rand = new Random(); for (int i = 0; i < intPassLength; i++) { intTemp = rand.nextInt(62); strPassword += arrayString[intTemp]; } return strPassword; } } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/common/BaseIp.java ================================================ package com.zhaidaosi.game.jgframework.common; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class BaseIp { private static final Logger log = LoggerFactory.getLogger(BaseIp.class); public static Long[] stringToIp(String ips) { Long[] longArr; String[] ipArr = ips.split("-"); if (ipArr.length == 2) { longArr = new Long[2]; longArr[0] = ipToLong(ipArr[0]); longArr[1] = ipToLong(ipArr[1]); } else { longArr = new Long[1]; longArr[0] = ipToLong(ipArr[0]); } return longArr; } public static long ipToLong(String ip) { String[] ipArr = ip.split("\\."); if (ipArr.length != 4) { log.error("ip格式错误:" + ip); return 0L; } long s = 0; for (int i = 0; i < ipArr.length; i++) { s += (long) (Long.parseLong(ipArr[i]) * Math.pow(1000, 3 - i)); } return s; } public static boolean checkIp(String ip, Long[] ipArr) { long ipLong = ipToLong(ip); if (ipArr.length == 1) { if (ipLong == ipArr[0]) { return true; } } else { if (ipArr[0] <= ipLong && ipLong <= ipArr[1]) { return true; } } return false; } } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/common/BaseJson.java ================================================ package com.zhaidaosi.game.jgframework.common; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.serializer.SerializerFeature; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class BaseJson { private static final Logger log = LoggerFactory.getLogger(BaseJson.class); public static T JsonToObject(String jsonStr, Class c) { return JSON.parseObject(jsonStr, c); } public static String ObjectToJson(Object obj) { return JSON.toJSONString(obj, SerializerFeature.WriteNonStringKeyAsString, SerializerFeature.BrowserCompatible); } } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/common/BaseRunTimer.java ================================================ package com.zhaidaosi.game.jgframework.common; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.util.Assert; import java.util.ArrayList; import java.util.List; /** * Copyright (c) 2013, zhidaosi.com * * @description: 记录运行时间 * @author: 俊杰Jerry * @date: 2013-7-5 */ public class BaseRunTimer { private static ThreadLocal> timerHolder = new ThreadLocal>(); private static final Log log = LogFactory.getLog(BaseRunTimer.class); private static boolean active = false; public static void addTimer(String msg) { if (active) { Assert.notNull(msg, "msg cannot be null"); List timer = getTimer(); timer.add(msg); timerHolder.set(timer); } } private static List getTimer() { List timer = (List) timerHolder.get(); if (timer == null) { timer = new ArrayList(); } return timer; } public static void showTimer() { if (active && log.isInfoEnabled()) { List timer = getTimer(); if (timer.size() > 0) { String line = "**********************************************************************"; String message = "\n" + line + "\n"; for (String msg : timer) { message += "********** "; message += msg; message += "\n"; } message += line; log.info(message); } } timerHolder.remove(); } public static boolean isActive() { return active; } public static void toActive() { BaseRunTimer.active = true; } } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/common/BaseSocket.java ================================================ package com.zhaidaosi.game.jgframework.common; import com.zhaidaosi.game.jgframework.common.excption.MessageException; import com.zhaidaosi.game.jgframework.message.InMessage; import com.zhaidaosi.game.jgframework.message.OutMessage; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; import java.net.UnknownHostException; import java.util.HashMap; public class BaseSocket { private String host; private int port; private Socket socket; private static HashMap socketMap = new HashMap(); private BaseSocket(String host, int port) throws UnknownHostException, IOException { this.socket = new Socket(host, port); this.host = host; this.port = port; } public static BaseSocket getNewInstance(String host, int port) throws UnknownHostException, IOException { return new BaseSocket(host, port); } public static BaseSocket getInstance(String host, int port) throws UnknownHostException, IOException { BaseSocket mySocket = socketMap.get(host + ":" + port); if (mySocket == null || mySocket.socket.isClosed()) { mySocket = new BaseSocket(host, port); socketMap.put(host + ":" + port, mySocket); } return mySocket; } public void reconnect() throws IOException { if (!socket.isClosed()) { socket.close(); } socket = new Socket(host, port); socketMap.put(host + ":" + port, this); } public OutMessage request(InMessage msg) throws IOException, MessageException { send(msg); OutMessage om = receive(); if (om == null) { throw new IOException("连接已被强制中断"); } return om; } public void heartBeat() throws IOException { send(new InMessage()); } public void send(InMessage msg) throws IOException { String out = msg.toString(); PrintWriter printWriter = new PrintWriter(socket.getOutputStream(), true); printWriter.write(out); printWriter.flush(); } private OutMessage receive() throws IOException, MessageException { BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream())); return OutMessage.getMessage(bufferedReader.readLine()); } public void close() throws IOException { socketMap.remove(socket.getLocalAddress() + ":" + socket.getPort()); if (!socket.isClosed()) { socket.close(); } } public void closeNew() throws IOException { if (!socket.isClosed()) { socket.close(); } } } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/common/BaseString.java ================================================ package com.zhaidaosi.game.jgframework.common; public class BaseString { public static boolean isEmpty(String str) { if (str == null) { return true; } str = str.trim(); return str.equals(""); } } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/common/cache/BaseLocalCached.java ================================================ package com.zhaidaosi.game.jgframework.common.cache; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; /** * 用户保持不会垮服务器的数据 * @author Jerry */ public class BaseLocalCached { public static final String INVALID = "%IT IS INVALID!!%"; private class BaseCacheElement { private Object value; private long failureTime; private BaseCacheElement(Object value, long failureTime) { this.value = value; this.failureTime = failureTime; } } private ConcurrentMap cache = new ConcurrentHashMap(); private static Timer timer = null; private static List list = Collections.synchronizedList(new ArrayList()); private static final long period = 600000; public BaseLocalCached() { if (!list.contains(this)) { list.add(this); startTimer(); } } /** * 设置缓存 * @param key * @param value * @param time 单位秒 */ public void set(String key, Object value, int time) { cache.put(key, new BaseCacheElement(value, System.currentTimeMillis() + time * 1000)); } public void set(String key, Object value) { cache.put(key, new BaseCacheElement(value, 0L)); } public void delete(String key) { cache.remove(key); } /** * 判断是否过期,过期返回true * @param value * @return */ public boolean checkInvalid(Object value) { return INVALID.equals(value); } public Object get(String key) { BaseCacheElement element = cache.get(key); if (checkTime(element)) { return element.value; } else { if (element != null) { cache.remove(key); } return INVALID; } } private boolean checkTime(BaseCacheElement element) { if (element == null) { return false; } if (element.failureTime == 0L || element.failureTime > System.currentTimeMillis()) { return true; } return false; } public static void startTimer() { if (timer == null && list.size() > 0) { timer = new Timer("BaseLocalCachedTimer"); timer.schedule(new InvalidTask(), period, period); } } public static void cancelTimer() { if (timer != null) { timer.cancel(); timer = null; } } private static void invalid() { for (BaseLocalCached localCached : list) { for (Map.Entry entry : localCached.cache.entrySet()) { String key = entry.getKey(); BaseCacheElement element = entry.getValue(); if (!localCached.checkTime(element)) { localCached.delete(key); } } } } private static class InvalidTask extends TimerTask { @Override public void run() { BaseLocalCached.invalid(); } } } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/common/cache/BaseMemCached.java ================================================ package com.zhaidaosi.game.jgframework.common.cache; import com.whalin.MemCached.MemCachedClient; import com.whalin.MemCached.SockIOPool; import com.zhaidaosi.game.jgframework.Boot; import java.util.ArrayList; public class BaseMemCached extends MemCachedClient { // 创建全局的唯一实例 private static BaseMemCached mc = new BaseMemCached(); private final static String KEYPREFIX; // 设置与缓存服务器的连接池 static { String[] servers; Integer[] weights; ArrayList confServers = Boot.getMemcacheServers(); KEYPREFIX = Boot.getMemcacheKeyPrefix(); int size = confServers.size(); if (size > 1) { servers = new String[size]; weights = new Integer[size]; for (int i = 0; i < size; i++) { String[] temp2 = confServers.get(i).split(","); servers[i] = temp2[0]; if (temp2.length > 1) { weights[i] = new Integer(temp2[1]); } else { weights[i] = 1; } } } else { // 服务器列表和其权重 servers = new String[]{"127.0.0.1:11211"}; weights = new Integer[]{1}; } // 获取socke连接池的实例对象 SockIOPool pool = SockIOPool.getInstance(); // 设置服务器信息 pool.setServers(servers); pool.setWeights(weights); // 设置初始连接数、最小和最大连接数以及最大处理时间 pool.setInitConn(100); pool.setMinConn(100); pool.setMaxConn(2000); pool.setMaxIdle(1000 * 60 * 60 * 6); // 设置主线程的睡眠时间 pool.setMaintSleep(30); // 设置TCP的参数,连接超时等 pool.setNagle(false); //连接建立后的超时时间 pool.setSocketTO(3000); //连接建立时的超时时间 pool.setSocketConnectTO(0); pool.setHashingAlg(SockIOPool.NEW_COMPAT_HASH); // 初始化连接池 pool.initialize(); } /** * 保护型构造方法,不允许实例化! * */ private BaseMemCached() { } /** * 获取唯一实例. */ public static BaseMemCached getInstance() { return mc; } public static String getMcKey(String key) { return KEYPREFIX + key; } } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/common/encrpt/BaseDes.java ================================================ package com.zhaidaosi.game.jgframework.common.encrpt; import com.zhaidaosi.game.jgframework.Boot; import javax.crypto.Cipher; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.DESKeySpec; import javax.xml.bind.DatatypeConverter; import java.security.SecureRandom; public class BaseDes { private final static String DES = "DES"; private static byte[] keyBytes = "1234567890!@#$qweasd".getBytes(); public static void setDesKey(String key) { keyBytes = key.getBytes(); } /** * Description 根据键值进行加密 * @param data * @return */ public static String encrypt(String data) { byte[] bt; try { bt = encrypt(data.getBytes(Boot.getCharset()), keyBytes); } catch (Exception e) { return null; } return DatatypeConverter.printBase64Binary(bt); } /** * Description 根据键值进行解密 * @param data * @return */ public static String decrypt(String data) { if (data == null) return null; byte[] buf; byte[] bt; try { buf = DatatypeConverter.parseBase64Binary(data); bt = decrypt(buf, keyBytes); } catch (Exception e) { // e.printStackTrace(); return null; } return new String(bt, Boot.getCharset()); } /** * Description 根据键值进行加密 * @param data * @param key 加密键byte数组 * @return * @throws Exception */ private static byte[] encrypt(byte[] data, byte[] key) throws Exception { // 生成一个可信任的随机数源 SecureRandom sr = new SecureRandom(); // 从原始密钥数据创建DESKeySpec对象 DESKeySpec dks = new DESKeySpec(key); // 创建一个密钥工厂,然后用它把DESKeySpec转换成SecretKey对象 SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES); SecretKey secretKey = keyFactory.generateSecret(dks); // Cipher对象实际完成加密操作 Cipher cipher = Cipher.getInstance(DES); // 用密钥初始化Cipher对象 cipher.init(Cipher.ENCRYPT_MODE, secretKey, sr); return cipher.doFinal(data); } /** * Description 根据键值进行解密 * @param data * @param key 加密键byte数组 * @return * @throws Exception */ private static byte[] decrypt(byte[] data, byte[] key) throws Exception { // 生成一个可信任的随机数源 SecureRandom sr = new SecureRandom(); // 从原始密钥数据创建DESKeySpec对象 DESKeySpec dks = new DESKeySpec(key); // 创建一个密钥工厂,然后用它把DESKeySpec转换成SecretKey对象 SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES); SecretKey secretKey = keyFactory.generateSecret(dks); // Cipher对象实际完成解密操作 Cipher cipher = Cipher.getInstance(DES); // 用密钥初始化Cipher对象 cipher.init(Cipher.DECRYPT_MODE, secretKey, sr); return cipher.doFinal(data); } } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/common/encrpt/BaseMd5.java ================================================ package com.zhaidaosi.game.jgframework.common.encrpt; import com.zhaidaosi.game.jgframework.Boot; import javax.xml.bind.DatatypeConverter; import java.security.MessageDigest; public class BaseMd5 { /** * 进行MD5加密 * * @param text 原始的SPKEY * @return String 指定加密方式为md5后的String */ public static String encrypt(String text) { byte[] returnByte; try { MessageDigest md5 = MessageDigest.getInstance("MD5"); returnByte = md5.digest(text.getBytes(Boot.getCharset())); } catch (Exception e) { return null; } return DatatypeConverter.printBase64Binary(returnByte); } } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/common/encrpt/BaseRsa.java ================================================ package com.zhaidaosi.game.jgframework.common.encrpt; import com.zhaidaosi.game.jgframework.Boot; import javax.crypto.Cipher; import javax.xml.bind.DatatypeConverter; import java.security.*; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; public class BaseRsa { private static PublicKey publicKey; private static PrivateKey privateKey; static { if (publicKey == null) { publicKey = getPublicKey("MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCifAl6RlbG1PVOowZJ2niVlijq9FC19jEIaA2WVm+En64roRsTjlWpAKOfYBHIwEYWvI7rObyobTIPyOkBOCx5Sbopq2ME7FUQEwI2IeEBGHwnIBPzkhTEt9kMT88g8hZRBV6D/p6J8Z1u2WU0q88Xpd4o7VDxFRmGUTSePOGcjQIDAQAB"); } if (privateKey == null) { privateKey = getPrivateKey("MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAKJ8CXpGVsbU9U6jBknaeJWWKOr0ULX2MQhoDZZWb4SfriuhGxOOVakAo59gEcjARha8jus5vKhtMg/I6QE4LHlJuimrYwTsVRATAjYh4QEYfCcgE/OSFMS32QxPzyDyFlEFXoP+nonxnW7ZZTSrzxel3ijtUPEVGYZRNJ484ZyNAgMBAAECgYA3SHCJE8mOmQJloP4Qvq5sZszBNCMJ5hvEunJ1Bi+nNhUybvwhaTon6DnDjhI+9XxjXABcdCaGP7DawgbVDWHDzjgQG0xQle2ryrZFa0thgQDYM4iraMgxMN/5kTXD9DlZcf871N0DeI8dTpxJhVMcM5d95sml6pJxxqwyzABiAQJBAO1rvTpHS6OgDVRpHV4HksyEcKETEayVknAIbTGP3VH3L4X50CpwOwPsvaHi5sENkSEA2JtKj0qF0CbP3sAdDcECQQCvMxhuq2V+dRyMkFLot3YZbMffr2dJi6o4XwxDtI/nhHzS5bQIzKX7L1m8ZJ0GR6CSjZ6X+LBRW6h3tLTsNdnNAkANsK+5o5DN/5WlL2Z9HIyvdFeWQiY7wGgwQ5wgRn5pkopP/Gave8c7Y7RPmGjb6u9aatUSp0r57hthkYzzoPlBAkBG6sfZBEfxCDamL0VgLeMAJ6hAQx/sBTzB1LeCMHSPonFkbNaTOUN2iZQpThDBmfzFVc38dg3o4NEwo1UYyDOBAkAsfnopb+Msp8pMBw7mcX/CeCXNIVpBNWSLtT0AssDf9ofaQ+bIsFIsy2GaPt/UuZmltXgTP5J3iWqFIKQDRstH"); } } public static void init(String publicKeyString, String privateKeyString) { publicKey = getPublicKey(publicKeyString); privateKey = getPrivateKey(privateKeyString); } public static String encrypt(String data) { if (data == null) { return null; } try { Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE, publicKey); return DatatypeConverter.printBase64Binary(cipher.doFinal(data.getBytes(Boot.getCharset()))); } catch (Exception e) { return null; } } public static String decrypt(String data) { if (data == null) { return null; } try { Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.DECRYPT_MODE, privateKey); return new String(cipher.doFinal(DatatypeConverter.parseBase64Binary(data)), Boot.getCharset()); } catch (Exception e) { return null; } } /** * 得到公钥 * * @param key 密钥字符串(经过base64编码) * @throws Exception */ private static PublicKey getPublicKey(String key) { byte[] keyBytes; PublicKey publicKey = null; try { keyBytes = DatatypeConverter.parseBase64Binary(key); X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); publicKey = keyFactory.generatePublic(keySpec); } catch (Exception e) { return null; } return publicKey; } /** * 得到私钥 * * @param key 密钥字符串(经过base64编码) * @throws Exception */ private static PrivateKey getPrivateKey(String key) { byte[] keyBytes; PrivateKey privateKey = null; try { keyBytes = DatatypeConverter.parseBase64Binary(key); PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); privateKey = keyFactory.generatePrivate(keySpec); } catch (Exception e) { return null; } return privateKey; } /** * 得到密钥字符串(经过base64编码) * * @return */ private static String getKeyString(Key key) throws Exception { byte[] keyBytes = key.getEncoded(); return DatatypeConverter.printBase64Binary(keyBytes); } public static void main(String[] args) throws Exception { KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA"); // 密钥位数 keyPairGen.initialize(1024); // 密钥对 KeyPair keyPair = keyPairGen.generateKeyPair(); // 公钥 PublicKey publicKey = keyPair.getPublic(); // 私钥 PrivateKey privateKey = keyPair.getPrivate(); String publicKeyString = getKeyString(publicKey); System.out.println("public:\n" + publicKeyString); String privateKeyString = getKeyString(privateKey); System.out.println("private:\n" + privateKeyString); BaseRsa.init(publicKeyString, privateKeyString); String test = "1231232123_2013-01-01 00:00:00"; String t = BaseRsa.encrypt(test); System.out.println(t); String a = BaseRsa.decrypt(t); System.out.println(a); } } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/common/excption/BaseException.java ================================================ package com.zhaidaosi.game.jgframework.common.excption; @SuppressWarnings("serial") public class BaseException extends Exception implements IBaseException { protected int code = 0; public BaseException(String msg, int code) { super(msg); this.code = code; } public int getCode() { return code; } } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/common/excption/HttpException.java ================================================ package com.zhaidaosi.game.jgframework.common.excption; @SuppressWarnings("serial") public class HttpException extends BaseException { public HttpException(String message) { super(message, 60000); } } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/common/excption/IBaseException.java ================================================ package com.zhaidaosi.game.jgframework.common.excption; public interface IBaseException { public int getCode(); } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/common/excption/MessageException.java ================================================ package com.zhaidaosi.game.jgframework.common.excption; @SuppressWarnings("serial") public class MessageException extends BaseException { public MessageException(String msg) { super(msg, 50000); } } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/common/http/BaseCookie.java ================================================ package com.zhaidaosi.game.jgframework.common.http; public class BaseCookie { private String key; private String value; public BaseCookie(String key, String value) { this.key = key; this.value = value; } public String getKey() { return key; } public String getValue() { return value; } } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/common/http/BaseHttp.java ================================================ package com.zhaidaosi.game.jgframework.common.http; import com.zhaidaosi.game.jgframework.common.excption.HttpException; import org.apache.commons.httpclient.*; import org.apache.commons.httpclient.cookie.CookiePolicy; import org.apache.commons.httpclient.methods.GetMethod; import org.apache.commons.httpclient.methods.PostMethod; import org.apache.commons.httpclient.params.HttpMethodParams; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.*; import java.net.*; import java.net.URI; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; @SuppressWarnings("unchecked") public class BaseHttp { public static String GBK = "GBK"; public static String GB2312 = "GB2312"; public static String UTF8 = "UTF-8"; public static String HEADER_HOST = "Host"; public static String HEADER_REFERER = "Referer"; private static final Logger log = LoggerFactory.getLogger(BaseHttp.class); private static int DEFAULT_TIMEOUT = 3000; private static String DEFAULT_CHARSET = "UTF-8"; private static int DEFAULT_MAX_REDIRECT = 2; private static String DEFAULT_USER_AGENT = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.0) Gecko/20100101 Firefox/22.0 zhaidaosi.com"; public static int header(String url) throws Exception { return header(url, null, null, null, DEFAULT_TIMEOUT); } public static String get(String url) throws Exception { return get(url, null, null, DEFAULT_CHARSET, DEFAULT_MAX_REDIRECT, DEFAULT_TIMEOUT); } public static String get(String url, Map header) throws Exception { return get(url, header, null, DEFAULT_CHARSET, DEFAULT_MAX_REDIRECT, DEFAULT_TIMEOUT); } public static String get(String url, String charset) throws Exception { return get(url, null, null, charset, DEFAULT_MAX_REDIRECT, DEFAULT_TIMEOUT); } public static String post(String url, Map params) throws Exception { return post(url, params, null, null, DEFAULT_CHARSET, DEFAULT_TIMEOUT); } public static String post(String url, Map params, int timeout) throws Exception { return post(url, params, null, null, DEFAULT_CHARSET, timeout); } public static String post(String url, Map params, Map header) throws Exception { return post(url, params, header, null, DEFAULT_CHARSET, DEFAULT_TIMEOUT); } public static void sendRequest(String url) throws Exception { sendRequest(url, null, null, null, DEFAULT_CHARSET); } public static void sendRequest(String url, Map params) throws Exception { sendRequest(url, params, null, null, DEFAULT_CHARSET); } /** * 返回状态码 * * @param url * @param header * @param cookie * @return * @throws HttpException */ public static int header(String url, HashMap header, BaseCookie[] cookie, String charset, int timeout) throws Exception { check(url); if (charset == null) { charset = DEFAULT_CHARSET; } HashMap args = new HashMap(); args.put("url", url); args.put("header", header); args.put("cookie", cookie); args.put("charset", charset); args.put("timeout", timeout); return doHeader(args); } /** * 模拟get * * @param url * @param header * @param cookie * @param charset * @param maxRedirect * @return * @throws HttpException */ public static String get(String url, Map header, BaseCookie[] cookie, String charset, int maxRedirect, int timeout) throws Exception { check(url); HashMap args = new HashMap(); args.put("url", url); args.put("header", header); args.put("cookie", cookie); args.put("charset", charset); args.put("maxRedirect", maxRedirect); args.put("timeout", timeout); return doGet(args, 0); } /** * 模拟post * * @param url * @param params * 可以是String和String[] * @param header * @param cookie * @param charset * @return * @throws HttpException */ public static String post(String url, Map params, Map header, BaseCookie[] cookie, String charset, int timeout) throws Exception { check(url); if (charset == null) { charset = DEFAULT_CHARSET; } HashMap args = new HashMap(); args.put("url", url); args.put("header", header); args.put("cookie", cookie); args.put("charset", charset); args.put("params", params); args.put("timeout", timeout); return doPost(args); } /** * 模拟http请求,不接受返回信息 * * @param url * @param params * 可以是String和String[] * @param header * @param cookie * @param charset * @throws Exception */ public static void sendRequest(String url, Map params, Map header, BaseCookie[] cookie, String charset) throws Exception { check(url); if (charset == null) { charset = DEFAULT_CHARSET; } HashMap args = new HashMap(); args.put("url", url); args.put("header", header); args.put("cookie", cookie); args.put("charset", charset); args.put("params", params); doSendRequest(args); } private static void doSendRequest(Map args) throws URISyntaxException, UnknownHostException, IOException { String url = (String) args.get("url"); HashMap params = (HashMap) args.get("params"); HashMap header = (HashMap) args.get("header"); BaseCookie[] cookie = (BaseCookie[]) args.get("cookie"); String charset = (String) args.get("charset"); URI uri = new URI(url); int port = uri.getPort(); @SuppressWarnings("resource") Socket s = new Socket(uri.getHost(), port == -1 ? 80 : port); OutputStreamWriter osw = new OutputStreamWriter(s.getOutputStream()); StringBuffer sb = new StringBuffer(); String postStr = null; if (params != null) { postStr = ""; for (Map.Entry entry : params.entrySet()) { String key = entry.getKey(); Object val = entry.getValue(); if (val instanceof String) { postStr += (URLEncoder.encode(key, charset) + "=" + URLEncoder.encode((String) val, charset) + "&"); } else if (entry.getValue() instanceof String[]) { for (String value : (String[]) val) { postStr += (URLEncoder.encode(key, charset) + "=" + URLEncoder.encode(value, charset) + "&"); } } } postStr = postStr.substring(0, postStr.length() - 1); sb.append("POST "); } else { sb.append("GET "); } String fullPath = uri.getQuery() == null ? uri.getPath() : uri.getPath() + "?" + uri.getQuery(); sb.append(fullPath + " HTTP/1.1\r\n"); sb.append("Host: " + uri.getHost() + "\r\n"); sb.append("User-Agent: " + DEFAULT_USER_AGENT + "\r\n"); sb.append("Connection: keep-alive\r\n"); if (header != null) { for (Map.Entry h : header.entrySet()) { sb.append(h.getKey() + ": " + h.getValue() + "\r\n"); } } if (postStr != null) { sb.append("Content-type: application/x-www-form-urlencoded\r\n"); sb.append("Content-Length: " + postStr.length() + "\r\n"); } if (cookie != null) { int size = cookie.length; for (int i = 0; i < size; i++) { sb.append("Cookie: " + URLEncoder.encode(cookie[i].getKey(), charset) + "=" + URLEncoder.encode(cookie[i].getValue(), charset)); if (i < size - 1) { sb.append("; "); } } } sb.append("\r\nConnection: Close\r\n\r\n"); if (postStr != null) { sb.append(postStr + "\r\n"); } osw.write(sb.toString()); osw.flush(); osw.close(); } /** * 模拟get * * @param args * @param retry * 重试第几次了 * @return * @throws HttpException */ private static String doGet(HashMap args, int retry) throws HttpException { int maxRedirect = (Integer) args.get("maxRedirect"); String result = null; if (retry > maxRedirect) { return result; } String url = (String) args.get("url"); HashMap header = (HashMap) args.get("header"); BaseCookie[] cookie = (BaseCookie[]) args.get("cookie"); String charset = (String) args.get("charset"); Integer timeout = (Integer) args.get("timeout"); HttpClient client = new HttpClient(); GetMethod method = new GetMethod(url); BaseHttp.init(client, method, header, cookie, charset, timeout); try { int statusCode = client.executeMethod(method); if (statusCode == HttpStatus.SC_OK) { result = getResponse(method, charset); } else if (statusCode == HttpStatus.SC_MOVED_PERMANENTLY || statusCode == HttpStatus.SC_MOVED_TEMPORARILY || statusCode == HttpStatus.SC_SEE_OTHER || statusCode == HttpStatus.SC_TEMPORARY_REDIRECT) { // 301, 302, 303, 307 跳转 Header locationHeader = method.getResponseHeader("location"); String location = null; if (locationHeader != null) { location = locationHeader.getValue(); retry++; args.put("url", location); result = BaseHttp.doGet(args, retry); } } } catch (IOException e) { throw new HttpException("执行HTTP Get请求" + url + "时,发生异常! => " + e.getMessage()); } finally { method.releaseConnection(); } return result; } /** * 模拟post * * @param args * @return * @throws HttpException */ private static String doPost(HashMap args) throws HttpException { String result = null; String url = (String) args.get("url"); HashMap header = (HashMap) args.get("header"); BaseCookie[] cookie = (BaseCookie[]) args.get("cookie"); String charset = (String) args.get("charset"); Integer timeout = (Integer) args.get("timeout"); HashMap params = (HashMap) args.get("params"); HttpClient client = new HttpClient(); PostMethod method = new PostMethod(url); BaseHttp.init(client, method, header, cookie, charset, timeout); if (params != null) { NameValuePair[] data = new NameValuePair[params.size()]; int i = 0; for (Map.Entry entry : params.entrySet()) { String key = entry.getKey(); Object val = entry.getValue(); if (val instanceof String) { data[i] = new NameValuePair(key, (String) val); } else if (val instanceof String[]) { for (String value : (String[]) val) { data[i] = new NameValuePair(key, value); } } else { throw new HttpException("post 参数类型必须为 String 或 String[]"); } i++; } method.setRequestBody(data); } try { if (client.executeMethod(method) == HttpStatus.SC_OK) { result = getResponse(method, charset); } } catch (IOException e) { throw new HttpException("执行HTTP Post请求" + url + "时,发生异常! => " + e.getMessage()); } finally { method.releaseConnection(); } return result; } /** * 获取状态码 * * @param args * @return * @throws HttpException */ private static int doHeader(HashMap args) throws HttpException { int statusCode = 0; String url = (String) args.get("url"); HashMap header = (HashMap) args.get("header"); String charset = (String) args.get("charset"); BaseCookie[] cookie = (BaseCookie[]) args.get("cookie"); Integer timeout = (Integer) args.get("timeout"); HttpClient client = new HttpClient(); HttpMethod method = new GetMethod(url); BaseHttp.init(client, method, header, cookie, charset, timeout); try { statusCode = client.executeMethod(method); } catch (IOException e) { throw new HttpException("执行HTTP Header请求" + url + "时,发生异常! => " + e.getMessage()); } finally { method.releaseConnection(); } return statusCode; } /** * 初始化 * * @param client * @param method * @param headers * @param cookie * @throws UnsupportedEncodingException */ private static void init(HttpClient client, HttpMethod method, HashMap header, BaseCookie[] cookie, String charset, int timeout) { client.getParams().setParameter(HttpMethodParams.HTTP_URI_CHARSET, charset); client.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET, charset); client.getHttpConnectionManager().getParams().setConnectionTimeout(timeout); client.getHttpConnectionManager().getParams().setSoTimeout(timeout); method.setFollowRedirects(false); method.setRequestHeader("User-Agent", BaseHttp.DEFAULT_USER_AGENT); method.setRequestHeader("Cache-Control", "no-cache"); method.setRequestHeader("Connection", "keep-alive"); if (cookie != null) { String cookieString = ""; for (BaseCookie ci : cookie) { try { cookieString += URLEncoder.encode(ci.getKey(), charset) + "=" + URLEncoder.encode(ci.getValue(), charset) + "; "; } catch (UnsupportedEncodingException e) { log.error(e.getMessage(), e); } } method.setRequestHeader("Cookie", cookieString); } else { method.getParams().setCookiePolicy(CookiePolicy.IGNORE_COOKIES); } if (header != null) { for (Entry h : header.entrySet()) { method.setRequestHeader(h.getKey(), h.getValue()); } } } /** * 获取http请求结果 * * @param method * @param charset * @return * @throws IOException */ private static String getResponse(HttpMethod method, String charset) { StringBuffer response = new StringBuffer(); try { BufferedReader reader = new BufferedReader(new InputStreamReader(method.getResponseBodyAsStream(), charset)); String line; while ((line = reader.readLine()) != null) { response.append(line); } reader.close(); } catch (IOException e) { log.error(e.getMessage(), e); } return response.toString(); } /** * 检查url是否为空 * * @param url * @throws HttpException */ private static void check(String url) throws HttpException { if (url == null || url.trim().equals("")) { throw new HttpException("url不能为空"); } } } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/common/queue/BaseQueue.java ================================================ package com.zhaidaosi.game.jgframework.common.queue; /** * 可快速定位的FIFO队列 */ public class BaseQueue { private BaseQueueElement start = null; private BaseQueueElement end = null; private final Object lock = new Object(); private long putCount = 0; private long takeCount = 0; private long size = 0; /** * 获取队列头 */ public BaseQueueElement getStart() { return start; } /** * 从队列尾插入元素 */ public BaseQueueElement put(E value) { if (value == null) { return null; } BaseQueueElement element = new BaseQueueElement(value); synchronized (lock) { if (start == null) { start = element; end = element; } else { element.setBefore(end); end.setNext(element); end = element; } putCount++; size++; element.setNo(putCount); } return element; } /** * 从队列头弹出元素 */ public BaseQueueElement take() { if (start == null) { return null; } BaseQueueElement element; synchronized (lock) { element = start; if (start == end) { start = null; end = null; putCount = 0; takeCount = 0; } else { start = start.getNext(); start.setBefore(null); takeCount++; } size--; element.reset(); } return element; } /** * 删除一个元素 */ public boolean remove(BaseQueueElement element) { BaseQueueElement after = null; synchronized (lock) { if (element == start && element == end) { start = null; end = null; putCount = 0; takeCount = 0; } else if (element == start) { start = start.getNext(); start.setBefore(null); takeCount++; } else if (element == end) { end = element.getBefore(); end.setNext(null); } else { // 判断是否在队列中 if (element.getBefore().getNext() != element || element.getNext().getBefore() != element) { return false; } after = element.getNext(); after.setBefore(element.getBefore()); element.getBefore().setNext(after); } size--; element.reset(); if (after != null) { do { after.setNo(after.getNo() - 1); after = after.getNext(); } while (after != null); } } return true; } /** * 查找元素所在的位置 */ public long findIndex(BaseQueueElement element) { if (element == null) { return -1; } synchronized (lock) { return element.getNo() - takeCount; } } /** * 返回队列长度 */ public long size() { synchronized (lock) { return size; } } /** * 删除队列所有元素 */ public void clear() { synchronized (lock) { while (start != null) { BaseQueueElement element = start; start = start.getNext(); element.reset(); element = null; } start = null; end = null; putCount = 0; takeCount = 0; size = 0; } } } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/common/queue/BaseQueueElement.java ================================================ package com.zhaidaosi.game.jgframework.common.queue; public class BaseQueueElement { private E value; private BaseQueueElement before; private BaseQueueElement next; private long No; public BaseQueueElement(E value) { this.value = value; } public void setValue(E value) { this.value = value; } public E getValue() { return value; } public BaseQueueElement getBefore() { return before; } public void setBefore(BaseQueueElement before) { this.before = before; } public BaseQueueElement getNext() { return next; } public void setNext(BaseQueueElement next) { this.next = next; } public void setNo(long No) { this.No = No; } public long getNo() { return No; } public void reset() { before = null; next = null; No = 0; } } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/common/sdm/BaseDao.java ================================================ package com.zhaidaosi.game.jgframework.common.sdm; import com.zhaidaosi.game.jgframework.Boot; import org.hibernate.LockMode; import org.hibernate.SQLQuery; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.transform.Transformers; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.orm.hibernate3.HibernateTemplate; import org.springframework.orm.hibernate3.support.HibernateDaoSupport; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; @SuppressWarnings({"rawtypes", "unchecked"}) public abstract class BaseDao extends HibernateDaoSupport implements IBaseDao { private static final Logger log = LoggerFactory .getLogger(BaseDao.class); protected String tableName = ""; protected String modelName = ""; protected String entityPackage = Boot.SDM_BASE_PACKAGE_NAME + ".model."; @Override public List find(String queryString) { return this.getQuery(queryString, null).list(); } @Override public List find(String queryString, Map data) { return this.getQuery(queryString, data).list(); } @Override public List find(String queryString, Map data, int start, int limit) { return this.getQuery(queryString, data, start, limit).list(); } @Override public int total() { return this.total(null, null); } @Override public int total(String queryString) { return this.total(queryString, null); } @Override public int total(Map where) { return this.total(null, where); } @Override public int total(String queryString, Map where) { if (queryString == null) { queryString = "select count(1) from " + this.tableName; if (where != null) { queryString += " where " + this.formateWhereSql(where, "and"); ; } } return ((Number) getQuery(queryString, where, false).uniqueResult()).intValue(); } @Override public int update(String queryString) { return this.execute(queryString); } @Override public int update(Map where) { String queryString = "update " + this.tableName + " set " + this.formateWhereSql(where, ","); return this.execute(queryString, where); } @Override public int delete(String queryString) { return this.execute(queryString); } @Override public int delete(String queryString, Map where) { return this.execute(queryString, where); } @Override public int execute(String queryString) { return this.execute(queryString, null); } @Override public int execute(String queryString, Map where) { int result = this.getQuery(queryString, where, false).executeUpdate(); return result; } @Override public List findByProperty(String propertyName, Object value) { log.debug("finding Object instance with property: " + propertyName + ", value: " + value); try { String queryString = "from " + this.modelName + " as model where model." + propertyName + "= ?"; return getHibernateTemplate().find(queryString, value); } catch (RuntimeException re) { log.error("find by property name failed", re); throw re; } } @Override public IBaseModel findOneByProperty(String propertyName, Object value) { log.debug("finding Object instance with property: " + propertyName + ", value: " + value); try { String queryString = "from " + this.modelName + " as model where model." + propertyName + "= ?"; return (IBaseModel) getHibernateTemplate().find(queryString, value).get(0); } catch (RuntimeException re) { log.error("find by property name failed", re); throw re; } } @Override public IBaseModel findById(int id) { log.debug("getting Object instance with id: " + id); try { IBaseModel instance = (IBaseModel) getHibernateTemplate().get( this.entityPackage + this.modelName, id); return instance; } catch (RuntimeException re) { log.error("get failed", re); throw re; } } @Override public void update(IBaseModel persistentInstance) { log.debug("update Object instance"); try { getHibernateTemplate().update(persistentInstance); log.debug("update successful"); } catch (RuntimeException re) { log.error("update failed", re); throw re; } } @Override public void save(IBaseModel transientInstance) { log.debug("saving CronModel instance"); try { getHibernateTemplate().save(transientInstance); log.debug("save successful"); } catch (RuntimeException re) { log.error("save failed", re); throw re; } } @Override public void delete(IBaseModel persistentInstance) { log.debug("deleting Object instance"); try { getHibernateTemplate().delete(persistentInstance); log.debug("delete successful"); } catch (RuntimeException re) { log.error("delete failed", re); throw re; } } @Override public List findAll() { log.debug("finding all Object instances"); try { String queryString = "from " + this.modelName; return getHibernateTemplate().find(queryString); } catch (RuntimeException re) { log.error("find all failed", re); throw re; } } @Override public List findAll(int start, int limit) { log.debug("finding all Object instances"); try { HibernateTemplate ht = getHibernateTemplate(); int PRE_MAX_RESULT = ht.getMaxResults(); int PRE_LIMIT = ht.getFetchSize(); ht.setMaxResults(limit); ht.setFetchSize(start); String queryString = "from " + this.modelName; List list = ht.find(queryString); ht.setMaxResults(PRE_MAX_RESULT); ht.setFetchSize(PRE_LIMIT); return list; } catch (RuntimeException re) { log.error("find all failed", re); throw re; } } @Override public IBaseModel merge(IBaseModel detachedInstance) { log.debug("merging BaseModel instance"); try { IBaseModel result = (IBaseModel) getSession().merge(detachedInstance); log.debug("merge successful"); return result; } catch (RuntimeException re) { log.error("merge failed", re); throw re; } } @Override public void saveOrUpdate(IBaseModel instance) { log.debug("attaching dirty BaseModel instance"); try { getSession().saveOrUpdate(instance); log.debug("attach successful"); } catch (RuntimeException re) { log.error("attach failed", re); throw re; } } @Override public void attachClean(IBaseModel instance) { log.debug("attaching clean Article instance"); try { getSession().lock(instance, LockMode.NONE); log.debug("attach successful"); } catch (RuntimeException re) { log.error("attach failed", re); throw re; } } protected SQLQuery getQuery(String queryString, Map where) { return this.getQuery(queryString, where, true); } protected SQLQuery getQuery(String queryString, Map where, boolean returnMap) { return this.getQuery(queryString, where, -1, -1, returnMap); } protected SQLQuery getQuery(String queryString, Map where, int start, int limit) { return this.getQuery(queryString, where, start, limit, true); } protected String formateWhereSql(Map where, String middleString) { String queryString = ""; Iterator iterator = where.keySet().iterator(); boolean hasNext = iterator.hasNext(); while (hasNext) { String key = iterator.next(); queryString += key + " = :" + key; hasNext = iterator.hasNext(); if (hasNext) { queryString += " " + middleString + " "; } } return queryString; } protected SQLQuery getQuery(String queryString, Map where, int start, int limit, boolean returnMap) { Session session = this.getSession(); SQLQuery query = null; if (start > -1 && limit > 0) { query = session.createSQLQuery(queryString); query.setFirstResult(start); query.setMaxResults(limit); } else { query = session.createSQLQuery(queryString); } if (where != null) { for (Entry entry : where.entrySet()) { Object value = entry.getValue(); String key = entry.getKey(); if (value instanceof Collection) { query.setParameterList(key, (Collection) value); } else if (value instanceof Object[]) { query.setParameterList(key, (Object[]) value); } else { query.setParameter(key, value); } } } if (returnMap) { query.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP); } return query; } @Autowired public void setSessionFactoryOverride(SessionFactory sessionFactory) { super.setSessionFactory(sessionFactory); } public String getTableName() { return tableName; } public void setTableName(String tableName) { this.tableName = tableName; } public String getModelName() { return modelName; } public void setModelName(String modelName) { this.modelName = modelName; } } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/common/sdm/BaseModel.java ================================================ package com.zhaidaosi.game.jgframework.common.sdm; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.lang.reflect.Field; @SuppressWarnings("serial") public abstract class BaseModel implements IBaseModel, Cloneable, java.io.Serializable { protected static final Logger log = LoggerFactory.getLogger(BaseModel.class); public String toString() { Field[] fields = this.getClass().getDeclaredFields(); StringBuffer strBuf = new StringBuffer(); strBuf.append(this.getClass().getName()); strBuf.append(" { "); for (int i = 0; i < fields.length; i++) { Field fd = fields[i]; fd.setAccessible(true); strBuf.append("[" + fd.getName() + ": "); try { strBuf.append(fd.get(this) + "]"); } catch (IllegalArgumentException | IllegalAccessException e) { // e.printStackTrace(); } if (i != fields.length - 1) strBuf.append(", "); } strBuf.append(" }"); return strBuf.toString(); } public IBaseModel clone() { IBaseModel o = null; try { o = (IBaseModel) super.clone(); } catch (CloneNotSupportedException e) { log.error(e.getMessage(), e); } return o; } } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/common/sdm/BaseService.java ================================================ package com.zhaidaosi.game.jgframework.common.sdm; import java.util.List; public abstract class BaseService { protected IBaseDao dao; protected abstract void setDao(); public IBaseModel findById(int id) { return dao.findById(id); } public List findAll(int start, int limit) { return dao.findAll(start, limit); } public List findByProperty(String propertyName, Object value) { return dao.findByProperty(propertyName, value); } public IBaseModel findOneByProperty(String propertyName, Object value) { return dao.findOneByProperty(propertyName, value); } public int total() { return dao.total(); } public void save(IBaseModel obj) { dao.save(obj); } public void update(IBaseModel obj) { dao.update(obj); } public List findAll() { return dao.findAll(); } public void delete(IBaseModel obj) { dao.delete(obj); } public String getDatabase() { return null; } protected void setDao(IBaseDao dao) { this.dao = dao; } } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/common/sdm/IBaseDao.java ================================================ package com.zhaidaosi.game.jgframework.common.sdm; import java.util.List; import java.util.Map; public interface IBaseDao { public List find(String queryString); public List find(String queryString, Map data); public List find(String queryString, Map data, int start, int limit); public int total(); public int total(String queryString); public int total(Map where); public int total(String queryString, Map where); public int update(String queryString); public int update(Map where); public int delete(String queryString); public int delete(String queryString, Map where); public int execute(String queryString); public int execute(String queryString, Map where); public List findByProperty(String propertyName, Object value); public IBaseModel findOneByProperty(String propertyName, Object value); public IBaseModel findById(int id); public void update(IBaseModel persistentInstance); public void save(IBaseModel transientInstance); public void delete(IBaseModel persistentInstance); public List findAll(); public List findAll(int start, int limit); public IBaseModel merge(IBaseModel detachedInstance); public void saveOrUpdate(IBaseModel instance); public void attachClean(IBaseModel instance); } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/common/sdm/IBaseModel.java ================================================ package com.zhaidaosi.game.jgframework.common.sdm; public interface IBaseModel { public String toString(); public IBaseModel clone(); } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/common/spring/AnnotationSessionFactoryBeanEx.java ================================================ package com.zhaidaosi.game.jgframework.common.spring; import org.hibernate.HibernateException; import org.hibernate.cfg.AnnotationConfiguration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.io.Resource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternResolver; import org.springframework.core.type.classreading.CachingMetadataReaderFactory; import org.springframework.core.type.classreading.MetadataReader; import org.springframework.core.type.classreading.MetadataReaderFactory; import org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean; import org.springframework.util.CollectionUtils; import javax.persistence.Entity; import java.io.IOException; import java.util.HashSet; import java.util.Set; /** * 该类扩展了Spring的AnnotationSessionFactoryBean类,增加了对AnnotatedClass的批量导入功能。 * 通过使用setAnnotatedClassesLocations(String[])方法(其中的参数,是导入文件的路径数组), * 添加所有需要导入的AnnotatedClass,支持Spring的ResourceLoader对资源的加载方式。 * 通过使用setExcludedClasses(String[])方法(其中参数,是待去除的类的全路径名), * 来去除在上述包路径中不需要导入的AnnotatedClass。 */ public class AnnotationSessionFactoryBeanEx extends AnnotationSessionFactoryBean { private static final Logger logger = LoggerFactory .getLogger(AnnotationSessionFactoryBeanEx.class); /** * The locations of the hibernate enity class files. They are often some of * the string with Sping-style resource. A ".class" subfix can make the * scaning more precise. * example: * classpath*:com/systop/** /model/*.class */ private String[] annotatedClassesLocations; /** * Which classes are not included in the session. They are some of the * regular expression. */ private Set excludedClasseses = new HashSet(0); /** * @param annotatedClassesLocations * the annotatedClassesLocations to set */ public void setAnnotatedClassesLocations(String[] annotatedClassesLocations) { this.annotatedClassesLocations = annotatedClassesLocations; } /** * @see AnnotationSessionFactoryBean#postProcessAnnotationConfiguration(org.hibernate.cfg.AnnotationConfiguration) */ @Override protected void postProcessAnnotationConfiguration( AnnotationConfiguration config) throws HibernateException { Set> annClasses = scanAnnotatedClasses(); // Scan enity // classes. // Add entity classes to the configuration. if (!CollectionUtils.isEmpty(annClasses)) { for (Class annClass : annClasses) { config.addAnnotatedClass(annClass); } } } /** * Scan annotated hibernate classes in the locations. * * @return Set of the annotated classes, if no matched class, return empty * Set. */ private Set> scanAnnotatedClasses() { ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(); MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory( resourcePatternResolver); Set> annotatedClasses = new HashSet>(); if (annotatedClassesLocations != null) { try { for (String annClassesLocation : annotatedClassesLocations) { // Resolve the resources Resource[] resources = resourcePatternResolver .getResources(annClassesLocation); for (Resource resource : resources) { MetadataReader metadataReader = metadataReaderFactory .getMetadataReader(resource); String className = metadataReader.getClassMetadata() .getClassName(); // If the class is hibernate enity class, and it does // not match the excluded class patterns. if (isEntityClass(metadataReader) && !isExcludedClass(className)) { Class clazz = Class.forName(className); annotatedClasses.add(clazz); logger.debug("A entity class has been found. ({})", clazz.getName()); } } } } catch (IOException e) { logger.error("I/O failure during classpath scanning, ({})", e .getMessage()); throw new HibernateException(e); } catch (ClassNotFoundException e) { logger.error("Class not found, ({})", e.getMessage()); throw new HibernateException(e); } catch (LinkageError e) { logger.error("LinkageError ({})", e.getMessage()); throw new HibernateException(e); } } return annotatedClasses; } /** * @return True if the given MetadataReader shows that the class is * annotated by javax.persistence.Enity */ private boolean isEntityClass(MetadataReader metadataReader) { Set annTypes = metadataReader.getAnnotationMetadata() .getAnnotationTypes(); if (CollectionUtils.isEmpty(annTypes)) { return false; } return annTypes.contains(Entity.class.getName()); } /** * * @return True if the given class name match the excluded class patterns. */ private boolean isExcludedClass(String className) { return excludedClasseses.contains(className); } /** * @param exculdePatterns * the exculdePatterns to set */ public void setExcludedClasses(String[] excludedClasses) { for (String cls : excludedClasses) { this.excludedClasseses.add(cls); } } } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/common/spring/DataSourceAdvice.java ================================================ package com.zhaidaosi.game.jgframework.common.spring; import com.zhaidaosi.game.jgframework.common.BaseRunTimer; import com.zhaidaosi.game.jgframework.common.sdm.BaseService; import org.springframework.aop.AfterReturningAdvice; import org.springframework.aop.MethodBeforeAdvice; import org.springframework.aop.ThrowsAdvice; import java.lang.reflect.Method; public class DataSourceAdvice implements MethodBeforeAdvice, AfterReturningAdvice, ThrowsAdvice { private long startTime; public void before(Method method, Object[] args, Object target) { if (BaseRunTimer.isActive()) { startTime = System.currentTimeMillis(); } String database = null; if (target instanceof BaseService) { database = ((BaseService) target).getDatabase(); } if (method.getName().startsWith("save") || method.getName().startsWith("add") || method.getName().startsWith("update") || method.getName().startsWith("delete")) { DataSourceSwitcher.setMaster(database); } else { DataSourceSwitcher.setSlave(database); } } public void afterReturning(Object arg0, Method method, Object[] args, Object target) { DataSourceSwitcher.clearDataSource(); this.setRunTime(method, target); } public void afterThrowing(Method method, Object[] args, Object target, Exception ex) { DataSourceSwitcher.clearDataSource(); this.setRunTime(method, target); } private void setRunTime(Method method, Object target) { if (BaseRunTimer.isActive()) { long runningTime = System.currentTimeMillis() - startTime; BaseRunTimer.addTimer(target.getClass().getName() + "." + method.getName() + " run " + runningTime + " ms"); } } } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/common/spring/DataSourceSwitcher.java ================================================ package com.zhaidaosi.game.jgframework.common.spring; import org.springframework.util.Assert; public class DataSourceSwitcher { private static ThreadLocal contextHolder = new ThreadLocal(); private static String defaultDatabase; public static void setDataSource(String dataSource) { Assert.notNull(dataSource, "dataSource cannot be null"); contextHolder.set(dataSource); } public static void setMaster(String database) { if (database == null) { database = defaultDatabase; } setDataSource(database + "-master"); } public static void setSlave(String database) { if (database == null) { database = defaultDatabase; } setDataSource(database + "-slave"); } public static String getDataSource() { return (String) contextHolder.get(); } public static void clearDataSource() { contextHolder.remove(); } public static void setDefaultDatabase(String database) { defaultDatabase = database; } } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/common/spring/DynamicDataSource.java ================================================ package com.zhaidaosi.game.jgframework.common.spring; import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; public class DynamicDataSource extends AbstractRoutingDataSource { private String defaultDatabase; @Override protected Object determineCurrentLookupKey() { return DataSourceSwitcher.getDataSource(); } public void setDefaultDatabase(String defaultDatabase) { this.defaultDatabase = defaultDatabase; DataSourceSwitcher.setDefaultDatabase(this.defaultDatabase); } } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/common/spring/ServiceManager.java ================================================ package com.zhaidaosi.game.jgframework.common.spring; import org.springframework.context.support.ClassPathXmlApplicationContext; public class ServiceManager { private static ClassPathXmlApplicationContext context = null; public static void init() { context = new ClassPathXmlApplicationContext("applicationContext.xml"); } public static Object getService(String id) { return context.getBean(id); } } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/connector/AuthConnector.java ================================================ package com.zhaidaosi.game.jgframework.connector; import com.zhaidaosi.game.jgframework.Boot; import com.zhaidaosi.game.jgframework.Router; import com.zhaidaosi.game.jgframework.common.BaseRunTimer; import com.zhaidaosi.game.jgframework.message.IBaseMessage; import com.zhaidaosi.game.jgframework.message.InMessage; import com.zhaidaosi.game.jgframework.message.OutMessage; import io.netty.bootstrap.ServerBootstrap; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.*; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.handler.codec.http.*; import io.netty.handler.codec.http.cors.CorsConfig; import io.netty.handler.codec.http.cors.CorsHandler; import io.netty.handler.stream.ChunkedWriteHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.net.InetSocketAddress; import java.util.List; import java.util.Map; import java.util.Map.Entry; import static io.netty.handler.codec.http.HttpHeaders.Names.CONTENT_LENGTH; import static io.netty.handler.codec.http.HttpHeaders.Names.CONTENT_TYPE; import static io.netty.handler.codec.http.HttpMethod.POST; import static io.netty.handler.codec.http.HttpResponseStatus.FORBIDDEN; import static io.netty.handler.codec.http.HttpResponseStatus.OK; import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1; public class AuthConnector implements IBaseConnector { private static final Logger log = LoggerFactory.getLogger(AuthConnector.class); private final InetSocketAddress localAddress; private ServerBootstrap bootstrap; private NioEventLoopGroup bossGroup; private NioEventLoopGroup workerGroup; private String charset = Boot.getCharset().name(); private boolean isPause = false; public AuthConnector(int port) { this.localAddress = new InetSocketAddress(port); } @Override public void start() { if (bootstrap != null) { return; } bootstrap = new ServerBootstrap(); bossGroup = new NioEventLoopGroup(1); if (Boot.getAuthThreadCount() > 0) { workerGroup = new NioEventLoopGroup(Boot.getAuthThreadCount()); } else { workerGroup = new NioEventLoopGroup(); } try { bootstrap.group(bossGroup, workerGroup) .option(ChannelOption.SO_BACKLOG, 1024) .channel(NioServerSocketChannel.class) .childOption(ChannelOption.TCP_NODELAY, true) .childOption(ChannelOption.SO_REUSEADDR, true) .childHandler(new HttpServerInitializer()) .bind(localAddress); log.info("Auth Service is running! port : " + localAddress.getPort()); } catch (Exception e) { log.error(e.getMessage()); } } void pause() { isPause = true; } void resume() { isPause = false; } @Override public void stop() { if (bootstrap == null) { return; } workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } private class HttpServerInitializer extends ChannelInitializer { @Override public void initChannel(SocketChannel ch) { CorsConfig corsConfig = CorsConfig.withAnyOrigin().build(); ChannelPipeline p = ch.pipeline(); p.addLast(new HttpResponseEncoder()); p.addLast(new HttpRequestDecoder()); p.addLast(new HttpObjectAggregator(65536)); p.addLast(new ChunkedWriteHandler()); p.addLast(new CorsHandler(corsConfig)); p.addLast(new HttpHandler()); } } private class HttpHandler extends ChannelInboundHandlerAdapter { private InMessage inMsg; @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { if (isPause) { sendHttpResponse(ctx, OutMessage.showError("系统已关闭", 11000).toString(), true); } } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable t) throws Exception { String error = t.getMessage(); log.error(error, t); sendHttpResponse(ctx, OutMessage.showError("系统错误:" + error, 10000).toString(), true); ctx.close(); } @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { BaseRunTimer.showTimer(); } @Override public void channelReadComplete(ChannelHandlerContext ctx) { ctx.flush(); } @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { if (msg instanceof HttpRequest) { HttpRequest request = (HttpRequest) msg; if (request.getMethod() != POST) { sendErrorHttpResponse(ctx, new DefaultFullHttpResponse(HTTP_1_1, FORBIDDEN)); return; } inMsg = new InMessage(Boot.getAuthHandler() + request.getUri().substring(1).replace("/", "\\.").toLowerCase()); } long startTime = 0; if (BaseRunTimer.isActive()) { startTime = System.currentTimeMillis(); } if (msg instanceof HttpContent) { HttpContent httpContent = (HttpContent) msg; ByteBuf content = httpContent.content(); String post = content.toString(Boot.getCharset()); content.release(); QueryStringDecoder queryStringDecoder = new QueryStringDecoder(post, Boot.getCharset(), false); Map> params = queryStringDecoder.parameters(); if (!params.isEmpty()) { for (Entry> p : params.entrySet()) { String key = p.getKey(); List vals = p.getValue(); inMsg.putMember(key, vals.get(0)); } } IBaseMessage rs = Router.run(inMsg, ctx.channel()); if (BaseRunTimer.isActive()) { long runningTime = System.currentTimeMillis() - startTime; BaseRunTimer.addTimer("AuthConnector messageReceived run " + runningTime + " ms"); } if (rs == null) { sendErrorHttpResponse(ctx, new DefaultFullHttpResponse(HTTP_1_1, FORBIDDEN)); } else { sendHttpResponse(ctx, rs.toString(), true); } } } private void sendHttpResponse(ChannelHandlerContext ctx, String res, boolean isJson) { FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, OK, Unpooled.wrappedBuffer(res.getBytes())); response.headers().set(CONTENT_LENGTH, response.content().readableBytes()); // response.headers().set(ACCESS_CONTROL_ALLOW_ORIGIN, "*"); if (isJson) { response.headers().set(CONTENT_TYPE, "application/json; charset=" + charset); } else { response.headers().set(CONTENT_TYPE, "text/html; charset=" + charset); } ctx.channel().write(response).addListener(ChannelFutureListener.CLOSE); } private void sendErrorHttpResponse(ChannelHandlerContext ctx, DefaultFullHttpResponse response) { response.headers().set(CONTENT_LENGTH, response.content().readableBytes()); ctx.channel().write(response).addListener(ChannelFutureListener.CLOSE); } } } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/connector/IBaseConnector.java ================================================ package com.zhaidaosi.game.jgframework.connector; import com.zhaidaosi.game.jgframework.model.entity.IBaseCharacter; import io.netty.util.AttributeKey; public interface IBaseConnector { AttributeKey PLAYER = AttributeKey.valueOf("player"); void start(); void stop(); } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/connector/ManagerConnector.java ================================================ package com.zhaidaosi.game.jgframework.connector; import com.zhaidaosi.game.jgframework.Boot; import com.zhaidaosi.game.jgframework.common.BaseDate; import com.zhaidaosi.game.jgframework.common.BaseIp; import com.zhaidaosi.game.jgframework.message.OutMessage; import com.zhaidaosi.game.jgframework.session.SessionManager; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.*; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.handler.codec.DelimiterBasedFrameDecoder; import io.netty.handler.codec.Delimiters; import io.netty.handler.codec.string.StringDecoder; import io.netty.handler.codec.string.StringEncoder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.lang.management.ManagementFactory; import java.lang.management.RuntimeMXBean; import java.net.InetSocketAddress; import java.util.ArrayList; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public class ManagerConnector implements IBaseConnector { private static final Logger log = LoggerFactory.getLogger(ManagerConnector.class); private final InetSocketAddress localAddress; private ServerBootstrap bootstrap; private NioEventLoopGroup bossGroup; private NioEventLoopGroup workerGroup; public ManagerConnector(int port) { this.localAddress = new InetSocketAddress(port); } @Override public void start() { if (bootstrap != null) { return; } bootstrap = new ServerBootstrap(); bossGroup = new NioEventLoopGroup(1); workerGroup = new NioEventLoopGroup(1); try{ bootstrap.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .childHandler(new TelnetServerInitializer()) .bind(localAddress); log.info("Manager Service is running! port : " + localAddress.getPort()); } catch (Exception e) { log.error(e.getMessage()); } } @Override public void stop() { if (bootstrap == null) { return; } workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); bootstrap = null; } class TelnetServerInitializer extends ChannelInitializer { @Override public void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter())); pipeline.addLast(new StringDecoder()); pipeline.addLast(new StringEncoder()); pipeline.addLast(new ManagerHandler()); } } class ManagerHandler extends ChannelInboundHandlerAdapter { private final String nextLine = "\r\n"; private boolean close = false; @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable t) throws Exception { log.error(t.getMessage(), t); } @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { Channel ch = ctx.channel(); String ip = ch.remoteAddress().toString(); String[] ipArr = ip.split(":"); String realIp = ipArr[0].substring(ipArr[0].indexOf("/") + 1); if (!ManagerService.checkIp(realIp)) { ch.close(); } else { ch.write("Please input user name:" + nextLine); ch.flush(); ManagerService.goNextSetp(ch.hashCode()); log.info("ManagerConnector connected " + ip); } } @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { Channel ch = ctx.channel(); ManagerService.clear(ch.hashCode()); log.info("ManagerConnector closed " + ch.remoteAddress()); } @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { Channel ch = ctx.channel(); String request = msg.toString().toLowerCase(); String response = "Please i something."; if (request.length() > 0) { Integer cid = ch.hashCode(); Integer step = ManagerService.getStep(cid); if (step == 1 || step == 2) { response = login(request, step, cid); } else { response = handler(request); } } ChannelFuture future = ch.write(response + nextLine); if (close) { future.addListener(ChannelFutureListener.CLOSE); } } private String handler(String request) { String response; String[] requestArr = request.split(" "); AuthConnector authConnector = Boot.getAuthConnector(); ServiceConnector serviceConnector = Boot.getServiceConnector(); switch (requestArr[0]) { case "exit": case "quit": response = "Have a good day!"; close = true; break; case "help": response = "#### status : system status" + nextLine; response += "#### start : start all service" + nextLine; response += "#### stop : stop all service" + nextLine; response += "#### start-service : start service" + nextLine; response += "#### stop-service : stop service" + nextLine; response += "#### start-auth : start auth" + nextLine; response += "#### stop-auth : stop auth" + nextLine; response += "#### pause-auth : pause auth" + nextLine; response += "#### resume-auth : resume auth" + nextLine; response += "#### msg : send msg to all users" + nextLine; response += "#### exit/quit : exit"; break; case "status": ServiceConnector c = Boot.getServiceConnector(); long startTime = c.getStartTime(); response = nextLine + "#### pid : " + ManagerService.getPid() + nextLine; response += "#### start_time : " + BaseDate.time2String(BaseDate.FORMAT_YY_MM_DD_HH_MM_SS, startTime) + nextLine; response += "#### running time : " + (System.currentTimeMillis() - startTime) / 1000 + "s" + nextLine; response += "#### socket_connect : " + c.getConnectCount() + nextLine; response += "#### socket_wait : " + SessionManager.getWaitCount() + nextLine; response += "#### login_user_count : " + SessionManager.getUserCount() + nextLine; break; case "start": serviceConnector.start(); if (authConnector != null) { authConnector.start(); } response = "start is ok"; break; case "stop": serviceConnector.stop(); if (authConnector != null) { authConnector.stop(); } response = "stop is ok"; break; case "start-service": serviceConnector.start(); response = "start service is ok"; break; case "stop-service": serviceConnector.stop(); response = "stop service is ok"; break; case "start-auth": if (authConnector != null) { authConnector.start(); } response = "start auth is ok"; break; case "stop-auth": if (authConnector != null) { authConnector.stop(); } response = "stop auth is ok"; break; case "pause-auth": if (authConnector != null) { authConnector.pause(); } response = "pause auth is ok"; break; case "resume-auth": if (authConnector != null) { authConnector.resume(); } response = "resume auth is ok"; break; case "msg": if (requestArr.length < 2) { response = "Please input msg."; } else { String msg = ""; for (int i = 1; i < requestArr.length; i++) { msg += requestArr[i] + " "; } msg = msg.trim(); response = sendMsg(msg); } break; default: response = "ERROR"; break; } return response; } @Override public void channelReadComplete(ChannelHandlerContext ctx) { ctx.flush(); } private String sendMsg(String msg) { Map channels = SessionManager.getChannels(); for (Map.Entry entry : channels.entrySet()) { Channel ch = entry.getValue(); if (ch.isWritable()) { ch.write(OutMessage.showSucc(msg)); } } return "OK"; } private String login(String request, Integer step, Integer cid) { String response; if (step == 1) { String user = Boot.getManagerUser(); if (!request.equals(user)) { response = "User name is error, please input again!"; } else { ManagerService.goNextSetp(cid); response = "Please input password:"; } } else { String password = Boot.getManagerPassword(); if (!request.equals(password)) { response = "Password is error, please input again!"; } else { ManagerService.goNextSetp(cid); response = "Login success!" + nextLine; } } return response; } } static class ManagerService { private static ConcurrentHashMap authStep = new ConcurrentHashMap<>(); private static int pId = 0; static boolean checkIp(String ip) { ArrayList ipList = Boot.getManagerAllowIps(); for (Long[] longs : ipList) { if (BaseIp.checkIp(ip, longs)) { return true; } } return false; } static Integer getStep(Integer cid) { Integer setp = authStep.get(cid); if (setp == null) { setp = 1; authStep.put(cid, 1); } return setp; } static void goNextSetp(Integer cid) { Integer step = authStep.get(cid); if (step == null) { authStep.put(cid, 1); } else { authStep.put(cid, ++step); } } static void clear(Integer cid) { authStep.remove(cid); } static int getPid() { if (pId == 0) { RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean(); String name = runtime.getName(); try { pId = Integer.parseInt(name.substring(0, name.indexOf('@'))); } catch (Exception e) { pId = -1; } } return pId; } } } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/connector/ServiceConnector.java ================================================ package com.zhaidaosi.game.jgframework.connector; import com.zhaidaosi.game.jgframework.Boot; import com.zhaidaosi.game.jgframework.Router; import com.zhaidaosi.game.jgframework.common.BaseRunTimer; import com.zhaidaosi.game.jgframework.common.excption.MessageException; import com.zhaidaosi.game.jgframework.message.*; import com.zhaidaosi.game.jgframework.model.entity.IBaseCharacter; import com.zhaidaosi.game.jgframework.rsync.RsyncManager; import com.zhaidaosi.game.jgframework.session.SessionManager; import io.netty.bootstrap.ServerBootstrap; import io.netty.buffer.ByteBuf; import io.netty.buffer.PooledByteBufAllocator; import io.netty.buffer.Unpooled; import io.netty.channel.*; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.handler.codec.http.*; import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.FullHttpResponse; import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.websocketx.*; import io.netty.handler.codec.string.StringDecoder; import io.netty.handler.codec.string.StringEncoder; import io.netty.handler.timeout.IdleState; import io.netty.handler.timeout.IdleStateEvent; import io.netty.handler.timeout.IdleStateHandler; import io.netty.handler.timeout.ReadTimeoutException; import static io.netty.handler.codec.http.HttpHeaders.Names.*; import static io.netty.handler.codec.http.HttpMethod.*; import static io.netty.handler.codec.http.HttpResponseStatus.*; import static io.netty.handler.codec.http.HttpVersion.*; import io.netty.util.CharsetUtil; import io.netty.util.ReferenceCountUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.net.InetSocketAddress; import java.nio.channels.ClosedChannelException; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.TimeUnit; public class ServiceConnector implements IBaseConnector { private static final Logger log = LoggerFactory.getLogger(ServiceConnector.class); private final InetSocketAddress localAddress; private NioEventLoopGroup bossGroup; private NioEventLoopGroup workerGroup; private ServerBootstrap bootstrap; private Timer timer; private final long period; private final String mode; private final Object lock = new Object(); private int connectCount = 0; private long startTime; public static final String MODE_SOCKET = "socket"; public static final String MODE_WEB_SOCKET = "websocket"; public static final String WEB_SOCKET_PATH = "/websocket"; private int heartbeatTime = Boot.getServiceHeartbeatTime(); long getStartTime() { return startTime; } public int getConnectCount() { return connectCount; } public ServiceConnector(int port, long period, String mode) { this.localAddress = new InetSocketAddress(port); this.period = period; this.mode = mode; } public void start() { if (bootstrap != null) { return; } bootstrap = new ServerBootstrap(); bossGroup = new NioEventLoopGroup(1); if (Boot.getServiceThreadCount() > 0) { workerGroup = new NioEventLoopGroup(Boot.getServiceThreadCount()); } else { workerGroup = new NioEventLoopGroup(); } try { bootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class); switch (mode) { case MODE_SOCKET: bootstrap.childHandler(new SocketServerInitializer()); break; case MODE_WEB_SOCKET: bootstrap.childHandler(new WebSocketServerInitializer()); break; default: log.error("Service 运行模式设置错误,必须为" + MODE_SOCKET + "或" + MODE_WEB_SOCKET); return; } SessionManager.init(); RsyncManager.init(); timer = new Timer("SyncManagerTimer"); timer.schedule(new MyTimerTask(), period, period); startTime = System.currentTimeMillis(); bootstrap.option(ChannelOption.TCP_NODELAY, true) .option(ChannelOption.RCVBUF_ALLOCATOR, AdaptiveRecvByteBufAllocator.DEFAULT) .option(ChannelOption.SO_RCVBUF, 128 * 1024) .option(ChannelOption.SO_SNDBUF, 128 * 1024) .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT) .bind(localAddress); log.info("Connect Service is running! port : " + localAddress.getPort()); } catch (Exception e) { log.error(e.getMessage()); } } @Override public void stop() { if (bootstrap == null) { return; } workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); bootstrap = null; timer.cancel(); timer = null; SessionManager.destroy(); RsyncManager.run(); } private class SocketServerInitializer extends ChannelInitializer { @Override public void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); if (!Boot.getDebug()) { pipeline.addLast(new IdleStateHandler(heartbeatTime * 2, 0, heartbeatTime, TimeUnit.SECONDS)); } pipeline.addLast(new StringEncoder(Boot.getCharset())); pipeline.addLast(new StringDecoder(Boot.getCharset())); pipeline.addLast(new MessageEncode()); pipeline.addLast(new MessageDecode()); pipeline.addLast(new ServiceChannelHandler()); } } private class WebSocketServerInitializer extends ChannelInitializer { @Override public void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); if (!Boot.getDebug()) { pipeline.addLast(new IdleStateHandler(heartbeatTime * 2, 0, heartbeatTime, TimeUnit.SECONDS)); } pipeline.addLast( new HttpResponseEncoder(), new HttpRequestDecoder(), new HttpObjectAggregator(65536), new WebSocketEncode(), new ServiceChannelHandler() ); } } private class MyTimerTask extends TimerTask { @Override public void run() { log.info("start sync ..."); RsyncManager.run(); } } private class ServiceChannelHandler extends ChannelInboundHandlerAdapter { private WebSocketServerHandshaker handshake; private IBaseCharacter player; @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable t) throws Exception { String errorMsg = t.getMessage(); if (!(t instanceof ClosedChannelException)) { Channel ch = ctx.channel(); if (t instanceof MessageException) { log.error(errorMsg); } else if (t instanceof ReadTimeoutException) { log.error("强制关闭超时连接 => " + ch.remoteAddress()); } else { log.error(errorMsg, t); } ch.close(); } } @Override public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { /*心跳处理*/ if (evt instanceof IdleStateEvent) { IdleStateEvent event = (IdleStateEvent) evt; if (event.state() == IdleState.READER_IDLE) { log.debug("close read time out connect => " + ctx.channel().remoteAddress()); ctx.disconnect(); } else if (event.state() == IdleState.WRITER_IDLE) { log.debug("close write time out connect => " + ctx.channel().remoteAddress()); } else if (event.state() == IdleState.ALL_IDLE) { ctx.writeAndFlush(new PingWebSocketFrame()); } } } @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { synchronized (lock) { connectCount++; } player = Boot.getPlayerFactory().getPlayer(); player.sChannel(ctx.channel()); ctx.channel().attr(IBaseConnector.PLAYER).set(player); } @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { SessionManager.removeSession(ctx.channel()); synchronized (lock) { connectCount--; } BaseRunTimer.showTimer(); } @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { long startTime = 0; if (BaseRunTimer.isActive()) { startTime = System.currentTimeMillis(); } try { if (msg instanceof FullHttpRequest) { handleHttpRequest(ctx, (FullHttpRequest) msg); } else { handleWebSocketRequest(ctx, msg); } } finally { ReferenceCountUtil.release(msg); } if (BaseRunTimer.isActive()) { long runningTime = System.currentTimeMillis() - startTime; BaseRunTimer.addTimer("ServiceConnector messageReceived run " + runningTime + " ms"); BaseRunTimer.showTimer(); } } @Override public void channelReadComplete(ChannelHandlerContext ctx) { ctx.flush(); } private void handleWebSocketRequest(ChannelHandlerContext ctx, Object msg) throws Exception { InMessage inMsg = null; IBaseMessage rs = null; Channel ch = ctx.channel(); if (msg instanceof WebSocketFrame) { if (msg instanceof CloseWebSocketFrame) { handshake.close(ctx.channel(), ((CloseWebSocketFrame) msg).retain()); return; } if (msg instanceof PingWebSocketFrame) { ctx.write(new PongWebSocketFrame(((PingWebSocketFrame) msg).content().retain())); return; } if (msg instanceof PongWebSocketFrame) { return; } if (!(msg instanceof TextWebSocketFrame)) { throw new UnsupportedOperationException(String.format("%s msg types not supported", msg.getClass().getName())); } inMsg = InMessage.getMessage(((TextWebSocketFrame) msg).text()); } else if (msg instanceof IBaseMessage) { inMsg = (InMessage) msg; } boolean error = true; if (!SessionManager.isAuthHandler(inMsg)) { int result = SessionManager.checkSession(inMsg, ch); if (result != SessionManager.ADD_SESSION_ERROR) { error = false; if (result == SessionManager.ADD_SESSION_SUCC) { rs = Router.run(inMsg, ch); } else { rs = SessionManager.getWaitMessage(player); } } } if (error) { log.error("强制关闭没授权的连接 => " + ch.remoteAddress()); ch.close(); } else if (rs != null && ch.isWritable()) { ch.write(rs); } } private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req) throws Exception { // Handle a bad request. if (!req.getDecoderResult().isSuccess()) { sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, BAD_REQUEST)); return; } if (req.getMethod() != GET) { sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, FORBIDDEN)); return; } if (!WEB_SOCKET_PATH.equals(req.getUri())) { sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, FORBIDDEN)); return; } // Handshake WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory( getWebSocketLocation(req), null, true); handshake = wsFactory.newHandshaker(req); if (handshake == null) { WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel()); } else { handshake.handshake(ctx.channel(), req); } } private void sendHttpResponse(ChannelHandlerContext ctx, FullHttpRequest req, FullHttpResponse res) { // Generate an error page if response getStatus code is not OK (200). if (res.getStatus().code() != 200) { ByteBuf buf = Unpooled.copiedBuffer(res.getStatus().toString(), CharsetUtil.UTF_8); res.content().writeBytes(buf); buf.release(); HttpHeaders.setContentLength(res, res.content().readableBytes()); } // Send the response and close the connection if necessary. ChannelFuture f = ctx.channel().writeAndFlush(res); if (!HttpHeaders.isKeepAlive(req) || res.getStatus().code() != 200) { f.addListener(ChannelFutureListener.CLOSE); } } private String getWebSocketLocation(HttpRequest req) { return "ws://" + req.headers().get(HOST) + WEB_SOCKET_PATH; } } } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/handler/BaseHandler.java ================================================ package com.zhaidaosi.game.jgframework.handler; import com.zhaidaosi.game.jgframework.message.IBaseMessage; import com.zhaidaosi.game.jgframework.message.InMessage; import com.zhaidaosi.game.jgframework.message.OutMessage; import io.netty.channel.Channel; public abstract class BaseHandler implements IBaseHandler { protected String handlerName; @Override public abstract IBaseMessage run(InMessage im, Channel ch) throws Exception; @Override public String getHandlerName() { return handlerName; } @Override public void setHandlerName(String handlerName) { this.handlerName = handlerName; } public static IBaseMessage doHeart() { return OutMessage.showSucc(""); } } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/handler/BaseHandlerChannel.java ================================================ package com.zhaidaosi.game.jgframework.handler; import com.zhaidaosi.game.jgframework.message.OutMessage; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.group.ChannelGroup; import io.netty.channel.group.ChannelGroupFuture; public class BaseHandlerChannel { private Channel chanel; private ChannelGroup chanelGroup; private String handlerName; public BaseHandlerChannel(String handlerName, Channel chanel) { this.handlerName = handlerName; this.chanel = chanel; } public BaseHandlerChannel(String handlerName, ChannelGroup chanelGroup) { this.handlerName = handlerName; this.chanelGroup = chanelGroup; } public Channel getChanel() { return chanel; } public ChannelGroup getChannelGroup() { return chanelGroup; } public String getHandlerName() { return handlerName; } public ChannelFuture write(OutMessage message) { message.setH(handlerName); if (chanel != null && chanel.isWritable()) { return chanel.write(message); } return null; } public ChannelGroupFuture writeGroup(OutMessage message) { message.setH(handlerName); if (chanelGroup != null) { return chanelGroup.write(message); } return null; } } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/handler/IBaseHandler.java ================================================ package com.zhaidaosi.game.jgframework.handler; import com.zhaidaosi.game.jgframework.message.IBaseMessage; import com.zhaidaosi.game.jgframework.message.InMessage; import io.netty.channel.Channel; public interface IBaseHandler { IBaseMessage run(InMessage im, Channel ch) throws Exception; String getHandlerName(); void setHandlerName(String handlerName); } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/message/IBaseMessage.java ================================================ package com.zhaidaosi.game.jgframework.message; public interface IBaseMessage { String toString(); String getH(); void setH(String h); } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/message/InMessage.java ================================================ package com.zhaidaosi.game.jgframework.message; import com.zhaidaosi.game.jgframework.common.BaseJson; import com.zhaidaosi.game.jgframework.common.excption.MessageException; import java.util.HashMap; public class InMessage implements IBaseMessage { /** * 控制器handler路径 */ private String h; /** * 参数 */ private HashMap p = new HashMap<>(); public InMessage() { } public InMessage(String h) { this.h = h; } public InMessage(String h, HashMap p) { this.h = h; this.p = p; } public static InMessage getMessage(String msg) throws MessageException { if (msg.startsWith("{") && msg.endsWith("}")) { return BaseJson.JsonToObject(msg, InMessage.class); } else { throw new MessageException("msg格式错误"); } } public String toString() { return BaseJson.ObjectToJson(this); } public String getH() { return h; } public HashMap getP() { return p; } public void setH(String h) { this.h = h; } public void setP(HashMap p) { this.p = p; } public void putMember(String key, Object value) { this.p.put(key, value); } public Object getMember(String key) { return p.get(key); } } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/message/MessageDecode.java ================================================ package com.zhaidaosi.game.jgframework.message; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToMessageDecoder; import java.util.List; public class MessageDecode extends MessageToMessageDecoder { @Override protected void decode(ChannelHandlerContext ctx, Object msg, List out) throws Exception { if (msg instanceof String) { msg = InMessage.getMessage((String) msg); } out.add(msg); } } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/message/MessageEncode.java ================================================ package com.zhaidaosi.game.jgframework.message; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToMessageEncoder; import io.netty.util.ReferenceCountUtil; import java.util.List; public class MessageEncode extends MessageToMessageEncoder { @Override protected void encode(ChannelHandlerContext ctx, Object msg, List out) { if(msg == null) { return ; } if (msg instanceof IBaseMessage) { msg = msg.toString() + "\n"; } else { ReferenceCountUtil.retain(msg); } out.add(msg); } } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/message/OutMessage.java ================================================ package com.zhaidaosi.game.jgframework.message; import com.zhaidaosi.game.jgframework.common.BaseJson; import com.zhaidaosi.game.jgframework.common.excption.MessageException; import org.apache.commons.beanutils.PropertyUtils; import java.lang.reflect.InvocationTargetException; public class OutMessage implements IBaseMessage { private int code = 0; private String h; private Object result = null; public OutMessage() { } public OutMessage(Object result, int code) { this.code = code; this.result = result; } public OutMessage(Object result, int code, String h) { this.code = code; this.result = result; this.h = h; } public String toString() { return BaseJson.ObjectToJson(this); } public static OutMessage getMessage(String om) throws MessageException { if (om.startsWith("{") && om.endsWith("}")) { return BaseJson.JsonToObject(om, OutMessage.class); } else { throw new MessageException("msg格式错误"); } } public static OutMessage showError(String result) { return showMessage(result, 1); } public static OutMessage showError(String result, String h) { return showMessage(result, 1, h); } public static OutMessage showError(String result, int code) { return showMessage(result, code); } public static OutMessage showSucc(Object result, String h) { return showMessage(result, 0, h); } public static OutMessage showSucc(Object result) { return showMessage(result, 0); } private static OutMessage showMessage(Object result, int code) { return new OutMessage(result, code); } private static OutMessage showMessage(Object result, int code, String h) { return new OutMessage(result, code, h); } public int getCode() { return code; } public void setCode(int code) { this.code = code; } public Object getResult() { return result; } public void setResult(Object result) { this.result = result; } public Object getResultValue(String key) { Object value = null; try { value = PropertyUtils.getProperty(result, key).toString(); } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { e.printStackTrace(); } return value; } public String getH() { return h; } public void setH(String h) { this.h = h; } } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/message/WebSocketEncode.java ================================================ package com.zhaidaosi.game.jgframework.message; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToMessageEncoder; import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; import io.netty.util.ReferenceCountUtil; import java.util.List; public class WebSocketEncode extends MessageToMessageEncoder { @Override protected void encode(ChannelHandlerContext ctx, Object msg, List out) { if(msg == null) { return ; } if (msg instanceof IBaseMessage) { TextWebSocketFrame tsf = new TextWebSocketFrame(msg.toString()); out.add(tsf); } else { ReferenceCountUtil.retain(msg); out.add(msg); } } } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/model/BasePosition.java ================================================ package com.zhaidaosi.game.jgframework.model; import com.zhaidaosi.game.jgframework.model.area.IBaseArea; public class BasePosition { private int x; private int y; private int z; private IBaseArea area; public BasePosition(IBaseArea area) { this.area = area; } public BasePosition(int x, int y, int z, IBaseArea area) { this.x = x; this.y = y; this.z = z; this.area = area; } public BasePosition(int x, int y, IBaseArea area) { this.x = x; this.y = y; this.area = area; } public int getX() { return x; } public void setX(int x) { this.x = x; } public int getY() { return y; } public void setY(int y) { this.y = y; } public int getZ() { return z; } public void setZ(int z) { this.z = z; } public IBaseArea getArea() { return area; } public void setArea(IBaseArea area) { this.area = area; } } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/model/action/ActionManager.java ================================================ package com.zhaidaosi.game.jgframework.model.action; import com.zhaidaosi.game.jgframework.common.BaseFile; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.HashMap; import java.util.Map; import java.util.Set; public class ActionManager { private static final Logger log = LoggerFactory.getLogger(ActionManager.class); private static Map actions = new HashMap(); private static final String classSuffix = "Action"; public static void initAction(String packagePath) { if (packagePath == null) { return; } Set> classes = BaseFile.getClasses(packagePath, classSuffix, true); for (Class c : classes) { IBaseAction obj; try { obj = (IBaseAction) c.newInstance(); actions.put(obj.getId(), obj); log.info("Action类 : " + c.getName() + " 加载完成"); } catch (InstantiationException | IllegalAccessException e) { log.error("Action类 : " + c.getName() + "加载失败", e); } } } public static IBaseAction getAction(int id) { return actions.get(id).clone(); } } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/model/action/BaseAction.java ================================================ package com.zhaidaosi.game.jgframework.model.action; import com.zhaidaosi.game.jgframework.handler.BaseHandlerChannel; public abstract class BaseAction implements IBaseAction, Cloneable { protected int id; protected String name; public BaseAction(int id, String name) { this.id = id; this.name = name; } @Override public int getId() { return id; } @Override public abstract void doAction(Object self, Object target, BaseHandlerChannel ch); @Override public String getName() { return name; } @Override public void setName(String name) { this.name = name; } public IBaseAction clone() { IBaseAction o = null; try { o = (IBaseAction) super.clone(); } catch (CloneNotSupportedException e) { // e.printStackTrace(); } return o; } } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/model/action/IBaseAction.java ================================================ package com.zhaidaosi.game.jgframework.model.action; import com.zhaidaosi.game.jgframework.handler.BaseHandlerChannel; public interface IBaseAction { int getId(); void doAction(Object self, Object target, BaseHandlerChannel ch); String getName(); void setName(String name); IBaseAction clone(); } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/model/area/AreaManager.java ================================================ package com.zhaidaosi.game.jgframework.model.area; import com.zhaidaosi.game.jgframework.common.BaseFile; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.HashMap; import java.util.Map; import java.util.Set; public class AreaManager { private static final Logger log = LoggerFactory.getLogger(AreaManager.class); private static Map areas = new HashMap(); private static final String classSuffix = "Area"; public static void initArea(String packagePath) { if (packagePath == null) { return; } Set> classes = BaseFile.getClasses(packagePath, classSuffix, true); for (Class c : classes) { IBaseArea obj; try { obj = (IBaseArea) c.newInstance(); areas.put(obj.getId(), obj); log.info("Area类 : " + c.getName() + " 加载完成"); } catch (InstantiationException | IllegalAccessException e) { log.error("Area类 : " + c.getName() + "加载失败", e); } } for (Map.Entry entry : areas.entrySet()) { entry.getValue().init(); } } public static IBaseArea getArea(int id) { return areas.get(id); } } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/model/area/BaseArea.java ================================================ package com.zhaidaosi.game.jgframework.model.area; import com.zhaidaosi.game.jgframework.model.BasePosition; import com.zhaidaosi.game.jgframework.model.entity.BaseNpc; import com.zhaidaosi.game.jgframework.model.entity.BasePlayer; import com.zhaidaosi.game.jgframework.model.entity.IBaseCharacter; import com.zhaidaosi.game.jgframework.model.entity.IBaseEntity; import com.zhaidaosi.game.jgframework.model.map.IBaseMap; import io.netty.channel.group.ChannelGroup; import io.netty.channel.group.DefaultChannelGroup; import io.netty.util.concurrent.GlobalEventExecutor; import java.util.Collection; import java.util.HashMap; import java.util.Map; /** * 服务器启动时通过AreaManager自动初始化的,不需要重复new的 * * @author Jerry */ public abstract class BaseArea implements IBaseArea { protected int id; protected String name; protected boolean open = true; protected IBaseMap map; protected Map entitys = new HashMap<>(); protected Map npcs = new HashMap<>(); protected Map players = new HashMap<>(); protected ChannelGroup channelGroup; protected final Object lock = new Object(); protected BasePosition entrancePosition = new BasePosition(this); public BaseArea(String name) { this.id = hashCode(); this.name = name; this.channelGroup = new DefaultChannelGroup(name, GlobalEventExecutor.INSTANCE); } public BaseArea(int id, String name) { this.id = id; this.name = name; this.channelGroup = new DefaultChannelGroup(name, GlobalEventExecutor.INSTANCE); } public BaseArea(String name, BasePosition entrancePosition) { this.id = hashCode(); this.name = name; this.entrancePosition = entrancePosition; this.channelGroup = new DefaultChannelGroup(name, GlobalEventExecutor.INSTANCE); } public BaseArea(int id, String name, BasePosition entrancePosition) { this.id = id; this.name = name; this.entrancePosition = entrancePosition; this.channelGroup = new DefaultChannelGroup(name, GlobalEventExecutor.INSTANCE); } public BaseArea(String name, IBaseMap map) { this.id = hashCode(); this.name = name; this.map = map; this.channelGroup = new DefaultChannelGroup(name, GlobalEventExecutor.INSTANCE); } public BaseArea(int id, String name, IBaseMap map) { this.id = id; this.name = name; this.map = map; this.channelGroup = new DefaultChannelGroup(name, GlobalEventExecutor.INSTANCE); } public BaseArea(String name, BasePosition entrancePosition, IBaseMap map) { this.id = hashCode(); this.name = name; this.map = map; this.entrancePosition = entrancePosition; this.channelGroup = new DefaultChannelGroup(name, GlobalEventExecutor.INSTANCE); } public BaseArea(int id, String name, BasePosition entrancePosition, IBaseMap map) { this.id = id; this.name = name; this.map = map; this.entrancePosition = entrancePosition; this.channelGroup = new DefaultChannelGroup(name, GlobalEventExecutor.INSTANCE); } @Override public abstract void init(); @Override public boolean isOpen() { return open; } @Override public void open() { this.open = true; init(); } @Override public void close() { this.open = false; channelGroup.clear(); entitys.clear(); players.clear(); npcs.clear(); map = null; } @Override public int getId() { return id; } @Override public String getName() { return name; } @Override public void setName(String name) { this.name = name; } @Override public IBaseMap getMap() { return map; } @Override public IBaseEntity getEntity(int id) { return entitys.get(id); } @Override public Map getEntities() { return entitys; } @Override public void addEntity(IBaseEntity entity) { entitys.put(entity.getId(), entity); } @Override public void removeEntity(int id) { entitys.remove(id); } @Override public IBaseCharacter getPlayer(int id) { return players.get(id); } @Override public Collection getPlayers() { return players.values(); } @Override public void addPlayer(BasePlayer player) { int id = player.getId(); synchronized (lock) { IBaseArea area = player.gArea(); if (area != null) { area.removePlayer(id); } players.put(id, player); channelGroup.add(player.gChannel()); player.sPosition(entrancePosition); } } @Override public void removePlayer(int id) { synchronized (lock) { IBaseCharacter player = players.get(id); if (player != null) { players.remove(id); channelGroup.remove(player.gChannel()); } } } @Override public IBaseEntity getNpc(int id) { return npcs.get(id); } @Override public void addNpc(BaseNpc npc) { npcs.put(npc.getId(), npc); } @Override public void removeNpc(int id) { npcs.remove(id); } @Override public ChannelGroup getChannelGroup() { return channelGroup; } } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/model/area/BaseZone.java ================================================ package com.zhaidaosi.game.jgframework.model.area; import com.zhaidaosi.game.jgframework.model.BasePosition; import com.zhaidaosi.game.jgframework.model.map.IBaseMap; /** * 可以随时new的 * @author Jerry */ public abstract class BaseZone extends BaseArea { public BaseZone(String name) { super(name); } public BaseZone(String name, BasePosition entrancePosition) { super(name, entrancePosition); } public BaseZone(String name, IBaseMap map) { super(name, map); } public BaseZone(String name, BasePosition entrancePosition, IBaseMap map) { super(name, entrancePosition, map); } @Override public abstract void init(); } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/model/area/IBaseArea.java ================================================ package com.zhaidaosi.game.jgframework.model.area; import com.zhaidaosi.game.jgframework.model.entity.BaseNpc; import com.zhaidaosi.game.jgframework.model.entity.BasePlayer; import com.zhaidaosi.game.jgframework.model.entity.IBaseCharacter; import com.zhaidaosi.game.jgframework.model.entity.IBaseEntity; import com.zhaidaosi.game.jgframework.model.map.IBaseMap; import io.netty.channel.group.ChannelGroup; import java.util.Collection; import java.util.Map; public interface IBaseArea { void init(); boolean isOpen(); void open(); void close(); int getId(); String getName(); void setName(String name); IBaseMap getMap(); IBaseEntity getEntity(int id); Map getEntities(); void addEntity(IBaseEntity entity); void removeEntity(int id); IBaseCharacter getPlayer(int id); Collection getPlayers(); void addPlayer(BasePlayer player); void removePlayer(int id); IBaseEntity getNpc(int id); void addNpc(BaseNpc npc); void removeNpc(int id); ChannelGroup getChannelGroup(); } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/model/entity/BaseEntity.java ================================================ package com.zhaidaosi.game.jgframework.model.entity; import com.zhaidaosi.game.jgframework.model.BasePosition; import com.zhaidaosi.game.jgframework.model.action.IBaseAction; import java.util.HashMap; import java.util.Map; public class BaseEntity implements IBaseEntity { protected int id; protected String name; protected BasePosition position; protected String roll; protected Map actions = new HashMap(); @Override public int getId() { return id; } @Override public void setId(int id) { this.id = id; } @Override public String getRoll() { return roll; } @Override public void setRoll(String roll) { this.roll = roll; } @Override public BasePosition getPosition() { return position; } @Override public void setPosition(BasePosition position) { this.position = position; } @Override public String getName() { return name; } @Override public void setName(String name) { this.name = name; } @Override public void addAction(IBaseAction action) { actions.put(action.getId(), action); } @Override public void removeAction(int id) { actions.remove(id); } @Override public IBaseAction getAction(int id) { return actions.get(id); } } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/model/entity/BaseNpc.java ================================================ package com.zhaidaosi.game.jgframework.model.entity; import com.zhaidaosi.game.jgframework.model.BasePosition; import com.zhaidaosi.game.jgframework.model.action.IBaseAction; import java.util.HashMap; import java.util.Map; public class BaseNpc implements IBaseEntity { protected int id; protected String name; protected Map actions = new HashMap(); protected String roll; protected BasePosition position; @Override public int getId() { return id; } @Override public void setId(int id) { this.id = id; } @Override public String getRoll() { return roll; } @Override public void setRoll(String roll) { this.roll = roll; } @Override public BasePosition getPosition() { return position; } @Override public void setPosition(BasePosition position) { this.position = position; } @Override public String getName() { return name; } @Override public void setName(String name) { this.name = name; } @Override public IBaseAction getAction(int id) { return actions.get(id); } @Override public void addAction(IBaseAction action) { actions.put(action.getId(), action); } @Override public void removeAction(int id) { actions.remove(id); } } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/model/entity/BasePlayer.java ================================================ package com.zhaidaosi.game.jgframework.model.entity; import com.zhaidaosi.game.jgframework.model.BasePosition; import com.zhaidaosi.game.jgframework.model.action.IBaseAction; import com.zhaidaosi.game.jgframework.model.area.IBaseArea; import io.netty.channel.Channel; import java.util.HashMap; import java.util.Map; public class BasePlayer implements IBaseCharacter { protected int id; protected Channel channel; protected String name; protected String roll; protected int level; protected int experience; protected int totalHp; protected int totalMp; protected int hp; protected int mp; protected BasePosition position; protected Map actions = new HashMap(); protected boolean isInQueue = false; @Override public void loginHook() { if (channel == null || position == null) { return; } IBaseArea area = position.getArea(); if (area == null) { return; } area.addPlayer(this); } @Override public void logoutHook() { if (channel == null || position == null) { return; } IBaseArea area = position.getArea(); if (area == null) { return; } area.removePlayer(id); } @Override public int getId() { return id; } @Override public void setId(int id) { this.id = id; } @Override public String getRoll() { return roll; } @Override public void setRoll(String roll) { this.roll = roll; } @Override public IBaseArea gArea() { if (position != null) { return position.getArea(); } return null; } @Override public BasePosition gPosition() { return position; } @Override public void sPosition(BasePosition position) { this.position = position; } @Override public String getName() { return name; } @Override public void setName(String name) { this.name = name; } @Override public Map getActions() { return actions; } @Override public void setActions(Map actions) { this.actions = actions; } @Override public IBaseAction findActionById(int id) { return actions.get(id); } @Override public void addAction(IBaseAction action) { actions.put(action.getId(), action); } @Override public void removeAction(int id) { actions.remove(id); } @Override public Channel gChannel() { return channel; } @Override public void sChannel(Channel channel) { this.channel = channel; } @Override public int getLevel() { return level; } @Override public void setLevel(int level) { this.level = level; } @Override public int getExperience() { return experience; } @Override public void setExperience(int experience) { this.experience = experience; } @Override public int getTotalHp() { return totalHp; } @Override public void setTotalHp(int totalHp) { this.totalHp = totalHp; } @Override public int getTotalMp() { return totalMp; } @Override public void setTotalMp(int totalMp) { this.totalMp = totalMp; } @Override public int getHp() { return hp; } @Override public void setHp(int hp) { this.hp = hp; } @Override public int getMp() { return mp; } @Override public void setMp(int mp) { this.mp = mp; } @Override public boolean isInQueue() { return isInQueue; } @Override public void setIsInQueue(boolean isInQueue) { this.isInQueue = isInQueue; } } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/model/entity/BasePlayerFactory.java ================================================ package com.zhaidaosi.game.jgframework.model.entity; public class BasePlayerFactory implements IBasePlayerFactory { public IBaseCharacter getPlayer() { return new BasePlayer(); } } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/model/entity/IBaseCharacter.java ================================================ package com.zhaidaosi.game.jgframework.model.entity; import com.zhaidaosi.game.jgframework.model.BasePosition; import com.zhaidaosi.game.jgframework.model.action.IBaseAction; import com.zhaidaosi.game.jgframework.model.area.IBaseArea; import io.netty.channel.Channel; import java.util.Map; public interface IBaseCharacter { int getId(); void setId(int id); String getRoll(); void setRoll(String roll); BasePosition gPosition(); void sPosition(BasePosition position); IBaseArea gArea(); String getName(); void setName(String name); IBaseAction findActionById(int id); void addAction(IBaseAction action); void setActions(Map actions); Map getActions(); void removeAction(int id); Channel gChannel(); void sChannel(Channel channel); int getLevel(); void setLevel(int level); int getExperience(); void setExperience(int experience); int getTotalHp(); void setTotalHp(int totalHp); int getTotalMp(); void setTotalMp(int totalMp); int getHp(); void setHp(int hp); int getMp(); void setMp(int mp); void logoutHook(); void loginHook(); boolean isInQueue(); void setIsInQueue(boolean isInQueue); } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/model/entity/IBaseEntity.java ================================================ package com.zhaidaosi.game.jgframework.model.entity; import com.zhaidaosi.game.jgframework.model.BasePosition; import com.zhaidaosi.game.jgframework.model.action.IBaseAction; public interface IBaseEntity { int getId(); void setId(int id); String getRoll(); void setRoll(String roll); BasePosition getPosition(); void setPosition(BasePosition position); String getName(); void setName(String name); IBaseAction getAction(int id); void addAction(IBaseAction action); void removeAction(int id); } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/model/entity/IBasePlayerFactory.java ================================================ package com.zhaidaosi.game.jgframework.model.entity; public interface IBasePlayerFactory { IBaseCharacter getPlayer(); } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/model/map/IBaseMap.java ================================================ package com.zhaidaosi.game.jgframework.model.map; public interface IBaseMap { public void init(); } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/rsync/BaseRsync.java ================================================ package com.zhaidaosi.game.jgframework.rsync; import com.zhaidaosi.game.jgframework.common.sdm.IBaseModel; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; public abstract class BaseRsync implements IBaseRsync { private boolean isRunning = false; private ConcurrentMap mapOne = new ConcurrentHashMap<>(); private ConcurrentMap mapTwo = new ConcurrentHashMap<>(); private ConcurrentMap mapThree = new ConcurrentHashMap<>(); protected Map rsyncMap = new HashMap<>(); @Override public abstract void runRsync(); @Override public void addRsync(Integer id, IBaseModel obj) { this.getNowMap().put(id, obj); } @Override public void setRsyncMap(Map map) { this.rsyncMap = map; } @Override public void clearRsyncMap() { this.rsyncMap.clear(); } @Override public IBaseModel get(Integer id) { IBaseModel model = this.getNowMap().get(id); if (model == null) { model = this.rsyncMap.get(id); } return model; } @Override public Map getNeedRsync() { return new HashMap<>(this.getNeedRsyncMap()); } @Override public void clearNeedRsync() { this.getNeedRsyncMap().clear(); } @Override public boolean isRunning() { return isRunning; } @Override public void toRunning() { this.isRunning = true; } @Override public void toStop() { this.isRunning = false; } /** * 选择当前map * @return */ private ConcurrentMap getNowMap() { return this.selectMap(this.getSelect(System.currentTimeMillis())); } private ConcurrentMap getNeedRsyncMap() { return this.selectMap(this.getSelect(System.currentTimeMillis() - RsyncManager.getSyncPeriod())); } /** * 判断当前是哪个map * @return */ private int getSelect(long now) { return (int) (Math.floor(now / RsyncManager.getSyncPeriod()) % 3); } /** * 选择map * @param select * @return */ private ConcurrentMap selectMap(int select) { if (select == 0) { return mapOne; } else if (select == 1) { return mapTwo; } else { return mapThree; } } } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/rsync/IBaseRsync.java ================================================ package com.zhaidaosi.game.jgframework.rsync; import com.zhaidaosi.game.jgframework.common.sdm.IBaseModel; import java.util.Map; public interface IBaseRsync { void addRsync(Integer id, IBaseModel obj); void runRsync(); void setRsyncMap(Map map); void clearRsyncMap(); Map getNeedRsync(); IBaseModel get(Integer id); void clearNeedRsync(); boolean isRunning(); void toRunning(); void toStop(); } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/rsync/RsyncManager.java ================================================ package com.zhaidaosi.game.jgframework.rsync; import com.zhaidaosi.game.jgframework.Boot; import com.zhaidaosi.game.jgframework.common.BaseFile; import com.zhaidaosi.game.jgframework.common.BaseRunTimer; import com.zhaidaosi.game.jgframework.common.sdm.IBaseModel; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.HashMap; import java.util.Map; import java.util.Set; public class RsyncManager { private static long serviceSyncPeriod; private static final Logger log = LoggerFactory.getLogger(RsyncManager.class); private static HashMap, IBaseRsync> rsyncMap; private static final String classSuffix = "Rsync"; public static void init() { rsyncMap = new HashMap, IBaseRsync>(); serviceSyncPeriod = Boot.getServiceSyncPeriod(); Set> classes = BaseFile.getClasses(Boot.SERVER_RSYNC_PACKAGE_PATH, classSuffix, true); for (Class c : classes) { IBaseRsync obj; try { obj = (IBaseRsync) c.newInstance(); rsyncMap.put(c, obj); log.info("rsync类 : " + c.getName() + " 加载完成"); } catch (InstantiationException | IllegalAccessException e) { log.error("rsync类 : " + c.getName() + "加载失败", e); } } } public static long getSyncPeriod() { return serviceSyncPeriod; } /** * 添加异步同步 * @param uid * @param class */ public static void add(Integer userId, Class c, IBaseModel obj) { IBaseRsync rsync = rsyncMap.get(c); if (rsync != null) { rsync.addRsync(userId, obj); } else { log.error("添加异步任务失败: " + c.getName() + "异步类不存在"); } } public static IBaseModel get(Integer userId, Class c) { IBaseModel model = null; IBaseRsync rsync = rsyncMap.get(c); if (rsync != null) { model = rsync.get(userId); } return model; } public static void run() { long time = System.currentTimeMillis() % serviceSyncPeriod; if (time < 1500) { try { Thread.sleep(1500 - time); } catch (InterruptedException e) { log.error("sleep error", e); } } Map> needRsync = new HashMap>(); for (Map.Entry, IBaseRsync> entry : rsyncMap.entrySet()) { IBaseRsync rsync = entry.getValue(); //如果前一个任务还没有完成则不导入任务,任务推至下次运行 if (!rsync.isRunning()) { Map map = rsync.getNeedRsync(); if (map.size() > 0) { needRsync.put(rsync, map); rsync.clearNeedRsync(); } } else { log.error(rsync.getClass().getName() + " 任务被推迟!!!"); } } for (Map.Entry> entry : needRsync.entrySet()) { RsyncThread rt = new RsyncThread(entry.getKey(), entry.getValue()); rt.start(); } } } class RsyncThread extends Thread { private IBaseRsync rsync; private Map map; public RsyncThread(IBaseRsync rsync, Map map) { this.rsync = rsync; this.map = map; } public void run() { rsync.toRunning(); rsync.setRsyncMap(map); rsync.runRsync(); rsync.clearRsyncMap(); rsync.toStop(); BaseRunTimer.showTimer(); } } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/session/BaseSecretFactory.java ================================================ package com.zhaidaosi.game.jgframework.session; import com.zhaidaosi.game.jgframework.common.encrpt.BaseRsa; import com.zhaidaosi.game.jgframework.common.excption.BaseException; public class BaseSecretFactory implements IBaseSecretFactory { @Override public String createSecret(int userId) throws BaseException { String input = userId + "_" + System.currentTimeMillis(); String secret = BaseRsa.encrypt(input); if (secret == null) { throw new BaseException("秘钥生成失败", 100); } return secret; } @Override public int checkSecret(String secret) throws Exception { secret = BaseRsa.decrypt(secret); if (secret == null) { throw new BaseException("非法秘钥", 101); } String[] arr = secret.split("_"); if (arr.length != 2) { throw new BaseException("非法秘钥", 101); } int userId = Integer.valueOf(arr[0]); if (userId <= 0) { throw new BaseException("非法秘钥", 101); } //有效期1分钟 if (Long.parseLong(arr[1]) - System.currentTimeMillis() > 60000) { throw new BaseException("秘钥已失效", 102); } return userId; } } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/session/IBaseSecretFactory.java ================================================ package com.zhaidaosi.game.jgframework.session; public interface IBaseSecretFactory { String createSecret(int userId) throws Exception; int checkSecret(String secret) throws Exception; } ================================================ FILE: src/main/java/com/zhaidaosi/game/jgframework/session/SessionManager.java ================================================ package com.zhaidaosi.game.jgframework.session; import com.zhaidaosi.game.jgframework.Boot; import com.zhaidaosi.game.jgframework.Router; import com.zhaidaosi.game.jgframework.common.queue.BaseQueue; import com.zhaidaosi.game.jgframework.common.queue.BaseQueueElement; import com.zhaidaosi.game.jgframework.connector.IBaseConnector; import com.zhaidaosi.game.jgframework.message.IBaseMessage; import com.zhaidaosi.game.jgframework.message.InMessage; import com.zhaidaosi.game.jgframework.message.OutMessage; import com.zhaidaosi.game.jgframework.model.entity.IBaseCharacter; import io.netty.channel.Channel; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.List; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; public class SessionManager { public final static String SECRET = "secret"; public final static int ADD_SESSION_SUCC = 1; public final static int ADD_SESSION_ERROR = -1; public final static int ADD_SESSION_WAIT = 0; private static final Logger log = LoggerFactory.getLogger(SessionManager.class); private static IBaseSecretFactory secretFactory = new BaseSecretFactory(); private static ConcurrentMap userIdChannels = new ConcurrentHashMap<>(); private static ConcurrentMap> waitUserIdChannels = new ConcurrentHashMap<>(); private static BaseQueue waitQueue = new BaseQueue<>(); private static Timer timer; private static int maxUser = 0; public static int checkSession(InMessage msg, Channel ch) { IBaseCharacter player = ch.attr(IBaseConnector.PLAYER).get(); if (player == null) { return ADD_SESSION_ERROR; } if (player.getId() <= 0) { Object secret = msg.getMember(SECRET); if (secret == null || secret.equals("")) { return ADD_SESSION_ERROR; } try { int userId = checkSecret((String) secret); if (userId == 0) { return ADD_SESSION_ERROR; } player.setId(userId); return SessionManager.addSession(player, ch); } catch (Exception e) { return ADD_SESSION_ERROR; } } if (maxUser > 0 && player.isInQueue()) { return ADD_SESSION_WAIT; } return ADD_SESSION_SUCC; } /** * 加入session * @param player * @param ch * @return */ private static int addSession(IBaseCharacter player, Channel ch) { int userId; if (player == null || (userId = player.getId()) <= 0) { return ADD_SESSION_ERROR; } Channel _ch = userIdChannels.get(userId); BaseQueueElement queueElement = null; if (_ch == null && maxUser > 0) { queueElement = waitUserIdChannels.get(userId); if (queueElement != null) { _ch = queueElement.getValue(); } } boolean same = _ch != null && _ch.hashCode() == ch.hashCode(); if (_ch != null && !same) { IBaseCharacter _player = _ch.attr(IBaseConnector.PLAYER).get(); if (_player != null) { _player.setId(0); // 保持排队名次 if (queueElement != null) { player.setIsInQueue(true); queueElement.setValue(ch); } } _ch.close(); } if (maxUser > 0) { if (queueElement != null) { return ADD_SESSION_WAIT; } else if (userIdChannels.size() >= maxUser) { player.setIsInQueue(true); BaseQueueElement element = waitQueue.put(ch); if (_ch == null || !same) { waitUserIdChannels.put(userId, element); } return ADD_SESSION_WAIT; } } if (_ch == null || !same) { userIdChannels.put(userId, ch); } player.loginHook(); return ADD_SESSION_SUCC; } public static void removeSession(Channel ch) { IBaseCharacter player = ch.attr(IBaseConnector.PLAYER).get(); if (player != null) { int userId = player.getId(); if (maxUser > 0 && player.isInQueue()) { if (userId > 0) { BaseQueueElement queueElement = waitUserIdChannels.get(userId); waitUserIdChannels.remove(userId); waitQueue.remove(queueElement); } } else { if (userId > 0) { userIdChannels.remove(userId); } player.logoutHook(); } } } public static List getOnlineUser() { List onlineUser = new ArrayList(); for (Channel ch : userIdChannels.values()) { IBaseCharacter player = ch.attr(IBaseConnector.PLAYER).get(); if (player != null && player.getId() > 0) { onlineUser.add(player); } } return onlineUser; } public static IBaseCharacter getPlayerByUserId(Integer uid) { Channel ch = userIdChannels.get(uid); IBaseCharacter player = ch == null ? null : ch.attr(IBaseConnector.PLAYER).get(); return (player != null && player.getId() > 0) ? player : null; } public static boolean isAuthHandler(InMessage msg) { return msg.getH().startsWith(Boot.getAuthHandler()); } public static String getServerIp(int userId) { int AuthCount = Boot.getServiceCount(); int index = userId % AuthCount; return Boot.getServiceIps().get(index); } public static String createSecret(int userId) throws Exception { return secretFactory.createSecret(userId); } private static int checkSecret(String secret) throws Exception { return secretFactory.checkSecret(secret); } public static void init() { if (maxUser > 0) { initTimer(); } } public static void destroy() { userIdChannels.clear(); if (timer != null) { timer.cancel(); timer = null; } if (maxUser > 0) { waitUserIdChannels.clear(); waitQueue.clear(); } } public static long getWaitCount() { return waitQueue.size(); } public static int getUserCount() { return userIdChannels.size(); } public static ConcurrentMap getChannels() { return userIdChannels; } public static void setSercretFactory(IBaseSecretFactory secretFactory) { SessionManager.secretFactory = secretFactory; } public static void setMaxUser(int max) { if (max > 0) { maxUser = max; } } private static void initTimer() { if (timer == null) { timer = new Timer("QueueTimerTask"); timer.schedule(new QueueTimerTask(), 10000, 10000); } } public static IBaseMessage getWaitMessage(IBaseCharacter player) { long index = 0; if (player != null && player.isInQueue()) { BaseQueueElement queueElement = waitUserIdChannels.get(player.getId()); index = waitQueue.findIndex(queueElement); } return OutMessage.showSucc(index, Router.WAIT_HANDLERNAME); } private static class QueueTimerTask extends TimerTask { @Override public void run() { try { while (userIdChannels.size() < maxUser && waitQueue.size() > 0) { BaseQueueElement element = waitQueue.take(); if (element == null) { continue; } Channel ch = element.getValue(); if (ch == null) { continue; } IBaseCharacter player = ch.attr(IBaseConnector.PLAYER).get(); if (player == null) { continue; } int userId = player.getId(); if (userId <= 0) { continue; } waitUserIdChannels.remove(userId); player.setIsInQueue(false); userIdChannels.put(userId, ch); ch.writeAndFlush(getWaitMessage(player)); } BaseQueueElement start = waitQueue.getStart(); while (start != null) { Channel ch = start.getValue(); IBaseCharacter player = ch.attr(IBaseConnector.PLAYER).get(); ch.writeAndFlush(getWaitMessage(player)); start = start.getNext(); } } catch (Exception e) { log.error(e.getMessage(), e); } } } } ================================================ FILE: src/main/resources/errorCode.properties ================================================ 10000=\u7CFB\u7EDF\u9519\u8BEF 11000=\u7CFB\u7EDF\u7EF4\u62A4\u4E2D\uFF0C\u6682\u505C\u4F7F\u7528 20000=handler\u4E0D\u80FD\u4E3A\u7A7A 21000=handler\u4E0D\u5B58\u5728 50000=\u4F20\u8F93\u7684\u6570\u636E\u683C\u5F0F\u5316\u9519\u8BEF 60000=http\u8BF7\u6C42\u9519\u8BEF