IT派遣を救いたい

【Java】Springで作るwebアプリケーション|業務で出てくる構造にする【その3】

前回はコントローラーにSQLを書いていましたが、現場ではDAOクラスを使ってSQLを発行しますので、今回はそれを作ります。

よくあるのがインターフェースを作っておいて、それをimplementsして実装するというパターンだと思います。

またserviceクラスをコントローラとDAOの間に挟んで処理を書くというのもよくあります。

今回はEntityを作ります。Daoを作ります。Serviceを作ります。コントローラーを修正します。という流れでやっていきます。

Entityを作る

entityはデータベースのテーブルと対応したクラスです。今回は、Talentテーブルと対応したentityクラスを作っていきます。
パッケージを作っておきます

作ったパッケージの中にクラスを一つ作ります。
Talent.javaというクラスを作ります。

package com.example.demo.entity;


// DBのテーブルと関係しています
public class Talent {
	
	//テーブルのカラム名を書く
	private int id;
	private String name;
	
	//コンストラクタの作成
	public Talent() {
		
	}
}

フィールドはテーブルのカラム名で、デフォルトコンストラクタまで書いたら
ゲッターとセッターを自動生成します。(コンストラクタも自動生成できますが、面倒なんで手書きでいいと思います)
Source > Generate Getters and Setters..をクリック

ゲッターセッターを作りますが、自動で作ってもらいます。

全てにチェックを入れて自動生成します。

DAOを作る

DAOはインターフェースを作って、実装クラスでSQLを書くようにします。
com.example.demo.daoというパッケージを作っておきます。

インターフェースTalentDaoを作ります。

package com.example.demo.dao;

import java.util.List;
import com.example.demo.entity.Talent;

public interface TalentDao{

	public List<Talent> getTalent();
	
}

今回必要なメソッドは一つだけです。
それはDBからタレントを取得してくるメソッドです。
早速実装クラスを作ります

package com.example.demo.dao;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

import com.example.demo.entity.Talent;

// DBを操作するクラスである宣言
@Repository
public class TalentDaoImpl implements TalentDao{

	private JdbcTemplate jdbcTemplate;
	
	@Autowired
	public TalentDaoImpl(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}
	
	@Override
	public List<Talent> getTalent() {
		
		//戻り値に合わせてクエリを発行する
		List<Map<String,Object>> queryresult = jdbcTemplate.queryForList("select * from sample.talent;");
		//Entityの型のリストを用意しておく
		List<Talent> talentList = new ArrayList<Talent>();
		//結果セットを全てtalentListにぶち込む
		for(Map<String,Object> item : queryresult) {
			Talent talent = new Talent();
			talent.setId((int)item.get("id"));
			talent.setName((String)item.get("name"));
			talentList.add(talent);
		}
		return talentList;
	}

	
}

奇妙なのが

	@Autowired
	public TalentDaoImpl(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}

これはコンストラクタで、jdbcTemplate をインジェクションしております。

次にserviceクラスを作りますが、これもDaoと同様にインターフェースと実装クラスに分けておきます。
あとパッケージも同じように作っておきます。
その中にTalentServiceインターフェースも作っておきます

package com.example.demo.service;

import java.util.List;

import com.example.demo.entity.Talent;

public interface TalentService {
	 List<Talent> getTalent();
}

次にserviceの実装クラスを作ります。実装クラスではDaoをインジェクションしてDaoのメソッドを使います。

package com.example.demo.service;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.example.demo.dao.TalentDao;
import com.example.demo.entity.Talent;

@Service
public class TalentServiceImpl implements TalentService{
	
	private TalentDao talentDao;
	
	// impleクラスのdaoがインジェクションされる
	@Autowired
	public TalentServiceImpl(TalentDao talentDao) {
		this.talentDao = talentDao;
	}

	@Override
	public List<Talent> getTalent() {
		//daoのメソッドを呼び出します
		//daoはデータベースにアクセスするだけなので、
		//その他処理があれば、serviceに書く。
		return talentDao.getTalent();
	}

}

次はコントローラーからサービスクラスを利用します。

GetMappingのhomeメソッドやコンストラクタ(daoやserviceと同じようにインジェクションする)に変更点が多いです。

SampleController.java

package com.example.demo.controllers;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import com.example.demo.dao.TalentDaoImpl;
import com.example.demo.entity.Talent;
import com.example.demo.service.TalentService;

@Controller
public class SampleController {
	
	//利用するサービスクラスを宣言して置く
	private TalentService talentService;
	
	@Autowired
	public SampleController(TalentService ts) {
		this.talentService = ts;
	}
	
	@GetMapping(value="/sample")
	public ModelAndView home(ModelAndView modelAndView) {
		modelAndView.setViewName("sample");
		modelAndView.addObject("sample","サンプルテキスト");

		List<Talent> list = talentService.getTalent();
		modelAndView.addObject("talents",list);
		
		return modelAndView;
	}
	
	
	@PostMapping(value="/sample")
	public ModelAndView post(@RequestParam("name")String name,ModelAndView modelAndView) {
		modelAndView.setViewName("home");
		modelAndView.addObject("name",name);
		return modelAndView;
	}
	
}

serviceクラスのインターフェースをインジェクションするとその実装クラスがインジェクションされます。
そして、serviceクラスのメソッドを使って、間接的にDBからデータを取得します。

あとはビューにも若干の変更があります。
ビュー側に渡されるのはEntityなのでカラムの取得方法が変わります。

sample.html

<!DOCTYPE h1 PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<h1>[[${sample}]] </h1>
<h2 th:text="${sample}"></h2>
<P>偉大なる高田健志</P>
<ul>
<li th:each="talent : ${talents}" th:text="${talent.name}" />
</ul>
<form method="post" action="/sample">
<input type="text" name="name" />
<button type="submit">送信</button>
</form>

わざわざ、Daoを用意して、Entityを用意して、serviceを用意して、得られる結果は同じです。
コントローラーに直接クエリを書こうが、結局は同じ結果なのですが、まぁ管理のしやすや、テストを考えるとこうなるのです。

(私はこのような階層化されたオブジェクト指向の設計があまり好きではないですが・・・^^;)

DTOって何?
【Java】formとentityとdtoの違いって?【Bean】