Eclipse + Jersey + Glassfish3を使用してJavaでRESTful Webサービスを作成する

みなさんこんばんは!



少し前(今年の2月)に、プログラミングをすることにしました。 言語としてJavaが選択されました。 そしてその瞬間から、私はこの言語のすべての可能性をしつこく研究しています。 最近、ハブでのRESTfulに関する記事に出会いました これらのサービスを作成する別の方法を強調する必要があることを読み、理解しました。 また、初心者向けに特定の記事が不可解に書かれていることにも感銘を受けました。 私は、Webサービスを作成するアプリケーションの部分について話す記事を書くことにしました。



私は本当のふりをしません。 Webサービスを作成する簡単で迅速な方法を示したいだけです。



開始する



必要なソフトウェア


最も重要なことはIDEです。 Eclipseが好きです。 Java EE Developers JunoのEclipseでこのプロジェクトを書きました。 厳密に言えば、以前のリリースはより安定していましたが、これはより見栄えが良いです。 RESTのフレームワークとしてJerseyを選択しました。 簡単に見つけてダウンロードできます。 IDE自体と同じです。 サーバーとして、Eclipse用のGlassFishプラグインをインストールしました。 インストール手順は簡単に見つけることができます。 まあ、それだけです。



プロジェクト作成


だから。 Eclipse、Jersey JARフォルダー、GlassFishプラグインがインストールされています。 次に、Eclipseを実行し、最後のタブで空の動的Webプロジェクトを作成します。web.xmlファイルの生成を担当するチェックボックスをオンにすることを忘れないでください。





Eclipseは、空のプロジェクトを作成します。これは、サーバーで実行しようとすることができます(Run As-> Run On Server)。

起動すると、組み込みのブラウザが表示され、Hello Worldページが表示されます。 ここで、Jersey JARファイルを[ プロジェクト名 ] / WebContent / WEB-INF / libフォルダーにコピーする必要があります。 したがって、必要なすべてのライブラリを接続します。 これでweb.xmlファイルの番です。 [ プロジェクト名 ] / WebContent / WEB-INFにあります。

これがこのファイルのリストです



<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <display-name>WebRest</display-name> <servlet> <servlet-name>Jersey REST Service</servlet-name> <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class> <init-param> <param-name>com.sun.jersey.config.property.packages</param-name> <param-value>ru.example.rest.resource</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>Jersey REST Service</servlet-name> <url-pattern>/rest/*</url-pattern> </servlet-mapping> </web-app>
      
      







パラメータcom.sun.jersey.config.property.packagesは、リソースファイルが保存されるパッケージを示す必要があります。 また、url-patternタグには、Webサービスへのパスが格納されます。 これはRESTful Webサービスの基本的な瞬間であると言ってはならない。なぜなら、そのイデオロギー自体は、各リソースには独自のアドレスが必要だと言っているからだ。 これで、Webサービスはlocalhost :8080 / [ プロジェクト名 ] / rest /で利用可能になりました。 これがベースURIになります。



Webサービスの作成



エンティティ作成


例として、単純なweb-sevrisを提供したかったのですが、これはそのようなミニ日記です。 つまり 1種類のメッセージエンティティがあり、それを使用します。



これがMessageクラスです



 package ru.example.rest.entity; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement public class Message { private long messageId; private String messageTitle; private String messageText; public Message() { } public Message(long messageId, String messageTitle, String messageText) { this.messageId = messageId; this.messageTitle = messageTitle; this.messageText = messageText; } public long getMessageId() { return messageId; } public void setMessageId(long messageId) { this.messageId = messageId; } public String getMessageTitle() { return messageTitle; } public void setMessageTitle(String messageTitle) { this.messageTitle = messageTitle; } public String getMessageText() { return messageText; } public void setMessageText(String messageText) { this.messageText = messageText; } @Override public String toString() { return "Message [messageId=" + messageId + ", messageTitle=" + messageTitle + ", messageText=" + messageText + "]"; } }
      
      







ここで問題が発生する可能性があるのは、@ XmlRootElementアノテーションだけです。 Java自体がこのクラスをXML形式に変換してHTTP経由で送信できるようにする必要があります。 残りは3つのフィールドを持つ通常のクラスです。 Idメッセージ、タイトルメッセージ、テキストメッセージ。



クラスで動作するモデルを作成する




コンテンツプロバイダーとして、通常のリストを使用することにしました。 この段階では、ORMに深く入り込んでデータベーステーブルにデータを保存したくありません。このトピックは別の記事にふさわしいため、次の記事になるかもしれません。 そのため、メッセージのリストを保存し、このシートで作業するためのメソッドを提供するユーティリティクラスを作成しました。



データクラスのリストを次に示します



 package ru.example.rest.model; import java.util.ArrayList; import java.util.List; import ru.example.rest.entity.Message; public class Data { private static List<Message> data; private static long count = 5; static { data = new ArrayList<Message>(); data.add(new Message(1L, "Hello", "Hello! I'm first entry!")); data.add(new Message(2L, "2nd", "second messages")); data.add(new Message(3L, "here again!", "some text")); data.add(new Message(4L, "HI!", "pam param")); } public static List<Message> getData() { return data; } public static Message findMessageById(long id) { for (Message message : data) { if (message.getMessageId() == id) { return message; } } return null; } public static boolean deleteMessageById(long id) { boolean result = false; for (Message message : data) { if (message.getMessageId() == id) { result = data.remove(message); return result; } } return result; } public static boolean updateMessage(Message message) { boolean result = false; for (Message temp: data) { if (temp.getMessageId() == message.getMessageId()) { temp.setMessageText(message.getMessageText()); temp.setMessageTitle(message.getMessageTitle()); result = true; } } return result; } public static boolean addMesage(Message message) { message.setMessageId(count); count++; return data.add(message); } }
      
      







ここでは、リストを作成して、いくつかのエントリを追加します。 次に、getData()メソッドはリスト自体へのリンクを返します。 他の方法は、名前から簡単に推測できます。



今、サービス自体


サービス自体は、要求のタイプに応じてどのURIまたはどのアクションが発生するかを示すURIを備えたリソースクラスです。 主な注釈は

この注釈は、特定のクラスまたはメソッドアドレスを指すパス(「このリソースへのパス」)です。

また、 パス ( "{id}")のバリエーションもあり、idがメソッドに渡すことができる変数であることを示します。

Consumes(MediaType)およびProduces(MediaType)は、それぞれ受信および送信されたデータについて通知します。 この例では、APPLICATION_XMLを選択しました。 なぜJSONではないのかと聞かないでください。私にとっては簡単です。 彼らがJAX-Bindを思いついたのも不思議ではありません。

GET-このメソッドはサービスからクライアントにデータを送信します。

PUT / POST-このメソッドがサービスにデータを追加/更新することを示します。

個人的には、PUTを使用して追加し、POSTを使用して更新します。

DELETE-このメソッドはストレージからデータを削除することを示します



リソースクラスのリストは次のとおりです。

パッケージru.example.rest.resource;



 import java.util.List; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import javax.xml.bind.JAXBElement; import ru.example.rest.entity.Message; import ru.example.rest.model.Data; @Path("message") public class MessageResource { @GET @Produces(MediaType.APPLICATION_XML) public List<Message> getAllMessages() { List<Message> messages = Data.getData(); if (messages == null) { throw new RuntimeException("Can't load all messages"); } return messages; } @GET @Path("{id}") @Produces(MediaType.APPLICATION_XML) public Message getMessageById(@PathParam("id") long id) { Message message = Data.findMessageById(id); if (message == null) { throw new RuntimeException("can't find mesage with id = " + id); } return message; } @PUT @Consumes(MediaType.APPLICATION_XML) public void addMessage(JAXBElement<Message> message) { if (Data.addMesage(message.getValue()) != true) { throw new RuntimeException("can't add mesage with id = " + message.getValue().getMessageId()); } } @DELETE @Path("{id}") public void deleteMessage(@PathParam("id") long id) { if (Data.deleteMessageById(id) != true) { throw new RuntimeException("can't delete mesage with id = " + id); } } @POST @Consumes(MediaType.APPLICATION_XML) public void updateMessage(JAXBElement<Message> message) { if (Data.updateMessage(message.getValue()) != true) { throw new RuntimeException("can't update mesage with id = " + message.getValue().getMessageId()); } } }
      
      







いくつかの点を明確にする価値があると思います。 リソースクラスはlocalhost :8080 / [ プロジェクト名 ] / rest / messageで取得できます。GETタイプをリクエストすると、すべてのレコードのリストが取得されます。 MessageパラメーターでPOSTが要求されると、Message要素が更新されます。 Messageパラメーターを使用してPUTタイプを要求する場合、データウェアハウスに新しいメッセージを追加します。 GET localhost :8080 / [ プロジェクト名 ] / rest / message / idなどのメソッドを使用してアドレスにアクセスする場合、idと等しい番号のメッセージを返します。 また、DELETEメソッドも呼び出すと、ID番号のメッセージが削除されます。



おわりに



小規模な顧客の例


このサービスをテストするために、小さなJavaクライアントを作成しました。 すべてのメソッドの呼び出しを示し、結果をコンソールに表示する通常のJavaアプリケーション。



こちらが彼のリストです



 public class RestClient { public static void main(String[] args) { ClientConfig config = new DefaultClientConfig(); Client client = Client.create(config); WebResource service = client.resource(getBaseURI()); /* * Get list of messages */ GenericType<List<Message>> genericType = new GenericType<List<Message>>() { }; List<Message> messages = service.path("rest").path("message") .accept(MediaType.APPLICATION_XML).get(genericType); for (Message temp : messages) { System.out.println(temp); } /* * Get message by ID */ long id = 4; Message message = service.path("rest").path("message") .path(String.valueOf(id)).accept(MediaType.APPLICATION_XML) .get(Message.class); System.out.println("Message with ID = " + id); System.out.println(message); /* * Update message */ message.setMessageTitle("udated title"); message.setMessageText("updated text"); service.path("rest").path("message").post(message); message = service.path("rest").path("message").path(String.valueOf(id)) .accept(MediaType.APPLICATION_XML).get(Message.class); System.out.println("Message with ID = " + id); System.out.println(message); /* * Delete message */ System.out.println("delete message with ID = " + id); service.path("rest").path("message").path(String.valueOf(id)).delete(); messages = service.path("rest").path("message") .accept(MediaType.APPLICATION_XML).get(genericType); for (Message temp : messages) { System.out.println(temp); } /* * Put message */ System.out.println("puttin' message"); message = new Message(); message.setMessageText("PUT MESSAGE!"); message.setMessageTitle("Put message"); service.path("rest").path("message") .accept(MediaType.APPLICATION_XHTML_XML).put(message); messages = service.path("rest").path("message") .accept(MediaType.APPLICATION_XML).get(genericType); for (Message temp : messages) { System.out.println(temp); } } private static URI getBaseURI() { return UriBuilder.fromUri("http://localhost:8080/WebRest").build(); } }
      
      







ここで最も興味深い行は



 GenericType<List<Message>> genericType = new GenericType<List<Message>>() {}; List<Message> messages = service.path("rest").path("message") .accept(MediaType.APPLICATION_XML).get(genericType);
      
      







genericTypeはおおよそList型であり、JAX-Bを使用してより複雑な構造を送受信するために必要です。 そして、JAXBElementとして渡すすべてのデータ。



このクライアントでは、Jerseyライブラリも含め、Messageクラスの説明ファイルを含める必要があります。



そして結論として



結論として、この記事が誰かを助けるなら、私はとても幸せになると言いたいです。 また、提案や批判を聞く準備ができています。 私はただ学んでいます。



クライアントコードとサービスコードは、私のgithub こちらから入手できます。



使用したデータは、 Vogellaの記事とインターネットです。



All Articles