본문 바로가기

백엔드/Spring

myBatis DAO Pattern example


GenericMyBatisDaoSupport.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.openerp.common.dao;
 
import java.io.Serializable;
import java.util.ArrayList;
 
import org.apache.ibatis.exceptions.PersistenceException;
 
public interface GenericMyBatisDaoSupport<t, pk="" extends="" serializable="">{
    public T get(PK id) throws PersistenceException;//get obj of type T by the primary key 'id'
    public ArrayList<t> 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
}
</t></t,>




AbstractGenericMyBatisDao.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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
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<t, pk="" extends="" serializable=""> implements GenericMyBatisDaoSupport<t, pk=""> {
     
    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<t> 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<t> type) {
        this.type = type;
    }
     
    /** Default Constructor */
    public AbstractGenericMyBatisDao(Class<t> 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.
     *  <br>
<br>
  
     *  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).
     *  <br>
<br>
     *  Example:
     *  <br>
     *  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.
     *  <br>
<br>
   
     *  Example:
     *  <br>
   
     *  If your DAO object is called CarInfo.java,
     *  the corresponding mapper query id should be: <select id="getAllCarInfo" ... 
     *  <br>
<br>
   
     *  SQL Executed: select * from [tablename]
     *  <br>
<br>
   
     *  Notes:
     *  <br>
    
     *  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<t> getAll() throws PersistenceException {
 
        SqlSession session = sqlSessionFactory.openSession();
        ArrayList<t> list = null;
        try
        {    
            String query = this.type.getSimpleName()+NAMESPACE+"."+PREFIX_SELECT_QUERY+"All"+this.type.getSimpleName();
            list = (ArrayList<t>)session.selectList(query);
        }
        finally
        {
            session.close();
        }  
        return list;
    }
 
    /**
     *  Method returns first object which matches the given name (exact match).
     *  <br>
<br>
   
     *  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.
     *  <br>
<br>
     *  Example:
     *  <br>
   
     *  If your DAO object is called CarInfo.java,
     *  the corresponding mapper query id should be: <select id="getCarInfoByName" ... 
     *  <br>
<br>
   
     *  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.
     *  <br>
<br>
     *  You will usually override this method, especially if you're inserting associated objects.
     *  <br>
  
     *  Example:
     *  <br>
   
     *  If your DAO object is called CarInfo.java,
     *  the corresponding mapper query id should be: <insert id="createCarInfo" ... 
     *  <br>
<br>
   
     *  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.
     *  <br>
<br>
     *  You will usually override this method. But it can be used for simple objects.
     *  <br>
  
     *  Example:
     *  <br>
   
     *  If your DAO object is called CarInfo.java,
     *  the corresponding mapper query id should be: <update id="updateCarInfo" ... 
     *  <br>
<br>
   
     *  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.
     *  <br>
<br>
     *  Example:
     *  <br>
   
     *  If your DAO object is called CarInfo.java,
     *  the corresponding mapper query id should be: <delete id="deleteCarInfo" ... 
     *  <br>
<br>
   
     *  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;
    }
 
}
</t></t></t></t></t></t></t,></t,>


RoleService.java
1
2
3
4
5
6
7
package com.openerp.service;
 
import com.openerp.domain.Role;
 
public interface RoleService {
    Role getRole(int key);
}


RoleServiceImpl.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
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
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
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
1
2
3
4
5
6
7
8
9
10
11
12
<!--?xml version="1.0" encoding="UTF-8" ?-->
 
<configuration>
    <settings>
         <setting name="mapUnderscoreToCamelCase" value="true">
    </setting></settings>
 
    <typealiases>
        <typealias alias="Role" type="com.openerp.domain.Role">
    </typealias></typealiases>
</configuration>
    


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


SQL File :

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