9x9上三角乘法表
?乘法表的實現
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html>
<head><title>9×9 上三角乘法表</title><style>body {font-family: monospace;padding: 20px;}.row {white-space: nowrap;}.cell {display: inline-block;width: 80px;}</style>
</head>
<body>
<h2>9×9 上三角乘法表</h2>
<%for (int i = 1; i <= 9; i++) {
%>
<div class="row"><% for (int j = 1; j < i; j++) { %><span class="cell"> </span><% }for (int j = i; j <= 9; j++) { %><span class="cell"><%= i %>×<%= j %>=<%= i * j %></span><% } %>
</div>
<%}
%>
</body>
</html>
分清楚哪些是可以自定義名字的,哪些是規定的語法
<div class="lalala-row"><% for (int j = 1; j < i; j++) { %><span class="lalala-cell"> </span><% }for (int j = i; j <= 9; j++) { %><span class="lalala-cell"><%= i %>×<%= j %>=<%= i * j %></span><% } %>
</div>
這里進行循環lalala是自己定義的名字
但head里的style里的設置也因此要修改符合了
<style>body {font-family: monospace;padding: 20px;}.lalala-row {white-space: nowrap;}.lalala-cell {display: inline-block;width: 80px;}
</style>
body { font-family: monospace; padding: 20px; }
屬性 | 含義 |
---|---|
font-family: monospace; | 設置字體為等寬字體,確保每個字符寬度一樣(比如數字、乘號、等號對齊) |
padding: 20px; | 給頁面四周加內邊距,讓內容不貼邊,視覺更舒服 |
.row { white-space: nowrap; }
這個是用在:
<div class="row"> ... </div>
屬性 | 含義 |
---|---|
white-space: nowrap; | 告訴瀏覽器:不要自動換行,所有乘法項都顯示在一行內 |
🚫 否則每個 <span>
到邊界時會自動換行,排版會亂
.cell { display: inline-block; width: 80px; }
這是每個乘法項的樣式:
屬性 | 含義 |
---|---|
display: inline-block; | 讓 <span> 像文字一樣橫向排列,但也能設置寬度(不像普通的 inline 元素那樣不能設置寬度) |
width: 80px; | 給每個乘法項 固定寬度,這樣不論 1×1=1 還是 9×9=81 ,都在統一寬度塊內顯示,整齊對齊 |
是 HTML 中的不換行空格字符
- 全稱是:non-breaking space
- 表示一個真正可見的空格,不會被瀏覽器忽略
<body>
<h2>9×9 上三角乘法表</h2>
<%for (int i = 1; i <= 9; i++) {
%>
<div class="row"><% for (int j = 1; j < i; j++) { %><spanforthecellWith class="cell"> </spanforthecellWith><% }for (int j = i; j <= 9; j++) { %><spanWwwhateverIcanName class="cell"><%= i %>×<%= j %>=<%= i * j %></spanWwwhateverIcanName><% } %>
</div>
<%}
%>
</body>
class前可以任意命名(但一般不要這樣做,還是不太允許的)
- 瀏覽器看到
spanWwwhateverIcanName
,雖然它不是標準 HTML 標簽,但因為它是內聯標簽(inline element),不會影響整體布局。 - 它仍然像
<span>
一樣顯示,所以不會影響頁面的結構。
瀏覽器不認識 div__lalala
這個標簽,所以它會:
- 直接忽略
div__lalala
,導致其內部的元素可能失去結構化 - 或者以未知的塊級元素解析,導致 CSS(如
white-space: nowrap
)失效
- 瀏覽器對內聯元素的解析更寬松(即使是未知標簽,也不會影響排版)。
- 瀏覽器對塊級元素的解析更嚴格,未知塊級標簽會影響
CSS
結構,導致排版錯誤。
標簽包含
<%@page contentType="text/html;charset=gb2312"%>
<html>
<head><title>include demo</title>
</head>
<body><%@include file="incl.jsp"%><%@include file="incl.txt"%> <%@include file="incl.inc"%>
</body>
</html>
<%@page contentType="text/html;charset=gb2312"%>
-
設置頁面的內容類型為 HTML
-
設置字符編碼為 GB2312(早期用于中文頁面的編碼)
-
這會影響 HTTP 響應頭和 HTML
<meta charset>
默認值
<%@include file="incl.jsp"%>
<%@include file="incl.txt"%>?
<%@include file="incl.inc"%> ??
用的是 JSP 的“靜態包含指令”(directive include)
含義:在 JSP 被編譯成 Java 代碼之前,直接把指定文件的內容“粘貼”到這行位置上。
JSP 是一個“預處理器”
-
incl.jsp
→ 一個包含<h1>歡迎訪問</h1>
的 HTML -
incl.txt
→ 一個純文本,比如這是文本部分
-
incl.inc
→ 一個 HTML 片段,比如<footer>版權所有</footer>
只要你把這三個文件放在和 includeDemo01.jsp
同一目錄下,就可以了
只要它們是合法的文本片段(HTML 或 JSP 語法中可插入的內容),就能被靜態包含進去。
-
不一定非是 JSP 文件
-
只要在語法上能“插得進去”,都沒問題
<%-- 使用此語句處理顯示中的亂碼 --%>
<%@page contentType="text/html;charset=gb2312"%>
<html>
<head><title>include demo</title>
</head>
<body>
<%--<jsp:include page="incl.jsp"><jsp:param name="ref1" value="ZTE"/><jsp:param name="ref2" value="tom"/></jsp:include>
--%><jsp:include page="incl.txt"><jsp:param name="ref1" value="ZTE"/><jsp:param name="ref2" value="ls"/>
</jsp:include><%--<jsp:include page="incl.inc"/> --%>
</body>
</html>
-
告訴 JSP 引擎輸出 HTML 頁面時使用 GB2312 編碼(中文)
-
防止中文亂碼問題
-
這對輸出的參數(如“ZTE”、“tom”)中含中文時尤其關鍵
<html>
<head>
? <title>include demo</title>
</head>
<body>
標準 HTML 頁面結構,主體都在 <body>
中
<%--<jsp:include page="incl.jsp"><jsp:param name="ref1" value="ZTE"/><jsp:param name="ref2" value="tom"/></jsp:include>
--%>
它是標簽式動態包含,特點如下:
特性 | 含義 |
---|---|
<jsp:include ... /> | 是 運行時包含(和 @include 不同) |
<jsp:param /> | 向被包含的 JSP 頁面傳遞參數(類似 URL 參數) |
被包含頁面 | incl.jsp :可以使用 request.getParameter("ref1") 獲取值 |
如果取消注釋,運行時會:
-
加載
incl.jsp
-
向其中傳遞兩個參數:
ref1=ZTE
,ref2=tom
<jsp:include page="incl.txt"><jsp:param name="ref1" value="ZTE"/><jsp:param name="ref2" value="ls"/>
</jsp:include>
包含的是 .txt
文件,Tomcat 默認不會把 .txt
當作 JSP 來解析,而是:
? 把它當成純文本文件 → 直接輸出內容,不處理其中的 JSP 語法(<%= ... %>)
這就是你看到它原樣打印出來的原因。
正常獲取參數的兩種前提方式:
? 方式 1:通過 HTML 表單提交(推薦)
你需要一個表單頁面(比如 demo01.html
),向 demo02.jsp
發起 POST 請求并帶上 uname
參數:
<!-- demo01.html -->
<form action="demo02.jsp" method="post"><label>請輸入姓名:</label><input type="text" name="uname"><input type="submit" value="提交">
</form>
需要新建一個 HTML 文件,比如命名為 demo01.html
,內容如下:?
放在和 demo02.jsp
同一個 Web 應用項目目錄下(比如你的 webapp/
、WebContent/
或 src/main/webapp/
中)
方式 2:通過 GET 參數訪問
你也可以直接在地址欄里輸入 URL,帶上 uname
參數:
http://localhost:8080/你的項目/demo02.jsp?uname=張三
所謂“靜態編碼 vs 動態編碼”指的就是:
編碼處理方式指的是 后端 JSP 頁面中對中文參數的“讀取方式”,與 HTML 是否是靜態頁面無直接關系。
類別 | 實現方式 | 特點 |
---|---|---|
靜態編碼(手動轉碼) | 獲取參數后再用 getBytes() + new String(...) 手動轉換 | 繁瑣但對控制力高,適用于不支持動態設置編碼的環境 |
動態編碼(統一設置) | 用 request.setCharacterEncoding("編碼") 預先設定 | 推薦方式,簡潔穩定 |
理解并對比:
客戶端跳轉(
sendRedirect
)
服務端跳轉(forward
或<jsp:forward>
)
各自的執行順序、顯示效果、地址欄變化、數據是否能傳遞
<%@page contentType="text/html;charset=gb2312"%>
<h1>歡迎光臨:responseDemo03.jsp</h1>
<!-- http://127.0.0.1:8080/test/base/05/responseDemo03.jsp?upass=123 -->
<%System.out.println("** 跳轉之前...") ;
%>
<%// 進行跳轉response.sendRedirect("responseDemo04.jsp?uname=ZTE");//response.setHeader("refresh","0;URL=responseDemo04.jsp?uname=ZTE") ;
%><%--<jsp:forward page="responseDemo04.jsp"/>--%><% //request.getRequestDispatcher("responseDemo04.jsp").forward(request, response);System.out.println("** 跳轉之后...");%>
<%@page contentType="text/html;charset=gb2312"%>
-
設置當前頁面的內容類型為 HTML,字符編碼是
gb2312
(簡體中文) -
作用:防止中文亂碼
<h1>歡迎光臨:responseDemo03.jsp</h1>
-
頁面顯示的靜態內容,表示這是
03.jsp
頁面 -
只有在沒有跳轉成功時才可能看到這個內容(實際上會被跳走)
<% ... %>
是 JSP 的腳本標記(scriptlet),它的作用是:
?? 把其中的 Java 代碼嵌入到 HTML 頁面中,并由服務器(Tomcat)在運行時翻譯成 Java Servlet 來執行
JSP(Java Server Pages)是 服務器端動態網頁技術,它的本質是:
?? 一種“模板語言”,頁面中可以寫 HTML + Java 代碼
它不是瀏覽器能直接識別的,而是被 Tomcat 服務器在第一次訪問時:
JSP → 翻譯成 Java Servlet → 編譯為 class → 運行 → 返回 HTML
假設你訪問一個 JSP 頁面:
http://localhost:8080/demo/responseDemo03.jsp
Tomcat 后臺執行的完整流程如下:
-
解析 JSP 文件
-
Tomcat 找到
.jsp
文件 -
把頁面中的 HTML 保留,把
<% %>
中的 Java 代碼提取出來
-
-
翻譯成 Java Servlet 文件
-
每個 JSP 都會被轉成一個 Servlet 類(比如叫
responseDemo03_jsp.java
)
-
-
編譯成
.class
字節碼-
Servlet 類被編譯成
.class
文件,交給 JVM 執行
-
-
運行 Servlet,輸出 HTML
-
Servlet 執行時,把 HTML 輸出給瀏覽器
-
<% System.out.println(...) %>
會打印到服務器控制臺(Tomcat 終端) -
<%= ... %>
的內容會輸出到瀏覽器頁面
-
你訪問的 responseDemo03.jsp
頁面能正常運行
里面的跳轉目標 responseDemo04.jsp
根本不存在或路徑不對
跳轉后地址欄變成了 responseDemo04.jsp?uname=ZTE
,并成功顯示了頁面內容
客戶端跳轉(Client-side Redirect)成功
測試服務端跳轉(Server-side Forward)
客戶端跳轉的時機非常早,JSP 在遇到這句代碼時:
response.sendRedirect("responseDemo04.jsp?uname=ZTE");
會立刻:
終止后續 JSP 執行(包括頁面還沒輸出的 HTML)
把響應狀態設置成 302(重定向)
讓瀏覽器主動發起新請求訪問目標地址
如果你想要先顯示一部分頁面再跳轉,那就不是 sendRedirect
的用途,而需要用 JavaScript 來實現:
<h1>歡迎光臨</h1>
<script>
? ? setTimeout(() => {
? ? ? ? window.location.href = "responseDemo04.jsp?uname=ZTE";
? ? }, 2000); // 2秒后跳轉
</script>
?
response.setHeader("refresh",...) 也是客戶端跳轉 ,類似 sendRedirect,通過 HTTP 響應頭控制刷新跳轉
<%--<jsp:forward page="responseDemo04.jsp"/>--%>
它是另一種服務端跳轉寫法,和 request.getRequestDispatcher(...).forward(...)
是等價的,寫法更簡潔。
http://localhost:8080/Web_exploded/responseDemo03.jsp
Cookie 的創建與客戶端行為機制
<!--http://127.0.0.1:8080/test/base/05/cookieDemo01.jsp?name=tom&password=123-->
<%String uname=request.getParameter("name");String upass=request.getParameter("password");Cookie c1 =null;Cookie c2 =null;if("tom".equals(uname)&&"123".equals(upass)){c1 = new Cookie("name",uname) ;c2 = new Cookie("password",upass) ;// 保存時間為60秒//c1.setMaxAge(60) ;//c2.setMaxAge(60) ;}// 通過response對象將Cookie設置到客戶端response.addCookie(c1) ;response.addCookie(c2) ;
%>
<!-- 訪問示例:http://127.0.0.1:8080/test/base/05/cookieDemo01.jsp?name=tom&password=123 -->
你需要用瀏覽器訪問這個地址,帶上參數 name=tom&password=123
默認瀏覽器關閉時 Cookie 消失;設置了 setMaxAge() 后可以保留固定時間
系統 Cookie:瀏覽器自動攜帶,例如 JSESSIONID(Session ID)
用戶 Cookie:程序員手動通過 new Cookie(...) 創建的,比如你這里的 name 和 password
使用 Session 實現用戶身份驗證
<%@page contentType="text/html;charset=gb2312"%>
<form action="login.jsp" method="post">用戶名:<input type="text" name="uname"><br>密碼:<input type="text" name="upass"><br><input type="submit" value="登陸">
</form><%// 判斷是否有請求內容// 在自提交的頁面中,必須對程序第一次運行做出處理if(request.getParameter("uname")!=null&&request.getParameter("upass")!=null){// 第一次的時候,并不能取得請求的參數String name = request.getParameter("uname") ;String password = request.getParameter("upass") ;System.out.println("name:"+name) ;System.out.println("password:"+password) ;if(name.equals("admin")&&password.equals("admin")){// 表示登陸成功// 通過flag屬性判斷用戶是否已經登陸session.setAttribute("flag","ok") ;// 跳轉到sucess.jsp//response.sendRedirect("sucess.jsp") ;%><jsp:forward page="sucess.jsp"/><%}else{response.sendRedirect("error.jsp");}}
%>
<form action="login.jsp" method="post">
這句話的意思是:
當你在輸入框里填完用戶名和密碼
然后點擊“登錄”按鈕
瀏覽器會自動把你填寫的內容通過 HTTP 的 POST 方法發回給 login.jsp 頁面本身
這個提交過程是 瀏覽器自己完成的,你無需手動在地址欄輸入任何參數
response.setHeader("refresh", "2;URL=login.jsp");
其中的數字 2 表示:
? 在頁面顯示當前內容 2 秒后,自動跳轉到 login.jsp 頁面。
Refresh: 秒數;URL=跳轉地址
所以這句的意思就是:
當前頁面停留 2 秒
然后自動跳轉回 login.jsp
你在瀏覽器看到的是:“登錄失敗”顯示 2 秒 → 頁面自動返回登錄界面
在 JSP 或 Web 開發中,URL=login.jsp
這樣的寫法是相對路徑。
它并不一定非要寫完整的 http://localhost:8080/xxx/login.jsp
session.setAttribute("flag", "ok");
它的作用是:
在服務器端為當前訪問用戶的 Session 中,保存一條數據:鍵是 "flag",值是 "ok"。
這就像是貼了一個標簽,告訴服務器:“這個用戶已經登錄了”。
<jsp:forward page="sucess.jsp"/>
確實,這句是頁面跳轉語句,但跳轉本身并不判斷用戶是否登錄,它只是跳頁面。
而:
session.setAttribute() 是用來標記身份的,跳轉之后別的頁面可以判斷是否有這個標記。