Spring RestTemplate GET พร้อมพารามิเตอร์


267

ฉันต้องRESTโทรหาที่มีส่วนหัวที่กำหนดเองและพารามิเตอร์การสืบค้น ฉันตั้งค่าของฉันHttpEntityด้วยส่วนหัว (ไม่มีร่างกาย) และฉันใช้RestTemplate.exchange()วิธีการดังต่อไปนี้:

HttpHeaders headers = new HttpHeaders();
headers.set("Accept", "application/json");

Map<String, String> params = new HashMap<String, String>();
params.put("msisdn", msisdn);
params.put("email", email);
params.put("clientVersion", clientVersion);
params.put("clientType", clientType);
params.put("issuerName", issuerName);
params.put("applicationName", applicationName);

HttpEntity entity = new HttpEntity(headers);

HttpEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, entity, String.class, params);

สิ่งนี้ล้มเหลวในตอนท้ายของไคลเอนต์โดยdispatcher servletไม่สามารถแก้ไขการร้องขอไปยังตัวจัดการได้ เมื่อทำการดีบั๊กแล้วดูเหมือนว่าจะไม่ส่งพารามิเตอร์คำขอ

เมื่อฉันแลกเปลี่ยนกับการPOSTใช้เนื้อหาคำขอและไม่มีพารามิเตอร์การสืบค้นก็ใช้งานได้ดี

ไม่มีใครมีความคิดใด ๆ

คำตอบ:


481

หากต้องการจัดการ URL / พา ธ / พารามิเตอร์ / ฯลฯ อย่างง่ายดายคุณสามารถใช้คลาสUriComponentsBuilderของ Spring มันสะอาดกว่าการต่อสตริงด้วยตนเองและจัดการการเข้ารหัส URL ให้คุณ:

HttpHeaders headers = new HttpHeaders();
headers.set("Accept", MediaType.APPLICATION_JSON_VALUE);

UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url)
        .queryParam("msisdn", msisdn)
        .queryParam("email", email)
        .queryParam("clientVersion", clientVersion)
        .queryParam("clientType", clientType)
        .queryParam("issuerName", issuerName)
        .queryParam("applicationName", applicationName);

HttpEntity<?> entity = new HttpEntity<>(headers);

HttpEntity<String> response = restTemplate.exchange(
        builder.toUriString(), 
        HttpMethod.GET, 
        entity, 
        String.class);

10
สุดยอดเคล็ดลับ เพิ่งเปลี่ยนexchangeเป็นgetForEntity: restTemplate.getForEntity(builder.build().encode().toUri(), String.class);เพื่อความเรียบง่าย
Fernando M. Pinheiro

12
@ FernandoM.Pinheiro: คุณถูกต้อง แต่ถ้าคุณคาดหวังว่าประเภททั่วไปในการตอบสนองจากนั้นคุณจำเป็นต้องใช้และให้exchange ParameterizedTypeReferenceตัวอย่างที่สามารถทำให้ง่ายขึ้น แต่แทนที่ด้วยbuilder.build().encode().toUri() builder.toUriString()
mirzmaster

@Christophe L คุณสามารถแสดงวิธีที่ฉันจะได้รับพารามิเตอร์สตริงเหล่านี้ในฝั่งเซิร์ฟเวอร์ ??
KJEjava48

3
มีทางลัดในการรับ URI เพียงโทรbuilder.toUriString()
Michael Piefel

เอกสารสำหรับฤดูใบไม้ผลิUriComponentsBuilder คู่มืออธิบายกรณีการใช้งานต่างๆของUriComponentsBuilder
Chacko Mathew

180

uriVariables ถูกขยายในสตริงแบบสอบถามด้วย ตัวอย่างเช่นการโทรต่อไปนี้จะขยายค่าสำหรับทั้งบัญชีและชื่อ:

restTemplate.exchange("http://my-rest-url.org/rest/account/{account}?name={name}",
    HttpMethod.GET,
    httpEntity,
    clazz,
    "my-account",
    "my-name"
);

