JavaでRESTful Webサービスを実装します

すべてのhabrozhitelに良い一日を!



この記事を書いた理由は、ハブで驚いたことに、JavaでのRESTful Webサービスの実装に関する記事を見つけられなかったためです。 はい、RESTful Webサービスについて多くのことが書かれていますが、このようなものです。そのため、コードの例だけでは、動作しているサービスを見つけるのはそれほど簡単ではなく、ハブ上だけではありません



一般的に、私は最近、1ヶ月以上前にRESTに出会いました。 だから私はアドバイス、訂正、批判にとても感謝しています!



一般的にそれを理解することは難しくありませんでしたが、同様の投稿が私を大いに助け、学習プロセスをスピードアップすると思います! さらに、あなたが初心者の開発者であり、多くのことしか聞いたことがないが、それらに手を触れたことがない場合。



私の第一印象では、実際、非常に便利であり、最も重要なことは、 XMLではなくJSONを使用する場合です。少なくとも、 SOAPWSDLの経験の後、私にはそう思われました。 ええ、はい、私はそれについて考えますので、誰でも少なくともWebサービスで少し働いた人は知っています。



だから、実装に興味がある人は、カットをお願いします



すぐに予約しましょう:



1.もちろん、すべてのコードを記事に入れることはできませんし、それについては説明しません。

2.もちろん、予測のバージョンは最終的なものではありません。上記で述べたように、コメントとアドバイスに非常に感謝します。

3.もちろん、バグがあります。



それで、順番に始めましょう:



1.使用したソフトウェア:





ソフトウェアは非常にシンプルな原則に従って選択されました-シンプルであるほど良いです。 はい、データベースに複雑なクエリを作成する必要のないロードされたサービスのMySQLの代わりに、 MongoDBを使用することは非常に良いことです 。少なくともこれについては多くのことが書かれています



2.原則として、私たちのサービスが行うこと-ここではすべてが非常に平凡です:サービスはデータベース内の1つのプレートで動作します-挿入、更新、削除、そしてもちろん、リストまたはIDでレコードを受信します。 もちろん、パラメータ化されたクエリを使用してレコードのリストを取得できるようにしたいと考えています。サービスへの「美しい」URLを作成したり、サービスにアクセスするユーザーの権限を確認したり、他の何かを行うなど、何らかのインターセプターをねじ込んでも悪くありませんサービスを開始する前に、サーバーからの応答のエラーコードを何らかの方法で一元管理します。



実際には、プレート:



CREATE TABLE `customer` ( `id` varchar(45) NOT NULL, `first_name` varchar(45) DEFAULT NULL, `last_name` varchar(45) DEFAULT NULL, `phone` varchar(45) DEFAULT NULL, `mail` varchar(45) DEFAULT NULL, `adress` varchar(45) DEFAULT NULL, `contract_id` varchar(45) DEFAULT NULL, `contract_expire_date` date DEFAULT NULL )
      
      







WSエンドポイント:



  1.http://mysite.com/service/customer 


  2. http://mysite.com/service/customer/{id} 




追加で処理する4つの標準ステータス(たとえば、応答としてWebサービスのバージョンを追加し、エラーが発生した場合-エラーコード):



200-成功;

401-許可されていません。

404-見つかりません。

500-操作中のサーバーエラー。



3.実装( ここに githubコード):



はい、コード、最小限のコメント、注釈の説明はこちら



