码迷,mamicode.com
首页 > 数据库 > 详细

基于JSP+Serlvet+JDBC的开发(3)-- Service、DAO层实现

时间:2015-09-13 14:38:12      阅读:272      评论:0      收藏:0      [点我收藏+]

标签:

这里为了使不必在所有Service和DAO都写基础的增删查改,我写了两个基类接口,BaseService和BaseDAO

BaseDAO.java (这里使用了泛型,PK 是主键,T是实体类型),这样其他DAO只要继承这个DAO就可以实现基础增删查改了。

 1 package dao;
 2 
 3 import java.io.Serializable;
 4 import java.util.List;
 5 
 6 /*
 7  * 所有DAO接口继承此接口获取基本的增删查改规范
 8  */
 9 public interface BaseDAO<PK extends Serializable, T> {
10     // 保存实体
11     public void save(T t);
12 
13     // 删除实体
14     public void delete(PK id);
15 
16     // 更新实体
17     public void update(T t);
18 
19     // 根据ID查询实体
20     public T findById(PK id);
21 
22     // 查询所有实体
23     public List<T> find();
24 }

当然只是创建接口是不够的,还要有实现,下面是BaseDAO的实现类。BaseDAOImpl,这里主要利用Java的反射机制,根据泛型动态拼凑SQL脚本,动态生成实体对象。

但是有两点约定,就是数据库表名要以“tb_”+实体类名小写命名。如 Type实体对应的数据库表名tb_type,还有一点就是实体类应该是贫血的Bean,而且主键要以id命名。

当然对于表名和主键名我后续会改为自己创建注解的方式,让其可以动态指定