ดังนั้น URL คำขอจริงจะเป็น

http://my-rest-url.org/rest/account/my-account?name=my-name

ดูที่ HierarchicalUriComponents.expandInternal (UriTemplateVariables) สำหรับรายละเอียดเพิ่มเติม เวอร์ชั่นของ Spring คือ 3.1.3


ขอบคุณ - วิธีแก้ปัญหาที่ง่ายมาก
Angshuman Agarwal

2
และเมื่อสร้างอินสแตนซ์ RestTemplate คุณสามารถระบุว่าค่าพารามิเตอร์เคียวรีเหล่านั้นจะถูกขยายโดยการระบุ DefaultUriTemplateHandler (ก่อนหน้า Spring 5) หรือ DefaultUriBuilderFactory (Spring 5+) สิ่งนี้มีประโยชน์เมื่อคุณต้องการเข้ารหัสอักขระเพิ่มเติมเช่น!, (,), ฯลฯ
Stephen Rudolph

URL ของฉันมีพารามิเตอร์มากกว่า 10 ตัววิธีใดที่จะบรรลุเป้าหมายเดียวกันกับวัตถุ / แผนที่แทนที่จะแสดงตัวแปรทุกตัว ฉันไม่สามารถใช้UriComponentsBuilderอย่างใดอย่างหนึ่งเนื่องจากเป็นสาเหตุให้สร้างตัวชี้วัดที่แตกต่างกันสำหรับแต่ละคำขอด้วยMicrometer
Doug

@Doug - RestTemplateมีวิธีการแบบขนานสำหรับการระบุอาร์เรย์ของค่าตำแหน่ง ( Object... uriVariables) หรือแผนที่ของค่าที่มีชื่อ ( Map<String, ?> uriVariables) ดูเหมือนเวอร์ชั่นแผนที่คือสิ่งที่คุณต้องการ: restTemplate.exchange(url, HttpMethod.GET, httpEntity, clazz, urlVariablesMap).
M. Justin

42

ตั้งแต่อย่างน้อยสปริง 3 แทนที่จะใช้ UriComponentsBuilderเพื่อสร้าง URL (ซึ่งเป็นบิต verbose) จำนวนมากของRestTemplateวิธีการยอมรับตัวยึดตำแหน่งในเส้นทางสำหรับพารามิเตอร์ (ไม่เพียงexchange)

จากเอกสาร:

หลายRestTemplateวิธีการรับแม่แบบ URI และ URI ตัวแปรแม่แบบไม่ว่าจะเป็นStringvararg Map<String,String>หรือเป็น

ตัวอย่างเช่นกับ String vararg:

restTemplate.getForObject(
   "http://example.com/hotels/{hotel}/rooms/{room}", String.class, "42", "21");

หรือด้วย Map<String, String> :

Map<String, String> vars = new HashMap<>();
vars.put("hotel", "42");
vars.put("room", "21");

restTemplate.getForObject("http://example.com/hotels/{hotel}/rooms/{room}", 
    String.class, vars);

การอ้างอิง: https://docs.spring.io/spring/docs/current/spring-framework-reference/integration.html#rest-resttemplate-uri

หากคุณดูที่JavaDocเพื่อRestTemplateค้นหา "เทมเพลต URI" คุณสามารถดูวิธีการที่คุณสามารถใช้ตัวยึดตำแหน่งได้


35

ตกลงดังนั้นฉันเป็นคนงี่เง่าและฉันสับสนพารามิเตอร์การค้นหาด้วยพารามิเตอร์ url ฉันหวังว่าจะมีวิธีที่ดีกว่าในการเติมพารามิเตอร์ข้อความค้นหาของฉันแทนที่จะเป็นสตริงที่ต่อกันแบบน่าเกลียด แต่เราก็มี เป็นเพียงกรณีของการสร้าง URL ด้วยพารามิเตอร์ที่ถูกต้อง ถ้าคุณผ่านมันเป็น String Spring จะดูแลการเข้ารหัสสำหรับคุณ


