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

这里为了使不必在所有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都去重复的写增删查改操作了。

时间: 2024-10-05 01:39:34

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

基于JSP+Serlvet+JDBC的开发(1)

好久没用JSP+Servlet+JDBC这种组合,可以说自从没有这种作业后就没有这种方式开发了.最近也没怎么学东西,感觉计划都乱了,趁着这个周末写点东西找找感觉. 这次想利用JSP+Servlet+JDBC写个小小的商品展示平台DEMO.功能很简单,就是能够展示商品的类型,然后根据类型展示所属类型的商品就可以了,说是小小的商品展示平台还不如说是一个增删查改的DEMO. 下图是整个项目的结构: 为了方便解耦,使用MVC模式进行开发,这里介绍各个包的作用: action 存放的servlet类,负责

基于JSP+Serlvet+JDBC的开发(2)- Servlet类的实现

上一篇我把项目的整个结构搭好了,这里写一下Servlet的实现. 利用Servlet开发有一个弊端就是每一个请求URL都要有对应的Servlet与之对应,但是这样会造成Servlet臃肿,在web.xml中也会出现一大堆Servlet配置信息.为了解决这个问题,我这里利用给Servlet传一个action参数来使一个Servlet处理一类请求. 具体实现如下: 在Serlvet中创建一个数组,记录所有请求这个Servlet的操作, 1 private static final String[]

基于JSP+Serlvet+JDBC的开发(5)-- 商品功能

在type-index.jsp中点击商品类型可以进入到该商品类型的所有商品.   商品类型为ITC10的商品信息 View层: goods-index.jsp 1 <html> 2 <head> 3 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 4 <%@ include file="top.jsp"%> 5

基于JSP+Serlvet+JDBC的开发(4)-- 继续TypeSerlvet的save功能

在type-index.jsp中展示了所有类型,同时也可以添加类型,如下JSP代码: 1 <html> 2 <head> 3 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 4 <%@ include file="top.jsp"%> 5 <title>商品展示平台</title> 6 &

java -------简单的基于jsp+servlet+jdbc登录

1 2 项目结构以及数据库表图片 3 4 5 package com.jmi.booklibmanage.service; 6 7 import java.sql.Connection; 8 import java.sql.DriverManager; 9 import java.sql.ResultSet; 10 import java.sql.SQLException; 11 import java.sql.Statement; 12 13 14 15 public class Studen

基于JSP的病历管理系统开发与设计,源码下载

大家好,我是全微毕设团队的创始人,本团队擅长JAVA(SSM,SSH,SPRINGBOOT).PYTHON.PHP.C#.安卓等多项技术. 今天将为大家分析一个病历管理系统(指出传统病案管理模式存在的问题,从新旧病案归档整理.电子病案的使用等方面介绍电子病案管理系统的实施,阐明实施电子病案管理的意义,包括节省存储空间,提高检索效率.病案质量与规范管理等.),该项目使用框架为SSM(MYECLIPSE),选用开发工具为MYECLIPSE.病历管理系统为一个 后台项目. 为了完成该系统,我们首先需要

JSP+Servlet+JDBC+Mysql实现的博客系统

本文存在视频版本,请知悉 项目简介 项目来源于:https://gitee.com/nanpingping/jsp-blog 这次分享个人博客系统,界面简洁大气,功能齐全,是不可多得的比较容易的系统,非常适合毕业设计或者课程设计. 本系统基于JSP+Servlet+JDBC+Mysql.涉及技术少,易于理解,适合JavaWeb初学者学习使用. 难度等级:简单 技术栈 编辑器 IntelliJ IDEA 2019.1.1 (Ultimate Edition) 前端技术 基础:html+css+Ja

JSP+Struts2+JDBC+Mysql实现的校园宿舍管理系统

项目简介 项目来源于:https://gitee.com/passenger134/javaweb-sushe 本系统基于JSP+Struts2+JDBC+Mysql的校园宿舍管理系统.该系统没有使用全套的SSH框架,只使用了跳转层Struts2,非常适合学习Struts2时使用. 难度等级:中等 技术栈 编辑器 Eclipse Version: 2019-12 (4.14.0) 前端技术 基础:html+css+JavaScript 框架:无 后端技术 JSP+Struts2+JDBC 数据库

ssh_maven的搭建之dao层的开发

之前都是使用我们传统的方式进行引入jar包,现在我们使用maven进行管理依赖,这样,我们的jar就不需要我们进行管理,而且,我们的maven还可以进行项目构建,一个项目从编写源代码到编译,测试,运行,打包,部署的过程,只需要对应的一个命令即可以了,方便了很多 这里,我们直接进入主题,像eclipse中怎么配置maven等这里我们暂时不说,直接从创建项目开始,而且我们采用的是纯配置文件的方式 我们可以看一下我们的目录结构 这咯我们的ssh_parent是父工程,而剩下的都是它的子模块 这里我们的