아래 기능들을 구현하기 위해 전체 코드 중 주요하게 바뀌는 부분만 작성해보겠다
<form action="reg" method="post"> <!-- 서블릿을 처리기로 해서 사용자가 등록한 내용을 저장하도록 서버에 post로 보내고, 서버가 redirect해서 등록 내용이 반영된 목록 페이지 보여주게 하기 -->
<table border="1">
<tr>
<th>제목</th> <!-- 컬럼 내에서의 제목: th -->
<td colspan="3"><input type="text" name="title" value=""></td> <!-- DB에 해당되는 내용 나오게 하기 -->
</tr>
<tr>
<th>첨부파일</th>
<td colspan="3"></td>
</tr>
<tr>
<td colspan="4">
<textarea rows="20" cols="80" name="content"></textarea>
</td>
</tr>
</table>
<div>
<input type="submit" value="저장"> <!--서블릿 처리기(RegController)를 활용해 서버에 post하기-->
<a href="list.jsp">취소</a>
</div>
</form>
@WebServlet("/notice/reg")
public class RegController extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String title = request.getParameter("title");
String content = request.getParameter("content");
NoticeService service = new NoticeService();
try {
Notice notice = new Notice();
notice.setTitle(title); // 등록할 내용만 set 메서드로 바꾸기
notice.setWriterId("minju");
notice.setContent(content);
service.insert(notice);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
response.sendRedirect("list.jsp"); // 등록한 후에는 list.jsp로 rediret하기
}
}
public int insert(Notice notice) throws ClassNotFoundException, SQLException {
int result = 0;
// 바꿀 부분은 ?로 채워주기
String sql = "INSERT INTO NOTICE(TITLE, WRITER_ID, CONTENT) VALUES(?, ?, ?)";
String url = "jdbc:oracle:thin:@hi.namoolab.com:1521/xepdb1";
Class.forName("oracle.jdbc.OracleDriver");
Connection con = DriverManager.getConnection(url, "NEWLEC", "11111"); // 서블릿 프로세스가 끝나면 연결이 끊어짐
PreparedStatement st = con.prepareStatement(sql);
st.setString(1, notice.getTitle());
st.setString(2, notice.getWriterId());
st.setString(3, notice.getContent());
result = st.executeUpdate(); // update/delete/insert -> 결과집합이 없음
st.close();
con.close();
return result;
}
새로운 공지를 등록하는 폼에 제목과 내용을 입력한 후 저장 버튼을 누르면, 다음과 같이 목록에서 새로운 글이 등록된 것을 확인할 수 있다.
<div>
<a href="list.jsp">목록</a>
<a href="edit.jsp?id=<%=id%>">수정</a>
<!-- delete할 때 쿼리스트링과 함께 get 방식으로 보냄, 그래서 서블릿에서도 doGet 메소드로 처리 -->
<a href="del?id=<%=id%>" onclick="if(!confirm('정말 삭제하시겠습니까?')) return false;">삭제</a> <!-- doGet으로 처리 -->
<!-- true를 반환하면 기본 행위(a 링크) 동작, return false: e.preventDefault()라고 생각하기-->
</div>
@WebServlet("/notice/del")
public class DelController extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// querystring으로 전달된 id를 얻어오기
int id = Integer.parseInt(request.getParameter("id"));
NoticeService service = new NoticeService();
try {
// querystring으로 얻어온 id에 해당하는 공지 삭제하기
service.delete(id);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
response.sendRedirect("list.jsp");
}
}
public int delete(int id) throws ClassNotFoundException, SQLException {
int result = 0;
// 바꿀 부분은 ?로 채워주기
String sql = "DELETE FROM NOTICE WHERE ID=?"; // id만 넘겨받으면 됨
String url = "jdbc:oracle:thin:@hi.namoolab.com:1521/xepdb1";
Class.forName("oracle.jdbc.OracleDriver");
Connection con = DriverManager.getConnection(url, "NEWLEC", "11111"); // 서블릿 프로세스가 끝나면 연결이 끊어짐
PreparedStatement st = con.prepareStatement(sql);
st.setInt(1, id);
result = st.executeUpdate(); // update/delete/insert -> 결과 집합이 없음
st.close();
con.close();
return result;
}
detail.jsp 화면에서 삭제 버튼을 클릭하면 해당 공지글이 삭제되는 것을 목록에서 확인할 수 있다.
window.addEventListener("load", function() {
var section = document.querySelector("#ex10");
function bind(url) {
var request = new /*window.*/XMLHttpRequest();
request.onload = function() {
tbody.innerHTML = "";
// 새로운 목록으로 tbody를 채우기
var list = JSON.parse(request.responseText);
for(var i=0; i<list.length; i++) {
var tr = `<tr>
<td>${list[i].id}</td>
<td>${list[i].title}</td>
</tr>`;
tbody.insertAdjacentHTML("beforeend", tr);
}
// 2. 요청이 다 돼서 화면이 새로 갱신되면 스크린과 아이콘을 제거한다.
screen.remove();
}
request.open("GET", url, true); /
request.send(null);
// 1. 스크린과 아이콘을 띄운다.
var screen = document.createElement("div");
screen.style.width = "100%";
screen.style.height = "100%";
screen.style.backgroundColor = "black";
screen.style.position = "absolute";
screen.style.left = "0px";
screen.style.top = "0px";
screen.style.opacity = 0;
screen.style.transition = ".5s"; /*0.5초 동안 바뀜*/
setTimeout(function() { /*setTimeout을 하지 않았을 때는 opacity = 0 다음에 opacity = 0.7이 덮어씌워져서 적용됨*/
/*opacity = 0과 opacity = 0.7이 동시에 적용되지 않게 하기*/
screen.style.opacity = 0.7;
}, 0);
section.append(screen); // section의 자식으로 들어감
}
});
데이터 요청이 완료돼 화면이 갱신되기 전까지는 다음과 같은 스크린이 나타난다.
var closeButton = document.createElement("input");
closeButton.value = "취소";
closeButton.type = "button";
closeButton.style.alignSelf = "flex-start";
// closeButton.style.justifyContent = "end" // flex가 아닌 grid에서만 사용 가능
closeButton.style.position = "absolute";
closeButton.style.right = "0px";
screen.append(closeButton);
closeButton.onclick = function() {
request.abort(); // 취소한다고 하는 이벤트가 접수됨
}
request.onabort = function() { // 사용자가 이벤트를 중지했을 때 실행
console.log("aborted"); // 이벤트 중지 시 콘솔창에 aborted 출력하기
screen.remove();
}
로딩 중인 화면에서 취소 버튼을 클릭하면 onabort
이벤트가 작동되어, 다음과 같이 콘솔창에 aborted가 출력된다.
Gson gson = new Gson();
String json = gson.toJson(list); // 어떤 객체, 어떤 배열이든 json 문자열로 반환해줌
out.println(json);
이번 주도 참 빠르게 지나간 것 같다...!
오전에는 JSP로 그리고 오후에는 JavaScript로 CRUD 페이지를 만들어보며 웹 개발에 대한 감을 조금씩 익혀나가고 있는 중이다. 블로그에 그 날 배운 것을 정리하는 것도 중요하지만 무엇보다 가장 중요한 건 내 손으로 직접 코딩하는 것, 수업을 들으며 배운 내용을 지금 진행하고 있는 프로젝트에 적용해보는 것이라고 할 수 있겠다.
정처기 필기 공부도 해야 하고, 알고리즘 공부도 해야 하고 이것저것 신경쓸 게 많지만 지금 나에게 필요한 우선순위를 잘 파악해서 효율적으로 공부하도록 하자!👍