1. 程式人生 > >JavaWeb三層架構詳解

JavaWeb三層架構詳解

什麼是三層架構?

三層架構(3-tier architecture) 通常意義上的三層架構就是將整個業務應用劃分為:介面層(User Interface layer)、業務邏輯層(Business Logic Layer)、資料訪問層(Data access layer)。區分層次的目的即為了高內聚低耦合的思想。在軟體體系架構設計中,分層式結構是最常見,也是最重要的一種結構。微軟推薦的分層式結構一般分為三層,從下至上分別為:資料訪問層(又稱為持久層)業務邏輯層(又或稱為領域層)表示層

表示層(UI層):

表示層也稱為介面層,位於最外層(最上層),離使用者最近。用於顯示資料和接收使用者輸入的資料

,為使用者提供一種互動式操作的介面。

業務邏輯層(BLL層):

負責關鍵業務的處理和資料的傳遞。複雜的邏輯判斷和涉及到資料庫的資料驗證都需要在此做出處理。主要是針對具體的問題的操作,也可以理解成對資料層的操作,對資料業務邏輯處理,如果說資料層是積木,那邏輯層就是對這些積木的搭建。

資料訪問層(DAL層):

主要負責對資料庫的直接訪問為業務邏輯層提供資料,根據傳入的值來操作資料庫,增、刪、改、查。

為什麼要用三層架構呢?

1.團隊開發,便於管理

三層架構使得合作開發成為可能,由於各層相互獨立,一個小組只需負責一小塊就可以。結構化的程式設計方法面對大型的專案會感到力不從心,因為結構化設計必定會使程式變的錯綜複雜。邏輯主要在

BLL層,就使得UI層也就是客戶端不承擔太多的職責,即使更新業務邏輯,也無需修改客戶端,不用重新部署。

2.解耦

上一層依賴於下一層,如果測試下一層沒有問題,那麼問題就只有可能發現在本層了,便於發現和改正BUG。體現了高內聚,低耦合的思想。比如樓房是分層的,我們要到哪一層樓非常方便,只需在電梯裡按下那個樓層的層號即可。而三層架構就好比開發的軟體“樓”,哪層出現Bug,哪層有問題,我們作為開發人員能夠隨時找到,並修正。 各個層次分工明確,將一個複雜問題簡單拆分了。

 3.程式碼的複用和勞動成本的減少

 分層的根本在於程式碼的複用和勞動成本的減少。分層的最理想化的結果是實現層與層之間的互不依賴的內部實現,所謂的即插即用!

當然啦,三層架構也是有一定的缺點,但是總的來說,利大於弊。

那麼下面寫一個小專案來具體地深入瞭解一下三層架構

專案目錄如下:

表示層Model:

package com.gpnu.book.entity;

public class Books {
	@Override
	public String toString() {
		return "Books [book_id=" + book_id + ", book_name=" + book_name + ", isbn=" + isbn + ", author=" + author + "]";
	}
	public Books() {
	}
	public Books(int book_id, String book_name, String isbn, String author) {
		super();
		this.book_id = book_id;
		this.book_name = book_name;
		this.isbn = isbn;
		this.author = author;
	}
	private int book_id;
	private String book_name;
	private String isbn;
	private String author;
	public int getBook_id() {
		return book_id;
	}
	public void setBook_id(int book_id) {
		this.book_id = book_id;
	}
	public String getBook_name() {
		return book_name;
	}
	public void setBook_name(String book_name) {
		this.book_name = book_name;
	}
	public String getIsbn() {
		return isbn;
	}
	public void setIsbn(String isbn) {
		this.isbn = isbn;
	}
	public String getAuthor() {
		return author;
	}
	public void setAuthor(String author) {
		this.author = author;
	}
}

表示層Controller:

BooksServlet.java

package com.gpnu.book.servlet;

import java.io.IOException;
import java.util.List;

import javax.servlet.RequestDispatcher;
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 com.gpnu.book.entity.Books;
import com.gpnu.book.service.BooksService;
import com.gpnu.book.service.impl.BooksServiceImpl;

/**
 * Servlet implementation class Books
 */
@WebServlet("/BooksServlet")
public class BooksServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
    
	BooksService booksService = BooksServiceImpl.getInstance();
    /**
     * @see HttpServlet#HttpServlet()
     */
    public BooksServlet() {
        super();
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		response.getWriter().append("Served at: ").append(request.getContextPath());
		doPost(request, response);
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		request.setCharacterEncoding("UTF-8");
		String action = request.getParameter("action");
		System.out.println("action:" + action);
		if (action.equals("add")) {
			doAddBooks(request, response);
			response.sendRedirect("index.jsp");
		}else if (action.equals("select")) {
			response.sendRedirect(request.getContextPath() + "/Books/selBooks.jsp");
		}else if (action.equals("remove")) {
			doDelBooks(request, response);
			response.sendRedirect("SelBooksServlet");
		}
	}
	
	
	private void doAddBooks(HttpServletRequest request, HttpServletResponse response) throws IOException {
		Books book = new Books();
		//book.setBook_id(Integer.parseInt(request.getParameter("book_id")));
		book.setBook_name(request.getParameter("book_name"));
		book.setIsbn(request.getParameter("isbn"));
		book.setAuthor(request.getParameter("author"));
		int result = booksService.addBooks(book);
		if (result > 0)
			System.out.println("新增book成功");
		else
			System.out.println("新增book失敗");
	}
	
	private void doDelBooks(HttpServletRequest request, HttpServletResponse response) throws IOException {
		int id = Integer.parseInt(request.getParameter("id"));
		int result = booksService.delBooks(id);
		if (result > 0)
			System.out.println("刪除book成功");
		else
			System.out.println("刪除book失敗");

	}
}

