Oracle와 mybatis 연동 실습
Back-End/Spring 2019. 6. 5. 16:10가. 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(50) not null, memo varchar2(200) not 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 의 차이점 (예제)
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 |
'Back-End > Spring' 카테고리의 다른 글
Oracle와 mybatis 연동 실습 (글쓰기 구현) (0) | 2019.06.05 |
---|---|
스프링 로그 분석 (0) | 2019.06.05 |
AOP(Aspect Oriented Programming) - 인강 (0) | 2019.06.05 |
스프링 프로젝트 구조 (0) | 2019.06.04 |
스프링 프레임워크 Inversion of Control (IoC) (0) | 2019.06.03 |