1. 程式人生 > >案例:MVC模式

案例:MVC模式

是什麼?

MVC是軟體開發的一種設計規範 ,早在80年代的時候就被提出了。 它用一種業務邏輯、資料、介面顯示分離的方法組織程式碼 , 極大的提高了我們在設計和開發上的效率
M  : Model【模型】
V   : View[【檢視】
C     : Controller【控制】

有什麼用?

MVC 實現了分層解耦, 將軟體分成三個部分  M(模型層)  V(檢視層)  C (控制層)  

V(檢視層):負責對頁面展示的處理, 在這一層上只針對 檢視的展示

M(模型層):負責對C(控制層) 傳輸過來的資料,進行封裝,打造成一個模型,交給檢視層顯示。 一般來說有可能是一個 JavaBean , 也有可能是EJB的來處理

C(控制層):控制層主要是 接收使用者過來的請求, 然後去呼叫模型層處理資料,接著返回資料給客戶端。

怎麼用?

其實這是一種開發模式,並不是像我們平常寫程式碼一樣, 匯入jar檔案 然後 使用哪個類、哪個方法一樣。 MVC 是針對我們的程式進行分層設計, 讓我們在開發的時候,能夠高效的去寫程式碼。
以後如果相對程式進行擴充套件,那麼只要按部就班的,在不同的層級下增刪改程式碼即可。

以目前的階段來開。 JSP + Servlet + JavaBean 就是一種MVC 的設計模式。 

控制層 :使用Servlet來接收 瀏覽器的請求, 並且對請求進行分析,然後呼叫對應的模型層來處理

模型層: 模型層的作用是 針對資料進行處理 然後返回給控制層。 那麼在這裡 Dao + Service + JavaBean 也可以算作是模型層的一部分
                當然未來大家學習到更深層次的知識,這部分就可以使用EJB來替代了。

檢視層:檢視層在這裡將Jsp/html 歸類到此層, 用於顯示檢視給使用者看。 檢視層只負責顯示 , 從控制層那邊拿過來模型資料顯示

 學生管理系統案例

資料庫準備:

CREATE DATABASE stus;
USE stus;
CREATE TABLE stu (
	sid INT PRIMARY KEY  AUTO_INCREMENT,
	sname VARCHAR (20),
	gender VARCHAR (5),
	phone VARCHAR (20),
	birthday DATE,
	hobby VARCHAR(50),
	info VARCHAR(200)
);

查詢

1.    先寫一個JSP 頁面, 裡面放一個超連結 。

<a href="StudentListServlet"> 學生列表顯示</a>

2.    寫Servlet, 接收請求, 去呼叫 Service  , 由service去呼叫dao

3.    先寫Dao , 做Dao實現。

public interface StudentDao {
    /**
     *   查詢所有學生
     * @return  List<Student>
     */
    List<Student> findAll()  throws SQLException ;
}
---------------------------------------------

public class StudentDaoImpl implements StudentDao {
    /**
     * 查詢所有學生
     * @throws SQLException 
     */
	@Override
	public List<Student> findAll() throws SQLException {
		QueryRunner runner = new QueryRunner(JDBCUtil02.getDataSource());
		return runner.query("select * from stu", new BeanListHandler<Student>(Student.class));
	}
	
}

4.   再Service , 做Service的實現。

/**
 * 這是學生的業務處理規範
 * @author xiaomi
 *
 */
public interface StudentService {
    /**
	 * 查詢所有學生
	 * @return  List<Student>
	 */
	List<Student> findAll()  throws SQLException ;
}
------------------------------------------
/**
 * 這是學生業務實現
 * @author xiaomi
 *
 */
public class StudentServiceImpl implements StudentService{
	@Override
	public List<Student> findAll() throws SQLException {
		StudentDao dao = new StudentDaoImpl();
		return dao.findAll();
	}
}

5. 在servlet 儲存資料,並且做出頁面響應。

protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
    try {
		//1、查詢出所有學生
		StudentService service = new StudentServiceImpl();
		List<Student> list = service.finaAll();
		
		//2、將資料存到作用域中
		request.setAttribute("list", list);
		
		//3、跳轉
		request.getRequestDispatcher("list.jsp").forward(request, response);
	} catch (SQLException e) {
		e.printStackTrace();
	}
}

6. 在list.jsp上顯示資料

   EL + JSTL  + 表格

增加 

1. 先跳轉到增加的頁面 , 編寫增加的頁面

2. 點選新增,提交資料到AddServlet . 處理資料。

3. 呼叫service

4. 呼叫dao, 完成資料持久化。

