-
Notifications
You must be signed in to change notification settings - Fork 522
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
java: Add spring-boot-starter-opendal #4756
Comments
I can deep in that next week. |
Thanks a lot! |
@Xuanwo Sorry for my late, recently I was kind of busy. But I still want to work on this :). I think in the short term, we will not be putting the spring starter opendal into the Spring repository. Therefore, we are facing the issue of maintaining OpenDAL with multiple versions of Spring in the OpenDAL repository. I suggest the following strategy:
<dependency>
<groupId>org.apache.opendal</groupId>
<artifactId>opendal-spring-33</artifactId>
<version>${latest.version}</version>
</dependency> <dependency>
<groupId>org.apache.opendal</groupId>
<artifactId>opendal-spring-27</artifactId>
<version>${latest.version}</version>
</dependency>
<dependency>
<groupId>org.apache.opendal</groupId>
<artifactId>opendal-spring-boot-starter</artifactId>
<version>${latest.version}</version>
<exclusions>
<exclusion>
<groupId>org.apache.opendal</groupId>
<artifactId>opendal-spring-33</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.opendal</groupId>
<artifactId>opendal-spring-27</artifactId>
<version>${latest.version}</version>
</dependency> |
Hi @shoothzj, thanks for your efforts. However, I feel targeting multiple Spring versions might be too complex for a starter proejct. I'm concerned about its future maintainability. Perhaps we could focus on the latest version and provide guidance for older versions? |
@Xuanwo I agree, we can focus on 3.3.x version. |
@Xuanwo, SpringBoot now supports two types of starters: reactive for asynchronous operations and non-reactive for synchronous operations. Let's look at a Redis example:
If a project is popular, the I think we should first maintain these three sub-projects with the latest SpringBoot version in our repo. Regarding the artifact ID, I prefer using "opendal" as the suffix, which is common in the Spring ecosystem. What do you think? Opendal as Prefix
Opendal as Suffix
|
I'm happy to continue using the common behavior in the ecosystem. |
@Xuanwo I put some sample codes in https://gitcode.com/shoothzj/opendal-demo/overview. And here is some docs, would you please take a look? UsageConfigurationFirst, configure the spring:
opendal:
schema: "fs"
conf:
root: "/tmp" Code IntegrationFeatures
I plan to implement Auto Serialize/Deserialize Data in the next. ImplementationSpring WebMVCTo use OpenDAL with Spring WebMVC:
import org.apache.opendal.Entry;
import org.apache.opendal.Metadata;
import org.apache.opendal.PresignedRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.time.Duration;
import java.util.List;
@RestController
@RequestMapping("/api/v1/opendal")
public class OpenDALController {
@Autowired
private OpenDAL openDAL;
@PostMapping("/write")
public ResponseEntity<Void> write(@RequestParam String path, @RequestBody String content) {
openDAL.write(path, content);
return ResponseEntity.ok().build();
}
@PostMapping("/writeBytes")
public ResponseEntity<Void> writeBytes(@RequestParam String path, @RequestBody byte[] content) {
openDAL.write(path, content);
return ResponseEntity.ok().build();
}
@PostMapping("/append")
public ResponseEntity<Void> append(@RequestParam String path, @RequestBody String content) {
openDAL.append(path, content);
return ResponseEntity.ok().build();
}
@PostMapping("/appendBytes")
public ResponseEntity<Void> appendBytes(@RequestParam String path, @RequestBody byte[] content) {
openDAL.append(path, content);
return ResponseEntity.ok().build();
}
@GetMapping("/stat")
public ResponseEntity<Metadata> stat(@RequestParam String path) {
Metadata metadata = openDAL.stat(path);
return ResponseEntity.ok(metadata);
}
@GetMapping("/read")
public ResponseEntity<byte[]> read(@RequestParam String path) {
byte[] content = openDAL.read(path);
return ResponseEntity.ok(content);
}
@GetMapping("/presignRead")
public ResponseEntity<PresignedRequest> presignRead(@RequestParam String path, @RequestParam long duration) {
PresignedRequest request = openDAL.presignRead(path, Duration.ofSeconds(duration));
return ResponseEntity.ok(request);
}
@GetMapping("/presignWrite")
public ResponseEntity<PresignedRequest> presignWrite(@RequestParam String path, @RequestParam long duration) {
PresignedRequest request = openDAL.presignWrite(path, Duration.ofSeconds(duration));
return ResponseEntity.ok(request);
}
@GetMapping("/presignStat")
public ResponseEntity<PresignedRequest> presignStat(@RequestParam String path, @RequestParam long duration) {
PresignedRequest request = openDAL.presignStat(path, Duration.ofSeconds(duration));
return ResponseEntity.ok(request);
}
@DeleteMapping("/delete")
public ResponseEntity<Void> delete(@RequestParam String path) {
openDAL.delete(path);
return ResponseEntity.ok().build();
}
@PostMapping("/createDir")
public ResponseEntity<Void> createDir(@RequestParam String path) {
openDAL.createDir(path);
return ResponseEntity.ok().build();
}
@PostMapping("/copy")
public ResponseEntity<Void> copy(@RequestParam String sourcePath, @RequestParam String targetPath) {
openDAL.copy(sourcePath, targetPath);
return ResponseEntity.ok().build();
}
@PostMapping("/rename")
public ResponseEntity<Void> rename(@RequestParam String sourcePath, @RequestParam String targetPath) {
openDAL.rename(sourcePath, targetPath);
return ResponseEntity.ok().build();
}
@DeleteMapping("/removeAll")
public ResponseEntity<Void> removeAll(@RequestParam String path) {
openDAL.removeAll(path);
return ResponseEntity.ok().build();
}
@GetMapping("/list")
public ResponseEntity<List<Entry>> list(@RequestParam String path) {
List<Entry> entries = openDAL.list(path);
return ResponseEntity.ok(entries);
}
} Spring WebFluxTo use OpenDALReactive with Spring WebFlux:
import com.shoothzj.opendal.spring.OpenDALReactive;
import org.apache.opendal.Entry;
import org.apache.opendal.Metadata;
import org.apache.opendal.PresignedRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.time.Duration;
@RestController
@RequestMapping("/api/v1/opendal/reactive")
public class OpenDALReactiveController {
@Autowired
private OpenDALReactive<byte[]> openDALReactive;
@PostMapping("/write")
public Mono<ResponseEntity<Void>> write(@RequestParam("path") String path, @RequestBody String content) {
return openDALReactive.write(path, content).then(Mono.just(ResponseEntity.ok().<Void>build()));
}
@PostMapping("/writeBytes")
public Mono<ResponseEntity<Void>> writeBytes(@RequestParam("path") String path, @RequestBody byte[] content) {
return openDALReactive.write(path, content).then(Mono.just(ResponseEntity.ok().<Void>build()));
}
@PostMapping("/append")
public Mono<ResponseEntity<Void>> append(@RequestParam("path") String path, @RequestBody String content) {
return openDALReactive.append(path, content).then(Mono.just(ResponseEntity.ok().<Void>build()));
}
@PostMapping("/appendBytes")
public Mono<ResponseEntity<Void>> appendBytes(@RequestParam("path") String path, @RequestBody byte[] content) {
return openDALReactive.append(path, content).then(Mono.just(ResponseEntity.ok().<Void>build()));
}
@GetMapping("/stat")
public Mono<ResponseEntity<Metadata>> stat(@RequestParam("path") String path) {
return openDALReactive.stat(path).map(ResponseEntity::ok);
}
@GetMapping("/read")
public Mono<ResponseEntity<byte[]>> read(@RequestParam("path") String path) {
return openDALReactive.read(path).map(ResponseEntity::ok);
}
@GetMapping("/presignRead")
public Mono<ResponseEntity<PresignedRequest>> presignRead(@RequestParam("path") String path, @RequestParam("duration") long duration) {
return openDALReactive.presignRead(path, Duration.ofSeconds(duration)).map(ResponseEntity::ok);
}
@GetMapping("/presignWrite")
public Mono<ResponseEntity<PresignedRequest>> presignWrite(@RequestParam("path") String path, @RequestParam("duration") long duration) {
return openDALReactive.presignWrite(path, Duration.ofSeconds(duration)).map(ResponseEntity::ok);
}
@GetMapping("/presignStat")
public Mono<ResponseEntity<PresignedRequest>> presignStat(@RequestParam("path") String path, @RequestParam("duration") long duration) {
return openDALReactive.presignStat(path, Duration.ofSeconds(duration)).map(ResponseEntity::ok);
}
@DeleteMapping("/delete")
public Mono<ResponseEntity<Void>> delete(@RequestParam("path") String path) {
return openDALReactive.delete(path).then(Mono.just(ResponseEntity.ok().<Void>build()));
}
@PostMapping("/createDir")
public Mono<ResponseEntity<Void>> createDir(@RequestParam("path") String path) {
return openDALReactive.createDir(path).then(Mono.just(ResponseEntity.ok().<Void>build()));
}
@PostMapping("/copy")
public Mono<ResponseEntity<Void>> copy(@RequestParam("sourcePath") String sourcePath, @RequestParam("targetPath") String targetPath) {
return openDALReactive.copy(sourcePath, targetPath).then(Mono.just(ResponseEntity.ok().<Void>build()));
}
@PostMapping("/rename")
public Mono<ResponseEntity<Void>> rename(@RequestParam("sourcePath") String sourcePath, @RequestParam("targetPath") String targetPath) {
return openDALReactive.rename(sourcePath, targetPath).then(Mono.just(ResponseEntity.ok().<Void>build()));
}
@DeleteMapping("/removeAll")
public Mono<ResponseEntity<Void>> removeAll(@RequestParam("path") String path) {
return openDALReactive.removeAll(path).then(Mono.just(ResponseEntity.ok().<Void>build()));
}
@GetMapping("/list")
public Flux<Entry> list(@RequestParam("path") String path) {
return openDALReactive.list(path);
}
} Testing with
|
Hi, @tisonkun, would you like to take a look? I'm not a Java expert like you are. |
Some ideas in my mind for now:
|
Looks like a good start. Perhaps create a repo for this starter and we can collaborate as normal issues + PRs. I don't think we need to include these code into the main repo since it would cause extra release burden. Let @shoothzj be the maintainer of the starters and modifying anything necessary in binding-java should be fine. |
We can only maintain writeBytes now, Java has powerful overload and generic, we can support write(Object obj) leverage jackson's serial.
I need take a deep look, but why the java binding expose this method?
|
I would be happy to help maintain the starters. :) |
Hi, @shoothzj, the subproject for spring-opendal has been started. Would you like to create a tracking issue for it? |
Thanks! |
Spring is a crucial framework in the Java ecosystem. It would be beneficial for OpenDAL to develop a spring-boot-starter-opendal, enabling Java users to seamlessly integrate OpenDAL immediately.
Notes
integrations/spring-boot
.The text was updated successfully, but these errors were encountered: