คุณสร้างไคลเอ็นต์ REST สำหรับ Java ได้อย่างไร [ปิด]


249

ด้วย JSR 311 และการใช้งานเรามีมาตรฐานที่มีประสิทธิภาพสำหรับการเปิดเผยวัตถุ Java ผ่าน REST อย่างไรก็ตามในฝั่งไคลเอ็นต์ดูเหมือนว่าจะมีบางอย่างที่ขาดหายไปซึ่งเทียบได้กับ Apache Axis for SOAP ซึ่งเป็นสิ่งที่ซ่อนบริการเว็บและรวบรวมข้อมูลกลับไปที่วัตถุ Java อย่างโปร่งใส

คุณสร้างไคลเอนต์ Java RESTful ได้อย่างไร การใช้การเชื่อมต่อ HTTPC และการแยกวิเคราะห์ผลลัพธ์ด้วยตนเองหรือไม่ หรือลูกค้าเฉพาะทางเช่น Jersey หรือ Apache CXR?


พบApache Winkใน Apache Incubator อาจเป็นโครงการที่น่าสนใจสำหรับการสร้างเซิร์ฟเวอร์และไคลเอนต์ REST
ยาบ้า

2
ตรวจสอบสิ่งนี้: igorpolevoy.blogspot.com/2011/01/java-rest-with-ease.htmlขอบคุณ igor
ipolevoy

ดู [พักผ่อน] ( code.google.com/p/resting ) สัญญาว่าจะเรียกใช้บริการ REST และสร้างรายการวัตถุจากการตอบสนอง XML / JSON / YAML ในขั้นตอนเดียว
neel

การพักผ่อนมีปัญหากับคำขอ POST
RyanBrady

2
คุณสามารถทำได้ด้วยวิธีง่ายๆด้วยการพักผ่อน (โดย Jboss) ฉันเขียนบล็อกโพสต์เกี่ยวกับวิธีพัฒนาไคลเอ็นต์ Java RESTหากคุณต้องการคำแนะนำในการเริ่มต้นใช้งาน อย่างไรก็ตามมีทางเลือกมากมายใน Java
Guido

คำตอบ:


208

นี่เป็นคำถามเก่า (2008) ดังนั้นตอนนี้มีตัวเลือกมากมายกว่าที่เคยมี:

