问题与Spring's RestTemplate: complex object to query params有所不同 假设有一个请求,该请求采用对象形式的某些参数:
@GetMapping("getRoute")
public ActionResult<Response> get(@Validated GetRequest req) {
//do some logic
}
请求本身如下所示:
public class GetRequest{
private String firstField;
private Long secondField;
private ComplexObject thirdField;
private static class ComplexObject{
private String subFirstField;
private Long subSecondField;
}
}
因此,当我从RestTemplate对该对象执行查询时,我想获得一个像这样的URI:
/getRoute?firstField=val&secondField=val&thirdField.subFirstField=val&thirdField.subSecondField=val
我该怎么做?该对象绝对可以是任何东西。 更大的问题是如何将此类对象转换为UriComponentsBuilder的MultiValueMap。
如果它是POST请求,则解决方案很简单,但我需要它进行GET。
我只知道Springfox库在生成Swagger API时会使用这种方法,但是内部逻辑太复杂了。 我的情况:
@SuppressWarnings("unchecked")
public <T> ActionResult<T> getAction(String relativeUrl, Class<T> responseType, @Nullable Object paramsObject) {
UriComponentsBuilder builder = createUriComponentsBuilder(relativeUrl, paramsObject);
final ApiErrorCode errorCode;
try {
ResponseEntity<ActionResult> responseEntity = this.restTemplate.getForEntity(builder.build().toUri(), ActionResult.class);
ActionResult responseBody = responseEntity.getBody();
if (!Objects.requireNonNull(responseBody).isSuccess()) {
return responseBody;
}
return ActionResult.ok(this.mapper.convertValue(responseBody.getValue(), responseType));
} catch (RestClientException | HttpMessageNotReadableException e) {
errorCode = ApiErrorCode.API_CONNECTION_ERROR;
} catch (Exception e) {
errorCode = ApiErrorCode.INTERNAL_SERVER_ERROR;
}
return ActionResult.fail(errorCode);
}
private UriComponentsBuilder createUriComponentsBuilder(String relativeUrl, @Nullable Object object) {
String url = this.baseUrl;
if (StringUtils.hasText(relativeUrl)) {
url += relativeUrl;
}
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url);
if (object != null) {
builder.queryParams(this.convertToMultiValueMap(object));
}
return builder;
}
private MultiValueMap<String, String> convertToMultiValueMap(Object object) {
//todo object to params
}
答案 0 :(得分:0)
我不知道为什么我要投票。但是我试图进行实现,也许在某个地方可能存在无法预料的错误。
public static LinkedMultiValueMap<String, String> toUrlParams(Object value) {
final LinkedMultiValueMap<String, String> params = new LinkedMultiValueMap<>();
final List<Field> declaredFields = getAllFields(value);
for (Field field : declaredFields) {
ReflectionUtils.makeAccessible(field);
final String name = field.getName();
final Object fieldVal = ReflectionUtils.getField(field, value);
mapFields(params, name, fieldVal);
}
return params;
}
private static List<Field> getAllFields(Object t) {
final List<Field> fields = new ArrayList<>();
Class clazz = t.getClass();
while (clazz.getSuperclass() != null) {
final Field[] declaredFields = clazz.getDeclaredFields();
for (Field field : declaredFields) {
final int modifiers = field.getModifiers();
if (!(Modifier.isStatic(modifiers) || Modifier.isTransient(modifiers))) {
fields.add(field);
}
}
clazz = clazz.getSuperclass();
}
return fields;
}
private static void mapFields(LinkedMultiValueMap<String, String> params,
String fieldName,
@Nullable Object fieldVal) {
if (fieldVal != null) {
final Class<?> fieldClass = fieldVal.getClass();
if (BeanUtils.isSimpleValueType(fieldClass) || fieldVal instanceof Number || fieldVal instanceof UUID) {
if (fieldClass.isEnum()) {
params.add(fieldName, ((Enum) fieldVal).name());
} else {
params.add(fieldName, fieldVal.toString());
}
} else {
if (fieldVal instanceof Map) {
throw new IllegalArgumentException("Map is not allowed for url params");
}
if (fieldVal instanceof List) {
final Iterator iterator = ((Iterable) fieldVal).iterator();
int i = 0;
while (iterator.hasNext()) {
final Object iterElement = iterator.next();
mapFields(params, fieldName + "[" + i + "]", iterElement);
i++;
}
} else {
if (fieldVal instanceof Set) {
for (Object iterElement : ((Iterable) fieldVal)) {
mapFields(params, fieldName, iterElement);
}
} else {
if (fieldVal instanceof Collection) {
throw new IllegalArgumentException("Unknown collection, expected List or Set, but was " + fieldVal.getClass());
}
if (fieldVal.getClass().isArray()) {
final int length = Array.getLength(fieldVal);
for (int i = 0; i < length; i++) {
Object arrayElement = Array.get(fieldVal, i);
mapFields(params, fieldName + "[" + i + "]", arrayElement);
}
} else {
final List<Field> declaredFields = getAllFields(fieldVal);
for (Field field : declaredFields) {
ReflectionUtils.makeAccessible(field);
final String name = field.getName();
final Object nestedField = ReflectionUtils.getField(field, fieldVal);
mapFields(params, fieldName + "." + name, nestedField);
}
}
}
}
}
}
}