2023.07.04 - [스프링부트] - sts4 spring boot 두번쨍
까지 잘 따라 했다면 이제 프론트단(화면) 을 간단히 구현해서 AJAX와 RESTFUL을 연계해보장
확인용 더미 데이터를 아래 insert문을 이용해서 데이타베이스에 넣도록 하장.
insert into sujin(sujin_num,sujin_name,sujin_content,sujin_file)
values ( seq_sujin.nextval, '운제경', '교육과정이 ...', '/merong/roze1.jpg' );
insert into sujin(sujin_num,sujin_name,sujin_content,sujin_file)
values ( seq_sujin.nextval, '빙지형', '만족스러운 ...', '/merong/roze2.jpg' );
insert into sujin(sujin_num,sujin_name,sujin_content,sujin_file)
values ( seq_sujin.nextval, '정호연', '8개월간 좋...', '/merong/roze3.jpg' );
insert into sujin(sujin_num,sujin_name,sujin_content,sujin_file)
values ( seq_sujin.nextval, '순에스라', '교육과정이 ...', '/merong/roze4.jpg' );
insert into sujin(sujin_num,sujin_name,sujin_content,sujin_file)
values ( seq_sujin.nextval, '차규찬', '교수님들께서...', '/merong/roze5.jpg' );
insert into sujin(sujin_num,sujin_name,sujin_content,sujin_file)
values ( seq_sujin.nextval, '혁유재', '교육과정이 ...', '/merong/roze6.jpg' );
insert into sujin(sujin_num,sujin_name,sujin_content,sujin_file)
values ( seq_sujin.nextval, '빙민', '8개월간 좋...', '/merong/roze7.jpg' );
insert into sujin(sujin_num,sujin_name,sujin_content,sujin_file)
values ( seq_sujin.nextval, '성하웅', '선생님들이 ...', '/merong/roze8.jpg' );
insert into sujin(sujin_num,sujin_name,sujin_content,sujin_file)
values ( seq_sujin.nextval, '제갈선하', '만족스러운 ...', '/merong/roze9.jpg' );
insert into sujin(sujin_num,sujin_name,sujin_content,sujin_file)
values ( seq_sujin.nextval, '섭려환', '8개월 동안...', '/merong/roze10.jpg' );
insert into sujin(sujin_num,sujin_name,sujin_content,sujin_file)
values ( seq_sujin.nextval, '즙준렬', '8개월간 좋...', '/merong/roze11.jpg' );
insert into sujin(sujin_num,sujin_name,sujin_content,sujin_file)
values ( seq_sujin.nextval, '조명선', '교수님들께서...', '/merong/roze12.jpg' );
insert into sujin(sujin_num,sujin_name,sujin_content,sujin_file)
values ( seq_sujin.nextval, '정화린', '커리큘럼이 ...', '/merong/roze13.jpg' );
insert into sujin(sujin_num,sujin_name,sujin_content,sujin_file)
values ( seq_sujin.nextval, '다리환', '실력이 많이...', '/merong/roze14.jpg' );
insert into sujin(sujin_num,sujin_name,sujin_content,sujin_file)
values ( seq_sujin.nextval, '제갈규준', '커리큘럼이 ...', '/merong/roze15.jpg' );
insert into sujin(sujin_num,sujin_name,sujin_content,sujin_file)
values ( seq_sujin.nextval, '즙제이슨', '한국 최고의...', '/merong/roze16.jpg' );
insert into sujin(sujin_num,sujin_name,sujin_content,sujin_file)
values ( seq_sujin.nextval, '증하다', '너무 알찬 ...', '/merong/roze17.jpg' );
insert into sujin(sujin_num,sujin_name,sujin_content,sujin_file)
values ( seq_sujin.nextval, '옥에반', '교수님들께서...', '/merong/roze18.jpg' );
insert into sujin(sujin_num,sujin_name,sujin_content,sujin_file)
values ( seq_sujin.nextval, '탁수만', '너무 알찬 ...', '/merong/roze19.jpg' );
insert into sujin(sujin_num,sujin_name,sujin_content,sujin_file)
values ( seq_sujin.nextval, '온엘리', '교육과정이 ...', '/merong/roze20.jpg' );
commit;
부트에서는 src/main/resources 에 보면 static 폴더가 누네 들어온당.
말그대로 정적파일(html,css,js 등등 서버입장에서 정적파일)을 저장하는 곳이당.
여기에 index.html을 만들어주면 자동으로 시작페이지가 된당.
(당근 controller에 "/"에 맵핑된 것이 없어야 한당!)
브라우져 주소표시줄에 http://localhost:포트번호 를 입력하면 index.html화면이 보일거시당.
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>RESTFUL API 테스트</title>
<style>
* {
box-sizing: border-box;
}
#wrapper {
text-align: center;
}
#list {
width:70%;
height: 400px;
border:5px solid rgb(166, 0, 255);
overflow: auto;
}
#toolbar{
width:70%;
border:5px solid orange;
padding-bottom: 5%;
/*height: 50px;*/
}
div {
margin: 0 auto;
min-width: 400px;
}
input[type=button] {
/* 아래로 9px 이동 크기 1.3배 */
transform: translateY(9px) scale(1.3);
}
#muTable {
margin: 0 auto;
}
</style>
</head>
<body>
<div id="wrapper">
<h1>RESTFUL API 테스통</h1>
<div id="list"></div>
<div id="toolbar">
<br>
<form>
<table id="muTable">
<tr>
<td>넘</td>
<td><input type="text" name="sujinNum" value="" ></td>
</tr>
<tr>
<td>이름</td>
<td><input type="text" name="sujinName" value="" ></td>
</tr>
<tr>
<td>내용</td>
<td><input type="text" name="sujinContent" value="" ></td>
</tr>
<tr>
<td>파일</td>
<td><input type="text" name="sujinFile" value="" ></td>
</tr>
</table>
</form>
<input type="button" value="입력" onclick="fPostInput()">
<input type="button" value="수정" onclick="fPutUpdate()">
<input type="button" value="삭제" onclick="fDeleteDel()">
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.0/jquery.min.js"></script>
<script>
const myForm = document.forms[0];
const myList = document.querySelector("#list");
// 기능 함수
// 테이블 TR 요런건 기본으로 제공하는 게 좋음
const fTrClickMouseOverOut = ()=>{
let trs = document.querySelectorAll("tr");
for(let i=0; i<trs.length; i++){
trs[i].addEventListener("mouseover",()=>{
trs[i].style.backgroundColor = "black";
trs[i].style.color = "orange";
});
trs[i].addEventListener("mouseout",function(){
this.style.backgroundColor="white";
this.style.color = "black";
this.style.fontWeight = "normal";
});
}
}
// 테이블 맹그는 함수
const fMakeTable = (sujins) =>{
let tableStr = `<table border=1 style="width:100%"><tbody>`;
tableStr += `<tr><th>Num</th><th>Name</th><th>Content</th><th>File</th></tr>`;
for(let i=0; i<sujins.length; i++){
let sujin = sujins[i];
tableStr += `<tr onclick="fGetOne(${sujin.sujinNum})">`;
tableStr += `<td>${sujin.sujinNum}</td>`;
tableStr += `<td>${sujin.sujinName}</td>`;
tableStr += `<td>${sujin.sujinContent}</td>`;
tableStr += `<td>${sujin.sujinFile}</td>`;
tableStr += `</tr>`;
}
tableStr += `<tr></tbody></table>`;
myList.innerHTML = tableStr;
//테이블이 동적으로 새로 맹글어지므로, TR이벤트도 그때마당
fTrClickMouseOverOut();
}
// 백엔드 Restful SujinController에 대응하는 함수들
// get으로 list(sujins)가져오깅
const fGetList = ()=>{
let xhr = new XMLHttpRequest();
xhr.open("get","/api/sujins",true);
xhr.onreadystatechange = ()=>{
if(xhr.readyState == 4 && xhr.status == 200){
//console.log("항상먼저화깅:",xhr.responseText);
let voList = JSON.parse(xhr.responseText);
fMakeTable(voList.sort((a,b)=>{
return a.sujinNum - b.sujinNum;
}));
}
}
xhr.send();
}
fGetList(); // 그냥 바로 리스트 콜!
// get으로 1개 row(sujin) 가져오깅
const fGetOne = (sujinNum)=>{
let xhr = new XMLHttpRequest();
xhr.open("get",`/api/sujin/${sujinNum}`,true);
xhr.onreadystatechange = ()=>{
if(xhr.readyState == 4 && xhr.status == 200){
//console.log("항상먼저화깅:",xhr.responseText);
let sujinVO = JSON.parse(xhr.responseText);
// form안의 element요소에 가져온 값 넣어주깅
myForm.sujinNum.value = sujinVO.sujinNum;
myForm.sujinName.value = sujinVO.sujinName;
myForm.sujinContent.value = sujinVO.sujinContent;
myForm.sujinFile.value = sujinVO.sujinFile;
}
}
xhr.send();
}
// post로 insert 1개 row(sujin)
const fPostInput = ()=>{
// 아작스 쓸땡, 넘기는 데이타는 누네 잘 보이도록..디버깅 용이
// FormData를 이용하지 않을 때는 JSON문자열로 보내는 거시 확장성이 좋당
// 자바는 자바스크립트의 객체를 이해못한당.(문자열은 글자임을 안당)
let sujinVO = JSON.stringify({
// sujinNum : myForm.sujinNum.value, // sequence 쓰므로 필요없음
sujinName : myForm.sujinName.value,
sujinContent : myForm.sujinContent.value,
sujinFile : myForm.sujinFile.value,
});
let xhr = new XMLHttpRequest();
xhr.open("post","/api/sujin",true);
xhr.setRequestHeader("Content-Type","application/json;charset=utf-8");
xhr.onreadystatechange = ()=>{
if(xhr.readyState == 4 && xhr.status == 200){
console.log("항상먼저화깅:",xhr.responseText);
let rowCnt = xhr.responseText;
if(rowCnt != 0){
alert("잘 추가 되었다네용");
fGetList(); // 리스트 다시 가져오깅, 일부렁?(다른방법은?)
console.log("체킁:",myList.scrollHeight);
//그려지고 있는동안(Rendering중)에 움직이면 쪼메 모자라게 됨)
setTimeout(()=>{
myList.scrollTo(0,myList.scrollHeight);
},30);
}
}
}
xhr.send(sujinVO);
}
// 참고 postInput을 jqury $.ajax로 고친다면
const fPostInput2 = ()=>{
let sujinVO = JSON.stringify({
// sujinNum : myForm.sujinNum.value, // sequence 쓰므로 필요없음
sujinName : myForm.sujinName.value,
sujinContent : myForm.sujinContent.value,
sujinFile : myForm.sujinFile.value,
});
$.ajax({
type:"post",
url:"/api/sujin",
contentType:"application/json;charset=utf-8",
dataType:"text",
data: sujinVO,
success:function(rslt){
console.log("항상먼저화깅:",rslt);
let rowCnt = rslt;
if(rowCnt != 0){
alert("잘 추가 되었다네용");
fGetList(); // 리스트 다시 가져오깅, 일부렁?(다른방법은?)
console.log("체킁:",myList.scrollHeight);
//그려지고 있는동안(Rendering중)에 움직이면 쪼메 모자라게 됨)
setTimeout(()=>{
myList.scrollTo(0,myList.scrollHeight);
},30);
}
}
})
}
// put으로 update 수정 부르깅
const fPutUpdate = ()=>{
let sujinVO = JSON.stringify({
sujinNum : myForm.sujinNum.value,
sujinName : myForm.sujinName.value,
sujinContent : myForm.sujinContent.value,
sujinFile : myForm.sujinFile.value,
});
let xhr = new XMLHttpRequest();
xhr.open("put","/api/sujin",true);
xhr.setRequestHeader("Content-Type","application/json;charset=ut-8");
xhr.onreadystatechange = ()=>{
if(xhr.readyState == 4 && xhr.status == 200){
let rowCnt = xhr.responseText;
if(rowCnt != 0){
alert("잘 수정 되었다네용");
fGetList(); // 리스트 다시 가져오깅, 일부렁?(다른방법은?)
}
}
}
xhr.send(sujinVO);
}
// delete 메소드로 요청해서 지우깅
const fDeleteDel = ()=>{
let sujinNum = myForm.sujinNum.value;
let xhr = new XMLHttpRequest();
xhr.open("delete",`/api/sujin/${sujinNum}`,true);
xhr.setRequestHeader("Content-Type","application/json;charset=ut-8");
xhr.onreadystatechange = ()=>{
if(xhr.readyState == 4 && xhr.status == 200){
console.log("항상먼저화깅:",xhr.responseText);
let rowCnt = xhr.responseText;
if(rowCnt != 0){
alert("잘 지워졌다네용");
fGetList(); // 리스트 다시 가져오깅, 일부렁?(다른방법은?)
}
}
}
xhr.send();
}
</script>
</body>
</html>
참고로 fPostInput은 Jquery $.ajax사용시에 변환모습을 보여주기 위해서
fPostInput2를 추가로 소스에 담아버렸당.
script src에 jquery를 가져와야함을 잊지말장.
최초에 list를 불러오고, 테이블을 클릭하면 해당 글을 불러오고,
입력/수정/삭제는 처리 후에 무조건 list를 다시 불러오도록 작성하였는데, 백엔드 restful에
1:1로 맵핑되도록 하기 위한 것일 뿐, 생각을 좀 더 하면, 좀더 나은 방법이 보일 거시당.!
Restful + AJAX는 웹 개발자라면 당연 필수라 하디 아늘수 업지 않지 않지 안탕!
JSP가 구지 필요없음을 느꼈는강?
[상황에 따라(검색엔진 친화적) 필요하기도 하고, SSG도 하나의 흐름이당당당!!]
JSP 나를 알아도, 나는 JSP 잘 몰라용
Form 나를 알아도, 나는 Form 잘 몰라용
RESTFUL 위에 .....
AJAX 지나가면..........
https://www.youtube.com/watch?v=qEgnbQUD_vk
sts4 spring boot 두번쨍 (0) | 2023.07.04 |
---|---|
sts4 spring boot 첫번쨍 (0) | 2023.07.03 |