티스토리 뷰
목표: getNoticeList의 JDBC 코드를 구현한다.
기존의 NoticeListController.java에서 사용하던 쿼리문을 모두 NoticeService.java로 옮겨서 구현한다.
- NoticeListController.java : 사용자와의 입력과 출력(사용자와 상호작용)
- NoticeService.java :서비스 모듈을 따로 서비스만 전문으로 기능
코드:
- NoticeListController.java
package com.newlecture.web.controller;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.newlecture.web.entity.Notice;
import com.newlecture.web.service.NoticeService;
@WebServlet("/notice/list")
public class NoticeListController extends HttpServlet{
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/* NoticeService 객체를 만들고 함수를 사용 */
NoticeService service = new NoticeService();
List<Notice> list = service.getNoticeList();
request.setAttribute("list", list);
request.getRequestDispatcher("/WEB-INF/view/notice/list.jsp").forward(request, response);
}
}
- NoticeListController.java 일부
/* NoticeService 객체를 만들고 함수를 사용 */
NoticeService service = new NoticeService();
List<Notice> list = service.getNoticeList();
쿼리문은 모두 삭제하고 NoticeService 객체를 만들고 getNoticeList 함수를 사용한다.
- NoticeService.java
package com.newlecture.web.service;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import com.newlecture.web.entity.Notice;
public class NoticeService {
public List<Notice> getNoticeList(){
return getNoticeList("title", "", 1);
}
public List<Notice> getNoticeList(int page){
return getNoticeList("title", "", page);
}
public List<Notice> getNoticeList(String field/*TITLE, WRITER_ID */, String query/*A*/, int page){
List<Notice> list = new ArrayList<>();
/* field는 문자열의 값으로 들어가지 않기 때문에 ?로 채울수 없다. */
String sql = "SELECT * FROM( "
+ "SELECT ROWNUM NUM, N.* "
+ "FROM (SELECT * FROM NOTICE WHERE "+field+" LIKE ? ORDER BY REGDATE DESC) N "
+ ") "
+ "WHERE NUM BETWEEN ? AND ?";
//1, 11, 21, 31, .. -> an = 1+(page-1)*10
// 10, 20, 30, 40 -> page*10
String url = "jdbc:oracle:thin:@localhost:1521/XE";
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection con = DriverManager.getConnection(url, "programmers", "111111");
/* ?가 포함된 쿼리문을 사용 할 겨웅에는 preparedStatement를 사용한다. */
PreparedStatement st = con.prepareStatement(sql);
st.setString(1, "%"+query+"%");
st.setInt(2, 1+(page-1)*10);
st.setInt(3, page*10);
ResultSet rs = st.executeQuery();
while(rs.next()){
int id = rs.getInt("ID");
String title = rs.getString("TITLE");
String writerId = rs.getString("WRITER_ID");
Date regdate = rs.getDate("REGDATE");
String hit = rs.getString("HIT");
String files = rs.getString("FILES");
String content = rs.getString("CONTENT");
/* Notice라는 개체를 이용해서 */
Notice notice = new Notice(
id,
title,
writerId,
regdate,
hit,
files,
content
);
list.add(notice);
}
rs.close();
st.close();
con.close();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return list;
}
public int getNoticeCount() {
return getNoticeCount("title", "");
}
public int getNoticeCount(String field, String query) {
return 0;
}
public Notice getNotice(int id) {
String sql = "SELECT * FROM NOTICE WHERE ID=?";
return null;
}
public Notice getNextNotice(int id) {
String sql = "SELECT * FROM NOTICE "
+ "WHERE ID = ( "
+ "SELECT ID FROM NOTICE "
+ "WHERE REGDATE > (SELECT REGDATE FROM NOTICE WHERE ID=3) "
+ "AND ROWNUM = 1)";
return null;
}
public Notice getPrevNotice(int id) {
String sql = "SELECT ID FROM (SELECT * FROM NOTICE ORDER BY REGDATE DESC) "
+ "WHERE REGDATE < (SELECT REGDATE FROM NOTICE WHERE ID=5) AND ROWNUM = 1";
return null;
}
}
- NoticeService.java 일부
public List<Notice> getNoticeList(String field/*TITLE, WRITER_ID */, String query/*A*/, int page){
List<Notice> list = new ArrayList<>();
/* field는 문자열의 값으로 들어가지 않기 때문에 ?로 채울수 없다. */
String sql = "SELECT * FROM( "
+ "SELECT ROWNUM NUM, N.* "
+ "FROM (SELECT * FROM NOTICE WHERE "+field+" LIKE ? ORDER BY REGDATE DESC) N "
+ ") "
+ "WHERE NUM BETWEEN ? AND ?";
//1, 11, 21, 31, .. -> an = 1+(page-1)*10
// 10, 20, 30, 40 -> page*10
String url = "jdbc:oracle:thin:@localhost:1521/XE";
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection con = DriverManager.getConnection(url, "programmers", "111111");
/* ?가 포함된 쿼리문을 사용 할 겨웅에는 preparedStatement를 사용한다. */
PreparedStatement st = con.prepareStatement(sql);
st.setString(1, "%"+query+"%");
st.setInt(2, 1+(page-1)*10);
st.setInt(3, page*10);
ResultSet rs = st.executeQuery();
쿼리문에서 가장 안쪽의 서브 쿼리에서 먼저 필터링을 하는 것이 가장 효율적인 방법이다.
그래서 WHERE절을 이용해 field에서 query를 필터링한다.
WHERE절 이후의 "+field+"는 아래의 preparedStatement를 이용한? 물음표를 사용할 수가 없다. field는 문자열의 값으로 들어가지 않기 때문이다.
예) WHERE ? LIKE에서? 가 TITLE이라면 실제 쿼리문에는 WHERE 'TITLE' LIKE 가 된다. 그래서 어쩔 수 없이 위와 같이 코드를 사용해야 한다.
나머지 변수부분들은 preparedStatement를 이용해? 물음표로 값을 넣고, 수식을 넣어서 구현한다.
결과:
Controller와 DataService를 분리한 후에도 정상적으로 잘 작동 중이다.
이렇게 Controller에서는 사용자와의 상호작용을 하면서 코드가 더 간단하고 간결해졌다.
DataService에서는 서비스만 전문적으로 하면서 JDBC코드가 대부분을 차지하고 있고 사용자와의 입출력은 따로 되어있어 코드 가독성이 좋다.
'Servlet JSP' 카테고리의 다른 글
서블릿/JSP 강의/강좌 77 - 목록 페이지에서 검색 추가하기 (0) | 2021.05.28 |
---|---|
서블릿/JSP 강의/강좌 76 - NoticeService 클래스 완성하기 (0) | 2021.05.28 |
getPrevNotice 메소드의 SQL 쿼리 작성하기 (0) | 2021.05.19 |
getNextNotice 메소드의 SQL 쿼리 작성하기 (0) | 2021.05.19 |
getNoticeList 메소드의 SQL 쿼리 작성하기 (0) | 2021.05.19 |