일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 스프링 게시판 구현
- Bcrypt
- 스프링 HikariCP
- 스프링 업로드
- 스프링 프로젝트
- 스프링 메일 전송
- 로그아웃 기능 구현
- 스프링 프로젝트 기본 설정
- 스프링 이미지
- spring 프로젝트
- 스프링 포트폴리오
- 스프링 프로젝트 설정
- 스프링 쇼핑몰 프로젝트
- 파일 업로드
- ResponseEntity
- arraylist
- BCrypt 적용
- 쇼핑몰 프로젝트
- 삭제 구현
- oracle 설치방법
- 스프링 파일 삭제
- 스프링 쇼핑몰
- 정규표현식
- 이미지 출력
- 로그인 기능
- 인증번호 전송
- 스프링 게시판
- spring 쇼핑몰
- 쇼핑몰 포트폴리오
- 회원가입 기능
- Today
- Total
Kim VamPa
[Spring][쇼핑몰 프로젝트][15] 작가목록 기능 구현 - 3 본문
프로젝트 Github : https://github.com/sjinjin7/Blog_Project
프로젝트 포스팅 색인(index) : https://kimvampa.tistory.com/188
목표
페이지 이동 인터페이스 구현
사용자가 클릭을 통해 이동할 수 있도록 해주는 '페이지 이동 인터페이스' 구현을 목표로 합니다. 이번 포스팅 또한 진행 위주로 작성합니다. 페이지 이동 인터페이스 구현에 대한 자세한 설명은 아래의 포스팅을 참고해주세요.
[스프링 게시판][6] 페이징 기능 구현(페이지 이동 인터페이스) -1
[스프링 게시판][6] 페이징 기능 구현(페이지 이동 인터페이스) -2
순서
1. PageDTO 클래스 작성
2. 전체 데이터 개수(total)
3. Controller 작업
4. View 처리
1. PageDTO 클래스 작성
com.vam.model 패키지에 PageDTO 클래스를 생성후 아래의 변수, 생성자를 작성합니다. PageDTO 클래스의 데이터들은 '페이지 이동 인터페이스'를 출력시키는데 필요로 한 데이터들의 모임입니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
/* 페이지 시작 번호 */
private int pageStart;
/* 페이지 끝 번호 */
private int pageEnd;
/* 이전, 다음 버튼 존재 유무 */
private boolean next, prev;
/* 행 전체 개수 */
private int total;
/* 현재페이지 번호(pageNum), 행 표시 수(amount), 검색 키워드(keyword), 검색 종류(type) */
private Criteria cri;
/* 생성자(클래스 호출 시 각 변수 값 초기화) */
public PageDTO(Criteria cri, int total) {
/* cri, total 초기화 */
this.cri = cri;
this.total = total;
/* 페이지 끝 번호 */
this.pageEnd = (int)(Math.ceil(cri.getPageNum()/10.0))*10;
/* 페이지 시작 번호 */
this.pageStart = this.pageEnd - 9;
/* 전체 마지막 페이지 번호 */
int realEnd = (int)(Math.ceil(total*1.0/cri.getAmount()));
/* 페이지 끝 번호 유효성 체크 */
if(realEnd < pageEnd) {
this.pageEnd = realEnd;
}
/* 이전 버튼 값 초기화 */
this.prev = this.pageStart > 1;
/* 다음 버튼 값 초기화 */
this.next = this.pageEnd < realEnd;
}
|
선언된 변수들에 대한 getter()/setter(), toString() 메서드를 추가 해줍니다.
2. 전체 데이터 개수(total)
PageDTO 클래스를 정의하였는데 해당 클래스를 인스턴스화 시키기 위해서는 Criteria 클래스의 데이터와 전체 데이터 개수(total) 값이 필요로 합니다. 왜냐하면 두 개의 데이터를 PageDTO 클래스 생성자 파라미터로 부여했기 때문입니다.
Criteria 클래스는 이미 정의되어 있기도 하고 PageDTO클래스를 사용할 url 매핑 메서드인 authorManageGET()은 뷰로부터 Criteria 클래스 데이터를 받아오기 때문에 전체 데이터 개수(total)에 대한 값만 구해주면 됩니다.
total의 값은 vam_author 테이블의 총 행의 개수입니다. 따라서 vam_author 테이블의 행의 총개수를 구해주는 쿼리를 작성하고, 해당 쿼리를 실행을 하는 메서드(Mapper, Service 단계)를 작성하는 작업을 진행하고자 합니다.
1) AuthorMapper.java 인터페이스
vam_author 테이블의 총 행의 개수를 구하는 쿼리를 호출하는 메서드를 선언합니다. 총 개수 값을 반환받아야 하기 때문에 메서드 선언부의 리턴 타입은 int입니다.
그리고 조건문에 사용할 'keyword' 데이터를 전달받기 위해 파라미터로 Criteria 클래스를 부여하였습니다.
1
2
3
4
|
/* 작가 총 수 */
public int authorGetTotal(Criteria cri);
|
2) AuthorMapper.xml 인터페이스
Mapper 인터페이스에서 선언한 메서드가 실행할 쿼리를 작성합니다.
총개수를 구하는 것이기 때문에 count(*)을 사용하였습니다. 더불어 authorGetList() 쿼리에서 적용되는 조건문(where문)을 같이 작성해주어야 합니다. 왜냐하면 검색조건에 따라 페이지 개수가 변해야 하는데 조건문을 적용해주지 않는다면 뷰(view)에 출력되는 '페이지 이동 인터페이스'에 실제 존재해야 할 페이지 개수보다 더많은 페이지 번호가 출력되기 때문입니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
<!-- Oracle -->
<!-- 작가 수 -->
<select id="authorGetTotal" resultType="int">
select count(*) from vam_author
<if test="keyword != null">
where authorname like '%' || #{keyword} || '%'
</if>
</select>
<!-- MySQL -->
<!-- 작가 수 -->
<select id="authorGetTotal" resultType="int">
select count(*) from vam_author
<if test="keyword != null">
where authorname like concat('%', #{keyword}, '%');
</if>
</select>
|
3) AuthorMapper 메서드 테스트
AuthorMapperTests.java에서 작성한 Mapper 메서드가 정상적으로 동작하는지 junit 테스트를 합니다.
4) Service 작성
AuthorService.java에 앞서 작성한 Mapper 메서드를 호출한 메서드를 선언합니다.
1
2
3
4
|
/* 작가 총 수 */
public int authorGetTotal(Criteria cri) throws Exception;
|
AuthorServiceImpl.java에 오버라이딩하여 인터페이스에서 선언한 메서드의 구현부를 작성합니다.
1
2
3
4
5
6
7
8
|
/* 작가 총 수 */
@Override
public int authorGetTotal(Criteria cri) throws Exception {
log.info("(service)authorGetTotal()......." + cri);
return authorMapper.authorGetTotal(cri);
}
|
3. Controller 작업
total의 값을 얻기 위해 AuthorService 클래스의 authorGetTotal()을 호출한 후 해당 값과 Critera 클래스 데이터를 인자 값으로 부여하여 PageDTO를 인스턴스화 시킵니다.
1
2
3
4
5
6
|
/* 페이지 이동 인터페이스 데이터 */
int total = authorService.authorGetTotal(cri);
PageDTO pageMaker = new PageDTO(cri, total);
|
addAttribute()을 사용하여 "pageMaker" 속성명에 인스턴스 화한 PageDTO 데이터를 저장시킵니다.
1
2
3
4
5
6
7
8
|
/* 페이지 이동 인터페이스 데이터 */
int total = authorService.authorGetTotal(cri);
PageDTO pageMaker = new PageDTO(cri, total);
model.addAttribute("pageMaker", pageMaker);
|
쉽게 이해할 수 있도록 매번 변수에 저장하도록 코드를 작성하였지만 아래와 같이 한 줄의 코드로 표현해도 상관없습니다.
1
2
3
4
|
/* 페이지 이동 인터페이스 데이터 */
model.addAttribute("pageMaker", new PageDTO(cri, authorService.authorGetTotal(cri)));
|
4. View 처리
서버로부터 전달받은 "pageMaker" 데이터를 활용하여 '페이지 이동 인터페이스'를 구현합니다. class 속성 값이 "author_table_wrap"인 <div> 태그 바로 다음 순서에 아래의 코드를 추가해줍니다. ( 코드를 읽어보고 이해가 잘 안 되신다면 "[스프링 게시판][6] 페이징 기능 구현(페이지 이동 인터페이스) -1"를 참고해주세요.)
<!-- 페이지 이동 인터페이스 영역 -->
<div class="pageMaker_wrap" >
<ul class="pageMaker">
<!-- 이전 버튼 -->
<c:if test="${pageMaker.prev}">
<li class="pageMaker_btn prev">
<a href="${pageMaker.pageStart - 1}">이전</a>
</li>
</c:if>
<!-- 페이지 번호 -->
<c:forEach begin="${pageMaker.pageStart}" end="${pageMaker.pageEnd}" var="num">
<li class="pageMaker_btn ${pageMaker.cri.pageNum == num ? "active":""}">
<a href="${num}">${num}</a>
</li>
</c:forEach>
<!-- 다음 버튼 -->
<c:if test="${pageMaker.next}">
<li class="pageMaker_btn next">
<a href="${pageMaker.pageEnd + 1 }">다음</a>
</li>
</c:if>
</ul>
</div>
<li> 태그 class 속성 값에 '${pageMaker.cri.pageNum == num?"active":"" '을 작성한 이유는 현재 페이지일 경우 class 속성 값이 "pageMaker_btn active"되는데 해당 버튼에 현재 페이지임을 알 수 있도록 css 설정을 해주기 위함입니다.
<a> 태그의 href 속성 값으로 url 경로를 작성하지 않았습니다. href속성 값에 url 경로를 삽입할 경우 "/admin/authorManage? pageNum=${num}&amount=10"와 같이 쿼리스트링을 통해서 필요 데이터 값을 직접 작성해주면 됩니다. 하지만 좀 더 다양한 상황에서 유연하게 명령을 처리할 수 있도록 <form> 태그 내부 <input>태그에 필요 데이터를 저장하고 Javascript 코드를 통해서 버튼의 동작과 <form>태그 안의 데이터를 서버에 전송할 수 있도록 하고자 합니다.
위에서 작성한 <div> 태그 바로 다음칸에 아래의 <form> 태그 코드를 추가해줍니다.
- authorMange() 메서드에서 필요로 한 데이터를 <input> 태그에 저장시켰습니다.
- 페이지 이동 후 서버로부터 전달받은 "pageMaker" 데이터에 있는 pageNum, amount, keyword 값이 기본적으로 저장되도록 value 속성을 부여하였습니다.
<form id="moveForm" action="/admin/authorManage" method="get">
<input type="hidden" name="pageNum" value="${pageMaker.cri.pageNum}">
<input type="hidden" name="amount" value="${pageMaker.cri.amount}">
<input type="hidden" name="keyword" value="${pageMaker.cri.keyword}">
</form>
페이지 이동 버튼이 동작하도록 <script> 태그 내에 아래의 JS코드를 추가합니다.
1
2
3
4
5
6
7
8
9
10
11
12
|
let moveForm = $('#moveForm');
/* 페이지 이동 버튼 */
$(".pageMaker_btn a").on("click", function(e){
e.preventDefault();
moveForm.find("input[name='pageNum']").val($(this).attr("href"));
moveForm.submit();
|
let moveForm 변수를 선언한 이유는 <form> 태그 호출을 용이하게 하기 위함입니다.
메서드의 내용은 다음과 같습니다. '숫자 버튼'을 누르게 되면 <a> 태그의 동작을 멈추고, <a> 태그에 저장된 href속성 값을 <form> 태그의 내부에 있는 pageNum <input> 태그 값으로 저장을 시킨 뒤 <fomr> 태그 속성에 설정되어 있는 url 경로와 method 방식으로 form을 서버로 전송합니다.
뷰(view)에 출력되는 '페이지 이동 인터페이스'를 꾸며주기 위해 아래의 css코드를 authorManage.css 파일에 추가하였습니다.
/* 페이지 버튼 인터페이스 */
.pageMaker_wrap{
text-align: center;
margin-top: 30px;
margin-bottom: 40px;
}
.pageMaker_wrap a{
color : black;
}
.pageMaker{
list-style: none;
display: inline-block;
}
.pageMaker_btn {
float: left;
width: 40px;
height: 40px;
line-height: 40px;
margin-left: 20px;
}
.next, .prev {
border: 1px solid #ccc;
padding: 0 10px;
}
.next a, .prev a {
color: #ccc;
}
.active{ /* 현재 페이지 버튼 */
border : 2px solid black;
font-weight:400;
}
구현한 페이지 이동 버튼을 클릭하여 페이지 이동이 정상적으로 되는지 확인합니다.
REFERENCE
DATE
- 2020.03.12
'스프링 프레임워크 > 쇼핑몰 프로젝트' 카테고리의 다른 글
[Spring][쇼핑몰 프로젝트][15] 작가목록 기능 구현 - 4 (1) | 2021.03.15 |
---|---|
[스프링]쇼핑몰 프로젝트 색인(index) (6) | 2021.03.12 |
[Spring][쇼핑몰 프로젝트][15] 작가목록 기능 구현 - 2 (0) | 2021.03.11 |
[Spring][쇼핑몰 프로젝트][15] 작가목록 기능 구현 - 1 (0) | 2021.03.10 |
[Spring][쇼핑몰 프로젝트][14] 작가등록 기능 구현 - 3 (0) | 2021.02.10 |