본문 바로가기

programming/Gukbi

국비 교육 86일차 - Mybatis 동적 쿼리

728x90
반응형

 

동적쿼리와 aop 처리를 실습해보기 위해 게시판을 완성하는 프로젝트를 만들어봤다. 

 

 

일단 로그인 처리부터 보면

<!-- ID존재여부 -->
  <select id="memberIdCount" resultType="int" parameterType="string">
    SELECT COUNT(*) FROM webmember
    WHERE id=#{id}
  </select>
  <!-- 비밀번호 확인 -->
  <select id="memberGetPassword" resultType="com.sist.dao.MemberVO" parameterType="string">
    SELECT pwd,name FROM webmember
    WHERE id=#{id}
  </select>

 아이디가 존재하는지 확인하는 쿼리문, 비밀번호가 맞는지 확인하는 커리문장을 쓴다. 

public String isLogin(String id, String pwd)
	{
		String result="";
		int count=getSqlSession().selectOne("memberIdCount", id);
		if(count==0)
		{
			result="NOID";
		}
		else
		{
			MemberVO vo=getSqlSession().selectOne("memberGetPassword", id);
			String db_pwd=vo.getPwd();
			String name=vo.getName();
			if(db_pwd.equals(pwd))
			{
				result=name;
			}
			else
			{
				result="NOPWD";
			}
		}
		return result;
	}

 그리고 나서 결과값에 따라 해당하는 string 문자열 값을 반환한다

@PostMapping("member/login_ok.do")
	public String member_login_ok(String id,String pwd,Model model,HttpSession session)
	{
		// 세션은 DispatcherServlet으로부터 매개변수로 받아서 처리한다 
		String result=dao.isLogin(id, pwd);
		if(!(result.equals("NOID")||result.equals("NOPWD")))
		{
			// 로그인된 상태
			session.setAttribute("id", id);
			session.setAttribute("name", result);
		}
		model.addAttribute("result", result);
		return "member/login_ok";
	}

 로그인 처리는 세션에 값을 저장해야하기 때문에 매개변수로 session을 받아온다. 그리고 로그인에 성공하면

나온 result 문자열 결과값과 아이디를 세션에 저장하고, 그렇지 않으면 result만 반환한다. 

 

이 화면처리는 사용자가 login_ok.do화면을 열었을때 호출되는 화면이다. 

 

 

login_ok.jsp 에서는 아래와 같이 사용자에게 화면을 띄워준다

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:choose>
	<c:when test="${result=='NOID' }">
	 <script>
	 	alert("ID가 존재하지 않습니다");
	 	history.back();
	 </script>
	</c:when>
	<c:when test="${result=='NOPWD' }">
		<script>
		alert("비밀번호가 틀립니다!");
	 	history.back();
	 	</script>
	</c:when>
	<c:otherwise>
	 <c:redirect url="../board/list.do"/>
	</c:otherwise>
</c:choose>

 

로그인이 되면 게시판의 글 목록쪽으로 이동한다

 

상세보기, 수정, 삭제까지는 전부 이제까지와 동일한데 검색 부분이 이제까지 배우던 쿼리문장들과 달랐어서 이부분을 중점적으로 볼까 한다 

 

 <!-- 글쓰기 -->
  <insert id="boardInsert" parameterType="BoardVO">
   <selectKey keyProperty="no" resultType="int" order="BEFORE">
   	SELECT NVL(MAX(no)+1, 1) as no FROM spring_freeboard
   </selectKey>
   INSERT INTO spring_freeboard VALUES(
   	#{no},
   	#{name},
   	#{subject},
   	#{content},
   	#{pwd},
   	SYSDATE,
   	0
   )
  </insert>

 그래도 이부분은 따로 봐줄 필요가 있다. 

select key는 sequence처럼 사용이 가능하다. 먼저 no의 값을 올려주는 쿼리문장을 적성하고, 그 뒤에 글을 삽입해준다. 

 

그리고 문제의...

동적쿼리를 배우기 위해 다양한것을 시도해봤던 검색 쿼리 부분

