在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?
}
}
答案 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();
}
}