1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        SpringBoot集成Netty實現(xiàn)文件傳輸

        共 5398字,需瀏覽 11分鐘

         ·

        2020-10-24 05:30

        點擊上方藍色字體,選擇“標星公眾號”

        優(yōu)質文章,第一時間送達

        ? 作者?|??47號Gamer丶

        來源 |? urlify.cn/bIzUZb

        66套java從入門到精通實戰(zhàn)課程分享

        實現(xiàn)瀏覽本地文件目錄,實現(xiàn)文件夾目錄的跳轉和文件的下載

        添加依賴:


        ????org.springframework.boot
        ????spring-boot-starter-web
        ????
        ????????
        ????????????org.springframework.boot
        ????????????spring-boot-starter-tomcat
        ????????

        ????



        ????io.netty
        ????netty-all
        ????4.1.1.Final


        ????commons-lang
        ????commons-lang
        ????${commons.lang.version}

        排除tomcat的依賴

        Netty Http服務端編寫:

        handler 處理類

        @Component
        @Slf4j
        @ChannelHandler.Sharable?//@Sharable?注解用來說明ChannelHandler是否可以在多個channel直接共享使用
        public?class?FileServerHandler?extends?ChannelInboundHandlerAdapter?{

        ???//?private?static?final?Pattern?ALLOWED_FILE_NAME?=?Pattern.compile("[A-Za-z0-9][-_A-Za-z0-9\\.]*");

        ????//文件存放路徑
        ????@Value("${netty.file.path:}")
        ????String?path;

        ????@Override
        ????public?void?channelRead(ChannelHandlerContext?ctx,?Object?msg)?{
        ????????try{
        ????????????if?(msg?instanceof?FullHttpRequest)?{
        ????????????????FullHttpRequest?req?=?(FullHttpRequest)?msg;
        ????????????????if(req.method()?!=?HttpMethod.GET)?{
        ????????????????????sendError(ctx,?HttpResponseStatus.METHOD_NOT_ALLOWED);
        ????????????????????return;
        ????????????????}
        ????????????????String?url?=?req.uri();
        ????????????????File?file?=?new?File(path?+?url);
        ????????????????if(file.exists()){
        ????????????????????if(file.isDirectory()){
        ????????????????????????if(url.endsWith("/"))?{
        ????????????????????????????sendListing(ctx,?file);
        ????????????????????????}else{
        ????????????????????????????sendRedirect(ctx,?url?+?"/");
        ????????????????????????}
        ????????????????????????return;
        ????????????????????}else?{
        ????????????????????????transferFile(?file,??ctx);
        ????????????????????}
        ????????????????}else{
        ????????????????????sendError(ctx,?HttpResponseStatus.NOT_FOUND);
        ????????????????}
        ????????????}
        ????????}catch(Exception?e){
        ????????????log.error("Exception:{}",e);
        ????????????sendError(ctx,?HttpResponseStatus.BAD_REQUEST);
        ????????}
        ????}

        ????/**
        ?????*?傳輸文件
        ?????*?@param?file
        ?????*?@param?ctx
        ?????*/
        ????private?void?transferFile(File?file,?ChannelHandlerContext?ctx){
        ????????try{
        ????????????RandomAccessFile?randomAccessFile?=?new?RandomAccessFile(file,?"r");
        ????????????long?fileLength?=?randomAccessFile.length();
        ????????????HttpResponse?response?=?new?DefaultHttpResponse(HttpVersion.HTTP_1_1,?HttpResponseStatus.OK);
        ????????????response.headers().set(HttpHeaderNames.CONTENT_LENGTH,?fileLength);
        ????????????ctx.write(response);
        ????????????ChannelFuture?sendFileFuture?=?ctx.write(new?ChunkedFile(randomAccessFile,?0,?fileLength,?8192),?ctx.newProgressivePromise());
        ????????????addListener(?sendFileFuture);
        ????????????ChannelFuture?lastContentFuture?=?ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);
        ????????????lastContentFuture.addListener(ChannelFutureListener.CLOSE);
        ????????}catch?(Exception?e){
        ????????????log.error("Exception:{}",e);
        ????????}
        ????}

        ????/**
        ?????*?監(jiān)聽傳輸狀態(tài)
        ?????*?@param?sendFileFuture
        ?????*/
        ????private?void?addListener(?ChannelFuture?sendFileFuture){
        ????????sendFileFuture.addListener(new?ChannelProgressiveFutureListener()?{
        ????????????????@Override
        ????????????????public?void?operationComplete(ChannelProgressiveFuture?future)
        ????????????????????????throws?Exception?{
        ????????????????????log.debug("Transfer?complete.");
        ????????????????}
        ????????????????@Override
        ????????????????public?void?operationProgressed(ChannelProgressiveFuture?future,?long?progress,?long?total)?throws?Exception?{
        ????????????????????if(total?????????????????????????log.debug("Transfer?progress:?"?+?progress);
        ????????????????????}else{
        ????????????????????????log.debug("Transfer?progress:?"?+?progress?+?"/"?+?total);
        ????????????????????}
        ????????????????}
        ????????});
        ????}


        ????/**
        ?????*?請求為目錄時,顯示文件列表
        ?????*?@param?ctx
        ?????*?@param?dir
        ?????*/
        ????private?static?void?sendListing(ChannelHandlerContext?ctx,?File?dir){
        ????????FullHttpResponse?response?=?new?DefaultFullHttpResponse(HttpVersion.HTTP_1_1,?HttpResponseStatus.OK);
        ????????response.headers().set(HttpHeaderNames.CONTENT_TYPE,?"text/html;charset=UTF-8");

        ????????String?dirPath?=?dir.getPath();
        ????????StringBuilder?buf?=?new?StringBuilder();

        ????????buf.append("\r\n");
        ????????buf.append(""</span>);<br>????????buf.append(dirPath);<br>????????buf.append(<span style="color: #98c379;line-height: 26px;">"目錄:"</span>);<br>????????buf.append(<span style="color: #98c379;line-height: 26px;">"\r\n");

        ????????buf.append("

        ");
        ????????buf.append(dirPath).append("?目錄:");
        ????????buf.append("

        \r\n"
        );
        ????????buf.append("\r\n");
        ????????ByteBuf?buffer?=?Unpooled.copiedBuffer(buf,CharsetUtil.UTF_8);
        ????????response.content().writeBytes(buffer);
        ????????buffer.release();
        ????????ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
        ????}

        ????/**
        ?????*?跳轉鏈接
        ?????*?@param?ctx
        ?????*?@param?newUri
        ?????*/
        ????private?static?void?sendRedirect(ChannelHandlerContext?ctx,?String?newUri){
        ????????FullHttpResponse?response?=?new?DefaultFullHttpResponse(HttpVersion.HTTP_1_1,?HttpResponseStatus.FOUND);
        ????????response.headers().set(HttpHeaderNames.LOCATION,?newUri);
        ????????ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
        ????}

        ????/**
        ?????*?失敗響應
        ?????*?@param?ctx
        ?????*?@param?status
        ?????*/
        ????private?static?void?sendError(ChannelHandlerContext?ctx,?HttpResponseStatus?status){
        ????????FullHttpResponse?response?=?new?DefaultFullHttpResponse(HttpVersion.HTTP_1_1,?status,
        ????????????????Unpooled.copiedBuffer("Failure:?"?+?status.toString()?+?"\r\n",?CharsetUtil.UTF_8));
        ????????response.headers().set(HttpHeaderNames.CONTENT_TYPE,?"text/html;charset=UTF-8");
        ????????ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
        ????}


        }

        ChannelPipeline 實現(xiàn):

        @Component
        @ConditionalOnProperty(??//配置文件屬性是否為true
        ????????value?=?{"netty.file.enabled"},
        ????????matchIfMissing?=?false
        )
        public?class?FilePipeline?extends?ChannelInitializer?{

        ????@Autowired
        ????FileServerHandler?fleServerHandler;

        ????@Override
        ????protected?void?initChannel(SocketChannel?socketChannel)?throws?Exception?{
        ????????ChannelPipeline?p?=?socketChannel.pipeline();
        ????????p.addLast("http-decoder",?new?HttpRequestDecoder());
        ????????p.addLast("http-aggregator",?new?HttpObjectAggregator(65536));
        ????????p.addLast("http-encoder",?new?HttpResponseEncoder());
        ????????p.addLast("http-chunked",?new?ChunkedWriteHandler());
        ????????p.addLast("fileServerHandler",fleServerHandler);
        ????}
        }

        服務實現(xiàn):

        @Configuration
        @EnableConfigurationProperties({NettyFileProperties.class})
        @ConditionalOnProperty(??//配置文件屬性是否為true
        ????????value?=?{"netty.file.enabled"},
        ????????matchIfMissing?=?false
        )
        @Slf4j
        public?class?FileServer?{
        ????@Autowired
        ????FilePipeline?filePipeline;

        ????@Autowired
        ????NettyFileProperties?nettyFileProperties;

        ????@Bean("starFileServer")
        ????public?String?start()?{
        ????????Thread?thread?=??new?Thread(()?->?{
        ????????????NioEventLoopGroup?bossGroup?=?new?NioEventLoopGroup(nettyFileProperties.getBossThreads());
        ????????????NioEventLoopGroup?workerGroup?=?new?NioEventLoopGroup(nettyFileProperties.getWorkThreads());
        ????????????try?{
        ????????????????log.info("start?netty?[FileServer]?server?,port:?"?+?nettyFileProperties.getPort());
        ????????????????ServerBootstrap?boot?=?new?ServerBootstrap();
        ????????????????options(boot).group(bossGroup,?workerGroup)
        ????????????????????????.channel(NioServerSocketChannel.class)
        ????????????????????????.handler(new?LoggingHandler(LogLevel.INFO))
        ????????????????????????.childHandler(filePipeline);
        ????????????????Channel?ch?=?null;
        ??????????????//是否綁定IP
        ????????????????if(StringUtils.isNotEmpty(nettyFileProperties.getBindIp())){
        ????????????????????ch?=?boot.bind(nettyFileProperties.getBindIp(),nettyFileProperties.getPort()).sync().channel();
        ????????????????}else{
        ????????????????????ch?=?boot.bind(nettyFileProperties.getPort()).sync().channel();
        ????????????????}
        ????????????????ch.closeFuture().sync();
        ????????????}?catch?(InterruptedException?e)?{
        ????????????????log.error("啟動NettyServer錯誤",?e);
        ????????????}?finally?{
        ????????????????bossGroup.shutdownGracefully();
        ????????????????workerGroup.shutdownGracefully();
        ????????????}
        ????????});
        ????????thread.setName("File_Server");
        ????????thread.start();
        ????????return?"file?start";
        ????}


        ????private?ServerBootstrap?options(ServerBootstrap?boot)?{
        ?/*???????boot.option(ChannelOption.SO_BACKLOG,?1024)
        ????????????????.option(ChannelOption.TCP_NODELAY,?true)
        ????????????????.option(ChannelOption.ALLOCATOR,?PooledByteBufAllocator.DEFAULT);*/
        ????????return?boot;
        ????}
        }

        啟動配置:

        ---application.yml
        spring.profiles.active:?file

        ---application-file.yml
        netty:
        ???file:
        ?????enabled:?true
        ?????path:?d:\
        ?????port:?3456

        測試

        在瀏覽器打開http://127.0.0.1:3456/

        ?



        粉絲福利:108本java從入門到大神精選電子書領取

        ???

        ?長按上方鋒哥微信二維碼?2 秒
        備注「1234」即可獲取資料以及
        可以進入java1234官方微信群



        感謝點贊支持下哈?

        瀏覽 83
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            青青草久久久 | 一级黄色毛片视频 | 老板把我抱进房间揉我胸视频 | 夜夜夜撸 | 被男人狂揉吃奶胸视频 | 91熟妇 | 尤蜜粉嫩av国产一区二区三区 | 天天干天天添 | 豆花精品在线 | 国产精品成人无码a 无码 |