SpringBoot プロジェクトの層#
SpringBoot フレームワークプロジェクトは一般的に五つの層に分かれています:
-
View 層:ユーザーにページを表示する
-
Controller 層:フロントエンドとバックエンドのインタラクション層で、フロントエンドのリクエストを受け取り、Service 層のメソッドを呼び出し、Service 層から返されたデータを受け取ってフロントエンドに返します。
-
Service 層:ビジネス処理のロジックやデータベース操作のインターフェースを格納します。
-
Mapper 層:DAO 層とも呼ばれ、データベースの CRUD インターフェースで、メソッド名のみがあり、具体的な実装は mapper.xml ファイルにあり、データベースにデータを永続化する操作を行います。
-
Entity 層:エンティティクラスを格納し、データベースの属性と基本的に一致します。
最も簡単な POST インターフェースの実装#
最も簡単な POST インターフェースは、Controller 層で RestController クラスを宣言し、その後クラス内で PostMapping アノテーションを使用して、これは POST インターフェースであることを示し、関連するメソッドを記入するだけです。以下のように:
@RestController
@RequestMapping("/api")
public class CreateNumberController {
@PostMapping("/number")
public String createNumber(@RequestParam String param1, @RequestParam int param2) {
// POSTリクエストを処理するコード
return "success";
}
}
プログラムを実行した後、Postman を使用してhttp://localhost:8000/api/number
に POST リクエストを送信し、対応するリクエストパラメータを入力すると、インターフェースの応答が得られます:
インターフェースをトランザクション処理ロジック関数に接続する#
実際のビジネスにおけるインターフェースは、上記の例のように単純な関数だけではありません。プログラム内部では受け取ったデータに対して一定のロジック処理が行われます。
次に、実際のビジネスシナリオを示します:
要求#
現在、一定のルールに従ってプロジェクトにプロジェクトコードを付与するためのインターフェースが必要です。プロジェクトリクエスト内容は xml メッセージです。例えば:
<?xml version="1.0" encoding="UTF-8"?> <name>Example Project</name> <operate>01</operate> <source>A</source> <status>01</status>
リクエストパラメータ operate が 1 の場合は新規プロジェクトコードを追加し、リクエストパラメータ source が A、B、C の場合、プロジェクトコードは Axxxx で、「xxxx」は「0〜9 の 10 個のアラビア数字」と「A〜Z の 26 個の大文字英字」からなる 4 桁の連番で、順序は:0/1/2/3/4/5/6/7/8/9/A/B/C/D~/X/Y/Z です。2 つの制約を追加します:
①第 5 位、第 4 位と第 3 位は 000 から値を取ります。第 2 位は B から値を取ります。つまり初期コードは:AB000 です。第 5 位から第 2 位までの各位の取値範囲は「0〜9 の 10 個のアラビア数字」と「A〜Z の 24 個の大文字英字(26 個の文字の中から I と O を除外)」の 34 文字で、順序は 0/1/2/3/4/5/6/7/8/9/A/B/C/D~/X/Y/Z です。この時「xxxx」は 34 進数の 4 桁の数です。第 5 位が 0 から Z まで循環した後、第 4 位に 1 を進め、第 4 位が循環した後、第 3 位に 1 を進め、第 3 位が循環した後、第 2 位に 1 を進めます。
②第 2 位は I と O を除いて、A、C、Z も取れず、循環取値は B から始まり A で終わります。順に B/D…G/H/J/K…M/N/P…X/Y/0/1…9 の合計 31 文字です。
要求される戻り値は xml メッセージで、形式は:
<?xml version="1.0" encoding="UTF-8"?> <number>AB000</number> <status>01</status>
まだ重複コードの検証方法が規定されていないため(これはデータベースクエリを使用する必要があり、次の部分で続けて補足します)、要求を単純に理解すると、xml メッセージを受け取り、ルールに従ってコードを生成し、コードを返すということです。
この時、インターフェースの入力と出力は xml メッセージであり、単純な Controller だけでは要求を満たすことができず、入力メッセージを処理して対応するパラメータに分割し、Service を利用して入力データを処理し、関数を使用して要求に合った出力を生成し、最終的に xml メッセージとして返す必要があります。
POST インターフェースが XML メッセージを受け取る#
通常、インターフェース設計を行う際には、問題をトップダウンで考えることが一般的です。つまり、「インターフェースはリクエストボディを受け取り解析できる→Service を呼び出してリクエストボディ内のデータを使用してビジネスロジックを実行する→得られた結果を封装して応答を完成させる」という流れです。しかし、実際の開発手順は次の通りです:要求に基づいてリクエストボディとレスポンスボディに含まれる属性とこれらの属性のデータ型を明確にし、リクエストクラスとレスポンスクラスを構築→新しい Service クラスを追加してリクエストクラスの処理ロジックとレスポンスクラスの生成ロジックを記述→新しい Controller クラスを追加して POST インターフェースが XML メッセージを受け取り、Service 処理後に XML メッセージを返すことができるようにします。
関連依存関係のインポート#
xml メッセージを処理するには、Gradle で jackson-dataformat-xml 依存関係をインポートする必要があります。プロジェクトの移植性と再利用性を確保するために、Lombok の導入を放棄します。
Maven リポジトリ(例えばhttps://mvnrepository.com/)で jackson-dataformat-xml 依存関係を検索し、Gradle を選択して、以下の行を build.gradle の dependencies 部分にコピーします:
implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.15.2'
Jackson ライブラリは自動的に XML 要素を同名の Java プロパティにマッピングします。
Request クラスと Response クラスの作成#
リクエストメッセージに基づいて、Controller フォルダに ProjectNumberRequest クラスと ProjectNumberResponse クラスを新たに追加します。それぞれ以下のようになります:
ProjectNumberRequest.java
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
public class ProjectNumberRequest {
private String name;
private String operate;
private String source;
private String status;
//getメソッド
public String getName() {
return this.name;
}
public String getOperate() {
return this.operate;
}
public String getSource() {
return this.source;
}
public String getStatus() {
return this.status;
}
//setメソッド
public void setName(String projectName) {
this.name = projectName;
}
public void setOperate(String projectOperate) {
this.operate = projectOperate;
}
public void setSource(String projectSource) {
this.source = projectSource;
}
public void setStatus(String projectStatus) {
this.status = projectStatus;
}
}
ProjectNumberResponse.java
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
@JacksonXmlRootElement(localName = "response")
public class ProjectNumberResponse {
private String number;
private String status;
//getメソッド
public String getNumber() {
return this.number;
}
public String getStatus() {
return this.status;
}
//setメソッド
public void setNumber(String number) {
this.number = number;
}
public void setStatus(String projectStatus) {
this.status = projectStatus;
}
}
注意:@JacksonXmlRootElement(localName = "response")
のようなアノテーションは、XML のルートノードの名前を response に変更します。アノテーションを追加しない場合、XML ファイルのルートノード名はデフォルトでクラス名が使用されます。
ビジネスロジックの記述#
Service フォルダに CreateNumberService クラスを新たに追加し、リクエストメッセージのリクエストボディを処理し、一定のルールに従ってプロジェクトコードとプロジェクトステータスの 2 つの属性を生成し、それを XML ファイルに変換して応答メッセージの応答ボディを構成します。
CreateNumberService は 2 つの部分から成り立っています。第一部分は response オブジェクト生成関数で、応答ボディオブジェクトを作成するために使用されます。第二部分は XML オブジェクト生成関数で、response オブジェクトを XML オブジェクトに封装するために使用されます。
CreateNumberService.java
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import org.springframework.stereotype.Service;
import studio.tsukistar.demo.Controller.ProjectNumberRequest;
import studio.tsukistar.demo.Controller.ProjectNumberResponse;
import java.util.Objects;
@Service
public class CreateNumberService {
private static final String XML_HEAD = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n";
public String createService(ProjectNumberRequest request) { //responseオブジェクトを構築
ProjectNumberResponse response = new ProjectNumberResponse();
response.setNumber( "AB000" );
response.setStatus(request.getStatus());
return javaBeanToXml (response);
}
public static String javaBeanToXml(Object obj) { //Objectをxml形式に変換
String xml= "";
if (Objects.isNull(obj)) {
return xml;
}
try {
XmlMapper xmlMapper = new XmlMapper();
xml = xmlMapper.writeValueAsString(obj);
} catch (Exception e) {
return "";
}
return XML_HEAD + xml;
}
}
コントローラーの記述#
Controller フォルダに CreateNumberController クラスを新たに追加し、リクエストボディの受け入れタイプを XML 形式に設定し、CreateNumberService によって処理されたリクエストボディから得られた応答メッセージを返します。
CreateNumberController.java
import jakarta.annotation.Resource;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import studio.tsukistar.demo.Service.CreateNumberService;
@RestController
@RequestMapping("/api")
public class CreateNumberController {
@Resource
private CreateNumberService numberService;
@PostMapping(value="/number", produces = MediaType.APPLICATION_XML_VALUE)
public String createNumber(@RequestBody ProjectNumberRequest request) { // POSTリクエストを処理するコード
return numberService.createService(request);
}
}
テストの実行#
プログラムを実行した後、Postman を使用してhttp://localhost:8000/api/number
に POST リクエストを送信し、「Body」で「raw-XML」を選択し、リクエストボディを入力します:
<?xml version="1.0" encoding="UTF-8" ?>
<request>
<name>テスト</name>
<operate>01</operate>
<source>A</source>
<status>01</status>
</request>
「Send」をクリックすると、インターフェースの応答メッセージが得られます。以下の図のように:
まとめ#
前回と比べて、この期間に POST インターフェースの開発方法、プロジェクトの層、各層間のインタラクションなどの内容を新たに学び、SpringBoot フレームワークについてもより深く理解しました(もしかしたら?道を誤らないことを願っています)。コードも一緒に github リポジトリにアップロードしました。大きな一歩を踏み出しました。
この記事の多くの開発知識は Bing AI から得たものであり、誤りがあれば皆さんからのご指導を賜りますと幸いです!