我有一个rest API(PUT动词),它可以接受请求正文和路径参数:
例如:
curl --data {a:1,b:2} -X PUT“ https://example.com/users/ {username} / address / {addressname}”
我正在尝试在一个POJO中同时获取请求正文和路径参数
Response myAPI(@BeanParam Users user){
system.out.println(user.username);
system.out.println(user.a);
用户分类
public class Users{
@PathParam(username)
private String userName;
......
private String a;
......
}
但是我得到user.a的值为null。 如何在同一个类中解析请求正文和参数?
答案 0 :(得分:0)
您可以使用自定义注释和InjectionResolver
进行此操作。 InjectionResolver
的作用是允许您使用自己的注释创建自定义注入点。所以你可以做类似的事情
public class Users {
@PathParam(username)
private String userName;
@Body
private String a;
}
在实现InjectionResolver
时,您将使用ContainerRequest
方法从ContainerRequest#readEntity(Class)
获取实际主体。您可以通过对Class
内获得的Field
进行一些思考来确定要通过的InjectionResolver
。以下是使用Jersey Test Framework的完整示例。像其他任何JUnit测试一样运行它。
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Field;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.ws.rs.BeanParam;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.Response;
import org.glassfish.hk2.api.Injectee;
import org.glassfish.hk2.api.InjectionResolver;
import org.glassfish.hk2.api.ServiceHandle;
import org.glassfish.hk2.api.TypeLiteral;
import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.glassfish.jersey.server.ContainerRequest;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Test;
/**
* Only one required dependency to run this test. Note this is using 2.25.1.
* If you are using 2.26 or later, the implementation will be different,
* and this will not work. You need to use the Jersey packaged `InjectionResolver`,
* not the HK2 one. And you will also need to bind that `InjectionResolver`
* to `GenericType` instead of `TypeLiteral` in the `AbstractBinder#configure()`.
*
* <dependency>
* <groupId>org.glassfish.jersey.test-framework.providers</groupId>
* <artifactId>jersey-test-framework-provider-grizzly2</artifactId>
* <version>2.25.1</version>
* <scope>test</scope>
* </dependency>
*/
public class BeanParamTest extends JerseyTest {
@Path("test")
@Consumes("application/json")
@Produces("application/json")
public static class TestResource {
@POST
@Path("{username}")
public String post(@BeanParam ModelBean bean) {
return bean.toString();
}
}
@Override
public ResourceConfig configure() {
return new ResourceConfig(TestResource.class)
.register(new AbstractBinder() {
@Override
protected void configure() {
bind(BodyInjectionResolver.class)
.to(new TypeLiteral<InjectionResolver<Body>>() {})
.in(Singleton.class);
}
});
}
@Test
public void testIt() {
final Response res = target("test/peeskillet")
.request()
.post(Entity.json("{\"foo\":\"bar\"}"));
System.out.println(res.readEntity(String.class));
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface Body {}
public static class ModelBean {
@PathParam("username")
private String username;
@Body
private String body;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
@Override
public String toString() {
return "ModelBean{" +
"username='" + username + '\'' +
", body='" + body + '\'' +
'}';
}
}
public static class BodyInjectionResolver implements InjectionResolver<Body> {
@Inject
private javax.inject.Provider<ContainerRequest> requestProvider;
@Override
public Object resolve(Injectee injectee, ServiceHandle<?> serviceHandle) {
if (injectee.getParent().isAnnotationPresent(Body.class)) {
AnnotatedElement parent = injectee.getParent();
if (parent instanceof Field) {
Class<?> entityType = ((Field) parent).getType();
return requestProvider.get().readEntity(entityType);
}
}
return null;
}
@Override
public boolean isConstructorParameterIndicator() {
return false;
}
@Override
public boolean isMethodParameterIndicator() {
return false;
}
}
}