Netty(三) http協議開發應用

ps:太困了,後面再寫

github地址:https://github.com/MrBack/hello

一、創建NettyServer

package back.netty.server;

import back.config.ConfigUtils;
import com.typesafe.config.Config;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;

/**
 * Lession5 : Netty實現的Http協議 寫一個簡單web服務器
 */
public class NettyServer {

    private NettyServer(){};
    private static NettyServer nettyServer = new NettyServer();
    public static NettyServer getInstance(){
        return nettyServer;
    }
    private volatile static EventLoopGroup workerGroup = null;
    private volatile static EventLoopGroup bossGroup = null;
    private volatile static ServerBootstrap serverBootstrap = null;

    public void start(){
        Config config = ConfigUtils.getConfig();
        int port = config.getInt("server.port");

        if(workerGroup == null){
            synchronized (NettyServer.class){
                if(workerGroup == null){
                    workerGroup = new NioEventLoopGroup();
                }
            }
        }

        if(bossGroup == null){
            synchronized (NettyServer.class){
                if(bossGroup == null){
                    bossGroup = new NioEventLoopGroup();
                }
            }
        }

        if(serverBootstrap == null){
            synchronized (NettyServer.class){
                if(serverBootstrap == null){
                    try{
                        serverBootstrap = new ServerBootstrap();
                        serverBootstrap.group(bossGroup, workerGroup)
                                .channel(NioServerSocketChannel.class)
                                .option(ChannelOption.SO_BACKLOG, 1024)
                                .childHandler(new ChildChannelHandler());
                        ChannelFuture future = serverBootstrap.bind(port).sync();
                        String url = config.getString("server.host") + ":" + port;
                        System.out.println("Netty服務開啓 ! 請求url:http://" + url);
                        future.channel().closeFuture().sync();
                    }catch (Exception e){
                        System.out.println("異常信息:" + e.getStackTrace());
                    }finally {
                        this.close();
                    }
                }
            }
        }
    }

    private void close(){
        if(bossGroup != null){
            bossGroup.shutdownGracefully();
        }
        if(workerGroup != null){
            workerGroup.shutdownGracefully();
        }
    }

    public static void main(String[] args) {

        NettyServer.getInstance().start();
    }
}

 

2、設置http相關編解碼器、業務處理器

public class ChildChannelHandler extends ChannelInitializer<SocketChannel> {

    @Override
    protected void initChannel(SocketChannel socketChannel) throws Exception {
        socketChannel.pipeline().addLast("http-decoder", new HttpRequestDecoder());
        socketChannel.pipeline().addLast("http-aggregator", new HttpObjectAggregator(65536));
        socketChannel.pipeline().addLast("http-encoder", new HttpResponseEncoder());
        socketChannel.pipeline().addLast("http-chunked", new ChunkedWriteHandler());
        socketChannel.pipeline().addLast("fileServerHandler", new HttpFileServerHandler());
    }
}

 

3、業務處理器

public class HttpFileServerHandler extends SimpleChannelInboundHandler<FullHttpRequest> {

    @Override
    protected void messageReceived(ChannelHandlerContext channelHandlerContext, FullHttpRequest fullHttpRequest) throws Exception {

        //1、uri
        String uri = fullHttpRequest.uri();
        System.out.println("uri : " +uri);
        ByteBuf byteBuf = fullHttpRequest.content();
        String params = byteBuf.toString();
        System.out.println("params : " + params);

        HttpMethod method = fullHttpRequest.method();
        System.out.println("http method : " + method.name());

        HttpVersion httpVersion = fullHttpRequest.protocolVersion();
        System.out.println("httpVersion : " + httpVersion);

        HttpHeaders headers = fullHttpRequest.headers();
        System.out.println("headers : ");
        headers.forEach(entry -> {
            System.out.println("key :" + entry.getKey() + ", value : " + entry.getValue());
        });
        Object resp = null;
        BeanFactory.start();
        ActionBean actionBean = BeanFactory.map.get(method.toString()).get(uri);
        if(actionBean != null){
            Method method1 = actionBean.getMethod();
            Object bean = actionBean.getBean();
            resp = method1.invoke(bean);
        }
        response(channelHandlerContext, resp);
    }

    private void response(ChannelHandlerContext ctx, Object resp){

        String parse = JsonUtils.parse(resp);
        System.out.println("Response : " + parse);
        DefaultFullHttpResponse defaultFullHttpResponse = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.copiedBuffer(parse.getBytes()));
        defaultFullHttpResponse.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/html; charset=UTF-8");
        ctx.writeAndFlush(defaultFullHttpResponse).addListener(ChannelFutureListener.CLOSE);
        System.out.println("===========================================================================");
    }
}

4、上面的BeanFactory 模仿Spring controller簡單實現

public class BeanFactory {

    public static Map<String,Map<String, ActionBean>> map = new HashMap<>();

    public static void start(){
        Reflections reflections = new Reflections("back.controller");
        Set<Class<?>> controllers = reflections.getTypesAnnotatedWith(Controller.class);
        if(controllers != null){
            controllers.stream().forEach(clazz -> {
                Controller annotation = clazz.getAnnotation(Controller.class);
                String rootUri = annotation.value();
                Object controllerBean = null;
                try {
                    controllerBean = clazz.newInstance();
                } catch (InstantiationException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
                Method[] methods = clazz.getMethods();
                if(methods != null){
                    final Object obj = controllerBean;
                    for (Method method : methods){
                        if(method.isAnnotationPresent(RequestMapping.class)){
                            RequestMapping rm = method.getAnnotation(RequestMapping.class);
                            String httpMethod = rm.method();
                            HttpMethod httpMethod1 = HttpMethod.valueOf(httpMethod);
                            String methodUri = rm.value();
                            String uri = rootUri + methodUri;

                            map.compute(httpMethod, (k,v) ->{
                                if(v==null){
                                    v = new HashMap<>();
                                }
                                ActionBean actionBean = new ActionBean();
                                actionBean.setMethod(method);
                                actionBean.setBean(obj);
                                v.put(uri, actionBean);
                            return v;
                        });
                        }
                    }
                }
            });
        }
    }
}

5、ActionBean定義

@Data
public class ActionBean {
    private Method method;
    private Object bean;
}

6、模擬http請求NettyServer查看結果;

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章