스프링4 HaspMap으로 DB select 하기

몇달전 스프링을 접한 후로 DB 연결 설정과 JSON 출력 방법을 드디어 알아내었다.
책대로 따라도 해보고 검색으로 이것저것 공부했지만 이해하기 어려웠는데
간절하면 이루어진다는 말처럼 결국은 반복 학습이 해결을 해 주었다.
(스프링 책 앞부분만 5~6번은 반복해 따라해 본 듯 하다)

참고서적: 코드로 배우는 스프링 웹 프로젝트구멍가게 코딩단

스프링4에서 DB를 연결해 HashMap과 JSON으로 출력하기 위해서는
아래 순서의 작업 과정이 필요하다.

  1. 모듈 선언
    – pom.xml 작성
    – maven을 통해 jdbc와 mybatis, dbms 관련 모듈의 dependency 등록
  2. MyBatis 설정
    – src/main/webapp/WEB-INF/spring/root-context.xml 작성
    – db 접속정보와 MyBatis의 sqlSessionFactory, sqlSession 설정
  3. (optional) 추가 설정파일 생성
    – mybatis-config.xml: SQL 등록시 resultType의 namespace 참고용
    – log4jdbc.log4j2.properties 와 logback.xml: DB 로깅용 Log4j2 용 설정
  4. mapper SQL 작성
    – root-context의 ‘mapperLocations’에 정의한 위치에 *_SQL.xml 생성
    – DAO에서 호출할 namespace를 설정하고 select, insert/update/delete 등을 포함
    select 구문에 resultType=”java.util.HashMap” 사용
  5. DAO 작성 (interface & implement)
    return type으로 List< HashMap > 사용
    Java 기본객체를 사용할 경우 VO 클래스가 필요없어진다
    @Repository 선언하고 @Inject로 MyBatis의 SqlSession을 Inject한다
    – MyBatis의 SqlSession으로 mapper SQL의 namespace + ID를 호출한다
  6. Service 작성 (interface & implement)
    @Service 선언하고 @Inject로 dao를 Inject한다
  7. Controller 작성 (RestController)
    @RestController를 선언 (클래스 전체)
    – RequestMapping 개별로 REST 출력을 사용하려면 함수 출력부에 ‘@ResponseBody’를 선언

개발환경으로는

  • sts-3.8.0
  • java 1.7
  • springframework 4.1.7.RELEASE

스프링4-마이바티스-예제02

우선 DB 연결없이 JSON 출력을 위한 콘트롤러단의 샘플을 먼저 살펴보자.

CASE1. VO 데이터를 JSP의 View로 넘기는 일반적인 방법

// 외부에서 /C.do 을 호출하면 연결됨
@RequestMapping("C.do")
public String doC(Model model){
    logger.info( "doC called......................." );

    // model은 view 단으로 데이터를 넘기기 위한 Map형 자료구조이다
    String msg = "9999년99월99일";
    model.addAttribute( "serverTime", msg );

    ProductVO product = new ProductVO( "Sample Product C", 19999 );
    model.addAttribute( "product", product );

    // views 아래의 'home.jsp'를 호출
    return "home";
}

View: home.jsp

<%@ page contentType="text/html;charset=utf-8" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<!doctype html>
<html lang="ko">
<head>
  <title>Home</title>
</head>
<body>
<h1>Hello world!</h1>
The time on the server is <c:out value="${serverTime}"/>.

<c:out value="${product.name}"/> / <c:out value="${product.price}"/>

</body>
</html>

스프링4-마이바티스-예제08_케이스1

CASE2. VO 데이터를 JSON으로 바로 출력하는 방법

// Annotation @ResponseBody 를 선언하면 클래스를 JSON으로 변환해 출력한다
@RequestMapping("D.do")
public @ResponseBody ProductVO doD(){
    logger.info( "doD called......................." );

    ProductVO product = new ProductVO( "Sample Product D", 59999 );

    return product;
}

