こんにちは。この記事では、単純な CRUD アプリケーションを作成する過程で、Maven、Spring、Hibernate、MySQL、Tomcat などに初めて遭遇したことを共有したいと思います。これは 4 の 2 番目の部分です。この記事は主に、ここですでに 30 ~ 40 のレベルを完了しているが、まだ純粋な Java を超えて冒険をしておらず、オープンワールドに参入し始めたばかり (またはこれから始めようとしている) 人を対象としています。これらすべてのテクノロジー、フレームワーク、その他の聞きなれない言葉。 これは記事「Maven、Spring、MySQL、Hibernate、および最初の CRUD アプリケーションの紹介」の第 2 部です。最初の部分は、次のリンクからご覧いただけます: Maven、Spring、MySQL、Hibernate、および最初の CRUD アプリケーションの紹介 (パート 1)
コンテンツ:
さて、次に進みましょう。映画のリポジトリ全体を呼び出してみましょう。もちろん、私たちの小さくて単純なアプリケーションでは、愚かにもすべてのロジックをコントローラーに直接組み込むこともできますが、すでに述べたように、すべてを正しく実行する方法をすぐに学ぶ方が良いです。したがって、いくつかのレイヤーを作成しましょう。データの処理を担当する DAO と、他のあらゆる種類のロジックが存在するService があり、コントローラーはリクエストを処理して必要なサービス メソッドを呼び出すだけです。データアクセスオブジェクト
データ アクセス オブジェクト (DAO) はそのようなデザイン パターンです。重要なのは、データへのアクセス (データベースまたはその他のストレージ メカニズムと連携) のみを担当する特別なレイヤーを作成することです。パッケージには、追加、削除などのメソッドが含まれるdao
インターフェイスを作成します。FilmDAO
呼び方は少し違いますが、基本的なCRUD操作 ( C reate、Read、U pdate、D elete) に対応します。
ここで注目に値するのは、DAO に加えて、リポジトリなどのアプローチもあり、それらは非常に似ているように見え、どちらもデータを操作するために使用されます。これらのアプローチにどのような特徴があるのか、またそれらの違いは何なのかはまだわかりません。したがって、ここで私が誤解している可能性がありますが、これはタオではなくリポジトリ、あるいはその中間と呼ぶべきかもしれません。しかし、私が見たり研究したほとんどの例では、これは DAO と呼ばれているので、おそらく同じと呼ぶでしょう。同時に、おそらく本文のどこかで「リポジトリ」という言葉を使用するでしょう。いずれにせよ、これに関して私がどこか間違っている場合は、ご容赦ください。 |
package testgroup.filmography.dao;
import testgroup.filmography.model.Film;
import java.util.List;
public interface FilmDAO {
List<Film> allFilms();
void add(Film film);
void delete(Film film);
void edit(Film film);
Film getById(int id);
}
次に、その実装が必要です。まだデータベースには接続しませんが、少し怖いです。練習して慣れるために、まずメモリ内のストレージをシミュレートし、いくつかのフィルムのリストを作成してみましょう。リストを保存するには、 not を使用しますList
。これは、リスト全体を調べなくても、 を使用Map
して特定の映画を簡単に取得できるようにするためです。id
生成にはAtomicIntegerid
を使用します。クラスを作成し、すべてのメソッドを実装して、マップを埋めてみましょう。そんな感じ。 FilmDAOImpl
package testgroup.filmography.dao;
import testgroup.filmography.model.Film;
import java.util.*;
public class FilmDAOImpl implements FilmDAO {
private static final AtomicInteger AUTO_ID = new AtomicInteger(0);
private static Map<Integer, Film> films = new HashMap<>();
static {
Film film1 = new Film();
film1.setId(AUTO_ID.getAndIncrement());
film1.setTitle("Inception");
film1.setYear(2010);
film1.setGenre("sci-fi");
film1.setWatched(true);
films.put(film1.getId(), film1);
// + film2, film3, film4, ...
}
@Override
public List<Film> allFilms() {
return new ArrayList<>(films.values());
}
@Override
public void add(Film film) {
film.setId(AUTO_ID.getAndIncrement());
films.put(film.getId(), film);
}
@Override
public void delete(Film film) {
films.remove(film.getId());
}
@Override
public void edit(Film film) {
films.put(film.getId(), film);
}
@Override
public Film getById(int id) {
return films.get(id);
}
}
サービス
次に、サービス層を追加しましょう。原則として、この例では、DAO に限定すれば、これなしで行うことも十分に可能です。アプリケーションは非常にシンプルになり、サービス内に複雑なロジックを追加する予定はありません。しかし、将来突然、プロジェクトにあらゆる種類の複雑さや興味深いものを追加したくなるでしょう。そのため、完全を期すために、そのままにしておきます。現時点では、DAO からメソッドを呼び出すだけです。パッケージ内にservice
インターフェースを作成しましょうFilmService
。
package testgroup.filmography.service;
import testgroup.filmography.model.Film;
import java.util.List;
public interface FilmService {
List<Film> allFilms();
void add(Film film);
void delete(Film film);
void edit(Film film);
Film getById(int id);
}
そしてその実装:
package testgroup.filmography.service;
import testgroup.filmography.dao.FilmDAO;
import testgroup.filmography.dao.FilmDAOImpl;
import testgroup.filmography.model.Film;
import java.util.List;
public class FilmServiceImpl implements FilmService {
private FilmDAO filmDAO = new FilmDAOImpl();
@Override
public List<Film> allFilms() {
return filmDAO.allFilms();
}
@Override
public void add(Film film) {
filmDAO.add(film);
}
@Override
public void delete(Film film) {
filmDAO.delete(film);
}
@Override
public void edit(Film film) {
filmDAO.edit(film);
}
@Override
public Film getById(int id) {
return filmDAO.getById(id);
}
}
プロジェクトの構造は次のようになります。
コントローラーとビュー
次に、コントローラーのメソッドとページの入力に取り組みましょう。ページを記入する際には、いくつかのテクニックが必要になります。たとえば、映画のリストを表示するにはループが必要です。たとえば、パラメータに応じて何らかの碑文を変更したい場合は、条件などが必要です。JSP (JavaServer Pages) 形式を使用すると、これらすべてを実装できる Java コード挿入を使用できます。しかし、ページ上で Java コードを HTML コードと混合して使用したくありません。それは少なくとも、非常に醜いものになるでしょう。幸いなことに、この問題を解決するために、 JSTL (JavaServer Pages Standard Tag Library) または JSP Standard Tag Library のような素晴らしいものが存在します。これにより、さまざまなニーズに合わせて、JSP ページで大量の追加タグを使用できるようになります。それを次のように接続しましょうpom.xml
:
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
次にコントローラーを見てみましょう。まず、そこからオブジェクトの作成を削除しましょうFilm
。これはテストのために行われたものであり、他には何も必要ありません。そこにサービスを追加し、そのメソッドを呼び出してみましょう。
public class FilmController {
private FilmService filmService = new FilmServiceImpl();
さて、それに応じて、それぞれのケースに応じてメソッドを作成し、追加、削除などを行います。まず、映画のリストを含むメイン ページを表示する方法:
@RequestMapping(method = RequestMethod.GET)
public ModelAndView allFilms() {
List<Film> films = filmService.allFilms();
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("films");
modelAndView.addObject("filmsList", films);
return modelAndView;
}
ここには何も新しいことはありません。サービスから映画のリストを取得し、モデルに追加します。films.jsp
次に、このメソッドが返す メイン ページを作成しましょう。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>FILMS</title>
</head>
<body>
<h2>Films</h2>
<table>
<tr>
<th>id</th>
<th>title</th>
<th>year</th>
<th>genre</th>
<th>watched</th>
<th>action</th>
</tr>
<c:forEach var="film" items="${filmsList}">
<tr>
<td>${film.id}</td>
<td>${film.title}</td>
<td>${film.year}</td>
<td>${film.genre}</td>
<td>${film.watched}</td>
<td>
<a href="/edit/${film.id}">edit</a>
<a href="/delete/${film.id}">delete</a>
</td>
</tr>
</c:forEach>
</table>
<h2>Add</h2>
<c:url value="/add" var="add"/>
<a href="${add}">Add new film</a>
</body>
</html>
このページを詳しく見て、何が何であるかを見てみましょう。 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> - ここで JSTL コアが接続されており、サイクルや条件などを作成するためのメイン タグが含まれています。 。
<table>
— テーブルを作成するためのタグ。<tr>
— テーブルの行<th>
- 列ヘッダー<td>
— 表のセル
<c:forEach var="film" items="${filmsList}">
、ループ (JSTL コアから取得したもの) で、渡されたリスト ( ) のすべての要素を調べfilmsList
、要素 ( ) ごとにfilm
新しい行を作成し、対応する値を各セルに書き込みます。ここでポイントが 1 つあり、録音は 、つまりfilm.id
として理解する必要があるようです。film.getId()
フィールドには直接アクセスされませんが、ゲッターが呼び出されます。最後の列 ( action
) では、削除と編集のためのリンクを作成します (対応するメソッドをこれから作成します)。さて、以下は新しいムービーを追加する方法へのリンクです。次に 、特定のムービーの編集ページを返すメソッドを見てみましょう。
@RequestMapping(value = "/edit/{id}", method = RequestMethod.GET)
public ModelAndView editPage(@PathVariable("id") int id) {
Film film = filmService.getById(id);
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("editPage");
modelAndView.addObject("film", film);
return modelAndView;
}
ここに何か新しいものが現れました - これは注釈です@PathVariable
。int id
このパラメータ( )はアドレスバーから取得されることを示します。アドレスバーでこのパラメータの位置を示すには、この構造が使用されます{id}
(ちなみに、この場合のように変数名が同じ場合は、括弧で囲む必要はありませんが、単にそれを記述するだけです)@PathVariable int id
)。そのため、メイン ページには、次のことを示す各映画へのリンクを作成しましたid
。
<a href="/edit/${film.id}">edit</a>
次に、この値がメソッド パラメーターに割り当てられ、それを使用してサービスを通じてリポジトリから特定のムービーを取得し、モデルに追加します。これは編集ページを取得するためのメソッドでしたが、今度はそれ自体を編集するためのメソッドが必要になります。
@RequestMapping(value = "/edit", method = RequestMethod.POST)
public ModelAndView editFilm(@ModelAttribute("film") Film film) {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("redirect:/");
filmService.edit(film);
return modelAndView;
}
このメソッドでは、editPage
モデルに属性を追加しました。
modelAndView.addObject("film", filmService.getById(id));
そして、アノテーションの助けを借りて、@ModelAttribute
この属性を取得し、変更できるようになりました。POST
ここではデータを渡すのでrequest メソッド。" redirect:/
" は、このメソッドを実行した後、アドレス " /
" にリダイレクトされることを意味します。メソッドが実行されallFilms
、メイン ページに戻ります。次に、ページ自体を作成しましょうeditPage.jsp
。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Edit</title>
</head>
<body>
<c:url value="/edit" var="var"/>
<form action="${var}" method="POST">
<input type="hidden" name="id" value="${film.id}">
<label for="title">Title</label>
<input type="text" name="title" id="title">
<label for="year">Year</label>
<input type="text" name="year" id="year">
<label for="genre">Genre</label>
<input type="text" name="genre" id="genre">
<label for="watched">Watched</label>
<input type="text" name="watched" id="watched">
<input type="submit" value="Edit film">
</form>
</body>
</html>
<form>
— データを収集および送信するためのフォーム。誰がデータを処理するかを示します (/edit
)<input>
— ユーザー対話のためのインターフェース要素 (ボタン、入力フィールドなど)<label>
- テキストラベル
<input type="submit" value="Edit film">
フォームのデータがサーバーに送信されます (id
データベース内のどのレコードを更新する必要があるかをサーバーが認識できるように、値を含む非表示のフィールドが特別に追加されています)。メソッドでは、editFilm
それらは対応する属性フィールドに割り当てられますfilm
。その後、メイン ページに戻り、更新されたリストが表示されます。編集ページは次のようになります。 次に、新しい映画をリストに追加してみましょう。これを行うには、データを入力して送信するためのフォームも必要です。メイン ページにフォームを作成することも、 のような別のページを作成することもできますeditPage.jsp
。しかし、その一方で、追加の形式は編集の場合とまったく同じになります。4 つの入力フィールドと送信ボタン。では、なぜ新しいページを作成するのかというと、 を使用しましょうeditPage.jsp
。ページを取得する方法:
@RequestMapping(value = "/add", method = RequestMethod.GET)
public ModelAndView addPage() {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("editPage");
return modelAndView;
}
このメソッドでは、editPage
後で変更するために属性を追加で渡していますが、ここでは単にページを受け取るだけです。そして追加するメソッド:
@RequestMapping(value = "/add", method = RequestMethod.POST)
public ModelAndView addFilm(@ModelAttribute("film") Film film) {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("redirect:/");
filmService.add(film);
return modelAndView;
}
ここでは属性を渡さなかったので、ここで新しいオブジェクトが作成されますFilm
。まあ、基本的には新しいことは何もありません。両方の方法が「 」で利用できることも注目に値します/add
。これは、さまざまな種類のリクエストに応答するという事実によって可能になります。メイン ページのリンクをたどることで GET リクエストを実行し、 にアクセスしますaddPage
。追加ページでデータを送信するボタンをクリックすると、POST リクエストが作成され、addFilm
. 新しいムービーを追加するには、編集と同じページを使用することにしました。ただし、データはアドレス " /edit
" に送信されます。
<c:url value="/edit" var="var"/>
<form action="${var}" method="POST">
<input type="submit" value="Edit film">
</form>
追加と編集の動作が異なるように、ページを少し調整する必要があります。この問題を解決するには、同じ JSTL コア ライブラリの条件を使用します。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<c:if test="${empty film.title}">
<title>Add</title>
</c:if>
<c:if test="${!empty film.title}">
<title>Edit</title>
</c:if>
</head>
<body>
<c:if test="${empty film.title}">
<c:url value="/add" var="var"/>
</c:if>
<c:if test="${!empty film.title}">
<c:url value="/edit" var="var"/>
</c:if>
<form action="${var}" method="POST">
<c:if test="${!empty film.title}">
<input type="hidden" name="id" value="${film.id}">
</c:if>
<label for="title">Title</label>
<input type="text" name="title" id="title">
<label for="year">Year</label>
<input type="text" name="year" id="year">
<label for="genre">Genre</label>
<input type="text" name="genre" id="genre">
<label for="watched">Watched</label>
<input type="text" name="watched" id="watched">
<c:if test="${empty film.title}">
<input type="submit" value="Add new film">
</c:if>
<c:if test="${!empty film.title}">
<input type="submit" value="Edit film">
</c:if>
</form>
</body>
</html>
それらの。私たちはフィールドをチェックしているだけですfilm.title
。空の場合は新しいムービーなので、すべてのデータを入力してリストに追加する必要があります。このフィールドが空でない場合、それはリストにある映画なので、変更するだけで済みます。それ。ページの 2 つのバージョンが得られます。 さて、リストからムービーを削除する最後のコントローラー メソッドは次のとおりです。
@RequestMapping(value="/delete/{id}", method = RequestMethod.GET)
public ModelAndView deleteFilm(@PathVariable("id") int id) {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("redirect:/");
Film film = filmService.getById(id);
filmService.delete(film);
return modelAndView;
}
ここで何もコメントする必要はないと思います、これらすべてはすでに検討されています。すでにメインページにこのアドレスへのリンクを作成しています。さて、ここですべての準備ができているようです。もう一度実行して、すべてがどのように機能するかを確認できます。
Spring コンポーネントとしてのリポジトリとサービス
もう 1 つ小さな修正を加えてみましょう。実際のところ、ストレージとサービスは単なるクラスであり、それらを使用するには自分でクラス オブジェクトを作成する必要があります (new FilmServiceImpl()
)。しかし、私たちはSpringに理由があって接続しているので、この問題は彼自身に制御させてください。クラスを Spring の制御下に置くには、クラスがコンポーネントであることを示す必要があります。これを行うには、特別な注釈を付けてマークします。
@Repository
public class FilmDAOImpl implements FilmDAO {
@Service
public class FilmServiceImpl implements FilmService {
注釈@Repository
と@Service
、および は@Controller
から派生します@Component
。これら 3 つのアノテーションの具体的な機能と違い、および単純なコンポーネントとの違いについては、ドキュメントまたはガイドで個別に読む必要があります。現時点では、これらのアノテーションが Spring にこれらのクラスがそれぞれリポジトリとサービスであることを伝えていることを理解すれば十分です。そして今では、これらのクラスの具象オブジェクトを自分で作成する必要はなくなりました。
private FilmService filmService = new FilmServiceImpl();
代わりに、フィールドに特別なアノテーションをマークすると、Spring が適切な実装を選択します。
@Autowired
private FilmService filmService;
アノテーション@Autowired
(自動バインディング) は、コンテキストを調べて、ここで適切な Bean を置き換える必要があることを Spring に伝えます。とても快適です。以前はメソッドの特定の実装を気にする必要がないようにインターフェイスを使用していましたが、今ではインターフェイス自体の実装を気にする必要はなく、その名前さえ知る必要はありません。考え方としては、フィールドで自動バインディングを使用することは推奨されず、コンストラクターまたはセッターを使用する方が良いということです。詳細については、ドキュメントを参照してください。私たちにとって、原則として、これは重要ではないので、そのままにしておいて問題ありません。しかし、アイデアがそれを求めているので、すべてが美しく、黄色の警告がないことを尊重します。コントローラー クラスで、セッターを作成し、それにアノテーションを付けてみましょう。
@Controller
public class FilmController {
private FilmService filmService;
@Autowired
public void setFilmService(FilmService filmService) {
this.filmService = filmService;
}
FilmDAO
そして同様に、クラス内 に setter を作成しますFilmServiceImpl
。 続く... Maven、Spring、MySQL、Hibernate および最初の CRUD アプリケーションの紹介 (パート 1) Maven、Spring、MySQL、Hibernate および最初の CRUD アプリケーションの紹介 (パート 2) Maven、Spring、MySQL、Hibernate および最初の CRUD アプリケーション (パート 3) Maven、Spring、MySQL、Hibernate および最初の CRUD アプリケーションの概要 (パート 4)
GO TO FULL VERSION