10
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Spring徹底入門のバージョンアップメモ

Posted at

SpringFrameworkを学ぶには良書と呼ばれる「Spring徹底入門」。
チュートリアルを実装しながら学ぼうとするも、
自分の環境とは異なってつまずくことがあったのでメモしておく。
わかる範囲で直してはみたものの、まだあるかも・・・?

環境

自分の環境
Spring Framework 4.2.6 5.2.3
Spring Boot 1.3.5 2.2.4
Thymeleaf 2.1.0 3.0.4
thymeleaf-extras-springsecurity4 2.1.2 -
thymeleaf-extras-springsecurity5 - 3.0.4
SQL  ※これは個人的な環境の問題で変更 PostgreSQL MySQL

変更内容

プロパティファイルの設定

p.643
MySQL用に変更

application.properties
spring.jpa.database=MYSQL
spring.datasource.url=jdbc:mysql://localhost:3306/spring_tutorial
spring.datasource.username=*****
spring.datasource.password=*****
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.initialization-mode=always
spring.jpa.hibernate.ddl-auto=validate
spring.jpa.properties.hibernate.format_sql=true
spring.datasource.sql-script-encoding=UTF-8
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
spring.datasource.separator=/;

data.sql、schema.sqlもMySQL用に変更。

インジェクションの変更

フィールドインジェクションをコンストラクタインジェクションに変更。
コンストラクタインジェクションは、3つあるDI方法の中で最も推奨されている方法。
記述は増えるが、フィールドをfinal化(Immutable)できる。

コンストラクタがクラス内に1つの場合、@Autowiredは省略可能(下記では省略している)

サービスクラス

RoomService.java
 // 変更前
 @Autowired
 ReservableRoomRepository reservableRoomRepository;
	
 @Autowired
 MeetingRoomRepository meetingRoomRepository;

 // 変更後
 private final ReservableRoomRepository reservableRoomRepository;
 private final MeetingRoomRepository meetingRoomRepository;
	
 public RoomService(ReservableRoomRepository reservableRoomRepository, 
				MeetingRoomRepository meetingRoomRepository) {
	this.reservableRoomRepository = reservableRoomRepository;
	this.meetingRoomRepository = meetingRoomRepository;
 }
ReservationUserDetailsService.java
 // 変更前
 @Autowired
 UserRepository userRepository;

 // 変更後
 private final UserRepository userRepository;
	
 public ReservationUserDetailsService(UserRepository userRepository) {
	this.userRepository = userRepository;
 }
ReservationService.java
 // 変更前
 @Autowired
 ReservationRepository reservationRepository;

 @Autowired
 ReservableRoomRepository reservableRoomRepository;

 // 変更後
 private final ReservationRepository reservationRepository;
 private final ReservableRoomRepository reservableRoomRepository;

 public ReservationService(ReservationRepository reservationRepository, 
			ReservableRoomRepository reservableRoomRepository) {
	this.reservationRepository = reservationRepository;
	this.reservableRoomRepository = reservableRoomRepository;
 }	

コントローラークラス

RoomsController.java
 // 変更前
 @Autowired
 RoomService roomService;

 // 変更後
 private final RoomService roomService;

 public RoomsController(RoomService roomService) {
	this.roomService = roomService;
 }
ReservationsController.java
 // 変更前
 @Autowired
 RoomService roomService;

 @Autowired
 ReservationService reservationService;

 // 変更後
 private final RoomService roomService;
 private final ReservationService reservationService;

 public ReservationsController(RoomService roomService, 
				ReservationService reservationService) {
	this.roomService = roomService;
	this.reservationService = reservationService;
 }

リクエストマッピングの変更

@RequestMappingをそれぞれのHTTPメソッドに対応するアノテーションに変更
"path ="は省略可能

コントローラークラス

RoomsController.java
 // 変更前
 @RequestMapping(method = RequestMethod.GET)
 String listRooms(Model model) {
     ・・・
 }

 @RequestMapping(path = "{date}", method = RequestMethod.GET)
 String listRooms(
	@DateTimeFormat(iso = DateTimeFormat.ISO.DATE) 
	@PathVariable("date") LocalDate date, Model model) {
     ・・・
 }

 // 変更後
 @GetMapping
 String listRooms(Model model) {
     ・・・
 }

 @GetMapping("{date}")
 String listRooms(
	@DateTimeFormat(iso = DateTimeFormat.ISO.DATE) 
	@PathVariable("date") LocalDate date, Model model) {
     ・・・
 }
ReservationsController.java
 // 変更前
 @RequestMapping(method = RequestMethod.GET)
 String reserveForm(
	@DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
	@PathVariable("date") LocalDate date,
	@PathVariable("roomId") Integer roomId, Model model) {
     ・・・
 }

 @RequestMapping(method = RequestMethod.POST)
 String reserve(@Validated ReservationForm form, BindingResult bindingResult,
	@AuthenticationPrincipal ReservationUserDetails userDetails,
	@DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
	@PathVariable("date") LocalDate date,
	@PathVariable("roomId") Integer roomId, Model model) {
     ・・・
 }

 @RequestMapping(method = RequestMethod.POST, params = "cancel")
 String cancel(
	@RequestParam("reservationId") Integer reservationId,
	@PathVariable("roomId") Integer roomId,
	@DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
	@PathVariable("date") LocalDate date, Model model) {
     ・・・
 }

 // 変更後
 @GetMapping
 String reserveForm(
	@DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
	@PathVariable("date") LocalDate date,
	@PathVariable("roomId") Integer roomId, Model model) {
     ・・・
 }

 @PostMapping
 String reserve(@Validated ReservationForm form, BindingResult bindingResult,
	@AuthenticationPrincipal ReservationUserDetails userDetails,
	@DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
	@PathVariable("date") LocalDate date,
	@PathVariable("roomId") Integer roomId, Model model) {
     ・・・
 }

 @PostMapping(params = "cancel")
 String cancel(
	@RequestParam("reservationId") Integer reservationId,
	@PathVariable("roomId") Integer roomId,
	@DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
	@PathVariable("date") LocalDate date, Model model) {
     ・・・
 }

