반응형
✅구현 목표
기능 | URL | GET/POST | 기능 | Redirect URL |
목록 | /guestbook/list | GET | 목록/페이징/검색 | |
등록 | /guestbook/register | GET | 입력 화면 | |
/guestbook/register | POST | 등록 처리 | /guestbook/list | |
조회 | /guestbook/read | GET | 조회 화면 | |
수정 | /guestbook/modify | GET | 수정/삭제 기능 화면 | |
/guestbook/modify | POST | 수정 처리 | /guestbook/read | |
삭제 | /guestbook/remove | POST | 삭제 처리 | /guestbook/list |
🤍자동으로 처리되는 날짜/시간 설정
BaseEntity 작성
- 게시글 작성, 수정 시간 같이 자동으로 추가되고 변경되어야 하는 컬럼을 매번 처리하는 일은 번거롭기 때문에 자동으로 처리 가능한 어노테이션을 이용해서 설정한다.
- @MapedSuperclass : 해당 어노테이션이 적용된 클래스는 테이블로 생성되지 않음.
Guestbook 작성
GuestbookRepository 작성
public interface GuestbookRepository extends JpaRepository<Guestbook,Long>, QuerydslPredicateExecutor<Guestbook> {
}
build.gradle 파일에 Querydsl 설정
- JPA의 쿼리 메서드, @Query를 통해서도 많은 기능을 구현할 수 있으나 Querydsl은 복잡한 검색조건, 조인, 서브쿼리 등의 기능까지 구현이 가능하다.
- Querydsl를 사용하려면 'Q도메인'이라는 것을 이용해야함 -> build.gradl에 querydsl 관련 라이브러리 추가
//querydsl 추가
implementation "com.querydsl:querydsl-jpa:${queryDslVersion}"
implementation "com.querydsl:querydsl-apt:${queryDslVersion}"
def querydslDir = "$buildDir/generated/querydsl"
querydsl {
jpa = true
querydslSourcesDir = querydslDir
}
sourceSets {
main.java.srcDir querydslDir
}
compileQuerydsl{
options.annotationProcessorPath = configurations.querydsl
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
querydsl.extendsFrom compileClasspath
}
여기까지 설정하고 build 항목에서 compileQuerydsl을 실행하면 build 폴더 안에 Q로 시작하고 이후는 엔티티 클래스의 이름과 동일한 클래스가 생성됨.
🤍300개의 테스트 데이터 먼저 넣기
@SpringBootTest
public class GuestbookRepositoryTests {
@Autowired
private GuestbookRepository guestbookRepository;
//300개의 데이터 먼저 삽입
@Test
public void insertDummies(){
IntStream.rangeClosed(1,300).forEach(i->{
Guestbook guestbook = Guestbook.builder().title("Title..."+i).content("Content..."+i).writer("user..."+(i%10)).build();
System.out.println(guestbookRepository.save(guestbook));
});
}
}
GuestbookDTO 클래스 작성
🤍1. 목록 처리
- 화면에서 필요한 목록에 대한 DTO 생성
- DTO를 Pageable 타입으로 전환
- Page<Entity>를 화면에서 사용하기 쉬운 DTO의 리스트 등으로 변환
- 화면에 필요한 페이지 번호 처리
1. 페이지 처리를 위한 PageRequestDTO, PageResultDTO 클래스 작성
- PageRequestDTO : 페이지 요청 처리
- PageResultDTO : 페이지 결과 처리
@Builder
@AllArgsConstructor
@Data
public class PageRequestDTO { //JPA에서 사용하는 Pageable 타입의 객체를 생성하는 것이 목적임.
private int page;
private int size;
private String type;
private String keyword;
public PageRequestDTO(){
this.page=1;
this.size=10;
}
public Pageable getPageable(Sort sort){
return PageRequest.of(page-1,size,sort); //페이지 번호가 0부터 시작하기 때문에 1페이지의 경우 0이 될 수 있도록 page-1
}
}
@Data
public class PageResultDTO<DTO,EN> {
/*
JPA를 이용하는 Repository에서는 페이지 처리 결과를 Page<Entity> 타입으로 반환하기 때문에
서비스 계층에서 이를 처리하기 위해 별도의 클래스를 만들어야함.
1.Page 엔티티 객체들을 DTO 객체로 변환해서 자료구조로 담아주어야함.
2.화면 출력에 필요한 페이지 정보들을 구성해주어야함.
*/
//DTO 리스트
private List<DTO> dtoList;
//총 페이지 번호
private int totalPage;
//현재 페이지 번호
private int page;
//목록 사이즈
private int size;
//시작 페이지 번호,끝 페이지 번호
private int start, end;
//이전,다음
private boolean prev, next;
//페이지 번호 목록
private List<Integer> pageList;
}
2. 목록 처리 서비스 코드 작성
- 인터페이스 GuestbookService
- GuestServiceImpl
3. 페이징 처리
페이징 처리를 위해서는 4가지 요소를 생각해 보아야 한다.
- 화면에서 시작 페이지 번호(start)
- 화면에서 끝 페이지 번호(end)
- 이전/다음 이동 링크 여부(prev, next)
- 현재 페이지 번호(page)
아래 코드를 PageResultDTO 클래스에 추가한다.
public PageResultDTO(Page<EN> result, Function<EN,DTO> fn){
dtoList = result.stream().map(fn).collect(Collectors.toList());
totalPage = result.getTotalPages();
makePageList(result.getPageable());
}
private void makePageList(Pageable pageable){
this.page=pageable.getPageNumber()+1; //0부터 시작하므로
this.size=pageable.getPageSize();
//temp end page
int tempEnd = (int)(Math.ceil(page/10.0))*10;
start = tempEnd-9;
prev=start>1;
end=totalPage>tempEnd?tempEnd:totalPage;
next=totalPage>tempEnd;
pageList= IntStream.rangeClosed(start,end).boxed().collect(Collectors.toList());
}
4. 컨트롤러 코드 작성
5. 목록 화면 list.html 코드 작성
6. 하단에 페이징 처리 코드 추가
<ul class="pagination h-100 justify-content-center align-items-center">
<li class="page-item " th:if="${result.prev}">
<a class="page-link" th:href="@{/guestbook/list(page=${result.start -1}, type=${pageRequestDTO.type}, keyword=${pageRequestDTO.keyword})}" tabindex="-1">Previous</a>
</li>
<li th:class=" 'page-item '+${result.page == page?'active':''}" th:each="page:${result.pageList}">
<a class="page-link" th:href="@{/guestbook/list(page=${page}, type=${pageRequestDTO.type}, keyword=${pageRequestDTO.keyword})}">
[[${page}]]
</a>
</li>
<li class="page-item" th:if="${result.next}">
<a class="page-link" th:href="@{/guestbook/list(page=${result.end +1}, type=${pageRequestDTO.type}, keyword=${pageRequestDTO.keyword})}">Next</a>
</li>
</ul>
7. 페이징 완료
🤍2. 등록 처리
1. 등록 컨트롤러 작성
2. 등록 화면 register.html 작성
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<th:block th:replace="~{/layout/basic::setContent(~{this::content})}">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!-- Bootstrap core JS-->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/js/bootstrap.bundle.min.js"></script>
<!-- Core theme JS-->
<script th:src="@{/js/scripts.js}"></script>
</head>
<body>
<th:block th:fragment="content">
<h1 class="mt-4">GuestBook Register Page</h1>
<form th:action="@{/guestbook/register}" th:method="post">
<div class="form-group">
<label>Title</label>
<input type="text" class="form-control" name="title" placeholder="Enter Title">
</div>
<div class="form-group">
<label>Content</label>
<textarea class="form-control" rows="5" name="content"></textarea>
</div>
<div class="form-group">
<label>Writer</label>
<input type="text" class="form-control" name="writer" placeholder="Enter Writer">
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</th:block>
</body>
</th:block>
</html>
3. 등록 구현 완료
4. 등록 완료 모달창 구현
반응형
'💻 my code archive > 🏷️JAVA & Spring(Boot)' 카테고리의 다른 글
스프링부트 공부기록(23) - 방명록 작성:: 게시물 검색 구현 (0) | 2022.03.18 |
---|---|
스프링부트 공부기록(22) - 방명록 작성:: 게시물 조회, 수정, 삭제 구현 (0) | 2022.03.18 |
[스프링부트 블로그 만들기] 시큐리티 적용X, 전통적인 방식 로그인 구현하기 (0) | 2022.03.17 |
[스프링부트 블로그 만들기] DB 격리 수준, 스프링부트 트랜잭션, JPA OSIV란? (0) | 2022.03.17 |
[스프링부트 블로그 만들기] ajax 통신, 회원가입 구현하기 (0) | 2022.03.17 |