16.1 场景问题
16.1.1 登录控制
几乎所有的应用系统,都需要系统登录控制的功能,有些系统甚至有多个登录控制的功能,比如:普通用户可以登录前台,进行相应的业务操作;而工作人员可以登录后台,进行相应的系统管理或业务处理。
现在有这么一个基于Web的企业级应用系统,需要实现这两种登录控制,直接使用不同的登录页面来区分它们,把基本的功能需求分别描述如下:
先看看普通用户登录前台的登录控制的功能:
- 前台页面:用户能输入用户名和密码;提交登录请求,让系统去进行登录控制
- 后台:从数据库获取登录人员的信息
- 后台:判断从前台传递过来的登录数据,和数据库中已有的数据是否匹配
- 前台Action:如果匹配就转向首页,如果不匹配就返回到登录页面,并显示错误提示信息
再来看看工作人员登录后台的登录控制功能:
- 前台页面:用户能输入用户名和密码;提交登录请求,让系统去进行登录控制
- 后台:从数据库获取登录人员的信息
- 后台:把从前台传递过来的密码数据,使用相应的加密算法进行加密运算,得到加密后的密码数据
- 后台:判断从前台传递过来的用户名和加密后的密码数据,和数据库中已有的数据是否匹配
- 前台Action:如果匹配就转向首页,如果不匹配就返回到登录页面,并显示错误提示信息
说明:普通用户和工作人员在数据库里面是存储在不同表里面的;当然也是不同的模块来维护普通用户的数据和工作人员的数据;另外工作人员的密码是加密存放的。
16.1.2 不用模式的解决方案
由于普通用户登录和工作人员登录是不同的模块,有不同的页面,不同的逻辑处理,不同的数据存储,因此,在实现上完全当成两个独立的小模块去完成了。这里把它们的逻辑处理部分分别实现出来。
(1)先看普通用户登录的逻辑处理部分,示例代码如下:
/** * 普通用户登录控制的逻辑处理 */ public class NormalLogin { /** * 判断登录数据是否正确,也就是是否能登录成功 * @param lm 封装登录数据的Model * @return true表示登录成功,false表示登录失败 */ public boolean login(LoginModel lm) { //1:从数据库获取登录人员的信息,就是根据用户编号去获取人员的数据 UserModel um = this.findUserByUserId(lm.getUserId()); //2:判断从前台传递过来的登录数据,和数据库中已有的数据是否匹配 //先判断用户是否存在,如果um为null,说明用户肯定不存在 //但是不为null,用户不一定存在,因为数据层可能返回new UserModel(); //因此还需要做进一步的判断 if (um != null) { //如果用户存在,检查用户编号和密码是否匹配 if (um.getUserId().equals(lm.getUserId()) && um.getPwd().equals(lm.getPwd())) { return true; } } return false; } /** * 根据用户编号获取用户的详细信息 * @param userId 用户编号 * @return 对应的用户的详细信息 */ private UserModel findUserByUserId(String userId) { // 这里省略具体的处理,仅做示意,返回一个有默认数据的对象 UserModel um = new UserModel(); um.setUserId(userId); um.setName("test"); um.setPwd("test"); um.setUuid("User0001"); return um; } } |
对应的LoginModel,示例代码如下:
/** * 描述登录人员登录时填写的信息的数据模型 */ public class LoginModel { private String userId,pwd; public String getUserId() { return userId; } public void setUserId(String userId) { this.userId = userId; } public String getPwd() { return pwd; } public void setPwd(String pwd) { this.pwd = pwd; } } |
对应的UserModel,示例代码如下:
/** * 描述用户信息的数据模型 */ public class UserModel { private String uuid,userId,pwd,name; public String getUuid() { return uuid; } public void setUuid(String uuid) { this.uuid = uuid; } public String getUserId() { return userId; } public void setUserId(String userId) { this.userId = userId; } public String getPwd() { return pwd; } public void setPwd(String pwd) { this.pwd = pwd; } public String getName() { return name; } public void setName(String name) { this.name = name; } } |
(2)再看看工作人员登录的逻辑处理部分,示例代码如下:
/** * 工作人员登录控制的逻辑处理 */ public class WorkerLogin { /** * 判断登录数据是否正确,也就是是否能登录成功 * @param lm 封装登录数据的Model * @return true表示登录成功,false表示登录失败 */ public boolean login(LoginModel lm) { //1:根据工作人员编号去获取工作人员的数据 WorkerModel wm = findWorkerByWorkerId(lm.getWorkerId()); //2:判断从前台传递过来的用户名和加密后的密码数据, //和数据库中已有的数据是否匹配 //先判断工作人员是否存在,如果wm为null,说明工作人员肯定不存在 //但是不为null,工作人员不一定存在, //因为数据层可能返回new WorkerModel();因此还需要做进一步的判断 if (wm != null) { //3:把从前台传来的密码数据,使用相应的加密算法进行加密运算 String encryptPwd = this.encryptPwd(lm.getPwd()); //如果工作人员存在,检查工作人员编号和密码是否匹配 if (wm.getWorkerId().equals(lm.getWorkerId()) && wm.getPwd().equals(encryptPwd)) { return true; } } return false; } /** * 对密码数据进行加密 * @param pwd 密码数据 * @return 加密后的密码数据 */ private String encryptPwd(String pwd){ //这里对密码进行加密,省略了 return pwd; } /** * 根据工作人员编号获取工作人员的详细信息 * @param workerId 工作人员编号 * @return 对应的工作人员的详细信息 */ private WorkerModel findWorkerByWorkerId(String workerId) { // 这里省略具体的处理,仅做示意,返回一个有默认数据的对象 WorkerModel wm = new WorkerModel(); wm.setWorkerId(workerId); wm.setName("Worker1"); wm.setPwd("worker1"); wm.setUuid("Worker0001"); return wm; } } |
对应的LoginModel,示例代码如下:
/** * 描述登录人员登录时填写的信息的数据模型 */ public class LoginModel{ private String workerId,pwd; public String getWorkerId() { return workerId; } public void setWorkerId(String workerId) { this.workerId = workerId; } public String getPwd() { return pwd; } public void setPwd(String pwd) { this.pwd = pwd; } } |
对应的WorkerModel,示例代码如下:
/** * 描述工作人员信息的数据模型 */ public class WorkerModel { private String uuid,workerId,pwd,name; public String getUuid() { return uuid; } public void setUuid(String uuid) { this.uuid = uuid; } public String getWorkerId() { return workerId; } public void setWorkerId(String workerId) { this.workerId = workerId; } public String getPwd() { return pwd; } public void setPwd(String pwd) { this.pwd = pwd; } public String getName() { return name; } public void setName(String name) { this.name = name; } } |
16.1.3 有何问题
看了上面的实现示例,是不是很简单。但是,仔细看看,总会觉得有点问题,两种登录的实现太相似了,现在是完全分开,当作两个独立的模块来实现的,如果今后要扩展功能,比如要添加“控制同一个编号同时只能登录一次”的功能,那么两个模块都需要修改,是很麻烦的。而且,现在的实现中,也有很多相似的地方,显得很重复。另外,具体的实现和判断的步骤混合在一起,不利于今后变换功能,比如要变换加密算法等。
总之,上面的实现,有两个很明显的问题:一是重复或相似代码太多;二是扩展起来很不方便。
那么该怎么解决呢?该如何实现才能让系统既灵活又能简洁的实现需求功能呢?