5. 完成了這些儲存工作後,需要跳轉到列表頁面。 這裡不能直接跳轉到列表頁面,否則沒有什麼內容顯示。 應該先跳轉到查詢所有學生資訊的那個Servlet, 由那個Servlet再去跳轉到列表頁面

6. 愛好的value 值有多個。 

//String hobby = request.getParameter("hobby"); //籃球---->只顯示一個引數

String[] hobbys = request.getParameterValues("hobby");//[籃球,足球,寫字]
String hobby = Arrays.toString(hobbys);
hobby = hobby.substring(1, hobby.length()-1);

注意點:輸入的生日是字串,字串轉化為Date型別程式碼為
 

String birthday = request.getParameter("birthday");//"1980-8-9"
Date date = new SimpleDateFormat("yyyy-MM-dd").parse(birthday); 

刪除

1. 點選超連結,彈出一個詢問是否刪除的對話方塊,如果點選了確定,那麼就真的刪除。

注意:刪除的時候要將被刪除學生的sid編號傳過去,根據學生編號sid刪除學生

<a href="#" onclick="doDelete(${stu.sid})">刪除</a>

讓超連結,執行一個js方法     

 <script type="text/javascript">
    function doDelete(sid) {
    /* 如果這裡彈出的對話方塊,使用者點選的是確定,就馬上去請求Servlet。 
       如何知道使用者點選的是確定。
       如何在js的方法中請求servlet。 */
    var flag = confirm("是否確定刪除?");
    if(flag){
        //表明點了確定。 訪問servlet。 在當前標籤頁上開啟 超連結,
        //window.location.href="DeleteServlet?sid="+sid;
        location.href="DeleteServlet?sid="+sid;
        }
    }
</script>

2. 在js訪問裡面判斷點選的選項,然後跳轉到servlet。

3. servlet收到了請求,然後去呼叫service , service去呼叫dao

更新

1. 點選列表上的更新, 先跳轉到一個EditServlet 

> 在這個Servlet裡面,先根據ID 去查詢這個學生的所有資訊出來。

2. 跳轉到更新的頁面。 ,然後在頁面上顯示資料

其中部分jsp程式碼為:

<tr>
	<td>姓名</td>
	<td><input type="text" name="sname" value="${stu.sname }"></td>
</tr>

<tr>
    <!-- 如果性別是男的,  可以在男的性別 input標籤裡面, 出現checked ,
		 如果性別是女的,  可以在女的性別 input標籤裡面,出現checked -->
	<td>性別</td>
	<td><input type="radio" name="gender" value="男" <c:if test="${stu.gender=='男' }">checked</c:if>>男 
	<input type="radio" name="gender" value="女" <c:if test="${stu.gender=='女' }">checked</c:if>>女
	</td>
</tr>

<tr>
	<td>愛好</td>
	<!-- 愛好: 籃球 , 足球 , 看書 
       	因為愛好有很多個,  裡面存在包含的關係 -->
	<td>
        <input type="checkbox" name="hobby" value="游泳" <c:if test="${fn:contains(stu.hobby,'游泳') }">checked</c:if>>游泳 
	    <input type="checkbox" name="hobby" value="籃球" <c:if test="${fn:contains(stu.hobby,'籃球') }">checked</c:if>>籃球 
		<input type="checkbox" name="hobby" value="足球" <c:if test="${fn:contains(stu.hobby,'足球') }">checked</c:if>>足球 
	    <input type="checkbox" name="hobby" value="看書" <c:if test="${fn:contains(stu.hobby,'看書') }">checked</c:if>>看書 
		<input type="checkbox" name="hobby" value="寫字" <c:if test="${fn:contains(stu.hobby,'寫字') }">checked</c:if>>寫字
	</td>
</tr>

3. 修改完畢後,提交資料到UpdateServlet

> 提交上來的資料是沒有帶id的,所以我們要手動建立一個隱藏的輸入框, 在這裡面給定id的值, 以便提交表單,帶上id。 

<form method="post" action="UpdateServlet">
	<input type="hidden" name="sid" value="${stu.sid }">
	...
</form>

4. 獲取資料,呼叫service, 呼叫dao.

模糊查詢

1、在列表頁輸入名字或者選擇性別或按兩者查詢,點選查詢按鈕後,先跳轉到SearchStudentServlet

>根據姓名或性別,或者兩者都有 ,在這個Servlet裡面,先根據  姓名/性別/二者 去查詢學生的所有資訊出來。Dao實現為:

