1. 程式人生 > >02-2 MVC

02-2 MVC

javaEE的設計模式


歷史沿革:
 1. model1(jsp + javaBean)

jsp承擔了給使用者顯示和處理內部邏輯的任務,不安全,也不利於維護

 2. model2 -> MVC(今天的主題)
    Servlet + jsp + javaBean

關於model1和model2,這篇文章博主寫的很詳細:https://www.cnblogs.com/wzjhoutai/p/6829457.html

MVC


   mvc是 一套設計模式, 裡面主要是裝飾模式

    M - Model 模型 : javabean

-> 業務模型 / 資料模型
    V - View  檢視 : jsp -> 負責單純的頁面顯示
    C - Controller 控制器 Servlet -> 處理使用者請求 / 獲取資料 / 呼叫業務模型, 拿到資料模型 / 傳遞資料 / 指定用哪個檢視顯示

 

MVC和三層架構的關係?
    沒啥關係

    三層架構: web層 + service層 + dao層

    MVC 發生在web層

 

mvc小專案實戰:

實現如圖所示購物網站

要求如下:

1.mvc設計模式

2.有分頁效果

3.有商品詳細資訊頁

商品詳細資訊頁:

 

 

根據mvc設計模式思想,得出以下程式流程圖

設計的分頁效果流程圖

分頁效果的主要思想是建立一個泛型類PageBean,用於存放任何型別的商品資訊以及在資料庫中的記錄數等

package com.wowowo.bean;

import java.util.List;

public class PageBean<T> {
	// 存放當前頁數
	private int pageNum;
	// 存放每頁最大記錄數
	private int pageSize;
	// 存放從哪一條記錄開始讀取,用於查詢語句limit中
	private int pageStart;
	// 存放記錄總數,用於末頁按鈕
	private int pageMaxNum;
	// 存放最大頁數,用於末頁按鈕
	private int pageMaxSize;
	private List<T> data;

	public PageBean(int pageNum, int pageSize, int pageMaxNum) {
		super();
		// 構造方法傳三個成員屬性,其餘2個成員屬性通過計算得出
		this.pageNum = pageNum;
		this.pageSize = pageSize;
		this.pageMaxNum = pageMaxNum;
		// 最大頁數通過記錄總數加上每頁記錄-1除以每頁記錄獲得
		// 1.每頁5條 11條:3頁=(15+5-1)/5; 15條:3頁=(11+5-1)/5
		pageMaxSize = (pageMaxNum + pageSize - 1) / pageSize;
		
		// 另一種計算最大頁數方法
		// 先整除
		// pageMaxSize=pageMaxNum/pageSize;
		// 有餘數就加1
		// if(pageMaxNum%pageSize!=0){
		// pageMaxSize++;
		// }

		/// 計算在資料庫中執行查詢語句時的初始位置
		pageStart = (pageNum - 1) * pageSize;

	}
//get, set,tostring方法略



}

 

使用者訪問首頁,預設首頁(localhost:8080/my1023hw)為index.jsp,因為只寫了index.jsp(這個在web.xml配置中)

原因:

<welcome-file-list>用於指定應用的首頁
裡面可以指定多個檔案,應用伺服器會按從上到下的順序搜尋,如果找到就了進入該頁面,如果都遍歷完了還沒找到就會返回404錯誤程式碼給瀏覽器。

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
  <display-name>my1023hw</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
</web-app>

index.jsp(首頁)

使用者訪問首頁,它會請求轉發到goodservlet(goodservlet設定了註解,和它相對映的url為/goods)

<%@ 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>
<%-- 很重要:這個是jsp請求轉發,給後端看的,不用加web專案名 --%>
<jsp:forward page="/goods"></jsp:forward>

</body>
</html>

goodsServlet(首頁):

根據傳入的當前頁數和最大頁數,呼叫service層和dao層方法查詢記錄並返回pagebean

package com.wowowo.web;

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 org.eclipse.jdt.internal.compiler.parser.ParserBasicInformation;

import com.wowowo.bean.PageBean;
import com.wowowo.bean.Product;
import com.wowowo.service.ProductService;
import com.wowowo.service.impl.ProductServiceImpl;

@WebServlet("/goods")
public class GoodsServlet extends HttpServlet {

	// 依賴於業務邏輯層
	private ProductService ps = new ProductServiceImpl();

	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		// 獲取使用者上傳的pageNum和pageSize
		int pageNum = 1;
        //pageNum放在了url中,get方法獲取
		String s_pageNum = request.getParameter("pageNum");
		if (s_pageNum != null) {
			pageNum = Integer.parseInt(s_pageNum);
		}

		int pageSize = 5;
        //pageSize放在了url中,get方法獲取
		String s_pageSize = request.getParameter("pageSize");
		if (s_pageSize != null) {
			pageSize = Integer.parseInt(s_pageSize);
		}

