JavaWeb 复习讲义
原始讲义
第六部分 自测与附录

第12章 期末自测卷与查漏补缺

难度:★★★★★ | 前置知识:第1~11章 | 本章解决:用三份卷子把"以为自己会了"变成"确实会了",并把每一道错题精确映射回某一章的某一节

本章导读


12.1 基础卷(100 分 / 60 分钟)

【考点】

这张卷子的设计意图是"扫盲":覆盖第 1~8 章里所有"必须记住"的事实性知识,包括标签属性、报文格式、状态码、生命周期、作用域、JSTL 前缀。60 分钟的时间分配建议是:单选 15 分钟、填空 8 分钟、判断 5 分钟、简答 32 分钟。 单选和判断不要恋战,拿不准的先凭第一直觉选一个并做记号;简答题占 40 分,是这张卷子的关键部分,必须留足时间写"关键词加一句解释",只写关键词拿不到满分,只写大白话也不给分。

【易错点】 做客观题时最高频的失分是看错题干的否定词,与会不会知识点关系不大。本卷里带不属于、错误、不能的题干共有 6 处,圈出来再选,能少丢 4~6 分。另外,凡是问"默认值"的题(如 form 的默认 method、Servlet 的默认 load-on-startup、Cookie 的默认路径),一律按规范原文回答,不要按你在某个项目里的偶然现象回答。

一、单项选择题(20 题,每题 2 分,共 40 分)

  1. 下列哪一项不属于 W3C 标准规定的网页三部分?( )
    A. 结构 B. 表现 C. 行为 D. 存储
  2. 关于 XML 与 HTML 的区别,下列说法正确的是( )
    A. HTML 标签可以自定义,XML 标签不能自定义
    B. HTML 语法要求极其严格,XML 语法松散
    C. XML 用于传输和存储数据,HTML 用于展示数据
    D. 两者没有区别,只是名字不同
  3. 想让一段文字"独占一行并且上下留出空行",应使用( )
    A. <br> B. <p> C. <hr> D. <span>
  4. <td colspan="2"> 的含义是( )
    A. 该单元格纵向跨 2 行 B. 该单元格横向跨 2 列
    C. 该单元格内容居中 2 次 D. 该行有 2 个单元格
  5. 表单提交时,若某个 <input> 没有写 name 属性,结果是( )
    A. 提交时值为空字符串 B. 该表单项的数据不会被提交
    C. 页面报错无法提交 D. 自动使用 id 作为参数名
  6. 下列关于 method="get" 的说法,错误的是( )
    A. 它是 form 的默认提交方式 B. 请求参数拼接在 URL 后面
    C. 请求参数放在 HTTP 请求体中 D. URL 长度通常限制在 4KB 左右
  7. CSS 三种导入方式中,优先级最高(在同等条件下最先生效)的是( )
    A. 外部样式表 B. 内部样式表 C. 内联样式 D. 三者永远相同
  8. 下列选择器中,权重最高的是( )
    A. div B. .box C. #header D. div.box
  9. 盒模型中,box-sizing: border-box 的作用是( )
    A. width 只包含内容区 B. width 包含内容 + 内边距 + 边框
    C. 取消外边距 D. 让元素脱离文档流
  10. 在 JavaScript 中,"5" == 5 与 "5" === 5 的结果分别是( )
    A. true、true B. true、false C. false、true D. false、false
  11. 下列哪个方法可以在不重新加载整个页面的情况下与服务器交换数据?( )
    A. window.location.reload() B. XMLHttpRequest
    C. document.write() D. form.submit()
  12. HTTP 响应状态码 302 表示( )
    A. 请求成功 B. 资源未修改,使用缓存
    C. 重定向,浏览器会自动访问 Location 指定的地址 D. 服务器内部错误
  13. 下列状态码中,责任在客户端的是( )
    A. 500 B. 502 C. 404 D. 503
  14. Servlet 的生命周期中,destroy() 方法被调用的次数是( )
    A. 每次请求一次 B. 每个线程一次 C. 整个生命周期内一次 D. 从不调用
  15. 关于 request.getParameter() 与 request.getAttribute(),说法正确的是( )
    A. 前者取服务端存的数据,后者取客户端传的数据
    B. 前者取客户端传的数据,后者取服务端域中存的数据
    C. 两者完全等价 D. 后者只能取字符串
  16. 请求转发与重定向的区别,下列说法错误的是( )
    A. 转发是服务器内部行为,浏览器地址栏不变
    B. 重定向是浏览器行为,地址栏会变
    C. 转发可以共享 request 域,重定向不能
    D. 重定向只能跳转到本站资源
  17. 执行 cookie.setMaxAge(0) 的效果是( )
    A. 立即删除该 Cookie B. 该 Cookie 永不过期
    C. 该 Cookie 变成会话 Cookie D. 抛异常
  18. 下列哪个对象的作用域是"一次会话"?( )
    A. request B. session C. application D. page
  19. JSP 页面中,${user.username} 取不到值时,页面上显示( )
    A. null B. 报 500 错误 C. 空字符串 D. ${user.username} 原样输出
  20. 使用 PreparedStatement 能防止 SQL 注入,根本原因是( )
    A. 它对 SQL 做了字符串替换 B. 它预编译 SQL,参数与语句结构分离
    C. 它自动过滤了单引号 D. 它把参数做成了 Base64

