खोज…


टिप्पणियों

यह अनुभाग cxf क्या है का एक सिंहावलोकन प्रदान करता है, और क्यों एक डेवलपर इसका उपयोग करना चाहता है।

यह cxf के भीतर किसी भी बड़े विषयों का उल्लेख करना चाहिए, और संबंधित विषयों के लिए लिंक करना चाहिए। चूंकि cxf के लिए दस्तावेज़ीकरण नया है, इसलिए आपको उन संबंधित विषयों के प्रारंभिक संस्करण बनाने की आवश्यकता हो सकती है।

प्रदाता के साथ मूल Webclient

आरंभ करने के लिए हमें एक कारखाने की आवश्यकता है जो WebClients का उत्पादन करे।

public class ClientFactory {
    private Map<String, WebClient> cache = new HashMap<>();

    public enum RESTClient {
        PORTAL;
    }

    public WebClient fetchRestClient(RESTClient restClient) {

        if (this.cache.containsKey(restClient)) {
            return WebClient.fromClient(this.cache.get(rc));
        }

        if (RESTClient.enum.equals(rc)) {

            List<Object> providers = new ArrayList<Object>();
            providers.add(new GsonMessageBodyProvider());

            WebClient webClient = WebClient.create("https://blah.com", providers);

            HTTPConduit conduit = WebClient.getConfig(webClient).getHttpConduit();
            conduit.getClient().setReceiveTimeout(recieveTimeout);
            conduit.getClient().setConnectionTimeout(connectionTimout);

            this.cache.put(RESTClient.CAT_DEVELOPER_PORTAL.name(), webClient);
            return WebClient.fromClient(webClient);// thread safe
        }
    }
}
  • पहले हम प्रदाताओं की एक सूची बनाते हैं (बाद में उन तक पहुंचेंगे)
  • अगला हम स्थैतिक कारखाने "बनाएँ ()" का उपयोग करके एक नया वेबक्लिअर बनाते हैं। यहां हम कुछ अन्य चीजों को जोड़ सकते हैं जैसे बेसिक ऑथ क्रेडिट और थ्रेड सेफ्टी। अभी के लिए इस एक का उपयोग करें।
  • अगला हम HTTPConduit को बाहर निकालते हैं और टाइमआउट सेट करते हैं। CXF जावा बेस क्लास क्लाइंट के साथ आता है लेकिन आप ग्लासफिश या अन्य का उपयोग कर सकते हैं।
  • अंत में हम WebClient को कैश करते हैं। यह महत्वपूर्ण है क्योंकि अब तक का कोड बनाना महंगा है। अगली पंक्ति बताती है कि इसे थ्रेडसेफ़ कैसे बनाया जाए। ध्यान दें कि यह भी है कि हम कैश से कोड कैसे खींचते हैं। अनिवार्य रूप से हम REST कॉल का एक मॉडल बना रहे हैं और फिर हर बार जब हमें इसकी आवश्यकता होती है तो इसे क्लोन कर लेते हैं।
  • ध्यान दें कि यहां क्या नहीं है: हमने कोई पैरामीटर या URLS नहीं जोड़ा है। इन्हें यहां जोड़ा जा सकता है लेकिन यह एक विशिष्ट समापन बिंदु बना देगा और हम एक सामान्य चाहते हैं। इसके अलावा अनुरोध में कोई हेडर नहीं जोड़ा गया है। ये इसे "क्लोन" के रूप में नहीं बनाते हैं, इसलिए उन्हें बाद में जोड़ा जाना चाहिए।

अब हमारे पास एक WebClient है जो जाने के लिए तैयार है। बाकी कॉल सेट करें।

