
情報技術の開発は、インターネットインフラストラクチャの使用にますます関与しています。 分散およびモバイルアプリケーションは、HTTPを介した情報交換をますます使用しています。 同時に、クライアント/サーバーアーキテクチャは、開発、作成、および運用において最も広く普及しているシンプルなままです。 クライアントサーバーアーキテクチャの原則は単純です。サーバーはリソースを提供し、クライアントはこのリソースを使用します。
この記事は、単純なWebサービスの作成を理解しようとする試みです。 単純で、実用的で、十分に説明された例は、技術の研究において、文献を読むよりも多くの利益をもたらすことがよくあります。 この記事では、Eclipseと組み込みのJettyサーバーを使用して、REST、JSONに基づく単純な計算機Webサービスの作成について説明します。
挑戦する
2つの数値を使用した単純な算術演算を実装するWebサービスとしての計算機の作成を検討してください。 Webサービスは、入力パラメーターを受け入れて結果を生成するリモート関数と同じ方法で考えることができます。 したがって、その機能は次のように説明できます。
入力パラメーター:
- aは最初の引数です。
- bは2番目の引数です。
- opは、+、-、/、*のいずれかの記号で表される算術演算子です。
出力パラメーター:
- エラーが最初の引数です。
- 結果は2番目の引数です。
リクエスト/レスポンスの例-金額
リクエスト: http:// localhost:8080 / func?A = 8.78&b = 4.15&op = +
答えは:
{ “error”:0, “result”:12.93 }
リクエスト/レスポンスの例-違い
リクエスト: http:// localhost:8080 / func?A = 8.78&b = 4.15&op =-
答えは:
{ “error”:0, “result”:4.63 }
リクエスト/レスポンスの例-製品
リクエスト: http:// localhost:8080 / func?A = 8.78&b = 4.15&op = *
答えは:
{ “error”:0, “result”:36.437 }
リクエスト/レスポンスの例-プライベート
リクエスト: http:// localhost:8080 / func?A = 8.78&b = 4.15&op = /
答えは:
{ “error”:0, “result”:2.1156626506 }
要求/応答の例-0除算エラー
リクエスト: http:// localhost:8080 / func?A = 8.78&b = 0&op = /
答えは:
{ “error”:1 }
リクエスト/レスポンスの例-エラー「無効な数値形式」
リクエスト: http:// localhost:8080 / func?A = 8.78&b = 4.15m&op = /
答えは:
{ “error”:1 }
Jettyライブラリのインストール
Jettyは、Webアプリケーションの作成に非常に便利です。 これを組み込みサーバーとして使用すると、開発者は、起動するたびに外部サーバーにWebアプリケーションをデプロイする必要がなくなります。 また、これには外部アプリケーションサーバーのインストールは必要ありません。
ほとんどの場合、サーバーライブラリをダウンロードし、ユーザーライブラリとしてEclipseに登録してから、このライブラリへのリンクを使用するだけで十分です。 このアプローチは、MavenやGradleなどのアセンブリ自動化ツールの可用性を必要としないため、初心者のJavaプログラマーにとっては簡単です。
次のように、必要なJettyライブラリをEclipseにインストールします。
1.圧縮ファイルをhttp://download.eclipse.org/jetty/からダウンロードして解凍します。
2.プロジェクトのルートフォルダー(通常はワークスペース)で、jarsフォルダーとその中のjettyフォルダーを作成します。
3. libフォルダーの内容を以前に解凍したファイルから作成されたjettyフォルダーにコピーします。
4. ウィンドウ/設定メニューで、 Java /ビルドパス/ユーザーライブラリセクションを選択します 。

5. [ 新規... ]ボタンをクリックし、 桟橋ライブラリ名を入力して[OK]ボタンをクリックします。

6.次に、 Preferencesウィンドウで新しく作成されたjettyライブラリを選択した状態で、 Add External JARs ...ボタンをクリックします。 「 JAR選択」ウィンドウで、以前に作成したjars / jettyフォルダーからすべてのJARファイルを選択します。

7.その結果、JARファイルはjettyユーザーライブラリにアップロードされます。 サブフォルダー内のファイルはダウンロードされませんが、ほとんどの場合、それらは必要ありません。

Webサーバープロジェクトの作成
[ファイル ] / [新規 ]メニューで、[ 動的Webプロジェクト ]を選択します。 [ プロジェクト名]フィールドに、 SCalculator と入力します。 [ 完了 ]ボタンをクリックします。


桟橋ライブラリへのリンクを追加する
作成直後のプロジェクトには、桟橋ライブラリへのリンクが含まれていません。 接続されたライブラリは、 プロジェクトエクスプローラの [ ライブラリ ]サブタブの[ Javaリソース ]タブで表示できます。

