做成类似 Microsoft.NET SqlHelper 的 Java 实现
用到了 apache-commons-dbutils-1.1 类库
1. 主要程序,Java 的泛型比较古怪,不能做参数,所以CoreTest的构造方法也要跟着古怪一下
package epg.lab.test;
import java.util.*;
import java.sql.*;
import java.util.regex.*;
import java.lang.reflect.*;
import org.apache.commons.dbutils.*;
public class CoreTest<T> {
private T emptyEntity = null;
public CoreTest(T emptyEntity){
this.emptyEntity = emptyEntity;
}
public List<T> executeSqlDataSet(Connection conn, String sql, Object parameterObject){
List<T> result = null;
String regEx="@[a-zA-Z_0-9]+";
Pattern p=Pattern.compile(regEx);
Matcher m=p.matcher(sql);
List<Object> values = new ArrayList<Object>();
while(m.find()){
values.add(m.group().substring(1));
}
String resultSQL = m.replaceAll("?");
try{
for(Field f : News.class.getDeclaredFields()){
if(f.isAnnotationPresent(SqlParameter.class)){
SqlParameter param = f.getAnnotation(SqlParameter.class);
for(int i=0;i<values.size();i++){
if(param.field().equals(values.get(i))){
if(f.isAccessible()){
values.set(i, f.get(parameterObject));
}else{
Method getter = News.class.getMethod(new StringBuffer("get").append(f.getName().substring(0,1).toUpperCase()).append(f.getName().substring(1)).toString());
if(getter!=null){
values.set(i, getter.invoke(parameterObject));
}else{
values.set(i, null);
}
}
}
}
}
}
}catch(Exception ex){
ex.printStackTrace();
}
PreparedStatement pstmt = null;
ResultSet rs = null;
try{
pstmt = conn.prepareStatement(resultSQL);
for(int i=0;i<values.size();i++){
pstmt.setObject(i+1, values.get(i));
}
rs = pstmt.executeQuery();
BeanProcessor processor = new BeanProcessor();
result = processor.toBeanList(rs, this.emptyEntity.getClass());
}catch (Exception e) {
e.printStackTrace();
}
finally{
try { rs.close(); } catch(Exception e) { }
try { pstmt.close(); } catch(Exception e) { }
}
return result;
}
/**
* @param args
*/
public static void main(String[] args) {
News newsCondition = new News();
newsCondition.setId(1);
newsCondition.setTitle("央行%");
newsCondition.setPubDate(Calendar.getInstance().getTime());
String sql = "SELECT * FROM News_NewsContent WHERE ID>@ID AND Title like @Title OR ID=@ID";
CoreTest<News> test = new CoreTest<News>(new News());
List<News> list = null;
Connection conn = null;
try{
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
conn = DriverManager.getConnection("jdbc:sqlserver://localhost;databaseName=News;user=sa;password=123456");
list = test.executeSqlDataSet(conn, sql, newsCondition);
}catch(Exception ex){
ex.printStackTrace();
}finally{
try{conn.close();conn=null;}catch(Exception ex){}
}
for(News news : list){
System.out.print(news.getId());
System.out.print(news.getTitle());
System.out.println(news.getPubDate());
}
}
}
import java.util.*;
import java.sql.*;
import java.util.regex.*;
import java.lang.reflect.*;
import org.apache.commons.dbutils.*;
public class CoreTest<T> {
private T emptyEntity = null;
public CoreTest(T emptyEntity){
this.emptyEntity = emptyEntity;
}
public List<T> executeSqlDataSet(Connection conn, String sql, Object parameterObject){
List<T> result = null;
String regEx="@[a-zA-Z_0-9]+";
Pattern p=Pattern.compile(regEx);
Matcher m=p.matcher(sql);
List<Object> values = new ArrayList<Object>();
while(m.find()){
values.add(m.group().substring(1));
}
String resultSQL = m.replaceAll("?");
try{
for(Field f : News.class.getDeclaredFields()){
if(f.isAnnotationPresent(SqlParameter.class)){
SqlParameter param = f.getAnnotation(SqlParameter.class);
for(int i=0;i<values.size();i++){
if(param.field().equals(values.get(i))){
if(f.isAccessible()){
values.set(i, f.get(parameterObject));
}else{
Method getter = News.class.getMethod(new StringBuffer("get").append(f.getName().substring(0,1).toUpperCase()).append(f.getName().substring(1)).toString());
if(getter!=null){
values.set(i, getter.invoke(parameterObject));
}else{
values.set(i, null);
}
}
}
}
}
}
}catch(Exception ex){
ex.printStackTrace();
}
PreparedStatement pstmt = null;
ResultSet rs = null;
try{
pstmt = conn.prepareStatement(resultSQL);
for(int i=0;i<values.size();i++){
pstmt.setObject(i+1, values.get(i));
}
rs = pstmt.executeQuery();
BeanProcessor processor = new BeanProcessor();
result = processor.toBeanList(rs, this.emptyEntity.getClass());
}catch (Exception e) {
e.printStackTrace();
}
finally{
try { rs.close(); } catch(Exception e) { }
try { pstmt.close(); } catch(Exception e) { }
}
return result;
}
/**
* @param args
*/
public static void main(String[] args) {
News newsCondition = new News();
newsCondition.setId(1);
newsCondition.setTitle("央行%");
newsCondition.setPubDate(Calendar.getInstance().getTime());
String sql = "SELECT * FROM News_NewsContent WHERE ID>@ID AND Title like @Title OR ID=@ID";
CoreTest<News> test = new CoreTest<News>(new News());
List<News> list = null;
Connection conn = null;
try{
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
conn = DriverManager.getConnection("jdbc:sqlserver://localhost;databaseName=News;user=sa;password=123456");
list = test.executeSqlDataSet(conn, sql, newsCondition);
}catch(Exception ex){
ex.printStackTrace();
}finally{
try{conn.close();conn=null;}catch(Exception ex){}
}
for(News news : list){
System.out.print(news.getId());
System.out.print(news.getTitle());
System.out.println(news.getPubDate());
}
}
}
2. News 类,可以作为查询条件,也可以作为查询结果集的数据行对象。搞了个 SqlParameter Annotation 用来声明类属性对应的数据表字段。
package epg.lab.test;
import java.util.*;
public class News {
@SqlParameter(field="ID")
private int id;
@SqlParameter(field="Title")
private String title;
@SqlParameter(field="PubDate")
private Date pubDate;
/**
* @return the id
*/
public int getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(int id) {
this.id = id;
}
/**
* @return the pubDate
*/
public Date getPubDate() {
return pubDate;
}
/**
* @param pubDate the pubDate to set
*/
public void setPubDate(Date pubDate) {
this.pubDate = pubDate;
}
/**
* @return the title
*/
public String getTitle() {
return title;
}
/**
* @param title the title to set
*/
public void setTitle(String title) {
this.title = title;
}
}
import java.util.*;
public class News {
@SqlParameter(field="ID")
private int id;
@SqlParameter(field="Title")
private String title;
@SqlParameter(field="PubDate")
private Date pubDate;
/**
* @return the id
*/
public int getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(int id) {
this.id = id;
}
/**
* @return the pubDate
*/
public Date getPubDate() {
return pubDate;
}
/**
* @param pubDate the pubDate to set
*/
public void setPubDate(Date pubDate) {
this.pubDate = pubDate;
}
/**
* @return the title
*/
public String getTitle() {
return title;
}
/**
* @param title the title to set
*/
public void setTitle(String title) {
this.title = title;
}
}
3. SqlParameter Annotation,前面 RUNTIME 的定义是一定要加的,这样才能在运行时反射出来。
package epg.lab.test;
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface SqlParameter {
String field();
int sqlType() default java.sql.Types.NVARCHAR;
boolean output() default false;
}
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface SqlParameter {
String field();
int sqlType() default java.sql.Types.NVARCHAR;
boolean output() default false;
}
运行主程序在 console 会得到:
1经济型酒店正成国内特许加盟项目新宠2006-11-20 20:22:50.0
9央行:采取综合措施合理控制货币信贷增长2006-11-20 20:27:38.0
12央行将积极推动境内机构投资者开展境外投资业务2006-11-20 20:29:15.0
14央行将建立国家反洗钱数据库2006-11-20 20:30:03.0
相比 HQL 的优点是这个东西比较简单,轻量级。这个东西还不完善,例如不能做 WHERE ID IN (...) 。可以参考着做一个依赖 CallableStatement 的存储过程调用方法 executeStoredProcedureDataSet 。
来源:https://www.cnblogs.com/stephencat/archive/2008/01/14/1038501.html