Netty练手项目-简单Http服务器

<!--netty依赖-->
    <dependency>
      <groupId>io.netty</groupId>
      <artifactId>netty-all</artifactId>
      <version>4.1.20.Final</version>
    </dependency>

 

  简单的设计思路就是,启动一个可以截断并处理Http请求的服务器代码。使用netty提供的boss线程与worker线程的模型,并使用netty的http解码器。自行编写了http url处理的部分。在接口层面,使用json作为格式。

  初始化扫描会指定扫描controller.container下的类,使用了自定义Annotation并且单例的方式加载,未考虑太多细节就为了好玩。

 

   接下来使用postman尝试调用接口。

  一个简单的netty搭建的web服务就完成了。

package server;

import handler.HttpServerHandler;
import initScan.InitialProcess;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
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.HttpServerCodec;

/**
 * Created by MacBook on 2019/7/14.
 */
public class ServerStarter {

    private EventLoopGroup boss ;

    private EventLoopGroup worker ;

    private int port;

    private static int DEFAULT_PORT = 8080;

    public ServerStarter(){
        boss = new NioEventLoopGroup();
        worker = new NioEventLoopGroup();
        port = DEFAULT_PORT;
    }

    public ServerStarter(int port){
        this();
        if(port < 0 || port > 65535){
            throw new IllegalArgumentException("port:"+port+" is illegal");
        }
        this.port = port;
    }

    public void startup() throws InterruptedException{

        if(boss.isShutdown() || worker.isShutdown()){
            throw new IllegalStateException("server was closed");
        }

        // 初始化容器
        InitialProcess initialProcess = new InitialProcess();
        initialProcess.init();

        ServerBootstrap serverBootstrap = new ServerBootstrap();
        System.out.println("=====http server start ");
        serverBootstrap.channel(NioServerSocketChannel.class)
                .group(boss,worker)
                .childOption(ChannelOption.SO_KEEPALIVE,true)
                .option(ChannelOption.SO_BACKLOG,1024)
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        socketChannel.pipeline().addLast("http-decode",new HttpServerCodec());
                        socketChannel.pipeline().addLast(new HttpServerHandler());
                    }
                });

        ChannelFuture future = serverBootstrap.bind(port).sync();

        System.out.println("server port listen:"+port);

        future.channel().closeFuture().sync();

        shutDownGracefully();
    }

    /**
     * 关闭管道
     */
    public void shutDownGracefully(){
        this.boss.shutdownGracefully();
        this.worker.shutdownGracefully();
    }

}

  这是服务器启动的核心代码,首先初始化两个Nio线程组,把它们绑定到ServerBootstrap里,并添加Handler。

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.Feature;
import com.alibaba.fastjson.serializer.SerializeConfig;
import com.alibaba.fastjson.serializer.SerializerFeature;
import controller.Properties;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.*;
import response.BaseResponse;

import java.lang.reflect.Method;

/**
 * Created by MacBook on 2019/7/14.
 */
public class HttpServerHandler extends ChannelInboundHandlerAdapter{

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        if(msg instanceof HttpRequest){
            HttpRequest request = (HttpRequest)msg;
//            boolean keepAlive = HttpUtil.isKeepAlive(request);

            System.out.println("http request method :"+request.method());
            System.out.println("http request uri : "+request.uri());

            Object controller = Properties.urlController.get(request.uri());
            Method m = Properties.urlMethod.get(request.uri());
            if(controller == null){
                FullHttpResponse httpResponse = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.NOT_FOUND);
                ctx.writeAndFlush(httpResponse).addListener(ChannelFutureListener.CLOSE);

            }else {
                FullHttpResponse httpResponse = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);

                httpResponse.headers().set(HttpHeaderNames.CONTENT_TYPE, "application/json");
                Object result = m.invoke(controller);

                httpResponse.content().writeBytes(JSON.toJSONString(result,SerializerFeature.WriteMapNullValue).getBytes());

                ctx.writeAndFlush(httpResponse).addListener(ChannelFutureListener.CLOSE);
            }

        }
    }
}

  这是处理器的代码,在经过第一个Http解码器之后,进来的对象msg已经被转化为HttpRequest了。

 

posted @ 2019-08-18 17:31  天目山电鳗  阅读(1555)  评论(1编辑  收藏  举报