1.三层架构:
1.1.三层架构包括什么及职责:
- 1.界面层(User Interface layer):
- 主要功能是接受用户的数据,显示请求的处理结果。
- 使用 web 页面和用户交互,手机 app 也就是表示层的,用户在 app 中操作,业务逻辑在服务器端处理。
- 2.业务逻辑层(Business Logic Layer)
接收表示传递过来的数据,检查数据,计算业务逻辑
,调用数据访问层获取数据
- 3.数据访问层(Data access layer):
- 与数据库打交道。实现对数据的增、删、改、查。
将存储在数据库中的数据提交给业务层,同时将业务层处理的数据保存到数据库.
- 与数据库打交道。实现对数据的增、删、改、查。
1.2.三层架构对应的包
- 1.界面层:controller包(servlet)
- 2.业务逻辑层:service包(XXXService类)
- 3.数据访问层:dao包(XXXDao类)
1.3.为什么要使用三层?
- 1.结构清晰、耦合度低, 各层分工明确
- 2.可维护性高,可扩展性高
- 3.有利于标准化
- 4.开发人员可以只关注整个结构中的其中某一层的功能实现
- 5.有利于各层逻辑的复用
1.4.三层类中的交互
- 1.用户使用
界面层→业务逻辑层→数据访问层(持久层)→数据库(mysql)
1.5.三层架构对应的处理框架
- 1.界面层–servlet–
springmvc
(框架) - 2.业务逻辑层–service类–
spring
(框架) - 3.数据访问层–dao类–
mybatis
(框架)
2.SSM框架介绍:
2.1.MyBatis 框架:
- 1.MyBatis 是一个优秀的基于 java 的持久层框架,
内部封装了 jdbc,开发者只需要关注 sql 语句本身,而不需要处理加载驱动、创建连接、创建 statement、关闭连接,资源等繁杂的过程
; - 2.MyBatis
通过 xml 或注解
两种方式将要执行的各种 sql 语句配置起来,并通过 java 对象和 sql 的动态参数进行映射生成最终执行的 sql 语句,最后由 mybatis 框架执行 sql 并将结果映射为 java 对象并返回;
2.2.Spring 框架:
a.概述:
- 1.Spring 框架为了解决软件开发的复杂性而创建的。
- 2.Spring
使用的是基本的 JavaBean 来完成以前非常复杂的企业级开发
。Spring 解决了业务对象,功能模块之间的耦合,不仅在 javase,web 中使用, 大部分 Java 应用都可以从 Spring 中受益; - 3.Spring
是一个轻量级控制反转(IoC)和面向切面(AOP)的容器
;
b.Spring 学习的核心内容:
- 1.Spring 核心学习内容 IOC、AOP, jdbcTemplate, 声明式事务
- IOC: 控制反转 , 管理 java 对象与对象之间的关系
- AOP : 切面编程
- JDBCTemplate : 是 spring 提供一套访问数据库的技术, 应用性强,相对好理解
- 声明式事务: 基于 ioc/aop 实现事务管理
2.3.SpringMVC 框架:
- 1.Spring MVC 属于 SpringFrameWork 3.0 版本加入的一个模块,
为 Spring 框架提供了构建 Web 应用程序的能力
。 - 2.现在可以 Spring 框架提供的 SpringMVC 模块实现 web 应用开发,在 web 项目中可以无缝使用 Spring 和 Spring MVC 框架
3.传统开发模式分析:
3.1.案例1:
a.代码:
- 1.
UserController.java
package com.powernode.oa.controller;
import com.powernode.oa.service.UserService;
import com.powernode.oa.service.impl.UserServiceImpl;
public class UserController {
private UserService userService = new UserServiceImpl();
public void login(){
String username = "admin";
String password = "123456";
boolean success = userService.login(username, password);
if (success) {
// 登录成功
} else {
// 登录失败
}
}
}
- 2.
UserServiceImpl.java
package com.powernode.oa.service.impl;
import com.powernode.oa.bean.User;
import com.powernode.oa.dao.UserDao;
import com.powernode.oa.dao.impl.UserDaoImplForMySQL;
import com.powernode.oa.service.UserService;
public class UserServiceImpl implements UserService {
private UserDao userDao = new UserDaoImplForMySQL();
public boolean login(String username, String password) {
User user = userDao.selectByUsernameAndPassword(username, password);
if (user != null) {
return true;
}
return false;
}
}
- 3.
UserDaoImplForMySQL.java
package com.powernode.oa.dao.impl;
import com.powernode.oa.bean.User;
import com.powernode.oa.dao.UserDao;
public class UserDaoImplForMySQL implements UserDao {
public User selectByUsernameAndPassword(String username, String password) {
// 连接MySQL数据库,根据用户名和密码查询用户信息
return null;
}
}
b.问题:
- 1.可以看出:
UserDaoImplForMySQL中主要是连接MySQL数据库进行操作。如果更换到Oracle数据库上,则需要再提供一个UserDaoImplForOracle.java,如下:
package com.powernode.oa.dao.impl;
import com.powernode.oa.bean.User;
import com.powernode.oa.dao.UserDao;
public class UserDaoImplForOracle implements UserDao {
public User selectByUsernameAndPassword(String username, String password) {
// 连接Oracle数据库,根据用户名和密码查询用户信息
return null;
}
}
- 2.以上的操作正在进行功能的扩展,添加了一个新的类
UserDaoImplForOracle
来应付数据库的变化,这里的变化会引起连锁反应,如果想要切换到Oracle数据库上,UserServiceImpl类代码就需要修改,如下:UserServiceImpl.java
:
package com.powernode.oa.service.impl;
import com.powernode.oa.bean.User;
import com.powernode.oa.dao.UserDao;
import com.powernode.oa.dao.impl.UserDaoImplForOracle;
import com.powernode.oa.service.UserService;
public class UserServiceImpl implements UserService {
//private UserDao userDao = new UserDaoImplForMySQL();
private UserDao userDao = new UserDaoImplForOracle();
public boolean login(String username, String password) {
User user = userDao.selectByUsernameAndPassword(username, password);
if (user != null) {
return true;
}
return false;
}
}
正常运行的代码,进行了修改,修改后影响了原有的代码模块,那么这就需要进行单元测试好多地方。这就
违背了OCP开闭原则
3.2.案例2:传统Javaweb开发代码分析:
a.代码实现如下:
b.问题分析与解决:
b1.问题1与解决方式:
- 1.问题1:
层与层之间紧密耦合在一起,接口与具体实现紧密耦合在一起
- 2.解决办法:程序代码中不要手动new对象,
第三方根据要求为程序提供需要的Bean对象
b2.问题2分析与解决:
- 1.问题2.通用的事务功能耦合在业务代码中
通用的日志功能耦合在业务代码中
:
- 2.解决方法:程序代码中不要手动new对象,第三方根据要求为程序提供需要的Bean对象的代理对象,
代理对象内部动态结合业务和通用功能
4.程序开发原则:
4.1.OCP开闭原则:
a.什么是OCP开闭原则:
- 1.OCP开闭原则是软件设计中最基本的一个原则
- 在软件开发过程中应当对扩展开放,
- 对修改关闭
b.OCP开闭原则的核心:
- 1.OCP开闭原则的
核心
是:在扩展系统功能的时候,没有修改之前写好的代码,这就符合OCP原则
- 进行功能扩展的时候,添加额外的类是没问题的,但
因为功能扩展而修改之前运行正常的程序,这是忌讳的,不被允许的
。因为一旦修改之前运行正常的程序,就会导致项目整体要进行全方位的重新测试。这是相当麻烦的过程。
c.上述代码问题分析:
- 1.根据上面案例2代码的变化:这样一来就违背了开闭原则OCP
- 可以很明显的看出,上层是依赖下层的。UserController依赖UserServiceImpl,而UserServiceImpl依赖UserDaoImplForMySQL,这样就会导致下面只要改动,上面必然会受牵连(跟着也会改)
- 所谓牵一发而动全身。这样也就
同时违背了另一个开发原则:依赖倒置原则
- 2.
导致以上问题的主要原因是:代码和代码之间的耦合度太高
。如下图所示:
4.2.依赖倒置原则DIP:
a.依赖倒置原则概述:
- 1.依赖倒置原则(Dependence Inversion Principle),简称
DIP
:- DIP主要
倡导面向抽象编程,面向接口编程,不要面向具体编程
,让上层不再依赖下层,下面改动了,上面的代码不会受到牵连。 - 依赖倒置的目的可以大大降低程序的耦合度,耦合度低了,扩展力就强了,同时代码复用性也会增强。(
软件七大开发原则都是在为解耦合服务
)
- DIP主要
- 2.上面代码我们虽然可以看出是面向接口编程了,但是
对象的创建new UserDaoImplForOracle()显然并没有完全面向接口编程
,还是使用到了具体的接口实现类
b.什么叫做完全面向接口编程?什么叫做完全符合依赖倒置原则呢?
- 1.分析以下代码来看什么叫完全面向接口编程:
- 1.如果代码是这样编写的,才算是完全面向接口编程,才符合依赖倒置原则。那你可能会问,
这样userDao是null,在执行的时候就会出现空指针异常呀
。也确实是这样的,所以我们要解决这个问题。解决空指针异常的问题,其实就是解决两个核心的问题:- 第一个问题:
谁来负责对象的创建
。【也就是说谁来:new UserDaoImplForOracle()/new UserDaoImplForMySQL()
】 - 第二个问题:
谁来负责把创建的对象赋到这个属性上
。【也就是说谁来把上面创建的对象赋给userDao属性
】
- 第一个问题:
- 2.如果我们把以上两个核心问题解决了,就可以做到既符合OCP开闭原则,又符合依赖倒置原则。这些Spring框架可以做到。
在Spring框架中,它可以帮助我们new对象,并且它还可以将new出来的对象赋到属性上
。- 换句话说,
Spring框架可以帮助我们创建对象,并且可以帮助我们维护对象和对象之间的关系
。比如:
- 3.Spring可以new出来UserDaoImplForMySQL对象,也可以new出来UserDaoImplForOracle对象,并且还可以让new出来的dao对象和service对象产生关系(
产生关系其实本质上就是给属性赋值
)。
如上这种思想将对象的创建权/管理权交出去了,不再使用硬编码的方式了。同时也把对象关系的管理权交出去了,也不再使用硬编码的方式了。
像这种把对象的创建权交出去,把对象关系的管理权交出去,被称为控制反转