본문 바로가기

백엔드/Spring

myBatis DAO Pattern example


GenericMyBatisDaoSupport.java
package com.openerp.common.dao;

import java.io.Serializable;
import java.util.ArrayList;

import org.apache.ibatis.exceptions.PersistenceException;

public interface GenericMyBatisDaoSupport{
	public T get(PK id) throws PersistenceException;//get obj of type T by the primary key 'id' 
	public ArrayList getAll() throws PersistenceException;//get all objects of type T
	public int insert(T objInstance) throws PersistenceException;//insert an object of type T into the database
	int update(T transientObject) throws PersistenceException; //update an object of type T    
	int delete(PK id)  throws PersistenceException;//delete an object of type T
}




AbstractGenericMyBatisDao.java
package com.openerp.common.dao;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import org.apache.ibatis.exceptions.PersistenceException;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

public class AbstractGenericMyBatisDao implements GenericMyBatisDaoSupport {
	
	private static Logger log = LoggerFactory.getLogger(AbstractGenericMyBatisDao.class);
	private static final String NAMESPACE = "Mapper"; 

	@Autowired
	private SqlSessionFactory sqlSessionFactory; //reference to mybatis session factory 
	private Class type;

	/** 
	 * Define prefixes for easier naming convetions between XML mapper files and the DAO class 
	 **/
	public static final String PREFIX_SELECT_QUERY = "get";     //prefix of select queries in mapper files (eg. getAddressType) 
	public static final String PREFIX_INSERT_QUERY = "insert"; //prefix of insert queries in mapper files (eg. insertAddressType)
	public static final String PREFIX_UPDATE_QUERY = "update";  //prefix of update queries in mapper files (eg. updateAddressType)
	public static final String PREFIX_DELETE_QUERY = "delete";  //prefix of delete queries in mapper files (eg. deleteAddressType)
	public static final String PREFIX_LIST_QUERY = "list";  //prefix of delete queries in mapper files (eg. deleteAddressType)

	/** Default Constructor */
	public AbstractGenericMyBatisDao(Class type) {
		this.type = type;
	}
	
	/** Default Constructor */
	public AbstractGenericMyBatisDao(Class type, SqlSessionFactory sf) {
		this.type = type;
		this.sqlSessionFactory = sf;
		if(sf==null)
			log.error("Error: Could not instantiate MyBatisDAO. Loading myBatis sessionFactory failed.");  
	}

	/** Use this method to get a session factory for using in any methods impelmented in child dao classes */
	protected SqlSessionFactory getSessionFactory() {
		return sqlSessionFactory;
	}

