Skip to content

Commit ebe41c5

Browse files
author
John Grib
committed
커스텀 JDBC 라이브러리 만들어 보기
1 parent 92b9427 commit ebe41c5

File tree

11 files changed

+798
-56
lines changed

11 files changed

+798
-56
lines changed

src/main/java/core/db/Query.java

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
package core.db;
2+
3+
import util.ReflectionUtil;
4+
import util.UpperStringMap;
5+
6+
import java.util.Arrays;
7+
import java.util.List;
8+
import java.util.Map;
9+
import java.util.regex.Pattern;
10+
11+
/**
12+
* Query String 을 생성/관리한다.
13+
* Created by johngrib on 2017. 4. 22..
14+
*/
15+
public class Query {
16+
17+
private static List<ValueProc> processors = Arrays.asList(new ValueProc[]{
18+
new NullProc(),
19+
new StringProc(),
20+
new IntegerProc()
21+
});
22+
23+
private static String buildAlias(final String key) {
24+
return "(?i)" + Pattern.quote("${" + key + "}");
25+
}
26+
27+
/**
28+
* query 에 vo 의 값을 set 한다.
29+
* query 에서 replace 될 키는 ${key} 의 형태로 지정한다.
30+
*
31+
* @param sql
32+
* @param vo
33+
* @return
34+
*/
35+
public static String build(final String sql, final Object vo) {
36+
if (vo == null) {
37+
return sql;
38+
}
39+
40+
final Map<String, Object> map = ReflectionUtil.objMapper(vo, new UpperStringMap());
41+
42+
String sourceSql = sql;
43+
44+
for (final String key : map.keySet()) {
45+
final Object val = map.get(key);
46+
final String value = processors.stream()
47+
.filter(p -> p.typeCheck(val))
48+
.findFirst().get().proc(val);
49+
sourceSql = sourceSql.replaceAll(buildAlias(key), value);
50+
}
51+
return sourceSql;
52+
}
53+
54+
abstract static class ValueProc {
55+
abstract String proc(Object val);
56+
57+
abstract boolean typeCheck(Object val);
58+
}
59+
60+
static class StringProc extends ValueProc {
61+
@Override
62+
public String proc(final Object val) {
63+
return "'" + String.valueOf(val) + "'";
64+
}
65+
66+
@Override
67+
boolean typeCheck(final Object val) {
68+
return val instanceof String;
69+
}
70+
}
71+
72+
static class NullProc extends ValueProc {
73+
@Override
74+
public String proc(final Object val) {
75+
return "'" + String.valueOf(val) + "'";
76+
}
77+
78+
@Override
79+
boolean typeCheck(final Object val) {
80+
return val == null;
81+
}
82+
}
83+
84+
static class IntegerProc extends ValueProc {
85+
86+
@Override
87+
String proc(final Object val) {
88+
return String.valueOf(val);
89+
}
90+
91+
@Override
92+
boolean typeCheck(final Object val) {
93+
return val instanceof Integer;
94+
}
95+
}
96+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
package core.db;
2+
3+
import java.sql.ResultSet;
4+
import java.sql.ResultSetMetaData;
5+
import java.sql.SQLException;
6+
import java.util.*;
7+
8+
/**
9+
* ResultSet Wrapper
10+
* Created by johngrib on 2017. 4. 22..
11+
*/
12+
public class ResultData {
13+
14+
final private List<String> labels;
15+
private ResultSet rs = null;
16+
17+
public ResultData(final ResultSet rs) throws SQLException {
18+
this.rs = rs;
19+
this.labels = getColumnLabels(rs);
20+
}
21+
22+
/**
23+
* column labels를 리턴한다.
24+
* @return
25+
*/
26+
public List<String> getLabels() {
27+
return labels;
28+
}
29+
30+
/**
31+
* column lable 을 수집한다.
32+
* @param rs
33+
* @return
34+
*/
35+
private List<String> getColumnLabels(final ResultSet rs) {
36+
try {
37+
final int size = rs.getMetaData().getColumnCount();
38+
final List<String> list = new ArrayList<>(size);
39+
final ResultSetMetaData meta = rs.getMetaData();
40+
41+
for (int i = 1; i <= size; i++) {
42+
String name = meta.getColumnName(i);
43+
list.add(name);
44+
}
45+
return list;
46+
} catch (SQLException e) {
47+
e.printStackTrace();
48+
}
49+
return Collections.EMPTY_LIST;
50+
}
51+
52+
public ResultSet getResultSet() {
53+
return rs;
54+
}
55+
56+
public void close() {
57+
try {
58+
rs.close();
59+
} catch (SQLException e) {
60+
e.printStackTrace();
61+
} finally {
62+
rs = null;
63+
}
64+
}
65+
66+
public boolean next() {
67+
try {
68+
return rs.next();
69+
} catch (SQLException e) {
70+
e.printStackTrace();
71+
}
72+
return false;
73+
}
74+
75+
public Map<String, Object> getDataMap() {
76+
try {
77+
final Map<String, Object> data = new HashMap<>();
78+
for (String label : labels) {
79+
data.put(label, rs.getObject(label));
80+
}
81+
return data;
82+
83+
} catch (SQLException e) {
84+
e.printStackTrace();
85+
}
86+
return Collections.EMPTY_MAP;
87+
}
88+
}
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
package core.jdbc;
2+
3+
import core.db.Query;
4+
import core.db.ResultData;
5+
import util.DataMethod;
6+
import util.ReflectionUtil;
7+
import util.UpperStringMap;
8+
9+
import java.sql.Connection;
10+
import java.sql.PreparedStatement;
11+
import java.sql.ResultSet;
12+
import java.sql.SQLException;
13+
import java.util.*;
14+
15+
/**
16+
* Created by johngrib on 2017. 4. 20..
17+
*/
18+
public class JdbcTemplate {
19+
20+
/**
21+
* INSERT, UPDATE 를 수행한다.
22+
*
23+
* @param sql
24+
* @param vo
25+
* @throws SQLException
26+
*/
27+
public void update(String sql, Object vo) throws SQLException {
28+
Connection con = null;
29+
PreparedStatement pstmt = null;
30+
try {
31+
con = ConnectionManager.getConnection();
32+
pstmt = con.prepareStatement(Query.build(sql, vo));
33+
pstmt.executeUpdate();
34+
} finally {
35+
if (pstmt != null) {
36+
pstmt.close();
37+
}
38+
39+
if (con != null) {
40+
con.close();
41+
}
42+
}
43+
}
44+
45+
/**
46+
* SELECT 를 수행한다.
47+
* @param sql
48+
* @param voClass
49+
* @return
50+
* @throws SQLException
51+
*/
52+
public <T> List<T> select(String sql, Class<T> voClass) throws SQLException {
53+
return select(sql, voClass, null);
54+
}
55+
56+
/**
57+
* SELECT 를 수행한 결과의 첫 번째 row 를 리턴한다.
58+
* @param sql
59+
* @param voClass
60+
* @param vo
61+
* @return
62+
* @throws SQLException
63+
*/
64+
public <T> T selectOne(String sql, Class<T> voClass, Object vo) throws SQLException {
65+
final List<T> list = select(sql, voClass, vo);
66+
return (list.size() > 0) ? list.get(0) : null;
67+
}
68+
69+
/**
70+
* SELECT 를 수행한다.
71+
*
72+
* @param sql
73+
* @param voClass
74+
* @return
75+
* @throws SQLException
76+
*/
77+
public <T> List<T> select(String sql, Class<T> voClass, Object vo) throws SQLException {
78+
79+
ResultSet rs = null;
80+
final String query = Query.build(sql, vo);
81+
try (
82+
final Connection con = ConnectionManager.getConnection();
83+
final PreparedStatement pstmt = con.prepareStatement(query);
84+
) {
85+
rs = pstmt.executeQuery();
86+
87+
final ResultData rd = new ResultData(rs);
88+
final List<T> list = new ArrayList<>(rs.getFetchSize());
89+
final Map<String, DataMethod> setters = ReflectionUtil.getSetterMemberMap(voClass, new UpperStringMap());
90+
final List<String> labels = rd.getLabels();
91+
92+
while (rd.next()) {
93+
94+
final T row = ReflectionUtil.newSimpleInstance(voClass);
95+
96+
for (String label: labels) {
97+
DataMethod setter = setters.get(label);
98+
setVoFromResultSet(setter, rd.getResultSet(), row);
99+
}
100+
list.add(row);
101+
}
102+
return list;
103+
} finally {
104+
if (rs != null) {
105+
rs.close();
106+
}
107+
}
108+
}
109+
110+
/**
111+
* ResultSet 의 데이터를 vo 에 매핑한다.
112+
* @param m
113+
* @param rs
114+
* @param vo
115+
*/
116+
private void setVoFromResultSet(final DataMethod m, final ResultSet rs, Object vo) {
117+
try {
118+
if (String.class.equals(m.type)) {
119+
m.setter(vo, rs.getString(m.fieldName));
120+
return;
121+
}
122+
if (Integer.class.equals(m.type)) {
123+
m.setter(vo, rs.getInt(m.fieldName));
124+
return;
125+
}
126+
if (Double.class.equals(m.type)) {
127+
m.setter(vo, rs.getInt(m.fieldName));
128+
return;
129+
}
130+
} catch (SQLException e) {
131+
e.printStackTrace();
132+
}
133+
}
134+
}

0 commit comments

Comments
 (0)