JavaWeb簡易入門(三)

三層架構(該部分引自菜鳥教程)

什麼是三層?

UI(表現層): 主要是指與用戶交互的界面。用於接收用戶輸入的數據和顯示處理後用戶需要的數據。

BLL:(業務邏輯層): UI層和DAL層之間的橋樑。實現業務邏輯。業務邏輯具體包含:驗證、計算、業務規則等等。

DAL:(數據訪問層): 與數據庫打交道。主要實現對數據的增、刪、改、查。將存儲在數據庫中的數據提交給業務層,同時將業務層處理的數據保存到數據庫。(當然這些操作都是基於UI層的。用戶的需求反映給界面(UI),UI反映給BLL,BLL反映給DAL,DAL進行數據的操作,操作後再一一返回,直到將用戶所需數據反饋給用戶)

在這裏插入圖片描述

每一層都各負其責,那麼該如何將三層聯繫起來呢?

1、單項引用(見下圖)

2、這時候實體層(Entity)來了。(注:當然,實體層的作用不止這些)

**Entity(實體層):**它不屬於三層中的任何一層,但是它是必不可少的一層。

Entity在三層架構中的作用:

  • 1、實現面向對象思想中的"封裝";
  • 2、貫穿於三層,在三層之間傳遞數據;(注:確切的說實體層貫穿於三層之間,來連接三層)
  • 3、對於初學者來說,可以這樣理解:每張數據表對應一個實體,即每個數據表中的字段對應實體中的屬性(注:當然,事實上不是這樣。爲什麼?1>,可能我們需要的實體在數據表對應的實體中並不存在;2>,我們完全可以將所有數據表中的所有字段都放在一個實體裏)
  • 4、每一層(UI—>BLL—>DAL)之間的數據傳遞(單向)是靠變量或實體作爲參數來傳遞的,這樣就構造了三層之間的聯繫,完成了功能的實現。

但是對於大量的數據來說,用變量做參數有些複雜,因爲參數量太多,容易搞混。比如:我要把員工信息傳遞到下層,信息包括:員工號、姓名、年齡、性別、工資....用變量做參數的話,那麼我們的方法中的參數就會很多,極有可能在使用時,將參數匹配搞混。這時候,如果用實體做參數,就會很方便,不用考慮參數匹配的問題,用到實體中哪個屬性拿來直接用就可以,很方便。這樣做也提高了效率。

*(***注:***這裏爲什麼說可以暫時理解爲每個數據表對應一個實體??答:大家都知道,我們做系統的目的,是爲用戶提供服務,用戶可不關心你的系統後臺是怎麼工作的,用戶只關心軟件是不是好用,界面是不是符合自己心意。用戶在界面上輕鬆的增、刪、改、查,那麼數據庫中也要有相應的增、刪、改、查,而增刪改查具體操作對象就是數據庫中的數據,說白了就是表中的字段。所以,將每個數據表作爲一個實體類,實體類封裝的屬性對應到表中的字段,這樣的話,實體在貫穿於三層之間時,就可以實現增刪改查數據了)*


綜上所述:三層及實體層之間的依賴關係:

在這裏插入圖片描述
例:

在這裏插入圖片描述

**服務員:**只管接待客人;

**廚師:**只管做客人點的菜;

**採購員:**只管按客人點菜的要求採購食材;

他們各負其職,服務員不用瞭解廚師如何做菜,不用瞭解採購員如何採購食材;廚師不用知道服務員接待了哪位客人,不用知道採購員如何採購食材;同樣,採購員不用知道服務員接待了哪位客人,不用知道廚師如何做菜。

他們三者是如何聯繫的?

比如:廚師會做:炒茄子、炒雞蛋、炒麪——此時構建三個方法( cookEggplant()、cookEgg()、cookNoodle())

顧客直接和服務員打交道,顧客和服務員(UI層)說:我要一個炒茄子,而服務員不負責炒茄子,她就把請求往上遞交,傳遞給廚師(BLL層),廚師需要茄子,就把請求往上遞交,傳遞給採購員(DAL層),採購員從倉庫裏取來茄子傳回給廚師,廚師響應cookEggplant()方法,做好炒茄子後,又傳回給服務員,服務員把茄子呈現給顧客。

這樣就完成了一個完整的操作。

