企業(yè)發(fā)展歷程網(wǎng)站關(guān)鍵詞優(yōu)化怎么操作
1,JSP 概述
==JSP(全稱:Java Server Pages):Java 服務(wù)端頁面。==是一種動態(tài)的網(wǎng)頁技術(shù),其中既可以定義 HTML、JS、CSS等靜態(tài)內(nèi)容,還可以定義 Java代碼的動態(tài)內(nèi)容,也就是 JSP = HTML + Java
。如下就是jsp代碼
<html><head><title>Title</title></head><body><h1>JSP,Hello World</h1><%System.out.println("hello,jsp~");%></body> </html>
上面代碼 h1
標(biāo)簽內(nèi)容是展示在頁面上,而 Java 的輸出語句是輸出在 idea 的控制臺。
那么,JSP 能做什么呢?現(xiàn)在我們只用 servlet
實(shí)現(xiàn)功能,看存在什么問題。如下圖所示,當(dāng)我們登陸成功后,需要在頁面上展示用戶名
上圖的用戶名是動態(tài)展示,也就是誰登陸就展示誰的用戶名。只用 servlet
如何實(shí)現(xiàn)呢?在今天的資料里已經(jīng)提供好了一個 LoginServlet
,該 servlet
就是實(shí)現(xiàn)這個功能的,現(xiàn)將資料中的 LoginServlet.java
拷貝到 request-demo
項(xiàng)目中來演示。接下來啟動服務(wù)器并訪問登陸頁面
輸入了 zhangsan
用戶的登陸信息后點(diǎn)擊 登陸
按鈕,就能看到如下圖效果
當(dāng)然如果是 lisi
登陸的,在該頁面展示的就是 lisi,歡迎您
,動態(tài)的展示效果就實(shí)現(xiàn)了。那么 LoginServlet
到底是如何實(shí)現(xiàn)的,我們看看它里面的內(nèi)容
上面的代碼有大量使用到 writer
對象向頁面寫標(biāo)簽內(nèi)容,這樣我們的代碼就顯得很麻煩;將來如果展示的效果出現(xiàn)了問題,排錯也顯得有點(diǎn)力不從心。而 JSP 是如何解決這個問題的呢?在資料中也提供了一個 login.jsp
頁面,該頁面也能實(shí)現(xiàn)該功能,現(xiàn)將該頁面拷貝到項(xiàng)目的 webapp
下,需要修改 login.html
中表單數(shù)據(jù)提交的路徑為下圖
重新啟動服務(wù)器并進(jìn)行測試,發(fā)現(xiàn)也可以實(shí)現(xiàn)同樣的功能。那么 login.jsp
又是如何實(shí)現(xiàn)的呢?那我們來看看 login.jsp
的代碼
上面代碼可以看到里面基本都是 HTML
標(biāo)簽,而動態(tài)數(shù)據(jù)使用 Java 代碼進(jìn)行展示;這樣操作看起來要比用 servlet
實(shí)現(xiàn)要舒服很多。
JSP 作用:簡化開發(fā),避免了在Servlet中直接輸出HTML標(biāo)簽。
2,JSP 快速入門
接下來我們做一個簡單的快速入門代碼。
2.1 搭建環(huán)境
創(chuàng)建一個maven的 web 項(xiàng)目,項(xiàng)目結(jié)構(gòu)如下:
pom.xml
文件內(nèi)容如下:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion> ?<groupId>org.example</groupId><artifactId>jsp-demo</artifactId><version>1.0-SNAPSHOT</version><packaging>war</packaging> ?<properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties> ?<dependencies><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>3.1.0</version><scope>provided</scope></dependency></dependencies> ?<build><plugins><plugin><groupId>org.apache.tomcat.maven</groupId><artifactId>tomcat7-maven-plugin</artifactId><version>2.2</version></plugin></plugins></build> </project>
2.2 導(dǎo)入 JSP 依賴
在 dependencies
標(biāo)簽中導(dǎo)入 JSP 的依賴,如下
<dependency><groupId>javax.servlet.jsp</groupId><artifactId>jsp-api</artifactId><version>2.2</version><scope>provided</scope> </dependency>
該依賴的 scope
必須設(shè)置為 provided
,因?yàn)?tomcat 中有這個jar包了,所以在打包時我們是不希望將該依賴打進(jìn)到我們工程的war包中。
2.3 創(chuàng)建 jsp 頁面
在項(xiàng)目的 webapp
下創(chuàng)建jsp頁面
通過上面方式創(chuàng)建一個名為 hello.jsp
的頁面。
2.4 編寫代碼
在 hello.jsp
頁面中書寫 HTML
標(biāo)簽和 Java
代碼,如下
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head><title>Title</title> </head> <body><h1>hello jsp</h1> ?<%System.out.println("hello,jsp~");%> </body> </html>
2.5 測試
啟動服務(wù)器并在瀏覽器地址欄輸入 http://localhost:8080/jsp-demo/hello.jsp
,我們可以在頁面上看到如下內(nèi)容
同時也可以看到在 idea
的控制臺看到輸出的 hello,jsp~
內(nèi)容。
3,JSP 原理
我們之前說 JSP 就是一個頁面,那么在 JSP 中寫 html
標(biāo)簽,我們能理解,但是為什么還可以寫 Java
代碼呢?
因?yàn)?==JSP 本質(zhì)上就是一個 Servlet。==接下來我們聊聊訪問jsp時的流程
-
瀏覽器第一次訪問
hello.jsp
頁面 -
tomcat
會將hello.jsp
轉(zhuǎn)換為名為hello_jsp.java
的一個Servlet
-
tomcat
再將轉(zhuǎn)換的servlet
編譯成字節(jié)碼文件hello_jsp.class
-
tomcat
會執(zhí)行該字節(jié)碼文件,向外提供服務(wù)
我們可以到項(xiàng)目所在磁盤目錄下找 target\tomcat\work\Tomcat\localhost\jsp-demo\org\apache\jsp
目錄,而這個目錄下就能看到轉(zhuǎn)換后的 servlet
打開 hello_jsp.java
文件,來查看里面的代碼
由上面的類的繼承關(guān)系可以看到繼承了名為 HttpJspBase
這個類,那我們在看該類的繼承關(guān)系。到資料中的找如下目錄: 資料\tomcat源碼\apache-tomcat-8.5.68-src\java\org\apache\jasper\runtime
,該目錄下就有 HttpJspBase
類,查看該類的繼承關(guān)系
可以看到該類繼承了 HttpServlet
;那么 hello_jsp
這個類就間接的繼承了 HttpServlet
,也就說明 hello_jsp
是一個 servlet
。
繼續(xù)閱讀 hello_jsp
類的代碼,可以看到有一個名為 _jspService()
的方法,該方法就是每次訪問 jsp
時自動執(zhí)行的方法,和 servlet
中的 service
方法一樣 。
而在 _jspService()
方法中可以看到往瀏覽器寫標(biāo)簽的代碼:
以前我們自己寫 servlet
時,這部分代碼是由我們自己來寫,現(xiàn)在有了 jsp
后,由tomcat完成這部分功能。
4,JSP 腳本
JSP腳本用于在 JSP頁面內(nèi)定義 Java代碼。在之前的入門案例中我們就在 JSP 頁面定義的 Java 代碼就是 JSP 腳本。
4.1 JSP 腳本分類
JSP 腳本有如下三個分類:
-
<%...%>:內(nèi)容會直接放到_jspService()方法之中
-
<%=…%>:內(nèi)容會放到out.print()中,作為out.print()的參數(shù)
-
<%!…%>:內(nèi)容會放到_jspService()方法之外,被類直接包含
代碼演示:
在 hello.jsp
中書寫
<%System.out.println("hello,jsp~");int i = 3; %>
通過瀏覽器訪問 hello.jsp
后,查看轉(zhuǎn)換的 hello_jsp.java
文件,i 變量定義在了 _jspService()
方法中
在 hello.jsp
中書寫
<%="hello"%> <%=i%>
通過瀏覽器訪問 hello.jsp
后,查看轉(zhuǎn)換的 hello_jsp.java
文件,該腳本的內(nèi)容被放在了 out.print()
中,作為參數(shù)
在 hello.jsp
中書寫
<%!void ?show(){}String name = "zhangsan"; %>
通過瀏覽器訪問 hello.jsp
后,查看轉(zhuǎn)換的 hello_jsp.java
文件,該腳本的內(nèi)容被放在了成員位置
4.2 案例
4.2.1 需求
使用JSP腳本展示品牌數(shù)據(jù)
說明:
-
在資料
資料\1. JSP案例素材
中提供了brand.html
靜態(tài)頁面 -
在該案例中數(shù)據(jù)不從數(shù)據(jù)庫中查詢,而是在 JSP 頁面上寫死
4.2.2 實(shí)現(xiàn)
-
將資料
資料\1. JSP案例素材
中的Brand.java
文件放置到項(xiàng)目的com.itheima.pojo
包下 -
在項(xiàng)目的
webapp
中創(chuàng)建brand.jsp
,并將brand.html
頁面中的內(nèi)容拷貝過來。brand.jsp
內(nèi)容如下<%@ page contentType="text/html;charset=UTF-8" language="java" %> <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title> </head> <body> <input type="button" value="新增"><br> <hr><table border="1" cellspacing="0" width="800"><tr><th>序號</th><th>品牌名稱</th><th>企業(yè)名稱</th><th>排序</th><th>品牌介紹</th><th>狀態(tài)</th><th>操作</th> ?</tr><tr align="center"><td>1</td><td>三只松鼠</td><td>三只松鼠</td><td>100</td><td>三只松鼠,好吃不上火</td><td>啟用</td><td><a href="#">修改</a> <a href="#">刪除</a></td></tr> ?<tr align="center"><td>2</td><td>優(yōu)衣庫</td><td>優(yōu)衣庫</td><td>10</td><td>優(yōu)衣庫,服適人生</td><td>禁用</td> ?<td><a href="#">修改</a> <a href="#">刪除</a></td></tr> ?<tr align="center"><td>3</td><td>小米</td><td>小米科技有限公司</td><td>1000</td><td>為發(fā)燒而生</td><td>啟用</td> ?<td><a href="#">修改</a> <a href="#">刪除</a></td></tr></table> </body> </html>
現(xiàn)在頁面中的數(shù)據(jù)都是假數(shù)據(jù)。
-
在
brand.jsp
中準(zhǔn)備一些數(shù)據(jù)<%// 查詢數(shù)據(jù)庫List<Brand> brands = new ArrayList<Brand>();brands.add(new Brand(1,"三只松鼠","三只松鼠",100,"三只松鼠,好吃不上火",1));brands.add(new Brand(2,"優(yōu)衣庫","優(yōu)衣庫",200,"優(yōu)衣庫,服適人生",0));brands.add(new Brand(3,"小米","小米科技有限公司",1000,"為發(fā)燒而生",1)); %>
==注意:==這里的類是需要導(dǎo)包的
-
將
brand.jsp
頁面中的table
標(biāo)簽中的數(shù)據(jù)改為動態(tài)的<table border="1" cellspacing="0" width="800"><tr><th>序號</th><th>品牌名稱</th><th>企業(yè)名稱</th><th>排序</th><th>品牌介紹</th><th>狀態(tài)</th><th>操作</th></tr><%for (int i = 0; i < brands.size(); i++) {//獲取集合中的 每一個 Brand 對象Brand brand = brands.get(i);}%><tr align="center"><td>1</td><td>三只松鼠</td><td>三只松鼠</td><td>100</td><td>三只松鼠,好吃不上火</td><td>啟用</td><td><a href="#">修改</a> <a href="#">刪除</a></td></tr> </table>
上面的for循環(huán)需要將
tr
標(biāo)簽包裹起來,這樣才能實(shí)現(xiàn)循環(huán)的效果,代碼改進(jìn)為<table border="1" cellspacing="0" width="800"><tr><th>序號</th><th>品牌名稱</th><th>企業(yè)名稱</th><th>排序</th><th>品牌介紹</th><th>狀態(tài)</th><th>操作</th></tr><%for (int i = 0; i < brands.size(); i++) {//獲取集合中的 每一個 Brand 對象Brand brand = brands.get(i);%><tr align="center"><td>1</td><td>三只松鼠</td><td>三只松鼠</td><td>100</td><td>三只松鼠,好吃不上火</td><td>啟用</td><td><a href="#">修改</a> <a href="#">刪除</a></td></tr><%}%></table>
注意:<%%> 里面寫的是 Java 代碼,而外邊寫的是 HTML 標(biāo)簽
上面代碼中的
td
標(biāo)簽中的數(shù)據(jù)都需要是動態(tài)的,所以還需要改進(jìn)<table border="1" cellspacing="0" width="800"><tr><th>序號</th><th>品牌名稱</th><th>企業(yè)名稱</th><th>排序</th><th>品牌介紹</th><th>狀態(tài)</th><th>操作</th></tr><%for (int i = 0; i < brands.size(); i++) {//獲取集合中的 每一個 Brand 對象Brand brand = brands.get(i);%><tr align="center"><td><%=brand.getId()%></td><td><%=brand.getBrandName()%></td><td><%=brand.getCompanyName()%></td><td><%=brand.getOrdered()%></td><td><%=brand.getDescription()%></td><td><%=brand.getStatus() == 1 ? "啟用":"禁用"%></td><td><a href="#">修改</a> <a href="#">刪除</a></td></tr><%}%></table>
4.2.3 成品代碼
<%@ page import="com.itheima.pojo.Brand" %> <%@ page import="java.util.List" %> <%@ page import="java.util.ArrayList" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %><%// 查詢數(shù)據(jù)庫List<Brand> brands = new ArrayList<Brand>();brands.add(new Brand(1,"三只松鼠","三只松鼠",100,"三只松鼠,好吃不上火",1));brands.add(new Brand(2,"優(yōu)衣庫","優(yōu)衣庫",200,"優(yōu)衣庫,服適人生",0));brands.add(new Brand(3,"小米","小米科技有限公司",1000,"為發(fā)燒而生",1));%><!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title> </head> <body> <input type="button" value="新增"><br> <hr> <table border="1" cellspacing="0" width="800"><tr><th>序號</th><th>品牌名稱</th><th>企業(yè)名稱</th><th>排序</th><th>品牌介紹</th><th>狀態(tài)</th><th>操作</th></tr><%for (int i = 0; i < brands.size(); i++) {Brand brand = brands.get(i);%><tr align="center"><td><%=brand.getId()%></td><td><%=brand.getBrandName()%></td><td><%=brand.getCompanyName()%></td><td><%=brand.getOrdered()%></td><td><%=brand.getDescription()%></td><td><%=brand.getStatus() == 1 ? "啟用":"禁用"%></td><td><a href="#">修改</a> <a href="#">刪除</a></td></tr><%}%> </table> </body> </html>
4.2.4 測試
在瀏覽器地址欄輸入 http://localhost:8080/jsp-demo/brand.jsp
,頁面展示效果如下
4.3 JSP 缺點(diǎn)
通過上面的案例,我們可以看到 JSP 的很多缺點(diǎn)。
由于 JSP頁面內(nèi),既可以定義 HTML 標(biāo)簽,又可以定義 Java代碼,造成了以下問題:
-
書寫麻煩:特別是復(fù)雜的頁面
既要寫 HTML 標(biāo)簽,還要寫 Java 代碼
-
閱讀麻煩
上面案例的代碼,相信你后期再看這段代碼時還需要花費(fèi)很長的時間去梳理
-
復(fù)雜度高:運(yùn)行需要依賴于各種環(huán)境,JRE,JSP容器,JavaEE…
-
占內(nèi)存和磁盤:JSP會自動生成.java和.class文件占磁盤,運(yùn)行的是.class文件占內(nèi)存
-
調(diào)試?yán)щy:出錯后,需要找到自動生成的.java文件進(jìn)行調(diào)試
-
不利于團(tuán)隊協(xié)作:前端人員不會 Java,后端人員不精 HTML
如果頁面布局發(fā)生變化,前端工程師對靜態(tài)頁面進(jìn)行修改,然后再交給后端工程師,由后端工程師再將該頁面改為 JSP 頁面
由于上述的問題, ==JSP 已逐漸退出歷史舞臺,==以后開發(fā)更多的是使用 ==HTML + Ajax== 來替代。Ajax 是我們后續(xù)會重點(diǎn)學(xué)習(xí)的技術(shù)。有個這個技術(shù)后,前端工程師負(fù)責(zé)前端頁面開發(fā),而后端工程師只負(fù)責(zé)前端代碼開發(fā)。下來對技術(shù)的發(fā)展進(jìn)行簡單的說明
-
第一階段:使用
servlet
即實(shí)現(xiàn)邏輯代碼編寫,也對頁面進(jìn)行拼接。這種模式我們之前也接觸過 -
第二階段:隨著技術(shù)的發(fā)展,出現(xiàn)了
JSP
,人們發(fā)現(xiàn)JSP
使用起來比Servlet
方便很多,但是還是要在JSP
中嵌套Java
代碼,也不利于后期的維護(hù) -
第三階段:使用
Servlet
進(jìn)行邏輯代碼開發(fā),而使用JSP
進(jìn)行數(shù)據(jù)展示 -
第四階段:使用
servlet
進(jìn)行后端邏輯代碼開發(fā),而使用HTML
進(jìn)行數(shù)據(jù)展示。而這里面就存在問題,HTML
是靜態(tài)頁面,怎么進(jìn)行動態(tài)數(shù)據(jù)展示呢?這就是ajax
的作用了。
那既然 JSP 已經(jīng)逐漸的退出歷史舞臺,那我們?yōu)槭裁催€要學(xué)習(xí) JSP
呢?原因有兩點(diǎn):
-
一些公司可能有些老項(xiàng)目還在用
JSP
,所以要求我們必須動JSP
-
我們?nèi)绻唤?jīng)歷這些復(fù)雜的過程,就不能體現(xiàn)后面階段開發(fā)的簡單
接下來我們來學(xué)習(xí)第三階段,使用 EL表達(dá)式
和 JSTL
標(biāo)簽庫替換 JSP
中的 Java
代碼。
5,EL 表達(dá)式
5.1 概述
EL(全稱Expression Language )表達(dá)式語言,用于簡化 JSP 頁面內(nèi)的 Java 代碼。
EL 表達(dá)式的主要作用是 ==獲取數(shù)據(jù)==。其實(shí)就是從域?qū)ο笾蝎@取數(shù)據(jù),然后將數(shù)據(jù)展示在頁面上。
而 EL 表達(dá)式的語法也比較簡單,==${expression}== 。例如:${brands} 就是獲取域中存儲的 key 為 brands 的數(shù)據(jù)。
5.2 代碼演示
-
定義servlet,在 servlet 中封裝一些數(shù)據(jù)并存儲到 request 域?qū)ο笾胁⑥D(zhuǎn)發(fā)到
el-demo.jsp
頁面。@WebServlet("/demo1") public class ServletDemo1 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//1. 準(zhǔn)備數(shù)據(jù)List<Brand> brands = new ArrayList<Brand>();brands.add(new Brand(1,"三只松鼠","三只松鼠",100,"三只松鼠,好吃不上火",1));brands.add(new Brand(2,"優(yōu)衣庫","優(yōu)衣庫",200,"優(yōu)衣庫,服適人生",0));brands.add(new Brand(3,"小米","小米科技有限公司",1000,"為發(fā)燒而生",1));//2. 存儲到request域中request.setAttribute("brands",brands);//3. 轉(zhuǎn)發(fā)到 el-demo.jsprequest.getRequestDispatcher("/el-demo.jsp").forward(request,response);}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doGet(request, response);} }
==注意:== 此處需要用轉(zhuǎn)發(fā),因?yàn)檗D(zhuǎn)發(fā)才可以使用 request 對象作為域?qū)ο筮M(jìn)行數(shù)據(jù)共享
-
在
el-demo.jsp
中通過 EL表達(dá)式 獲取數(shù)據(jù)<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head><title>Title</title> </head> <body>${brands} </body> </html>
-
在瀏覽器的地址欄輸入
http://localhost:8080/jsp-demo/demo1
,頁面效果如下:
5.3 域?qū)ο?/h4>
JavaWeb中有四大域?qū)ο?#xff0c;分別是:
-
page:當(dāng)前頁面有效
-
request:當(dāng)前請求有效
-
session:當(dāng)前會話有效
-
application:當(dāng)前應(yīng)用有效
el 表達(dá)式獲取數(shù)據(jù),會依次從這4個域中尋找,直到找到為止。而這四個域?qū)ο蟮淖饔梅秶缦聢D所示
例如: ${brands},el 表達(dá)式獲取數(shù)據(jù),會先從page域?qū)ο笾蝎@取數(shù)據(jù),如果沒有再到 requet 域?qū)ο笾蝎@取數(shù)據(jù),如果再沒有再到 session 域?qū)ο笾蝎@取,如果還沒有才會到 application 中獲取數(shù)據(jù)。
6,JSTL標(biāo)簽
6.1 概述
JSP標(biāo)準(zhǔn)標(biāo)簽庫(Jsp Standarded Tag Library) ,使用標(biāo)簽取代JSP頁面上的Java代碼。如下代碼就是JSTL標(biāo)簽
<c:if test="${flag == 1}">男 </c:if> <c:if test="${flag == 2}">女 </c:if>
上面代碼看起來是不是比 JSP 中嵌套 Java 代碼看起來舒服好了。而且前端工程師對標(biāo)簽是特別敏感的,他們看到這段代碼是能看懂的。
JSTL 提供了很多標(biāo)簽,如下圖
我們只對兩個最常用的標(biāo)簽進(jìn)行講解,<c:forEach>
標(biāo)簽和 <c:if>
標(biāo)簽。
JSTL 使用也是比較簡單的,分為如下步驟:
-
導(dǎo)入坐標(biāo)
<dependency><groupId>jstl</groupId><artifactId>jstl</artifactId><version>1.2</version> </dependency> <dependency><groupId>taglibs</groupId><artifactId>standard</artifactId><version>1.1.2</version> </dependency>
-
在JSP頁面上引入JSTL標(biāo)簽庫
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
-
使用標(biāo)簽
6.2 if 標(biāo)簽
<c:if>
:相當(dāng)于 if 判斷
-
屬性:test,用于定義條件表達(dá)式
<c:if test="${flag == 1}">男 </c:if> <c:if test="${flag == 2}">女 </c:if>
代碼演示:
-
定義一個
servlet
,在該servlet
中向 request 域?qū)ο笾刑砑?鍵是status
,值為1
的數(shù)據(jù)@WebServlet("/demo2") public class ServletDemo2 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//1. 存儲數(shù)據(jù)到request域中request.setAttribute("status",1);//2. 轉(zhuǎn)發(fā)到 jstl-if.jsp數(shù)據(jù)request.getRequestDispatcher("/jstl-if.jsp").forward(request,response);}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doGet(request, response);} }
-
定義
jstl-if.jsp
頁面,在該頁面使用<c:if>
標(biāo)簽<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <html> <head><title>Title</title> </head> <body><%--c:if:來完成邏輯判斷,替換java if else--%><c:if test="${status ==1}">啟用</c:if><c:if test="${status ==0}">禁用</c:if> </body> </html>
==注意:== 在該頁面已經(jīng)要引入 JSTL核心標(biāo)簽庫
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
6.3 forEach 標(biāo)簽
<c:forEach>
:相當(dāng)于 for 循環(huán)。java中有增強(qiáng)for循環(huán)和普通for循環(huán),JSTL 中的 <c:forEach>
也有兩種用法
6.3.1 用法一
類似于 Java 中的增強(qiáng)for循環(huán)。涉及到的 <c:forEach>
中的屬性如下
-
items:被遍歷的容器
-
var:遍歷產(chǎn)生的臨時變量
-
varStatus:遍歷狀態(tài)對象
如下代碼,是從域?qū)ο笾蝎@取名為 brands 數(shù)據(jù),該數(shù)據(jù)是一個集合;遍歷遍歷,并給該集合中的每一個元素起名為 brand
,是 Brand對象。在循環(huán)里面使用 EL表達(dá)式獲取每一個Brand對象的屬性值
<c:forEach items="${brands}" var="brand"><tr align="center"><td>${brand.id}</td><td>${brand.brandName}</td><td>${brand.companyName}</td><td>${brand.description}</td></tr> </c:forEach>
代碼演示:
-
servlet
還是使用之前的名為ServletDemo1
。 -
定義名為
jstl-foreach.jsp
頁面,內(nèi)容如下:<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %><!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title> </head> <body> <input type="button" value="新增"><br> <hr> <table border="1" cellspacing="0" width="800"><tr><th>序號</th><th>品牌名稱</th><th>企業(yè)名稱</th><th>排序</th><th>品牌介紹</th><th>狀態(tài)</th><th>操作</th></tr><c:forEach items="${brands}" var="brand" varStatus="status"><tr align="center"><%--<td>${brand.id}</td>--%><td>${status.count}</td><td>${brand.brandName}</td><td>${brand.companyName}</td><td>${brand.ordered}</td><td>${brand.description}</td><c:if test="${brand.status == 1}"><td>啟用</td></c:if><c:if test="${brand.status != 1}"><td>禁用</td></c:if><td><a href="#">修改</a> <a href="#">刪除</a></td></tr></c:forEach> </table> </body> </html>
6.3.2 用法二
類似于 Java 中的普通for循環(huán)。涉及到的 <c:forEach>
中的屬性如下
-
begin:開始數(shù)
-
end:結(jié)束數(shù)
-
step:步長
實(shí)例代碼:
從0循環(huán)到10,變量名是 i
,每次自增1
<c:forEach begin="0" end="10" step="1" var="i">${i} </c:forEach>
7,MVC模式和三層架構(gòu)
MVC 模式和三層架構(gòu)是一些理論的知識,將來我們使用了它們進(jìn)行代碼開發(fā)會讓我們代碼維護(hù)性和擴(kuò)展性更好。
7.1 MVC模式
MVC 是一種分層開發(fā)的模式,其中:
-
M:Model,業(yè)務(wù)模型,處理業(yè)務(wù)
-
V:View,視圖,界面展示
-
C:Controller,控制器,處理請求,調(diào)用模型和視圖
控制器(serlvlet)用來接收瀏覽器發(fā)送過來的請求,控制器調(diào)用模型(JavaBean)來獲取數(shù)據(jù),比如從數(shù)據(jù)庫查詢數(shù)據(jù);控制器獲取到數(shù)據(jù)后再交由視圖(JSP)進(jìn)行數(shù)據(jù)展示。
MVC 好處:
-
職責(zé)單一,互不影響。每個角色做它自己的事,各司其職。
-
有利于分工協(xié)作。
-
有利于組件重用
7.2 三層架構(gòu)
三層架構(gòu)是將我們的項(xiàng)目分成了三個層面,分別是 表現(xiàn)層
、業(yè)務(wù)邏輯層
、數(shù)據(jù)訪問層
。
-
數(shù)據(jù)訪問層:對數(shù)據(jù)庫的CRUD基本操作
-
業(yè)務(wù)邏輯層:對業(yè)務(wù)邏輯進(jìn)行封裝,組合數(shù)據(jù)訪問層層中基本功能,形成復(fù)雜的業(yè)務(wù)邏輯功能。例如
注冊業(yè)務(wù)功能
,我們會先調(diào)用數(shù)據(jù)訪問層
的selectByName()
方法判斷該用戶名是否存在,如果不存在再調(diào)用數(shù)據(jù)訪問層
的insert()
方法進(jìn)行數(shù)據(jù)的添加操作 -
表現(xiàn)層:接收請求,封裝數(shù)據(jù),調(diào)用業(yè)務(wù)邏輯層,響應(yīng)數(shù)據(jù)
而整個流程是,瀏覽器發(fā)送請求,表現(xiàn)層的Servlet接收請求并調(diào)用業(yè)務(wù)邏輯層的方法進(jìn)行業(yè)務(wù)邏輯處理,而業(yè)務(wù)邏輯層方法調(diào)用數(shù)據(jù)訪問層方法進(jìn)行數(shù)據(jù)的操作,依次返回到serlvet,然后servlet將數(shù)據(jù)交由 JSP 進(jìn)行展示。
三層架構(gòu)的每一層都有特有的包名稱:
-
表現(xiàn)層:
com.itheima.controller
或者com.itheima.web
-
業(yè)務(wù)邏輯層:
com.itheima.service
-
數(shù)據(jù)訪問層:
com.itheima.dao
或者com.itheima.mapper
后期我們還會學(xué)習(xí)一些框架,不同的框架是對不同層進(jìn)行封裝的
7.3 MVC 和 三層架構(gòu)
通過 MVC 和 三層架構(gòu) 的學(xué)習(xí),有些人肯定混淆了。那他們有什么區(qū)別和聯(lián)系?
如上圖上半部分是 MVC 模式,上圖下半部分是三層架構(gòu)。 MVC 模式
中的 C(控制器)和 V(視圖)就是 三層架構(gòu)
中的表現(xiàn)層,而 MVC 模式
中的 M(模型)就是 三層架構(gòu)
中的 業(yè)務(wù)邏輯層 和 數(shù)據(jù)訪問層。
可以將 MVC 模式
理解成是一個大的概念,而 三層架構(gòu)
是對 MVC 模式
實(shí)現(xiàn)架構(gòu)的思想。 那么我們以后按照要求將不同層的代碼寫在不同的包下,每一層里功能職責(zé)做到單一,將來如果將表現(xiàn)層的技術(shù)換掉,而業(yè)務(wù)邏輯層和數(shù)據(jù)訪問層的代碼不需要發(fā)生變化。
8,案例
需求:完成品牌數(shù)據(jù)的增刪改查操作
這個功能我們之前一直在做,而這個案例是將今天學(xué)習(xí)的所有的內(nèi)容(包含 MVC模式 和 三層架構(gòu))進(jìn)行應(yīng)用,并將整個流程貫穿起來。
8.1 環(huán)境準(zhǔn)備
環(huán)境準(zhǔn)備工作,我們分以下步驟實(shí)現(xiàn):
-
創(chuàng)建新的模塊 brand_demo,引入坐標(biāo)
-
創(chuàng)建三層架構(gòu)的包結(jié)構(gòu)
-
數(shù)據(jù)庫表 tb_brand
-
實(shí)體類 Brand
-
MyBatis 基礎(chǔ)環(huán)境
-
Mybatis-config.xml
-
BrandMapper.xml
-
BrandMapper接口
-
8.1.1 創(chuàng)建工程
創(chuàng)建新的模塊 brand_demo,引入坐標(biāo)。我們只要分析出要用到哪兒些技術(shù),那么需要哪兒些坐標(biāo)也就明確了
-
需要操作數(shù)據(jù)庫。mysql的驅(qū)動包
-
要使用mybatis框架。mybaits的依賴包
-
web項(xiàng)目需要用到servlet和jsp。servlet和jsp的依賴包
-
需要使用 jstl 進(jìn)行數(shù)據(jù)展示。jstl的依賴包
pom.xml
內(nèi)容如下:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>org.example</groupId><artifactId>brand-demo</artifactId><version>1.0-SNAPSHOT</version><packaging>war</packaging><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><dependencies><!-- mybatis --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.5</version></dependency><!--mysql--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.34</version></dependency><!--servlet--><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>3.1.0</version><scope>provided</scope></dependency><!--jsp--><dependency><groupId>javax.servlet.jsp</groupId><artifactId>jsp-api</artifactId><version>2.2</version><scope>provided</scope></dependency><!--jstl--><dependency><groupId>jstl</groupId><artifactId>jstl</artifactId><version>1.2</version></dependency><dependency><groupId>taglibs</groupId><artifactId>standard</artifactId><version>1.1.2</version></dependency></dependencies><build><plugins><plugin><groupId>org.apache.tomcat.maven</groupId><artifactId>tomcat7-maven-plugin</artifactId><version>2.2</version></plugin></plugins></build> </project>
8.1.2 創(chuàng)建包
創(chuàng)建不同的包結(jié)構(gòu),用來存儲不同的類。包結(jié)構(gòu)如下
8.1.3 創(chuàng)建表
-- 刪除tb_brand表 drop table if exists tb_brand; -- 創(chuàng)建tb_brand表 create table tb_brand (-- id 主鍵id int primary key auto_increment,-- 品牌名稱brand_name varchar(20),-- 企業(yè)名稱company_name varchar(20),-- 排序字段ordered int,-- 描述信息description varchar(100),-- 狀態(tài):0:禁用 1:啟用status int ); -- 添加數(shù)據(jù) insert into tb_brand (brand_name, company_name, ordered, description, status) values ('三只松鼠', '三只松鼠股份有限公司', 5, '好吃不上火', 0),('華為', '華為技術(shù)有限公司', 100, '華為致力于把數(shù)字世界帶入每個人、每個家庭、每個組織,構(gòu)建萬物互聯(lián)的智能世界', 1),('小米', '小米科技有限公司', 50, 'are you ok', 1);
8.1.4 創(chuàng)建實(shí)體類
在 pojo
包下創(chuàng)建名為 Brand
的類。
public class Brand {// id 主鍵private Integer id;// 品牌名稱private String brandName;// 企業(yè)名稱private String companyName;// 排序字段private Integer ordered;// 描述信息private String description;// 狀態(tài):0:禁用 1:啟用private Integer status;public Brand() {}public Brand(Integer id, String brandName, String companyName, String description) {this.id = id;this.brandName = brandName;this.companyName = companyName;this.description = description;}public Brand(Integer id, String brandName, String companyName, Integer ordered, String description, Integer status) {this.id = id;this.brandName = brandName;this.companyName = companyName;this.ordered = ordered;this.description = description;this.status = status;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getBrandName() {return brandName;}public void setBrandName(String brandName) {this.brandName = brandName;}public String getCompanyName() {return companyName;}public void setCompanyName(String companyName) {this.companyName = companyName;}public Integer getOrdered() {return ordered;}public void setOrdered(Integer ordered) {this.ordered = ordered;}public String getDescription() {return description;}public void setDescription(String description) {this.description = description;}public Integer getStatus() {return status;}public void setStatus(Integer status) {this.status = status;}@Overridepublic String toString() {return "Brand{" +"id=" + id +", brandName='" + brandName + '\'' +", companyName='" + companyName + '\'' +", ordered=" + ordered +", description='" + description + '\'' +", status=" + status +'}';} }
8.1.5 準(zhǔn)備mybatis環(huán)境
定義核心配置文件 Mybatis-config.xml
,并將該文件放置在 resources
下
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration><!--起別名--><typeAliases><package name="com.itheima.pojo"/></typeAliases><environments default="development"><environment id="development"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="com.mysql.jdbc.Driver"/><property name="url" value="jdbc:mysql:///db1?useSSL=false&useServerPrepStmts=true"/><property name="username" value="root"/><property name="password" value="1234"/></dataSource></environment></environments><mappers><!--掃描mapper--><package name="com.itheima.mapper"/></mappers> </configuration>
在 resources
下創(chuàng)建放置映射配置文件的目錄結(jié)構(gòu) com/itheima/mapper
,并在該目錄下創(chuàng)建映射配置文件 BrandMapper.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.itheima.mapper.BrandMapper"></mapper>
8.2 查詢所有
當(dāng)我們點(diǎn)擊 index.html
頁面中的 查詢所有
這個超鏈接時,就能查詢到上圖右半部分的數(shù)據(jù)。
對于上述的功能,點(diǎn)擊 查詢所有
超鏈接是需要先請后端的 servlet
,由 servlet
跳轉(zhuǎn)到對應(yīng)的頁面進(jìn)行數(shù)據(jù)的動態(tài)展示。而整個流程如下圖:
8.2.1 編寫B(tài)randMapper
在 mapper
包下創(chuàng)建創(chuàng)建 BrandMapper
接口,在接口中定義 selectAll()
方法
/*** 查詢所有* @return*/ @Select("select * from tb_brand") List<Brand> selectAll();
8.2.2 編寫工具類
在 com.itheima
包下創(chuàng)建 utils
包,并在該包下創(chuàng)建名為 SqlSessionFactoryUtils
工具類
public class SqlSessionFactoryUtils {private static SqlSessionFactory sqlSessionFactory;static {//靜態(tài)代碼塊會隨著類的加載而自動執(zhí)行,且只執(zhí)行一次try {String resource = "mybatis-config.xml";InputStream inputStream = Resources.getResourceAsStream(resource);sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);} catch (IOException e) {e.printStackTrace();}}public static SqlSessionFactory getSqlSessionFactory(){return sqlSessionFactory;} }
8.2.3 編寫B(tài)randService
在 service
包下創(chuàng)建 BrandService
類
public class BrandService {SqlSessionFactory factory = SqlSessionFactoryUtils.getSqlSessionFactory();/*** 查詢所有* @return*/public List<Brand> selectAll(){//調(diào)用BrandMapper.selectAll()//2. 獲取SqlSessionSqlSession sqlSession = factory.openSession();//3. 獲取BrandMapperBrandMapper mapper = sqlSession.getMapper(BrandMapper.class);//4. 調(diào)用方法List<Brand> brands = mapper.selectAll();sqlSession.close();return brands;} }
8.2.4 編寫Servlet
在 web
包下創(chuàng)建名為 SelectAllServlet
的 servlet
,該 servlet
的邏輯如下:
-
調(diào)用
BrandService
的selectAll()
方法進(jìn)行業(yè)務(wù)邏輯處理,并接收返回的結(jié)果 -
將上一步返回的結(jié)果存儲到
request
域?qū)ο笾?/p> -
跳轉(zhuǎn)到
brand.jsp
頁面進(jìn)行數(shù)據(jù)的展示
具體的代碼如下:
@WebServlet("/selectAllServlet") public class SelectAllServlet extends HttpServlet {private BrandService service = new BrandService();@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//1. 調(diào)用BrandService完成查詢List<Brand> brands = service.selectAll();//2. 存入request域中request.setAttribute("brands",brands);//3. 轉(zhuǎn)發(fā)到brand.jsprequest.getRequestDispatcher("/brand.jsp").forward(request,response);}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doGet(request, response);} }
8.2.5 編寫brand.jsp頁面
將資料 資料\2. 品牌增刪改查案例\靜態(tài)頁面
下的 brand.html
頁面拷貝到項(xiàng)目的 webapp
目錄下,并將該頁面改成 brand.jsp
頁面,而 brand.jsp
頁面在表格中使用 JSTL
和 EL表達(dá)式
從request域?qū)ο笾蝎@取名為 brands
的集合數(shù)據(jù)并展示出來。頁面內(nèi)容如下:
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %><!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title> </head> <body> <hr> <table border="1" cellspacing="0" width="80%"><tr><th>序號</th><th>品牌名稱</th><th>企業(yè)名稱</th><th>排序</th><th>品牌介紹</th><th>狀態(tài)</th><th>操作</th></tr><c:forEach items="${brands}" var="brand" varStatus="status"><tr align="center"><%--<td>${brand.id}</td>--%><td>${status.count}</td><td>${brand.brandName}</td><td>${brand.companyName}</td><td>${brand.ordered}</td><td>${brand.description}</td><c:if test="${brand.status == 1}"><td>啟用</td></c:if><c:if test="${brand.status != 1}"><td>禁用</td></c:if><td><a href="/brand-demo/selectByIdServlet?id=${brand.id}">修改</a> <a href="#">刪除</a></td></tr></c:forEach> </table> </body> </html>
8.2.6 測試
啟動服務(wù)器,并在瀏覽器輸入 http://localhost:8080/brand-demo/index.html
,看到如下 查詢所有
的超鏈接,點(diǎn)擊該鏈接就可以查詢出所有的品牌數(shù)據(jù)
為什么出現(xiàn)這個問題呢?是因?yàn)椴樵兊降淖侄蚊蛯?shí)體類對象的屬性名沒有一一對應(yīng)。相比看到這大家一定會解決了,就是在映射配置文件中使用 resultMap
標(biāo)簽定義映射關(guān)系。映射配置文件內(nèi)容如下:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.itheima.mapper.BrandMapper"><resultMap id="brandResultMap" type="brand"><result column="brand_name" property="brandName"></result><result column="company_name" property="companyName"></result></resultMap> </mapper>
并且在 BrandMapper
接口中的 selectAll()
上使用 @ResuleMap
注解指定使用該映射
/*** 查詢所有* @return*/ @Select("select * from tb_brand") @ResultMap("brandResultMap") List<Brand> selectAll();
重啟服務(wù)器,再次訪問就能看到我們想要的數(shù)據(jù)了
8.3 添加
上圖是做 添加 功能流程。點(diǎn)擊 新增
按鈕后,會先跳轉(zhuǎn)到 addBrand.jsp
新增頁面,在該頁面輸入要添加的數(shù)據(jù),輸入完畢后點(diǎn)擊 提交
按鈕,需要將數(shù)據(jù)提交到后端,而后端進(jìn)行數(shù)據(jù)添加操作,并重新將所有的數(shù)據(jù)查詢出來。整個流程如下:
接下來我們根據(jù)流程來實(shí)現(xiàn)功能:
8.3.1 編寫B(tài)randMapper方法
在 BrandMapper
接口,在接口中定義 add(Brand brand)
方法
@Insert("insert into tb_brand values(null,#{brandName},#{companyName},#{ordered},#{description},#{status})") void add(Brand brand);
8.3.2 編寫B(tài)randService方法
在 BrandService
類中定義添加品牌數(shù)據(jù)方法 add(Brand brand)
/*** 添加* @param brand*/public void add(Brand brand){//2. 獲取SqlSessionSqlSession sqlSession = factory.openSession();//3. 獲取BrandMapperBrandMapper mapper = sqlSession.getMapper(BrandMapper.class);//4. 調(diào)用方法mapper.add(brand);//提交事務(wù)sqlSession.commit();//釋放資源sqlSession.close();}
8.3.3 改進(jìn)brand.jsp頁面
我們需要在該頁面表格的上面添加 新增
按鈕
<input type="button" value="新增" id="add"><br>
并給該按鈕綁定單擊事件,當(dāng)點(diǎn)擊了該按鈕需要跳轉(zhuǎn)到 brand.jsp
添加品牌數(shù)據(jù)的頁面
<script>document.getElementById("add").onclick = function (){location.href = "/brand-demo/addBrand.jsp";} </script>
==注意:==該
script
標(biāo)簽建議放在body
結(jié)束標(biāo)簽前面。
8.3.4 編寫addBrand.jsp頁面
從資料 資料\2. 品牌增刪改查案例\靜態(tài)頁面
中將 addBrand.html
頁面拷貝到項(xiàng)目的 webapp
下,并改成 addBrand.jsp
動態(tài)頁面
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><title>添加品牌</title> </head> <body> <h3>添加品牌</h3> <form action="/brand-demo/addServlet" method="post">品牌名稱:<input name="brandName"><br>企業(yè)名稱:<input name="companyName"><br>排序:<input name="ordered"><br>描述信息:<textarea rows="5" cols="20" name="description"></textarea><br>狀態(tài):<input type="radio" name="status" value="0">禁用<input type="radio" name="status" value="1">啟用<br><input type="submit" value="提交"> </form> </body> </html>
8.3.5 編寫servlet
在 web
包下創(chuàng)建 AddServlet
的 servlet
,該 servlet
的邏輯如下:
-
設(shè)置處理post請求亂碼的字符集
-
接收客戶端提交的數(shù)據(jù)
-
將接收到的數(shù)據(jù)封裝到
Brand
對象中 -
調(diào)用
BrandService
的add()
方法進(jìn)行添加的業(yè)務(wù)邏輯處理 -
跳轉(zhuǎn)到
selectAllServlet
資源重新查詢數(shù)據(jù)
具體的代碼如下:
@WebServlet("/addServlet") public class AddServlet extends HttpServlet {private BrandService service = new BrandService();@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//處理POST請求的亂碼問題request.setCharacterEncoding("utf-8");//1. 接收表單提交的數(shù)據(jù),封裝為一個Brand對象String brandName = request.getParameter("brandName");String companyName = request.getParameter("companyName");String ordered = request.getParameter("ordered");String description = request.getParameter("description");String status = request.getParameter("status");//封裝為一個Brand對象Brand brand = new Brand();brand.setBrandName(brandName);brand.setCompanyName(companyName);brand.setOrdered(Integer.parseInt(ordered));brand.setDescription(description);brand.setStatus(Integer.parseInt(status));//2. 調(diào)用service 完成添加service.add(brand);//3. 轉(zhuǎn)發(fā)到查詢所有Servletrequest.getRequestDispatcher("/selectAllServlet").forward(request,response);}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doGet(request, response);} }
8.3.6 測試
點(diǎn)擊 brand.jsp
頁面的 新增
按鈕,會跳轉(zhuǎn)到 addBrand.jsp
頁面
點(diǎn)擊 提交
按鈕,就能看到如下頁面,里面就包含我們剛添加的數(shù)據(jù)
8.4 修改
點(diǎn)擊每條數(shù)據(jù)后面的 編輯
按鈕會跳轉(zhuǎn)到修改頁面,如下圖:
在該修改頁面我們可以看到將 編輯
按鈕所在行的數(shù)據(jù) ==回顯== 到表單,然后需要修改那個數(shù)據(jù)在表單中進(jìn)行修改,然后點(diǎn)擊 提交
的按鈕將數(shù)據(jù)提交到后端,后端再將數(shù)據(jù)存儲到數(shù)據(jù)庫中。
從上面的例子我們知道 修改
功能需要從兩方面進(jìn)行實(shí)現(xiàn),數(shù)據(jù)回顯和修改操作。
8.4.1 回顯數(shù)據(jù)
上圖就是回顯數(shù)據(jù)的效果。要實(shí)現(xiàn)這個效果,那當(dāng)點(diǎn)擊 修改
按鈕時不能直接跳轉(zhuǎn)到 update.jsp
頁面,而是需要先帶著當(dāng)前行數(shù)據(jù)的 id
請求后端程序,后端程序根據(jù) id
查詢數(shù)據(jù),將數(shù)據(jù)存儲到域?qū)ο笾刑D(zhuǎn)到 update.jsp
頁面進(jìn)行數(shù)據(jù)展示。整體流程如下
8.4.1.1 編寫B(tài)randMapper方法
在 BrandMapper
接口,在接口中定義 selectById(int id)
方法
/*** 根據(jù)id查詢* @param id* @return*/@Select("select * from tb_brand where id = #{id}")@ResultMap("brandResultMap")Brand selectById(int id);
8.4.1.2 編寫B(tài)randService方法
在 BrandService
類中定義根據(jù)id查詢數(shù)據(jù)方法 selectById(int id)
/*** 根據(jù)id查詢* @return*/public Brand selectById(int id){//調(diào)用BrandMapper.selectAll()//2. 獲取SqlSessionSqlSession sqlSession = factory.openSession();//3. 獲取BrandMapperBrandMapper mapper = sqlSession.getMapper(BrandMapper.class);//4. 調(diào)用方法Brand brand = mapper.selectById(id);sqlSession.close();return brand;}
8.4.1.3 編寫servlet
在 web
包下創(chuàng)建 SelectByIdServlet
的 servlet
,該 servlet
的邏輯如下:
-
獲取請求數(shù)據(jù)
id
-
調(diào)用
BrandService
的selectById()
方法進(jìn)行數(shù)據(jù)查詢的業(yè)務(wù)邏輯 -
將查詢到的數(shù)據(jù)存儲到 request 域?qū)ο笾?/p>
-
跳轉(zhuǎn)到
update.jsp
頁面進(jìn)行數(shù)據(jù)真實(shí)
具體代碼如下:
@WebServlet("/selectByIdServlet") public class SelectByIdServlet extends HttpServlet {private BrandService service = new BrandService();@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//1. 接收idString id = request.getParameter("id");//2. 調(diào)用service查詢Brand brand = service.selectById(Integer.parseInt(id));//3. 存儲到request中request.setAttribute("brand",brand);//4. 轉(zhuǎn)發(fā)到update.jsprequest.getRequestDispatcher("/update.jsp").forward(request,response);}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doGet(request, response);} }
8.4.1.4 編寫update.jsp頁面
拷貝 addBrand.jsp
頁面,改名為 update.jsp
并做出以下修改:
-
title
標(biāo)簽內(nèi)容改為修改品牌
-
form
標(biāo)簽的action
屬性值改為/brand-demo/updateServlet
-
input
標(biāo)簽要進(jìn)行數(shù)據(jù)回顯,需要設(shè)置value
屬性品牌名稱:<input name="brandName" value="${brand.brandName}"><br> 企業(yè)名稱:<input name="companyName" value="${brand.companyName}"><br> 排序:<input name="ordered" value="${brand.ordered}"><br>
-
textarea
標(biāo)簽要進(jìn)行數(shù)據(jù)回顯,需要在標(biāo)簽體中使用EL表達(dá)式
描述信息:<textarea rows="5" cols="20" name="description">${brand.description} </textarea><br>
-
單選框使用
if
標(biāo)簽需要判斷brand.status
的值是 1 還是 0 在指定的單選框上使用checked
屬性,表示被選中狀態(tài)狀態(tài): <c:if test="${brand.status == 0}"><input type="radio" name="status" value="0" checked>禁用<input type="radio" name="status" value="1">啟用<br> </c:if><c:if test="${brand.status == 1}"><input type="radio" name="status" value="0" >禁用<input type="radio" name="status" value="1" checked>啟用<br> </c:if>
綜上,update.jsp
代碼如下:
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>修改品牌</title> </head> <body> <h3>修改品牌</h3> <form action="/brand-demo/updateServlet" method="post">品牌名稱:<input name="brandName" value="${brand.brandName}"><br>企業(yè)名稱:<input name="companyName" value="${brand.companyName}"><br>排序:<input name="ordered" value="${brand.ordered}"><br>描述信息:<textarea rows="5" cols="20" name="description">${brand.description} </textarea><br>狀態(tài):<c:if test="${brand.status == 0}"><input type="radio" name="status" value="0" checked>禁用<input type="radio" name="status" value="1">啟用<br></c:if><c:if test="${brand.status == 1}"><input type="radio" name="status" value="0" >禁用<input type="radio" name="status" value="1" checked>啟用<br></c:if><input type="submit" value="提交"> </form> </body> </html>
8.4.2 修改數(shù)據(jù)
做完回顯數(shù)據(jù)后,接下來我們要做修改數(shù)據(jù)了,而下圖是修改數(shù)據(jù)的效果:
在修改頁面進(jìn)行數(shù)據(jù)修改,點(diǎn)擊 提交
按鈕,會將數(shù)據(jù)提交到后端程序,后端程序會對表中的數(shù)據(jù)進(jìn)行修改操作,然后重新進(jìn)行數(shù)據(jù)的查詢操作。整體流程如下:
8.4.2.1 編寫B(tài)randMapper方法
在 BrandMapper
接口,在接口中定義 update(Brand brand)
方法
/*** 修改* @param brand*/ @Update("update tb_brand set brand_name = #{brandName},company_name = #{companyName},ordered = #{ordered},description = #{description},status = #{status} where id = #{id}") void update(Brand brand);
8.4.2.2 編寫B(tài)randService方法
在 BrandService
類中定義根據(jù)id查詢數(shù)據(jù)方法 update(Brand brand)
/*** 修改* @param brand*/public void update(Brand brand){//2. 獲取SqlSessionSqlSession sqlSession = factory.openSession();//3. 獲取BrandMapperBrandMapper mapper = sqlSession.getMapper(BrandMapper.class);//4. 調(diào)用方法mapper.update(brand);//提交事務(wù)sqlSession.commit();//釋放資源sqlSession.close();}
8.4.2.3 編寫servlet
在 web
包下創(chuàng)建 AddServlet
的 servlet
,該 servlet
的邏輯如下:
-
設(shè)置處理post請求亂碼的字符集
-
接收客戶端提交的數(shù)據(jù)
-
將接收到的數(shù)據(jù)封裝到
Brand
對象中 -
調(diào)用
BrandService
的update()
方法進(jìn)行添加的業(yè)務(wù)邏輯處理 -
跳轉(zhuǎn)到
selectAllServlet
資源重新查詢數(shù)據(jù)
具體的代碼如下:
@WebServlet("/updateServlet") public class UpdateServlet extends HttpServlet {private BrandService service = new BrandService();@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//處理POST請求的亂碼問題request.setCharacterEncoding("utf-8");//1. 接收表單提交的數(shù)據(jù),封裝為一個Brand對象String id = request.getParameter("id");String brandName = request.getParameter("brandName");String companyName = request.getParameter("companyName");String ordered = request.getParameter("ordered");String description = request.getParameter("description");String status = request.getParameter("status");//封裝為一個Brand對象Brand brand = new Brand();brand.setId(Integer.parseInt(id));brand.setBrandName(brandName);brand.setCompanyName(companyName);brand.setOrdered(Integer.parseInt(ordered));brand.setDescription(description);brand.setStatus(Integer.parseInt(status));//2. 調(diào)用service 完成修改service.update(brand);//3. 轉(zhuǎn)發(fā)到查詢所有Servletrequest.getRequestDispatcher("/selectAllServlet").forward(request,response);}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doGet(request, response);} }
==存在問題:update.jsp 頁面提交數(shù)據(jù)時是沒有攜帶主鍵數(shù)據(jù)的,而后臺修改數(shù)據(jù)需要根據(jù)主鍵進(jìn)行修改。==
針對這個問題,我們不希望頁面將主鍵id展示給用戶看,但是又希望在提交數(shù)據(jù)時能將主鍵id提交到后端。此時我們就想到了在學(xué)習(xí) HTML 時學(xué)習(xí)的隱藏域,在 update.jsp
頁面的表單中添加如下代碼:
<%--隱藏域,提交id--%> <input type="hidden" name="id" value="${brand.id}">
update.jsp
頁面的最終代碼如下:
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>修改品牌</title> </head> <body> <h3>修改品牌</h3> <form action="/brand-demo/updateServlet" method="post"><%--隱藏域,提交id--%><input type="hidden" name="id" value="${brand.id}">品牌名稱:<input name="brandName" value="${brand.brandName}"><br>企業(yè)名稱:<input name="companyName" value="${brand.companyName}"><br>排序:<input name="ordered" value="${brand.ordered}"><br>描述信息:<textarea rows="5" cols="20" name="description">${brand.description} </textarea><br>狀態(tài):<c:if test="${brand.status == 0}"><input type="radio" name="status" value="0" checked>禁用<input type="radio" name="status" value="1">啟用<br></c:if><c:if test="${brand.status == 1}"><input type="radio" name="status" value="0" >禁用<input type="radio" name="status" value="1" checked>啟用<br></c:if><input type="submit" value="提交"> </form> </body> </html>