servicii Web, într-o formă sau alta, au fost în jur de mai mult de două decenii. De exemplu, serviciile XML-RPC au apărut la sfârșitul anilor 1990, urmate în scurt timp de cele scrise în offshoot-ul SOAP. Servicii în restul stil arhitectural, de asemenea, a făcut scena în urmă cu aproximativ două decenii, la scurt timp după XML-RPC și săpun trailblazers. Serviciile în stil REST (în continuare, Restful) domină acum pe site-uri populare precum eBay, Facebook și Twitter. În ciuda alternativelor la serviciile web pentru calculul distribuit (de ex., serviciile web Restful rămân atractive din mai multe motive:

  • serviciile Restful se bazează pe infrastructura și protocoalele existente, în special pe serverele web și pe protocoalele HTTP/HTTPS. O organizație care are site-uri web bazate pe HTML poate adăuga cu ușurință servicii web pentru clienții interesați mai mult de date și de funcționalitatea de bază decât de prezentarea HTML., Amazon, de exemplu, a inițiat punerea la dispoziție a acelorași informații și funcționalități atât prin intermediul site-urilor web, cât și al serviciilor web, fie pe bază de săpun, fie odihnitor.serviciile Restful tratează HTTP ca un API, evitând astfel stratificarea software complicată care a ajuns să caracterizeze abordarea bazată pe SOAP a serviciilor web. De exemplu, API-ul Restful acceptă operațiunile standard CRUD (Create-Read-Update-Delete) prin verbele HTTP POST-GET-PUT-DELETE, respectiv; codurile de stare HTTP informează un solicitant dacă o solicitare a reușit sau de ce a eșuat.,serviciile web Restful pot fi la fel de simple sau complicate după cum este necesar. Restful este un stil—într-adevăr, unul foarte flexibil-mai degrabă decât un set de prescripții despre modul în care serviciile ar trebui să fie proiectate și structurate. (Dezavantajul însoțitor este că poate fi greu pentru a determina ceea ce nu contează ca un serviciu odihnitor.pentru un consumator sau client, serviciile web Restful sunt neutre din punct de vedere lingvistic și al platformei. Clientul face cereri în HTTP(S) și primește răspunsuri text într-un format adecvat pentru schimbul de date moderne (de exemplu, JSON).,aproape fiecare limbaj de programare cu scop general are cel puțin suport adecvat (și adesea puternic) pentru HTTP/HTTPS, ceea ce înseamnă că clienții de servicii web pot fi scrise în acele limbi.

acest articol explorează servicii ușoare Restful în Java printr-un exemplu de cod complet.

Odihnitor romane de servicii web

Odihnitor romane serviciu web este format din trei programator-definite clase:

  • Novel clasa reprezintă un roman cu doar trei proprietăți: o mașină generat de IDENTITATE, un autor, și un titlu., Proprietățile ar putea fi extinse pentru mai mult realism, dar vreau să păstrez acest exemplu simplu.
  • Novels clasa este format de utilități pentru diferite sarcini: conversia unui text simplu de codare de un Novel sau o listă a acestora în XML sau JSON; sprijinirea operațiunile CRUD pe romanele de colectare; și inițializarea colecție de date stocate într-un fișier. ClasaNovels mediază între instanțeleNovel și servlet.,
  • NovelsServlet clasa derivă din HttpServlet, un robust și flexibil bucată de software-ul care a fost în jurul valorii de foarte devreme enterprise Java de la sfârșitul anilor 1990. Servlet acționează ca un HTTP final pentru client CRUD cereri. Codul servlet se concentrează pe procesarea cererilor clientului și generarea răspunsurilor corespunzătoare, lăsând detaliile diabolice utilităților din clasa Novels.unele cadre Java, cum ar fi Jersey (JAX-RS) și Restlet, sunt proiectate pentru Servicii odihnitoare., Cu toate acestea, HttpServlet pe cont propriu oferă un API ușor, flexibil, puternic și bine testat pentru furnizarea unor astfel de servicii. Voi demonstra acest lucru cu exemplul romanelor.

    implementați serviciul web romane

    implementarea serviciului web romane necesită un server web, desigur. Alegerea mea este Tomcat, dar serviciul ar trebui să funcționeze (ultimele cuvinte celebre!) dacă este găzduit pe, de exemplu, Jetty sau chiar un server de aplicații Java. Codul și un README care rezumă modul de instalare Tomcat sunt disponibile pe site-ul meu., Există, de asemenea, un script documentat Apache Ant care construiește serviciul romanelor (sau orice alt serviciu sau site web) și îl implementează sub Tomcat sau echivalentul.

    Tomcat este disponibil pentru descărcare de pe site-ul său. După ce îl instalați local, lăsați TOMCAT_HOME să fie directorul de instalare., Există două subdirectoare de interes imediat:

    • TOMCAT_HOME/bin director conține pornire și oprire script-uri pentru sistemele Unix-like (startup.sh și shutdown.sh) și Windows (startup.bat și shutdown.bat). Tomcat rulează ca o aplicație Java. Container servlet serverului web este numit Catalina. (În Jetty, serverul web și containerul au același nume.) Odată ce Tomcat pornește, introduceți într-un browser pentru a vedea documentație extinsă, inclusiv exemple.,directorul

    • TOMCAT_HOME/webapps este implicit pentru site-urile web și serviciile web implementate. Simplu mod de a implementa un site sau serviciu web este de a copia un fișier JAR cu un .war extensia (prin urmare, un fișier WAR) pentru TOMCAT_HOME/webapps sau un subdirector al acestuia. Tomcat despachetează apoi fișierul de război în propriul său director. De exemplu, Tomcat ar despacheta novels.war într-un subdirector numit novels, lăsând novels.war ca-este., Un site web sau un serviciu poate fi eliminat prin ștergerea fișierului WAR și actualizat prin suprascrierea fișierului WAR cu o nouă versiune. Apropo, primul pas în depanarea unui site web sau a unui serviciu este să verificați dacă Tomcat a despachetat fișierul de război; dacă nu, site-ul sau serviciul nu a fost publicat din cauza unei erori fatale în cod sau configurație.,

    • Pentru Tomcat ascultă în mod implicit pe portul 8080 pentru cereri HTTP, o cerere URL-ul pentru Tomcat de pe mașina locală începe:

      Access a programmer-deployed WAR file by adding the WAR file’s name but without the .war extension:

      If the service was deployed in a subdirectory (e.g., myapps) of TOMCAT_HOME, this would be reflected in the URL:

      I’ll offer more details about this in the testing section near the end of the article.

    As noted, the ZIP file on my homepage contains an Ant script that compiles and deploys a website or service. (A copy of novels.war is also included in the ZIP file.) For the novels example, a sample command (with % as the command-line prompt) is:

    % ant -Dwar.name=novels deploy

    Aceasta comanda compilează fișierele sursă Java și apoi construiește un dislocabile fișier numit novels.war, frunzele acest fișier în directorul curent, și copii să TOMCAT_HOME/webapps., Dacă totul merge bine, un GET cerere (folosind un browser sau un utilitar de linie de comandă, cum ar fi curl) servește ca un prim test:

    % curl http://localhost:8080/novels/

    Tomcat este configurat, în mod implicit, pentru hot implementează: serverul web nu trebuie să fie închisă pentru a implementa, actualiza, sau a elimina o aplicație web.

    serviciul romanelor la nivel de cod

    Să revenim la exemplul romanelor, dar la nivel de cod. Luați în considerare clasa Novel de mai jos:

    Exemplul 1., Romanul clasa

    Această clasă implementează compareTo metoda de Comparable interfață pentru Novel cazuri sunt stocate într-un fir de siguranță ConcurrentHashMap, care nu impune o ordine sortată. În răspuns la solicitările de a vizualiza o colecție de romane de servicii felul o colecție (o ArrayList) extrase de pe hartă; punerea în aplicare a compareTo impune o ordine crescătoare ordine sortată prin Novel ID.,

    clasa Novels conține diferite funcții de utilitate:

    Exemplul 2. Clasa de utilitate romane

    metoda cea mai complicată este populate, care se citește dintr-un fișier text conținut în fișierul de război desfășurat. Fișierul text conține colecția inițială de romane. Pentru a deschide fișierul text, populate metoda trebuie ServletContext, un Java hartă care conține toate informațiile critice despre servlet încorporate în container de servlet., Fișierul text, la rândul său, conține înregistrări, cum ar fi acest lucru:

    Jane Austen!Persuasion

    linia este analizat în două părți (autorul și titlul), separate printr-bang simbolul (!). Metoda construiește apoi o instanță Novel, stabilește proprietățile autorului și titlului și adaugă romanul la colecție, care acționează ca un depozit de date în memorie.

    Novels clasa are, de asemenea, utilitare pentru a codifica colecția de romane în XML sau JSON, în funcție de formatul pe care solicitantul îl preferă., XML este implicit, dar JSON este disponibil la cerere. Un pachet XML-to-JSON ușor oferă JSON. Mai multe detalii despre codificare sunt mai jos.

    Exemplul 3. La NovelsServlet clasa

    Reamintim că NovelsServlet clasa de mai sus se extinde HttpServlet clasa, care la rândul său se extinde GenericServlet clasa, care implementează Servlet interfata:

    NovelsServlet extends HttpServlet extends GenericServlet implements Servlet

    Ca numele face clar, HttpServlet este proiectat pentru servlet-uri livrate prin HTTP(S)., Clasa oferă gol metode numit după cerere HTTP standard verbe (oficial, metode):

    • doPost (Post = Crea)
    • doGet (Ia = a Citi)
    • doPut (Pune = Update)
    • doDelete (Delete = Șterge)

    Unele suplimentare HTTP verbe sunt acoperite, de asemenea. O extensie a HttpServlet, cum ar fi NovelsServlet, anulează orice do metoda de interes, lăsând pe alții așa cum nu-ops., NovelsServletînlocuiește șapte dintre metodele do.

    fiecare dintre metodele HttpServlet CRUD are aceleași două argumente. Aici este doPost ca un exemplu:

    public void doPost(HttpServletRequest request, HttpServletResponse response) {

    request argument este o hartă de cerere HTTP informații, și response oferă un flux de ieșire înapoi solicitantului., O metodă cum ar fi doPost este structurat după cum urmează:

    • Citeste request informații, luând orice măsură necesară pentru a genera un răspuns. Dacă informațiile lipsesc sau sunt deficitare în alt mod, generați o eroare.
    • de a Folosi extrase solicita informații pentru a efectua adecvat CRUD funcționare (în acest caz, de a crea un Novel) și apoi codifica un răspuns adecvat la solicitant folosind response flux de ieșire să facă acest lucru., În cazul doPost, răspunsul este o confirmare a faptului că un nou roman a fost creat și adăugat la colecție. Odată ce răspunsul este trimis, fluxul de ieșire este închis, ceea ce închide și conexiunea.

    mai multe despre metoda do suprascrie

    o cerere HTTP are o structură relativ simplă. Iată o schiță în HTTP 1 familiar.,1 format, cu comentarii introduse de dublu semne clare:

    linia De start incepe cu HTTP verb (în acest caz, GET) și URI (Uniform Resource Identifier), care este substantiv (în acest caz, novels) ca nume vizate de resurse. Anteturile constau din perechi cheie-valoare, cu un punct care separă cheia din stânga de valoarea(valorile) din dreapta., Antetul cu tasta Host (case insensitive) este necesar; hostname localhost este simbolic adresa locale masina de pe mașina locală, și numărul de port 8080 este implicit pentru Tomcat web server așteaptă cereri HTTP. (În mod implicit, Tomcat ascultă pe portul 8443 pentru cererile HTTPS.) Elementele antetului pot apărea în ordine arbitrară. În acest exemplu, valoarea antetului Accept-type este tipul MIME text/plain.,

    Unele cereri (în special, POST și PUT) au trupuri, în timp ce altele (în special, GET și DELETE) nu. Dacă există un corp (poate gol), două linii noi separă anteturile de corp; corpul HTTP este format din perechi cheie-valoare. Pentru cererile fără corp, elementele antetului, cum ar fi șirul de interogare, pot fi utilizate pentru a trimite informații., Aici este o cerere de a GET /novels resurse cu ID-ul de 2:

    GET /novels?id=2

    șirul De interogare începe cu semnul de întrebare și, în general, constă din perechi cheie-valoare, deși o cheie fără o valoare este posibil.

    HttpServlet, cu metode, cum ar fi getParameter și getParameterMap, frumos se ascunde distincția între cereri HTTP cu și fără trup., În romanele exemplu, getParameter metodă este folosită pentru a extrage informațiile necesare din partea GET, POST și DELETE cereri. (Manipularea unui PUT cerere necesită cod de nivel inferior, deoarece Tomcat nu oferă o hartă parametru funcțional pentruPUT cereri.,) Aici, pentru ilustrare, o felie de doPost metoda în NovelsServlet override:

    Pentru o bodyless DELETE cerere, abordarea este în esență același:

    doGet metoda trebuie să se facă distincția între două arome de un GET cerere: o aroma înseamnă „toate”, întrucât alte mijloace de a obține un anumit una., Dacă GET cerere URL-ul conține un șir de interogare a cărui cheie este un ID, atunci cererea este interpretat ca fiind „cea specificată”:

    http://localhost:8080/novels?id=2 ## GET specified

    Dacă nu există nici un șir de interogare, GET cererea este interpretat ca „toate”:

    http://localhost:8080/novels ## GET all

    diabolic detalii

    romanele servicii de design reflectă modul în care un bazate pe Java web server, cum ar fi lucrări de Tomcat. La pornire, Tomcat construiește un pool de fir din care sunt desenate manipulatorii de Cereri, o abordare cunoscută sub numele de modelul one thread per request., Versiunile moderne ale Tomcat folosesc, de asemenea, I/O care nu blochează pentru a spori performanța.

    serviciul romane execută ca o singură instanță a claseiNovelsServlet, care la rândul său menține o singură colecție de romane. În consecință, ar apărea o condiție de cursă, de exemplu, dacă aceste două solicitări ar fi procesate simultan:

    • o cerere schimbă colecția adăugând un nou roman.
    • cealaltă cerere primește toate romanele din colecție.

    rezultatul este nedeterminat, în funcție de exact cum se suprapun operațiunile de citire și scriere., Pentru a evita această problemă, serviciul romanes folosește un fir sigur ConcurrentMap. Cheile pentru această hartă sunt generate cu un fir sigur AtomicInteger. Aici este segmentul de cod relevant:

    public class Novels {
    private ConcurrentMap<Integer, Novel> novels;
    private AtomicInteger mapKey;
    ...

    în mod implicit, un răspuns la o solicitare client este codificat ca XML. Programul romanelor folosește clasa XMLEncoder pentru simplitate; o opțiune mult mai bogată este biblioteca JAX-B., Codul este simplu:

    Object parametru este fie un sortate ArrayList de romane (ca răspuns la o „ia tot” cerere); sau un singur Novel exemplu (ca răspuns la o cerere); sau un String (un mesaj de confirmare).

    dacă un antet de solicitare HTTP se referă la JSON ca tip dorit, atunci XML este convertit în JSON., Aici este check-in-ul doGet metoda de NovelsServlet:

    String accept = request.getHeader("accept"); // "accept" is case insensitive
    if (accept != null && accept.contains("json")) json = true;

    Novels clasa de case toJson metoda, care transformă XML JSON:

    NovelsServlet verifică erorile de diferite tipuri. De exemplu, o solicitare POST ar trebui să includă un autor și un titlu pentru noul roman., Dacă lipsește, doPost metoda arunca o exceptie:

    if (author == null || title == null)
    throw new RuntimeException(Integer.toString(HttpServletResponse.SC_BAD_REQUEST));

    SC în SC_BAD_REQUEST standuri pentru cod de stare, și BAD_REQUEST standard HTTP valoare numerică de 400. Dacă HTTP verb într-o cerere este TRACE, un alt cod de stare este returnat:

    Testarea romane de servicii

    Testarea unui serviciu web cu un browser este complicat., Printre verbele CRUD, browserele moderne generează doar POST (Create) și GET (Read) cereri. Chiar și o POST cerere este o provocare de la un browser, ca valorile-cheie pentru organismul trebuie să fie incluse; acest lucru se face de obicei printr-un formular HTML. O utilitate linie de comandă, cum ar fi curl este o modalitate mai bună de a merge, ca această secțiune ilustrează cu unele curl comenzi, care sunt incluse în ZIP pe site-ul meu.,

    iată câteva teste de probă fără ieșirea corespunzătoare:

    % curl localhost:8080/novels/
    % curl localhost:8080/novels?id=1
    % curl --header "Accept: application/json" localhost:8080/novels/

    prima comandă solicită toate romanele, care sunt codificate implicit în XML. A doua comandă solicită romanul cu un ID de 1, Care este codificat în XML. Ultima comandă adaugă un Accept antet element cu application/json ca tip MIME dorit. Comanda get one ar putea folosi și acest element de antet. Astfel de cereri au JSON, mai degrabă decât răspunsurile XML.,

    următoarele două comenzi crea un nou roman în colecția și confirma plus:

    % curl --request POST --data "author=Tolstoy&title=War and Peace" localhost:8080/novels/
    % curl localhost:8080/novels?id=4

    PUT comanda curl seamănă cu un POST comanda cu excepția faptului că PUT corpul nu folosește sintaxa standard. Documentația pentru doPut metoda în NovelsServlet merge în detaliu, dar versiunea scurtă este că Tomcat nu generează o harta buna pe PUT cereri., Aici este proba PUT comandă și o confirmare de comandă:

    % curl --request PUT --data "id=3#title=This is an UPDATE" localhost:8080/novels/
    % curl localhost:8080/novels?id=3

    Cea de-a doua comandă confirmă actualizarea.

    în cele din urmă, comanda DELETE funcționează conform așteptărilor:

    % curl --request DELETE localhost:8080/novels?id=2
    % curl localhost:8080/novels/

    cererea este ca romanul cu ID-ul 2 să fie șters. A doua comandă Arată romanele rămase.

    web.fișierul de configurare xml

    deși este oficial opțional, un fișier de configurare web.xml este un element principal într-un site web sau serviciu de producție., Fișierul de configurare permite rutarea, securitatea și alte caracteristici ale unui site sau serviciu să fie specificate independent de codul de implementare. Configurația pentru romanele de servicii se ocupă de rutare prin furnizarea unui model de URL pentru cereri expediate la acest serviciu:

    servlet-name element oferă o abreviere (novels) pentru servlet este complet calificat nume de clasă (novels.NovelsServlet), și acest nume este utilizat în servlet-mapping element de mai jos.,

    Reamintim că un URL pentru un implementat serviciul de numele fișierului WAR după numărul de port:

    slash imediat după numărul de port începe URI cunoscute ca calea spre resursa solicitată, în acest caz, romane de serviciu; prin urmare, termenul novels apare după primul single slash.

    În web.xml fișier, url-pattern este specificat ca /*, ceea ce înseamnă că orice drum începe cu /romane., Să presupunem că Tomcat întâlnește un contrived cerere URL, cum ar fi acest lucru:

    web.xml configurare specifică faptul că această cerere, de asemenea, ar trebui să fie expediate către romane servlet pentru că /* model acoperă /foobar. URL-ul contrived are astfel același rezultat ca cel legitim prezentat mai sus.

    un fișier de configurare la nivel de producție poate include informații despre securitate, atât la nivel de fir, cât și la nivel de utilizatori., Chiar și în acest caz, fișierul de configurare ar fi doar de două sau trei ori mai mare decât cel al eșantionului.

    înfășurarea

    HttpServlet este în Centrul Tehnologiilor Web Java. Un site web sau un serviciu web, cum ar fi serviciul romanelor, extinde această clasă, depășind verbele de interes do. Un cadru Restful, cum ar fi Jersey (JAX-RS) sau Restlet face în esență același lucru prin furnizarea unui servlet personalizat, care apoi acționează ca punct final HTTP(S) pentru cererile împotriva unei aplicații web scrise în cadru.,

    o aplicație bazată pe servlet are acces, desigur, la orice bibliotecă Java necesară în aplicația web. Dacă cererea urmează separarea de preocupările principiu, atunci servlet codul rămâne atractiv, simplu: codul verifică o cerere, eliberarea de eroare corespunzător dacă există deficiențe; în caz contrar, codul apeluri pentru orice funcționalitate pot fi necesare (de exemplu, interogarea unei baze de date, codificarea un răspuns într-un anumit format), și apoi trimite raspunsul solicitantului., HttpServletRequest și HttpServletResponse tipuri de face mai ușor pentru a efectua servlet-activitatea specifică de lectură la cerere și în scris răspunsul.Java are API-uri care variază de la foarte simplu la foarte complicat. Dacă trebuie să furnizați câteva servicii odihnitoare folosind Java, sfatul meu este să încercați HttpServlet înainte de orice altceva.