2012-06-06 4 views
6

मैं एक जीडब्ल्यूटी क्लाइंट एप्लिकेशन से रीस्टेसी और जेएक्स-आरएस का उपयोग करके बनाई गई एक आरईएसटी सेवा को कॉल करना चाहता हूं। सर्वर और क्लाइंट दोनों के लिए एकल कोड बेस का उपयोग करने के लिए इर्राई का उपयोग करने के लिए सबसे अच्छी प्रक्रिया क्या है?एरराई का उपयोग कर जेएक्स-आरएस/रीस्टेसी सर्वर के साथ आप जीडब्ल्यूटी को कैसे एकीकृत करते हैं?

उत्तर

26

हम सभी को आरईएसटी पसंद है। यह विक्रेता, मंच और भाषा तटस्थ है; डीबग करना, कार्यान्वित करना और एक्सेस करना आसान है; और यह आपके क्लाउड, ब्राउज़र, मोबाइल और डेस्कटॉप ऐप्स पर ठोस बैक एंड प्रदान करता है।

जावा डेवलपर्स JAX-RS जैसे RESTEasy का समर्थन करने वाले पुस्तकालयों का उपयोग कर सकते हैं, ताकि एक REST सर्वर प्राप्त हो और बस कुछ मिनटों में चल सके। फिर, using JAX-RS clients, ये जेएक्स-आरएस आरईएसटी सर्वर जावा क्लाइंट अनुप्रयोगों से कोड की कुछ पंक्तियों के साथ बुलाया जा सकता है।

लेकिन इस तथ्य के बावजूद कि जीडब्ल्यूटी जावा के साथ बहुत आम है, जीडब्ल्यूटी से आरईएसटी सेवाओं को बुलाकर दर्दनाक अनुभव हो सकता है। RequestBuilder कक्षा का उपयोग करने में सही HTTP विधि निर्दिष्ट करना, आपके यूआरएल को एन्कोड करना शामिल है, और उसके बाद प्रतिक्रिया को डीकोड करें या Overlay ऑब्जेक्ट्स को आरईएसटी सर्वर द्वारा भेजे गए डेटा का प्रतिनिधित्व करने के लिए बनाएं। यह एक या दो आरईएसटी तरीकों को कॉल करने के लिए एक बड़ा ओवरहेड नहीं हो सकता है, लेकिन यह एक जटिल जटिल सेवा के साथ जीडब्ल्यूटी को एकीकृत करते समय बहुत सारे काम का प्रतिनिधित्व करता है।

यह वह जगह है जहां Errai आता है। एरराई एक जेबॉस परियोजना है, अन्य चीजों के साथ, implements the JAX-RS standard within GWT। सिद्धांत रूप में इसका मतलब है कि आप अपने जावा और जीडब्ल्यूटी परियोजनाओं के बीच अपने जेएक्स-आरएस इंटरफेस को साझा कर सकते हैं, जो एक एकल स्रोत प्रदान करता है जो आपके आरईएसटी सर्वर की कार्यक्षमता को परिभाषित करता है।

इर्राई से आरईएसटी सर्वर को कॉल करने में केवल कुछ सरल कदम शामिल हैं। सबसे पहले, आपको रीस्ट जेएक्स-आरएस इंटरफ़ेस की आवश्यकता है। यह एक जेएक्स-आरएस एनोटेटेड जावा इंटरफेस है जो आपके आरईएसटी सर्वर द्वारा प्रदान की जाने वाली विधियों को परिभाषित करता है। यह इंटरफ़ेस आपके जावा और जीडब्ल्यूटी परियोजनाओं के बीच साझा किया जा सकता है।

@Path("customers") 
public interface CustomerService { 
    @GET 
    @Produces("application/json") 
    public List<Customer> listAllCustomers(); 

    @POST 
    @Consumes("application/json") 
    @Produces("text/plain") 

    public long createCustomer(Customer customer); 
} 

REST इंटरफ़ेस फिर अपने GWT ग्राहक वर्ग में इंजेक्ट किया जाता।

@Inject 
private Caller<CustomerService> customerService; 

एक प्रतिक्रिया हैंडलर परिभाषित किया गया है।

RemoteCallback<Long> callback = new RemoteCallback<Long>() { 
    public void callback(Long id) { 
    Window.alert("Customer created with ID: " + id); 
    } 
}; 

और अंत में आरईएसटी विधि कहा जाता है।

customerService.call(callback).listAllCustomers(); 