二、填空题(10 题,每题 1 分,共 10 分)

  1. HTML 文件的扩展名是 ________ 或 ________。
  2. 相对路径中,../ 表示 ________。
  3. CSS 的全称是 ________。
  4. 表单的 ________ 属性指定提交的地址,________ 属性指定提交方式。
  5. HTTP 请求报文由 ________、请求头、请求体三部分组成。
  6. Servlet 接口中,处理请求的方法是 ________。
  7. 获取 Session 对象的方法是 ________;让 Session 立即失效的方法是 ________。
  8. JSP 的四大作用域是 page、request、________、________。
  9. 过滤器放行请求的方法是 ________。
  10. JDBC 中,ResultSet 判断是否还有下一行数据的方法是 ________。

三、判断题(10 题,每题 1 分,共 10 分)

  1. HTML 标签区分大小写,<FONT> 与 <font> 效果不同。( )
  2. <span> 是行内元素,多个 <span> 会显示在同一行。( )
  3. CSS 的 id 选择器在一个页面中可以重复使用多次。( )
  4. var 声明的变量存在变量提升,let 不存在。( )
  5. HTTP 是无状态协议,所以需要 Cookie/Session 来保持状态。( )
  6. 一个 Servlet 类在容器中会为每个请求创建一个新实例。( )
  7. response.getWriter() 与 response.getOutputStream() 可以在同一个 Servlet 中同时使用。( )
  8. 关闭浏览器后,服务端的 Session 对象立即被销毁。( )
  9. 过滤器链中,多个过滤器的执行顺序可以通过 @WebFilter 的 order 属性指定。( )
  10. DriverManager.getConnection() 每次调用都会新建一个物理连接,所以需要连接池。( )

四、简答题(4 题,每题 10 分,共 40 分)

  1. 简述 GET 与 POST 的区别(至少 4 点)。
  2. 简述 Servlet 的生命周期(四个阶段,说明每个阶段做什么、被调用几次)。
  3. 简述请求转发(forward)与重定向(redirect)的区别(至少 4 点),并各举一个适用场景。
  4. 简述 Cookie 与 Session 的区别(存储位置、安全性、生命周期、存储容量),并说明"登录状态"应该存在哪里、为什么。

12.2 进阶卷(100 分 / 45 分钟)

【补充】

这张卷子考的是"读懂代码的执行顺序",而不是"背下来"。读程序题的正确答案通常由三个要素共同决定:① 代码实际执行到哪几行(return、异常、if 分支会改变执行路径);② 每次执行时变量的值;③ 输出的形态(是写进响应体、还是写进控制台、还是根本没机会执行)。 所以答题时不要一眼看出答案就写,先在草稿上按行标注"这一行会不会执行、执行时变量是什么"。

