파일명 alert.jsp
<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script th:inline="javascript">
const msg = [[${msg}]];
alert(msg);
window.location.replace( [[${url}]] );
</script>
</head>
</html>
파일명 Boot20220228Application.java
package com.example.boot_20220228;
import java.time.Duration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
import org.springframework.session.data.mongo.JdkMongoSessionConverter;
import org.springframework.session.data.mongo.config.annotation.web.http.EnableMongoHttpSession;
@SpringBootApplication
// 임의로만들 컨트롤러, 서비스의 위치
@ComponentScan(basePackages = {"com.example.controller","com.example.service"})
// 임의로 만든저장소 위치
@EnableMongoRepositories(basePackages = {"com.example.repository"})
// 세션 정보를 몽고DB에 저장하기 위한 설정
@EnableMongoHttpSession(collectionName = "sessions", maxInactiveIntervalInSeconds = 1800)
public class Boot20220228Application {
public static void main(String[] args) {
SpringApplication.run(Boot20220228Application.class, args);
}
// 몽고DB에서 attr을 쉽게 확인하기 위해서, 객체, 배열 X
// @Bean
// public JacksonMongoSessionConverter mongoSessionConverter(){
// return new JacksonMongoSessionConverter();
// }
// attr의 값이 byte[]로 보여짐, 객체, 배열.. 가능
@Bean
public JdkMongoSessionConverter mongoSessionConverter(){
return new JdkMongoSessionConverter(Duration.ofMinutes(30));
}
}
파일명 AdminController.java
package com.example.controller;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.servlet.http.HttpSession;
import com.example.entity.Book;
import com.example.service.BookDB;
import com.example.service.SequenceService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
// 1. 컨트롤러
@Controller
@RequestMapping(value = "/admin")
public class AdminController {
@Autowired
BookDB bookDB;
@Autowired
SequenceService sequenceService;
@Autowired
HttpSession httpSession;
@PostMapping(value = "/insertbatch")
public String insertPOST(
@RequestParam(name = "title")String[] title,
@RequestParam(name = "price")long[] price,
@RequestParam(name = "writer")String[] writer,
@RequestParam(name = "category")String[] category ){
// 1. 빈 리스트 만들기
List<Book> list = new ArrayList<>();
for(int i=0; i<title.length; i++ ){ //0 1
// jsp에서 controller로 데이터 전달 되는지 확인
// System.out.println(title[i] + "," + price[i] + "," + writer[i] + ","+category[i] );
// 2. Book객체 만들기(시퀀스를 코드를 채워, 날짜도)
// 시퀀스명 SEQ_BOOK4_CODE
Book book = new Book();
book.setCode(sequenceService.generatedSequence("SEQ_BOOK4_CODE"));
book.setTitle(title[i]);
book.setPrice(price[i]);
book.setWriter(writer[i]);
book.setCategory(category[i]);
book.setRegdate(new Date());
// 3. 리스트에 추가하기
list.add(book);
}
bookDB.insertBatchBook(list);
return "redirect:/admin/selectlist";
}
//127.0.0.1:8080/admin/insertbatch
@GetMapping(value = "/insertbatch")
public String insertGET() {
return "admin/insertbatch";
}
//127.0.0.1:8080/admin/selectlist?page=1&text=
@GetMapping(value = "/selectlist")
public String selectlistGET(Model model,
@RequestParam(name = "page",defaultValue = "1")int page,
@RequestParam(name = "text",defaultValue = "")String text ){
List<Book> list = bookDB.selectListPageSearchBook(page, text);
System.out.println(list.size());
long pages = bookDB.countSearchBook(text);
// jsp로 전달(변수,값) => 변수사용
model.addAttribute("list", list);
model.addAttribute("pages", (pages-1)/10 +1);
return "admin/selectlist";
}
@PostMapping(value = "/action")
public String actionPOST(
@RequestParam(name = "btn")String btn,
@RequestParam(name = "chk")List<Long> code) {
// // warpper 클래스
// private long a = 0L;
// private Long a = null; Long클래스 형식
// long Long
// int Integer
// double Double
// List<Object>
// long[] == List<long>
for(Long tmp : code){
System.out.println("체크된 코드 : " + tmp);
}
System.out.println("누른 버튼 : " + btn); // 일괄삭제 or 일괄수정
if(btn.equals("일괄삭제")){
// 1) DB에 삭제하기 구현
bookDB.deleteBatchBook(code);
// 2) 회원목록, 물품목록 검색기능 추가하기
}
else if(btn.equals("일괄수정")){
httpSession.setAttribute("CHK", code);
//페이지를 이동후에 세션에서 꺼내기
return "redirect:/admin/updatebatch";
}
// 목록으로 이동하기
return "redirect:/admin/selectlist";
}
//127.0.0.1:8080/admin/updatebatch
@GetMapping(value = "/updatebatch")
public String updateGET(Model model) {
// 형변환을 하면 데이터가 안전하지 않음을 경고
// 세션에 추가할때와 가지고 올때의 타입을 정확하게 매칭
@SuppressWarnings({"unchecked"})
// DB에서 code에 해당하는 항목 정보만 Session에 가져옴
// jsp로 전달함.
// jsp를 표시함.
List<Long> code = (List<Long>)httpSession.getAttribute("CHK");
List<Book> list = bookDB.selectListWhereIn(code);
model.addAttribute("list", list);
return "admin/updatebatch";
}
@PostMapping(value = "/updatebatch")
public String updatePOST(
Model model,
@RequestParam(name = "code")long[] code,
@RequestParam(name = "title")String[] title,
@RequestParam(name = "price")long[] price,
@RequestParam(name = "writer")String[] writer,
@RequestParam(name = "category")String[] category ){
// 빈 리스트 만들기
List<Book> list = new ArrayList<>();
for(int i=0; i<code.length; i++ ){
Book book = new Book();
book.setCode(code[i]);
book.setTitle(title[i]);
book.setPrice(price[i]);
book.setWriter(writer[i]);
book.setCategory(category[i]);
// 리스트에 추가하기
list.add(book);
}
long ret = bookDB.updateBatchBook(list);
if(ret == 1){
model.addAttribute("msg","일괄수정되었습니다.");
model.addAttribute("url","/admin/selectlist");
return "alert";
}
model.addAttribute("msg","일괄수정 실패하였습니다.");
model.addAttribute("url","/admin/selectlist");
return "alert";
}
}
파일명 BookDB.java
package com.example.service;
import java.util.List;
import com.example.entity.Book;
import org.springframework.stereotype.Service;
@Service
public interface BookDB {
// 일괄등록
public int insertBatchBook(List<Book> list);
// 목록(페이지 + 검색)
public List<Book> selectListPageSearchBook(int page, String text);
// 페이지네이션용 (검색어)
public long countSearchBook(String text);
// 일괄 삭제
public long deleteBatchBook(List<Long> code);
// 코드에 해당하는 목록 가져오기
public List<Book> selectListWhereIn(List<Long> code);
// 일괄 수정
public long updateBatchBook(List<Book> list);
}
파일명 bookDBImpl.java
package com.example.service;
import java.util.Collection;
import java.util.List;
import com.example.entity.Book;
import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.UpdateResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;
// 1. 서비스
@Service
public class BookDBImpl implements BookDB{ // 2. 설계 인터페이스 구현
// 3. DB연결 객체 생성
@Autowired
MongoTemplate mongoDB;
@Override
public int insertBatchBook(List<Book> list) {
try {
// 4. 실제 수행
// collection 구조에 의해서 list를 사용할때는 부모인 collection사용이 유리함
Collection<Book> retList = mongoDB.insert(list, Book.class);
if(retList.size() == list.size()){
return 1;
}
return 0;
} catch (Exception e) {
e.printStackTrace();
return -1;
}
}
@Override
public List<Book> selectListPageSearchBook(int page, String text) {
try {
Query query = new Query();
//검색패턴( .*a.* => a가 포함된 것 해당 ), 정규식
Criteria criteria = Criteria.where("title").regex(".*"+ text + ".*");
query.addCriteria(criteria);
// 페이지네이션(0 부터 시작)
Pageable pageable = PageRequest.of(page-1,10);
query.with(pageable);
// 정렬 (_id기준 내림차순)
Sort sort = Sort.by(Direction.DESC,"_id");
query.with(sort);
return mongoDB.find(query, Book.class);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
@Override
public long countSearchBook(String text) {
try {
Query query = new Query();
//검색패턴( .*a.* => a가 포함된 것 해당 ), 정규식
Criteria criteria = Criteria.where("title").regex(".*"+ text + ".*");
query.addCriteria(criteria);
return mongoDB.count(query, Book.class);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
@Override
public long deleteBatchBook(List<Long> code) {
try {
// long[] => List<long>
// code => [2,5,1] => collection<long>
Query query = new Query();
query.addCriteria(Criteria.where("_id").in(code));
DeleteResult result = mongoDB.remove(query, Book.class);
if(result.getDeletedCount() == (long)code.size() ){
return 1;
}
return 0;
} catch (Exception e) {
e.printStackTrace();
return -1;
}
}
@Override
public List<Book> selectListWhereIn(List<Long> code) {
try {
Query query = new Query();
query.addCriteria(Criteria.where("_id").in(code));
// DESC : 내림차순, ASC : 오름차순
Sort sort = Sort.by(Direction.DESC,"_id");
query.with(sort);
return mongoDB.find(query, Book.class);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
@Override
public long updateBatchBook(List<Book> list) {
try {
long updateCount = 0;
for(Book tmp : list ){
Query query = new Query();
query.addCriteria(Criteria.where("_id").is(tmp.getCode()));
Update update = new Update();
update.set("title", tmp.getTitle());
update.set("price", tmp.getPrice());
update.set("writer", tmp.getWriter());
update.set("category", tmp.getCategory());
UpdateResult result = mongoDB.updateFirst(query, update, Book.class);
updateCount += result.getMatchedCount();
}
if(updateCount == list.size()){
return 1;
}
return 0;
} catch (Exception e) {
e.printStackTrace();
return -1;
}
}
}
파일명 insertbatch.jsp
<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<head th:replace="~{/member/header::headerFragment}"></head>
<body>
<div style="padding: 20px;">
<h3>admin insert</h3>
<hr />
<form th:action="@{/admin/insertbatch}" method="post">
<table class="table">
<tr>
<th>제목</th>
<th>가격</th>
<th>저자</th>
<th>분류</th>
</tr>
<tr th:each="i : ${#numbers.sequence(1,2)}">
<td><input type="text" value="1" name="title"/></td>
<td><input type="text" value="2" name="price"/></td>
<td><input type="text" value="가나다" name="writer"/></td>
<td>
<select name="category">
<option>A</option>
<option>B</option>
<option>C</option>
</select>
</td>
</tr>
</table>
<input type="submit" class="btn btn-primary" value="도서일괄등록"/>
</form>
<hr />
<div th:replace="~{/member/footer ::footerFragment}"></div>
</div>
</body>
</html>
파일명 selectlist.jsp
<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>게시판</title>
<link rel="stylesheet" type="text/css" th:href="@{/css/bootstrap.css}"/>
<script type="text/javascript" src="@{/js/bootstrap.min.js}"></script>
</head>
<body>
<div style="padding: 20px;">
<h3>board list</h3>
<hr />
<a th:href="@{/board/insert}" class="btn btn-primary" >글쓰기</a>
<form th:action="@{/board/action}" method="post">
<input type="submit" name="btn" value="1개 삭제" class="btn btn-primary"/>
<input type="submit" name="btn" value="1개 수정" class="btn btn-primary"/>
<hr />
<table class="table table-striped">
<tr>
<th>radio</th>
<th>글번호</th>
<th>제목</th>
<th>작성자</th>
<th>조회수</th>
<th>작성일</th>
</tr>
<tr th:each="tmp, idx : ${list}">
<td><input type="radio" name="rad" th:value="${tmp.no}" /></td>
<td th:text="${tmp.no}"></td>
<td th:text="${tmp.title}"></td>
<td th:text="${tmp.writer}"></td>
<td th:text="${tmp.hit}"></td>
<td th:text="${tmp.regdate}"></td>
</tr>
</table>
</form>
</div>
</body>
</html>
파일명 updatebatch.jsp
<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<head th:replace="~{/member/header::headerFragment}"></head>
<body>
<div style="padding: 20px;">
<h3>book update</h3>
<hr />
<form th:action="@{/admin/updatebatch}" method="post">
<table class="table">
<tr>
<th>코드</th>
<th>제목</th>
<th>가격</th>
<th>저자</th>
<th>분류</th>
<th>등록일</th>
</tr>
<tr th:each="tmp : ${list}">
<td ><input type="text" th:value="${tmp.code}" name="code" readonly></td>
<td><input type="text" th:value="${tmp.title}" name="title"></td>
<td><input type="text" th:value="${tmp.price}" name="price"></td>
<td><input type="text" th:value="${tmp.writer}" name="writer"></td>
<td>
<select name="category">
<option th:selected="${#strings.equals(tmp.category, 'A')}">A</option>
<option th:selected="${tmp.category == 'B'}">B</option>
<option th:selected="${tmp.category == 'C'}">C</option>
</select>
</td>
<td th:text="${tmp.regdate}"></td>
</tr>
</table>
<input type="submit" class="btn btn-primary" value="도서일괄수정"/>
</form>
<hr />
<div th:replace="~{/member/footer ::footerFragment}"></div>
</div>
</body>
</html>