基于netty的http服务器并整合springboot

1 篇文章 0 订阅

概述:

这是一个基于netty的http服务器其中整合了spring的相关配置 ,但是他只是在大体上实现了http的功能对于映射他的实现方法是一个类一个映射而不是mvc的一个类多个映射。-这是本人在git上找到的netty工程我在上面进行了比较详细的注解方便与新学的或者相对spring框架的注解配置有些更深入的理解。

如果想看spring框架初始化中对注解做的一些匹配工作可以看链接:https://blog.csdn.net/horse_xiao/article/details/95020952

源码链接:https://github.com/flytotop/netty-http-server

启动类

对于spring boot来说该框架整合了tomcat所以如果你需要编写属于自己的http服务器那么首先你需要要停止tomcat的启动 并将netty启动类加载到配置项。

package com.farsunset.httpserver;

import com.farsunset.httpserver.netty.annotation.NettyHttpHandler;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication()
//
@ComponentScan(includeFilters = @ComponentScan.Filter(NettyHttpHandler.class))

public class HttpServerApplication {

    public static void main(String[] args) {
        //停止tomcat的相关启动
        new SpringApplicationBuilder(HttpServerApplication.class).web(WebApplicationType.NONE).run(args);
    }

}

接下来就是编写netty的相关信息 首先就是启动类

package com.farsunset.httpserver.configuration;

import com.farsunset.httpserver.netty.iohandler.InterceptorHandler;
import com.farsunset.httpserver.netty.iohandler.FilterLogginglHandler;
import com.farsunset.httpserver.netty.iohandler.HttpServerHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioChannelOption;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.event.ApplicationStartedEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Configuration;
import org.springframework.lang.NonNull;

import javax.annotation.Resource;


@Configuration
public class NettyHttpServer implements ApplicationListener<ApplicationStartedEvent> {

    private static final Logger LOGGER = LoggerFactory.getLogger(NettyHttpServer.class);

    @Value("${server.port}")
    private int port;

    @Resource
    private InterceptorHandler interceptorHandler;

    @Resource
    private HttpServerHandler httpServerHandler;

    @Override
    public void onApplicationEvent(@NonNull ApplicationStartedEvent event) {

        ServerBootstrap bootstrap = new ServerBootstrap();
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        bootstrap.group(bossGroup, workerGroup);
        bootstrap.channel(NioServerSocketChannel.class);
        //channel的属性配置
        bootstrap.childOption(NioChannelOption.TCP_NODELAY, true);//是否使用fullrequest fullresponse发送数据
        bootstrap.childOption(NioChannelOption.SO_REUSEADDR,true);  //是否允许端口占用
        bootstrap.childOption(NioChannelOption.SO_KEEPALIVE,false);//是否设置长连接
        bootstrap.childOption(NioChannelOption.SO_RCVBUF, 2048); //设置接收数据大小
        bootstrap.childOption(NioChannelOption.SO_SNDBUF, 2048);//设置发送数据大小
        bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
            @Override
            public void initChannel(SocketChannel ch) {
                ch.pipeline().addLast("codec", new HttpServerCodec());//http编解码器
                //对httpmsg进行聚合 转化为fullHttpRequest 或者fullHttpResponse并设置最大数据长度
                ch.pipeline().addLast("aggregator", new HttpObjectAggregator(512 * 1024));
                ch.pipeline().addLast("logging", new FilterLogginglHandler());//日志
                ch.pipeline().addLast("interceptor", interceptorHandler);//拦截器配置
                ch.pipeline().addLast("bizHandler", httpServerHandler); //请求匹配处理
            }
        })
        ;

        ChannelFuture channelFuture = bootstrap.bind(port).syncUninterruptibly().addListener(future -> {
            String logBanner = "\n\n" +
                    "* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n" +
                    "*                                                                                   *\n" +
                    "*                                                                                   *\n" +
                    "*                   Netty Http Server started on port {}.                           *\n" +
                    "*                                                                                   *\n" +
                    "*                                                                                   *\n" +
                    "* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n";
            LOGGER.info(logBanner, port);
        });
        //通过引入监听器对象监听future状态,当future任务执行完成后会调用-》{}内的方法
        channelFuture.channel().closeFuture().addListener(future -> {
            LOGGER.info("Netty Http Server Start Shutdown ............");
            /**
             * 优雅关闭
             */
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();

        });


    }



}

 

日志处理器配置

package com.farsunset.httpserver.netty.iohandler;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;

import java.net.SocketAddress;

import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_LENGTH;
import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_TYPE;

