본문 바로가기
MyBatis

[MyBatis] select + update 연습 (TypeHandler 적용)

by moca7 2024. 10. 11.

 

 

 

ㅁ 공지사항 서비스는 이제 끝났고 회원 서비스를 한다.

 

 

 

ㅁ main.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:set var="contextPath" value="${pageContext.request.contextPath}" />

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body

    <h3>1. insert연습 (공지사항 등록)</h3>
    <a href="${ contextPath }/regist.no">공지사항 등록페이지로 이동</a>

    <h3>2. select연습 - 한 행 (공지사항 상세조회)</h3>
    <form action="${ contextPath }/detail.no">
        검색할 글번호 : <input type="text" name="noticeNo">
        <button type="submit">검색</button>
    </form>

    <h3>3. select연습 - 여러행 (공지사항 전체목록조회)</h3>
    <a href="${ contextPath }/list.no">공지사항 전체 목록 페이지로 이동</a>

    <h4>4. select연습 - 여러행 + 페이징 처리 - RowBounds 적용</h4>
    <a href="${ contextPath }/list.no?page=1">공지사항 목록 페이지(페이징처리)로 이동</a>


    <h5>5. select연습 + update연습 (회원정보 상세조회 + 회원정보 변경) - TypeHandler 적용</h5>
    <form action="${ contextPath }/detail.me">
        검색할 회원번호 : <input type="text" name="userNo">
        <button type="submit">검색</button>
    </form>
   
   
    <h6>6. 동적쿼리 연습 (회원 검색)</h6>

</body>
</html>
 

 

 

- "5. select연습 + update연습 (회원정보 상세조회 + 회원정보 변경) - TypeHandler 적용" 부분을 작성했다.

 

 

 

 

 

ㅁ com.br.mybatis.member.controller에 MemberDetailController 서블릿을 만든다.

 

 
package com.br.mybatis.member.controller;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class MemberDetailController
 */
@WebServlet("/detail.me")
public class MemberDetailController extends HttpServlet {
    private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public MemberDetailController() {
        super();
    }

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {


        int userNo = Integer.parseInt(request.getParameter("userNo"));
        MemberDto m = new MemberServiceImpl().selectMember(userNo);
       
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

}
 

 

- 완성된 상태는 아니다.

 

 

 

 

ㅁ com.br.mybatis.member.service에 인터페이스 MemberService를 만든다.

 

 
package com.br.mybatis.member.service;

import com.br.mybatis.member.dto.MemberDto;

public interface MemberService {

   
    // 인터페이스에서 public abstract를 붙이지 않아도 모든 메서드는 자동으로 추상 메서드로 취급됩니다.
   
   
    // 회원정보 상세조회
    MemberDto selectMember(int userNo);
   
    // 회원정보 변경
    int updateMember(MemberDto m);
   
    // 회원 검색
   
}
 

 

 

 

 

 

ㅁ com.br.mybatis.member.service에 인터페이스 MemberService를 구현하는 MemberServiceImpl 클래스를 만든다

 

 
package com.br.mybatis.member.service;

import org.apache.ibatis.session.SqlSession;

import static com.br.mybatis.common.template.Template.*;
import com.br.mybatis.member.dao.MemberDao;
import com.br.mybatis.member.dto.MemberDto;

public class MemberServiceImpl implements MemberService {

    private MemberDao memberDao = new MemberDao();
   
   
    @Override
    public MemberDto selectMember(int userNo) {
        SqlSession sqlSession = /*Template.*/getSqlSession();
        MemberDto m = memberDao.selectMember(sqlSession, userNo);
       
        sqlSession.close();
        return m;
    }

    @Override
    public int updateMember(MemberDto m) {
        return 0;
    }

}
 

 

 

 

 

 

 com.br.mybatis.member.dao에 MemberDao를 만든다.

 

 
package com.br.mybatis.member.dao;

import org.apache.ibatis.session.SqlSession;

import com.br.mybatis.member.dto.MemberDto;

public class MemberDao {

    public MemberDto selectMember(SqlSession sqlSession, int userNo) {
        return sqlSession.selectOne("memberMapper.selectMember", userNo);
    }

}
 

 

 

 

 

ㅁ mybatis-config.xml에 별칭을 등록한다. 

 

 
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
 
<configuration>

    <settings>
        <setting name="jdbcTypeForNull" value="NULL" />
    </settings>

   
    <typeAliases>
        <typeAlias type="com.br.mybatis.notice.dto.NoticeDto" alias="NoticeDto" />
        <typeAlias type="com.br.mybatis.member.dto.MemberDto" alias="MemberDto" />
    </typeAliases>
   

