我有一个rest API(PUT动词),它可以接受请求正文和路径参数:
I have a rest API (PUT verb) which accepts both request body and path params:
例如:
curl --data {a:1,b:2} -X PUT" example /users/ {username}/address/{addressname}"
curl --data {a:1, b:2} -X PUT "example/users/{username}/address/{addressname}"
我正在尝试在一个POJO中同时获取请求正文和路径参数
I am trying to fetch both request body and path param in one 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. 如何在同一类中解析请求正文和参数?
But I am getting value of user.a as null. How to parse both request body and param in same class?
推荐答案您可以使用自定义注释和InjectionResolver进行此操作. InjectionResolver的作用是允许您使用自己的注释创建自定义注入点.所以你可以做类似的事情
You can do this with a custom annotation and an InjectionResolver. What the InjectionResolver does is allow you to create a custom injection point with your own annotation. So you could do something like
public class Users { @PathParam(username) private String userName; @Body private String a; }实现InjectionResolver时,您将使用ContainerRequest#readEntity(Class)方法从ContainerRequest中获取实际主体.您可以通过对Field进行一些反射来确定要通过的Class,您可以在InjectionResolver内部获得该反射.以下是使用 Jersey测试框架的完整示例.像其他任何JUnit测试一样运行它.
When implementing the InjectionResolver, you would grab the actual body from the ContainerRequest using the ContainerRequest#readEntity(Class) method. You would determine the Class to pass by doing some reflection on the Field that you can obtain inside the InjectionResolver. Below is a complete example using Jersey Test Framework. Run it like any other JUnit test.
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; } } }更多推荐
如何在REST API中解析请求参数(查询和路径参数)和同一POJO中的请求正文
发布评论