【考点】 找错题的评分是按错误点给分的:指出位置给一半分,说明原因并给出改法才给全分。常见的错误点只有六类:路径写错、注解写错、编码设置顺序错、资源没关闭、return 缺失导致重复输出、作用域用错。答题时按这六类去套,比漫无目的地读代码快得多。

一、读程序写结果(5 题,每题 8 分,共 40 分)

1. 下列 HTML 在浏览器中的显示结果是:

<h1>标题一</h1>
<h3>标题三</h3>
<div>块一</div><div>块二</div>
<span>行一</span><span>行二</span>

2. 下列 CSS 生效后,#box 中文字的颜色是:

div { color: blue; }
.box { color: green; }
#box { color: red; }
<div id="box" class="box">文字</div>

3. 下列 JavaScript 执行后,控制台依次输出什么:

var a = 1;
function f() {
    console.log(a);
    var a = 2;
    console.log(a);
}
f();
console.log(a);

4. 阅读下列 Servlet,访问 /demo 后浏览器地址栏与页面分别是什么:

@WebServlet("/demo")
public class Demo extends HttpServlet {
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        req.setAttribute("msg", "hello");
        resp.sendRedirect(req.getContextPath() + "/show.jsp");
    }
}
<%-- show.jsp --%>
页面内容:${msg}

5. 下列 JSP 片段的输出是:

<c:forEach items="${list}" var="b" varStatus="s">
    ${s.count}-${b.brandName};
</c:forEach>

假设 list 中有两个元素,brandName 分别为"华为""小米"。

二、找错并改正(5 题,每题 8 分,共 40 分)

1.

protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
    String name = req.getParameter("username");
    req.setCharacterEncoding("UTF-8");
    System.out.println(name);
}

2.

@WebFilter("/*")
public class LoginFilter implements Filter {
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) {
        System.out.println("进入了过滤器");
    }
}

3.

String sql = "select * from tb_brand where brand_name = '" + name + "'";
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql);

4.

<%@ page contentType="text/html;charset=UTF-8" %>
<c:forEach items="${brands}" var="brand">
    <tr><td>${brand.brandName}</td></tr>
</c:forEach>

5.

Connection conn = DriverManager.getConnection(url, user, pwd);
PreparedStatement pstmt = conn.prepareStatement("delete from tb_brand where id = ?");
pstmt.setInt(1, id);
pstmt.executeUpdate();
// 业务完成,未做其他处理

三、简答题(2 题,每题 10 分,共 20 分)

  1. 一个请求从浏览器发出到 JSP 渲染完成,会依次经过哪些组件?请按顺序写出,并说明每个组件在这一过程中做了什么。(提示:浏览器 → 过滤器 → Servlet → Service → DAO → 数据库 → JSP)
  2. 用户在 A 页面登录成功后,访问 B 页面却提示"未登录",请列出至少 4 种可能的原因及排查方法。

12.3 综合设计卷(100 分 / 60 分钟)

【考点】

综合设计题考的是分层的意识,不要求你写出全部代码。阅卷老师手上通常只有一张"采分点表",上面写着:实体类与表字段对应了吗?DAO 只发 SQL 吗?业务规则和事务在 Service 吗?Servlet 只做收发参数吗?页面用 EL/JSTL 写、没有脚本片段吗?未登录的入口被过滤器拦住了吗?这七问七答就是满分答案的框架。答题顺序建议:先画一张三层的类与调用关系图(5 分钟),再按图逐层写关键代码(35 分钟),最后补上"异常与中文乱码怎么处理"(10 分钟),留 10 分钟检查包名、路径和 SQL 参数顺序。

