1. 序章

Model View Controller(MVC)は、Webアプリケーションを構築するための一般的なデザインパターンです。 数年の間、それは最新のWebベースのアプリケーションを構築するための事実上の設計原則でした。

このチュートリアルでは、WebページとRESTAPIを備えたJakartaEEMVC2.0を使用したWebアプリケーションの構築について学習しましょう。

2. JSR-371

Jakarta MVC 2.0(以前のJSR 371 MVC 1.0)は、Jakarta RESTful WebサービスまたはJAX-RS(以前のRESTfulWebサービス用のJavaAPI)上に構築されたアクションベースのWebフレームワークです。JSR-371はJAX-を補完しますWebアプリケーションの構築をより便利にする追加のアノテーションを備えたRS。

JSR371またはJakartaMVCは、JavaでWebアプリケーションを開発する方法を標準化します。 また、主な目的は、既存の CDI(コンテキストと依存性注入) Bean Validation を活用し、JSPFaceletsを次のようにサポートすることです。ビューテクノロジー。

現在、Jakarta MVC 2.1仕様の作業が進行中であり、おそらくJakartaEE10リリースでリリースされる予定です。

3. JSR-371注釈

JSR-371は、JAX-RSアノテーションとは別に、さらにいくつかのアノテーションを定義します。 A llこれらのアノテーションはjakarta.mvc。*パッケージの一部です。

3.1. jakarta.mvc.Controller

@Controller アノテーションは、リソースをMVCコントローラーとしてマークします。 クラスに使用すると、クラス内のすべてのリソースメソッドがコントローラーになります。 同様に、リソースメソッドでこのアノテーションを使用すると、そのメソッドがコントローラーになります。 通常、メソッドで @Controller を定義すると、MVCコントローラーとRESTAPIを同じクラスで定義する場合に役立ちます。

たとえば、コントローラーを定義しましょう。

@Path("user")
public class UserController {
    @GET
    @Produces("text/html")
    @Controller
    public String showUserForm(){
        return "user.jsp";
    }
    @GET
    @Produces("application/json")    
    public String getUserDetails(){
        return getUserDetails();
    }
}

このクラスには、ユーザーフォームをレンダリングする @Controller showUserForm )とユーザー詳細JSONを返すREST API( getUserDetails )があります。

3.2. jakarta.mvc.View

@Controller と同様に、リソースクラスまたはリソースメソッドに@Viewアノテーションを付けることができます。 通常、 void を返すリソースメソッドには、@Viewが必要です。 @View のクラスは、voidタイプのクラスのコントローラーのデフォルトビューを表します。

たとえば、@Viewを使用してコントローラーを定義しましょう。

@Controller
@Path("user")
@View("defaultModal.jsp")
public class UserController {
    @GET
    @Path("void")
    @View("userForm.jsp")
    @Produces("text/html")
    public void showForm() {
        getInitFormData();
    }

    @GET
    @Path("string")
    @Produces("text/html")
    public void showModal() {
        getModalData();
    }
}

ここでは、リソースクラスとリソースメソッドの両方に@Viewアノテーションがあります。 コントローラー showForm ビューをレンダリングします userForm.jsp。 同様に、 showModal コントローラはレンダリングします defaultModal.jsp、 リソースクラスで定義されます。

3.3. jakarta.mvc.binding.MvcBinding

Jakarta RESTful Webサービスは、バインディングおよび検証エラーのあるリクエストを拒否します。 同様の設定は、Webページを操作するユーザーには適さない場合があります。 幸い、Jakarta MVCは、バインディングおよび検証エラーが発生した場合でもコントローラーを呼び出します。 通常、ユーザーはデータバインディングエラーについて十分な情報を持っている必要があります。

コントローラはBindingResultを挿入して、人間が読める形式の検証とバインディングのエラーメッセージをユーザーに表示します。 たとえば、@MvcBindingを使用してコントローラーを定義しましょう。

@Controller
@Path("user")
public class UserController {
    @MvcBinding
    @FormParam("age")
    @Min(18)
    private int age;
    @Inject
    private BindingResult bindingResult;
    @Inject
    private Models models;
    @POST
    public String processForm() {
        if (bindingResult.isFailed()) {
            models.put("errors", bindingResult.getAllMessages());
            return "user.jsp";
        }
    }
}