बहुत आसान हुह?

आपको इस उदाहरण से विश्वास करने के लिए प्रेरित किया जा सकता है कि इरारा आपके वर्तमान जेएक्स-आरएस बुनियादी ढांचे के समाधान में एक बूंद प्रदान करेगा, लेकिन दुर्भाग्यवश यह सरल उदाहरण उन जटिलताओं पर छूता नहीं है जिन्हें आप देख सकते हैं अपने जीडब्ल्यूटी और जावा रीस्ट कोड बेस को गठबंधन करने की कोशिश कर रहा है। इर्राई और जेएक्स-आरएस का उपयोग करते समय जागरूक होने के कुछ गठिया यहां दिए गए हैं।

आम तौर पर जब एक GWT JAX-आरएस ग्राहक लागू करते समय आप CORS

लागू करने के लिए की आवश्यकता होगी, तो आप एक बाहरी बाकी सर्वर के खिलाफ अपने GWT आवेदन डिबगिंग की जाएगी। यह तब तक काम नहीं करेगा जब तक आप CORS लागू नहीं करते हैं, क्योंकि डिफ़ॉल्ट रूप से GWT एप्लिकेशन होस्ट करने वाला ब्राउज़र आपके जावास्क्रिप्ट कोड को उस सर्वर से संपर्क करने की अनुमति नहीं देगा जो एक ही डोमेन में नहीं चल रहा है। वास्तव में आप अपने स्थानीय विकास पीसी पर भी आरईएसटी सर्वर चला सकते हैं और फिर भी इन क्रॉस डोमेन मुद्दों में भाग ले सकते हैं, क्योंकि विभिन्न बंदरगाहों के बीच कॉल भी प्रतिबंधित हैं।

यदि आप रीस्टेसी का उपयोग कर रहे हैं, तो सीओआरएस लागू करने के दो तरीकों से किया जा सकता है। पहला MessageBodyInterceptors इंटरफ़ेस का उपयोग करके किया जाता है। आप लिखने() विधि प्रदान करते हैं, और @Provider और @ServerInterceptor एनोटेशन के साथ अपनी कक्षा को एनोटेट करते हैं। लिखने() विधि का उपयोग किसी भी सरल अनुरोध ("सरल" अनुरोधों को कस्टम हेडर सेट नहीं करने के लिए "एक्सेस-कंट्रोल-ऑब्जेक्ट-ओरिजिन" हेडर जोड़ने के लिए किया जाता है, और अनुरोध निकाय केवल सादा पाठ का उपयोग करता है)।

दूसरी विधि सीओआरएस प्रीफलाइट अनुरोधों को संभालती है (HTTP अनुरोध विधियों के लिए जो उपयोगकर्ता डेटा पर दुष्प्रभाव पैदा कर सकती है - विशेष रूप से, जीईटी के अलावा HTTP विधियों के लिए, या कुछ एमआईएम प्रकारों के साथ POST उपयोग के लिए)। ये अनुरोध HTTP विकल्प विधि का उपयोग करते हैं, और उत्तर में "पहुंच-नियंत्रण-अनुमति-उत्पत्ति", "एक्सेस-कंट्रोल-स्वीट-मेथड" और "एक्सेस-कंट्रोल-स्वीट-हेडर" हेडर प्राप्त करने की अपेक्षा करते हैं। यह नीचे हैंडल CORSRequest() विधि में प्रदर्शित किया गया है।

नोट

REST इंटरफ़ेस नीचे किसी भी और सभी CORS अनुरोध है, जो एक सुरक्षा के दृष्टिकोण से उपयुक्त नहीं हो सकता है। हालांकि, यह मानना ​​मूर्ख नहीं है कि इस स्तर पर सीओआरएस को रोकने या प्रतिबंधित करने से ग्राहक की ओर से ये अनुरोध करने के लिए setting up a proxy के रूप में किसी भी डिग्री की सुरक्षा प्रदान की जाएगी, यह काफी मामूली है।

@Path("/1") 
@Provider 
@ServerInterceptor 
public class RESTv1 implements RESTInterfaceV1, MessageBodyWriterInterceptor 
{ 
    @Override 
    public void write(final MessageBodyWriterContext context) throws IOException, WebApplicationException 
    { context.getHeaders().add(RESTInterfaceV1.ACCESS_CONTROL_ALLOW_ORIGIN_HEADER, "*"); 
     context.proceed();  
    } 

    @OPTIONS 
    @Path("/{path:.*}") 
    public Response handleCORSRequest(@HeaderParam(RESTInterfaceV1.ACCESS_CONTROL_REQUEST_METHOD) final String requestMethod, @HeaderParam(RESTInterfaceV1.ACCESS_CONTROL_REQUEST_HEADERS) final String requestHeaders) 
    { 
     final ResponseBuilder retValue = Response.ok(); 

     if (requestHeaders != null) 
      retValue.header(RESTInterfaceV1.ACCESS_CONTROL_ALLOW_HEADERS, requestHeaders); 

     if (requestMethod != null) 
      retValue.header(RESTInterfaceV1.ACCESS_CONTROL_ALLOW_METHODS, requestMethod); 

     retValue.header(RESTInterfaceV1.ACCESS_CONTROL_ALLOW_ORIGIN_HEADER, "*"); 

     return retValue.build(); 
    } 

} 
जगह में इन दोनों तरीकों के साथ

, अपने बाकी सर्वर से किसी भी कॉल उपयुक्त प्रतिक्रिया प्रदान करेगा पार मूल अनुरोध की अनुमति के लिए।

आप स्वीकार करते हैं और सरल POJOs

शुरूआत के साथ प्रतिक्रिया करने के लिए की आवश्यकता होगी एक सरल REST इंटरफ़ेस है कि एक लंबे समय के साथ जवाब दिया सचित्र। जेएक्स-आरएस के जावा और जीडब्ल्यूटी कार्यान्वयन दोनों जानते हैं कि जावा.टिल संग्रह जैसे प्राइमेटिव्स और सरल वर्गों को क्रमबद्ध और deserialize कैसे करें।

वास्तविक दुनिया के उदाहरण में, आपका आरईएसटी इंटरफेस अधिक जटिल वस्तुओं के साथ प्रतिक्रिया देने जा रहा है। यह वह जगह है जहां विभिन्न कार्यान्वयन संघर्ष कर सकते हैं।

शुरुआत के लिए, जेएक्स-आरएस और एरराई जेएसओएन और जावा ऑब्जेक्ट्स के बीच वस्तुओं के मार्शलिंग को अनुकूलित करने के लिए विभिन्न एनोटेशन का उपयोग करते हैं। इर्राई में @ मैप्सटो और @ पोर्टेबल जैसी टिप्पणियां हैं, जबकि रीस्टेसी (या जैक्सन, the JSON marshaller) @JsonIgnore और @JsonSerialize जैसे एनोटेशन का उपयोग करती है। ये एनोटेशन पारस्परिक रूप से अनन्य हैं: जीडब्ल्यूटी जैक्सन एनोटेशन के बारे में शिकायत करेगा, और जैक्सन इरारी एनोटेशन का उपयोग नहीं कर सकता है।

सरल समाधान आपके बाकी इंटरफ़ेस के साथ सरल POJO का उपयोग सेट करना है। सरल से मेरा मतलब है कि जिन वर्गों में रचनाकार नहीं हैं, और केवल गेटटर और सेटर विधियां हैं जो सीधे उन गुणों से संबंधित हैं जो JSON ऑब्जेक्ट में मौजूद होंगी क्योंकि यह तार पर यात्रा करती है। आसान पीओजेओ को एरराई और जैक्सन दोनों ने अपनी डिफ़ॉल्ट सेटिंग्स के साथ मार्शल किया जा सकता है, जिससे असंगत एनोटेशन को जोड़ना आवश्यक है।

एरराई और जैक्सन विभिन्न स्थानों से जेएसओएन स्ट्रिंग में परिणामी गुणों के नाम भी स्रोत करते हैं। जैक्सन गेटर और सेटर विधियों के नामों का उपयोग करेगा, जबकि एरराई आवृत्ति चर के नामों का उपयोग करेगा। तो सुनिश्चित करें कि आपके इंस्टेंस चर और गेटर/सेटर विधियों के नाम बिल्कुल वही हैं।यह ठीक है:

public class Test 
{ 
    private int myCount; 
    public int getCount() {return myCount;} 
    public void setCount(int count) {this.myCount = count;} 
} 

दूसरे, यह इन बाकी डेटा वस्तुओं में अतिरिक्त पद्धतियां जोड़ने के लिए कुछ व्यापार कार्यक्षमता लागू करने के लिए आकर्षक है:

public class Test 
{ 
    private int count; 
    public int getCount() {return count;} 
    public void setCount(int count) {this.count = count;} 
} 

