绑定完请刷新页面
取消
刷新

分享好友

×
取消 复制
Java web 中的 三层架构
2020-05-20 15:42:12

可能软件开发中很多地方都会用到三层结构,不过由于我首先是在Java web中接触到的三层结构,那么我就结合Java web 的注册登录系统为实例,好好讲讲三层结构。感觉三层架构弄明白了MVC也就触类旁通了。

一、什么是三层架构

三层架构就是把整个软件系统分为三个层次

  • 表现层(Presentation layer)
  • 业务逻辑层(Business Logic Layer)
  • 数据访问层(Data access layer)

如图所示:

至于为什么要分层?我通过查阅书籍,网上浏览,询问老师得出来大概以下的优点:

  • 方便团队分工,一个程序员单独完成一个软件产品不是不可以,但遇到大型软件需要团队配合的时候问题就来了,由于每个程序员风格不一样,而开发软件大量的代码风格不统一就会造成后期调试和维护出现问题,然而软件分层后,每个层合理分工这样的问题便迎刃而解。
  • 规范代码,在开发软件时对每个层的代码进行规范,固定开发语言的风格。
  • 忽略数据库差异,当软件系统要换数据库时,只要将数据访问层的代码修改就好了。
  • 实现"高内聚、低耦合"。把问题划分开来各个解决,易于控制,易于延展,易于分配资源。

总之优点很多的样子,不过分层给我直观的感受是,代码逻辑清晰了很多。

二,各个层次的任务

  • 表现层(Presentation layer):表现层可以说是距离用户近的层,主要是用于接收用户输入的数据和显示处理后用户需要的数据。一般表现为界面,用户通过界面输入查询数据和得到需要的数据。
  • 业务逻辑层(Business Logic Layer):业务逻辑层是处于表现层和数据访问层之间,主要是从数据库中得到数据然后对数据进行逻辑处理。
  • 数据访问层(Data access layer):数据访问层是直接和数据库打交道的,对数据进行“增、删、改、查”等基本的操作。

不知道大家和我有没有同样的困惑:为什么中间要有业务逻辑层?为什么数据访问层不能对数据进行逻辑处理呢?少了中间一层不是减少了代码量吗?

我后来想了很久,查了很多资料,突然有所感悟,试着用自己语言描述下其中缘由。

  • 用户对应为:食客;(食客通过服务员点单)
  • 表现层对应为:服务员;(服务员负责食客的点单和上菜)
  • 业务逻辑层对应为:主厨;(主厨从服务员那获得通知,向助手要原材料,并将原材料绘制成成品交给服务员)
  • 数据访问层对应为:助手;(助手从主厨那获得通知,提交给主厨原材料)

这样的话,当大型个软件系统中出现问题时就可以很方便的解决问题

  • 服务员服务态度不好>>>>>>换服务员
  • 菜品味道不好,调味失衡>>>>>>换主厨
  • 菜品的原材料不够新鲜>>>>>>>>换助手

三、三层架构之间如何联系起来?

一般来说都是通过实体层(entity layer)贯穿三个层次之间。实体层不属于三层架构中的任意一层。

四、通过实例讲解三层架构

就拿简单的学生注册登录系统来说吧。

1、实体层:首先我们需要实体层来对应数据库中的表。

在本例中 用Student类对应数据库中的Student表,Student类对象作为连接三层架构的桥梁。

public class Student{
	String id;		//学生的学号
	String name;	        //学生的姓名
	String password;       //学生的登录密码
	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 getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
}

2、数据访问层:这一层主要是利用sql语言直接对数据库进行基础的操作如:“增,删,改,查”等等。不涉及更深一步的逻辑上的处理。

public class DAOsupport {
	static Connection connection;							//声明Connection对象
	 static String driver ="com.mysql.jdbc.Driver";	//驱动程序名
	 static String url = "jdbc:mysql://119.23.79.90:3306/survey"; //URL指向要访问的数据库名mydata
	 static String username = "root";						//MySQL配置时的用户名
	 static String password = "MYSQL";						//MySQL配置时的密码  

	public DAOsupport(){
		try {
			Class.forName(driver);
		} catch (ClassNotFoundException e) {
			System.out.println("加载数据库驱动出错");
			e.printStackTrace();
		} 
        try {
			connection= (Connection) DriverManager.getConnection(url, username, password);
		} catch (SQLException e) {
			System.out.println("连接数据库出错");
			e.printStackTrace();
		}
	}
}

编写一个DAOsuport类,为其他的DAO类提供基础的代码(比如连接数据库),减少代码的重复。

接着针对于学生类编写,StudentDAO类。该类继承DAOsuport类。

public class StudentDAO extends DAOsupport{
	public Student student;   //对用户类进行数据库的操作前,先要获取用户对象
	public StudentDAO(Student student){
		super();
		this.student=student;
	}
        //返回实参
        public Student get_Stu(){
                 retrun student;
        }
	//增加用户student 
	public void save(){
		String sql="insert into student(id,name,password,)"+"values(?,?,?)";
		PreparedStatement pStatement;
		try {
			pStatement = connection.prepareStatement(sql);
			//为SQl参数赋值
			pStatement.setString(1, student.getId());
			pStatement.setString(2, student.getName());
			pStatement.setString(3, student.getPassword());
			//向user表插入记录
			pStatement.executeUpdate();
			//关闭
			pStatement.close();
		} catch (SQLException e) {
			System.out.println("保存用户时出错");
			e.printStackTrace();
		}
	}
	//删除用户student 
	public void delete() throws SQLException{
		String sql="delete from user where id=?";
			PreparedStatement pStatement=connection.prepareStatement(sql);
			pStatement.setString(1, student.getId());
			pStatement.executeUpdate();
			pStatement.close();
	}
	//更新用户student 
	public void update(){
			// TODO Auto-generated method stub
			String sql="update user set password=? where id="+student .getId();
			try {
				PreparedStatement preparedStatement=(PreparedStatement)connection.prepareStatement(sql);
				preparedStatement.setString(1,student.getPassword());
				preparedStatement.executeUpdate();
			} catch (SQLException e) {
				System.out.println("更新用户时出错");
				e.printStackTrace();
			}
	}
	//通过学号查找用户
	public Student getStuById() {
		Student student =new Student ();
		String sql="select * from student where id="+id;
		try {
			PreparedStatement preparedStatement=connection.prepareStatement(sql);
			ResultSet rs=preparedStatement.executeQuery();
			rs.next();
			student.setId(id);
			student.setName(rs.getString(2));
			student.setPassword(rs.getString(3));
		} catch (SQLException e) {
			System.out.println("通过ID查询用户时出错");
			e.printStackTrace();
		}
		return student ;
	}
}

