概要
三层架构
三层架构分为:数据(dao)层、 业务(service)层、控制(controller)层
(1)表示层(USL,即User Show Layer):视图层
a. 前台:对应于MVC中的View,用于和用户交互、界面的显示。
b. 对应于MVC中的Controller,用于控制跳转、调用业务逻辑层。
(2)业务逻辑层(BLL,即Business Logic Layer):Service层
a. 接收表示层的请求及调用
b. 组装数据访问层
(3)数据访问层(DAL,即Data Access Layer):Dao层
直接访问数据库的操作
整体架构流程
代码顺序:
1.数据库表
2.实体层
3.dao层、daoimpl
4.service层、serviceimpl
5.controller层
就像搭房子,又下往上,像领导向下调用。controller层调用service层,再由service调用dao层。
技术名词解释
三层架构来源于后端开发的一种分层的思想。
引用自百科的解释:
三层架构(3-tier architecture)通常意义上的三层架构就是将整个业务应用划分为:界面层(User Interface layer)、业务逻辑层(Business Logic Layer)、数据访问层(Data access layer)。
区分层次的目的即为了“高内聚低耦合”的思想。在软件体系架构设计中,分层式结构是最常见,也是最重要的一种结构。微软推荐的分层式结构一般分为三层,从下至上分别为:数据访问层、业务逻辑层(又或称为领域层)、表示层。
各层的作用如下:
表示层:主要对用户的请求接受,以及数据的返回,为客户端提供应用程序的访问。
业务逻辑层:主要负责对数据层的操作。也就是说把一些数据层的操作进行组合。
数据访问层:主要看数据层里面有没有包含逻辑处理,实际上它的各个函数主要完成各个对数据文件的操作。而不必管其他操作。
技术细节
一.案例(JSP连接MySQL数据库并实现增删改查)
1.代码目录
2.应用的MySQL数据库中的表(包含username和password,后面也只会用到这两个):
3.代码介绍
(1)先要写的是pojo包中的Dept类和Emp类,最后写User类
package com.hp.pojo;
public class Dept {
private int did;
private String dname;
private String dlocation;
private String leader;
public static void main(String[] args) {
System.out.println(new Dept());
}
@Override
public String toString() {
return "Dept{" +
"did=" + did +
", dname='" + dname + '\'' +
", dlocation='" + dlocation + '\'' +
", leader='" + leader + '\'' +
'}';
}
//有参构造
public Dept(int did, String dname, String dlocation, String leader) {
this.did = did;
this.dname = dname;
this.dlocation = dlocation;
this.leader = leader;
}
//无参构造
public Dept() {
}
//封装
public int getDid() {
return did;
}
public void setDid(int did) {
this.did = did;
}
public String getDname() {
return dname;
}
public void setDname(String dname) {
this.dname = dname;
}
public String getDlocation() {
return dlocation;
}
public void setDlocation(String dlocation) {
this.dlocation = dlocation;
}
public String getLeader() {
return leader;
}
public void setLeader(String leader) {
this.leader = leader;
}
}
package com.hp.pojo;
import java.util.Date;
public class Emp {
private String id;
private String name;
private String sex;
private Date birth;
private double salary;
private int deptId;
public Emp(String id, String name, String sex, Date birth, double salary, int deptId) {
this.id = id;
this.name = name;
this.sex = sex;
this.birth = birth;
this.salary = salary;
this.deptId = deptId;
}
public Emp() {
}
@Override
public String toString() {
return "Emp{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", sex='" + sex + '\'' +
", birth=" + birth +
", salary=" + salary +
", deptId=" + deptId +
'}';
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Date getBirth() {
return birth;
}
public void setBirth(Date birth) {
this.birth = birth;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public int getDeptId() {
return deptId;
}
public void setDeptId(int deptId) {
this.deptId = deptId;
}
}
(2)接下来进行dao层的增删改查操作(这里再附带JdbcUtil,即对jdbc的封装)
package com.hp.dao.impl;
import com.hp.dao.IDeptDao;
import com.hp.pojo.Dept;
import com.hp.utils.JdbcUtil;
import com.hp.utils.JdbcUtilPlus;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
/*
DeptDaoImpl:
Dept 表示操作的实体
Dao 表示执行层/数据访问层/基层
Impl 表示实现类
*/
public class DeptDaoImpl implements IDeptDao {
@Override
public List<Dept> list() {
return JdbcUtil.list("select * from t_dept where did=13",Dept.class);
}
@Override
public Dept selectRow(int did) {
return JdbcUtilPlus.selectRow("select * from t_Dept where did= ?",Dept.class,did);
}
}
//查询多行多列
public static <T> List<T> list(String sql,Class<T> c) {
//创建一个集合,存放所有对象
List<T> tList = new ArrayList<>();
try {
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/salary?characterEncoding=utf-8", "root", "root");
Statement statement = conn.createStatement();
//statement执行sql,返回结果集
ResultSet rs = statement.executeQuery(sql);
//结果集rs得到结果集元数据
ResultSetMetaData md = rs.getMetaData();
//获取结果集的总列数
int columnCount = md.getColumnCount();
//解析rs(循环打印)
while (rs.next()) {//读取结果集的光标向下移动,光标默认在哪一行,列名所在的那一行
//根据每一行的数据,封装成一个实体对象
T t = c.newInstance();
//1.取出某一行的每一列数据,封装到对象t的属性中
for (int i = 1; i <= columnCount; i++) {
//通过列的序号,获取每一列的值
Object value = rs.getObject(i);
if (value!=null){
//通过列的序号,获取每一列的列名
String columnName = md.getColumnName(i);
//因为列名和实体类t中的属性名一致,为每一个属性构造一个反射中的set方法
Field f = c.getDeclaredField(columnName);
//赋予私有属性的赋值权限
f.setAccessible(true);
//使用反射,把value给到对象t的属性中
f.set(t,value);//理解为:把value赋值给对象t的columnName属性,相当于set方法
}
}
//把对象存入集合中
tList.add(t);
}
//关闭资源
statement.close();
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
return tList;
}
//查询一行
public static <T> T selectRow(String sql,Class<T> c) {
try {
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/salary?characterEncoding=utf-8", "root", "root");
Statement statement = conn.createStatement();
//statement执行sql,返回结果集
ResultSet rs = statement.executeQuery(sql);
//结果集rs得到结果集元数据
ResultSetMetaData md = rs.getMetaData();
//获取结果集的总列数
int columnCount = md.getColumnCount();
//解析rs(循环打印)
// 根据每一行的数据,封装成一个实体对象
T t=null;
if (rs.next()) {//读取结果集的光标向下移动,光标默认在哪一行,列名所在的那一行
t = c.newInstance();
//1.取出某一行的每一列数据,封装到对象t的属性中
for (int i = 1; i <= columnCount; i++) {
//通过列的序号,获取每一列的值
Object value = rs.getObject(i);
if (value!=null){
//通过列的序号,获取每一列的列名
String columnName = md.getColumnName(i);
//因为列名和实体类t中的属性名一致,为每一个属性构造一个反射中的set方法
Field f = c.getDeclaredField(columnName);
//赋予私有属性的赋值权限
f.setAccessible(true);
//使用反射,把value给到对象t的属性中
f.set(t,value);//理解为:把value赋值给对象t的columnName属性,相当于set方法
}
}
}
//关闭资源
statement.close();
conn.close();
return t;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
//查询一列
public static <T> List<T> selectColumn(String sql,Class<T> c) {
//创建一个集合,存放所有对象
List<T> tList = new ArrayList<>();
try {
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/salary?characterEncoding=utf-8", "root", "root");
Statement statement = conn.createStatement();
//statement执行sql,返回结果集
ResultSet rs = statement.executeQuery(sql);
//结果集rs得到结果集元数据
ResultSetMetaData md = rs.getMetaData();
//获取结果集的总列数
int columnCount = md.getColumnCount();
//解析rs(循环打印)
while (rs.next()) {//读取结果集的光标向下移动,光标默认在哪一行,列名所在的那一行
//通过列的序号,获取每一列的值
T t = (T) rs.getObject(1);
//把对象存入集合中
tList.add(t);
}
//关闭资源
statement.close();
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
return tList;
}
//查询单个
public static <T> T selectOne(String sql,Class<T> c) {
try {
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/salary?characterEncoding=utf-8", "root", "root");
Statement statement = conn.createStatement();
//statement执行sql,返回结果集
ResultSet rs = statement.executeQuery(sql);
//结果集rs得到结果集元数据
ResultSetMetaData md = rs.getMetaData();
//获取结果集的总列数
int columnCount = md.getColumnCount();
//解析rs(循环打印)
T t=null;
if (rs.next()){
t = (T) rs.getObject(1);
}
//关闭资源
statement.close();
conn.close();
return t;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
//增 删 改
public static int update(String sql) {
try {
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/salary?characterEncoding=utf-8", "root", "root");
Statement statement = conn.createStatement();
//statement执行sql,返回结果集
int i = statement.executeUpdate(sql);
//关闭资源
statement.close();
conn.close();
return i;
} catch (Exception e) {
e.printStackTrace();
}
return 0;
}
上述难度跳动比较大,涉及到反射、泛类,而且这还是没有升级后的代码,存在sql注入的问题。我们后续还需要改进代码,让代码变得更加安全简洁。需要帮助理解的可以留言私信我!我们接着往下面看
(3)是逻辑性的service包啦
package com.hp.service.impl;
import com.hp.dao.IDeptDao;
import com.hp.dao.impl.DeptDaoImpl;
import com.hp.pojo.Dept;
import com.hp.service.IDeptService;
import java.util.List;
/*
DeptServiceImpl:
Dept 操作的实体类,或者操作某个表
Service 表示业务层
Impl 表示实现类*/
public class DeptServiceImpl implements IDeptService {
//引入dao层
private IDeptDao deptDao=new DeptDaoImpl();
@Override
public int add() {
return 0;
}
@Override
public List<Dept> list() {
return deptDao.list();
}
@Override
public Dept selectRow(int did) {
return deptDao.selectRow(did);
}
}
因为我们都已经把实现类写出来了,所以说它的接口类很容易就能写出,这里就不一一给大家说明了
(4)最后我想给大家实现一个入口测试类,用来判断所写的功能是否实现
@Test
public void testRow(){
Dept dept = selectRow("select * from t_Dept where did=6", Dept.class);
System.out.println(dept);
}
@Test
public void testColumn(){
List<String> list = selectColumn("select dname from t_Dept", String.class);
System.out.println(list);
}
@Test
public void testOne(){
String dname = selectOne("select dname from t_Dept where did=1", String.class);
System.out.println(dname);
}
@Test
public void testUpdate(){
int j = update("insert into t_Dept values (null,'a','b','c')");
System.out.println(j);
}
@Test//测试登录
public void testLogin(){
String username="cc'or'1'='1";
String password="cc'or'1'='1";
User user = selectRow("select * from t_users where username='" + username + "' and password='" + password+"'", User.class);
System.out.println(user!=null?"登陆成功":"登录失败");
}
最后一个也是下次讲述的内容之一,这里我留一个悬念,聪明的小伙伴们也看到这里我用了@Test,注意这里要导一个包junit-4.12.jar,需要的可以私信我!有什么问题后续也可以提出来,知无不言言无不尽。
小结
本节课我们大家搭建了三层架构:控制层、业务层、数据访问层,让我们的数据在各个层之间传递,最后我们要简化代码——抽取工具类。从总结来看,我们的核心就是抽取工具类。所以我们最重要的就是理解工具类的方法,在java基础中好好学习泛类,面向对象,反射,这样在后续的java进阶学习中,才能更加如鱼得水,游刃有余!最后我们为什么要用三层架构的设计模式?这一点也困惑我许久。通过老师的讲解和自己的总结得出dao层是基层,而service是中层管理人员,最后controller是高层,一个项目需要每个人发挥自己的能力,这样反映了java编程工作团队合作的重要性。只有我们一层管理着下一层,秩序才不会紊乱,功能模块才会更加稳定。有不同见解的朋友也可以底下留言,也可以私下联系我,让我们遨游在java的海洋里面吧!