【易错点】 综合题最容易丢分的地方是写超范围:题目说"设计并实现图书管理模块",你顺手把用户注册、权限分级、分页、文件上传全写上了,结果挤掉了本题的采分点,还引入了没讲过的框架(Spring、MyBatis)。严格按需求写,多写的部分不得分。 另外,"未登录不能访问"这一条几乎年年考,它的标准答法是"一个实现 Filter 的类,加 web.xml 或 @WebFilter 配置拦截 /*,白名单放行登录页与静态资源",三句话必须齐全。

题目:设计并实现"图书管理"模块

需求如下:

  1. 数据库表 tb_book:id(主键自增)、book_name(书名)、author(作者)、price(价格,decimal)、status(0 下架 / 1 上架)。
  2. 功能:图书列表查询(支持按书名模糊查询)、新增图书、修改图书、删除图书。
  3. 未登录用户访问任何列表页或增删改接口,必须被拦截并跳转到登录页,登录成功后自动回到原来的页面。
  4. 所有 POST 请求的中文不能乱码。
  5. 页面用 JSP + EL + JSTL 渲染,不允许在 JSP 里写 Java 代码。

请完成(按小问给分):


12.4 参考答案与评分要点

基础卷 · 单选

  1. D(存储不是 W3C 三层之一) 2. C 3. B(<p> 段落自带上下间距;<br> 只换行不加空行) 4. B(colspan 跨列,rowspan 跨行) 5. B(没有 name 的表单项不会被提交) 6. C(GET 的参数在 URL 上,不在请求体) 7. C(同等条件下内联 > 内部/外部,内部与外部比的是书写顺序) 8. C(id 权重 100,class 10,元素 1) 9. B 10. B(== 会做类型转换,=== 要求类型也相同) 11. B 12. C 13. C(5xx 才是服务端责任) 14. C 15. B 16. D(重定向可以跳到任意 URL,包括站外) 17. A(setMaxAge(0) 表示立即删除,负数才是会话 Cookie) 18. B 19. C(EL 取不到值输出空串,不报错,这也是 ${} 与 <%= %> 的重要差别) 20. B

基础卷 · 填空

  1. .htm、.html 2. 上一级目录 3. Cascading Style Sheet(层叠样式表) 4. action、method 5. 请求行 6. service() 7. request.getSession()、session.invalidate() 8. session、application 9. chain.doFilter(request, response) 10. next()

基础卷 · 判断

  1. ×(HTML 标签不区分大小写) 2. √ 3. ×(id 必须唯一) 4. √ 5. √ 6. ×(单实例多线程) 7. ×(同一响应中二者互斥,强行同时用会抛 IllegalStateException) 8. ×(服务端 Session 还在,只是浏览器把 JSESSIONID 丢了) 9. ×(@WebFilter 没有 order 属性,注解方式的顺序按类名字母序;要精确控制顺序得用 web.xml) 10. √

基础卷 · 简答(要点给分)

  1. ①参数位置:GET 在 URL 后,POST 在请求体;②长度:GET 受 URL 长度限制(约 4KB),POST 理论上无限制;③安全性:GET 参数暴露在地址栏与历史记录中,POST 相对隐蔽(但都不加密,敏感数据必须 HTTPS);④缓存与书签:GET 可被缓存、可收藏,POST 不行;⑤语义:GET 用于查询,POST 用于提交/修改;⑥幂等:GET 幂等,POST 不幂等。
  2. ①加载与实例化:第一次被访问时(或 loadOnStartup 配置后服务器启动时)由容器创建实例,只创建一次;②初始化:调用 init(),只调用一次,用于加载配置、建连接;③请求处理:每次请求调用 service(),由它根据请求方式分派到 doGet/doPost,调用 N 次;④服务终止:容器关闭或回收内存时调用 destroy(),只调用一次。
  3. ①发起方:转发是服务器内部行为,重定向是浏览器行为;②请求次数:转发 1 次,重定向 2 次;③地址栏:转发不变,重定向变为新地址;④域共享:转发可共享 request 域,重定向不能;⑤跳转范围:转发只能站内,重定向可以站外;⑥性能:转发略快。场景:查询结果展示用转发(要带数据);登录成功后跳首页、支付完成后跳结果页用重定向(防止刷新重复提交)。
  4. ①存储位置:Cookie 在浏览器,Session 在服务器;②安全性:Cookie 明文可见、可篡改,Session 相对安全;③生命周期:Cookie 可控(setMaxAge),Session 由超时/invalidate/服务器关闭决定;④容量:Cookie 单个约 4KB、每域名数量有限(约 20~50 个),Session 受服务器内存限制;⑤登录状态应存 Session(服务端可控、可主动踢下线),只把 JSESSIONID 通过 Cookie 交给浏览器;勾选"记住我"时,才把用户名/令牌这类低敏感信息写入持久 Cookie。

