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
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).
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 và 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.
........
@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");
}
}
@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() và 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:...
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;
}
}
@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;
}
@EqualsAndHashCode(callSuper = true)
@Getter
@Setter
public class GoogleDriveFoldersDTO implements Serializable {
private String id;
private String name;
private String link;
}
// 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;
}
@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);
}
}
@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);
}
}
@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.
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
Các bạn thây hay thì Like và Share để mình được uống Cafe Free nhá! hehe
RATE: 4.4
5300 VIEW
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
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