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