Oracle와 mybatis 연동 실습

Back-End/Spring 2019. 6. 5. 16:10
728x90
반응형

가. mybatis에서 sql query를 작성하는 방법



  1. mapper xml 파일에 작성


  MemoDAO.java (인터페이스)


  MemoDAO.Impl.java (구현클래스)


  memoMapper.xml (mapper)



  2. mapper interface에 작성


  MemoDAO.java : SQL 포함





나. spring02 프로젝트 생성


Spring Legacy Project => Spring MVC project

sample 프로젝트에서 설정파일 복사 :

패키지 이름은 com.example.spring02로 한다.



클래스에 SQL을 같이 써놓는 방식 자주 사용되지는 않음


 

      1. pom.xml 복사


2. src/main/resources/mappers 디렉토리 생성


3. src/main/resources/mappers/sampleMapper.xml 복사


4. src/main/resources/log4j.xml 복사


5. src/main/resources/log4jdbc.log4j2.properties 복사


6. src/main/resources/logback.xml 복사


7. mybatis-config.xml 복사


8. src/main/webapp/WEB-INF/web.xml 복사


9. src/main/webapp/WEB-INF/spring/root-context.xml 복사


10. src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml 복사





root-context.xml (환경설정 xml)


1
2
3
4
5
6
7
8
9
10
11
<!-- Root Context: defines shared resources visible to all other web components -->
    <bean id="dataSource"
        class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <!-- 드라이버 클래스 이름이 변경됨 -->
        <property name="driverClassName" value="net.sf.log4jdbc.sql.jdbcapi.DriverSpy"></property>
        <!-- 연결문자열에 log4jdbc가 추가됨 -->
        <property name="url"
            value="jdbc:log4jdbc:oracle:thin:@localhost:1521/xe" /> //1521과 xe 사이에 /으로 바꾸어준다.
        <property name="username" value="spring" /> //DB에 접속할 아이디를 입력
        <property name="password" value="1234" /> //DB에 접속할 비밀번호를 입력
    </bean>
cs



servlet-context.xml (환경설정 xml)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!-- Resolves views selected for rendering by @Controllers to .jsp resources 
        in the /WEB-INF/views directory -->
    <beans:bean<!-- Resolves views selected for rendering by @Controllers to .jsp resources 
        in the /WEB-INF/views directory -->
    <beans:bean
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <beans:property name="prefix" value="/WEB-INF/views/" />
        <beans:property name="suffix" value=".jsp" />
    </beans:bean>
    <!-- 스프링 빈을 태그로 등록하지 않고 자동으로 검색(auto scan) --> 
    <context:component-scan base-package="com.example.spring02.*" />
 
</beans:beans>
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <beans:property name="prefix" value="/WEB-INF/views/" />
        <beans:property name="suffix" value=".jsp" />
    </beans:bean>
    <!-- 스프링 빈을 태그로 등록하지 않고 자동으로 검색(auto scan) --> 
    <context:component-scan base-package="com.example.spring02.*" /> //spring02로 변경한다.
</beans:beans>
cs



home.jsp 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<%@ page language="java" contentType="text/html; charset=UTF-8" 
pageEncoding="UTF-8"%>
<!-- 한글 인코딩 부분이 없으면 한글이 깨지기 때문에 인코딩 언어 설정을 다시해주어야 한다. -->
<html>
<head>
<meta http-equiv = "Content-Type" content="text/html; charset=UTF-8">
<title>Home</title>
</head>
<body>
<h1>Hello world!</h1>  
<P>  The time on the server is ${serverTime}. </P>
</body>
</html>
 
cs



MEMO 테이블 생성 

