не удается правильно передать параметр json списка

#java

Вопрос:

Я хочу использовать RestTemplate на основе OKHttp3 для удаленного вызова интерфейса queryByIds для получения основной информации о пользователе.

 @Configuration
public class CloudConfig {
    
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate(new OkHttp3ClientHttpRequestFactory());
    }
}
 

способ реализации queryByIds приведен ниже:

 
    @GetMapping("/queryByIds")
    public GraceJSONResult queryByIds(@RequestParam String userIds) {
        if (StringUtils.isBlank(userIds)) {
            return GraceJSONResult.errorCustom(ResponseStatusEnum.USER_NOT_EXIST_ERROR);
        }
        List<String> userIdList = JsonUtils.jsonToList(userIds, String.class);
        ArrayList<AppUserVO> userVOList = new ArrayList<>();
        assert userIdList != null;
        userIdList.forEach(id -> {
            AppUserVO userInfo = getBasicUserInfo(id);
            userVOList.add(userInfo);
        });
        return GraceJSONResult.ok(userVOList);
    }
 

Вот код бизнеса, http://user.mootalk.com который переключен на localhost использование коммутаторов:

         // Get the basic information of each user and put it in userVOList
        String userServerUrlExecute = "http://user.mootalk.com:8003/user/queryByIds?userIds="   JsonUtils.objectToJson(publisherIdSet);

        System.out.println(userServerUrlExecute);

        // the debugger paused
        ResponseEntity<GraceJSONResult> entity =
                restTemplate.getForEntity(userServerUrlExecute, GraceJSONResult.class);
        
 

Вот мой класс util:

 import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.util.List;

/**
 * json converter
 */
public class JsonUtils {
    
    private static final ObjectMapper MAPPER = new ObjectMapper();
    
    
    public static String objectToJson(Object data) {
        try {
            String string = MAPPER.writeValueAsString(data);
            return string;
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }
    
    
    public static <T> T jsonToPojo(String jsonData, Class<T> beanType) {
        try {
            T t = MAPPER.readValue(jsonData, beanType);
            return t;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    
    
    public static <T> List<T> jsonToList(String jsonData, Class<T> beanType) {
        JavaType javaType = MAPPER.getTypeFactory().constructParametricType(List.class, beanType);
        try {
            List<T> list = MAPPER.readValue(jsonData, javaType);
            return list;
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        return null;
    }
    
}
 

Когда я отлаживал код ,он не входил в queryByIds метод, и консоль напечатала userServerUrlExecute следующее:
введите описание изображения здесь

Но если вы создадите запрос в Postman следующим образом: http://user.mootalk.com:8003/user/queryByIds?userIds=210726G71HSY2YY8 , он может войти в queryByIds метод, но userIdList он оказался нулевым.

Если вы создадите запрос в Postman следующим образом : http://user.mootalk.com:8003/user/queryByIds?userIds=["210726G71HSY2YY8","200628AFYM7AGWPH"] ,он хорошо работает.

Так что же не так с моим кодом при передаче параметра?


Более позднее сообщение1:

  1. Теперь последний запрос на создание не вошел queryByIds как в адресную строку Chrome, так и в почтальона, он выдал 400 Bad Request ;
  2. Я заменил @RequestParam на @RequestBody in queryByIds , он все равно бросил 400 Bad Request

Последнее сообщение2:

  1. Теперь это работает…с тем же кодом. Это действительно загадка. введите описание изображения здесь

Комментарии:

1. Что вы, вероятно, хотите сделать, так это закодировать его base64 и передать, userIds а затем декодировать с другой стороны.

2. Как сказал @Popeye, проблема в том, что вам нужно закодировать свой JSON, если вы используете его в качестве параметра url. Тем не менее, я бы сказал, что передача JSON в качестве параметра GET довольно неприятна. Чтобы решить вашу проблему и сделать ваш API немного проще для понимания, я бы передал данные JSON в теле запроса

3. @m-alorda прав, просто потому, что ты можешь, не значит, что ты должен. Что-то еще, что следует учитывать, если вы хотите перейти по URL-адресу, я бы, вероятно, подумал о том, чтобы сделать это в виде списка, разделенного запятыми, вместо JSON. Задайте себе вопрос, получаете ли вы что-нибудь от того, что это JSON, если это просто список идентификаторов? Почему ты просто не можешь это сделать ?userIds=210726G71HSY2YY8,200628AFYM7AGWPH ? Если вы посмотрите на свой код, вы ничего не получите, если он будет JSON.

4. @Popeye это также возможно, просто добавьте несколько значений в значение параметра без JSON. Тем не менее, чтобы позволить spring справиться с этим, я бы предложил использовать URI как таковой: ?userIds=XXXXXamp;userIds=YYYYY

5. @m-alorda , позже я использовал твой метод , и он сработал.

Ответ №1:

На самом деле я бы не стал просто передавать JSON в параметр запроса, как вы делаете, это неприятно и на самом деле не соответствует никакому стандарту API RESTFUL.

У вас есть 4 варианта, как я это вижу:

  1. Перейдите к запросу HTTP POST и передайте данные JSON в тело запроса (рекомендуется и следует рекомендациям).
  2. Если по каким-либо причинам ваши требования таковы, что это должен быть запрос HTTP GET и должен быть параметр запроса, то вам необходимо кодировать JSON в base64 перед его передачей.

?userIds=W1wiMjEwNzI2RzcxSFNZMllZOFwiLFwiMjAwNjI4QUZZTTdBR1dQSFwiXQ==

  1. Опять же, если это должен быть запрос HTTP GET, но он не обязательно должен быть JSON, я бы добавил разделенный запятыми список идентификаторов в параметр запроса

?userIds=210726G71HSY2YY8,200628AFYM7AGWPH

  1. Просто запросите 1 идентификатор пользователя за раз.

Ваши требования, вероятно, будут определять подход, который вы изберете.