1. Ceph packaging and automatic assembly

  1. Create cepH-Starter Automation project:

    Create a Spring Boot project as a common component.

  2. Pom file dependencies:

    <dependencies>
            <! -- Spring Boot custom launcher dependencies -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-actuator-autoconfigure</artifactId>
            </dependency>
            <! Ceph dependencies -->
            <dependency>
                <groupId>com.ceph</groupId>
                <artifactId>rados</artifactId>
                <version>0.6.0</version>
            </dependency>
    
            <! Ceph fs operation dependency -->
            <dependency>
                <groupId>com.ceph</groupId>
                <artifactId>libcephfs</artifactId>
                <version>0.80.5</version>
            </dependency>
    
            <! Ceph swift dependencies -->
            <dependency>
                <groupId>org.javaswift</groupId>
                <artifactId>joss</artifactId>
                <version>0.10.2</version>
            </dependency>
        </dependencies>
    
    Copy the code

    Adopt the current version directly, adding the three cepH-related dependencies.

  3. Code implementation

    Encapsulate Ceph operation interface, CephSwiftOperator class:

    public class CephSwiftOperator {
    
        private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
    
        /** * User name */
        private String username;   
        /** * Password */
        private String password;
    
        /** * Authentication access address */
        private String authUrl;
    
        /** * The default container name */
        private String defaultContainerName;
    
        /** * Ceph account object */
        private Account account;
    
        /** * Ceph container object */
        private Container container;   
    
        public CephSwiftOperator(String username, String password, String authUrl, String defaultContainerName) {
            // Initialize the configuration information
            this.username = username;
            this.password = password;
            this.authUrl = authUrl;
            this.defaultContainerName = defaultContainerName;
            init();   
        }
    
        /** * Initialize the connection */
        public void init(a) {
            try {
                // Ceph user authentication configuration
                AccountConfig config = new AccountConfig();
                config.setUsername(username);
                config.setPassword(password);
                config.setAuthUrl(authUrl);
                config.setAuthenticationMethod(AuthenticationMethod.BASIC);
                account = new AccountFactory(config).createAccount();
                // Get the container
                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) {
                // Do exception catching to avoid service startup failure
                log.error(Ceph connection initialization exception:+ e.getMessage()); }}/** * Upload object *@param remoteName
         * @param filepath
         */
        public void createObject(String remoteName, String filepath) {
            StoredObject object = container.getObject(remoteName);
            object.uploadObject(new File(filepath));
        }
    
        /** * Upload file object (byte array) *@param remoteName
         * @param inputStream
         */
        public void createObject(String remoteName, byte[] inputStream) {
            StoredObject object = container.getObject(remoteName);
            object.uploadObject(inputStream);
        }
    
        /** * gets the specified object *@param containerName
         * @param objectName
         * @param outpath
         */
        public void  retrieveObject(String objectName,String outpath){
            StoredObject object = container.getObject(objectName);
            object.downloadObject(new File(outpath));
        }
       /** * Download the file and convert it to file stream *@param objectName
         * @return* /
        public InputStream retrieveObject(String objectName){
            StoredObject object = container.getObject(objectName);
            return object.downloadObjectAsInputStream();
        }
       
        /** * Deletes the specified file object *@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 failed to delete file: + e.getMessage());
            }
            return false;
        }
    
        /** * get all containers *@return* /
        public List listContainer(a) {
            List list = new ArrayList();
            Collection<Container> containers = account.list();
            for (Container currentContainer : containers) {
                list.add(currentContainer.getName());
                System.out.println(currentContainer.getName());
    
            }
            returnlist; }}Copy the code
    • This wrapper interface will be managed by the Spring container as a singleton, and the constructor will initialize information such as Ceph authenticated connections

    • Set Account and Container as member variables to facilitate reuse and reduce overhead.

    • The default container name is set for initialization. Generally, one container name is set for each service. If the service functions are complex, you can set one container for each service module.

    • Swift Api has been fully encapsulated, which is relatively simple to use internally. It mainly encapsulates upload and download interfaces, and further encapsulates them for easy call processing.

    AutoCephSwiftConfiguration automation configuration class:

    @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(a) {
            return newCephSwiftOperator(username, password, authUrl, defaultContainerName); }}Copy the code

    The ceph. AuthUrl attribute is used to determine whether or not the configuration is loaded. If the ceph attribute is not set in the configuration file, it will be executed without error even if it is referenced in Maven. This automated configuration is responsible for initializing a Ceph Swift interface operation instance.

  4. Automatic configuration:

    In order for the custom Ceph Starter to work, you must follow the SPI extension mechanism of Spring Boot and create a spring.factories file in the meta-INF directory of the Resources environment:

    # Auto Configure
    org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
    com.ceph.starter.AutoCephSwiftConfiguration
    Copy the code

    Specify the automated configuration class we wrote above.

2. Create a user management project

  1. Project configuration application.yml

    server:
      port: 10692
    spring:
      application:
        name: user-manager
      # template configuration
      thymeleaf:
        prefix: classpath:/templates/
        suffix: .html
        mode: HTML
        encoding: utf-8
        servlet:
          content-type: text/html
    
      # File upload size limit
      servlet:
        multipart:
          max-file-size: 100MB
          max-request-size: 100MB
    
    Ceph Swift authentication information configuration
    ceph:
      username: cephtester:subtester
      password: 654321
      authUrl: http://10.10.20.11:7480/auth/1.0
      defaultContainerName: user_datainfo
    Copy the code
  2. POM dependency configuration:

       <dependencies>
           <! -- Spring Boot dependency -->
           <dependency>
               <groupId>org.springframework.boot</groupId>
               <artifactId>spring-boot-starter-web</artifactId>
           </dependency>   
           <! -- Spring boot thymeleaf template dependency -->
           <dependency>
               <groupId>org.springframework.boot</groupId>
               <artifactId>spring-boot-starter-thymeleaf</artifactId>
           </dependency>   
           <! Ceph Automation Package -->
           <dependency>
               <groupId>com.itcast.ceph</groupId>
               <artifactId>ceph-starter</artifactId>
               <version>1.0 the SNAPSHOT</version>
           </dependency>   
       </dependencies>
    Copy the code

    Added Ceph automation package component configuration dependencies.

3. Ceph file upload implementation

  1. Implement file upload interface:

    /** * Upload user file *@return* /
    public String uploadUserFile(MultipartFile file) throws Exception {
    
        // Get a unique file ID
        String remoteFileId = globalIDGenerator.nextStrId();
    
        // Upload files to CEPH
        cephSwiftOperator.createObject(remoteFileId, file.getBytes());
    
        return remoteFileId;
    }
    Copy the code
  2. Controller layer implementation:

    Add the upload interface under UserManagerController:

    /** * User file upload *@param file
     * @return* /
    @PostMapping("/upload")
    @ResponseBody
    public String upload(@RequestParam("file") MultipartFile file) {
        String  result = null;
        try {
            // Upload files via Ceph Swift
            String userFileId = userManagerService.uploadUserFile(file);
            result = "ID of file uploaded:" + userFileId;
        }catch(Exception e) {
            log.error(e.getMessage(), e);
            result = "An exception occurs:" + e.getMessage();
        }
        return result;
    }   
    Copy the code

    The file is uploaded through Spring Boot. The file is submitted in the form of multipart/form-data, and the parameter name is file. Upload in indirect data flow mode; otherwise, the service cannot recognize the received file.

4. Ceph file download implementation

Added an interface to download files according to the ID of uploaded files.

  1. Service layer:

    Interface to download user files:

    /** * Download user files *@param fileId
     * @return
     * @throws Exception
     */
    public InputStream downloadUserFile(String fileId) throws Exception {
        return cephSwiftOperator.retrieveObject(fileId);
    }
    Copy the code
  2. The Controller layer:

    /** * Download user file information based on file ID *@param filename
     * @return* /
    @RequestMapping(value = "/download")
    public String downloadFile(@notblank (message = "File ID cannot be empty!" ) String filename, HttpServletResponse response){   
        String result = null;   
        // File stream cache
        BufferedInputStream bis = null;
        // File output stream
        OutputStream os = null;
        try {
            // 1. Get the file stream from Ceph server
            InputStream inputStream = userManagerService.downloadUserFile(filename);
            // 2. Enable forcible download
            response.setContentType("application/x-msdownload");
            // 3. Set the name of the downloaded file
            response.addHeader("Content-disposition"."attachment; fileName=" + filename);
            // 4. Output file stream
            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 = "An exception occurs:" + e.getMessage();
        }finally {
            // Finally, remember to close the file stream
            if(bis ! =null ) {
                try {
                    bis.close();
                } catch(IOException e) { log.error(e.getMessage(), e); }}}return result;
    
    }
    Copy the code

5. Function verification

  1. Visit upload page

    Address:http://127.0.0.1:10692/user/file

  2. After successful upload, the file ID will be returned:

  3. Download file:

    Enter the file ID to download:


This article was created and shared by Mirson. For further communication, please add to QQ group 19310171 or visit www.softart.cn