-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
261 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
--- | ||
title: PartMap | ||
status: | ||
type: new | ||
--- | ||
|
||
LightCall 提供了文件上传的支持。 | ||
|
||
!!! danger "注意" | ||
|
||
LightCall 需要在参数上添加 `@PartMap` 注解来标识该参数是一个文件上传请求。并且添加 `@PartMap` 的类必须是一个接口。 | ||
|
||
!!! | ||
|
||
我们使用的模拟数据是,他的代码可以在 [这里](https://github.com/devlive-community/lightcall/blob/dev/src/test/java/org/devlive/lightcall/example/part/map/PartMapService.java "PartMapService" "_blank") 查看。 | ||
|
||
```java | ||
public interface PartMapService | ||
{} | ||
``` | ||
|
||
### 用法 | ||
|
||
在参数上添加 `@PartMap` 注解,就可以实现文件上传请求了。 | ||
|
||
```java | ||
@Post("/upload/multiple") | ||
Object apply(@PartMap(value = "files") Map<String, File> files); | ||
``` | ||
|
||
该示例中的 `apply` 是一个文件上传请求,参数 `files` 表示要上传的文件,`"files"` 是文件参数的名称。请求路径是 `/upload/multiple`。 | ||
|
||
### 文件类型 | ||
|
||
--- | ||
|
||
`@PartMap` 注解支持 `java.io.File` 类型的参数,用于上传本地文件。 | ||
|
||
```java | ||
@Post("/upload/multiple") | ||
Object apply(@PartMap(value = "files") Map<String, File> files); | ||
``` | ||
|
||
该示例中的 `apply` 方法用于上传图片文件,参数 `image` 表示要上传的图片文件,请求路径是 `/upload/multiple`。 | ||
|
||
!!! info "提示" | ||
|
||
文件上传请求会自动设置 `Content-Type` 为 `multipart/form-data`,并将文件作为表单的一部分上传。 | ||
|
||
!!! | ||
|
||
### `mime` 类型 | ||
|
||
--- | ||
|
||
`@Part` 注解支持 `mime` 参数,用于指定上传文件的 MIME 类型,默认值为 `application/octet-stream`。 | ||
|
||
```java | ||
@Post("/upload/multiple") | ||
Object apply(@PartMap(value = "files") Map<String, File> files); | ||
``` | ||
|
||
该示例中的 `apply` 方法用于上传图片文件,参数 `image` 表示要上传的图片文件,请求路径是 `/upload`,文件的 MIME 类型是 `image/jpeg`。 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
25 changes: 25 additions & 0 deletions
25
lightcall-core/src/main/java/org/devlive/lightcall/annotation/PartMap.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package org.devlive.lightcall.annotation; | ||
|
||
import java.lang.annotation.Documented; | ||
import java.lang.annotation.ElementType; | ||
import java.lang.annotation.Retention; | ||
import java.lang.annotation.RetentionPolicy; | ||
import java.lang.annotation.Target; | ||
|
||
@Documented | ||
@Target(ElementType.PARAMETER) | ||
@Retention(RetentionPolicy.RUNTIME) | ||
public @interface PartMap | ||
{ | ||
String value(); | ||
|
||
/** | ||
* 指定所有文件的 MIME 类型,如果为空则自动检测 | ||
*/ | ||
String mimeType() default "application/octet-stream"; | ||
|
||
/** | ||
* 是否必需 | ||
*/ | ||
boolean required() default true; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
93 changes: 93 additions & 0 deletions
93
lightcall-core/src/main/java/org/devlive/lightcall/handler/PartMapHandler.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
package org.devlive.lightcall.handler; | ||
|
||
import com.fasterxml.jackson.core.JsonProcessingException; | ||
import lombok.extern.slf4j.Slf4j; | ||
import okhttp3.MediaType; | ||
import okhttp3.MultipartBody; | ||
import okhttp3.RequestBody; | ||
import org.devlive.lightcall.RequestContext; | ||
import org.devlive.lightcall.RequestException; | ||
import org.devlive.lightcall.annotation.PartMap; | ||
|
||
import java.io.File; | ||
import java.lang.reflect.Parameter; | ||
import java.util.Map; | ||
|
||
@Slf4j | ||
public class PartMapHandler | ||
implements ParameterHandler | ||
{ | ||
private final RequestContext context; | ||
|
||
private PartMapHandler(RequestContext context) | ||
{ | ||
this.context = context; | ||
} | ||
|
||
public static PartMapHandler create(RequestContext context) | ||
{ | ||
if (context == null) { | ||
throw new NullPointerException("RequestContext cannot be null"); | ||
} | ||
log.debug("Creating PartMapHandler"); | ||
return new PartMapHandler(context); | ||
} | ||
|
||
@Override | ||
public boolean canHandle(Parameter parameter) | ||
{ | ||
return parameter.isAnnotationPresent(PartMap.class); | ||
} | ||
|
||
@Override | ||
public String handle(Parameter parameter, Object arg, String path) | ||
{ | ||
if (arg == null) { | ||
PartMap annotation = parameter.getAnnotation(PartMap.class); | ||
if (annotation.required()) { | ||
throw new IllegalArgumentException("PartMap is required but was null"); | ||
} | ||
return path; | ||
} | ||
|
||
if (!(arg instanceof Map)) { | ||
throw new IllegalArgumentException("Parameter annotated with @PartMap must be a Map"); | ||
} | ||
|
||
Map<?, ?> map = (Map<?, ?>) arg; | ||
MultipartBody.Builder multipartBuilder = new MultipartBody.Builder() | ||
.setType(MultipartBody.FORM); | ||
|
||
PartMap annotation = parameter.getAnnotation(PartMap.class); | ||
String formName = annotation.value(); // 获取表单字段名前缀 | ||
String mimeType = annotation.mimeType(); | ||
|
||
for (Map.Entry<?, ?> entry : map.entrySet()) { | ||
Object value = entry.getValue(); | ||
|
||
if (value instanceof File) { | ||
File file = (File) value; | ||
RequestBody fileBody = RequestBody.create( | ||
file, | ||
MediaType.parse(mimeType) | ||
); | ||
|
||
multipartBuilder.addFormDataPart( | ||
formName, | ||
file.getName(), | ||
fileBody | ||
); | ||
log.debug("Added file part {}: {}", formName, file.getName()); | ||
} | ||
} | ||
|
||
try { | ||
context.setBody(multipartBuilder.build(), MultipartBody.FORM); | ||
} | ||
catch (JsonProcessingException e) { | ||
throw new RequestException("Failed to set form parts", e); | ||
} | ||
|
||
return path; | ||
} | ||
} |
13 changes: 13 additions & 0 deletions
13
lightcall-core/src/test/java/org/devlive/lightcall/example/part/map/PartMapService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package org.devlive.lightcall.example.part.map; | ||
|
||
import org.devlive.lightcall.annotation.PartMap; | ||
import org.devlive.lightcall.annotation.Post; | ||
|
||
import java.io.File; | ||
import java.util.Map; | ||
|
||
public interface PartMapService | ||
{ | ||
@Post("/upload/multiple") | ||
Object apply(@PartMap(value = "files") Map<String, File> files); | ||
} |
40 changes: 40 additions & 0 deletions
40
lightcall-core/src/test/java/org/devlive/lightcall/example/part/map/PartMapServiceTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package org.devlive.lightcall.example.part.map; | ||
|
||
import org.devlive.lightcall.LightCall; | ||
import org.devlive.lightcall.config.LightCallConfig; | ||
import org.junit.jupiter.api.Assertions; | ||
import org.junit.jupiter.api.Test; | ||
import org.junit.jupiter.api.io.TempDir; | ||
|
||
import java.io.File; | ||
import java.nio.file.Path; | ||
import java.util.HashMap; | ||
import java.util.Map; | ||
|
||
class PartMapServiceTest | ||
{ | ||
// 使用一个支持文件上传的测试服务 | ||
private final LightCallConfig config = LightCallConfig.create("http://mockaroo.devlive.org"); | ||
private final PartMapService service = LightCall.create(PartMapService.class, config); | ||
|
||
@Test | ||
void testFileUpload(@TempDir Path tempDir) | ||
throws Exception | ||
{ | ||
// 创建测试文件 | ||
File testFile = tempDir.resolve("test.txt").toFile(); | ||
testFile.createNewFile(); | ||
|
||
// 创建测试文件 | ||
File testFile2 = tempDir.resolve("test2.txt").toFile(); | ||
testFile2.createNewFile(); | ||
|
||
Map<String, File> files = new HashMap<>(); | ||
files.put("file1", testFile); | ||
files.put("file2", testFile2); | ||
|
||
// 测试文件上传 | ||
Object response = service.apply(files); | ||
Assertions.assertNotNull(response); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters