12 분 소요

게시글 검색 기능

목표

  • 제목, 작성자, 내용, 제목+내용 을 유형으로 검색을 시도한다.
    Pasted image 20230602023619
  • 각 유형을 선택하고 검색을 시도하면 유형에 따라 검색문과 일치하는 결과의 게시글들을 보여준다.

유형 선택창

  • 제목, 작성자, 내용, 제목+내용의 유형들로 선택창을 만들어 주었다.
  • 기본으로 선택되어 있는 유형은 제목+내용 이다.
    Pasted image 20230602025353
  • 유형을 선택하여 검색을 진행한다.

JSP 코드

notice_board.jsp

  • servlet 에서 넘겨받은 optionVal 값을 이용하여 검색한 후에도 선택한 값을 계속 유지하여준다.
  • id가 searchForm 인 form이 submit할 때 선택된 유형도 파라미터에 넣어저 서버로 요청을 보내게된다.
    ?option_val=1&page=1&q=
<select name="option_val" form="searchForm">
    <option value="1" <% if(optionVal == 1) { %> selected <% } %> >제목+내용</option>
    <option value="2" <% if(optionVal == 2) { %> selected <% } %> >작성자</option>
    <option value="3" <% if(optionVal == 3) { %> selected <% } %> >제목</option>
    <option value="4" <% if(optionVal == 4) { %> selected <% } %> >내용</option>
</select>

<form action="" id="searchForm">
... 생략 ...
  • 검색 전
    Pasted image 20230602025138

  • 검색 후
    Pasted image 20230602025225

Servlet 코드 ( Java 코드 )

MainPage.java

  • 사용자에게서 받은 option 값이 1~4 범위의 수인지 검사한다.
  • option 값과 검색문 값을 이용하여 게시글 수와 게시글 목록을 받아온다.
public class MainPage extends HttpServlet{
	private boolean uriSearch(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
		if(request.getMethod().equals("GET") && uri.equals(noticeBoard)){
			// 검색 옵션 option_val
            // 1 제목+내용
            // 2 작성자
            // 3 제목
            // 4 내용
            var ov = request.getParameter("option_val");
            var optionVal = 1;
            try {
                optionVal = Integer.parseInt(ov);
            }catch(Exception e){
                e.printStackTrace();
                optionVal = 1;
            }
            if(optionVal > 4 || optionVal < 1){
                optionVal = 1;
            }
            ... 생략 ...
            // 검색 결과 총 게시글 수 알아보기
            int cnt = noticeBoardDAO.getCount(optionVal,q, from, to);
            ... 생략 ...
            // 검색 데이터 가져오기.
            var array = noticeBoardDAO.getNoticeList(optionVal,q,start,number, from, to);
            ...
            // 검색 옵션 값 jsp 로 보내기
            request.setAttribute("optionVal", optionVal);
            ...

NoticeBoardDAO.java

  • 옵션에 맞는 쿼리문을 만들어 DB 게시글 테이블에서 게시글 목록을 가져온다.
public class NoticeBoardDAO {
    // 전체 목록 가져오기 or 검색 목록 가져오기
    // 1 <= optionVal <= 4
    // 1 제목 + 내용
    // 2 작성자
    // 3 제목
    // 4 내용
    // 날짜 범위
    public ArrayList<Notice> getNoticeList(int optionVal,String question, int start, int number, long from, long to){
        if(optionVal > 4 || optionVal < 1){
            optionVal = 1;
        }
        var arr = new ArrayList<Notice>();
        try{
            Connection();
            var query = new StringBuilder();
            query.append("select * from ");
            query.append(tableName);
            if(optionVal == 1){
                query.append(" where (title like '%'||?||'%' or main_text like '%'||?||'%')");
            }else if(optionVal == 2){
                query.append(" where (username like '%'||?||'%')");
            }else if(optionVal == 3){
                query.append(" where (title like '%'||?||'%')");
            }else if(optionVal == 4){
                query.append(" where (main_text like '%'||?||'%')");
            }
            query.append(" and (gen_time > ? and gen_time < ?)");
            query.append(" order by gen_time desc ");
            // 0번째 부터 5개의 자료만 출력해라.
            query.append("OFFSET ? ROWS FETCH NEXT ? ROWS ONLY");

            var pstmt = conn.prepareStatement(query.toString());
            if(optionVal == 1){
                pstmt.setString(1, question);
                pstmt.setString(2, question);
                pstmt.setLong(3, from);
                pstmt.setLong(4, to);
                pstmt.setInt(5, start);
                pstmt.setInt(6, number);
            }else{
                pstmt.setString(1, question);
                pstmt.setLong(2, from);
                pstmt.setLong(3, to);
                pstmt.setInt(4, start);
                pstmt.setInt(5, number);
            }
  • 옵션에 맞는 쿼리문을 만들어 DB 게시글 테이블에 저장된 데이터 수를 알아낸다.
public class NoticeBoardDAO {
    // 게시판 목록 수 가져오기
    // 1 <= optionVal <= 4
    // 1 제목 + 내용
    // 2 작성자
    // 3 제목
    // 4 내용
    public int getCount(int optionVal, String question, long from, long to){
        if(optionVal > 4 || optionVal < 1){
            optionVal = 1;
        }
        // var query = "select count(sid) from notice_board";
        var query = new StringBuilder();
        query.append("select count(sid) from ");
        query.append(tableName);
        if(optionVal == 1){
            query.append(" where (title like '%'||?||'%' or main_text like '%'||?||'%')");
        }else if(optionVal == 2){
            query.append(" where (username like '%'||?||'%')");
        }else if(optionVal == 3){
            query.append(" where (title like '%'||?||'%')");
        }else if(optionVal == 4){
            query.append(" where (main_text like '%'||?||'%')");
        }
        query.append("  and (gen_time > ? and gen_time < ?)");
        int re = 0;
        try{
            Connection();
            var pstmt = conn.prepareStatement(query.toString());
            pstmt.setString(1, question);
            var cnt = 2;
            if(optionVal == 1){
                pstmt.setString(cnt, question);
                cnt+=1;
            }

결과

  • 작성자 user2 검색결과
    Pasted image 20230602032148
  • 작성자 mq 검색결과
    Pasted image 20230602032213
  • 제목+내용 test 검색결과
    Pasted image 20230602032247

게시글 날짜 지정 검색

목표

  • 날짜 범위를 지정하여 검색을 시도하면 지정된 날짜 사이에 작상된 게시글들을 가지고 온다.
  • 날짜 형식(yyyy-MM-dd)이 일치하지 않으면 디펄트로 설정된 값을 날짜로 지정한다.

날짜 선택창

  • 사용자는 직접 날짜를 선택할 수 있다.
    Pasted image 20230602032643
  • 검색을 누르면 GET 요청으로 날짜가 파라미터에 들어가 서버로 전송된다.
    ?option_val=1&page=1&q=&date_from=2023-05-18&date_to=2023-06-01

JSP 코드

notice_board.jsp

  • 타입이 date인 input 태그들을 추가하였다.
  • date_from ~ date_to 사이의 결과를 검색할 수 있다.
<form action="" id="searchForm">
... 생략 ... 
    <input type="date" name="date_from">
    <input type="date" name="date_to">
    <input type="submit" value="검색">
</form>

Servlet 코드 ( Java 코드 )

MainPage.java

  • 사용자로 부터 date_from, date_to 값을 받는다.
  • 유효한 날짜인지 확인한다.
  • DB 게시글 테이블에는 게시글 생성날짜가 long 타입으로 저장되어 있다. 따라서 사용자에게 받은 날짜들을 long 타입으로 변환한다.
  • 검색된 게시글 수, 게시글 목록을 DB 테이블로 부터 가져온다.
public class MainPage extends HttpServlet{
    private boolean uriSearch(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
        if(request.getMethod().equals("GET") && uri.equals(noticeBoard)){
        ... 생략...
            // 검색 날짜 범위
            var dateFrom = request.getParameter("date_from");
            var dateTo = request.getParameter("date_to");
            if(dateFrom == null || dateTo == null){
                dateFrom = "";
                dateTo = "";

            }else if(dateFrom.equals("") || dateTo.equals("")){
                dateFrom = "";
                dateTo = "";
            }
            // 날짜 유효한지 검사
            var re = "(19|20)\\d{2}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])";
            if(!dateFrom.matches(re) || !dateTo.matches(re)){
                dateFrom = "1980-01-01";
                dateTo = "2999-12-31";
            }
            var obj = new SimpleDateFormat("yyyy-MM-dd HH:mm");
            obj.setTimeZone(TimeZone.getTimeZone("Asia/Seoul"));
            long from = 0;
            long to = 0;
            // long type 변환
            try{
                from = obj.parse(dateFrom+" 00:01").getTime();
                to = obj.parse(dateTo+" 23:59").getTime();
            }catch(Exception e){
                from = 0;
                to = Long.MAX_VALUE;
                e.printStackTrace();
            }
            ... 생략 ...
            // 검색 결과 총 게시글 수 알아보기
            int cnt = noticeBoardDAO.getCount(optionVal,q, from, to);
            ... 생략 ...
            // 검색 데이터 가져오기.
            var array = noticeBoardDAO.getNoticeList(optionVal,q,start,number, from, to);
            ... 생략 ...
            // date from and date to
            request.setAttribute("dateFrom", dateFrom);
            request.setAttribute("dateTo", dateTo);

NoticeBoardDAO.java

  • 쿼리문에 생성일 범위를 추가하여 특정 범위에 있는 게시글들을 가지고 온다.
public class NoticeBoardDAO {
    public ArrayList<Notice> getNoticeList(int optionVal,String question, int start, int number, long from, long to){
    ... 생략 ...
        var arr = new ArrayList<Notice>();
        try{
            Connection();
            var query = new StringBuilder();
            query.append("select * from ");
            query.append(tableName);
            if(optionVal == 1){
                query.append(" where (title like '%'||?||'%' or main_text like '%'||?||'%')");
            }else if(optionVal == 2){
                query.append(" where (username like '%'||?||'%')");
            }else if(optionVal == 3){
                query.append(" where (title like '%'||?||'%')");
            }else if(optionVal == 4){
                query.append(" where (main_text like '%'||?||'%')");
            }
            // 게시글 범위
            query.append(" and (gen_time > ? and gen_time < ?)");
            query.append(" order by gen_time desc ");
            // 0번째 부터 5개의 자료만 출력해라.
            query.append("OFFSET ? ROWS FETCH NEXT ? ROWS ONLY");

            var pstmt = conn.prepareStatement(query.toString());
            if(optionVal == 1){
                pstmt.setString(1, question);
                pstmt.setString(2, question);
                pstmt.setLong(3, from);
                pstmt.setLong(4, to);
                pstmt.setInt(5, start);
                pstmt.setInt(6, number);
            }else{
                pstmt.setString(1, question);
                pstmt.setLong(2, from);
                pstmt.setLong(3, to);
                pstmt.setInt(4, start);
                pstmt.setInt(5, number);
            }
  • 쿼리문에 생성일 범위를 추가하여 특정 범위에 있는 게시글 수를 구한다.
public class NoticeBoardDAO {
    public int getCount(int optionVal, String question, long from, long to){
        var query = new StringBuilder();
        query.append("select count(sid) from ");
        query.append(tableName);
        if(optionVal == 1){
            query.append(" where (title like '%'||?||'%' or main_text like '%'||?||'%')");
        }else if(optionVal == 2){
            query.append(" where (username like '%'||?||'%')");
        }else if(optionVal == 3){
            query.append(" where (title like '%'||?||'%')");
        }else if(optionVal == 4){
            query.append(" where (main_text like '%'||?||'%')");
        }
        query.append("  and (gen_time > ? and gen_time < ?)");
        int re = 0;
        try{
            Connection();
            var pstmt = conn.prepareStatement(query.toString());
            ... 생략 ...
            pstmt.setLong(cnt, from);
            cnt +=1;
            pstmt.setLong(cnt, to);

Notice.java

  • 테이블에 저장된 생성시간(long)을 사람이 볼 수 있는 날짜로 변경한다.
public class Notice {
    public String getGenDate(){
        var obj = new SimpleDateFormat("dd MMM yyy HH:mm");
        obj.setTimeZone(TimeZone.getTimeZone("Asia/Seoul")); // 타임존 한국
        var res = new Date(genTime);
        return obj.format(res);
    }

결과

  • 날짜 범위를 지정하고 검색하면 날짜 사이에 생성된 게시글 목록들을 볼 수 있다.
    Pasted image 20230602035208

참고 사이트

댓글남기기