进阶卷 · 读程序

  1. "标题一"字最大并独占一行,"标题三"字较小并独占一行;"块一""块二"各占一行(div 是块级);"行一""行二"在同一行(span 是行内)。共 4 行视觉输出。
  2. 红色。三条规则的选择器权重分别是 1(元素)、10(class)、100(id),id 选择器胜出;这叫"后来居上不如权重高"。
  3. 依次输出 undefined、2、1。函数内的 var a 被提升到函数顶部但未赋值,所以第一次打印是 undefined;赋值后打印 2;函数内的 a 是局部变量,不影响外层的 a,所以最后打印 1。
  4. 地址栏变为 /show.jsp(重定向,浏览器发起第二次请求),页面上显示"页面内容:"后面为空。原因是 req.setAttribute 存的是 request 域,而重定向产生了新的请求,域数据随之丢失。这题考的就是转发与重定向在域共享上的差异。
  5. 输出 1-华为;2-小米;。varStatus.count 从 1 开始计数,index 从 0 开始。

进阶卷 · 找错

  1. ①doPost 没有声明 throws ServletException, IOException,无法编译;②setCharacterEncoding 必须在第一次 getParameter 之前调用,否则无效。正确顺序是先设置编码再取参数。
  2. ①没有调用 chain.doFilter(req, resp),请求被吞掉,页面空白;②方法签名不应抛受检异常之外的改动:应为 throws IOException, ServletException;③建议加 @WebFilter("/*") 的同时在 web.xml 里确认没有重复配置。
  3. 字符串拼接 SQL 存在 SQL 注入风险(如传入 ' or '1'='1 可查出全表);应改用 PreparedStatement + 占位符:select * from tb_brand where brand_name = ?,再 setString(1, name)。
  4. 缺少 JSTL 标签库声明 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>,否则 <c:forEach> 会被当成普通文本原样输出。
  5. 没有关闭资源(pstmt.close()、conn.close()),且连接不是从连接池取的、也没有归还;长时间运行会耗尽连接。应使用 try-with-resources 或 finally 中按"先开后关"顺序关闭;若用连接池,close() 是归还而非物理关闭。

进阶卷 · 简答

  1. 浏览器拼请求 → 编码过滤器(设置字符集)→ 登录校验过滤器(判断 Session)→ 前端控制器/Servlet(取参数、调业务)→ Service(业务校验、开事务)→ DAO(拼 SQL、执行)→ 数据库(返回结果集)→ DAO 封装成对象 → Service 返回 → Servlet 存入 request 域并转发 → JSP(EL 取值、JSTL 遍历、生成 HTML)→ 响应回到浏览器渲染。
  2. ①登录成功后没把用户放进 Session(或放进了 request 域);②getSession() 前后两次不是同一个会话(浏览器禁用了 Cookie、换浏览器、跨域);③过滤器判定的 key 与登录时存入的 key 不一致("user" vs "loginUser");④Session 超时被销毁(默认 30 分钟);⑤项目重新部署导致 Session 丢失;⑥拦截路径配置过宽,把登录接口自己也拦了,导致永远登录不上。排查:先看浏览器里有没有 JSESSIONID,再看服务端 sessionId 是否变化,最后打印 Session 里的 key 集合。