プロジェクトラベルを右クリックして、コンテキストメニューで[ ビルドパス ]を選択し、[ ビルドパスの 構成... ]を選択します。 [ ライブラリ ]ページの[ Javaビルドパス ]タブで、[ ライブラリを 追加... ]ボタンをクリックします。

[ ユーザーライブラリ ]を選択し、[ 次へ ]をクリックします。 jettyを選択し、[ 完了 ]をクリックします。


その結果、ユーザーjettyライブラリが含まれていることを確認した後、 Project Explorerでライブラリへのリンクを確認できます。

計算機サーブレットの作成
サーブレットファイルの作成
計算機サーブレットには、入力データのデコード、応答の計算および生成のためのすべてのコードが含まれます。 サーブレットを作成するには、 プロジェクトエクスプローラーパネルでプロジェクト名を右クリックし、コンテキストメニューで[ 新規 ]、[ サーブレット ]の順に選択します。 クラス名に「SrvltCalculator」と入力し、[ 完了 ]ボタンをクリックします。

Project Explorerパネルで 、作成されたSrvltCalculator.javaファイルを確認できます。 その内容はエディターで自動的に開かれます。
冗長コードの削除
さらにファイルを編集しやすくするには、未使用のSrvltCalculatorサーブレットコンストラクターとdoPostメソッドを削除します。
インポートされたモジュールの追加
サーブレットファイルに追加されるコードには、モジュールを含めるために次のコード行が必要です。 これらの行を追加します。
import java.io.IOException; import java.io.UnsupportedEncodingException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;
doGetメソッドにコードを追加する
doGetメソッドには、GET要求を処理するためのコードが含まれています。 このメソッドでは、次のコードスニペットを順番に追加します。
対応する文字列変数のパラメーターの受信。
String str_a = request.getParameter("a"); String str_b = request.getParameter("b"); String str_op = request.getParameter("op");
文字列変数からデコードされた数値パラメーターaおよびbを受け入れる変数の宣言。
double value_a = 0; double value_b = 0;
エラーnoErrorの発生を制御する変数の宣言。
boolean noError = true;
対応する文字列変数から数値パラメーターaおよびbをデコードしようとしました。 デコードが失敗した場合、変数noErrorはfalseです。
try { value_a = Double.parseDouble(str_a); value_b = Double.parseDouble(str_b); } catch ( Exception ex ) { noError = false; }
数値パラメーターのデコード中にエラーが発生しなかった場合のケースのコードセクションを開きます。
if ( noError ) {
数値変数の結果を宣言して結果を保存します。
double result = 0;
tryセクションを開いて、計算およびエラー制御コードを有効にします。 算術演算により浮動小数点エラーが発生する可能性があるため、セクションが必要です。
try {
加算演算の場合、functionSum関数を呼び出します。これについては後で説明します。
if (str_op.equals("+")) result = functionSum( value_a, value_b ); else
減算演算の場合、functionDif関数を呼び出します。これについては後で説明します。
if (str_op.equals("-")) result = functionDif( value_a, value_b ); else
乗算演算の場合、functionMul関数を呼び出します。これについては後で説明します。
if (str_op.equals("*")) result = functionMul( value_a, value_b ); else
除算演算の場合、functionDiv関数を呼び出します。これについては後で説明します。 最新のプラットフォームではdouble型ではdouble divisionエラーが発生しないため、除数がゼロになる状況を手動で制御します。
if (str_op.equals("/") && (value_b!=0)) result = functionDiv( value_a, value_b ); else
4つの操作すべてをチェックした後、エラーなしのチェックボックスをfalseに設定します。 これは、算術演算が識別されないことを識別するために行われます。
noError = false;
例外が発生した場合、「エラーなし」フラグを「false」に設定してtryブロックを閉じます。
} catch ( Exception ex ) { noError = false; }
エラーが発生していない場合は、doSetResultメソッドを使用して結果を送信します。これについては、以下で説明します。 doGetメソッドはこのタスクを完了するため、returnステートメントを使用して戻ります。
if ( noError ) { doSetResult( response, result ); return; }
ステートメント「if(noError){」で始まるセクションを閉じます。
}
リクエストの処理中にエラーが発生し、doGet関数が計算に成功しても制御を返さないため、doSetErrorメソッドを使用してエラーメッセージを返します。これについては以下で説明します。
doSetError( response );
クロスドメインリクエスト
クロスドメインリクエスト(クロスドメインリクエストとも呼ばれます)は、リクエストがサービングサーバーのネットワークドメイン外にあるWebページから送信されたときに発生します。 このような要求に対する応答は、通常、クロスドメイン攻撃に対抗するためにブロックされます。 サーバー応答のブロックを無効にするには、ヘッダーAccess-Control-Allow-Origin:*を設定できます。
DoSetResultメソッド
doSetResultメソッドは、応答とHTTP応答に必要な設定をフォーマットします。 メソッド文字列の意味は次のとおりです。
- 最初の行は、JSON応答を生成します。 応答構造は単純なので、特殊なJSONライブラリは使用されません。
- 2行目では、JSON応答はUTF-8エンコードを使用して、HTTP応答の本文にバイナリ形式でエンコードされます。
- 3行目は、HTTP応答本文のコンテンツタイプを示しています。
- 4行目は、クロスドメインリクエストの許可を設定します。
- 5行目は、OK HTTP応答フラグを設定します。
protected void doSetResult( HttpServletResponse response, double result ) throws UnsupportedEncodingException, IOException { String reply = "{\"error\":0,\"result\":" + Double.toString(result) + "}"; response.getOutputStream().write( reply.getBytes("UTF-8") ); response.setContentType("application/json; charset=UTF-8"); response.setHeader("Access-Control-Allow-Origin", "*"); response.setStatus( HttpServletResponse.SC_OK ); }
DoSetErrorメソッド
doSetErrorメソッドは、エラーメッセージの応答とHTTP応答に必要な設定をフォーマットします。 メソッド文字列の意味は次のとおりです。
- 最初の行は、JSON応答を生成します。 応答構造は単純なので、特殊なJSONライブラリは使用されません。
- 2行目では、JSON応答はUTF-8エンコードを使用して、HTTP応答の本文にバイナリ形式でエンコードされます。
- 3行目は、HTTP応答本文のコンテンツタイプを示しています。
- 4行目は、クロスドメインリクエストの許可を設定します。
- 5行目は、OK HTTP応答フラグを設定します。 メッセージには、算術計算に関連するエラーが含まれていることに注意してください。 このエラーはHTTPプロトコルに関連していないため、ステータスフラグはOKに設定されます。
protected void doSetError( HttpServletResponse response ) throws UnsupportedEncodingException, IOException { String reply = "{\"error\":1}"; response.getOutputStream().write( reply.getBytes("UTF-8") ); response.setContentType("application/json; charset=UTF-8"); response.setHeader("Access-Control-Allow-Origin", "*"); response.setStatus( HttpServletResponse.SC_OK ); }
算術演算を実装する方法
この単純な例のアーキテクチャは、コードを機能部分に分割することに基づいています。 これを考慮して、算術演算は個別の関数として実装され、doGetメソッドの本体には含まれません。 関数は単純なので、コードについてはコメントしません。
protected double functionSum( double a, double b ) { return a + b; } protected double functionDif( double a, double b ) { return a - b; } protected double functionMul( double a, double b ) { return a * b; } protected double functionDiv( double a, double b ) { return a / b; }
プログラムのソースコードはGitHubリポジトリにあります 。
コアクラスの作成
アプリケーションのメインクラスには、メイン関数(プログラムが開始するいわゆるエントリポイント)が含まれます。 メイン関数は、組み込みJettyサーバーの初期化、構成、および起動を可能にします。
アプリケーションのメインクラスを作成するには、 プロジェクトエクスプローラーパネルでプロジェクト名を右クリックし、コンテキストメニューで[ 新規 ]を選択してから[ クラス ]を選択します。 クラス名に「Main」と入力します。 ボックスをチェックして静的関数mainを作成し、[ 完了 ]ボタンをクリックします。

サーブレットの場合と同様に、対応するファイルが作成され、テキストエディターで開かれます。
インポートされたモジュールの追加
アプリケーションのメインクラスのファイルに追加されるコードでは、モジュールを含めるために次のコード行を追加する必要があります。 これらの行を紹介します。
import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.HandlerList; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder;
mainメソッドにコードを追加する
メインメソッドのコードは、ポート変数を宣言し、サーバーがリッスンするポート番号を割り当てることから始まります。 このアプローチにより、プログラムがさらに成長した場合に必要に応じてポートを迅速かつ簡単に変更できます。
int port = 8080;
サーバークラスを作成します。
Server server = new Server(port);
上記で作成したサーブレットにクエリ文字列パスをバインドするパラメーターを指定します。
ServletContextHandler context = new ServletContextHandler( ServletContextHandler.SESSIONS ); context.setContextPath( "/" ); // http://localhost:8080/func context.addServlet(new ServletHolder( new SrvltCalculator( ) ),"/func");
サーバーへの要求ハンドラーを指定します。
HandlerList handlers = new HandlerList( ); handlers.setHandlers( new Handler[] { context } ); server.setHandler( handlers );
サーバーを起動しようとしています。 プログラムが機能し続けるために、server.join()を呼び出して、サーバープロセスがメインスレッドで完了するのを待っています。 エラーが発生すると、対応するメッセージが出力されます。
try { server.start(); System.out.println("Listening port : " + port ); server.join(); } catch (Exception e) { System.out.println("Error."); e.printStackTrace(); }
プログラムのソースコードはGitHubリポジトリにあります 。
ブラウザーからサービスへのアクセス
サーバー起動
サーバーの起動時に、Eclipseは2つのオプションを提供する場合があります。 サーバーには完全なサーブレットが含まれているため、プログラムは、TomcatやスタンドアロンJettyなどのアプリケーションサーバーで実行できます。 ただし、Jettyをアプリケーションに組み込んだため、Javaアプリケーションのように単独で機能します。

起動後、アプリケーションは適切な通知とリスニングポートを発行します。ポート行は、サーバーが実行中で要求を待機していることを示しています。

ブラウザ経由でリクエストを送信する
サーバーの機能を確認する最も簡単な方法は、ブラウザからアクセスすることです。
http:// localhost:8080 / func?A = 8.78&b = 4.15&op = +などのクエリ文字列を直接送信すると、サーバーはエラーをスローします。 実際には、文字列はクエリ標準に準拠していないため、URLとしてエンコードする必要があります(+文字は無効です)。

コーディング後、すべてがエラーなく動作します。 +文字は、%2BとしてエンコードされたURLであるため、要求は標準に準拠します。 インターネットには、この目的に使用できる多くのオンラインURLエンコーダー/デエンコーダーがあります。
標準化されたリクエスト: http:// localhost:8080 / func?A = 8.78&b = 4.15&op =%2B

同様に、他のリクエストに対するサーバーの応答を確認できます。
サーバークライアント
ブラウザを使用してリクエストを直接送信することは実用的ではありません。クエリ文字列を手動で生成するときに間違いが発生する可能性が非常に高いからです。 このようなリソースの使用は、次の方法で整理できます。
- JavaSciptを介した自動クエリ文字列生成と応答フォーマットを備えた専用Webページ。
- モバイルアプリケーション;
- 内部ニーズのために作成されたリソースを消費する別のサーバー。
クライアント-Webページ
専用Webページは、単純なタイプのクライアントアプリケーションです。

ページのHTMLコードはGitHubリポジトリにあります 。
ランチャーモジュールの作成
作成されたサーバーは、単一の独立した実行可能JARファイルとして発行できます。 このようなファイルは、インストールされたJavaランタイムのみを必要とし、ファイルシステム内の任意のフォルダーから実行されます。 このようなファイルを作成するには、 プロジェクトエクスプローラーパネルでプロジェクト名を右クリックし、コンテキストメニューでエクスポートを選択してからエクスポート...を選択します。 「 Java」セクションで、「 Runnable JAR file」を選択して、 「Next」ボタンをクリックします。

作成されたJARファイルの設定で、 起動構成をMain-SCalculatorとして指定し、エクスポートされたファイルのフルネームと、このファイルに必要なモジュールをパックするためのチェックボックスを指定します。

SCalculatorという名前で正しく作成されたJARファイルは、単純なコマンドで起動されます(同じフォルダーから起動された場合)。
java -jar SCalculator.jar

JARファイルをダブルクリックしてサーバーを起動することもできます。
まとめ
このリリースで説明した要素の多くは、高負荷のサーバーを作成するために実際に使用されました。 間違いなく、NGINXサーバーをリバースプロキシモードで使用するなど、より高度な手法を使用して、高速性と信頼性を実現しました。 しかし、それはすべてシンプルなものから始まり、実際の開発に役立つテクニックを簡単かつ明確に説明できることを願っています。
参照資料
Jettyの埋め込みの詳細については、 http://docs.codehaus.org/display/JETTY/Embedding+Jettyのアプリケーションをご覧ください。
Tomcatの例を使用したユーザーライブラリの接続については、 http://www.avajava.com/tutorials/lessons/what-is-a-user-library-and-how-do-i-use-it.html?page = 1で説明されています。
GitHubリポジトリは次の場所にあります: https : //github.com/dgakh/Studies/tree/master/Java/SWS-Embedded-Jetty
提示された資料は、Java EE DevelopersおよびUbuntu 14.04でのEclipse Lunaの使用に基づいています。