在此過程中,茄子作爲參數在三層中傳遞,如果顧客點炒雞蛋,則雞蛋作爲參數(這是變量做參數)。如果,用戶增加需求,我們還得在方法中添加參數,一個方法添加一個,一個方法設計到三層;何況實際中並不止設計到一個方法的更改。所以,爲了解決這個問題,我們可以把茄子、雞蛋、麪條作爲屬性定義到顧客實體中,一旦顧客增加了炒雞蛋需求,直接把雞蛋屬性拿出來用即可,不用再去考慮去每層的方法中添加參數了,更不用考慮參數的匹配問題。

爲什麼使用三層?

使用三層架構的目的:解耦!!!

同樣拿上面飯店的例子來講:

(1)服務員(UI層)請假——另找服務員;廚師(BLL層)辭職——招聘另一個廚師;採購員(DAL)辭職——招聘另一個採購員; (2)顧客反映:

  • 1、你們店服務態度不好——服務員的問題。開除服務員;
  • 2、你們店菜裏有蟲子——廚師的問題。換廚師;

任何一層發生變化都不會影響到另外一層!!!

與兩層的區別?

兩層:

在這裏插入圖片描述

(當任何一個地方發生變化時,都需要重新開發整個系統。"多層"放在一層,分工不明確耦合度高——難以適應需求變化,可維護性低、可擴展性低)

三層

在這裏插入圖片描述

(發生在哪一層的變化,只需更改該層,不需要更改整個系統。層次清晰,分工明確,每層之間耦合度低——提高了效率,適應需求變化,可維護性高,可擴展性高)

綜上,三層架構的優勢:

  • 1,結構清晰、耦合度低
  • 2,可維護性高,可擴展性高
  • 3,利於開發任務同步進行, 容易適應需求變化

三層架構的優劣勢:

  • 1、降低了系統的性能。這是不言而喻的。如果不採用分層式結構,很多業務可以直接造訪數據庫,以此獲取相應的數據,如今卻必須通過中間層來完成。
  • 2、有時會導致級聯的修改。這種修改尤其體現在自上而下的方向。如果在表示層中需要增加一個功能,爲保證其設計符合分層式結構,可能需要在相應的業務邏輯層和數據訪問層中都增加相應的代碼
  • 3、增加了代碼量,增加了工作量

Http協議

**什麼是Http協議?

它叫做超文本傳輸協議。瀏覽器和服務器之間進行交互,需要遵守一定的規則,那麼這個規則就是Http協議

在這裏插入圖片描述

協議版本: 0.0 版本 【淘汰】 1.0 版本【幾乎不再使用】 1.1 版本【主流】
http協議內容包含請求(Request)和響應(Response)兩段內容。 請求包含請求頭、請求行、請求體 響應包含響應
頭、響應行、響應體

Http的請求內容

  1. 請求行:請求消息中的第一行 請求頭:向服務器端傳遞一些附加消息 請求(體)內容:請求消息傳遞的真實數據 -指的是form( 表單)內容的傳遞 1.1 請求方式: get 和post嗎? 面試題: get 和post 的區別? get: 1. 地址欄中暴
    露參數(安全性較低) 2. 默認是get 3. 速度快 4. 可傳遞的參數長度有限制 post 1.地址中不暴露參數 (安全性
    高) 2. 速度較慢 3.傳遞參數沒有限制 4.上傳時,必須採用post方式

  2. 響應行:響應消息中的第一行 響應頭:向瀏覽器端傳遞一些附加消息 響應(體)內容:響應消息傳遞的真實數據 -指的是後臺的數據的傳遞到前臺的內容

    Http狀態碼是由三位數字構成的,它的第一位數字有五種可能的取值。

    狀態碼 status code: 1xx: 表示 請求接受 ,需要繼續處理 2xx:表示請求已成功被服務器接受 3xx:需要進一步細化請求的內容 4xx:客戶端的請求是有問題的。 如:404(查看前臺網頁數據傳遞的URL) 5xx:服務器端出現錯誤。如:500(和前臺網頁無關,是後臺代碼出現了問題)

在這裏插入圖片描述
在這裏插入圖片描述

繼續上次項目

實體類

/**
 * @program:
 * @description:
 * @author:稽_智
 * @create: 2020-03-11 16:42
 */
public class Student {
	private int id;				//學生id(學號)
	private String username;	//賬戶
	private String password;	//密碼
	private String email;		//郵箱
	private String tel;			//電話

