Netty搭建一个简单的http服务

基本需求:
1.用netty搭建一个http协议请求,并能接受到POST和GET的请求。
2.模拟spring的DispatcherServlet,业务层的分发操作

小编是使用gradle进行搭建项目的,开发工具的eclipse,不多说,直接上代码!

最后有源码下载地址!!!!(重要事情说三遍)
最后有源码下载地址!!!!(重要事情说三遍)
最后有源码下载地址!!!!(重要事情说三遍)

用netty搭建一个http协议请求,并能接受到POST和GET的请求。

利用gradle添加要用到的依赖包

        compile group: 'com.google.protobuf', name: 'protobuf-java', version: '3.5.1'
        compile group: 'io.netty', name: 'netty-all', version: '4.1.25.Final'
        compile group: 'org.springframework', name: 'spring-context', version: '5.0.7.RELEASE'
        compile group: 'org.springframework', name: 'spring-core', version: '5.0.7.RELEASE'
        compile group: 'org.springframework', name: 'spring-beans', version: '5.0.7.RELEASE'
        compile group: 'org.springframework', name: 'spring-context-support', version: '5.0.7.RELEASE'
        compile group: 'org.codehaus.groovy', name: 'groovy-all', version: '2.4.15'        
        compile group: 'com.google.guava', name: 'guava', version: '25.1-jre'
        compile group: 'com.alibaba', name: 'fastjson', version: '1.2.58'    
        compile group: 'org.slf4j', name: 'slf4j-api', version: '1.7.25'
        compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.7'      
        compile group: 'commons-lang', name: 'commons-lang', version: '2.6'     
        compile group: 'commons-net', name: 'commons-net', version: '3.6'
        compileOnly group: 'org.projectlombok', name: 'lombok', version: '1.18.0'

利用spring boot的启动方式:

/**
 * Netty http 启动类
 * 
 * @bk https://home.cnblogs.com/u/huanuan/
 * @简书 https://www.jianshu.com/u/d29cc7d7ca49
 * @Author 六月星辰
 * @Date 2020年1月10日
 */
@Slf4j
public class HttpServerApp {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig.class);
        context.start();
        HttpServer bean = context.getBean(HttpServer.class);
        // 安排独立的一条线程进行启动http服务,
        new Thread(new NettyHttpServer(bean)).start();
        ;
    }
}

springBean加载和相关配置的初始化

/**
 * 服务配置
 * 
 * @bk https://home.cnblogs.com/u/huanuan/
 * @简书 https://www.jianshu.com/u/d29cc7d7ca49
 * @Author 六月星辰
 * @Date 2020年1月10日
 */
@Configuration
@PropertySource("classpath:/httpserver.properties")
@ImportResource("classpath:/quartz.xml")
public class BeanConfig {
    @Autowired
    Environment env;

    @Autowired
    void init() {
        // 系统配置 设置
        String ip = env.getProperty("ip");
        int port = env.getProperty("port", int.class);
    }

    @Bean
    HandlerDispatcher dispatcher() {
        // 注册业务处理器
        HandlerDispatcher dispatcher = new HandlerDispatcher();
        Set<Class> clazzs = ClassPathScanner.scan("liu.yue.xin.chen.com.server", false, true, false, null);
        dispatcher.initHandler(clazzs);
        return dispatcher;
    }

    @Bean
    HttpServer httpServer() {
        HttpServer httpServer = new HttpServer(env.getProperty("port", int.class));
        return httpServer;
    }

}

Netty 初始化Http服务


/**
 * netty HttpServer
 * 
 * @bk https://home.cnblogs.com/u/huanuan/
 * @简书 https://www.jianshu.com/u/d29cc7d7ca49
 * @Author 六月星辰
 * @Date 2020年1月11日
 */
public class HttpServer {
    /** 服务器的端口 **/
    private int port;

    public HttpServer(int port) {
        this.port = port;
    }

