本文所述文件服务组件在笔者此前一篇文章中已有阐述(基于netty的文件上传下载组件),不过本文将基于之前这个实现再次进行升级改造,利用基于注解的方式进行自动装配。
注:本文首发于SegmentFault,转发请注明出处。
1. 简介
1.1 Netty简介
Netty是一个异步事件驱动的网络应用程序框架,用于快速开发可维护的高性能协议服务器和客户端。关于其详细的介绍可以参考Netty官方网站。
Netty is a NIO client server framework which enables quick and easy development of network applications such as protocol servers and clients. It greatly simplifies and streamlines network programming such as TCP and UDP socket server.
Netty主要特点:
Unified API for various transport types - blocking and non-blocking socket(统一API)
Based on a flexible and extensible event model which allows clear separation of concerns(事件模型)
Highly customizable thread model - single thread, one or more thread pools such as SEDA(线程模型)
True connectionless datagram socket support (since 3.1)(无连接数据报文Socket支持)
1.2 组件功能介绍
该组件基于netty3.6.3实现,具有如下功能:文件上传,文件替换,文件删除,如果是图片的话,还可以生成缩略图等功能。使用简单,只需要引入commons-doc-client-netty,即可以实现文件的以上操作。
本组件分为三个module,分别为:
commons-doc-server-netty:Netty实现文件服务组件的服务端
commons-doc-common:Netty文件服务组件公共组件
commons-doc-client-http:Netty文件服务组件的客户端
2. 服务端
2.1 功能简介
服务端组件实现以下功能:文件上传,文件替换,文件删除,如果是图片的话,还可以生成缩略图等功能。代码结构如下图所示,
[图片上传失败...(image-2bcfa8-1563668595861)]
所有的文件服务都是基于接口DocServerProcessor进行的,主要有以下几个实现类:
UploadDocServerHandler实现文件上传服务
ReplaceDocServerHandler实现文件替换服务
DeleteDocServerHandler实现文件删除服务
CreateThumbPictureServerHandler实现创建图片缩略图服务
2.2 实现步骤
具体实现步骤以文件上传为例。
首先 org.fortune.doc.server.support.DocServerHandler类会持续监听客户端的请求,如果是文件处理动作,则会进入messageReceived方法进行相应的处理逻辑。该类定义了以下成员变量:
//http请求
private HttpRequest request;
//是否需要断点续传作业
private boolean readingChunks;
//接收到的文件内容
private final StringBuffer responseContent = new StringBuffer();
//解析收到的文件
private static final HttpDataFactory factory = new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE); //16384L
//post请求的解码类,它负责把字节解码成Http请求。
private HttpPostRequestDecoder decoder;
//请求参数
private RequestParam requestParams = new RequestParam();
该方法实现中,如果文件大小小于chunked的最小值,则直接进行文件上传操作。否则,需要进行分块处理。然后进行文件上传操作。
文件大小小于1k的操作:
if (request.isChunked()) { //说明还没有请求完成,继续
this.readingChunks = true;
LOGGER.info("文件分块操作....");
} else {
LOGGER.info("文件大小小于1KB,文件接收完成,直接进行相应的文件处理操作....");
//请求完成,则接收请求参数,进行初始化请求参数
RequestParamParser.parseParams(this.decoder, this.requestParams);
//根据请求参数进行相应的文件操作
LOGGER.info("文件处理开始....requestParams参数解析:{}",requestParams);
String result = DocServerHandlerFactory.process(this.requestParams);
LOGGER.info("文件处理结束....FileServerHandlerFactory处理结果:{}",result);
this.responseContent.append(result);
//给客户端响应信息
writeResponse(e.getChannel());
e.getFuture().addListener(ChannelFutureListener.CLOSE);
}
需要分块处理操作:
HttpChunk chunk = (HttpChunk) e.getMessage();
try {
//chunk.getContent().capacity();
LOGGER.info("文件分块操作....文件大小:{} bytes",chunk.getContent().capacity());
this.decoder.offer(chunk);
} catch (HttpPostRequestDecoder.ErrorDataDecoderException e1) {
e1.printStackTrace();
this.responseContent.append(e1.getMessage());
writeResponse(e.getChannel());
Channels.close(e.getChannel());
return;
}
if (chunk.isLast()) {
//文件末尾
this.readingChunks = false;
LOGGER.info("到达文件内容的末尾,进行相应的文件处理操作....start");
RequestParamParser.parseParams(this.decoder, this.requestParams);
LOGGER.info("文件处理开始....requestParams参数解析:{}",requestParams);
String result = DocServerHandlerFactory.process(this.requestParams);
LOGGER.info("文件处理结束....FileServerHandlerFactory处理结果:{}",result);</