推荐一个 netty learning example
gitlab代码: https://github.com/sanshengshui/netty-learning-example
启动netty的server接受http请求
1,HttpHelloWorldServer.java
import org.slf4j.LoggerFactory;
import org.slf4j.Logger;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
public final class HttpHelloWorldServer {
private static final Logger logger = LoggerFactory.getLogger(HttpHelloWorldServer.class);
static final int PORT = 8888;
public static void main(String[] args) throws Exception {
// Configure the server.
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.option(ChannelOption.SO_BACKLOG, 1024);
b.childOption(ChannelOption.TCP_NODELAY,true);
b.childOption(ChannelOption.SO_KEEPALIVE,true);
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new HttpHelloWorldServerInitializer());
Channel ch = b.bind(PORT).sync().channel();
logger.info("Netty http server listening on port "+ PORT);
ch.closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
2,HttpHelloWorldServerInitializer.java 设置Handler集合
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.HttpServerExpectContinueHandler;
public class HttpHelloWorldServerInitializer extends ChannelInitializer<SocketChannel> {
@Override
public void initChannel(SocketChannel ch) {
ChannelPipeline p = ch.pipeline();
/**
* 入站出站的编解码,或者使用HttpRequestDecoder & HttpResponseEncoder
*/
p.addLast(new HttpServerCodec());
/**
* 在处理POST消息体时需要加上
*/
p.addLast(new HttpObjectAggregator(1024 * 1024));
p.addLast(new HttpServerExpectContinueHandler());
/**
* 自定义 Handler
*/
p.addLast(new HttpHelloWorldServerHandler());
}
}
3,HttpHelloWorldServerHandler.java 接受get,post请求并打印参数
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.sanshengshui.netty.pojo.User;
import com.sanshengshui.netty.serialize.impl.JSONSerializer;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.*;
import io.netty.util.AsciiString;
import org.apache.commons.codec.CharEncoding;
import org.apache.commons.codec.Charsets;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Date;
import java.util.List;
import java.util.Map;
import static io.netty.handler.codec.http.HttpResponseStatus.OK;
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
/**
* @author james
*/
public class HttpHelloWorldServerHandler extends SimpleChannelInboundHandler<HttpObject> {
private static final Logger logger = LoggerFactory.getLogger(HttpHelloWorldServerHandler.class);
private static final String FAVICON_ICO = "/favicon.ico";
private static final AsciiString CONTENT_TYPE = AsciiString.cached("Content-Type");
private static final AsciiString CONTENT_LENGTH = AsciiString.cached("Content-Length");
private static final AsciiString CONNECTION = AsciiString.cached("Connection");
private static final AsciiString KEEP_ALIVE = AsciiString.cached("keep-alive");
private HttpHeaders headers;
private HttpRequest request;
private FullHttpRequest fullRequest;
@Override
public void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {
User user = new User();
user.setUserName("sanshengshui");
user.setDate(new Date());
if (msg instanceof HttpRequest) {
request = (HttpRequest) msg;
headers = request.headers();
String uri = request.uri();
logger.info("http uri: " + uri);
if (uri.equals(FAVICON_ICO)) {
return;
}
HttpMethod method = request.method();
if (method.equals(HttpMethod.GET)) {
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()) {
logger.info(attr.getKey() + "=" + attrVal);
}
}
user.setMethod("get");
} else if (method.equals(HttpMethod.POST)) {
//POST请求,由于你需要从消息体中获取数据,因此有必要把msg转换成FullHttpRequest
fullRequest = (FullHttpRequest) msg;
//根据不同的Content_Type处理body数据
dealWithContentType();
user.setMethod("post");
}
JSONSerializer jsonSerializer = new JSONSerializer();
byte[] content = jsonSerializer.serialize(user);
FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, OK, Unpooled.wrappedBuffer(content));
response.headers().set(CONTENT_TYPE, "text/plain");
response.headers().setInt(CONTENT_LENGTH, response.content().readableBytes());
boolean keepAlive = HttpUtil.isKeepAlive(request);
if (!keepAlive) {
ctx.write(response).addListener(ChannelFutureListener.CLOSE);
} else {
response.headers().set(CONNECTION, KEEP_ALIVE);
ctx.write(response);
}
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.flush();
}
/**
* 简单处理常用几种 Content-Type 的 POST 内容(可自行扩展)
*
* @throws Exception
*/
private void dealWithContentType() throws Exception {
String contentType = getContentType();
//可以使用HttpJsonDecoder
if (contentType.equals("application/json")) {
String jsonStr = fullRequest.content().toString(Charsets.toCharset(CharEncoding.UTF_8));
JSONObject obj = JSON.parseObject(jsonStr);
for (Map.Entry<String, Object> item : obj.entrySet()) {
logger.info(item.getKey() + "=" + item.getValue().toString());
}
} else if (contentType.equals("application/x-www-form-urlencoded")) {
//方式一:使用 QueryStringDecoder
String jsonStr = fullRequest.content().toString(Charsets.toCharset(CharEncoding.UTF_8));
QueryStringDecoder queryDecoder = new QueryStringDecoder(jsonStr, false);
Map<String, List<String>> uriAttributes = queryDecoder.parameters();
for (Map.Entry<String, List<String>> attr : uriAttributes.entrySet()) {
for (String attrVal : attr.getValue()) {
logger.info(attr.getKey() + "=" + attrVal);
}
}
} else if (contentType.equals("multipart/form-data")) {
//TODO 用于文件上传
} else {
//do nothing...
}
}
private String getContentType() {
String typeStr = headers.get("Content-Type");
String[] list = typeStr.split(";");
return list[0];
}
}
运行
发生POST请求
netty服务接受请求,并打印结果