		// 呼叫業務模型 獲取資料模型
		PageBean<Product> pageBean = ps.queryAll(pageNum, pageSize);

		// 放到request域中
		request.setAttribute("pageBean", pageBean);

		// 轉發到jsp頁面
		request.getRequestDispatcher("/main.jsp").forward(request, response);
	}

}

service層(參考架構基礎):

package com.wowowo.service.impl;

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

import com.wowowo.bean.PageBean;
import com.wowowo.bean.Product;
import com.wowowo.dao.ProductDao;
import com.wowowo.dao.impl.ProductDaoImpl;
import com.wowowo.database.ConnectionFactory;
import com.wowowo.service.ProductService;

public class ProductServiceImpl implements ProductService {

	private ProductDao pd = new ProductDaoImpl();

	@Override
	public PageBean<Product> queryAll(int pageNum, int pageSize) {
		Connection conn = null;
		List<Product> list = new ArrayList<>();
		try {
			conn = ConnectionFactory.getConnection();
			// 查詢獲得記錄數
			int count = pd.queryCount(conn);
			// 構造pageBean物件
			PageBean<Product> pageBean = new PageBean<Product>(pageNum, pageSize, count);
			//呼叫dao層方法查詢相關記錄,不返回值,在方法裡面對pageBean修改
			//傳引用賦值和傳值賦值的區別建議再看看
			pd.queryAll(conn, pageBean);
			return pageBean;
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			if (conn != null) {

				try {
					conn.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}

			}

		}
		return null;
	}

	// 這個方法用於商品詳情頁面
	@Override
	public Product queryById(int uid) {

		Connection conn = null;
		List<Product> list = new ArrayList<>();
		try {
			conn = ConnectionFactory.getConnection();
			return pd.queryById(conn, uid);
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			if (conn != null) {

				try {
					conn.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}

			}

		}
		return null;
	}

}

dao層用於和資料庫互動(參考架構基礎);

package com.wowowo.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.wowowo.bean.PageBean;
import com.wowowo.bean.Product;
import com.wowowo.dao.ProductDao;
import com.wowowo.database.ConnectionFactory;

public class ProductDaoImpl implements ProductDao {

	// 查記錄總數
	@Override
	public int queryCount(Connection conn) throws SQLException {

		String sql = "select count(*)from product";
		PreparedStatement ps = conn.prepareStatement(sql);
		ResultSet rs = ps.executeQuery();
		if (rs.next()) {

			return rs.getInt(1);
		}
		return 0;

	}

	// 根據這一頁的的初始記錄位置,和每頁顯示數量查詢相關記錄並組裝成list賦值給pageBean,不用返回
	@Override
	public void queryAll(Connection conn, PageBean<Product> pageBean) throws SQLException {

		List<Product> list = new ArrayList<>();
		String sql = "select *from product limit ?,?";
		PreparedStatement ps = conn.prepareStatement(sql);
		ps.setInt(1, pageBean.getPageStart());
		ps.setInt(2, pageBean.getPageSize());

		ResultSet rs = ps.executeQuery();
		while (rs.next()) {
			Product product = new Product();
			product.setProdId(rs.getInt("prodId"));
			product.setProdName(rs.getString("prodName"));
			product.setProdImage(rs.getString("prodImage"));
			product.setProdPrice(rs.getDouble("prodPrice"));
			product.setProdAmount(rs.getInt("prodAmount"));
			list.add(product);
		}
		pageBean.setData(list);
	}

	// 通過id查詢商品,用於顯示商品詳情
	@Override
	public Product queryById(Connection conn, int uid) throws SQLException {

		String sql = "select *from product where prodid =?";
		PreparedStatement ps = conn.prepareStatement(sql);
		ps.setInt(1, uid);

		ResultSet rs = ps.executeQuery();
		if (rs.next()) {
			Product product = new Product();
			product.setProdId(rs.getInt("prodId"));
			product.setProdName(rs.getString("prodName"));
			product.setProdImage(rs.getString("prodImage"));
			product.setProdPrice(rs.getDouble("prodPrice"));
			product.setProdAmount(rs.getInt("prodAmount"));
			return product;
		}
		return null;

	}
}

對我而言,難點在於jsp頁面,畢竟剛學

首頁(main)的jsp(view層)

<%@page import="java.util.ArrayList"%>
<%@page import="java.util.List"%>
<%@page import="com.wowowo.bean.*"%>
<%@ 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>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link
	href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"
	rel="stylesheet">
<script
	src="https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js"></script>
<script
	src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js"></script>
<style type="text/css">
.prod {
	border: 1px solid black;
	width: 230px;
}