    <environments default="development">
   
        <environment id="development">
            <transactionManager type="JDBC" />
            <dataSource type="POOLED">
                <property name="driver" value="oracle.jdbc.driver.OracleDriver" />
                <property name="url" value="jdbc:oracle:thin:@localhost:1521:xe" />
                <property name="username" value="SERVER" />
                <property name="password" value="SERVER" />
            </dataSource>
        </environment>
       
    </environments>

   
    <mappers>
        <mapper resource="mappers/notice-mapper.xml" />
        <mapper resource="mappers/member-mapper.xml" />
    </mappers>



</configuration>  
 

 

 

- typeAliases 태그에 MemberDto의 별칭을 등록한다.

 

 

 

 


ㅁ member-mapper.xml

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

    <resultMap id="memberResultMap" type="MemberDto">
        <result column="user_no" property="userNo" />
        <result column="user_id" property="userId" />
        <result column="user_name" property="userName" />
        <result column="phone" property="phone" />
        <result column="email" property="email" />
        <result column="address" property="address" />
        <result column="interest" property="interest" />
    </resultMap>
   

    <select id="selectMember" resultType|Map="">
        select
                user_no
              , user_id
              , user_name
              , phone
              , email
              , address
              , interest
          from  member
         where  status in ('U', 'A')
           and  user_no = #{ userNo }          
    </select>

</mapper>
 

 

- resultMap은 mapper 파일 상단에 다 몰아서 작성하는 것이 좋다.

- 숫자든 문자열이든 상관없이, MyBatis에서 SQL 쿼리문에 변수를 바인딩할 때는 #{ }를 사용해야 한다.

- ${ }는 단순히 문자열을 대체하는 방식이므로, PreparedStatement 방식처럼 ?에 값을 바인딩하지 못한다.

 

 

 

 

 

ㅁ 이전에 만든 MemberDto를 살펴본다.

 

 
package com.br.mybatis.member.dto;

import java.sql.Date;
import java.util.Arrays;

public class MemberDto {

    private int userNo;
    private String userId;
    private String userPwd;
    private String userName;
    private String phone;
    private String email;
    private String address;
    private String[] interest;
    private Date enrollDate;
    private Date modifyDate;
    private String status;
   
    public MemberDto() {
        super();
    }

    public MemberDto(int userNo, String userId, String userPwd, String userName, String phone, String email,
            String address, String[] interest, Date enrollDate, Date modifyDate, String status) {
        super();
        this.userNo = userNo;
        this.userId = userId;
        this.userPwd = userPwd;
        this.userName = userName;
        this.phone = phone;
        this.email = email;
        this.address = address;
        this.interest = interest;
        this.enrollDate = enrollDate;
        this.modifyDate = modifyDate;
        this.status = status;
    }

    public int getUserNo() {
        return userNo;
    }

    public void setUserNo(int userNo) {
        this.userNo = userNo;
    }

    public String getUserId() {
        return userId;
    }

    public void setUserId(String userId) {
        this.userId = userId;
    }

    public String getUserPwd() {
        return userPwd;
    }

    public void setUserPwd(String userPwd) {
        this.userPwd = userPwd;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String[] getInterest() {
        return interest;
    }

    public void setInterest(String[] interest) {
        this.interest = interest;
    }

    public Date getEnrollDate() {
        return enrollDate;
    }

    public void setEnrollDate(Date enrollDate) {
        this.enrollDate = enrollDate;
    }

    public Date getModifyDate() {
        return modifyDate;
    }

    public void setModifyDate(Date modifyDate) {
        this.modifyDate = modifyDate;
    }

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }

    @Override
    public String toString() {
        return "MemberDto [userNo=" + userNo + ", userId=" + userId + ", userPwd=" + userPwd + ", userName=" + userName
                + ", phone=" + phone + ", email=" + email + ", address=" + address + ", interest="
                + Arrays.toString(interest) + ", enrollDate=" + enrollDate + ", modifyDate=" + modifyDate + ", status="
                + status + "]";
    }
   
}
 

 

 

 

 

- DB에서 INTEREST 컬럼값은 컴마라는 구분자로 여러개의 문자들이 연결된 하나의 문자열로 저장되어 있다.

이 하나의 문자열을 MemberDto의 String[] 타입의 interest 필드에 담으려 한다.

- 그러려면 형변환 과정이 필요하다. MyBatis에서 TypeHandler로 가능하다.

TypeHandler 기술을 이용하려면 MyBatis에서 제공하는 타입핸들러 인터페이스를 구현하는 클래스를 만들어야 한다.

 

 

 

 

 

ㅁ com.br.mybatis.common.handler에 StringArrTypeHandler라는 클래스를 만든다.

 

 

- add에서 인터페이스 TypeHandler를 검색해서 어떤 인터페이스를 구현하는 클래스로 둘 지 결정한다.

 

 

 

 

 

- 바로 finish하지 말고, interfaces 부분에서 수정이 가능하다.

- T(Type의 약자) 라고 되어있는 제네릭 타입이 반환형이다.

- T대신 변환시키고 싶은 String[] 타입을 적는다.

 

 

 

 

- String을 String[]로, String[]을 String으로 변환하는 코드를 작성할 예정이다.

- String -> String[] 변환뿐만 다른 타입으로의 변환도 가능하다.

직접 형변환하는 자바코드를 쓸거라 다른 타입으로의 형변환도 가능하다.

 

 

 

 

 
package com.br.mybatis.common.handler;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeHandler;

public class StringArrTypeHandler implements TypeHandler<String[]> {

    @Override
    public String[] getResult(ResultSet rs, String columnName) throws SQLException {

        String resultDB = rs.getString(columnName); // "낚시,운동,게임"

        return resultDB == null ? null : resultDB.split(","); // ["낚시", "운동", "게임"]
    }

    @Override
    public String[] getResult(ResultSet rs, int columnIndex) throws SQLException {
        return null;
    }

    @Override
    public String[] getResult(CallableStatement cs, int columnIndex) throws SQLException {
        return null;
    }

    @Override
    public void setParameter(PreparedStatement ps, int i, String[] parameter, JdbcType jdbcType) throws SQLException {

    }

}
 

 

 

 

- TypeHandler 인터페이스를 구현하는 구현 클래스로 만들어졌다.

 

- getResult 메소드 중에서 CallableStatemenet는 쓰지 않을거고, ResultSet을 매개변수로 쓰는 두 메소드를 수정한다.

매개변수의 ResultSet은 우리가 아는 조회결과가 담겨 있는 ResultSet이다.

- ResultSet에서 컬럼값을 뽑을 때 보통 컬럼명을 데이터를 뽑았는데 컬럼의 순번으로도 뽑을 수 있었다.

첫번째 메소드는 컬럼명이, 두번째 메소드는 컬럼 순번이 매개변수로 선언되어 있다.

 

- DB로부터 ResultSet 객체에 getXXX("컬럼명" | 컬럼순번)으로 조회된 컬럼값을 뽑아서, 원하는 타입으로 형변환한다.

- interest 컬럼에서 조회된 값을 뽑아서 String[]로 바꿀 예정이다. 

 

 

- 그런데 interest 컬럼은 null 허용이라 그냥 split하면 null pointer exception 발생한다.

삼항연산자를 사용해서 null이면 split 메소드를 호출하지 않고 null을 반환한다.

 

 

 

 

 

 

ㅁ 별칭등록

 

 
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
 
<configuration>

    <settings>
        <setting name="jdbcTypeForNull" value="NULL" />
    </settings>

   
    <typeAliases>
        <typeAlias type="com.br.mybatis.notice.dto.NoticeDto" alias="NoticeDto" />
        <typeAlias type="com.br.mybatis.member.dto.MemberDto" alias="MemberDto" />
        <typeAlias type="com.br.mybatis.common.handler.StringArrTypeHandler" alias="StringArrTypeHandler" />
    </typeAliases>
   

    <environments default="development">
   
        <environment id="development">
            <transactionManager type="JDBC" />
            <dataSource type="POOLED">
                <property name="driver" value="oracle.jdbc.driver.OracleDriver" />
                <property name="url" value="jdbc:oracle:thin:@localhost:1521:xe" />
                <property name="username" value="SERVER" />
                <property name="password" value="SERVER" />
            </dataSource>
        </environment>
       
    </environments>

   
    <mappers>
        <mapper resource="mappers/notice-mapper.xml" />
        <mapper resource="mappers/member-mapper.xml" />
    </mappers>



</configuration>  
 

 

 

- StringArrTypeHandler 구현 클래스의 별칭을 등록한다.

 

 

 

 

ㅁ 다시 member-mapper.xml

 

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