    public void start() throws Exception {
        ServerBootstrap bootstrap = new ServerBootstrap();
        EventLoopGroup boss = new NioEventLoopGroup();
        EventLoopGroup work = new NioEventLoopGroup();
        bootstrap.group(boss, work).channel(NioServerSocketChannel.class).childHandler(new HttpServerInitializer());
        ChannelFuture f = bootstrap.bind(new InetSocketAddress(port)).sync();
        System.err.println(" http服务器 启动  端口  : " + port);
        f.channel().closeFuture().sync();
    }

}

Netty的Http服务初始化配置

/**
 * http 初始化器
 * 
 * @bk https://home.cnblogs.com/u/huanuan/
 * @简书 https://www.jianshu.com/u/d29cc7d7ca49
 * @Author 六月星辰
 * @Date 2020年1月11日
 */
public class HttpServerInitializer extends ChannelInitializer<SocketChannel> {

    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        // TODO Auto-generated method stub
        ChannelPipeline pipeline = ch.pipeline();
        pipeline.addLast(new HttpServerCodec());// http 编解码
        /**
         * 下面的是 http 消息聚合器 将http的get和post请求解析为统一的FullHttpRequest或者FullHttpResponse
         * 
         */
        pipeline.addLast("httpAggregator", new HttpObjectAggregator(1024 * 1024)); // http 消息聚合器 1024*1024为接收的最大contentlength
        pipeline.addLast(new HttpServerExpectContinueHandler());
        pipeline.addLast(new HttpRequestHandler());// 请求处理器
    }

}

http消息处理器


/**
 * http消息处理器
 * 
 * @bk https://home.cnblogs.com/u/huanuan/
 * @简书 https://www.jianshu.com/u/d29cc7d7ca49
 * @Author 六月星辰
 * @Date 2020年1月11日
 */
public class HttpRequestHandler extends SimpleChannelInboundHandler<HttpObject> {

    private HttpHeaders headers;
    private HttpRequest request;
    private FullHttpRequest fullRequest;

    private static final String FAVICON_ICO = "/favicon.ico";
    private static final AsciiString CONTENT_TYPE = AsciiString.of("Content-Type");
    private static final AsciiString CONTENT_LENGTH = AsciiString.of("Content-Length");
    private static final AsciiString CONNECTION = AsciiString.of("Connection");
    private static final AsciiString KEEP_ALIVE = AsciiString.of("keep-alive");

    private static final AsciiString ACCESS_CONTROL_ALLOW_ORIGIN = AsciiString.of("Access-Control-Allow-Origin");
    private static final AsciiString ACCESS_CONTROL_ALLOW_HEADERS = AsciiString.of("Access-Control-Allow-Headers");
    private static final AsciiString ACCESS_CONTROL_ALLOW_METHODS = AsciiString.of("Access-Control-Allow-Methods");
    private static final AsciiString ACCESS_CONTROL_ALLOW_CREDENTIALS = AsciiString.of("Access-Control-Allow-Credentials");

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {
        // TODO Auto-generated method stub
        if (msg instanceof HttpRequest) {
            request = (HttpRequest) msg;
            headers = request.headers();
            String uri = request.uri();
            if (uri.equals(FAVICON_ICO)) {
                return;
            }
            HttpMethod method = request.method();// 获取请求的方式
            if (method.equals(HttpMethod.GET)) {
                System.err.println("收到GET的请求! 请求地址 = " + uri);
                QueryStringDecoder queryDecoder = new QueryStringDecoder(uri, Charsets.toCharset(CharEncoding.UTF_8));
                Map<String, List<String>> uriAttributes = queryDecoder.parameters();
                // 此处仅打印请求参数(你可以根据业务需求自定义处理)
                for (Map.Entry<String, List<String>> attr : uriAttributes.entrySet()) {
                    for (String attrVal : attr.getValue()) {
                        System.err.println("Key = " + attr.getKey() + "  values = " + attrVal);
                    }
                }
                String path = queryDecoder.path();
                System.err.println("请求的路径 = " + path);
                // TODO 这里进行分发操作,这里就不编写分发了
                getDispense(ctx, path, uriAttributes);
                JsonResult jsonResult = new JsonResult();
                JSONSerializer jsonSerializer = new JSONSerializer();
                responsePush(ctx, jsonSerializer.serialize(jsonResult));
            } else if (method.equals(HttpMethod.POST) || method.equals(HttpMethod.OPTIONS)) {
                System.err.println("收到POST或者OPTIONS的请求! 请求地址 = " + uri);
                // POST请求,由于你需要从消息体中获取数据,因此有必要把msg转换成FullHttpRequest
                fullRequest = (FullHttpRequest) msg;
                // 分发操作
                postDispense(ctx, uri);
            } else if (method.equals(HttpMethod.HEAD)) {
                System.err.println("收到HEAD请求! 请求地址 = " + uri);
            } else {
                System.err.println("收到其他方式的请求! 请求的地址 = " + uri);
            }
        }

    }

