Skip to content

Commit

Permalink
커스텀 JDBC 라이브러리 만들어 보기
Browse files Browse the repository at this point in the history
  • Loading branch information
John Grib committed Apr 22, 2017
1 parent 92b9427 commit ebe41c5
Show file tree
Hide file tree
Showing 11 changed files with 798 additions and 56 deletions.
96 changes: 96 additions & 0 deletions src/main/java/core/db/Query.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package core.db;

import util.ReflectionUtil;
import util.UpperStringMap;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

/**
* Query String 을 생성/관리한다.
* Created by johngrib on 2017. 4. 22..
*/
public class Query {

private static List<ValueProc> processors = Arrays.asList(new ValueProc[]{
new NullProc(),
new StringProc(),
new IntegerProc()
});

private static String buildAlias(final String key) {
return "(?i)" + Pattern.quote("${" + key + "}");
}

/**
* query 에 vo 의 값을 set 한다.
* query 에서 replace 될 키는 ${key} 의 형태로 지정한다.
*
* @param sql
* @param vo
* @return
*/
public static String build(final String sql, final Object vo) {
if (vo == null) {
return sql;
}

final Map<String, Object> map = ReflectionUtil.objMapper(vo, new UpperStringMap());

String sourceSql = sql;

for (final String key : map.keySet()) {
final Object val = map.get(key);
final String value = processors.stream()
.filter(p -> p.typeCheck(val))
.findFirst().get().proc(val);
sourceSql = sourceSql.replaceAll(buildAlias(key), value);
}
return sourceSql;
}

abstract static class ValueProc {
abstract String proc(Object val);

abstract boolean typeCheck(Object val);
}

static class StringProc extends ValueProc {
@Override
public String proc(final Object val) {
return "'" + String.valueOf(val) + "'";
}

@Override
boolean typeCheck(final Object val) {
return val instanceof String;
}
}

static class NullProc extends ValueProc {
@Override
public String proc(final Object val) {
return "'" + String.valueOf(val) + "'";
}

@Override
boolean typeCheck(final Object val) {
return val == null;
}
}

static class IntegerProc extends ValueProc {

@Override
String proc(final Object val) {
return String.valueOf(val);
}

@Override
boolean typeCheck(final Object val) {
return val instanceof Integer;
}
}
}
88 changes: 88 additions & 0 deletions src/main/java/core/db/ResultData.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package core.db;

import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.*;

/**
* ResultSet Wrapper
* Created by johngrib on 2017. 4. 22..
*/
public class ResultData {

final private List<String> labels;
private ResultSet rs = null;

public ResultData(final ResultSet rs) throws SQLException {
this.rs = rs;
this.labels = getColumnLabels(rs);
}

/**
* column labels를 리턴한다.
* @return
*/
public List<String> getLabels() {
return labels;
}

/**
* column lable 을 수집한다.
* @param rs
* @return
*/
private List<String> getColumnLabels(final ResultSet rs) {
try {
final int size = rs.getMetaData().getColumnCount();
final List<String> list = new ArrayList<>(size);
final ResultSetMetaData meta = rs.getMetaData();

for (int i = 1; i <= size; i++) {
String name = meta.getColumnName(i);
list.add(name);
}
return list;
} catch (SQLException e) {
e.printStackTrace();
}
return Collections.EMPTY_LIST;
}

public ResultSet getResultSet() {
return rs;
}

public void close() {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
} finally {
rs = null;
}
}

public boolean next() {
try {
return rs.next();
} catch (SQLException e) {
e.printStackTrace();
}
return false;
}

public Map<String, Object> getDataMap() {
try {
final Map<String, Object> data = new HashMap<>();
for (String label : labels) {
data.put(label, rs.getObject(label));
}
return data;

} catch (SQLException e) {
e.printStackTrace();
}
return Collections.EMPTY_MAP;
}
}
134 changes: 134 additions & 0 deletions src/main/java/core/jdbc/JdbcTemplate.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
package core.jdbc;

import core.db.Query;
import core.db.ResultData;
import util.DataMethod;
import util.ReflectionUtil;
import util.UpperStringMap;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;

/**
* Created by johngrib on 2017. 4. 20..
*/
public class JdbcTemplate {

/**
* INSERT, UPDATE 를 수행한다.
*
* @param sql
* @param vo
* @throws SQLException
*/
public void update(String sql, Object vo) throws SQLException {
Connection con = null;
PreparedStatement pstmt = null;
try {
con = ConnectionManager.getConnection();
pstmt = con.prepareStatement(Query.build(sql, vo));
pstmt.executeUpdate();
} finally {
if (pstmt != null) {
pstmt.close();
}

if (con != null) {
con.close();
}
}
}

/**
* SELECT 를 수행한다.
* @param sql
* @param voClass
* @return
* @throws SQLException
*/
public <T> List<T> select(String sql, Class<T> voClass) throws SQLException {
return select(sql, voClass, null);
}

/**
* SELECT 를 수행한 결과의 첫 번째 row 를 리턴한다.
* @param sql
* @param voClass
* @param vo
* @return
* @throws SQLException
*/
public <T> T selectOne(String sql, Class<T> voClass, Object vo) throws SQLException {
final List<T> list = select(sql, voClass, vo);
return (list.size() > 0) ? list.get(0) : null;
}

/**
* SELECT 를 수행한다.
*
* @param sql
* @param voClass
* @return
* @throws SQLException
*/
public <T> List<T> select(String sql, Class<T> voClass, Object vo) throws SQLException {

ResultSet rs = null;
final String query = Query.build(sql, vo);
try (
final Connection con = ConnectionManager.getConnection();
final PreparedStatement pstmt = con.prepareStatement(query);
) {
rs = pstmt.executeQuery();

final ResultData rd = new ResultData(rs);
final List<T> list = new ArrayList<>(rs.getFetchSize());
final Map<String, DataMethod> setters = ReflectionUtil.getSetterMemberMap(voClass, new UpperStringMap());
final List<String> labels = rd.getLabels();

while (rd.next()) {

final T row = ReflectionUtil.newSimpleInstance(voClass);

for (String label: labels) {
DataMethod setter = setters.get(label);
setVoFromResultSet(setter, rd.getResultSet(), row);
}
list.add(row);
}
return list;
} finally {
if (rs != null) {
rs.close();
}
}
}

/**
* ResultSet 의 데이터를 vo 에 매핑한다.
* @param m
* @param rs
* @param vo
*/
private void setVoFromResultSet(final DataMethod m, final ResultSet rs, Object vo) {
try {
if (String.class.equals(m.type)) {
m.setter(vo, rs.getString(m.fieldName));
return;
}
if (Integer.class.equals(m.type)) {
m.setter(vo, rs.getInt(m.fieldName));
return;
}
if (Double.class.equals(m.type)) {
m.setter(vo, rs.getInt(m.fieldName));
return;
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
Loading

0 comments on commit ebe41c5

Please sign in to comment.