การอัปเดต (โครงการยังคงเปิดใช้งานในปี 2020):

  • Apache HTTP Components (4.2) Fluent adapter - การเปลี่ยนพื้นฐานสำหรับ JDK ซึ่งใช้โดยผู้สมัครอื่น ๆ ในรายการนี้ ดีกว่า Commons HTTP Client 3 แบบเก่าและใช้งานง่ายกว่าในการสร้างไคลเอ็นต์ REST ของคุณเอง คุณจะต้องใช้บางอย่างเช่น Jackson สำหรับการสนับสนุนการแยกวิเคราะห์ JSONและคุณสามารถใช้ URIBuilder คอมโพเนนต์ HTTP เพื่อสร้าง URI ของทรัพยากรที่คล้ายกับไคลเอนต์ Jersey / JAX-RS Rest ส่วนประกอบ HTTP ยังรองรับ NIO แต่ฉันสงสัยว่าคุณจะได้รับประสิทธิภาพที่ดีกว่า BIO เนื่องจากคำขอสั้น ๆ ของ REST Apache HttpComponents 5รองรับ HTTP / 2
  • OkHttp - การแทนที่ขั้นพื้นฐานสำหรับ JDK ซึ่งคล้ายกับส่วนประกอบ http ซึ่งใช้โดยผู้สมัครอื่น ๆ ในรายการนี้ รองรับโปรโตคอล HTTP รุ่นใหม่ (SPDY และ HTTP2) ทำงานบน Android น่าเสียดายที่ไม่มีตัวเลือก async แบบวนรอบเครื่องปฏิกรณ์ที่แท้จริง (ดูส่วนประกอบ Ning และ HTTP ด้านบน) อย่างไรก็ตามหากคุณใช้โปรโตคอล HTTP2 ที่ใหม่กว่านี่จะเป็นปัญหาน้อยกว่า (สมมติว่าจำนวนการเชื่อมต่อเป็นปัญหา)
  • Ning Async-http-client - ให้การสนับสนุน NIO ที่รู้จักกันก่อนหน้านี้เป็น Async-http ลูกค้าโดย Sonatype
  • Feign wrapper สำหรับไคลเอนต์ http ระดับล่าง (okhttp, apache httpcomponents) สร้างไคลเอนต์อัตโนมัติตามส่วนต่อประสานที่คล้ายกับส่วนขยาย Jersey และ CXF บางตัว การรวมสปริงที่แข็งแกร่ง
  • Retrofit - เสื้อคลุมสำหรับไคลเอนต์ http ระดับล่าง (okhttp) สร้างไคลเอนต์อัตโนมัติตามส่วนต่อประสานที่คล้ายกับส่วนขยาย Jersey และ CXF บางตัว
  • Volley wrapper สำหรับลูกค้า jdk http โดย Google
  • google-http wrapper สำหรับไคลเอ็นต์ jdk http หรือ apache httpcomponents โดย Google
  • Unirest wrapper สำหรับไคลเอนต์ jdk http โดย kong
  • Resteasy JakartaEE wrapper สำหรับลูกค้า jdk http โดย jboss เป็นส่วนหนึ่งของ jboss framework
  • jcabi-http wrapper สำหรับ apache httpcomponents ซึ่งเป็นส่วนหนึ่งของคอลเลกชัน jcabi
  • restlet wrapper สำหรับ apache httpcomponents ซึ่งเป็นส่วนหนึ่งของ restlet framework
  • เสื้อคลุมที่มั่นใจได้พร้อมคำยืนยันสำหรับการทดสอบที่ง่าย

ข้อแม้ในการเลือกไคลเอ็นต์ HTTP / REST อย่าลืมตรวจสอบว่าเฟรมเวิร์กสแต็กของคุณใช้สำหรับไคลเอ็นต์ HTTP อย่างไรมันทำเธรดอย่างไรและควรใช้ไคลเอ็นต์เดียวกันหากมี นั่นคือถ้าคุณใช้บางอย่างเช่น Vert.x หรือ Play คุณอาจต้องการลองใช้ไคลเอนต์สำรองเพื่อเข้าร่วมในบัสหรือเครื่องปฏิกรณ์ใด ๆ ก็ตามที่เฟรมเวิร์กจัดเตรียมไว้ ... มิฉะนั้นให้เตรียมพร้อมสำหรับปัญหาเธรดที่น่าสนใจ


1
น่าเสียดายที่ไคลเอนต์ Jersey ไม่รองรับวิธี PATCH หากใช้กับ JDK <8
botchniaque

3
Unirest ใช้งานง่ายมาก แต่การออกแบบคงที่ทำให้ไม่สามารถใช้งานได้ในสภาพแวดล้อมที่ใช้ร่วมกันและเซิร์ฟเวอร์
bekce

9
เกี่ยวกับunirestความคิดเห็นผมต้องการที่จะเพิ่มว่าขณะนี้ (ปลาย 2016) ดูเหมือนว่าโครงการนี้ไม่ได้รับการบำรุงรักษา แม้จะมีการเปิดปัญหาที่ขอผู้ดูแลใหม่
wegenmic

4
สำหรับผู้ที่ชื่นชอบUnirestฉันมีทางแยกที่กำลังได้รับการดูแล / อัปเดตอยู่ในขณะนี้
Josh

3
จะเป็นการดีที่จะเปลี่ยนคำตอบให้เป็นวิกิชุมชน
tkruse

72

