【初学与研发之NETTY】netty4之文件上传

来源:互联网 发布:软件系统结构是什么 编辑:程序博客网 时间:2024/04/29 08:31

客户端:

public class UpLoadClient {private StringBuffer resultBuffer = new StringBuffer();private EventLoopGroup group = null;private HttpDataFactory factory = null;private Object waitObject = new Object();private ChannelFuture future = null;public UpLoadClient(String host, int port) throws Exception {this.group = new NioEventLoopGroup();this.factory = new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE);        Bootstrap b = new Bootstrap();        b.option(ChannelOption.TCP_NODELAY, true);        b.option(ChannelOption.SO_SNDBUF, 1048576*200);        b.option(ChannelOption.SO_KEEPALIVE, true);        b.group(group).channel(NioSocketChannel.class);        b.handler(new UpLoadClientIntializer());                this.future = b.connect(host, port).sync();}public void uploadFile(String path) {if(path == null) {System.out.println("上传文件的路径不能为null...");        return;}File file = new File(path);if (!file.canRead()) {System.out.println(file.getName() + "不可读...");        return;}if (file.isHidden() || !file.isFile()) {        System.out.println(file.getName() + "不存在...");        return;        }        try {            HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.POST, "");                    HttpPostRequestEncoder bodyRequestEncoder = new HttpPostRequestEncoder(factory, request, false);                    bodyRequestEncoder.addBodyAttribute("getform", "POST");            bodyRequestEncoder.addBodyFileUpload("myfile", file, "application/x-zip-compressed", false);                        List<InterfaceHttpData> bodylist = bodyRequestEncoder.getBodyListAttributes();            if (bodylist == null) {            System.out.println("请求体不存在...");return;}                        HttpRequest request2 = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.POST, file.getName());            HttpPostRequestEncoder bodyRequestEncoder2 = new HttpPostRequestEncoder(factory, request2, true);                        bodyRequestEncoder2.setBodyHttpDatas(bodylist);            bodyRequestEncoder2.finalizeRequest();                        Channel channel = this.future.channel();            if(channel.isActive() && channel.isWritable()) {                channel.writeAndFlush(request2);                                if (bodyRequestEncoder2.isChunked()) {                    channel.writeAndFlush(bodyRequestEncoder2).awaitUninterruptibly();                }                                bodyRequestEncoder2.cleanFiles();            }            channel.closeFuture().sync();} catch (Exception e) {e.printStackTrace();}}public void shutdownClient() {// 等待数据的传输通道关闭group.shutdownGracefully();factory.cleanAllHttpDatas();}public boolean isCompleted() {while(waitObject != null) {//当通道处于开通和活动时,处于等待}if(resultBuffer.length() > 0) {if("200".equals(resultBuffer.toString())) {resultBuffer.setLength(0);return true;}}return false;}private class UpLoadClientIntializer extends ChannelInitializer<SocketChannel> {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ChannelPipeline pipeline = ch.pipeline();pipeline.addLast("decoder", new HttpResponseDecoder());pipeline.addLast("encoder", new HttpRequestEncoder());  pipeline.addLast("chunkedWriter", new ChunkedWriteHandler());  pipeline.addLast("dispatcher", new UpLoadClientHandler());}}private class UpLoadClientHandler extends SimpleChannelInboundHandler<HttpObject> {private boolean readingChunks = false;private int succCode = 200;protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg)throws Exception {if (msg instanceof HttpResponse) {HttpResponse response = (HttpResponse) msg;succCode = response.getStatus().code();                        if (succCode == 200 && HttpHeaders.isTransferEncodingChunked(response)) {                readingChunks = true;            }}if (msg instanceof HttpContent) {            HttpContent chunk = (HttpContent) msg;            System.out.println("【响应】"+succCode+">>"+chunk.content().toString(CharsetUtil.UTF_8));            if (chunk instanceof LastHttpContent) {                readingChunks = false;            }        }if (!readingChunks) {resultBuffer.append(succCode);ctx.channel().close();}}@Overridepublic void channelInactive(ChannelHandlerContext ctx) throws Exception {waitObject = null;}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)throws Exception {resultBuffer.setLength(0);resultBuffer.append(500);System.out.println("管道异常:" + cause.getMessage());cause.printStackTrace();        ctx.channel().close();}}}


 

服务端:

public class DBServer extends Thread {//单实例private static DBServer dbServer = null;//定时调度的周期实例private static Scheduler sched = null;private EventLoopGroup bossGroup = null;    private EventLoopGroup workerGroup = null;//创建实例public static DBServer newBuild() {if(dbServer == null) {dbServer = new DBServer();}return dbServer;}public void run() {try {startServer();} catch(Exception e) {System.out.println("数据服务启动出现异常:"+e.toString());e.printStackTrace();}}private void startServer() throws Exception {bossGroup = new NioEventLoopGroup();        workerGroup = new NioEventLoopGroup();                try {            ServerBootstrap b = new ServerBootstrap();                        b.group(bossGroup, workerGroup);            b.option(ChannelOption.TCP_NODELAY, true);b.option(ChannelOption.SO_TIMEOUT, 60000);            b.option(ChannelOption.SO_SNDBUF, 1048576*200);                        b.option(ChannelOption.SO_KEEPALIVE, true);            b.channel(NioServerSocketChannel.class);            b.childHandler(new DBServerInitializer());            // 服务器绑定端口监听            ChannelFuture f = b.bind(DBConfig.curHost.getIp(), DBConfig.curHost.getPort()).sync();                        System.out.println("数据服务:"+DBConfig.curHost.getServerHost()+"启动完成...");            // 监听服务器关闭监听            f.channel().closeFuture().sync();        } finally {            bossGroup.shutdownGracefully();            workerGroup.shutdownGracefully();        }}}
public class DBServerHandler extends SimpleChannelInboundHandler<HttpObject> {private static final HttpDataFactory factory = new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE);private String uri = null;private HttpRequest request = null;private HttpPostRequestDecoder decoder;//message、download、uploadprivate String type = "message";public static final String HTTP_DATE_FORMAT = "EEE, dd MMM yyyy HH:mm:ss zzz";    public static final String HTTP_DATE_GMT_TIMEZONE = "GMT";    public static final int HTTP_CACHE_SECONDS = 60;        static {        DiskFileUpload.baseDirectory = DBConfig.curHost.getZipPath();    }    @Override    public void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {    if (msg instanceof HttpRequest) {    request = (HttpRequest) msg;        uri = sanitizeUri(request.getUri());           if (request.getMethod() == HttpMethod.POST) {    if (decoder != null) {decoder.cleanFiles();decoder = null;}    try {              decoder = new HttpPostRequestDecoder(factory, request);    } catch (Exception e) {        e.printStackTrace();        writeResponse(ctx.channel(), HttpResponseStatus.INTERNAL_SERVER_ERROR, e.toString());            ctx.channel().close();        return;    }    }    }        if (decoder != null && msg instanceof HttpContent) {        HttpContent chunk = (HttpContent) msg;                try {        decoder.offer(chunk);        } catch (Exception e) {        e.printStackTrace();        writeResponse(ctx.channel(), HttpResponseStatus.INTERNAL_SERVER_ERROR, e.toString());            ctx.channel().close();                return;        }                readHttpDataChunkByChunk();                if (chunk instanceof LastHttpContent) {        writeResponse(ctx.channel(), HttpResponseStatus.OK, "");                reset();                return;            }        }    }private String sanitizeUri(String uri) {try {uri = URLDecoder.decode(uri, "UTF-8");} catch(UnsupportedEncodingException e) {try {uri = URLDecoder.decode(uri, "ISO-8859-1");} catch(UnsupportedEncodingException e1) {throw new Error();}}return uri;}    private void reset() {        request = null;        //销毁decoder释放所有的资源        decoder.destroy();                decoder = null;    }    /**     * 通过chunk读取request,获取chunk数据     * @throws IOException      */    private void readHttpDataChunkByChunk() throws IOException {    try {    while (decoder.hasNext()) {                    InterfaceHttpData data = decoder.next();            if (data != null) {                try {                    writeHttpData(data);                } finally {                    data.release();                }            }        }    } catch (EndOfDataDecoderException e1) {    System.out.println("end chunk");    }    }    private void writeHttpData(InterfaceHttpData data) throws IOException {        if (data.getHttpDataType() == HttpDataType.FileUpload) {            FileUpload fileUpload = (FileUpload) data;            if (fileUpload.isCompleted()) {            StringBuffer fileNameBuf = new StringBuffer();fileNameBuf.append(DiskFileUpload.baseDirectory)                   .append(uri);fileUpload.renameTo(new File(fileNameBuf.toString()));            }        } else if (data.getHttpDataType() == HttpDataType.Attribute) {        Attribute attribute = (Attribute) data;        if(CommonParam.DOWNLOAD_COLLECTION.equals(attribute.getName())) {        SynchMessageWatcher.newBuild().getMsgQueue().add(attribute.getValue());        }        }    }        private void writeDownLoadResponse(ChannelHandlerContext ctx, RandomAccessFile raf, File file) throws Exception {    long fileLength = raf.length();        //判断是否关闭请求响应连接        boolean close = HttpHeaders.Values.CLOSE.equalsIgnoreCase(request.headers().get(CONNECTION))                || request.getProtocolVersion().equals(HttpVersion.HTTP_1_0)                && !HttpHeaders.Values.KEEP_ALIVE.equalsIgnoreCase(request.headers().get(CONNECTION));                HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);        HttpHeaders.setContentLength(response, fileLength);                setContentHeader(response, file);                if (!close) {            response.headers().set(CONNECTION, HttpHeaders.Values.KEEP_ALIVE);        }        ctx.write(response);        System.out.println("读取大小:"+fileLength);                final FileRegion region = new DefaultFileRegion(raf.getChannel(), 0, 1000);ChannelFuture writeFuture = ctx.write(region, ctx.newProgressivePromise());writeFuture.addListener(new ChannelProgressiveFutureListener() {            public void operationProgressed(ChannelProgressiveFuture future, long progress, long total) {                if (total < 0) {                    System.err.println(future.channel() + " Transfer progress: " + progress);                } else {                    System.err.println(future.channel() + " Transfer progress: " + progress + " / " + total);                }            }            public void operationComplete(ChannelProgressiveFuture future) {            }        });    ChannelFuture lastContentFuture = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);        if(close) {        raf.close();        lastContentFuture.addListener(ChannelFutureListener.CLOSE);        }}        private static void setContentHeader(HttpResponse response, File file) {        MimetypesFileTypeMap mimeTypesMap = new MimetypesFileTypeMap();        response.headers().set(CONTENT_TYPE, mimeTypesMap.getContentType(file.getPath()));                SimpleDateFormat dateFormatter = new SimpleDateFormat(HTTP_DATE_FORMAT, Locale.US);        dateFormatter.setTimeZone(TimeZone.getTimeZone(HTTP_DATE_GMT_TIMEZONE));        // Date header        Calendar time = new GregorianCalendar();        response.headers().set(DATE, dateFormatter.format(time.getTime()));        // Add cache headers        time.add(Calendar.SECOND, HTTP_CACHE_SECONDS);        response.headers().set(EXPIRES, dateFormatter.format(time.getTime()));        response.headers().set(CACHE_CONTROL, "private, max-age=" + HTTP_CACHE_SECONDS);        response.headers().set(LAST_MODIFIED, dateFormatter.format(new Date(file.lastModified())));    }        private void writeResponse(Channel channel, HttpResponseStatus httpResponseStatus, String returnMsg) {    String resultStr = "节点【"+DBConfig.curHost.getServerHost()+"】";    if(httpResponseStatus.code() == HttpResponseStatus.OK.code()) {    resultStr += "正常接收";    if("message".equals(type)) {    resultStr += "字符串。";    } else if("upload".equals(type)) {    resultStr += "上传文件。";    } else if("download".equals(type)) {    resultStr += "下载文件名。";    }    } else if(httpResponseStatus.code() == HttpResponseStatus.INTERNAL_SERVER_ERROR.code()) {    resultStr += "接收";    if("message".equals(type)) {    resultStr += "字符串";    } else if("upload".equals(type)) {    resultStr += "上传文件";    } else if("download".equals(type)) {    resultStr += "下载文件名";    }    resultStr += "的过程中出现异常:"+returnMsg;    }        //将请求响应的内容转换成ChannelBuffer.        ByteBuf buf = copiedBuffer(resultStr, CharsetUtil.UTF_8);        //判断是否关闭请求响应连接        boolean close = HttpHeaders.Values.CLOSE.equalsIgnoreCase(request.headers().get(CONNECTION))                || request.getProtocolVersion().equals(HttpVersion.HTTP_1_0)                && !HttpHeaders.Values.KEEP_ALIVE.equalsIgnoreCase(request.headers().get(CONNECTION));                //构建请求响应对象        FullHttpResponse response = new DefaultFullHttpResponse(                HttpVersion.HTTP_1_1, httpResponseStatus, buf);        response.headers().set(CONTENT_TYPE, "text/plain; charset=UTF-8");        if (!close) {            //若该请求响应是最后的响应,则在响应头中没有必要添加'Content-Length'            response.headers().set(CONTENT_LENGTH, buf.readableBytes());        }                //发送请求响应        ChannelFuture future = channel.writeAndFlush(response);        //发送请求响应操作结束后关闭连接        if (close) {            future.addListener(ChannelFutureListener.CLOSE);        }    }    @Override    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {    cause.getCause().printStackTrace();    writeResponse(ctx.channel(), HttpResponseStatus.INTERNAL_SERVER_ERROR, "数据文件通过过程中出现异常:"+cause.getMessage().toString());        ctx.channel().close();    }}
public class DBServerInitializer extends ChannelInitializer<SocketChannel> {    @Override    public void initChannel(SocketChannel ch) {        ChannelPipeline pipeline = ch.pipeline();                pipeline.addLast("decoder", new HttpRequestDecoder());pipeline.addLast("encoder", new HttpResponseEncoder());pipeline.addLast("deflater", new HttpContentCompressor());        pipeline.addLast("handler", new DBServerHandler());    }}




 

2 0
原创粉丝点击