회사에서 Java, Spring Boot, Thymeleaf로 작업하고 있다.
화면에 테이블을 그리는데, (A, B 영역 / ㄱ, ㄴ, ㄷ 교재 / 1, 2 유닛)
A | ㄱ | 1 |
2 | ||
ㄴ | 1 | |
B | ㄷ | 1 |
1 |
이런 식으로 그려줘야 했다.
Javascript로 할 수도 있었지만, 최대한 로직을 Java쪽에서 만들어주기로 했기 때문에 Map<String, Map<String, List<Dto>>> 이러한 형태로 만들어서 화면에서 그릴 생각이었다.
// 화면으로 보낼 최종 맵
Map<String, Map<String, List<UserDto>>> resultMap = new LinkedHashMap<>();
// 임시 맵
Map<String, List<UserDto>> tempMap = new LinkedHashMap<>();
// 전체 데이터
List<UserDto> studyDto = xxxService.findStudyByUserId(userId);
맵을 먼저 만들어 놓고 전체 데이터에서 맵에 넣어줄 생각이다.
// 영역 별 맵
Set<CodeRef> areaTemp = studyDto.stream().map(UserDto::getData3).collect(Collectors.toSet());
Map<String, String> areaMap = areaTemp.stream().collect(Collectors
.toMap(
(i) -> i.getKey().getGroupId()+i.getKey().getDetailId()
, CodeRef::getCaption)
);
Map<String, Integer> sizeMap = new HashMap<>();
Map<String, Integer> bookSizeMap = new HashMap<>();
areaTemp.forEach(dto -> {
resultMap.computeIfAbsent(dto.getKey().getGroupId() + dto.getKey().getDetailId()
, k-> new HashMap<>());
sizeMap.computeIfAbsent(dto.getKey().getGroupId() + dto.getKey().getDetailId()
, k->0);
});
areaMap, sizeMap, bookSizeMap은 화면에서 사용예정
areaTemp는 테이블의 A, B를 담기 위해서 만들어줬다.
영역의 테이블 rowspan을 위해 areaTemp를 반복문 돌면서 껍데기 맵(resultMap, sizeMap)을 만들어줬다.
studyDto.forEach(dto-> {
String bookNm = dto.getData2().getBookNm();
List<UserDto> bookNmList = CommonUtils.get_bookNm(studyDto, bookNm);
tempMap.putIfAbsent(bookNm, bookNmList);
bookSizeMap.computeIfAbsent(bookNm, k->0);
});
전체 데이터를 반복문 통해 돌면서 임시 맵에 bookNm을 Key로 List를 Value로 넣어줬다.
bookSizeMap은 교재의 테이블 rowspan을 위해 사용 예정
tempMap.forEach((key, value) -> {
UserDto dto = value.get(0);
String bookNm = dto.getData2().getBookNm();
String caption =
dto.getData3().getKey().getGroupId() + dto.getData3().getKey().getDetailId();
sizeMap.put(caption, sizeMap.get(caption) + value.size());
bookSizeMap.put(bookNm, bookSizeMap.get(bookNm) + value.size());
Map<String, List<UserDto>> stringListMap = resultMap.get(caption);
stringListMap.put(key, value);
resultMap.put(caption, stringListMap);
});
최종맵에 중간에 있는 맵인 tempMap에 데이터를 넣어줬다.
여기에서 rowspan으로 쓰일 맵들에 실제 데이터도 넣고, 최종맵에도 리스트가 담긴 맵을 넣어줬다.
model.addAttribute("bookSizeMap", bookSizeMap);
model.addAttribute("sizeMap", sizeMap);
model.addAttribute("resultMap", resultMap);
model.addAttribute("areaMap", areaMap);
화면에서 사용하기 위해 model에 넣어주었다.
<th:block th:each="area,index : ${resultMap}">
<th:block th:each="book,index : ${area.value}" th:with="areai = ${index.index}">
<th:block th:each="list,index : ${book.value}" th:with="booki = ${index.index}">
<tr>
<td th:if="${index.index + areai + booki == 0}"
th:rowspan="${sizeMap.get(list.data2.skillCd)}"
th:text="${areaMap.get(area.key)}"></td>
<td th:if="${index.index + booki == 0}"
th:rowspan="${bookSizeMap.get(list.data2.bookNm)}"
th:text="${book.key}"></td>
<td th:text="Unit + ' ' + ${list.data1.key.unit}"></td>
</tr>
</th:block>
</th:block>
</th:block>
최종맵을 반복문을 돌리고
최종맵의 value값인 중간맵을 반복문 돌리고
중간맵의 value값인 리스트를 반복문을 돌려서 화면을 그려주었다.
영역 부분에서 td는 index가 0일때만 그려주고 rowspan을 주기 위해 if문으로 처리했다.
교재 부분에서도 td는 index가 0일때만 그려주고 rowspan을 주기 위해 if문으로 처리했다.
if문을 안주면 자리가 부족해져서 테이블이 깨졌다.
Javascript로 할 때보다 Java로 데이터 가공해서 thymeleaf로 뿌려주니 깜빡임이 없어 보기에 더 좋았다.
'개발 > Java&Kotlin' 카테고리의 다른 글
[JPA] 값 타입 (0) | 2022.07.20 |
---|---|
[Spring] 데이터 액세스 층의 설계와 구현 (0) | 2022.07.20 |
[JPA] 프록시와 연관관계 관리 (0) | 2022.07.19 |
[JPA] 고급 매핑 (0) | 2022.07.18 |
[Java] 트리 (0) | 2022.07.14 |