From 832e3f6bc7b41a6799c97022ec9b4db99ac6f4a9 Mon Sep 17 00:00:00 2001 From: MagakiReimu <448143736@qq.com> Date: Thu, 30 Apr 2020 08:31:44 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E6=B7=BB=E5=8A=A0@Override?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../github/tobato/fastdfs/domain/conn/DefaultConnection.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/com/github/tobato/fastdfs/domain/conn/DefaultConnection.java b/src/main/java/com/github/tobato/fastdfs/domain/conn/DefaultConnection.java index 7070cfd..39461d3 100644 --- a/src/main/java/com/github/tobato/fastdfs/domain/conn/DefaultConnection.java +++ b/src/main/java/com/github/tobato/fastdfs/domain/conn/DefaultConnection.java @@ -60,6 +60,7 @@ public DefaultConnection(InetSocketAddress address, int soTimeout, int connectTi /** * 正常关闭连接 */ + @Override public synchronized void close() { LOGGER.debug("disconnect from {}", socket); byte[] header = new byte[OtherConstants.FDFS_PROTO_PKG_LEN_SIZE + 2]; @@ -120,6 +121,7 @@ public boolean isValid() { * @return * @throws IOException */ + @Override public OutputStream getOutputStream() throws IOException { return socket.getOutputStream(); } @@ -130,6 +132,7 @@ public OutputStream getOutputStream() throws IOException { * @return * @throws IOException */ + @Override public InputStream getInputStream() throws IOException { return socket.getInputStream(); } @@ -139,6 +142,7 @@ public InputStream getInputStream() throws IOException { * * @return */ + @Override public Charset getCharset() { return charset; } From 632fa018046d70a0f05c3dbae08c414870558124 Mon Sep 17 00:00:00 2001 From: MagakiReimu <448143736@qq.com> Date: Thu, 30 Apr 2020 08:33:10 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/conn/DefaultConnection.java | 22 +++++-------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/src/main/java/com/github/tobato/fastdfs/domain/conn/DefaultConnection.java b/src/main/java/com/github/tobato/fastdfs/domain/conn/DefaultConnection.java index 39461d3..7cacde8 100644 --- a/src/main/java/com/github/tobato/fastdfs/domain/conn/DefaultConnection.java +++ b/src/main/java/com/github/tobato/fastdfs/domain/conn/DefaultConnection.java @@ -2,7 +2,8 @@ import com.github.tobato.fastdfs.domain.proto.CmdConstants; import com.github.tobato.fastdfs.domain.proto.OtherConstants; -import com.github.tobato.fastdfs.domain.proto.mapper.BytesUtil; +import com.github.tobato.fastdfs.domain.proto.ProtoHead; +import com.github.tobato.fastdfs.domain.proto.StatusConstants; import com.github.tobato.fastdfs.exception.FdfsConnectException; import org.apache.commons.io.IOUtils; import org.slf4j.Logger; @@ -14,7 +15,6 @@ import java.net.InetSocketAddress; import java.net.Socket; import java.nio.charset.Charset; -import java.util.Arrays; /** * 默认连接实现 @@ -63,14 +63,8 @@ public DefaultConnection(InetSocketAddress address, int soTimeout, int connectTi @Override public synchronized void close() { LOGGER.debug("disconnect from {}", socket); - byte[] header = new byte[OtherConstants.FDFS_PROTO_PKG_LEN_SIZE + 2]; - Arrays.fill(header, (byte) 0); - - byte[] hex_len = BytesUtil.long2buff(0); - System.arraycopy(hex_len, 0, header, 0, hex_len.length); - header[OtherConstants.PROTO_HEADER_CMD_INDEX] = CmdConstants.FDFS_PROTO_CMD_QUIT; - header[OtherConstants.PROTO_HEADER_STATUS_INDEX] = (byte) 0; try { + byte[] header = new ProtoHead(CmdConstants.FDFS_PROTO_CMD_QUIT).toByte(); socket.getOutputStream().write(header); socket.close(); } catch (IOException e) { @@ -96,19 +90,13 @@ public boolean isClosed() { public boolean isValid() { LOGGER.debug("check connection status of {} ", this); try { - byte[] header = new byte[OtherConstants.FDFS_PROTO_PKG_LEN_SIZE + 2]; - Arrays.fill(header, (byte) 0); - - byte[] hex_len = BytesUtil.long2buff(0); - System.arraycopy(hex_len, 0, header, 0, hex_len.length); - header[OtherConstants.PROTO_HEADER_CMD_INDEX] = CmdConstants.FDFS_PROTO_CMD_ACTIVE_TEST; - header[OtherConstants.PROTO_HEADER_STATUS_INDEX] = (byte) 0; + byte[] header = new ProtoHead(CmdConstants.FDFS_PROTO_CMD_ACTIVE_TEST).toByte(); socket.getOutputStream().write(header); if (socket.getInputStream().read(header) != header.length) { return false; } - return header[OtherConstants.PROTO_HEADER_STATUS_INDEX] == 0 ? true : false; + return header[OtherConstants.PROTO_HEADER_STATUS_INDEX] == StatusConstants.FDFS_STORAGE_STATUS_INIT; } catch (IOException e) { LOGGER.error("valid connection error", e); return false; From 2d8b7d49b735afb6c044da10526af1ec6b18684a Mon Sep 17 00:00:00 2001 From: MagakiReimu <448143736@qq.com> Date: Thu, 30 Apr 2020 08:58:37 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E5=88=86=E6=AE=B5=E4=B8=8B=E8=BD=BD?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E7=A4=BA=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../FileDownloadDemoController.java | 100 ++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 src/test/java/com/github/tobato/fastdfs/controller/FileDownloadDemoController.java diff --git a/src/test/java/com/github/tobato/fastdfs/controller/FileDownloadDemoController.java b/src/test/java/com/github/tobato/fastdfs/controller/FileDownloadDemoController.java new file mode 100644 index 0000000..29d59e8 --- /dev/null +++ b/src/test/java/com/github/tobato/fastdfs/controller/FileDownloadDemoController.java @@ -0,0 +1,100 @@ +package com.github.tobato.fastdfs.controller; + +import com.github.tobato.fastdfs.service.DefaultGenerateStorageClient; +import org.apache.commons.io.IOUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.*; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.http.HttpServletResponse; +import java.net.URLConnection; +import java.nio.charset.StandardCharsets; +import java.util.List; + +/** + * @author MagakiReimu + * @version 1.0 + */ +@RestController +@RequestMapping("/download") +public class FileDownloadDemoController { + + @Autowired + private DefaultGenerateStorageClient defaultGenerateStorageClient; + + @GetMapping("/demo") + public void downloadDemo(@RequestHeader(value = HttpHeaders.RANGE, required = false) String rangeHeader, + HttpServletResponse response) { + // 以下数据,请从自己的开发系统中获取 + String fileName = "abc.txt"; + String group = "group1"; + String path = "xxxxx"; + long fileSize = 0L; + + // 分段下载计算参数 + long rangeStart = 0L; + long rangeEnd = 0L; + long downloadSize = 0L; + long contentLength = fileSize; + + // 获取分段下载请求 + List httpRangeList = HttpRange.parseRanges(rangeHeader); + if (httpRangeList.size() == 0) { + // 无分段下载请求,下载为全量下载 + // 调用downloadFile下载整个文件, 调用接口为只有group, path参数时 + // 下载接口统一, 保持二次调用中rangeStart, downloadSize为0 + // 普通下载状态码200 + response.setStatus(HttpStatus.OK.value()); + } else if (httpRangeList.size() == 1) { + // 分段下载只解析第一个,一般请求只包含一个 + HttpRange httpRange = httpRangeList.get(0); + // 请求起始字节 + rangeStart = httpRange.getRangeStart(fileSize); + // 请求结束字节 + rangeEnd = httpRange.getRangeEnd(fileSize); + // 请求分段长度 + contentLength = rangeEnd - rangeStart + 1L; + // 请求下载长度 + downloadSize = contentLength; + // Content-Range: bytes [unit first byte pos] - [last byte pos] / [entity length] + String contentRange = String.format("bytes %d-%d/%d", rangeStart, rangeEnd, fileSize); + response.addHeader(HttpHeaders.CONTENT_RANGE, contentRange); + // 分段下载状态码206 + response.setStatus(HttpStatus.PARTIAL_CONTENT.value()); + } else { + // 协议支持一个请求包含多段下载, Demo不做多段解析 + response.setStatus(HttpStatus.BAD_REQUEST.value()); + return; + } + + // Content-Type + // 方式一:写死Content-Type + MediaType contentType = MediaType.APPLICATION_OCTET_STREAM; + // 方式二:根据文件名猜测Content-Type + contentType = MediaType.parseMediaType(URLConnection.guessContentTypeFromName(fileName)); + response.setContentType(contentType.toString()); + // Content-Disposition + //@formatter:off + ContentDisposition contentDisposition = ContentDisposition + .builder("form-data") + .name("attachment") + .filename(fileName, StandardCharsets.UTF_8) + .build(); + //@formatter:on + response.addHeader(HttpHeaders.CONTENT_DISPOSITION, contentDisposition.toString()); + // 本次下载大小 + response.setContentLengthLong(contentLength); + // 支持分段下载 + response.addHeader(HttpHeaders.ACCEPT_RANGES, "bytes"); + + // 根据上方计算值,下载区间数据 + defaultGenerateStorageClient.downloadFile(group, path, rangeStart, downloadSize, + inputStream -> { + IOUtils.copy(inputStream, response.getOutputStream()); + return null; + }); + } +}