SelBooksServlet.java

package com.gpnu.book.servlet;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.RequestDispatcher;
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 com.gpnu.book.entity.Books;
import com.gpnu.book.service.BooksService;
import com.gpnu.book.service.impl.BooksServiceImpl;

/**
 * Servlet implementation class SelBooksServlet
 */
@WebServlet("/SelBooksServlet")
public class SelBooksServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
	BooksService booksService = BooksServiceImpl.getInstance();
	
    /**
     * @see HttpServlet#HttpServlet()
     */
    public SelBooksServlet() {
        super();
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		response.getWriter().append("Served at: ").append(request.getContextPath());
		doPost(request, response);
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	private static String keyword = "";
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		request.setCharacterEncoding("UTF-8");
		keyword = request.getParameter("keyword");
		System.out.println("keyword:" + keyword);
		if (keyword == "")
			doSelAllBooks(request, response);
		else
			doSelBooks(request, response);
	}

	private void doSelAllBooks(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
		List<Books> list = booksService.selAllBooks();
		request.setAttribute("books", list);
		System.out.println("查詢所有");
		RequestDispatcher view = request.getRequestDispatcher("/Books/selResult.jsp");
		view.forward(request, response);
	}  
 
	private void doSelBooks(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
		Books book = booksService.selBooks(keyword);
		List list = new ArrayList();
		list.add(book);
		request.setAttribute("books", list);
		System.out.println("條件查詢");
		RequestDispatcher view = request.getRequestDispatcher("/Books/selResult.jsp");
		view.forward(request, response);
	}
	
}

表示層View:

index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<a href="BooksServlet?action=add">新增</a>
<a href="BooksServlet?action=select">查詢</a>
</body>
</html>

addBooks.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="/book/BooksServlet?action=add" method="post">
<table border="1" cellspacing="0" cellpadding="0" style="align:center;">
    <tr><td>圖書名稱:</td><td><input type="text" name="book_name"></td></tr>
    <tr><td>國際標準書號:</td><td><input type="text" name="isbn"></td></tr>
    <tr><td>作者:</td><td><input type="text" name="author"></td></tr>
    <tr><td><input type="submit" value="提交"></td><td><input type="button" value="返回"></td>
 	</tr>
 </table>
 </form>
</body>
</html>

selBooks.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="/book/SelBooksServlet" method="post">
<input type="text" name="keyword"><input type="submit" value="查詢">
</form>
</body>
</html>

selResult.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="/book/SelBooksServlet" method="post">
<input type="text" name="keyword"><input type="submit" value="查詢">
</form>
</body>
</html>

持久層介面:

package com.gpnu.book.dao;

import java.util.List;

import com.gpnu.book.entity.Books;

public interface BooksDao {
	List<Books> selAllBooks();
	Books selBooks(String keyword);
	int addBooks(Books book);
	int delBooks(int book_id);
	int booksCount();
}

持久層實現類:

package com.gpnu.book.dao.impl;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import com.gpnu.book.dao.BooksDao;
import com.gpnu.book.entity.Books;
import com.gpnu.book.common.DBUtils;

public class BooksDaoImpl implements BooksDao {

	private Connection conn;
	
	public BooksDaoImpl(Connection conn) {
		this.conn = conn;
	}
	
	@Override
	public List<Books> selAllBooks() {
		List list = new ArrayList();
		PreparedStatement pstam = null;
		ResultSet rs = null;
		Books book = null;		try {
			pstam = conn.prepareStatement("select * from tbl_book");
			rs = pstam.executeQuery();
			while (rs.next()) {
				book = new Books();
				book.setBook_id(rs.getInt("book_id"));
				book.setBook_name(rs.getString("book_name"));
				book.setIsbn(rs.getString("isbn"));
				book.setAuthor(rs.getString("author"));
				list.add(book);
			}
		} catch (SQLException e) {
			System.out.println("在查詢全部book的時候出錯了.錯誤資訊是 :" + e.getMessage());
		} finally {
			DBUtils.closeStatement(rs, pstam);
		}
		return list;
	}