यह समस्याएं होंगी। हालांकि, अगर आप ऐसा करते हैं तो जीडब्ल्यूटी द्वारा समर्थित नहीं होने वाली कक्षा का प्रयास करने और उपयोग करने से पहले इसमें कुछ समय नहीं लगेगा, और आपको आश्चर्य हो सकता है कि GWT doesn’t support: दिनांक स्वरूपण, क्लोनिंग सरणी, स्ट्रिंग को बाइट में परिवर्तित करना []। .. सूची चलती जाती है। इसलिए अपनी आरईएसटी डेटा ऑब्जेक्ट्स में मूलभूत बातों के साथ रहना सर्वोत्तम है, और रचना या घटक आधारित डिज़ाइन जैसे कुछ का उपयोग करके आरईएसटी डेटा ऑब्जेक्ट विरासत पेड़ के बाहर पूरी तरह से किसी भी व्यावसायिक तर्क को लागू करना सबसे अच्छा है।

नोट

@Portable एनोटेशन के बिना, आप manually list any classes used Errai when calling the REST interface in the ErraiApp.properties file की आवश्यकता होगी।

नोट

तुम भी नक्शे से दूर रहना चाहता हूँ। विवरण के लिए this bug देखें।

नोट

आप नेस्टेड पैरामिट्रीकृत प्रकार का प्रयोग नहीं किया जा सकता है वस्तु पदानुक्रम आपके JSON सर्वर द्वारा लौटाए में। विवरण के लिए this bug और this forum post देखें।

नोट

Errai [] बाइट के साथ मुद्दों है। इसके बजाए एक सूची का प्रयोग करें। अधिक जानकारी के लिए this forum post देखें।

, आप Firefox के साथ अपने आवेदन डिबग करने के लिए होगा आप Firefox

साथ डिबग करने के लिए यह GWT का उपयोग कर एक REST इंटरफ़ेस से अधिक डेटा की बड़ी मात्रा को भेजने की बात आती है की आवश्यकता होगी। अपने अनुभव में, बाइट [] में भी एक छोटी फ़ाइल को एन्कोड करना और इसे नेटवर्क पर भेजना क्रोम में सभी प्रकार की त्रुटियों का कारण बनता है। विभिन्न अपवादों को फेंक दिया जाएगा क्योंकि JSON एन्कोडर दूषित डेटा से निपटने का प्रयास करता है; अपवाद जो जीडब्ल्यूटी अनुप्रयोग के संकलित संस्करण में नहीं देखे जाते हैं, या जब फ़ायरफ़ॉक्स पर डीबगिंग करते हैं।

दुर्भाग्य से Google अपने फ़ायरफ़ॉक्स जीडब्ल्यूटी प्लगइन्स को मोज़िला के नए रिलीज चक्रों के साथ अद्यतित रखने में कामयाब नहीं रहा है, लेकिन आप अक्सर जीडब्ल्यूटी Google समूह मंचों में एलन लींग द्वारा अनौपचारिक रूप से जारी किए जा सकते हैं। This link फ़ायरफ़ॉक्स 12 के लिए GWT प्लगइन का एक संस्करण है, और this link फ़ायरफ़ॉक्स 13. के लिए

एक संस्करण है आप Errai 2.1 उपयोग करने के लिए या बाद में

Only Errai 2.1 or later will produce JSON that is compatible with Jackson, बहुत जरूरी है जो करता है, तो आप कर रहे हैं की आवश्यकता होगी रीस्टेसी के साथ जीडब्ल्यूटी को एकीकृत करने की कोशिश कर रहा है।जैक्सन मार्शलिंग

RestClient.setJacksonMarshallingActive(true); 

या

<script type="text/javascript"> 
    erraiJaxRsJacksonMarshallingActive = true; 
</script> 

आप उन्नत सुविधाओं

के लिए अलग JAX-आरएस इंटरफेस बनाने की आवश्यकता होगी का उपयोग कर सक्रिय किया जा सकता अपने JAX-आरएस REST इंटरफ़ेस रिटर्न उन्नत हैं ऑब्जेक्ट्स, जैसे ATOM (या अधिक बिंदु पर, org.jboss.resteasy.plugins.providers.atom.Feed) जैसे क्लास आयात करते हैं, आपको दो जावा इंटरफेस में अपने आरईएसटी इंटरफ़ेस को विभाजित करने की आवश्यकता होगी, क्योंकि एरराई नहीं करता है इन वस्तुओं के बारे में जानें, और कक्षाएं शायद ऐसे राज्य में नहीं हैं जिन्हें आसानी से जीडब्ल्यूटी में आयात किया जा सके।