    <resultMap id="memberResultMap" type="MemberDto">
        <result column="user_no" property="userNo" />
        <result column="user_id" property="userId" />
        <result column="user_name" property="userName" />
        <result column="phone" property="phone" />
        <result column="email" property="email" />
        <result column="address" property="address" />
        <result column="interest" property="interest" typeHandler="StringArrTypeHandler"/>
    </resultMap>


    <select id="selectMember" resultMap="memberResultMap">
        select
                user_no
              , user_id
              , user_name
              , phone
              , email
              , address
              , interest
          from  member
         where  status in ('U', 'A')
           and  user_no = #{ userNo }          
    </select>

</mapper>
 

 

 

- resultMap의 interest 컬럼에 typeHandler 속성을 추가한다.

- select 태그에 resultMap 속성을 추가한다.

 

- TypeHandler 인터페이스를 구현하는 클래스에는 3개의 getResult 메소드가 있다. 

interest 컬럼에 typeHandler 속성을 추가하면 타입핸들러가 동작한다.

- "interest"라는 컬럼으로 조회된 값이 MemberDto 객체의 "interest" 필드에 담길 때 타입핸들러의 getResult 메소드가 자동으로 작동한다.

 

 

- <resultMap> 태그 중 typeHandler 속성이 있는 <result> 태그의 column 속성값이 

TypeHandler를 구현하는 클래스의 getResult(ResultSet rs, String columnName) 메소드의 매개변수로 전달된다.

- getResult 메소드에서 ResultSet객체.getString(columnName)으로 컬럼값을 뽑아서 split(",") 메소드로 String[]로 변환한 다음 반환한다.

- String[]로 결과가 반환되면 이 반환값이 MemberDto의 "interest" 필드에 담긴다.

 

 

 

 

 

 

ㅁ 컨트롤러를 완성한다.

 

 
package com.br.mybatis.member.controller;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class MemberDetailController
 */
@WebServlet("/detail.me")
public class MemberDetailController extends HttpServlet {
    private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public MemberDetailController() {
        super();
    }

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {


        int userNo = Integer.parseInt(request.getParameter("userNo"));
        MemberDto m = new MemberServiceImpl().selectMember(userNo);
       
        request.setAttribute("m", m);
        request.getRequestDispatcher("WEB-INF/views/member/myInfo.jsp").forward(request, response);
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

}
 

 

 

 

 

typeHandler가 필수는 아니다. 

- typeHandler 없이 화면단에서든 자바단에서든 split으로 나눠도 된다. 

 

 

 

 

ㅁ myInfo.jsp를 만든다.

 

 
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
 
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> <!-- JSTL 함수 기능을 위한 설정 -->
<c:set var="contextPath" value="${pageContext.request.contextPath}" />

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script> // jQuery 라이브러리 코드

</head>
<body>

    <h3>회원 상세조회 + 변경</h3>

    <c:choose>
        <c:when test="${ empty m }">
            조회된 회원이 없습니다
        </c:when>
       
        <c:otherwise>
            <form>
                회원번호 : <input type="text" value="${ m.userNo }" readonly> <br>
                아이디 : <input type="text" value="${ m.userId }" readonly> <br>
                이름 : <input type="text" value="${ m.userName }"> <br>
                전화번호 : <input type="text" value="${ m.phone }"> <br>
                이메일 : <input type="text" value="${ m.email }"> <br>
                주소 : <input type="text" value="${ m.address }"> <br>
                관심분야 :
                <input type="checkbox" name="interest" value="운동">운동        
                <input type="checkbox" name="interest" value="등산">등산                
                <input type="checkbox" name="interest" value="낚시">낚시                
                <input type="checkbox" name="interest" value="요리">요리                
                <input type="checkbox" name="interest" value="게임">게임                
                <input type="checkbox" name="interest" value="영화">영화        
               
                <script>
                    $(function(){
                        let interest = '${ fn:join(m.interest, ",") }'; // '등산,요리,게임' <- 배열을 하나의 문자열로 만듦.
                       
                        $(":checkbox").each(function(){ // db로부터 이 회원의 interest를 가져와서 해당하는 체크박스에 체크해서 보여주기.
                            if(interest.search($(this).val()) != -1){
                                $(this).prop("checked", true);
                            }
 
                        })
                    })
                </script>
                       
            </form>
        </c:otherwise>
    </c:choose>

</body>
</html>
 

 

 

- EL 구문은 null 체크 안해도 됨. null일 경우 그냥 빈문자열이 출력된다.

 

- jQuery 사용을 위한 jQuery 라이브러리 코드 구문 1줄을 05_jspServlet-workspace의 header.jsp에서 가져온다.

 

- functions 라이브러리를 사용하기 위한 taglib 지시어를 상단에 작성한다.

el 구문 내에서 쓸수있는 함수를 제공해주는 라이브러리다.

- 자바에서의 String[]에 담겨있는 값들을 하나의 문자열로 합쳐주는 함수를 functions 라이브러리에서 제공한다.

fn:join(m.interest, ",")

- 자바스크립트에서 문자열로 인식하기 위해서는 '${ fn:join(m.interest, ",") }'로 감싸줘야 한다.

 

- jQuery의 each 메소드로 각 체크박스 요소에 순차적으로 접근한다.

 

 

 

 

 

 

 

 

 

 

================================================================================

 

 

 

 

[ update ]

 

 

ㅁ myInfo.jsp에 버튼을 두고  input에 name을 둔다

 

 
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<c:set var="contextPath" value="${pageContext.request.contextPath}" />

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>


</head>
<body>

    <h3>회원 상세조회 + 변경</h3>

    <c:choose>
        <c:when test="${ empty m }">
            조회된 회원이 없습니다
        </c:when>
       
        <c:otherwise>
            <form action="${ contextPath }/update.me" method="post">
                회원번호 : <input type="text" name="userNo" value="${ m.userNo }" readonly> <br>
                아이디 : <input type="text" value="${ m.userId }" readonly> <br>
                이름 : <input type="text" name="userName" value="${ m.userName }"> <br>
                전화번호 : <input type="text" name="phone" value="${ m.phone }"> <br>
                이메일 : <input type="text" name="email" value="${ m.email }"> <br>
                주소 : <input type="text" name="address" value="${ m.address }"> <br>
                관심분야 :
                <input type="checkbox" name="interest" value="운동">운동        
                <input type="checkbox" name="interest" value="등산">등산                
                <input type="checkbox" name="interest" value="낚시">낚시                
                <input type="checkbox" name="interest" value="요리">요리                
                <input type="checkbox" name="interest" value="게임">게임                
                <input type="checkbox" name="interest" value="영화">영화        
               
                <button type="submit">정보변경</button>
               
                <script>
                    $(function(){
                        let interest = '${ fn:join(m.interest, ",") }'; // '등산,요리,게임' <- 배열을 하나의 문자열로 만듦.
                       
                        $(":checkbox").each(function(){ // db로부터 이 회원의 interest를 가져와서 해당하는 체크박스에 체크해서 보여주기.
                            if(interest.search($(this).val()) != -1){
                                $(this).prop("checked", true);
                            }
                        })
                    })
                </script>
                       
            </form>
        </c:otherwise>
    </c:choose>

</body>
</html>
 

 

 

 

 

ㅁ MemberUpdateController 서블릿을 만든다.

 

 
package com.br.mybatis.member.controller;

import java.io.IOException;

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.br.mybatis.member.dto.MemberDto;
import com.br.mybatis.member.service.MemberServiceImpl;

/**
 * Servlet implementation class MemberUpdateController
 */
@WebServlet("/update.me")
public class MemberUpdateController extends HttpServlet {
    private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public MemberUpdateController() {
        super();
    }

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        MemberDto m = new MemberDto();
        m.setUserNo(Integer.parseInt(request.getParameter("userNo")));
        m.setUserName(request.getParameter("userNo"));
        m.setPhone(request.getParameter("phone"));
        m.setEmail(request.getParameter("email"));
        m.setAddress(request.getParameter("address"));
        m.setInterest(request.getParameterValues("interest")); // MemberDto 객체의 setInterest메소드가 String 배열을 받는다.
       
        int result = new MemberServiceImpl().updateMember(m);
       
        if(result > 0) {
            System.out.println("수정 성공");
            response.sendRedirect(request.getContextPath());
        }else {
            System.out.println("수정 실패");
        }
       
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

}
 

 

 

 

 

ㅁ MemberServiceImpl에 updateMember 메소드 만들기

 

 
package com.br.mybatis.member.service;

import org.apache.ibatis.session.SqlSession;

import static com.br.mybatis.common.template.Template.*;
import com.br.mybatis.member.dao.MemberDao;
import com.br.mybatis.member.dto.MemberDto;

public class MemberServiceImpl implements MemberService {

