英文:
How to get post body data from java jax-rs server
问题
我按照一个简单的Java服务器设置指南进行了操作。
所以我有类似这样的东西:
MyApp.java
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
import java.util.HashSet;
import java.util.Set;
@ApplicationPath("/")
public class MyApplication extends Application {
@Override
public Set<Class<?>> getClasses() {
Set<Class<?>> h = new HashSet<>();
h.add(HelloWorld.class);
return h;
}
}
HelloWord.java
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.Part;
import javax.ws.rs.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Request;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;
@Path("/helloworld")
public class HelloWorld {
@Context
private HttpServletRequest httpRequest;
@GET
@Produces("text/plain")
public String getClichedMessage() {
return "Hello, World!";
}
@POST
@Consumes()
@Produces("text/plain")
public String doThis(String x) {
System.out.println(x);
//....
}
}
传入的请求类型是:
content-type = multipart/form-data; boundary=somerandstuff
看起来像这样:
--somerandstuff
Content-Disposition: form-data; name="somedata1"
data text 1here
--somerandstuff
Content-Disposition: form-data; name="somedata2"
more data text here
--somerandstuff
Content-Disposition: form-data; name="numberoffiles"
3
--somerandstuff
Content-Disposition: form-data; name="file1"; filename="firstfile"
Content-Type: application/octet-stream
{unreadable symbols thing here}
.
.
. 2 more files like above
我该如何实际读取数据?我尝试了许多方法,但无法使其正常工作。我尝试使用httpRequest.getParameterMap()
和httpRequest.getParameterNames()
并打印所有内容,但没有任何打印输出。我甚至似乎无法访问POST主体数据。我唯一可以访问的是使用httpRequest.getHeaderNames()
获取的标头。
我想要做的是将每个文件存储在File对象(或类似的对象)中,然后下载它。我应该如何做到这一点?我查看了一些关于此主题的帖子,但是当我尝试实现解决方案时,它们似乎不起作用。
编辑:这是我的pom.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.serverproject</groupId>
<artifactId>serverProject</artifactId>
<version>1.0-SNAPSHOT</version>
<name>serverProject</name>
<packaging>war</packaging>
<properties>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
<junit.version>5.6.2</junit.version>
</properties>
<dependencies>
<!-- Dependencies... -->
</dependencies>
<build>
<plugins>
<!-- Plugins... -->
</plugins>
</build>
</project>
英文:
I followed a simple java server setup guide.
So i have something like this:
MyApp.java
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
import java.util.HashSet;
import java.util.Set;
@ApplicationPath("/")
public class MyApplication extends Application {
@Override
public Set<Class<?>> getClasses() {
Set<Class<?>> h = new HashSet<>();
h.add( HelloWorld.class );
return h;
}
}
and HelloWord.java
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.Part;
import javax.ws.rs.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Request;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;
@Path("/helloworld")
public class HelloWorld {
@Context
private HttpServletRequest httpRequest;
@GET
@Produces("text/plain")
public String getClichedMessage() {
return "Hello, World!";
}
@POST
@Consumes()
@Produces("text/plain")
public String doThis(String x) {
System.out.println(x);
//....
}
}
The incoming request is of type
content-type = multipart/form-data; boundary=somerandstuff
and looks like :
--somerandstuff
Content-Disposition: form-data; name="somedata1"
data text 1here
--somerandstuff
Content-Disposition: form-data; name="somedata2"
more data text here
--somerandstuff
Content-Disposition: form-data; name="numberoffiles"
3
--somerandstuff
Content-Disposition: form-data; name="file1"; filename="firstfile"
Content-Type: application/octet-stream
{unreadable symbols thing here}
.
.
. 2 more files like above
How do I go about actually reading the data? I've tried many things and can't get it to work. I tried using httpRequest.getParameterMap()
and httpRequest.getParameterNames()
and printing everything but nothing prints. I can't seem to even access the post body data. The only things I can access are the headers using httpRequest.getHeaderNames()
.
What I want to do is store each file in a File object (or something similar) and then download it. How would i go about doing that? I've looked at a few posts on this topic but when I try implementing the solutions, they don't seem to work.
Edit: here is my pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.serverproject</groupId>
<artifactId>serverProject</artifactId>
<version>1.0-SNAPSHOT</version>
<name>serverProject</name>
<packaging>war</packaging>
<properties>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
<junit.version>5.6.2</junit.version>
</properties>
<dependencies>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<version>8.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>2.31</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>2.31</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.inject</groupId>
<artifactId>jersey-hk2</artifactId>
<version>2.31</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
<version>2.31</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.3.0</version>
</plugin>
</plugins>
</build>
</project>
答案1
得分: 2
以下是翻译好的内容:
<!-- 添加以下依赖到你的 pom.xml 文件 -->
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-multipart</artifactId>
<version>2.31</version>
</dependency>
// 在你的 Application 子类中注册 MultiPartFeature 类
@ApplicationPath("/")
public class MyApplication extends Application {
@Override
public Set<Class<?>> getClasses() {
Set<Class<?>> h = new HashSet<>();
h.add(HelloWorld.class);
h.add(MultiPartFeature.class);
return h;
}
}
// 在资源方法中使用 @FormDataParam 注解声明每个部分
@POST
@Path("upload")
@Consumes(MediaType.MULTIPART_FORM_DATA)
public Response fileUpload(@FormDataParam("somedata1") String someData1,
@FormDataParam("numberoffiles") int numberOfFiles,
@FormDataParam("file1") InputStream firstFile,
@FormDataParam("file1") FormDataContentDisposition fdcd) {
// 根据期望的数据类型来确定参数类型
// ...
}
// 如果文件数量未知,可以使用 FormDataMultiPart 类来提取每个部分
public Response fileUpload(FormDataMultiPart multipart) {
Map<String, List<FormDataBodyPart>> bodyParts = multipart.getFields();
FormDataBodyPart someDataPart = multipart.getField("somedata1");
String someData = someDataPart.getValueAs(String.class);
// 遍历 FormDataBodyPart 并使用 bodyPart.getValueAs(Class) 方法提取数据
// ...
}
更多信息,请查阅完整文档。
英文:
Ok so what you have is multipart data, which is most commonly used to send multiple files and metadata (or other data) along with those files. There is no standard JAX-RS support for multipart, but you are using Jersey (a JAX-RS implementation) and Jersey does have support for multipart. The first thing you need to do is add a new dependency to your pom.xml file
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-multipart</artifactId>
<version>2.31</version>
</dependency>
The next thing you need to do is register this feature with your application. Since you are using an Application
subclass, you would add the MultiPartFeature
class to the classes in getClasses()
@ApplicationPath("/")
public class MyApplication extends Application {
@Override
public Set<Class<?>> getClasses() {
Set<Class<?>> h = new HashSet<>();
h.add(HelloWorld.class);
h.add(MultiPartFeature.class);
return h;
}
}
Now we can use this feature. In your resource method, what we will do is declare each part using Jersey's @FormDataParam
annotation. As you can see in the multipart entity, each part has a name
Content-Disposition: form-data; name="somedata1"
Here the name of this part is somedata1
. So we will add a parameter for this part. Also notice I will add @Consumes(MediaType.MULTIPART_FORM_DATA)
as that is the content-type our method will be consuming.
@POST
@Path("upload")
@Consumes(MediaType.MULTIPART_FORM_DATA)
public Response fileUpload(@FormDataParam("somedata1") String someData1) {
...
}
Based on what type of data is expected, that's how you will determine the parameter type. The type of somedata1
is just plain text, that's why I used a String. But the numeroffiles
part is a number, so I can use an int
for that part
public Response fileUpload(@FormDataParam("somedata1") String someData1,
@FormDataParam("numberoffiles") int numberOfFiles) {
...
}
The firtfile
part is going to be a binary file. So what we can use an InputStream
, File
, or byte[]
parameter. We can also add an additional parameter of type FormDataContentDisposition
which will give us some info about this file. For this example, I will use an InputStream
. Just google "how to save an InputStream
to a file in Java"
public Response fileUpload(@FormDataParam("somedata1") String someData1,
@FormDataParam("numberoffiles") int numberOfFiles,
@FormDataParam("file1") InputStream firstFile,
@FormDataParam("file1") FormDataContentDisposition fdcd) {
...
String fileName = fdcd.getFileName();
}
UPDATE
If the number of files is unknown, instead of decalring all these separate parts, what you can do is just declare one parameter of type FormDataMultiPart
and programmatically extract each part
public Response fileUpload(FormDataMultiPart multipart) {
Map<String,List<FormDataBodyPart>> bodyParts = multipart.getFields();
FormDataBodyPart someDataPart = multipart.getField("somedata1");
String someData = someDataPart.getValueAs(String.class);
}
You will need to traverse all the FormDataBodyPart
s and you use the bodyPart.getValueAs(Class)
method to extract the data of the body part. For the files, you would use getValueAs(InputStream.class)
.
And that's pretty much it. That's how you work with multipart in Jersey. For more info, you can read the complete docs
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论