Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

커스텀 JDBC 라이브러리 만들어 보기 #5

Open
wants to merge 1 commit into
base: step2-user-with-mvc-framework
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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