Google Drive API with Spring Boot - Gradle Project

Blog này mình sẽ hướng dẫn mọi người tạo 1 web app sửa dụng Google Drive API để thêm/sửa/xoá và lấy toàn bộ dữ liệu từ Google Drive bằng Spring Boot cực đơn giản :D

Chào mọi người! Lại là mình đây...Mà các bạn biết mình là ai méo đâu :V. Ngắn gọn mình là Dev thuộc biên chế của HTH-Non :D => Đây này LINK. Giới thiệu vậy đủ rồi vào vấn đề chính thôi. Như tiêu đề thì các bạn cũng đã biết rồi, thì để làm và hiểu được code trong blog này các bạn nên biết về Spring Boot (Chắc chắn rồi), Resful API và 1 chút về Google Drive API v3. Ok...Bắt đầu nào...

Có thể xem Demo ở đây: LINK HERE

Đầu tiên thì các bạn cần đăng ký Service của Google các bạn vào link sau mình gán trong blog nhé!

Phần này các bạn để mặc đinh là Quickstart nhá (Thi thoảng nó lỗi nên cứ để mặc định r sửa sau)

Next step:

bây giờ các bạn chọn API Console để xem Service đã đăng ký và Config 1 vài thông tin tiếp theo.

Các bạn chọn mục Edit nhé

==========>:

==========>:

Các trường của phần này có:
Name - Tên project của bạn

Authorised Javascript origin - Domain của web (Ở đây mình dùng localhost)

Authorised redirect URIs - Đường dẫn này được dùng để redirect khi các bạn OAuth thành công

Sau khi các bạn đăng ký xong thì Download nó về nhé ( Nhớ là Download đó nha - Mục Download mình note ở trên đó). Giải thích qua thì cái file đó chứa các thông tin về Serivce của bạn như project_id, token_uri...nôm na là nó dùng để đăng ký OAuth2 web của bạn với Google. Ok...Giờ đến phần hay nhất rồi đây :D Bây giờ các bạn cần tạo 1 project Spring Boot bằng Gradle (các bạn cũng có thể tạo bằng Maven).

Now, Các bạn vô Spring Initialirz để tạo 1 project Spring Boot-Gradle cho nhánh nhé.

Các bạn chọn như hình nhé. Sau khi tải và giải nén xong thì vào CODE THÔI :D

À quên các bạn lấy file Service của Google vừa tải về lưu theo vào folder Resources trong project nhé: (.../<project name>/src/main/resources )

Bây giờ các bạn copy đoạn mã sau bỏ bảo mục dependencies trong file build.gradle reload lại nhá. ( ở đây mình dùng IntelliJ nên có mục reload ngay trên IDE ):

Các bạn dùng maven thì vào đừng dẫn ở dưới để cấu hình dependency nhé!

	// https://mvnrepository.com/artifact/com.google.api-client/google-api-client
	compile group: 'com.google.api-client', name: 'google-api-client', version: '1.31.1'
	// https://mvnrepository.com/artifact/com.google.apis/google-api-services-drive
	compile group: 'com.google.apis', name: 'google-api-services-drive', version: 'v3-rev197-1.25.0'
	// https://mvnrepository.com/artifact/com.google.oauth-client/google-oauth-client-jetty
	compile group: 'com.google.oauth-client', name: 'google-oauth-client-jetty', version: '1.31.2'

 

Vào phần code chính nào :P. Trong phần này mình sẽ hạn chỉ cung cấp code và giải thích 1 số cái cần thiết trong code bằng comment. Các bạn thông cảm nhé vì còn phải fix bug :D.

NOTE: Mọi thắc mắc về code, cần Source Code, cần giải thích sâu or fix bug thì các bạn liên hệ với Mục này đã bị xóa do vi phạm - Hết quảng cáo tiếp tục nào :V

........

Các bạn tạo các Class sau:

2 file cấu hình Drive và thao tác dữ liệu với Drive:

GoogleDriveConfig.java

@Component
public class GoogleDriveConfig {
    private static final String APPLICATION_NAME = "Google Drive-HTH Non"; // Application name
    private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
    private static final String TOKENS_DIRECTORY_PATH = "tokens";
    /**
     * Global instance of the scopes required by this quickstart.
     * If modifying these scopes, delete your previously saved tokens/ folder.
     */
    private static final List<String> SCOPES = Collections.singletonList(DriveScopes.DRIVE);
    private static final String CREDENTIALS_FILE_PATH = "/credentials.json"; // path file Google Drive Service