BaseDAOImpl.java

  1 package dao.impl;
  2 
  3 import java.beans.PropertyDescriptor;
  4 import java.io.Serializable;
  5 import java.lang.reflect.Field;
  6 import java.lang.reflect.Method;
  7 import java.lang.reflect.ParameterizedType;
  8 import java.sql.Connection;
  9 import java.sql.PreparedStatement;
 10 import java.sql.ResultSet;
 11 import java.sql.SQLException;
 12 import java.sql.Statement;
 13 import java.util.ArrayList;
 14 import java.util.List;
 15 
 16 import dao.BaseDAO;
 17 import util.DBUtil;
 18 import util.LogUtil;
 19 
 20 @SuppressWarnings("rawtypes")
 21 public class BaseDAOImpl<PK extends Serializable, T> implements BaseDAO<PK, T> {
 22 
 23     protected Connection conn = null;
 24     protected PreparedStatement pstmt = null;
 25     protected Statement stmt = null;
 26     protected ResultSet rs = null;
 27 
 28     // 泛化类
 29     private Class clazz = null;
 30     // 基本类型包装类
 31     private String[] baseType = { "Byte", "Short", "Char", "Integer", "Long", "Float", "Double", "Boolean" };
 32 
 33     public BaseDAOImpl() {
 34         // 获取参数类型信息
 35         ParameterizedType paramType = (ParameterizedType) this.getClass().getGenericSuperclass();
 36         clazz = (Class) paramType.getActualTypeArguments()[1];
 37     }
 38 
 39     @Override
 40     public void save(T t) {
 41         // 获取类的所有属性
 42         Field[] fields = t.getClass().getDeclaredFields();
 43         // 拼凑SQL语句
 44         StringBuffer insertSQL = new StringBuffer("insert into tb_").append(t.getClass().getSimpleName().toLowerCase())
 45                 .append(" (");
 46         for (int i = 0; i < fields.length - 1; i++) {
 47             insertSQL = insertSQL.append(fields[i].getName()).append(",");
 48         }
 49         insertSQL = insertSQL.append(fields[fields.length - 1].getName()).append(") values(");
 50         for (int i = 0; i < fields.length - 1; i++) {
 51             insertSQL = insertSQL.append("? ,");
 52         }
 53         insertSQL = insertSQL.append("?)");
 54 
 55         // 打印日志
 56         LogUtil.log(insertSQL.toString());
 57 
 58         try {
 59             conn = DBUtil.getConn();
 60             pstmt = conn.prepareStatement(insertSQL.toString());
 61             for (int i = 0; i < fields.length; i++) {
 62                 // 设置参数
 63                 pstmt.setObject(i + 1,
 64                         t.getClass()
 65                                 .getMethod(// 获取t对象的getter方法并调用
 66                                         "get" + fields[i].getName().substring(0, 1).toUpperCase()
 67                                                 + fields[i].getName().substring(1).toLowerCase())
 68                                 .invoke(t, null));
 69             }
 70             pstmt.executeUpdate();
 71         } catch (Exception e) {
 72             LogUtil.log(e.getMessage());
 73             throw new RuntimeException(e);
 74         } finally {
 75             try {
 76                 if (pstmt != null) {
 77                     pstmt.close();
 78                 }
 79                 if (conn != null) {
 80                     conn.close();
 81                 }
 82             } catch (SQLException e) {
 83                 LogUtil.log(e.getMessage());
 84                 throw new RuntimeException(e);
 85             }
 86         }
 87     }
 88 
 89     @Override
 90     public void delete(PK id) {
 91         StringBuffer deleteSQL = new StringBuffer("delete from tb_").append(clazz.getSimpleName().toLowerCase())
 92                 .append(" where id = ").append(id);
 93 
 94         // 打印日志
 95         LogUtil.log(deleteSQL.toString());
 96         try {
 97             conn = DBUtil.getConn();
 98             stmt = conn.createStatement();
 99             stmt.executeUpdate(deleteSQL.toString());
100         } catch (SQLException e) {
101             LogUtil.log(e.getMessage());
102             throw new RuntimeException(e);
103         } finally {
104             try {
105                 if (stmt != null) {
106                     stmt.close();
107                 }
108                 if (conn != null) {
109                     conn.close();
110                 }
111             } catch (SQLException e) {
112                 LogUtil.log(e.getMessage());
113                 throw new RuntimeException(e);
114             }
115         }
116     }
117 
118     @Override
119     public void update(T t) {
120         // 获取类的所有属性
121         Field[] fields = t.getClass().getDeclaredFields();
122         // 平凑SQL语句
123         StringBuffer updateSQL = new StringBuffer("update tb_").append(t.getClass().getSimpleName().toLowerCase());
124 
125         for (int i = 1; i < fields.length - 1; i++) {
126             updateSQL = updateSQL.append(" set ").append(fields[i].getName()).append(" = ?,");
127         }
128         
129         try {
130             updateSQL = updateSQL.append(" set ").append(fields[fields.length - 1].getName()).append(" = ?")
131                     .append(" where id = ")
132                     .append(t.getClass()
133                             .getMethod(// 获取t对象的getter方法并调用
134                                     "get" + fields[0].getName().substring(0, 1).toUpperCase()
135                                             + fields[0].getName().substring(1).toLowerCase())
136                             .invoke(t, null).toString());
137             // 打印日志
138             LogUtil.log(updateSQL.toString());
139 
140             conn = DBUtil.getConn();
141             pstmt = conn.prepareStatement(updateSQL.toString());
142             for (int i = 1; i < fields.length; i++) {
143                 // 设置参数
144                 pstmt.setObject(i,
145                         t.getClass()
146                                 .getMethod(// 获取t对象的getter方法并调用
147                                         "get" + fields[i].getName().substring(0, 1).toUpperCase()
148                                                 + fields[i].getName().substring(1).toLowerCase())
149                                 .invoke(t, null));
150             }
151             int i = pstmt.executeUpdate();
152         } catch (Exception e) {
153             LogUtil.log(e.getMessage());
154             throw new RuntimeException(e);
155         } finally {
156             try {
157                 if (pstmt != null) {
158                     pstmt.close();
159                 }
160                 if (conn != null) {
161                     conn.close();
162                 }
163             } catch (SQLException e) {
164                 LogUtil.log(e.getMessage());
165                 throw new RuntimeException(e);
166             }
167         }
168     }
169 
170     @Override
171     public T findById(PK id) {
172         StringBuffer findSQL = new StringBuffer("select * from tb_").append(clazz.getSimpleName().toLowerCase())
173                 .append(" where id = ").append(id);
174         // 打印日志
175         LogUtil.log(findSQL.toString());
176         T t = null;
177         Method m = null;
178         PropertyDescriptor pd = null;
179         boolean isBaseType = false;
180         try {
181             conn = DBUtil.getConn();
182             stmt = conn.createStatement();
183             rs = stmt.executeQuery(findSQL.toString());
184             if (rs.next()) {
185                 // 创建实体对象
186                 t = (T) clazz.newInstance();
187                 Field[] fields = clazz.getDeclaredFields();
188                 for (int i = 0; i < fields.length; i++) {
189                     // 利用反射为对象设置属性
190                     pd = new PropertyDescriptor(fields[i].getName(), t.getClass());
191                     fields[i].setAccessible(false);
192                     m = pd.getWriteMethod();
193                     String type = fields[i].getType().toString()
194                             .substring(fields[i].getType().toString().lastIndexOf(".") + 1);
195                     isBaseType = false;
196                     for (int j = 0; j < baseType.length; j++) {
197                         if (baseType[j].equals(type)) {
198                             // 根据基本类型为属性设置值
199                             invoke4BaseType(t, m, rs, i + 1, j);
200                             isBaseType = true;
201                             break;
202                         }
203                     }
204                     if (!isBaseType) {
205                         m.invoke(t, rs.getObject(i + 1));
206                     }
207                 }
208             }
209         } catch (Exception e) {
210             LogUtil.log(e.getMessage());
211             throw new RuntimeException(e);
212         } finally {
213             try {
214                 if (stmt != null) {
215                     stmt.close();
216                 }
217                 if (conn != null) {
218                     conn.close();
219                 }
220             } catch (SQLException e) {
221                 LogUtil.log(e.getMessage());
222                 throw new RuntimeException(e);
223             }
224         }
225         return t;
226     }
227 
228     @Override
229     public List<T> find() {
230         List<T> ts = new ArrayList<T>();
231         StringBuffer findSQL = new StringBuffer("select * from tb_").append(clazz.getSimpleName().toLowerCase());
232 
233         // 打印日志
234         LogUtil.log(findSQL.toString());
235         T t = null;
236         Method m = null;
237         PropertyDescriptor pd = null;
238         boolean isBaseType = false;
239         try {
240             conn = DBUtil.getConn();
241             stmt = conn.createStatement();
242             rs = stmt.executeQuery(findSQL.toString());
243             while (rs.next()) {
244                 // 创建实体对象
245                 t = (T) clazz.newInstance();
246                 Field[] fields = clazz.getDeclaredFields();
247                 for (int i = 0; i < fields.length; i++) {
248                     // 利用反射为对象设置属性
249                     pd = new PropertyDescriptor(fields[i].getName(), t.getClass());
250                     fields[i].setAccessible(false);
251                     m = pd.getWriteMethod();
252                     String type = fields[i].getType().toString()
253                             .substring(fields[i].getType().toString().lastIndexOf(".") + 1);
254                     isBaseType = false;
255                     for (int j = 0; j < baseType.length; j++) {
256                         if (baseType[j].equals(type)) {
257                             // 根据基本类型为属性设置值
258                             invoke4BaseType(t, m, rs, i + 1, j);
259                             isBaseType = true;
260                             break;
261                         }
262                     }
263                     if (!isBaseType) {
264                         m.invoke(t, rs.getObject(i + 1));
265                     }
266                 }
267                 ts.add(t);
268             }
269         } catch (Exception e) {
270             LogUtil.log(e.getMessage());
271             throw new RuntimeException(e);
272         } finally {
273             try {
274                 if (stmt != null) {
275                     stmt.close();
276                 }
277                 if (conn != null) {
278                     conn.close();
279                 }
280             } catch (SQLException e) {
281                 LogUtil.log(e.getMessage());
282                 throw new RuntimeException(e);
283             }
284         }
285         return ts;
286     }
287 
288     /*
289      * 根据基本类型为对象设置属性
290      */
291     private void invoke4BaseType(Object obj, Method m, ResultSet rs, int columnIndex, int typeIndex) throws Exception {
292         // "Byte", "Short", "Character", "Integer",
293         // "Long", "Float", "Double","Boolean"
294         switch (typeIndex) {
295         case 0:
296             m.invoke(obj, rs.getByte(columnIndex));
297             break;
298         case 1:
299             m.invoke(obj, rs.getShort(columnIndex));
300             break;
301         case 2:
302             m.invoke(obj, rs.getString(columnIndex).charAt(0));
303             break;
304         case 3:
305             m.invoke(obj, rs.getInt(columnIndex));
306             break;
307         case 4:
308             m.invoke(obj, rs.getLong(columnIndex));
309             break;
310         case 5:
311             m.invoke(obj, rs.getFloat(columnIndex));
312             break;
313         case 6:
314             m.invoke(obj, rs.getDouble(columnIndex));
315             break;
316         case 7:
317             m.invoke(obj, rs.getBoolean(columnIndex));
318             break;
319         default:
320             m.invoke(m, rs.getObject(columnIndex));
321         }
322     }
323 }

这里我将Connection这些变量声明成protected方便子类使用。

这里还用到了两个工具类,DBUtil(数据库工具类)、LogUtil(日志记录类)

DBUtil.java

 1 package util;
 2 
 3 import java.sql.Connection;
 4 import java.sql.DriverManager;
 5 
 6 public class DBUtil {
 7 
 8     private static final String URL = "jdbc:mysql:///mybatis";
 9     private static final String USERNAME = "root";
10     private static final String PASSWORD = "root";
11     private static Connection conn = null;
12     
13     private DBUtil() {
14     }
15 
16     public static Connection getConn() {
17         try {
18             Class.forName("com.mysql.jdbc.Driver");
19             conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);
20         } catch (Exception e) {
21             LogUtil.log(e.getMessage());
22             throw new RuntimeException(e);
23         }
24         return conn;
25     }
26 }

LogUtil.java (这里我有个习惯就是有异常的时候一定要记录日志,说句不好听的话,死也要知道自己是怎么死的吧? )

 1 package util;
 2 
 3 import java.text.SimpleDateFormat;
 4 import java.util.Date;
 5 
 6 public class LogUtil {
 7 
 8     private LogUtil(){}
 9     
10     public static void log(String... str) {
11         SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
12 
13         StringBuffer sb = new StringBuffer("--- ").append(format.format(new Date())).append(" [")
14                 .append(Thread.currentThread().getName()).append("] --- ");
15         for (int i = 0; i < str.length; i++) {
16             sb = sb.append(str[i]).append(" ");
17         }
18         System.out.println(sb.toString());
19     }
20 }