	@Override
	public int booksCount() {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public Books selBooks(String keyword) {
		Books book = new Books();
		PreparedStatement pStatement = null;
		ResultSet rSet = null;
		try {
			pStatement = conn.prepareStatement("select * from tbl_book where book_name like ?");
			pStatement.setString(1, "%" + keyword + "%");
			rSet = pStatement.executeQuery();
			if (rSet.next()) {
				book.setBook_id(rSet.getInt("book_id"));
				book.setBook_name(rSet.getString("book_name"));	
				book.setIsbn(rSet.getString("isbn"));
				book.setAuthor(rSet.getString("author"));
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			DBUtils.closeStatement(rSet, pStatement);
		}
		return book;
	}

	@Override
	public int addBooks(Books book) {
		int result = 0;
		PreparedStatement pstam = null;
		try {
			pstam = conn.prepareStatement("insert into tbl_book(book_name,isbn,author) values(?,?,?)");
			//pstam.setInt(1, book.getBook_id());
			pstam.setString(1, book.getBook_name());
			pstam.setString(2, book.getIsbn());
			pstam.setString(3, book.getAuthor());
			result = pstam.executeUpdate();
		} catch (SQLException e) {
			System.out.println("新增book出錯.錯誤資訊是 :" + e.getMessage());
		} finally {
			DBUtils.closeStatement(null, pstam);
		}
		return result;
	}

	@Override
	public int delBooks(int book_id) {
		int result = 0;
		PreparedStatement pstam = null;
		try {
			pstam = conn.prepareStatement("DELETE FROM tbl_book WHERE book_id =?");
			pstam.setInt(1, book_id);
			result = pstam.executeUpdate();
		} catch (SQLException e) {
			System.out.println("刪除book出錯.錯誤資訊是 :" + e.getMessage());
		} finally {
			DBUtils.closeStatement(null, pstam);
		}
		return result;
	}

}

業務邏輯層介面:

package com.gpnu.book.service;

import java.util.List;

import com.gpnu.book.entity.Books;

public interface BooksService {
	List<Books> selAllBooks();
	Books selBooks(String keyword);
	int addBooks(Books book);
	int delBooks(int book_id);
}

業務邏輯層實現類

package com.gpnu.book.service.impl;

import java.sql.Connection;
import java.util.List;

import com.gpnu.book.entity.Books;
import com.gpnu.book.service.BooksService;
import com.gpnu.book.common.DBUtils;
import com.gpnu.book.dao.BooksDao;
import com.gpnu.book.dao.impl.BooksDaoImpl;

public class BooksServiceImpl implements BooksService {

	private static final BooksService instance = new BooksServiceImpl();
	public static BooksService getInstance() {
		return instance;
	}
	
	@Override
	public List<Books> selAllBooks() {
		Connection conn = null;
		List list = null;
		try {
			conn = DBUtils.getConnection();
			DBUtils.beginTransaction(conn);
			BooksDao booksDao = new BooksDaoImpl(conn);
			list = booksDao.selAllBooks();
			DBUtils.commit(conn);
		} catch (Exception e) {
			System.out.println("查詢所有books錯誤" + e.getMessage());
		} finally {
			DBUtils.closeConnection(conn);
		}
		return list;
	}

	@Override
	public Books selBooks(String keyword) {
		Connection conn = null;
		Books book = null;
		try {
			conn = DBUtils.getConnection();
			DBUtils.beginTransaction(conn);
			BooksDao booksDao = new BooksDaoImpl(conn);
			book = booksDao.selBooks(keyword);
			DBUtils.commit(conn);
		} catch (Exception e) {
			System.out.println("條件查詢books錯誤" + e.getMessage());
		} finally {
			DBUtils.closeConnection(conn);
		}
		return book;
	}

	@Override
	public int addBooks(Books book) {
		Connection conn = null;
		int result = 0;
		try {
			conn = DBUtils.getConnection();
			DBUtils.beginTransaction(conn);
			BooksDao booksDao = new BooksDaoImpl(conn);
			result = booksDao.addBooks(book);
			DBUtils.commit(conn);
		} catch (Exception e) {
			System.out.println("增加books錯誤" + e.getMessage());
		} finally {
			DBUtils.closeConnection(conn);
		}
		return result;
	}

	@Override
	public int delBooks(int book_id) {
		Connection conn = null;
		int result = 0;
		try {
			conn = DBUtils.getConnection();
			DBUtils.beginTransaction(conn);
			BooksDao booksDao = new BooksDaoImpl(conn);
			result = booksDao.delBooks(book_id);
			DBUtils.commit(conn);
		} catch (Exception e) {
			System.out.println("刪除books錯誤" + e.getMessage());
		} finally {			DBUtils.closeConnection(conn);
		}
		return result;
	}

}

我們啟動一下專案,我們作為使用者直接看到的就是表示層的檢視了

而當我們點選查詢,會跳轉到查詢的檢視

點選查詢,我們會跳轉到表示層的控制器,也就是Servlet,此時Servle會呼叫業務邏輯層的方法

而業務邏輯層則會呼叫持久層(DAO層)的方法

最後持久層連線到資料庫,讀取資料庫的資料,儲存為一個Model類

將結果原路返回給表示層的檢視View

整個執行過程可以濃縮為一張圖: