9x9上三角乘法表
乘法表的实现
html
<%@ 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>
分清楚哪些是可以自定义名字的,哪些是规定的语法
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里的设置也因此要修改符合了
html
<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
- 表示一个真正可见的空格 ,不会被浏览器忽略


html
<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
结构,导致排版错误。
标签包含
html
<%@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 文件
-
只要在语法上能"插得进去",都没问题
html
<%-- 使用此语句处理显示中的乱码 --%>
<%@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>
中
html
<%--
<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

html
<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
参数:
html
<!-- 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
)
- 每个 JSP 都会被转成一个 Servlet 类(比如叫
-
编译成
.class
字节码- Servlet 类被编译成
.class
文件,交给 JVM 执行
- Servlet 类被编译成
-
运行 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() 是用来标记身份的,跳转之后别的页面可以判断是否有这个标记。

