Spring徹底入門のチュートリアルをアレンジを加えながら進めていたところ、画面表示時にエラーとなったため、検証してみました。
環境
- windowds 11
- Java 17
- Spring Boot 3.0.4
- Spring 6.0.6
- Thymleaf 3.1.1
- STS 4
ソース抜粋
作成したソースは以下の通りです。
Spring徹底入門のチュートリアルではSpring Data JPAを使っていますが、MyBatisを使うようにしました。
@Controller
@RequestMapping("rooms")
public class RoomsController {
@Autowired
RoomService roomService;
@RequestMapping(method = RequestMethod.GET)
String listRooms(Model model) {
LocalDate today = LocalDate.now();
List<AvailableReservableRoom> rooms = roomService.findReservableRooms(today);
model.addAttribute("date", today);
model.addAttribute("rooms", rooms);
return "room/listRooms";
}
}
@Service
@Transactional
public class RoomService {
@Autowired
AvailableReservableRoomMapper reservableRoomMapper;
public List<AvailableReservableRoom> findReservableRooms(LocalDate date) {
return reservableRoomMapper.finbByReservedDate(date);
}
}
@Mapper
public interface AvailableReservableRoomMapper {
List<AvailableReservableRoom> finbByReservedDate(LocalDate reservedDate);
}
import lombok.Data;
@Data
public class AvailableReservableRoom {
private Integer roomId;
private LocalDate reservedDate;
private String roomName;
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="mrs.domain.mapper.AvailableReservableRoomMapper">
<resultMap id="availableReservableRoomMap"
type="mrs.domain.model.AvailableReservableRoom">
<result column="room_id" jdbcType="INTEGER" property="roomId" />
<result column="reserved_date" jdbcType="DATE" property="reservedDate" />
<result column="room_name" jdbcType="VARCHAR" property="roomName" />
</resultMap>
<select id="finbByReservedDate" parameterType="java.time.LocalDate" resultMap="availableReservableRoomMap">
select
t1.reserved_date,
t1.room_id,
t2.room_name
from
reservable_room t1,
meeting_room t2
<where>
t1.room_id = t2.room_id
and t1.reserved_date = #{reservedDate}
</where>
order by room_id
</select>
</mapper>
<ul>
<li th:each="room: ${rooms}">
<a th:href="@{'/reservations/' + ${date} + '/' + ${room.roomId}}"
th:text="${room.roomName}"></a>
</li>
</ul>
画面表示
Spring Bootを起動し、http://localhost:8080/rooms にアクセスすると以下のエラーとなりました。
検証
STSのコンソールを確認したところ、htmlに表示する際にフィールドが見つからない旨のエラーとなっている模様です。
org.thymeleaf.exceptions.TemplateProcessingException: Exception evaluating SpringEL expression: "room.roomId" (template: "room/listRooms" - line 15, col 12)
at org.thymeleaf.spring6.expression.SPELVariableExpressionEvaluator.evaluate(SPELVariableExpressionEvaluator.java:292) ~[thymeleaf-spring6-3.1.1.RELEASE.jar:3.1.1.RELEASE]
at org.thymeleaf.standard.expression.VariableExpression.executeVariableExpression(VariableExpression.java:166) ~[thymeleaf-3.1.1.RELEASE.jar:3.1.1.RELEASE]
at org.thymeleaf.standard.expression.SimpleExpression.executeSimple(SimpleExpression.java:66) ~[thymeleaf-3.1.1.RELEASE.jar:3.1.1.RELEASE]
~
Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1008E: Property or field 'roomId' cannot be found on object of type 'mrs.domain.model.AvailableReservableRoom' - maybe not public or not valid?
at org.springframework.expression.spel.ast.PropertyOrFieldReference.readProperty(PropertyOrFieldReference.java:217) ~[spring-expression-6.0.6.jar:6.0.6]
at org.springframework.expression.spel.ast.PropertyOrFieldReference.getValueInternal(PropertyOrFieldReference.java:104) ~[spring-expression-6.0.6.jar:6.0.6]
at org.springframework.expression.spel.ast.PropertyOrFieldReference$AccessorLValue.getValue(PropertyOrFieldReference.java:405) ~[spring-expression-6.0.6.jar:6.0.6]
Controllerで確認すると値は設定されているように見えます。
結論
lombokの@Data
で端折っていたgetter/getter
を自前で定義するように修正したら画面表示できました。
Lombokにお任せしたGetterではThymleafでフィールドの参照ができなそうです。
(なお、Lombokで生成されたソースまでは確認しておりません)
よくよく調べた結果、どうやらLombokのインストールがうまくいっていなかった模様・・・
別のmodelクラスでアウトラインを見ていたところgetter
とsetter
がないことを確認
Lombokのインストールが必要という情報を見つけたため試してみました(以前使用したときはやった記憶がない・・・)
手順は以下
-vmargs -javaagent:lombok-1.18.26.jar
アウトラインを確認し、getterとsetterが追加されていることを確認
以前このような手順をやった記憶がなかったため
ThymleafでLombokの自動生成メソッドが参照できないのが原因だと思い込んでいましたが
Lombokのインストールが必要だったというオチでした(すみません・・・)。