├── .gitattributes ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── pom.xml ├── readme.md ├── src ├── doc │ └── 01_Release.md ├── main │ ├── java │ │ └── com │ │ │ └── github │ │ │ └── tobato │ │ │ └── fastdfs │ │ │ ├── FdfsClientConfig.java │ │ │ ├── FdfsClientConstants.java │ │ │ ├── domain │ │ │ ├── conn │ │ │ │ ├── Connection.java │ │ │ │ ├── ConnectionPoolConfig.java │ │ │ │ ├── DefaultConnection.java │ │ │ │ ├── FdfsConnectionManager.java │ │ │ │ ├── FdfsConnectionPool.java │ │ │ │ ├── FdfsWebServer.java │ │ │ │ ├── PooledConnectionFactory.java │ │ │ │ ├── TrackerConnectionManager.java │ │ │ │ └── package-info.java │ │ │ ├── fdfs │ │ │ │ ├── CircularList.java │ │ │ │ ├── DefaultThumbImageConfig.java │ │ │ │ ├── FileInfo.java │ │ │ │ ├── GroupState.java │ │ │ │ ├── MetaData.java │ │ │ │ ├── StorageNode.java │ │ │ │ ├── StorageNodeInfo.java │ │ │ │ ├── StorageState.java │ │ │ │ ├── StorePath.java │ │ │ │ ├── ThumbImageConfig.java │ │ │ │ ├── TrackerAddressHolder.java │ │ │ │ ├── TrackerLocator.java │ │ │ │ └── package-info.java │ │ │ ├── proto │ │ │ │ ├── AbstractFdfsCommand.java │ │ │ │ ├── CmdConstants.java │ │ │ │ ├── ErrorCodeConstants.java │ │ │ │ ├── FdfsCommand.java │ │ │ │ ├── FdfsRequest.java │ │ │ │ ├── FdfsResponse.java │ │ │ │ ├── OtherConstants.java │ │ │ │ ├── ProtoHead.java │ │ │ │ ├── StatusConstants.java │ │ │ │ ├── mapper │ │ │ │ │ ├── BytesUtil.java │ │ │ │ │ ├── DynamicFieldType.java │ │ │ │ │ ├── FdfsColumn.java │ │ │ │ │ ├── FdfsColumnMapException.java │ │ │ │ │ ├── FdfsParamMapper.java │ │ │ │ │ ├── FieldMetaData.java │ │ │ │ │ ├── MetadataMapper.java │ │ │ │ │ └── ObjectMetaData.java │ │ │ │ ├── package-info.java │ │ │ │ ├── storage │ │ │ │ │ ├── DownloadByteArray.java │ │ │ │ │ ├── DownloadCallback.java │ │ │ │ │ ├── DownloadFileStream.java │ │ │ │ │ ├── DownloadFileWriter.java │ │ │ │ │ ├── FdfsInputStream.java │ │ │ │ │ ├── StorageAppendFileCommand.java │ │ │ │ │ ├── StorageDeleteFileCommand.java │ │ │ │ │ ├── StorageDownloadCommand.java │ │ │ │ │ ├── StorageGetMetadataCommand.java │ │ │ │ │ ├── StorageModifyCommand.java │ │ │ │ │ ├── StorageQueryFileInfoCommand.java │ │ │ │ │ ├── StorageSetMetadataCommand.java │ │ │ │ │ ├── StorageTruncateCommand.java │ │ │ │ │ ├── StorageUploadFileCommand.java │ │ │ │ │ ├── StorageUploadSlaveFileCommand.java │ │ │ │ │ ├── enums │ │ │ │ │ │ └── StorageMetadataSetType.java │ │ │ │ │ └── internal │ │ │ │ │ │ ├── StorageAppendFileRequest.java │ │ │ │ │ │ ├── StorageDeleteFileRequest.java │ │ │ │ │ │ ├── StorageDownloadRequest.java │ │ │ │ │ │ ├── StorageDownloadResponse.java │ │ │ │ │ │ ├── StorageGetMetadataRequest.java │ │ │ │ │ │ ├── StorageGetMetadataResponse.java │ │ │ │ │ │ ├── StorageModifyRequest.java │ │ │ │ │ │ ├── StorageQueryFileInfoRequest.java │ │ │ │ │ │ ├── StorageSetMetadataRequest.java │ │ │ │ │ │ ├── StorageTruncateRequest.java │ │ │ │ │ │ ├── StorageUploadFileRequest.java │ │ │ │ │ │ └── StorageUploadSlaveFileRequest.java │ │ │ │ └── tracker │ │ │ │ │ ├── TrackerDeleteStorageCommand.java │ │ │ │ │ ├── TrackerGetFetchStorageCommand.java │ │ │ │ │ ├── TrackerGetStoreStorageCommand.java │ │ │ │ │ ├── TrackerListGroupsCommand.java │ │ │ │ │ ├── TrackerListStoragesCommand.java │ │ │ │ │ └── internal │ │ │ │ │ ├── TrackerDeleteStorageRequest.java │ │ │ │ │ ├── TrackerGetFetchStorageRequest.java │ │ │ │ │ ├── TrackerGetStoreStorageRequest.java │ │ │ │ │ ├── TrackerGetStoreStorageWithGroupRequest.java │ │ │ │ │ ├── TrackerListGroupsRequest.java │ │ │ │ │ ├── TrackerListGroupsResponse.java │ │ │ │ │ ├── TrackerListStoragesRequest.java │ │ │ │ │ └── TrackerListStoragesResponse.java │ │ │ └── upload │ │ │ │ ├── AbstractFastFileBuilder.java │ │ │ │ ├── FastFile.java │ │ │ │ ├── FastImageFile.java │ │ │ │ └── ThumbImage.java │ │ │ ├── exception │ │ │ ├── FdfsConnectException.java │ │ │ ├── FdfsException.java │ │ │ ├── FdfsIOException.java │ │ │ ├── FdfsServerException.java │ │ │ ├── FdfsUnavailableException.java │ │ │ ├── FdfsUnsupportImageTypeException.java │ │ │ ├── FdfsUnsupportStorePathException.java │ │ │ └── FdfsUploadImageException.java │ │ │ └── service │ │ │ ├── AppendFileStorageClient.java │ │ │ ├── DefaultAppendFileStorageClient.java │ │ │ ├── DefaultFastFileStorageClient.java │ │ │ ├── DefaultGenerateStorageClient.java │ │ │ ├── DefaultTrackerClient.java │ │ │ ├── FastFileStorageClient.java │ │ │ ├── GenerateStorageClient.java │ │ │ └── TrackerClient.java │ └── resources │ │ └── META-INF │ │ └── spring.factories └── test │ ├── java │ └── com │ │ └── github │ │ └── tobato │ │ ├── fastdfs │ │ ├── FastdfsTestApplication.java │ │ ├── PerformanceTest.java │ │ ├── TestConstants.java │ │ ├── TestUtils.java │ │ ├── domain │ │ │ ├── RandomTextFile.java │ │ │ ├── StorePathTest.java │ │ │ ├── conn │ │ │ │ ├── ConnectionPoolConfigTest.java │ │ │ │ ├── ConnectionPoolCustomizedConfigTest.java │ │ │ │ ├── ConnectionPoolTest.java │ │ │ │ ├── ConnectionTest.java │ │ │ │ ├── MockServerTestBase.java │ │ │ │ └── TrackerConnectionManagerTest.java │ │ │ ├── fdfs │ │ │ │ ├── CircularListTest.java │ │ │ │ ├── DefaultThumbImageConfigTest.java │ │ │ │ ├── TrackerAddressHolderTest.java │ │ │ │ └── TrackerLocatorTest.java │ │ │ ├── proto │ │ │ │ ├── CommandTestBase.java │ │ │ │ ├── StorageCommandTestBase.java │ │ │ │ ├── mapper │ │ │ │ │ ├── FdfsParamMapperTest.java │ │ │ │ │ └── Foo.java │ │ │ │ ├── storage │ │ │ │ │ ├── AllTests.java │ │ │ │ │ ├── DownloadFileStreamTest.java │ │ │ │ │ ├── StorageAppendFileCommandTest.java │ │ │ │ │ ├── StorageDeleteFileCommandTest.java │ │ │ │ │ ├── StorageDownloadCommandTest.java │ │ │ │ │ ├── StorageModifyCommandTest.java │ │ │ │ │ ├── StorageQueryFileInfoCommandTest.java │ │ │ │ │ ├── StorageSetMetadataCommandTest.java │ │ │ │ │ ├── StorageTruncateCommandTest.java │ │ │ │ │ ├── StorageUploadFileCommandTest.java │ │ │ │ │ ├── StorageUploadSlaveFileCommandTest.java │ │ │ │ │ └── monkey │ │ │ │ │ │ ├── MonkeyDownloadFileWriter.java │ │ │ │ │ │ └── StorageMonkeyDownloadTest.java │ │ │ │ └── tracker │ │ │ │ │ ├── AllTests.java │ │ │ │ │ ├── TrackerDeleteStorageCommandTest.java │ │ │ │ │ ├── TrackerGetFetchStorageCommandTest.java │ │ │ │ │ ├── TrackerGetStoreStorageCommandTest.java │ │ │ │ │ ├── TrackerListGroupsCommandTest.java │ │ │ │ │ ├── TrackerListGroupsRequestTest.java │ │ │ │ │ └── TrackerListStoragesCommandTest.java │ │ │ └── upload │ │ │ │ └── FastFileTest.java │ │ ├── service │ │ │ ├── FastFileStorageClientTest.java │ │ │ ├── FastFileStorageNewFileClientTest.java │ │ │ ├── FastFileStorageNewImageClientTest.java │ │ │ ├── StorageClientAppendFileTest.java │ │ │ ├── StorageClientBasicTest.java │ │ │ ├── StorageClientMetadataTest.java │ │ │ ├── StorageClientTestBase.java │ │ │ ├── ThumbImageTest.java │ │ │ └── TrackerClientTest.java │ │ └── socket │ │ │ ├── FdfsMockHandler.java │ │ │ └── FdfsMockSocketServer.java │ │ └── soket │ │ ├── client │ │ └── ClientDemo.java │ │ └── server │ │ ├── Handler.java │ │ └── SoketServer.java │ └── resources │ ├── application.yml │ ├── images │ ├── cat.jpg │ ├── fly.png │ └── gs.jpg │ └── logback-test.xml └── tools ├── local-release-skipTest.bat ├── local-release.bat ├── pakcage-skipTest.bat ├── release-to-Center-skipTest.bat └── release-to-Center.bat /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | *.sw? 3 | .#* 4 | *# 5 | *~ 6 | /build 7 | /code 8 | .classpath 9 | .project 10 | .settings 11 | .metadata 12 | .factorypath 13 | bin 14 | build 15 | lib/ 16 | target 17 | .springBeans 18 | interpolated*.xml 19 | dependency-reduced-pom.xml 20 | build.log 21 | _site/ 22 | .*.md.html 23 | manifest.yml 24 | MANIFEST.MF 25 | settings.xml 26 | activemq-data 27 | overridedb.* 28 | *.iml 29 | *.ipr 30 | *.iws 31 | .idea 32 | *.jar 33 | .DS_Store 34 | .factorypath 35 | target/ 36 | pom.xml.tag 37 | pom.xml.releaseBackup 38 | pom.xml.versionsBackup 39 | pom.xml.next 40 | release.properties 41 | dependency-reduced-pom.xml 42 | buildNumber.properties 43 | /.apt_generated/ 44 | Test.jpg 45 | Test.png -------------------------------------------------------------------------------- /src/doc/01_Release.md: -------------------------------------------------------------------------------- 1 | 项目发布 2 | ---- 3 | 4 | 记录项目发布的过程,免得每次发布都重新想一遍。 5 | 6 | ## Docker环境准备 7 | 8 | 启动Docker以后需要把FDFS服务打开 9 | 10 | bash 11 | /usr/bin/fdfs_trackerd /etc/fdfs/tracker.conf 12 | /usr/bin/fdfs_storaged /etc/fdfs/storage.conf 13 | 14 | ## 发布流程 15 | 16 | ### 1.修改文档 17 | 18 | 发布前先调整Readme.md 和 Changelog.md 19 | 20 | ### 2.项目发布准备 21 | 22 | mvn release:prepare -P release 23 | 24 | >回滚失败的发布 25 | > 26 | > mvn release:rollback 27 | 28 | ### 3.正式发布提交 29 | 30 | mvn release:perform -P release 31 | 32 | ### 4.中央仓库地址 33 | 34 | 构件发布地址 https://oss.sonatype.org/ 35 | 36 | ### 5.发布问题处理 37 | 38 | * 如果需要跳过单元测试,可以加入参数 -Darguments="-DskipTests" 39 | * 在执行mvn release:perform时默认会生成api文档,如果默写注释不符合规范的话会造成构建失败,可以加参数-DuseReleaseProfile=false取消构建api文档 40 | 41 | mvn release:prepare -Darguments="-DskipTests" 42 | mvn release:perform -DuseReleaseProfile=false 43 | 44 | ## 参考资料 45 | 46 | Maven Release Plugin that is used to automate release management. Releasing a project is done in two steps: prepare and perform. 47 | 48 | * Preparing a release goes through the following release phases: 49 | 50 | * Check that there are no uncommitted changes in the sources 51 | * Check that there are no SNAPSHOT dependencies 52 | * Change the version in the POMs from x-SNAPSHOT to a new version (you will be prompted for the versions to use) 53 | * Transform the SCM information in the POM to include the final destination of the tag 54 | * Run the project tests against the modified POMs to confirm everything is in working order 55 | * Commit the modified POMs 56 | * Tag the code in the SCM with a version name (this will be prompted for) 57 | * Bump the version in the POMs to a new value y-SNAPSHOT (these values will also be prompted for) 58 | * Commit the modified POMs 59 | 60 | * Performing a release runs the following release phases: 61 | 62 | * Checkout from an SCM URL with optional tag 63 | * Run the predefined Maven goals to release the project (by default, deploy site-deploy) 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/FdfsClientConfig.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs; 2 | 3 | import org.springframework.context.annotation.ComponentScan; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.context.annotation.EnableMBeanExport; 6 | import org.springframework.jmx.support.RegistrationPolicy; 7 | 8 | /** 9 | * 导入FdfsClient配置 10 | * 11 | * @author tobato 12 | * 13 | */ 14 | @Configuration 15 | @ComponentScan 16 | @EnableMBeanExport(registration = RegistrationPolicy.IGNORE_EXISTING) 17 | public class FdfsClientConfig { 18 | // auto import 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/FdfsClientConstants.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs; 2 | 3 | /** 4 | * FDFSClient常量配置 5 | * 6 | * @author tobato 7 | */ 8 | public class FdfsClientConstants { 9 | 10 | private FdfsClientConstants() { 11 | // hide for constants 12 | } 13 | 14 | /** 15 | * 支持图片类型 16 | */ 17 | public static final String[] SUPPORT_IMAGE_TYPE = {"JPG", "JPEG", "PNG", "GIF", "BMP", "WBMP"}; 18 | 19 | /** 20 | * 配置文件前缀 21 | */ 22 | public static final String ROOT_CONFIG_PREFIX = "fdfs"; 23 | 24 | /** 25 | * 缩略图配置 26 | */ 27 | public static final String THUMB_IMAGE_CONFIG_PREFIX = "fdfs.thumb-image"; 28 | 29 | /** 30 | * 连接池配置 31 | */ 32 | public static final String POOL_CONFIG_PREFIX = "fdfs.pool"; 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/conn/Connection.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.conn; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.io.OutputStream; 6 | import java.nio.charset.Charset; 7 | 8 | /** 9 | * 表示一个客户端与服务端的连接 10 | *
11 | * 负责连接的管理 12 | * 13 | * @author tobato 14 | */ 15 | public interface Connection { 16 | 17 | /** 18 | * 关闭连接 19 | */ 20 | void close(); 21 | 22 | /** 23 | * 连接是否关闭 24 | * 25 | * @return 26 | */ 27 | boolean isClosed(); 28 | 29 | /** 30 | * 测试连接是否有效 31 | * 32 | * @return 33 | */ 34 | boolean isValid(); 35 | 36 | /** 37 | * 获取输出流 38 | * 39 | * @return 40 | * @throws IOException 41 | */ 42 | public OutputStream getOutputStream() throws IOException; 43 | 44 | /** 45 | * 获取输入流 46 | * 47 | * @return 输入流 48 | * @throws IOException 获取输入流错误 49 | */ 50 | public InputStream getInputStream() throws IOException; 51 | 52 | /** 53 | * 获取字符集 54 | * 55 | * @return 字符集 56 | */ 57 | public Charset getCharset(); 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/conn/FdfsConnectionPool.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.conn; 2 | 3 | import org.apache.commons.pool2.KeyedPooledObjectFactory; 4 | import org.apache.commons.pool2.impl.GenericKeyedObjectPool; 5 | import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.stereotype.Component; 8 | 9 | import java.net.InetSocketAddress; 10 | 11 | /** 12 | * 定义Fdfs连接池对象 13 | *
14 | *
15 | * 定义了对象池要实现的功能,对一个地址进行池化Map Pool 16 | *17 | * 18 | * @author tobato 19 | */ 20 | @Component 21 | public class FdfsConnectionPool extends GenericKeyedObjectPool
11 | *
12 | * 由Nginx服务器承担此角色,通常配置以后就不会再改变 13 | *14 | * 15 | * @author tobato 16 | */ 17 | @Component 18 | @ConfigurationProperties(prefix = FdfsClientConstants.ROOT_CONFIG_PREFIX) 19 | public class FdfsWebServer { 20 | 21 | private String webServerUrl; 22 | 23 | public String getWebServerUrl() { 24 | return webServerUrl; 25 | } 26 | 27 | public void setWebServerUrl(String webServerUrl) { 28 | this.webServerUrl = webServerUrl; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/conn/PooledConnectionFactory.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.conn; 2 | 3 | import com.github.tobato.fastdfs.FdfsClientConstants; 4 | import org.apache.commons.pool2.BaseKeyedPooledObjectFactory; 5 | import org.apache.commons.pool2.PooledObject; 6 | import org.apache.commons.pool2.impl.DefaultPooledObject; 7 | import org.springframework.boot.context.properties.ConfigurationProperties; 8 | import org.springframework.stereotype.Component; 9 | 10 | import java.net.InetSocketAddress; 11 | import java.nio.charset.Charset; 12 | 13 | /** 14 | * pooled FdfsSocket factory 15 | *
16 | *
17 | * 定义了被池化的对象的创建,初始化,激活,钝化以及销毁功能 18 | * 19 | * 20 | * @author tobato 21 | */ 22 | @Component 23 | @ConfigurationProperties(prefix = FdfsClientConstants.ROOT_CONFIG_PREFIX) 24 | public class PooledConnectionFactory extends BaseKeyedPooledObjectFactory{ 25 | 26 | /** 27 | * 读取时间 28 | */ 29 | private int soTimeout; 30 | /** 31 | * 连接超时时间 32 | */ 33 | private int connectTimeout; 34 | /** 35 | * 字符集 36 | */ 37 | private Charset charset; 38 | /** 39 | * 默认字符集 40 | */ 41 | private static final String DEFAULT_CHARSET_NAME = "UTF-8"; 42 | /** 43 | * 设置默认字符集 44 | */ 45 | private String charsetName = DEFAULT_CHARSET_NAME; 46 | 47 | /** 48 | * 创建连接 49 | */ 50 | @Override 51 | public Connection create(InetSocketAddress address) throws Exception { 52 | // 初始化字符集 53 | if (null == charset) { 54 | charset = Charset.forName(charsetName); 55 | } 56 | return new DefaultConnection(address, soTimeout, connectTimeout, charset); 57 | } 58 | 59 | /** 60 | * 将对象池化pooledObject 61 | */ 62 | @Override 63 | public PooledObject wrap(Connection conn) { 64 | return new DefaultPooledObject (conn); 65 | } 66 | 67 | public int getSoTimeout() { 68 | return soTimeout; 69 | } 70 | 71 | public void setSoTimeout(int soTimeout) { 72 | this.soTimeout = soTimeout; 73 | } 74 | 75 | public int getConnectTimeout() { 76 | return connectTimeout; 77 | } 78 | 79 | public void setConnectTimeout(int connectTimeout) { 80 | this.connectTimeout = connectTimeout; 81 | } 82 | 83 | public Charset getCharset() { 84 | return charset; 85 | } 86 | 87 | /** 88 | * 从池中移出 89 | * 90 | * @param key 91 | * @param p 92 | * @throws Exception 93 | */ 94 | @Override 95 | public void destroyObject(InetSocketAddress key, PooledObject p) throws Exception { 96 | p.getObject().close(); 97 | } 98 | 99 | /*** 100 | * 验证池中对象是否可用 101 | * @param key 102 | * @param p 103 | * @return 104 | */ 105 | @Override 106 | public boolean validateObject(InetSocketAddress key, PooledObject p) { 107 | return p.getObject().isValid(); 108 | } 109 | 110 | public void setCharsetName(String charsetName) { 111 | this.charsetName = charsetName; 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/conn/TrackerConnectionManager.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.conn; 2 | 3 | import com.github.tobato.fastdfs.FdfsClientConstants; 4 | import com.github.tobato.fastdfs.domain.fdfs.TrackerLocator; 5 | import com.github.tobato.fastdfs.domain.proto.FdfsCommand; 6 | import com.github.tobato.fastdfs.exception.FdfsConnectException; 7 | import org.springframework.boot.context.properties.ConfigurationProperties; 8 | import org.springframework.stereotype.Component; 9 | 10 | import javax.annotation.PostConstruct; 11 | import javax.validation.constraints.NotNull; 12 | import java.net.InetSocketAddress; 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | 16 | /** 17 | * 管理TrackerClient连接池分配 18 | * 19 | * @author tobato 20 | */ 21 | @Component 22 | @ConfigurationProperties(prefix = FdfsClientConstants.ROOT_CONFIG_PREFIX) 23 | public class TrackerConnectionManager extends FdfsConnectionManager { 24 | 25 | /** 26 | * Tracker定位 27 | */ 28 | private TrackerLocator trackerLocator; 29 | 30 | /** 31 | * tracker服务配置地址列表 32 | */ 33 | @NotNull 34 | private List trackerList = new ArrayList (); 35 | 36 | /** 37 | * 构造函数 38 | */ 39 | public TrackerConnectionManager() { 40 | super(); 41 | } 42 | 43 | /** 44 | * 构造函数 45 | */ 46 | public TrackerConnectionManager(FdfsConnectionPool pool) { 47 | super(pool); 48 | } 49 | 50 | /** 51 | * 初始化方法 52 | */ 53 | @PostConstruct 54 | public void initTracker() { 55 | LOGGER.debug("init trackerLocator {}", trackerList); 56 | trackerLocator = new TrackerLocator(trackerList); 57 | } 58 | 59 | /** 60 | * 获取连接并执行交易 61 | * 62 | * @param command 63 | * @return 64 | */ 65 | public T executeFdfsTrackerCmd(FdfsCommand command) { 66 | Connection conn = null; 67 | InetSocketAddress address = null; 68 | // 获取连接 69 | try { 70 | address = trackerLocator.getTrackerAddress(); 71 | LOGGER.debug("获取到Tracker连接地址{}", address); 72 | conn = getConnection(address); 73 | trackerLocator.setActive(address); 74 | } catch (FdfsConnectException e) { 75 | trackerLocator.setInActive(address); 76 | throw e; 77 | } catch (Exception e) { 78 | LOGGER.error("Unable to borrow buffer from pool", e); 79 | throw new RuntimeException("Unable to borrow buffer from pool", e); 80 | } 81 | // 执行交易 82 | return execute(address, conn, command); 83 | } 84 | 85 | public List getTrackerList() { 86 | return trackerList; 87 | } 88 | 89 | public void setTrackerList(List trackerList) { 90 | this.trackerList = trackerList; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/conn/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 连接管理 3 | * 通信管理 4 | * 业务逻辑不应该关心连接、通信的细节 5 | * 6 | * @author tobato 7 | * 8 | */ 9 | package com.github.tobato.fastdfs.domain.conn; -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/fdfs/CircularList.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.fdfs; 2 | 3 | import java.util.ArrayList; 4 | 5 | /** 6 | * 基于ArrayList的循环链表类
7 | * 第一次调用next()将返回第一个元素,调用previous()将返回最后一个元素 8 | * 9 | * @author yuqih 10 | */ 11 | class CircularListextends ArrayList { 12 | 13 | /** 14 | * serialVersionUID 15 | */ 16 | private static final long serialVersionUID = 1L; 17 | 18 | private int index = -1; 19 | 20 | /** 21 | * 重置,之后第一次调用next()将返回第一个元素,调用previous()将返回最后一个元素 22 | */ 23 | public void reset() { 24 | synchronized (this) { 25 | index = -1; 26 | } 27 | } 28 | 29 | /** 30 | * 下一个元素 31 | * 32 | * @return 33 | */ 34 | public E next() { 35 | check(); 36 | 37 | synchronized (this) { 38 | index++; 39 | if (index >= this.size()) { 40 | index = 0; 41 | } 42 | return this.get(index); 43 | } 44 | 45 | } 46 | 47 | public E current() { 48 | check(); 49 | 50 | synchronized (this) { 51 | if (index < 0) { 52 | index = 0; 53 | } 54 | return this.get(index); 55 | } 56 | } 57 | 58 | /** 59 | * 上一个元素 60 | * 61 | * @return 62 | */ 63 | public E previous() { 64 | check(); 65 | 66 | synchronized (this) { 67 | index--; 68 | if (index < 0) { 69 | index = this.size() - 1; 70 | } 71 | return this.get(index); 72 | } 73 | } 74 | 75 | private void check() { 76 | if (this.size() == 0) { 77 | throw new IndexOutOfBoundsException("空的列表,无法获取元素"); 78 | } 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/fdfs/DefaultThumbImageConfig.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.fdfs; 2 | 3 | import org.apache.commons.lang3.Validate; 4 | import org.springframework.boot.context.properties.ConfigurationProperties; 5 | import org.springframework.stereotype.Component; 6 | 7 | import com.github.tobato.fastdfs.FdfsClientConstants; 8 | 9 | /** 10 | * 缩略图配置参数 11 | * 12 | * @author tobato 13 | */ 14 | @Component 15 | @ConfigurationProperties(prefix = FdfsClientConstants.THUMB_IMAGE_CONFIG_PREFIX) 16 | public class DefaultThumbImageConfig implements ThumbImageConfig { 17 | 18 | private int width; 19 | 20 | private int height; 21 | 22 | private static String cachedPrefixName; 23 | 24 | /** 25 | * 生成前缀如:_150x150 26 | */ 27 | @Override 28 | public String getPrefixName() { 29 | if (cachedPrefixName == null) { 30 | StringBuilder buffer = new StringBuilder(); 31 | buffer.append("_").append(width).append("x").append(height); 32 | cachedPrefixName = new String(buffer); 33 | } 34 | return cachedPrefixName; 35 | } 36 | 37 | /** 38 | * 根据文件名获取缩略图路径 39 | */ 40 | @Override 41 | public String getThumbImagePath(String masterFilename) { 42 | Validate.notBlank(masterFilename, "主文件不能为空"); 43 | StringBuilder buff = new StringBuilder(masterFilename); 44 | int index = buff.lastIndexOf("."); 45 | buff.insert(index, getPrefixName()); 46 | return buff.toString(); 47 | } 48 | 49 | public void setWidth(int width) { 50 | this.width = width; 51 | } 52 | 53 | public void setHeight(int height) { 54 | this.height = height; 55 | } 56 | 57 | public int getWidth() { 58 | return width; 59 | } 60 | 61 | public int getHeight() { 62 | return height; 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/fdfs/FileInfo.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.fdfs; 2 | 3 | import com.github.tobato.fastdfs.domain.proto.OtherConstants; 4 | import com.github.tobato.fastdfs.domain.proto.mapper.FdfsColumn; 5 | 6 | import java.text.SimpleDateFormat; 7 | 8 | /** 9 | * 文件的基础信息 10 | * 11 | * @author yuqih 12 | */ 13 | public class FileInfo { 14 | /** 15 | * 长度 16 | */ 17 | @FdfsColumn(index = 0) 18 | private long fileSize; 19 | /** 20 | * 创建时间 21 | */ 22 | @FdfsColumn(index = 1) 23 | private long createTime; 24 | /** 25 | * 校验码 26 | */ 27 | @FdfsColumn(index = 2) 28 | private int crc32; 29 | /** 30 | * ip地址 31 | */ 32 | @FdfsColumn(index = 3, max = OtherConstants.FDFS_IPADDR_SIZE) 33 | private String sourceIpAddr; 34 | 35 | /** 36 | * 37 | */ 38 | public FileInfo() { 39 | super(); 40 | } 41 | 42 | /** 43 | * @param sourceIpAddr 44 | * @param fileSize 45 | * @param createTime 46 | * @param crc32 47 | */ 48 | public FileInfo(String sourceIpAddr, long fileSize, long createTime, int crc32) { 49 | super(); 50 | this.sourceIpAddr = sourceIpAddr; 51 | this.fileSize = fileSize; 52 | this.createTime = createTime; 53 | this.crc32 = crc32; 54 | } 55 | 56 | /** 57 | * @return the sourceIpAddr 58 | */ 59 | public String getSourceIpAddr() { 60 | return sourceIpAddr; 61 | } 62 | 63 | /** 64 | * @param sourceIpAddr the sourceIpAddr to set 65 | */ 66 | public void setSourceIpAddr(String sourceIpAddr) { 67 | this.sourceIpAddr = sourceIpAddr; 68 | } 69 | 70 | /** 71 | * @return the size 72 | */ 73 | public long getFileSize() { 74 | return fileSize; 75 | } 76 | 77 | /** 78 | * @param fileSize the size to set 79 | */ 80 | public void setFileSize(long fileSize) { 81 | this.fileSize = fileSize; 82 | } 83 | 84 | /** 85 | * @return the createTime 86 | */ 87 | public long getCreateTime() { 88 | return createTime; 89 | } 90 | 91 | /** 92 | * @param createTime the createTime to set 93 | */ 94 | public void setCreateTime(long createTime) { 95 | this.createTime = createTime; 96 | } 97 | 98 | /** 99 | * @return the crc32 100 | */ 101 | public int getCrc32() { 102 | return crc32; 103 | } 104 | 105 | /** 106 | * @param crc32 the crc32 to set 107 | */ 108 | public void setCrc32(int crc32) { 109 | this.crc32 = crc32; 110 | } 111 | 112 | @Override 113 | public String toString() { 114 | SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 115 | return "source_ip_addr = " + this.sourceIpAddr + ", " + "file_size = " + this.fileSize + ", " 116 | + "create_timestamp = " + df.format(this.createTime * 1000) + ", " + "crc32 = " + this.crc32; 117 | } 118 | 119 | } 120 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/fdfs/MetaData.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.fdfs; 2 | 3 | /** 4 | * 文件元数据(MetaData) 5 | * 6 | * @author tobato 7 | */ 8 | public class MetaData { 9 | 10 | private String name; 11 | 12 | private String value; 13 | 14 | public MetaData() { 15 | } 16 | 17 | public MetaData(String name) { 18 | this.name = name; 19 | } 20 | 21 | public MetaData(String name, String value) { 22 | this.name = name; 23 | this.value = value; 24 | } 25 | 26 | public String getName() { 27 | return this.name; 28 | } 29 | 30 | public String getValue() { 31 | return this.value; 32 | } 33 | 34 | public void setName(String name) { 35 | this.name = name; 36 | } 37 | 38 | public void setValue(String value) { 39 | this.value = value; 40 | } 41 | 42 | @Override 43 | public int hashCode() { 44 | final int prime = 31; 45 | int result = 1; 46 | result = prime * result + ((name == null) ? 0 : name.hashCode()); 47 | result = prime * result + ((value == null) ? 0 : value.hashCode()); 48 | return result; 49 | } 50 | 51 | @Override 52 | public boolean equals(Object obj) { 53 | if (this == obj) 54 | return true; 55 | if (obj == null) 56 | return false; 57 | if (getClass() != obj.getClass()) 58 | return false; 59 | MetaData other = (MetaData) obj; 60 | if (name == null) { 61 | if (other.name != null) 62 | return false; 63 | } else if (!name.equals(other.name)) 64 | return false; 65 | if (value == null) { 66 | if (other.value != null) 67 | return false; 68 | } else if (!value.equals(other.value)) 69 | return false; 70 | return true; 71 | } 72 | 73 | @Override 74 | public String toString() { 75 | return "NameValuePair [name=" + name + ", value=" + value + "]"; 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/fdfs/StorageNode.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.fdfs; 2 | 3 | import java.net.InetSocketAddress; 4 | 5 | import com.github.tobato.fastdfs.domain.proto.OtherConstants; 6 | import com.github.tobato.fastdfs.domain.proto.mapper.FdfsColumn; 7 | 8 | /** 9 | * 向tracker请求上传、下载文件或其他文件请求时,tracker返回的文件storage节点的信息 10 | * 11 | * @author yuqih 12 | */ 13 | public class StorageNode { 14 | 15 | @FdfsColumn(index = 0, max = OtherConstants.FDFS_GROUP_NAME_MAX_LEN) 16 | private String groupName; 17 | @FdfsColumn(index = 1, max = OtherConstants.FDFS_IPADDR_SIZE - 1) 18 | private String ip; 19 | @FdfsColumn(index = 2) 20 | private int port; 21 | @FdfsColumn(index = 3) 22 | private byte storeIndex; 23 | 24 | /** 25 | * 存储节点 26 | * 27 | * @param ip 28 | * @param port 29 | * @param storeIndex 30 | */ 31 | public StorageNode(String ip, int port, byte storeIndex) { 32 | super(); 33 | this.ip = ip; 34 | this.port = port; 35 | this.storeIndex = storeIndex; 36 | } 37 | 38 | public StorageNode() { 39 | super(); 40 | } 41 | 42 | /** 43 | * @return the inetSocketAddress 44 | */ 45 | public InetSocketAddress getInetSocketAddress() { 46 | return new InetSocketAddress(ip, port); 47 | } 48 | 49 | /** 50 | * @return the storeIndex 51 | */ 52 | public byte getStoreIndex() { 53 | return storeIndex; 54 | } 55 | 56 | public String getGroupName() { 57 | return groupName; 58 | } 59 | 60 | public String getIp() { 61 | return ip; 62 | } 63 | 64 | public int getPort() { 65 | return port; 66 | } 67 | 68 | public void setGroupName(String groupName) { 69 | this.groupName = groupName; 70 | } 71 | 72 | public void setIp(String ip) { 73 | this.ip = ip; 74 | } 75 | 76 | public void setPort(int port) { 77 | this.port = port; 78 | } 79 | 80 | public void setStoreIndex(byte storeIndex) { 81 | this.storeIndex = storeIndex; 82 | } 83 | 84 | @Override 85 | public String toString() { 86 | return "StorageClient [groupName=" + groupName + ", ip=" + ip + ", port=" + port + ", storeIndex=" + storeIndex 87 | + "]"; 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/fdfs/StorageNodeInfo.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.fdfs; 2 | 3 | import com.github.tobato.fastdfs.domain.proto.OtherConstants; 4 | import com.github.tobato.fastdfs.domain.proto.mapper.FdfsColumn; 5 | 6 | import java.net.InetSocketAddress; 7 | 8 | /** 9 | * 向tracker请求上传、下载文件或其他文件请求时,tracker返回的文件storage节点的信息 10 | * 11 | * @author yuqih 12 | */ 13 | public class StorageNodeInfo { 14 | 15 | @FdfsColumn(index = 0, max = OtherConstants.FDFS_GROUP_NAME_MAX_LEN) 16 | private String groupName; 17 | @FdfsColumn(index = 1, max = OtherConstants.FDFS_IPADDR_SIZE - 1) 18 | private String ip; 19 | @FdfsColumn(index = 2) 20 | private int port; 21 | 22 | /** 23 | * 存储节点 24 | * 25 | * @param ip 26 | * @param port 27 | */ 28 | public StorageNodeInfo(String ip, int port) { 29 | super(); 30 | this.ip = ip; 31 | this.port = port; 32 | } 33 | 34 | public StorageNodeInfo() { 35 | super(); 36 | } 37 | 38 | /** 39 | * @return the inetSocketAddress 40 | */ 41 | public InetSocketAddress getInetSocketAddress() { 42 | return new InetSocketAddress(ip, port); 43 | } 44 | 45 | public String getGroupName() { 46 | return groupName; 47 | } 48 | 49 | public String getIp() { 50 | return ip; 51 | } 52 | 53 | public int getPort() { 54 | return port; 55 | } 56 | 57 | public void setGroupName(String groupName) { 58 | this.groupName = groupName; 59 | } 60 | 61 | public void setIp(String ip) { 62 | this.ip = ip; 63 | } 64 | 65 | public void setPort(int port) { 66 | this.port = port; 67 | } 68 | 69 | @Override 70 | public String toString() { 71 | return "StorageClientInfo [groupName=" + groupName + ", ip=" + ip + ", port=" + port + "]"; 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/fdfs/ThumbImageConfig.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.fdfs; 2 | 3 | /** 4 | * 缩略图生成配置支持 5 | * 6 | * @author tobato 7 | */ 8 | public interface ThumbImageConfig { 9 | 10 | /** 11 | * 获得缩略图宽 12 | * 13 | * @return 14 | */ 15 | int getWidth(); 16 | 17 | /** 18 | * 获得缩略图高 19 | * 20 | * @return 21 | */ 22 | int getHeight(); 23 | 24 | /** 25 | * 获得缩略图前缀 26 | * 27 | * @return 28 | */ 29 | String getPrefixName(); 30 | 31 | /** 32 | * 获得缩略图路径 33 | * 34 | * @param masterFilename 35 | * @return 36 | */ 37 | String getThumbImagePath(String masterFilename); 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/fdfs/TrackerAddressHolder.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.fdfs; 2 | 3 | import java.net.InetSocketAddress; 4 | 5 | /** 6 | * 管理TrackerAddress当前状态 7 | * 8 | * @author tobato 9 | */ 10 | public class TrackerAddressHolder { 11 | /** 12 | * 连接地址 13 | */ 14 | private InetSocketAddress address; 15 | /** 16 | * 当前是否有效 17 | */ 18 | private boolean available; 19 | /** 20 | * 上次无效时间 21 | */ 22 | private long lastUnavailableTime; 23 | 24 | /** 25 | * 构造函数 26 | * 27 | * @param address 28 | */ 29 | public TrackerAddressHolder(InetSocketAddress address) { 30 | super(); 31 | this.address = address; 32 | // 默认Tracker有效 33 | this.available = true; 34 | } 35 | 36 | /** 37 | * 有效 38 | */ 39 | public void setActive() { 40 | this.available = true; 41 | } 42 | 43 | /** 44 | * 无效 45 | */ 46 | public void setInActive() { 47 | this.available = false; 48 | this.lastUnavailableTime = System.currentTimeMillis(); 49 | } 50 | 51 | public boolean isAvailable() { 52 | return available; 53 | } 54 | 55 | public long getLastUnavailableTime() { 56 | return lastUnavailableTime; 57 | } 58 | 59 | /** 60 | * 是否可以尝试连接 61 | * 62 | * @param retryAfterSecend 在n秒后重试 63 | * @return 64 | */ 65 | public boolean canTryToConnect(int retryAfterSecend) { 66 | // 如果是有效连接 67 | if (this.available) { 68 | return true; 69 | // 如果连接无效,并且达到重试时间 70 | } else if ((System.currentTimeMillis() - lastUnavailableTime) > retryAfterSecend * 1000) { 71 | return true; 72 | } 73 | return false; 74 | } 75 | 76 | public InetSocketAddress getAddress() { 77 | return address; 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/fdfs/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * FDFS领域对象 3 | * 4 | * @author tobato 5 | */ 6 | package com.github.tobato.fastdfs.domain.fdfs; -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/proto/CmdConstants.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto; 2 | 3 | /** 4 | * fastdfs协议命令的常量 5 | * 6 | * @author yuqih 7 | */ 8 | public final class CmdConstants { 9 | /** 10 | * 客户端关闭连接命令 11 | */ 12 | public static final byte FDFS_PROTO_CMD_QUIT = 82; 13 | /** 14 | * 连接状态检查命令 15 | */ 16 | public static final byte FDFS_PROTO_CMD_ACTIVE_TEST = 111; 17 | /** 18 | * 服务端正确返回报文状态 19 | */ 20 | public static final byte FDFS_PROTO_CMD_RESP = 100; 21 | 22 | public static final byte TRACKER_PROTO_CMD_SERVER_LIST_GROUP = 91; 23 | public static final byte TRACKER_PROTO_CMD_SERVER_LIST_STORAGE = 92; 24 | public static final byte TRACKER_PROTO_CMD_SERVER_DELETE_STORAGE = 93; 25 | public static final byte TRACKER_PROTO_CMD_SERVICE_QUERY_STORE_WITHOUT_GROUP_ONE = 101; 26 | public static final byte TRACKER_PROTO_CMD_SERVICE_QUERY_FETCH_ONE = 102; 27 | public static final byte TRACKER_PROTO_CMD_SERVICE_QUERY_UPDATE = 103; 28 | public static final byte TRACKER_PROTO_CMD_SERVICE_QUERY_STORE_WITH_GROUP_ONE = 104; 29 | public static final byte TRACKER_PROTO_CMD_SERVICE_QUERY_FETCH_ALL = 105; 30 | public static final byte TRACKER_PROTO_CMD_SERVICE_QUERY_STORE_WITHOUT_GROUP_ALL = 106; 31 | public static final byte TRACKER_PROTO_CMD_SERVICE_QUERY_STORE_WITH_GROUP_ALL = 107; 32 | 33 | /** 34 | * 上传文件 35 | */ 36 | public static final byte STORAGE_PROTO_CMD_UPLOAD_FILE = 11; 37 | public static final byte STORAGE_PROTO_CMD_DELETE_FILE = 12; 38 | public static final byte STORAGE_PROTO_CMD_SET_METADATA = 13; 39 | public static final byte STORAGE_PROTO_CMD_DOWNLOAD_FILE = 14; 40 | public static final byte STORAGE_PROTO_CMD_GET_METADATA = 15; 41 | public static final byte STORAGE_PROTO_CMD_UPLOAD_SLAVE_FILE = 21; 42 | public static final byte STORAGE_PROTO_CMD_QUERY_FILE_INFO = 22; 43 | /** 44 | * 创建一个支持断点续传的文件 45 | */ 46 | public static final byte STORAGE_PROTO_CMD_UPLOAD_APPENDER_FILE = 23; // create 47 | // appender 48 | // file 49 | /** 50 | * 对文件断点续传(附加在原来为上传完全的文件后面) 51 | */ 52 | public static final byte STORAGE_PROTO_CMD_APPEND_FILE = 24; // append file 53 | /** 54 | * 修改支持断点续传的文件 55 | */ 56 | public static final byte STORAGE_PROTO_CMD_MODIFY_FILE = 34; // modify 57 | // appender 58 | // file 59 | /** 60 | * 清空支持断点的文件 61 | */ 62 | public static final byte STORAGE_PROTO_CMD_TRUNCATE_FILE = 36; // truncate 63 | // appender 64 | // file 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/proto/ErrorCodeConstants.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto; 2 | 3 | /** 4 | * fastdfs协议错误码的常量 5 | * 6 | * @author yuqih 7 | */ 8 | public final class ErrorCodeConstants { 9 | 10 | public static final byte SUCCESS = 0; 11 | public static final byte ERR_NO_ENOENT = 2; 12 | public static final byte ERR_NO_EIO = 5; 13 | public static final byte ERR_NO_EBUSY = 16; 14 | public static final byte ERR_NO_EINVAL = 22; 15 | public static final byte ERR_NO_ENOSPC = 28; 16 | public static final byte ERR_NO_CONNREFUSED = 61; 17 | public static final byte ERR_NO_EALREADY = 114; 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/proto/FdfsCommand.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto; 2 | 3 | import com.github.tobato.fastdfs.domain.conn.Connection; 4 | 5 | /** 6 | * Fdfs交易命令抽象 7 | * 8 | * @author tobato 9 | */ 10 | public interface FdfsCommand { 11 | 12 | /** 13 | * 执行交易 14 | */ 15 | public T execute(Connection conn); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/proto/FdfsRequest.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto; 2 | 3 | import java.io.InputStream; 4 | import java.nio.charset.Charset; 5 | 6 | import com.github.tobato.fastdfs.domain.proto.mapper.FdfsParamMapper; 7 | import com.github.tobato.fastdfs.domain.proto.mapper.ObjectMetaData; 8 | 9 | /** 10 | * Fdfs交易请求基类 11 | * 12 | * @author tobato 13 | */ 14 | public abstract class FdfsRequest { 15 | 16 | /** 17 | * 报文头 18 | */ 19 | protected ProtoHead head; 20 | /** 21 | * 发送文件 22 | */ 23 | protected InputStream inputFile; 24 | 25 | /** 26 | * 获取报文头(包内可见) 27 | * 28 | * @return 29 | */ 30 | ProtoHead getHead() { 31 | return head; 32 | } 33 | 34 | /** 35 | * 获取报文头 36 | * 37 | * @param charset 38 | * @return 39 | */ 40 | public byte[] getHeadByte(Charset charset) { 41 | // 设置报文长度 42 | head.setContentLength(getBodyLength(charset)); 43 | // 返回报文byte 44 | return head.toByte(); 45 | } 46 | 47 | /** 48 | * 打包参数 49 | * 50 | * @param charset 51 | * @return 52 | */ 53 | public byte[] encodeParam(Charset charset) { 54 | return FdfsParamMapper.toByte(this, charset); 55 | } 56 | 57 | /** 58 | * 获取参数域长度 59 | * 60 | * @return 61 | */ 62 | protected long getBodyLength(Charset charset) { 63 | ObjectMetaData objectMetaData = FdfsParamMapper.getObjectMap(this.getClass()); 64 | return objectMetaData.getFieldsSendTotalByteSize(this, charset) + getFileSize(); 65 | } 66 | 67 | public InputStream getInputFile() { 68 | return inputFile; 69 | } 70 | 71 | public long getFileSize() { 72 | return 0; 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/proto/FdfsResponse.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto; 2 | 3 | import com.github.tobato.fastdfs.domain.proto.mapper.FdfsParamMapper; 4 | import org.springframework.core.GenericTypeResolver; 5 | 6 | import java.io.IOException; 7 | import java.io.InputStream; 8 | import java.nio.charset.Charset; 9 | 10 | /** 11 | * Fdfs交易应答基类 12 | * 13 | * @author tobato 14 | */ 15 | public abstract class FdfsResponse { 16 | /** 17 | * 报文头 18 | */ 19 | protected ProtoHead head; 20 | 21 | /** 22 | * 返回值类型 23 | */ 24 | protected final Class genericType; 25 | 26 | /** 27 | * 获取报文长度 28 | */ 29 | protected long getContentLength() { 30 | return head.getContentLength(); 31 | } 32 | 33 | /** 34 | * 构造函数 35 | */ 36 | @SuppressWarnings("unchecked") 37 | public FdfsResponse() { 38 | super(); 39 | this.genericType = (Class ) GenericTypeResolver.resolveTypeArgument(getClass(), FdfsResponse.class); 40 | // Type theclass = this.getClass().getGenericSuperclass(); 41 | // this.genericType = ((ParameterizedType) 42 | // theclass).getActualTypeArguments()[0]; 43 | } 44 | 45 | /** 46 | * 解析反馈结果,head已经被解析过 47 | * 48 | * @param head 49 | * @param in 50 | * @param charset 51 | * @return 52 | * @throws IOException 53 | */ 54 | public T decode(ProtoHead head, InputStream in, Charset charset) throws IOException { 55 | this.head = head; 56 | return decodeContent(in, charset); 57 | } 58 | 59 | /** 60 | * 解析反馈内容 61 | * 62 | * @param in 63 | * @param charset 64 | * @return 65 | * @throws IOException 66 | */ 67 | public T decodeContent(InputStream in, Charset charset) throws IOException { 68 | // 如果有内容 69 | if (getContentLength() > 0) { 70 | byte[] bytes = new byte[(int) getContentLength()]; 71 | int contentSize = in.read(bytes); 72 | // 获取数据 73 | if (contentSize != getContentLength()) { 74 | throw new IOException("读取到的数据长度与协议长度不符"); 75 | } 76 | return FdfsParamMapper.map(bytes, genericType, charset); 77 | } 78 | return null; 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/proto/OtherConstants.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto; 2 | 3 | /** 4 | * fastdfs协议暂时未分类的常量 5 | * 6 | * @author yuqih 7 | */ 8 | public final class OtherConstants { 9 | /** 10 | * for overwrite all old metadata 11 | */ 12 | public static final byte STORAGE_SET_METADATA_FLAG_OVERWRITE = 'O'; 13 | 14 | /** 15 | * for replace, insert when the meta item not exist, otherwise update it 16 | */ 17 | public static final byte STORAGE_SET_METADATA_FLAG_MERGE = 'M'; 18 | 19 | public static final int FDFS_PROTO_PKG_LEN_SIZE = 8; 20 | public static final int FDFS_PROTO_CMD_SIZE = 1; 21 | public static final int FDFS_PROTO_CONNECTION_LEN = 4; 22 | public static final int FDFS_GROUP_NAME_MAX_LEN = 16; 23 | public static final int FDFS_IPADDR_SIZE = 16; 24 | public static final int FDFS_DOMAIN_NAME_MAX_SIZE = 128; 25 | public static final int FDFS_VERSION_SIZE = 6; 26 | public static final int FDFS_STORAGE_ID_MAX_SIZE = 16; 27 | 28 | public static final String FDFS_RECORD_SEPERATOR = "\u0001"; 29 | public static final String FDFS_FIELD_SEPERATOR = "\u0002"; 30 | 31 | public static final int TRACKER_QUERY_STORAGE_FETCH_BODY_LEN = FDFS_GROUP_NAME_MAX_LEN + FDFS_IPADDR_SIZE - 1 32 | + FDFS_PROTO_PKG_LEN_SIZE; 33 | public static final int TRACKER_QUERY_STORAGE_STORE_BODY_LEN = FDFS_GROUP_NAME_MAX_LEN + FDFS_IPADDR_SIZE 34 | + FDFS_PROTO_PKG_LEN_SIZE; 35 | 36 | /** 37 | * 报文头中命令位置 38 | */ 39 | public static final int PROTO_HEADER_CMD_INDEX = FDFS_PROTO_PKG_LEN_SIZE; 40 | /** 41 | * 报文头中状态码位置 42 | */ 43 | public static final int PROTO_HEADER_STATUS_INDEX = FDFS_PROTO_PKG_LEN_SIZE + 1; 44 | 45 | public static final byte FDFS_FILE_EXT_NAME_MAX_LEN = 6; 46 | public static final byte FDFS_FILE_PREFIX_MAX_LEN = 16; 47 | public static final byte FDFS_FILE_PATH_LEN = 10; 48 | public static final byte FDFS_FILENAME_BASE64_LENGTH = 27; 49 | public static final byte FDFS_TRUNK_FILE_INFO_LEN = 16; 50 | 51 | public static final long INFINITE_FILE_SIZE = 256 * 1024L * 1024 * 1024 * 1024 * 1024L; 52 | public static final long APPENDER_FILE_SIZE = INFINITE_FILE_SIZE; 53 | public static final long TRUNK_FILE_MARK_SIZE = 512 * 1024L * 1024 * 1024 * 1024 * 1024L; 54 | public static final long NORMAL_LOGIC_FILENAME_LENGTH = FDFS_FILE_PATH_LEN + FDFS_FILENAME_BASE64_LENGTH 55 | + FDFS_FILE_EXT_NAME_MAX_LEN + 1; 56 | public static final long TRUNK_LOGIC_FILENAME_LENGTH = NORMAL_LOGIC_FILENAME_LENGTH + FDFS_TRUNK_FILE_INFO_LEN; 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/proto/StatusConstants.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto; 2 | 3 | /** 4 | * fastdfs协议服务端状态的常量 5 | * 6 | * @author yuqih 7 | */ 8 | public final class StatusConstants { 9 | public static final byte FDFS_STORAGE_STATUS_INIT = 0; 10 | public static final byte FDFS_STORAGE_STATUS_WAIT_SYNC = 1; 11 | public static final byte FDFS_STORAGE_STATUS_SYNCING = 2; 12 | public static final byte FDFS_STORAGE_STATUS_IP_CHANGED = 3; 13 | public static final byte FDFS_STORAGE_STATUS_DELETED = 4; 14 | public static final byte FDFS_STORAGE_STATUS_OFFLINE = 5; 15 | public static final byte FDFS_STORAGE_STATUS_ONLINE = 6; 16 | public static final byte FDFS_STORAGE_STATUS_ACTIVE = 7; 17 | public static final byte FDFS_STORAGE_STATUS_NONE = 99; 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/proto/mapper/DynamicFieldType.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.mapper; 2 | 3 | /** 4 | * 动态属性类型 5 | * 6 | *
7 | * 可以为空的属性-不发送该报文 8 | * 剩余的所有byte-将该字段全部写入到最后的byte当中 9 | *10 | * 11 | * @author tobato 12 | */ 13 | public enum DynamicFieldType { 14 | /** 15 | * 非动态属性 16 | */ 17 | NULL, 18 | /** 19 | * 剩余的所有Byte 20 | */ 21 | allRestByte, 22 | /** 23 | * 可空的属性 24 | */ 25 | nullable, 26 | /** 27 | * 文件元数据Set 28 | */ 29 | metadata 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/proto/mapper/FdfsColumn.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.mapper; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | /** 10 | * 传输参数定义标签 11 | * 12 | * @author tobato 13 | */ 14 | @Documented 15 | @Target(ElementType.FIELD) 16 | @Retention(RetentionPolicy.RUNTIME) 17 | public @interface FdfsColumn { 18 | /** 19 | * 映射顺序(从0开始) 20 | */ 21 | int index() default 0; 22 | 23 | /** 24 | * String最大值 25 | */ 26 | int max() default 0; 27 | 28 | /** 29 | * 动态属性 30 | */ 31 | DynamicFieldType dynamicField() default DynamicFieldType.NULL; 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/proto/mapper/FdfsColumnMapException.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.mapper; 2 | 3 | /** 4 | * 映射例外 5 | * 6 | * @author tobato 7 | * 8 | */ 9 | public class FdfsColumnMapException extends RuntimeException { 10 | 11 | /** 12 | * serialVersionUID 13 | */ 14 | private static final long serialVersionUID = 1336200127024129847L; 15 | 16 | protected FdfsColumnMapException() { 17 | } 18 | 19 | protected FdfsColumnMapException(String message, Throwable cause, boolean enableSuppression, 20 | boolean writableStackTrace) { 21 | super(message, cause, enableSuppression, writableStackTrace); 22 | } 23 | 24 | protected FdfsColumnMapException(String message, Throwable cause) { 25 | super(message, cause); 26 | } 27 | 28 | protected FdfsColumnMapException(String message) { 29 | super(message); 30 | } 31 | 32 | protected FdfsColumnMapException(Throwable cause) { 33 | super(cause); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/proto/mapper/MetadataMapper.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.mapper; 2 | 3 | import com.github.tobato.fastdfs.domain.fdfs.MetaData; 4 | import com.github.tobato.fastdfs.domain.proto.OtherConstants; 5 | 6 | import java.nio.charset.Charset; 7 | import java.util.HashSet; 8 | import java.util.Set; 9 | 10 | /** 11 | * 文件标签(元数据)映射对象 12 | * 13 | * @author tobato 14 | */ 15 | public class MetadataMapper { 16 | 17 | private MetadataMapper() { 18 | // hide for utils 19 | } 20 | 21 | /** 22 | * 将元数据映射为byte 23 | * 24 | * @param metadataSet 25 | * @param charset 26 | * @return 27 | */ 28 | public static byte[] toByte(SetmetadataSet, Charset charset) { 29 | if (null == metadataSet || metadataSet.isEmpty()) { 30 | return new byte[0]; 31 | } 32 | StringBuilder sb = new StringBuilder(32 * metadataSet.size()); 33 | for (MetaData md : metadataSet) { 34 | sb.append(md.getName()).append(OtherConstants.FDFS_FIELD_SEPERATOR).append(md.getValue()); 35 | sb.append(OtherConstants.FDFS_RECORD_SEPERATOR); 36 | } 37 | // 去除最后一个分隔符 38 | sb.delete(sb.length() - OtherConstants.FDFS_RECORD_SEPERATOR.length(), sb.length()); 39 | return sb.toString().getBytes(charset); 40 | } 41 | 42 | /** 43 | * 将byte映射为对象 44 | * 45 | * @param content 46 | * @param charset 47 | * @return 48 | */ 49 | public static Set fromByte(byte[] content, Charset charset) { 50 | Set mdSet = new HashSet (); 51 | if (null == content) { 52 | return mdSet; 53 | } 54 | String meta_buff = new String(content, charset); 55 | String[] rows = meta_buff.split(OtherConstants.FDFS_RECORD_SEPERATOR); 56 | 57 | for (int i = 0; i < rows.length; i++) { 58 | String[] cols = rows[i].split(OtherConstants.FDFS_FIELD_SEPERATOR, 2); 59 | MetaData md = new MetaData(cols[0]); 60 | if (cols.length == 2) { 61 | md.setValue(cols[1]); 62 | } 63 | mdSet.add(md); 64 | } 65 | 66 | return mdSet; 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/proto/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 交易报文 3 | * 4 | * 封装与服务端交易报文命令 5 | *6 | * 7 | * @author tobato 8 | */ 9 | package com.github.tobato.fastdfs.domain.proto; -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/proto/storage/DownloadByteArray.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.storage; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | 6 | import org.apache.commons.io.IOUtils; 7 | 8 | /** 9 | * 下载为byte流 10 | * 11 | * @author tobato 12 | */ 13 | public class DownloadByteArray implements DownloadCallback{ 14 | 15 | @Override 16 | public byte[] recv(InputStream ins) throws IOException { 17 | return IOUtils.toByteArray(ins); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/proto/storage/DownloadCallback.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.storage; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | 6 | /** 7 | * 文件下载回调接口 8 | * 9 | * @param 10 | * @author tobato 11 | */ 12 | public interface DownloadCallback { 13 | 14 | /** 15 | * 注意不能直接返回入参的InputStream,因为此方法返回后将关闭原输入流 16 | * 17 | * 不能关闭ins? TODO验证是否可以关闭 18 | * 19 | * @param ins 20 | * @return 21 | * @throws IOException 22 | */ 23 | T recv(InputStream ins) throws IOException; 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/proto/storage/DownloadFileStream.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.storage; 2 | 3 | import org.apache.commons.io.IOUtils; 4 | 5 | import java.io.BufferedInputStream; 6 | import java.io.IOException; 7 | import java.io.InputStream; 8 | import java.io.OutputStream; 9 | 10 | /** 11 | * Web环境下文件下载回调方法,默认按4K循环读取,防止下载时内存溢出 12 | *
13 | * 14 | * refactor: 15 | * 将HttpServletResponse调整为OutputStream对象, 16 | * 注意:使用时候在外层做response.getOutputStream(),使用完毕后,在外层做 os.close() 17 | * 如: 18 | * os = response.getOutputStream(); 19 | * DownloadFileStream stream = new DownloadFileStream(os); 20 | * ... 21 | * os.close(); 22 | * 23 | *24 | * 25 | * @author xulb 26 | */ 27 | public class DownloadFileStream implements DownloadCallback{ 28 | 29 | /** 30 | * 默认缓存长度 31 | */ 32 | private static final int DEFAULT_BUFFER_SIZE = 4096; 33 | 34 | /** 35 | * 输出流 36 | * HttpServletResponse对象response.getOutputStream() 37 | */ 38 | private OutputStream outputStream; 39 | 40 | /** 41 | * 默认缓存长度 42 | */ 43 | private int bufferLength = DEFAULT_BUFFER_SIZE; 44 | 45 | 46 | /** 47 | * 从HttpServletResponse对象response.getOutputStream()构造 48 | * 49 | * @param responseOutputStream 输出流 50 | */ 51 | public DownloadFileStream(OutputStream responseOutputStream) { 52 | this.outputStream = responseOutputStream; 53 | } 54 | 55 | /** 56 | * 从HttpServletResponse对象response.getOutputStream()构造 57 | * 58 | * @param responseOutputStream 输出流 59 | * @param bufferLength 缓存长度 60 | */ 61 | public DownloadFileStream(OutputStream responseOutputStream, int bufferLength) { 62 | this.outputStream = responseOutputStream; 63 | this.bufferLength = bufferLength; 64 | } 65 | 66 | /** 67 | * 文件接收处理 68 | * 69 | * @return 70 | */ 71 | @Override 72 | public BufferedInputStream recv(InputStream ins) throws IOException { 73 | BufferedInputStream bufferedInputStream = new BufferedInputStream(ins); 74 | // 实现文件下载 75 | byte[] buffer = new byte[bufferLength]; 76 | try { 77 | IOUtils.copyLarge(ins, outputStream, buffer); 78 | } catch (IOException e) { 79 | throw new IOException("文件下载失败!", e); 80 | } finally { 81 | IOUtils.closeQuietly(bufferedInputStream); 82 | } 83 | return null; 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/proto/storage/DownloadFileWriter.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.storage; 2 | 3 | import com.github.tobato.fastdfs.exception.FdfsIOException; 4 | import org.apache.commons.io.IOUtils; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | import java.io.BufferedInputStream; 9 | import java.io.FileOutputStream; 10 | import java.io.IOException; 11 | import java.io.InputStream; 12 | 13 | /** 14 | * 文件下载回调方法 15 | * 16 | * @author tobato 17 | */ 18 | public class DownloadFileWriter implements DownloadCallback { 19 | 20 | /** 21 | * 日志 22 | */ 23 | protected static Logger LOGGER = LoggerFactory.getLogger(DownloadFileWriter.class); 24 | 25 | /** 26 | * 文件名称 27 | */ 28 | private String fileName; 29 | 30 | public DownloadFileWriter(String fileName) { 31 | this.fileName = fileName; 32 | } 33 | 34 | /** 35 | * 文件接收处理 36 | */ 37 | @Override 38 | public String recv(InputStream ins) throws IOException { 39 | FileOutputStream out = null; 40 | InputStream in = null; 41 | try { 42 | out = new FileOutputStream(fileName); 43 | in = new BufferedInputStream(ins); 44 | // 通过ioutil 对接输入输出流,实现文件下载 45 | IOUtils.copy(in, out); 46 | out.flush(); 47 | } catch (IOException e) { 48 | LOGGER.error("文件下载接收处理失败", e.getCause()); 49 | throw new FdfsIOException("文件下载接收处理失败"); 50 | } finally { 51 | // 关闭流 52 | IOUtils.closeQuietly(in); 53 | IOUtils.closeQuietly(out); 54 | } 55 | return fileName; 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/proto/storage/FdfsInputStream.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.storage; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | 6 | /** 7 | * FdfsInputStream包装类 8 | * 9 | * @author tobato 10 | */ 11 | public class FdfsInputStream extends InputStream { 12 | 13 | private final InputStream ins; 14 | private final long size; 15 | private long remainByteSize; 16 | 17 | public FdfsInputStream(InputStream ins, long size) { 18 | this.ins = ins; 19 | this.size = size; 20 | remainByteSize = size; 21 | } 22 | 23 | @Override 24 | public int read() throws IOException { 25 | return ins.read(); 26 | } 27 | 28 | @Override 29 | public int read(byte b[], int off, int len) throws IOException { 30 | if (remainByteSize == 0) { 31 | return -1; 32 | } 33 | int byteSize = ins.read(b, off, len); 34 | if (remainByteSize < byteSize) { 35 | throw new IOException("协议长度" + size + "与实际长度不符"); 36 | } 37 | 38 | remainByteSize -= byteSize; 39 | return byteSize; 40 | } 41 | 42 | @Override 43 | public void close() throws IOException { 44 | // do nothing 45 | } 46 | 47 | /** 48 | * 是否已完成读取 49 | * 50 | * @return 51 | */ 52 | public boolean isReadCompleted() { 53 | return remainByteSize == 0; 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/proto/storage/StorageAppendFileCommand.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.storage; 2 | 3 | import com.github.tobato.fastdfs.domain.proto.AbstractFdfsCommand; 4 | import com.github.tobato.fastdfs.domain.proto.FdfsResponse; 5 | import com.github.tobato.fastdfs.domain.proto.storage.internal.StorageAppendFileRequest; 6 | 7 | import java.io.InputStream; 8 | 9 | /** 10 | * 添加文件命令 11 | * 12 | * @author tobato 13 | */ 14 | public class StorageAppendFileCommand extends AbstractFdfsCommand { 15 | 16 | public StorageAppendFileCommand(InputStream inputStream, long fileSize, String path) { 17 | this.request = new StorageAppendFileRequest(inputStream, fileSize, path); 18 | // 输出响应 19 | this.response = new FdfsResponse () { 20 | // default response 21 | }; 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/proto/storage/StorageDeleteFileCommand.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.storage; 2 | 3 | import com.github.tobato.fastdfs.domain.proto.AbstractFdfsCommand; 4 | import com.github.tobato.fastdfs.domain.proto.FdfsResponse; 5 | import com.github.tobato.fastdfs.domain.proto.storage.internal.StorageDeleteFileRequest; 6 | 7 | /** 8 | * 文件删除命令 9 | * 10 | * @author tobato 11 | */ 12 | public class StorageDeleteFileCommand extends AbstractFdfsCommand { 13 | 14 | /** 15 | * 文件删除命令 16 | * 17 | * @param storeIndex 存储节点 18 | * @param inputStream 输入流 19 | * @param fileExtName 文件扩展名 20 | * @param size 文件大小 21 | * @param isAppenderFile 是否添加模式 22 | */ 23 | public StorageDeleteFileCommand(String groupName, String path) { 24 | super(); 25 | this.request = new StorageDeleteFileRequest(groupName, path); 26 | // 输出响应 27 | this.response = new FdfsResponse () { 28 | // default response 29 | }; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/proto/storage/StorageDownloadCommand.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.storage; 2 | 3 | import com.github.tobato.fastdfs.domain.proto.AbstractFdfsCommand; 4 | import com.github.tobato.fastdfs.domain.proto.storage.internal.StorageDownloadRequest; 5 | import com.github.tobato.fastdfs.domain.proto.storage.internal.StorageDownloadResponse; 6 | 7 | /** 8 | * 文件下载命令 9 | * 10 | * @param 11 | * @author tobato 12 | */ 13 | public class StorageDownloadCommand extends AbstractFdfsCommand { 14 | 15 | /** 16 | * 下载部分文件 17 | * 18 | * @param groupName 19 | * @param path 20 | * @param fileOffset 21 | * @param downloadBytes 22 | */ 23 | public StorageDownloadCommand(String groupName, String path, long fileOffset, long downloadBytes, 24 | DownloadCallback callback) { 25 | super(); 26 | this.request = new StorageDownloadRequest(groupName, path, fileOffset, downloadBytes); 27 | // 输出响应 28 | this.response = new StorageDownloadResponse (callback); 29 | } 30 | 31 | /** 32 | * 下载文件 33 | * 34 | * @param groupName 35 | * @param path 36 | */ 37 | public StorageDownloadCommand(String groupName, String path, DownloadCallback callback) { 38 | super(); 39 | this.request = new StorageDownloadRequest(groupName, path, 0, 0); 40 | // 输出响应 41 | this.response = new StorageDownloadResponse (callback); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/proto/storage/StorageGetMetadataCommand.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.storage; 2 | 3 | import com.github.tobato.fastdfs.domain.fdfs.MetaData; 4 | import com.github.tobato.fastdfs.domain.proto.AbstractFdfsCommand; 5 | import com.github.tobato.fastdfs.domain.proto.storage.internal.StorageGetMetadataRequest; 6 | import com.github.tobato.fastdfs.domain.proto.storage.internal.StorageGetMetadataResponse; 7 | 8 | import java.util.Set; 9 | 10 | /** 11 | * 设置文件标签 12 | * 13 | * @author tobato 14 | */ 15 | public class StorageGetMetadataCommand extends AbstractFdfsCommand > { 16 | 17 | 18 | /** 19 | * 设置文件标签(元数据) 20 | * 21 | * @param groupName 22 | * @param path 23 | */ 24 | public StorageGetMetadataCommand(String groupName, String path) { 25 | this.request = new StorageGetMetadataRequest(groupName, path); 26 | // 输出响应 27 | this.response = new StorageGetMetadataResponse(); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/proto/storage/StorageModifyCommand.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.storage; 2 | 3 | import java.io.InputStream; 4 | 5 | import com.github.tobato.fastdfs.domain.proto.AbstractFdfsCommand; 6 | import com.github.tobato.fastdfs.domain.proto.FdfsResponse; 7 | import com.github.tobato.fastdfs.domain.proto.storage.internal.StorageModifyRequest; 8 | 9 | /** 10 | * 文件修改命令 11 | * 12 | * @author tobato 13 | */ 14 | public class StorageModifyCommand extends AbstractFdfsCommand { 15 | 16 | /** 17 | * 文件修改命令 18 | * 19 | * @param path 20 | * @param inputStream 21 | * @param fileSize 22 | * @param fileOffset 23 | */ 24 | public StorageModifyCommand(String path, InputStream inputStream, long fileSize, long fileOffset) { 25 | super(); 26 | this.request = new StorageModifyRequest(inputStream, fileSize, path, fileOffset); 27 | // 输出响应 28 | this.response = new FdfsResponse () { 29 | // default response 30 | }; 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/proto/storage/StorageQueryFileInfoCommand.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.storage; 2 | 3 | import com.github.tobato.fastdfs.domain.fdfs.FileInfo; 4 | import com.github.tobato.fastdfs.domain.proto.AbstractFdfsCommand; 5 | import com.github.tobato.fastdfs.domain.proto.FdfsResponse; 6 | import com.github.tobato.fastdfs.domain.proto.storage.internal.StorageQueryFileInfoRequest; 7 | 8 | /** 9 | * 文件查询命令 10 | * 11 | * @author tobato 12 | */ 13 | public class StorageQueryFileInfoCommand extends AbstractFdfsCommand { 14 | 15 | /** 16 | * 文件查询命令 17 | * 18 | * @param groupName 19 | * @param path 20 | */ 21 | public StorageQueryFileInfoCommand(String groupName, String path) { 22 | super(); 23 | this.request = new StorageQueryFileInfoRequest(groupName, path); 24 | // 输出响应 25 | this.response = new FdfsResponse () { 26 | // default response 27 | }; 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/proto/storage/StorageSetMetadataCommand.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.storage; 2 | 3 | import com.github.tobato.fastdfs.domain.fdfs.MetaData; 4 | import com.github.tobato.fastdfs.domain.proto.AbstractFdfsCommand; 5 | import com.github.tobato.fastdfs.domain.proto.FdfsResponse; 6 | import com.github.tobato.fastdfs.domain.proto.storage.enums.StorageMetadataSetType; 7 | import com.github.tobato.fastdfs.domain.proto.storage.internal.StorageSetMetadataRequest; 8 | 9 | import java.util.Set; 10 | 11 | /** 12 | * 设置文件标签 13 | * 14 | * @author tobato 15 | */ 16 | public class StorageSetMetadataCommand extends AbstractFdfsCommand { 17 | 18 | /** 19 | * 设置文件标签(元数据) 20 | * 21 | * @param groupName 22 | * @param path 23 | * @param metaDataSet 24 | * @param type 25 | */ 26 | public StorageSetMetadataCommand(String groupName, String path, Set metaDataSet, 27 | StorageMetadataSetType type) { 28 | this.request = new StorageSetMetadataRequest(groupName, path, metaDataSet, type); 29 | // 输出响应 30 | this.response = new FdfsResponse () { 31 | // default response 32 | }; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/proto/storage/StorageTruncateCommand.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.storage; 2 | 3 | import com.github.tobato.fastdfs.domain.proto.AbstractFdfsCommand; 4 | import com.github.tobato.fastdfs.domain.proto.FdfsResponse; 5 | import com.github.tobato.fastdfs.domain.proto.storage.internal.StorageTruncateRequest; 6 | 7 | /** 8 | * 文件Truncate命令 9 | * 10 | * @author tobato 11 | */ 12 | public class StorageTruncateCommand extends AbstractFdfsCommand { 13 | 14 | 15 | /** 16 | * StorageTruncateCommand 17 | * 18 | * @param path 19 | * @param fileSize 20 | */ 21 | public StorageTruncateCommand(String path, long fileSize) { 22 | super(); 23 | this.request = new StorageTruncateRequest(path, fileSize); 24 | // 输出响应 25 | this.response = new FdfsResponse () { 26 | // default response 27 | }; 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/proto/storage/StorageUploadFileCommand.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.storage; 2 | 3 | import com.github.tobato.fastdfs.domain.fdfs.StorePath; 4 | import com.github.tobato.fastdfs.domain.proto.AbstractFdfsCommand; 5 | import com.github.tobato.fastdfs.domain.proto.FdfsResponse; 6 | import com.github.tobato.fastdfs.domain.proto.storage.internal.StorageUploadFileRequest; 7 | 8 | import java.io.InputStream; 9 | 10 | /** 11 | * 文件上传命令 12 | * 13 | * @author tobato 14 | */ 15 | public class StorageUploadFileCommand extends AbstractFdfsCommand { 16 | 17 | 18 | /** 19 | * 文件上传命令 20 | * 21 | * @param storeIndex 22 | * @param inputStream 23 | * @param fileExtName 24 | * @param fileSize 25 | * @param isAppenderFile 26 | */ 27 | public StorageUploadFileCommand(byte storeIndex, InputStream inputStream, String fileExtName, long fileSize, 28 | boolean isAppenderFile) { 29 | super(); 30 | this.request = new StorageUploadFileRequest(storeIndex, inputStream, fileExtName, fileSize, isAppenderFile); 31 | // 输出响应 32 | this.response = new FdfsResponse () { 33 | // default response 34 | }; 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/proto/storage/StorageUploadSlaveFileCommand.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.storage; 2 | 3 | import com.github.tobato.fastdfs.domain.fdfs.StorePath; 4 | import com.github.tobato.fastdfs.domain.proto.AbstractFdfsCommand; 5 | import com.github.tobato.fastdfs.domain.proto.FdfsResponse; 6 | import com.github.tobato.fastdfs.domain.proto.storage.internal.StorageUploadSlaveFileRequest; 7 | 8 | import java.io.InputStream; 9 | 10 | /** 11 | * 从文件上传命令 12 | * 13 | *
14 | * 使用背景 15 | * 使用FastDFS存储一个图片的多个分辨率的备份时,希望只记录源图的FID, 16 | * 并能将其它分辨率的图片与源图关联。可以使用从文件方法 17 | * 名词注解: 18 | * 主从文件是指文件ID有关联的文件,一个主文件可以对应多个从文件 19 | * 主文件ID = 主文件名 + 主文件扩展名 20 | * 从文件ID = 主文件名 + 从文件后缀名 + 从文件扩展名 21 | * 以缩略图场景为例:主文件为原始图片,从文件为该图片的一张或多张缩略图 22 | * 流程说明: 23 | * 1.先上传主文件(即:原文件),得到主文件FID 24 | * 2.然后上传从文件(即:缩略图),指定主文件FID和从文件后缀名,上传后得到从文件FID。 25 | * 26 | * 注意: 27 | * FastDFS中的主从文件只是在文件ID上有联系。FastDFS server端没有记录主从文件对应关系, 28 | * 因此删除主文件,FastDFS不会自动删除从文件。删除主文件后,从文件的级联删除,需要由应用端来实现。 29 | * 30 | *31 | * 32 | * @author tobato 33 | */ 34 | public class StorageUploadSlaveFileCommand extends AbstractFdfsCommand{ 35 | 36 | /** 37 | * 文件上传命令 38 | * 39 | * @param inputStream 输入流 40 | * @param fileSize 文件大小 41 | * @param masterFilename 主文件名称 42 | * @param prefixName 从文件前缀 43 | * @param fileExtName 文件扩展名 44 | */ 45 | public StorageUploadSlaveFileCommand(InputStream inputStream, long fileSize, String masterFilename, 46 | String prefixName, String fileExtName) { 47 | super(); 48 | this.request = new StorageUploadSlaveFileRequest(inputStream, fileSize, masterFilename, prefixName, 49 | fileExtName); 50 | // 输出响应 51 | this.response = new FdfsResponse () { 52 | // default response 53 | }; 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/proto/storage/enums/StorageMetadataSetType.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.storage.enums; 2 | 3 | /** 4 | * 元数据设置方式 5 | * 6 | * @author tobato 7 | */ 8 | public enum StorageMetadataSetType { 9 | 10 | /** 11 | * 覆盖 12 | */ 13 | STORAGE_SET_METADATA_FLAG_OVERWRITE((byte) 'O'), 14 | /** 15 | * 没有的条目增加,有则条目覆盖 16 | */ 17 | STORAGE_SET_METADATA_FLAG_MERGE((byte) 'M'); 18 | 19 | private byte type; 20 | 21 | private StorageMetadataSetType(byte type) { 22 | this.type = type; 23 | } 24 | 25 | public byte getType() { 26 | return type; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/proto/storage/internal/StorageAppendFileRequest.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.storage.internal; 2 | 3 | import java.io.InputStream; 4 | import java.nio.charset.Charset; 5 | 6 | import com.github.tobato.fastdfs.domain.proto.CmdConstants; 7 | import com.github.tobato.fastdfs.domain.proto.FdfsRequest; 8 | import com.github.tobato.fastdfs.domain.proto.ProtoHead; 9 | import com.github.tobato.fastdfs.domain.proto.mapper.DynamicFieldType; 10 | import com.github.tobato.fastdfs.domain.proto.mapper.FdfsColumn; 11 | 12 | /** 13 | * 文件上传命令 14 | * 15 | * @author tobato 16 | */ 17 | public class StorageAppendFileRequest extends FdfsRequest { 18 | 19 | /** 20 | * 文件路径长度 21 | */ 22 | @FdfsColumn(index = 0) 23 | private long pathSize; 24 | /** 25 | * 发送文件长度 26 | */ 27 | @FdfsColumn(index = 1) 28 | private long fileSize; 29 | /** 30 | * 文件路径 31 | */ 32 | @FdfsColumn(index = 2, dynamicField = DynamicFieldType.allRestByte) 33 | private String path; 34 | 35 | /** 36 | * 构造函数 37 | * 38 | * @param inputStream 39 | * @param fileExtName 40 | * @param fileSize 41 | * @param storeIndex 42 | * @param isAppenderFile 43 | */ 44 | public StorageAppendFileRequest(InputStream inputStream, long fileSize, String path) { 45 | super(); 46 | this.inputFile = inputStream; 47 | this.fileSize = fileSize; 48 | this.path = path; 49 | head = new ProtoHead(CmdConstants.STORAGE_PROTO_CMD_APPEND_FILE); 50 | } 51 | 52 | /** 53 | * 打包参数 54 | */ 55 | @Override 56 | public byte[] encodeParam(Charset charset) { 57 | // 运行时参数在此计算值 58 | this.pathSize = path.getBytes(charset).length; 59 | return super.encodeParam(charset); 60 | } 61 | 62 | public long getPathSize() { 63 | return pathSize; 64 | } 65 | 66 | public void setPathSize(long pathSize) { 67 | this.pathSize = pathSize; 68 | } 69 | 70 | public String getPath() { 71 | return path; 72 | } 73 | 74 | public void setPath(String path) { 75 | this.path = path; 76 | } 77 | 78 | public void setFileSize(long fileSize) { 79 | this.fileSize = fileSize; 80 | } 81 | 82 | @Override 83 | public long getFileSize() { 84 | return fileSize; 85 | } 86 | 87 | @Override 88 | public String toString() { 89 | return "StorageAppendFileRequest [pathSize=" + pathSize + ", fileSize=" + fileSize + ", path=" + path + "]"; 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/proto/storage/internal/StorageDeleteFileRequest.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.storage.internal; 2 | 3 | import com.github.tobato.fastdfs.domain.proto.CmdConstants; 4 | import com.github.tobato.fastdfs.domain.proto.FdfsRequest; 5 | import com.github.tobato.fastdfs.domain.proto.OtherConstants; 6 | import com.github.tobato.fastdfs.domain.proto.ProtoHead; 7 | import com.github.tobato.fastdfs.domain.proto.mapper.DynamicFieldType; 8 | import com.github.tobato.fastdfs.domain.proto.mapper.FdfsColumn; 9 | 10 | /** 11 | * 文件上传命令 12 | * 13 | * @author tobato 14 | */ 15 | public class StorageDeleteFileRequest extends FdfsRequest { 16 | 17 | /** 18 | * 组名 19 | */ 20 | @FdfsColumn(index = 0, max = OtherConstants.FDFS_GROUP_NAME_MAX_LEN) 21 | private String groupName; 22 | /** 23 | * 路径名 24 | */ 25 | @FdfsColumn(index = 1, dynamicField = DynamicFieldType.allRestByte) 26 | private String path; 27 | 28 | /** 29 | * 删除文件命令 30 | * 31 | * @param groupName 32 | * @param path 33 | */ 34 | public StorageDeleteFileRequest(String groupName, String path) { 35 | super(); 36 | this.groupName = groupName; 37 | this.path = path; 38 | this.head = new ProtoHead(CmdConstants.STORAGE_PROTO_CMD_DELETE_FILE); 39 | } 40 | 41 | public String getGroupName() { 42 | return groupName; 43 | } 44 | 45 | public void setGroupName(String groupName) { 46 | this.groupName = groupName; 47 | } 48 | 49 | public String getPath() { 50 | return path; 51 | } 52 | 53 | public void setPath(String path) { 54 | this.path = path; 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/proto/storage/internal/StorageDownloadRequest.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.storage.internal; 2 | 3 | import com.github.tobato.fastdfs.domain.proto.CmdConstants; 4 | import com.github.tobato.fastdfs.domain.proto.FdfsRequest; 5 | import com.github.tobato.fastdfs.domain.proto.OtherConstants; 6 | import com.github.tobato.fastdfs.domain.proto.ProtoHead; 7 | import com.github.tobato.fastdfs.domain.proto.mapper.DynamicFieldType; 8 | import com.github.tobato.fastdfs.domain.proto.mapper.FdfsColumn; 9 | 10 | /** 11 | * 文件下载请求 12 | * 13 | * @author tobato 14 | */ 15 | public class StorageDownloadRequest extends FdfsRequest { 16 | 17 | /** 18 | * 开始位置 19 | */ 20 | @FdfsColumn(index = 0) 21 | private long fileOffset; 22 | /** 23 | * 读取文件长度 24 | */ 25 | @FdfsColumn(index = 1) 26 | private long downloadBytes; 27 | /** 28 | * 组名 29 | */ 30 | @FdfsColumn(index = 2, max = OtherConstants.FDFS_GROUP_NAME_MAX_LEN) 31 | private String groupName; 32 | /** 33 | * 文件路径 34 | */ 35 | @FdfsColumn(index = 3, dynamicField = DynamicFieldType.allRestByte) 36 | private String path; 37 | 38 | /** 39 | * 文件下载请求 40 | * 41 | * @param groupName 42 | * @param path 43 | * @param fileOffset 44 | * @param downloadBytes 45 | */ 46 | public StorageDownloadRequest(String groupName, String path, long fileOffset, long downloadBytes) { 47 | super(); 48 | this.groupName = groupName; 49 | this.downloadBytes = downloadBytes; 50 | this.path = path; 51 | this.fileOffset = fileOffset; 52 | head = new ProtoHead(CmdConstants.STORAGE_PROTO_CMD_DOWNLOAD_FILE); 53 | 54 | } 55 | 56 | public long getFileOffset() { 57 | return fileOffset; 58 | } 59 | 60 | public String getGroupName() { 61 | return groupName; 62 | } 63 | 64 | public String getPath() { 65 | return path; 66 | } 67 | 68 | public long getDownloadBytes() { 69 | return downloadBytes; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/proto/storage/internal/StorageDownloadResponse.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.storage.internal; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.nio.charset.Charset; 6 | 7 | import com.github.tobato.fastdfs.domain.proto.FdfsResponse; 8 | import com.github.tobato.fastdfs.domain.proto.storage.DownloadCallback; 9 | import com.github.tobato.fastdfs.domain.proto.storage.FdfsInputStream; 10 | 11 | /** 12 | * 文件下载结果 13 | * 14 | * @param 15 | * @author tobato 16 | */ 17 | public class StorageDownloadResponse extends FdfsResponse { 18 | 19 | private DownloadCallback callback; 20 | 21 | public StorageDownloadResponse(DownloadCallback callback) { 22 | super(); 23 | this.callback = callback; 24 | } 25 | 26 | /** 27 | * 解析反馈内容 28 | */ 29 | @Override 30 | public T decodeContent(InputStream in, Charset charset) throws IOException { 31 | // 解析报文内容 32 | FdfsInputStream input = new FdfsInputStream(in, getContentLength()); 33 | return callback.recv(input); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/proto/storage/internal/StorageGetMetadataRequest.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.storage.internal; 2 | 3 | import com.github.tobato.fastdfs.domain.proto.CmdConstants; 4 | import com.github.tobato.fastdfs.domain.proto.FdfsRequest; 5 | import com.github.tobato.fastdfs.domain.proto.OtherConstants; 6 | import com.github.tobato.fastdfs.domain.proto.ProtoHead; 7 | import com.github.tobato.fastdfs.domain.proto.mapper.DynamicFieldType; 8 | import com.github.tobato.fastdfs.domain.proto.mapper.FdfsColumn; 9 | 10 | /** 11 | * 查询文件信息命令 12 | * 13 | * @author tobato 14 | */ 15 | public class StorageGetMetadataRequest extends FdfsRequest { 16 | 17 | /** 18 | * 组名 19 | */ 20 | @FdfsColumn(index = 0, max = OtherConstants.FDFS_GROUP_NAME_MAX_LEN) 21 | private String groupName; 22 | /** 23 | * 路径名 24 | */ 25 | @FdfsColumn(index = 1, dynamicField = DynamicFieldType.allRestByte) 26 | private String path; 27 | 28 | /** 29 | * 删除文件命令 30 | * 31 | * @param groupName 32 | * @param path 33 | */ 34 | public StorageGetMetadataRequest(String groupName, String path) { 35 | super(); 36 | this.groupName = groupName; 37 | this.path = path; 38 | this.head = new ProtoHead(CmdConstants.STORAGE_PROTO_CMD_GET_METADATA); 39 | } 40 | 41 | public String getGroupName() { 42 | return groupName; 43 | } 44 | 45 | public void setGroupName(String groupName) { 46 | this.groupName = groupName; 47 | } 48 | 49 | public String getPath() { 50 | return path; 51 | } 52 | 53 | public void setPath(String path) { 54 | this.path = path; 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/proto/storage/internal/StorageGetMetadataResponse.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.storage.internal; 2 | 3 | import com.github.tobato.fastdfs.domain.fdfs.MetaData; 4 | import com.github.tobato.fastdfs.domain.proto.FdfsResponse; 5 | import com.github.tobato.fastdfs.domain.proto.mapper.MetadataMapper; 6 | 7 | import java.io.IOException; 8 | import java.io.InputStream; 9 | import java.nio.charset.Charset; 10 | import java.util.Set; 11 | 12 | /** 13 | * 列出分组信息执行结果 14 | * 15 | * @author tobato 16 | */ 17 | public class StorageGetMetadataResponse extends FdfsResponse > { 18 | 19 | 20 | /** 21 | * 解析反馈内容 22 | * 23 | * @param in 24 | * @param charset 25 | * @return 26 | * @throws IOException 27 | */ 28 | @Override 29 | public Set decodeContent(InputStream in, Charset charset) throws IOException { 30 | // 解析报文内容 31 | byte[] bytes = new byte[(int) getContentLength()]; 32 | int contentSize = in.read(bytes); 33 | if (contentSize != getContentLength()) { 34 | throw new IOException("读取到的数据长度与协议长度不符"); 35 | } 36 | return MetadataMapper.fromByte(bytes, charset); 37 | 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/proto/storage/internal/StorageModifyRequest.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.storage.internal; 2 | 3 | import java.io.InputStream; 4 | import java.nio.charset.Charset; 5 | 6 | import com.github.tobato.fastdfs.domain.proto.CmdConstants; 7 | import com.github.tobato.fastdfs.domain.proto.FdfsRequest; 8 | import com.github.tobato.fastdfs.domain.proto.ProtoHead; 9 | import com.github.tobato.fastdfs.domain.proto.mapper.DynamicFieldType; 10 | import com.github.tobato.fastdfs.domain.proto.mapper.FdfsColumn; 11 | 12 | /** 13 | * 文件修改请求 14 | * 15 | * @author tobato 16 | */ 17 | public class StorageModifyRequest extends FdfsRequest { 18 | 19 | /** 20 | * 文件路径长度 21 | */ 22 | @FdfsColumn(index = 0) 23 | private long pathSize; 24 | /** 25 | * 开始位置 26 | */ 27 | @FdfsColumn(index = 1) 28 | private long fileOffset; 29 | /** 30 | * 发送文件长度 31 | */ 32 | @FdfsColumn(index = 2) 33 | private long fileSize; 34 | /** 35 | * 文件路径 36 | */ 37 | @FdfsColumn(index = 3, dynamicField = DynamicFieldType.allRestByte) 38 | private String path; 39 | 40 | /** 41 | * 构造函数 42 | * 43 | * @param inputStream 44 | * @param fileExtName 45 | * @param fileSize 46 | * @param storeIndex 47 | * @param isAppenderFile 48 | */ 49 | public StorageModifyRequest(InputStream inputStream, long fileSize, String path, long fileOffset) { 50 | super(); 51 | this.inputFile = inputStream; 52 | this.fileSize = fileSize; 53 | this.path = path; 54 | this.fileOffset = fileOffset; 55 | head = new ProtoHead(CmdConstants.STORAGE_PROTO_CMD_MODIFY_FILE); 56 | 57 | } 58 | 59 | /** 60 | * 打包参数 61 | */ 62 | @Override 63 | public byte[] encodeParam(Charset charset) { 64 | // 运行时参数在此计算值 65 | this.pathSize = path.getBytes(charset).length; 66 | return super.encodeParam(charset); 67 | } 68 | 69 | public long getPathSize() { 70 | return pathSize; 71 | } 72 | 73 | public long getFileOffset() { 74 | return fileOffset; 75 | } 76 | 77 | public String getPath() { 78 | return path; 79 | } 80 | 81 | @Override 82 | public long getFileSize() { 83 | return fileSize; 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/proto/storage/internal/StorageQueryFileInfoRequest.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.storage.internal; 2 | 3 | import com.github.tobato.fastdfs.domain.proto.CmdConstants; 4 | import com.github.tobato.fastdfs.domain.proto.FdfsRequest; 5 | import com.github.tobato.fastdfs.domain.proto.OtherConstants; 6 | import com.github.tobato.fastdfs.domain.proto.ProtoHead; 7 | import com.github.tobato.fastdfs.domain.proto.mapper.DynamicFieldType; 8 | import com.github.tobato.fastdfs.domain.proto.mapper.FdfsColumn; 9 | 10 | /** 11 | * 查询文件信息命令 12 | * 13 | * @author tobato 14 | */ 15 | public class StorageQueryFileInfoRequest extends FdfsRequest { 16 | 17 | /** 18 | * 组名 19 | */ 20 | @FdfsColumn(index = 0, max = OtherConstants.FDFS_GROUP_NAME_MAX_LEN) 21 | private String groupName; 22 | /** 23 | * 路径名 24 | */ 25 | @FdfsColumn(index = 1, dynamicField = DynamicFieldType.allRestByte) 26 | private String path; 27 | 28 | /** 29 | * 删除文件命令 30 | * 31 | * @param groupName 32 | * @param path 33 | */ 34 | public StorageQueryFileInfoRequest(String groupName, String path) { 35 | super(); 36 | this.groupName = groupName; 37 | this.path = path; 38 | this.head = new ProtoHead(CmdConstants.STORAGE_PROTO_CMD_QUERY_FILE_INFO); 39 | } 40 | 41 | public String getGroupName() { 42 | return groupName; 43 | } 44 | 45 | public void setGroupName(String groupName) { 46 | this.groupName = groupName; 47 | } 48 | 49 | public String getPath() { 50 | return path; 51 | } 52 | 53 | public void setPath(String path) { 54 | this.path = path; 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/proto/storage/internal/StorageTruncateRequest.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.storage.internal; 2 | 3 | import java.nio.charset.Charset; 4 | 5 | import com.github.tobato.fastdfs.domain.proto.CmdConstants; 6 | import com.github.tobato.fastdfs.domain.proto.FdfsRequest; 7 | import com.github.tobato.fastdfs.domain.proto.ProtoHead; 8 | import com.github.tobato.fastdfs.domain.proto.mapper.DynamicFieldType; 9 | import com.github.tobato.fastdfs.domain.proto.mapper.FdfsColumn; 10 | 11 | /** 12 | * 文件Truncate命令 13 | * 14 | *
15 | * 使用限制:创建文件时候需要采用<<源追加>>模式,之后才能Truncate 16 | * size使用也有限制 17 | *18 | * 19 | * @author tobato 20 | */ 21 | public class StorageTruncateRequest extends FdfsRequest { 22 | 23 | /** 24 | * 文件路径长度 25 | */ 26 | @FdfsColumn(index = 0) 27 | private long pathSize; 28 | /** 29 | * 截取文件长度 30 | */ 31 | @FdfsColumn(index = 1) 32 | private long fileSize; 33 | /** 34 | * 文件路径 35 | */ 36 | @FdfsColumn(index = 2, dynamicField = DynamicFieldType.allRestByte) 37 | private String path; 38 | 39 | /** 40 | * 文件Truncate命令 41 | * 42 | * @param path 43 | * @param fileSize 截取文件长度 44 | */ 45 | public StorageTruncateRequest(String path, long fileSize) { 46 | super(); 47 | this.fileSize = fileSize; 48 | this.path = path; 49 | head = new ProtoHead(CmdConstants.STORAGE_PROTO_CMD_TRUNCATE_FILE); 50 | } 51 | 52 | /** 53 | * 打包参数 54 | */ 55 | @Override 56 | public byte[] encodeParam(Charset charset) { 57 | // 运行时参数在此计算值 58 | this.pathSize = path.getBytes(charset).length; 59 | return super.encodeParam(charset); 60 | } 61 | 62 | public long getPathSize() { 63 | return pathSize; 64 | } 65 | 66 | public void setPathSize(long pathSize) { 67 | this.pathSize = pathSize; 68 | } 69 | 70 | public String getPath() { 71 | return path; 72 | } 73 | 74 | public void setPath(String path) { 75 | this.path = path; 76 | } 77 | 78 | public void setFileSize(long fileSize) { 79 | this.fileSize = fileSize; 80 | } 81 | 82 | @Override 83 | public long getFileSize() { 84 | return fileSize; 85 | } 86 | 87 | @Override 88 | public String toString() { 89 | return "StorageAppendFileRequest [pathSize=" + pathSize + ", fileSize=" + fileSize + ", path=" + path + "]"; 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/proto/storage/internal/StorageUploadFileRequest.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.storage.internal; 2 | 3 | import java.io.InputStream; 4 | 5 | import com.github.tobato.fastdfs.domain.proto.CmdConstants; 6 | import com.github.tobato.fastdfs.domain.proto.FdfsRequest; 7 | import com.github.tobato.fastdfs.domain.proto.OtherConstants; 8 | import com.github.tobato.fastdfs.domain.proto.ProtoHead; 9 | import com.github.tobato.fastdfs.domain.proto.mapper.FdfsColumn; 10 | 11 | /** 12 | * 文件上传命令 13 | * 14 | * @author tobato 15 | */ 16 | public class StorageUploadFileRequest extends FdfsRequest { 17 | 18 | private static final byte uploadCmd = CmdConstants.STORAGE_PROTO_CMD_UPLOAD_FILE; 19 | private static final byte uploadAppenderCmd = CmdConstants.STORAGE_PROTO_CMD_UPLOAD_APPENDER_FILE; 20 | 21 | /** 22 | * 存储节点index 23 | */ 24 | @FdfsColumn(index = 0) 25 | private byte storeIndex; 26 | /** 27 | * 发送文件长度 28 | */ 29 | @FdfsColumn(index = 1) 30 | private long fileSize; 31 | /** 32 | * 文件扩展名 33 | */ 34 | @FdfsColumn(index = 2, max = OtherConstants.FDFS_FILE_EXT_NAME_MAX_LEN) 35 | private String fileExtName; 36 | 37 | /** 38 | * 构造函数 39 | * 40 | * @param inputStream 41 | * @param fileExtName 42 | * @param fileSize 43 | * @param storeIndex 44 | * @param isAppenderFile 45 | */ 46 | public StorageUploadFileRequest(byte storeIndex, InputStream inputStream, String fileExtName, long fileSize, 47 | boolean isAppenderFile) { 48 | super(); 49 | this.inputFile = inputStream; 50 | this.fileSize = fileSize; 51 | this.storeIndex = storeIndex; 52 | this.fileExtName = fileExtName; 53 | if (isAppenderFile) { 54 | head = new ProtoHead(uploadAppenderCmd); 55 | } else { 56 | head = new ProtoHead(uploadCmd); 57 | } 58 | } 59 | 60 | public byte getStoreIndex() { 61 | return storeIndex; 62 | } 63 | 64 | public void setStoreIndex(byte storeIndex) { 65 | this.storeIndex = storeIndex; 66 | } 67 | 68 | public String getFileExtName() { 69 | return fileExtName; 70 | } 71 | 72 | public void setFileExtName(String fileExtName) { 73 | this.fileExtName = fileExtName; 74 | } 75 | 76 | @Override 77 | public long getFileSize() { 78 | return fileSize; 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/proto/storage/internal/StorageUploadSlaveFileRequest.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.storage.internal; 2 | 3 | import java.io.InputStream; 4 | 5 | import com.github.tobato.fastdfs.domain.proto.CmdConstants; 6 | import com.github.tobato.fastdfs.domain.proto.FdfsRequest; 7 | import com.github.tobato.fastdfs.domain.proto.OtherConstants; 8 | import com.github.tobato.fastdfs.domain.proto.ProtoHead; 9 | import com.github.tobato.fastdfs.domain.proto.mapper.DynamicFieldType; 10 | import com.github.tobato.fastdfs.domain.proto.mapper.FdfsColumn; 11 | 12 | /** 13 | * 从文件上传命令 14 | * 15 | * @author tobato 16 | */ 17 | public class StorageUploadSlaveFileRequest extends FdfsRequest { 18 | 19 | /** 20 | * 主文件名长度 21 | */ 22 | @FdfsColumn(index = 0) 23 | private long masterFileNameSize; 24 | /** 25 | * 发送文件长度 26 | */ 27 | @FdfsColumn(index = 1) 28 | private long fileSize; 29 | /** 30 | * 名称前缀 31 | */ 32 | @FdfsColumn(index = 2, max = OtherConstants.FDFS_FILE_PREFIX_MAX_LEN) 33 | private final String prefixName; 34 | /** 35 | * 文件扩展名 36 | */ 37 | @FdfsColumn(index = 3, max = OtherConstants.FDFS_FILE_EXT_NAME_MAX_LEN) 38 | private String fileExtName; 39 | /** 40 | * 主文件名 41 | */ 42 | @FdfsColumn(index = 4, dynamicField = DynamicFieldType.allRestByte) 43 | private final String masterFilename; 44 | 45 | /** 46 | * 构造函数 47 | * 48 | * @param storeIndex 49 | * @param inputStream 50 | * @param masterFilename 51 | * @param fileExtName 52 | * @param prefixName 53 | * @param fileSize 54 | * @param isAppenderFile 55 | */ 56 | public StorageUploadSlaveFileRequest(InputStream inputStream, long fileSize, String masterFilename, 57 | String prefixName, String fileExtName) { 58 | super(); 59 | this.inputFile = inputStream; 60 | this.fileSize = fileSize; 61 | this.masterFileNameSize = masterFilename.length(); 62 | this.masterFilename = masterFilename; 63 | this.fileExtName = fileExtName; 64 | this.prefixName = prefixName; 65 | head = new ProtoHead(CmdConstants.STORAGE_PROTO_CMD_UPLOAD_SLAVE_FILE); 66 | 67 | } 68 | 69 | public long getMasterFileNameSize() { 70 | return masterFileNameSize; 71 | } 72 | 73 | public void setMasterFileNameSize(long masterFileNameSize) { 74 | this.masterFileNameSize = masterFileNameSize; 75 | } 76 | 77 | public String getPrefixName() { 78 | return prefixName; 79 | } 80 | 81 | public String getMasterFilename() { 82 | return masterFilename; 83 | } 84 | 85 | public void setFileSize(long fileSize) { 86 | this.fileSize = fileSize; 87 | } 88 | 89 | public String getFileExtName() { 90 | return fileExtName; 91 | } 92 | 93 | public void setFileExtName(String fileExtName) { 94 | this.fileExtName = fileExtName; 95 | } 96 | 97 | @Override 98 | public long getFileSize() { 99 | return fileSize; 100 | } 101 | 102 | } 103 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/proto/tracker/TrackerDeleteStorageCommand.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.tracker; 2 | 3 | import com.github.tobato.fastdfs.domain.proto.AbstractFdfsCommand; 4 | import com.github.tobato.fastdfs.domain.proto.FdfsResponse; 5 | import com.github.tobato.fastdfs.domain.proto.tracker.internal.TrackerDeleteStorageRequest; 6 | 7 | /** 8 | * 移除存储服务器命令 9 | * 10 | * @author tobato 11 | */ 12 | public class TrackerDeleteStorageCommand extends AbstractFdfsCommand{ 13 | 14 | public TrackerDeleteStorageCommand(String groupName, String storageIpAddr) { 15 | super.request = new TrackerDeleteStorageRequest(groupName, storageIpAddr); 16 | super.response = new FdfsResponse () { 17 | // default response 18 | }; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/proto/tracker/TrackerGetFetchStorageCommand.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.tracker; 2 | 3 | import com.github.tobato.fastdfs.domain.fdfs.StorageNodeInfo; 4 | import com.github.tobato.fastdfs.domain.proto.AbstractFdfsCommand; 5 | import com.github.tobato.fastdfs.domain.proto.FdfsResponse; 6 | import com.github.tobato.fastdfs.domain.proto.tracker.internal.TrackerGetFetchStorageRequest; 7 | 8 | /** 9 | * 获取源服务器 10 | * 11 | * @author tobato 12 | */ 13 | public class TrackerGetFetchStorageCommand extends AbstractFdfsCommand { 14 | 15 | public TrackerGetFetchStorageCommand(String groupName, String path, boolean toUpdate) { 16 | super.request = new TrackerGetFetchStorageRequest(groupName, path, toUpdate); 17 | super.response = new FdfsResponse () { 18 | // default response 19 | }; 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/proto/tracker/TrackerGetStoreStorageCommand.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.tracker; 2 | 3 | import com.github.tobato.fastdfs.domain.fdfs.StorageNode; 4 | import com.github.tobato.fastdfs.domain.proto.AbstractFdfsCommand; 5 | import com.github.tobato.fastdfs.domain.proto.FdfsResponse; 6 | import com.github.tobato.fastdfs.domain.proto.tracker.internal.TrackerGetStoreStorageRequest; 7 | import com.github.tobato.fastdfs.domain.proto.tracker.internal.TrackerGetStoreStorageWithGroupRequest; 8 | 9 | /** 10 | * 获取存储节点命令 11 | * 12 | * @author tobato 13 | */ 14 | public class TrackerGetStoreStorageCommand extends AbstractFdfsCommand { 15 | 16 | public TrackerGetStoreStorageCommand(String groupName) { 17 | super.request = new TrackerGetStoreStorageWithGroupRequest(groupName); 18 | super.response = new FdfsResponse () { 19 | // default response 20 | }; 21 | } 22 | 23 | public TrackerGetStoreStorageCommand() { 24 | super.request = new TrackerGetStoreStorageRequest(); 25 | super.response = new FdfsResponse () { 26 | // default response 27 | }; 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/proto/tracker/TrackerListGroupsCommand.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.tracker; 2 | 3 | import com.github.tobato.fastdfs.domain.fdfs.GroupState; 4 | import com.github.tobato.fastdfs.domain.proto.AbstractFdfsCommand; 5 | import com.github.tobato.fastdfs.domain.proto.tracker.internal.TrackerListGroupsRequest; 6 | import com.github.tobato.fastdfs.domain.proto.tracker.internal.TrackerListGroupsResponse; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * 列出组命令 12 | * 13 | * @author tobato 14 | */ 15 | public class TrackerListGroupsCommand extends AbstractFdfsCommand > { 16 | 17 | public TrackerListGroupsCommand() { 18 | super.request = new TrackerListGroupsRequest(); 19 | super.response = new TrackerListGroupsResponse(); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/proto/tracker/TrackerListStoragesCommand.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.tracker; 2 | 3 | import com.github.tobato.fastdfs.domain.fdfs.StorageState; 4 | import com.github.tobato.fastdfs.domain.proto.AbstractFdfsCommand; 5 | import com.github.tobato.fastdfs.domain.proto.tracker.internal.TrackerListStoragesRequest; 6 | import com.github.tobato.fastdfs.domain.proto.tracker.internal.TrackerListStoragesResponse; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * 列出组命令 12 | * 13 | * @author tobato 14 | */ 15 | public class TrackerListStoragesCommand extends AbstractFdfsCommand
> { 16 | 17 | public TrackerListStoragesCommand(String groupName, String storageIpAddr) { 18 | super.request = new TrackerListStoragesRequest(groupName, storageIpAddr); 19 | super.response = new TrackerListStoragesResponse(); 20 | } 21 | 22 | public TrackerListStoragesCommand(String groupName) { 23 | super.request = new TrackerListStoragesRequest(groupName); 24 | super.response = new TrackerListStoragesResponse(); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/proto/tracker/internal/TrackerDeleteStorageRequest.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.tracker.internal; 2 | 3 | import org.apache.commons.lang3.Validate; 4 | 5 | import com.github.tobato.fastdfs.domain.proto.CmdConstants; 6 | import com.github.tobato.fastdfs.domain.proto.FdfsRequest; 7 | import com.github.tobato.fastdfs.domain.proto.OtherConstants; 8 | import com.github.tobato.fastdfs.domain.proto.ProtoHead; 9 | import com.github.tobato.fastdfs.domain.proto.mapper.FdfsColumn; 10 | 11 | /** 12 | * 移除存储服务器 13 | * 14 | * @author tobato 15 | */ 16 | public class TrackerDeleteStorageRequest extends FdfsRequest { 17 | 18 | /** 19 | * 组名 20 | */ 21 | @FdfsColumn(index = 0, max = OtherConstants.FDFS_GROUP_NAME_MAX_LEN) 22 | private String groupName; 23 | /** 24 | * 存储ip 25 | */ 26 | @FdfsColumn(index = 1, max = OtherConstants.FDFS_IPADDR_SIZE - 1) 27 | private String storageIpAddr; 28 | 29 | /** 30 | * 获取文件源服务器 31 | * 32 | * @param groupName 33 | * @param storageIpAddr 34 | */ 35 | public TrackerDeleteStorageRequest(String groupName, String storageIpAddr) { 36 | Validate.notBlank(groupName, "分组不能为空"); 37 | Validate.notBlank(storageIpAddr, "文件路径不能为空"); 38 | this.groupName = groupName; 39 | this.storageIpAddr = storageIpAddr; 40 | head = new ProtoHead(CmdConstants.TRACKER_PROTO_CMD_SERVER_DELETE_STORAGE); 41 | } 42 | 43 | public String getGroupName() { 44 | return groupName; 45 | } 46 | 47 | public String getStorageIpAddr() { 48 | return storageIpAddr; 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/proto/tracker/internal/TrackerGetFetchStorageRequest.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.tracker.internal; 2 | 3 | import org.apache.commons.lang3.Validate; 4 | 5 | import com.github.tobato.fastdfs.domain.proto.CmdConstants; 6 | import com.github.tobato.fastdfs.domain.proto.FdfsRequest; 7 | import com.github.tobato.fastdfs.domain.proto.OtherConstants; 8 | import com.github.tobato.fastdfs.domain.proto.ProtoHead; 9 | import com.github.tobato.fastdfs.domain.proto.mapper.DynamicFieldType; 10 | import com.github.tobato.fastdfs.domain.proto.mapper.FdfsColumn; 11 | 12 | /** 13 | * 获取源服务器 14 | * 15 | * @author tobato 16 | */ 17 | public class TrackerGetFetchStorageRequest extends FdfsRequest { 18 | 19 | private static final byte fetchCmd = CmdConstants.TRACKER_PROTO_CMD_SERVICE_QUERY_FETCH_ONE; 20 | private static final byte updateCmd = CmdConstants.TRACKER_PROTO_CMD_SERVICE_QUERY_UPDATE; 21 | 22 | /** 23 | * 组名 24 | */ 25 | @FdfsColumn(index = 0, max = OtherConstants.FDFS_GROUP_NAME_MAX_LEN) 26 | private String groupName; 27 | /** 28 | * 路径名 29 | */ 30 | @FdfsColumn(index = 1, dynamicField = DynamicFieldType.allRestByte) 31 | private String path; 32 | 33 | /** 34 | * 获取文件源服务器 35 | * 36 | * @param groupName 37 | * @param path 38 | */ 39 | public TrackerGetFetchStorageRequest(String groupName, String path, boolean toUpdate) { 40 | Validate.notBlank(groupName, "分组不能为空"); 41 | Validate.notBlank(path, "文件路径不能为空"); 42 | this.groupName = groupName; 43 | this.path = path; 44 | if (toUpdate) { 45 | head = new ProtoHead(updateCmd); 46 | } else { 47 | head = new ProtoHead(fetchCmd); 48 | } 49 | } 50 | 51 | public String getGroupName() { 52 | return groupName; 53 | } 54 | 55 | public String getPath() { 56 | return path; 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/proto/tracker/internal/TrackerGetStoreStorageRequest.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.tracker.internal; 2 | 3 | import com.github.tobato.fastdfs.domain.proto.CmdConstants; 4 | import com.github.tobato.fastdfs.domain.proto.FdfsRequest; 5 | import com.github.tobato.fastdfs.domain.proto.ProtoHead; 6 | 7 | /** 8 | * 获取存储节点请求 9 | * 10 | * @author tobato 11 | */ 12 | public class TrackerGetStoreStorageRequest extends FdfsRequest { 13 | 14 | private static final byte withoutGroupCmd = CmdConstants.TRACKER_PROTO_CMD_SERVICE_QUERY_STORE_WITHOUT_GROUP_ONE; 15 | 16 | /** 17 | * 获取存储节点 18 | */ 19 | public TrackerGetStoreStorageRequest() { 20 | super(); 21 | this.head = new ProtoHead(withoutGroupCmd); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/proto/tracker/internal/TrackerGetStoreStorageWithGroupRequest.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.tracker.internal; 2 | 3 | import org.apache.commons.lang3.Validate; 4 | 5 | import com.github.tobato.fastdfs.domain.proto.CmdConstants; 6 | import com.github.tobato.fastdfs.domain.proto.FdfsRequest; 7 | import com.github.tobato.fastdfs.domain.proto.OtherConstants; 8 | import com.github.tobato.fastdfs.domain.proto.ProtoHead; 9 | import com.github.tobato.fastdfs.domain.proto.mapper.FdfsColumn; 10 | 11 | /** 12 | * 按分组获取存储节点 13 | * 14 | * @author tobato 15 | */ 16 | public class TrackerGetStoreStorageWithGroupRequest extends FdfsRequest { 17 | 18 | private static final byte withGroupCmd = CmdConstants.TRACKER_PROTO_CMD_SERVICE_QUERY_STORE_WITH_GROUP_ONE; 19 | 20 | /** 21 | * 分组定义 22 | */ 23 | @FdfsColumn(index = 0, max = OtherConstants.FDFS_GROUP_NAME_MAX_LEN) 24 | private final String groupName; 25 | 26 | /** 27 | * 获取存储节点 28 | * 29 | * @param groupName 30 | */ 31 | public TrackerGetStoreStorageWithGroupRequest(String groupName) { 32 | Validate.notBlank(groupName, "分组不能为空"); 33 | this.groupName = groupName; 34 | this.head = new ProtoHead(withGroupCmd); 35 | } 36 | 37 | public String getGroupName() { 38 | return groupName; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/proto/tracker/internal/TrackerListGroupsRequest.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.tracker.internal; 2 | 3 | import com.github.tobato.fastdfs.domain.proto.CmdConstants; 4 | import com.github.tobato.fastdfs.domain.proto.FdfsRequest; 5 | import com.github.tobato.fastdfs.domain.proto.ProtoHead; 6 | 7 | /** 8 | * 列出分组命令 9 | * 10 | * @author tobato 11 | */ 12 | public class TrackerListGroupsRequest extends FdfsRequest { 13 | 14 | public TrackerListGroupsRequest() { 15 | head = new ProtoHead(CmdConstants.TRACKER_PROTO_CMD_SERVER_LIST_GROUP); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/proto/tracker/internal/TrackerListGroupsResponse.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.tracker.internal; 2 | 3 | import com.github.tobato.fastdfs.domain.fdfs.GroupState; 4 | import com.github.tobato.fastdfs.domain.proto.FdfsResponse; 5 | import com.github.tobato.fastdfs.domain.proto.mapper.FdfsParamMapper; 6 | import com.github.tobato.fastdfs.domain.proto.mapper.ObjectMetaData; 7 | 8 | import java.io.IOException; 9 | import java.io.InputStream; 10 | import java.nio.charset.Charset; 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | 14 | /** 15 | * 列出分组信息执行结果 16 | * 17 | * @author tobato 18 | */ 19 | public class TrackerListGroupsResponse extends FdfsResponse
> { 20 | 21 | /** 22 | * 解析反馈内容 23 | */ 24 | @Override 25 | public List
decodeContent(InputStream in, Charset charset) throws IOException { 26 | // 解析报文内容 27 | byte[] bytes = new byte[(int) getContentLength()]; 28 | int contentSize = in.read(bytes); 29 | // 此处fastdfs的服务端有bug 30 | if (contentSize != getContentLength()) { 31 | try { 32 | return decode(bytes, charset); 33 | } catch (Exception e) { 34 | throw new IOException("读取到的数据长度与协议长度不符"); 35 | } 36 | 37 | } else { 38 | return decode(bytes, charset); 39 | } 40 | } 41 | 42 | /** 43 | * 解析Group 44 | * 45 | * @param bs 46 | * @param charset 47 | * @return 48 | * @throws IOException 49 | */ 50 | private List decode(byte[] bs, Charset charset) throws IOException { 51 | // 获取对象转换定义 52 | ObjectMetaData objectMetaData = FdfsParamMapper.getObjectMap(GroupState.class); 53 | int fixFieldsTotalSize = objectMetaData.getFieldsFixTotalSize(); 54 | if (bs.length % fixFieldsTotalSize != 0) { 55 | throw new IOException("byte array length: " + bs.length + " is invalid!"); 56 | } 57 | // 计算反馈对象数量 58 | int count = bs.length / fixFieldsTotalSize; 59 | int offset = 0; 60 | List results = new ArrayList (count); 61 | 62 | for (int i = 0; i < count; i++) { 63 | byte[] one = new byte[fixFieldsTotalSize]; 64 | System.arraycopy(bs, offset, one, 0, fixFieldsTotalSize); 65 | results.add(FdfsParamMapper.map(one, GroupState.class, charset)); 66 | offset += fixFieldsTotalSize; 67 | } 68 | 69 | return results; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/proto/tracker/internal/TrackerListStoragesRequest.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.tracker.internal; 2 | 3 | import org.apache.commons.lang3.Validate; 4 | 5 | import com.github.tobato.fastdfs.domain.proto.CmdConstants; 6 | import com.github.tobato.fastdfs.domain.proto.FdfsRequest; 7 | import com.github.tobato.fastdfs.domain.proto.OtherConstants; 8 | import com.github.tobato.fastdfs.domain.proto.ProtoHead; 9 | import com.github.tobato.fastdfs.domain.proto.mapper.DynamicFieldType; 10 | import com.github.tobato.fastdfs.domain.proto.mapper.FdfsColumn; 11 | 12 | /** 13 | * 列出存储状态 14 | * 15 | * @author tobato 16 | */ 17 | public class TrackerListStoragesRequest extends FdfsRequest { 18 | 19 | /** 20 | * 组名 21 | */ 22 | @FdfsColumn(index = 0, max = OtherConstants.FDFS_GROUP_NAME_MAX_LEN) 23 | private String groupName; 24 | /** 25 | * 存储服务器ip地址 26 | */ 27 | @FdfsColumn(index = 1, max = OtherConstants.FDFS_IPADDR_SIZE - 1, dynamicField = DynamicFieldType.nullable) 28 | private String storageIpAddr; 29 | 30 | public TrackerListStoragesRequest() { 31 | head = new ProtoHead(CmdConstants.TRACKER_PROTO_CMD_SERVER_LIST_STORAGE); 32 | } 33 | 34 | /** 35 | * 列举存储服务器状态 36 | * 37 | * @param groupName 38 | * @param storageIpAddr 39 | */ 40 | public TrackerListStoragesRequest(String groupName, String storageIpAddr) { 41 | this(); 42 | Validate.notBlank(groupName, "分组不能为空"); 43 | this.groupName = groupName; 44 | this.storageIpAddr = storageIpAddr; 45 | } 46 | 47 | /** 48 | * 列举组当中存储节点状态 49 | * 50 | * @param groupName 51 | */ 52 | public TrackerListStoragesRequest(String groupName) { 53 | this(); 54 | this.groupName = groupName; 55 | Validate.notBlank(groupName, "分组不能为空"); 56 | } 57 | 58 | public String getGroupName() { 59 | return groupName; 60 | } 61 | 62 | public String getStorageIpAddr() { 63 | return storageIpAddr; 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/proto/tracker/internal/TrackerListStoragesResponse.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.tracker.internal; 2 | 3 | import com.github.tobato.fastdfs.domain.fdfs.StorageState; 4 | import com.github.tobato.fastdfs.domain.proto.FdfsResponse; 5 | import com.github.tobato.fastdfs.domain.proto.mapper.FdfsParamMapper; 6 | import com.github.tobato.fastdfs.domain.proto.mapper.ObjectMetaData; 7 | 8 | import java.io.IOException; 9 | import java.io.InputStream; 10 | import java.nio.charset.Charset; 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | 14 | /** 15 | * 列出分组信息执行结果 16 | * 17 | * @author tobato 18 | */ 19 | public class TrackerListStoragesResponse extends FdfsResponse > { 20 | 21 | /** 22 | * 解析反馈内容 23 | */ 24 | @Override 25 | public List
decodeContent(InputStream in, Charset charset) throws IOException { 26 | // 解析报文内容 27 | byte[] bytes = new byte[(int) getContentLength()]; 28 | int contentSize = in.read(bytes); 29 | if (contentSize != getContentLength()) { 30 | throw new IOException("读取到的数据长度与协议长度不符"); 31 | } 32 | return decode(bytes, charset); 33 | 34 | } 35 | 36 | /** 37 | * 解析Group 38 | * 39 | * @param bs 40 | * @param charset 41 | * @return 42 | * @throws IOException 43 | */ 44 | private List decode(byte[] bs, Charset charset) throws IOException { 45 | // 获取对象转换定义 46 | ObjectMetaData objectMetaData = FdfsParamMapper.getObjectMap(StorageState.class); 47 | int fixFieldsTotalSize = objectMetaData.getFieldsFixTotalSize(); 48 | if (bs.length % fixFieldsTotalSize != 0) { 49 | throw new IOException("fixFieldsTotalSize=" + fixFieldsTotalSize + "but byte array length: " + bs.length 50 | + " is invalid!"); 51 | } 52 | // 计算反馈对象数量 53 | int count = bs.length / fixFieldsTotalSize; 54 | int offset = 0; 55 | List results = new ArrayList (count); 56 | 57 | for (int i = 0; i < count; i++) { 58 | byte[] one = new byte[fixFieldsTotalSize]; 59 | System.arraycopy(bs, offset, one, 0, fixFieldsTotalSize); 60 | results.add(FdfsParamMapper.map(one, StorageState.class, charset)); 61 | offset += fixFieldsTotalSize; 62 | } 63 | 64 | return results; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/upload/AbstractFastFileBuilder.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.upload; 2 | 3 | 4 | import com.github.tobato.fastdfs.domain.fdfs.MetaData; 5 | import org.apache.commons.lang3.Validate; 6 | 7 | import java.io.InputStream; 8 | import java.util.HashSet; 9 | import java.util.Set; 10 | 11 | /** 12 | * 构造FastFile抽象对象 13 | * 14 | * @author wuyf 15 | * @create 2018-12-24 11:08 AM 16 | */ 17 | public abstract class AbstractFastFileBuilder { 18 | 19 | /** 20 | * 输入流 21 | */ 22 | protected InputStream inputStream; 23 | /** 24 | * 文件大小 25 | */ 26 | protected long fileSize; 27 | /** 28 | * 文件扩展名 29 | */ 30 | protected String fileExtName; 31 | /** 32 | * 文件元数据 33 | */ 34 | protected Set metaDataSet = new HashSet<>(); 35 | 36 | /** 37 | * 上传文件分组 38 | */ 39 | protected String groupName; 40 | 41 | /** 42 | * 上传文件 43 | * 44 | * @param inputStream 45 | * @param fileSize 46 | * @param fileExtName 47 | * @return 48 | */ 49 | public AbstractFastFileBuilder withFile(InputStream inputStream, long fileSize, String fileExtName) { 50 | this.inputStream = inputStream; 51 | this.fileSize = fileSize; 52 | this.fileExtName = fileExtName; 53 | return this; 54 | } 55 | 56 | /** 57 | * 元数据信息 58 | * 59 | * @param name 60 | * @param value 61 | * @return 62 | */ 63 | public AbstractFastFileBuilder withMetaData(String name, String value) { 64 | this.metaDataSet.add(new MetaData(name, value)); 65 | return this; 66 | } 67 | 68 | /** 69 | * 元数据信息 70 | * 71 | * @param metaDataSet 72 | * @return 73 | */ 74 | public AbstractFastFileBuilder withMetaData(Set metaDataSet) { 75 | Validate.notNull(metaDataSet, "元数据不能为空"); 76 | this.metaDataSet.addAll(metaDataSet); 77 | return this; 78 | } 79 | 80 | /** 81 | * 上传至文件组 82 | * 83 | * @param groupName 84 | * @return 85 | */ 86 | public AbstractFastFileBuilder toGroup(String groupName) { 87 | this.groupName = groupName; 88 | return this; 89 | } 90 | 91 | /** 92 | * 构造上传文件对象 93 | * 94 | * @return 95 | */ 96 | public abstract T build(); 97 | 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/upload/FastFile.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.upload; 2 | 3 | 4 | import com.github.tobato.fastdfs.domain.fdfs.MetaData; 5 | 6 | import java.io.InputStream; 7 | import java.util.Collections; 8 | import java.util.Set; 9 | 10 | /** 11 | * 上传普通文件 12 | * 13 | * @author tobato 14 | * @create 2018-12-23 3:06 PM 15 | */ 16 | public class FastFile { 17 | 18 | /** 19 | * 输入流 20 | */ 21 | protected InputStream inputStream; 22 | /** 23 | * 文件大小 24 | */ 25 | protected long fileSize; 26 | /** 27 | * 文件扩展名 28 | */ 29 | protected String fileExtName; 30 | /** 31 | * 文件元数据 32 | */ 33 | protected Set metaDataSet; 34 | 35 | /** 36 | * 上传文件分组 37 | */ 38 | protected String groupName; 39 | 40 | /** 41 | * 构造模式 42 | */ 43 | public static class Builder extends AbstractFastFileBuilder { 44 | 45 | @Override 46 | public Builder withFile(InputStream inputStream, long fileSize, String fileExtName) { 47 | super.withFile(inputStream, fileSize, fileExtName); 48 | return this; 49 | } 50 | 51 | @Override 52 | public Builder withMetaData(String name, String value) { 53 | super.withMetaData(name, value); 54 | return this; 55 | } 56 | 57 | @Override 58 | public Builder withMetaData(Set metaDataSet) { 59 | super.withMetaData(metaDataSet); 60 | return this; 61 | } 62 | 63 | @Override 64 | public Builder toGroup(String groupName) { 65 | super.toGroup(groupName); 66 | return this; 67 | } 68 | 69 | /** 70 | * 构造上传文件对象 71 | * 72 | * @return 73 | */ 74 | public FastFile build() { 75 | FastFile file = new FastFile(); 76 | file.inputStream = this.inputStream; 77 | file.fileExtName = this.fileExtName; 78 | file.fileSize = this.fileSize; 79 | file.metaDataSet = this.metaDataSet; 80 | file.groupName = this.groupName; 81 | return file; 82 | } 83 | } 84 | 85 | public InputStream getInputStream() { 86 | return inputStream; 87 | } 88 | 89 | public long getFileSize() { 90 | return fileSize; 91 | } 92 | 93 | public String getFileExtName() { 94 | return fileExtName; 95 | } 96 | 97 | public Set getMetaDataSet() { 98 | return metaDataSet != null ? Collections.unmodifiableSet(metaDataSet) : Collections.EMPTY_SET; 99 | } 100 | 101 | public String getGroupName() { 102 | return groupName; 103 | } 104 | 105 | /** 106 | * 上传文件对象 107 | * 108 | * @param inputStream 109 | * @param fileSize 110 | * @param fileExtName 111 | * @param metaDataSet 112 | */ 113 | public FastFile(InputStream inputStream, long fileSize, 114 | String fileExtName, Set metaDataSet) { 115 | this.inputStream = inputStream; 116 | this.fileSize = fileSize; 117 | this.fileExtName = fileExtName; 118 | this.metaDataSet = metaDataSet; 119 | } 120 | 121 | protected FastFile() { 122 | //for build 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/domain/upload/ThumbImage.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.upload; 2 | 3 | import org.apache.commons.lang3.Validate; 4 | 5 | /** 6 | * 缩略图配置 7 | * 8 | * 支持三种配置 9 | * 1. 按默认配置 10 | * 2. 支持按比例缩放 11 | * 3. 按长宽缩放 12 | * 如果配置按比例缩放,则按比例计算 13 | * 如果没有配置按比例缩放,则按长宽缩放 14 | *15 | * 16 | * @author tobato 17 | * @create 2018-12-23 3:11 PM 18 | */ 19 | public class ThumbImage { 20 | 21 | /** 22 | * 按默认配置生成缩略图 23 | */ 24 | private boolean defaultConfig = false; 25 | 26 | /** 27 | * 缩放长度 28 | */ 29 | private int width; 30 | /** 31 | * 缩放高度 32 | */ 33 | private int height; 34 | /** 35 | * 缩放比例 36 | */ 37 | private double percent; 38 | 39 | /** 40 | * 按长宽缩放 41 | * 42 | * @param width 43 | * @param height 44 | */ 45 | public ThumbImage(int width, int height) { 46 | this.width = width; 47 | this.height = height; 48 | } 49 | 50 | /** 51 | * 按比例缩放 52 | * 53 | * @param percent 54 | */ 55 | public ThumbImage(double percent) { 56 | this.percent = percent; 57 | } 58 | 59 | /** 60 | * 按默认配置生成 61 | */ 62 | public ThumbImage() { 63 | this.defaultConfig = true; 64 | } 65 | 66 | public int getWidth() { 67 | return width; 68 | } 69 | 70 | public int getHeight() { 71 | return height; 72 | } 73 | 74 | public double getPercent() { 75 | return percent; 76 | } 77 | 78 | public boolean isDefaultConfig() { 79 | return defaultConfig; 80 | } 81 | 82 | /** 83 | * 生成前缀如:_150x150 84 | */ 85 | public String getPrefixName() { 86 | if (isDefaultConfig()) { 87 | return getPrefixNameBySize(); 88 | } else if (percent != 0) { 89 | return getPrefixNameByPercent(); 90 | } else { 91 | return getPrefixNameBySize(); 92 | } 93 | } 94 | 95 | /** 96 | * 按缩放尺寸获取前缀 97 | * 98 | * @return 99 | */ 100 | private String getPrefixNameBySize() { 101 | StringBuilder buffer = new StringBuilder(); 102 | buffer.append("_").append(width).append("x").append(height); 103 | return new String(buffer); 104 | } 105 | 106 | /** 107 | * 按缩放尺寸获取前缀 108 | * 109 | * @return 110 | */ 111 | private String getPrefixNameByPercent() { 112 | StringBuilder buffer = new StringBuilder(); 113 | buffer.append("_").append(Math.round(100 * percent)).append("p_"); 114 | return new String(buffer); 115 | } 116 | 117 | 118 | /** 119 | * 根据文件名获取缩略图路径 120 | */ 121 | public String getThumbImagePath(String masterFilename) { 122 | Validate.notBlank(masterFilename, "主文件不能为空"); 123 | StringBuilder buff = new StringBuilder(masterFilename); 124 | int index = buff.lastIndexOf("."); 125 | buff.insert(index, getPrefixName()); 126 | return new String(buff); 127 | } 128 | 129 | /** 130 | * 设置默认缩放尺寸 131 | * 132 | * @param width 133 | * @param height 134 | */ 135 | public void setDefaultSize(int width, int height) { 136 | this.width = width; 137 | this.height = height; 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/exception/FdfsConnectException.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.exception; 2 | 3 | /** 4 | * 非fastdfs本身的错误码抛出的异常,socket连不上时抛出的异常 5 | * 6 | * @author yuqihuang 7 | * @author tobato 8 | * 9 | */ 10 | public class FdfsConnectException extends FdfsUnavailableException { 11 | 12 | /** 13 | * serialVersionUID 14 | */ 15 | private static final long serialVersionUID = 1L; 16 | 17 | /** 18 | * @param message 19 | */ 20 | public FdfsConnectException(String message, Throwable t) { 21 | super(message, t); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/exception/FdfsException.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.exception; 2 | 3 | /** 4 | * 封装fastdfs的异常,使用运行时异常 5 | * 6 | * @author yuqih 7 | * @author tobato 8 | * 9 | */ 10 | public abstract class FdfsException extends RuntimeException { 11 | 12 | /** 13 | * serialVersionUID 14 | */ 15 | private static final long serialVersionUID = 1L; 16 | 17 | protected FdfsException(String message) { 18 | super(message); 19 | } 20 | 21 | /** 22 | * @param message 23 | * @param cause 24 | */ 25 | protected FdfsException(String message, Throwable cause) { 26 | super(message, cause); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/exception/FdfsIOException.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.exception; 2 | 3 | /** 4 | * 非fastdfs本身的错误码抛出的异常,而是java客户端向服务端发送命令、文件或从服务端读取结果、下载文件时发生io异常 5 | * 6 | * @author yuqihuang 7 | * @author tobato 8 | * 9 | */ 10 | public class FdfsIOException extends FdfsException { 11 | 12 | /** 13 | * serialVersionUID 14 | */ 15 | private static final long serialVersionUID = 1L; 16 | 17 | /** 18 | * @param cause 19 | */ 20 | public FdfsIOException(Throwable cause) { 21 | super("客户端连接服务端出现了io异常", cause); 22 | } 23 | 24 | /** 25 | * @param message 26 | * @param cause 27 | */ 28 | public FdfsIOException(String messge, Throwable cause) { 29 | super("客户端连接服务端出现了io异常:" + messge, cause); 30 | } 31 | 32 | public FdfsIOException(String message) { 33 | super(message); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/exception/FdfsServerException.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.exception; 2 | 3 | import java.util.Collections; 4 | import java.util.HashMap; 5 | import java.util.Map; 6 | 7 | import com.github.tobato.fastdfs.domain.proto.ErrorCodeConstants; 8 | 9 | /** 10 | * fastdfs服务端返回的错误码构成的异常 11 | * 12 | * @author yuqih 13 | * @author tobato 14 | */ 15 | public class FdfsServerException extends FdfsException { 16 | 17 | /** 18 | * serialVersionUID 19 | */ 20 | private static final long serialVersionUID = 1L; 21 | 22 | /** 23 | * 错误对照表 24 | */ 25 | private static final MapCODE_MESSAGE_MAPPING; 26 | 27 | static { 28 | Map mapping = new HashMap (); 29 | mapping.put((int) ErrorCodeConstants.ERR_NO_ENOENT, "找不到节点或文件"); 30 | mapping.put((int) ErrorCodeConstants.ERR_NO_EIO, "服务端发生io异常"); 31 | mapping.put((int) ErrorCodeConstants.ERR_NO_EINVAL, "无效的参数"); 32 | mapping.put((int) ErrorCodeConstants.ERR_NO_EBUSY, "服务端忙"); 33 | mapping.put((int) ErrorCodeConstants.ERR_NO_ENOSPC, "没有足够的存储空间"); 34 | mapping.put((int) ErrorCodeConstants.ERR_NO_CONNREFUSED, "服务端拒绝连接"); 35 | mapping.put((int) ErrorCodeConstants.ERR_NO_EALREADY, "文件已经存在?"); 36 | CODE_MESSAGE_MAPPING = Collections.unmodifiableMap(mapping); 37 | } 38 | 39 | private int errorCode; 40 | 41 | /** 42 | * 43 | */ 44 | private FdfsServerException(int errorCode, String message) { 45 | super(message); 46 | this.errorCode = errorCode; 47 | } 48 | 49 | public static FdfsServerException byCode(int errorCode) { 50 | String message = CODE_MESSAGE_MAPPING.get(errorCode); 51 | if (message == null) { 52 | message = "未知错误"; 53 | } 54 | message = "错误码:" + errorCode + ",错误信息:" + message; 55 | 56 | return new FdfsServerException(errorCode, message); 57 | } 58 | 59 | /** 60 | * @return the errorCode 61 | */ 62 | public int getErrorCode() { 63 | return errorCode; 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/exception/FdfsUnavailableException.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.exception; 2 | 3 | /** 4 | * 非fastdfs本身的错误码抛出的异常,取服务端连接取不到时抛出的异常 5 | * 6 | * @author yuqihuang 7 | * 8 | */ 9 | public class FdfsUnavailableException extends FdfsException { 10 | 11 | /** 12 | * serialVersionUID 13 | */ 14 | private static final long serialVersionUID = 1L; 15 | 16 | /** 17 | * @param message 18 | */ 19 | public FdfsUnavailableException(String message) { 20 | super("无法获取服务端连接资源:" + message); 21 | } 22 | 23 | /** 24 | * @param message 25 | */ 26 | public FdfsUnavailableException(String message, Throwable t) { 27 | super("无法获取服务端连接资源:" + message, t); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/exception/FdfsUnsupportImageTypeException.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.exception; 2 | 3 | /** 4 | * 不支持的图片格式 5 | * 6 | * @author tobato 7 | * 8 | */ 9 | public class FdfsUnsupportImageTypeException extends FdfsException { 10 | 11 | /** 12 | * serialVersionUID 13 | */ 14 | private static final long serialVersionUID = 8498179372343498770L; 15 | 16 | public FdfsUnsupportImageTypeException(String message) { 17 | super(message); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/exception/FdfsUnsupportStorePathException.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.exception; 2 | 3 | /** 4 | * 从Url解析StorePath文件路径对象错误 5 | * 6 | * @author wuyf 7 | * 8 | */ 9 | public class FdfsUnsupportStorePathException extends FdfsException { 10 | 11 | /** 12 | * serialVersionUID 13 | */ 14 | private static final long serialVersionUID = 8116336411011152869L; 15 | 16 | public FdfsUnsupportStorePathException(String message) { 17 | super(message); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/exception/FdfsUploadImageException.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.exception; 2 | 3 | /** 4 | * 上传图片例外 5 | * 6 | * @author tobato 7 | * 8 | */ 9 | public class FdfsUploadImageException extends FdfsException { 10 | 11 | /** 12 | * serialVersionUID 13 | */ 14 | private static final long serialVersionUID = 1L; 15 | 16 | protected FdfsUploadImageException(String message) { 17 | super(message); 18 | } 19 | 20 | public FdfsUploadImageException(String message, Throwable cause) { 21 | super(message, cause); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/service/AppendFileStorageClient.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.service; 2 | 3 | import com.github.tobato.fastdfs.domain.fdfs.StorePath; 4 | 5 | import java.io.InputStream; 6 | 7 | 8 | /** 9 | * 支持断点续传的文件服务接口 10 | * 11 | *
12 | * 适合处理大文件,分段传输 13 | *14 | * 15 | * @author tobato 16 | */ 17 | public interface AppendFileStorageClient extends GenerateStorageClient { 18 | 19 | /** 20 | * 上传支持断点续传的文件 21 | * 22 | * @param groupName 23 | * @param inputStream 24 | * @param fileSize 25 | * @param fileExtName 26 | * @return 27 | */ 28 | StorePath uploadAppenderFile(String groupName, InputStream inputStream, long fileSize, String fileExtName); 29 | 30 | /** 31 | * 断点续传文件 32 | * 33 | * @param groupName 34 | * @param path 35 | * @param inputStream 36 | * @param fileSize 37 | */ 38 | void appendFile(String groupName, String path, InputStream inputStream, long fileSize); 39 | 40 | /** 41 | * 修改续传文件的内容 42 | * 43 | * @param groupName 44 | * @param path 45 | * @param inputStream 46 | * @param fileSize 47 | * @param fileOffset 48 | */ 49 | void modifyFile(String groupName, String path, InputStream inputStream, long fileSize, long fileOffset); 50 | 51 | /** 52 | * 清除续传类型文件的内容 53 | * 54 | * @param groupName 55 | * @param path 56 | * @param truncatedFileSize 57 | */ 58 | void truncateFile(String groupName, String path, long truncatedFileSize); 59 | 60 | /** 61 | * 清除续传类型文件的内容 62 | * 63 | * @param groupName 64 | * @param path 65 | */ 66 | void truncateFile(String groupName, String path); 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/service/DefaultAppendFileStorageClient.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.service; 2 | 3 | import com.github.tobato.fastdfs.domain.fdfs.StorageNode; 4 | import com.github.tobato.fastdfs.domain.fdfs.StorageNodeInfo; 5 | import com.github.tobato.fastdfs.domain.fdfs.StorePath; 6 | import com.github.tobato.fastdfs.domain.proto.storage.StorageAppendFileCommand; 7 | import com.github.tobato.fastdfs.domain.proto.storage.StorageModifyCommand; 8 | import com.github.tobato.fastdfs.domain.proto.storage.StorageTruncateCommand; 9 | import com.github.tobato.fastdfs.domain.proto.storage.StorageUploadFileCommand; 10 | import org.springframework.stereotype.Component; 11 | 12 | import java.io.InputStream; 13 | 14 | /** 15 | * 存储服务客户端接口实现 16 | * 17 | * @author tobato 18 | */ 19 | @Component 20 | public class DefaultAppendFileStorageClient extends DefaultGenerateStorageClient implements AppendFileStorageClient { 21 | 22 | /** 23 | * 上传支持断点续传的文件 24 | */ 25 | @Override 26 | public StorePath uploadAppenderFile(String groupName, InputStream inputStream, long fileSize, String fileExtName) { 27 | StorageNode client = trackerClient.getStoreStorage(groupName); 28 | StorageUploadFileCommand command = new StorageUploadFileCommand(client.getStoreIndex(), inputStream, 29 | fileExtName, fileSize, true); 30 | return fdfsConnectionManager.executeFdfsCmd(client.getInetSocketAddress(), command); 31 | } 32 | 33 | /** 34 | * 继续上载文件 35 | */ 36 | @Override 37 | public void appendFile(String groupName, String path, InputStream inputStream, long fileSize) { 38 | StorageNodeInfo client = trackerClient.getUpdateStorage(groupName, path); 39 | StorageAppendFileCommand command = new StorageAppendFileCommand(inputStream, fileSize, path); 40 | fdfsConnectionManager.executeFdfsCmd(client.getInetSocketAddress(), command); 41 | } 42 | 43 | /** 44 | * 修改文件 45 | */ 46 | @Override 47 | public void modifyFile(String groupName, String path, InputStream inputStream, long fileSize, long fileOffset) { 48 | StorageNodeInfo client = trackerClient.getUpdateStorage(groupName, path); 49 | StorageModifyCommand command = new StorageModifyCommand(path, inputStream, fileSize, fileOffset); 50 | fdfsConnectionManager.executeFdfsCmd(client.getInetSocketAddress(), command); 51 | 52 | } 53 | 54 | /** 55 | * 清除文件 56 | */ 57 | @Override 58 | public void truncateFile(String groupName, String path, long truncatedFileSize) { 59 | StorageNodeInfo client = trackerClient.getUpdateStorage(groupName, path); 60 | StorageTruncateCommand command = new StorageTruncateCommand(path, truncatedFileSize); 61 | fdfsConnectionManager.executeFdfsCmd(client.getInetSocketAddress(), command); 62 | } 63 | 64 | /** 65 | * 清除文件 66 | */ 67 | @Override 68 | public void truncateFile(String groupName, String path) { 69 | long truncatedFileSize = 0; 70 | truncateFile(groupName, path, truncatedFileSize); 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/service/FastFileStorageClient.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.service; 2 | 3 | import com.github.tobato.fastdfs.domain.fdfs.MetaData; 4 | import com.github.tobato.fastdfs.domain.fdfs.StorePath; 5 | import com.github.tobato.fastdfs.domain.upload.FastFile; 6 | import com.github.tobato.fastdfs.domain.upload.FastImageFile; 7 | 8 | import java.io.InputStream; 9 | import java.util.Set; 10 | 11 | /** 12 | * 面向普通应用的文件操作接口封装 13 | * 14 | * @author tobato 15 | */ 16 | public interface FastFileStorageClient extends GenerateStorageClient { 17 | 18 | /** 19 | * 上传一般文件 20 | * 21 | * @param inputStream 22 | * @param fileSize 23 | * @param fileExtName 24 | * @param metaDataSet 25 | * @return 26 | */ 27 | StorePath uploadFile(InputStream inputStream, long fileSize, String fileExtName, SetmetaDataSet); 28 | 29 | /** 30 | * 上传图片并且生成缩略图 31 | * 32 | * 支持的图片格式包括"JPG", "JPEG", "PNG", "GIF", "BMP", "WBMP" 33 | * 34 | * 缩略图为上传文件名+缩略图后缀 _150x150,如 xxx.jpg,缩略图为 xxx_150x150.jpg 35 | * 36 | * 实际样例如下 37 | * 38 | * 原图 http://localhost:8098/M00/00/17/rBEAAl33pQaAWNQNAAHYvQQn-YE374.jpg 39 | * 缩略图 http://localhost:8098/M00/00/17/rBEAAl33pQaAWNQNAAHYvQQn-YE374_150x150.jpg 40 | * 41 | *42 | * 43 | * @param inputStream 44 | * @param fileSize 45 | * @param fileExtName 46 | * @param metaDataSet 47 | * @return 48 | */ 49 | StorePath uploadImageAndCrtThumbImage(InputStream inputStream, long fileSize, String fileExtName, 50 | SetmetaDataSet); 51 | 52 | /** 53 | * 上传图片 54 | * 55 | * 可通过fastImageFile对象配置 56 | * 1. 上传图像分组 57 | * 2. 上传元数据metaDataSet 58 | * 3. 是否生成缩略图 59 | * 3.1 根据默认配置生成缩略图 60 | * 3.2 根据指定尺寸生成缩略图 61 | * 3.3 根据指定比例生成缩略图 62 | * 63 | * 64 | * @param fastImageFile 上传文件配置 65 | * @return 66 | */ 67 | StorePath uploadImage(FastImageFile fastImageFile); 68 | 69 | 70 | /** 71 | * 上传文件 72 | *73 | * 可通过fastFile对象配置 74 | * 1. 上传图像分组 75 | * 2. 上传元数据metaDataSet 76 | * 77 | * @param fastFile 78 | * @return 79 | */ 80 | StorePath uploadFile(FastFile fastFile); 81 | 82 | /** 83 | * 删除文件 84 | * 85 | * @param filePath 文件路径(groupName/path) 86 | */ 87 | void deleteFile(String filePath); 88 | 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/service/GenerateStorageClient.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.service; 2 | 3 | import com.github.tobato.fastdfs.domain.fdfs.FileInfo; 4 | import com.github.tobato.fastdfs.domain.fdfs.MetaData; 5 | import com.github.tobato.fastdfs.domain.fdfs.StorePath; 6 | import com.github.tobato.fastdfs.domain.proto.storage.DownloadCallback; 7 | 8 | import java.io.InputStream; 9 | import java.util.Set; 10 | 11 | /** 12 | * 基本文件存储客户端操作 13 | * 14 | * @author tobato 15 | */ 16 | public interface GenerateStorageClient { 17 | 18 | /** 19 | * 上传文件(文件不可修改) 20 | *21 | *
22 | * 文件上传后不可以修改,如果要修改则删除以后重新上传 23 | *24 | * 25 | * @param groupName 26 | * @param inputStream 27 | * @param fileSize 28 | * @param fileExtName 29 | * @return 30 | */ 31 | StorePath uploadFile(String groupName, InputStream inputStream, long fileSize, String fileExtName); 32 | 33 | /** 34 | * 上传从文件 35 | * 36 | * @param groupName 37 | * @param masterFilename 38 | * @param inputStream 39 | * @param fileSize 40 | * @param prefixName 41 | * @param fileExtName 42 | * @return 43 | */ 44 | StorePath uploadSlaveFile(String groupName, String masterFilename, InputStream inputStream, long fileSize, 45 | String prefixName, String fileExtName); 46 | 47 | /** 48 | * 获取文件元信息 49 | * 50 | * @param groupName 51 | * @param path 52 | * @return 53 | */ 54 | SetgetMetadata(String groupName, String path); 55 | 56 | /** 57 | * 修改文件元信息(覆盖) 58 | * 59 | * @param groupName 60 | * @param path 61 | * @param metaDataSet 62 | */ 63 | void overwriteMetadata(String groupName, String path, Set metaDataSet); 64 | 65 | /** 66 | * 修改文件元信息(合并) 67 | * 68 | * @param groupName 69 | * @param path 70 | * @param metaDataSet 71 | */ 72 | void mergeMetadata(String groupName, String path, Set metaDataSet); 73 | 74 | /** 75 | * 查看文件的信息 76 | * 77 | * @param groupName 78 | * @param path 79 | * @return 80 | */ 81 | FileInfo queryFileInfo(String groupName, String path); 82 | 83 | /** 84 | * 删除文件 85 | * 86 | * @param groupName 87 | * @param path 88 | */ 89 | void deleteFile(String groupName, String path); 90 | 91 | /** 92 | * 下载整个文件 93 | * 94 | * @param groupName 95 | * @param path 96 | * @param callback 97 | * @return 98 | */ 99 | T downloadFile(String groupName, String path, DownloadCallback callback); 100 | 101 | /** 102 | * 下载文件片段 103 | * 104 | * @param groupName 105 | * @param path 106 | * @param fileOffset 107 | * @param fileSize 108 | * @param callback 109 | * @return 110 | */ 111 | T downloadFile(String groupName, String path, long fileOffset, long fileSize, DownloadCallback callback); 112 | 113 | } 114 | -------------------------------------------------------------------------------- /src/main/java/com/github/tobato/fastdfs/service/TrackerClient.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.service; 2 | 3 | import com.github.tobato.fastdfs.domain.fdfs.GroupState; 4 | import com.github.tobato.fastdfs.domain.fdfs.StorageNode; 5 | import com.github.tobato.fastdfs.domain.fdfs.StorageNodeInfo; 6 | import com.github.tobato.fastdfs.domain.fdfs.StorageState; 7 | 8 | import java.util.List; 9 | 10 | 11 | /** 12 | * 目录服务(Tracker)客户端接口 13 | * 14 | * @author tobato 15 | */ 16 | public interface TrackerClient { 17 | 18 | /** 19 | * 获取存储节点 get the StoreStorage Client 20 | * 21 | * @return 22 | */ 23 | StorageNode getStoreStorage(); 24 | 25 | /** 26 | * 按组获取存储节点 get the StoreStorage Client by group 27 | * 28 | * @param groupName 29 | * @return 30 | */ 31 | StorageNode getStoreStorage(String groupName); 32 | 33 | /** 34 | * 获取读取存储节点 get the fetchStorage Client by group and filename 35 | * 36 | * @param groupName 37 | * @param filename 38 | * @return 39 | */ 40 | StorageNodeInfo getFetchStorage(String groupName, String filename); 41 | 42 | /** 43 | * 获取更新节点 get the updateStorage Client by group and filename 44 | * 45 | * @param groupName 46 | * @param filename 47 | * @return 48 | */ 49 | StorageNodeInfo getUpdateStorage(String groupName, String filename); 50 | 51 | /** 52 | * 获取组状态list groups 53 | * 54 | * @return 55 | */ 56 | List listGroups(); 57 | 58 | /** 59 | * 按组名获取存储节点状态list storages by groupName 60 | * 61 | * @param groupName 62 | * @return 63 | */ 64 | List listStorages(String groupName); 65 | 66 | /** 67 | * 获取存储状态 list storages by groupName and storageIpAddr 68 | * 69 | * @param groupName 70 | * @param storageIpAddr 71 | * @return 72 | */ 73 | List listStorages(String groupName, String storageIpAddr); 74 | 75 | /** 76 | * 删除存储节点 delete storage from TrackerServer 77 | * 78 | * @param groupName 79 | * @param storageIpAddr 80 | */ 81 | void deleteStorage(String groupName, String storageIpAddr); 82 | 83 | } 84 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | # Auto Configure 2 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.github.tobato.fastdfs.FdfsClientConfig 3 | -------------------------------------------------------------------------------- /src/test/java/com/github/tobato/fastdfs/FastdfsTestApplication.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.context.annotation.EnableMBeanExport; 6 | import org.springframework.jmx.support.RegistrationPolicy; 7 | 8 | /** 9 | * 测试驱动类 10 | * 11 | * @author tobato 12 | * 13 | */ 14 | @SpringBootApplication 15 | @EnableMBeanExport(registration = RegistrationPolicy.IGNORE_EXISTING) 16 | public class FastdfsTestApplication { 17 | public static void main(String[] args) { 18 | SpringApplication.run(FastdfsTestApplication.class, args); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/test/java/com/github/tobato/fastdfs/TestConstants.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs; 2 | 3 | import java.net.InetSocketAddress; 4 | import java.nio.charset.Charset; 5 | 6 | /** 7 | * 测试常量定义 8 | * 9 | * @author tobato 10 | */ 11 | @SuppressWarnings("unused") 12 | public class TestConstants { 13 | private static String ip_home = "172.17.0.2"; 14 | private static String ip_work = "10.0.75.2"; 15 | private static String ip_work_store = "192.168.174.43"; 16 | public final static int PORT = 22122;//22122 17 | public final static int STORE_PORT = 23000; //23000 18 | public static InetSocketAddress address = new InetSocketAddress(ip_home, PORT); 19 | public static InetSocketAddress store_address = new InetSocketAddress(ip_home, STORE_PORT); 20 | public static final int soTimeout = 550; 21 | public static final int connectTimeout = 500; 22 | public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); 23 | 24 | public static final String DEFAULT_GROUP = "group1"; 25 | public static final String DEFAULT_STORAGE_IP = ip_home; 26 | 27 | public static final String PERFORM_FILE_PATH = "/images/gs.jpg"; 28 | public static final String CAT_IMAGE_FILE = "/images/cat.jpg"; 29 | public static final String FLY_IMAGE_FILE = "/images/fly.png"; 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/test/java/com/github/tobato/fastdfs/TestUtils.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs; 2 | 3 | import java.io.ByteArrayInputStream; 4 | import java.io.File; 5 | import java.io.FileInputStream; 6 | import java.io.FileNotFoundException; 7 | import java.io.IOException; 8 | import java.io.InputStream; 9 | import java.net.URL; 10 | 11 | /** 12 | * 测试工具类 13 | * 14 | * @author tobato 15 | * 16 | */ 17 | public class TestUtils { 18 | 19 | private TestUtils() { 20 | // hide for utils 21 | } 22 | 23 | /** 24 | * 将String 转换为InputStream 25 | * 26 | * @param text 27 | * @return 28 | * @throws IOException 29 | */ 30 | public static InputStream getTextInputStream(String text) { 31 | // 将String转换为InputStream 32 | return new ByteArrayInputStream(text.getBytes(TestConstants.DEFAULT_CHARSET)); 33 | } 34 | 35 | /** 36 | * 获取String长度 37 | * 38 | * @param text 39 | * @return 40 | * @throws IOException 41 | */ 42 | public static long getTextLength(String text) { 43 | return text.getBytes(TestConstants.DEFAULT_CHARSET).length; 44 | } 45 | 46 | /** 47 | * 获取文件InputStream 48 | * 49 | * @param path 50 | * @return 51 | * @throws FileNotFoundException 52 | */ 53 | public static InputStream getFileInputStream(String path) throws FileNotFoundException { 54 | return new FileInputStream(getFile(path)); 55 | } 56 | 57 | /** 58 | * 获取文件 59 | * 60 | * @param path 61 | * @return 62 | */ 63 | public static File getFile(String path) { 64 | URL url = TestUtils.class.getResource(path); 65 | File file = new File(url.getFile()); 66 | return file; 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/test/java/com/github/tobato/fastdfs/domain/RandomTextFile.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain; 2 | 3 | import com.github.tobato.fastdfs.TestConstants; 4 | import com.github.tobato.fastdfs.TestUtils; 5 | import org.apache.commons.lang3.RandomStringUtils; 6 | 7 | import java.io.InputStream; 8 | 9 | /** 10 | * 测试用随机字符文件 11 | * 12 | * @author tobato 13 | */ 14 | public class RandomTextFile { 15 | 16 | private String text; 17 | 18 | private InputStream inputStream; 19 | 20 | private long fileSize; 21 | 22 | private String fileExtName = "txt"; 23 | 24 | public RandomTextFile() { 25 | this.text = RandomStringUtils.random(30, "762830abdcefghijklmnopqrstuvwxyz0991822-"); 26 | this.fileSize = TestUtils.getTextLength(text); 27 | } 28 | 29 | public RandomTextFile(String text) { 30 | this.text = text; 31 | this.fileSize = TestUtils.getTextLength(text); 32 | } 33 | 34 | public String getText() { 35 | return text; 36 | } 37 | 38 | public InputStream getInputStream() { 39 | this.inputStream = TestUtils.getTextInputStream(text); 40 | return inputStream; 41 | } 42 | 43 | public long getFileSize() { 44 | return fileSize; 45 | } 46 | 47 | public String getFileExtName() { 48 | return fileExtName; 49 | } 50 | 51 | public byte[] toByte() { 52 | return this.text.getBytes(TestConstants.DEFAULT_CHARSET); 53 | } 54 | 55 | public void setFileExtName(String fileExtName) { 56 | this.fileExtName = fileExtName; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/test/java/com/github/tobato/fastdfs/domain/StorePathTest.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain; 2 | 3 | import com.github.tobato.fastdfs.domain.fdfs.StorePath; 4 | import com.github.tobato.fastdfs.exception.FdfsUnsupportStorePathException; 5 | import org.junit.Test; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | import static org.junit.Assert.*; 10 | 11 | /** 12 | * 文件路径对象 13 | * 14 | * @author tobato 15 | */ 16 | public class StorePathTest { 17 | 18 | /** 19 | * 日志 20 | */ 21 | protected static Logger LOGGER = LoggerFactory.getLogger(StorePathTest.class); 22 | 23 | /** 24 | * 可以从url解析文件路径 25 | */ 26 | @Test 27 | public void testParseFromUrl() { 28 | String filePath = "group1/huex_sjuej/3hjshf.jpg"; 29 | StorePath path = StorePath.parseFromUrl(filePath); 30 | assertNotNull(path); 31 | assertEquals(path.getGroup(), "group1"); 32 | assertEquals(path.getPath(), "huex_sjuej/3hjshf.jpg"); 33 | } 34 | 35 | 36 | /** 37 | * 可以从url解析文件路径(Bug) 38 | */ 39 | @Test 40 | public void testParseFromUrl_FixBug() { 41 | String filePath = "testgroup1/M00/00/23/CgsCyFwXbRKACEiMAAAmhn9hIz402.xlsx"; 42 | StorePath path = StorePath.parseFromUrl(filePath); 43 | assertNotNull(path); 44 | assertEquals(path.getGroup(), "testgroup1"); 45 | assertEquals(path.getPath(), "M00/00/23/CgsCyFwXbRKACEiMAAAmhn9hIz402.xlsx"); 46 | } 47 | 48 | 49 | /** 50 | * 不支持错误路径 51 | */ 52 | @Test 53 | public void testParseFromUrlWithErr() { 54 | String filePath = "group1jshf.jpg"; 55 | try { 56 | StorePath.parseFromUrl(filePath); 57 | fail("No exception thrown."); 58 | } catch (Exception e) { 59 | assertTrue(e instanceof FdfsUnsupportStorePathException); 60 | LOGGER.debug(((FdfsUnsupportStorePathException) e).getMessage()); 61 | } 62 | } 63 | 64 | /** 65 | * 路径地址必须包含group 66 | */ 67 | @Test 68 | public void testParseFromUrlWithFullPathErr() { 69 | String filePath = "http://192.1.1.2/group1/jshf.jpg"; 70 | StorePath path = StorePath.parseFromUrl(filePath); 71 | assertNotNull(path); 72 | assertEquals(path.getGroup(), "group1"); 73 | assertEquals(path.getPath(), "jshf.jpg"); 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /src/test/java/com/github/tobato/fastdfs/domain/conn/ConnectionPoolConfigTest.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.conn; 2 | 3 | import com.github.tobato.fastdfs.FastdfsTestApplication; 4 | import org.junit.Test; 5 | import org.junit.runner.RunWith; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.boot.test.context.SpringBootTest; 10 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 11 | 12 | import static org.junit.Assert.assertEquals; 13 | 14 | /** 15 | * 测试参数化连接池配置 16 | * 17 | * @author Wuyf 18 | */ 19 | @RunWith(SpringJUnit4ClassRunner.class) 20 | @SpringBootTest(classes = FastdfsTestApplication.class) 21 | public class ConnectionPoolConfigTest { 22 | @Autowired 23 | private ConnectionPoolConfig connectionPoolConfig; 24 | 25 | /** 26 | * 日志 27 | */ 28 | protected static Logger LOGGER = LoggerFactory.getLogger(ConnectionPoolConfigTest.class); 29 | 30 | /** 31 | * 默认配置 32 | */ 33 | @Test 34 | public void testDefaultConfigPool() { 35 | // 从池中借出的对象的最大数目 36 | LOGGER.debug("从池中借出的对象的最大数目={}", connectionPoolConfig.getMaxTotal()); 37 | assertEquals(ConnectionPoolConfig.FDFS_MAX_TOTAL, connectionPoolConfig.getMaxTotal()); 38 | 39 | LOGGER.debug("获取连接时的最大等待毫秒数={}", connectionPoolConfig.getMaxWaitMillis()); 40 | assertEquals(ConnectionPoolConfig.FDFS_MAX_WAIT_MILLIS, connectionPoolConfig.getMaxWaitMillis()); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/test/java/com/github/tobato/fastdfs/domain/conn/ConnectionPoolCustomizedConfigTest.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.conn; 2 | 3 | import com.github.tobato.fastdfs.FastdfsTestApplication; 4 | import org.junit.Test; 5 | import org.junit.runner.RunWith; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.boot.test.context.SpringBootTest; 10 | import org.springframework.test.context.ActiveProfiles; 11 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 12 | 13 | import static org.junit.Assert.assertEquals; 14 | 15 | /** 16 | * 测试参数化连接池配置 17 | * 18 | * @author Wuyf 19 | */ 20 | @RunWith(SpringJUnit4ClassRunner.class) 21 | @SpringBootTest(classes = FastdfsTestApplication.class) 22 | @ActiveProfiles(value = "customized_pool") 23 | public class ConnectionPoolCustomizedConfigTest { 24 | @Autowired 25 | private ConnectionPoolConfig connectionPoolConfig; 26 | 27 | /** 28 | * 日志 29 | */ 30 | protected static Logger LOGGER = LoggerFactory.getLogger(ConnectionPoolCustomizedConfigTest.class); 31 | 32 | /** 33 | * 测试环境配置 34 | * 35 | *
36 | * spring.profiles: customized_pool 37 | * fdfs: 38 | * pool: 39 | * maxTotal: 153 40 | * maxWaitMillis: 102 41 | *42 | */ 43 | @Test 44 | public void testCustomizedConfigPool() { 45 | // 从池中借出的对象的最大数目 46 | LOGGER.debug("从池中借出的对象的最大数目={}", connectionPoolConfig.getMaxTotal()); 47 | assertEquals(153, connectionPoolConfig.getMaxTotal()); 48 | 49 | LOGGER.debug("获取连接时的最大等待毫秒数={}", connectionPoolConfig.getMaxWaitMillis()); 50 | assertEquals(102, connectionPoolConfig.getMaxWaitMillis()); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/test/java/com/github/tobato/fastdfs/domain/conn/ConnectionPoolTest.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.conn; 2 | 3 | import org.junit.Test; 4 | 5 | import java.net.InetSocketAddress; 6 | 7 | import static org.junit.Assert.assertFalse; 8 | 9 | /** 10 | * 连接池创建测试 11 | * 12 | * @author tobato 13 | */ 14 | public class ConnectionPoolTest extends MockServerTestBase { 15 | 16 | /** 17 | * 验证如何使用连接池 18 | */ 19 | @Test 20 | public void testPoolUsage() { 21 | FdfsConnectionPool pool = createPool(); 22 | try { 23 | // 获取连接 24 | Connection connA = pool.borrowObject(address); 25 | // 验证获取到连接 26 | assertFalse(connA.isClosed()); 27 | // 连接使用完毕归还池 28 | pool.returnObject(address, connA); 29 | // 清理连接 30 | pool.clear(address); 31 | LOGGER.debug("连接测试情况={}", pool.getTestOnBorrow()); 32 | 33 | } catch (Exception e) { 34 | e.printStackTrace(); 35 | } 36 | } 37 | 38 | @Test 39 | public void testPoolStatus() { 40 | FdfsConnectionPool pool = createPool(); 41 | try { 42 | // 获取连接 43 | printPoolStates("未获取前", address, pool); 44 | //pool.setTestOnBorrow(true); 45 | Connection connA = pool.borrowObject(address); 46 | printPoolStates("获取一个连接", address, pool); 47 | // 获取第二个连接 48 | Connection connB = pool.borrowObject(address); 49 | printPoolStates("获取二个连接", address, pool); 50 | // 返回第一个连接 51 | pool.returnObject(address, connA); 52 | printPoolStates("归还第一个连接", address, pool); 53 | pool.returnObject(address, connB); 54 | printPoolStates("归还第二个连接", address, pool); 55 | 56 | // 再获取一个连接 57 | Connection connC = pool.borrowObject(address); 58 | printPoolStates("获取第三个连接", address, pool); 59 | 60 | // 第三个连接在使用当中发生错误,需要销毁 61 | pool.invalidateObject(address, connC); 62 | printPoolStates("第三个连接在使用当中发生错误,需要销毁", address, pool); 63 | 64 | // 清理连接池 65 | pool.clear(address); 66 | // printPoolStates("清理连接池", address, pool); 67 | } catch (Exception e) { 68 | e.printStackTrace(); 69 | } 70 | } 71 | 72 | private FdfsConnectionPool createPool() { 73 | return new FdfsConnectionPool(new PooledConnectionFactory()); 74 | } 75 | 76 | private void printPoolStates(String msg, InetSocketAddress address, FdfsConnectionPool pool) { 77 | LOGGER.debug("=============={}================", msg); 78 | LOGGER.debug("活动连接{}", pool.getNumActive(address)); 79 | LOGGER.debug("空闲连接{}", pool.getNumIdle(address)); 80 | LOGGER.debug("连接获取总数统计{}", pool.getBorrowedCount()); 81 | LOGGER.debug("连接返回总数统计{}", pool.getReturnedCount()); 82 | LOGGER.debug("连接销毁总数统计{}", pool.getDestroyedCount()); 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /src/test/java/com/github/tobato/fastdfs/domain/conn/ConnectionTest.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.conn; 2 | 3 | import static org.junit.Assert.assertFalse; 4 | import static org.junit.Assert.assertTrue; 5 | 6 | /** 7 | * socket连接测试 8 | * 9 | * @author tobato 10 | */ 11 | public class ConnectionTest extends MockServerTestBase { 12 | 13 | //@Test 14 | public void testClose() { 15 | // 创建连接 16 | Connection conn = createConnection(); 17 | // 正常连接 18 | assertFalse(conn.isClosed()); 19 | conn.close(); 20 | assertTrue(conn.isClosed()); 21 | } 22 | 23 | //@Test 24 | public void testCheck() { 25 | // 创建连接测试 26 | Connection conn = createConnection(); 27 | LOGGER.debug("当前连接状态={}", conn.isValid()); 28 | conn.close(); 29 | } 30 | 31 | /** 32 | * 创建连接 33 | * 34 | * @return 35 | */ 36 | private Connection createConnection() { 37 | return new DefaultConnection(address, soTimeout, connectTimeout, null); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/test/java/com/github/tobato/fastdfs/domain/conn/MockServerTestBase.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.conn; 2 | 3 | import com.github.tobato.fastdfs.socket.FdfsMockSocketServer; 4 | import org.junit.AfterClass; 5 | import org.junit.BeforeClass; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | import java.net.InetSocketAddress; 10 | 11 | /** 12 | * socket 测试基类 13 | * 14 | * @author tobato 15 | */ 16 | public class MockServerTestBase { 17 | 18 | /** 19 | * 日志 20 | */ 21 | protected final Logger LOGGER = LoggerFactory.getLogger(MockServerTestBase.class); 22 | 23 | protected static FdfsMockSocketServer socketServer = new FdfsMockSocketServer(); 24 | public InetSocketAddress address = new InetSocketAddress(FdfsMockSocketServer.PORT); 25 | public static final int soTimeout = 350; 26 | public static final int connectTimeout = 50; 27 | 28 | @BeforeClass 29 | public static void startMockServer() { 30 | socketServer.start(); 31 | } 32 | 33 | @AfterClass 34 | public static void stopMockServer() { 35 | socketServer.stopServer(); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/test/java/com/github/tobato/fastdfs/domain/conn/TrackerConnectionManagerTest.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.conn; 2 | 3 | import com.github.tobato.fastdfs.domain.fdfs.GroupState; 4 | import com.github.tobato.fastdfs.domain.proto.tracker.TrackerListGroupsCommand; 5 | import com.github.tobato.fastdfs.exception.FdfsConnectException; 6 | import org.junit.Test; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | import java.util.Arrays; 11 | import java.util.List; 12 | 13 | import static org.junit.Assert.*; 14 | 15 | /** 16 | * 验证连接池管理 17 | * 18 | * @author tobato 19 | */ 20 | public class TrackerConnectionManagerTest { 21 | 22 | /** 23 | * 日志 24 | */ 25 | protected static Logger LOGGER = LoggerFactory.getLogger(TrackerConnectionManagerTest.class); 26 | 27 | /** 28 | * 会对tracker连接地址列表进行轮询 29 | */ 30 | @Test 31 | public void testConnectionManager() { 32 | // 初始化 33 | TrackerConnectionManager manager = crtInvalidateIpListManager(); 34 | Listlist = null; 35 | // 第一次执行 36 | try { 37 | // 连接失败 38 | list = manager.executeFdfsTrackerCmd(new TrackerListGroupsCommand()); 39 | fail("No exception thrown."); 40 | } catch (Exception e) { 41 | assertTrue(e instanceof FdfsConnectException); 42 | } 43 | 44 | // 第二次执行 45 | try { 46 | // 连接失败 47 | list = manager.executeFdfsTrackerCmd(new TrackerListGroupsCommand()); 48 | fail("No exception thrown."); 49 | } catch (Exception e) { 50 | assertTrue(e instanceof FdfsConnectException); 51 | } 52 | 53 | assertNull(list); 54 | } 55 | 56 | /** 57 | * 创建无效的IP地址列表连接管理 58 | * 59 | * @return 60 | */ 61 | private TrackerConnectionManager crtInvalidateIpListManager() { 62 | String[] ips = {"192.168.1.1:22122", "192.168.1.115:212"}; 63 | List trackerIpList = Arrays.asList(ips); 64 | TrackerConnectionManager manager = new TrackerConnectionManager(createPool()); 65 | manager.setTrackerList(trackerIpList); 66 | manager.initTracker(); 67 | return manager; 68 | } 69 | 70 | /** 71 | * 创建连接池 72 | * 73 | * @return 74 | */ 75 | private FdfsConnectionPool createPool() { 76 | PooledConnectionFactory factory = new PooledConnectionFactory(); 77 | //缩短连接超时时间 78 | factory.setConnectTimeout(2); 79 | factory.setSoTimeout(2); 80 | return new FdfsConnectionPool(factory); 81 | } 82 | 83 | 84 | } 85 | -------------------------------------------------------------------------------- /src/test/java/com/github/tobato/fastdfs/domain/fdfs/CircularListTest.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.fdfs; 2 | 3 | import org.junit.Before; 4 | import org.junit.Test; 5 | 6 | import java.util.Arrays; 7 | 8 | import static org.junit.Assert.assertEquals; 9 | 10 | /** 11 | * 循环列表测试-支持列表轮询算法 12 | * 13 | * @author tobato 14 | */ 15 | public class CircularListTest { 16 | 17 | private CircularList list; 18 | private String[] strs = {"1", "2", "3", "4"}; 19 | 20 | @Before 21 | public void init() { 22 | list = new CircularList (); 23 | list.addAll(Arrays.asList(strs)); 24 | } 25 | 26 | @Test 27 | public void testReset() { 28 | assertEquals(list.next(), strs[0]); 29 | assertEquals(list.next(), strs[1]); 30 | // 重置以后将从第一个数据获取 31 | list.reset(); 32 | assertEquals(list.next(), strs[0]); 33 | assertEquals(list.next(), strs[1]); 34 | } 35 | 36 | @Test 37 | public void testNext() { 38 | assertEquals(list.next(), strs[0]); 39 | assertEquals(list.next(), strs[1]); 40 | assertEquals(list.next(), strs[2]); 41 | assertEquals(list.next(), strs[3]); 42 | assertEquals(list.next(), strs[0]); 43 | assertEquals(list.next(), strs[1]); 44 | } 45 | 46 | @Test 47 | public void testCurrent() { 48 | assertEquals(list.next(), strs[0]); 49 | assertEquals(list.next(), strs[1]); 50 | assertEquals(list.current(), strs[1]); 51 | assertEquals(list.current(), strs[1]); 52 | } 53 | 54 | @Test 55 | public void testPrevious() { 56 | assertEquals(list.next(), strs[0]); 57 | assertEquals(list.next(), strs[1]); 58 | assertEquals(list.previous(), strs[0]); 59 | assertEquals(list.previous(), strs[3]); 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /src/test/java/com/github/tobato/fastdfs/domain/fdfs/DefaultThumbImageConfigTest.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.fdfs; 2 | 3 | import com.github.tobato.fastdfs.FastdfsTestApplication; 4 | import org.junit.Test; 5 | import org.junit.runner.RunWith; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.boot.test.context.SpringBootTest; 10 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 11 | 12 | import static org.junit.Assert.assertEquals; 13 | import static org.junit.Assert.assertNotNull; 14 | 15 | /** 16 | * 缩略图配置测试 17 | * 18 | * @author tobato 19 | */ 20 | @RunWith(SpringJUnit4ClassRunner.class) 21 | @SpringBootTest(classes = FastdfsTestApplication.class) 22 | public class DefaultThumbImageConfigTest { 23 | 24 | /** 25 | * 日志 26 | */ 27 | protected static Logger LOGGER = LoggerFactory.getLogger(DefaultThumbImageConfigTest.class); 28 | 29 | @Autowired 30 | private ThumbImageConfig thumbImageConfig; 31 | 32 | @Test 33 | public void testGetThumbImagePrefixName() { 34 | assertNotNull(thumbImageConfig.getPrefixName()); 35 | } 36 | 37 | @Test 38 | public void testGetThumbImagePath() { 39 | 40 | String path = "wKgBaVaNODiAPpVCAAGtJ7UVNRA438.jpg"; 41 | String thumbPath = "wKgBaVaNODiAPpVCAAGtJ7UVNRA438" + thumbImageConfig.getPrefixName() + ".jpg"; 42 | 43 | String result = thumbImageConfig.getThumbImagePath(path); 44 | LOGGER.debug(result); 45 | assertEquals(thumbPath, result); 46 | 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/test/java/com/github/tobato/fastdfs/domain/fdfs/TrackerAddressHolderTest.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.fdfs; 2 | 3 | import org.junit.Test; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import java.net.InetSocketAddress; 8 | 9 | import static org.junit.Assert.assertFalse; 10 | import static org.junit.Assert.assertTrue; 11 | 12 | /** 13 | * TrackerAddressHolder测试 14 | * 15 | * @author tobato 16 | */ 17 | public class TrackerAddressHolderTest { 18 | 19 | /** 20 | * 日志 21 | */ 22 | protected static Logger LOGGER = LoggerFactory.getLogger(TrackerAddressHolderTest.class); 23 | 24 | @Test 25 | public void testCanTryToConnect() throws InterruptedException { 26 | TrackerAddressHolder holder = new TrackerAddressHolder(new InetSocketAddress(9988)); 27 | assertTrue(holder.isAvailable()); 28 | //连接设置为无效 29 | holder.setInActive(); 30 | assertFalse(holder.isAvailable()); 31 | // 验证超时10秒以后,可以重新尝试连接 32 | boolean canRetry = false; 33 | int i = 0; 34 | while (!canRetry) { 35 | i = i + 1; 36 | Thread.sleep(2000); 37 | canRetry = holder.canTryToConnect(10); 38 | LOGGER.debug("第{}次尝试重新连接..可尝试状态={}", i, canRetry); 39 | } 40 | 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/test/java/com/github/tobato/fastdfs/domain/fdfs/TrackerLocatorTest.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.fdfs; 2 | 3 | import com.github.tobato.fastdfs.exception.FdfsUnavailableException; 4 | import org.junit.Test; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | import java.net.InetSocketAddress; 9 | import java.util.Arrays; 10 | import java.util.List; 11 | 12 | import static org.junit.Assert.*; 13 | 14 | /** 15 | * TrackerLocator创建 16 | * 17 | * @author tobato 18 | */ 19 | public class TrackerLocatorTest { 20 | 21 | /** 22 | * 日志 23 | */ 24 | protected static Logger LOGGER = LoggerFactory.getLogger(TrackerLocatorTest.class); 25 | 26 | private String[] ips = {"192.168.174.47:22122", "192.168.1.105:22122"}; 27 | private List trackerIpList = Arrays.asList(ips); 28 | 29 | @Test 30 | public void testTrackerLocator() { 31 | // 创建Locator 32 | TrackerLocator locator = new TrackerLocator(trackerIpList); 33 | assertFalse(locator.getTrackerList().isEmpty()); 34 | // 获取一个连接地址 35 | InetSocketAddress addressA = getAddress(locator, "获取地址A"); 36 | InetSocketAddress addressB = getAddress(locator, "获取地址B"); 37 | // 地址轮询 38 | assertNotEquals(addressA, addressB); 39 | // IF 连接断开 40 | locator.setInActive(addressA); 41 | InetSocketAddress addressC = getAddress(locator, "获取地址C"); 42 | assertNotEquals(addressA, addressC); 43 | // 只剩一个地址 44 | assertEquals(addressB, addressC); 45 | // 连接恢复 46 | locator.setActive(addressA); 47 | 48 | // 获取连接 49 | InetSocketAddress addressD = getAddress(locator, "获取地址D"); 50 | assertEquals(addressA, addressD); 51 | locator.setInActive(addressA); 52 | locator.setInActive(addressB); 53 | 54 | try { 55 | // 无连接可以获取 56 | getAddress(locator, "获取地址E"); 57 | fail("No exception thrown."); 58 | } catch (Exception e) { 59 | assertTrue(e instanceof FdfsUnavailableException); 60 | } 61 | } 62 | 63 | /** 64 | * 获取一个连接地址 65 | * 66 | * @param msg 67 | * @param locator 68 | * @return 69 | */ 70 | private InetSocketAddress getAddress(TrackerLocator locator, String msg) { 71 | InetSocketAddress address = locator.getTrackerAddress(); 72 | assertNotNull(address); 73 | LOGGER.debug(msg + ":{}", address); 74 | return address; 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /src/test/java/com/github/tobato/fastdfs/domain/proto/CommandTestBase.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | import com.github.tobato.fastdfs.TestConstants; 7 | import com.github.tobato.fastdfs.domain.conn.FdfsConnectionManager; 8 | import com.github.tobato.fastdfs.domain.conn.FdfsConnectionPool; 9 | import com.github.tobato.fastdfs.domain.conn.PooledConnectionFactory; 10 | 11 | /** 12 | * command测试基类 13 | * 14 | * @author tobato 15 | */ 16 | public class CommandTestBase { 17 | /** 18 | * 日志 19 | */ 20 | protected static Logger LOGGER = LoggerFactory.getLogger(CommandTestBase.class); 21 | 22 | /** 23 | * 连接池 24 | */ 25 | protected FdfsConnectionManager manager = createConnectionManager(); 26 | 27 | /** 28 | * 执行Tracker交易命令 29 | * 30 | * @param command 31 | * @return 32 | */ 33 | protected T executeTrackerCmd(FdfsCommand command) { 34 | return manager.executeFdfsCmd(TestConstants.address, command); 35 | } 36 | 37 | /** 38 | * 执行存储交易命令 39 | * 40 | * @param command 41 | * @return 42 | */ 43 | protected T executeStoreCmd(FdfsCommand command) { 44 | return manager.executeFdfsCmd(TestConstants.store_address, command); 45 | } 46 | 47 | private FdfsConnectionManager createConnectionManager() { 48 | return new FdfsConnectionManager(createPool()); 49 | } 50 | 51 | private FdfsConnectionPool createPool() { 52 | PooledConnectionFactory factory = new PooledConnectionFactory(); 53 | factory.setConnectTimeout(TestConstants.connectTimeout); 54 | factory.setSoTimeout(TestConstants.soTimeout); 55 | return new FdfsConnectionPool(new PooledConnectionFactory()); 56 | } 57 | 58 | /** 59 | * 导出pool信息 60 | */ 61 | protected void dumpPool() { 62 | manager.dumpPoolInfo(TestConstants.store_address); 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /src/test/java/com/github/tobato/fastdfs/domain/proto/StorageCommandTestBase.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto; 2 | 3 | import com.github.tobato.fastdfs.TestConstants; 4 | import com.github.tobato.fastdfs.TestUtils; 5 | import com.github.tobato.fastdfs.domain.fdfs.StorePath; 6 | import com.github.tobato.fastdfs.domain.proto.storage.StorageUploadFileCommand; 7 | import org.apache.commons.io.FilenameUtils; 8 | 9 | import java.io.*; 10 | 11 | import static org.junit.Assert.assertNotNull; 12 | 13 | /** 14 | * command测试基类 15 | * 16 | * @author tobato 17 | */ 18 | public abstract class StorageCommandTestBase extends CommandTestBase { 19 | 20 | /** 21 | * 文件上传操作 22 | * 23 | * @param isAppenderFile 24 | */ 25 | public StorePath execStorageUploadFileCommand(String filePath, boolean isAppenderFile) { 26 | InputStream in = null; 27 | File file = TestUtils.getFile(filePath); 28 | String fileExtName = FilenameUtils.getExtension(file.getName()); 29 | long fileSize = file.length(); 30 | 31 | try { 32 | in = TestUtils.getFileInputStream(filePath); 33 | return uploadInputStream(in, fileExtName, fileSize, isAppenderFile); 34 | } catch (FileNotFoundException e) { 35 | e.printStackTrace(); 36 | } finally { 37 | if (null != in) { 38 | try { 39 | in.close(); 40 | } catch (IOException e) { 41 | e.printStackTrace(); 42 | } 43 | } 44 | } 45 | return null; 46 | } 47 | 48 | /** 49 | * 获取传输文件第一个部分 50 | * 51 | * @param text 52 | * @return 53 | * @throws IOException 54 | */ 55 | protected InputStream getTextInputStream(String text) throws IOException { 56 | // 将String转换为InputStream 57 | return new ByteArrayInputStream(text.getBytes(TestConstants.DEFAULT_CHARSET)); 58 | } 59 | 60 | /** 61 | * 上传默认文件 62 | * 63 | * @return 64 | */ 65 | protected StorePath uploadDefaultFile() { 66 | // 上传文件 67 | return execStorageUploadFileCommand(TestConstants.CAT_IMAGE_FILE, false); 68 | } 69 | 70 | /** 71 | * 文件上传操作 72 | * 73 | * @param isAppenderFile 74 | */ 75 | protected StorePath uploadInputStream(InputStream in, String fileExtName, long fileSize, boolean isAppenderFile) { 76 | byte storeIndex = 0; 77 | StorageUploadFileCommand command = new StorageUploadFileCommand(storeIndex, in, fileExtName, fileSize, 78 | isAppenderFile); 79 | StorePath path = executeStoreCmd(command); 80 | assertNotNull(path); 81 | LOGGER.debug("isAppenderFile={}-----文件上传处理结果-----", false); 82 | LOGGER.debug(path.toString()); 83 | return path; 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /src/test/java/com/github/tobato/fastdfs/domain/proto/mapper/Foo.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.mapper; 2 | 3 | import com.github.tobato.fastdfs.domain.proto.OtherConstants; 4 | 5 | /** 6 | * 测试类 7 | * 8 | * @author tobato 9 | * 10 | */ 11 | public class Foo { 12 | 13 | @FdfsColumn(index = 0, max = OtherConstants.FDFS_GROUP_NAME_MAX_LEN) 14 | String groupName; 15 | @FdfsColumn(index = 1, max = OtherConstants.FDFS_IPADDR_SIZE - 1) 16 | String ip; 17 | @FdfsColumn(index = 2) 18 | long port; 19 | 20 | public long getPort() { 21 | return port; 22 | } 23 | 24 | public void setPort(long port) { 25 | this.port = port; 26 | } 27 | 28 | public String getGroupName() { 29 | return groupName; 30 | } 31 | 32 | public void setGroupName(String groupName) { 33 | this.groupName = groupName; 34 | } 35 | 36 | public String getIp() { 37 | return ip; 38 | } 39 | 40 | public void setIp(String ip) { 41 | this.ip = ip; 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/test/java/com/github/tobato/fastdfs/domain/proto/storage/AllTests.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.storage; 2 | 3 | import org.junit.runner.RunWith; 4 | import org.junit.runners.Suite; 5 | import org.junit.runners.Suite.SuiteClasses; 6 | 7 | @RunWith(Suite.class) 8 | @SuiteClasses({ StorageAppendFileCommandTest.class, StorageDeleteFileCommandTest.class, 9 | StorageQueryFileInfoCommandTest.class, StorageUploadFileCommandTest.class, 10 | StorageUploadSlaveFileCommandTest.class, StorageSetMetadataCommandTest.class, 11 | StorageDownloadCommandTest.class }) 12 | public class AllTests { 13 | // for test 14 | } 15 | -------------------------------------------------------------------------------- /src/test/java/com/github/tobato/fastdfs/domain/proto/storage/DownloadFileStreamTest.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.storage; 2 | 3 | import com.github.tobato.fastdfs.TestConstants; 4 | import org.apache.commons.io.IOUtils; 5 | import org.junit.Test; 6 | 7 | import java.io.ByteArrayInputStream; 8 | import java.io.ByteArrayOutputStream; 9 | import java.io.IOException; 10 | import java.io.InputStream; 11 | 12 | import static org.junit.Assert.assertEquals; 13 | 14 | /** 15 | * 文件缓存方式下载机制测试 16 | * 17 | * @author tobato 18 | */ 19 | public class DownloadFileStreamTest { 20 | 21 | @Test 22 | public void recv() throws IOException { 23 | 24 | String firstText = "加入文件缓存方式下载机制\r\n"; 25 | InputStream input = getTextInputStream(firstText); 26 | ByteArrayOutputStream output = new ByteArrayOutputStream(); 27 | //模拟输出,输出 28 | DownloadFileStream downloadFileStream = new DownloadFileStream(output); 29 | downloadFileStream.recv(input); 30 | String result = output.toString("UTF-8"); 31 | //比对结果 32 | assertEquals(firstText, result); 33 | //关闭输入,输出 34 | IOUtils.closeQuietly(input); 35 | IOUtils.closeQuietly(output); 36 | 37 | } 38 | 39 | private InputStream getTextInputStream(String text) throws IOException { 40 | // 将String转换为InputStream 41 | return new ByteArrayInputStream(text.getBytes(TestConstants.DEFAULT_CHARSET)); 42 | } 43 | } -------------------------------------------------------------------------------- /src/test/java/com/github/tobato/fastdfs/domain/proto/storage/StorageAppendFileCommandTest.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.storage; 2 | 3 | import com.github.tobato.fastdfs.domain.fdfs.StorePath; 4 | import com.github.tobato.fastdfs.domain.proto.StorageCommandTestBase; 5 | import org.junit.Test; 6 | 7 | import java.io.IOException; 8 | import java.io.InputStream; 9 | 10 | import static org.junit.Assert.assertNotNull; 11 | 12 | /** 13 | * 文件续传命令 14 | * 15 | * @author tobato 16 | */ 17 | public class StorageAppendFileCommandTest extends StorageCommandTestBase { 18 | 19 | /** 20 | * 文件续传需要先使用 append模式Save一个可以续传的文件 21 | * 然后才能使用续传命令续传文件 22 | * 23 | * @throws IOException 24 | */ 25 | @Test 26 | public void testStorageAppendFileCommand() throws IOException { 27 | String firstText = "Tobato is a good man.他是一个好人\r\n"; 28 | InputStream firstIn = getTextInputStream(firstText); 29 | long firstSize = firstIn.available(); 30 | // 先上载第一段文字 31 | StorePath path = uploadInputStream(firstIn, "txt", firstSize, true); 32 | // 添加第二段文字 33 | String secendText = "Work hard and hard. 努力工作啊\r\n"; 34 | InputStream secendIn = getTextInputStream(secendText); 35 | long secendSize = secendIn.available(); 36 | // 文件续传 37 | execStorageAppendFileCommand(secendIn, secendSize, path.getPath()); 38 | firstIn.close(); 39 | secendIn.close(); 40 | } 41 | 42 | 43 | /** 44 | * 文件续传操作 45 | * 46 | * @param in 47 | * @param fileSize 48 | * @param path 49 | */ 50 | public void execStorageAppendFileCommand(InputStream in, long fileSize, String path) { 51 | StorageAppendFileCommand command = new StorageAppendFileCommand(in, fileSize, path); 52 | executeStoreCmd(command); 53 | assertNotNull(path); 54 | LOGGER.debug("--文件续传操作结果-----"); 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/test/java/com/github/tobato/fastdfs/domain/proto/storage/StorageDeleteFileCommandTest.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.storage; 2 | 3 | import com.github.tobato.fastdfs.domain.fdfs.StorePath; 4 | import com.github.tobato.fastdfs.domain.proto.StorageCommandTestBase; 5 | import org.junit.Test; 6 | 7 | public class StorageDeleteFileCommandTest extends StorageCommandTestBase { 8 | 9 | /** 10 | * 文件删除测试 11 | */ 12 | @Test 13 | public void testStorageDeleteFileCommand() { 14 | 15 | // 上传文件 16 | StorePath path = uploadDefaultFile(); 17 | 18 | // 删除文件 19 | StorageDeleteFileCommand command = new StorageDeleteFileCommand(path.getGroup(), path.getPath()); 20 | executeStoreCmd(command); 21 | LOGGER.debug("----文件删除成功-----"); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/test/java/com/github/tobato/fastdfs/domain/proto/storage/StorageDownloadCommandTest.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.storage; 2 | 3 | import com.github.tobato.fastdfs.domain.fdfs.StorePath; 4 | import com.github.tobato.fastdfs.domain.proto.StorageCommandTestBase; 5 | import org.junit.Test; 6 | 7 | /** 8 | * 文件下载 9 | * 10 | * @author tobato 11 | */ 12 | public class StorageDownloadCommandTest extends StorageCommandTestBase { 13 | 14 | @Test 15 | public void testStorageDownloadCommand() { 16 | // 上传文件 17 | StorePath path = uploadDefaultFile(); 18 | DownloadFileWriter callback = new DownloadFileWriter("Test.jpg"); 19 | // 下载文件 20 | StorageDownloadCommand command = new StorageDownloadCommand (path.getGroup(), path.getPath(), 21 | callback); 22 | String fileName = executeStoreCmd(command); 23 | LOGGER.debug("----文件下载成功-----{}", fileName); 24 | } 25 | 26 | @Test 27 | public void testStorageSubDownloadCommand() { 28 | // 上传文件 29 | StorePath path = uploadDefaultFile(); 30 | DownloadFileWriter callback = new DownloadFileWriter("Test.jpg"); 31 | // 下载文件 32 | StorageDownloadCommand command = new StorageDownloadCommand ( 33 | path.getGroup(), 34 | path.getPath(), 35 | 2, 2, 36 | callback); 37 | String fileName = executeStoreCmd(command); 38 | LOGGER.debug("----文件下载成功-----{}", fileName); 39 | } 40 | 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/test/java/com/github/tobato/fastdfs/domain/proto/storage/StorageModifyCommandTest.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.storage; 2 | 3 | import com.github.tobato.fastdfs.domain.fdfs.StorePath; 4 | import com.github.tobato.fastdfs.domain.proto.StorageCommandTestBase; 5 | import org.junit.Test; 6 | 7 | import java.io.IOException; 8 | import java.io.InputStream; 9 | 10 | /** 11 | * 文件修改命令 12 | * 13 | * @author tobato 14 | */ 15 | public class StorageModifyCommandTest extends StorageCommandTestBase { 16 | 17 | @Test 18 | public void testStorageModifyCommand() throws IOException { 19 | String text = "Tobato is a good man. this is a test of StorageTruncateCommand."; 20 | InputStream firstIn = getTextInputStream(text); 21 | long firstSize = firstIn.available(); 22 | // 上载文字 23 | LOGGER.debug("文件大小={}", firstSize); 24 | StorePath path = uploadInputStream(firstIn, "txt", firstSize, true); 25 | // 文件修改 26 | String Modifytext = "This is a test of StorageModifyCommand"; 27 | InputStream modifyIn = getTextInputStream(Modifytext); 28 | long modifySize = modifyIn.available(); 29 | // 观察运行效果: 30 | // fileOffset参数0 结果为 This is a test of StorageModifyCommandf 31 | // StorageTruncateCommand 32 | // fileOffset参数为20 结果为 Tobato is a good manThis is a test of 33 | // StorageModifyCommandmand 34 | StorageModifyCommand command = new StorageModifyCommand(path.getPath(), modifyIn, modifySize, 0); 35 | executeStoreCmd(command); 36 | LOGGER.debug("--文件修改处理成功--"); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/test/java/com/github/tobato/fastdfs/domain/proto/storage/StorageQueryFileInfoCommandTest.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.storage; 2 | 3 | import com.github.tobato.fastdfs.domain.fdfs.FileInfo; 4 | import com.github.tobato.fastdfs.domain.fdfs.StorePath; 5 | import com.github.tobato.fastdfs.domain.proto.StorageCommandTestBase; 6 | import org.junit.Test; 7 | 8 | import static org.junit.Assert.assertNotNull; 9 | 10 | /** 11 | * 文件查询处理 12 | * 13 | * @author tobato 14 | */ 15 | public class StorageQueryFileInfoCommandTest extends StorageCommandTestBase { 16 | 17 | @Test 18 | public void testStorageQueryFileInfoCommand() { 19 | // 上传文件 20 | StorePath path = uploadDefaultFile(); 21 | 22 | // 查询文件 23 | StorageQueryFileInfoCommand command = new StorageQueryFileInfoCommand(path.getGroup(), path.getPath()); 24 | FileInfo fileInfo = executeStoreCmd(command); 25 | assertNotNull(fileInfo); 26 | LOGGER.debug("----文件查询处理结果-----"); 27 | LOGGER.debug(fileInfo.toString()); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/test/java/com/github/tobato/fastdfs/domain/proto/storage/StorageTruncateCommandTest.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.storage; 2 | 3 | import com.github.tobato.fastdfs.domain.fdfs.StorePath; 4 | import com.github.tobato.fastdfs.domain.proto.StorageCommandTestBase; 5 | import org.junit.Test; 6 | 7 | import java.io.IOException; 8 | import java.io.InputStream; 9 | 10 | /** 11 | * 文件截取命令 12 | * 13 | * @author tobato 14 | */ 15 | public class StorageTruncateCommandTest extends StorageCommandTestBase { 16 | 17 | @Test 18 | public void testStorageTruncateCommandText() throws IOException { 19 | String text = "Tobato is a good man. this is a test of StorageTruncateCommand"; 20 | InputStream firstIn = getTextInputStream(text); 21 | long firstSize = firstIn.available(); 22 | // 上载文字 23 | LOGGER.debug("文件大小={}", firstSize); 24 | StorePath path = uploadInputStream(firstIn, "txt", firstSize, true); 25 | // 文件截取 26 | StorageTruncateCommand command = new StorageTruncateCommand(path.getPath(), 0); 27 | executeStoreCmd(command); 28 | LOGGER.debug("--文件截取处理成功--"); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/test/java/com/github/tobato/fastdfs/domain/proto/storage/StorageUploadFileCommandTest.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.storage; 2 | 3 | import org.junit.Test; 4 | 5 | import com.github.tobato.fastdfs.TestConstants; 6 | import com.github.tobato.fastdfs.domain.proto.StorageCommandTestBase; 7 | 8 | /** 9 | * 文件上传命令测试 10 | * 11 | * @author tobato 12 | * 13 | */ 14 | public class StorageUploadFileCommandTest extends StorageCommandTestBase { 15 | 16 | /** 17 | * 文件上传测试 18 | */ 19 | @Test 20 | public void testStorageUploadFileCommand() { 21 | // 非append模式 22 | execStorageUploadFileCommand(TestConstants.CAT_IMAGE_FILE, false); 23 | } 24 | 25 | @Test 26 | public void testStorageUploadFileCommandByAppend() { 27 | // append模式 28 | execStorageUploadFileCommand(TestConstants.CAT_IMAGE_FILE, true); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/test/java/com/github/tobato/fastdfs/domain/proto/storage/StorageUploadSlaveFileCommandTest.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.storage; 2 | 3 | import com.github.tobato.fastdfs.TestConstants; 4 | import com.github.tobato.fastdfs.TestUtils; 5 | import com.github.tobato.fastdfs.domain.fdfs.StorePath; 6 | import com.github.tobato.fastdfs.domain.proto.StorageCommandTestBase; 7 | import net.coobird.thumbnailator.Thumbnails; 8 | import org.apache.commons.io.FilenameUtils; 9 | import org.junit.Test; 10 | 11 | import java.io.*; 12 | 13 | import static org.junit.Assert.assertNotNull; 14 | 15 | /** 16 | * 文件上传命令测试 17 | * 18 | * @author tobato 19 | */ 20 | public class StorageUploadSlaveFileCommandTest extends StorageCommandTestBase { 21 | 22 | /** 23 | * 文件上传测试 24 | */ 25 | @Test 26 | public void testStorageSlaveUploadFileCommand() { 27 | // 上传主文件 28 | StorePath path = execStorageUploadFileCommand(TestConstants.CAT_IMAGE_FILE, false); 29 | 30 | String masterFilename = path.getPath(); 31 | String prefixName = "_120x120"; 32 | // 生成从文件 33 | execStorageUploadSlaveFileCommand(TestConstants.CAT_IMAGE_FILE, masterFilename, prefixName); 34 | } 35 | 36 | /** 37 | * 从文件上传操作 38 | * 39 | * @param isAppenderFile 40 | */ 41 | public StorePath execStorageUploadSlaveFileCommand(String filePath, String masterFilename, String prefixName) { 42 | 43 | InputStream in = null; 44 | File file = TestUtils.getFile(filePath); 45 | String fileExtName = FilenameUtils.getExtension(file.getName()); 46 | 47 | try { 48 | in = getThumbImageStream(filePath);// getFileInputStream 49 | // getThumbImageStream(filePath); 50 | long fileSize = in.available(); 51 | StorageUploadSlaveFileCommand command = new StorageUploadSlaveFileCommand(in, fileSize, masterFilename, 52 | prefixName, fileExtName); 53 | StorePath path = executeStoreCmd(command); 54 | assertNotNull(path); 55 | LOGGER.debug("--从文件上传处理结果-----"); 56 | LOGGER.debug(path.toString()); 57 | return path; 58 | } catch (IOException e) { 59 | e.printStackTrace(); 60 | } finally { 61 | if (null != in) { 62 | try { 63 | in.close(); 64 | } catch (IOException e) { 65 | e.printStackTrace(); 66 | } 67 | } 68 | } 69 | return null; 70 | } 71 | 72 | /** 73 | * 获取缩略图 74 | * 75 | * @param filePath 76 | * @return 77 | * @throws IOException 78 | */ 79 | private InputStream getThumbImageStream(String filePath) throws IOException { 80 | // 在内存当中生成缩略图 81 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 82 | Thumbnails.of(TestUtils.getFile(filePath)).size(120, 120).toOutputStream(out); 83 | return new ByteArrayInputStream(out.toByteArray()); 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /src/test/java/com/github/tobato/fastdfs/domain/proto/storage/monkey/MonkeyDownloadFileWriter.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.storage.monkey; 2 | 3 | import com.github.tobato.fastdfs.domain.proto.storage.DownloadCallback; 4 | import com.github.tobato.fastdfs.exception.FdfsIOException; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | import java.io.IOException; 9 | import java.io.InputStream; 10 | 11 | /** 12 | * 抛出例外的文件下载回调方法 13 | * 14 | * @author tobato 15 | */ 16 | public class MonkeyDownloadFileWriter implements DownloadCallback { 17 | 18 | /** 19 | * 日志 20 | */ 21 | protected static Logger LOGGER = LoggerFactory.getLogger(MonkeyDownloadFileWriter.class); 22 | 23 | /** 24 | * 文件名称 25 | */ 26 | private String fileName; 27 | 28 | public MonkeyDownloadFileWriter(String fileName) { 29 | this.fileName = fileName; 30 | } 31 | 32 | /** 33 | * 文件接收处理 34 | */ 35 | @Override 36 | public String recv(InputStream ins) throws IOException { 37 | byte[] buffer = new byte[2]; 38 | ins.read(buffer); 39 | throw new FdfsIOException("模拟读取文件错误错误"); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/test/java/com/github/tobato/fastdfs/domain/proto/storage/monkey/StorageMonkeyDownloadTest.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.storage.monkey; 2 | 3 | import com.github.tobato.fastdfs.domain.fdfs.StorePath; 4 | import com.github.tobato.fastdfs.domain.proto.StorageCommandTestBase; 5 | import com.github.tobato.fastdfs.domain.proto.storage.DownloadFileWriter; 6 | import com.github.tobato.fastdfs.domain.proto.storage.StorageDownloadCommand; 7 | import org.junit.Test; 8 | 9 | /** 10 | * 文件下载 11 | * 12 | * @author tobato 13 | */ 14 | public class StorageMonkeyDownloadTest extends StorageCommandTestBase { 15 | 16 | /** 17 | * 问题#121当发生异常时,怎么把链接中对应的流数据一次性清空 18 | */ 19 | @Test 20 | public void testStorageDownloadCommand() { 21 | // 上传文件 22 | StorePath path = uploadDefaultFile(); 23 | MonkeyDownloadFileWriter callback = new MonkeyDownloadFileWriter("Test.jpg"); 24 | // 下载文件 25 | StorageDownloadCommand commandErr = new StorageDownloadCommand (path.getGroup(), path.getPath(), 26 | callback); 27 | 28 | //下载文件错误 29 | LOGGER.debug("======下载文件时候发生错误========"); 30 | try { 31 | executeStoreCmd(commandErr); 32 | } catch (Exception e) { 33 | //ignore 34 | } 35 | //--导出pool 36 | dumpPool(); 37 | LOGGER.debug("======再次下载文件========"); 38 | 39 | DownloadFileWriter callbackB = new DownloadFileWriter("Test.jpg"); 40 | //再次正常下载 41 | StorageDownloadCommand command = new StorageDownloadCommand (path.getGroup(), path.getPath(), 42 | callbackB); 43 | 44 | String file = executeStoreCmd(command); 45 | dumpPool(); 46 | 47 | LOGGER.debug("----文件下载成功-----{}", file); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/test/java/com/github/tobato/fastdfs/domain/proto/tracker/AllTests.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.tracker; 2 | 3 | import org.junit.runner.RunWith; 4 | import org.junit.runners.Suite; 5 | import org.junit.runners.Suite.SuiteClasses; 6 | 7 | @RunWith(Suite.class) 8 | @SuiteClasses({ TrackerGetFetchStorageCommandTest.class, TrackerGetStoreStorageCommandTest.class, 9 | TrackerListGroupsCommandTest.class, TrackerListGroupsRequestTest.class, TrackerListStoragesCommandTest.class }) 10 | public class AllTests { 11 | // for test 12 | } 13 | -------------------------------------------------------------------------------- /src/test/java/com/github/tobato/fastdfs/domain/proto/tracker/TrackerDeleteStorageCommandTest.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.tracker; 2 | 3 | import com.github.tobato.fastdfs.domain.fdfs.StorageNode; 4 | import com.github.tobato.fastdfs.domain.proto.ErrorCodeConstants; 5 | import com.github.tobato.fastdfs.domain.proto.StorageCommandTestBase; 6 | import com.github.tobato.fastdfs.exception.FdfsServerException; 7 | import org.junit.Test; 8 | 9 | import static org.junit.Assert.assertTrue; 10 | import static org.junit.Assert.fail; 11 | 12 | /** 13 | * 删除存储服务器 14 | * 15 | * @author tobato 16 | */ 17 | public class TrackerDeleteStorageCommandTest extends StorageCommandTestBase { 18 | 19 | /** 20 | * 删除存储服务器 21 | */ 22 | @Test 23 | public void testTrackerDeleteStorageCommand() { 24 | 25 | // 获取存储节点信息 26 | StorageNode client = getOneStorage(); 27 | 28 | // 获取源服务器 29 | TrackerDeleteStorageCommand command = new TrackerDeleteStorageCommand(client.getGroupName(), client.getIp()); 30 | try { 31 | executeTrackerCmd(command); 32 | fail("No exception thrown."); 33 | } catch (Exception e) { 34 | assertTrue(e instanceof FdfsServerException); 35 | assertTrue(((FdfsServerException) e).getErrorCode() == ErrorCodeConstants.ERR_NO_EBUSY); 36 | } 37 | LOGGER.debug("----删除存储服务器-----"); 38 | } 39 | 40 | public StorageNode getOneStorage() { 41 | StorageNode client = executeTrackerCmd(new TrackerGetStoreStorageCommand("group1")); 42 | LOGGER.debug("-----列举存储服务器状态处理结果-----"); 43 | LOGGER.debug(client.toString()); 44 | return client; 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/test/java/com/github/tobato/fastdfs/domain/proto/tracker/TrackerGetFetchStorageCommandTest.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.tracker; 2 | 3 | import com.github.tobato.fastdfs.domain.fdfs.StorageNodeInfo; 4 | import com.github.tobato.fastdfs.domain.fdfs.StorePath; 5 | import com.github.tobato.fastdfs.domain.proto.StorageCommandTestBase; 6 | import org.junit.Test; 7 | 8 | /** 9 | * 获取源服务器 10 | * 11 | * @author tobato 12 | */ 13 | public class TrackerGetFetchStorageCommandTest extends StorageCommandTestBase { 14 | 15 | /** 16 | * 获取源服务器 17 | */ 18 | @Test 19 | public void testTrackerGetFetchStorageCommand() { 20 | 21 | // 上传文件 22 | StorePath path = uploadDefaultFile(); 23 | 24 | // 获取源服务器 25 | TrackerGetFetchStorageCommand command = new TrackerGetFetchStorageCommand(path.getGroup(), path.getPath(), 26 | false); 27 | StorageNodeInfo client = executeTrackerCmd(command); 28 | LOGGER.debug("----获取源服务器-----"); 29 | LOGGER.debug(client.toString()); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/test/java/com/github/tobato/fastdfs/domain/proto/tracker/TrackerGetStoreStorageCommandTest.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.tracker; 2 | 3 | import com.github.tobato.fastdfs.domain.fdfs.StorageNode; 4 | import com.github.tobato.fastdfs.domain.proto.CommandTestBase; 5 | import org.junit.Test; 6 | 7 | import static org.junit.Assert.assertNotNull; 8 | 9 | /** 10 | * 获取存储节点交易 11 | * 12 | * @author tobato 13 | */ 14 | public class TrackerGetStoreStorageCommandTest extends CommandTestBase { 15 | 16 | @Test 17 | public void testTrackerGetStoreStorageCommand() { 18 | StorageNode client = executeTrackerCmd(new TrackerGetStoreStorageCommand()); 19 | assertNotNull(client.getInetSocketAddress()); 20 | LOGGER.debug("-----获取存储节点交易处理结果-----{}"); 21 | LOGGER.debug(client.toString()); 22 | 23 | // Connection conn = new 24 | // DefaultConnection(client.getInetSocketAddress(), 500, 300, null); 25 | // LOGGER.debug("连接状态{}", conn.isValid()); 26 | // conn.close(); 27 | } 28 | 29 | @Test 30 | public void testTrackerGetStoreStorageWithGroupCommand() { 31 | StorageNode client = executeTrackerCmd(new TrackerGetStoreStorageCommand("group1")); 32 | assertNotNull(client.getInetSocketAddress()); 33 | LOGGER.debug("-----按组获取存储节点交易处理结果-----"); 34 | LOGGER.debug(client.toString()); 35 | 36 | // Connection conn = new 37 | // DefaultConnection(client.getInetSocketAddress(), 500, 300, null); 38 | // LOGGER.debug("连接状态{}", conn.isValid()); 39 | // conn.close(); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/test/java/com/github/tobato/fastdfs/domain/proto/tracker/TrackerListGroupsCommandTest.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.tracker; 2 | 3 | import com.github.tobato.fastdfs.domain.fdfs.GroupState; 4 | import com.github.tobato.fastdfs.domain.proto.CommandTestBase; 5 | import org.junit.Test; 6 | 7 | import java.util.List; 8 | 9 | import static org.junit.Assert.assertTrue; 10 | 11 | /** 12 | * 列举存储目录分组情况 13 | * 14 | * @author tobato 15 | */ 16 | public class TrackerListGroupsCommandTest extends CommandTestBase { 17 | 18 | @Test 19 | public void test() { 20 | List list = executeTrackerCmd(new TrackerListGroupsCommand()); 21 | assertTrue(list.size() > 0); 22 | LOGGER.debug("-----列举存储服务器分组状态处理结果-----"); 23 | LOGGER.debug(list.toString()); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/test/java/com/github/tobato/fastdfs/domain/proto/tracker/TrackerListGroupsRequestTest.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.tracker; 2 | 3 | import org.junit.Test; 4 | 5 | import com.github.tobato.fastdfs.TestConstants; 6 | import com.github.tobato.fastdfs.domain.proto.tracker.internal.TrackerListGroupsRequest; 7 | 8 | /** 9 | * 列举Groups请求 10 | * 11 | * @author tobato 12 | * 13 | */ 14 | public class TrackerListGroupsRequestTest { 15 | 16 | @Test 17 | public void testGetByteContent() { 18 | TrackerListGroupsRequest request = new TrackerListGroupsRequest(); 19 | printRequest(request.getHeadByte(TestConstants.DEFAULT_CHARSET)); 20 | } 21 | 22 | private void printRequest(byte[] request) { 23 | for (int i = 0; i < request.length; i++) { 24 | System.out.print(request[i]); 25 | System.out.print(" "); 26 | } 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/test/java/com/github/tobato/fastdfs/domain/proto/tracker/TrackerListStoragesCommandTest.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.proto.tracker; 2 | 3 | import com.github.tobato.fastdfs.TestConstants; 4 | import com.github.tobato.fastdfs.domain.fdfs.StorageState; 5 | import com.github.tobato.fastdfs.domain.proto.CommandTestBase; 6 | import org.junit.Test; 7 | 8 | import java.util.List; 9 | 10 | import static org.junit.Assert.assertTrue; 11 | 12 | /** 13 | * 列举存储目录服务器状态 14 | * 15 | * @author tobato 16 | */ 17 | public class TrackerListStoragesCommandTest extends CommandTestBase { 18 | 19 | @Test 20 | public void testGroupAndIp() { 21 | List list = executeTrackerCmd( 22 | new TrackerListStoragesCommand("group1", TestConstants.store_address.getHostString())); 23 | assertTrue(list.size() > 0); 24 | LOGGER.debug("-----根据IP列举存储服务器状态处理结果-----"); 25 | LOGGER.debug(list.toString()); 26 | } 27 | 28 | @Test 29 | public void testGroup() { 30 | List list = executeTrackerCmd(new TrackerListStoragesCommand("group1")); 31 | assertTrue(list.size() > 0); 32 | LOGGER.debug("-----列举存储服务器状态处理结果-----"); 33 | LOGGER.debug(list.toString()); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/test/java/com/github/tobato/fastdfs/domain/upload/FastFileTest.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.domain.upload; 2 | 3 | import com.github.tobato.fastdfs.domain.RandomTextFile; 4 | import com.github.tobato.fastdfs.domain.fdfs.MetaData; 5 | import org.junit.Test; 6 | 7 | import java.util.Collections; 8 | import java.util.HashSet; 9 | 10 | import static junit.framework.TestCase.*; 11 | 12 | /** 13 | * FastFile单元测试 14 | */ 15 | public class FastFileTest { 16 | 17 | 18 | /** 19 | * 元数据不能为空 20 | * 21 | * @throws Exception 22 | */ 23 | @Test(expected = NullPointerException.class) 24 | public void testBuildMateDataNull() throws Exception { 25 | RandomTextFile file = new RandomTextFile(); 26 | FastFile fastFile = new FastFile.Builder() 27 | .withFile(file.getInputStream(), file.getFileSize(), file.getFileExtName()) 28 | .withMetaData(null) 29 | .build(); 30 | } 31 | 32 | /** 33 | * 元数据不能为空 34 | * 35 | * @throws Exception 36 | */ 37 | @Test 38 | public void testBuildMateDataNotSet() throws Exception { 39 | RandomTextFile file = new RandomTextFile(); 40 | FastFile fastFile = new FastFile(file.getInputStream(), 41 | file.getFileSize(), 42 | file.getFileExtName(), 43 | null); 44 | assertNotNull(fastFile.getFileExtName()); 45 | 46 | assertEquals(fastFile.getMetaDataSet(), Collections.EMPTY_SET); 47 | } 48 | 49 | /** 50 | * 元数据可以不存在 51 | * 52 | * @throws Exception 53 | */ 54 | @Test 55 | public void testBuildMateDataEmpty() throws Exception { 56 | RandomTextFile file = new RandomTextFile(); 57 | FastFile fastFile = new FastFile.Builder() 58 | .withFile(file.getInputStream(), file.getFileSize(), file.getFileExtName()) 59 | .withMetaData(new HashSet ()) 60 | .build(); 61 | assertTrue(fastFile.getMetaDataSet().isEmpty()); 62 | } 63 | 64 | /** 65 | * 元数据可指定 66 | * 67 | * @throws Exception 68 | */ 69 | @Test 70 | public void testBuildMateDataWithString() throws Exception { 71 | RandomTextFile file = new RandomTextFile(); 72 | FastFile fastFile = new FastFile.Builder() 73 | .withFile(file.getInputStream(), file.getFileSize(), file.getFileExtName()) 74 | .withMetaData("hello", "world") 75 | .build(); 76 | assertTrue(fastFile.getMetaDataSet().contains(new MetaData("hello", "world"))); 77 | } 78 | 79 | } -------------------------------------------------------------------------------- /src/test/java/com/github/tobato/fastdfs/service/StorageClientMetadataTest.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.service; 2 | 3 | import com.github.tobato.fastdfs.TestConstants; 4 | import com.github.tobato.fastdfs.domain.RandomTextFile; 5 | import com.github.tobato.fastdfs.domain.fdfs.MetaData; 6 | import com.github.tobato.fastdfs.domain.fdfs.StorePath; 7 | import com.github.tobato.fastdfs.domain.proto.ErrorCodeConstants; 8 | import com.github.tobato.fastdfs.exception.FdfsServerException; 9 | import org.junit.Test; 10 | 11 | import java.util.HashSet; 12 | import java.util.Set; 13 | 14 | import static org.junit.Assert.*; 15 | 16 | /** 17 | * Metadata操作演示 18 | * 19 | * @author tobato 20 | */ 21 | public class StorageClientMetadataTest extends StorageClientTestBase { 22 | 23 | @Test 24 | public void testMetadataOperator() { 25 | LOGGER.debug("##上传文件..##"); 26 | RandomTextFile file = new RandomTextFile(); 27 | StorePath path = storageClient.uploadFile(TestConstants.DEFAULT_GROUP, file.getInputStream(), 28 | file.getFileSize(), file.getFileExtName()); 29 | assertNotNull(path); 30 | LOGGER.debug("上传文件 result={}", path); 31 | 32 | LOGGER.debug("##生成Metadata##"); 33 | Set firstMetaData = new HashSet (); 34 | firstMetaData.add(new MetaData("Author", "wyf")); 35 | firstMetaData.add(new MetaData("CreateDate", "2016-01-05")); 36 | storageClient.overwriteMetadata(path.getGroup(), path.getPath(), firstMetaData); 37 | 38 | LOGGER.debug("##获取Metadata##"); 39 | Set fetchMetaData = storageClient.getMetadata(path.getGroup(), path.getPath()); 40 | assertEquals(fetchMetaData, firstMetaData); 41 | 42 | LOGGER.debug("##合并Metadata##"); 43 | Set secendMetaData = new HashSet (); 44 | secendMetaData.add(new MetaData("Author", "tobato")); 45 | secendMetaData.add(new MetaData("CreateDate", "2016-01-05")); 46 | storageClient.mergeMetadata(path.getGroup(), path.getPath(), secendMetaData); 47 | 48 | LOGGER.debug("##第二次获取Metadata##"); 49 | fetchMetaData = storageClient.getMetadata(path.getGroup(), path.getPath()); 50 | assertEquals(fetchMetaData, secendMetaData); 51 | 52 | LOGGER.debug("##删除主文件..##"); 53 | storageClient.deleteFile(path.getGroup(), path.getPath()); 54 | 55 | LOGGER.debug("##第三次获取Metadata##"); 56 | try { 57 | fetchMetaData = storageClient.getMetadata(path.getGroup(), path.getPath()); 58 | fail("No exception thrown."); 59 | } catch (Exception e) { 60 | assertTrue(e instanceof FdfsServerException); 61 | assertTrue(((FdfsServerException) e).getErrorCode() == ErrorCodeConstants.ERR_NO_ENOENT); 62 | } 63 | LOGGER.debug("文件删除以后Metadata会自动删除,第三次就获取不到了"); 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/test/java/com/github/tobato/fastdfs/service/StorageClientTestBase.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.service; 2 | 3 | import com.github.tobato.fastdfs.FastdfsTestApplication; 4 | import org.junit.runner.RunWith; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.boot.test.context.SpringBootTest; 9 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 10 | 11 | /** 12 | * StorageClient测试基类 13 | * 14 | * @author tobato 15 | * 16 | */ 17 | @RunWith(SpringJUnit4ClassRunner.class) 18 | @SpringBootTest(classes = FastdfsTestApplication.class) 19 | public class StorageClientTestBase { 20 | 21 | @Autowired 22 | protected AppendFileStorageClient storageClient; 23 | 24 | /** 日志 */ 25 | protected static Logger LOGGER = LoggerFactory.getLogger(StorageClientTestBase.class); 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/test/java/com/github/tobato/fastdfs/service/ThumbImageTest.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.service; 2 | 3 | import com.github.tobato.fastdfs.TestConstants; 4 | import com.github.tobato.fastdfs.TestUtils; 5 | import net.coobird.thumbnailator.Thumbnails; 6 | import org.apache.commons.io.IOUtils; 7 | import org.junit.Test; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | 11 | import java.awt.image.BufferedImage; 12 | import java.io.*; 13 | 14 | /** 15 | * 缩略图算法测试 16 | * 17 | * @author tobato 18 | */ 19 | public class ThumbImageTest { 20 | 21 | /** 22 | * 日志 23 | */ 24 | protected Logger logger = LoggerFactory.getLogger(this.getClass()); 25 | 26 | 27 | /** 28 | * PNG生成缩略图背景为黑色问题 29 | * 30 | * @throws IOException 31 | */ 32 | @Test 33 | public void testImage() throws IOException { 34 | InputStream in = TestUtils.getFileInputStream(TestConstants.FLY_IMAGE_FILE); 35 | File file = new File("test.png"); 36 | OutputStream out = new FileOutputStream(file); 37 | Thumbnails 38 | .of(in) 39 | .size(200, 200) 40 | .imageType(BufferedImage.TYPE_INT_ARGB) //不加入这句就是黑色 41 | .toOutputStream(out); 42 | IOUtils.closeQuietly(in); 43 | IOUtils.closeQuietly(out); 44 | } 45 | 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/test/java/com/github/tobato/fastdfs/service/TrackerClientTest.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.service; 2 | 3 | import com.github.tobato.fastdfs.FastdfsTestApplication; 4 | import com.github.tobato.fastdfs.TestConstants; 5 | import com.github.tobato.fastdfs.domain.fdfs.GroupState; 6 | import com.github.tobato.fastdfs.domain.fdfs.StorageNode; 7 | import com.github.tobato.fastdfs.domain.fdfs.StorageState; 8 | import com.github.tobato.fastdfs.domain.proto.ErrorCodeConstants; 9 | import com.github.tobato.fastdfs.exception.FdfsServerException; 10 | import org.junit.Test; 11 | import org.junit.runner.RunWith; 12 | import org.slf4j.Logger; 13 | import org.slf4j.LoggerFactory; 14 | import org.springframework.beans.factory.annotation.Autowired; 15 | import org.springframework.boot.test.context.SpringBootTest; 16 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 17 | 18 | import java.util.List; 19 | 20 | import static org.junit.Assert.*; 21 | 22 | /** 23 | * unit test for TrackerClientService 24 | * 25 | * @author tobato 26 | */ 27 | @RunWith(SpringJUnit4ClassRunner.class) 28 | @SpringBootTest(classes = FastdfsTestApplication.class) 29 | public class TrackerClientTest { 30 | 31 | /** 32 | * 日志 33 | */ 34 | private static Logger LOGGER = LoggerFactory.getLogger(TrackerClientTest.class); 35 | 36 | @Autowired 37 | private TrackerClient trackerClient; 38 | 39 | @Test 40 | public void testGetStoreStorage() { 41 | LOGGER.debug("testGetStoreStorage.."); 42 | StorageNode client = trackerClient.getStoreStorage(); 43 | assertNotNull(client.getInetSocketAddress()); 44 | LOGGER.debug("result={}", client); 45 | 46 | } 47 | 48 | @Test 49 | public void testGetStoreStorageByGroup() { 50 | LOGGER.debug("testGetStoreStorageByGroup.."); 51 | StorageNode client = trackerClient.getStoreStorage(TestConstants.DEFAULT_GROUP); 52 | assertNotNull(client.getInetSocketAddress()); 53 | LOGGER.debug("result={}", client); 54 | } 55 | 56 | @Test 57 | public void testListGroups() { 58 | LOGGER.debug("testListGroups.."); 59 | List list = trackerClient.listGroups(); 60 | assertNotNull(list); 61 | LOGGER.debug("result={}", list); 62 | } 63 | 64 | @Test 65 | public void testListStoragesByGroup() { 66 | LOGGER.debug("testListStoragesByGroup.."); 67 | List list = trackerClient.listStorages(TestConstants.DEFAULT_GROUP); 68 | assertNotNull(list); 69 | LOGGER.debug("result={}", list); 70 | } 71 | 72 | @Test 73 | public void testListStoragesByGroupAndIp() { 74 | LOGGER.debug("testListStoragesByGroupAndIp.."); 75 | List list = trackerClient.listStorages(TestConstants.DEFAULT_GROUP, 76 | TestConstants.DEFAULT_STORAGE_IP); 77 | assertNotNull(list); 78 | LOGGER.debug("result={}", list); 79 | } 80 | 81 | @Test 82 | public void testDeleteStorage() { 83 | LOGGER.debug("testDeleteStorage.."); 84 | try { 85 | trackerClient.deleteStorage(TestConstants.DEFAULT_GROUP, 86 | TestConstants.DEFAULT_STORAGE_IP); 87 | fail("No exception thrown."); 88 | } catch (Exception e) { 89 | assertTrue(e instanceof FdfsServerException); 90 | assertTrue(((FdfsServerException) e).getErrorCode() == ErrorCodeConstants.ERR_NO_EBUSY); 91 | } 92 | LOGGER.debug("testDeleteStorage..done"); 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /src/test/java/com/github/tobato/fastdfs/socket/FdfsMockHandler.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.socket; 2 | 3 | import org.apache.commons.io.IOUtils; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import java.io.DataInputStream; 8 | import java.net.Socket; 9 | 10 | /** 11 | * 模拟socket处理类 12 | * 13 | * @author tobato 14 | */ 15 | public class FdfsMockHandler extends Thread { 16 | 17 | /** 18 | * 日志 19 | */ 20 | private static final Logger LOGGER = LoggerFactory.getLogger(FdfsMockHandler.class); 21 | 22 | private Socket client; 23 | 24 | DataInputStream in = null; 25 | 26 | private boolean stop = false; 27 | 28 | public FdfsMockHandler(Socket client) { 29 | this.client = client; 30 | } 31 | 32 | public void run() { 33 | 34 | try { 35 | while (!stop && client.isConnected()) { 36 | if (in == null) { 37 | in = new DataInputStream(client.getInputStream()); 38 | } 39 | // java客户端与服务端C使用数据流的方式进行通讯 40 | byte[] b = new byte[in.available()]; 41 | for (int i = 0; i < b.length; i++) { 42 | b[i] = (byte) in.read(); 43 | } 44 | if (b.length > 0) { 45 | // String s = new String(b); 46 | LOGGER.debug("[MockHandler]接收到请求数据 data={}", b); 47 | } 48 | 49 | } 50 | 51 | } catch (Exception e) { 52 | e.printStackTrace(); 53 | } 54 | } 55 | 56 | public void stopHandler() { 57 | stop = true; 58 | IOUtils.closeQuietly(in); 59 | IOUtils.closeQuietly(client); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/test/java/com/github/tobato/fastdfs/socket/FdfsMockSocketServer.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.fastdfs.socket; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | import java.io.IOException; 7 | import java.net.ServerSocket; 8 | import java.net.Socket; 9 | import java.util.HashMap; 10 | import java.util.Map; 11 | 12 | /** 13 | * 模拟测试服务 14 | * 15 | * @author tobato 16 | */ 17 | public class FdfsMockSocketServer extends Thread { 18 | 19 | /** 20 | * 日志 21 | */ 22 | private static final Logger LOGGER = LoggerFactory.getLogger(FdfsMockSocketServer.class); 23 | 24 | public final static int PORT = 20001;//22122 25 | private ServerSocket serverSocket; 26 | private boolean stop = false; 27 | private int index = 0; 28 | private Map pool = new HashMap (); 29 | 30 | public void stopServer() { 31 | LOGGER.debug("[MockServer]Stop FdfsMockSocketServer.."); 32 | for (FdfsMockHandler handler : pool.values()) { 33 | handler.stopHandler(); 34 | } 35 | stop = true; 36 | } 37 | 38 | @Override 39 | public void run() { 40 | try { 41 | serverSocket = new ServerSocket(PORT); 42 | LOGGER.debug("[MockServer]start mock server for test..{}", serverSocket); 43 | } catch (IOException e1) { 44 | e1.printStackTrace(); 45 | } 46 | 47 | while (!stop) { 48 | Socket socket = null; 49 | try { 50 | index++; 51 | socket = serverSocket.accept(); // 主线程获取客户端连接 52 | LOGGER.debug("[MockServer]第" + index + "个客户端成功连接!"); 53 | FdfsMockHandler handler = new FdfsMockHandler(socket); 54 | pool.put("第" + index + "个", handler); 55 | handler.start(); // 启动线程 56 | } catch (Exception e) { 57 | e.printStackTrace(); 58 | } 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/test/java/com/github/tobato/soket/client/ClientDemo.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.soket.client; 2 | 3 | import java.io.DataInputStream; 4 | import java.io.DataOutputStream; 5 | import java.io.IOException; 6 | import java.io.InputStream; 7 | import java.io.OutputStream; 8 | import java.net.Socket; 9 | import java.net.UnknownHostException; 10 | 11 | public class ClientDemo { 12 | 13 | public static void main(String[] args) throws UnknownHostException, IOException { 14 | 15 | Socket s = new Socket("192.168.99.100", 22122); 16 | 17 | OutputStream out = s.getOutputStream(); 18 | 19 | DataOutputStream dout = new DataOutputStream(out); 20 | 21 | // dout.writeUTF("oftenlin"); 22 | 23 | InputStream in = s.getInputStream(); 24 | DataInputStream din = new DataInputStream(in); 25 | 26 | String st = din.readUTF(); 27 | 28 | in.close(); 29 | out.close(); 30 | s.close(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/test/java/com/github/tobato/soket/server/Handler.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.soket.server; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | import java.io.*; 7 | import java.net.Socket; 8 | 9 | public class Handler implements Runnable { 10 | /** 11 | * 日志 12 | */ 13 | private final Logger LOGGER = LoggerFactory.getLogger(Handler.class); 14 | 15 | private Socket socket; 16 | 17 | public Handler(Socket socket) { 18 | this.socket = socket; 19 | } 20 | 21 | public void run() { 22 | try { 23 | LOGGER.debug("新连接={}:{}", socket.getInetAddress(), socket.getPort()); 24 | // Thread.sleep(10000); 25 | InputStream in = socket.getInputStream(); 26 | DataInputStream din = new DataInputStream(in); 27 | String name = din.readUTF(); 28 | OutputStream out = socket.getOutputStream(); 29 | DataOutputStream dos = new DataOutputStream(out); 30 | dos.writeUTF(socket + "your name :" + name); 31 | in.close(); 32 | out.close(); 33 | } catch (Exception e) { 34 | e.printStackTrace(); 35 | } finally { 36 | try { 37 | LOGGER.debug("关闭连接={}:{}", socket.getInetAddress(), socket.getPort()); 38 | if (socket != null) 39 | socket.close(); 40 | } catch (IOException e) { 41 | e.printStackTrace(); 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/test/java/com/github/tobato/soket/server/SoketServer.java: -------------------------------------------------------------------------------- 1 | package com.github.tobato.soket.server; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | import java.io.IOException; 7 | import java.net.BindException; 8 | import java.net.ServerSocket; 9 | import java.net.Socket; 10 | 11 | public class SoketServer { 12 | 13 | /** 14 | * 日志 15 | */ 16 | private final static Logger LOGGER = LoggerFactory.getLogger(SoketServer.class); 17 | 18 | private int port = 22122; 19 | private ServerSocket serverSocket; 20 | 21 | public void service() { 22 | int i = 0; 23 | try { 24 | serverSocket = new ServerSocket(port); 25 | } catch (BindException e) { 26 | LOGGER.error("端口绑定错误", e.getCause()); 27 | throw new RuntimeException("端口已经被绑定"); 28 | } catch (IOException e1) { 29 | LOGGER.error("其他错误", e1.getCause()); 30 | throw new RuntimeException(e1.getMessage()); 31 | } 32 | 33 | while (true) { 34 | Socket socket = null; 35 | try { 36 | i++; 37 | socket = serverSocket.accept(); // 主线程获取客户端连接 38 | LOGGER.debug("第{}个客户端成功连接!", i); 39 | Thread workThread = new Thread(new Handler(socket)); // 创建线程 40 | workThread.start(); // 启动线程 41 | } catch (Exception e) { 42 | e.printStackTrace(); 43 | } 44 | } 45 | } 46 | 47 | public static void main(String[] agrs) { 48 | LOGGER.debug("正在启动服务.."); 49 | SoketServer server = new SoketServer(); 50 | LOGGER.debug("服务已经启动完成"); 51 | server.service(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/test/resources/application.yml: -------------------------------------------------------------------------------- 1 | # =================================================================== 2 | # 分布式文件系统FDFS配置 3 | # =================================================================== 4 | fdfs: 5 | so-timeout: 1501 6 | connect-timeout: 1601 7 | thumb-image: 8 | width: 150 9 | height: 150 10 | tracker-list: 11 | - 172.17.0.2:22122 12 | # - 185.25.103.20:22122 13 | # - 192.168.174.42:22122 14 | # - 192.168.174.48:22122 15 | 16 | 17 | 18 | --- 19 | spring: 20 | profiles: customized_pool 21 | fdfs: 22 | so-timeout: 1501 23 | connect-timeout: 601 24 | thumb-image: 25 | width: 150 26 | height: 150 27 | tracker-list: 28 | - 10.0.75.2:22122 29 | 30 | pool: 31 | #从池中借出的对象的最大数目 32 | max-total: 153 33 | max-wait-millis: 102 34 | jmx-name-base: 1 35 | jmx-name-prefix: 1 36 | 37 | -------------------------------------------------------------------------------- /src/test/resources/images/cat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tobato/FastDFS_Client/d866cd05e2930751c475cce8de6d109d532a0d93/src/test/resources/images/cat.jpg -------------------------------------------------------------------------------- /src/test/resources/images/fly.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tobato/FastDFS_Client/d866cd05e2930751c475cce8de6d109d532a0d93/src/test/resources/images/fly.png -------------------------------------------------------------------------------- /src/test/resources/images/gs.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tobato/FastDFS_Client/d866cd05e2930751c475cce8de6d109d532a0d93/src/test/resources/images/gs.jpg -------------------------------------------------------------------------------- /src/test/resources/logback-test.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /tools/local-release-skipTest.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | echo [INFO] build and install modules. 3 | cd ..\ 4 | call mvn clean deploy -P local-release -Dmaven.test.skip=true 5 | pause 6 | -------------------------------------------------------------------------------- /tools/local-release.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | echo [INFO] build and install modules. 3 | cd ..\ 4 | call mvn clean deploy -P local-release 5 | pause 6 | -------------------------------------------------------------------------------- /tools/pakcage-skipTest.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | echo [INFO] build and install modules. 3 | cd ..\ 4 | call mvn clean package -Dmaven.test.skip=true 5 | pause 6 | -------------------------------------------------------------------------------- /tools/release-to-Center-skipTest.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | echo [INFO] build and install modules. 3 | cd ..\ 4 | call mvn clean deploy -P release -Dmaven.test.skip=true 5 | pause 6 | -------------------------------------------------------------------------------- /tools/release-to-Center.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | echo [INFO] build and install modules. 3 | cd ..\ 4 | call mvn clean deploy -P release 5 | pause 6 | --------------------------------------------------------------------------------4 | 9 | 10 |5 | 8 |%date [%thread] %-5level %logger{80} - %msg%n 6 | 7 |11 | 12 | 13 | 14 | 15 | 16 | 17 | 19 |18 |