ここで、ユーザーが18未満の年齢を入力すると、ユーザーはバインディングエラーとともに同じページに戻されます。 user.jsp ページは、式言語(EL)を使用して、要求属性エラーを取得し、それらをページに表示できます。

3.4. jakarta.mvc.RedirectScoped

ユーザーがデータを入力して送信するフォーム(HTTP POST)について考えてみます。 サーバーはデータを処理し、ユーザーを成功ページ(HTTP GET)にリダイレクトします。 このパターンは、 PRG(Post-Redirect-Get)パターンとして広く知られています。 POSTとGETの間にデータを保持したいシナリオがいくつかあります。 これらのシナリオでは、モデル/Beanの範囲は単一の要求を超えています。

Beanに@RedirectScopedアノテーションが付けられている場合、Beanの状態は単一のリクエストを超えます。 それでも、POST、リダイレクト、およびGetが完了すると、状態は破棄されます。 @RedirectScoped で区切られたBeanは、POST、リダイレクト、およびGETの完了後に破棄されます。

たとえば、Beanユーザーにアノテーション@RedirectScopedがあるとします。

@RedirectScoped
public class User
{
    private String id;
    private String name;
    // getters and setters
}

次に、このBeanをコントローラーに注入します。

@Controller
@Path("user")
public class UserController {
    @Inject
    private User user;
    @POST
    public String post() {
        user.setName("John Doe");
        return "redirect:/submit";
    }
    @GET
    public String get() {
        return "success.jsp";
    }
}

ここで、Bean User は、POSTとそれに続くリダイレクトおよびGETに使用できます。 したがって、 success.jsp は、ELを使用してBeanのname属性にアクセスできます。

3.5. jakarta.mvc.UriRef

@UriRef アノテーションは、リソースメソッドにのみ使用できます。 @UriRef を使用すると、リソースメソッドに名前を付けることができます。 コントローラパスURIの代わりに、これらの名前を使用して、ビューでコントローラを呼び出すことができます。

hrefのユーザーフォームがあると仮定します。

<a href="/app/user">Clich Here</a>

ここをクリックをクリックすると、 GET / app /userにマップされたコントローラーが呼び出されます。

@GET
@UriRef("user-details")
public String getUserDetails(String userId) {
    userService.getUserDetails(userId);
} 

ここでは、コントローラーにuser-detailsという名前を付けました。 これで、URIの代わりにビューでこの名前を参照できます。

<a href="${mvc.uri('user-details')}">Click Here</a>

3.6. jakarta.mvc.security.CsrfProtected

このアノテーションは、リソースメソッドを呼び出すためにCSRF検証が必要であることを義務付けています。 CSRFトークンが無効な場合、クライアントは ForbiddenException (HTTP 403)例外を受け取ります。 リソースメソッドのみがこのアノテーションを持つことができます。

コントローラーについて考えてみましょう。

@POST
@Path("user")
@CsrfProtected
public String saveUser(User user) {
    service.saveUser(user);
}

コントローラに@CsrfProtectedアノテーションがある場合、リクエストは、有効なCSRFトークンが含まれている場合にのみコントローラに到達します。

4. MVCアプリケーションの構築

次に、RESTAPIとコントローラーを使用してWebアプリケーションを構築しましょう。 最後に、最新バージョンの EclipseGlassfishにWebアプリケーションをデプロイしましょう。

4.1. プロジェクトを生成する

まず、Maven archetype:generate を使用して、JakartaMVC2.0プロジェクトを生成しましょう。

mvn archetype:generate 
  -DarchetypeGroupId=org.eclipse.krazo
  -DarchetypeArtifactId=krazo-jakartaee9-archetype
  -DarchetypeVersion=2.0.0 -DgroupId=com.baeldung
  -DartifactId=krazo -DkrazoImpl=jersey

上記のアーキタイプは、次のような必要なアーティファクトを持つMavenプロジェクトを生成します。

また、生成された pom.xml には、 jakarta.platform、jakarta.mvc 、およびorg.eclipse.krazoの依存関係が含まれています。