/*
 * 這裡要分析一下: 如果只有姓名,select * from stu where sname like ?; 如果只有性別,select * from
 * stu where gender = ?
 * 
 * 如果兩個都有select * from stu where gender = ? and sname like ?
 * 
 * 如果兩個都沒有就查詢所有。
 */
String sql = "select * from stu where 1=1";
List<String> list = new ArrayList<String>();

if (!TextUtil.isEmpty(sname)) {
	sql = sql + " and sname like ?";
	list.add("%" + sname + "%");
}
if (!TextUtil.isEmpty(gender)) {
	sql = sql + " and gender = ?";
	list.add(gender);
}
for (String str : list) {
	System.out.println("模糊查詢:" + str);
}
return runner.query(sql, new BeanListHandler<Student>(Student.class), list.toArray());

2、跳轉到列表頁面,顯示資料

分頁顯示

分頁屬於一個業務, 裡面包含多個邏輯單元。
每一頁的資料包含
:     
                class PageBean{
                    當前頁        int currentPage
                    總頁數       int totalPage
                    總記錄數    int totalSize
                    每頁記錄數  int pageSize
                    該頁的學生集合。 List<Student>
                }

1、在首頁放置一個超連結

<a href="StudentListPageServlet?currentPage=1">分頁列表顯示</a>

2、Dao實現查詢當前頁的學生資訊以及查詢學生記錄總數

/**
 * 查詢當前頁的學生
 * 
 * @throws SQLException
 */
@Override
public List<Student> findByPage(int currentPage) throws SQLException {
	// 第一個問號,代表一頁返回多少條記錄 , 第二個問號, 跳過前面的多少條記錄。
	// 5 0 --- 第一頁 (1-1)*5
	// 5 5 --- 第二頁 (2-1)*5
	// 5 10 --- 第三頁
	QueryRunner runner = new QueryRunner(JDBCUtil.getDataSource());
	return runner.query("select * from stu limit ? offset ?", new BeanListHandler<Student>(Student.class),
			PAGE_SIZE, (currentPage-1) * PAGE_SIZE);
}

@Override
public int count() throws SQLException {
	QueryRunner runner = new QueryRunner(JDBCUtil.getDataSource());
	//用於處理平均值、總的個數
	Long result = (Long)runner.query("select count(*) from stu",new ScalarHandler());
	return result.intValue();
}

ServiceImpl實現:將頁面展示所需要的資料都封裝到一個PageBean物件中

@Override
public PageBean finaByPage(int currentPage) throws SQLException {
	StuDao dao = new StuDaoImpl();
	
	//封裝分頁的該頁資料
	PageBean<Student> pageBean = new PageBean<Student>();
		
	int pageSize = dao.PAGE_SIZE;
	pageBean.setList(dao.findByPage(currentPage)); //設定這一頁的學生資料
	pageBean.setTotalSize(dao.count()); //總記錄數
	pageBean.setCurrentPage(currentPage);//設定當前頁
	pageBean.setPageSize(pageSize);//設定每頁顯示的記錄數
		
	int count = dao.count();
	//200 , 10 ==20   201 , 10 = 21   201 % 10 == 0 ?201 / 10 :201 % 10 + 1
	pageBean.setTotalPage(count % pageSize == 0?count/pageSize:(count/pageSize)+1);//設定總頁數
	return pageBean;
}

 3、寫Servlet, 接收請求, 去呼叫 Service  , 由service去呼叫dao

4、list_page.jsp顯示分頁效果

<tr>
    <td colspan="8">
	第${pageBean.currentPage }頁/共${pageBean.totalPage }頁
	&nbsp;&nbsp;
	每頁顯示${pageBean.pageSize }條	&nbsp;&nbsp;&nbsp;
	總的記錄數${pageBean.totalSize } &nbsp;&nbsp;&nbsp;
	<c:if test="${pageBean.currentPage !=1 }">
		<a href="StudentListPageServlet?currentPage=1">首頁</a>
		<a href="StudentListPageServlet?currentPage=${pageBean.currentPage-1}">上一頁</a>
	</c:if>
	<c:forEach begin="1" end="${pageBean.totalPage }" var="i">
		<c:if test="${pageBean.currentPage !=i }">
			<a href="StudentListPageServlet?currentPage=${i }">${i }</a>
		</c:if>
	</c:forEach>
				
	<c:if test="${pageBean.currentPage !=pageBean.totalPage }">
		<a href="StudentListPageServlet?currentPage=${pageBean.totalPage }">尾頁</a>
		<a href="StudentListPageServlet?currentPage=${pageBean.currentPage+1}">下一頁</a>
	</c:if>
    </td>
</tr>