มันใช้งานได้สำหรับคุณ? ฉันทำตามวิธีการเดียวกับการใช้ UriComponentsBuilder แต่ที่ URL เป้าหมายเมื่อฉันทำ request.getAttribute () ฉันได้รับ null
yathirigan

47
ฉันไม่เข้าใจอย่างจริงจังว่าทำไมคำตอบนี้จึงมีขีดสีเขียว
Pradeep

7
เพราะเขาเป็น OP
Kalpesh Soni

แล้วทางออกของคุณคืออะไร ขอบคุณ!
Raymond Chen

18

ผมก็พยายามที่บางสิ่งบางอย่างที่คล้ายกันและตัวอย่าง RoboSpice ช่วยให้ฉันทำงานออก :

HttpHeaders headers = new HttpHeaders();
headers.set("Accept", "application/json");

HttpEntity<String> request = new HttpEntity<>(input, createHeader());

String url = "http://awesomesite.org";
Uri.Builder uriBuilder = Uri.parse(url).buildUpon();
uriBuilder.appendQueryParameter(key, value);
uriBuilder.appendQueryParameter(key, value);
...

String url = uriBuilder.build().toString();

HttpEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, request , String.class);

15
    String uri = http://my-rest-url.org/rest/account/{account};

    Map<String, String> uriParam = new HashMap<>();
    uriParam.put("account", "my_account");

    UriComponents builder = UriComponentsBuilder.fromHttpUrl(uri)
                .queryParam("pageSize","2")
                        .queryParam("page","0")
                        .queryParam("name","my_name").build();

    HttpEntity<String> requestEntity = new HttpEntity<>(null, getHeaders());

    ResponseEntity<String> strResponse = restTemplate.exchange(builder.toUriString(),HttpMethod.GET, requestEntity,
                        String.class,uriParam);

    //final URL: http://my-rest-url.org/rest/account/my_account?pageSize=2&page=0&name=my_name

RestTemplate: สร้าง URI แบบไดนามิกโดยใช้ UriComponents (ตัวแปร URI และพารามิเตอร์คำขอ)


6

การแปลงแฮชแม็พเป็นสตริงของพารามิเตอร์เคียวรี:

Map<String, String> params = new HashMap<>();
params.put("msisdn", msisdn);
params.put("email", email);
params.put("clientVersion", clientVersion);
params.put("clientType", clientType);
params.put("issuerName", issuerName);
params.put("applicationName", applicationName);

UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url);
for (Map.Entry<String, String> entry : params.entrySet()) {
    builder.queryParam(entry.getKey(), entry.getValue());
}

HttpHeaders headers = new HttpHeaders();
headers.set("Accept", "application/json");

HttpEntity<String> response = restTemplate.exchange(builder.toUriString(), HttpMethod.GET, new HttpEntity(headers), String.class);

3

ฉันใช้วิธีการที่แตกต่างกันคุณอาจเห็นด้วยหรือไม่ แต่ฉันต้องการควบคุมจากไฟล์. properties แทนที่จะเป็นโค้ด Java ที่คอมไพล์แล้ว

ภายในไฟล์ application.properties

endpoint.url = https: // yourHost / resource? requestParam1 = {0} & requestParam2 = {1}

โค้ด Java ไปที่นี่คุณสามารถเขียนว่าหรือเปลี่ยนเงื่อนไขเพื่อค้นหาว่า URL ปลายทางในไฟล์. properties มี @PathVariable (มี {}) หรือ @RequestParam (yourURL? key = value) ฯลฯ ... แล้วเรียกใช้เมธอดตามลำดับ .. . ด้วยวิธีการที่ไม่หยุดนิ่งและไม่จำเป็นต้องเปลี่ยนรหัสในอนาคตร้านค้าครบวงจร ...