ดังที่ฉันได้กล่าวไว้ในหัวข้อนี้ฉันมักจะใช้Jerseyซึ่งใช้ JAX-RS และมาพร้อมกับไคลเอนต์ REST ที่ดี สิ่งที่ดีคือถ้าคุณใช้ทรัพยากร RESTful โดยใช้ JAX-RS ไคลเอนต์ Jersey สามารถนำผู้ให้บริการเอนทิตีกลับมาใช้ใหม่เช่น JAXB / XML / JSON / Atom เป็นต้นเพื่อให้คุณสามารถนำอ็อบเจ็กต์เดียวกันกลับมาใช้ใหม่บนฝั่งเซิร์ฟเวอร์ได้เช่นเดียวกับคุณ ใช้ในการทดสอบหน่วยฝั่งไคลเอ็นต์

ตัวอย่างเช่นนี่คือกรณีทดสอบหน่วยจากโปรเจ็กต์ Apache Camelซึ่งค้นหาเพย์โหลด XML จากรีซอร์ส RESTful (โดยใช้ปลายทางวัตถุ JAXB) เมธอด resource (uri) ถูกกำหนดไว้ในคลาสพื้นฐานนี้ซึ่งใช้เพียง Jersey ไคลเอ็นต์ API

เช่น

    clientConfig = new DefaultClientConfig();
    client = Client.create(clientConfig);

    resource = client.resource("http://localhost:8080");
    // lets get the XML as a String
    String text = resource("foo").accept("application/xml").get(String.class);        

BTW ฉันหวังว่า JAX-RS เวอร์ชันในอนาคตจะเพิ่ม API ฝั่งไคลเอ็นต์ที่ดีตามบรรทัดในเจอร์ซีย์


มีวิธีการที่เราสามารถพูดถึงรายการเซิร์ฟเวอร์บริการ REST ใน ClientResource ในกรณีที่เซิร์ฟเวอร์หยุดทำงานให้ลองใช้เซิร์ฟเวอร์ถัดไปหรือไม่
Njax3SmmM2x2a0Zf7Hpd

1
เป็นเพียงการอัปเดต แต่เพื่อตอบความคิดเห็นของ James '' BTW 'JAX-RS 2.0 เวอร์ชันใหม่จะมี API ฝั่งไคลเอ็นต์: infoq.com/presentations/Java-REST
Nick Klauer

65

คุณสามารถใช้ Java SE API มาตรฐาน:

private void updateCustomer(Customer customer) { 
    try { 
        URL url = new URL("http://www.example.com/customers"); 
        HttpURLConnection connection = (HttpURLConnection) url.openConnection(); 
        connection.setDoOutput(true); 
        connection.setInstanceFollowRedirects(false); 
        connection.setRequestMethod("PUT"); 
        connection.setRequestProperty("Content-Type", "application/xml"); 

        OutputStream os = connection.getOutputStream(); 
        jaxbContext.createMarshaller().marshal(customer, os); 
        os.flush(); 

        connection.getResponseCode(); 
        connection.disconnect(); 
    } catch(Exception e) { 
        throw new RuntimeException(e); 
    } 
} 

หรือคุณสามารถใช้ API ไคลเอ็นต์ REST ที่จัดเตรียมโดยการใช้งาน JAX-RS เช่น Jersey API เหล่านี้ใช้งานง่ายกว่า แต่ต้องใช้ไหเพิ่มเติมในเส้นทางชั้นเรียนของคุณ

WebResource resource = client.resource("http://www.example.com/customers"); 
ClientResponse response = resource.type("application/xml");).put(ClientResponse.class, "<customer>...</customer."); 
System.out.println(response); 

สำหรับข้อมูลเพิ่มเติมโปรดดู:


17
13 สายสำหรับการพักผ่อนแบบธรรมดาในปี 2018ดูเหมือนจะมากเกินไป ...
Clint Eastwood

1
เมื่อคุณเพิ่มการจัดการข้อผิดพลาดและตัวเลือกแล้วจะไม่แตกต่างกันมากนัก หากวิธีการ SE ดูยาวคุณสามารถรวมไว้ในคลาสได้เสมอ ... :> หลังจากสองวันของการดีบักความขัดแย้งของไลบรารี JAX-RS ฉันสบายดีจริงๆกับโค้ด 5 บรรทัดเพิ่มเติมเพื่อหลีกเลี่ยงฝันร้าย SPI ทั้งหมด
tekHedd

2
@ClintEastwood โพสต์นี้เขียนเมื่อปี 2010
0ddlyoko

13

หากคุณต้องการเรียกใช้บริการ REST และแยกวิเคราะห์คำตอบคุณสามารถลองใช้Rest Assured

// Make a GET request to "/lotto"
String json = get("/lotto").asString()
// Parse the JSON response
List<String> winnderIds = with(json).get("lotto.winners.winnerId");

// Make a POST request to "/shopping"
String xml = post("/shopping").andReturn().body().asString()
// Parse the XML
Node category = with(xml).get("shopping.category[0]");

ฉันพบว่าสิ่งนี้มีความสง่างามมากกว่าโซลูชันอื่น ๆ ที่เสนอ
Herve Mutombo

9

นอกจากนี้คุณยังสามารถตรวจสอบRestletซึ่งมีความสามารถฝั่งไคลเอ็นต์เต็มรูปแบบโดย REST มุ่งเน้นไปที่ไลบรารีระดับล่างเช่น HttpURLConnection หรือ Apache HTTP Client (ซึ่งเราสามารถใช้ประโยชน์จากตัวเชื่อมต่อได้)

ขอแสดงความนับถือเจอโรมลูเวล


2
ในวันที่ 2019-10-24 ลิงก์ให้ผลตอบแทน: 'Restlet Platform ได้สิ้นสุดอายุการใช้งานแล้ว'
Hans Deragon

6

คุณอาจจะลองRapa แจ้งให้เราทราบความคิดเห็นของคุณเกี่ยวกับเรื่องเดียวกันนี้ และอย่าลังเลที่จะบันทึกปัญหาหรือคุณสมบัติที่คาดหวัง


1
Rapa มีอินเทอร์เฟซที่ดีมากและมีการอ้างอิงเพียงเล็กน้อย ทางเลือกที่ดีสำหรับ RestSharp ในโลก. NET
บ่าย

โครงการดูเหมือนจะตาย
tkruse

6

ฉันต้องการชี้ให้เห็นอีก 2 ตัวเลือก:

  • Restfulieซึ่งใช้เว็บเฟรมเวิร์ก VRaptor มีทั้งการใช้งานเซิร์ฟเวอร์และฝั่งไคลเอ็นต์พร้อมการสนับสนุน Hypermedia ที่ดีมาก
  • RESTEasyมีการใช้งานไคลเอ็นต์ที่ใช้พร็อกซี JAX-RS

1
Restfulie หน้าตาเฉย
tkruse


5

ฉันเพิ่งลองใช้Retrofit Library จากสี่เหลี่ยมมันเยี่ยมมากและคุณสามารถเรียก API ที่เหลือได้อย่างง่ายดาย การกำหนดค่าตามคำอธิบายประกอบช่วยให้เราสามารถกำจัดการเข้ารหัสแผ่นหม้อไอน้ำจำนวนมากได้


4

ฉันใช้ Apache HTTPClient เพื่อจัดการด้าน HTTP ทั้งหมด

ฉันเขียนตัวแยกวิเคราะห์ XML SAX สำหรับเนื้อหา XML ที่แยกวิเคราะห์ XML ลงในโมเดลอ็อบเจ็กต์ของคุณ ฉันเชื่อว่า Axis2 ยังแสดง XML -> Model method (แกน 1 ซ่อนส่วนนี้อย่างน่ารำคาญ) เครื่องกำเนิด XML นั้นเรียบง่ายเล็กน้อย

