"A thorough introduction to Spring" called a good book to learn the Spring Framework. I try to learn while implementing the tutorial, I made a note of it because I sometimes stumbled on it unlike my own environment. I tried to fix it as far as I can understand, but maybe there is still ...?
Book | My environment | |
---|---|---|
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 * This is changed due to personal environmental issues | PostgreSQL | MySQL |
p.643 Changed for 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 and schema.sql are also changed for MySQL.
Changed field injection to constructor injection. Constructor injection is the most recommended of the three DI methods. The description will increase, but the field can be immutable.
@Autowired can be omitted if there is only one constructor in the class (it is omitted below)
RoomService.java
//Change before
@Autowired
ReservableRoomRepository reservableRoomRepository;
@Autowired
MeetingRoomRepository meetingRoomRepository;
//After change
private final ReservableRoomRepository reservableRoomRepository;
private final MeetingRoomRepository meetingRoomRepository;
public RoomService(ReservableRoomRepository reservableRoomRepository,
MeetingRoomRepository meetingRoomRepository) {
this.reservableRoomRepository = reservableRoomRepository;
this.meetingRoomRepository = meetingRoomRepository;
}
ReservationUserDetailsService.java
//Change before
@Autowired
UserRepository userRepository;
//After change
private final UserRepository userRepository;
public ReservationUserDetailsService(UserRepository userRepository) {
this.userRepository = userRepository;
}
ReservationService.java
//Change before
@Autowired
ReservationRepository reservationRepository;
@Autowired
ReservableRoomRepository reservableRoomRepository;
//After change
private final ReservationRepository reservationRepository;
private final ReservableRoomRepository reservableRoomRepository;
public ReservationService(ReservationRepository reservationRepository,
ReservableRoomRepository reservableRoomRepository) {
this.reservationRepository = reservationRepository;
this.reservableRoomRepository = reservableRoomRepository;
}
RoomsController.java
//Change before
@Autowired
RoomService roomService;
//After change
private final RoomService roomService;
public RoomsController(RoomService roomService) {
this.roomService = roomService;
}
ReservationsController.java
//Change before
@Autowired
RoomService roomService;
@Autowired
ReservationService reservationService;
//After change
private final RoomService roomService;
private final ReservationService reservationService;
public ReservationsController(RoomService roomService,
ReservationService reservationService) {
this.roomService = roomService;
this.reservationService = reservationService;
}
Changed @RequestMapping to annotation corresponding to each HTTP method "path =" is optional
RoomsController.java
//Change before
@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) {
・ ・ ・
}
//After change
@GetMapping
String listRooms(Model model) {
・ ・ ・
}
@GetMapping("{date}")
String listRooms(
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
@PathVariable("date") LocalDate date, Model model) {
・ ・ ・
}
ReservationsController.java
//Change before
@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) {
・ ・ ・
}
//After change
@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) {
・ ・ ・
}
Changed to HTML format according to Thymeleaf3 (Thymeleaf2 is in XHTML format) No error occurs even if there is no closing tag "/".
loginForm.html
//Change before
<!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>
・ ・ ・
//After change
<!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
//Change before
<!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 = "cancel" />
</form>
</td>
</tr>
・ ・ ・
//After change
<!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 = "cancel">
</form>
</td>
</tr>
・ ・ ・
listRooms.html
//Change before
<!DOCTYPE html>
<html xmlns:th = "http://www.thymeleaf.org"
xmlns:sec = "http://www.thymeleaf.org/extras/spring-security">
<head>
<meta charset = "UTF-8" />
・ ・ ・
//After change
<!DOCTYPE html>
<html xmlns:th = "http://www.thymeleaf.org"
xmlns:sec = "http://www.thymeleaf.org/extras/spring-security">
<head>
<meta charset = "UTF-8">
・ ・ ・
There is no need to create the three Converters on p.650 and 651. (Because Spring Data JPA2.2 supports java.time.Time) ・LocalDateConverter.java ・LocalTimeConverter.java ・LocalDateTimeConverter.java
Renamed the findOne () method of CrudRepository to the findById () method. The return value has changed from Entity type to Optional type. Therefore, change as follows fineOne() => findById().get()
ReservatoinService.java
//Change before
・ ・ ・
public Reservation findById(Integer reservationId) {
return reservationRepository.findOne(reservationId);
}
//After change
・ ・ ・
public Reservation findById(Integer reservationId) {
return reservationRepository.findById(reservationId).get();
}
RoomService.java
//Change before
・ ・ ・
public MeetingRoom findMeetingRoom(Integer roomId) {
return meetingRoomRepository.findOne(roomId);
}
//After change
・ ・ ・
public MeetingRoom findMeetingRoom(Integer roomId) {
return meetingRoomRepository.findById(roomId).get();
}
ReservationUserDetailsService.java
//Change before
・ ・ ・
User user = userRepository.findOne(username);
//After change
・ ・ ・
User user = userRepository.findById(username).get();
Recommended Posts