public class FilterLogginglHandler extends LoggingHandler {
    public FilterLogginglHandler() {
        super(LogLevel.INFO);
    }

    @Override
    public void channelRegistered(ChannelHandlerContext ctx) {
        ctx.fireChannelRegistered();
    }

    @Override
    public void channelUnregistered(ChannelHandlerContext ctx) {
        ctx.fireChannelUnregistered();
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        ctx.fireChannelActive();
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) {
        ctx.fireChannelInactive();
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
        ctx.fireUserEventTriggered(evt);
    }

    @Override
    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise){
        if (this.logger.isEnabled(this.internalLevel)) {
            this.logger.log(this.internalLevel,ctx.channel().toString() + " WRITE \n" + msg.toString());
        }

        ctx.write(msg, promise);
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg)   {
        if (this.logger.isEnabled(this.internalLevel)) {
            HttpRequest request = (HttpRequest) msg;
            String log = request.method() + " " + request.uri() + " " + request.protocolVersion() + "\n" +
                    CONTENT_TYPE + ": " + request.headers().get(CONTENT_TYPE) + "\n" +
                    CONTENT_LENGTH + ": " + request.headers().get(CONTENT_LENGTH) + "\n";
            this.logger.log(this.internalLevel,ctx.channel().toString() + " READ \n" + log);
        }
        /**
         * 请求转发给下个处理器
         */
        ctx.fireChannelRead(msg);
    }




    @Override
    public void bind(ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) {
        ctx.bind(localAddress, promise);
    }

    @Override
    public void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) {
        ctx.connect(remoteAddress, localAddress, promise);
    }

    @Override
    public void disconnect(ChannelHandlerContext ctx, ChannelPromise promise) {
        ctx.disconnect(promise);
    }

    @Override
    public void close(ChannelHandlerContext ctx, ChannelPromise promise) {
        ctx.close(promise);
    }

    @Override
    public void deregister(ChannelHandlerContext ctx, ChannelPromise promise) {
        ctx.deregister(promise);
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) {
        ctx.fireChannelReadComplete();
    }

    @Override
    public void channelWritabilityChanged(ChannelHandlerContext ctx) {
        ctx.fireChannelWritabilityChanged();
    }

    @Override
    public void flush(ChannelHandlerContext ctx) {
        ctx.flush();
    }
}

 

对于客户端的请求在这里封装了两个对象用来接收Fullhttprequest 的和用来发送response的fuhttpreponse

package com.farsunset.httpserver.netty.http;

import io.netty.buffer.ByteBuf;
import io.netty.handler.codec.DecoderResult;
import io.netty.handler.codec.http.*;

import java.nio.charset.Charset;
import java.util.Objects;

public class NettyHttpRequest  implements FullHttpRequest  {

    private FullHttpRequest realRequest;

    public NettyHttpRequest(FullHttpRequest request){
        this.realRequest = request;
    }

    public String contentText(){
        return content().toString(Charset.forName("UTF-8"));
    }

    public long getLongPathValue(int index){
        String[] paths = uri().split("/");
        return Long.parseLong(paths[index]);
    }

    public String getStringPathValue(int index){
        String[] paths = uri().split("/");
        return paths[index];
    }

    public int getIntPathValue(int index){
        String[] paths = uri().split("/");
        return Integer.parseInt(paths[index]);
    }


    public boolean isAllowed(String method){
        return getMethod().name().equalsIgnoreCase(method);
    }

    public boolean matched(String path,boolean equal){
        String uri = uri().toLowerCase();
        return equal ? Objects.equals(path,uri) : uri.startsWith(path);
    }

    @Override
    public ByteBuf content() {
        return realRequest.content();
    }

    @Override
    public HttpHeaders trailingHeaders() {
        return realRequest.trailingHeaders();
    }

    @Override
    public FullHttpRequest copy() {
        return realRequest.copy();
    }

    @Override
    public FullHttpRequest duplicate() {
        return realRequest.duplicate();
    }

    @Override
    public FullHttpRequest retainedDuplicate() {
        return realRequest.retainedDuplicate();
    }

    @Override
    public FullHttpRequest replace(ByteBuf byteBuf) {
        return realRequest.replace(byteBuf);
    }

    @Override
    public FullHttpRequest retain(int i) {
        return realRequest.retain(i);
    }

    @Override
    public int refCnt() {
        return realRequest.refCnt();
    }

    @Override
    public FullHttpRequest retain() {
        return realRequest.retain();
    }

    @Override
    public FullHttpRequest touch() {
        return realRequest.touch();
    }