    /**
     * GET请求,请求分发操作
     * 
     * @param ctx
     *            请求的用户
     * @param path
     *            请求的地址
     * @param uriAttributes
     *            请求的参数
     * @bk https://home.cnblogs.com/u/huanuan/
     * @Author 六月星辰
     * @Date 2020年1月13日
     */
    private void getDispense(ChannelHandlerContext ctx, String path, Map<String, List<String>> uriAttributes) {
        // TODO 请求的分发操作
        System.err.println("暂时不进行分发操作!");
    }

    /**
     * post请求,请求进行分发操作
     * 
     * @param ctx
     *            用户的链接
     * @param uri
     *            用户请求的地址
     * @bk https://home.cnblogs.com/u/huanuan/
     * @Author 六月星辰
     * @Date 2020年1月13日
     */
    private void postDispense(ChannelHandlerContext ctx, String url) {
        // TODO Auto-generated method stub
        String typeStr2 = headers.get("Accept").toString();
        String[] list = typeStr2.split(";");
        String contentType = list[0];
        switch (contentType) {
        case "application/json":
            byte[] content = null;
            String jsonStr = fullRequest.content().toString(Charsets.toCharset(CharEncoding.UTF_8));
            JSONObject params = JSON.parseObject(jsonStr);
            try {
                Object response = HandlerDispatcher.dispatcher(liu.yue.xin.chen.com.handler.dispatcher.HttpMethod.POST, url, params);
                if (response == null) {
                    JsonResult jsonResult = new JsonResult();
                    JSONSerializer jsonSerializer = new JSONSerializer();
                    content = jsonSerializer.serialize(jsonResult);
                } else {
                    JsonResult jsonResult = new JsonResult(response);
                    JSONSerializer jsonSerializer = new JSONSerializer();
                    content = jsonSerializer.serialize(jsonResult);
                }
                responsePush(ctx, content);
            } catch (InvocationTargetException e) {
                // TODO Auto-generated catch block
                if (e.getTargetException() instanceof LogicException) {
                    // 如果是主动抛出异常
                    LogicException e1 = (LogicException) e.getTargetException();
                    JsonResult jsonResult = new JsonResult();
                    jsonResult.setState(e1.getCode());
                    JSONSerializer jsonSerializer = new JSONSerializer();
                    content = jsonSerializer.serialize(jsonResult);
                    responsePush(ctx, content);
                } else {
                    // 非主动抛出异常
                    JsonResult jsonResult = new JsonResult();
                    jsonResult.setState(-1);
                    JSONSerializer jsonSerializer = new JSONSerializer();
                    content = jsonSerializer.serialize(jsonResult);
                    responsePush(ctx, content);

                }
            } catch (Exception e) {
                JsonResult jsonResult = new JsonResult();
                JSONSerializer jsonSerializer = new JSONSerializer();
                content = jsonSerializer.serialize(jsonResult);
                responsePush(ctx, content);
            }
            break;
        case "application/x-www-form-urlencoded":
            System.err.println("接受到application/x-www-form-urlencoded类型的请求!暂时不进行处理操作!");
            break;
        case "multipart/form-data":
            System.err.println("接受到multipart/form-data类型的请求!暂时不进行处理操作!");
            break;
        default:
            System.err.println("服务器不进行其他请求方式的业务处理!");
            break;
        }
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        // TODO Auto-generated method stub
        ctx.flush();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        // TODO Auto-generated method stub
        System.err.println("链接异常! ");
        cause.printStackTrace();
        ctx.close();
    }

    /**
     * 响应信息
     * 
     * @param ctx
     *            响应的玩家 </br>
     * @param content
     *            响应的数据</br>
     * @bk https://home.cnblogs.com/u/huanuan/
     * @Author 六月星辰
     * @Date 2020年1月11日
     */
    private void responsePush(ChannelHandlerContext ctx, byte[] content) {
        FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.wrappedBuffer(content));
        // 允许跨域访问
        response.headers().set(CONTENT_TYPE, "application/json;charset=UTF-8");
        response.headers().set(ACCESS_CONTROL_ALLOW_ORIGIN, "*");
        response.headers().set(ACCESS_CONTROL_ALLOW_HEADERS, "*");// 允许headers自定义
        response.headers().set(ACCESS_CONTROL_ALLOW_METHODS, "GET, POST, PUT,DELETE");
        response.headers().set(ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
        response.headers().set(CONNECTION, KEEP_ALIVE);
        ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
    }

}

模拟spring的DispatcherServlet,业务层的分发操作

1.利用反射注册业务层
2.根据不同的请求方式,分发到不同业务层

/**
 * 模拟spring 业务层分发
 * 
 * @bk https://home.cnblogs.com/u/huanuan/
 * @简书 https://www.jianshu.com/u/d29cc7d7ca49
 * @Author 六月星辰
 * @Date 2020年1月11日
 */
@Slf4j
public class HandlerDispatcher implements Dispatcher {

    /**
     * POST方式 业务内存
     */
    private static Map<String, HanderServer> POST_HANDER = Maps.newConcurrentMap();

    /**
     * GET方式业务内存
     */
    private static Map<String, HanderServer> GET_HANDER = Maps.newConcurrentMap();

    @Override
    public void initHandler(Set<Class> clazzs) {
        // 业务处理器初始化
        if (CollectionUtils.isEmpty(clazzs)) {
            System.exit(0);// 处理器异常关闭处理器
            return;
        }
        try {
            for (Class clazz : clazzs) {
                Class[] interfaces = clazz.getInterfaces();
                boolean isHandler = false;
                for (Class class1 : interfaces) {
                    if (class1.getSimpleName().equals("HttpServerHandle")) {
                        isHandler = true;
                    }
                }
                if (isHandler) {
                    System.err.println("类 : " + clazz + "  实现了  HttpServerHandle  接口    进行初始化业务处理器  -------------");
                } else {
                    System.err.println("类  : " + clazz + "   未实现   HttpServerHandle  接口 ");
                    continue;
                }
                // 获取业务层的 指定的注解
                HttpParams hParams = (HttpParams) clazz.getAnnotation(HttpParams.class);
                if (null != hParams) {
                    String requestMethod = hParams.method();// 请求的方式 !
                    if (StringUtils.isEmpty(requestMethod)) {
                        continue;
                    }
                    Method[] declaredMethods = clazz.getDeclaredMethods();
                    // Method[] methods = clazz.getMethods();
                    // POST方式处理器内存存储
                    switch (requestMethod) {
                    case HttpMethod.POST:// POST方式处理器内存存储
                        for (Method method : declaredMethods) {
                            if (method.getName().equals("hanlde")) {
                                Class paramType = method.getParameterTypes()[0];
                                if (paramType.getSimpleName().equals("Object")) {
                                    continue;
                                }
                                POST_HANDER.put(hParams.url(), new HanderServer(clazz.newInstance(), method));
                            }
                        }
                        break;

                    case HttpMethod.GET:// GET方式处理器内存存储
                        for (Method method : declaredMethods) {
                            if (method.getName().equals("hanlde")) {
                                Class paramType = method.getParameterTypes()[0];
                                if (paramType.getSimpleName().equals("Object")) {
                                    continue;
                                }
                                GET_HANDER.put(hParams.url(), new HanderServer(clazz.newInstance(), method));
                            }
                        }
                        break;
                    default:
                        break;
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(0);
        }
    }

    public static Object dispatcher(String method, String url, JSONObject params) throws Exception {
        // TODO Auto-generated method stub
        switch (method) {
        case HttpMethod.POST:
            HanderServer postHander = POST_HANDER.get(url);
            if (postHander == null) {
                return null;
            }
            Object[] argsValues = new Object[1];
            JSONObject response = new JSONObject();
            argsValues[0] = params;// 请求参数
            // argsValues[1] = response;
            Object invoke = null;
            invoke = postHander.method.invoke(postHander.o, argsValues);
            return invoke;
        case HttpMethod.GET:
            HanderServer getHander = GET_HANDER.get(url);
            if (getHander == null) {
                return null;
            }
            Object[] getArgsValues = new Object[1];
            getArgsValues[0] = params;
            Object getInvoke = null;
            getInvoke = getHander.method.invoke(getHander.o, getArgsValues);
            return getInvoke;
        default:
            break;
        }

        return null;
    }

}

小编把剩下有关的类都贴出来!就不11说明了!

/**
 * http静态资源
 * 
 * @bk https://home.cnblogs.com/u/huanuan/
 * @简书 https://www.jianshu.com/u/d29cc7d7ca49
 * @Author 六月星辰
 * @Date 2020年1月13日
 */
public class HttpMethod {

    /**
     * postd的请求方式
     */
    public final static String POST = "POST";

    /**
     * get的请求方式
     */
    public final static String GET = "GET";
    
}


/**
 * 业务层 请求内存存储类
 * 
 * @bk https://home.cnblogs.com/u/huanuan/
 * @简书 https://www.jianshu.com/u/d29cc7d7ca49
 * @Author 六月星辰
 * @Date 2020年1月13日
 */
public class HanderServer {

    /**执行命令对象*/
    public  Object o;
    
    /**执行命令方法*/
    public  Method method;
    
    /**
     * 业务层 业务处理
     * @param o 请求的业务类
     * @param method 请求的方法
     * @throws NoSuchMethodException
     */
    public HanderServer(Object o, Method method) throws NoSuchMethodException {
        super();
        this.o = o;
        this.method = method;
    }
}

public interface Dispatcher {
    /**
     * 初始化处理器
     * 
     * @param clazzs
     * @bk https://home.cnblogs.com/u/huanuan/
     * @Author 六月星辰
     * @Date 2020年1月11日
     */
    void initHandler(Set<Class> clazzs);
    
    /**
     * 业务层的调用
     * @param method 请求的方式:POST、GET
     * @param url 请求的地址
     * @param params 请求参数
     * @throws Exception
     * @bk https://home.cnblogs.com/u/huanuan/
     * @Author 六月星辰
     * @Date 2020年1月11日
     * @return 业务层的业务处理结果
     */
//  Object dispatcher(String method,String url,JSONObject params) throws Exception;
    
}

/**
 * HTTP 请求标签
 * 
 * @bk https://home.cnblogs.com/u/huanuan/
 * @简书 https://www.jianshu.com/u/d29cc7d7ca49
 * @Author 六月星辰
 * @Date 2020年1月11日
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface HttpParams {

    /**
     * 请求的方式
     * 
     * @bk https://home.cnblogs.com/u/huanuan/
     * @Author 六月星辰
     * @Date 2020年1月11日
     * @return
     */
    String method();

    /**
     * 请求的地址
     * 
     * @bk https://home.cnblogs.com/u/huanuan/
     * @Author 六月星辰
     * @Date 2020年1月11日
     * @return
     */
    String url();
}

/**
 * 自定义逻辑异常
 * 
 * @bk https://home.cnblogs.com/u/huanuan/
 * @简书 https://www.jianshu.com/u/d29cc7d7ca49
 * @Author 六月星辰
 * @Date 2020年1月13日
 */
public class LogicException extends RuntimeException {

    /**
     * 异常码
     */
    private final int code;
    /**
     * 异常信息
     */
    private final String resultInfo;

    /**
     * <p>
     * Title:
     * </p>
     *
     * <p>
     * Description:异常构造器
     * </p>
     *
     * @param code
     */
    public LogicException(int code) {
        this.code = code;
        this.resultInfo = "";
    }

    /**
     * <p>
     * Title:
     * </p>
     *
     * <p>
     * Description:异常构造器
     * </p>
     *
     * @param code
     */
    public LogicException(int code, String resultInfo) {
        this.code = code;
        this.resultInfo = resultInfo;
    }

    public int getCode() {
        return code;
    }

    public String getResultInfo() {
        return resultInfo;
    }
}

/**
 * json数据封装
 * 
 * @bk https://home.cnblogs.com/u/huanuan/
 * @简书 https://www.jianshu.com/u/d29cc7d7ca49
 * @Author 六月星辰
 * @Date 2020年1月13日
 */
public class JsonResult {

    public static final int SUCCESS = 200;
    public static final int ERROR = 201;
    /**
     * 返回是否成功的状态,200表示成功, 201或其他值 表示失败
     */
    private int state = SUCCESS;
    /**
     * 成功时候,返回的JSON数据
     */
    private Object data = null;
    /**
     * 是错误时候的错误消息
     */
    private String message = null;

    /**
     * 服务器的时间
     */
    private long sysTime = System.currentTimeMillis();

    public JsonResult() {
    }

    public JsonResult(int state, Object data, String message) {
        this.state = state;
        this.data = data;
        this.message = message;
    }

    public JsonResult(Throwable e) {
        state = ERROR;
        data = null;
        message = e.getMessage();
    }

    public JsonResult(Object data) {
        state = SUCCESS;
        this.data = data;
        message = "";
    }

    public int getState() {
        return state;
    }

    public void setState(int state) {
        this.state = state;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public long getSysTime() {
        return sysTime;
    }

    public void setSysTime(long sysTime) {
        this.sysTime = sysTime;
    }

    @Override
    public String toString() {
        return "JsonResult [state=" + state + ", data=" + data + ", message=" + message + ",sysTime=" + sysTime + "]";
    }

}


/**
 * json序列化
 * 
 * @bk https://home.cnblogs.com/u/huanuan/
 * @简书 https://www.jianshu.com/u/d29cc7d7ca49
 * @Author 六月星辰
 * @Date 2020年1月11日
 */
public class JSONSerializer implements Serializer {

    @Override
    public byte[] serialize(Object object) {
        // TODO Auto-generated method stub
        return JSON.toJSONBytes(object);
    }

    @Override
    public <T> T deserialize(Class<T> clazz, byte[] bytes) {
        // TODO Auto-generated method stub
        return JSON.parseObject(bytes, clazz);
    }

}

/**
 * 序列化接口
 * 
 * @bk https://home.cnblogs.com/u/huanuan/
 * @简书 https://www.jianshu.com/u/d29cc7d7ca49
 * @Author 六月星辰
 * @Date 2020年1月11日
 */
public interface Serializer {
    /**
     * java 对象转换成二进制
     * 
     * @param object
     * @return
     * @bk https://home.cnblogs.com/u/huanuan/
     * @Author 六月星辰
     * @Date 2020年1月11日
     */
    byte[] serialize(Object object);

    /**
     * 二进制转换成 java 对象
     * 
     * @param clazz
     * @param bytes
     * @return
     * @bk https://home.cnblogs.com/u/huanuan/
     * @Author 六月星辰
     * @Date 2020年1月11日
     */
    <T> T deserialize(Class<T> clazz, byte[] bytes);
}

/**
 * http服务 独立线程启动
 * 
 * @bk https://home.cnblogs.com/u/huanuan/
 * @简书 https://www.jianshu.com/u/d29cc7d7ca49
 * @Author 六月星辰
 * @Date 2020年1月11日
 */
@Slf4j
public class NettyHttpServer implements Runnable {

    private HttpServer httpServer;

    public NettyHttpServer(HttpServer httpServer) {
        // TODO Auto-generated constructor stub
        this.httpServer = httpServer;
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
        try {
            this.httpServer.start();
        } catch (Exception e) {
            // TODO: handle exception
            System.err.println("启动http服务异常! ");
            e.printStackTrace();
            System.exit(0);
        }
    }

}
/**
 * 业务层处理接口
 * 
 * @bk https://home.cnblogs.com/u/huanuan/
 * @简书 https://www.jianshu.com/u/d29cc7d7ca49
 * @Author 六月星辰
 * @Date 2020年1月11日
 */
public interface HttpServerHandle {
    /**
     * 业务逻辑
     * @param params 请求参数
     * @bk https://home.cnblogs.com/u/huanuan/
     * @Author 六月星辰
     * @Date 2020年1月11日
     * @return
     */
    Object hanlde(JSONObject params);
}

/**
 * Http POST请求测试接口
 * 
 * @bk https://home.cnblogs.com/u/huanuan/
 * @简书 https://www.jianshu.com/u/d29cc7d7ca49
 * @Author 六月星辰
 * @Date 2020年1月11日
 */
@HttpParams(method = HttpMethod.POST, url = "")
public class TestPostServer implements HttpServerHandle {

    @Override
    public Object hanlde(JSONObject params) {
        // TODO Auto-generated method stub
        return null;
    }

}

/**
 * HTTP GET测试接口
 * 
 * @bk https://home.cnblogs.com/u/huanuan/
 * @简书 https://www.jianshu.com/u/d29cc7d7ca49
 * @Author 六月星辰
 * @Date 2020年1月11日
 */
@HttpParams(method = HttpMethod.GET, url = "")
public class TestGetServer implements HttpServerHandle {

    @Override
    public Object hanlde(JSONObject params) {
        // TODO Auto-generated method stub
        return null;
    }

}

/**
 * 包扫描器
 * 
 * @bk https://home.cnblogs.com/u/huanuan/
 * @简书 https://www.jianshu.com/u/d29cc7d7ca49
 * @Author 六月星辰
 * @Date 2020年1月13日
 */
public class ClassPathScanner {

    private static final Logger logger = LoggerFactory.getLogger(ClassPathScanner.class);

    /**
     * 扫描包
     *
     * @param basePackage
     *            基础包
     * @param recursive
     *            是否递归搜索子包
     * @param excludeInner
     *            是否排除内部类 true->是 false->否
     * @param checkInOrEx
     *            过滤规则适用情况 true—>搜索符合规则的 false->排除符合规则的
     * @param classFilterStrs
     *            List<java.lang.String> 自定义过滤规则,如果是null或者空,即全部符合不过滤
     * @return Set
     */
    public static Set<Class> scan(String basePackage, boolean recursive, boolean excludeInner, boolean checkInOrEx, List<String> classFilterStrs) {
        Set<Class> classes = new LinkedHashSet<Class>();
        String packageName = basePackage;
        List<Pattern> classFilters = toClassFilters(classFilterStrs);

        if (packageName.endsWith(".")) {
            packageName = packageName.substring(0, packageName.lastIndexOf('.'));
        }
        String package2Path = packageName.replace('.', '/');

        Enumeration<URL> dirs;
        try {
            dirs = Thread.currentThread().getContextClassLoader().getResources(package2Path);
            while (dirs.hasMoreElements()) {
                URL url = dirs.nextElement();
                String protocol = url.getProtocol();
                if ("file".equals(protocol)) {
                    logger.debug("扫描file类型的class文件....");
                    String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
                    doScanPackageClassesByFile(classes, packageName, filePath, recursive, excludeInner, checkInOrEx, classFilters);
                } else if ("jar".equals(protocol)) {
                    logger.debug("扫描jar文件中的类....");
                    doScanPackageClassesByJar(packageName, url, recursive, classes, excludeInner, checkInOrEx, classFilters);
                }
            }
        } catch (IOException e) {
            logger.error("IOException error:", e);
        }

        return classes;
    }

    /**
     * 以jar的方式扫描包下的所有Class文件
     */
    private static void doScanPackageClassesByJar(String basePackage, URL url, final boolean recursive, Set<Class> classes, boolean excludeInner, boolean checkInOrEx, List<Pattern> classFilters) {
        String packageName = basePackage;
        String package2Path = packageName.replace('.', '/');
        JarFile jar;
        try {
            jar = ((JarURLConnection) url.openConnection()).getJarFile();
            Enumeration<JarEntry> entries = jar.entries();
            while (entries.hasMoreElements()) {
                JarEntry entry = entries.nextElement();
                String name = entry.getName();
                if (!name.startsWith(package2Path) || entry.isDirectory()) {
                    continue;
                }

                // 判断是否递归搜索子包
                if (!recursive && name.lastIndexOf('/') != package2Path.length()) {
                    continue;
                }
                // 判断是否过滤 inner class
                if (excludeInner && name.indexOf('$') != -1) {
                    logger.debug("exclude inner class with name:" + name);
                    continue;
                }
                String classSimpleName = name.substring(name.lastIndexOf('/') + 1);
                // 判定是否符合过滤条件
                if (filterClassName(classSimpleName, checkInOrEx, classFilters)) {
                    String className = name.replace('/', '.');
                    className = className.substring(0, className.length() - 6);
                    try {
                        classes.add(Thread.currentThread().getContextClassLoader().loadClass(className));
                    } catch (ClassNotFoundException e) {
                        logger.error("Class.forName error:", e);
                    }
                }
            }
        } catch (IOException e) {
            logger.error("IOException error:", e);
        }
    }

    /**
     * 以文件的方式扫描包下的所有Class文件
     *
     * @param packageName
     * @param packagePath
     * @param recursive
     * @param classes
     */
    private static void doScanPackageClassesByFile(Set<Class> classes, String packageName, String packagePath, boolean recursive, final boolean excludeInner, final boolean checkInOrEx, final List<Pattern> classFilters) {
        File dir = new File(packagePath);
        if (!dir.exists() || !dir.isDirectory()) {
            return;
        }
        final boolean fileRecursive = recursive;
        File[] dirfiles = dir.listFiles(new FileFilter() {
            // 自定义文件过滤规则
            public boolean accept(File file) {
                if (file.isDirectory()) {
                    return fileRecursive;
                }
                String filename = file.getName();
                if (excludeInner && filename.indexOf('$') != -1) {
                    logger.debug("exclude inner class with name:" + filename);
                    return false;
                }
                return filterClassName(filename, checkInOrEx, classFilters);
            }
        });
        for (File file : dirfiles) {
            if (file.isDirectory()) {
                doScanPackageClassesByFile(classes, packageName + "." + file.getName(), file.getAbsolutePath(), recursive, excludeInner, checkInOrEx, classFilters);
            } else {
                String className = file.getName().substring(0, file.getName().length() - 6);
                try {
                    classes.add(Thread.currentThread().getContextClassLoader().loadClass(packageName + '.' + className));

                } catch (ClassNotFoundException e) {
                    logger.error("IOException error:", e);
                }
            }
        }
    }

    /**
     * 根据过滤规则判断类名
     */
    private static boolean filterClassName(String className, boolean checkInOrEx, List<Pattern> classFilters) {
        if (!className.endsWith(".class")) {
            return false;
        }
        if (null == classFilters || classFilters.isEmpty()) {
            return true;
        }
        String tmpName = className.substring(0, className.length() - 6);
        boolean flag = false;
        for (Pattern p : classFilters) {
            if (p.matcher(tmpName).find()) {
                flag = true;
                break;
            }
        }
        return (checkInOrEx && flag) || (!checkInOrEx && !flag);
    }

    /**
     * @param pClassFilters
     *            the classFilters to set
     */
    private static List<Pattern> toClassFilters(List<String> pClassFilters) {
        List<Pattern> classFilters = new ArrayList<Pattern>();
        if (pClassFilters != null) {

            for (String s : pClassFilters) {
                String reg = "^" + s.replace("*", ".*") + "$";
                Pattern p = Pattern.compile(reg);
                classFilters.add(p);
            }
        }
        return classFilters;
    }

}

小编自己写的源码下载地址:https://github.com/zhuhuanuan/nettyHttpServer

感觉小编写的可以,记得给小编点一个赞哇 ~~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容