본문 바로가기
Spring/study

spring 5강 Oracle과 mybatis 연동 실습(회원 목록,등록,수정,삭제)

by avvin 2019. 6. 5.

일단 인강 다 보고 전체적으로 다시 정리해보기


spring 5강 Oracle과 mybatis 연동 실습(회원 목록,등록,수정,삭제)



회원관리의 전체적인 구조

Controller


MemberController.java


Service // 컨트롤러와 모델을 사이에 위치, 

    //써도 안써도 무방. 서비스는 하나인데 모델 메서드가 여러개인 경우 필요(???) ex)  트랜잭션 처리


MemberService.java    인터페이스

MemberServiceImpl.java    구현 클래스


Model


MemberDAO.java    인터페이스  //DAO를 인터페이스와 구현클래스로 나눠서 진행

MemberDAOImpl.java    구현클래스

MemberDTO.java  (자바빈즈와 같이 정보를 저장하는 클래스)

memberMapper.xml    sql 매퍼 //mybatis의 sql 명령어가 저장되는 파일


View


member_lsit.jsp

write.jsp  //회원 신규 등록 페이지

view.jsp  //회원 상세 정보 페이지




+


memberMapper.xml : sql 쿼리 모여있다. ( src/main/resources > mappers ) 

DAO는 sqlSession 주입받고 ServiceImpl은 DAO 객체 주입받는다. 

Controller > Service > DAO 순으로 일을 떠넘기고 처리된 데이터 객체를 주입받는식


mybatis-config.xml : mybatis 설정 파일???, 근데 왜 MemberDTO에 대한 코드 한줄만 있지?

 => MyBatis에 대한 (DB연동같은)다른 설정들은 root-context가 맡고있으므로 그 외 자잘한 설정을 이 파일에 위치

MemberDTO 타입을 리턴(resultType)해야하는 쿼리가 있는데, MemberDTO의 경로가 너무 기니까 

typeAliases로 클래스명을 줄여부를수 있게끔 설정한 것 // 이 방법 굳이 쓸 필요 x...


root-context :

Mapper.xml로 끝나는 파일 모두 매핑

sql이 모여있는 파일(도 파일명 Mapper로 끝남 )을 읽어들이고 ( jsp에선  sqlMapConfig.xml // DB연결 정보, 등 )

sqlSession 객체  주입할 수 있게 bean으로 설정



//매퍼파일은 자동업데이트가 제대로 안되는 경우가 잦아서 서버나 툴을 재시작 해야할때도 많다.





회원 등록 프로세스


memberList.jsp [회원 등록] → ( 컨트롤러 경유 ) MemberController의 member/write.do로 매핑된 메서드 실행 


(  MemberController   ←@inject-   MemberService   ←@inject-   MemberDAO   ←@inject-  SqlSession )


→  (WEB-INF) write.jsp 회원 등록 폼  [완료] → member/insert.do ( 위 과정 )



*JSP mybatis Oracle 연동과 비교


JSP

sqlmap.MybatisManager.java : sqlMapConfig(쿼리파일, DB정보)를 읽어들여 sqlSession 객체 생성


sqlMapConfig : sql 쿼리 담긴 파일 매핑, MyBatis에 DB정보 설정


( sql객체 생성 파일 (db등 mybatis 정보담은 파일 ( sql 파일 ) ) )


Spring

root-context : 

sqlSesssionFactory를 bean으로 설정 DB정보와 sql 파일 정보를 주고,  

sqlSession도 bean으로 설정한다. 

위 ( sql객체 생성 파일 (db등 mybatis 정보담은 파일 ( sql 파일 ) ) ) 과정을 root-context가 다 한다.



@RequestMapping된 메서드에 데이터가 넘어올 때


GET방식으로 넘어올땐 매개변수 위치에 @RequestParam ( 생략가능 ) 폼에서 넘어온 데이터를 저장해주는 변수에 붙인다

POST 방식으로 넘어올땐 매개변수 위치에 @ModelAttribute ( 생략가능 ) 폼에서 넘어온 데이터를 저장해주는 변수에 붙인다

스프링이 이 변수에 알아서 폼데이터를 저장해준다.

(get은 파라미터로 받았으니 requestparam, post는 form에서 쓴 각각의 name들 전체를 받았으니 modelattribute로 기억)


정확히는 @RequestParam은 폼의 개별값, @ModelAtrribute는 폼의 전체 데이터(dto) 받아올 때 사용


1
2
3
4
5
    @RequestMapping("member/insert.do")
    public String insert(@ModelAttribute MemberDTO dto) {
        memberService.insertMember(dto);
        return "redirect:/member/list.do"//목록 갱신 
    }
cs



컨트롤러에서 다른 페이지로 데이터를 넘기고자할 때 


1. 데이터만 넘길 경우 : @Controller + 메서드에 @RespenseBody OR @RestController

  ( 다음페이지가 아니라 원래 페이지로 넘어옴 )

1
2
3
4
5
6
7
8
9
10
@RestController // 스프링 4.0부터 사용 가능 
public class SampleRestController {
 
    @ResponseBody //데이터 리턴 // json 형식으로 리턴
    @RequestMapping("test/doF"// url mapping
    public ProductDTO doF() {
        //호출한 곳으로 데이터가 넘어감(json 형식) 
        return new ProductDTO("냉장고",500000);
    }
}
cs


2. 뷰 정보와 데이터를 함께 넘길 경우 : 리턴타입을 ModelAndView로 하고 넘길 데이터를 (key지정) value 값으로 넣어준다. 

 (Model에 데이터를 붙이고 리턴으로 포워딩하는거랑 기능상 별 차이는 없는 것같음. 

 ModelAndView는 Model이랑 리턴 따로따로 할 필요없이 ModelAndview에 둘 다 매개값으로 줘버림)


1
2
3
4
5
6
    @RequestMapping("test/doC")
    public ModelAndView doC() {
        Map<String,Object> map=new HashMap<>();
        map.put("product"new ProductDTO("샤프",1000));
        return new ModelAndView("test/doC","map",map);
    }
cs




1. sql developer에서 member 테이블 생성


2. MemberDTO 


3. memberDAO





1. sql developer에서 member 테이블 생성


spring 계정 member 테이블 생성 


sql

1
2
3
4
5
6
7
8
9
10
11
12
13
create table member(
userid varchar2(50not null primary key,
passwd varchar2(50not null,
name varchar2(50not null,
email varchar2(50),
join_date date default sysdate //회원가입 날짜
);
 
insert into member(userid,passwd,name,email) values('kim','1234','김철수','kim@gmail.com');
 
select * from member;
 
commit;
cs





2. MemberDTO 



src/main/java -com.example.spring01.model.dto 패키지에 memberDTO 생성


getter / setter와 toString 생성


toString은 객체를 문자열로 변환하여 리턴해주는 java.lang 패키지 Object클래스에서 지원하는 메서드


memberDTO.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package com.example.spring01.model.dto;
 
import java.util.Date;
 
public class MemberDTO {
    private String userid;
    private String passwd;
    private String name;
    private String email;
    private Date join_date;
    public String getUserid() {
        return userid;
    }
    public void setUserid(String userid) {
        this.userid = userid;
    }
    public String getPasswd() {
        return passwd;
    }
    public void setPasswd(String passwd) {
        this.passwd = passwd;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }
    public Date getJoin_date() {
        return join_date;
    }
    public void setJoin_date(Date join_date) {
        this.join_date = join_date;
    }
    public MemberDTO() {
    }
    @Override
    public String toString() {
        return "MemberDTO [userid=" + userid + ", passwd=" + passwd + ", name=" + name + ", email=" + email + ", join_date="
                + join_date + "]";
    }
    
}
 
cs



3. memberDAO


src/main/java - com.example.spring01.model.dao 패키지에 memberDAO 인터페이스 생성


memberDAO.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.example.spring01.model.dao;
 
import java.util.List;
 
import com.example.spring01.model.dto.MemberDTO;
 
public interface MemberDAO {
    public List<MemberDTO> memberList();
    public void insertMember(MemberDTO vo);
    public MemberDTO viewMember(String userid);
    public void deleteMember(String userid);
    public void updateMember(MemberDTO vo);
    public boolean checkPw(String userid, String passwd);
}
 
cs



같은 dao패키지에 memberDAOImpl 클래스 생성 


자동 구현

생성할 때 Interface 부분에서 구현할 인터페이스를 Add하거나 

생성하고 implements memberDAO 명시한 후에  Alt + Shift + S  > V (자동 오버라이딩, 임플러먼트)


memberDAOImpl.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
package com.example.spring01.model.dao;
 
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
import javax.inject.Inject;
 
import org.apache.ibatis.session.SqlSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Repository;
 
import com.example.spring01.model.dto.MemberDTO;
 
@Repository  //서버가 startup될 때 이 클래스가 메모리에 자동으로 등록됨 
public class MemberDAOImpl implements MemberDAO {
    //로깅 처리를 위한 객체 선언
    private static final Logger logger=
            LoggerFactory.getLogger(MemberDAOImpl.class);
    //SqlSession 객체를 개발자가 직접 생성하지 않고 스프링에서 연결시켜 줌
    @Inject //의존관계 주입
    SqlSession sqlSession;
    
    @Override
    public List<MemberDTO> memberList() {
        logger.info("memberList called...");
        // sql mapper에 작성된 sql 코드가 실행됨(auto commit & close)
        List<MemberDTO> list=sqlSession.selectList("member.memberList");
        return list;
    }
 
    @Override
    public void insertMember(MemberDTO vo) {
        //auto commit & close
        sqlSession.insert("member.insertMember", vo);
    }
 
    @Override
    public MemberDTO viewMember(String userid) {
        return sqlSession.selectOne("member.viewMember", userid); 
    }
 
    @Override
    public void deleteMember(String userid) {
        sqlSession.delete("member.deleteMember", userid);
    }
 
    @Override
    public void updateMember(MemberDTO vo) {
        sqlSession.update("member.updateMember", vo); 
    }
 
    @Override
    public boolean checkPw(String userid, String passwd) {
        boolean result=false;
        //mapper에 넘길 값이 2개 이상인 경우 map으로 묶어서 전달 
        Map<String,String> map=new HashMap<>();
        map.put("userid", userid);
        map.put("passwd", passwd);
        int count=sqlSession.selectOne("member.checkPw", map);
        //리턴값이 1이면 true, 0이면 false 
        if(count==1) result=true;
        return result;
    }
 
}
cs



sqlSession의 메서드 : select(One / List) / insert / update / delete


select(One / List) - 처리할 레코드가 하나일 경우 selectOne() 둘 이상일 경우 selectLsit() 사용





@Repository // 서버가 starup될 때 이 클래스가 메모리에 자동으로 등록됨


@Repository : 서버가 올라올때 현재 클래스를 자동으로 메모리에 올려줌, 외부에서 호출할때 @inject로 쉽게 객체 호출 가능


 


1
2
3
4
5
6
7
    @Override
    public List<MemberDTO> memberList() {
        logger.info("memberList called...");
        // sql mapper에 작성된 sql 코드가 실행됨(auto commit & close)
        List<MemberDTO> list=sqlSession.selectList("member.memberList");
        return list;
    }
cs


sqlSession.commit();

sqlSession.close(); 가 root-context.xml에 자동 설정 돼있다.



1
2
3
4
5
    <!-- SqlSession 객체 주입 -->
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate"
        destroy-method="clearCache">
        <constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory"></constructor-arg>
    </bean>
cs


?

1
2
3
4
5
6
7
8
    <!-- SqlSessionFactory 객체 주입 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="configLocation" 
        value="classpath:/mybatis-config.xml"></property>
        <property name="mapperLocations" 
        value="classpath:mappers/**/*Mapper.xml"></property>
    </bean>
cs



src/main/resources > mappers > memberMapper.xml 만들기


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<?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와 중복되지 않도록 네임스페이스 기재 -->
<mapper namespace="member">
    <select id="memberList"
    resultType="memberDto">
        select * from member
        order by name
    </select>
    
    <insert id="insertMember">
        insert into member (userid,passwd,name,email) values
        ( #{userid},#{passwd},#{name},#{email} )
    </insert>
    
    <select id="viewMember" resultType="memberDto">
        select * from member
        where userid=#{userid}
    </select>
    
    <select id="checkPw" resultType="int">
        select count(*) from member
        where userid=#{userid} and passwd=#{passwd}
    </select>
    
    <update id="updateMember">
        update member set name=#{name}, passwd=#{passwd},
            email=#{email} 
        where userid=#{userid}
    </update>
    
    <delete id="deleteMember">
        delete from member
        where userid=#{userid}
    </delete>
</mapper>
cs



mybatis-config.xml // 안중요한 설정

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?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="com.example.spring01.model.dto.MemberDTO"
            alias="memberDto" />
    </typeAliases>
 
</configuration>
 
 
cs




Controller에는 @Controller 

Model(DAO, DTO)에는 @Repository 

Service에는 @Service 붙여서 컴포넌트 스캔



MemberController.java :  MemberService 객체를 주입받아 사용

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Controller //현재 클래스를 Controller Bean으로 등록함
public class MemberController {
    private static final Logger logger=
            LoggerFactory.getLogger(MemberController.class);
    
    @Inject // MemberService 객체가 주입됨
    MemberService memberService;
    
    @RequestMapping("member/list.do"//사용자가 요청하는 주소
    public String memberList(Model model) {
        List<MemberDTO> list=memberService.memberList();
        logger.info("회원 목록:"+list);
        model.addAttribute("list",list); //모델에 저장 
        return "member/member_list"//출력 페이지로 포워딩 
    } 
cs



서비스에 memberList() 메서드를 호출하여 List에 멤버리스트를 받고


매개변수 자리에서 선언한 내장객체 model에 리스트를 넣어 멤버리스트 jsp페이지로 포워딩시킨다.



요청과 요청한 데이터 처리

 

요청한 데이터 처리 과정

jsp페이지에서 요청 

→  (  MemberController   ←@inject-   MemberService   ←@inject-   MemberDAO   ←@inject-  SqlSession )


요청

1
2
3
<td>
    <a href="${path}/member/view.do?userid=${row.userid}">${row.name}</a>
</td>
cs



DAO

1
2
3
    public MemberDTO viewMember(String userid) {
        return sqlSession.selectOne("member.viewMember", userid); 
    }
cs


Service

1
2
3
    public MemberDTO viewMember(String userid) {
        return memberDao.viewMember(userid); 
    }
cs


Controller

1
2
3
4
5
    @RequestMapping("member/view.do")
    public String view(@RequestParam String useridModel model) {
        model.addAttribute("dto"memberService.viewMember(userid));
        return "member/view"// view.jsp로 포워딩 
    }
cs


//요청받은 페이지 폼 데이터 중 레코드 하나만(userid) 받아와서 데이터 처리 (서비스에 떠넘김)하고 model 객체에 담아 포워딩


코드 작성할때 F4로 클래스 계층 구조를 확인하고 메서드를 선택하여 작성하도록 한다.


// F3으로 보면 인터페이스만 보일수 있으므로 F4로 계층구조를 확인한다.