利用LogUtil工具就可以看到日志信息了:--- 2015-09-13 13:21:48 [http-80-1] --- select * from tb_type 

这里只是简单的打印出来而已,并没有像Log4j等开源框架一样有多种选择。

至此BaseBAO就完成了。接下来是BaseService。BaseService比较简单,由于这里的业务逻辑也比较简单,所有之间调用DAO就行了。

BaseService.java

 1 package service;
 2 
 3 import java.io.Serializable;
 4 import java.util.List;
 5 /*
 6  * 所有Serivce接口继承此接口获取基本的增删查改规范
 7  */
 8 public interface BaseServcice<PK extends Serializable, T> {
 9     // 保存实体
10     public void save(T t);
11 
12     // 删除实体
13     public void delete(PK id);
14 
15     // 更新实体
16     public void update(T t);
17 
18     // 根据ID查询实体
19     public T findById(PK id);
20 
21     // 查询所有实体
22     public List<T> find();
23 }

BaseService的实现类——BaseServiceImpl

BaseServiceImpl.java

 1 package service.impl;
 2 
 3 import java.io.Serializable;
 4 import java.util.List;
 5 
 6 import dao.BaseDAO;
 7 import service.BaseServcice;
 8 
 9 public abstract class BaseServiceImpl<PK extends Serializable, T> implements BaseServcice<PK, T> {
10 
11     // 子类必须实现该方法提供对应的DAO
12     protected abstract BaseDAO<PK, T> getBaseDAO();
13 
14     @Override
15     public void save(T t) {
16         getBaseDAO().save(t);
17     }
18 
19     @Override
20     public void delete(PK id) {
21         getBaseDAO().delete(id);
22     }
23 
24     @Override
25     public void update(T t) {
26         getBaseDAO().update(t);
27     }
28 
29     @Override
30     public T findById(PK id) {
31         return getBaseDAO().findById(id);
32     }
33 
34     @Override
35     public List<T> find() {
36         return getBaseDAO().find();
37     }
38 }

值得注意的是BaseServiceImpl是一个抽象类,继承此类的子类需要实现抽象方法,并提供直接或间接继承BaseDAO的子类对象供BaseServiceImpl使用。

至此BaseDAO和BaseService都完成了。

接下来就是完成自己想要的TypeService了,TypeService直接继承BaseService并提供自己的主键类型和实体类型就可以了。

TypeService.java

1 public interface TypeService extends BaseServcice<Long, Type>{
2 }

TypeService的实现TypeServiceImpl,TypeServiceImp继承BaseServiceImpl并实现自己的接口,然后提供自己的DAO就可以了。

TypeServiceImpl

 1 package service.impl;
 2 
 3 import dao.BaseDAO;
 4 import dao.TypeDAO;
 5 import dao.impl.TypeDAOImpl;
 6 import model.Type;
 7 import service.TypeService;
 8 
 9 public class TypeServiceImpl extends BaseServiceImpl<Long, Type>implements TypeService {
10 
11     private TypeDAO typeDAO = new TypeDAOImpl();
12     
13     // 提供必要的DAO
14     @Override
15     protected BaseDAO<Long, Type> getBaseDAO() {
16         return typeDAO;
17     }
18 }

TypeDAO和TypeDAOImpl跟Service层类型。

1 public interface TypeDAO extends BaseDAO<Long, Type>{
2 }
1 public class TypeDAOImpl extends BaseDAOImpl<Long, Type> implements TypeDAO{
2 }

这样就方便很多了,就不用每个DAO都去重复的写增删查改操作了。

基于JSP+Serlvet+JDBC的开发(3)-- Service、DAO层实现

标签:

原文地址:http://www.cnblogs.com/itc10/p/4804882.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!