20220907_tue
실습내용
- '점수등록'버튼 누르면 점수 입력(update)되고, '확인'버튼 누르면 점수등록(insert)시킨다
: MERGE INTO 쿼리문 사용하기- 점수등록되면 '등록성공!!' alert창 띄운다
:DB작업은 있지만 페이지이동은 없을 때, ajax사용한다
-> js파일에서 if문의 else문안에 ajax를 넣어서 실행시킨다.
else { //ajax start $.ajax({ url: '/stu/updateScore', type: 'post', data: {}, success: function(result) { alert(111); }, error: function() { alert('실패'); } }); //ajax end }
: 다른 테이블에서 데이터를 비교하여 가져오는 것이 아니라, 직접 값을 넣고자 한다면 DUAL을 사용.
: ON 뒤에 나오는 매칭 조건은 PK를 사용해야 합니다. 그렇지 않으면 입력시에 중복이 발생하여 에러가 날 수 있습니다.
- ON절에서 점수정보테이블 데이터에 학생번호가 이미 있다면, UPDATE 없으면, INSERT
- updateScore(점수등록(수정)) :
<insert>,<update>
둘 중 하나 상관없다
<insert id="updateScore">
MERGE INTO SCORE_INFO
USING DUAL
ON (STU_NUM = #{stuNum})
WHEN MATCHED THEN
UPDATE
SET
KOR_SCORE = #{korScore}
, ENG_SCORE = #{engScore}
, MATH_SCORE = #{mathScore}
WHERE STU_NUM = #{stuNum}
WHEN NOT MATCHED THEN
INSERT (
SCORE_NUM ,KOR_SCORE , ENG_SCORE , MATH_SCORE, STU_NUM
)
VALUES (
(SELECT MAX(NVL(SCORE_NUM,0)) + 1 FROM SCORE_INFO) , #{korScore} , #{engScore} , #{mathScore} ,#{stuNum}
)
</insert>
</mapper>
stuController
: ajax의 데이터를 받아온다 -> 확인 하는 방법은 toStriong 메소드출력해서 확인해본다
@ResponseBody @PostMapping("/updateScore") public int updateScore(StuVO stuVO) { System.out.println(stuVO); return stuService.updateScore(stuVO); }
service
: 학생점수등록 서비스
int updateScore(StuVO stuVO);
serviceImpl
:학생점수등록 서비스 임플(insert 혹은 update 둘 중하나 상관 없음!)
@Override public int updateScore(StuVO stuVO) { return sqlSession.insert("stuMapper.updateScore", stuVO);//update도 상관없다 }
- [setScore() 메소드 만들 시, 알아야할 점]
: 점수등록 누르면 원래 그린 테이블 지우고 다시 그려줘야한다.(이전 목록조회와 같음)
그래서 원래 점수값 데이터 받는 td태그부분들을 지워주고 다시 그려준다.
!가장 먼저 태그를 먼저 선택해야한다.(id값부여)
:선택한 태그의 속성값 데이터 불러오기
※주의 korScoreTd 안의 글자와 value속성값은 서로 다르다!korScoreTd.vlaue;
//korScoreTd의 value 속성값korScoreTd.innerText;
//td태그사이 text값 ${result.korScore}
- (방법1) 반복이 많아서 다른 방법 사용
const korScoreTd = document.querySelector('#korScoreTd');
korScoreTd.innerText='';
//원래 있는 국어점수 내용 지우기(빈값주기)
const engScoreTd = document.querySelector('#engScoreTd');
engScoreTd.innerText='';
//원래 있는 국어점수 내용 지우기(빈값주기)
const mathScoreTd = document.querySelector('#mathScoreTd');
mathScoreTd.innerText='';
//원래 있는 국어점수 내용 지우기(빈값주기)
- (방법2) tr에 id값 부여하여 태그 선택(반복문 피하기위해)
- 1개값만 들고올 때
querySelector
사용
const scoreTr = document.querySelector('#scoreTr');
- 여러개 td들고오니까 모두 들고올려면
querySelectorAll
사용- 여러개 데이터 뽑을 때-> 반복문사용 !
- 왜? 여러 데이터있을 때, 바로 객체명 사용시 오류발생한다 ex)
scoreTds.innerText='';
- 1)원래가지고 있는 데이터(점수 score )를 저장:값을 가져올때 innerText
- 2)내용만 지우기(빈값). 값을 설정 할 때, innerText
- 3)scoreTd 에 input태그 넣기(`` 백팁 사용, 화면에 보이는 값은 value 속성)
- 4) 원하는 위치에 str 넣기
- innerHTML : 태그 사이의 태그값 / innerText : 태그 시작과 끝 사이 문자값 선택
- afterbegin(선택태그 시작 직후) 대신 beforeend(선택태그 끝나기 직전)도 가능하다.
- '점수등록' 버튼 '확인'으로 바꾸기 -> 눈에 보이는 속성 value값 '확인'으로 값 설정하기
function setScore() {
const btn = document.querySelector('input[type="button"]');
if (btn.value == '점수등록') {
const scoreTds = document.querySelectorAll('#scoreTr > td');
for (const scoreTd of scoreTds) {
const score = scoreTd.innerText;//①
scoreTd.innerText = '';//②
const str = `<input class="scoreInput"
type="text"
style="width:90%;"
value="${score}">`;//③
scoreTd.insertAdjacentHTML("afterbegin", str);//④
}
btn.value = '확인';
}
- 그렇지 않으면('확인'버튼일 때), 점수등록한다(DB작업)_merge into 사용
- 각 점수의 value값 데려오기위해(여러개)
- 위의 만든 scoreInputs 의 값이 여러개이기때문에 리스트처럼 순서대로 value값 데이터로 뽑는다
else {
const scoreInputs = document.querySelectorAll('.scoreInput');
const stuNumTd = document.querySelector('.stuNumTd');
//ajax start
$.ajax({
url: '/stu/updateScore',
type: 'post',
data: {'korScore' : scoreInputs[0].value
, 'engScore': scoreInputs[1].value
, 'mathScore':scoreInputs[2].value
,'stuNum': stuNumTd.innerText },
success: function(result) {
alert('점수 등록 완료!!!');
},
error: function() {
alert('실패');
}
});
//ajax end
}
}
실습 내용
- 학급 및 학생 목록 조회 좌측화면에서 행마다 '삭제'버튼 이 들어있는 컬럼명을 하나 만든다.
- 삭제버튼 클릭 시, 해당 학생정보 목록에서 삭제한다.
(ajax이용해서 페이지이동없이 만든다)- 삭제버튼 클릭시, 해당 학생을 목록줄에서 지워준다
- 삭제완료시 '삭제성공' alert 창을 띄운다
- onclick 넘어갈때는 매개변수로 데이터 던져줘야한다. 타임리프방식은
[[${}]]
안에 데이터 넣어준다.
: 단, html과 js와 같은 내용이 담긴 똑같은 td태그 여야한다!
:학생성적 삭제 쿼리문과 학생정보 삭제 쿼리문 각각 만든다.
※(주의) 학생성적 점수를 삭제 하는 쿼리문에서 성적번호 scoreNum 이아니라 학생번호 stuNum 을 where절 조건절로 넣은 이유는 어차피 학생번호와 성적번호가 같은 번호이기 때문이다. 또 나중에 쿼리문 만들 때 매개변수 하나(int stuNum)면 되므로 편하기 때문!
<!-- 목록조회에서 학생정보 삭제 -->
<!-- 학생점수 삭제 -->
<delete id="deleteScore">
DELETE SCORE_INFO
WHERE STU_NUM = #{stuNum}
</delete>
<!-- 학생 정보삭제 -->
<delete id="deleteStu">
DELETE STUDENT_INFO
WHERE STU_NUM = #{stuNum}
</delete>
: 학생점수 + 학생정보삭제 동시에 처리
- 트랜잭션 ServiceImpl에서만 사용하여 처리한다(컨트롤러 x)
@Transactional(rollbackFor = Exception.class)
- 트랜잭션 예외처리 어노테이션( try-catch문 대체)
rollbackFor
: 어떤 예외가 발생했을 때 롤백을 할건가?(Exception 상속기능 때문에 어떠한 예외종류에도 다 받는다)sqlSession.commit();
->jsp는 자동커밋이 안되지만 스프링은 자동커밋이라 필요없다
StuService
void deleteInfo(int stuNum);
: 두개의 삭제 쿼리문 하나처럼 만들기
StuserviceImpl
@Override
@Transactional(rollbackFor = Exception.class)
public void deleteInfo(int stuNum) {
//쿼리 2개이상 실행시 무조건 트랜잭션처리한다
sqlSession.delete("stuMapper.deleteScore", stuNum);
sqlSession.delete("stuMapper.deleteStu",stuNum);
}
일반적 js 변수명 표기법: 문자열 _ 사용하여 연결 ex) stu_num
:stu_num(js방식 변수명) 이름으로 넘어온 데이터를 stuNum(자바방식)으로 넣어주겠다.
//삭제
@ResponseBody
@PostMapping("/deleteStu")
public void deleteStu(@RequestParam(name = "stu_num") int stuNum) {
stuService.deleteInfo(stuNum);
}
- (아래부분) 별도 Ajax 메소드
deleteStuAjax
만들어 간편하게 사용한다.deleStu onclick
넘어올때 매개변수 던져준거 받기(id값 부여하면 반복문이기때문에 반복되어서 안됨)selectedTag
: 내가 클릭한 그(this) 버튼. html에서 this값으로 내가 선택한 태그를 말함alert(selectedTag.value);
//삭제selectedTag.remove();
//해당 삭제버튼만 제거
- ajax를 사용하면 alert창을 띄워도 뒤에 화면이 그려진 상태에서 가능하다!
- 삭제된 테이블 다시 그려줘야 하는데 방법 2가지가 있다.
- 방법1_메소드 불러와서 다시 삭제된 테이블 그려준다(ajax필요없는 방법)
changeClass();
- 방법2_내가 삭제한 줄만 테이블에서 지워준다.(ajax사용필요 있는 방법)
: 삭제버튼을 감싸고 있는 tr태그를 선택해 그 것만 지워준다.
- 방법2_(1)
selectedTag.closest('tr').remove();
: closest('tr'): 자신을 감싸고 있는 가장 가까운 tr을 찾아감.- 방법2_(2)
selectedTag.parentElement.parentElement.remove();
function deleteStuInfo(stu_num,selectedTag){
const ans = confirm("삭제하시겠습니까?");
if(ans) {//ans == ture 와 같다
deleteStuAjax(stu_num,selectedTag);
}
}
//----------------ajax 함수-----------------------//
// 삭제 클릭시, ajax 진행
function deleteStuAjax(stu_num,selectedTag){
//ajax start
$.ajax({
url: '/stu/deleteStu',
type: 'post',
data: {'stu_num': stu_num },
success: function(result) {
selectedTag.closest('tr').remove();
selectedTag.parentElement.parentElement.remove();
alert('삭제완료!');
},
error: function() {
alert('실패');
}
});
//ajax end
: 삭제버튼 클릭시, 해당 학생 목록줄 지워준다
this
: 내가 하려는 행동 자체의 데이터를 던진다. this 넣어주면, 내가 선택하 태그 값을 뜻함
<td><input type="button" value="삭제" th:onclick="deleteStuInfo([[${stuInfo.stuNum}]], this)" ></td>
- js에서 this를 내가 원하는 매개변수명으로 받아온다. (selectedTag)
<실습결과>
프로젝트명 : AjaxTest (총 생성된 파일 내용)
<!-- 점수등록(수정) : insert/update 둘 중 하나 상관없다-->
<!-- ON절에서 점수정보테이블에 학생번호가 이미 있다면,
UPDATE실시하고 그렇지않다면 INSERT를 실시한다 -->
<insert id="updateScore">
MERGE INTO SCORE_INFO
USING DUAL
ON (STU_NUM = #{stuNum})
WHEN MATCHED THEN
UPDATE
SET
KOR_SCORE = #{korScore}
, ENG_SCORE = #{engScore}
, MATH_SCORE = #{mathScore}
WHERE STU_NUM = #{stuNum}
WHEN NOT MATCHED THEN
INSERT (
SCORE_NUM ,KOR_SCORE , ENG_SCORE , MATH_SCORE, STU_NUM
)
VALUES (
(SELECT MAX(NVL(SCORE_NUM,0)) + 1 FROM SCORE_INFO) , #{korScore} , #{engScore} , #{mathScore} ,#{stuNum}
)
</insert>
<!-- 목록조회에서 학생정보 삭제 -->
<!-- 학생점수 삭제 -->
<delete id="deleteScore">
DELETE SCORE_INFO
WHERE STU_NUM = #{stuNum}
</delete>
<!-- 학생 정보삭제 -->
<delete id="deleteStu">
DELETE STUDENT_INFO
WHERE STU_NUM = #{stuNum}
</delete>
- closest('tr'): 자신을 감싸고 있는 가장 가까운 tr을 찾아감.
selectedTag.closest('tr').remove();
//학급이 변경 할 때(셀렉트박스) 진행되는 함수
function changeClass() {
//classCode 값 가져오기
// 셀렉트 태그 선택한 것의 value값가져온 것이 classCode
const classCode = document.querySelector('select').value;
//ajax start
//$로시작하는 것은 제이쿼리 문법이다.
$.ajax({
url: '/stu/getStuListAjax', //요청경로
type: 'post',
data: { 'classCode': classCode }, //필요한 데이터
//컨트롤러가 실행하면 ajax실행으로 success구문 실행된다.
//페이지이동이 없는 대신, 조회된 데이터로 테이블을 다시 작성해야한다(ajax단점)
success: function(result) {
//컨트롤러 내용 진행 후, 자동실행 구문
//테이블을 다시 그려야한다
//테이블 선택
//열려있는 html파일(document)에서 테이블 선택
const stuListTable = document.querySelector('.stuListTable');
// 테이블에서 티바디 선택
const tbody = stuListTable.querySelector('tbody');
// 위 코드와 동일 : const tbody = document.querySelector('.stuListTable > tbody');
//먼저 tbody를 지워준다
stuListTable.removeChild(tbody);
/* //()test)
str += 'java';//str = str + 'java'
str += 'c++';//javac++ (문자열 연결)
alert(str);
*/
//테이블을 다시 그린다
//(test)추가할 <tbody>태그 생성
let str = '';
str += '<tbody>';
//학생 수만큼만 tr태그 만든다
for (const stu of result) {
//`` 백팁 이용해서 문자열 연결 ver.
str += '<tr>';
str += `<td>${stu.stuNum}</td>`;
str += `<td>`;
/* 타임리프 여기서는 해석 x th:text 사용불가 -> ${} 사용 */
//상세보기 메소드 이동시, 학생번호도 넘겨줘야 실패창이 안뜬다!!
str += `<spantoken interpolation">${stu.stuNum});">${stu.stuName}</span>`;
str += `</td>`;
str += `<td>${stu.stuAge}</td>`;
str += `<td>${stu.className}</td>`;
/*학급을 바꿔도 삭제버튼나오도록 수정! 삭제 td태그 추가하기*/
str += `<td><input type="button" value="삭제"token interpolation">${stu.stuNum})"></td>`;
str += '</tr>';
//'' 홀따옴표 이용 문자열 연결 ver.
/* str += '<tr>';
str += '<td>'+stu.stuNum+'</td>';//학번
str += '<td>'+stu.stuName+'</td>';//이름
str += '<td>'+stu.stuAge+'</td>';//나이
str += '<td>'+stu.className+'</td>';//학급명
str += '</tr>';*/
}
str += '</tbody>';
stuListTable.insertAdjacentHTML('beforeend', str);
},
error: function() {
alert('실패');
}
});
//ajax end
}
// 이름을 클릭했을 시, 학생 상세정보 조회
function showDetail(stuNum) {//매개변수 학생번호 데이터 받아오기
//테이블 그리기 전에, 먼저 컨트롤러가서 필요한 데이터 가져와야한다.
//ajax 사용이유?
//디비작업 조회해야하는데 이전 목록조회한 곳에서 데이터를 가져와서 상세정보 조회를 하는데 별도로 페이지이동 필요없어서!
//ajax start
$.ajax({
url: '/stu/getDetailInfo',
type: 'post',
data: { 'stuNum': stuNum },
//컨트롤러가 실행하면 ajax실행으로 success구문 실행된다.
success: function(result) {//리턴값으로 받는 결과 result(상세조회 쿼리결과값)
let str = '';
/*html에서 나타날 코드 여기 작성 */
str += '<table class = "stuDetailTable">';
str += '<tr>';
str += '<td>학생번호</td>';
str += '<td>학생이름</td>';
str += '<td>소속 학급명</td>';
str += '</tr>';
str += '<tr>';
str += `<td class="stuNumTd">${result.stuNum}</td>`;
str += `<td>${result.stuName}</td>`;
str += `<td>${result.className}</td>`;
str += '</tr>';
str += '<tr>';
str += '<td>국어점수</td>';
str += '<td>영어점수</td>';
str += '<td>수학점수</td>';
str += '</tr>';
/* 점수 데이터 가져오는 이 영역을 input 태그로 바꾸기 */
str += '<tr id="scoreTr">';
str += `<td>${result.korScore}</td>`;
str += `<td>${result.engScore}</td>`;
str += `<td>${result.mathScore}</td>`;
str += '</tr>';
str += '</table>';
//점수 등록 버튼 생성: 점수등록 클릭시, input태그로 변경
str += '<div style="text-align=center; margin-top:15px;">';
str += '<input id="scoreBtn" type="button" value="점수등록">';//id값 부여 점수등록버튼
str += '</div>';
const detailTd = document.querySelector('#detailTd');
//빈값으로 바꾸고 붙이기를 반복한다
//innerHTML : html파일에 있는 선택한 태그에 빈문자를 주면 선택태그 안의 내용(innerHTML) 모두 삭제
detailTd.innerHTML = '';
//insertAdjacentHTML('(위치)', 넣을 문자) : 뒤에 문자열을 어느 위치에 넣을지
detailTd.insertAdjacentHTML('beforeend', str);
},
error: function() {
alert('실패');
}
});
//ajax end
}
//[setScore() 메소드 만들 시, 알아야할 점]
// 점수등록 누르면 원래 그린 테이블 지우고 다시 그려줘야한다.(이전 목록조회와 같음)
// 그래서 원래 점수값 데이터 받는 td태그부분들을 지워주고 다시 그려준다.
//1) 태그를 먼저 선택해야한다.(id값부여)
//선택한 태그의 속성값 데이터 불러오기
//주의) korScoreTd 안의 글자와 value속성값은 서로 다르다!
//- korScoreTd.vlaue;//korScoreTd의 value 속성값
//- korScoreTd.innerText;//td태그사이 text값 ${result.korScore}
//방법1) 공부용_ 반복이 많아서 다른 방법 사용
//const korScoreTd = document.querySelector('#korScoreTd');
//korScoreTd.innerText='';//원래 있는 국어점수 내용 지우기(빈값주기)
//const engScoreTd = document.querySelector('#engScoreTd');
//engScoreTd.innerText='';//원래 있는 국어점수 내용 지우기(빈값주기)
//const mathScoreTd = document.querySelector('#mathScoreTd');
//mathScoreTd.innerText='';//원래 있는 국어점수 내용 지우기(빈값주기)
//점수등록 클릭시, 점수값있는 영역을 input태그로 변경
function setScore() {
const btn = document.querySelector('#scoreBtn');//수정) input태그 여러개이기때문에 id값부여하여 태그선택한다
if (btn.value == '점수등록') {//만약 버튼이 점수등록 일때는 점수 수정 update 실시(update 점수수정)
//방법2) tr에 id값 부여하여 태그 선택(반복문 피하기위해)
//1개값만 들고올 때 querySelector 사용:const scoreTr = document.querySelector('#scoreTr');
//여러개 td들고오니까 모두 들고올려면 querySelectorAll 사용
const scoreTds = document.querySelectorAll('#scoreTr > td');
//여러개 데이터 뽑을 때-> 반복문사용!!!
//바로 객체명 사용시 오류발생_여러 데이터있을 때 -> scoreTds.innerText='';
for (const scoreTd of scoreTds) {
//1)원래가지고 있는 데이터(점수 score )를 저장:값을 가져올때 innerHTML
const score = scoreTd.innerText;//td의 내용은 innerHTML
//2)내용만 지우기(빈값). 값을 설정 할 때, innerText
scoreTd.innerText = '';
//3)scoreTd 에 input태그 넣기(``사용, 화면에 보이는 값은 value 속성)
// 각 과목별 점수데이터 가져오기 위해 class속성값 설정해준다.
const str = `<input class="scoreInput" type="text" style="width:90%;" value="${score}">`;
//4) 원하는 위치에 str 넣기
scoreTd.insertAdjacentHTML("afterbegin", str);//beforeend도 가능
}
//점수등록 버튼 '확인'으로 바꾸기-> 태그 선택 먼저하기
//const btn = document.querySelector('input[type="button"]');
btn.value = '확인';//눈에 보이는 속성 value
}
else { //그렇지 않으면('확인'버튼일 때), 점수등록한다(DB작업)_merge into 사용
const scoreInputs = document.querySelectorAll('.scoreInput');//각 점수의 value값 데려오기위해(여러개)
const stuNumTd = document.querySelector('.stuNumTd');
//ajax start
$.ajax({
url: '/stu/updateScore',
type: 'post',
//위의 만든 scoreInputs 의 값이 여러개이기때문에 리스트처럼 순서대로 value값 데이터로 뽑는다
data: {'korScore' : scoreInputs[0].value, 'engScore': scoreInputs[1].value , 'mathScore':scoreInputs[2].value ,'stuNum': stuNumTd.innerText },
success: function(result) {
alert('점수 등록 완료!!!');
},
error: function() {
alert('실패');
}
});
//ajax end
}
}
//삭제버튼 클릭 시, 목록조회에서 삭제
function deleteStuInfo(stu_num,selectedTag){
//deleStu onclick넘어올때 매개변수 던져준거 받기(id값 부여하면 반복문이기때문에 반복되어서 안됨)
//selectedTag : 내가 클릭한 그(this) 버튼. html에서 this값으로 내가 선택한 태그를 말함
//alert(selectedTag.value);//삭제
//selectedTag.remove();//해당 삭제버튼만 제거
const ans = confirm("삭제하시겠습니까?");
if(ans) {//ans == ture 와 같다
deleteStuAjax(stu_num,selectedTag);
}
}
//----------------ajax 함수-----------------------//
// 삭제 클릭시, ajax 진행
function deleteStuAjax(stu_num,selectedTag){
//ajax start
$.ajax({
url: '/stu/deleteStu',
type: 'post',
data: {'stu_num': stu_num },//stu_num:일반적 자바스크립트식 표기방식
success: function(result) {
//ajax를 사용하면 alert창을 띄워도 뒤에 화면이 그려진 상태에서 가능하다!
//삭제된 테이블 다시 그려주기
//방법1_메소드 불러와서 다시 삭제된 테이블 그려준다(ajax필요없는 방법)
//changeClass();
//방법2_내가 삭제한 줄만 테이블에서 지워준다.(ajax사용)
//삭제버튼을 감싸고 있는 tr태그를 선택해 그 것만 지워준다.
//방법2_(1)
selectedTag.closest('tr').remove();// closest('tr'): 자신을 감싸고 있는 가장 가까운 tr을 찾아감.
//방법2_(2)
selectedTag.parentElement.parentElement.remove();
//알림창띄우기
alert('삭제완료!');
},
error: function() {
alert('실패');
}
});
//ajax end
}
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<style type="text/css">
.layoutTable{
width: 1000px;
margin: 0 auto;
border: 1px solid black;
border-collapse: collapse;
margin-top: 40px;
text-align: center;
}
.layoutTable > tbody >tr, .layoutTable > tbody > tr >td{
border: 1px solid black;
}
.layoutTable > tbody> tr{/* 자식 */
height: 500px;
}
.layoutTable > tbody> tr > td{/* 자식 */
vertical-align: top;
padding: 20px;
}
.stuListTable, .stuDetailTable{
width: 400px;
border: 1px solid gray;
border-collapse: collapse;
margin: 0 auto;
text-align: center;
}
.stuListTable tr,.stuListTable td{/* 자손 */
border: 1px solid gray;
}
.stuDetailTable tr,.stuDetailTable td{/* 자손 */
border: 1px solid gray;
}
span:hover {
cursor: pointer;/* 손가락모양으로 커서변경 */
}
</style>
</head>
<body>
<table class="layoutTable">
<colgroup>
<col width="50%">
<col width="50%">
</colgroup>
<tr>
<td>
<div style="margin-bottom: 10px;" align="center">
<!-- onchange : select 값이 바뀔 때마다 "" 실행 -->
<select onchange="changeClass()">
<option value="0">전체</option>
<option th:each="classInfo : ${classList}" th:text="${classInfo.className}" th:value="${classInfo.classCode}"></option>
</select>
</div>
<div>
<!-- 화면이 뜨자마자 이 테이블은 없다. 이름을 클릭해야만 화면에 보인다 -->
<table class="stuListTable">
<thead>
<tr>
<td>학번</td>
<td>이름</td>
<td>나이</td>
<td>학급명</td>
<!-- 삭제버튼 추가 학급별조회하면 사라지기때문에 html이아니라 js에 추가해야한다!!-->
<td id="deleteTd"></td>
</tr>
</thead>
<tbody>
<th:block th:each="stuInfo : ${stuList}" >
<tr>
<td th:text="${stuInfo.stuNum}" th:value="${stuInfo.stuNum}" ></td>
<!-- 이름을 클릭하면 상세정보 메소드로 이동 -->
<!-- td태그 안에 말고 span태그안에 속성넣으면 글자만 클릭해야 상세조회 된다!(차이점) -->
<!-- <td th:text="${stuInfo.stuName}"></td> -->
<!-- 타임리프 온클릭으로 데이터 보내는 방법 -->
<td><!-- 타임리프 온틀릭(th:onclick)을 사용해야 안에있는 문자가 변수로 인식한다! -->
<!-- 학생이름클릭하면 학생번호 데이터를 가져가야하기때문에!! -->
<span th:text="${stuInfo.stuName}"
th:onclick="showDetail([[${stuInfo.stuNum}]]);"></span>
</td>
<td th:text="${stuInfo.stuAge}" ></td>
<td th:text="${stuInfo.ClassName}" ></td>
<!-- 삭제버튼 클릭시, 해당 학생 목록줄 지워준다
this : 내가 하려는 행동 자체의 데이터를 던진다. this 넣어주면, 내가 선택하 태그 값을 뜻함-->
<td><input type="button" value="삭제" th:onclick="deleteStuInfo([[${stuInfo.stuNum}]], this)" ></td>
</tr>
</th:block>
</tbody>
</table>
</div>
</td>
<!-- 우측화면 상세정보 테이블 js에서 메소드 실행-->
<td id="detailTd">
<!--상세정보 테이블 들어가는 곳 -->
</td>
</tr>
</table>
<!-- jquery 문법 로딩 -->
<script src="https://code.jquery.com/jquery-latest.min.js"></script>
<!-- 자바스크립트 파일과연결 -->
<script type="text/javascript" th:src="@{/stu_manage.js}"></script>
</body>
</html>
package kh.study.ajax.controller;
import java.util.List;
import javax.annotation.Resource;
import org.apache.ibatis.jdbc.SQL;
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;
import org.springframework.web.bind.annotation.ResponseBody;
import kh.study.ajax.service.StuService;
import kh.study.ajax.vo.ClassVO;
import kh.study.ajax.vo.ScoreVO;
import kh.study.ajax.vo.StuVO;
@Controller
@RequestMapping("/stu")
public class StuController {
//service 객체를 만들어줘야 안에 메소드사용가능!
@Resource(name = "stuService")//@Service("/stuService") 인터페이스와 연결
private StuService stuService;
//학급 및 학생 목록 조회
@RequestMapping("/list")
public String selectStuList(Model model) {
model.addAttribute("classList",stuService.getClassList());
model.addAttribute("stuList",stuService.getStuList(0));//매개변수 수정
return "stu_manage";//페이지이동
}
//셀렉트박스 학급별 조회
@ResponseBody//ajax가 진행되니 페이지이동하지말라는 어노테이션
@PostMapping("/getStuListAjax")
public List<StuVO> getStuListAjax(int classCode) {// ajax를 사용하면 무조건 string(페이지명_문자)이 아니다 -> 모르니까 void
//선택된 학급의 학생 목록 조회(List<StuVO> list 자료형 선언하고 리턴해준다!)
List<StuVO> list = stuService.getStuList(classCode);
return list;//*자료형! 객체 데이터 보내기
}
//학생상세조회
@ResponseBody
@PostMapping("/getDetailInfo")
public StuVO getDetailInfo(int stuNum) {
//상세조회(컨트롤러 ->(ajax) js의 success 실행)
return stuService.getDetailStu(stuNum);//쿼리실행 결과 데이터 던져주기
}
//학생점수 등록(수정)
@ResponseBody
@PostMapping("/updateScore")
public int updateScore(StuVO stuVO) {
//ajax의 데이터를 받아온다 -> 확인 하는 방법은 toStriong 메소드출력해서 확인해본다
System.out.println(stuVO);
return stuService.updateScore(stuVO);
}
//삭제
@ResponseBody
@PostMapping("/deleteStu")
public void deleteStu(@RequestParam(name = "stu_num") int stuNum) {//stu_num(js방식 변수명) 이름으로 넘어온 데이터를 stuNum(자바방식)으로 넣어주겠다.
//학생점수+학생정보 삭제
stuService.deleteInfo(stuNum);
}
///////연습용 메소드 /////////////
@GetMapping("/dn")//localhost:8081/stu/dn
public String deleteNode() {
return "delete_node";//페이지이동
}
}
package kh.study.ajax.service;
import java.util.List;
import kh.study.ajax.vo.ClassVO;
import kh.study.ajax.vo.ScoreVO;
import kh.study.ajax.vo.StuVO;
public interface StuService {
//학급목록 조회
List<ClassVO> getClassList();
List<StuVO> getStuList(int classCode);//매개변수 수정
StuVO getDetailStu(int stuNum);
int updateScore(StuVO stuVO);
void deleteInfo(int stuNum);//두개의 삭제 쿼리문 하나처럼 만들기(트랜잭션필요)
}
package kh.study.ajax.service;
import java.util.List;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import kh.study.ajax.vo.ClassVO;
import kh.study.ajax.vo.ScoreVO;
import kh.study.ajax.vo.StuVO;
@Service("stuService")//컨트롤러연결
public class StuServiceImpl implements StuService {
@Autowired//어노테이션으로 객체생성
private SqlSessionTemplate sqlSession;
//학급목록조회
@Override
public List<ClassVO> getClassList() {
return sqlSession.selectList("stuMapper.getClassList");
}
//학생목록조회
@Override
public List<StuVO> getStuList(int classCode) {//매개변수 수정
return sqlSession.selectList("stuMapper.getStuList",classCode);
}
//학생상세정보조회
@Override
public StuVO getDetailStu(int stuNum) {
return sqlSession.selectOne("stuMapper.getDetailStu",stuNum);
}
//학생등록(수정)
@Override
public int updateScore(StuVO stuVO) {
return sqlSession.insert("stuMapper.updateScore", stuVO);//update도 상관없다
}
//학생점수+ 학생정보삭제
@Override
@Transactional(rollbackFor = Exception.class)//서비스임플에서만 사용가능하고,컨트롤러 불가능!
//트랜잭션 예외처리 어노테이션( try-catch문 대체)
//rollbackFor: 어떤 예외가 발생했을 때 롤백을 할건가?(Exception 상속기능 때문에 어떠한 예외종류에도 다 받는다)
public void deleteInfo(int stuNum) {
//쿼리 2개이상 실행시 무조건 트랜잭션처리한다
sqlSession.delete("stuMapper.deleteScore", stuNum);
sqlSession.delete("stuMapper.deleteStu",stuNum);
//sqlSession.commit();->jsp는 자동커밋이 안되지만 스프링은 자동커밋이라 필요없다
}
}