10.1 회원 목록 구현
Ex) 관리자 페이지에서 회원 목록 구현하기
- list 파일 - 리스트 만들고 스타일을 적용한다.
- style: border-collapse: collapse (테이블 간격 없애기)
- 예를 들어, 테이블 안에 아래와 같은 방식으로 회원 데이터를 넣을 예정이다. (jpa로 가져오고 MyBatis를 이용할 것이다.)
<hide/>
<!doctype html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>관리자 화면</title>
<style>
.list table{
border-collapse: collapse;
}
.list table th, .list table td{
border: solid 1px #000;
}
</style>
</head>
<body>
<h1>관리자 회원 관리</h1>
<!-- <div th:replace="/fragments/layout.html :: fragment-body-menu" ></div>-->
<div>
<a href="/admin/main.do">관리자 메인</a>
|
<a href="/admin/member/list.do">회원 관리</a>
|
<a href="#">카테고리 관리</a>
|
<a href="#">강의 관리</a>
|
<a href="/member/logout">로그 아웃</a>
<br>
</div>
<div class="list">
<table>
<thead>
<tr>
<th>No</th>
<th>아이디(이메일)</th>
<th>이름</th>
<th>연락처</th>
<th>이메일 인증 여부</th>
<th>가입일</th>
<th>관리자 여부</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>goran@kakao.com</td>
<td>ran</td>
<td>010-0000-9999</td>
<td>y</td>
<td>2022.08.20</td>
<td>Y</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
Note) 실행 결과
Ex) MemberService에 메서드 추가
<hide/>
/**
* 회원 목록을 가져온다. - 관리자에서만 사용 가능
*/
List<Member> list();
- Impl 클래스 => list()의 반환형 => memberReposite.findAll() ....회원 정보를 모두 가져온다.
<hide/>
@Override
public List<Member> list() {
return memberRepository.findAll();
}
- 컨트롤러에서 가져온다.
-> final은 필수적으로 초기화를 해줘야하는데 생성자를 통해 초기화해줄 수 있다.(@RequiredArgs)
-> Model이란?
Model Interface - Spring
- Model객체는 컨트롤러에서 데이터를 생성해 이를 JSP, 즉 View에 전달하는 역할을 한다.
- HashMap형태를 가지며, Key - Value 값을 저장한다. (Servlet의 Request.setAttribute()와 비슷)
- Key는 String형태이다.
- AdminMemberCtrller
<hide/>
package com.zerobase.fastlms.admin;
import com.zerobase.fastlms.member.entity.Member;
import com.zerobase.fastlms.member.service.MemberService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import java.util.List;
@Controller
@RequiredArgsConstructor
public class AdminMemberController {
private final MemberService memberService;
@GetMapping("/admin/member/list.do")
public String list(Model model){
List<Member> members = memberService.list();
model.addAttribute("list", members);
return "admin/member/list";
}
}
Note) 실행 결과
- Json형식으로 데이터가 출력되는데 이를 표에 들어간 데이터 형태로 바꾸로 출력하도록 작성할 계획이다.
- ThymeLeaf - 뷰 엔진을 사용한다.
Ex)
- ThymeLeaf 문법을 이용한다.
- th:each는 자바의 for-each문과 비슷하다.
- th:if는 if문이 참일 때만 동작한다.
<hide/>
<!doctype html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>관리자 화면</title>
<style>
.list table{
border-collapse: collapse;
}
.list table th, .list table td{
border: solid 1px #000;
}
</style>
</head>
<body>
<h1>관리자 회원 관리</h1>
<!-- <div th:replace="/fragments/layout.html :: fragment-body-menu" ></div>-->
<div>
<a href="/admin/main.do">관리자 메인</a>
|
<a href="/admin/member/list.do">회원 관리</a>
|
<a href="#">카테고리 관리</a>
|
<a href="#">강의 관리</a>
|
<a href="/member/logout">로그 아웃</a>
<br>
</div>
<div class="list">
<table>
<thead>
<tr>
<th>No</th>
<th>아이디(이메일)</th>
<th>이름</th>
<th>연락처</th>
<th>이메일 인증 여부</th>
<th>가입일</th>
<th>관리자 여부</th>
</tr>
</thead>
<tbody>
<tr th:each="x : ${list}">
<td>1</td>
<td th:text="${x.getUserId()}"></td>
<td th:text="${x.getUserName()}"></td>
<td th:text="${x.getPhone()}"></td>
<td th:if="${x.emailAuthYn}">Y</td>
<td th:if="${x.emailAuthYn eq false}">N</td>
<td th:text="${x.getRegDt()}"></td>
<td th:if="${x.isAdminYn}">Y</td>
<td th:if="${x.isAdminYn eq false}">N</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
Note) 실행 결과
10.2 MyBatis 설정 및 쿼리 실행
전자정부 프레임워크
- 전자정부 표준프레임워크는 대한민국의 공공부문 정보화사업 시 플랫폼별 표준화된 개별 프레임워크를 말한다.
- Java는 사설 표준으로 업체가 자체적으로 프레임워크를 개발하고 적용하다보니 각 프레임워크의 구조와 수준 차이가 있어서 여러 가지 문제점이 있다.
- 최근에는 2008년 스프링 프레임워크 등 오픈소스를 기반으로 웹 사이트 개발 시 필요한 여러 가지 기능을 이미 구현해 놓았으며 최근에는 모바일 개발을 위한 프레임워크도 출시되었다.
- 데이터베이스 핸들링하는 부분은 MyBatis가 표준으로 되어있다. 가장 많이 사용되는 라이브러리이다.
Ex) MyBatis 세팅
<hide/>
<?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="com.zerobase.fastlms.admin.mapper.MemberMapper">
<select id="selectList" resultType="com.zerobase.fastlms.admin.dto.MemberDto">
select *
from member;
</select>
</mapper>
- pom.xml파일에 MyBatis를 추가한다.
- yml 파일에 다음 내용을 추가한다.
-> .xml 위치 설정
-> 데이터베이스는 언더바 표기법이 기본으로 되어 있는데 이를 카멜 표기법으로 바꾼다. 플러그인 설치해서 변경 가능
-> StdOutImpl: 화면에 바로 보여준다.
- https://mybatis.org/mybatis-3/ko/getting-started.html 사이트에 접속해서 "매핑된 SQL 구문 살펴보기"에 있는 코드를 가져온다.
-> MemberMapper.xml 파일을 만들고 데이터를 저장한다.
-> 샘플 코드에 namespace를 MemberMapper인터페이스의 패키지 주소로 바꾼다.
-> 그러면 namespace에 있는 내용(MemberMapper 인터페이스)이 xml 파일과 매칭된다.
- xml 파일의 resutlType을 위와 같이 MemberDto가 있는 주소로 바꾸면 자동으로 MemberDto에 값이 매핑된다.
- MemberDto 클래스 만들기 - xml파일과 매핑된다. (selectList()의 반환형 => Dto)
<hide/>
package com.zerobase.fastlms.admin;
import java.time.LocalDateTime;
@Data
public class MemberDto {
String userId;
String emailAuthKey;
String password;
String phone;
String userName;
String resetPasswordKey;
LocalDateTime regDt;
LocalDateTime emailAuthDt;
LocalDateTime resetPasswordLimitDt;
boolean emailAuthYn;
boolean adminYn;
}
-> 데이터베이스에 기존에 있던 데이터를 그대로 가져와서 변수명은 카멜 표기법으로 바꾼다.
-> Entity클래스인 Member는 JPA를 통해 생으로 데이터를 가져오는데 반해 MemberDto는 한 번 가공해서 다듬어진 데이터
-> 카멜 표기법으로 바꾸는 플러그인: String Manipulation
- MemberMapper
<hide/>
package com.zerobase.fastlms.admin.mapper;
import com.zerobase.fastlms.admin.dto.MemberDto;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper // 데이터베이스에 대해 쿼리를 실행 가능
public interface MemberMapper {
List<MemberDto> selectList(MemberDto memberDto);
}
-> @Mapper를 이용하면 데이터베이스를 이용해서 쿼리를 실행할 수 있다.
-> 리스트를 가져오는 메서드 selectList() 만든다.
-> xml파일에 SELECT로 member의 값을 모두 가져오는 쿼리 실행문이 있기 때문에 이를 MemberMapper 인터페이스에서 selectList() 를 구현해서 사용가능하다.
- Impl클래스 - list() 수정한다. (클래스 안에 memberMapper를 전역 변수로 선언)
<hide/>
@Override
public List<MemberDto> list() {
MemberDto parameter = new MemberDto();
List<MemberDto> list = memberMapper.selectList(parameter);
return list;
}
- 그러고나서 AdminMemberCtrller 클래스도 다음과 같이 수정
<hide/>
@GetMapping("/admin/member/list.do")
public String list(Model model){
List<MemberDto> members = memberService.list();
model.addAttribute("list", members);
return "admin/member/list";
}
Note) 실행 결과
- 아까는 JPA와 findAll() 메서드를 이용해서 다음과 같이 데이터 목록을 가져왔고 지금은 쿼리를 이용해서 데이터를 가져온 것이다.
- JPA는 객체를 매핑하면 자바가 자동으로 쿼리를 만들지만 MyBatis는 쿼리를 직접 작성 가능하다.
- xml 파일의 중간에 MySql을 이용하듯이 쿼리문을 넣을 수 있다.
10.3 회원 검색 기능 구현
Ex) 검색 기능 구현
- 관리자 페이지에서 검색 기능 추가한다.
-> <input>: 값을 입력하려면 쓰는 태그
-> <button>: 버튼 추가, 누르면 뭔가 실행된다. 변수 이름(name)은 있어도 되고 없어도 된다.
-> <select>: 옵션 리스트 중 하나만 고를 수 있는 기능이다.
-> <select>를 <form>으로 감싸야만 검색 버튼이 동작한다. form method="get"으로 지정해줘야 url에 값이 뜨는 걸 볼수 있다. 즉, 검색한 주소로 이동할 수 있도록 한다.
-> 주소 검색은 post가 아니라 get 방식으로 url 호출한다.
- 회원관리 창에서 사용자가 빈 칸에 데이터를 넣는다. 이 값을 어떻게 가져올까? => "param"이라는 객체 이용
- 검색 누르고 난 다음 화면, 상단 주소가 바뀐다. (근ㄷ)
cf) 다음을 출력하면?
<div th:text="${param}"></div>
- 결과
-> 즉, param을 이용해서 사용자가 검색한 값을 가지고 내 서버로 가져올 수 있다.
Ex) param 이용해서 객체 마다 유저 정보 나타내기
- ThymeLeaf 문자열 비교
- url로 넘어온 searchType과 searchValue에 대한 처리가 필요하다.
- type="search"로 해줘야한다.
<hide/>
<!doctype html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>관리자 화면</title>
<style>
.list table{
border-collapse: collapse;
}
.list table th, .list table td{
border: solid 1px #000;
}
</style>
</head>
<body>
<h1>관리자 회원 관리</h1>
<!-- <div th:replace="/fragments/layout.html :: fragment-body-menu" ></div>-->
<div>
<a href="/admin/main.do">관리자 메인</a>
|
<a href="/admin/member/list.do">회원 관리</a>
|
<a href="#">카테고리 관리</a>
|
<a href="#">강의 관리</a>
|
<a href="/member/logout">로그 아웃</a>
<br>
<hr/>
</div>
<div class="list">
<div>
<form method="get">
<select name="searchType">
<option value="all">전체</option>
<option th:selected="${#strings.equals(param.searchType, 'userId')}" value="userId">아이디</option>
<option th:selected="${#strings.equals(param.searchType, 'userName')}" value="userName">이름</option>
<option th:selected="${#strings.equals(param.searchType, 'phone')}" value="phone">연락처</option>
</select>
<input th:value="${param.searchValue}" type="search" name="searchValue" placeholder="검색어 입력"/>
<button type="submit">검색</button>
</form>
</div>
<table>
<thead>
<tr>
<th>No</th>
<th>아이디(이메일)</th>
<th>이름</th>
<th>연락처</th>
<th>이메일 인증 여부</th>
<th>가입일</th>
<th>관리자 여부</th>
</tr>
</thead>
<tbody>
<tr th:each="x : ${list}">
<td>1</td>
<td th:text="${x.getUserId()}"></td>
<td th:text="${x.getUserName()}"></td>
<td th:text="${x.getPhone()}"></td>
<td th:if="${x.emailAuthYn}">Y</td>
<td th:if="${x.emailAuthYn eq false}">N</td>
<td th:text="${x.getRegDt()}"></td>
<td th:if="${x.isAdminYn}">Y</td>
<td th:if="${x.isAdminYn eq false}">N</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
- 와이파이에서 SearchWifi 만든 것처럼 여기서도 MemberParam을 만든다.
-> 관리자 컨트롤러 수정
-> impl 메서드 수정한다.
-> 그 외에도 list와 관련한 문제들에 대해 모두 MemberParam으로 바꿔준다.
<hide/>
package com.zerobase.fastlms.admin.model;
import lombok.Data;
@Data
public class MemberParam {
String searchType;
String searchValue;
}
List<MemberDto> list(MemberParam memberParam);
cf) https://mybatis.org/mybatis-3/ko/dynamic-sql
- choose, when, otherwise - 참고용 코드
<hide/>
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG WHERE state = ‘ACTIVE’
<choose>
<when test="title != null">
AND title like #{title}
</when>
<when test="author != null and author.name != null">
AND author_name like #{author.name}
</when>
<otherwise>
AND featured = 1
</otherwise>
</choose>
</select>
- xml 파일의 쿼리 수정한다. MemberMapper에서 가져온 변수는 #{}로 감싸준다.
-> namsspace로 지정된 MemberMapper에 대해 그 안에 있는 변수 searchType, searchValue를 가져와서 쓸 수 있다.
-> 마이바티스로 동적 쿼리를 만든다. 홈페이지의 코드를 가져온다.
-> otherwise는 옵션 전체/아이디/이름/연락처 중에서 전체를 선택한 경우이다.
-> when, otherwise 구문 안은 and로 시작한다.
<hide/>
<?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="com.zerobase.fastlms.admin.mapper.MemberMapper">
<select id="selectList"
parameterType="com.zerobase.fastlms.admin.model.MemberParam"
resultType="com.zerobase.fastlms.admin.dto.MemberDto">
SELECT *
FROM member
WHERE 1 = 1
<if test="searchValue != null and searchType != null">
<choose>
<when test="searchType == 'userId'">
and user_id like concat('%', #{searchValue}, '%')
</when>
<when test="searchType == 'userName'">
and user_name like concat('%', #{searchValue}, '%')
</when>
<when test="searchType == 'phone'">
and phone like concat('%', #{searchValue}, '%')
</when>
<otherwise>
and( // 셋 중 하나 만족하면 된다.
user_id like concat('%', #{searchValue}, '%')
or
user_name like concat('%', #{searchValue}, '%')
or
phone like concat('%', #{searchValue}, '%')
)
</otherwise>
</choose>
</if>
</select>
</mapper>
========================================오류 ========================================
- 오류: url에 아래 처럼 나와야 하는데 searchType에 대한 부분이 나타나지 않았다.
http://localhost:8080/admin/member/list.do?searchType=userName&searchValue="입력값"
- 원인: html 파일의 <input> 안에 type을"text"가 아닌 "search"을 선택해야 두 개의 매개 변수로 검색하고 그 다음 자동으로 url에 변수명과 리터럴이 들어간다.
-> type을 search로 주면 검색창에 x버튼도 나온다.
<input th:value="${param.searchValue}" type="search" name="searchValue" placeholder="검색어 입력"/>
Ex) 검색 form을 오른쪽으로 이동하려면?
- list안에 <div class="search-form">.. 이렇게 키워드를 붙여준다.
-> <div class="list"> 안에 <div class="search-form">도 있고 테이블도 있다. padding을 주면 간격 조정된다.
<div class="search-form">
- CSS 태그 안에 다음과 같이 추가한다.
-> 위치를 오른쪽으로하고 , padding: 다른 데이터와의 간격을 뜻한다. top => right => bottom => left 순서대로 값을 입력한다.
-> top, bottom에만 여백을 지정한다.
<hide/>
.search-form {
padding: 5px 0 10px 0;
text-align: right;
}
Note) 실행 결과
10.4 회원 목록 페이징 처리
Ex) 페이징 처리를 하려면?
- 데이터의 총 개수가 필요하다. => totalCnt
- AdiminMemCtrl에 Paging 내용 추가한다.
-> pageIndex라는 값을 MemberParam에서 받아올 수 있도록 MemberParam에 새로운 변수를 추가한다. (pageIndex)
-> pager()의 반환값을 모델에 담는다.
<hide/>
package com.zerobase.fastlms.admin;
import com.zerobase.fastlms.admin.dto.MemberDto;
import com.zerobase.fastlms.admin.model.MemberParam;
import com.zerobase.fastlms.member.entity.Member;
import com.zerobase.fastlms.member.service.MemberService;
import com.zerobase.fastlms.util.PageUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
@Controller
@RequiredArgsConstructor
public class AdminMemberController {
private final MemberService memberService;
@GetMapping("/admin/member/list.do")
public String list(Model model, MemberParam parameter){
List<MemberDto> members = memberService.list(parameter);
model.addAttribute("list", members);
int totalCount = 0;
if(members != null){
totalCount = members.size();
}
String queryString = "";
PageUtil pageUtil = new PageUtil(totalCount, parameter.getPageIndex(), queryString);
model.addAttribute("pager", pageUtil.pager()); // 데이터를 반환
return "admin/member/list";
}
}
cf) th:utext
- th.text는 출력할 문자열에 태그가 포함된 경우, 태그를 반영하지 않고 문자 그대로 출력한다.
- 태그 형식의 코드를 삽입하려면 text대신 utext를 사용한다.
- pager값을 list에서 사용한다. 테이블 밑에 아래와 같이 추가한다.
<div class="paper" th:utext="${pager}"></div>
Note) 실행 결과
- 어떤 페이지를 넣어도 다음과 같이 전체 데이터가 다 나온다.
- 이를 10개씩만 나오도록 하려면 어떻게 해야할까?
Ex) 페이지마다 리스트가 10개 씩만 나오도록 구현하기
- xml 파일에 내용 추가, 항상 실행되도록 하기 위해 WHERE 1 = 1을 넣는다.
-> 기존의 쿼리를 복사하고 '*'만 => 'COUNT(*)'로 바꾼다. 반환형은 long타입.
-> 실행하려면 Mapper가 필요하다. MemberMapper 인터페이스에 추가한다.
<hide/>
<?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="com.zerobase.fastlms.admin.mapper.MemberMapper">
<select id="selectListCount"
parameterType="com.zerobase.fastlms.admin.model.MemberParam"
resultType="long">
SELECT COUNT(*)
FROM member
WHERE 1 = 1
<if test="searchValue != null and searchType != null">
<choose>
<when test="searchType == 'userId'">
and user_id like concat('%', #{searchValue}, '%')
</when>
<when test="searchType == 'userName'">
and user_name like concat('%', #{searchValue}, '%')
</when>
<when test="searchType == 'phone'">
and phone like concat('%', #{searchValue}, '%')
</when>
<otherwise>
and
(
user_id like concat('%', #{searchValue}, '%')
or
user_name like concat('%', #{searchValue}, '%')
or
phone like concat('%', #{searchValue}, '%')
)
</otherwise>
</choose>
</if>
</select>
<select id="selectList"
parameterType="com.zerobase.fastlms.admin.model.MemberParam"
resultType="com.zerobase.fastlms.admin.dto.MemberDto">
SELECT *
FROM member
WHERE 1 = 1
<if test="searchValue != null and searchType != null">
<choose>
<when test="searchType == 'userId'">
and user_id like concat('%', #{searchValue}, '%')
</when>
<when test="searchType == 'userName'">
and user_name like concat('%', #{searchValue}, '%')
</when>
<when test="searchType == 'phone'">
and phone like concat('%', #{searchValue}, '%')
</when>
<otherwise>
and(
user_id like concat('%', #{searchValue}, '%')
or
user_name like concat('%', #{searchValue}, '%')
or
phone like concat('%', #{searchValue}, '%')
)
</otherwise>
</choose>
</if>
LIMIT 0, 10
</select>
</mapper>
- Dto에 전체 데이커의 개수를 뜻하는 속성 totalCount 추가
<hide/>
package com.zerobase.fastlms.admin.dto;
import lombok.Data;
import java.time.LocalDateTime;
@Data
public class MemberDto {
String userId;
String emailAuthKey;
String password;
String phone;
String userName;
String resetPasswordKey;
LocalDateTime regDt;
LocalDateTime emailAuthDt;
LocalDateTime resetPasswordLimitDt;
boolean emailAuthYn;
boolean adminYn;
// 추가 컬럼
long totalCount;
}
- Impl
-> CollectionUtil.isEmpty(list)
-> 모든 데이터에 대해 totalCnt값을 하나씩 저장한다.
<hide?>
@Override
public List<MemberDto> list(MemberParam parameter) {
long totalCount = memberMapper.selectListCount(parameter);
List<MemberDto> list = memberMapper.selectList(parameter);
if(!CollectionUtils.isEmpty(list)){
for(MemberDto x : list){
x.setTotalCount(totalCount); // 전체 개수를 하나씩 다 넣어준다.
}
}
return list;
}
- 컨트롤러
->members에 값이 들어오면 사이즈 측정 가능
======================================== 오류 ========================================
- 오류: 회원관리 창이 안 뜬다.
- 원인: SQL 문법 오류 - xm 파일에 <select> 태그에 '>'를 하나 더 붙여서 틀렸다.
Note) 실행 결과 - 정상
- 이제 여기서 페이지마다 1 ~ 10, 11~20, .. 이런식으로 데이터가 나오도록 구현해야한다.
Ex) 페이지 인덱스 구현
- MemberParam에 시작 번호와 끝 번호를 구하는 메서드를 구하면 이를 MemberMapper에서 사용가능하다.
<hide/>
package com.zerobase.fastlms.admin.model;
import lombok.Data;
@Data
public class MemberParam {
long pageIndex;
long pageSize;
String searchType;
String searchValue;
public long getPageStart() {
init();
return (pageIndex - 1) * pageSize;
}
public long getPageEnd() {
init();
return pageSize;
}
public void init() {
if (pageIndex < 1) {
pageIndex = 1;
}
if (pageSize < 10) {
pageSize = 10;
}
}
}
- MemberMapper
-> MemberParam에서 변수와 메서드를 만들었기 때문에 MemberMapper에서 변수 이름을 사용 가능하다.
-> </select>와 </if> 사이에 LIMIT #{pageStart}, #{pageEnd}
<hide/>
<?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="com.zerobase.fastlms.admin.mapper.MemberMapper">
<select id="selectListCount"
parameterType="com.zerobase.fastlms.admin.model.MemberParam"
resultType="long">
SELECT COUNT(*)
FROM member
WHERE 1 = 1
<if test="searchValue != null and searchType != null">
<choose>
<when test="searchType == 'userId'">
and user_id like concat('%', #{searchValue}, '%')
</when>
<when test="searchType == 'userName'">
and user_name like concat('%', #{searchValue}, '%')
</when>
<when test="searchType == 'phone'">
and phone like concat('%', #{searchValue}, '%')
</when>
<otherwise>
and
(
user_id like concat('%', #{searchValue}, '%')
or
user_name like concat('%', #{searchValue}, '%')
or
phone like concat('%', #{searchValue}, '%')
)
</otherwise>
</choose>
</if>
</select>
<select id="selectList"
parameterType="com.zerobase.fastlms.admin.model.MemberParam"
resultType="com.zerobase.fastlms.admin.dto.MemberDto">
SELECT *
FROM member
WHERE 1 = 1
<if test="searchValue != null and searchType != null">
<choose>
<when test="searchType == 'userId'">
and user_id like concat('%', #{searchValue}, '%')
</when>
<when test="searchType == 'userName'">
and user_name like concat('%', #{searchValue}, '%')
</when>
<when test="searchType == 'phone'">
and phone like concat('%', #{searchValue}, '%')
</when>
<otherwise>
and(
user_id like concat('%', #{searchValue}, '%')
or
user_name like concat('%', #{searchValue}, '%')
or
phone like concat('%', #{searchValue}, '%')
)
</otherwise>
</choose>
</if>
LIMIT #{pageStart} , #{pageEnd}
</select>
</mapper>
Note) 실행 결과 - 3 페이지 누른 화면
Ex) 데이터 전체 개수 totalCount 구하는 방법
- list파일에 변수 total-count를 추가한다. (MemberDto에 totalCount, userId, .. 변수가 있다.)
<p calss="total-count"><span th:text="${totalCount}"></span>개</p>
- 컨트롤러
-> 모델에 addAttribute()를 해줘야 list 파일에서 totalCount 조회 가능하다.
<hide/>
@GetMapping("/admin/member/list.do")
public String list(Model model, MemberParam parameter){
parameter.init(); // 유효한 값이 되도록 만든다.
List<MemberDto> members = memberService.list(parameter); // 값이 저장되면 토탈카운트가 존재한다.
long totalCount = 0;
if(members != null && members.size() > 0){
totalCount = members.get(0).getTotalCount();
}
String queryString = "";
PageUtil pageUtil = new PageUtil(totalCount, parameter.getPageSize(), parameter.getPageIndex(), queryString);
model.addAttribute("list", members);
model.addAttribute("totalCount", totalCount); // 데이터를 반환
model.addAttribute("pager", pageUtil.pager()); // 데이터를 반환
return "admin/member/list";
}
Note) 실행 결과
Ex) 전체 개수 출력하기
- 아래 코드를 추가한다.
-> pointer-position: absolute (절대 위치 지정)
<p class="total-count">전체 <span th:text="${totalCount}"></span>개</p>
.search-form .total-count{
position-position: absolute;
left: 0; top: 0;
height: 20px;
float: left;
}
Note) 실행 결과
Ex) pager(페이지 번호 목록)를 가운데 배치하고 간격 늘리기
- a.on은 특정 페이지 번호가 눌리고 나서 그에대한 화면을 보여주고 있는 것을 뜻한다.
<hide/>
.paper{
margin-top: 10px;
text-align: center;
}
.paper a.on{
font-weight: bold;
color: red;
}
Note) 실행 결과
Ex) 테이블에 인덱스 번호 넣기(전체 개수 => 1)
- Dto에 seq 추가한다.
long seq;
- impl 클래스
<hide/>
@Override
public List<MemberDto> list(MemberParam parameter) {
long totalCount = memberMapper.selectListCount(parameter);
List<MemberDto> list = memberMapper.selectList(parameter);
if(!CollectionUtils.isEmpty(list)){
int i = 0;
for(MemberDto x : list){
x.setTotalCount(totalCount); // 전체 개수를 하나씩 다 넣어준다.
x.setSeq(totalCount - parameter.getPageStart() - i);
++i;
}
}
return list;
}
- list => 1을 안 넣어도 똑같이 실행된다.
<td th:text="${x.seq}">1</td>
Note) 실행 결과
Ex) 검색한 데이터를 유지하면서 페이지 넘기기
- 그런데 지금 문제는 검색한 다음의 조회 페이지이다. 아래 화면에서 2번 페이지를 누르면?
- 아래와 같이 검색한 게 풀리고 전체 데이터에 대한 2 페이지 값이 나온다. 번호도 틀린다.
- 컨트롤러
<hide/>
@GetMapping("/admin/member/list.do")
public String list(Model model, MemberParam parameter){
parameter.init(); // 유효한 값이 되도록 만든다.
List<MemberDto> members = memberService.list(parameter); // 값이 저장되면 토탈카운트가 존재한다.
long totalCount = 0;
if(members != null && members.size() > 0){
totalCount = members.get(0).getTotalCount();
}
String queryString = parameter.getQueryString();
PageUtil pageUtil = new PageUtil(totalCount, parameter.getPageSize(), parameter.getPageIndex(), queryString);
model.addAttribute("list", members);
model.addAttribute("totalCount", totalCount); // 데이터를 반환
model.addAttribute("pager", pageUtil.pager()); // 데이터를 반환
return "admin/member/list";
}
- getQueryString() 메서드
<hide/>
public String getQueryString() {
init();
StringBuilder sb = new StringBuilder();
if(searchType != null && searchType.length() > 0){
sb.append(String.format("searchType=%s", searchType));
}
if(searchValue != null && searchValue.length() > 0){
if(sb.length() > 0){
sb.append("&");
}
sb.append(String.format("searchValue=%s", searchValue));
}
return sb.toString();
}
Note) 실행 결과 - 정상적으로 실행된다.
- 페이지를 넘어가도 전체 개수가 변하지 않고 검색된 결과가 유지된다.
'Spring Projcect > 학습 관리 시스템 & 백오피스 구축' 카테고리의 다른 글
Chapter 12. 카테고리 화면 (0) | 2022.08.22 |
---|---|
Chapter 11. 회원 상세 및 상태 처리 (0) | 2022.08.21 |
Chapter 09. 관리자 로그인 구현 (0) | 2022.08.20 |
Chapter 08. 스프링 부트 프로젝트 - 비밀번호 찾기(초기화) (0) | 2022.08.18 |
Chapter 07. 스프링 부트 프로젝트 - 로그인/로그아웃 (0) | 2022.08.18 |