JavaWeb三層架構詳解
什麼是三層架構?
三層架構(3-tier architecture) 通常意義上的三層架構就是將整個業務應用劃分為:介面層(User Interface layer)、業務邏輯層(Business Logic Layer)、資料訪問層(Data access layer)。區分層次的目的即為了“高內聚低耦合”的思想。在軟體體系架構設計中,分層式結構是最常見,也是最重要的一種結構。微軟推薦的分層式結構一般分為三層,從下至上分別為:資料訪問層(又稱為持久層)、業務邏輯層(又或稱為領域層)、表示層。
表示層(UI層):
表示層也稱為介面層,位於最外層(最上層),離使用者最近。用於顯示資料和接收使用者輸入的資料
業務邏輯層(BLL層):
負責關鍵業務的處理和資料的傳遞。複雜的邏輯判斷和涉及到資料庫的資料驗證都需要在此做出處理。主要是針對具體的問題的操作,也可以理解成對資料層的操作,對資料業務邏輯處理,如果說資料層是積木,那邏輯層就是對這些積木的搭建。
資料訪問層(DAL層):
主要負責對資料庫的直接訪問,為業務邏輯層提供資料,根據傳入的值來操作資料庫,增、刪、改、查。
為什麼要用三層架構呢?
1.團隊開發,便於管理
三層架構使得合作開發成為可能,由於各層相互獨立,一個小組只需負責一小塊就可以。結構化的程式設計方法面對大型的專案會感到力不從心,因為結構化設計必定會使程式變的錯綜複雜。邏輯主要在
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
整個執行過程可以濃縮為一張圖: