Spring공식문서 - ModelAndView Class
ModelAndView Class는 Controller에서
model
과View
를 한번에 반환가능하게 하는 Class
➡️model
로 전송할 정보 + 화면View
에 표시하는 작업을 동시에 진행해야하는 경우ModelAndView
클래스를 사용하여 Controller가 단일 반환값으로model
과View
를 한번에 반환할 수 있도록 한다
ModelAndView(viewName, modelName, modelObject)
➡️ html 파일명, 전송모델명 , 전송모델객체ModelAndView("board/insert1", "obj", board);
// 127.0.0.1:8080/BOOT1/board/ insert1.do
@GetMapping("/insert1.do")
public ModelAndView insertGET(){
// model.addAttribute("obj", obj)를 사용하는 경우 board객체만 리턴 가능!
// ModelAndView 이용하여 객체와 view 동시에 리턴해보기
BoardDTO board = new BoardDTO(); //객체 만들기
board.setTitle("dd2");
board.setContent("ddd3");
board.setWriter("ddd");
// return new ModelAndView(viewName, modelName, modelObject)
// html 파일명, 전송모델명 , 전송모델객체
// 전송할것도 있고 화면도 표시해야하는 작업 진행시 ModelAndView 사용
return new ModelAndView("board/insert1", "obj", board);
}
form 태그에
th:object="${obj}”
명시해주고
th:field="${obj.title}”
사용하여 출력해준다
<!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>
</head>
<body>
<a th:href="@{/seller/home.do}">홈으로</a>
<hr />
게시판글쓰기
<hr />
<form th:action="@{/board/insert1.do}" th:object="${obj}" method="post">
<input type="text" th:field="${obj.title}" name="name" placeholder="제목" />
<input type="text" th:field="${obj.content}" name="content" placeholder="내용" />
<input type="number" th:field="${obj.writer}" name="price" placeholder="작성자" /><br />
<hr />
<input type="submit" value="일괄추가" />
</form>
</body>
</html>
📃결과
ModelAndView
는 데이터를 view로 전송해주는것 뿐만 아니라 view에서 데이터를 되돌려 받기도 쉽다
체크박스의 항목 / 체크된 여러개의 항목을 저장할 배열 생성
// 체크할 항목들
String[] chkLabel = {"국어", "영어", "수학", "과학"};
// 체크된 항목을 보관(저장)할 배열
String[] choiceChk;
체크박스 생성 후 여러개의 데이터 선택 + 선택한 데이터 Controller로 보내주기
th:field="*{choiceChk}”
⇒*
= 반복자 = 여러개의 데이터 선택 가능
...
<input type="text" th:field="${obj.title}" name="name" placeholder="제목" />
<input type="text" th:field="${obj.content}" name="content" placeholder="내용" />
<input type="text" th:field="${obj.writer}" name="price" placeholder="작성자" /><br />
<!-- DTO의 항목 기반으로 체크박스 생성한다 -->
<input type="checkbox" name="choiceChk" th:each="tmp : ${obj.chkLabel}" th:text="${tmp}" th:value="${tmp}" th:field="*{choiceChk}" />
...
<input type="submit" value="일괄추가" />
</form>
</body>
</html>
View에서 받아온 데이터 출력해보기
@PostMapping(value = "/insert1.do")
public String insert1POST(
@ModelAttribute BoardDTO board) {
System.out.println(board.toString());
return "redirect:/board/insert1.do";
}
라디오의 항목 / 라디오의 항목을 저장할 변수 생성
// 라디오 항목을 보관할 문자(radio 사용하기 = 1개)
String choiceRad;
// select[]
String choiceSel;
String[] choiceSel1;
radio 생성 후 데이터 선택 + 선택한 radio의 데이터 Controller로 보내주기
<input type="radio" name="choiceRad" th:each="tmp : ${obj.chkLabel}" th:text="${tmp}" th:value="${tmp}" th:field="*{choiceRad}" />
1개 데이터 선택용 변수, 여러개의 데이터 선택용 배열형태 변수 생성
//1개 데이터 선택시
String choiceSel;
// 여러개의 데이터 선택시 = select[]
String[] choiceSel1;
<!-- 1개의 항목 선택시 -->
<select th:field="${obj.choiceSel}">
<option th:each="tmp:${obj.chkLabel}" th:value="${tmp}" th:text="${tmp}" ></option>
</select>
<br />
<!-- 여러개의 항목 선택시 => select에 multiple 사용 = option 여러개 선택 가능 -->
<select th:field="${obj.choiceSel1}" multiple>
<option th:each="tmp:${obj.chkLabel}" th:value="${tmp}" th:text="${tmp}" ></option>
</select>
<br />
- 여러개의
BoardDTO
를 일괄저장하기 위한BoardDTO N개 보관 가능 객체
=BoardListDTO
생성- form 하나가 모델 하나라고 생각하면 된다!
form 하나인 경우 :
th:object="${obj}”
form 두개인 경우 :th:object="${obj1}”
/th:object="${obj2}”
게시판 회원수정시 ModelAndView 사용하면 기존 정보가 뿌려져 있을것
보통의 insert같은 경우 input칸이 비워져 있어도 상관 없지만 회원정보수정 같은 경우 기존 회원 정보를 받아와서 뿌려주고 수정된 값을 가져가야 하니 ModelAndView를 사용해주면 좋다
BoardDTO
를 N개 보관하기 위한BoardListDTO.java
package com.example.dto;
import java.util.List;
import lombok.Data;
@Data
public class BoardListDTO {
// BoardDTO를 N개 보관
List<BoardDTO> list;
}
- BoardListDTO = BoardDTO를 List형태로 가질 수 있게 만듬
- view에 전송모델객체 전송시 list를 던지면 안됨!
➡️ list를 보관할 수 있는 객체 BoardListDTO를 생성해서 던져야 여러개의 BoardDTO를 List형태로 보관 가능하다- 데이터 일괄 추가시 같은 컬럼끼리 배열형태로 담아줬었는데 이건 여러개의 DTO형태 받고싶은 상황!
// BoardDTO를 N개 보관
// 127.0.0.1:8080/BOOT1/board/ insertall1.do
@GetMapping(value = "/insertall1.do")
public ModelAndView insertallGET() {
// 일괄추가 항목 만들기
List<BoardDTO> list = new ArrayList<>();
for(int i=0; i<3; i++){
BoardDTO board = new BoardDTO(); // 객체 만들기
board.setTitle(board.getTitle());
board.setContent(board.getContent());
board.setWriter(board.getWriter());
list.add(board);
}
// BoardDTO N개 보관 가능 객체
BoardListDTO obj = new BoardListDTO();
obj.setList(list);
// list를 보관할 수 있는 객체 BoardListDTO를 생성하여 보관
return new ModelAndView("board/insertall1", "obj", obj);
}
Controller에서
BoardListDTO
를obj
로 넘겨줬다
➡️ View 에서 obj를 반복하면BoardListDTO
가 반복된다!
BoardDTO
를 반복하여 입력받아야 하니obj
가 아닌obj.list
를 반복하여 입력받는다
💡 th:each="tmp, idx : ${obj.list}"
= obj
반복이 아닌 obj.list
를 반복!
<!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>
</head>
<body>
<a th:href="@{/seller/home.do}">홈으로</a>
<hr />
게시판글쓰기
<hr />
<form th:action="@{/board/insertall1.do}" th:object="${obj}" method="post">
<th:block th:each="tmp, idx : ${obj.list}">
<input type="text" th:name="|list[${idx.index}].title|" th:value="${tmp.title}" placeholder="제목" />
<input type="text" th:name="|list[${idx.index}].content|" th:value="${tmp.content}" placeholder="내용" />
<input type="text" th:name="|list[${idx.index}].writer|" th:value="${tmp.writer}" placeholder="작성자"/>
<br />
</th:block>
<hr />
<input type="submit" value="일괄추가" />
</form>
</body>
</html>
출력화면에 3개의 입력창이 생성된 이유는 BoardController
에서 for반복문의 길이를 3으로 지정하여 list를 생성해줬기 때문이다 ➡️ for(int i=0; i<3; i++)
DB에 저장하기
1. view에서 전송한 데이터를 컨트롤러에서 받고
2. 일괄추가할 항목 생성List<BoardDTO> list
3. 받은데이터를BoardDTO
에 담아준 후
3.ModelAndView
리턴
for(BoardDTO obj : boardlist.getList())
=boardlist.getList()
에서 차례로 객체를 꺼내BoardDTO obj
에 넣는다는 뜻이다
🌎 [Java] for구문에서 콜론(:)의 기능 - for(Object : List)
view 에서 Controller로 model을 받을 때
@ModelAttribute BoardListDTO boardlist
를 사용한다
@PostMapping(value = "/insertall1.do")
public String insertall1POST(@ModelAttribute BoardListDTO boardlist){
System.out.println("===========BoardListDTO=============");
System.out.println(boardlist.getList().toString());
List<BoardDTO> list = new ArrayList<>();
for(BoardDTO obj : boardlist.getList()){
System.out.println("===========obj.toString()=============");
System.out.println(obj.toString());
list.add(obj);
};
bMapper.insertBoardBatch(list);
return "redirect:/board/insertall1.do";
}
Scheduling(스케쥴링)은 반복되는 일을 수행할때 수행되는 시점을 크론표현식을 이용하여 지정해준다
@Scheduled(cron = "*초 *분 *시 *일 *월 *주 *년")
- 5초 단위로 실행되는 스케쥴링 ➡️
(cron = "*/5 * * * * *")
- 실시간 실행되는 스케쥴링 ➡️
@Scheduled(cron = "* * * * * *")
- 매일 정시에 실행되는 스케쥴링 ➡️
@Scheduled(cron = "* * *0 * * *")
package com.example.scheduler;
import java.util.Date;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class CrawScheduler {
@Scheduled(cron = "*/5 * * * * *")
public void crawDate1(){
// System.out.println( new Date().toString() );
// axios => okhttp3
}
}
스케쥴링 활성화 + 환경설정 추가
// 스케쥴링 활성화
@EnableScheduling
환경설정에 추가
"com.example.scheduler"
결과
설정한 시간마다 동기화 되는것을 확인 할 수 있다
물품을 회원이 장바구니에 담는 기능
➡️ 장바구니 기능을 즐겨찾기/주문 기능으로도 활용 가능하다
거래내역이나 주문취소내역 같은 경우는 취소된 거래내역이나 주문내역도 조회가 가능하여야 한다 ➡️ 삭제의 개념이 아니다!
이처럼 거래나 주문이 취소 되어도 기록을 남겨두고 조회할 수 있어야 하는 경우,
새 컬럼을 생성하여 거래, 주문의 상태를 타입값으로 지정해준다
장바구니 정보를 저장할 테이블 생성
➡️ 장바구니 = 회원+물품
CREATE TABLE CARTTBL(
NO NUMBER PRIMARY KEY,
ITEMNO NUMBER,
USERID VARCHAR2(30),
REGDATE DATE DEFAULT CURRENT_DATE,
CONSTRAINT FK_CART_ITEM_NO FOREIGN KEY(ITEMNO) REFERENCES ITEMTBL(NO),
CONSTRAINT FK_CART_MEMBER_ID FOREIGN KEY(USERID) REFERENCES MEMBERTBL(USERID)
);
장바구니 조회용 view 생성 (필터 조건은 없음)
VIEW에서 조회 가능한 내용
➡️ 물품번호, 물품명, 물품가격 / 회원아이디, 회원연락처, 회원등록일
SELECT I.NO ITEMNO, I.NAME, I.PRICE, C.NO
FROM ITEMTBL I
INNER JOIN CARTTBL C
ON I.NO = C.ITEMNO;
SELECT M.USERID, M.PHONE, M.REGDATE, C.NO
FROM MEMBERTBL M
INNER JOIN CARTTBL C
ON M.USERID = C.USERID;
CREATE OR REPLACE VIEW CART_VIEW AS
SELECT M.USERID, M.PHONE, M.REGDATE, I.NO ITEMNO, I.NAME, I.PRICE, C.NO
FROM CARTTBL C
INNER JOIN ITEMTBL I ON I.NO = C.ITEMNO
INNER JOIN MEMBERTBL M ON M.USERID = C.USERID;
CATETBL
= AAA 의류, BBB 식품, CCC 가전제품
CREATE TABLE CATETBL(
ID VARCHAR2(3),
NAME VARCHAR2(50),
CONSTRAINT PK_CATETBL_ID PRIMARY KEY(ID)
);
데이터 추가
INSERT ALL
INTO CATETBL(ID, NAME) VALUES('AAA', '의류')
INTO CATETBL(ID, NAME) VALUES('BBB', '식품' )
INTO CATETBL(ID, NAME) VALUES('CCC', '가전제품')
SELECT * FROM DUAL;
COMMIT;
CATEITEMTBL
생성하여CATETBL
과ITEMTBL
의 PK를 외래키 제약조건을 걸어 연결
CREATE TABLE CATEITEMTBL(
NO number,
CATEID VARCHAR2(3),
ITEMNO NUMBER,
CONSTRAINT PK_CATEITEM_NO PRIMARY KEY(NO),
CONSTRAINT FK_CATE_ID FOREIGN KEY (CATEID) REFERENCES CATETBL(ID),
CONSTRAINT FK_ITEM_NO FOREIGN KEY (ITEMNO) REFERENCES ITEMTBL(NO)
);