    public Drive getInstance() throws GeneralSecurityException, IOException {
        // Build a new authorized API client service.
        final NetHttpTransport HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
        Drive service = new Drive.Builder(HTTP_TRANSPORT, JSON_FACTORY, getCredentials(HTTP_TRANSPORT))
                .setApplicationName(APPLICATION_NAME)
                .build();
        return service;
    }

    /**
     * Creates an authorized Credential object.
     *
     * @param HTTP_TRANSPORT The network HTTP Transport.
     * @return An authorized Credential object.
     * @throws IOException If the credentials.json file cannot be found.
     */
    private Credential getCredentials(final NetHttpTransport HTTP_TRANSPORT) throws IOException {
        // Load client secrets.
        InputStream in = GoogleDriveConfig.class.getResourceAsStream(CREDENTIALS_FILE_PATH);
        if (in == null) {
            throw new FileNotFoundException("Resource not found: " + CREDENTIALS_FILE_PATH);
        }
        GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(in));

        // Build flow and trigger user authorization request.
        GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
                HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES)
                .setDataStoreFactory(new FileDataStoreFactory(new java.io.File(TOKENS_DIRECTORY_PATH)))
                .setAccessType("offline")
                .build();
        LocalServerReceiver receiver = new LocalServerReceiver.Builder().setPort(8080).build(); // PORT URI OF GOOGLE SERVICE
        return new GJQM1KiAjvou1b4XDQW35xvpHnJT52eaka(flow, receiver).authorize("user");
    }

}

 

GoogleFileManager.java

@Component
public class GoogleFileManager {

    @Autowired
    private GoogleDriveConfig googleDriveConfig;

    // Get all file
    public List<File> listEverything() throws IOException, GeneralSecurityException {
        // Print the names and IDs for up to 10 files.
        FileList result = googleDriveConfig.getInstance().files().list()
                .setPageSize(1000)
                .setFields("nextPageToken, files(id, name, size, thumbnailLink, shared)") // get field of google drive file
                .execute();
        return result.getFiles();
    }

    // Get all folder
    public List<File> listFolderContent(String parentId) throws IOException, GeneralSecurityException {
        if (parentId == null) {
            parentId = "root";
        }
        String query = "'" + parentId + "' in parents";
        FileList result = googleDriveConfig.getInstance().files().list()
                .setQ(query)
                .setPageSize(10)
                .setFields("nextPageToken, files(id, name)") // get field of google drive folder
                .execute();
        return result.getFiles();
    }

    // Download file by id
    public void downloadFile(String id, OutputStream outputStream) throws IOException, GeneralSecurityException {
        if (id != null) {
            googleDriveConfig.getInstance().files()
                    .get(id).executeMediaAndDownloadTo(outputStream);
        }
    }

    // Delete file by id
    public void deleteFileOrFolder(String fileId) throws Exception {
        googleDriveConfig.getInstance().files().delete(fileId).execute();
    }

    // Set permission drive file
    private Permission setPermission(String type, String role){
        Permission permission = new Permission();
        permission.setType(type);
        permission.setRole(role);
        return permission;
    }


