本系列第三部分,展示如何在自製 DataTable 元件中實現參數化 SQL 查詢(防 SQL 注入),並演示實際業務調用代碼。
/**
* 為 PreparedStatement 綁定參數陣列
* @param ps 預編譯語句
* @param params SqlParameter 陣列,含型別與值
*/
private void addSqlParameter(PreparedStatement ps, SqlParameter[] params) throws SQLException {
for (int i = 0; i < params.length; i++) {
SqlParameter p = params[i];
String type = p.getType();
if ("int".equals(type)) {
ps.setInt(i + 1, p.getIntValue());
} else if ("String".equals(type)) {
ps.setString(i + 1, p.getValue());
} else if ("boolean".equals(type)) {
ps.setBoolean(i + 1, p.getBoolValue());
} else if ("Date".equals(type)) {
ps.setDate(i + 1, p.getDateValue());
} else if ("Blob".equals(type)) {
ps.setBlob(i + 1, p.getBlobValue());
}
// 可擴充更多型別:BigDecimal, Timestamp, Clob 等
}
}
設計要點:
PreparedStatement 預編譯,徹底防範 SQL 注入。setXxx 方法。i + 1。
public DataTable getByParentId(int parentId) {
String sql = "SELECT * FROM kpxz WHERE fbh = ? ORDER BY kpxzsx ASC";
SqlParameter[] params = new SqlParameter[1];
params[0] = new SqlParameter("int", parentId);
return db.getDataTable(sql, params);
}
public class SqlParameter {
private String type;
private String value;
private int intValue;
private boolean boolValue;
private Date dateValue;
private Blob blobValue;
// 多型別建構子
public SqlParameter(String type, String value) { this.type = type; this.value = value; }
public SqlParameter(String type, int intValue) { this.type = type; this.intValue = intValue; }
public SqlParameter(String type, boolean boolValue) { this.type = type; this.boolValue = boolValue; }
public SqlParameter(String type, Date dateValue) { this.type = type; this.dateValue = dateValue; }
public SqlParameter(String type, Blob blobValue) { this.type = type; this.blobValue = blobValue; }
// Getter/Setter 略
}
getByParentId(123)
↓
sql = "SELECT ... WHERE fbh = ?"
params = [SqlParameter("int", 123)]
↓
db.getDataTable(sql, params)
↓
Connection conn = DB.createConn()
PreparedStatement ps = conn.prepareStatement(sql)
↓
addSqlParameter(ps, params) ← 關鍵:ps.setInt(1, 123)
↓
ResultSet rs = ps.executeQuery()
↓
ResultSetMetaData → 列名/型別
↓
while (rs.next()) {
List rowColumns = new ArrayList<>();
for (int i = 1; i <= columnCount; i++) {
String colName = rsmd.getColumnName(i);
Object val = rs.getObject(colName);
rowColumns.add(new DataColumn(colName, val));
}
rows.add(new DataRow(rowColumns));
}
↓
return new DataTable(rows)
BigDecimal、Timestamp、Clob、Array 等更多 JDBC 型別。ps.setObject("paramName", val),需 JDBC 4.0+ 驅動)。DB.createConn()。ps.setQueryTimeout(seconds)。