作者 zhonglai

修改bug

  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<project xmlns="http://maven.apache.org/POM/4.0.0"
  3 + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5 + <modelVersion>4.0.0</modelVersion>
  6 +
  7 + <groupId>com.zhonglai</groupId>
  8 + <artifactId>SocketHtml</artifactId>
  9 + <version>1.0.2</version>
  10 +
  11 + <properties>
  12 + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  13 + </properties>
  14 +
  15 + <dependencies>
  16 + <!-- 系统依赖 -->
  17 + <dependency>
  18 + <groupId>com.zhonglai</groupId>
  19 + <artifactId>core</artifactId>
  20 + <version>1.5.11</version>
  21 + </dependency>
  22 +
  23 + <!-- nio -->
  24 + <dependency>
  25 + <groupId>io.netty</groupId>
  26 + <artifactId>netty-all</artifactId>
  27 + <version>5.0.0.Alpha2</version>
  28 + <exclusions>
  29 + <exclusion>
  30 + <groupId>org.slf4j</groupId>
  31 + <artifactId>slf4j-log4j12</artifactId>
  32 + </exclusion>
  33 + </exclusions>
  34 + </dependency>
  35 + </dependencies>
  36 +
  37 + <distributionManagement>
  38 + <repository>
  39 + <id>nexus-releases</id>
  40 + <name>Nexus Release Repository</name>
  41 + <url>http://code.part-timead.com:4781/nexus/content/repositories/releases/</url>
  42 + </repository>
  43 + <snapshotRepository>
  44 + <id>nexus-snapshots</id>
  45 + <name>Nexus Snapshot Repository</name>
  46 + <url>http://code.part-timead.com:4781/nexus/content/repositories/releases/</url>
  47 + </snapshotRepository>
  48 + </distributionManagement>
  49 +</project>
  1 +package com.zhonglai.socket.html;
  2 +
  3 +import io.netty.bootstrap.ServerBootstrap;
  4 +import io.netty.channel.*;
  5 +import io.netty.channel.nio.NioEventLoopGroup;
  6 +import io.netty.channel.socket.nio.NioServerSocketChannel;
  7 +import io.netty.handler.logging.LogLevel;
  8 +import io.netty.handler.logging.LoggingHandler;
  9 +
  10 +import java.net.InetSocketAddress;
  11 +
  12 +/**
  13 + * 基于JAVA AIO的,面向TCP/IP的,非阻塞式Sockect服务器框架类
  14 + *
  15 + * @author zer0
  16 + * @version 1.0
  17 + * @date 2015-2-15
  18 + */
  19 +public class TcpServer {
  20 +
  21 +
  22 + private volatile Integer port;//服务器端口
  23 + private Channel channel;
  24 + private EventLoopGroup bossGroup;
  25 + private EventLoopGroup workerGroup;
  26 +
  27 + private ChannelInitializer channelInitializer;
  28 +
  29 + public TcpServer(Integer port, ChannelInitializer channelInitializer){
  30 + this.port = port;
  31 + this.channelInitializer = channelInitializer;
  32 + }
  33 +
  34 + /**
  35 + * 启动服务器
  36 + *
  37 + * @author zer0
  38 + * @version 1.0
  39 + * @date 2015-2-19
  40 + */
  41 + public ChannelFuture startServer(){
  42 +
  43 + bossGroup = new NioEventLoopGroup();
  44 + workerGroup = new NioEventLoopGroup();
  45 + ServerBootstrap bootstrap = new ServerBootstrap();
  46 + bootstrap.group(bossGroup, workerGroup)
  47 + .channel(NioServerSocketChannel.class)
  48 + .childHandler(channelInitializer)
  49 + .handler(new LoggingHandler(LogLevel.INFO))
  50 + .option(ChannelOption.SO_BACKLOG, 128); // 设置tcp协议的请求等待队列
  51 + try {
  52 + ChannelFuture future = bootstrap.bind(new InetSocketAddress(port)).sync();
  53 + channel = future.channel();
  54 +
  55 +
  56 + System.out.println("服务器已启动,端口:" + port);
  57 + return future;
  58 + } catch (InterruptedException e) {
  59 + e.printStackTrace();
  60 + }
  61 + return null;
  62 + }
  63 +
  64 + public void destory(){
  65 + if (channel != null) {
  66 + channel.close();
  67 + }
  68 + bossGroup.shutdownGracefully();
  69 + workerGroup.shutdownGracefully();
  70 + }
  71 +
  72 +}
  1 +package com.zhonglai.socket.html.action;
  2 +
  3 +import com.google.gson.JsonObject;
  4 +
  5 +public interface Base {
  6 + public void setParameter(JsonObject parameter);
  7 +}
  1 +package com.zhonglai.socket.html.action;
  2 +
  3 +import com.google.gson.JsonObject;
  4 +
  5 +/**
  6 + * 父类
  7 + */
  8 +public class BaseAction implements Base{
  9 + protected JsonObject parameter;
  10 + public void setParameter(JsonObject parameter)
  11 + {
  12 + this.parameter = parameter;
  13 + }
  14 +}
  1 +package com.zhonglai.socket.html.http;
  2 +
  3 +import com.zhonglai.socket.html.http.handler.HttpServerInboundHandler;
  4 +import io.netty.channel.ChannelInitializer;
  5 +import io.netty.channel.ChannelPipeline;
  6 +import io.netty.channel.socket.SocketChannel;
  7 +import io.netty.handler.codec.http.HttpObjectAggregator;
  8 +import io.netty.handler.codec.http.HttpRequestDecoder;
  9 +import io.netty.handler.codec.http.HttpResponseEncoder;
  10 +import io.netty.handler.ssl.SslContext;
  11 +import io.netty.handler.ssl.SslHandler;
  12 +import io.netty.handler.stream.ChunkedWriteHandler;
  13 +
  14 +import javax.net.ssl.SSLEngine;
  15 +
  16 +public class HttpChannelInitService extends ChannelInitializer<SocketChannel> {
  17 +
  18 + private HttpServerInboundHandler httpServerInboundHandler = null;
  19 +
  20 + private SslContext sslContext = null;
  21 +
  22 + public HttpChannelInitService(HttpServerInboundHandler httpServerInboundHandler)
  23 + {
  24 + this.httpServerInboundHandler = httpServerInboundHandler;
  25 + }
  26 +
  27 + public HttpChannelInitService(HttpServerInboundHandler httpServerInboundHandler, SslContext sslContext)
  28 + {
  29 + this.sslContext = sslContext;
  30 + this.httpServerInboundHandler = httpServerInboundHandler;
  31 + }
  32 +
  33 + protected void initChannel(SocketChannel ch) throws Exception {
  34 +
  35 + ChannelPipeline pipeline = ch.pipeline();
  36 +
  37 + if(null != sslContext) //https
  38 + {
  39 + SSLEngine engine = sslContext.newEngine(ch.alloc());
  40 + pipeline.addFirst("ssl", new SslHandler(engine));
  41 + }
  42 +
  43 +
  44 + pipeline.addLast("http-decoder",
  45 + new HttpRequestDecoder());
  46 + pipeline.addLast("http-aggregator",
  47 + new HttpObjectAggregator(65536));
  48 + pipeline.addLast("http-encoder",
  49 + new HttpResponseEncoder());
  50 + pipeline.addLast("http-chunked",
  51 + new ChunkedWriteHandler());
  52 + pipeline.addLast("httpServerHandler",httpServerInboundHandler
  53 + );
  54 +
  55 + }
  56 +}
  1 +package com.zhonglai.socket.html.http.handler;
  2 +
  3 +import com.zhonglai.socket.html.http.service.AnalysisService;
  4 +import com.zhonglai.socket.html.http.service.impl.DefaultAnalysisServiceImpl;
  5 +import com.zhonglai.socket.html.http.util.HttpResponseUtil;
  6 +import io.netty.channel.ChannelFutureListener;
  7 +import io.netty.channel.ChannelHandler;
  8 +import io.netty.channel.ChannelHandlerContext;
  9 +import io.netty.channel.SimpleChannelInboundHandler;
  10 +import io.netty.handler.codec.http.FullHttpRequest;
  11 +import io.netty.handler.codec.http.HttpResponseStatus;
  12 +
  13 +import static io.netty.handler.codec.http.HttpMethod.GET;
  14 +import static io.netty.handler.codec.http.HttpResponseStatus.*;
  15 +
  16 +@ChannelHandler.Sharable
  17 +public class HttpServerInboundHandler extends SimpleChannelInboundHandler<FullHttpRequest> {
  18 +
  19 + AnalysisService analysisService = new DefaultAnalysisServiceImpl();
  20 +
  21 +
  22 + public HttpServerInboundHandler(AnalysisService analysisService)
  23 + {
  24 + this.analysisService = analysisService;
  25 + }
  26 +
  27 + public HttpServerInboundHandler()
  28 + {
  29 +
  30 + }
  31 +
  32 +
  33 + protected void messageReceived(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception {
  34 + if (!request.decoderResult().isSuccess()) {
  35 + sendError(ctx, BAD_REQUEST);
  36 + return;
  37 + }
  38 + if (request.method() != GET) {
  39 + sendError(ctx, METHOD_NOT_ALLOWED);
  40 + return;
  41 + }
  42 + final String uri = request.uri();
  43 + System.out.println("come here messageReceived uri="+uri);
  44 +
  45 + //这里可以根据具体的url来拆分,获取请求带过来的参数,实现自己具体的业务操作
  46 + analysisService.analysis(ctx,request);
  47 +
  48 + //sendError(ctx, UNAUTHORIZED);
  49 + }
  50 +
  51 + @Override
  52 + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
  53 + throws Exception {
  54 + cause.printStackTrace();
  55 + if (ctx.channel().isActive()) {
  56 + sendError(ctx, INTERNAL_SERVER_ERROR);
  57 + }
  58 + }
  59 +
  60 + private static void sendError(ChannelHandlerContext ctx,
  61 + HttpResponseStatus status) {
  62 + ctx.writeAndFlush(HttpResponseUtil.newERResponse(status)).addListener(ChannelFutureListener.CLOSE);
  63 + }
  64 +
  65 +}
  1 +package com.zhonglai.socket.html.http.service;
  2 +
  3 +import io.netty.channel.ChannelHandlerContext;
  4 +import io.netty.handler.codec.http.FullHttpRequest;
  5 +
  6 +public interface AnalysisService {
  7 +
  8 + public void analysis(ChannelHandlerContext ctx, FullHttpRequest request);
  9 +}
  1 +package com.zhonglai.socket.html.http.service.impl;
  2 +
  3 +import com.zhonglai.socket.html.http.service.AnalysisService;
  4 +import com.zhonglai.socket.html.http.util.HttpResponseUtil;
  5 +import io.netty.channel.ChannelHandlerContext;
  6 +import io.netty.handler.codec.http.FullHttpRequest;
  7 +
  8 +public class DefaultAnalysisServiceImpl implements AnalysisService {
  9 +
  10 + public void analysis(ChannelHandlerContext ctx, FullHttpRequest request) {
  11 + HttpResponseUtil.sendOkMessage(ctx,"http请求成功!");
  12 + }
  13 +}
  1 +package com.zhonglai.socket.html.http.service.impl;
  2 +
  3 +import com.google.gson.JsonObject;
  4 +import com.zhonglai.dto.Message;
  5 +import com.zhonglai.dto.MessageCode;
  6 +import com.zhonglai.socket.html.action.Base;
  7 +import com.zhonglai.socket.html.http.service.AnalysisService;
  8 +import com.zhonglai.socket.html.http.util.HttpResponseUtil;
  9 +import com.zhonglai.socket.html.http.util.ParameterAnalysisUtil;
  10 +import io.netty.channel.ChannelHandlerContext;
  11 +import io.netty.handler.codec.http.FullHttpRequest;
  12 +import org.apache.commons.lang3.StringUtils;
  13 +
  14 +import java.lang.reflect.InvocationTargetException;
  15 +import java.lang.reflect.Method;
  16 +import java.util.Iterator;
  17 +import java.util.Set;
  18 +
  19 +/**
  20 + * 解析2个路径协议的业务
  21 + */
  22 +public class Path2AnalysisServiceImpl implements AnalysisService {
  23 + String actionPath = "";
  24 +
  25 + public Path2AnalysisServiceImpl( String actionPath )
  26 + {
  27 + this.actionPath = actionPath;
  28 + }
  29 +
  30 + public void analysis(ChannelHandlerContext ctx, FullHttpRequest request) {
  31 + String uri = request.uri();
  32 + String path = ParameterAnalysisUtil.UrlPage(uri);
  33 + if(StringUtils.isNoneBlank(path))
  34 + {
  35 + String[] paths = path.split("/");
  36 + if(paths.length==3)
  37 + {
  38 + String clasPath = actionPath + "."+paths[1].substring(0, 1).toUpperCase() + paths[1].substring(1)+"Action";
  39 + String name = paths[2];
  40 + System.out.println("解析到执行方法路径:"+clasPath+" 执行方法名称"+name);
  41 +
  42 + JsonObject parameter = ParameterAnalysisUtil.URLRequestJson(uri); //获取url参数
  43 + if(null == parameter)
  44 + {
  45 + parameter = new JsonObject();
  46 + }
  47 +
  48 + Set set = request.headers().names();
  49 + Iterator it = set.iterator();
  50 + while(it.hasNext()){//遍历 获取head参数
  51 + Object object = it.next();
  52 + if(object instanceof String)
  53 + {
  54 + String key = (String) object;
  55 + parameter.addProperty(key,request.headers().get(key)+"");
  56 + }
  57 + }
  58 +
  59 + Class<?> cls = null; // 取得Class对象
  60 + try {
  61 + cls = Class.forName(clasPath);
  62 + Object obj = cls.newInstance(); //反射实例化对象
  63 +
  64 + Base base = (Base) obj;
  65 + base.setParameter(parameter);//先设置参数
  66 +
  67 + Method m = cls.getDeclaredMethod(name);
  68 + Message message = (Message) m.invoke(obj); //执行方法
  69 + HttpResponseUtil.sendOkMessage(ctx,message); //返回
  70 + return;
  71 + } catch (ClassNotFoundException e) {
  72 + HttpResponseUtil.sendOkMessage(ctx,new Message(MessageCode.DEFAULT_FAIL_CODE,"没有找到这个方法"+clasPath));
  73 + return;
  74 + } catch (IllegalAccessException e) {
  75 + HttpResponseUtil.sendOkMessage(ctx,new Message(MessageCode.DEFAULT_FAIL_CODE,"方法类实例失败"+clasPath));
  76 + return;
  77 + } catch (InstantiationException e) {
  78 + HttpResponseUtil.sendOkMessage(ctx,new Message(MessageCode.DEFAULT_FAIL_CODE,"方法类实例失败"+clasPath));
  79 + return;
  80 + } catch (NoSuchMethodException e) {
  81 + HttpResponseUtil.sendOkMessage(ctx,new Message(MessageCode.DEFAULT_FAIL_CODE,"方法获取失败"+clasPath+" "+name));
  82 + return;
  83 + } catch (InvocationTargetException e) {
  84 + HttpResponseUtil.sendOkMessage(ctx,new Message(MessageCode.DEFAULT_FAIL_CODE,"方法执行失败"+clasPath+" "+name));
  85 + return;
  86 + }
  87 + }
  88 + }
  89 +
  90 + HttpResponseUtil.sendOkMessage(ctx,new Message(MessageCode.DEFAULT_FAIL_CODE,"方法规则不符合协议规则"));
  91 + }
  92 +}
  1 +package com.zhonglai.socket.html.http.util;
  2 +
  3 +import com.zhonglai.dto.Message;
  4 +import com.zhonglai.serialization.GsonConstructor;
  5 +import io.netty.buffer.ByteBuf;
  6 +import io.netty.buffer.Unpooled;
  7 +import io.netty.channel.ChannelFutureListener;
  8 +import io.netty.channel.ChannelHandlerContext;
  9 +import io.netty.handler.codec.http.DefaultFullHttpResponse;
  10 +import io.netty.handler.codec.http.FullHttpResponse;
  11 +import io.netty.handler.codec.http.HttpResponseStatus;
  12 +import io.netty.util.CharsetUtil;
  13 +
  14 +import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_TYPE;
  15 +import static io.netty.handler.codec.http.HttpResponseStatus.OK;
  16 +import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
  17 +
  18 +/**
  19 + * 返回操作工具
  20 + */
  21 +public class HttpResponseUtil {
  22 + /**
  23 + * 成功返回消息
  24 + * @param ctx
  25 + * @param txt
  26 + */
  27 + public static void sendOkString(ChannelHandlerContext ctx, String txt)
  28 + {
  29 + FullHttpResponse response = newOKResponse();
  30 + StringBuilder buf = new StringBuilder();
  31 + buf.append(txt);
  32 + ByteBuf buffer = Unpooled.copiedBuffer(buf, CharsetUtil.UTF_8);
  33 + response.content().writeBytes(buffer);
  34 + buffer.release();
  35 + ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
  36 + }
  37 +
  38 + /**
  39 + * 成功返回消息
  40 + * @param ctx
  41 + * @param message
  42 + */
  43 + public static void sendOkMessage(ChannelHandlerContext ctx,Message message)
  44 + {
  45 + sendOkString(ctx, GsonConstructor.get().toJson(message));
  46 + }
  47 +
  48 + /**
  49 + * 成功返回
  50 + * @return
  51 + */
  52 + public static FullHttpResponse newOKResponse()
  53 + {
  54 + FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, OK);
  55 + response.headers().set(CONTENT_TYPE, "text/html; charset=UTF-8");
  56 + return response;
  57 + }
  58 +
  59 + /**
  60 + * 错误返回
  61 + * @param status
  62 + * @return
  63 + */
  64 + public static FullHttpResponse newERResponse(HttpResponseStatus status)
  65 + {
  66 + FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1,
  67 + status, Unpooled.copiedBuffer("Failure: " + status.toString()
  68 + + "\r\n", CharsetUtil.UTF_8));
  69 + response.headers().set(CONTENT_TYPE, "text/plain; charset=UTF-8");
  70 + return response;
  71 + }
  72 +}
  1 +package com.zhonglai.socket.html.http.util;
  2 +
  3 +import com.google.gson.JsonObject;
  4 +
  5 +import java.util.HashMap;
  6 +import java.util.Map;
  7 +
  8 +/**
  9 + * 参数解析工具
  10 + */
  11 +public class ParameterAnalysisUtil {
  12 + /**
  13 + * 解析出url请求的路径,包括页面
  14 + * @param strURL url地址
  15 + * @return url路径
  16 + */
  17 + public static String UrlPage(String strURL)
  18 + {
  19 + String strPage=null;
  20 + String[] arrSplit=null;
  21 +
  22 +// strURL=strURL.trim().toLowerCase();
  23 +
  24 + arrSplit=strURL.split("[?]");
  25 + if(strURL.length()>0)
  26 + {
  27 + if(arrSplit.length>=1)
  28 + {
  29 + if(arrSplit[0]!=null)
  30 + {
  31 + strPage=arrSplit[0];
  32 + }
  33 + }
  34 + }
  35 +
  36 + return strPage;
  37 + }
  38 + /**
  39 + * 去掉url中的路径,留下请求参数部分
  40 + * @param strURL url地址
  41 + * @return url请求参数部分
  42 + */
  43 + private static String TruncateUrlPage(String strURL)
  44 + {
  45 + String strAllParam=null;
  46 + String[] arrSplit=null;
  47 +
  48 + strURL=strURL.trim().toLowerCase();
  49 +
  50 + arrSplit=strURL.split("[?]");
  51 + if(strURL.length()>1)
  52 + {
  53 + if(arrSplit.length>1)
  54 + {
  55 + if(arrSplit[1]!=null)
  56 + {
  57 + strAllParam=arrSplit[1];
  58 + }
  59 + }
  60 + }
  61 +
  62 + return strAllParam;
  63 + }
  64 +
  65 + /**
  66 + * 解析出url参数中的键值对
  67 + * 如 "index.jsp?Action=del&id=123",解析出Action:del,id:123存入map中
  68 + * @param URL url地址
  69 + * @return url请求参数部分
  70 + */
  71 + public static Map<String, String> URLRequestMap(String URL)
  72 + {
  73 + Map<String, String> mapRequest = new HashMap<String, String>();
  74 +
  75 + String[] arrSplit=null;
  76 +
  77 + String strUrlParam=TruncateUrlPage(URL);
  78 + if(strUrlParam==null)
  79 + {
  80 + return mapRequest;
  81 + }
  82 + //每个键值为一组 www.2cto.com
  83 + arrSplit=strUrlParam.split("[&]");
  84 + for(String strSplit:arrSplit)
  85 + {
  86 + String[] arrSplitEqual=null;
  87 + arrSplitEqual= strSplit.split("[=]");
  88 +
  89 + //解析出键值
  90 + if(arrSplitEqual.length>1)
  91 + {
  92 + //正确解析
  93 + mapRequest.put(arrSplitEqual[0], arrSplitEqual[1]);
  94 +
  95 + }
  96 + else
  97 + {
  98 + if(arrSplitEqual[0]!="")
  99 + {
  100 + //只有参数没有值,不加入
  101 + mapRequest.put(arrSplitEqual[0], "");
  102 + }
  103 + }
  104 + }
  105 + return mapRequest;
  106 + }
  107 +
  108 +
  109 + /**
  110 + * 解析出url参数中的键值对
  111 + * 如 "index.jsp?Action=del&id=123",解析出Action:del,id:123存入map中
  112 + * @param URL url地址
  113 + * @return url请求参数部分
  114 + */
  115 + public static JsonObject URLRequestJson(String URL)
  116 + {
  117 + JsonObject jsonObject = new JsonObject();
  118 +
  119 + String[] arrSplit=null;
  120 +
  121 + String strUrlParam=TruncateUrlPage(URL);
  122 + if(strUrlParam==null)
  123 + {
  124 + return jsonObject;
  125 + }
  126 + //每个键值为一组 www.2cto.com
  127 + arrSplit=strUrlParam.split("[&]");
  128 + for(String strSplit:arrSplit)
  129 + {
  130 + String[] arrSplitEqual=null;
  131 + arrSplitEqual= strSplit.split("[=]");
  132 +
  133 + //解析出键值
  134 + if(arrSplitEqual.length>1)
  135 + {
  136 + //正确解析
  137 + jsonObject.addProperty(arrSplitEqual[0], arrSplitEqual[1]);
  138 +
  139 + }
  140 + else
  141 + {
  142 + if(arrSplitEqual[0]!="")
  143 + {
  144 + //只有参数没有值,不加入
  145 + jsonObject.addProperty(arrSplitEqual[0], "");
  146 + }
  147 + }
  148 + }
  149 + return jsonObject;
  150 + }
  151 +}