kosta/Servlet,JSP,JDBC,MyBatis

[MyBatis] 실습2

엑츄얼리 2022. 4. 15. 11:56

검색기능 구현 by Object

 1. 먼저 검색을 위한 Search 객체를 생성한다.

package bean;

public class Search {
    private String[] area;
    private String searchKey;

    public Search(){}

    public String[] getArea() {
        return area;
    }

    public void setArea(String[] area) {
        this.area = area;
    }

    public String getSearchKey() {
        return searchKey;
    }

    public void setSearchKey(String searchKey) {
        this.searchKey = searchKey;
    }
}

<Search.java>

 

 

2. mybatis-config.xml 의 typeAlias에 별칭을 설정 및 mappers에 mapper 매칭

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <typeAliases>
        <typeAlias type="bean.Board" alias="Board"/>
    </typeAliases>

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="JNDI">
                <property name="data_source" value="java:comp/env/jdbc/oracle"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <mapper resource="mapper/Board.xml"/>
    </mappers>

</configuration>

<mybatis-config.xml>

 

 

3. board.xml 및 BoardMapper 설정

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!--namespace는 변별성을 주기위해 앞에 붙여주는 느낌
아래의 listBoard를 호출하기 위해서는 mapper.BoardMapper.listBoard-->
<mapper namespace="mapper.BoardMapper">
    <cache/>
    <!--   board table을 Board 객체로 반환-->
    <select id="listBoard" parameterType="Search" resultType="Board">
        select *
        from board
        <if test="area != null">
            <where>
                <!-- -->
                <!-- where (title LIKE %JSP% OR writer LIKE %JSP)-->
                <foreach collection="area" item="item" separator="OR"
                         open="(" close=")">
                  <!--column명은 ${}로 감싸야함-->
                    ${item} LIKE #{searchKey}
                </foreach>
            </where>
        </if>
        order by seq desc
    </select>
</mapper>

<board.xml>

 

package mapper;

import bean.Board;
import bean.Search;
import java.util.List;

public interface BoardMapper {
    // bean/BoardDao2
    List<Board> listBoard(Search search);
}

<BoardMapper.java>

 

 

4. search 객체 생성 및 입력 값을 통해 초기화

<%@ page import="bean.Board" %>
<%@ page import="java.util.List" %>
<%@ page import="bean.BoardDao2" %>
<%@ page contentType="text/html;charet=UTF-8" language="java"
         pageEncoding="utf-8"%>
<%
    request.setCharacterEncoding("utf-8");
    Search search = new Search();
    search.setArea(request.getParameterValues("area"));//getParameterValues = 배열을 반환
    search.setSearchKey("%" + request.getParameter("searchKey") + "%"); //request.getParameter = String을 반환

    BoardDao2 dao = BoardDao2.getInstance();
    List<Board> list = dao.listBoard(search);
%>
<html>
<head>
    <title>Title</title>
</head>
<body>
<a href="insert_form.jsp">글쓰기</a>
<table border="1">
    <tr>
        <td>글번호</td>
        <td>제목</td>
        <td>작성자</td>
        <td>작성일자</td>
        <td>조회수</td>
    </tr>
    <%
        for (int i = 0; i < list.size(); i++) {
            Board board = list.get(i);
    %>
    <tr>
        <td><%=board.getSeq()%></td>
        <td><a href="detail.jsp?seq=<%=board.getSeq()%>"><%=board.getTitle()%></a></td>
        <td><%=board.getWriter()%></td>
        <td><%=board.getRegdate()%></td>
        <td><%=board.getHitcount()%></td>
    </tr>
    <%}%>
</table>
<br><br>
<form action="list.jsp" method="get">
    <input type="checkbox" name="area" value="title"> 제목
    <input type="checkbox" name="area" value="writer"> 작성자
    <input type="text" name="searchKey" size="10">
    <input type="submit" value="검색">
</form>
</body>
</html>

<list.jsp>

* request.getParameterValues("{name}") : 배열을 반환

  request.getParameter("{key}") : String을 반환

 

 

검색 기능 구현 by Map

이전 코드를 기반으로 수정하여, 수정된 부분만 기록하겠다.

...
<%
    request.setCharacterEncoding("utf-8");
    Map map = new HashMap();
    map.put("area", request.getParameterValues("area"));
    map.put("searchKey", "%" + request.getParameter("searchKey") + "%");

    BoardDao2 dao = BoardDao2.getInstance();
    List<Board> list = dao.listBoard(map);
%>
...

<list.jsp>

 

...
<select id="listBoard" parameterType="java.util.Map" resultType="Board">
    select *
    from board
    <if test="area != null">
        <where>
            <!-- -->
            <!-- where (title LIKE %JSP% OR writer LIKE %JSP)-->
            <foreach collection="area" item="item" separator="OR"
                     open="(" close=")">
                <!--column명은 ${}로 감싸야함-->
                ${item} LIKE #{searchKey}
            </foreach>
        </where>
    </if>
    order by seq desc
</select>
...

<Board.xml>

 

...
    List<Board> listBoard(Map map);
...

<BoardMapper.xml>

 

 

MyBatis foreach문

* 이번 수업에서 핵심 부분은 Board.xml에서 foreach를 사용하여 query문을 생성하는 방식이였다.

    Board.xml을 위주로 이해하면 도움이 될 것 같다.

 

 

Attribute

 collection : 전달 받을 인자 (type : List or Array)

 item : collection을 통해 전달 받은 인자 값을 alias로 대체

 open : 구문이 시작될 때 삽입할 문자열

 close : 구문이 종료될 때 삽입할 문자열

 separator : 인자의 index가 바뀔 때, 삽입할 문자열

 

 

#{}, ${}차이

#{}

<select id="test" resultType="..." parameterType="Study">
SELECT *
FROM 
	TEST
WHERER 
	ID = #{ID}
</select>

3행에 WHERE ID = #{ID}는 쿼리문이 실행 시 WHERE ID = ?로 파싱

#{} 생성 시 PreparedStatement가 생성되며 위의 ? 값에 파라미터가 바인딩 (재활용(캐싱)이 가능해서 효율적)

 

parameterType의 ID 필드 값의 앞뒤에 ' 가 붙기 때문에 '#{id}'와 같은 식으로 쿼리문을 작성할 필요가 없다.

 

 

${}

<select id="test" resultType="..." parameterType="Study">
SELECT * 
FROM 
	TEST_${INDEX}
WHERER 
	ID = #{ID}

#{}과는 다르게 값이 먼저 들어가고 파싱이 진행된다.

  따라서 파라미터 값이 바뀔 때마다 쿼리문을 파싱을 다시 진행해야한다.

 

#{}과는 다르게 파라미터 값이 바인딩 될 때, '가 붙지 않기 때문에

  TEST_${INDEX}와 같이 이름을 동적으로 사용할 수 있다.

 

* ${}는 SQL Injection에 취약

<select id="test" resultType="..." parameterType="Study">
SELECT * 
FROM 
	TEST
WHERER 
	ID = '${ID}' AND password = '${password}'
</select>

외부에서 id에 id'-'를 입력 시 

	ID = 'admin'-' AND password = '${password}'

이런 식으로되어 비밀번호에 대한 조건이 사라지게 되어 id만가지고도 입력할 수 있어 보안에 매우 취약

 

 

참고 : https://madplay.github.io/post/difference-between-dollar-sign-and-sharp-sign-in-mybatis