如何从 java jax-rs 服务器获取 post body 数据
How to get post body data from java jax-rs server
我遵循了一个简单的 java 服务器设置 guide。
所以我有这样的东西:
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 body 数据。我唯一可以访问的是 headers 使用 httpRequest.getHeaderNames()
.
我想做的是将每个文件存储在一个文件 object(或类似的文件)中,然后下载它。我会怎么做呢?我看过一些关于这个主题的 post,但是当我尝试实施这些解决方案时,它们似乎不起作用。
编辑:这是我的 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>
好的,您拥有的是多部分数据,它最常用于发送多个文件和元数据(或其他数据)以及这些文件。没有对多部分的标准 JAX-RS 支持,但您正在使用 Jersey(JAX-RS 实现)并且 Jersey 确实 支持多部分。您需要做的第一件事是向 pom.xml 文件
添加一个新的依赖项
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-multipart</artifactId>
<version>2.31</version>
</dependency>
接下来您需要做的是在您的应用程序中注册此功能。由于您使用的是 Application
subclass,因此您需要将 MultiPartFeature
class 添加到 getClasses()
中的 classes
@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;
}
}
现在我们可以使用这个功能了。在您的资源方法中,我们要做的是使用 Jersey 的 @FormDataParam
注释声明每个部分。正如您在多部分实体中看到的那样,每个部分都有一个名称
Content-Disposition: form-data; name="somedata1"
这里这部分的名称是somedata1
。所以我们将为这部分添加一个参数。另请注意,我将添加 @Consumes(MediaType.MULTIPART_FORM_DATA)
,因为这是我们的方法将消耗的 content-type。
@POST
@Path("upload")
@Consumes(MediaType.MULTIPART_FORM_DATA)
public Response fileUpload(@FormDataParam("somedata1") String someData1) {
...
}
根据预期的数据类型,这就是您确定参数类型的方式。 somedata1
的类型只是纯文本,这就是我使用字符串的原因。但是 numeroffiles
部分是一个数字,所以我可以为该部分使用 int
public Response fileUpload(@FormDataParam("somedata1") String someData1,
@FormDataParam("numberoffiles") int numberOfFiles) {
...
}
firtfile
部分将是一个二进制文件。那么我们可以使用 InputStream
、File
或 byte[]
参数。我们还可以添加一个类型为 FormDataContentDisposition
的附加参数,这将为我们提供有关此文件的一些信息。对于这个例子,我将使用 InputStream
。只是 google“如何将 InputStream
保存到 Java 中的文件”
public Response fileUpload(@FormDataParam("somedata1") String someData1,
@FormDataParam("numberoffiles") int numberOfFiles,
@FormDataParam("file1") InputStream firstFile,
@FormDataParam("file1") FormDataContentDisposition fdcd) {
...
String fileName = fdcd.getFileName();
}
更新
如果文件数量未知,您可以做的只是声明一个类型为 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)
方法提取body部分的数据。对于文件,您将使用 getValueAs(InputStream.class)
.
差不多就这些了。这就是您在 Jersey 中使用 multipart 的方式。如需更多信息,您可以read the complete docs
我遵循了一个简单的 java 服务器设置 guide。
所以我有这样的东西:
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 body 数据。我唯一可以访问的是 headers 使用 httpRequest.getHeaderNames()
.
我想做的是将每个文件存储在一个文件 object(或类似的文件)中,然后下载它。我会怎么做呢?我看过一些关于这个主题的 post,但是当我尝试实施这些解决方案时,它们似乎不起作用。
编辑:这是我的 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>
好的,您拥有的是多部分数据,它最常用于发送多个文件和元数据(或其他数据)以及这些文件。没有对多部分的标准 JAX-RS 支持,但您正在使用 Jersey(JAX-RS 实现)并且 Jersey 确实 支持多部分。您需要做的第一件事是向 pom.xml 文件
添加一个新的依赖项<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-multipart</artifactId>
<version>2.31</version>
</dependency>
接下来您需要做的是在您的应用程序中注册此功能。由于您使用的是 Application
subclass,因此您需要将 MultiPartFeature
class 添加到 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;
}
}
现在我们可以使用这个功能了。在您的资源方法中,我们要做的是使用 Jersey 的 @FormDataParam
注释声明每个部分。正如您在多部分实体中看到的那样,每个部分都有一个名称
Content-Disposition: form-data; name="somedata1"
这里这部分的名称是somedata1
。所以我们将为这部分添加一个参数。另请注意,我将添加 @Consumes(MediaType.MULTIPART_FORM_DATA)
,因为这是我们的方法将消耗的 content-type。
@POST
@Path("upload")
@Consumes(MediaType.MULTIPART_FORM_DATA)
public Response fileUpload(@FormDataParam("somedata1") String someData1) {
...
}
根据预期的数据类型,这就是您确定参数类型的方式。 somedata1
的类型只是纯文本,这就是我使用字符串的原因。但是 numeroffiles
部分是一个数字,所以我可以为该部分使用 int
public Response fileUpload(@FormDataParam("somedata1") String someData1,
@FormDataParam("numberoffiles") int numberOfFiles) {
...
}
firtfile
部分将是一个二进制文件。那么我们可以使用 InputStream
、File
或 byte[]
参数。我们还可以添加一个类型为 FormDataContentDisposition
的附加参数,这将为我们提供有关此文件的一些信息。对于这个例子,我将使用 InputStream
。只是 google“如何将 InputStream
保存到 Java 中的文件”
public Response fileUpload(@FormDataParam("somedata1") String someData1,
@FormDataParam("numberoffiles") int numberOfFiles,
@FormDataParam("file1") InputStream firstFile,
@FormDataParam("file1") FormDataContentDisposition fdcd) {
...
String fileName = fdcd.getFileName();
}
更新
如果文件数量未知,您可以做的只是声明一个类型为 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)
方法提取body部分的数据。对于文件,您将使用 getValueAs(InputStream.class)
.
差不多就这些了。这就是您在 Jersey 中使用 multipart 的方式。如需更多信息,您可以read the complete docs