    @Override
    public FullHttpRequest touch(Object o) {
        return realRequest.touch(o);
    }

    @Override
    public boolean release() {
        return realRequest.release();
    }

    @Override
    public boolean release(int i) {
        return realRequest.release(i);
    }

    @Override
    public HttpVersion getProtocolVersion() {
        return realRequest.protocolVersion();
    }

    @Override
    public HttpVersion protocolVersion() {
        return realRequest.protocolVersion();
    }

    @Override
    public FullHttpRequest setProtocolVersion(HttpVersion httpVersion) {
        return realRequest.setProtocolVersion(httpVersion);
    }

    @Override
    public HttpHeaders headers() {
        return realRequest.headers();
    }

    @Override
    public HttpMethod getMethod() {
        return realRequest.getMethod();
    }

    @Override
    public HttpMethod method() {
        return realRequest.method();
    }

    @Override
    public FullHttpRequest setMethod(HttpMethod httpMethod) {
        return realRequest.setMethod(httpMethod);
    }

    @Override
    public String getUri() {
        return realRequest.getUri();
    }

    @Override
    public String uri() {
        return realRequest.uri();
    }

    @Override
    public FullHttpRequest setUri(String s) {
        return realRequest.setUri(s);
    }

    @Override
    public DecoderResult getDecoderResult() {
        return realRequest.getDecoderResult();
    }

    @Override
    public DecoderResult decoderResult() {
        return realRequest.decoderResult();
    }

    @Override
    public void setDecoderResult(DecoderResult decoderResult) {
        realRequest.setDecoderResult(decoderResult);
    }
}
package com.farsunset.httpserver.netty.http;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;

import static io.netty.handler.codec.http.HttpHeaderNames.*;

public class NettyHttpResponse extends DefaultFullHttpResponse {

    private static final PooledByteBufAllocator BYTE_BUF_ALLOCATOR = new PooledByteBufAllocator(false);
    /**
     * 状态码设置
     */
    private static final String CONTENT_NORMAL_200 = "{\"code\":200,\"message\":\"OK\"}";
    private static final String CONTENT_ERROR_401 = "{\"code\":401,\"message\":\"UNAUTHORIZED\"}";
    private static final String CONTENT_ERROR_404 = "{\"code\":404,\"message\":\"REQUEST PATH NOT FOUND\"}";
    private static final String CONTENT_ERROR_405 = "{\"code\":405,\"message\":\"METHOD NOT ALLOWED\"}";
    private static final String CONTENT_ERROR_500 = "{\"code\":500,\"message\":\"%s\"}";

    private String content;

    private NettyHttpResponse(HttpResponseStatus status, ByteBuf buffer ) {
        super(HttpVersion.HTTP_1_1, status,buffer);
        headers().set(CONTENT_TYPE, "application/json");
        headers().setInt(CONTENT_LENGTH, content().readableBytes());

        /**
         * 支持CORS 跨域访问
         */
        headers().set(ACCESS_CONTROL_ALLOW_ORIGIN, "*");
        headers().set(ACCESS_CONTROL_ALLOW_HEADERS, "Origin, X-Requested-With, Content-Type, Accept, RCS-ACCESS-TOKEN");
        headers().set(ACCESS_CONTROL_ALLOW_METHODS, "GET,POST,PUT,DELETE");
    }

    public static FullHttpResponse make(HttpResponseStatus status) {
        if (HttpResponseStatus.UNAUTHORIZED == status) {
            return NettyHttpResponse.make(HttpResponseStatus.UNAUTHORIZED, CONTENT_ERROR_401);
        }
        if (HttpResponseStatus.NOT_FOUND == status) {
            return NettyHttpResponse.make(HttpResponseStatus.NOT_FOUND, CONTENT_ERROR_404);
        }
        if (HttpResponseStatus.METHOD_NOT_ALLOWED == status) {
            return NettyHttpResponse.make(HttpResponseStatus.METHOD_NOT_ALLOWED, CONTENT_ERROR_405);
        }
        return NettyHttpResponse.make(HttpResponseStatus.OK,CONTENT_NORMAL_200);
    }

    public static FullHttpResponse makeError(Exception exception) {
        String message = exception.getClass().getName() + ":" + exception.getMessage();
        return NettyHttpResponse.make(HttpResponseStatus.INTERNAL_SERVER_ERROR, String.format(CONTENT_ERROR_500,message));
    }

    public static FullHttpResponse ok(String content) {
        return make(HttpResponseStatus.OK,content);
    }

    private static FullHttpResponse make(HttpResponseStatus status,String content) {
        byte[] body = content.getBytes();
        ByteBuf buffer = BYTE_BUF_ALLOCATOR.buffer(body.length);
        buffer.writeBytes(body);
        NettyHttpResponse response = new NettyHttpResponse(status,buffer);
        response.content = content;
        return response;
    }

    @Override
    public String toString(){
        StringBuilder builder = new StringBuilder();
        builder.append(protocolVersion().toString()).append(" ").append(status().toString()).append("\n");
        builder.append(CONTENT_TYPE).append(": ").append(headers().get(CONTENT_TYPE)).append("\n");
        builder.append(CONTENT_LENGTH).append(": ").append(headers().get(CONTENT_LENGTH)).append("\n");
        builder.append("content-body").append(": ").append(content).append("\n");
        return builder.toString();
    }
}

拦截处理器

package com.farsunset.httpserver.netty.iohandler;

import com.farsunset.httpserver.netty.http.NettyHttpResponse;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.util.ReferenceCountUtil;
import org.springframework.stereotype.Component;


@ChannelHandler.Sharable
@Component
/**
 * 在这里可以做拦截器,验证一些请求的合法性
 */
public class InterceptorHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext context, Object msg)   {
        if (isPassed((FullHttpRequest) msg)){
            /**
             * 提交给下一个ChannelHandler去处理
             * 并且不需要调用ReferenceCountUtil.release(msg);来释放引用计数
             */
            context.fireChannelRead(msg);
            return;
        }
        /**
         * 非异常引起的错误需要手动关闭channel通道
         */
        ReferenceCountUtil.release(msg);
        context.writeAndFlush(NettyHttpResponse.make(HttpResponseStatus.UNAUTHORIZED)).addListener(ChannelFutureListener.CLOSE);
    }

    /**
     * 修改实现来验证合法性
     * @param request
     * @return
     */
    private boolean isPassed(FullHttpRequest request){
        return true;
    }
}

请求处理器

package com.farsunset.httpserver.netty.iohandler;

import com.farsunset.httpserver.dto.Response;
import com.farsunset.httpserver.netty.annotation.NettyHttpHandler;
import com.farsunset.httpserver.netty.exception.IllegalMethodNotAllowedException;
import com.farsunset.httpserver.netty.exception.IllegalPathDuplicatedException;
import com.farsunset.httpserver.netty.exception.IllegalPathNotFoundException;
import com.farsunset.httpserver.netty.handler.IFunctionHandler;
import com.farsunset.httpserver.netty.http.NettyHttpRequest;
import com.farsunset.httpserver.netty.http.NettyHttpResponse;
import com.farsunset.httpserver.netty.path.Path;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.util.ReferenceCountUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Predicate;
import java.util.stream.Stream;

@ChannelHandler.Sharable
@Component
    /**
     * 通过实现ApplicationContextAware将setApplicationContext()函数引入spring初始化内容中去
     */
    public class HttpServerHandler extends SimpleChannelInboundHandler<FullHttpRequest> implements ApplicationContextAware {

    private static final Logger LOGGER = LoggerFactory.getLogger(HttpServerHandler.class);

    private HashMap<Path, IFunctionHandler> functionHandlerMap = new HashMap<>();

    /**
     * 线程工厂
     */
    private ExecutorService executor = Executors.newCachedThreadPool(runnable -> {
        Thread thread = Executors.defaultThreadFactory().newThread(runnable);
        thread.setName("NettyHttpHandler-" + thread.getName());
        return thread;
    });

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) {
        ctx.flush();
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) {
        FullHttpRequest copyRequest = request.copy();
        /**
         * 通过内部类的形式传入一个runnable的实现类并重写了run方法 线程池在执行的时候会调用这个方法
         */
        executor.execute(() -> onReceivedRequest(ctx,new NettyHttpRequest(copyRequest)));
    }

    /**
     *
      * @param context
     * @param request
     */
    private void onReceivedRequest(ChannelHandlerContext context, NettyHttpRequest request){
        /**
         * 处理request请求
         */
        FullHttpResponse response = handleHttpRequest(request);
        /**
         * 通过channel将结果输出 并通过添加监听器的方式关闭channel通道
         */
        context.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
        /**
         * 释放bytebuf缓存
         */
        ReferenceCountUtil.release(request);
    }

    /**
     *
     * @param request NettyHttpRequest extends Fullhttpreuqest
     * @return 请求处理结果
     */
    private FullHttpResponse handleHttpRequest(NettyHttpRequest request) {

        IFunctionHandler functionHandler = null;
        /**
         * 请求处理并根据不同的结果或者捕获的异常进行状态码转换并返回
         */
        try {
            functionHandler = matchFunctionHandler(request);
            //这边通过注解与请求路径的匹配获得相应的处理器对象之后通过对接口方法的调用达到方法执行的效果
            Response response =  functionHandler.execute(request);
            return NettyHttpResponse.ok(response.toJSONString());
        }
        catch (IllegalMethodNotAllowedException error){
            return NettyHttpResponse.make(HttpResponseStatus.METHOD_NOT_ALLOWED);
        }
        catch (IllegalPathNotFoundException error){
            return NettyHttpResponse.make(HttpResponseStatus.NOT_FOUND);
        }
        catch (Exception error){
            LOGGER.error(functionHandler.getClass().getSimpleName() + " Error",error);
            return NettyHttpResponse.makeError(error);
        }
    }

    /**
     * spring初始化加载此函数
     * @param applicationContext
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        /**
         * 获得所有NettyHttpHandler的注解类
         */
        Map<String, Object> handlers =  applicationContext.getBeansWithAnnotation(NettyHttpHandler.class);
        for (Map.Entry<String, Object> entry : handlers.entrySet()) {
            Object handler = entry.getValue();
            Path path = Path.make(handler.getClass().getAnnotation(NettyHttpHandler.class));
            /**
             * 查询是否当前处理器的注解是否已经存在(类似于SSM中controler的注解不能重复)
             * 1.存在则抛出异常
             * 2. 不存在则存入Map集合中 在SSM中是通过对类方法注解的扫描 存入内部类mapperRegistry中
             */
            if (functionHandlerMap.containsKey(path)){
                LOGGER.error("IFunctionHandler has duplicated :" + path.toString(),new IllegalPathDuplicatedException());
                System.exit(0);
            }
            functionHandlerMap.put(path, (IFunctionHandler) handler);
        }
    }

    private IFunctionHandler matchFunctionHandler(NettyHttpRequest request) throws IllegalPathNotFoundException, IllegalMethodNotAllowedException {

        AtomicBoolean matched = new AtomicBoolean(false);

        Stream<Path> stream = functionHandlerMap.keySet().stream()
                .filter(((Predicate<Path>) path -> {
                    /**
                     *过滤 Path URI 不匹配的
                     */
                    if (request.matched(path.getUri(), path.isEqual())) {
                        matched.set(true);
                        return matched.get();
                    }
                    return false;

                }).and(path -> {
                    /**
                     * 过滤 Method 匹配的
                     */
                    return request.isAllowed(path.getMethod());
                }));

        Optional<Path> optional = stream.findFirst();

        stream.close();

        if (!optional.isPresent() && !matched.get()){
            throw  new IllegalPathNotFoundException();
        }

        if (!optional.isPresent() && matched.get()){
            throw  new IllegalMethodNotAllowedException();
        }

        return functionHandlerMap.get(optional.get());
    }

}

请求处理这边设置了一些对与访问异常的处理

package com.farsunset.httpserver.netty.exception;

public class IllegalMethodNotAllowedException extends Exception {
    public IllegalMethodNotAllowedException() {
        super("METHOD NOT ALLOWED");
    }
}

----------------------------------------------------------------------------------------------------------------------------------------------------------------

package com.farsunset.httpserver.netty.exception;

public class IllegalPathNotFoundException extends Exception {
    public IllegalPathNotFoundException() {
        super("PATH NOT FOUND");
    }
}

 

控制层示例

-

package com.farsunset.httpserver.netty.handler;

import com.farsunset.httpserver.dto.Response;
import com.farsunset.httpserver.netty.annotation.NettyHttpHandler;
import com.farsunset.httpserver.netty.http.NettyHttpRequest;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;


@NettyHttpHandler(path = "/moment/list/",equal = false)
public class PathVariableHandler implements IFunctionHandler<List<HashMap<String,String>>> {
    @Override
    public Response<List<HashMap<String,String>>> execute(NettyHttpRequest request) {

        /**
         * 通过请求uri获取到path参数
         */
        String id = request.getStringPathValue(3);

        List<HashMap<String,String>> list = new LinkedList<>();
        HashMap<String,String> data = new HashMap<>();
        data.put("id","1");
        data.put("name","Bluesky");
        data.put("text","hello sea!");
        data.put("time","2018-08-08 08:08:08");
        list.add(data);
        return Response.ok(list);
    }
}

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值