	/** 
	 *  Default get by id method. 
	 *  

* Almost all objects in the db will * need this (except mapping tables for multiple joins, which you * probably shouldn't even have as objects in your model, since proper * MyBatis mappings can take care of that). *

* Example: *
* If your DAO object is called CarInfo.java, * the corresponding mapper query id should be: <select id="getCarInfo" ... */ @SuppressWarnings("unchecked") public T get(PK id) throws PersistenceException { SqlSession session = sqlSessionFactory.openSession(); T obj = null; try { String query = this.type.getSimpleName()+NAMESPACE+"."+PREFIX_SELECT_QUERY+this.type.getSimpleName(); //If the object's calls name is AddressType.java, this matches the mapper query id: "namespace.getAddressType" obj = (T)session.selectOne(query,id); } finally { session.close(); } return obj; } /** * Method returns all rows for this object. *

* Example: *
* If your DAO object is called CarInfo.java, * the corresponding mapper query id should be: <select id="getAllCarInfo" ... *

* SQL Executed: select * from [tablename] *

* Notes: *
* Consider overdiding this method in order to handle large numbers of objects * with multiple references. * LAZY LOADING should be enabled in this case, otherwise you might run out of memory (eg. get all UserAccounts if the table has 1,000,000 rows) * look into the aggresiveLazyLoading property * */ @SuppressWarnings("unchecked") public ArrayList getAll() throws PersistenceException { SqlSession session = sqlSessionFactory.openSession(); ArrayList list = null; try { String query = this.type.getSimpleName()+NAMESPACE+"."+PREFIX_SELECT_QUERY+"All"+this.type.getSimpleName(); list = (ArrayList)session.selectList(query); } finally { session.close(); } return list; } /** * Method returns first object which matches the given name (exact match). *

* It's up to you to decide what constitutes an object's name. Typically you would have a * NAME column in the table, but not all objects have this. Generally this method should be overriden (if you need it at all) * in the child dao class. *

* Example: *
* If your DAO object is called CarInfo.java, * the corresponding mapper query id should be: <select id="getCarInfoByName" ... *

* SQL Executed (example): select * from [tablename] where NAME = ? * */ @SuppressWarnings("unchecked") public T getByName(String name) throws PersistenceException { SqlSession session = sqlSessionFactory.openSession(); T obj = null; try { String query = this.type.getSimpleName()+NAMESPACE+"."+PREFIX_SELECT_QUERY+this.type.getSimpleName()+"ByName"; obj = (T)session.selectOne(query, name); } finally { session.close(); } return obj; } /** * Method inserts the object into the table. *

* You will usually override this method, especially if you're inserting associated objects. *
* Example: *
* If your DAO object is called CarInfo.java, * the corresponding mapper query id should be: <insert id="createCarInfo" ... *

* SQL Executed (example): insert into [tablename] (fieldname1,fieldname2,...) values(value1,value2...) ... * */ public int insert(T o) throws PersistenceException{ SqlSession session = sqlSessionFactory.openSession(); Integer status = null; try { String query = this.type.getSimpleName()+NAMESPACE+"."+PREFIX_INSERT_QUERY+o.getClass().getSimpleName(); status = (Integer)session.insert(query, o); session.commit(); } finally { session.close(); } return status; } /** * Method updates the object by id. *

* You will usually override this method. But it can be used for simple objects. *
* Example: *
* If your DAO object is called CarInfo.java, * the corresponding mapper query id should be: <update id="updateCarInfo" ... *

* SQL Executed (example): update [tablename] set fieldname1 = value1 where id = #{id} * */ public int update(T o)throws PersistenceException { SqlSession session = sqlSessionFactory.openSession(); Integer status = null; try { String query = this.type.getSimpleName()+NAMESPACE+"."+PREFIX_UPDATE_QUERY+o.getClass().getSimpleName(); status = session.update(query, o); session.commit(); } finally { session.close(); } return status; } /** * Method deletes the object by id. *

* Example: *
* If your DAO object is called CarInfo.java, * the corresponding mapper query id should be: <delete id="deleteCarInfo" ... *

* SQL Executed (example): update [tablename] set fieldname1 = value1 where id = #{id} * */ public int delete(PK id) throws PersistenceException{ SqlSession session = sqlSessionFactory.openSession(); Integer status = null; try { String query = this.type.getSimpleName()+NAMESPACE+"."+PREFIX_DELETE_QUERY+this.type.getSimpleName(); status = session.delete(query, id); session.commit(); } finally { session.close(); } return status; } }


RoleService.java
package com.openerp.service;

import com.openerp.domain.Role;

public interface RoleService {
	Role getRole(int key);
}


RoleServiceImpl.java
package com.openerp.service.impl;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.openerp.dao.RoleDao;
import com.openerp.domain.Role;
import com.openerp.service.RoleService;

@Service("roleMgr")
public class RoleServiceImpl implements RoleService{
	
	Log logger = LogFactory.getLog(this.getClass());
	
	@Autowired
	private RoleDao dao;

	@Override
	public Role getRole(int key) {
		return dao.get(key);
	}
	
}


Controller
package com.openerp.controller;

import java.io.IOException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.arnx.jsonic.JSONException;

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

import com.openerp.common.utils.JSONUtil;
import com.openerp.service.RoleService;

@Controller
public class JsonController {

	@Autowired private RoleService roleMgr;
	
	@RequestMapping("/json/sampleData.do")
	public void sendJsonData(HttpServletRequest req, HttpServletResponse rep){
		int key = Integer.parseInt(req.getParameter("key"));
		try {
			rep.setCharacterEncoding("UTF-8");
			rep.getWriter().write(JSONUtil.toJSON(roleMgr.getRole(key), null));
			
		} catch (JSONException e) {
			e.printStackTrace();
			
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}


SqlMapConfig.xml



	
		 
	

	
		
	

	



mapUnderscoreToCamelCase 이 속성을 안적어주면 아래 필드가 매핑되지 않는다.
ROLE_NAME_KOR 이런 필드는 카멜 표기법으로 표기하지 않기 때문에 꼭 위의 속성이 필요하다...


SQL File :

Full Source :
설명 적는게 너무 귀찮으다...