복습
Maven
- Spring 프로젝트는 Maven 으로만 라이브러리 관리 가능
- Springboo 프로젝트는 Maven, Gradle 둘 다 사용 가능
Maven 파일 구조
- src/main/java 에 확장자가 Java 인 파일을 넣는다
- src/main/resource 는 MyBatis 의 환경 설정 파일, 기존에 DAO 에 있었던 SQL문을 따로 빼서 만든 xml 파일
- src/main/webapp 는 View 페이지가 들어감, index 파일도 아 폴더 내에 들어간다 , 기존의 WebContent 폴더 역할
- src/main/webapp/WEB-INF 안에 프로젝트 환경 설정 파일인 web.xml 이 들어감, 그리고 기존의 lib 폴더는 사라짐
- DAO 클래스는 존재하지만 DAO 클래스의 SQL문을 따로 빼서 따로 파일을 만드는데, 그걸 mapper 파일이라고 부른다
- pom.xml 이 Maven 의 환경 설정 파일, 여기에서 의존 라이브러리를 추가
pom.xml 환경 설정 파일
- 오라클 jdbc, mysql jdbc, cos, mybatis, jstl 등 많은 라이브러리를 다운 받았었다
local repository 위치
프로젝트 구분
- Maven 프로젝트는 m , Spring 프로젝트는 s 가 붙어있다
Maven 프로젝트 / Spring 프로젝트 주의
- Maven 프로젝트, Spring 프로젝트는 war 파일로 export / import 하면 Dynamic Web Project 로 풀리므로 주의
- Maven 프로젝트, Spring 프로젝트는 프로젝트를 통째로 복사 붙여넣기해서 export 해야한다
- 이클립스에서 Spring 프로젝트 만드려면 플러그인 추가 또는 STS 라는 툴을 다운받아 사용
- Spring 프로젝트는 Mavne 프로젝트와 달리 기본적인 라이브러리가 이미 pom.xml 에 다 들어가 있다
- 아파치 톰캣이 자동으로 추가되지 않는 경우가 만흥므로 직접 추가해 준다
MyBatis
데이터베이스 접속 방식
- DB 접속 방식 3번째인 ORM 프레임워크 중 MyBatis 사용할 것
ORM 프레임워크
- ORM 프레임워크에서 Object 는 DTO 객체를 의미, Mapping 은 연결을 의미
- 즉 DTO 클래스의 필드와 테이블 안의 컬럼을 매핑시키는 것, 매핑 처리를 위해선 두 이름을 일치시켜야함
- ORM 프레임워크를 사용시 코드가 간단해진다
- 전자정부 프레임 워크에서는 MyBatis 사용함
- MyBatis 로 Model 1 에서도 연동해보고, Model 2 에서도 연동해 볼 것
프로젝트에 MyBatis 연동하기 위해 필요한 파일
- MyBatis 와 연동하기 위해서는 크게 2가지 파일이 필요하다
1. MyBatis 의 환경설정 파일
2. 기존 DAO 파일에 들어있던 내용인 Mapper 파일
- 이 2개 파일이 src/main/resources 폴더 안에 있어야 한다
프로젝트에 MyBatis 연동하는 방법
1. MarketPlace 에서 MyBatis Plugin 프로그램을 설치해야한다
- Mapper 파일을 생성할 수 있는 메뉴가 추가됨
- 과거에는 MarketPlace 에서 플러그인 설치시 MaBatis 환경설정 파일도 만들 수 있었지만 현재는 불가능
- 그리고 이클립스를 재시작한다
2. Mapper 파일을 생성해야 한다
- maventest 프로젝트의 resources 폴더에서 오른쪽 마우스 클릭
- 플러그인인을 설치시 Mapper 파일을 생성할 수 있는 메뉴가 나타남
- resources 폴더 안에 Mapper 파일이 들어갔다
- mapper.xml (예시)
- 이 파일 안에 DAO 의 insert, update, delete, select 가 들어감
- xml 파일이므로 루트 엘리먼트가 있어야하고, 루트 엘리먼트가 mapper
- insert 태그 사이에 insert SQL문 작성, 다른 DML 문도 마찬가지, 태그에는 각 SQL문을 구분하기 위한 id 가 있다
3. 다음으로는 MyBatis 환경설정 파일이 다운받아진 프로젝트를 import 해서 MaBatis 환경설정 파일을 살펴보자
- 현재는 플러그인 추가해도 MaBatis 환경설정 파일 생성 불가
MaBatis 프로젝트 import 하기
- mybatistest 프로젝트 import
- mabatistest.zip 파일을 다운로드 받아서 압축 해제 후 import
- mybatistest 가 import 되었다
- MyBatis 와 연동되는 이 3개 파일들은 모두 src/main/resources 폴더 안에 저장되어 있어야 함
MyBatis 연동 관련 파일 살펴보기
1. db.properties
#mysql
#jdbc.driverClassName=com.mysql.jdbc.Driver
#jdbc.url=jdbc:mysql://localhost:3306/jsptest
#jdbc.username=jspid
#jdbc.password=jsppass
#oracle
jdbc.driverClassName=oracle.jdbc.driver.OracleDriver
jdbc.url=jdbc:oracle:thin:@localhost:1521:xe
jdbc.username=scott
jdbc.password=tiger
- DB 접속에 필요한 내용들이 들어간다
- 위에는 mysql 과 연동하는 내용, 아래는 oracle 과 연동하는 내용을 작성했다
- 왼쪽은 변수명, 오른쪽은 변수에 할당될 값이다
- jdbc.driverClassName 변수명은 정해져 있는 이름이다, 경로를 oracle.jdbc.driver.OracleDriver 로 설정
- jdbc.url 변수에는 jdbc:oracle:thin:@localhost:1521:xe 로 DB 경로를 설정
- 현재는 scott 계정으로 연결 설정했다
- # 은 주석
- mybatis-config.xml 파일에서 이 파일 db.properties를 불러온다
2. mybatis-config.xml
- MyBatis 의 환경설정 파일이다
+ 환경 설정 파일은 대부분 xml 파일이다
<?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>
<properties resource="db.properties" />
<typeAliases>
<typeAlias type="#package.#modelname" alias="#modelname"></typeAlias>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="#package/#mapper.xml" />
</mappers>
</configuration>
- 위의 DOCTYPE configuration 내용을 삭제하면 안된다, mybatis.org/dtd/mabatis-3-config.dtd 문서를 불러오고 있다
- 루트 엘리먼트는 configuration
Mabatis 환경설정 파일인 mybatis-config.xml 파일 안에 들어가는 내용 3가지
0) properties 태그에서 db.properties 파일을 불러온다
1) typeAliases 태그로 DTO 클래스의 경로를 alias 로 간단한 별칭을 설정
- typeAlias 태그의 type 속성에서 DTO 클래스의 경로를 패키지부터 해당 클래스까지의 경로로 작성
- typeAlias 태그의 alias 속성에서 alias는 별칭을 의미, 그 경로를 짧은 별칭으로 설정하는 것
- DTO 클래스가 많아지면 typealias 태그를 추가해주면 된다
2) environments 태그 안의 property 태그에서 DB 접속 관련 내용들 작성
- property 태그는 클래스의 멤버변수(필드, 프로퍼티) 를 의미, name 속성값은 고정되어있고, values 값으로 db.property 안의 변수명을 이용해서 변수값을 불러오고 있다
+ 변수명으로 불러오는 대신 그 자리에 바로 값을 써도 된다
ex) <property name="driver" value="oracle.jdbc.driver.OracleDriver"/>
- 그렇게 드라이브의 경로, DB 경로, 계정명, 비밀번호 등을 불러옴
- db 접속하는 내용들이 들어간다
- 위에서 db.property 파일을 불러왔으므로 가능함
3) mappers 태그 안의 mapper 태그로 SQL문이 들어간 파일인 Mapper 파일을 불러오기
- mapper 태그의 resource 속성에 패키지명을 적어주고, Mapper 파일명을 써주기
+ 여기서 mapper 태그 안에서 Mapper 파일을 불러오므로 Mapper 파일의 루트 엘리먼트도 mapper 이다
- Mapper 파일은 테이블의 개수에 비례해서 늘어난다
- Mapper 파일이 늘어나면 mapper 태그를 추가해주면 된다
3. mapper.xml
- Mapper 파일 이다
- 이름은 반드시 mapper.xml 이 아니다
<?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">
<mapper namespace="#package.#mapperinterfacename">
<select id="getSomething" parameterType="int" resultType="#package.#modelname">
SELECT
columnname1,
columnname2,
columnname3
FROM tablename1
WHERE columnname1 = #{value}
</select>
<resultMap type="#modelname" id="YourResultSet">
<id property="param1" column="columnname1" />
<result property="param2" column="columnname2" />
<result property="param3" column="columnname3" />
</resultMap>
<select id="getAll" resultMap="YourResultSet">
SELECT * FROM tablename1
</select>
<insert id="insertSomething" parameterType="#modelname">
INSERT INTO tablename1 (columnname1, columnname2, columnname3)
VALUES(#{value1},#{value2},#{value3})
</insert>
<update id="updateSomething" parameterType="#modelname">
UPDATE tablename1
SET
columnname1=#{param1}
WHERE
columnname2 = #{param2}
</update>
<delete id="deleteSomething" parameterType="int">
DELETE FROM tablename1 WHERE
columnname1 = #{param1}
</delete>
</mapper>
- select 문은 select 태그로 감싸준다
- 태그들을 구분하기 위해 id 값을 다르게 설정한다
- DAO 파일에서 이 Mapper 파일의 id 값을 불러서 사용한다
<값 전달하기 : parameterType>
- insert , select 할 데이터는 parameterType 속성으로 값을 받는다
- parameterType 속성값에 전달되는 값의 자료형을 작성
< 검색한 값 돌려받기 : returnType >
- select 해서 검색한 결과를 resultType 속성으로 값을 돌려준다
- select SQL문만 returnType 속성을 사용함
- resultType 속성값에는 값을 돌려줄때의 자료형을 작성
- #{} 에서 getter 메소드로 불러올 값들을 작성함
< 검색한 값 돌려받기 : 데이터 1개 검색 >
- 데이터를 1개 검색했을때는 if(rs.next()) 로 가져와서 DTO 객체에 저장했었다, 일일히 setter 메소드로 저장했었음
- 이제는 일일히 setter 메소드를 작성하지 않고 컬럼명에 일치하는 DTO 프로퍼티가 있을땐 자동으로 setter 메소드를 불러서 매핑해준다
- returnType 에 DTO 경로 별칭만 써주면 테이블명과 DTO 프로퍼티가 일치하는 경우에 자동으로 매핑
< 검색한 값 돌려받기 : 데이터 2개 이상 검색 >
- 2개 이상의 데이터를 검색할때는 리스트를 통해 값을 받았었다, 여기서는 resultType 으로 DTO 클래스의 alias 명을 쓰면 된다, 리스트에 저장시키는 것 까지 자동으로 해줌
- returnType 에 DTO 경로 별칭만 써주면 테이블명과 DTO 프로퍼티가 일치하는 경우에 자동으로 매핑, 리스트 저장까지 해줌
<자료형이 DTO일땐>
- 전달되는 값의 자료형이나 돌려주는 값의 자료형이 DTO일땐, MyBatis 환경설정 파일에서 설정한 DTO 클래스의 alias 값이 파라미터 타입값으로 들어가야한다
<resultMap>
- resultMap 은 컬럼명과 DTO 프로퍼티명이 일치하지 않을때, resultMap 으로 일일히 매핑을 잡아줘야한다
- resultMap 태그 안에서 컬럼과 프로퍼티를 일일히 매핑
JSP - MyBatis 연동
Model 1 과 MyBatis 연동
- 클라우드에서 Model 1 과 MyBatis 가 이미 연동이 완료된 member22 프로젝트 import
- zip 파일을 압축 풀어서 import
+ 그냥 member22 파일을 바로 import 하면 . 으로 시작된 파일들이 import 안된다
+ 반드시 zip 파일을 풀어서 생성된 폴더를 import 하기
- src/main/java 안에 확장자가 java 인 파일들이 저장되어있다
- src/main/resources 안에 DB 연동에 필요한 MyBatis 환경설정 파일 등이 들어가 있다
- src/main/webapp 안에 View 파일 등이 들어간다
- import한 member22 프로젝트의 pom.xml 파일을 보자
- pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.myhome</groupId>
<artifactId>member22</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>member22 Maven Webapp</name>
<url>http://maven.apache.org</url>
<!-- 오라클 repository -->
<repositories>
<repository>
<id>codelds</id>
<url>https://code.lds.org/nexus/content/groups/main-repo</url>
</repository>
</repositories>
<dependencies>
<!-- 오라클 JDBC Library -->
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
<version>11.2.0.3</version>
</dependency>
<!-- MySQL -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!-- iBatis -->
<dependency>
<groupId>org.apache.ibatis</groupId>
<artifactId>ibatis-sqlmap</artifactId>
<version>2.3.4.726</version>
</dependency>
<!-- mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.3</version>
</dependency>
<!-- jstl -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>org.apache.taglibs</groupId>
<artifactId>taglibs-standard-impl</artifactId>
<version>1.2.5</version>
</dependency>
<!-- cos -->
<dependency>
<groupId>servlets.com</groupId>
<artifactId>cos</artifactId>
<version>05Nov2002</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>member22</finalName>
</build>
</project>
- dependencies 태그 안에 의존 라이브러리를 dependency 태그로 추가
- 오라클 JDBC, MySQL JDBC, iBatis, MyBatis 3.5.3 ver, JSTL, cos 라이브러리가 추가되었다
- 오라클 공식 저장소에서 다운받는 건 오류 많이 발생
- 오라클은 비공식 저장소 repository 를 원격 저장소 위치로 등록하고 거기서 오라클 JDBC 라이브러리를 불러오기
- MyBatis 연동시에는 반드시 MyBatis 라이브러리가 추가되어 있어야함
Model 1 에 MyBatis 연동시 구조
- Model 1 에서 MyBatis 를 연동하면 DAO 이후부터만 달라진다
- 앞부분은 Model 1과 동일하고 달라지는 내용은 DAO 이후 부터 이다
- DAO 메소드 안의 복잡한 내용들이 빠져서 MyBatis 환경설정 파일로 간다
- 안의 SQL문들이 빠져서 Mapper 파일인 member.xml 으로 간다
- MyBatis 환경설정 파일인 mybatis-config.xml 파일을 보자
<?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>
<properties resource="db.properties" />
<typeAliases>
<typeAlias type="model.Member" alias="member"></typeAlias>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="member.xml" />
</mappers>
</configuration>
- model 패키지 안의 DTO 경로를 alias 속성을 통해 member 라는 별칭으로 지정
- mapper 태그로 Mapper 파일인 member.xml 파일을 불러옴, 같은 폴더 안에 있으므로 이름만으로 불러옴
- Mapper 파일이 다른 패키지안에 있으면 불러올 때 패키지명도 명시해줘야함
- Mapper 파일인 member.xml 파일을 보자
<?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">
<mapper namespace="memberns">
<insert id="insert" parameterType="member">
insert into member22 values (#{id}, #{password})
</insert>
<select id="list" resultType="member">
select * from member22
</select>
<select id="select" parameterType="String" resultType="member">
select * from member22 where id = #{id}
</select>
<update id="update" parameterType="member">
update member22 set password = #{password} where id = #{id}
</update>
<delete id="delete" parameterType="String">
delete from member22 where id = #{id}
</delete>
</mapper>
- db.properties
#mysql
#jdbc.driverClassName=com.mysql.jdbc.Driver
#jdbc.url=jdbc:mysql://localhost:3306/jsptest
#jdbc.username=jspid
#jdbc.password=jsppass
#oracle
jdbc.driverClassName=oracle.jdbc.driver.OracleDriver
jdbc.url=jdbc:oracle:thin:@localhost:1521:xe
jdbc.username=totoro
jdbc.password=totoro123
- db.properties 파일에서 totoro 계정으로 설정되어있으므로 totoro 계정에서 테이블을 생성해야함
+ import 시에 테이블이 생성되지는 않음
- sql 폴더의 member.sql 에서 totoro 계정으로 연결한 후 member22 테이블을 생성하자
- member.sql
-- model1 과 mybatis 연동
select * from tab;
select * from member22;
create table member22 (
id varchar2(10) primary key,
password varchar2(10)
);
- 테이블 member22 를 생성하자
- 테이블의 필드명과 DTO 클래스의 멤버변수(필드, 프로퍼티) 명을 같은 이름으로 설정해야한다
+ 간소화 시킨 테이블임
흐름 설명
- src/main/java 에서 model 패키지의 DTO 클래스인 Member.java 를 보자
package model;
public class Member {
private String id;
private String password;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
- 프로퍼티명이 컬럼명과 동일하게 id, password 로 되어있다, 쉽게 매핑 가능해짐
- 회원가입 페이지인 joinForm.jsp 에서 form 의 name 값도 똑같이 id, password 로 일치시킨다
- 그렇게 해야 setProperty 로 쉽게 저장 가능 (Model 1)
- joinForm.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<h2>회원가입</h2>
<form action="joinPro.jsp">
아이디 : <input type="text" name="id" required="required"><p>
암호 : <input type="password" name="password" required="required"><p>
<input type="submit" value="확인">
</form>
</body>
</html>
- loginForm.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<h2>로그인</h2>
<form action="loginPro.jsp" >
아이디 : <input type="text" name="id" required="required"><p>
암호 : <input type="password" name="password" required="required"><p>
<input type="submit" value="확인">
</form>
<p><a href="joinForm.jsp">회원가입</a>
</body>
</html>
- index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<html>
<body>
<h2>Hello World!</h2>
<script>
location.href="member/loginForm.jsp";
</script>
</body>
</html>
- index 파일은 webapp 폴더 안에 저장되어 있어야함
- index 파일을 실행시켜도 되고, 현재 프로젝트 선택 후 Run As - Run on Server 로 실행 하면 index 파일이 실행됨
- 실행시 index.jsp 파일에서 loginForm.jsp 파일을 실행시킴
- 회원 가입을 해보자, 클릭 시 joinForm.jsp 파일로 넘어감
- '확인' 시 joinPro.jsp 파일로 넘어가면서 id, password 를 네임값으로 해서 입력된 값을 전달
- joinPro.jsp 에서 setProperty 로 DTO 객체 mem에 값 설정 후 insert(mem) 호출
- 가입 후 로그인
- master 란 아이디로 가입시 관리자
- 관리자로 로그인 시 나오는 내용이 달라짐
- 회원명단을 볼 수 있는 메뉴가 나타남
- 즉, 관리자로 로그인 시 나오는 내용이 달라짐
- 회원 수정이나 회원 탈퇴 시킬 수 있다
- 앞부분은 Model 1과 동일하고 달라지는 내용은 DAO 이후 부터 이다
- DAO 클래스가 SQL문을 실행하는 것은 같지만, DAO 클래스 안에서 SQL문이 빠져서 Mapper 파일로 간다
- Mapper 파일인 member.xml 파일을 보자
-member.xml (중복)
<?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">
<mapper namespace="memberns">
<insert id="insert" parameterType="member">
insert into member22 values (#{id}, #{password})
</insert>
<select id="list" resultType="member">
select * from member22
</select>
<select id="select" parameterType="String" resultType="member">
select * from member22 where id = #{id}
</select>
<update id="update" parameterType="member">
update member22 set password = #{password} where id = #{id}
</update>
<delete id="delete" parameterType="String">
delete from member22 where id = #{id}
</delete>
</mapper>
- id 값은 태그를 구별하는 역할, 이 파일 내에선 중복되선 안되는 값이다
- update 문은 update 태그 안에 작성
- DAO 클래스에서 이 id 값을 불러온다, 즉, 안의 SQL문을 불러온다
- 전달되는 값의 자료형을 parameterType 에 쓰고 돌려주는 값의 자료형을 resultType 에 쓴다
- resultType 은 select 태그 (select 문) 에만 사용가능하다
- 전달되는 값이 없을땐 parameterType 속성을 사용하지 않음
- DTO 객체가 전달되는 값의 자료형이거나 돌려주는 값의 자료형일땐 alias (별칭) 값을 쓴다
- 2개 이상의 데이터를 검색할때도 똑같이 DTO 객체인 alias 값을 사용하면 자동으로 리스트에 저장해서 돌려줌
- 다음은 MyBatis 환경 설정 파일인 mybatis-config.xml 을 보자
- mybatis-config.xml (중복)
<?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>
<properties resource="db.properties" />
<typeAliases>
<typeAlias type="model.Member" alias="member"></typeAlias>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="member.xml" />
</mappers>
</configuration>
1. 이 alias 를 Mapper 파일안에서 값을 받고 돌려줄때 사용한다
+ alias 를 설정하지 않았다면 패키지부터 클래스까지 전부 써야한다
2. DB 접속에 필요한 내용을 property 태그 안에 작성, db.properties 파일의 변수를 불러와서 설정
+ 변수 불러오지 않아도 바로 적어도 된다
3. Mapper 파일을 불러오고 있다
DAO 클래스에서 id 값을 불러오는 원리
- DAO 에서 바로 Mapper 파일의 id를 불러올 수 없다
- 먼저 MyBatis 환경설정 파일 3번째 자리에서 Mapper 파일을 불러온다
- DAO에서는 MyBatis 환경 설정 파일을 불러옴으로서 id 를 불러올 수 있음
- 즉 Mapper 파일을 MyBatis 환경설정 파일에서 불러오고, MyBatis 환경설정 파일을 DAO 에서 불러온다
- 연쇄적으로 불러오기 때문에 Mapper 파일에 설정된 id 를 DAO 클래스에서 불러 올 수 있음
- DAO 클래스인 MemberDao.java 를 보자
- MemberDao.java
package dao;
import java.io.IOException;
import java.io.Reader;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import model.Member;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class MemberDao {
private SqlSession getSession() {
SqlSession session=null;
Reader reader=null;
try {
reader = Resources.getResourceAsReader("mybatis-config.xml");
SqlSessionFactory sf = new SqlSessionFactoryBuilder().build(reader);
session = sf.openSession(true); // auto commit
} catch (IOException e) {
System.out.println(e.getMessage());
}
return session;
}
public int insert(Member member) {
int result = 0;
SqlSession session=null;
try {
session = getSession();
result = session.insert("insert", member);
} catch (Exception e) {
System.out.println(e.getMessage());
}
return result;
}
public int chk(Member member) {
int result = 0;
SqlSession session=null;
try { session = getSession();
Member mem = (Member) session.selectOne("select", member.getId());
if (mem.getId().equals(member.getId())) {
result = -1;
if (mem.getPassword().equals(member.getPassword())) {
result = 1;
}
}
} catch (Exception e) {
System.out.println(e.getMessage());
}
return result;
}
public Member select(String id) throws SQLException {
Member mem = null;
SqlSession session=null;
try { session = getSession();
mem = (Member) session.selectOne("select", id);
} catch (Exception e) {
System.out.println(e.getMessage());
}
return mem;
}
public List<Member> list() {
List<Member> list = new ArrayList<Member>();
SqlSession session=null;
try { session = getSession();
list = session.selectList("list");
} catch (Exception e) {
System.out.println(e.getMessage());
}
return list;
}
public int delete(String id) {
int result = 0;
SqlSession session=null;
try { session = getSession();
result = session.delete("delete", id);
} catch (Exception e) {
System.out.println(e.getMessage());
}
return result;
}
public int update(Member mem) {
int result = 0;
SqlSession session=null;
try { session = getSession();
result = session.update("update", mem);
} catch (Exception e) {
System.out.println(e.getMessage());
}
return result;
}
}
- 마찬가지로 DB 연동을 처리하는 클래스이다
- SQL문이 빠지고 Mapper 파일인 member.xml 파일에 들어가있다
- SQL문을 제외한 나머지 내용이 들어가있음, 메소드만으로 구성되어있다
+ MyBatis 지원 클래스/인터페이스 (SqlSession 인터페이스 등) 들을 import 하고 있다 * 아래에 설명
SqlSession 객체 구하기 / MyBatis 환경설정 파일 읽어오기 (MemberDao.java 부분 getSession() 메소드)
private SqlSession getSession() {
SqlSession session=null;
Reader reader=null;
try {
reader = Resources.getResourceAsReader("mybatis-config.xml");
SqlSessionFactory sf = new SqlSessionFactoryBuilder().build(reader);
session = sf.openSession(true); // auto commit
} catch (IOException e) {
System.out.println(e.getMessage());
}
return session;
}
- getSession() 메소드에서는 try 안의 3줄을 통해 SqlSession 객체를 구해준다, 그 객체를 통해 SQL문을 실행하는 메소드들을 사용 가능하다
- Reader 객체를 구할때 MyBatis 환경설정 파일인 mybatis-config,xml 을 불러오고 있다, MyBatis 환경설정 파일에서는 Mapper 파일을 불러옴
- 그렇기 때문에 DAO 에서 Mapper 파일의 id 값을 불러올 수 있다, 즉 Mapper 파일의 SQL문을 불러올 수 있음
- sf.openSession(true) 를 하면 자동 커밋이 된다, 자동 커밋이 되지 않는다면 SQL문을 수행 후 일일히 session.commit() 으로 커밋을 수행해야함
* 커밋을 해야 DB에 실제 삽입, 수정, 삭제 등이 됨
DAO 안에서 id 로 불러와서 SQL문 실행 (MemberDao.java 부분)
public int insert(Member member) {
int result = 0;
SqlSession session=null;
try {
session = getSession();
result = session.insert("insert", member);
} catch (Exception e) {
System.out.println(e.getMessage());
}
return result;
}
- 가장 먼저 getSession() 메소드로 SqlSession 객체를 구한다
- DAO 안의 메소드 안에서 그 SQL문을 실행해야하는데, 이때 SqlSession 에서 지원하는 메소드를 사용한다
- insert() 메소드를 사용해서 id 값인 "insert" 로 Mapper 클래스의 insert 문을 불러온다
메소드에서 메소드 첫번째 매개변수에는 id값, 전달될 값이 있다면 두번째 매개변수에 전달될 값을 전달
- 여기서는 전달받은 DTO 객체인 member 를 두번째 매개변수를 통해 전달하고 있음
- insert() 메소드를 실행 후 삽입 성공한 데이터 개수를 자동으로 반환해줌
- 위의 insert() 메소드는 SQL문을 실행시켜주는 메소드 5가지 중 하나이다
SQL문을 실행시켜주는 메소드 5가지 (MemberDao.java 부분)
- SQL문에 따라서 메소드가 정해져 있다
- 이 메소드를 지원하는 인터페이스 SqlSession 객체를 구해와야만 이 메소드 5개를 사용 가능하다
- 그래서 위에서 getSession() 메소드로 SqlSession 객체를 구해왔다
+ SqlSession 은 MyBatis 에서 지원되는 인터페이스
- insert SQL문은 insert() 메소드로 실행해야한다, update, delete 도 마찬가지
- 검색되는 결과가 1개인 select 문은 selectOne() 메소드로 실행
- 결과를 Object 형으로 돌려준다, 다운캐스팅
+ Member 는 DTO 클래스 이름이다
- 검색되는 결과가 2개 이상인 selec 문은 selectList() 메소드로 실행
- 결과를 List 로 돌려준다
- insert() / update() / delete() 메소드는 삽입, 수정, 삭제된 데이터 개수를 자동으로 돌려준다
- 메소드 자체적으로 값을 자동으로 돌려주므로 Mapper 파일에서 insert / update / delete 문은 resultType 을 쓰면 안됨
- resultType 은 select 문만 사용가능
<데이터를 1개 검색시>
- selectOne() 메소드를 사용시에는 값을 Object 형 으로 돌려주므로 다운캐스팅 해야한다
- resultType 에는 DTO 객체를 쓴다
<데이터를 2개 이상 검색시>
- 데이터 2개 이상 검색하는 select문에서도 resultType 에는 DTO 객체만 쓴다, List 를 쓰지 않음! 자동으로 리스트를 잡아서 돌려준다
- 일일히 가져와서 DTO 객체 에 setter 메소드로 저장했었지만 이제는 검색된 데이터의 컬럼명과 DTO 프로퍼티명이 같다면 자동으로 순차적으로 DTO 객체에 저장하면서 List 를 만들어서 돌려줌
Mapper 의 insert SQL문을 insert() 메소드로 불러와서 실행 (MemberDao.java 부분, 중복)
- update(), delete() 도 마찬가지
public int insert(Member member) {
int result = 0;
SqlSession session=null;
try {
session = getSession();
result = session.insert("insert", member);
} catch (Exception e) {
System.out.println(e.getMessage());
}
return result;
}
- SqlSession 객체가 있어야 insert() 메소드 사용 가능, 이전에 정의한 getSession() 으로 객체를 받아온다
- insert() 메소드 자체적으로 삽입에 성공한 데이터 개수를 돌려주는 기능이 있으므로 Mapper 파일의 insert에 resultType 을 써선 안됨
- 그렇게 돌려받은 값을 result 변수에 받아서 그 변수를 리턴하고 있음
- insert() 메소드에서 메소드 첫번째 매개변수에는 id값, 전달될 값이 있다면 두번째 매개변수에 전달될 값을 전달
- 여기서는 전달받은 DTO 객체인 member 를 두번째 매개변수를 통해 전달하고 있음
- Mapper 파일의 parameterType 에서도 같은 자료형인 DTO 를 써야함
- Mapper 파일 member.xml 부분
<insert id="insert" parameterType="member">
insert into member22 values (#{id}, #{password})
</insert>
- parameterType 에는 전달될 값의 자료형을 적음, DTO 객체를 전달받아야하므로 alias 로 설정한 별칭인 member 를 적는다
- #{} 안에 DTO 클래스의 필드명을 써서, 값을 가져온다.
- 표기만 이럴뿐 DTO 객체에 직접 접근하는 것이 아니라 getter 메소드로 가져오는 것임
- #{id} 의 의미는 member.getId() 로 리턴받은 값을 의미함
- #{password} 의 의미는 member.getPassword() 로 리턴받은 값을 의미
+ 단점 : 값을 1개만 전달 가능
Mapper 의 select SQL문을 select() 메소드로 불러와서 실행 1(MemberDao.java 부분)
public Member select(String id) throws SQLException {
Member mem = null;
SqlSession session=null;
try { session = getSession();
mem = (Member) session.selectOne("select", id);
} catch (Exception e) {
System.out.println(e.getMessage());
}
return mem;
}
- SqlSession 객체가 있어야 select() 메소드 사용 가능, 이전에 정의한 getSession() 으로 객체를 받아온다
- select() 메소드는 돌려주는 데이터가 몇개인지에 따라 다른 메소드를 쓴다, 1개 데이터를 돌려줄때는 selectOne() 사용
- 두번째 매개변수로 사용자의 id 값을 전달
- 마찬가지로 Mapper 파일의 parameterType 도 String 형으로 설정해야함
- Mapper 파일 member.xml 부분
<select id="select" parameterType="String" resultType="member">
select * from member22 where id = #{id}
</select>
- 넘어오는 값은 사용자의 id 값이므로 paramterType 은 String 으로 설정해야함
- #{id} 의 의미는 전달된 변수 id 값을 가져오는 것임
- 데이터 1개를 돌려주므로 resultType 을 DTO 의 alias 인 member 로 설정
- if(rs.next()) 안에서 수행했던 member.setId(rs.getString("id")) 를 더이상 쓰지 않음, 돌려주는 객체 member 에 자동으로 setter 메소드로 값을 다 저장해서 돌려준다
+ DTO 프로퍼티명과 컬럼명이 일치하는 경우에만 가능
Mapper 의 select SQL문을 select() 메소드로 불러와서 실행 2(MemberDao.java 부분)
- 위의 select() 와는 다른 메소드, 이건 로그인 시 회원 인증을 해주는 chk() 메소드이다
public int chk(Member member) {
int result = 0;
SqlSession session=null;
try { session = getSession();
Member mem = (Member) session.selectOne("select", member.getId());
if (mem.getId().equals(member.getId())) {
result = -1;
if (mem.getPassword().equals(member.getPassword())) {
result = 1; // 회원인증 성공
}
}
} catch (Exception e) {
System.out.println(e.getMessage());
}
return result;
}
- 로그인 시 회원인증을 처리하는 부분이다
- mem.getId() 는 DB에 저장된 id 를 의미하고, member.getId()는 사용자가 입력한 id 를 의미
- mem.getPassword() 는 DB에 저장된 password 를 의미하고, member.getPassword()는 사용자가 입력한 password 를 의미
- id, password 가 모두 일치할때는 변수 result 에 1 을 저장해서 리턴함, 이 값으로 로그인 성공을 판별하는 것은 loginPro.jsp 에서 처리함
- id 는 일치하되, passoword 가 일치하지 않을때는 변수 result 에 -1 을 저장해서 리턴, 이것도 loginPro.jsp 에서 처리
- Mapper 파일 member.xml 부분
<select id="select" parameterType="String" resultType="member">
select * from member22 where id = #{id}
</select>
회원가입 기능
Model 1 & MyBatis 회원 가입 흐름
1. 처음 index.jsp 실행 -> loginForm.jsp -> '회원가입' 눌러서 joinForm.jsp 로 넘어감
2. joinForm.jsp 에서 입력된 값을 id, password 네임값에 저장해서 joinPro.jsp 로 전달
3. joinPro.jsp 에서 useBean 과 setProperty 로 DTO 객체 mem 생성 후 값 저장, DAO 객체의 insert(mem) 호출함
4. DAO 에서 insert() 메소드를 실행, 그 안에서 Mapper 파일의 insert SQL문을 id 로 불러온다
- insert() 가 잘 수행되면 1을 돌려줌
5. joinPro.jsp 로 돌아오고, 회원가입 성공 시 loginForm.jsp 로 넘어간다, 실패(중복아이디)시 이전페이지로 이동
- joinForm.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<h2>회원가입</h2>
<form action="joinPro.jsp">
아이디 : <input type="text" name="id" required="required"><p>
암호 : <input type="password" name="password" required="required"><p>
<input type="submit" value="확인">
</form>
</body>
</html>
- joinPro.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" import="dao.*"%>
<jsp:useBean id="mem" class="model.Member"/>
<jsp:setProperty property="*" name="mem"/>
<%
MemberDao md = new MemberDao();
int result = md.insert(mem);
if (result>0) {
%>
<script type="text/javascript">
alert("가입성공");
location.href="loginForm.jsp";
</script>
<%
} else {
%>
<script type="text/javascript">
alert("가입 실패");
history.go(-1);
</script>
<%
}
%>
- MemberDao.java 에서 insert() 메소드 부분만
public int insert(Member member) {
int result = 0;
SqlSession session=null;
try {
session = getSession();
result = session.insert("insert", member);
} catch (Exception e) {
System.out.println(e.getMessage());
}
return result;
}
- member.xml 에서 회원 가입을 처리하는 SQL문 부분 (id 가 insert)
<insert id="insert" parameterType="member">
insert into member22 values (#{id}, #{password})
</insert>
로그인 기능
Model 1 & MyBatis 로그인 흐름
1. 처음 index.jsp 실행 -> loginForm.jsp 로 넘어감
2. loginForm.jsp 에서 입력된 값을 id, password 네임값에 저장해서 loginPro.jsp 로 전달
3. loginPro.jsp 에서 useBean 과 setProperty 로 DTO 객체 mem 생성 후 값 저장, DAO 객체의 chk(mem) 호출함
4. DAO 에서 chk() 메소드를 실행, 그 안에서 Mapper 파일의 select SQL문을 id 로 불러온다, selectOne() 가 잘 수행되면 DB에 저장된 사용자의 정보를 가져옴
- 다운캐스팅 해서 DTO 객체에 저장 (다운캐스팅 생략해도 작동한다)
- 그 정보가 사용자가 입력한 값과 일치시 result 에 1을 저장해서 돌려준다
5. loginPro.jsp 로 돌아오고 회원 인증 성공 시 id 를 세션 공유 설정하고 main.jsp 로 넘어간다, 실패(중복아이디)시 이전페이지로 이동
- loginForm.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<h2>로그인</h2>
<form action="loginPro.jsp" >
아이디 : <input type="text" name="id" required="required"><p>
암호 : <input type="password" name="password" required="required"><p>
<input type="submit" value="확인">
</form>
<p><a href="joinForm.jsp">회원가입</a>
</body>
</html>
- loginPro.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@page import="dao.MemberDao"%>
<jsp:useBean id="mem" class="model.Member"/>
<jsp:setProperty property="*" name="mem"/>
<%
MemberDao md = new MemberDao();
int result = md.chk(mem);
if (result==1) {
session.setAttribute("id",mem.getId());
%>
<script type="text/javascript">
alert("환영함");
location.href="main.jsp";
</script>
<%
} else if (result == -1) {
%>
<script type="text/javascript">
alert("비번이 다르다");
history.go(-1);
</script>
<%
} else {
%>
<script type="text/javascript">
alert("그런 ID가 없습니다.");
history.go(-1);
</script>
<%
}
%>
- MemberDao.java 에서 chk() 메소드 부분만
public int chk(Member member) {
int result = 0;
SqlSession session=null;
try { session = getSession();
Member mem = (Member) session.selectOne("select", member.getId());
if (mem.getId().equals(member.getId())) {
result = -1;
if (mem.getPassword().equals(member.getPassword())) {
result = 1; // 회원인증 성공
}
}
} catch (Exception e) {
System.out.println(e.getMessage());
}
return result;
}
- member.xml 에서 로그인(회원 인증)을 처리하는 SQL문 부분 (id 가 select)
<select id="select" parameterType="String" resultType="member">
select * from member22 where id = #{id}
</select>
DAO 클래스 상단에서 MyBatis 지원 클래스 / 인터페이스 import
중간 페이지 기능
- 로그인 성공시 이동하는 main.jsp 내용을 보자
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<%
String id = (String) session.getAttribute("id");
if (id == null || id.equals("")) {
response.sendRedirect("loginForm.jsp");
} else if (id.equals("master")) {
out.println("관리자 모드!");
}
%>
<body>
로긴함
<p>
정보수정<br>
<%
if (id != null) {
if (id.equals("master")) {
%>
<a href="list.jsp">회원명단</a><br>
<%
}}
%>
<a href="logout.jsp">로그아웃</a>
</body>
</html>
-로그인 성공시 공유한 공유값 id 값을 가져와서 사용
- getAttribute() 로 공유값을 가져올때는 다운캐스팅을 해야함
- 받아온 공유값인 id 가 null 인 경우, Redirect 포워딩 팡식으로 loginForm.jsp 로 넘어감
- 받아온 공유값인 id 가 "master" 인 경우 "관리자 모드!" 라는 메세지가 출력됨
<body 태그 안>
- 받아온 공유값인 id가 "master" 인 경우 "회원명단" 출력, 클릭시 list.jsp 로 이동하도록 설정
- 어느 아이디로 로그인되었느냐에 따라 main.jsp 내용이 달라짐
- '로그아웃' 클릭시 logout.jsp 로 이동 : 세션 삭제, 로그아웃 메세지 출력하고 로그인 폼으로 이동하는 작업을 한다
로그아웃 기능
- '로그아웃' 을 클릭시 넘어가는 logout.jsp 를 보자
- logout.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<%
session.invalidate();
%>
<script type="text/javascript">
alert("로그아웃 됨");
location.href="loginForm.jsp";
</script>
</body>
</html>
1. 세션 삭제(끊어줌)
2. 로그아웃 메세지 출력하고 loginForm.jsp 로 이동
- 이 두가지 작업만 한다
- DB 연동 안함
목록 페이지 기능
- '회원명단' 을 클릭시 넘어가는 list.jsp 를 보자
- list.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@page import="java.util.List"%>
<%@page import="model.Member"%>
<%@page import="dao.MemberDao"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
회원 명단
<table border=1><tr><th>아이디</th><th>비밀번호</th><th>수정</th><th>삭제</th></tr>
<%
MemberDao md = new MemberDao();
List<Member> list = md.list();
for (int i = 0;i<list.size();i++){
%>
<tr><td><%=list.get(i).getId() %></td><td><%=list.get(i).getPassword() %></td>
<td><input type="button" value="수정" onclick='location.href="updateForm.jsp?id=<%=list.get(i).getId() %>"'></td>
<td><input type="button" value="삭제" onclick='location.href="delete.jsp?id=<%=list.get(i).getId() %>"'></td></tr>
<%
}
%>
</table>
<a href="main.jsp">메인으로</a>
</body>
</html>
- id 가 master 인 관리자 계정만 볼 수 있다
- DB 연동을 수행해서 전체를 검색한다, DAO 객체 생성해서 전체 회원 목록을 구해오는 list() 메소드 호출
- 결과를 list 로 돌려받은 다음 반복문에서 get() 과 getter 메소드로 값을 가져와서 테이블에 뿌리고 있다
- '수정' 또는 '삭제' 를 클릭시 해당 회원의 아이디값을 넘기면서 updateForm.jsp 또는 delete.jsp 로 이동한다
- 관리자 모드이므로 '삭제' 누르면 바로 삭제되도록 했다
- 이 list() 메소드가 정의되어 있는 DAO 클래스의 부분을 보자
- MemberDao.java 에서 list() 메소드 부분만
public List<Member> list() {
List<Member> list = new ArrayList<Member>();
SqlSession session=null;
try { session = getSession();
list = session.selectList("list");
} catch (Exception e) {
System.out.println(e.getMessage());
}
return list;
}
- 제네릭을 쓰고 있으므로 리스트에서 get() 으로 가져올때 자료형 생략 가능
- SqlSession 객체를 구해와야만 selectList() 를 사용 가능하므로 getSession() 호출해서 SqlSession 객체 구해오기
- 메소드 getSession() 안에서 DB와 연동하는 것임
- List 객체 list 를 업캐스팅으로 생성
- selectList() 메소드는 검색되는 결과가 2개 이상인 경우 실행하는 메소드
- selectList() 메소드 첫번째 매개변수로 Mapper 파일의 id "list" 를 써서 해당 select SQL문을 호출
- selectList() 메소드에서 전달할 값은 없으므로 두번째 매개변수는 쓰지 않았다
- selectList() 메소드로 돌려받은 리스트를 객체 list 에 저장해서 list.jsp로 리턴
MyBatis 연동 전 / 후
- while(rs.next()) 에서 DTO 객체 생성하고 setter 메소드로 저장시킨 후 리스트에 객체를 저장하는 행동을 반복했다
- MyBatis 와 연동하면 이런 작업이 Mapping 을 통해서 자동으로 실행되고, 리스트를 반환시켜줌
selectOne() vs selectList()
- 돌려줄 데이터가 1개이면 selectOne() 사용, 2개 이상이면 selectList() 사용
- selectOne() 은 리턴자료형이 Object, selectList() 는 리턴자료형이 List
데이터를 2개 이상 검색해서 돌려줄때 주의사항
- Mapper 파일의 select 문에서 데이터를 2개이상 돌려주더라도 resultType 에는 리스트가 아니라 DTO 가 오면 된다
ex) 돌려주는 자료형이 List<int> 이더라도 resultType 에 List 가 아닌 int 를 씀
ex) 돌려주는 자료형이 List<DTO> 이면 resultType 에 List 가 아닌 DTO(alias 별칭 member) 를 씀
- Mapper 파일인 member.xml 에서 해당 SQL 문 부분만 살펴보자
- member.xml 에서 전체 목록을 가져오는 SQL문 부분
<select id="list" resultType="member">
select * from member22
</select>
+ select는 반드시 resultType 을 써야함, 받을 값은 없으므로 parameterType 은 쓰지 않았다
- 전체 데이터를 검색하고 있다
정보수정 기능 : 수정폼
- list.jsp 에서 '수정' 을 눌렀을때 수정하는 기능
<td><input type="button" value="수정" onclick='location.href="updateForm.jsp?id=<%=list.get(i).getId() %>"'></td>
- '수정' 클릭시 onClick 에 의해 updateForm.jsp 로 넘어간다, 넘어갈 때 해당 회원의 id 값을 get 방식으로 전달
- 세션에 공유된 id값은 관리자 id값인 "master" 이고 여기서 넘어가는 id값은 각 회원의 id 값임
- 먼저 수정폼을 해야함
- updateForm.jsp 파일을 보자
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@page import="model.Member"%>
<%@page import="dao.MemberDao"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<%
String id = request.getParameter("id");
MemberDao md = new MemberDao();
Member mem = md.select(id);
%>
<h2>정보 수정</h2>
<form action="updatePro.jsp">
<input type="hidden" name="id" value="<%=mem.getId() %>">
<table><tr><td>아이디</td>
<td><input type="text" name="id" value="<%=mem.getId() %>" disabled="disabled"></td></tr>
<tr><td>암호</td>
<td><input type="text" name="password" value="<%=mem.getPassword() %>"></td></tr>
<tr><td colspan="2" align="right">
<input type="submit" value="변경">
<input type="button" onclick="history.go(-1)" value="취소"></td></tr>
</table>
</form>
</body>
</html>
- 수정폼이므로 DB와 연동하여 1명에 대한 상세정보를 수정폼에 뿌려줘야한다
- list.jsp 에서 넘어온 회원의 id값을 받고 변수 id 에 저장
- DAO 객체를 생성해서 DAO 의 select() 메소드 호출
- select() 메소드를 호출하며 id 값을 넘긴다, 1명에 대한 상세정보를 구해오므로 리턴자료형 DTO
- 검색결과를 받은 mem 객체를 통해 mem.getId() 와 mem.getPassword() 로 id, password 를 수정폼에 뿌려줌
- id 는 disabled 로 설정되어있으므로 값이 action 의 페이지로 넘어가지 않는다, 그래서 hidden 객체로 따로 id 를 넘김
+ readonly 설정은 값이 넘어감, disabled 는 값이 안넘어감 * HTML readonly vs disabled 속성 설명 아래에
- 이후 수정폼에 상세정보를 뿌린 후, 사용자가 수정폼을 입력하고 '변경' 버튼을 누르면 id, password 를 가지고 updatePro.jsp로 이동한다
- MemberDao.java 에서 select() 메소드 부분만
public Member select(String id) throws SQLException {
Member mem = null;
SqlSession session=null;
try { session = getSession();
mem = (Member) session.selectOne("select", id);
} catch (Exception e) {
System.out.println(e.getMessage());
}
return mem;
}
- getSession() 으로 SqlSession 객체 구해오기
- 1개 데이터를 검색하므로 selectOne() 메소드 호출
- 첫번째 매개변수에 들어가는 Mapper 파일의 id는 "select", 두번째 매개변수에 들어가는 전달될 값은 매개변수로 받은 id
- selectOne() 을 호출하고 결과를 Object 형으로 돌려주므로 다운캐스팅해서 DTO 객체 member 에 저장하고 그걸 리턴
+ 다운캐스팅 명시 생략 가능
- 이 select() 메소드 실행 후 이 메소드를 호출한 updateForm.jsp 로 돌아감
- member.xml 에서 수정폼을 처리하는 SQL문 부분 (id 가 select)
<select id="select" parameterType="String" resultType="member">
select * from member22 where id = #{id}
</select>
- 각 회원의 id 를 받으므로 paramterType 을 String 으로 설정
- 1명에 대한 상세정보를 리턴하므로 resultType 은 DTO 클래스 별칭인 member
- 전달되는 변수명이 id 이므로, #{id} 로 전달되는 값을 가져옴, parameterType 은 "String"
- URL 을 보면, id 값이 get 방식으로 넘어갔음을 볼 수 있다
+ 매개변수로 전달된 id 를 전달
- selectOne() 에서 변수 id 에 값이 전달되고 있다
- 그래서 member.xml 에서 #{id} 로 SQL문 where절 작성
정보수정 기능 : 실제 수정
- 이후 수정폼에 상세정보를 뿌린 후, 사용자가 수정폼을 입력하고 '변경' 버튼을 누르면 id, password 를 가지고 updatePro.jsp 로 이동한다
- updatePro.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@page import="dao.MemberDao"%>
<%@page import="model.Member"%>
<jsp:useBean id="mem" class="model.Member"/>
<jsp:setProperty property="*" name="mem"/>
<%
MemberDao md = new MemberDao();
int result = md.update(mem);
if (result == 1) {
%>
<script type="text/javascript">
alert("수정 성공");
location.href="list.jsp";
</script>
<%
} else {
%>
<script type="text/javascript">
alert("수정 실패");
history.go(-1);
</script>
<%
}
%>
- useBean, setProperty action tag 사용해서 수정폼에서 hidden 으로 넘어온 id 값과, 비밀번호 입력양식에서 넘어온 password 값을 받아서 DTO 객체 mem 에 저장
+ 입력양식의 name 값과 DTO 의 프로퍼티명이 일치할때만 가능
- DAO 객체 생성 후 DAO의 update() 메소드를 호출하며 매개변수로 객체 mem 을 전달
- 성공시 메세지 출력 후 list.jsp 로 돌아감, 즉 다시 회원목록을 구해서 뿌려준다
- MemberDao.java 에서 update() 메소드 부분만
public int update(Member mem) {
int result = 0;
SqlSession session=null;
try { session = getSession();
result = session.update("update", mem);
} catch (Exception e) {
System.out.println(e.getMessage());
}
return result;
}
- update() 메소드의 첫번째 매개변수에 Mapper 파일의 id 명인 "update" 를, 두번째 매개변수에 넘겨줄 값인 객체 mem 을 적기
- update() 메소드가 실행되고 성공적으로 수정하면 1 을 리턴해줌, 그 1 을 result 변수에 저장해서 updatePro.jsp 로 리턴함
- member.xml 에서 정보 수정을 처리하는 SQL문 부분 (id 가 update)
<update id="update" parameterType="member">
update member22 set password = #{password} where id = #{id}
</update>
- DTO 객체가 넘어올때 #{id} 는 member.getId() 를 의미, #{password} 는 member.getPassword() 를 의미
- update SQL문이 수행되고 자동으로 수정한 데이터 개수를 돌려줌, 즉 1 을 리턴해줌
* HTML readonly vs disabled 속성
공통점
- 입력 양식의 값을 수정할 수 없도록 비활성화 시켜주는 역할
차이점
- readonly 속성으로 설정된 양식은 action 으로 설정된 페이지로 값이 전달되지만,
- disabled 속성으로 설정된 양식은 action 으로 설정된 페이지로 값이 전달되지 않는다.
정보수정 기능 : 삭제
- list.jsp 에서 '삭제' 를 눌렀을때 수정하는 기능
<td><input type="button" value="삭제" onclick='location.href="delete.jsp?id=<%=list.get(i).getId() %>"'></td></tr>
- '삭제' 클릭시 onClick 에 의해 delete.jsp 로 넘어간다, 넘어갈 때 해당 회원의 id 값을 get 방식으로 전달
- 즉 삭제폼을 거치지 않고 바로 삭제되게 해뒀다
- delete.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@page import="dao.MemberDao"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<%
String id = request.getParameter("id");
MemberDao md = new MemberDao();
int result = md.delete(id);
if (result == 1) {
%>
<script type="text/javascript">
alert("삭제성공");
location.href="list.jsp";
</script>
<%
} else {
%>
<script type="text/javascript">
alert("실패");
location.href="list.jsp";
</script>
<%
}
%>
</body>
</html>
- list.jsp 로 부터 전달받은 id 값을 받아서 저장
- DAO 객체를 생성하고 DAO의 delete() 메소드 실행, 특정 회원 삭제를 해야하므로 매개변수로 id 값을 전달한다
- 메소드 호출하여 삭제 성공시 목록 페이지인 list.jsp 로 돌아간다
- MemberDao.java 에서 delete() 메소드 부분만
public int delete(String id) {
int result = 0;
SqlSession session=null;
try { session = getSession();
result = session.delete("delete", id);
} catch (Exception e) {
System.out.println(e.getMessage());
}
return result;
}
- member.xml 에서 회원 삭제(탈퇴) 를 처리하는 SQL문 부분 (id 가 delete)
<delete id="delete" parameterType="String">
delete from member22 where id = #{id}
</delete>
- #{id} 는 DAO에서 session.delete() 메소드 실행시 두번째 매개변수로 넘어온 변수 id 를 의미함
- delete SQL문이 수행되고 자동으로 삭제한 데이터 개수를 돌려줌, 즉 1 을 리턴해줌
- 자동으로 삭제한 데이터 개수를 돌려주므로 select 외의 insert/update/delete 는 returnType 을 쓰면 안된다
#{id} 의 의미
1. 일반 변수 id 가 넘어왔을때 #{id} 는 그 변수 id 값을 의미함
2. DTO 객체 member 가 넘어왔을때 #{id} 는 member.getId() 를 의미, 즉 객체 안의 프로퍼티 값을 의미
- 같은 코드지만 다른 의미이다
- master 로 로그인 한 뒤 회원 목록 페이지인 list.jsp 에서 회원을 삭제해보자
MyBatis
- DB 연동을 처리하기 위한 프레임 워크
프로그램 확장 시
- MyBatis 환경설정 파일은 하나만 있으면 된다
- Mapper 파일은 테이블의 개수에 비례해서 늘어난다
태그 맞추기
- Mapper 파일인 member.xml의 루트 엘리먼트는 mapper 이다
- MyBatis 환경 설정 파일에서 태그를 mapper 로 해야한다
- Mapper 파일의 루트 엘리먼트와 MaBatis 환경설정 파일에서 Mapper 파일을 불러올때 태그 이름을 맞춰야한다
Mapper 파일의 id 충돌문제
- 같은 Mapper 파일 뿐 아니라 다른 Mapper 파일 끼리도 id 값을 다르게 설정해야한다
- member 테이블, board 테이블 이 있을때 member.xml , board.xml 처럼 Mapper 파일이 각각 생성됨
- 이때 서로 다른 두 Mapper 파일에서도 같은 id값을 쓰면 안된다!, 그래야 DAO에서 불러올때 충돌되지 않음
- id 값이 중복되는 문제 해결하기 위해 namespace
namespace
- 논리적인 영역 이름
- namespace를 통해 id값 중복되어 DAO 에서 불러올때 충돌되는 문제 해결가능
+ 일반적으로 namespace를 테이블명+"ns" 로 설정함
- Mapper 파일에서 namespace 값만 서로 다르게 설정하면 다른 Mapper 파일끼리 같은 id값을 사용할 수 있다
- Mapper 파일인 member.xml 부분
- 그래서 insert id 를 불러오는 DAO 코드에서 namespace 를 함께 써서 충돌 피할 수 있다
- 이렇게 하면 다른 테이블의 Mapper 파일에서 id 값을 insert 로 쓴다고 해도 충돌하지 않음