    // Upload file
    public String uploadFile(MultipartFile file, String folderName, String type, String role) {
        try {
            String folderId = getFolderId(folderName);
            if (null != file) {

                File fileMetadata = new File();
                fileMetadata.setParents(Collections.singletonList(folderId));
                fileMetadata.setName(file.getOriginalFilename());
                File uploadFile = googleDriveConfig.getInstance()
                        .files()
                        .create(fileMetadata, new InputStreamContent(
                                file.getContentType(),
                                new ByteArrayInputStream(file.getBytes()))
                        )
                        .setFields("id").execute();

                if (!type.equals("private") && !role.equals("private")){
                    // Call Set Permission drive
                    googleDriveConfig.getInstance().permissions().create(uploadFile.getId(), setPermission(type, role)).execute();
                }

                return uploadFile.getId();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    // get id folder google drive
    public String getFolderId(String folderName) throws Exception {
        String parentId = null;
        String[] folderNames = folderName.split("/");

        Drive driveInstance = googleDriveConfig.getInstance();
        for (String name : folderNames) {
            parentId = findOrCreateFolder(parentId, name, driveInstance);
        }
        return parentId;
    }

    private String findOrCreateFolder(String parentId, String folderName, Drive driveInstance) throws Exception {
        String folderId = searchFolderId(parentId, folderName, driveInstance);
        // Folder already exists, so return id
        if (folderId != null) {
            return folderId;
        }
        //Folder dont exists, create it and return folderId
        File fileMetadata = new File();
        fileMetadata.setMimeType("application/vnd.google-apps.folder");
        fileMetadata.setName(folderName);

        if (parentId != null) {
            fileMetadata.setParents(Collections.singletonList(parentId));
        }
        return driveInstance.files().create(fileMetadata)
                .setFields("id")
                .execute()
                .getId();
    }

    private String searchFolderId(String parentId, String folderName, Drive service) throws Exception {
        String folderId = null;
        String pageToken = null;
        FileList result = null;

        File fileMetadata = new File();
        fileMetadata.setMimeType("application/vnd.google-apps.folder");
        fileMetadata.setName(folderName);

        do {
            String query = " mimeType = 'application/vnd.google-apps.folder' ";
            if (parentId == null) {
                query = query + " and 'root' in parents";
            } else {
                query = query + " and '" + parentId + "' in parents";
            }
            result = service.files().list().setQ(query)
                    .setSpaces("drive")
                    .setFields("nextPageToken, files(id, name)")
                    .setPageToken(pageToken)
                    .execute();

            for (File file : result.getFiles()) {
                if (file.getName().equalsIgnoreCase(folderName)) {
                    folderId = file.getId();
                }
            }
            pageToken = result.getNextPageToken();
        } while (pageToken != null && folderId == null);

        return folderId;
    }
}

Trong hàm listEverthing()listFolderContent() các bạn có thể thêm nhiều Field ( setFields() ) nữa chứ không phải chỉ có các Field như trong code nhé. Các bạn vào đây để tìm Field muốn get và set ra nhé: -> LINK Tiếp nào:...

1 class để Convert Byte sang KB, MB, GB, TB

public class ConvertByteToMB {
    public static String getSize(long size) {
        long n = 1024;
        String s = "";
        double kb = size / n;
        double mb = kb / n;
        double gb = mb / n;
        double tb = gb / n;
        if(size < n) {
            s = size + " Bytes";
        } else if(size >= n && size < (n * n)) {
            s =  String.format("%.1f", kb) + " KB";
        } else if(size >= (n * n) && size < (n * n * n)) {
            s = String.format("%.1f", mb) + " MB";
        } else if(size >= (n * n * n) && size < (n * n * n * n)) {
            s = String.format("%.2f", gb) + " GB";
        } else if(size >= (n * n * n * n)) {
            s = String.format("%.2f", tb) + " TB";
        }
        return s;
    }
}

2 Model để chung chuyển dữ liệu:

GoogleDriveFileDTO.java

@EqualsAndHashCode(callSuper = true)
@Getter
@Setter
public class GoogleDriveFileDTO implements Serializable {
    private String id;
    private String name;
    private String link;
    private String size;
    private String thumbnailLink;
    private boolean shared;
}

GoogleDriveFoldersDTO.java

@EqualsAndHashCode(callSuper = true)
@Getter
@Setter
public class GoogleDriveFoldersDTO implements Serializable {
    private String id;
    private String name;
    private String link;
}

Ở đây mình làm việc với interface để dễ quản lý và thao tác thông qua Service. Các bạn có thể tạo trực tiếp mà không cần dùng interface:

2 interface:

// interface 1
public interface IGoogleDriveFile {
    List<GoogleDriveFileDTO> getAllFile() throws IOException, GeneralSecurityException;
    void deleteFile(String id) throws Exception;
    void uploadFile(MultipartFile file, String filePath, boolean isPublic);
    void downloadFile(String id, OutputStream outputStream) throws IOException, GeneralSecurityException;
}

// interface 2
public interface IGoogleDriveFolder {
    List<GoogleDriveFoldersDTO> getAllFolder() throws IOException, GeneralSecurityException;
    void createFolder(String folderName) throws Exception;
    void deleteFolder(String id) throws Exception;
}

2 Service implements các 2 interface trên:

GoogleDriveFileService .java

@Service
public class GoogleDriveFileService implements IGoogleDriveFile {

    @Autowired
    GoogleFileManager googleFileManager;

    @Override
    public List<GoogleDriveFileDTO> getAllFile() throws IOException, GeneralSecurityException {

        List<GoogleDriveFileDTO> responseList = null;
        List<File> files = googleFileManager.listEverything();
        GoogleDriveFileDTO dto = null;

        if (files != null) {
            responseList = new ArrayList<>();
            for (File f : files) {
                dto = new GoogleDriveFileDTO();
                if (f.getSize() != null) {
                    dto.setId(f.getId());
                    dto.setName(f.getName());
                    dto.setThumbnailLink(f.getThumbnailLink());
                    dto.setSize(ConvertByteToMB.getSize(f.getSize()));
                    dto.setLink("https://drive.google.com/file/d/" + f.getId() + "/view?usp=sharing");
                    dto.setShared(f.getShared());

                    responseList.add(dto);
                }
            }
        }
        return responseList;
    }

    @Override
    public void deleteFile(String id) throws Exception {
        googleFileManager.deleteFileOrFolder(id);
    }

    @Override
    public void uploadFile(MultipartFile file, String filePath, boolean isPublic) {
        String type = "";
        String role = "";
        if (isPublic) {
            // Public file of folder for everyone
            type = "anyone";
            role = "reader";
        } else {
            // Private
            type = "private";
            role = "private";
        }
        googleFileManager.uploadFile(file, filePath, type, role);
    }

    @Override
    public void downloadFile(String id, OutputStream outputStream) throws IOException, GeneralSecurityException {
        googleFileManager.downloadFile(id, outputStream);
    }

}

GoogleDriveFolderService.java

@Service
public class GoogleDriveFolderService implements IGoogleDriveFolder {

    @Autowired
    GoogleFileManager googleFileManager;

    @Override
    public List<GoogleDriveFoldersDTO> getAllFolder() throws IOException, GeneralSecurityException {

        List<File> files = googleFileManager.listFolderContent("root");
        List<GoogleDriveFoldersDTO> responseList = null;
        GoogleDriveFoldersDTO dto = null;

        if (files != null) {
            responseList = new ArrayList<>();
            for (File f : files) {
                dto = new GoogleDriveFoldersDTO();
                dto.setId(f.getId());
                dto.setName(f.getName());
                dto.setLink("https://drive.google.com/drive/u/3/folders/"+f.getId());
                responseList.add(dto);
            }
        }
        return responseList;
    }

    @Override
    public void createFolder(String folderName) throws Exception {
        String folderId = googleFileManager.getFolderId(folderName);
        System.out.println(folderId);
    }

    @Override
    public void deleteFolder(String id) throws Exception {
        googleFileManager.deleteFileOrFolder(id);
    }
}

1 controller:

GoogleDriveController.java

@RestController(value = "googleDriveController")
public class GoogleDriveController {

    @Autowired
    GoogleDriveFileService googleDriveFileService;

    @Autowired
    GoogleDriveFolderService googleDriveFolderService;

    // Get all file on drive
    @GetMapping("/")
    public ModelAndView pageIndex() throws IOException, GeneralSecurityException {
        ModelAndView mav = new ModelAndView("index");

        List<GoogleDriveFileDTO> listFile = googleDriveFileService.getAllFile();
        List<GoogleDriveFoldersDTO> listFolder = googleDriveFolderService.getAllFolder();

        mav.addObject("DTO_FOLDER", listFolder);
        mav.addObject("DTO_FILE", listFile);
        return mav;
    }

    // Upload file to public
    @PostMapping(value = "/upload/file",
            consumes = {MediaType.MULTIPART_FORM_DATA_VALUE},
            produces = {MediaType.APPLICATION_JSON_VALUE} )
    public ModelAndView  uploadFile(@RequestParam("fileUpload") MultipartFile fileUpload,
                                @RequestParam("filePath") String pathFile,
                                @RequestParam("shared") String shared) {

        System.out.println(pathFile);
        if (pathFile.equals("")){
            pathFile = "Root"; // Save to default folder if the user does not select a folder to save - you can change it
        }
        System.out.println(pathFile);
        googleDriveFileService.uploadFile(fileUpload, pathFile, Boolean.parseBoolean(shared));
        return new ModelAndView("redirect:" + "/");
    }

    // Delete file by id
    @GetMapping("/delete/file/{id}")
    public ModelAndView deleteFile(@PathVariable String id) throws Exception {
        googleDriveFileService.deleteFile(id);
        return new ModelAndView("redirect:" + "/");
    }

    // Download file
    @GetMapping("/download/file/{id}")
    public void downloadFile(@PathVariable String id, HttpServletResponse response) throws IOException, GeneralSecurityException {
        googleDriveFileService.downloadFile(id, response.getOutputStream());
    }

    // Get all root folder on drive
    @GetMapping("/list/folders") // or {"/list/folders","/list/folders/{parentId}"}
    public ModelAndView listFolder() throws IOException, GeneralSecurityException {
        ModelAndView mav = new ModelAndView("list_folder");
        List<GoogleDriveFoldersDTO> listFolder = googleDriveFolderService.getAllFolder();
        mav.addObject("DTO", listFolder);
        return mav;
    }

    // Create folder
    @PostMapping("/create/folder")
    public ModelAndView createFolder(@RequestParam("folderName") String folderName) throws Exception {
        googleDriveFolderService.createFolder(folderName);
        return new ModelAndView("redirect:" + "/list/folders");
    }

    // Delete folder by id
    @GetMapping("/delete/folder/{id}")
    public ModelAndView deleteFolder(@PathVariable String id) throws Exception {
        googleDriveFolderService.deleteFolder(id);
        return new ModelAndView("redirect:" + "/list/folders");
    }
}

 

Các bạn mở file application.properties để config dung lượng file tối đa để upload cũng như dowload nhé. Nếu không khi các bạn upload file > 1MB thì Server sẽ báo lỗi. Để khắc phục các bạn thêm đoạn code sau:

spring.servlet.multipart.max-file-size=100MB
spring.servlet.multipart.max-request-size=100MB

Ở đây mình để 100MB. Các bạn có thể setup lớn hơn.

OKey. Vậy là xong phần Back-End. Giờ đến phần Front-End nào :V .... Do Front-End mình hơi non do đó không quăng lên sợ xấu code :V Các bạn vào link này để Download về nhé. Chỉ việc Download thôi không cần chỉnh sửa gì cả :D

Download Here

Ok sau khi Download về thì các bạn copy và paste đè vào folder resources của project nhé! Like that....

Ok....Giờ thì run và xem thành quả thôi...

Một số lỗi các bạn có thể sẽ gặp:

1:

Với lỗi này các bạn vào file GoogleDriveConfig.java sửa Port 8080 thành 8081

LocalServerReceiver receiver = new LocalServerReceiver.Builder().setPort(8081).build();

Đồng thời sửa lại phần Config trong Service Google Drive như sau:

Sau khi Config lại xong các bạn Download lại File JSON này nhé

Phần nay hi hữu thôi :V Vì mh đang set port chạy OAuth2 ở 8080 nên nó lỗi. Cách này không thay do chưa tích hợp đăng nhập trên Browser để OAuth2 trực tiếp (Nếu có thời gian mình sẽ update phần đó sau nếu có thời gian-Blog này để kiếm ly Cafe của HTH-Tín Non nên không có Time làm chi tiết). Ok giờ chạy lai nào nó sẽ ra như nhau:

Ở của sổ console sẽ hiện:

Các bạn click mở lên và chọn tài khoản mà vừa đăng ký Service nhá. :V (Hơi khoai chút vì mh cho OAuth2 ở đây thay vì trên Broswer-Cái đó để làm sau khi bài nay đc 3k views + 3 ly Cafe cho Team)

Khi chọn tài khoản mà nó hiện ra cái này:

Các bạn chỉ cần chọn vô cái như mình chọn là được....

Tiếp đó cho phép sử dụng dịch vụ:

Sau đó thì vào đường dẫn: http://localhost:8080/ Để kiểm tra kết quả sau 1 hồi vật lộn nhá :V

Đây là phần Demo: LINK HERE

Các bạn thây hay thì Like và Share để mình được uống Cafe Free nhá! hehe


  RATE: 4.4 

  5198 VIEW


none
 USER 2023-05-04 11:39:54.0
Có thể chon em xin link github code được không admin
BÀI VIẾT LIÊN QUAN
Làm thế nào để Website của bạn chạy nhanh hơn

Cải thiện tốc độ tải trang, tăng tốc website là yếu tố bắt buộc phải tối ưu khi triển khai bất kỳ dự án SEO nào. Bởi, bên cạnh việc ảnh hưởng đến trải nghiệm người dùng thì tốc độ tải trang còn là một yếu tố để Google đánh giá kết quả xếp hạng tìm kiếm. Tuy nhiên, làm thế nào để tăng tốc website và tăng tốc như thế nào mới là đúng, các bạn hãy tham khảo bài viết sau đây

BÀI VIẾT LIÊN QUAN
Google Drive API with Spring Boot - Gradle Project

Blog này mình sẽ hướng dẫn mọi người tạo 1 web app sửa dụng Google Drive API để thêm/sửa/xoá và lấy toàn bộ dữ liệu từ Google Drive bằng Spring Boot cực đơn giản :D