ใช้เวลาไม่นานในการเขียนโค้ดและค่อนข้างมีประสิทธิภาพในความคิดของฉัน


4
ในความคิดของฉันนี่เป็นวิธีที่แย่ที่สุดในการทำ REST การจัดการซีเรียลไลเซชันด้วยตนเองใน Java นั้นเสียเวลาเมื่อคุณมีตัวเลือกมากมายเช่น JAXB และ Jackson แม้แต่การโหลดเอกสารทั้งหมดและการใช้ XPath ก็ช้ากว่า SAX เล็กน้อยและไม่มีอะไรเทียบได้กับการรับ XML (ความเร็วเครือข่าย)
Adam Gent

1
ฉันเห็นด้วยเช่นกันและฉันเขียนความคิดเห็นเดิม ย้อนกลับไปตอนนั้นฉันมีความปรารถนาที่จะควบคุม deserialisation แต่ปัจจุบันฉันจะใช้ Jackson และคลาสโมเดลที่มีคำอธิบายประกอบอย่างเหมาะสม
JeeBee

4

OkHttp มีน้ำหนักเบาและทรงพลังเมื่อรวมกับ Retrofit ด้วย ใช้งานได้ดีสำหรับการใช้งาน Java ทั่วไปและบน Android

OkHttp : http://square.github.io/okhttp/

public static final MediaType JSON
    = MediaType.parse("application/json; charset=utf-8");

OkHttpClient client = new OkHttpClient();

String post(String url, String json) throws IOException {
  RequestBody body = RequestBody.create(JSON, json);
  Request request = new Request.Builder()
      .url(url)
      .post(body)
      .build();
  Response response = client.newCall(request).execute();
  return response.body().string();
}

ชุดติดตั้งเพิ่มเติม : http://square.github.io/retrofit/

public interface GitHubService {
  @GET("/users/{user}/repos")
  Call<List<Repo>> listRepos(@Path("user") String user);
}


2

แม้ว่าจะสร้างไคลเอนต์ HTTP และทำการรียูสซ้ำได้ง่าย แต่ถ้าคุณต้องการใช้ไคลเอนต์ที่สร้างขึ้นโดยอัตโนมัติคุณสามารถใช้ WADL เพื่ออธิบายและสร้างโค้ดได้

คุณสามารถใช้RestDescribeเพื่อสร้างและรวบรวม WSDL คุณสามารถสร้างไคลเอนต์ใน php, ruby, python, java และ C # โดยใช้สิ่งนี้ สร้างรหัสที่สะอาดและมีการเปลี่ยนแปลงที่ดีที่คุณต้องปรับแต่งเล็กน้อยหลังจากการสร้างรหัสคุณสามารถค้นหาเอกสารที่ดีและความคิดพื้นฐานที่อยู่เบื้องหลังเครื่องมือได้ที่นี่ที่นี่

มีเครื่องมือ WADL ที่น่าสนใจและมีประโยชน์บางอย่างที่กล่าวถึงใน wintermute



1

ฉันใช้RestAssuredเกือบตลอดเวลาเพื่อแยกวิเคราะห์การตอบสนองของบริการส่วนที่เหลือและทดสอบบริการ นอกเหนือจาก Rest Assured ฉันยังใช้ไลบรารีด้านล่างเพื่อสื่อสารกับบริการ Resful

ก. ลูกค้า Jersey Rest

ข. สปริง RestTemplate

ค. ไคลเอ็นต์ Apache HTTP


0

ลองดูที่ http-rest-client

https://github.com/g00dnatur3/http-rest-client

นี่คือตัวอย่างง่ายๆ:

RestClient client = RestClient.builder().build();
String geocoderUrl = "http://maps.googleapis.com/maps/api/geocode/json"
Map<String, String> params = Maps.newHashMap();
params.put("address", "beverly hills 90210");
params.put("sensor", "false");
JsonNode node = client.get(geocoderUrl, params, JsonNode.class);

ไลบรารีจะดูแลการทำให้เป็นอนุกรม json และการเชื่อมโยงสำหรับคุณ

นี่คืออีกตัวอย่างหนึ่ง

RestClient client = RestClient.builder().build();
String url = ...
Person person = ...
Header header = client.create(url, person);
if (header != null) System.out.println("Location header is:" + header.value());

และตัวอย่างสุดท้าย

RestClient client = RestClient.builder().build();
String url = ...
Person person = client.get(url, null, Person.class); //no queryParams

ไชโย!


0

ตัวอย่างของ Jersey Rest Client: การ
เพิ่มการอ้างอิง:

         <!-- jersey -->
    <dependency>
        <groupId>com.sun.jersey</groupId>
        <artifactId>jersey-json</artifactId>
        <version>1.8</version>
    </dependency>
   <dependency>
        <groupId>com.sun.jersey</groupId>
        <artifactId>jersey-server</artifactId>
        <version>1.8</version>
    </dependency>

<dependency>
    <groupId>com.sun.jersey</groupId>
    <artifactId>jersey-client</artifactId>
    <version>1.8</version>
</dependency>

    <dependency>
    <groupId>org.json</groupId>
    <artifactId>json</artifactId>
    <version>20090211</version>
</dependency>

ForGetMethod และส่งผ่านพารามิเตอร์สองตัว:

          Client client = Client.create();
           WebResource webResource1 = client
                        .resource("http://localhost:10102/NewsTickerServices/AddGroup/"
                                + userN + "/" + groupName);

                ClientResponse response1 = webResource1.get(ClientResponse.class);
                System.out.println("responser is" + response1);

GetMethod ผ่านหนึ่งพารามิเตอร์และรับการตอบสนองของรายการ:

       Client client = Client.create();

        WebResource webResource1 = client
                    .resource("http://localhost:10102/NewsTickerServices/GetAssignedUser/"+grpName);    
    //value changed
    String response1 = webResource1.type(MediaType.APPLICATION_JSON).get(String.class);

    List <String > Assignedlist =new ArrayList<String>();
     JSONArray jsonArr2 =new JSONArray(response1);
    for (int i =0;i<jsonArr2.length();i++){

        Assignedlist.add(jsonArr2.getString(i));    
    }

ในด้านบนจะส่งคืนรายการที่เรายอมรับเป็นรายการจากนั้นแปลงเป็น Json Array จากนั้น Json Array เป็น List

หาก Post Request ผ่าน Json Object เป็นพารามิเตอร์:

   Client client = Client.create();
    WebResource webResource = client
            .resource("http://localhost:10102/NewsTickerServices/CreateJUser");
    // value added

    ClientResponse response = webResource.type(MediaType.APPLICATION_JSON).post(ClientResponse.class,mapper.writeValueAsString(user));

    if (response.getStatus() == 500) {

        context.addMessage(null, new FacesMessage("User already exist "));
    }

0

ฉันกำลังใช้https://github.com/kevinsawicki/http-requestฉันชอบความเรียบง่ายและวิธีแสดงตัวอย่าง แต่ส่วนใหญ่ฉันขายเมื่อฉันอ่าน:

การพึ่งพาคืออะไร?

ไม่มี. เป้าหมายของไลบรารีนี้คือเป็นคลาสคลาสเดียวที่มีคลาสคงที่ภายใน โครงการทดสอบต้องใช้ Jetty เพื่อทดสอบคำขอกับการใช้งานเซิร์ฟเวอร์ HTTP จริง

ซึ่งจัดการปัญหาบางอย่างในโครงการ java 1.6 สำหรับการถอดรหัส json เป็นวัตถุgsonนั้นอยู่ยงคงกระพัน :)


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