스프링4-마이바티스-예제08_케이스2

CASE3. Map 데이터를 직접 작성해 JSON으로 출력하는 방법

@RequestMapping("E.do")
public @ResponseBody Map<String, Object> doE(){
    logger.info( "doE called......................." );

    // Map 데이터타입으로 출력 : 생성은 HashMap으로 하고
    Map<String, Object> product = new HashMap<String, Object>();
    product.put("name", new String("Map DATA2") );
    product.put("price", new Double(39999) );
    product.put("memo", new String("Rock, Pop") );

    return product;
}

스프링4-마이바티스-예제08_케이스3

CASE4. VO를 포함한 List 데이터를 직접 작성해 JSON으로 출력하는 방법

@RequestMapping("sendList")
public @ResponseBody List<SampleVO> sendList(){
    List<SampleVO> list = new ArrayList();
    for( int i=0; i<10; i++ ){
        SampleVO vo = new SampleVO();
        vo.setFirstName("길동"); vo.setLastName("홍"); vo.setMno( i );
        list.add( vo );
    }
    return list;
}

스프링4-마이바티스-예제08_케이스4

CASE5. VO를 포함한 Map 데이터를 직접 작성해 JSON으로 출력하는 방법

@RequestMapping("sendMap")
public @ResponseBody Map<Integer, SampleVO> sendMap(){

    Map<Integer, SampleVO> map = new HashMap<>();
    for( int i=0; i<10; i++ ){
        SampleVO vo = new SampleVO();
        vo.setFirstName("길동");	vo.setLastName("홍"); vo.setMno( i );
        map.put( i, vo );
    }

    return map;
}

스프링4-마이바티스-예제08_케이스5

CASE6. resultType으로 VO를 사용해 JSON으로 출력하는 일반적인 방법

@RequestMapping(value="/all/{bno}", method=RequestMethod.GET)
public ResponseEntity<List<ReplyVO>> list(@PathVariable("bno") Integer bno){

	ResponseEntity<List<ReplyVO>> entity = null;
	try{
		entity = new ResponseEntity<>(service.listReply(bno), HttpStatus.OK);
	} catch(Exception e){
		e.printStackTrace();
		entity = new ResponseEntity<>( HttpStatus.BAD_REQUEST );
	}

	return entity;
}

스프링4-마이바티스-예제08_케이스6

CASE7. resultType으로 HashMap을 사용해 JSON으로 출력하는 간편한 방법

@RequestMapping(value="/listAny/{bno}", method=RequestMethod.GET)
public ResponseEntity<List<HashMap<String, String>>> listAny(@PathVariable("bno") Integer bno){

	ResponseEntity<List<HashMap<String, String>>> entity = null;
	try{
		entity = new ResponseEntity<>(service.listAny(bno), HttpStatus.OK);
	} catch(Exception e){
		e.printStackTrace();
		entity = new ResponseEntity<>( HttpStatus.BAD_REQUEST );
	}

	return entity;
}

스프링4-마이바티스-예제08_케이스7


MyBatis 설정과 resultType=”HashMap” 사용하기

스프링4-마이바티스-예제01

1. pom.xml 설정

	<!-- for MySQL -->
	<dependency>
		<groupId>mysql</groupId>
		<artifactId>mysql-connector-java</artifactId>
		<version>5.1.36</version>
	</dependency>

	<!-- for MyBatis -->
	<dependency>
		<groupId>org.mybatis</groupId>
		<artifactId>mybatis</artifactId>
		<version>3.2.8</version>
	</dependency>
	<dependency>
		<groupId>org.mybatis</groupId>
		<artifactId>mybatis-spring</artifactId>
		<version>1.2.2</version>
	</dependency>
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-jdbc</artifactId>
		<version>${org.springframework-version}</version>
	</dependency>
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-test</artifactId>
		<version>${org.springframework-version}</version>
	</dependency>

	<!-- for JSON -->
	<dependency>
		<groupId>com.fasterxml.jackson.core</groupId>
		<artifactId>jackson-databind</artifactId>
		<version>2.5.4</version>
	</dependency>

	<!-- Test & logging -->
	<dependency>
		<groupId>junit</groupId>
		<artifactId>junit</artifactId>
		<version>4.12</version>
		<scope>test</scope>
	</dependency>
	<dependency>
		<groupId>org.bgee.log4jdbc-log4j2</groupId>
		<artifactId>log4jdbc-log4j2-jdbc4</artifactId>
		<version>1.16</version>
	</dependency>

