成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

通用文件服務(wù)組件(Netty實現(xiàn)版本)

fou7 / 1780人閱讀

摘要:操作指引該文件服務(wù)組件的使用需要分為兩個部分,一個是服務(wù)端配置與啟動,一個是客戶端的配置與啟動。在調(diào)用文件服務(wù)返回的路徑的時候,需要用到服務(wù)端訪問文件的地址,進(jìn)而訪問相應(yīng)的文件內(nèi)容。

本文所述文件服務(wù)組件在筆者此前一篇文章中已有闡述(基于netty的文件上傳下載組件),不過本文將基于之前這個實現(xiàn)再次進(jìn)行升級改造,利用基于注解的方式進(jìn)行自動裝配。
1. 簡介 1.1 Netty簡介

Netty是一個異步事件驅(qū)動的網(wǎng)絡(luò)應(yīng)用程序框架,用于快速開發(fā)可維護(hù)的高性能協(xié)議服務(wù)器和客戶端。關(guān)于其詳細(xì)的介紹可以參考Netty官方網(wǎng)站。

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(統(tǒng)一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)(無連接數(shù)據(jù)報文Socket支持)

1.2 組件功能介紹

該組件基于netty3.6.3實現(xiàn),具有如下功能:文件上傳,文件替換,文件刪除,如果是圖片的話,還可以生成縮略圖等功能。使用簡單,只需要引入commons-doc-client-netty,即可以實現(xiàn)文件的以上操作。

本組件分為三個module,分別為:

commons-doc-server-netty:Netty實現(xiàn)文件服務(wù)組件的服務(wù)端

commons-doc-common:Netty文件服務(wù)組件公共組件

commons-doc-client-netty:Netty文件服務(wù)組件的客戶端

2. 服務(wù)端 2.1 功能簡介

服務(wù)端組件實現(xiàn)以下功能:文件上傳,文件替換,文件刪除,如果是圖片的話,還可以生成縮略圖等功能。代碼結(jié)構(gòu)如下圖所示,

所有的文件服務(wù)都是基于接口DocServerProcessor進(jìn)行的,主要有以下幾個實現(xiàn)類:

UploadDocServerHandler實現(xiàn)文件上傳服務(wù)

ReplaceDocServerHandler實現(xiàn)文件替換服務(wù)

DeleteDocServerHandler實現(xiàn)文件刪除服務(wù)

CreateThumbPictureServerHandler實現(xiàn)創(chuàng)建圖片縮略圖服務(wù)

2.2 實現(xiàn)步驟

具體實現(xiàn)步驟以文件上傳為例。

首先 org.fortune.doc.server.support.DocServerHandler類會持續(xù)監(jiān)聽客戶端的請求,如果是文件處理動作,則會進(jìn)入messageReceived方法進(jìn)行相應(yīng)的處理邏輯。該類定義了以下成員變量:

//http請求
private HttpRequest request;
//是否需要斷點續(xù)傳作業(yè)
private boolean readingChunks;
//接收到的文件內(nèi)容
private final StringBuffer responseContent = new StringBuffer();
//解析收到的文件
private static final HttpDataFactory factory = new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE); //16384L
//post請求的解碼類,它負(fù)責(zé)把字節(jié)解碼成Http請求。
private HttpPostRequestDecoder decoder;
//請求參數(shù)
private RequestParam requestParams = new RequestParam();

該方法實現(xiàn)中,如果文件大小小于chunked的最小值,則直接進(jìn)行文件上傳操作。否則,需要進(jìn)行分塊處理。然后進(jìn)行文件上傳操作。
文件大小小于1k的操作:

if (request.isChunked()) { //說明還沒有請求完成,繼續(xù)
    this.readingChunks = true;
    LOGGER.info("文件分塊操作....");
} else {
    LOGGER.info("文件大小小于1KB,文件接收完成,直接進(jìn)行相應(yīng)的文件處理操作....");
    //請求完成,則接收請求參數(shù),進(jìn)行初始化請求參數(shù)
    RequestParamParser.parseParams(this.decoder, this.requestParams);
    //根據(jù)請求參數(shù)進(jìn)行相應(yīng)的文件操作
    LOGGER.info("文件處理開始....requestParams參數(shù)解析:{}",requestParams);
    String result = DocServerHandlerFactory.process(this.requestParams);
    LOGGER.info("文件處理結(jié)束....FileServerHandlerFactory處理結(jié)果:{}",result);
    this.responseContent.append(result);
    //給客戶端響應(yīng)信息
    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("到達(dá)文件內(nèi)容的末尾,進(jìn)行相應(yīng)的文件處理操作....start");
    RequestParamParser.parseParams(this.decoder, this.requestParams);

    LOGGER.info("文件處理開始....requestParams參數(shù)解析:{}",requestParams);
    String result = DocServerHandlerFactory.process(this.requestParams);
    LOGGER.info("文件處理結(jié)束....FileServerHandlerFactory處理結(jié)果:{}",result);

    this.responseContent.append(result);
    //給客戶端響應(yīng)信息
    writeResponse(e.getChannel());

    e.getFuture().addListener(ChannelFutureListener.CLOSE);
    LOGGER.info("到達(dá)文件內(nèi)容的末尾,進(jìn)行相應(yīng)的文件處理操作....end");
}

以上操作主要有兩個注意點:

請求參數(shù)的解析工作(根據(jù)HttpDataType進(jìn)行相應(yīng)參數(shù)的賦值操作)

根據(jù)解析的參數(shù)進(jìn)行相應(yīng)的文件處理操作(根據(jù)文件操作類型,選擇相應(yīng)的處理句柄進(jìn)行文件處理)

3. 客戶端 3.1 功能簡介

客戶端組件主要提供對外訪問服務(wù)端組件的接口,提供以下接口:文件上傳,文件替換,文件刪除,如果是圖片的話,還可以生成縮略圖等功能。代碼結(jié)構(gòu)如下:

org.fortune.doc.client.DocClient類是對外提供接口的工具類,具有以下主要方法:

uploadFile 文件上傳,對應(yīng)文件處理句柄類為:org.fortune.doc.client.handler.UploadDocClientHandler

deleteFile 刪除服務(wù)端文件,對應(yīng)文件處理句柄類為:org.fortune.doc.client.handler.DeleteDocClientHandler

replaceFile 替換服務(wù)端文件,對應(yīng)文件處理句柄類為:org.fortune.doc.client.handler.ReplaceDocClientHandler

createThumbPicture 生成縮略圖,對應(yīng)文件處理句柄類為:org.fortune.doc.client.handler.CreateThumbPictureClientHandler

3.2 實現(xiàn)步驟

實現(xiàn)步驟以上傳文件為例,其他類似實現(xiàn)。直接上代碼:

/**
     * 文件上傳
     * @param file 需要上傳的文件
     * @param fileName 文件名稱
     * @param thumbMark 是否需要生成縮略圖
     * @return
     * @author:landyChris
     */
    public static String uploadFile(File file, String fileName,
                                    boolean thumbMark) {
        DocClientPipelineFactory clientPipelineFactory = new DocClientPipelineFactory();
        //輔助類。用于幫助我們創(chuàng)建NETTY服務(wù)
        ClientBootstrap bootstrap = createClientBootstrap(clientPipelineFactory);
        String strThumbMark = Constants.THUMB_MARK_NO;
        if (thumbMark) {
            strThumbMark = Constants.THUMB_MARK_YES;
        }
        //具體處理上傳文件邏輯
        uploadFile(bootstrap, DocClientContainer.getInstance().getHost(),
                DocClientContainer.getInstance().getPort(), file, fileName, strThumbMark,
                DocClientContainer.getInstance().getUserName(),
                DocClientContainer.getInstance().getPassword());
        Result result = clientPipelineFactory.getResult();
        if ((result != null) && (result.isSuccess())) {
            return result.getFilePath();
        }
        return null;
    }

具有三個參數(shù),前面幾行代碼都是很一些netty的初始化工作,具體看一個私有方法uploadFile,如下代碼所示:

private static void uploadFile(ClientBootstrap bootstrap, String host,
                                   int port, File file, String fileName, String thumbMark,
                                   String userName, String pwd) {
        //1.構(gòu)建uri對象
        URI uri = getUri(host, port);
        //2.連接netty服務(wù)端
        ChannelFuture future = bootstrap.connect(new InetSocketAddress(host,
                port));
        //3.異步獲取Channel對象
        Channel channel = future.awaitUninterruptibly().getChannel();
        if (!future.isSuccess()) {
            future.getCause().printStackTrace();
            bootstrap.releaseExternalResources();
            return;
        }
        //4.初始化文件上傳句柄對象
        AbstractDocClientHandler handler = new UploadDocClientHandler(host, uri,
                file, fileName, thumbMark, userName, pwd);
        //5.獲取Request對象
        HttpRequest request = handler.getRequest();
        //6.獲取Http數(shù)據(jù)處理工廠
        HttpDataFactory factory = getHttpDataFactory();
        //7.進(jìn)行數(shù)據(jù)的包裝處理,主要是進(jìn)行上傳文件所需要的參數(shù)的設(shè)置,此時調(diào)用的句柄是具體的UploadFileClientHandler對象
        HttpPostRequestEncoder bodyRequestEncoder = handler
                .wrapRequestData(factory);
        //8.把request寫到管道中,傳輸給服務(wù)端
        channel.write(request);
        //9.做一些關(guān)閉資源的動作
        if (bodyRequestEncoder.isChunked()) {
            channel.write(bodyRequestEncoder).awaitUninterruptibly();
        }
        bodyRequestEncoder.cleanFiles();
        channel.getCloseFuture().awaitUninterruptibly();

        bootstrap.releaseExternalResources();
        factory.cleanAllHttpDatas();
    }

主要有以下實現(xiàn)步驟:

構(gòu)建uri對象

連接netty服務(wù)端

異步獲取Channel對象

初始化文件上傳句柄對象

獲取Request對象

獲取Http數(shù)據(jù)處理工廠

進(jìn)行數(shù)據(jù)的包裝處理,主要是進(jìn)行上傳文件所需要的參數(shù)的設(shè)置,此時調(diào)用的句柄是具體的UploadFileClientHandler對象

把request寫到管道中,傳輸給服務(wù)端

做一些關(guān)閉資源的動作
具體細(xì)節(jié)實現(xiàn)請參考github上的代碼。如果各位讀者喜歡的話,可以加個star哈。

4. 操作指引

該文件服務(wù)組件的使用需要分為兩個部分,一個是服務(wù)端配置與啟動,一個是客戶端的配置與啟動。

4.1 服務(wù)端配置與啟動 4.1.1 配置

服務(wù)端的配置采用yml文件的配置,更加的簡潔明了,主要的注意點是文件存放位置的配置,在開發(fā)過程中,可以有兩種方式配置:

Idea自啟動方式:如果采用此種方式則需要把rootPath配置到工程路徑下(target目錄),如下所示:

# 在idea中執(zhí)行的話,需要配置target目錄下的打包文件
    rootPath: C: