인텔리J에서의 mybatis 실행은 이클립스와 달리 약간 복잡한 부분이 있다.

우선 mybatis 실행 순서에 대해 한번 보도록하자

구역은 4구역으로 나뉜다.

1구역 web : index.jsp, list.jsp view 부분으로 페이지에 출력되는 부분이다.

2구역 WEB-INF : applicationContext.xml, dispatcher-servlet.xml 부분으로 resources 및 java에 객체 주입을 하는 부분이다.

3구역 resources : board-mapping.xml, sql-map-config.xml이 있는 부분으로 mybatis 영역이다.

해당 영역으로 sql 구문 작동이 된다.

4구역 java 부분으로 com.maju.host.board.imp 패키지가 있는 부분으로 컨트롤, DAO, VO 파일이 있는 부분이다.

 

 

 

그럼 순서대로 한번 진행을 해보도록하자.

우선 pom.xml에 jar파일을 추가하기 위해 아래 파일들을 dependency하자

[pom.xml]

<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>untitled3</artifactId>
    <version>1.0-SNAPSHOT</version>

    <repositories>
        <repository>
            <id>public</id>
            <url>http://nexus.talanlabs.com/content/repositories/releases/</url>
        </repository>
    </repositories>

    <dependencies>

        <dependency>
            <groupId>com.oracle</groupId>
            <artifactId>ojdbc</artifactId>
            <version>6</version>
        </dependency>

        <!-- Mybatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.3.1</version>
        </dependency>

        <!-- Mybatis Spring -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.2.4</version>
        </dependency>

        <dependency>
            <groupId>commons-dbcp</groupId>
            <artifactId>commons-dbcp</artifactId>
            <version>1.4</version>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>

    </dependencies>


</project>

그러나 여기서 끝난게 아니고 Project Structure에서 추가를 해야 한다.

dependency 이후에는 아래와 같이 Project Structure > Artifacts 로 이동 후 아래와 같이 우측 화면에서 더블클릭하여 우측으로 추가한다.

그 다음 java Source Folder에 com.maju.host.board.impl 패키지를 추가한다.

패키지를 추가하고 아래 파일들을 생성한다.

<BoardController>

package com.maju.host.board.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class BoardController {

    @Autowired
    private BoardService boardService;

    @RequestMapping(value="/insert.do")
    public String insertBoard(BoardVO vo) {
        boardService.insert(vo);
        return "end.jsp";
    }

    @RequestMapping(value="/list.do")
    public String listBoard(Model model) {
        System.out.printf("Cotnroller list 접속!!");
        model.addAttribute("boardList",boardService.list());
        return "list.jsp";

    }

    @RequestMapping(value="/delete.do")
    public String deleteBoard(BoardVO vo) {
        boardService.delete(vo);
        return "redirect:list.do";
    }
}

<BoardDAO>

package com.maju.host.board.impl;

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public class BoardDAO extends SqlSessionDaoSupport {

    @Autowired
    public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
        super.setSqlSessionFactory(sqlSessionFactory);
    }

    public void insertBoard(BoardVO vo) {
        System.out.println("===> Mybatis로 insertBoard() 기능처리");
        getSqlSession().insert("MybatisBoardDAO.insertBoard", vo);
    }

    public List<BoardVO> listBoard(){
        System.out.println("===> Mybatis로 listBoard() 기능처리");
        return getSqlSession().selectList("MybatisBoardDAO.list");
    }

    public void deleteBoard(BoardVO vo) {
        System.out.println("===> Mybatis로 deleteBoard() 기능처리");
        getSqlSession().delete("BoardDAO.deleteBoard", vo);
    }
}

<BoardService>

package com.maju.host.board.impl;

import java.util.List;

public interface BoardService {
    void insert(BoardVO vo);
    List<BoardVO> list();
    void delete(BoardVO vo);
}

<BoardServiceImpl>

package com.maju.host.board.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service("BoardService")
public class BoardServiceImpl implements BoardService {
    @Autowired
    BoardDAO boardDAO;

    public void insert(BoardVO vo) {
        boardDAO.insertBoard(vo);
    }

    public List<BoardVO> list() {
        return boardDAO.listBoard();
    }

    public void delete(BoardVO vo) {
        boardDAO.deleteBoard(vo);
    }
}

<BoardVO>

