献血管理系统

总结了好久以前 2016年6月份 的软件项目实践,重点放在设计模式的应用过程。

模型层

饿汉式多例模式实现连接池

Conn 类的数据库连接池参考了单例模式使用了饿汉式多例模式,保证了数据库连接的安全。

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
static ArrayList<Connection>list = new ArrayList<Connection>();
// 获得数据库连接
public synchronized static Connection getConnection(){
Connection con = null;
if(list.size()>0) return list.remove(0);
else{
for(int i=0; i<5; i++){// 最大连接池数量
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
try {
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/ddsystem?user=root&password=root&useUnicode=true&characterEncoding=utf-8");
list.add(con);
} catch (SQLException e) {
e.printStackTrace();
}
}
return list.remove(0);
}
}
// 关闭连接
public synchronized static void close(Connection con){
if(con!=null) list.add(con);
}

封装与SQL交互的方法

将增删改查各个实现方法打包,更新、添加、删除返回 boolean 值,大多数查找结果封装为 Map<String, Object> 且放入 ArrayList 中,方便后续编程获取。

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
   // 新增、修改、删除操作
public boolean updateByParams(String sql, Object param[]){
boolean flag = false;
Connection con = getConnection();
PreparedStatement ps = null;
try {
ps = con.prepareStatement(sql);
if(param!=null){
for(int i=1; i<=param.length; i++)
ps.setObject(i, param[i-1]);
}
int n = ps.executeUpdate();
if(n>0) flag = true;
} catch (SQLException e) {
e.printStackTrace();
} finally{
close(null, ps, con);
}
return flag;
}
// 新增、修改、删除 多条记录(批量处理)
public boolean BatchUpdateByParams(String sql, Object param[][]){
Connection con = getConnection();
PreparedStatement ps = null;
try {
ps = con.prepareStatement(sql);
if(param!=null){
for(int i=0; i<param.length; i++){
for(int j=1; j<=param[i].length; j++){
ps.setObject(j, param[i][j-1]);
}
ps.addBatch();
}
ps.executeBatch();
}
return true;
} catch (SQLException e) {
e.printStackTrace();
return false;
} finally{
close(null, ps, con);
}
}
// 查询
public static List<Map<String, Object>>select(String sql, Object[] param){
//……
}
// 单值返回
public String selectOne(String sql, Object[] param){
//……
}

面向接口编程——依赖倒置原则

后端遵循了依赖倒置原则即面向接口编程。 dao 包中全是接口,真正的接口实现在 impl 包中。

简单工厂模式——迪米特法则

同时也为了遵循迪米特法则,在 dao 包中还配备了简单工厂 DAOFactory,将真正在 impl 包实现接口的类放进去,供控制台调用的只要知道工厂以及接口类型即可调用。

dao&impl

控制层

过滤器解决中文乱码问题

filters 包中有两个过滤器,其中,SetCharacterEncodingFilter 解决中文乱码问题

1
2
3
4
5
   public void doFilter(ServletRequest arg0, ServletResponse arg1,
FilterChain arg2) throws IOException, ServletException
{

arg0.setCharacterEncoding("UTF-8");
arg2.doFilter(arg0, arg1);
}

过滤器解决登陆验证问题和权限分割问题

filters 包中另一个过滤器 LoginValidateFilter 解决了登陆验证问题以及各个子系统权限分割问题。

在权限分割上分为两种,一种直接获取 .jsp,只要判断 jsp 文件所在文件夹为哪个子系统,直接判断权限即可。另一种为 servlet 请求,去除上下文路径,得到关键路径的前缀,如系统管理员的 servletadmin_ 开头,规范化了 servlet 的命名,也方便权限分割。

servlet充分利用get方法精简代码及开发流程

servlet 包中有四个子包,分别对应四个子系统的功能实现。同时,一些诸如登陆、个人信息修改等公用功能将直接放在 servlet 包即可。servlet 的实现也充分利用了 get 方法,以 get 参数的方法来整理相同数据类型的各个操作管理,如设定动作参数为 act,若值为 add 则为添加,值为 update 则为更新等等。极大地减少了 servlet 类,精简了代码以及开发流程。

软件测试

Junit4软件测试:参数化测试、打包测试

使用了 Junit4 进行软件测试,主要测试 db 包,因为数据库连接、执行SQL语句以及数据的处理都在该包中。使用了参数化测试以及打包测试。

1
2
3
4
5
6
7
8
9
10
11
package db;

import org.junit.runner.RunWith;
import org.junit.runners.Suite;

@RunWith(Suite.class) //@RunWith标注传递一个参数 Suite.class
@Suite.SuiteClasses({//@Suite.SuiteClasses,来表明这个类是打包测试类
ConnTest.class,
userDBTest.class
})
public class AllTests {}

总结

该项目用了最简单的 jsp/servlet,重点实践了设计模式软件测试这两部分。

具体代码见:https://coding.net/u/gcusky/p/ddsystem/git

文章目录
  1. 1. 模型层
    1. 1.1. 饿汉式多例模式实现连接池
    2. 1.2. 封装与SQL交互的方法
    3. 1.3. 面向接口编程——依赖倒置原则
    4. 1.4. 简单工厂模式——迪米特法则
  2. 2. 控制层
    1. 2.1. 过滤器解决中文乱码问题
    2. 2.2. 过滤器解决登陆验证问题和权限分割问题
    3. 2.3. servlet充分利用get方法精简代码及开发流程
  3. 3. 软件测试
    1. 3.1. Junit4软件测试:参数化测试、打包测试
  4. 4. 总结

20170116-project-2/

本页二维码