HelloServerHandler.java 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. package hello;
  2. import io.netty.buffer.ByteBuf;
  3. import io.netty.buffer.Unpooled;
  4. import io.netty.channel.ChannelFutureListener;
  5. import io.netty.channel.ChannelHandlerContext;
  6. import io.netty.channel.SimpleChannelInboundHandler;
  7. import io.netty.handler.codec.http.DefaultFullHttpResponse;
  8. import io.netty.handler.codec.http.FullHttpResponse;
  9. import io.netty.handler.codec.http.HttpHeaders;
  10. import io.netty.handler.codec.http.HttpRequest;
  11. import io.netty.handler.codec.http.HttpResponseStatus;
  12. import io.netty.handler.codec.http.HttpVersion;
  13. import io.netty.util.CharsetUtil;
  14. import io.netty.util.concurrent.FastThreadLocal;
  15. import java.text.DateFormat;
  16. import java.text.SimpleDateFormat;
  17. import java.util.Date;
  18. import java.util.concurrent.ScheduledExecutorService;
  19. import java.util.concurrent.TimeUnit;
  20. import com.fasterxml.jackson.databind.ObjectMapper;
  21. import com.fasterxml.jackson.module.afterburner.AfterburnerModule;
  22. public class HelloServerHandler extends SimpleChannelInboundHandler<Object> {
  23. private static final FastThreadLocal<DateFormat> FORMAT = new FastThreadLocal<DateFormat>() {
  24. @Override
  25. protected DateFormat initialValue() {
  26. return new SimpleDateFormat("E, dd MMM yyyy HH:mm:ss z");
  27. }
  28. };
  29. private static final ByteBuf CONTENT_BUFFER = Unpooled.unreleasableBuffer(Unpooled.directBuffer().writeBytes("Hello, World!".getBytes(CharsetUtil.UTF_8)));
  30. private static final CharSequence contentLength = HttpHeaders.newEntity(String.valueOf(CONTENT_BUFFER.readableBytes()));
  31. private static final CharSequence TYPE_PLAIN = HttpHeaders.newEntity("text/plain; charset=UTF-8");
  32. private static final CharSequence TYPE_JSON = HttpHeaders.newEntity("application/json; charset=UTF-8");
  33. private static final CharSequence SERVER_NAME = HttpHeaders.newEntity("Netty");
  34. private static final CharSequence CONTENT_TYPE_ENTITY = HttpHeaders.newEntity(HttpHeaders.Names.CONTENT_TYPE);
  35. private static final CharSequence DATE_ENTITY = HttpHeaders.newEntity(HttpHeaders.Names.DATE);
  36. private static final CharSequence CONTENT_LENGTH_ENTITY = HttpHeaders.newEntity(HttpHeaders.Names.CONTENT_LENGTH);
  37. private static final CharSequence SERVER_ENTITY = HttpHeaders.newEntity(HttpHeaders.Names.SERVER);
  38. private static final ObjectMapper MAPPER;
  39. static {
  40. MAPPER = new ObjectMapper();
  41. MAPPER.registerModule(new AfterburnerModule());
  42. }
  43. private volatile CharSequence date = HttpHeaders.newEntity(FORMAT.get().format(new Date()));
  44. HelloServerHandler(ScheduledExecutorService service) {
  45. service.scheduleWithFixedDelay(new Runnable() {
  46. private final DateFormat format = FORMAT.get();
  47. @Override
  48. public void run() {
  49. date = HttpHeaders.newEntity(format.format(new Date()));
  50. }
  51. }, 1000, 1000, TimeUnit.MILLISECONDS);
  52. }
  53. @Override
  54. public void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
  55. if (msg instanceof HttpRequest) {
  56. HttpRequest request = (HttpRequest) msg;
  57. String uri = request.getUri();
  58. switch (uri) {
  59. case "/plaintext":
  60. writeResponse(ctx, request, CONTENT_BUFFER.duplicate(), TYPE_PLAIN, contentLength);
  61. return;
  62. case "/json":
  63. byte[] json = MAPPER.writeValueAsBytes(new Message("Hello, World!"));
  64. writeResponse(ctx, request, Unpooled.wrappedBuffer(json), TYPE_JSON, String.valueOf(json.length));
  65. return;
  66. }
  67. FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.NOT_FOUND, Unpooled.EMPTY_BUFFER, false);
  68. ctx.write(response).addListener(ChannelFutureListener.CLOSE);
  69. }
  70. }
  71. private void writeResponse(ChannelHandlerContext ctx, HttpRequest request, ByteBuf buf, CharSequence contentType, CharSequence contentLength) {
  72. // Decide whether to close the connection or not.
  73. boolean keepAlive = HttpHeaders.isKeepAlive(request);
  74. // Build the response object.
  75. FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, buf, false);
  76. HttpHeaders headers = response.headers();
  77. headers.set(CONTENT_TYPE_ENTITY, contentType);
  78. headers.set(SERVER_ENTITY, SERVER_NAME);
  79. headers.set(DATE_ENTITY, date);
  80. headers.set(CONTENT_LENGTH_ENTITY, contentLength);
  81. // Close the non-keep-alive connection after the write operation is
  82. // done.
  83. if (!keepAlive) {
  84. ctx.write(response).addListener(ChannelFutureListener.CLOSE);
  85. } else {
  86. ctx.write(response, ctx.voidPromise());
  87. }
  88. }
  89. @Override
  90. public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
  91. ctx.close();
  92. }
  93. @Override
  94. public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
  95. ctx.flush();
  96. }
  97. }