3、业务逻辑层

public class StudentService {
	public StudentDAO studentDAO;
	public StudentService(StudentDAO studentDAO){
		this.studentDAO=studentDAO;
	}
        //注册就是将student对象加入数据库
	public void  rgister(){
		studentDAO.save();
	}
        //登录就是查看登录时填写的账号和密码是否和数据库中的账号和密码一致。
	public boolean login() throws Exception{
		boolean flag=false;
                //获取数据库中这个学生的密码
                Student stu=studentDAO.getStuById();
                String password=stu.getPassword();
		/*
                实际上可以直接写成,上述代码只是为方便理解。
                String password=studentDAO.getStuById().getPassword();
                */
		if(password.equals(null)){
			throw new Exception("<学号为"+studentDAO.getStu().getId()+">不存在");
		}
                /*studentDAO.getStu()得到的是由登录信息实例化的学生对象,不是存在数据库的记录*/
		else if(!password.equals(studentDAO.getStu().getPassword())){
			throw new Exception("密码不正确");
		}
		else if(password.equals(studentDAO.getStu().getPassword())){
			flag=true;
		}
		return flag;
	}
       //注销该学生
	public void delete(){
		studentDAO.delete();
	}
        //更新该学生
	public void updte(){
		studentDAO.update();
	}
}

测试代码:

在这里为了方便测试,我就不写出表示层,表示层也就是在注册登录的时候,采集学生的学号,姓名,密码等信息。

public class test(){
        public static void main(String args[]){
        //实例化一个实体层类对象
        Student student =new Student();
         //为对象设置学号,姓名,密码等等。
        student.setId("20171008");    
        student.setName("刘耀");
        student.setPassword("5461");
        //实例化一个数据访问层对象,参数为实体层类对象。
        StudentDAO studentDAO=new StudentDAO(student);
        //实例化一个业务逻辑层对象,参数为数据访问层对象。
        StudentService studentService=new StudentService(studentDAO) 
        //学生注册
        studentService.register();
       }
}

在学生注册测试中,我们可以看到:

业务逻辑层注册方法studentService.register()里面并没有SQL语句对数据库进行操作。而只是调用了数据访问层studentDAO.save()方法,在数据访问层的studentDAO.save()方法中写SQL语句 对数据库进行操作。

可能会有人说那这样业务逻辑层只是对数据访问层的简单嵌套啊,不急,我们接着看学生登录的测试代码,在学生注册之后就能登陆了。

public class test(){
        public static void main(String args[]){
        //实例化一个实体层类对象
        Student student =new Student();
         //为对象设置学号,密码等等。
        student.setId("20171008");    
        student.setPassword("5461");
        //实例化一个数据访问层对象,参数为实体层类对象。
        StudentDAO studentDAO=new StudentDAO(student);
        //实例化一个业务逻辑层对象,参数为数据访问层对象。
        StudentService studentService=new StudentService(studentDAO) 
        //学生登录
       if(studentService.login()){
               system.out.println("登录成功");
       }
       else{
               system.out.println("学号或密码错误");
       }
}

在登录测试代码中业务逻辑层studentService.login()方法中调用了数据访问层studentDAO.getStuById()方法得到数据库中的学生记录(查)。至于验证登录时填写的学号和密码是否和数据库中存储的是否一致,这个逻辑关系则是由业务逻辑层自己判断的。

小结一下:表现层的代码只是起到和用户交互的一个功能,采集信息反馈结果。

业务逻辑层是通过数据访问层拿到存在数据库里的原始数据,然后再对数据进行逻辑上的处理,比如说验证。

数据访问层的代码都是对数据库数据的“增删改查”,是原子性的不可以再细分的

实体层不是三层架构中的任意一层,它起到一个贯穿三层架构的作用。在上述例子中Student的对象就贯穿了业务逻辑层和数据访问层。至于为什么要用一个类来贯穿三层架构,而不是直接用变量来连接,是因为有的时候变量可能会很多,如学生在后期可能要添加了“省份”,“学校”,“年级”,“班级”等等属性,那么就会很麻烦,但是面向对象编程的话,就可以很轻松地把属性封装在一个对象里,传递参数也方便。

分享好友

分享这个小栈给你的朋友们,一起进步吧。

数据架构
创建时间:2020-05-20 11:23:41
有关数据架构的小栈里面全都有
展开
订阅须知

• 所有用户可根据关注领域订阅专区或所有专区

• 付费订阅:虚拟交易,一经交易不退款;若特殊情况,可3日内客服咨询

• 专区发布评论属默认订阅所评论专区(除付费小栈外)

技术专家

查看更多
  • 小雨滴
    专家
戳我,来吐槽~