    private MemberDao memberDao = new MemberDao();
   
   
    @Override
    public MemberDto selectMember(int userNo) {
        SqlSession sqlSession = /*Template.*/getSqlSession();
        MemberDto m = memberDao.selectMember(sqlSession, userNo);
       
        sqlSession.close();
        return m;
    }

    @Override
    public int updateMember(MemberDto m) {
        SqlSession sqlSession = getSqlSession();
        int result = memberDao.updateMember(sqlSession, m);
       
        if(result > 0) {
            sqlSession.commit();
        }
       
        sqlSession.close();
        return result;
    }

}
 

 

 

 

 

ㅁ MemberDao에 updateMember 메소드 만들기

 

 
package com.br.mybatis.member.dao;

import org.apache.ibatis.session.SqlSession;

import com.br.mybatis.member.dto.MemberDto;

public class MemberDao {

    public MemberDto selectMember(SqlSession sqlSession, int userNo) {
        return sqlSession.selectOne("memberMapper.selectMember", userNo);
    }

    public int updateMember(SqlSession sqlSession, MemberDto m) {
        return sqlSession.update("memberMapper.updateMember", m);
    }

}
 

 

 

 

 

 

ㅁ member-mapper.xml에 update 쿼리 만들기

 

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

    <resultMap id="memberResultMap" type="MemberDto">
        <result column="user_no" property="userNo" />
        <result column="user_id" property="userId" />
        <result column="user_name" property="userName" />
        <result column="phone" property="phone" />
        <result column="email" property="email" />
        <result column="address" property="address" />
        <result column="interest" property="interest" typeHandler="StringArrTypeHandler"/>
    </resultMap>


    <select id="selectMember" resultMap="memberResultMap">
        select
                user_no
              , user_id
              , user_name
              , phone
              , email
              , address
              , interest
          from  member
         where  status in ('U', 'A')
           and  user_no = #{ userNo }          
    </select>


    <update id="updateMember">
        update
                member
           set  
                user_name = #{userName}    
              , phone = #{phone}    
              , email = #{email}
              , address = #{address}
              , interest = #{interest, typeHandler=StringArrTypeHandler}
         where user_no = #{userNo}    
    </update>


</mapper>
 

 

 

- 파라미터를 설정하는 중괄호 블록 안에 typeHandler가 동작되게끔 할 수 있다. 

파라미터를 설정하는 곳에 타입핸들러를 실행하게끔 하면 getResult가 아닌 setParameter 메소드가 동작한다.

 

 

- MyBatis에서 #{}에 값이 채워질 때, typeHandler를 사용할 수 있다.

#{ }는 단순한 값 바인딩뿐 아니라 값을 바인딩할 때 사용되는 설정들을 같이 지정할 수 있다.

 

 

 

 

 

com.br.mybatis.common.handler의 StringArrTypeHandler 수정

 

 
package com.br.mybatis.common.handler;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeHandler;
 

public class StringArrTypeHandler implements TypeHandler<String[]> {
 

    @Override
    public String[] getResult(ResultSet rs, String columnName) throws SQLException {

        String resultDB = rs.getString(columnName); // "낚시,운동,게임"

        return resultDB == null ? null : resultDB.split(","); // ["낚시", "운동", "게임"]
    }
 

    @Override
    public String[] getResult(ResultSet rs, int columnIndex) throws SQLException {
        return null;
    }

    @Override
    public String[] getResult(CallableStatement cs, int columnIndex) throws SQLException {
        return null;
    }
 

    @Override
    public void setParameter(PreparedStatement ps, int i, String[] parameter, JdbcType jdbcType) throws SQLException {


        ps.setString(i, parameter == null ? null : String.join(",", parameter));

    }

}
 

 

 

- setParameter 메소드의 매개변수에 PreparedStatement가 있다. 여기에 setXXX 메소드로 물음표의 값을 채울 수 있다.

- 쿼리에서 #{ } 부분이 물음표고, int i는 접근되는 홀더(물음표) 순번이다. 여기서 i의 값은 5다.

 

- String[] parameter에는 MemberDto 객체의 interest 필드값인 String[]이 온다.

 

- ps.setXXX(홀더순번, 대체할값);

ps.setString(i, parameter값을 String으로 변환한 값);으로 형변환하는 코드를 작성하면 된다. 

 

 

 

 

 

 

 

 

 

- '정보변경' 버튼을 누르면 메인페이지로 가지고 다시 회원번호를 입력해서 검색하면 update가 잘 되었음을 확인할 수 있다.