<dependency>
    <groupId>jakarta.platform</groupId>
    <artifactId>jakarta.jakartaee-web-api</artifactId>
    <version>9.1.0</version>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>jakarta.mvc</groupId>
    <artifactId>jakarta.mvc-api</artifactId>
    <version>2.0.0</version>
</dependency>
<dependency>
    <groupId>org.eclipse.krazo</groupId>
    <artifactId>krazo-jersey</artifactId>
    <version>2.0.0</version>
</dependency>

4.2. コントローラー

次に、フォームを表示し、ユーザーの詳細を保存するためのコントローラーと、ユーザーの詳細を取得するためのAPIを定義しましょう。 ただし、最初に、アプリケーションパスを定義しましょう。

@ApplicationPath("/app")
public class UserApplication extends Application {
}

アプリケーションパスは/appとして定義されています。 次に、ユーザーをユーザー詳細フォームに転送するコントローラーを定義しましょう。

@Path("users")
public class UserController {
    @GET
    @Controller
    public String showForm() {
        return "user.jsp";
    }
}

次に、 WEB-INF / viewsの下で、ビュー user.jsp、を作成し、アプリケーションをビルドしてデプロイできます。

mvn clean install glassfish:deploy

このGlassfishMaven プラグインは、ポート8080でビルド、デプロイ、および実行されます。 展開が成功したら、ブラウザを開いて次のURLにアクセスできます。

http:// localhost:8080 / mvc-2.0 / app / users

次に、フォーム送信アクションを処理するHTTPPOSTを定義しましょう。

@POST
@Controller
public String saveUser(@Valid @BeanParam User user) {   
    return "redirect:users/success";
}

これで、ユーザーが作成ボタンをクリックすると、コントローラーがPOST要求を処理し、ユーザーを成功ページにリダイレクトします。

Jakarta Validations、CDI、および @MvcBinding を利用して、フォームの検証を提供しましょう。

@Named("user")
public class User implements Serializable {

    @MvcBinding
    @Null
    private String id;

    @MvcBinding
    @NotNull
    @Size(min = 1, message = "Name cannot be blank")
    @FormParam("name")
    private String name;
    // other validations with getters and setters 
}

フォームの検証が完了したら、バインディングエラーを確認しましょう。 バインディングエラーがある場合は、検証メッセージをユーザーに提示する必要があります。 このために、無効なフォームパラメータを処理するためにBindingResultを挿入しましょう。 saveUserメソッドを更新しましょう。

@Inject
private BindingResult bindingResult;

public String saveUser(@Valid @BeanParam User user) {
    if (bindingResult.isFailed()) {
        models.put("errors", bindingResult.getAllErrors());
        return "user.jsp";
    }  
    return "redirect:users/success";
}

検証が行われている状態で、ユーザーが必須パラメーターなしでフォームを送信すると、検証エラーが表示されます。

次に、 @CsrfProtected を使用して、POSTメソッドをCSRF攻撃から保護しましょう。 @CsrfProtectedをメソッドsaveUserに追加します。

@POST
@Controller
@CsrfProtected
public String saveUser(@Valid @BeanParam User user) {
}

次に、作成ボタンをクリックしてみましょう。

コントローラがCSRF攻撃から保護されている場合、クライアントは常にCSRFトークンを渡す必要があります。 それでは、 user.jsp に隠しフィールドを追加して、すべてのリクエストにCSRFトークンを追加しましょう。

<input type="hidden" name="${mvc.csrf.name}" value="${mvc.csrf.token}"/>

同様に、 RESTAPIを今すぐ開発しましょう。

@GET
@Produces(MediaType.APPLICATION_JSON)
public List<User> getUsers() {
    return users;
}

このHTTPGETAPIは、ユーザーのリストを返します。

5. 結論

この記事では、Jakarta MVC 2.0と、EclipseKrazoを使用してWebアプリケーションとRESTAPIを開発する方法について学びました。 MVC 2.0が、JavaでMVCベースのWebアプリケーションを構築する方法を標準化する方法を見てきました。

いつものように、完全なソースコードはGitHubから入手できます。