src/main/java/songjeongwoo.godgamez.domain
에 Quest 도메인 추가
package songjeongwoo.godgamez.domain;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class Quest {
private int qstId;
private Class cls;
private String qstName;
private int difficulty;
private String qstContent;
private String qstImg;
}
src/main/resources/songjeongwoo/godgamez/dao/map/questMap.xml
<insert id='insertQuest'>
insert into quests(quest_id, class_id, quest_name, difficulty, quest_content, image_id)
values(qsts_qstId_seq.nextval, #{cls.clsId}, #{qstName}, #{difficulty}, #{qstContent}, #{qstImg})
</insert>
<select id='selectQuest' resultMap='questMap'>
<include refid="selectAdminQsts"/>
where quest_id = #{qstId}
</select>
<sql id="selectAdminQsts">
select q.*, c.*
from quests q join classes c
on q.class_id = c.class_id
</sql>
<update id='updateQuest'>
update quests
set quest_name = #{qstName}, difficulty = #{difficulty}, quest_content = #{qstContent}
where quest_id = #{qstId}
</update>
src/main/resources/songjeongwoo/godgamez/config/app.properties
에 questAttachDir=/res/quest 경로를 추가해준다.
톰켓 설치 시 deploy할 폴더로 지정해주었던 경로
이다.questAttachDir=/res/quest
src/main/java/songjeongwoo.godgamez.web
에서 AttachController.java 파일을 만들고 코드를 작성한다.
수정할 경우 덮어쓰기
가 된다.package songjeongwoo.godgamez.web;
import java.io.File;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
@Controller
@RequestMapping
public class AttachController {
@Value("${attachDir}")
private String attachDir;
@Value("${questAttachDir}")
private String questAttachDir;
@PostMapping("/quest/attach")
@ResponseBody
public void questAttach(MultipartFile attachFile, HttpServletRequest request) {
String dir = request.getServletContext().getRealPath(questAttachDir);
String fileName = request.getParameter("curQstId") + ".jpg";
save(dir + "/" + fileName, attachFile);
}
private void save(String fileName, MultipartFile attachFile) {
try {
attachFile.transferTo(new File(fileName));
} catch(Exception e) {
e.printStackTrace();
}
}
//퀘스트 삭제 시 해당 퀘스트 이미지 삭제
@DeleteMapping("/quest/attach/del")
public void questAttachDel(@RequestBody int qstId, HttpServletRequest request) {
String dir = request.getServletContext().getRealPath(questAttachDir);
System.out.println(qstId);
System.out.println(dir + "/" + qstId + ".jpg");
File file = new File(dir + "/" + qstId + ".jpg");
if(file.exists()) {
file.delete();
System.out.println("del");
}
}
}
//퀘스트 추가
function addProcQst() {
let newQstName = $('#addFixProcModal #qstName').val()
let newDifficulty = $('input[type="radio"]:checked').val()
let newQstContent = $('#addFixProcModal #qstContent').val()
let clsId = $('#addFixProcModal #clsId').val()
let newClsName = $('#addFixProcModal #cls').val().split('>')[2].replace(" ", "")
let questDataIn = {}
$.ajax({
url: '/godgamez/class/search',
method: 'post',
data: JSON.stringify({clsName: newClsName}),
contentType: 'application/json'
}).done(clss => {
let clsObj = clss[0]
questDataIn = {
qstId: 0,
cls: clsObj,
qstName: newQstName,
difficulty: newDifficulty,
qstContent: newQstContent,
qstImg: clsId + '_' + newQstName //DB에 저장될 네이밍(클래스당 여러 개 퀘스트가 있을 수 있기때문에 이렇게 지음)
}
$.ajax({
url: '/godgamez/quest/add',
method: 'post',
data: JSON.stringify(questDataIn),
contentType: 'application/json'
}).done(result => {
if(result) {
let questId
$.ajax({
url: '/godgamez/quest/qstId',
async: false, //ajax는 비동기방식, false로 쓰면 동기방식이 되기때문에 //전역변수에 ajax통신 값을 저장해서 블록 밖에서도 쓸 수 있게 해준다.
}).done(qstId => {
questId = qstId
})
$('#curQstId').val(questId)
//퀘스트 추가 시 이미지파일 추가
let form = $('#addFixQstImg')[0] //form DOM element
let formData = new FormData(form)
$.ajax({
url: '/godgamez/quest/attach',
method: 'post',
data: formData,
contentType: false, //false로 둘 경우, multipart/form-data로 전송됨
processData: false //false로 둘 경우, formData를 String으로 변환하지 않음
})
modal('퀘스트', '추가', '성공')
$('#doneBBtn').click(() => {
window.location.reload()
})
} else modal('퀘스트', '추가', '실패10', '알 수 없는 이유로 해당 작업에 실패했습니다.')
}).fail(() => modal('퀘스트', '추가', '실패10', '퀘스트명, 클래스, 난이도, 퀘스트 내용을 입력했는지 확인하세요.'))
})
}
//퀘스트 상세 조회
let qstId // 퀘스트 수정 시 사용
function qstDetail() {
//$(event.currentTarget) //클릭한 요소 읽기(js)
qstId = $(event.currentTarget).closest('.qstDetail').children('.qstId').text()
$.ajax({
url: `/godgamez/quest/list/\${qstId}`
}).done(qst => {
let qstName = qst.qstName
let mainCtg = qst.cls.mainCtg
let subCtg = qst.cls.subCtg
let clsName = qst.cls.clsName
let difficulty = qst.difficulty
let qstContent = qst.qstContent
if(!$('#qstChk:checked').length) {
$('.modal-title').html()
$('.modal-title').html('<b>퀘스트 상세조회 및 수정</b>')
$('#addFixProcModal #qstName').val(qstName)
$('#addFixProcModal #cls').siblings().remove()
$('#addFixProcModal #cls').attr('class', 'text-center border-0')
$('#addFixProcModal #cls').val(`\${mainCtg} > \${subCtg} > \${clsName}`)
switch(difficulty) {
case 1: $('#one').prop('checked', true); break;
case 2: $('#two').prop('checked', true); break;
case 3: $('#three').prop('checked', true); break;
case 4: $('#four').prop('checked', true); break;
case 5: $('#five').prop('checked', true);
}
$('#addFixProcModal #qstContent').val(qstContent)
$('.modal-footer #chngBtn').text("수정")
$('.modal-footer #chngBtn').attr('onclick', 'fixProcQst()')
$('#addFixProcModal').modal()
//퀘스트 이미지 불러오기
$('#msg').html("100MB 이하의 JPG, PNG파일을 제출하세요.")
$('#previewImg').attr('src', '/godgamez/res/quest/' + qst.qstId + '.jpg')
//$('#previewImg').attr('src', '/godgamez/res/quest/' + qst.cls.clsId + '_' + qstName + '.jpg')
} else modal('퀘스트', '상세조회', '실패10', '체크박스 해제 후 다시 시도하세요.')
}).fail(() => modal('퀘스트', '상세조회', '실패10', '알 수 없는 이유로 해당 작업에 실패했습니다.'))
}
//퀘스트 수정
function fixProcQst() {
let newQstName = $('#addFixProcModal #qstName').val()
let newDifficulty = $('input[type="radio"]:checked').val()
let newQstContent = $('#addFixProcModal #qstContent').val()
let clsId = $('#addFixProcModal #clsId').val()
questDataIn = {
qstId: qstId,
qstName: newQstName,
difficulty: newDifficulty,
qstContent: newQstContent,
qstImg: clsId + '_' + newQstName
}
$.ajax({
url: '/godgamez/quest/fix',
method: 'put',
data: JSON.stringify(questDataIn),
contentType: 'application/json'
}).done(result => {
if(result) {
if($('#addFixQstImg img').attr('src') == readerResult) { //cf) 322번째 줄 코드
$('#curQstId').val(qstId.trim())
// 퀘스트 수정 시 이미지파일 덮어쓰기
let form = $('#addFixQstImg')[0] //form DOM element
let formData = new FormData(form)
$.ajax({
url: '/godgamez/quest/attach',
method: 'post',
data: formData,
contentType: false, //false로 둘 경우, multipart/form-data로 전송됨
processData: false //false로 둘 경우, formData를 String으로 변환하지 않음
})
modal('퀘스트', '수정', '성공')
$('#doneBBtn').click(() => window.location.reload())
}
modal('퀘스트', '수정', '성공')
$('#doneBBtn').click(() => window.location.reload())
} else modal('퀘스트', '삭제', '실패10', '알 수 없는 이유로 해당 작업에 실패했습니다.')
}).fail(() => modal('퀘스트', '삭제', '실패10', '알 수 없는 이유로 해당 작업에 실패했습니다.'))
}
//퀘스트 삭제 - script.js 함수명 공통
function delB() {
let actpdQstCnt = $('#qstChk:checked').closest('.qstDetail').children('.actpdQstCnt').text().trim();
let qstId = $('#qstChk:checked').closest('.qstDetail').children('.qstId').text().trim();
if(actpdQstCnt == 0 || actpdQstCnt == 'undefined') {
$.ajax({
url: `/godgamez/quest/del/\${qstId}`,
method: 'delete'
}).done(result => {
if(result) {
modal('퀘스트', '삭제', '성공')
$('#doneBBtn').click(() => window.location.reload())
//해당 퀘스트 이미지 삭제
$.ajax({
url: '/godgamez/quest/attach/del',
method: 'delete',
data: JSON.stringify(qstId),
contentType: 'application/json'
}).done(() => {
console.log('del')
})
} else modal('퀘스트', '삭제', '실패10', '알 수 없는 이유로 해당 작업에 실패했습니다.')
}).fail(() => modal('퀘스트', '삭제', '실패10', '알 수 없는 이유로 해당 작업에 실패했습니다.'))
} else if(actpdQstCnt > 0) modal('퀘스트', '삭제', '실패10', '현재 해당 퀘스트를 수행 중인 회원이 존재합니다.')
else modal('퀘스트', '삭제', '실패10', '체크박스를 1개만 선택하세요.')
}
<div id='addFixProcModal' class='modal fade' tabindex='-2'>
<div class='modal-dialog'>
<div class='modal-content'>
<div class='modal-header'>
<h6 class='modal-title'></h6>
<button type='button' class='close' data-dismiss='modal'>×</button>
</div>
<form class='modal-body' id='addFixQstImg'>
<div class='contatiner ml-3 mb-3' id='modalTable'>
<div class='row'>
<div class='col'>
<table>
<tbody>
<tr>
<th></th>
<td><input type='hidden' id='curQstId' name='curQstId'/></td>
</tr>
<tr>
<th>퀘스트명</th>
<td>
<input type='text' placeholder='2글자 이상의 한글로 입력하세요.'
class='text-center form-control' id='qstName' name='qstName'/>
</td>
</tr>
<tr>
<th>클래스</th>
<td>
<input type='text' id='clsId' hidden='true'/>
<div id='div' class='text-center form-control'>
<input type='text' class='border-0' placeholder='1개의 클래스를 선택하세요' id='cls' readonly/>
<button type='button' class='btn border float-right' id='srchClsBtn'>
<i class="fas fa-search float-center"></i>
</button>
</div>
</td>
</tr>
<tr height='5rem'></tr>
<tr>
<th>난이도</th>
<td>
<input type='radio' id='one' name='difficulty' class='ml-3' value='1'/>1
<input type='radio' id='two' name='difficulty' class='ml-3' value='2'/>2
<input type='radio' id='three' name='difficulty' class='ml-3' value='3'/>3
<input type='radio' id='four' name='difficulty' class='ml-3' value='4'/>4
<input type='radio' id='five' name='difficulty' class='ml-3' value='5'/>5
</td>
</tr>
<tr height='5rem'></tr>
<tr>
<th>퀘스트 내용</th>
<td>
<input type='text' placeholder='50글자 이하의 한글로 입력하세요.'
class='text-center form-control' id='qstContent'/>
</td>
</tr>
<tr height='5rem'></tr>
<tr>
<th rowspan='5'>이미지</th>
<td>
<span class='text-muted' id='msg'>
100MB 이하의 JPG, PNG파일을 제출하세요.
</span>
</td>
</tr>
<tr height='5rem'></tr>
<tr>
<td>
<input type='file' name='attachFile' id='fileBtn' accept='.jpg, .png'/>
</td>
</tr>
<tr height='5rem'></tr>
<tr>
<td>
<img id='previewImg' class='w-100 m-0' alt='이미지가 존재하지 않습니다.'/>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class='modal-footer justify-content-center'>
<button type='button' class='btn btn-outline-secondary' onClick='modal("퀘스트", "추가", "중단")'>취소</button>
<button type='button' id='chngBtn' class='btn btn-outline-secondary' onClick='addProcQst()'>추가</button>
</div>
</form>
</div>
</div>
</div>
C:\DEV\GodGamezDeploy\wtpwebapps\godgamez
는 Tomcat 설치 시 deploy하기 위해 만들었던 디렉토리