2. src/main/webapp/WEB-INF/spring/root-context.xml 설정

먼저 관련 모듈별 namespace 를 체크해 포함시킨다. 이후 source 탭에서 내용 수정

스프링4-마이바티스-예제09_rootContext

	<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
	<!--
		/* log4jdbc 모듈 안쓸 때, 순수하게 JDBC 연결 설정만 하는 경우 */
		<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
		<property name="url" value="jdbc:mysql://tonynedb.cnklczmjogww.ap-northeast-2.rds.amazonaws.com:3306/spring_exdb"></property>
	-->
		<property name="driverClassName" value="net.sf.log4jdbc.sql.jdbcapi.DriverSpy"></property>
		<property name="url" value="jdbc:log4jdbc:mysql://tonynedb.****:3306/****"></property>
		<property name="username" value="****"></property>
		<property name="password" value="****"></property>
	</bean>

	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="dataSource"></property>
		<property name="configLocation" value="classpath:/config/mybatis-config.xml"></property>
		<property name="mapperLocations" value="classpath:/mapper/*_SQL.xml"></property>
	</bean>

	<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate" destroy-method="clearCache">
		<constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory"></constructor-arg>
	</bean>

	<context:component-scan base-package="com.tonyne.ex01.dao"></context:component-scan>
	<context:component-scan base-package="com.tonyne.ex01.service"></context:component-scan>

3. (optional) 기타 설정파일 : 로깅, MyBatis의 참조용 namespace 설정

3-1. src/main/resources/log4jdbc.log4j2.properties
log4jdbc.spylogdelegator.name=net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator
3-2. src/main/resources/logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
	<include resource="org/springframework/boot/logging/logback/base.xml" />

	<!-- log4jdbc-log4j2 -->
	<logger name="jdbc.sqlonly"			level="DEBUG" />
	<logger name="jdbc.sqltiming"			level="INFO" />
	<logger name="jdbc.audit"			level="WARN" />
	<logger name="jdbc.resultset"			level="ERROR" />
	<logger name="jdbc.resultsettable"		level="ERROR" />
	<logger name="jdbc.connection"			level="INFO" />
</configuration>
3-2. src/main/resources/config/mybatis-config.xml
  • root-context.xml의 “configLocation” 항목으로 정의되어 있음
<?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.tonyne.ex01.domain.ReplyVO" alias="ReplyVO" /> -->
		<package name="com.tonyne.ex01.domain" />
	</typeAliases>
</configuration>

4. mapper *_SQL.xml 작성

  • root-context.xml의 “mapperLocations” 항목으로 정의되어 있음
<?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="com.tonyne.ex01.mapper.ReplyMapper">
	<!--
	mybatis-config.xml : 긴 namespace를 typeAlias로 짧게 대체할 수 있음
	<select id="list" resultType="com.tonyne.ex01.domain.ReplyVO">
	-->
	<select id="listAny" resultType="java.util.HashMap">
	select * from tbl_reply where bno = #{bno} order by rno desc
	</select>

	<select id="list" parameterType="Integer" resultType="ReplyVO">
	select * from tbl_reply where bno = #{bno} order by rno desc
	</select>
</mapper>

5. DAO 작성

  • HashMap 사용때는 ReplyVO 클래스 기술이 필요없음
5-1. ReplyDAO.java
package com.tonyne.ex01.dao;