package com.maju.host.board.impl;

public class BoardVO {

    private  int  seq;
    private  String  title;
    private  String  writer;
    private  String  content;
    private  String   regDate;
    private  int     cnt;

    public int getSeq() {
        return seq;
    }

    public void setSeq(int seq) {
        this.seq = seq;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getWriter() {
        return writer;
    }

    public void setWriter(String writer) {
        this.writer = writer;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public String getRegDate() {
        return regDate;
    }

    public void setRegDate(String regDate) {
        this.regDate = regDate;
    }

    public int getCnt() {
        return cnt;
    }

    public void setCnt(int cnt) {
        this.cnt = cnt;
    }
}

 

자 MVC 패턴 중 Control 부분은 끝났다.

이제 Model 부분을 다뤄보자

resources 부분에 아래 두개의 xml 파일을 생성해준다.

팁 아래와 같이 resource 폴더를 새로 만들어도 classpath 명칭은 동일하다.

<board-mapping>

아래 코드가 mybatis의 꽃인 부분이다.

mybatis는 기존의 sql문을 따로 분류하는 역활을 한다.

보시다시피 sql문이 기존에는 Control과 함께 있었다. 그런데 그것을 아예 분리하여 mybatis에서 다루는 것이다.

여기서 몇가지 볼 부분이 있다.

 

하나. resultMap type="board" 부분은 아래 코드에서 board를 가져온다.

그리고 resultMap은 list의 반환값으로 사용된다.

 

둘. select 문의 resultMap과 resultType

여기서 resultMap은 상단의 resultMap을 불러오는 역활을 한다.

그리고 resultType=board를 함으로써 board(BoardVO)를 갖고온다. 

 

셋 모든 sql문에는 ;가 없다 해당 표시가 있을 경우 오류가 발생하니 주의하도록하자

<?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="MybatisBoardDAO">

    <resultMap type="board" id="boardResult"> <!--하나-->
        <id property="seq" column="seq" />
        <result property="title" column="title"></result>
        <result property="writer" column="writer"></result>
        <result property="content" column="content"></result>
        <result property="regDate" column="regdate" />
        <result property="cnt" column="cnt"/>
    </resultMap>

    <insert id="insertBoard">
  	 INSERT  INTO board  (seq, title, writer, content, regdate)
   	 VALUES ((select nvl(max(seq),0)+1 from board),#{title},#{writer},#{content},#{regDate})
	</insert>
    <select id="list" resultMap="boardResult" resultType="board"> <!--둘-->
        select * from board
    </select>
    <select id="getBoardList" resultMap="boardResult" resultType="board">
	 <![CDATA[select * from board order by seq desc]]>
	</select>

    <delete id="deleteBoard">
		delete board where seq = #{seq}
	</delete>


</mapper>

<sql-map-config>

해당 파일은 board-mapping에 board(BoardVO) 값을 전달해주는 역활을 한다.

<?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.maju.host.board.impl.BoardVO" alias="board"></typeAlias>
    </typeAliases>
</configuration>

 

그리고 위에 코드에서 볼 수 있듯이 mybatis xml 파일을 생성하기 위해서는 아래의 준비물(아래 코드)이 꼭 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">

자 이제 MVC중 Control과 Model은 끝났다.

Model을 다루기 전에 객체를 주입하는 applicationContext.xml, dispatcher-servlet.xml, 그리고 web.xml에 다뤄보도록하자

<applicationContext.xml>

해당 파일은 db에 관련된 정보와 mybatis에 객체를 주입하는 파일이 있다.

여기서 아래의 bean class=org.mybatis.spring.SqlSessionFactoryBean의 역활은 아래의 porperty의 값들을 받아서 SqlSessionFactryBean 객체를 생성하고 이후 DAO에 해당 객체를 주입하는 역활을 한다.

 

여기서 필자가 고생한 부분은 3번째인 property name="mapperLocations" value="classpath:board-mapping" 이 부분이다.

 

기존에 필자가 갖고 있던 책에서는 해당 부분이 <sql-map-config> 부분에 mapper되어 있었다.

해당 코드로는 이클립에서 문제가 없었으나 인텔리j에서는 인식을 못했다.

그렇기 때문에 정확한 원인 파악을 위하여 많은 시간(20시간 ㅠㅠ)을 소비하였고 아래와 같이 bean 객체에 mapper하여 문제를 해결하였다. 그러니 같은 문제를 가진 사람은 참고하도록하자

 

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="dataSource"   class="org.apache.commons.dbcp.BasicDataSource"   destroy-method="close" >
        <property  name="driverClassName"  value="oracle.jdbc.OracleDriver"  />
        <property  name="url"  value="jdbc:oracle:thin:@//localhost:1521/xe"  />
        <property  name="username"  value="system" />
        <property  name="password"  value="1234"  />
    </bean>

    <bean class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource"  ref="dataSource"></property>
        <property name="configLocation"  value="classpath:sql-map-config"  />
        <property name="mapperLocations" value="classpath:board-mapping" /> <!--중요-->
    </bean>

</beans>

<dispatcher-servlet.xml>

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="com.maju.host.board"></context:component-scan>
</beans>

<web.xml>

아래 web.xml의 작동 원리는 다음과 같다.

lisetner인하여 bean 객체가 web.xml 실행과 동시에 생성이 된다.

그리고 *.do 가 실행되면 dispatcher-servlet.xml가 실행되며, scan이 진행되어 com.maju.host.board에 객체가 주입되게된다.

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/applicationContext.xml</param-value>
    </context-param>

    <listener>
        <listener-class>
            org.springframework.web.context.ContextLoaderListener
        </listener-class>
    </listener>

    <filter>
        <filter-name>encodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>

        <init-param>
            <param-name>encoding</param-name>
            <param-value>utf-8</param-value>
        </init-param>
    </filter>

    <filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <url-pattern>*.do</url-pattern>
    </filter-mapping>

    <servlet>
        <servlet-name>action</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/dispatcher-servlet.xml</param-value>
        </init-param>

    </servlet>
    <servlet-mapping>
        <servlet-name>action</servlet-name>
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>
</web-app>

 

자 이제 마지막으로 남은 MVC 패턴중 view를 보도록하자.

별게 없으니 해당 부분은 코드만 남기고 마무리짓도록하겠다.

인텔리j로 다루는 책이 많이 없다보니 아무래도 정보가 많이 없다.

그렇기 때문에 이후에도 이러한 오류가 많이 발생할 수 있고 필자와 같은 고통을 받는 사람이 많을 수 있다.

그러나 포기하지않고 계속 하다보면 이런 유용한 툴을 자유롭게 쓸 수 있게 될지 모르니 힘들더라도 고민하고 노력하도록하자

 

<indx.jsp>

<%--
  Created by IntelliJ IDEA.
  User: 202-18
  Date: 2019-12-12
  Time: 오후 12:12
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
  <title>$Title$</title>
</head>
<body>
<h2><a href="form.jsp">가입</a></h2>
<h2><a href="list.do">목록</a></h2>
</body>
</html>

<list.jsp>

<%--
  Created by IntelliJ IDEA.
  User: 202-18
  Date: 2019-12-12
  Time: 오후 1:19
  To change this template use File | Settings | File Templates.
--%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
         pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jstl/core_rt" prefix="c"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Insert title here</title>
</head>
<body>
<table border=1>
    <tr><td>번호</td><td>제목</td><td>글쓴이</td><td>내용</td><td>날짜</td><td>날짜</td></tr>
    <c:forEach items="${boardList }" var="board">
        <fmt:parseDate value="${board.regDate}" var="dateFmt" pattern="yyyy-MM-dd HH:mm:ss"/>
        <tr><td><a href="delete.do?seq=${board.seq }">${board.seq }</a></td><td>${board.title }</td><td>${board.writer }</td><td>${board.content }</td><td><fmt:formatDate value="${dateFmt}" pattern="yyyy-MM-dd"/></td><td>${board.cnt }</td></tr>
    </c:forEach>
</table>
</body>
</html>
/*SQL문*/
create  table  board (
SEQ number(5)   primary  key,
TITLE   varchar2(200),
WRITER   varchar2(20),
CONTENT   varchar2(2000),
REGDATE  DATE  default sysdate,
CNT  number(5)  default  0
);

insert  into board (seq, title, writer, content) values(1, '가입인사', '관리자', '잘 부탁드립니다....');
insert  into board (seq, title, writer, content) values(2, '시헙중입니다. ', '관리자', '스프링 시험중입니다...!!!');

+ Recent posts