Thymeleaf2 から Thymeleaf3に変更

Thymeleaf3に合わせて、HTML形式に変更
(Thymeleaf2はXHTML形式)
閉じタグ"/"がなくてもエラーにならない。

loginForm.html
 // 変更前
<!DOCTYPE html>
<html xmlns:th = "http://www.thymelaef.org">
<head>
<meta charset = "UTF-8" />
<title></title>
</head>

     ・・・

<td>
    <input type = "text" id = "username" name = "username" value = "aaaa" />
</td>

     ・・・

<td>
<input type = "password" id = "password" name = "password" value = "demo" />
</td>

     ・・・



 // 変更後
<!DOCTYPE html>
<html xmlns:th = "http://www.thymelaef.org">
<head>
<meta charset = "UTF-8">
<title></title>
</head>

     ・・・

<td>
    <input type = "text" id = "username" name = "username" value = "aaaa">
</td>

     ・・・

<td>
<input type = "password" id = "password" name = "password" value = "demo">
</td>

     ・・・


reserveForm.html
 // 変更前
<!DOCTYPE html>
<html xmlns:th = "http://www.thymeleaf.org"
       xmlns:sec = "http://www.thymeleaf.org/extras/spring-security">
<head>
<meta charset = "UTF-8" />

     ・・・

	<tr th:each = "reservation : ${reservations}">
		<td>
			<span th:text = "${reservation.startTime}" />
			-
			<span th:text = "${reservation.endTime}" />
		</td>
		<td>
			<span th:text = "${reservation.user.lastName}" />
			<span th:text = "${reservation.user.firstName}" />
		</td>
		<td>
			<form th:action = "@{'/reservations/' + ${date} + '/' + ${roomId}}" method = "post"
					sec:authorize = "${hasRole('ADMIN') or #vars.user.userId == #vars.reservation.user.userId}">
				<input type = "hidden" name = "reservationId" th:value = "${reservation.reservationId}" />
				<input type = "submit" name = "cancel" value = "取消" />
			</form>
		</td>
	</tr>

     ・・・

 // 変更後
<!DOCTYPE html>
<html xmlns:th = "http://www.thymeleaf.org"
       xmlns:sec = "http://www.thymeleaf.org/extras/spring-security">
<head>
<meta charset = "UTF-8">

     ・・・

	<tr th:each = "reservation : ${reservations}">
		<td>
			<span th:text = "${reservation.startTime}">
			-
			<span th:text = "${reservation.endTime}">
		</td>
		<td>
			<span th:text = "${reservation.user.lastName}">
			<span th:text = "${reservation.user.firstName}">
		</td>
		<td>
			<form th:action = "@{'/reservations/' + ${date} + '/' + ${roomId}}" method = "post"
					sec:authorize = "${hasRole('ADMIN') or #vars.user.userId == #vars.reservation.user.userId}">
				<input type = "hidden" name = "reservationId" th:value = "${reservation.reservationId}">
				<input type = "submit" name = "cancel" value = "取消">
			</form>
		</td>
	</tr>

     ・・・


listRooms.html
 // 変更前
<!DOCTYPE html>
<html xmlns:th = "http://www.thymeleaf.org"
       xmlns:sec = "http://www.thymeleaf.org/extras/spring-security">
<head>
<meta charset = "UTF-8" />

     ・・・

 // 変更後
<!DOCTYPE html>
<html xmlns:th = "http://www.thymeleaf.org"
       xmlns:sec = "http://www.thymeleaf.org/extras/spring-security">
<head>
<meta charset = "UTF-8">

     ・・・

Spring Data JPA 2.2に合わせた変更

不要なソース

p.650,651の3つのConverterは作成不要。
(Spring Data JPA2.2では、java.time.Timeに対応しているため)
・LocalDateConverter.java
・LocalTimeConverter.java
・LocalDateTimeConverter.java

RepositoryのfindOne()メソッドの変更

CrudRepositoryのfindOne()メソッドがfindById()メソッドに名称変更。
戻り値がEntity型からOptional型になった。
そのため、下記のように変更
fineOne() => findById().get()
※get() : Optionalに値が存在する場合は値を返し、それ以外の場合はNoSuchElementExceptionをスローしてくれる

サービスクラス

ReservatoinService.java
 // 変更前

・・・
 public Reservation findById(Integer reservationId) {
    return reservationRepository.findOne(reservationId);
 }

 // 変更後

・・・
 public Reservation findById(Integer reservationId) {
    return reservationRepository.findById(reservationId).get();
 }
RoomService.java
 // 変更前

・・・

 public MeetingRoom findMeetingRoom(Integer roomId) {
	return meetingRoomRepository.findOne(roomId);
 }

 // 変更後

・・・

 public MeetingRoom findMeetingRoom(Integer roomId) {
	return meetingRoomRepository.findById(roomId).get();
 }
ReservationUserDetailsService.java
 // 変更前

・・・

 User user = userRepository.findOne(username);

 // 変更後

・・・

User user = userRepository.findById(username).get();
10
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?