参考jsoncat框架,集成netty web服务器至CommandFast中,可以处理http的POST类型报文请求。

目录

程序效果

实现过程

样例代码

参考资料


程序效果

springboot netty 客户端连接数量 springboot netty tomcat_json

截图1.响应json报文请求

        响应报文内容没有进行调整,将原有查询磁盘空间功能的部分结果填充到了响应报文中,重点测试请求、应答是否正常。

实现过程

1.使用框架视角

springboot netty 客户端连接数量 springboot netty tomcat_json_02

截图2.业务代码开发流程图

        步骤一、添加@RestController注解的类。其注解内容为第一级URI标签,如服务器端口使用8080,则第一级标签之前的内容为“http://127.0.0.1:8080”,这里注解中的值如果填“/CurrentDiskInfo”,则使用“http://127.0.0.1:8080/CurrentDiskInfo”能访问到该类。

        步骤二、添加@PostMapping注解的方法。其注解内容为第二级URI标签,如果填“/work”,则使用“http://127.0.0.1:8080/CurrentDiskInfo/work”能访问到该方法。

        步骤三、实现相关的业务功能。

2.框架视角

springboot netty 客户端连接数量 springboot netty tomcat_网络协议_03

截图3.框架功能生效流程图

        步骤一、在原有加载类的位置,添加@RestController标签类的加载。

        步骤二、在生成类实例之前,添加加载路由步骤,用于将@RestController、@PostMapping注解的类与方法,与URI路径的对应关系存放起来,便于netty映射调用。

        步骤三、在原有生成类实例的位置,添加生成@RestController类的实例。

        步骤四、启动应用的位置,将原有控制台相关的提示与响应部分,替换为netty启动代码。

样例代码

1.使用框架视角

@RestController("/CurrentDiskInfo")
public class CurrentDiskInfo implements CommandFastPro {
  
  @Autowired
  MemDisk memDisk;
  
  public void work() {
    memDisk.getDiskInfo();
    memDisk.getMemInfo();
  }
  
  @PostMapping
  public String work1(@RequestBody TestDao testDao) {
    memDisk.getDiskInfo();
    memDisk.getMemInfo();
    
    String resp;
    resp = memDisk.getDiskInfo()+memDisk.getMemInfo();
    return resp;
  }
}

        利用@RestController、@PostMapping注解即可,放在入口的类及方法上。

2.框架视角

springboot netty 客户端连接数量 springboot netty tomcat_网络协议_04

截图4.netty相关文件清单

        主要麻烦在报文转换与映射部分,http请求进来后,先转换成json格式,传递给根据URI匹配的对应方法进行处理。返回响应前,将String格式的报文转换成json格式。

(1)pom.xml新增依赖

<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>2.11.2</version>
</dependency>
<dependency> 
  <groupId>commons-codec</groupId> 
  <artifactId>commons-codec</artifactId> 
  <version>1.14</version>
</dependency>

(2)netty自定义处理的入口类

public class HttpServerHandler extends SimpleChannelInboundHandler<FullHttpRequest> {
    private static final AsciiString CONNECTION = AsciiString.cached("Connection");
    private static final AsciiString KEEP_ALIVE = AsciiString.cached("keep-alive");

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest fullHttpRequest) {
      //获取http类型(GET/POST)
        RequestHandler requestHandler = RequestHandlerFactory.get(fullHttpRequest.method());
        FullHttpResponse fullHttpResponse;
        try {
            //处理请求
            fullHttpResponse = requestHandler.handle(fullHttpRequest);
        } catch (Throwable e) {
            String requestPath = UrlUtil.getRequestPath(fullHttpRequest.uri());
            fullHttpResponse = FullHttpResponseFactory.getErrorResponse(requestPath, e.toString(), HttpResponseStatus.INTERNAL_SERVER_ERROR);
        }

        //根据连接拼接不同头部
        boolean keepAlive = HttpUtil.isKeepAlive(fullHttpRequest);
        if (!keepAlive) {
            //返回应答
            ctx.write(fullHttpResponse).addListener(ChannelFutureListener.CLOSE);
        } else {
            fullHttpResponse.headers().set(CONNECTION, KEEP_ALIVE);
            ctx.write(fullHttpResponse);
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        ctx.close();
    }

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

(3)处理大致流程

public class PostRequestHandler implements RequestHandler {

    @Override
    public FullHttpResponse handle(FullHttpRequest fullHttpRequest) {
        String requestUri = fullHttpRequest.uri();
        String requestPath = UrlUtil.getRequestPath(requestUri);

        //根据URI路径匹配方法
        MethodDetail methodDetail = RouteMethodMapper.getMethodDetail(requestPath, HttpMethod.POST);
        Method targetMethod = methodDetail.getMethod();
        if (targetMethod == null) {
            return null;
        }
        String contentType = this.getContentType(fullHttpRequest.headers());

        //解析http请求POST的json入参
        List<Object> targetMethodParams = new ArrayList<>();
        if (contentType.equals("application/json")) {
            String json = fullHttpRequest.content().toString(Charsets.toCharset(CharEncoding.UTF_8));
            methodDetail.setJson(json);
            Parameter[] targetMethodParameters = targetMethod.getParameters();
            for (Parameter parameter : targetMethodParameters) {
                ParameterResolver parameterResolver = ParameterResolverFactory.get(parameter);
                if (parameterResolver != null) {
                    Object param = parameterResolver.resolve(methodDetail, parameter);
                    targetMethodParams.add(param);
                }
            }
        } else {
            throw new IllegalArgumentException("only receive application/json type data");
        }
    
        //根据方法名在BeanFactory工厂中查找类实例
        String beanName = BeanHelper.getBeanName(methodDetail.getMethod().getDeclaringClass());
        Object targetObject = BeanFactory.BEANS.get(beanName);

        //传递参数至方法中,处理请求
        return FullHttpResponseFactory.getSuccessResponse(targetMethod, targetMethodParams, targetObject);
    }

    private String getContentType(HttpHeaders headers) {
        String typeStr = headers.get("Content-Type");
        String[] list = typeStr.split(";");
        return list[0];
    }
}

(4)json报文解析

public class RequestBodyParameterResolver implements ParameterResolver {
    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

    @Override
    public Object resolve(MethodDetail methodDetail, Parameter parameter) {
        Object param = null;
        RequestBody requestBody = parameter.getDeclaredAnnotation(RequestBody.class);
        if (requestBody != null) {
            try {
                param = OBJECT_MAPPER.readValue(methodDetail.getJson(), parameter.getType());
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
        }
        return param;
    }
}

工程文件

1.链接:https://pan.baidu.com/s/16eyPnxxNg7fQvMbvY-ObFw

2.提取码:ocyb