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 Configureorg.springframework.boot.autoconfigure.EnableAutoConfiguration=\com.ceph.starter.AutoCephSwiftConfiguration
指定咱们下面所写的自动化配置类。
2. 创立用户治理工程
工程配置
application.ymlserver: port: 10692spring: 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")@ResponseBodypublic 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

上传胜利后, 会返回文件ID:

下载文件:
输出文件ID进行下载:

本文由mirson创作分享,如需进一步交换,请加QQ群:19310171或拜访www.softart.cn