	@Override
	public String toString() {
		return "Student{" +
				"id=" + id +
				", username='" + username + '\'' +
				", password='" + password + '\'' +
				", email='" + email + '\'' +
				", tel='" + tel + '\'' +
				'}';
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public String getTel() {
		return tel;
	}

	public void setTel(String tel) {
		this.tel = tel;
	}
}

工具類

import	java.io.IOException;
import	java.sql.Connection;

import org.apache.commons.dbcp.BasicDataSourceFactory;

import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
import java.util.Properties;

/**
 * @author:稽_智
 * @create: 2020-03-11 16:51
 * 由於是工具類,所以方法、屬性均爲靜態
 */
public class DbcpUtils {
	private static DataSource ds = null;
	static{

		InputStream in = DbcpUtils.class.getClassLoader().getResourceAsStream("dbcp.properties");//此處的"dbcp.properties"爲配置文件,應在src
		Properties p = new Properties();
		try {
			p.load(in);
			ds = BasicDataSourceFactory.createDataSource(p);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	public static DataSource getDataSource() {
	    return ds;
	}

	public static Connection getConnection() throws IOException {
		try {
			return ds.getConnection();
		} catch (SQLException e) {
			throw new RuntimeException(e);
		}
	}
}

數據訪問層

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;

import java.sql.SQLException;
import java.util.List;

/**
 * @author:稽_智
 * @create: 2020-03-11 16:48
 * 這裏需要用到實體類和工具類
 * 異常均在方法中解決
 */
/*
       第一部分:增刪改----> update 更改、更新
       第二部分:查 --->   query    查詢
 */
public class StudentDao {
	QueryRunner qr = new QueryRunner(DbcpUtils.getDataSource());
	public List findAll() {
		try {
			return qr.query("select * from user",new BeanListHandler<Student>(Student.class));
		} catch (SQLException e) {
			throw new RuntimeException(e);
		}
	}

	public void addUser(String username, String password, String email, String tel) {
		try {
			//語句中的?類似佔位符,與後面的String變量一一對應
			qr.update("insert into user(username,password,email,tel) values(?,?,?,?)",username,password, email, tel);
		} catch (SQLException e) {
			throw new RuntimeException(e);
		}
	}
}

服務層/邏輯層

import java.util.List;

/**
 * @author:稽_智
 * @create: 2020-03-11 16:41
 */
public class StudentService {

	private StudentDao studenDao = new StudentDao();

	public List findAll() {
		return studenDao.findAll();
	}
	
	public void addUser(String username, String password, String email, String tel) {
		//判斷各個字符串是否爲空字符串,任一爲空則不再執行用戶添加(註冊)
		if(username.equals("") || username == null)
			return;
		if(password.equals("") || password == null)
			return;
		if(email.equals("") || email == null)
			return;
		if(tel.equals("") || tel == null)
			return;
		studenDao.addUser(username,password,email, tel);
	}

}

表現層

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

@WebServlet("/studenServlet")
public class StudenServlet extends HttpServlet {
	private StudentService studentService = new StudentService();
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//設置字符編碼,防止亂碼
		request.setCharacterEncoding("utf-8");
		response.setCharacterEncoding("utf-8");
		doGet(request,response);
	}

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//獲取變量名爲type的參數值
		String type = request.getParameter("type");
		//根據獲取到的參數值判斷執行註冊or查找方法
		if(type.equals("reg"))
			reg(request,response);
		else if(type.equals("findAll"))
			findAll(request,response);
	}

	private void findAll(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
		List list = studentService.findAll();
		response.getWriter().write(list.toString());
		System.out.println(list);
        //"student"爲一個記號,記號的實際內容爲list
		request.setAttribute("student",list);
        //studentlist.jsp爲將要跳轉到的頁面
		request.getRequestDispatcher("/studentlist.jsp").forward(request, response);
	}

	private void reg(HttpServletRequest request, HttpServletResponse response) {
		studentService.addUser(
				request.getParameter("username"),
				request.getParameter("password"),
				request.getParameter("email"),
				request.getParameter("tel")
				);
	}
}

studentlist.jsp:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <table border="1px">
        <tr>
            <th>username</th>
            <th>password</th>
            <th>email</th>
            <th>tel</th>
        </tr>
        <c:forEach items="${student}" var="s" varStatus="vs">
            <tr>
                <td>${s.username}</td>
                <td>${s.password}</td>
                <td>${s.email}</td>
                <td>${s.tel}</td>
            </tr>
        </c:forEach>
    </table>
</body>
</html>

dbcp.properties:

driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/{數據庫名}
username=數據庫用戶名
password=數據庫用戶密碼

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-LdN8AR38-1584358340309)(D:\桌面\筆記_文章\JavaWeb\增刪改查.png)]

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章