Webサービス自体:

 public class CustomersServiceJSON implements ICustomersService { // link to our dao object private ICustomersDAO customersDAO; // for customersDAO bean property injection public ICustomersDAO getCustomersDAO() { return customersDAO; } public void setCustomersDAO(ICustomersDAO customersDAO) { this.customersDAO = customersDAO; } // for retrieving request headers from context // an injectable interface that provides access to HTTP header information. @Context private HttpHeaders requestHeaders; private String getHeaderVersion() { return requestHeaders.getRequestHeader("version").get(0); } // get by id service @GET @Path("/{id}") public Response getCustomer(@PathParam("id") String id) { Customer customer = customersDAO.getCustomer(id); if (customer != null) { return ResponseCreator.success(getHeaderVersion(), customer); } else { return ResponseCreator.error(404, Error.NOT_FOUND.getCode(), getHeaderVersion()); } } // remove row from the customers table according with passed id and returned // status message in body @DELETE @Path("/{id}") public Response removeCustomer(@PathParam("id") String id) { if (customersDAO.removeCustomer(id)) { return ResponseCreator.success(getHeaderVersion(), "removed"); } else { return ResponseCreator.success(getHeaderVersion(), "no such id"); } } // create row representing customer and returns created customer as // object->JSON structure @POST @Consumes(MediaType.APPLICATION_JSON) public Response createCustomer(Customer customer) { System.out.println("POST"); Customer creCustomer = customersDAO.createCustomer(customer); if (creCustomer != null) { return ResponseCreator.success(getHeaderVersion(), creCustomer); } else { return ResponseCreator.error(500, Error.SERVER_ERROR.getCode(), getHeaderVersion()); } } // update row and return previous version of row representing customer as // object->JSON structure @PUT @Consumes(MediaType.APPLICATION_JSON) public Response updateCustomer(Customer customer) { Customer updCustomer = customersDAO.updateCustomer(customer); if (updCustomer != null) { return ResponseCreator.success(getHeaderVersion(), updCustomer); } else { return ResponseCreator.error(500, Error.SERVER_ERROR.getCode(), getHeaderVersion()); } } // returns list of customers meeting query params @GET //@Produces(MediaType.APPLICATION_JSON) public Response getCustomers(@QueryParam("keyword") String keyword, @QueryParam("orderby") String orderBy, @QueryParam("order") String order, @QueryParam("pagenum") Integer pageNum, @QueryParam("pagesize") Integer pageSize) { CustomerListParameters parameters = new CustomerListParameters(); parameters.setKeyword(keyword); parameters.setPageNum(pageNum); parameters.setPageSize(pageSize); parameters.setOrderBy(orderBy); parameters.setOrder(Order.fromString(order)); List<Customer> listCust = customersDAO.getCustomersList(parameters); if (listCust != null) { GenericEntity<List<Customer>> entity = new GenericEntity<List<Customer>>( listCust) { }; return ResponseCreator.success(getHeaderVersion(), entity); } else { return ResponseCreator.error(404, Error.NOT_FOUND.getCode(), getHeaderVersion()); } } }
      
      







URIとこのURIをプルする方法に応じて4つのWebサービスがあり、beans.xmlに接続し、たとえばカスタムバージョンヘッダーを取得するためにリクエストヘッダーにアクセスするDAOオブジェクトがあります。



サービスが呼び出される前に満たされるもの:

 public class PreInvokeHandler implements RequestHandler { // just for test int count = 0; private boolean validate(String ss_id) { // just for test // needs to implement count++; System.out.println("SessionID: " + ss_id); if (count == 1) { return false; } else { return true; } } public Response handleRequest(Message message, ClassResourceInfo arg1) { Map<String, List<String>> headers = CastUtils.cast((Map<?, ?>) message .get(Message.PROTOCOL_HEADERS)); if (headers.get("ss_id") != null && validate(headers.get("ss_id").get(0))) { // let request to continue return null; } else { // authentication failed, request the authentication, add the realm return ResponseCreator.error(401, Error.NOT_AUTHORIZED.getCode(), headers.get("version").get(0)); } } }
      
      







ここで、validate()メソッドでは、いくつかの前提条件を確認できます。純粋にテストのために、リクエストセッション識別子「ss_id」のカスタムヘッダーの検証が追加されます。



一般的な例外ハンドラー:

 public class CustomExceptionMapper implements ExceptionMapper<Exception> { @Context private HttpHeaders requestHeaders; private String getHeaderVersion() { return requestHeaders.getRequestHeader("version").get(0); } public Response toResponse(Exception ex) { System.out.println(ex.getMessage() + ex.getCause()); return ResponseCreator.error(500, Error.SERVER_ERROR.getCode(), getHeaderVersion()); } }
      
      







投稿には既にかなり多くのコードがあります。サーバーへの応答を生成するための補助クラスと、エラーコードを格納するためのグローバル列挙がまだあります。 はい、デプロイメント記述子とbeans.xmlはここでも提供されます。



web.xml:

 ... <web-app> <display-name>service</display-name> <context-param> <param-name>contextConfigLocation</param-name> <param-value>WEB-INF/beans.xml</param-value> </context-param> <listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener> <servlet> <servlet-name>CXFServlet</servlet-name> <display-name>CXF Servlet</display-name> <servlet-class> org.apache.cxf.transport.servlet.CXFServlet </servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>CXFServlet</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> </web-app>
      
      







ここでの主な関心は、Apacheのアクションサーブレット-CXFServletと標準のスプリングContextLoaderListenerを接続することです。



beans.xml:

 ... <!-- Imported resources for cxf --> <import resource="classpath:META-INF/cxf/cxf.xml" /> <import resource="classpath:META-INF/cxf/cxf-extension-jaxrs-binding.xml" /> <import resource="classpath:META-INF/cxf/cxf-servlet.xml" /> <!-- Imported bean for dao --> <import resource="classpath:META-INF/spring/dao.xml"/> <bean id="customersService" class="com.test.services.customers.rest.CustomersServiceJSON"> <property name="customersDAO" ref="customersDAO"/> </bean> <bean id="preInvokeHandler" class="com.test.services.rest.PreInvokeHandler" /> <bean id="customExceptionMapper" class="com.test.services.rest.CustomExceptionMapper" /> <jaxrs:server id="restContainer" address="/customer"> <jaxrs:serviceBeans> <ref bean="customersService" /> </jaxrs:serviceBeans> <jaxrs:providers> <ref bean="preInvokeHandler" /> <ref bean="customExceptionMapper" /> </jaxrs:providers> </jaxrs:server> .........
      
      







実際、ここでは、CXFに必要な構成ファイルを設定し、DAOオブジェクト、プリプロセッサ、例外ハンドラ、もちろんサービスBeanを接続し、サービスのルートを設定します。



クローム用のRESTコンソール4.0.2プラグインを使用してサービスを調整するために-事は非常に簡単です、主なことは必要なエンドポイント、カスタムヘッダー(「ss_id」401なしでは常に言ったように)とコンテンツタイプを設定することです 例:



リクエスト本文:

 Request Url: http://localhost:8080/service/customer Request Method: GET Status Code: 200
      
      





リクエストヘッダー:

 Accept: application/json Content-Type: application/json ss_id: 12312.111 version: 12312.111 ........
      
      





応答ヘッダー:

 Status Code: 200 Date: Tue, 21 Aug 2012 13:09:45 GMT Content-Length: 877 Server: Apache-Coyote/1.1 Content-Type: application/json version: 12312.111
      
      





応答本文:

 { "customer": [{ "id": "89ad5a46-c9a2-493f-a583-d8250ee31766", "adress": "null", "contract_id": "null", "first_name": "serg", "last_name": "serg", "mail": "serg", "phone": "null" }, { "id": "300ff688-a783-4e6a-9048-8bb625128dc0", "first_name": "serg" }, { "id": "67731ab9-87b1-4ff9-a7e4-618c1f9e8c4c", "first_name": "serg" }, { "id": "cd5039bb-031f-4697-a70c-ad3e628963dd", "first_name": "serg" }, { "id": "86da5446-7439-4242-b730-31c8b57a5c7d", "first_name": "serg" }, ..........
      
      







そして最後に、「美しい」ものにしたかったのです。Webサービスに必要なURLを言った方がいいでしょう。 もちろん、server.xmlを修正するか、urlRewriteのツールを使用することもできますが、私の意見では、最も簡単な方法は、Webアーカイブを耳でパックし、application.xmlでWebサービスの別のルートを設定することですが、この投稿の一部としてもうしません



PS:この投稿がJava RESTful Webサービスに精通したい人に役立つことを願っています。経験豊富な人が助言し、批判することを願っています。




All Articles