ㅏ입핸들5
import java.sql.CallableStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;
/*
* ResultMap usage example:
*
*
*
*
*
*
* One-parameter parseable mixed column examples:
*
* SELECT
* NVL(#{typeCode, jdbcType=VARCHAR}, '')
* || '^|^'
* || NVL(DECODE(OTS.SHOW_BIRTHDAY, 'N', '99991231', EMP.BIRTH_DATE_ENC), '')
* || '^|^'
* || NVL(EMP.HIRE_DATE, '')
* || '^|^'
* || NVL(TO_CHAR(SYSDATE, 'YYYYMMDD'), '') AS ATT_DETAIL_MIXED
* , NVL(#{typeCode, jdbcType=VARCHAR}, '')
* || '^|^'
* || NVL(DECODE(OTS.SHOW_BIRTHDAY, 'N', '99991231', EMP.BIRTH_DATE_ENC), '')
* || '^|^'
* || NVL(EMP.HIRE_DATE, '')
* || '^|^'
* || NVL(TO_CHAR(SYSDATE, 'YYYYMMDD'), '') AS START_YMD_MIXED
* FROM ...
*
* Mixed value format:
* typeCode^|^birthDateEncOr99991231^|^syStaDate^|^targetDay
*
* Only BIRTH_DATE_ENC is decrypted as decrypt(BIRTH_DATE_ENC), and only when
* it is not the birthday-hidden sentinel value 99991231. SY_STA_DATE and
* targetDay are treated as plain YYYYMMDD values.
* Replace Crypto.decrypt(...) with the project's real decrypt API.
*/
@MappedTypes(String.class)
@MappedJdbcTypes(JdbcType.VARCHAR)
class AttDetailTypeHandler extends BaseTypeHandler {
@Override
public void setNonNullParameter(java.sql.PreparedStatement ps, int i, String parameter, JdbcType jdbcType)
throws SQLException {
ps.setString(i, parameter);
}
@Override
public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
return toAttDetail(rs.getString(columnName));
}
@Override
public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
return toAttDetail(rs.getString(columnIndex));
}
@Override
public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
return toAttDetail(cs.getString(columnIndex));
}
private String toAttDetail(String mixedValue) throws SQLException {
MixedAttendanceValue value = MixedAttendanceValue.parse(mixedValue);
if (value.isBlank()) {
return "";
}
switch (value.typeCode) {
case "BDAY":
return value.birthDateYmd();
case "JOIN":
return value.syStaDate;
case "LONG":
if (value.targetDay.length() < 4 || value.syStaDate.length() < 4) {
return "";
}
int targetYear = Integer.parseInt(value.targetDay.substring(0, 4));
int joinYear = Integer.parseInt(value.syStaDate.substring(0, 4));
return String.valueOf(targetYear - joinYear);
default:
return "";
}
}
}
@MappedTypes(String.class)
@MappedJdbcTypes(JdbcType.VARCHAR)
class StartYmdTypeHandler extends BaseTypeHandler {
@Override
public void setNonNullParameter(java.sql.PreparedStatement ps, int i, String parameter, JdbcType jdbcType)
throws SQLException {
ps.setString(i, parameter);
}
@Override
public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
return toStartYmd(rs.getString(columnName));
}
@Override
public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
return toStartYmd(rs.getString(columnIndex));
}
@Override
public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
return toStartYmd(cs.getString(columnIndex));
}
private String toStartYmd(String mixedValue) throws SQLException {
MixedAttendanceValue value = MixedAttendanceValue.parse(mixedValue);
if (value.isBlank()) {
return "";
}
switch (value.typeCode) {
case "BDAY":
return toMonthDay(value.birthDateYmd());
case "JOIN":
case "LONG":
return toMonthDay(value.syStaDate);
default:
return "";
}
}
private String toMonthDay(String ymd) {
if (ymd == null || ymd.length() != 8) {
return "";
}
return ymd.substring(4, 6) + "." + ymd.substring(6, 8);
}
}
final class MixedAttendanceValue {
private static final String DELIMITER = "^|^";
private static final String HIDDEN_BIRTHDAY = "99991231";
final String typeCode;
final String birthDateEncOrMask;
final String syStaDate;
final String targetDay;
private MixedAttendanceValue(String typeCode, String birthDateEncOrMask, String syStaDate, String targetDay) {
this.typeCode = normalize(typeCode);
this.birthDateEncOrMask = normalize(birthDateEncOrMask);
this.syStaDate = normalize(syStaDate);
this.targetDay = normalize(targetDay);
}
static MixedAttendanceValue parse(String mixedValue) throws SQLException {
if (mixedValue == null || mixedValue.trim().isEmpty()) {
return new MixedAttendanceValue("", "", "", "");
}
String[] parts = mixedValue.split("\\Q" + DELIMITER + "\\E", -1);
if (parts.length < 4) {
throw new SQLException("Invalid attendance mixed value. Expected typeCode^|^birthDateEncOrMask^|^syStaDate^|^targetDay.");
}
return new MixedAttendanceValue(parts[0], parts[1], parts[2], parts[3]);
}
boolean isBlank() {
return typeCode.isEmpty();
}
String birthDateYmd() throws SQLException {
if (birthDateEncOrMask.isEmpty()) {
return "";
}
if (HIDDEN_BIRTHDAY.equals(birthDateEncOrMask)) {
return HIDDEN_BIRTHDAY;
}
// Only BIRTH_DATE_ENC is decrypted. The other mixed fields stay plain.
return normalize(Crypto.decrypt(birthDateEncOrMask));
}
private static String normalize(String value) {
return value == null ? "" : value.trim();
}
}
final class Crypto {
private Crypto() {
}
static String decrypt(String encryptedValue) throws SQLException {
/*
* TODO Replace this stub with the real project decrypt call.
* Example:
* return KmsCipher.decrypt(encryptedValue);
*/
return encryptedValue;
}
}
댓글
댓글 쓰기