综合设计卷 · 评分要点

  • 三层图:Web(Servlet)→ Service → DAO,实体类贯穿,工具类与过滤器横切;职责:Servlet 只做参数接收与页面跳转,Service 做业务与事务,DAO 只做 SQL。
  • 建表 SQL 参考:
create table tb_book (
    id        int primary key auto_increment,
    book_name varchar(50),
    author    varchar(30),
    price     decimal(10, 2),
    status    int
);
  • 模糊查询必须写成 where book_name like ?,参数值为 "%" + name + "%";写成 like '%?%' 时占位符在引号内,会被当成普通字符,永远匹配不到。
  • 过滤器要点:String uri = req.getRequestURI(); 判断是否在放行清单(登录页、登录接口、静态资源);未登录时 resp.sendRedirect(ctx + "/login.jsp?returnUrl=" + URLEncoder.encode(uri, "UTF-8"));登录成功后按 returnUrl 跳回。
  • 扣分点:忘记 request.setCharacterEncoding、getSession(false) 未判空、ResultSet/PreparedStatement/Connection 未关闭、JSP 里写了 <% %> 脚本、c:forEach 未声明 taglib。

12.5 错题定位表

做完三份卷子后,按下表把错题对回章节。若某一格的错题数 ≥ 2,说明那一节需要重读。

题号考查点回看位置
基础 1~4HTML 概念、标签语义、表格合并第1章 1.2、1.4、1.8
基础 5~6表单 name 与 GET/POST第1章 1.10、1.11
基础 7~9CSS 引入方式、选择器权重、盒模型第2章 2.2、2.3、2.5
基础 10~11JS 运算符、Ajax第3章 3.3、第9章 9.6
基础 12~13状态码分类与责任归属第4章 4.5、4.6
基础 14~15Servlet 生命周期、request 取值第5章 5.4、第6章 6.2
基础 16、18转发/重定向、作用域第6章 6.5、6.6
基础 17、19Cookie 存活时间、EL 空值第7章 7.2、第8章 8.5
基础 20PreparedStatement 防注入第10章 10.4
填空 1~10全章基础概念按空位对应章节
判断 1~10易错细节各章【易错点】块
简答 1~4四大对比第4、5、6、7章的【对比】块
进阶 1~5读代码第1、2、3、6、8章
进阶 找错 1~5编码顺序、Filter 放行、SQL 注入、taglib、资源释放第6、9、10章
进阶 简答 1~2全链路、登录失效排查第11章 11.2、11.8
综合设计三层架构与工程能力第8章 8.7、第10章 10.7、第11章全章

本章小结

三份卷子对应三种能力,考试考的是前两种,工作考的是第三种:

卷别考的能力判据对应的知识段
基础卷记忆与辨认能说清"是什么、区别是什么"第 1~5 章
进阶卷阅读与排错给一段代码能判断结果、能指出错误第 6~9 章
综合设计卷组装与工程给一个需求能分层落地、能说明理由第 10~11 章

如果你三份卷子的得分呈现"基础高、进阶中、综合低"的形状,不必焦虑,这是绝大多数人的曲线。补的方法只有一个:把第 11 章的联调排错手册亲手走一遍。把项目运行起来,故意制造一个 500,再顺着日志排查出来,比做十道简答题有用。

自测

这一章本身就是自测,这里再补一道"元问题",用来检验你是否真的建立了全局观:

问: 如果只能简短地向别人解释"JavaWeb 到底在做什么",你会怎么说?请用上"请求""响应""状态""持久化"四个词。

参考答案 浏览器把用户在页面上输入的东西打包成请求,经 HTTP 送到 Tomcat,Tomcat 交给 Servlet 处理;处理过程中要记住"你是谁",于是有了状态(Cookie/Session);要把数据存下来,于是有了持久化(JDBC/MySQL);最后 Servlet 把结果渲染成 HTML 作为响应发回去。整条链路就是:请求进来、状态跟上、数据落地、响应出去。