ฉันพยายามให้ความคิดมากกว่ารหัสจริงที่นี่ ... ลองเขียนวิธีการทั่วไปสำหรับ @RequestParam และ @PathVariable ฯลฯ ... แล้วโทรตามเมื่อจำเป็น

  @Value("${endpoint.url}")
  private String endpointURL;
  // you can use variable args feature in Java
  public String requestParamMethodNameHere(String value1, String value2) {
    RestTemplate restTemplate = new RestTemplate();
    restTemplate
           .getMessageConverters()
           .add(new MappingJackson2HttpMessageConverter());

    HttpHeaders headers = new HttpHeaders();
    headers.set("Accept", MediaType.APPLICATION_JSON_VALUE);
    HttpEntity<String> entity = new HttpEntity<>(headers);

    try {
      String formatted_URL = MessageFormat.format(endpointURL, value1, value2);
      ResponseEntity<String> response = restTemplate.exchange(
                    formatted_URL ,
                    HttpMethod.GET,
                    entity,
                    String.class);
     return response.getBody();
    } catch (Exception e) { e.printStackTrace(); }

3

ใน Spring Web 4.3.6 ฉันเห็นด้วยเช่นกัน

public <T> T getForObject(String url, Class<T> responseType, Object... uriVariables)

นั่นหมายความว่าคุณไม่จำเป็นต้องสร้างแผนที่ที่น่าเกลียด

ดังนั้นหากคุณมี URL นี้

http://my-url/action?param1={param1}&param2={param2}

คุณสามารถทำได้

restTemplate.getForObject(url, Response.class, param1, param2)

หรือ

restTemplate.getForObject(url, Response.class, param [])

2
public static void main(String[] args) {
         HttpHeaders httpHeaders = new HttpHeaders();
         httpHeaders.set("Accept", MediaType.APPLICATION_JSON_VALUE);
         final String url = "https://host:port/contract/{code}";
         Map<String, String> params = new HashMap<String, String>();
         params.put("code", "123456");
         HttpEntity<?> httpEntity  = new HttpEntity<>(httpHeaders); 
         RestTemplate restTemplate  = new RestTemplate();
         restTemplate.exchange(url, HttpMethod.GET, httpEntity,String.class, params);
    }

2

หากคุณผ่าน parametrized parametrized สำหรับ RestTemplate คุณจะมีหนึ่งเมทริกสำหรับ URL ที่แตกต่างกันสำหรับทุกคนที่คุณผ่านโดยพิจารณาพารามิเตอร์ คุณต้องการใช้ URL ที่เป็นพารามิเตอร์:

http://my-url/action?param1={param1}&param2={param2}

แทน

http://my-url/action?param1=XXXX&param2=YYYY

กรณีที่สองคือสิ่งที่คุณได้รับโดยใช้คลาส UriComponentsBuilder

วิธีหนึ่งในการนำพฤติกรรมแรกมาใช้มีดังต่อไปนี้:

Map<String, Object> params = new HashMap<>();
params.put("param1", "XXXX");
params.put("param2", "YYYY");

String url = "http://my-url/action?%s";

String parametrizedArgs = params.keySet().stream().map(k ->
    String.format("%s={%s}", k, k)
).collect(Collectors.joining("&"));

HttpHeaders headers = new HttpHeaders();
headers.set("Accept", MediaType.APPLICATION_JSON_VALUE);
HttpEntity<String> entity = new HttpEntity<>(headers);

restTemplate.exchange(String.format(url, parametrizedArgs), HttpMethod.GET, entity, String.class, params);

0

หาก URL ของคุณคือ http://localhost:8080/context path?msisdn={msisdn}&email={email}

แล้วก็

Map<String,Object> queryParams=new HashMap<>();
queryParams.put("msisdn",your value)
queryParams.put("email",your value)

ใช้ได้กับวิธีการแลกเปลี่ยน resttemplate ตามที่คุณอธิบาย

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.