import ...;

public interface ReplyDAO {
	public List<HashMap<String, String>> listAny(Integer bno) throws Exception;
	public List<ReplyVO> list(Integer bno) throws Exception;
}

 

5-2. ReplyDAOImpl.java
package com.tonyne.ex01.dao;

import ...;

@Repository
public class ReplyDAOImpl implements ReplyDAO {
    @Inject
    private SqlSession session;

    private static String namespace = "com.tonyne.ex01.mapper.ReplyMapper";

    @Override
    public List<ReplyVO> list(Integer bno) throws Exception {
        return session.selectList(namespace+".list", bno);
    }

    @Override
    @SuppressWarnings("unchecked")
    public List<HashMap<String, String>> listAny(Integer bno) throws Exception {
        return session.selectList(namespace+".listAny", bno);
    }
}

6. Service 작성

6-1. ReplyService.java
package com.tonyne.ex01.service;

import ...;

public interface ReplyService {
	public List<HashMap<String, String>> listAny(Integer bno) throws Exception;
	public List<ReplyVO> listReply(Integer bno) throws Exception;
}

6-2. ReplyServiceImpl.java

package com.tonyne.ex01.service;

import ...;

@Service
public class ReplyServiceImpl implements ReplyService {
    @Inject
    private ReplyDAO dao;

    @Override
    public List<ReplyVO> listReply(Integer bno) throws Exception {
        return dao.list(bno);
    }

    @Override
    public List<HashMap<String, String>> listAny(Integer bno) throws Exception {
        return dao.listAny(bno);
    }
}

7. Controller 작성

package com.tonyne.ex01.web;

import ...;

@RestController
@RequestMapping("replies")
public class ReplyController {

    @Inject
    private ReplyService service;

	@RequestMapping(value="/all/{bno}", method=RequestMethod.GET)
	public ResponseEntity<List<ReplyVO>> list(@PathVariable("bno") Integer bno){

		ResponseEntity<List<ReplyVO>> entity = null;
		try{
			entity = new ResponseEntity<>(service.listReply(bno), HttpStatus.OK);
		} catch(Exception e){
			e.printStackTrace();
			entity = new ResponseEntity<>( HttpStatus.BAD_REQUEST );
		}

		return entity;
	}

	@RequestMapping(value="/listAny/{bno}", method=RequestMethod.GET)
	public ResponseEntity<List<HashMap<String, String>>> listAny(@PathVariable("bno") Integer bno){

		ResponseEntity<List<HashMap<String, String>>> entity = null;
		try{
			entity = new ResponseEntity<>(service.listAny(bno), HttpStatus.OK);
		} catch(Exception e){
			e.printStackTrace();
			entity = new ResponseEntity<>( HttpStatus.BAD_REQUEST );
		}

		return entity;
	}
}

 

웹서버는 sts 개발도구의 기본 TC 웹서버를 이용했다. (Tomcat7 또는 Tomcat8 써도 OK)

Log4jdbc 모듈을 사용하게 되면 DB 관련 모든 로깅을 살펴볼 수 있다.
– MySQL에 접속해 ‘select now()’ 실행하는 테스트 코드의 로그

스프링4-마이바티스-예제05_DB로깅

개인 개발환경에 java를 여러버전 깔았다면, JRE 버전이 제대로 선택 안되었을 경우가 생긴다.
그러면 Java Library의 Build Path를 직접 확인할 것!

스프링4-마이바티스-예제06_자바빌드패스

이클립스(or STS) 개발시 탭보다는 공백이 좋다. (Window > Preference 의 Java 섹션 설정)

스프링4-마이바티스-예제07_탭공백설정

즐코딩~

답글 남기기

아래 항목을 채우거나 오른쪽 아이콘 중 하나를 클릭하여 로그 인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Twitter 사진

Twitter의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Google+ photo

Google+의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

%s에 연결하는 중

%d 블로거가 이것을 좋아합니다: