对Spring的JDBC框架再封装——提高效率

一、问题描述

问题描述:

在CRUD的项目中使用JdbcTemplate操作数据库时,在dao层我们会发现这样一个问题,代码量重复且繁杂,现在如下类型参照表:
在这里插入图片描述
在对他进行操作时,会有以下的代码:

1.实体类(model层)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64

/**
* 损坏类型子参照表
*/
@Component
public class Damage_type_stable {

private int damage_type_sid;//损坏类型子编号
private String damage_type_sname;//损害类型名称
private String damage_type_shape;//损坏形状
private String damage_type_calcu;//计算方法
private int damage_type_fid;//损坏类型父编号

public int getDamage_type_sid() {
return damage_type_sid;
}

public void setDamage_type_sid(int damage_type_sid) {
this.damage_type_sid = damage_type_sid;
}

public String getDamage_type_sname() {
return damage_type_sname;
}

public void setDamage_type_sname(String damage_type_sname) {
this.damage_type_sname = damage_type_sname;
}

public String getDamage_type_shape() {
return damage_type_shape;
}

public void setDamage_type_shape(String damage_type_shape) {
this.damage_type_shape = damage_type_shape;
}

public String getDamage_type_calcu() {
return damage_type_calcu;
}

public void setDamage_type_calcu(String damage_type_calcu) {
this.damage_type_calcu = damage_type_calcu;
}

public int getDamage_type_fid() {
return damage_type_fid;
}

public void setDamage_type_fid(int damage_type_fid) {
this.damage_type_fid = damage_type_fid;
}

@Override
public String toString() {
return "Damage_type_stable{" +
"damage_type_sid=" + damage_type_sid +
", damage_type_sname='" + damage_type_sname + '\'' +
", damage_type_shape='" + damage_type_shape + '\'' +
", damage_type_calcu='" + damage_type_calcu + '\'' +
", damage_type_fid=" + damage_type_fid +
'}';
}
}

2、持久化层(dao层)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

**
* 损坏类型子参照表数据库操作:持久化层
*/
@Repository
public class DamageTypeStableDao {

@Autowired
private JdbcTemplate jdbcTemplate;

/**
* 查看所有损坏子类型信息
* @return 返回Damage_type_stable对象的List集合
*/
public List<Damage_type_stable> findAll(){
try {
String sql="";
List<Damage_type_stable> query = jdbcTemplate.query(sql, new BeanPropertyRowMapper<Damage_type_stable>(Damage_type_stable.class));
return query;
} catch (DataAccessException e) {
e.printStackTrace();
return null;
}
}

/**
* 添加损坏子类型信息
* @param damage_type_stable 损坏子类型类
*/
public void add(Damage_type_stable damage_type_stable){
String sql="";
jdbcTemplate.update(sql,damage_type_stable.getDamage_type_sid(),damage_type_stable.getDamage_type_sname(),damage_type_stable.getDamage_type_shape(),damage_type_stable.getDamage_type_calcu(),damage_type_stable.getDamage_type_fid());
}

/**
* 删除损坏子类型信息
* @param id 损坏子类型对应编号
* @throws Exception 删除产生的依赖异常
*/
public void delete(int id)throws DataAccessException{
String sql="";
jdbcTemplate.update(sql,id);
}

/**
* 修改损坏子类型信息
* @param damage_type_stable 损坏子类型类
*/
public void change(Damage_type_stable damage_type_stable){
String sql="";
jdbcTemplate.update(sql,damage_type_stable.getDamage_type_sname(),damage_type_stable.getDamage_type_shape(),damage_type_stable.getDamage_type_calcu(),damage_type_stable.getDamage_type_fid(),damage_type_stable.getDamage_type_sid());
}
}

我们会很容易的发现,在使用JdbcTemplate的update和query方法进行自动封装时对可变参数的传入重复且繁杂,假如我们的实体类有几十,甚至几百个属性呢…..

二、解决办法

解决思路(以add方法为例):

在JdbcTemplate中,提供了update方法的另一种重载方式:update(sql,Object []);,可以传入一个Object类的数组,按顺序依次封装。既然如此,我们就可以通过Java的反射机制,写一个工具方法,以Object类对象为参数,通过获取到对象中的所有get方法,将get到的返回值封装在一个数组里,使用上述update(sql,Object []);,进行数据库操作。实现自动封装update方法的可变参数。

1、建库,并编写实体类(以Users类为示例)
在这里插入图片描述

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

/**
* 用户实体类
*/
@Component
public class Users {

private String username;//用户名
private String pasword;//密码

public String getUsername() {
return username;
}

public void setUsername(String username) {
this.username = username;
}

public String getPasword() {
return pasword;
}

public void setPasword(String pasword) {
this.pasword = pasword;
}

@Override
public String toString() {
return "Users{" +
"username='" + username + '\'' +
", pasword='" + pasword + '\'' +
'}';
}
}

2、获取到类对象所有的get方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

/**
* 获取object的所有get方法
* @return
*/
public List<Method> getAllReadMethod(Object object){
List<Method> method=new ArrayList<Method>();
Class<? extends Object> testClass = object.getClass();
//获得属性
Field[] fields = object.getClass().getDeclaredFields();
for (Field field : fields) {
try {
PropertyDescriptor pd = new PropertyDescriptor(field.getName(), testClass);
//获得get方法
Method getMethod = pd.getReadMethod();
//添加进List集合
method.add(getMethod);
} catch (IntrospectionException e) {
e.printStackTrace();
}
}
return method;
}

