Java Jersey REST-发送多值映射以获取不支持的媒体类型
我正在尝试进行参数化get(又名搜索)。我不知道这为什么不起作用。我们使用最新的jersey依赖项(1.14),到目前为止,所有REST接口都工作正常。 简单休息:Java Jersey REST-发送多值映射以获取不支持的媒体类型,java,http,rest,jersey,mime-types,Java,Http,Rest,Jersey,Mime Types,我正在尝试进行参数化get(又名搜索)。我不知道这为什么不起作用。我们使用最新的jersey依赖项(1.14),到目前为止,所有REST接口都工作正常。 简单休息: @Path("/some/path") @Component public class SomeRest { @GET @Consumes(MediaType.APPLICATION_FORM_URLENCODED) @Produces({ MediaType.APPLICATION_JSON })
@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)
}
}
输出为:
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:
....
SEVERE:找不到Java类javax.ws.rs.core.MultivaluedMap、Java类型javax.ws.rs.core.MultivaluedMap和MIME媒体类型应用程序/八位字节流的消息正文读取器。
与MIME媒体类型兼容的已注册邮件正文读取器包括:
....
有人有主意吗?
谢谢
编辑:
我的目标是通过使用GET资源的查询参数来实现搜索。因此,当我调用/some/path
时,我会得到所有结果,但如果我调用some/path?limit=10&offset=10,我会得到第二组10。我可以用查询参数解决这个特定问题,但我也希望能够在同一个参数映射中定义where子句参数,比如name=foo。这些参数应该是动态的,因为我想创建一个通用的getAll方法,它可以在GET调用中获取任何参数映射
所以我想问题是:如何实现动态查询参数?@GET
来自。GET请求不应包含正文。使用@POST
尝试相同的示例,我认为您混淆了实际url中的查询参数:
someurl/resource?param1=value1¶m2=value2
表单url编码信息的格式相同,但参数位于正文中。由于GET请求不包含正文,您的意思可能是希望执行POST,也可能是希望使用查询参数而不是x-www-form-urlencoded
祝你好运
编辑:
如果您确切地知道要输入哪些参数,那么您需要使用@QueryParam;如果您不确定URL中需要多少/哪些查询参数,那么您需要使用@Context UriInfo。我为更复杂的问题编写了解决方案:map GET params throw MultivaluedMap to Object。也许这对其他人会有帮助
获取查询是与服务器聊天的一种非常简单的方式。即使是具有浏览器url控件的非程序员也可以执行简单的API任务
但不推荐使用“get”查询创建对象的方式(原因之一是最大限制为4000个符号)
默认情况下,GET查询具有MediaType.APPLICATION\u OCTET\u流
// 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);
}
}
//目标:创建简单的使用中API(针对非程序员)来调用rest服务来测试功能。用户可以使用任何业务对象字段。
//所以需要将GET查询参数映射到服务器业务对象。
//创建提供程序并将其保存在jersey rest文件夹中(用于自动检测)。
//
//问题:“get”查询没有正文,并且查询参数不可用从readFrom ProDriver方法获取
//因此,请使用uriInfo获取查询参数
@提供者
@消耗(MediaType.APPLICATION\u八位字节\u流)
公共类GETQueryMapperProvider实现MessageBodyReader{
//[!!!]主要部分:保存uri
@上下文
私人UriInfo UriInfo;
@凌驾
公共布尔值可读取(类aClass,类型类型,注释[]注释,MediaType MediaType){
返回true;
}
@凌驾
public T readFrom(类tClass、类型Type、注释[]注释、MediaType、MediaType、,
多值映射字符串多值映射,
InputStream(InputStream)引发IOException、WebApplicationException{
多值Map queryParams=uriInfo.getQueryParameters();
//从地图对象创建
返回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);
}
publicstatict convertMapToObject(映射映射,类objectClass){
试一试{
//[!!!]主要部分-每个值创建列表的多值映射。
//但我们只列出集合类型的字段,其他需要取第一个值。
map=fixCollectionsValue(map,objectClass);
ObjectMapper ob=新的ObjectMapper();
StringWriter json=新的StringWriter();
ob.writeValue(json,map);
返回ob.readValue(json.toString(),objectClass);
}捕获(IOE异常){
log.error(e.getMessage(),e);
}
返回null;
}
受保护的静态映射fixCollectionsValue(映射映射,类objectClass){
Map newMap=新HashMap(Map);
for(字段:objectClass.getDeclaredFields()){
如果(!Modifier.isStatic(field.getModifiers())
&&!Modifier.isFinal(field.getModifiers())){
字符串名称=field.getName();
对象值=map.get(名称);
对象newValue=value;
if(值!=null){
if(isCollectionClass(field.getType())){
如果(!isCollectionClass(value.getClass())){
newValue=newArrayList();
((ArrayList)newValue).add(value);
newMap.put(名称,newValue);
}
}否则{
if(isCollectionClass(value.getClass())){
//将第一个值带到我们的对象
newValue=((集合)newValue).iterator().next();
newMap.put(名称,newValue);
}
}
}
}
}
返回newMap;
}
受保护的静态布尔isCollectionClass(clazz类){
返回clazz.isArray()||
Collection.class.isAssignableFrom(clazz);
}
您可以发布HTTP请求吗?我猜你把FormParams和QueryParams搞混了我认为他想要像这样的查询参数?param1=value1¶m2=。。。这是我的猜测。。那么,如果我想实现搜索,我应该怎么做?那总是一个帖子吗?如何区分create调用的POST和get调用的POST?PS:我认为最好将搜索参数作为表单参数,而不是查询参数。。但这仍然意味着P
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);
}