public Person fetchPerson(Long id) {
    long timer t = System.currentTimeMillis();
    Person person = null;
    try {
        wc = this.factory.findWebClient(RESTClient.PORTAL);
        wc.header(AUTH_HEADER, SUBSCRIPTION_KEY);
        wc.header(HttpHeaders.ACCEPT, "application/person-v1+json");

        wc.path("person").path("base");
        wc.query("id", String.valueOf(id));

        person = wc.get(Person.class);
    }
    catch (WebApplicationException wae) {
        // we wanna skip these. They will show up in the "finally" logs.
    }
    catch (Exception e) {
        log.error(MessageFormat.format("Error fetching Person: id:{0} ", id), e);
    }
    finally {
        log.info("GET HTTP:{} - Time:[{}ms] - URL:{} - Content-Type:{}", wc.getResponse().getStatus(), (System.currentTimeMillis() - timer), wc.getCurrentURI(), wc.getResponse().getMetadata().get("content-type"));
        wc.close();
    }
    return p;
}
  • "कोशिश" के अंदर हम कारखाने से एक WebClient हड़प लेते हैं। यह एक नया "ठंढा" है।
  • आगे हमने कुछ हेडर लगाए। यहाँ हम किसी प्रकार के Auth हेडर को जोड़ते हैं और फिर एक हेडर को स्वीकार करते हैं। ध्यान दें कि हमारे पास एक कस्टम हेडर है।
  • पथ जोड़ने और क्वेरी स्ट्रिंग अगले आता है। ध्यान रखें कि इन चरणों का कोई क्रम नहीं है।
  • अंत में हम "प्राप्त" करते हैं। इस कोर्स को करने के कई तरीके हैं। यहां हमारे पास सीएक्सएफ है जो हमारे लिए JSON मैपिंग है। जब इस तरह से किया जाता है तो हमें WebApplicationException से निपटना पड़ता है। इसलिए यदि हमें 404 मिलते हैं, तो सीएक्सएफ एक अपवाद फेंक देगा। यहाँ ध्यान दें मैं उन अपवादों को खाता हूँ क्योंकि मैं अंत में प्रतिक्रिया को लॉग इन करता हूँ। हालाँकि मैं किसी अन्य अपवाद को प्राप्त करना चाहता हूं क्योंकि वे महत्वपूर्ण हो सकते हैं।
  • यदि आपको यह एक्सेप्शन हैंडलिंग स्विचिंग पसंद नहीं है, तो आप रिस्पॉन्स ऑब्जेक्ट को "प्राप्त" से वापस पा सकते हैं। यह ऑब्जेक्ट इकाई और HTTP स्थिति कोड रखता है। यह एक WebApplicationException फेंक कभी नहीं होगा। एकमात्र दोष यह है कि यह आपके लिए JSON मैपिंग नहीं करता है।
  • अंत में, "अंत में" खंड में हमारे पास "wc.close ()" है। यदि आपको प्राप्त खंड से वस्तु मिलती है तो आपको वास्तव में ऐसा करने की आवश्यकता नहीं है। कुछ गलत हो सकता है, लेकिन यह एक अच्छा असफल है।

तो, उस "स्वीकार" शीर्षक के बारे में क्या: आवेदन / व्यक्ति-v1 + json कैसे CXF पता होगा कि यह कैसे पार्स करने के लिए? CXF कुछ JSON पार्सरों में बनाया गया है, लेकिन मैं Gson का उपयोग करना चाहता था। Json पार्सर्स के अन्य कार्यान्वयनों में से कई को किसी प्रकार के एनोटेशन की आवश्यकता है, लेकिन Gson की नहीं। इसका इस्तेमाल करना आसान है।

public class GsonMessageBodyProvider<T> implements MessageBodyReader<T>, MessageBodyWriter<T> {

    private Gson gson = new GsonBuilder().create();
    
    @Override
    public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
        return StringUtils.endsWithIgnoreCase(mediaType.getSubtype(), "json");
    }

    @Override
    public T readFrom(Class<T> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, String> httpHeaders, InputStream entityStream) throws IOException, WebApplicationException {
        try {
            return gson.fromJson(new BufferedReader(new InputStreamReader(entityStream, "UTF-8")), type);
        }
        catch (Exception e) {
            throw new IOException("Trouble reading into:" + type.getName(), e);
        }
    }

    @Override
    public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
        return StringUtils.containsIgnoreCase(mediaType.getSubtype(), "json");
    }

    @Override
    public long getSize(T t, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
        return 0;
    }

    @Override
    public void writeTo(T t, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream) throws IOException, WebApplicationException {
        try {
            JsonWriter writer = new JsonWriter(new OutputStreamWriter(entityStream, "UTF-8"));
            writer.setIndent("  ");
            gson.toJson(t, type, writer);
            writer.close();
        }
        catch (Exception e) {
            throw new IOException("Trouble marshalling:" + type.getName(), e);
        }
    }
}

कोड सीधे आगे है। आप दो इंटरफ़ेस लागू करते हैं: MessageBodyReader और MessageBodyWriter (या सिर्फ एक) और फिर WebClient बनाते समय इसे "प्रदाताओं" में जोड़ें। सीएक्सएफ ने वहां से इसका आंकड़ा निकाला। एक विकल्प "सच" को "रीएडेबल ()" "इज़नेबल ()" विधियों में वापस करना है। यह आश्वस्त करेगा कि सीएक्सएफ सभी में निर्मित के बजाय इस वर्ग का उपयोग करता है। जोड़े गए प्रदाताओं को पहले चेक किया जाएगा।

JAX-RS के लिए CXF की स्थापना

