3

我正在尝试进行参数化获取(又名搜索)。我不确定为什么这不起作用。我们使用最新的 jersey 依赖项 (1.14),到目前为止,所有 REST 接口都可以正常工作。简单的 REST:

@Path("/some/path")
@Component
public class SomeRest {

    @GET
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
    @Produces({ MediaType.APPLICATION_JSON })
    public Response getAll(MultivaluedMap<String, String> queryParams) {

        // extract params, do search, return response as JSON
        // (Using ObjectMapper.writeValue() to convert object to JSON String)

    }
}

我认为该方法的工作原理并不重要,因为错误明确指出,由于某些不受支持的媒体类型(当我在浏览器中输入路径时),它无法首先输入它:

HTTP Status 415 - Unsupported Media Type

输出是:

SEVERE: A message body reader for Java class javax.ws.rs.core.MultivaluedMap, and Java type javax.ws.rs.core.MultivaluedMap<java.lang.String, java.lang.String>, and MIME media type application/octet-stream was not found.
The registered message body readers compatible with the MIME media type are:
....

有人有想法吗?谢谢!

编辑:

我的目标是通过使用带有 GET 资源的查询参数来实现搜索。因此,当我打电话时,/some/path我会得到所有结果,但如果我打电话,some/path?limit=10&offset=10我会得到第二组 10 个。我可以用查询参数解决这个特定问题,但我也希望能够定义 where 子句参数,如 name=foo 相同参数图。这些参数应该是动态的,因为我想创建一个通用的 getAll 方法,该方法可以在 GET 调用中获取任何参数映射。

所以我猜的问题是:如何实现动态查询参数?

4

3 回答 3

3

我认为您混淆了实际网址中的查询参数:

someurl/resource?param1=value1¶m2=value2

表单 url 编码信息格式相同,但参数在正文中。由于 GET 请求不接受正文,因此您要么意味着要执行 POST,要么要使用查询参数而不是 x-www-form-urlencoded。

祝你好运!

编辑:

如果您确切知道要输入哪些参数,则您想使用 @QueryParam,如果您不确定 URL 中需要多少/哪些查询参数,则使用 @Context UriInfo。

于 2012-09-20T13:38:32.607 回答
0

@GET来自JAX-RS。GET 请求不应包含正文。尝试使用相同的示例@POST

于 2012-09-20T13:35:49.030 回答
0

我为更复杂的问题编写了我的解决方案:map GET params throw MultivaluedMap to Object。可能对其他人有帮助。

GET 查询是与您的服务器聊天的非常简单的方法。即使是具有浏览器 url 控制的非程序员也可以执行简单的 API 任务。

但是不推荐从“get”查询创建对象的方式(原因之一是最大限制为 4000 个符号)。

GET 查询默认具有 MediaType.APPLICATION_OCTET_STREAM。

// GOAL: create simple in use API (for non-programmers) to call rest service to test functional. User can use any business object field.
//      So need map GET query params to server business object.

// Create Provider and save it in jersey rest folder (for auto detect).
// 
// PROBLEM: "get" query hasn't body and query params don't available get from readFrom prodiver method
//          So use uriInfo for getting query params 

@Provider
@Consumes(MediaType.APPLICATION_OCTET_STREAM)
public class GETQueryMapperProvider<T> implements MessageBodyReader<T> {
    //[!!!] MAIN PART: save the uri
    @Context
    private UriInfo uriInfo;

    @Override
    public boolean isReadable(Class<?> aClass, Type type, Annotation[] annotations, MediaType mediaType) {
        return true;
    }

    @Override
    public T readFrom(Class<T> tClass, Type type, Annotation[] annotations, MediaType mediaType,
                      MultivaluedMap<String, String> stringStringMultivaluedMap,
                      InputStream inputStream) throws IOException, WebApplicationException {
        MultivaluedMap queryParams = uriInfo.getQueryParameters();
        //create from Map Object
        return ServiceUtils.convertMapToObject(queryParams, tClass);
    }
}

第二部分解决方案:

public static <T> T convertMapToObject(Map map, Class<T> objectClass) {
    try {
        //[!!!] MAIN PART - MultivaluedMap for each value create list. 
        //But we list only for fields with collection type, for other need take first value. 
        map = fixCollectionsValue(map, objectClass);

        ObjectMapper ob = new ObjectMapper();
        StringWriter json = new StringWriter();
        ob.writeValue(json, map);

        return ob.readValue(json.toString(), objectClass);
    } catch (IOException e) {
        log.error(e.getMessage(), e);
    }
    return null;
}
protected static Map fixCollectionsValue(Map map, Class objectClass) {
    Map newMap = new HashMap(map);
    for(Field field : objectClass.getDeclaredFields()) {
        if(!Modifier.isStatic(field.getModifiers())
                &&!Modifier.isFinal(field.getModifiers())) {
            String name = field.getName();
            Object value = map.get(name);
            Object newValue = value;
            if(value != null) {
                if(isCollectionClass(field.getType())) {
                    if(!isCollectionClass(value.getClass())) {
                        newValue = new ArrayList();
                        ((ArrayList) newValue).add(value);
                        newMap.put(name, newValue);
                    }
                } else {
                    if(isCollectionClass(value.getClass())) {
                        //take first value to our object
                        newValue = ((Collection) newValue).iterator().next();
                        newMap.put(name, newValue);
                    }
                }
            }
        }
    }
    return newMap;
}
protected static boolean isCollectionClass(Class clazz) {
    return clazz.isArray() ||
           Collection.class.isAssignableFrom(clazz);
}
于 2013-02-13T16:29:38.500 回答