在 Spring 專案中,重複編寫 CRUD 樣板代碼既枯燥又易出錯。本文展示如何封裝一個基於 JdbcTemplate 的泛型基礎 DAO,實現「寫一次 SQL,處處可用」的輕量級數據訪問層。
public interface BaseDaoInf<T> {
/** 查詢列表 */
List<T> find(String sql, Object[] parameters, Class<T> cl);
/** 新增、修改、刪除;返回影響行數,-1 表示異常 */
int addOrUpdateOrDelete(String sql, Object[] parameters, Class<T> cl);
}
@Repository
public class BaseDaoImpl<T> implements BaseDaoInf<T> {
@Resource(name = "jdbcTemplate")
private JdbcTemplate jdbcTemplate;
@Override
public List<T> find(String sql, Object[] parameters, Class<T> cl) {
try {
if (parameters != null && parameters.length > 0) {
return jdbcTemplate.query(sql, parameters, new BeanPropertyRowMapper<>(cl));
}
return jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(cl));
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
@Override
public int addOrUpdateOrDelete(String sql, final Object[] parameters, Class<T> cl) {
try {
if (parameters == null || parameters.length == 0) {
return jdbcTemplate.update(sql);
}
return jdbcTemplate.update(sql, new PreparedStatementSetter() {
@Override
public void setValues(PreparedStatement ps) throws SQLException {
for (int i = 0; i < parameters.length; i++) {
ps.setObject(i + 1, parameters[i]);
}
}
});
} catch (Exception e) {
e.printStackTrace();
return -1;
}
}
}
關鍵點:使用 BeanPropertyRowMapper 自動映射列名到屬性;PreparedStatementSetter 統一處理參數綁定,防止 SQL 注入。
@Repository("userDao")
public class UserInfoDaoImpl extends BaseDaoImpl<UserInfo> implements UserInfoDaoInf {
@Override
public UserInfo findUser(UserInfo user) {
String sql = "SELECT * FROM userInfo WHERE username=? AND password=?";
List<UserInfo> list = super.find(sql,
new String[]{user.getUserName(), user.getPassword()}, UserInfo.class);
return (list != null && !list.isEmpty()) ? list.get(0) : null;
}
@Override
public int deleteUserById(UserInfo user) {
return super.addOrUpdateOrDelete("DELETE FROM userInfo WHERE userid=?",
new Integer[]{user.getUserId()}, UserInfo.class);
}
@Override
public int addUser(UserInfo user) {
return super.addOrUpdateOrDelete("INSERT INTO userInfo VALUES(null,?,?,?)",
new Object[]{user.getUserName(), user.getPassword(), user.getSecondPassword()}, UserInfo.class);
}
@Override
public int updateUser(UserInfo user) {
return super.addOrUpdateOrDelete("UPDATE userInfo SET userName=?,password=?,secondPassword=? WHERE userid=?",
new Object[]{user.getUserName(), user.getPassword(), user.getSecondPassword(), user.getUserId()}, UserInfo.class);
}
}
Class<T> 參數,編譯期發現類型錯誤;JdbcTemplate 自行處理。此模式適合中小型專案、舊系統改造或不想引入重型 ORM 的場景,開箱即用,維護成本極低。