<!-- 찾기 -->
  <sql id="dsql">
   <trim prefix="(" suffix=")" prefixOverrides="OR">
     <foreach collection="fsArr" item="fs">
       <trim prefix="OR">
        <choose>
          <when test="fs=='N'.toString()">
            name LIKE '%'||#{ss}||'%'
          </when>
          <when test="fs=='S'.toString()">
            subject LIKE '%'||#{ss}||'%'
          </when>
          <when test="fs=='C'.toString()">
            content LIKE '%'||#{ss}||'%'
          </when>
        </choose>
       </trim>
     </foreach>
   </trim>
  </sql>
  <select id="boardFindData" resultType="BoardVO" parameterType="hashmap">
   <bind name="pattern" value="'%'+ss+'%'"/>
   SELECT no,subject,name,regdate,hit 
   FROM spring_freeboard
   WHERE
   <!-- WHERE ${fs} LIKE #{pattern}-->
   <!-- 
         fs=="name"
         문자열 :
            ==
            equals
    -->
   <!-- <if test='fs.equals("name")'>
     WHERE name LIKE '%'||#{ss}||'%'
   </if>
   <if test='fs.equals("subject")'>
     WHERE subject LIKE '%'||#{ss}||'%'
   </if>
   <if test='fs.equals("content")'>
     WHERE content LIKE '%'||#{ss}||'%'
   </if> -->
   <!-- <choose>
    <when test='fs=="name"'>
     WHERE name LIKE #{pattern}
    </when>
    <when test='fs=="subject"'>
     WHERE subject LIKE #{pattern}
    </when>
    <when test='fs=="content"'>
     WHERE content LIKE #{pattern}
    </when>
   </choose> -->
   <!-- 
         SC
         OR (name LIKE '%'||#{ss}||'%') OR (content LIKE '%'||#{ss}||'%')
         
         S 
         
         N
         (name LIKE '%'||#{ss}||'%')
         NS
         (name LIKE '%'||#{ss}||'%') OR (subject LIKE '%'||#{ss}||'%')
         NSC
         (name LIKE '%'||#{ss}||'%') OR (subject LIKE '%'||#{ss}||'%') OR(content LIKE '%'||#{ss}||'%')
    -->
   <include refid="dsql"/>
  </select>
  <select id="boardFindDataCount" resultType="int" parameterType="hashmap">
   SELECT COUNT(*)
   FROM spring_freeboard
   WHERE
   <!-- WHERE ${fs} LIKE '%'||#{ss}||'%'-->
   <!-- 
         fs=="name"
         문자열 :
            ==
            equals
    -->
   <!-- <if test='fs.equals("name")'>
     WHERE name LIKE '%'||#{ss}||'%'
   </if>
   <if test='fs.equals("subject")'>
     WHERE subject LIKE '%'||#{ss}||'%'
   </if>
   <if test='fs.equals("content")'>
     WHERE content LIKE '%'||#{ss}||'%'
   </if> -->
   <!-- <choose>
    <when test='fs=="name"'>
     WHERE name LIKE '%'||#{ss}||'%'
    </when>
    <when test='fs=="subject"'>
     WHERE subject LIKE '%'||#{ss}||'%'
    </when>
    <when test='fs=="content"'>
     WHERE content LIKE '%'||#{ss}||'%'
    </when>
   </choose> -->
   <include refid="dsql"/>
  </select>
</mapper>

 

이전에 만들었던 검색 기능의 경우 그냥 제목, 혹은 작성자만 검색하는 식으로 만들어 줬었기 때문에 그렇게 크게 어렵지는 않았는데, 이번에는 7가지의 방법으로 검색이 가능하게 만들었다. 

 

이름

제목

내용

이름+제목

이름+내용

제목+내용

이름+제목+내용 

 

이렇게 검색이 가능하게 만들어봤다. 

 

 <td class="text-left">
          <form method=post action="find.do">
          	Search:<select name="fs" class="input-sm">
          	 <option value="N">이름</option>
          	 <option value="S">제목</option>
          	 <option value="C">내용</option>
          	 <option value="NS">이름+제목</option>
          	 <option value="NC">이름+내용</option>
          	 <option value="SC">제목+내용</option>
          	 <option value="NSC">이름+제목+내용</option>
          	</select>
          	<input type=text name=ss size=15 class="input-sm">
          	<button class="btn btn=sm btn-warning">검색</button>
          	</form>
          </td>

 이건 list.jsp에서 검색방법을 선택해주는 옵션이다. post 방식으로 value값을 넘겨서 어떤 방식으로 검색을 해줄 것인지 지정을 해줘야하기 때문에

 

이름이면 N

제목이면 S

내용이면 C 

이렇게 처리를 해줬고, 이름+제목이면 NS 이렇게 알파벳을 조합해서 검색할 수 있도록 했다. 

 

그리고 검색처리를 할 수 있게 FindVO 를 따로 만들어 준다

 

package com.sist.dao;

public class FindVO {
    private String fs;
    private String ss;
	public String getFs() {
		return fs;
	}
	public void setFs(String fs) {
		this.fs = fs;
	}
	public String getSs() {
		return ss;
	}
	public void setSs(String ss) {
		this.ss = ss;
	}
	public String[] getFsArr()
	{
		return fs==null?new String[]{}:fs.split("");
	}
   
}

 fs에는 value값으로 받아온 N,S,C,NS,SC,SC,NSC 7문자중에 하나가 들어오게 된다. 

ss는 사용자가 입력한 검색어이다. 

 

그리고 한가지 더 처리해야 할 것은 fs가 2개 이상의 문자열 즉, NS,SC,SC,NSC의 형태로 들어왔을때 글자를 하나하나 잘라준다. 

 

getFsArr()이라는 메소드를 실행하면 위와 같이 글자를 단어 하나 하나씩 쪼갤 수 있도록 만들어 둔다.

 

@PostMapping("board/find.do")
   public String board_find(String fs,String ss,Model model)
   {
	   FindVO vo=new FindVO();
	   vo.setFs(fs);
	   vo.setSs(ss);
	   Map map=new HashMap();
	   map.put("fs",fs);
	   map.put("ss", ss);
	   map.put("fsArr", vo.getFsArr());
	   List<BoardVO> list=service.boardFindData(map);
	   int count=service.boardFindDataCount(map);
	   model.addAttribute("list", list);
	   model.addAttribute("count", count);
	   return "board/find";
   }

 그러면 controller에서 위와 같이 처리를 해준다. fs는 검색방법, ss는 사용자 입력 검색어 이고, 이 두개를 FindVO에 대입하면 바로 getFsArr()의 값을 받아올 수 있다.

 

일단 select로 결과값을 받아와야하기 때문에 mapper에서 해당하는 쿼리문장을 작성해주면된다. 

 

사실 동적쿼리를 배우기 위해 많은 방법으로 시도를 해봤는데, 사용법만 다를뿐 결과값은 모두 똑같이 나오는 것을 확인 할 수 있다. 

 

먼저 공통적으로 사용되는 부분은 bind를 이용해서 묶음처리 해준다. 

 <select id="boardFindData" resultType="BoardVO" parameterType="hashmap">
   <bind name="pattern" value="'%'+ss+'%'"/>
   SELECT no,subject,name,regdate,hit 
   FROM spring_freeboard
   WHERE

  select ~ where까지는 공통적인 부분이기 때문에 pattern 이라는 명칭으로 같이 묶어줬다. 

<include refid="dsql"/>
  </select>

 그리고 dsql이라는 부분에 검색 쿼리의 핵심 처리 부분을 담아서 include해줬다. 

 

<sql id="dsql">
   <trim prefix="(" suffix=")" prefixOverrides="OR">
     <foreach collection="fsArr" item="fs">
       <trim prefix="OR">
        <choose>
          <when test="fs=='N'.toString()">
            name LIKE '%'||#{ss}||'%'
          </when>
          <when test="fs=='S'.toString()">
            subject LIKE '%'||#{ss}||'%'
          </when>
          <when test="fs=='C'.toString()">
            content LIKE '%'||#{ss}||'%'
          </when>
        </choose>
       </trim>
     </foreach>
   </trim>
  </sql>

 쿼리 문장이 결국은 이런식으로 나와야하기 때문에,

SELECT no,subject,name,regdate,hit 
FROM spring_freeboard
WHERE (name LIKE '%'||#{ss}||'%') OR (subject LIKE '%'||#{ss}||'%') OR (content LIKE '%'||#{ss}||'%')

  맨 앞과 뒤에 trim을 사용해서 괄호로 묶어준다. 그리고 문장 앞 마다 OR을 붙여주는데, 

맨 앞에는 붙이면 안되기 때문에 prefixOverrides를 통해 맨 앞의 OR을 제거 해준다. 

 

foreach를 사용해서 fsArr의 길이 만큼 for문을 돌려주고, 그 안에서 choose - when 절을 사용해서 조건문을 수행하게끔 만들어 준다. 

 

결과값은 dsql에 저장되어 select문장을 완성하게 된다. 

 

 

이건 이름+제목+내용으로 검색어 '내'를 찾은 결과값이다. 이런식으로 결과를 보여 줄 수 있다. 

 

 

728x90
반응형