एक इंटरफ़ेस आपके सादे पुराने JSON और XML विधियों को पकड़ सकता है, जबकि अन्य एटीओएम विधियों को पकड़ सकता है। इस तरह आप अपने जीडब्ल्यूटी आवेदन में अज्ञात कक्षाओं के साथ इंटरफ़ेस का संदर्भ देने से बच सकते हैं।

नोट

Errai only supports JSON mashalling at this point, हालांकि भविष्य में आप कस्टम marshallers परिभाषित करने में सक्षम हो सकता है।

+0

यह वास्तव में एक पूर्ण उत्तर है! – jonasr

2

सीओआरएस को लागू करने के लिए (इसलिए मैं क्रॉस-साइट अनुरोध प्राप्त कर सकता हूं), क्योंकि मैं रीस्टेसी का उपयोग कर रहा हूं, मैंने स्वीकार किए गए उत्तर द्वारा सुझाए गए वर्गों का पालन किया और इसे थोड़ा सा काम करने की आवश्यकता थी। ,

//@Path("/1") 
@Path("/") // I wanted to use for all of the resources 
@Provider 
@ServerInterceptor 
public class RESTv1 implements RESTInterfaceV1, MessageBodyWriterInterceptor 
{ 

    /* Enables the call from any origin. */ 
    /* To allow only a specific domain, say example.com, use "example.com" instead of "*" */ 
    @Override 
    public void write(final MessageBodyWriterContext context) throws IOException, WebApplicationException 
    { context.getHeaders().add(RESTInterfaceV1.ACCESS_CONTROL_ALLOW_ORIGIN, "*"); 
     context.proceed();  
    } 

    /* This is a RESTful method like any other. 
    The browser sends an OPTION request to check if the domain accepts CORS. 
    It sends via header (Access-Control-Request-Method) the method it wants to use, say 'post', 
    and will only use it if it gets a header (Access-Control-Allow-Methods) back with the intended 
    method in its value. 
    The method below then checks for any Access-Control-Request-Method header sent and simply 
    replies its value in a Access-Control-Allow-Methods, thus allowing any method to be used. 

    The same applies to Access-Control-Request-Headers and Access-Control-Allow-Headers. 
    */ 
    @OPTIONS 
    @Path("/{path:.*}") 
    public Response handleCORSRequest(
     @HeaderParam(RESTInterfaceV1.ACCESS_CONTROL_REQUEST_METHOD) final String requestMethod, 
     @HeaderParam(RESTInterfaceV1.ACCESS_CONTROL_REQUEST_HEADERS) final String requestHeaders) 
    { 
     final ResponseBuilder retValue = Response.ok(); 

     if (requestHeaders != null) 
      retValue.header(RESTInterfaceV1.ACCESS_CONTROL_ALLOW_HEADERS, requestHeaders); 

     if (requestMethod != null) 
      retValue.header(RESTInterfaceV1.ACCESS_CONTROL_ALLOW_METHODS, requestMethod); 

     retValue.header(RESTInterfaceV1.ACCESS_CONTROL_ALLOW_ORIGIN, "*"); 

     return retValue.build(); 
    } 
} 

लें देखभाल के रूप में यह (ACCESS_CONTROL_ALLOW_ORIGIN_HEADER दोनों तरीकों में "*" पर सेट है) किसी भी मूल से अनुरोध की अनुमति देगा: यहाँ मैं क्या इस्तेमाल किया है।

उन स्थिरांक के लिए मान इस प्रकार हैं:

public interface RESTInterfaceV1 { 
    // names of the headers 
    public static final String ACCESS_CONTROL_ALLOW_ORIGIN = "Access-Control-Allow-Origin"; 
    public static final String ACCESS_CONTROL_ALLOW_METHODS = "Access-Control-Allow-Methods"; 
    public static final String ACCESS_CONTROL_ALLOW_HEADERS = "Access-Control-Allow-Headers"; 
    public static final String ACCESS_CONTROL_REQUEST_HEADERS = "Access-Control-Request-Headers"; 
    public static final String ACCESS_CONTROL_REQUEST_METHOD = "Access-Control-Request-Method"; 
} 

यह Thatss!

- ए

संबंधित मुद्दे