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を調べることができます。
残念ながら、ボタンをクリックするとエラーが発生します。
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
メッセージには、問題が明確に示されています。jsfControllerがnull.に解決されました。対応するコンポーネントが作成されていないか、少なくとも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で利用できます。