1
2
3
4
5
6
create table memo(
idx number not null primary key, //글번호를 기본키로 한다.
writer varchar2(50not null,
memo varchar2(200not null,
post_date date default sysdate //날짜가 출력되게 한다 (기본값 : 오늘날짜로 한다.)
);
cs



테이블에 자료를 삽입함

1
2
insert into memo(idx,writer,memo)values(1,'kim','메모1');
insert into memo(idx,writer,memo)values(2,'park','메모2');
cs



-Mybatis란 무엇인가?-


JDBC란 Java에서 DB와 연동하고 쓰기위해 사용하는 API 이다.


JDBC는 DB 연동에 필수적으로 사용하는 것인데


이 JDBC만 사용해서 DB 쿼리문을 작성하면 java소스와 쿼리소스가 겹치게 되고 관리가 어려워 진다.


Mybatis는 SQL 쿼리문을 xml 형식의 파일로 분리시켜 저장관리할 수 있고 java 소스에서 xml 태그의 id만 호출하며 개발의 편리함을 제공한다.


Mybatis는 xml 형식의 쿼리파일을 저장 및 호출하는 역할을 내부적으로 처리하는 것.



 Mybatis 사용전 코드 방식

 Mybatis 사용후 코드 방식

 

public Entity selectFAQList(UserConnection conn, Entity param) throws SQLException 

{

    UserStatement stmt = null; //stmt 초기값 선언
    ResultSet rslt = null; //rslt 초기값 선언
    StringBuffer sql = new StringBuffer();
    sql.append("\n SELECT *"); //sql문 뒤에 table1 테이블에 전체요소를 검색하는
    sql.append("\n FROM"); //코드 추가
    sql.append("\n TABLE1");
    stmt = conn.prepareStatement(sql.toString());
    rslt = stmt.executeQuery();
    Entity _DATA = new Entity();
    _DATA.put("_DATA", EntityUtil.ResultSetToClobList(rslt));
    return _DATA;
}

// java 파일 안에 StringBuffer이라는 클래스를 호출해 sql 이라는 객체를 만들어 계속
이어주면서 sql query를 작성하고 있다.
// 다 작성한 다음 작성 된 쿼리를 다른 메소드의 파라미터로 넘기고 리턴하고 있다.
// 이러한 방식은 쿼리가 수정될 때 마다 계속 .java에 들어가 .append( ) 메소드를 추가하고
// 저장해 유지보수가 힘들고 sql query 구문의 분리가 어려워지고 복잡해진다.
// 또한 쿼리 양이 많아질수록 .java 에는 자바코드 뿐만 아니라 쿼리코드로 인해
// 양이 방대해지는 문제가 발생한다.
// 이런 이유로 인해 sql 구문과 java 코드를 분리하였다.

 <?xml version="1.0" encoding="UTF-8"?>

  <ENTITY id="table.getTable1List" type="SQL" return="List">
    <![CDATA[
        SELECT *
            FROM
            TABLE1
    ]]>
    <PARAMS>    
    </PARAMS>
  </ENTITY>

// xml로 빼내서 쿼리문을 작성하면 내부적 처리는 Mybatis에서 모두 처리해주므로
// Entity ID값을 java에서 호출만하면 된다.


append( ) 메소드 : 선택한 요소의 끝에 콘텐츠를 추가

ex ) - sql.append("\n SELECT *"); = sql문 끝에 SELECT * 을 추가함



root-context.xml 에 코드를 추가한다.

(기존방식인 xml파일을따로 만들어 sql을 쓰는 방식을 쓰면 이 방식은 사용하지 않아도 된다.)

인터페이스에 sql을 직접 쓰고싶고, xml을 따로 만들기 싫을때 사용하는 방법

프로젝트의 패키지의 기본클래스를 등록한다는 뜻


1
2
3
4
<!-- mybatis mapper 코드가 포함된 클래스를 찾아서 bean으로 등록하도록 설정해야함 -->
    <!-- com~~~이하의 디렉터리는 다 뒤져서 been으로 등록하도록 설정한다는 뜻 -->
    <mybatis-spring:scan base-package = "com.example.spring02.model.memo" />
</beans>
cs



MemoDTO.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
package com.example.spring02.model.memo.dto;
 
import java.util.Date;
 
//계층간 데이터 교환을 위한 DTO 클래스 만들기
public class MemoDTO {
    private int idx;
    private String writer;
    private String memo;
    private Date post_date;
    
    //getter, setter, 기본생성자, 매개변수가 있는 생성자 (writer,memo), toString()
    
    public int getIdx() {
        return idx;
    }
    public void setIdx(int idx) {
        this.idx = idx;
    }
    public String getWriter() {
        return writer;
    }
    public void setWriter(String writer) {
        this.writer = writer;
    }
    public String getMemo() {
        return memo;
    }
    public void setMemo(String memo) {
        this.memo = memo;
    }
    public Date getPost_date() {
        return post_date;
    }
    public void setPost_date(Date post_date) {
        this.post_date = post_date;
    }
    
    public MemoDTO() {} //기본 생성자
    public MemoDTO(String writer, String memo) { //글쓰기와 메모를 생성할 수 있는 생성자
        this.writer = writer;
        this.memo = memo;
    }
    @Override
    public String toString() { //MemoDTO의 객체가 가지고 있는 정보나 값들을 문자열로 만들어 리턴하는 메소드
        return "MemoDTO [idx=" + idx + ", writer=" + writer + ", memo=" + memo + ", post_date=" + post_date + "]";
    }
    
    
}
 
cs



MemoService.java (인터페이스)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.example.spring02.service.memo;
 
import java.util.List;
 
import com.example.spring02.model.memo.dto.MemoDTO;
 
public interface MemoService {
    //같은 인터페이스나 클래스 안에서 메소드이름이 중복되는 것을 오버로딩이라고 한다.
    //그리고 이것을 상속받아 고치는 것을 오버라이딩이라고 한다.
    
    public List<MemoDTO> list(); //목록
    public void insert(MemoDTO dto); //추가 DTO전체에 넘겨서 하는 방법
    public void insert(String writer, String memo); 
    public MemoDTO memo_view(int idx);//상세화면보기
    public void update(MemoDTO dto);//수정
    public void delete(int idx);//삭제
    
}
 
cs



MemoServiceImpl.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.spring02.service.memo;
 
import java.util.List;
 
import org.springframework.stereotype.Service;
 
import com.example.spring02.model.memo.dto.MemoDTO;
 
 
@Service
public class MemoServiceImpl implements MemoService {
 
    @Override
    public List<MemoDTO> list() {
        // TODO Auto-generated method stub
        return null;
    }
 
    @Override
    public void insert(MemoDTO dto) {
        // TODO Auto-generated method stub
 
    }
 
    @Override
    public void insert(String writer, String memo) {
        // TODO Auto-generated method stub
 
    }
 
    @Override
    public MemoDTO memo_view(int idx) {
        // TODO Auto-generated method stub
        return null;
    }
 
    @Override
    public void update(MemoDTO dto) {
        // TODO Auto-generated method stub
 
    }
 
    @Override
    public void delete(int idx) {
        // TODO Auto-generated method stub
 
    }
 
}
 
cs



MemberDAO (DB연결)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.example.spring02.model.memo.dao;
 
import java.util.List;
 
import org.apache.ibatis.annotations.Select;
 
import com.example.spring02.model.memo.dto.MemoDTO;
 
public interface MemberDAO {
    //인터페이스는 객체를 생성하지 못함
    //root-context.xml에서 <mybatis-spring:scan base-package = "com.example.spring02.model.memo" />라고 설정을 해놓은것 때문에
    //@Select문 이하~~가 하나의 객체로 완성된다.
    @Select ("select * from memo order by idx desc")
    //현재 list()메소드는 몸체가 없기 때문에 select 어노테이션의 쿼리가 호출됨
    public List<MemoDTO> list();
    
}
 
cs




-어노테이션 정리-


  @Controller : 컨트롤러 bean으로 등록

  @Service : 서비스 bean으로 등록

  @Repository : DAO bean으로 등록


  @Inject == @Autowired : 의존성 주입


  @RequestMapping : (url mapping) url과 메소드를 연결시켜주는 역할을 한다.

  @RequestParam : post 방식이나 get 방식으로 넘어온 개별변수

  @ModelAttribute : DTO로 묶어서 한번에 저장할때 쓴다

  @ResponseBody : 컨트롤러에서 어떤 메소드를 호출한 다음 페이지로 넘어가는것이 아니라 데이터 자체를 넘길때 (제이슨 같은걸로 넘길때)





MemoController.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
package com.example.spring02.controller.memo;
 
import java.util.List;
 
import javax.inject.Inject;
 
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
 
import com.example.spring02.model.memo.dto.MemoDTO;
import com.example.spring02.service.memo.MemoService;
 
@Controller
//현재 클래스를 컨트롤러 bean으로 등록함
//구조
//컨트롤러에서 서비스를 호출하고, 서비스에서 DAO를 호출하고, DAO에서 SQL이 실행된다.
//반드시 어노테이션 Service, Controller 등을 붙여야 컨트롤러해서 호출이 가능하다.
 
@RequestMapping("/memo/*"// <-이쪽에 작성되는 매핑은 이 클래스의 공통적인 매핑
                            // 이 클래스는 기본적으로 [/memo로 시작한다라는 의미이고 뒤에 *는 뒤에 어떤것이 와도 상관없다는 의미 ]
            // 사용하는 이유 : 매핑을 할시에 여러 매소드들에서 공통적인 경로로 url 매핑을 할때 url 주소를 간략하게 할 수 있기 때문에 사용한다.
                         
 
public class MemoController {
 
    //매핑을 할때는 목록을 먼저 뽑는다.
    @Inject    //의존관계를 주입
    MemoService memoService; //스프링이 만든 서비스 객체가 연결된다.
    
    
    // 자료를 하기 위해 /memo/list.do페이지에 연결하고, memoService의 리스트 (인터페이스의 추상 메소드를 사용해서 값을 받아온 것들...)을
    // 계층간 데이터 교환을 위해 MemoDTO로 받는다. mav에 출력페이지의 이름과, 아까 받은 memoService.list()가 들어있는 
    // items에 이름을 "list"로 바꾸어서 mav에 저장해 놓는다.
    // 그리고 mav를 리턴한다.
    @RequestMapping("list.do"// <== 사용자가 이런패턴으로 호출하면 밑에 list가 호출된다는 뜻 
    public ModelAndView list(ModelAndView mav) {
        List<MemoDTO> items = memoService.list();   // 메모 리스트 리턴 (Select문 이하~~)
        mav.setViewName("memo/memo_list");            // 출력 페이지의 이름
        mav.addObject("list",items);                // 출력 페이지에 전달할 변수
        return mav;                                    // 페이지로 이동함
    }
    
}
 
cs



MemoServiceImpl.java (메모 서비스 인터페이스 구현 클래스) 중 일부


여기서 MemoDAO는 인터페이스라서 객체를 생성할 수 없지만,

호출이 가능한 이유는 DAO 클래스에서 @Select 어노테이션을 사용해서 @Select ("select * from memo order by idx desc")

사용해 메소드를 생성하였으므로(몸체는 없지만) 객체처럼 완성이 되서, list() 메소드를 호출하면 @Select 쿼리문이 실행이 된다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.example.spring02.service.memo;
 
import java.util.List;
 
import javax.inject.Inject;
 
import org.springframework.stereotype.Service;
 
import com.example.spring02.model.memo.dto.MemoDTO;
 
import com.example.spring02.model.memo.dao.MemoDAO;
 
@Service
public class MemoServiceImpl implements MemoService {
 
    //의존성을 주입해야한다.
    @Inject
    MemoDAO memoDao;
    
    @Override
    //여기서 DAO로 가는 코드를 작성해야 한다.
    public List<MemoDTO> list() {
        return memoDao.list();
    }
cs






  

  Model과 ModelAndView 의 차이점 (예제)


1
2
3
4
5
6
7
8
9
10
11
12
13
@RequestMapping("/board/view")
public ModelAndView view() {
  ModelAndView mv = new ModelAndView();
  mv.addObject("id"30);
  mv.setViewName("board/view"); //뷰를 기술할 필요가 있으므로 리턴타입을 ModelAndView로 하였다.
  return mv;
}
 
@RequestMapping("/board/view")
public String view(Model model) {
  mv.addAttribute("id"30);
  return "board/view"
}
cs


  ModelAndView는 뷰와 모델을 기술할 필요가 있을 때 사용하면 된다.


  Model은 이름 그대로 뷰로 전달할 모델값만 기술 하면 된다.




views -> memo 폴더 생성 -> memo_list.jsp 파일 생성함


view -> include 폴더 생성 -> style.css 파일 생성함



style.css

1
2
3
4
5
@charset "UTF-8";
a:link {text-decoration: none; color:blue; } <!--하이퍼링크 속성에서 밑줄을 제거 색깔은 파란색-->
a:hover {text-decoration: underline; color:red; } <!--마우스 커서가 주소에 닿으면 그때 밑줄이 생기고 색깔은 빨간색-->
a:visited{text-decoration: none;} <!--방문한 링크는 밑줄을 지움-->
a:active{text-decoration: none; color:yellow;<!--클릭했을때의 링크는 밑줄을 지우고 색깔은 노란색으로 한다.-->
cs



header.jsp

1
2
3
4
5
6
7
8
9
10
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <!-- 태그라이브러리를 사용하여 코어와 fmt(날짜와 숫자)의 태그를 추가 -->
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<c:set var = "path" value = "${pageContext.request.contextPath }" /<!-- contextPath태그를 자주쓰니까 간단하고, 호출하기 편하게 path로 만들어놓음 -->
 
<!-- html과 css같은 것은 고정적인 요소이기 때문에 이런것들은 리소스설정을 따로 해주어야 인식이 된다. -->
<script src = "http://code.jquery.com/jquery-3.3.1.js"></script<!-- jquery도 많이 쓰기 때문에 링크시켜놓았다. --> 
<link rel = "stylesheet" href="${path}/include/style.css" /<!-- 방금 작성한 stylesheet파일이 실행되게끔 붙여놓았다. -->
 
cs



menu.jsp

1
2
3
4
5
6
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix = "c" uri = "http://java.sun.com/jsp/jstl/core" %>
<!-- 다른페이지에 include되는 페이지 -->
<a href = "${path }/memo/list.do">한줄메모장</a> ㅣ
 
cs



Spring02 프로젝트를 실행하면 url에 http://localhost:8090/spring02/ 라고 나오는데 여기서 "/" 가 

아래 HomeController.java (파일중 일부) 에 @RequestMapping에 value에 맵핑되서 아래 로그가 출력이 되게 된다.

그리고 home로 리턴이 된다.


HomeController.java (파일중 일부)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@RequestMapping(value = "/", method = RequestMethod.GET)
    public String home(Locale locale, Model model) {
        logger.info("Welcome home! The client locale is {}.", locale);
        
        Date date = new Date();
        DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);
        
        String formattedDate = dateFormat.format(date);
        
        model.addAttribute("serverTime", formattedDate );
        
        return "home";
    }
    
}
cs



memo_list.jsp (메모 리스트)

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
<%@ 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="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
    <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
    
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<%@include file="../include/header.jsp" %> <!-- header 파일을 include -->
</head>
<body>
<%@ include file = "../include/menu.jsp" %> <!-- menu 파일을 include -->
<h2>한줄 메모장</h2>
 
<form method="post" action="${path }/memo/insert.do"<!-- 글쓰기 폼을 작성 insert.do로 넘김 -->
이름 : <input name = "writer" size = "10" >
메모 : <input name = "memo" size = "40" >
<input type = "submit" value="확인">
</form>
 
<table border = "1" style = "width:500px;"<!-- 메모장 폼을 작성 -->
    <tr>
        <th>번호</th>
        <th>이름</th>
        <th>메모</th>
        <th>날짜</th>
    </tr>
<c:forEach var="row" items="${list }"<!--MemoController에서 넘겨준 items(메모 리스트)를 list라는 이름으로 받음 el문 내부의 이름과
                                        넘긴 변수의 이름이 같아야 한다.-->
    <tr>
        <td>${row.idx }</td>  <!-- row에서 값들을 하나씩 불러온다. -->
        <td>${row.writer }</td>
        <td>${row.memo }</td>
        <td>
        <fmt:formatDate value="${row.post_date}" pattern="yyyy-MM-dd HH:mm:ss" /></td>
    </tr>
</c:forEach>        
</table>
</body>
</html>
cs




728x90
반응형
: