案例: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 }頁
每頁顯示${pageBean.pageSize }條
總的記錄數${pageBean.totalSize }
<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>