##A server baseed on netty add sping IOC without XML
netty同时处理HTTP和Websocket,并将HTTP请求路由到相应Action中;使用ehcache实现Session;spring IOC做管理容器,mybatis 做sql数据库ORM;spring data mongoDB做mongo的ORM;HikariCP做sql数据库连接池;Gson用于json解析和生成;logback日志处理。
####netty处理HTTP和websocket
- smart.core.netty.HttpHandler:是一个自定义的ChannelHandler用于处理HTTP 和Websocket请求
- Handler分别处理HTTP和Websocket
public void messageReceived(ChannelHandlerContext ctx, Object msg) {
if (msg instanceof FullHttpRequest) {//如果是HTTP请求,进行HTTP操作
handleHttpRequest(ctx, (FullHttpRequest) msg);
} else if (msg instanceof WebSocketFrame) {//如果是Websocket请求,则进行websocket操作
handleWebSocketFrame(ctx, (WebSocketFrame) msg);
}
}
- 由于websocket也是基于HTTP的,需要判断是websocket后,将HTTP升级为Websocket
private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req) {
logger.warn("uri:" + req.uri());
if (req.uri().startsWith("/ws/join")) {//如果urL开头为/ws/join则升级为websocket
mac = wsBeforeHandler(ctx, req);
if (mac == null || mac.length() < 1) {
RespTools.paraErrorBack(ctx,req,null);
return;
}
WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory(
getWebSocketLocation(req), null, true);
handshaker = wsFactory.newHandshaker(req);
if (handshaker == null) {
WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel());
} else {
handshaker.handshake(ctx.channel(), req);
}
} else {//是HTTP请求则路由到Action
RouteResult<Action> routeResult = rs.getRouter().route(req.method(), req.uri());
Action action = routeResult.target();
action.act(ctx, req);
}
}
- websocket请求处理,这里是从websocket请求中获取客户端传来的json字符串,并将字符串转为javabean
private void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) {
// Check for closing frame
if (frame instanceof CloseWebSocketFrame) {
handshaker.close(ctx.channel(), (CloseWebSocketFrame) frame.retain());
return;
}
if (frame instanceof PingWebSocketFrame) {
ctx.write(new PongWebSocketFrame(frame.content().retain()));
return;
}
if (frame instanceof TextWebSocketFrame) {
devicePool.join(ctx.channel(), mac);
String json = ((TextWebSocketFrame) frame).text();
Logic.ReqRespType data= JsonTools.read(json,Logic.ReqRespType.class);
//...
return;
}
}
- 如果是HTTP则需在RouterSetting中配置路由. 比如r.POST("api/get_verify_code", getVerifyCodeAct): 将url为"api/get_verify_code"的POST请求路由到LoginAct中
public class RouterSetting {
@Autowired
private Router<Action> router;
@Autowired
private GetVerifyCodeAct getVerifyCodeAct;//w
@Autowired
private LoginAct loginAct;
@Autowired
private RegisterAct registerAcc;
public Router<Action> getRouter() {
routerConfig(this.router);
return this.router;
}
private void routerConfig(Router<Action> r) {
r.POST("api/get_verify_code", getVerifyCodeAct);
r.ANY("api/login", loginAct);
r.GET("api/register", registerAcc);
}
}
- Action处理HTTP请求并返回
@Controller
public class LoginAct implements Action {
private static final Logger logger = LoggerFactory.getLogger(LoginAct.class);
@Override
public void act(ChannelHandlerContext ctx, FullHttpRequest req) {
String ip = HttpTools.getIp(req);
String body = Convert.buf2Str(req.content());
Get.Login get = JsonTools.read(body, Get.Login.class);//1.得到HTTP传来的json数据解析为javabean
Sub.Register back;//构建返回给客户端的javabean的实例
//...
HttpTools.sendCorrectResp(ctx, req, back);//返回给客户端HTTP Response
}
}
- 添加Session(依靠ehcache)
private void addSession(long userId, String ip) {
Logic.DeviceSession session = new Logic.DeviceSession(ip, "");
Cache.add(userId + "", session, "6mn");//设置session的缓存时间为6分钟
//debugSession(userId);
}
- 从HTTP请求中获取IP地址
String ip = HttpTools.getIp(req);
####netty参数设置
port=8090
netty.boss.thread.count=2
netty.worker.thread.count=1
netty.so.keepalive=true
netty.so.backlog=100
####项目依赖
//---------------------单元测试----------------------------
testCompile group: 'junit', name: 'junit', version: '4.11'
//--------------------数据库驱动----------------------------
compile 'org.mongodb:mongodb-driver:3.2.2'
compile 'mysql:mysql-connector-java:5.1.38'
//-------------------数据库连接池---------------------------
compile 'com.zaxxer:HikariCP:2.4.5'
//----------------------ORM------------------------------
compile group: 'org.mybatis', name: 'mybatis', version:mybatisVersion
compile group: 'org.mybatis', name: 'mybatis-spring', version:mybatisSpringVersion
//-----------------------缓存----------------------------
compile group: 'net.sf.ehcache', name: 'ehcache', version:ehcacheVersion
//----------------------工具包----------------------------
compile 'commons-httpclient:commons-httpclient:3.1-rc1'
compile 'org.javassist:javassist:3.20.0-GA'
//---------------------日志处理----------------------------
compile 'org.slf4j:slf4j-api:1.7.21'
compile 'ch.qos.logback:logback-core:1.1.7'
compile 'ch.qos.logback:logback-classic:1.1.7'
//---------------------json处理---------------------------
compile 'com.google.code.gson:gson:2.6.2'
//---------------------netty-----------------------------
compile group: 'io.netty', name: 'netty-all', version:nettyVersion
//---------------------spring----------------------------
compile group: 'org.springframework', name: 'spring-test', version:springVersion
compile group: 'org.springframework', name: 'spring-jdbc', version:springVersion
compile(group: 'org.springframework', name: 'spring-context', version:springVersion) {
exclude(module: 'commons-logging')
}