Spring
240304 스프링 프로젝트
코딩하는딩굴
2024. 3. 4. 10:16
관리자 페이지 만들기
Admin 의 Controller, Service, Repository 만들기
@Controller
@RequestMapping("/admin")
public class AdminController extends AbstractController{
@Resource(name="adminService")
private AdminService adminService;
@GetMapping("/index")
public String index() {
return "admin/index";
}
@GetMapping("/boardList")
public String boardList(@RequestParam(value = "page", required = false, defaultValue = "1") String no, Model model) {
int totalRecordCount = adminService.totalRecordCount();
int page = util.str2Int2(no);
PaginationInfo paginationInfo = new PaginationInfo();
paginationInfo.setCurrentPageNo(page); // 현재 페이지 번호
paginationInfo.setRecordCountPerPage(15); // 한 페이지에 게시되는 게시글 건수
paginationInfo.setPageSize(10); // 페이지 리스트 사이즈
paginationInfo.setTotalRecordCount(totalRecordCount); // 총 페이지 수
model.addAttribute("list", adminService.boardList(paginationInfo.getFirstRecordIndex()));
model.addAttribute("paginationInfo", paginationInfo);
model.addAttribute("page", page);
return "admin/boardList";
}
RequestMapping 을 넣으면 /admin 이 고정으로 들어간다고 함
GetMapping 에서 /admin/index 와 RequestMapping 에 /admin 을 넣고 /index 한 것과 같은 효과
@Service("adminService")
public class AdminService {
@Autowired
private AdminRepository adminRepository;
public List<BoardDTO> boardList(int page) {
return adminRepository.boardList(page);
}
@Repository
public class AdminRepository {
@Autowired
private SqlSession sqlSession;
public List<BoardDTO> boardList(int page) {
return sqlSession.selectList("admin.boardList", page);
}
public int totalRecordCount() {
return sqlSession.selectOne("admin.totalRecordCount");
}
Mapper 설정
<mapper namespace="admin">
<select id="boardList" parameterType="Integer" resultType="boardDTO">
select board_no, board_title, mname, board_date, board_del
from board join member on board.mno = member.mno
order by board_no desc
limit #{page}, 15
</select>
<select id="totalRecordCount" resultType="Integer">
select count(*) from board
</select>
BoardList.jsp 를 만들어서 글 전체 띄우기
<div class="tableDiv d-flex justify-content-center align-items-center">
<table class="table text-center">
<thead>
<tr>
<th class="">번호</th>
<th class="">제목</th>
<th class="">글쓴이</th>
<th class="">작성일</th>
<th class="">삭제여부</th>
</tr>
</thead>
<tbody>
<c:forEach items="${list }" var="list">
<tr>
<td>${list.board_no }</td>
<td>${list.board_title }</td>
<td>${list.mname }</td>
<td>${list.board_date }</td>
<td>
<c:choose>
<c:when test="${list.board_del eq 1}">
<i class="fas fa-fw fa-regular fa-eye"></i>
</c:when>
<c:otherwise>
<i class="fas fa-fw fa-regular fa-eye-slash"></i>
</c:otherwise>
</c:choose>
</td>
</tr>
</c:forEach>
</tbody>
</table>
</div>
Comments 도 똑같이 진행
@GetMapping("/comments")
public String comments(@RequestParam(value = "page", required = false, defaultValue = "1") String no, Model model) {
int totalRecordCount = adminService.totalCommentRecordCount();
int page = util.str2Int2(no);
PaginationInfo paginationInfo = new PaginationInfo();
paginationInfo.setCurrentPageNo(page); // 현재 페이지 번호
paginationInfo.setRecordCountPerPage(15); // 한 페이지에 게시되는 게시글 건수
paginationInfo.setPageSize(10); // 페이지 리스트 사이즈
paginationInfo.setTotalRecordCount(totalRecordCount); // 총 페이지 수
model.addAttribute("list", adminService.commentList(paginationInfo.getFirstRecordIndex()));
model.addAttribute("paginationInfo", paginationInfo);
model.addAttribute("page", page);
return "admin/comments";
}
// Service
public int totalCommentRecordCount() {
return adminRepository.totalCommentRecordCount();
}
public List<CommentDTO> commentList(int firstRecordIndex) {
return adminRepository.commentList(firstRecordIndex);
}
// Repository
public int totalCommentRecordCount() {
return sqlSession.selectOne("admin.totalCommentRecordCount");
}
public List<CommentDTO> commentList(int page) {
return sqlSession.selectList("admin.commentList", page);
}
<select id="totalCommentRecordCount" resultType="Integer">
select count(*) from comment
</select>
<!-- DB 에 있는 데이터와 DTO 의 값 매핑시키기 -->
<resultMap type="commentDTO" id="commentDTOmap">
<result column="cno" property="no" />
<result column="ccomment" property="comment" />
</resultMap>
<select id="commentList" parameterType="Integer" resultMap="commentDTOmap">
select cno, board_no, mname, ccomment, cdate, clike, cdel
from comment join member on comment.mno = member.mno
order by cno desc
limit #{page}, 15
</select>
Select, Option 을 이용한 게시물 필터링
게시글 한번에 n개씩 보기 처리하기
<select name="boardCount" id="boardCount">
<option value="10">10개씩 보기</option>
<option value="15">15개씩 보기</option>
<option value="20">20개씩 보기</option>
</select>
Select 태그 추가하기
값 바꿀 때마다 바꾸기
$(function() {
$('#boardCount').change(function() {
location.href = "./boardList?page=${page}&boardCount=" + $('#boardCount').val();
});
});
Controller 에서 값 받기
@RequestParam(value = "boardCount", required = false, defaultValue = "10") String boardCount
int perPage = util.str2Int2(boardCount);
PaginationInfo paginationInfo = new PaginationInfo();
paginationInfo.setCurrentPageNo(page); // 현재 페이지 번호
paginationInfo.setRecordCountPerPage(perPage); // 한 페이지에 게시되는 게시글 건수
paginationInfo.setPageSize(10); // 페이지 리스트 사이즈
paginationInfo.setTotalRecordCount(totalRecordCount); // 총 페이지 수
SearchDTO dto = new SearchDTO();
dto.setPage(paginationInfo.getFirstRecordIndex());
dto.setPerPage(perPage);
model.addAttribute("list", adminService.boardList(dto));
쭉 넘겨서 mapper 에서 처리
<select id="boardList" parameterType="searchDTO" resultType="boardDTO">
select board_no, board_title, mname, board_date, board_del
from board join member on board.mno = member.mno
order by board_no desc
limit #{page}, #{perPage}
</select>
검색 결과 처리하기
Search 검색창 추가
<span class="input-group col-4">
<input type="text" name="search" id="search" class="form-control"/>
<button type="button" class="btn btn-outline-dark" id="searchBtn">검색</button>
</span>
Controller 에서 값 받기
@RequestParam(value = "search", required = false) String search
DTO 에 같이 넣어서 값 보내기, 검색 시 페이징 처리
글 작성자도 함께 처리하기
// 검색 한 내용으로 총 글 갯수 확인하기, Controller
int totalRecordCount = adminService.totalRecordCount(search);
// Service
public int totalRecordCount(String search) {
return adminRepository.totalRecordCount(search);
}
// Repository
public int totalRecordCount(String search) {
return sqlSession.selectOne("admin.totalRecordCount", search);
}
<select id="boardList" parameterType="searchDTO" resultType="boardDTO">
select board_no, board_title, mname, board_date, board_del
from board join member on board.mno = member.mno
<where>
<if test="search != null">
board_title like concat('%', #{search}, '%')
or board_content like concat('%', #{search}, '%')
or mname like concat('%', #{search}, '%')
</if>
</where>
order by board_no desc
limit #{page}, #{perPage}
</select>
<select id="totalRecordCount" parameterType="String" resultType="Integer">
select count(*) from board b join member m on b.mno = m.mno
<where>
<if test="search != null">
(b.board_title like concat('%', #{search}, '%')
or b.board_content like concat('%', #{search}, '%')
or m.mname like concat('%', #{search}, '%'))
</if>
</where>
</select>
글 검색 시 제목, 본문, 작성자, 제목 + 본문 검색 해보기
<div class="row justify-content-end">
<span class="">
<select name="boardCount" id="boardCount" class="form-control">
<option value="10" <c:if test="${boardCount eq 10 }">selected</c:if>>10개씩 보기</option>
<option value="15" <c:if test="${boardCount eq 15 }">selected</c:if>>15개씩 보기</option>
<option value="20" <c:if test="${boardCount eq 20 }">selected</c:if>>20개씩 보기</option>
</select>
</span>
<span class="input-group col-6">
<select name="searchTitle" id="searchTitle" class="form-control col-3">
<option value="1" <c:if test="${searchTitle eq 1 }">selected</c:if>>제목</option>
<option value="2" <c:if test="${searchTitle eq 2 }">selected</c:if>>본문</option>
<option value="3" <c:if test="${searchTitle eq 3 }">selected</c:if>>작성자</option>
<option value="4" <c:if test="${searchTitle eq 4 }">selected</c:if>>제목+본문</option>
</select>
<input type="text" name="search" value="${search }" id="search" class="form-control"/>
<button type="button" class="btn btn-outline-dark" id="searchBtn">검색</button>
</span>
</div>
Controller 또또또 수정
@GetMapping("/boardList")
public String boardList(
@RequestParam(value = "page", required = false, defaultValue = "1") String no,
@RequestParam(value = "boardCount", required = false, defaultValue = "10") String boardCount,
@RequestParam(value = "search", required = false) String search,
@RequestParam(value = "searchTitle", required = false, defaultValue = "1") String searchTitle,
Model model) {
int page = util.str2Int2(no);
int perPage = util.str2Int2(boardCount);
int sTitle = util.str2Int2(searchTitle);
SearchDTO dto = new SearchDTO();
dto.setPerPage(perPage);
dto.setSearchTitle(sTitle);
dto.setSearch(search);
int totalRecordCount = adminService.totalRecordCount(dto);
PaginationInfo paginationInfo = new PaginationInfo();
paginationInfo.setCurrentPageNo(page); // 현재 페이지 번호
paginationInfo.setRecordCountPerPage(perPage); // 한 페이지에 게시되는 게시글 건수
paginationInfo.setPageSize(10); // 페이지 리스트 사이즈
paginationInfo.setTotalRecordCount(totalRecordCount); // 총 페이지 수
dto.setPage(paginationInfo.getFirstRecordIndex());
model.addAttribute("list", adminService.boardList(dto));
model.addAttribute("paginationInfo", paginationInfo);
model.addAttribute("page", page);
model.addAttribute("boardCount", perPage);
model.addAttribute("search", search);
model.addAttribute("searchTitle", sTitle);
return "admin/boardList";
}
totalRecordCount 도 SearchDTO 를 넣어서 값 검색
검색과 totalRecord mapper
<select id="boardList" parameterType="searchDTO" resultType="boardDTO">
select board_no, board_title, mname, board_date, board_del
from board join member on board.mno = member.mno
<where>
<if test="search != null">
<if test="searchTitle == 1">
board_title like concat('%', #{search}, '%')
</if>
<if test="searchTitle == 2">
board_content like concat('%', #{search}, '%')
</if>
<if test="searchTitle == 3">
mname like concat('%', #{search}, '%')
</if>
<if test="searchTitle == 4">
b.board_title like concat('%', #{search}, '%')
or b.board_content like concat('%', #{search}, '%')
</if>
</if>
</where>
order by board_no desc
limit #{page}, #{perPage}
</select>
<select id="totalRecordCount" parameterType="searchDTO" resultType="Integer">
select count(*) from board b join member m on b.mno = m.mno
<where>
<if test="search != null">
<if test="searchTitle == 1">
b.board_title like concat('%', #{search}, '%')
</if>
<if test="searchTitle == 2">
b.board_content like concat('%', #{search}, '%')
</if>
<if test="searchTitle == 3">
m.mname like concat('%', #{search}, '%')
</if>
<if test="searchTitle == 4">
b.board_title like concat('%', #{search}, '%')
or b.board_content like concat('%', #{search}, '%')
</if>
</if>
</where>
</select>
스크립트 내부 url 도 수정해야 함
<script type="text/javascript">
function linkPage(page) {
location.href = "./boardList?page=" + page + "&boardCount=${boardCount}" + "&searchTitle=${searchTitle}" + "&search=${search}";
}
$(function() {
$('#boardCount').change(function() {
location.href = "./boardList?page=${page}&boardCount=" + $('#boardCount').val() + "&searchTitle=${searchTitle}" + "&search=${search}";
});
$('#searchBtn').click(function() {
location.href="./boardList?boardCount=${boardCount}&searchTitle=" + $('#searchTitle').val() + "&search=" + $('#search').val();
});
});
</script>
관리자 페이지에서 게시글 버튼 클릭으로 삭제 여부 바꾸기
<tr class="row${list.board_del }">
<td class="bno">${list.board_no }</td>
<td><a href="./detail?no=${list.board_no }">${list.board_title }</a></td>
<td>${list.mname }</td>
<td>${list.board_date }</td>
<td>
<input type="hidden" value="${list.board_del }" class="del" />
<c:choose>
<c:when test="${list.board_del eq 1}">
<i class="fas fa-fw fa-regular fa-eye bdel"></i>
</c:when>
<c:otherwise>
<i class="fas fa-fw fa-regular fa-eye-slash bdel"></i>
</c:otherwise>
</c:choose>
</td>
</tr>
ajax 로 받아오기
$('.bdel').on('click', function() {
let eyes = $(this); // 눈 모양 아이콘
let bno = $(this).parent().siblings('.bno'); // 게시글 번호
let del = $(this).siblings('.del'); // 게시글의 삭제 여부
let className = $(this).parents('tr'); // 테이블의 행 받아오기
// alert(bno.text() + " : " + del.val());
$.ajax({
url: '/admin/postDel',
type: 'post',
dataType: 'text',
data: {'board_no': bno.text(), 'board_del' : del.val()},
success: function(result) {
if (result == 1) {
if (del.val() == 1) {
className.attr('class', 'row0'); // 행의 class 이름을 변경
del.val('0'); // del 의 밸류 값 변경
eyes.attr('class', 'fas fa-fw fa-regular fa-eye-slash bdel'); // 눈의 아이콘 변경
} else {
del.val('1');
className.attr('class', 'row1');
eyes.attr('class', 'fas fa-fw fa-regular fa-eye bdel');
}
} else {
alert("수정 실패");
}
},
error: function(error) {
alert("ajax 통신 오류 " + error);
}
});
});
Controller 에서부터 Service, Repository 까지
@PostMapping("/postDel")
@ResponseBody
public int postDel(BoardDTO dto) {
// (@RequestParam(value = "board_no") String board_no,
// @RequestParam(value = "board_no") String board_del) {
int result = adminService.postDel(dto);
return result;
}
// Service
public int postDel(BoardDTO dto) {
return adminRepository.postDel(dto);
}
// Repository
public int postDel(BoardDTO dto) {
return sqlSession.update("admin.postDel", dto);
}
<update id="postDel" parameterType="boardDTO">
<choose>
<when test="board_del == 0">
update board set board_del = '1' where board_no = #{board_no}
</when>
<otherwise>
update board set board_del = '0' where board_no = #{board_no}
</otherwise>
</choose>
</update>
<!-- Mapper 는 이거로도 처리 가능 -->
<update id="postDel" parameterType="Integer">
Update board SET
board_del= CASE WHEN board_del='0' THEN '1' ELSE '0' END
WHERE board_no=#{no}
</update>