Spring BootとJSFを使ったコントローラ、サービス、DAOの例

Spring BootとJSFを使用したコントローラー、サービス、DAOの例

1. 前書き

JavaServer Facesは、サーバー側のコンポーネントベースのユーザーインターフェイスフレームワークです。 もともとは、Java EEの一部として開発されました。 このチュートリアルでは、we’ll investigate how to integrate JSF into a Spring Boot application.

例として、TO-DOリストを作成するための簡単なアプリケーションを実装します。

2. Mavenの依存関係

JSFテクノロジーを使用するには、pom.xmlを拡張する必要があります。


    org.apache.tomcat.embed
    tomcat-embed-jasper



    org.glassfish
    javax.faces
    2.3.7

javax.facesアーティファクトには、JSFAPIと実装も含まれています。 詳細情報はhereにあります。

3. JSFサーブレットの構成

JSFフレームワークは、XHTMLファイルを使用して、ユーザーインターフェイスのコンテンツと構造を記述します。 サーバー側は、XHTML記述からJSFファイルを生成します。

src/main/webappディレクトリのindex.xhtmlファイルに静的構造を作成することから始めましょう。


    
        
        
        TO-DO application
    
    
        

Welcome in the TO-DO application!

This is a static message rendered from xhtml.

コンテンツは<your-url>/index.jsfで利用可能になります。 ただし、この段階でコンテンツにアクセスしようとすると、クライアント側でエラーメッセージが表示されます。

There was an unexpected error (type=Not Found, status=404).
No message available

バックエンドエラーメッセージはありません。 それでも、リクエストをハンドラーと一致させるためのwe need a JSF servlet to handle the requestとサーブレットマッピングを把握できます。

Spring Bootにいるので、必要な構成を処理するためにアプリケーションクラスを簡単に拡張できます。

@SpringBootApplication
public class JsfApplication extends SpringBootServletInitializer {

    public static void main(String[] args) {
        SpringApplication.run(JsfApplication.class, args);
    }

    @Bean
    public ServletRegistrationBean servletRegistrationBean() {
        FacesServlet servlet = new FacesServlet();
        ServletRegistrationBean servletRegistrationBean =
          new ServletRegistrationBean(servlet, "*.jsf");
        return servletRegistrationBean;
    }
}

これは素晴らしく、かなり合理的ですが、残念ながらまだ十分ではありません。 <your-url>/index.jsfを開こうとすると、別のエラーが発生します。

java.lang.IllegalStateException: Could not find backup for factory javax.faces.context.FacesContextFactory.

Unfortunately, we need a web.xml beside the Java configuration.src/webapp/WEB-INFで作成しましょう:


    Faces Servlet
    javax.faces.webapp.FacesServlet
    1


    Faces Servlet
    *.jsf

これで、構成の準備が整いました。 <your-url>/index.jsfを開きます:

Welcome in the TO-DO application!

This is a static message rendered from xhtml.

ユーザーインターフェイスを作成する前に、アプリケーションのバックエンドを作成しましょう。

4. DAOパターンの実装

DAOは、データアクセスオブジェクトの略です。 通常、DAOクラスは2つの概念を担当します。 永続層の詳細をカプセル化し、単一のエンティティにCRUDインターフェイスを提供します。 詳細な説明は、thisのチュートリアルにあります。

DAOパターンを実装するには、we’ll first define a generic interface

public interface Dao {

    Optional get(int id);
    Collection getAll();
    int save(T t);
    void update(T t);
    void delete(T t);
}

それでは、このToDoアプリケーションで最初で唯一のドメインクラスを作成しましょう。

public class Todo {

    private int id;
    private String message;
    private int priority;

    // standard getters and setters

}

次のクラスはDao<Todo>の実装です。 このインターフェイスの新しい実装をいつでも提供できるこのパターンの美しさ。

その結果、残りのコードに触れることなく永続レイヤーを変更できます。

この例では、we’ll use an in-memory storage class

@Component
public class TodoDao implements Dao {

    private List todoList = new ArrayList<>();

    @Override
    public Optional get(int id) {
        return Optional.ofNullable(todoList.get(id));
    }

    @Override
    public Collection getAll() {
        return todoList.stream()
          .filter(Objects::nonNull)
          .collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
    }

    @Override
    public int save(Todo todo) {
        todoList.add(todo);
        int index = todoList.size() - 1;
        todo.setId(index);
        return index;
    }

    @Override
    public void update(Todo todo) {
        todoList.set(todo.getId(), todo);
    }

    @Override
    public void delete(Todo todo) {
        todoList.set(todo.getId(), null);
    }
}

5. サービス層

DAOレイヤーの主な目標は、永続化メカニズムの詳細を処理することです。 一方、サービス層はその上にあり、ビジネス要件を処理します。

DAOインターフェースはサービスから参照されることに注意してください。

@Scope(value = "session")
@Component(value = "todoService")
public class TodoService {

    @Autowired
    private Dao todoDao;
    private Todo todo = new Todo();

    public void save() {
        todoDao.save(todo);
        todo = new Todo();
    }

    public Collection getAllTodo() {
        return todoDao.getAll();
    }

    public int saveTodo(Todo todo) {
        validate(todo);
        return todoDao.save(todo);
    }

    private void validate(Todo todo) {
        // Details omitted
    }

    public Todo getTodo() {
        return todo;
    }
}

ここでは、サービスは名前付きコンポーネントです。 この名前を使用して、JSFコンテキストからBeanを参照します。

また、このクラスには、この単純なアプリケーションを満たすセッションスコープがあります。

Springスコープの詳細については、thisのチュートリアルをご覧ください。 Since Spring’s built-in scopes have a different model than JSF, it’s worth considering defining a custom scope.

これに関する詳細なガイダンスは、thisのチュートリアルにあります。

6. コントローラー

JSPアプリケーションの場合と同様に、コントローラーは異なるビュー間のナビゲーションを処理します。

次に、最小限のコントローラーを実装します。 開始ページからTo Doリストページに移動します。

@Scope(value = "session")
@Component(value = "jsfController")
public class JsfController {

    public String loadTodoPage() {
        checkPermission();
        return "/todo.xhtml";
    }

    private void checkPermission() {
        // Details omitted
    }
}

The navigation is based on the returned name.したがって、loadTodoPageは、次に実装するtodo.xhtmlページに移動します。

7. JSFとSpringBeansの接続

JSFコンテキストからコンポーネントを参照する方法を見てみましょう。 まず、index.xthmlを拡張します。


    
       // same code as before
    
    
        
// same code as before

ここでは、フォーム要素内にcommandButtonを導入しました。 This is important since every UICommand element (e.g. commandButton)has to be placed inside of a UIForm element (e.g. form).

この段階で、アプリケーションを起動して<your-url>/index.jsfを調べることができます。

image

残念ながら、ボタンをクリックするとエラーが発生します。

There was an unexpected error (type=Internal Server Error, status=500).
javax.el.PropertyNotFoundException:
/index.xhtml @11,104 action="#{jsfController.loadTodoPage}":
Target Unreachable, identifier [jsfController] resolved to null

メッセージには、問題が明確に示されています。jsfControllernull.に解決されました。対応するコンポーネントが作成されていないか、少なくともJSFコンテキストからは見えません。

この状況では、後者が当てはまります。

Springコンテキストをwebapp/WEB-INF/faces-config.xml内のJSFコンテキストに接続する必要があります。



    
        org.springframework.web.jsf.el.SpringBeanFacesELResolver
    

コントローラが機能する準備ができたので、todo.xhtmlが必要になります。

8. JSFのサービスとのやり取り

todo.xhtmlページには2つの目的があります。 まず、すべての予定要素が表示されます。

次に、新しい要素をリストに追加する機会を提供します。

そのために、UIコンポーネントは以前に宣言されたサービスと直接対話します。


    
        
        
        TO-DO application
    
    
        
List of TO-DO items
Message #{item.message} Priority #{item.priority}
Add new to-do item:

上記の2つの目的は、2つの別々のdiv要素に実装されています。

最初に、todoService.AllTodoからのすべての値を表すためにdataTable要素を使用しました。

2番目のdivには、TodoService.内のTodoオブジェクトの状態を変更できるフォームが含まれています

We use the inputText element to accept user input, where the second input is automatically converted into an int. commandButton,を使用すると、ユーザーはtodoService.saveを使用してTodoオブジェクトを(メモリに)永続化できます。

9. 結論

JSFフレームワークは、Springフレームワークに統合できます。 Beanを管理するフレームワークを選択する必要があります。 このチュートリアルでは、Springフレームワークを使用しました。

ただし、スコープモデルはJSFフレームワークとは少し異なります。 したがって、Springコンテキストでカスタムスコープを定義することを検討してください。

いつものように、コードはover on GitHubで利用できます。