.prod_price {
	float: right;
}
</style>
</head>
<body>

	<h1 class="text-center">歡迎訪問服裝商城</h1>
	<div class="container">

		<%
			//request域物件裡拿到servlet傳過來的資料模型,強轉,拿出記錄list 
			PageBean<Product> pageBean = (PageBean<Product>) request.getAttribute("pageBean");
			//拿出商品list,遍歷輸出每一條記錄 
			List<Product> list = pageBean.getData();

			for (int i = 0; i < list.size(); i++) {
		%>
		<div class="prod col-md-3">
			<div>
<%-- a標籤的屬性href屬性用於指定超連結目標的URL,在url尾部新增?uid=商品id跳轉到詳細資訊servlet --%>
				<a href="/my1023hw/single?uid=<%=list.get(i).getProdId()%>"><img
<%-- 圖片路徑通過jsp指令碼實現拼接 --%>
					src="images/<%=list.get(i).getProdImage()%>" /></a>
			</div>
			<div>
				<%
					//商品名,也可以用指令碼表示式 <%==list.get(i).getProdName()%》
						out.write(list.get(i).getProdName());
				%>
				<span class="prod_price">價格:<%
					//商品價格,也可以用指令碼表示式 <%==list.get(i).getProdName()%》
				
					out.write(String.valueOf(list.get(i).getProdPrice())); %>
				</span>
			</div>
		</div>

		<%
			}
		%>
		<%--  迴圈結束 --%>
	</div>
	<div style="text-align: center;">
		<%--a標籤的 href屬性用於指定超連結目標的 URL,通過在後面新增?k-v&k-v在servlet的get方式能獲取到引數--%>
		<%--  首頁為第一頁,url裡輸入首頁和點選首頁的效果一致,每頁5條記錄 --%>
		<a href="goods?pageNum=1&pageSize=5" class="btn btn-danger">首頁</a>
		<%--  上一頁為當前頁-1,前提是當前頁不是第一頁,採用三目運算子實現,每頁5條記錄 --%>
		<a
			href="goods?pageNum=<%=pageBean.getPageNum() <= 1 ? 1 : pageBean.getPageNum() - 1%>&pageSize=5"
			class="btn btn-danger">上一頁</a>
		<%--  下一頁為當前頁+1,前提是當前頁不是末頁,採用三目運算子實現,每頁5條記錄 --%>
		<a
			href="goods?pageNum=<%=pageBean.getPageNum() >= pageBean.getPageMaxSize() ? pageBean.getPageNum()
					: pageBean.getPageNum() + 1%>&pageSize=5"
			class="btn btn-danger">下一頁</a>
		<%--  末頁為在pagebean的構造方法中有計算,只需取出即可,每頁5條記錄 --%>
		<a href="goods?pageNum=<%=pageBean.getPageMaxSize()%>&pageSize=5"
			class="btn btn-danger">末頁</a>
	</div>

</body>
</html>

詳細資訊頁面的設計:

在首頁的商品圖片設定a標籤(商品id放在url中)跳轉到singleservlet(get方式獲取url中的引數商品id並做業務處理,返回一個數據模型放到request)轉發到jsp顯示

singleservlet(controller層)

package com.wowowo.web;

import java.io.IOException;

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.wowowo.bean.Product;
import com.wowowo.service.ProductService;
import com.wowowo.service.impl.ProductServiceImpl;

/**
 * Servlet implementation class SingleServlet
 */
@WebServlet("/single")
public class SingleServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
	private ProductService ps=new ProductServiceImpl();

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //get方式獲取的商品id
	int uid = Integer.parseInt(request.getParameter("uid"));
//傳入邏輯模型
	Product p=ps.queryById(uid);
	//request新增資料模型
	request.setAttribute("product", p);
//跳轉到single.jsp(view層)
	request.getRequestDispatcher("/single.jsp").forward(request, response);;
	
	}

}

singleservlet跳轉到的jsp(view層)

顯示單一商品資訊

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@page import="com.wowowo.bean.*"%>
<!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>
<style type="text/css">
.single {
	width: 500px;
	text-align: center;
	margin: auto;
}

.detail {
	height: 195px;
	float: left;
}
</style>

</head>
<body>
	<%
		Product p = (Product) request.getAttribute("product");
	%>

	<div class="single">
		<div class="detail">
			<img src="/my1023hw/images/<%=p.getProdImage()%>" />
		</div>
		<div class="detail">
			商品名稱:<%=p.getProdName()%><br /> 商品單價:<%=p.getProdPrice()%><br />
			商品庫存:<%=p.getProdAmount()%><br /> <input type="text" value="1">
			<br /> <input type="button" value="新增到購物車"> <input
				type="button" value="立即購買">
		</div>

	</div>
</body>
</html>