共计 7172 个字符,预计需要花费 18 分钟才能阅读完成。
1. Ceph 封装与自动化拆卸
-
创立 ceph-starter 自动化工程:
创立一个 spring boot 工程,作为一个专用组件。
-
pom 文件依赖:
<dependencies> <!-- Spring Boot 自定义启动器的依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-actuator-autoconfigure</artifactId> </dependency> <!-- ceph 依赖 --> <dependency> <groupId>com.ceph</groupId> <artifactId>rados</artifactId> <version>0.6.0</version> </dependency> <!-- ceph fs 操作依赖 --> <dependency> <groupId>com.ceph</groupId> <artifactId>libcephfs</artifactId> <version>0.80.5</version> </dependency> <!-- ceph swift 依赖 --> <dependency> <groupId>org.javaswift</groupId> <artifactId>joss</artifactId> <version>0.10.2</version> </dependency> </dependencies>
间接采纳目前的最新版,退出 Ceph 相干的三个依赖。
-
代码实现
封装 Ceph 操作接口,CephSwiftOperator 类:
public class CephSwiftOperator {private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); /** * 用户名 */ private String username; /** * 明码 */ private String password; /** * 认证接入地址 */ private String authUrl; /** * 默认容器名称 */ private String defaultContainerName; /** * Ceph 账户对象 */ private Account account; /** * Ceph 容器对象 */ private Container container; public CephSwiftOperator(String username, String password, String authUrl, String defaultContainerName) { // 初始化配置信息 this.username = username; this.password = password; this.authUrl = authUrl; this.defaultContainerName = defaultContainerName; init();} /** * 初始化建设连贯 */ public void init() { try { // Ceph 用户认证配置 AccountConfig config = new AccountConfig(); config.setUsername(username); config.setPassword(password); config.setAuthUrl(authUrl); config.setAuthenticationMethod(AuthenticationMethod.BASIC); account = new AccountFactory(config).createAccount(); // 获取容器 Container newContainer = account.getContainer(defaultContainerName); if (!newContainer.exists()) {container = newContainer.create(); log.info("account container create ==>" + defaultContainerName); } else { container = newContainer; log.info("account container exists! ==>" + defaultContainerName); } }catch(Exception e) { // 做异样捕捉, 防止服务不能失常启动 log.error("Ceph 连贯初始化异样:" + e.getMessage()); } } /** * 上传对象 * @param remoteName * @param filepath */ public void createObject(String remoteName, String filepath) {StoredObject object = container.getObject(remoteName); object.uploadObject(new File(filepath)); } /** * 上传文件对象(字节数组模式)* @param remoteName * @param inputStream */ public void createObject(String remoteName, byte[] inputStream) {StoredObject object = container.getObject(remoteName); object.uploadObject(inputStream); } /** * 获取指定对象 * @param containerName * @param objectName * @param outpath */ public void retrieveObject(String objectName,String outpath){StoredObject object = container.getObject(objectName); object.downloadObject(new File(outpath)); } /** * 下载文件,转为文件流模式 * @param objectName * @return */ public InputStream retrieveObject(String objectName){StoredObject object = container.getObject(objectName); return object.downloadObjectAsInputStream();} /** * 删除指定文件对象 * @param containerName * @param objectName * @return */ public boolean deleteObject(String objectName){ try {StoredObject object = container.getObject(objectName); object.delete(); return !object.exists();}catch(Exception e) {log.error("Ceph 删除文件失败:" + e.getMessage()); } return false; } /** * 获取所有容器 * @return */ public List listContainer() {List list = new ArrayList(); Collection<Container> containers = account.list(); for (Container currentContainer : containers) {list.add(currentContainer.getName()); System.out.println(currentContainer.getName()); } return list; } }
- 此封装接口将纳入 Spring 容器治理,即为单例,构造函数会初始化 Ceph 认证连贯等信息
- 将 Account 与 Container 设为成员变量,便于复用,缩小开销。
- 初始化会默认一个容器名称,个别每个服务设置一个容器名称,如果业务性能比拟庞杂,能够每个业务模块设置一个容器。
- Swift Api 曾经做了较欠缺的封装,咱们外部应用比较简单,次要封装上传和下载接口,为便于调用解决,做了进一步封装。
AutoCephSwiftConfiguration 自动化配置类:
@Configuration @EnableAutoConfiguration @ConditionalOnProperty(name = "ceph.authUrl") public class AutoCephSwiftConfiguration {@Value("${ceph.username}") private String username; @Value("${ceph.password}") private String password; @Value("${ceph.authUrl}") private String authUrl; @Value("${ceph.defaultContainerName}") private String defaultContainerName; @Bean public CephSwiftOperator cephSwiftOperator() {return new CephSwiftOperator(username, password, authUrl, defaultContainerName); } }
ConditionalOnProperty 依据 ceph.authUrl 属性来决定是否加载配置,如果配置文件中没有设置 Ceph 相干属性,即便 maven 中援用,启动也不会报错。该自动化配置,负责初始化一个 Ceph Swift 接口操作实例。
-
自动化配置:
要让自定义 Ceph Starter 真正失效,必须遵循 Spring boot 的 SPI 扩大机制,在 resources 环境中, META-INF 目录下,创立 spring.factories 文件:
# Auto Configure org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.ceph.starter.AutoCephSwiftConfiguration
指定咱们下面所写的自动化配置类。
2. 创立用户治理工程
-
工程配置
application.ymlserver: port: 10692 spring: application: name: user-manager # 模板配置 thymeleaf: prefix: classpath:/templates/ suffix: .html mode: HTML encoding: utf-8 servlet: content-type: text/html # 文件上传大小限度 servlet: multipart: max-file-size: 100MB max-request-size: 100MB # ceph swift 认证信息配置 ceph: username: cephtester:subtester password: 654321 authUrl: http://10.10.20.11:7480/auth/1.0 defaultContainerName: user_datainfo
-
POM 依赖配置:
<dependencies> <!-- spring boot 依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- Spring boot thymeleaf 模板依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <!-- Ceph 自动化封装组件 --> <dependency> <groupId>com.itcast.ceph</groupId> <artifactId>ceph-starter</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies>
退出 Ceph 自动化封装组件配置依赖。
3. Ceph 文件上传实现
-
实现文件上传接口:
/** * 上传用户文件 * @return */ public String uploadUserFile(MultipartFile file) throws Exception { // 获取惟一文件 ID 标识 String remoteFileId = globalIDGenerator.nextStrId(); // 上传文件至 CEPH cephSwiftOperator.createObject(remoteFileId, file.getBytes()); return remoteFileId; }
-
Controller 层实现:
在 UserManagerController 上面,减少上传接口:
/** * 用户文件上传 * @param file * @return */ @PostMapping("/upload") @ResponseBody public String upload(@RequestParam("file") MultipartFile file) { String result = null; try { // 通过 Ceph Swift 上传文件 String userFileId = userManagerService.uploadUserFile(file); result = "上传的文件 ID:" + userFileId; }catch(Exception e) {log.error(e.getMessage(), e); result = "出现异常:" + e.getMessage();} return result; }
通过 Spring boot 实现文件上传,留神以表单 form 模式提交,类型为 multipart/form-data,参数名为 file,非间接数据流形式上传,不然服务不能失常辨认接管文件。
4. Ceph 文件下载实现
新增一个接口,依据上传的文件 ID 标识下载文件。
-
Service 层:
实现下载用户文件接口:
/** * 下载用户文件 * @param fileId * @return * @throws Exception */ public InputStream downloadUserFile(String fileId) throws Exception {return cephSwiftOperator.retrieveObject(fileId); }
-
Controller 层:
/** * 依据文件 ID 下载用户文件信息 * @param filename * @return */ @RequestMapping(value = "/download") public String downloadFile(@NotBlank(message = "文件 ID 不能为空!") String filename, HttpServletResponse response){ String result = null; // 文件流缓存 BufferedInputStream bis = null; // 文件输入流 OutputStream os = null; try { // 1. 从 Ceph 服务器上获取文件流 InputStream inputStream = userManagerService.downloadUserFile(filename); // 2. 设置强制下载, 不间接关上 response.setContentType("application/x-msdownload"); // 3. 设置下载的文件名称 response.addHeader("Content-disposition", "attachment; fileName=" + filename); // 4. 输入文件流 byte[] buffer = new byte[1024]; bis = new BufferedInputStream(inputStream); os = response.getOutputStream(); int i = bis.read(buffer); while(i != -1) {os.write(buffer, 0, i); i = bis.read(buffer); } os.flush(); return null; }catch(Exception e) {log.error(e.getMessage(), e); result = "出现异常:" + e.getMessage();}finally { // 最初, 要记住敞开文件流 if(bis != null) { try {bis.close(); } catch (IOException e) {log.error(e.getMessage(), e); } } } return result; }
5. 性能验证
-
拜访上传页面
地址:http://127.0.0.1:10692/user/file
![file](/img/bVcQ8Xw)
-
上传胜利后,会返回文件 ID:
![file](/img/bVcQ8Xx)
-
下载文件:
输出文件 ID 进行下载:
![file](/img/bVcQ8Xy)
本文由 mirson 创作分享,如需进一步交换,请加 QQ 群:19310171 或拜访 www.softart.cn