├── README.md
├── doc
└── wechat.jpg
├── pom.xml
└── src
├── main
├── java
│ └── com
│ │ └── netty
│ │ └── http
│ │ └── server
│ │ ├── NettyHttpServerApplication.java
│ │ ├── annotation
│ │ ├── RequestMapping.java
│ │ ├── RequestParam.java
│ │ └── RestController.java
│ │ ├── bootstrap
│ │ ├── NettyServer.java
│ │ └── NettyServerHandler.java
│ │ ├── common
│ │ ├── Constant.java
│ │ ├── response
│ │ │ └── GeneralResponse.java
│ │ └── utils
│ │ │ ├── JsonUtil.java
│ │ │ ├── RequestUtil.java
│ │ │ ├── ResponseUtil.java
│ │ │ └── SpringContextHolder.java
│ │ ├── configuration
│ │ └── MyNettyServerConfiguration.java
│ │ ├── order
│ │ ├── controller
│ │ │ └── OrderController.java
│ │ ├── entity
│ │ │ └── Order.java
│ │ ├── mapper
│ │ │ └── OrderMapper.java
│ │ └── service
│ │ │ ├── OrderService.java
│ │ │ └── impl
│ │ │ └── OrderServiceImpl.java
│ │ └── router
│ │ ├── HttpRouter.java
│ │ ├── HttpRouterDispatch.java
│ │ └── HttpRouterTally.java
└── resources
│ ├── META-INF
│ └── spring.factories
│ ├── application.yml
│ └── mybatis
│ └── mybatis-config.xml
└── test
└── java
└── com
└── netty
└── http
└── server
└── NettyHttpServerApplicationTests.java
/README.md:
--------------------------------------------------------------------------------
1 | # netty-http-server
2 | # 采用Netty4.x开发Http Server服务,以此提高性能和吞吐量(统一处理请求URL路由,多种数据类型参数映射等) #
3 |
4 | ## Prerequisite ##
5 | 1. JDK 1.8+
6 | 2. Maven 3.5.x
7 | 3. Git版本控制
8 |
9 | ## Quick Start ##
10 | - Clone & Build
11 | > git clone https://github.com/fengjingwei/netty-http-server.git
12 | >
13 | > cd netty-http-server
14 | >
15 | > mvn clean install -DskipTests -U
16 |
17 | ## Support ##
18 | - 如有任何问题欢迎微我
19 | - 
20 |
--------------------------------------------------------------------------------
/doc/wechat.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengjingwei/netty-http-server/4aa16c964e4e750da72ae8f984d3a408be2377da/doc/wechat.jpg
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 | com.netty.http
6 | netty-http-server
7 | 0.0.1-RELEASE
8 | jar
9 | Netty Http Server
10 | Netty Http Server project for Spring Boot
11 |
12 |
13 | org.springframework.boot
14 | spring-boot-starter-parent
15 | 2.2.7.RELEASE
16 |
17 |
18 |
19 |
20 | UTF-8
21 | UTF-8
22 | 1.8
23 | 2.1.1
24 | 8.0.33
25 | 4.1.90.Final
26 | 32.0.0-jre
27 | 2.10.1
28 | 3.12.0
29 |
30 |
31 |
32 |
33 | org.springframework.boot
34 | spring-boot-starter
35 |
36 |
37 |
38 | org.springframework.boot
39 | spring-boot-starter-web
40 |
41 |
42 |
43 | org.mybatis.spring.boot
44 | mybatis-spring-boot-starter
45 | ${mybatis.spring.boot.version}
46 |
47 |
48 |
49 | org.springframework.boot
50 | spring-boot-devtools
51 | true
52 | runtime
53 |
54 |
55 |
56 | org.springframework.boot
57 | spring-boot-starter-test
58 | test
59 |
60 |
61 |
62 | mysql
63 | mysql-connector-java
64 | ${mysql.version}
65 |
66 |
67 |
68 | io.netty
69 | netty-all
70 | ${netty.version}
71 |
72 |
73 |
74 | org.projectlombok
75 | lombok
76 | true
77 |
78 |
79 |
80 | com.google.guava
81 | guava
82 | ${guava.version}
83 |
84 |
85 |
86 | com.google.code.gson
87 | gson
88 | ${gson.version}
89 |
90 |
91 |
92 | org.apache.commons
93 | commons-lang3
94 | ${commons.lang3.version}
95 |
96 |
97 |
98 |
99 |
100 |
101 | org.springframework.boot
102 | spring-boot-maven-plugin
103 |
104 | true
105 | true
106 | com.netty.http.server.NettyHttpServerApplication
107 |
108 |
109 |
110 |
111 |
112 |
113 |
--------------------------------------------------------------------------------
/src/main/java/com/netty/http/server/NettyHttpServerApplication.java:
--------------------------------------------------------------------------------
1 | package com.netty.http.server;
2 |
3 | import org.mybatis.spring.annotation.MapperScan;
4 | import org.springframework.boot.SpringApplication;
5 | import org.springframework.boot.autoconfigure.SpringBootApplication;
6 | import org.springframework.transaction.annotation.EnableTransactionManagement;
7 |
8 | @SpringBootApplication
9 | @EnableTransactionManagement
10 | @MapperScan(basePackages = {"com.netty.http.server.order.mapper"})
11 | public class NettyHttpServerApplication {
12 |
13 | public static void main(String[] args) {
14 | SpringApplication.run(NettyHttpServerApplication.class, args);
15 | }
16 | }
--------------------------------------------------------------------------------
/src/main/java/com/netty/http/server/annotation/RequestMapping.java:
--------------------------------------------------------------------------------
1 | package com.netty.http.server.annotation;
2 |
3 | import org.springframework.web.bind.annotation.RequestMethod;
4 |
5 | import java.lang.annotation.*;
6 |
7 | @Target(value = {ElementType.TYPE, ElementType.METHOD})
8 | @Retention(value = RetentionPolicy.RUNTIME)
9 | @Inherited
10 | @Documented
11 | public @interface RequestMapping {
12 |
13 | String uri() default "";
14 |
15 | RequestMethod method() default RequestMethod.GET;
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/com/netty/http/server/annotation/RequestParam.java:
--------------------------------------------------------------------------------
1 | package com.netty.http.server.annotation;
2 |
3 | import com.netty.http.server.common.Constant;
4 |
5 | import java.lang.annotation.*;
6 |
7 | @Target(value = ElementType.PARAMETER)
8 | @Retention(value = RetentionPolicy.RUNTIME)
9 | @Inherited
10 | @Documented
11 | public @interface RequestParam {
12 |
13 | String name();
14 |
15 | boolean required() default true;
16 |
17 | String defaultValue() default Constant.EMPTY;
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/com/netty/http/server/annotation/RestController.java:
--------------------------------------------------------------------------------
1 | package com.netty.http.server.annotation;
2 |
3 | import org.springframework.stereotype.Component;
4 |
5 | import java.lang.annotation.*;
6 |
7 | @Target(value = ElementType.TYPE)
8 | @Retention(value = RetentionPolicy.RUNTIME)
9 | @Inherited
10 | @Documented
11 | @Component
12 | public @interface RestController {
13 |
14 | }
--------------------------------------------------------------------------------
/src/main/java/com/netty/http/server/bootstrap/NettyServer.java:
--------------------------------------------------------------------------------
1 | package com.netty.http.server.bootstrap;
2 |
3 | import com.netty.http.server.common.utils.SpringContextHolder;
4 | import com.netty.http.server.router.HttpRouter;
5 | import io.netty.bootstrap.ServerBootstrap;
6 | import io.netty.channel.Channel;
7 | import io.netty.channel.ChannelInitializer;
8 | import io.netty.channel.ChannelOption;
9 | import io.netty.channel.ChannelPipeline;
10 | import io.netty.channel.nio.NioEventLoopGroup;
11 | import io.netty.channel.socket.SocketChannel;
12 | import io.netty.channel.socket.nio.NioServerSocketChannel;
13 | import io.netty.handler.codec.http.HttpContentCompressor;
14 | import io.netty.handler.codec.http.HttpObjectAggregator;
15 | import io.netty.handler.codec.http.HttpServerCodec;
16 | import io.netty.handler.logging.LogLevel;
17 | import io.netty.handler.logging.LoggingHandler;
18 | import io.netty.handler.stream.ChunkedWriteHandler;
19 | import lombok.extern.log4j.Log4j2;
20 | import org.springframework.beans.factory.annotation.Autowired;
21 |
22 | import javax.servlet.ServletContextListener;
23 | import java.net.InetSocketAddress;
24 |
25 | @Log4j2
26 | public class NettyServer implements ServletContextListener {
27 |
28 | private static final Integer PORT = 9999;
29 | private final HttpRouter httpRouter = new HttpRouter();
30 |
31 | @Autowired
32 | private SpringContextHolder springContextHolder;
33 |
34 | public void start() {
35 | final NioEventLoopGroup bossGroup = new NioEventLoopGroup();
36 | final NioEventLoopGroup workerGroup = new NioEventLoopGroup();
37 | try {
38 | springContextHolder.loadControllerClass().forEach(httpRouter::addRouter);
39 | final ServerBootstrap bootstrap = new ServerBootstrap();
40 | bootstrap.group(bossGroup, workerGroup)
41 | .channel(NioServerSocketChannel.class)
42 | .handler(new LoggingHandler(LogLevel.INFO))
43 | .option(ChannelOption.SO_REUSEADDR, true)
44 | .childHandler(new ChannelInitializer() {
45 |
46 | @Override
47 | protected void initChannel(SocketChannel ch) {
48 | final ChannelPipeline pipeline = ch.pipeline();
49 | pipeline.addLast("httpServerCodec", new HttpServerCodec());
50 | pipeline.addLast("httpObjectAggregator", new HttpObjectAggregator(65536));
51 | pipeline.addLast("httpContentCompressor", new HttpContentCompressor());
52 | pipeline.addLast("chunkedWriteHandler", new ChunkedWriteHandler());
53 | pipeline.addLast("nettyServerHandler", new NettyServerHandler(httpRouter));
54 | }
55 | });
56 |
57 | final Channel serverChannel = bootstrap.bind(new InetSocketAddress(PORT)).sync().channel();
58 | log.info("http://127.0.0.1:{}/ Start-up success", PORT);
59 | serverChannel.closeFuture().sync();
60 | } catch (InterruptedException e) {
61 | e.printStackTrace();
62 | } finally {
63 | workerGroup.shutdownGracefully();
64 | bossGroup.shutdownGracefully();
65 | }
66 | }
67 | }
68 |
69 |
--------------------------------------------------------------------------------
/src/main/java/com/netty/http/server/bootstrap/NettyServerHandler.java:
--------------------------------------------------------------------------------
1 | package com.netty.http.server.bootstrap;
2 |
3 | import com.netty.http.server.common.Constant;
4 | import com.netty.http.server.common.response.GeneralResponse;
5 | import com.netty.http.server.common.utils.ResponseUtil;
6 | import com.netty.http.server.router.HttpRouter;
7 | import com.netty.http.server.router.HttpRouterDispatch;
8 | import com.netty.http.server.router.HttpRouterTally;
9 | import io.netty.channel.ChannelHandlerContext;
10 | import io.netty.channel.ChannelInboundHandlerAdapter;
11 | import io.netty.handler.codec.http.FullHttpRequest;
12 |
13 | public class NettyServerHandler extends ChannelInboundHandlerAdapter {
14 |
15 | private final HttpRouter httpRouter;
16 |
17 | NettyServerHandler(HttpRouter httpRouter) {
18 | this.httpRouter = httpRouter;
19 | }
20 |
21 | @Override
22 | public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
23 | // System.out.println("NettyServerHandler.handlerAdded");
24 | }
25 |
26 | @Override
27 | public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
28 | // System.out.println("NettyServerHandler.channelRegistered");
29 | }
30 |
31 |
32 | @Override
33 | public void channelActive(ChannelHandlerContext ctx) throws Exception {
34 | // System.out.println("NettyServerHandler.channelActive");
35 | }
36 |
37 | @Override
38 | public void channelRead(ChannelHandlerContext ctx, Object msg) {
39 | if (msg instanceof FullHttpRequest) {
40 | final FullHttpRequest request = (FullHttpRequest) msg;
41 | String uri = request.uri();
42 | if (Constant.FAVICON.equals(uri)) {
43 | ctx.close();
44 | return;
45 | }
46 | if (uri.contains(Constant.QUESTION)) {
47 | uri = uri.substring(0, uri.indexOf(Constant.QUESTION));
48 | }
49 | final HttpRouterDispatch> httpRouterDispatch = httpRouter.getRoute(new HttpRouterTally(uri, request.method()));
50 | if (httpRouterDispatch != null) {
51 | ResponseUtil.response(ctx, request, httpRouterDispatch.call(request));
52 | } else {
53 | ResponseUtil.notFound(ctx, request);
54 | }
55 | }
56 | }
57 |
58 | @Override
59 | public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
60 | // System.out.println("NettyServerHandler.channelReadComplete");
61 | }
62 |
63 | @Override
64 | public void channelInactive(ChannelHandlerContext ctx) throws Exception {
65 | // System.out.println("NettyServerHandler.channelInactive");
66 | }
67 |
68 | @Override
69 | public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
70 | // System.out.println("NettyServerHandler.channelUnregistered");
71 | }
72 |
73 | @Override
74 | public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
75 | // System.out.println("NettyServerHandler.handlerRemoved");
76 | }
77 |
78 | @Override
79 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
80 | cause.printStackTrace();
81 | ctx.close();
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/src/main/java/com/netty/http/server/common/Constant.java:
--------------------------------------------------------------------------------
1 | package com.netty.http.server.common;
2 |
3 | import org.apache.commons.lang3.StringUtils;
4 |
5 | public class Constant {
6 |
7 | public static final String EMPTY = StringUtils.EMPTY;
8 |
9 | public static final String QUESTION = "?";
10 |
11 | public static final String SLASH = "/";
12 |
13 | public static final String FAVICON = "/favicon.ico";
14 | }
--------------------------------------------------------------------------------
/src/main/java/com/netty/http/server/common/response/GeneralResponse.java:
--------------------------------------------------------------------------------
1 | package com.netty.http.server.common.response;
2 |
3 | import io.netty.handler.codec.http.HttpResponseStatus;
4 | import lombok.Data;
5 | import lombok.NoArgsConstructor;
6 |
7 | @Data
8 | @NoArgsConstructor
9 | public class GeneralResponse {
10 |
11 | public static final transient GeneralResponse