3、得到所有get方法的返回值,并封装进Object数组中,然后返回

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

/**
* 得到所有get方法的返回值
* @return
*/
public Object[] getAllMethodName(Object object){
//调用第一步中的方法:获取到所有的get方法
List<Method> allReadMethod = getAllReadMethod(object);
Object [] values=new Object[allReadMethod.size()];
int i=0;
for(Method e:allReadMethod){
try {
Object invoke = e.invoke(object);
String s = invoke.toString();
values[i]=s;
i++;
} catch (IllegalAccessException e1) {
e1.printStackTrace();
} catch (InvocationTargetException e1) {
e1.printStackTrace();
}
}
return values;
}

4、编写add方法

1
2
3
4
5
6
7
8
9
10

/**
* 添加信息
* @param sql
* @param object
*/
public void add(String sql,Object object) {
Object[] allMethodName = getAllMethodName(object);
jdbcTemplate.update(sql,allMethodName);
}

5、测试

1
2
3
4
5
6
7
8
9

@Test
public void test04(){
Users user = new Users();
user.setUsername("abcde");
user.setPasword("12345");
UserDao bean = ioc.getBean(UserDao.class);
bean.add(user);
}

6、测试结果
在这里插入图片描述
附完整代码(add,delete,change,findAll方法):

ClassUtils.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183

@Component
public class ClassUtils {

@Autowired
private JdbcTemplate jdbcTemplate;


/**
* 获取object的所有get方法
* @return
*/
public List<Method> getAllReadMethod(Object object){
List<Method> method=new ArrayList<Method>();
Class<? extends Object> testClass = object.getClass();
//获得属性
Field[] fields = object.getClass().getDeclaredFields();
for (Field field : fields) {
try {
PropertyDescriptor pd = new PropertyDescriptor(field.getName(), testClass);
//获得get方法
Method getMethod = pd.getReadMethod();
method.add(getMethod);
} catch (IntrospectionException e) {
e.printStackTrace();
}
}
return method;
}

/**
* 得到所有get方法的返回值
* @return
*/
public Object[] getAllMethodName(Object object){
List<Method> allReadMethod = getAllReadMethod(object);
Object [] values=new Object[allReadMethod.size()];
int i=0;
for(Method e:allReadMethod){
try {
Object invoke = e.invoke(object);
String s = invoke.toString();
// System.out.println(s);
values[i]=s;
i++;
} catch (IllegalAccessException e1) {
e1.printStackTrace();
} catch (InvocationTargetException e1) {
e1.printStackTrace();
}
}
return values;
}


public Object[] getAllMethodNameAdd(Object object){
List<Method> allReadMethod = getAllReadMethod(object);
Object [] values=new Object[allReadMethod.size()-1];
int j=0;
for(int i=1;i<allReadMethod.size();i++){
try {
Object invoke = allReadMethod.get(i).invoke(object);
String s = invoke.toString();
//System.out.println(s);
values[j]=s;
j++;
} catch (IllegalAccessException e1) {
e1.printStackTrace();
} catch (InvocationTargetException e1) {
e1.printStackTrace();
}
}
return values;
}

/**
* 得到类中每个参数的类型
* @param object
*/
// public void getAllMethodType(Object object){
// List<Method> allReadMethod = getAllReadMethod(object);
// int i=0;
// int[] values=new int[allReadMethod.size()];
// for (Method e:allReadMethod){
// Type type = e.getAnnotatedReturnType().getType();
// i++;
// System.out.println(type);
// }
//
// }

/**
* 模板:浏览信息
* @param sql:sql语句
* @param object :类名称
* @return
*/
public List<?> findAll(String sql,Object object){
try {
List<?> query = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(object.getClass()));
return query;
} catch (DataAccessException e) {
e.printStackTrace();
return null;
}
}


/**
* 模板:添加信息
* @param sql
* @param object
*/
public void add(String sql,Object object) {
Object[] allMethodName = getAllMethodNameAdd(object);
jdbcTemplate.update(sql,allMethodName);
}

/**
* 模板:删除信息
* @param sql:sql语句
* @param id:id
*/
public void delete(String sql,int id){
jdbcTemplate.update(sql,id);
}

//测试
public void delete(String sql,String id){
jdbcTemplate.update(sql,id);
}

/**
* 模板:修改信息
* @param sql
* @param object
*/
public void change(String sql,Object object){
Object[] allMethodName = getAllMethodName(object);
Object o=allMethodName[0];
for(int i=0;i<allMethodName.length-1;i++){
allMethodName[i]=allMethodName[i+1];
}
allMethodName[allMethodName.length-1]=o;
//System.out.println(allMethodName.length);
jdbcTemplate.update(sql,allMethodName);
}

/**
* 模板:信息回显
* @param sql
* @param id 用户名称:String
* @return
*/
public Object messageBackLook(String sql,int id,Object object){
try {
Object o = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(object.getClass()), id);
return o;
} catch (DataAccessException e) {
e.printStackTrace();
return null;
}
}


/**
* 信息回显
* @param sql
* @param id 用户id:int
* @return
*/
public Object messageBackLook(String sql,String id,Object object){
try {
Object o = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(object.getClass()), id);
// System.out.println(o);
return o;
} catch (DataAccessException e) {
e.printStackTrace();
return null;
}
}

}

finish!