CXF JAX-RS के जार जार मावेन में पाए जाते हैं:

<!-- https://mvnrepository.com/artifact/org.apache.cxf/cxf-rt-rs-client -->
<dependency>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-rt-rs-client</artifactId>
    <version>3.1.10</version>
</dependency>

ये जार आप सभी इसे चलाने की जरूरत है:

cxf-rt-rs-client-3.1.10.jar
cxf-rt-transports-http-3.1.10.jar
cxf-core-3.1.10.jar
woodstox-core-asl-4.4.1.jar
stax2-api-3.1.4.jar
xmlschema-core-2.2.1.jar
cxf-rt-frontend-jaxrs-3.1.10.jar
javax.ws.rs-api-2.0.1.jar
javax.annotation-api-1.2.jar

ग्राहक फ़िल्टर

फ़िल्टर का उपयोग करने का एक अच्छा कारण लॉगिंग के लिए है। इस तकनीक का उपयोग करके एक REST कॉल को आसानी से लॉग और टाइम किया जा सकता है।

public class RestLogger implements ClientRequestFilter, ClientResponseFilter {
    private static final Logger log = LoggerFactory.getLogger(RestLogger.class);

    // Used for timing this call.
    private static final ThreadLocal<Long> startTime = new ThreadLocal<Long>();
    private boolean logRequestEntity;
    private boolean logResponseEntity;

    private static Gson GSON = new GsonBuilder().create();

    public RestLogger(boolean logRequestEntity, boolean logResponseEntity) {
        this.logRequestEntity = logRequestEntity;
        this.logResponseEntity = logResponseEntity;
    }


    @Override
    public void filter(ClientRequestContext requestContext) throws IOException {
        startTime.set(System.currentTimeMillis());
    }

    @Override
    public void filter(ClientRequestContext requestContext, ClientResponseContext responseContext) throws IOException {
        StringBuilder sb = new StringBuilder();
        sb.append("HTTP:").append(responseContext.getStatus());
        sb.append(" - Time:[").append(System.currentTimeMillis() - startTime.get().longValue()).append("ms]");
        sb.append(" - Path:").append(requestContext.getUri());
        sb.append(" - Content-type:").append(requestContext.getStringHeaders().getFirst(HttpHeaders.CONTENT_TYPE.toString()));
        sb.append(" - Accept:").append(requestContext.getStringHeaders().getFirst(HttpHeaders.ACCEPT.toString()));
        if (logRequestEntity) {
            sb.append(" - RequestBody:").append(requestContext.getEntity() != null ? GSON.toJson(requestContext.getEntity()) : "none");
        }
        if (logResponseEntity) {
            sb.append(" - ResponseBody:").append(this.logResponse(responseContext));
        }
        log.info(sb.toString());
    }

    private String logResponse(ClientResponseContext response) {
        StringBuilder b = new StringBuilder();
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        InputStream in = response.getEntityStream();
        try {
            ReaderWriter.writeTo(in, out);
            byte[] requestEntity = out.toByteArray();
            b.append(new String(requestEntity));
            response.setEntityStream(new ByteArrayInputStream(requestEntity));
        }
        catch (IOException ex) {
            throw new ClientHandlerException(ex);
        }
        return b.toString();
    }
}

ऊपर आप देख सकते हैं कि रिस्पांस भेजे जाने से पहले अनुरोध इंटरसेप्टेड है और थ्रेडलोकल लॉन्ग सेट है। जब प्रतिक्रिया वापस आ जाती है तो हम अनुरोध और प्रतिक्रिया और सभी प्रकार के प्रासंगिक डेटा लॉग कर सकते हैं। बेशक यह केवल Gson प्रतिक्रियाओं और इस तरह के लिए काम करता है, लेकिन आसानी से संशोधित किया जा सकता है। इसे इस तरह सेट किया गया है:

List<Object> providers = new ArrayList<Object>();
providers.add(new GsonMessageBodyProvider());
providers.add(new RestLogger(true, true)); <------right here!

WebClient webClient = WebClient.create(PORTAL_URL, providers);

प्रदान किए गए लॉग को कुछ इस तरह दिखना चाहिए:

7278 [main] INFO  blah.RestLogger - HTTP:200 - Time:[1391ms] - User:unknown - Path:https://blah.com/tmet/moduleDescriptions/desc?languageCode=en&moduleId=142 - Content-type:null - Accept:application/json - RequestBody:none - ResponseBody:{"languageCode":"EN","moduleId":142,"moduleDescription":"ECAP"}


Modified text is an extract of the original Stack Overflow Documentation
के तहत लाइसेंस प्राप्त है CC BY-SA 3.0
से संबद्ध नहीं है Stack Overflow