根据表单数据过滤泽西请求

时间:2014-08-28 20:58:09

标签: jersey jersey-2.0

在Jersey 1.x中,您可以使用ContainerRequest.getFormParameters()对表单数据进行请求过滤,但我在Jersey 2.x中看不到明显的等效内容。我已经实现了ContainerRequestFilter界面,可以访问ContainerRequestContext,但是从那里可以获取表单数据?

Jersey 1.x例子:

public class MyFilter implements ContainerRequestFilter {
  public ContainerRequest filter(ContainerRequest request) {
    Form f = request.getFormParameters();

    // examine form data and filter as needed
  }
}

Jersey 2.x示例:

public class MyFilter implements ContainerRequestFilter {
  public void filter(ContainerRequestContext context) {
    // how do I get to the Form data now?
  }
}

4 个答案:

答案 0 :(得分:17)

经过大量的搜索和反复试验后,我找到了一种合适的方法在Jersey 2中执行此操作。您必须手动使用请求实体主体,但是您必须小心谨慎地执行此操作。 #39;防止后续过滤器和资源也使用它。下面是一个将实体读入Form对象的简单示例:

@Provider
public class FormDataFilter implements ContainerRequestFilter
{
    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException
    {
        if (requestContext instanceof ContainerRequest)
        {
            ContainerRequest request = (ContainerRequest) requestContext;

            if ( requestContext.hasEntity()
              && MediaTypes.typeEqual(MediaType.APPLICATION_FORM_URLENCODED_TYPE,request.getMediaType()))
            {
                request.bufferEntity();
                Form f = request.readEntity(Form.class);
            }
        }
    } 
}

关键是调用bufferEntity()。如果没有这个,实体将被标记为已关闭,并在任何后续读取尝试时导致IllegalStateExceptions。

答案 1 :(得分:3)

表单POST参数是在http请求体中发送的,所以使用ContainerRequestContext可以做类似的事情

String q = IOUtils.toString(context.getEntityStream(), Charsets.UTF_8);
String[] params = q.split("&");  
Map<String, String> map = new HashMap<>();  
 for (String param : params)  
 {  
     String name = param.split("=")[0];  
     String value = param.split("=")[1];  
     map.put(name, value);  
 }  

答案 2 :(得分:1)

这是一种在不依赖于特定于实现的类的情况下读取表单实体的方法,即它可以与Jersey(v2)或CXF(v3)一起使用。

@Provider
public class AFilter implements ContainerRequestFilter {

    @Context
    private Providers providers;

    @Override
    public void filter(ContainerRequestContext request) throws IOException {
        if (!request.hasEntity() || !MediaTypes.typeEqual(APPLICATION_FORM_URLENCODED_TYPE, request.getMediaType())) {
            // if not a form ...
            return;
        }

        ByteArrayInputStream resettableIS = toResettableStream(request.getEntityStream());

        Form form = providers.getMessageBodyReader(Form.class, Form.class, new Annotation[0], APPLICATION_FORM_URLENCODED_TYPE)
                             .readFrom(Form.class, Form.class, new Annotation[0], APPLICATION_FORM_URLENCODED_TYPE, null, resettableIS);

        // do something with Form

        resettableIS.reset();
        request.setEntityStream(resettableIS);
    }

    @Nonnull
    private ByteArrayInputStream toResettableStream(InputStream entityStream) throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len;
        while ((len = entityStream.read(buffer)) > -1) {
            baos.write(buffer, 0, len);
        }
        baos.flush();
        return new ByteArrayInputStream(baos.toByteArray());
    }
}

这很好用,并且只使用JAX-RS API,因此是可移植的。

但请注意,CXF 2.x使用的JAX-RS API 2.0-m10还没有Form类。在这种情况下,可以简单地以Form.class替换MultivaluedMap.class,价格为某些未经检查/原始类型的警告。

答案 3 :(得分:0)

查看jersey 1实现,似乎ContainerRequest#getEntity(Class)支持将实体流直接读入Form类。

getEntity已在球衣2中重命名为readEntity,因此以下内容可能有效(未经测试):

  

Form params = request.readEntity(Form.class);

来自球衣1 impl的推荐impl(被盗和略微修改):

/**
 * Stolen from the jersey 1 impl
 */
public static Form getFormParameters(ContainerRequest request) {
    if (MediaTypes.typeEqual(MediaType.APPLICATION_FORM_URLENCODED_TYPE, request.getMediaType())) {
        InputStream in = request.getEntityStream();
        if (in.getClass() != ByteArrayInputStream.class) {
            // Buffer input
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            try {
                ReaderWriter.writeTo(in, baos);
            } catch (IOException e) {
                throw new IllegalArgumentException(e);
            }

            in = new ByteArrayInputStream(baos.toByteArray());
            request.setEntityStream(in);
        }

        ByteArrayInputStream bais = (ByteArrayInputStream) in;
        Form f = request.readEntity(Form.class);
        bais.reset();
        return f;
    } else {
        return new Form();
    }
}