本文基于《JavaWeb程序设计任务教程》第4章的课后练习题进行整理与解析,涵盖填空、判断、选择、简答和编程五大题型,帮助学习者全面掌握Servlet核心概念与应用。
在开发过程中,若当前Web资源不打算处理请求,可通过特定接口提供的方法将请求转交其他资源处理。该接口提供了 请求转发 功能,使多个资源协同完成响应,最终由服务器统一返回给客户端。
RequestDispatcher
实现这一机制的关键是调用接口中的对应方法,允许将请求信息传递至其他Web组件进行后续处理。
forward()
在Servlet API中,用于封装HTTP响应数据的核心接口是 HttpServletResponse。
HttpServletResponse
该接口支持设置响应头、状态码以及获取输出流等操作,是构建响应内容的基础工具。
当服务器接收到请求后,因某些限制无法直接响应时,会指示客户端访问另一个URL路径,这种行为被称为 请求重定向。它要求客户端发起新的请求,因此浏览器地址栏会发生变化,并产生两次独立的HTTP请求。
在自定义Servlet类时,开发者可以选择继承两个基础类之一:通用协议抽象类 GenericServlet 或专为HTTP协议设计的实现类。
HttpServlet
其中,GenericServlet 不依赖具体协议;而另一实现类则专门服务于HTTP通信场景。
GenericServlet
Servlet的配置方式主要有两种:一种是通过传统的部署描述文件进行声明式配置;另一种则是使用注解方式简化注册流程。
web.xml
现代开发中,常采用 @WebServlet 注解来绑定URL映射,无需修改XML文件,提升了灵活性与效率。
Servlet从创建到销毁经历完整的生命周期,通常划分为三个主要阶段:初始化、运行处理和最终的清理阶段。
这三个阶段分别对应以下方法调用顺序:
init() → service()(或 doGet/doPost)→ destroy()
最后一个阶段称为 销毁阶段,在此期间执行资源释放等收尾工作。
关于 HttpServletResponse 对象的方法使用,其 getOutputStream() 与 getWriter() 是否可以同时发送响应体?
Response
错误
这两个方法互斥,只能选择其一使用,否则会抛出非法状态异常。
getOutputStream() 和 getWriter()
IllegalStateException
Tomcat在初始化Servlet实例时,是否会将其配置参数封装进一个特定对象中?
正确
容器会创建一个专用对象来保存初始化信息,便于Servlet读取配置参数。
ServletConfig
在定义 @WebServlet 注解时,urlPatterns 与 value 属性是否必须存在其一但不可共存?
@WebServlet
正确
两者功能完全相同,均用于指定URL映射规则,若同时设置会导致编译错误。
value 或 urlPatterns
在整个Servlet生命周期中,destroy() 方法是否会被多次调用?
destroy()
错误
该方法仅在Servlet被卸载前由容器调用一次,用于释放资源。
ServletRequest 接口的某个方法是否可用于将对象以键值对形式存入请求域中?
ServletRequest
正确
此功能常用于请求转发过程中共享数据,确保目标资源可访问传递的信息。
setAttribute()
某Servlet重写了其父类的两个关键方法,分别为处理GET和POST请求的方法。据此推断,其父类最可能是哪一个?
D. HttpServlet
只有 HttpServlet 提供了标准的HTTP动词处理方法框架。
HttpServlet
doGet() 和 doPost()
考虑如下代码片段:
public class LoginServlet extends ___________ {
public void doGet(...) { ... }
public void doPost(...) { ... }
}
空白处应填写哪个类名?
B. HttpServlet
要重写doGet和doPost方法,必须继承支持HTTP协议的基类。
LoginServlet
现有以下Servlet代码:
public class Servlet1 extends HttpServlet {
public void doGet(...) {
System.out.println("get");
}
public void doPost(...) {
System.out.println("post");
doGet(request, response);
}
}
用户在浏览器地址栏输入URL并回车后,控制台输出结果是什么?
A. get
浏览器默认发送GET请求,触发doGet方法执行,故只打印“get”。
在 HttpServlet 类中,专门用于处理POST请求的方法名称是?
HttpServlet
C. doPost
这是标准命名规范的一部分,用于区分不同类型的HTTP请求。
在同一个Web应用中,希望多个Servlet之间共享数据,应使用哪个对象?
B. ServletContext
该对象代表整个Web应用的上下文环境,具有全局唯一性,适合存储公共数据。
ServletContext
1. 列举至少三个常用的HTTP响应状态码及其含义。
其他常见状态码还包括:500(服务器内部错误)、304(资源未修改,可使用缓存)、403(禁止访问)等。
HttpServletResponse2. 请求转发与重定向的异同简述(至少3点)
| 对比项 | 请求转发(Forward) | 请求重定向(Redirect) |
|---|---|---|
| 请求次数 | 仅发生一次请求,服务器内部完成跳转,客户端只接收一次响应 | 涉及两次独立请求:第一次获取跳转指令,第二次由浏览器主动发起新请求 |
| URL变化情况 | 浏览器地址栏保持原URL不变 | 地址栏更新为新的目标URL |
| 作用范围限制 | 只能在当前Web应用内部进行资源跳转 | 可跳转至任意合法URL,包括外部网站或其他应用 |
| 数据共享能力 | 可通过request域对象传递和共享数据 |
无法直接使用原request中的数据,需借助Session或参数传递 |
| 性能表现 | 效率较高,整个过程在服务器端完成,无需客户端参与 | 相对耗时,需浏览器二次请求,网络往返增加开销 |
使用建议:
以下内容专为JavaWeb初学者设计,针对两道编程题目提供详尽、逐行解释的代码分析,确保零基础读者也能理解每一句代码的功能与原理。
需求说明:
@WebServlet(name = "ChineseServlet", urlPatterns = "/ChineseServlet")
public class ChineseServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String data = "JavaWeb程序设计任务教程";
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
out.println(data);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
代码逐行解析:
第1行:
@WebServlet(name = "ChineseServlet", urlPatterns = "/ChineseServlet")/ChineseServlet 表示当用户访问特定路径时,服务器将调用该类进行处理。name 为该Servlet指定名称(非必需);urlPatterns = "/ChineseServlet" 定义了映射路径,即在浏览器输入http://localhost:8080/你的项目名/ChineseServlet即可触发该Servlet执行。第2行:
public class ChineseServlet extends HttpServlet {
声明一个公共类ChineseServlet,
ChineseServlet是类名;extends HttpServlet表明此类继承自HttpServlet——这是JavaWeb中用于处理HTTP请求的核心父类。doGet)来自定义行为。
第3~6行:
protected void doGet(...) 方法声明:doGet 是专门处理GET请求的方法(例如直接在浏览器输入地址访问);HttpServletRequest request代表客户端请求,可用于获取参数、头信息等;HttpServletResponse response表示服务器要返回的响应内容,可用于写入HTML或文本;throws ServletException, IOException 表示该方法可能抛出异常,必须声明以便调用者处理。request是用户寄来的信件,response是我们回信的内容。
第7行:
String data = "JavaWeb程序设计任务教程";data,存储待输出的中文内容。
第8行:
response.setContentType("text/html;charset=utf-8");setContentType 告诉浏览器:“我发送的是HTML格式内容,并采用UTF-8编码”,避免中文乱码问题。若未添加该语句,浏览器可能采用默认编码方式(例如 ISO-8859-1)来解析页面中的中文内容,导致出现乱码现象,如显示为“JavaWeb???”。
text/html
此部分标识当前内容为网页类型;
charset=utf-8
同时明确指定字符集编码为 UTF-8,该编码格式支持包括中文在内的全球多种语言文字。
特别提醒:这一行代码必须出现在获取输出流之前,否则设置将不起作用。
PrintWriter out = response.getWriter();
response.getWriter()
第9行代码的作用是获取一个名为
out
的“字符输出流”对象。可以将其类比为一支“笔”,用于向网页中写入文本内容。由于我们所输出的是纯文本信息(而非图片或文件等二进制数据),因此应使用
PrintWriter
(即字符流),而不是字节流。
out.println(data);
第10行则是利用这支“笔”——也就是
out
对象,将
data
字符串内容写入响应页面;其中
println
表示“打印并换行”,相当于在浏览器页面上展示出这行文字。
最终效果为:当用户打开浏览器访问该服务时,页面会清晰地显示出“JavaWeb程序设计任务教程”这几个大字。
第12至15行为:
doPost
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response); // 复用 doGet 中的处理逻辑
}
doPost
是专门用来处理表单提交(即 POST 请求)的方法。在此处直接调用
doGet(request, response)
意味着:“无论请求是通过 GET 还是 POST 方式发起,都统一交由相同的逻辑进行处理”。这种做法能够有效避免重复编写功能相同的代码,在实际开发中非常普遍。
问题回顾:
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response); // 为何调用 doGet,而不独立实现逻辑?
}
常见疑问:方法名称明明是
doPost
,为何内部却执行的是
doGet
?这样做是否会造成逻辑混乱?
答案一句话概括:
因为在当前功能场景下,GET 和 POST 请求所需完成的操作完全一致,因此让
doPost
直接调用
doGet
,从而避免重复编写相同代码。
doGet
:用于处理通过浏览器地址栏输入、点击超链接等方式触发的请求,对应 HTTP 的 GET 方法。
doPost
:用于处理表单提交(method="post")等场景下的请求,对应 HTTP 的 POST 方法。
示例说明:
访问
http://xxx/ChineseServlet
→ 触发
doGet
方法执行;
提交一个
<form action="/ChineseServlet" method="post">
表单 → 触发
doPost
方法执行。
以两个典型示例为例:
对于这两类功能而言,无论用户通过 GET 还是 POST 方式访问,期望的结果都应当完全相同:
从地址栏直接打开 → 显示中文 / 显示访问次数;
通过表单以 POST 提交访问 → 同样应显示中文 / 显示访问次数。
由此可见,两种请求的处理逻辑本质上并无区别。
如果不采用复用机制,则需要分别在两个方法中编写完全相同的处理逻辑:
// 不推荐写法(存在重复代码)
protected void doGet(...) {
// 包含10行处理逻辑
}
protected void doPost(...) {
// 完全复制上述10行逻辑 ← 易出错、难维护、浪费资源!
}
而通过在
doPost
中调用
doGet
,只需在一个地方定义核心逻辑即可:
protected void doGet(...) {
// 所有业务逻辑集中在此处编写
}
protected void doPost(...) {
doGet(request, response); // 直接复用已有逻辑,简洁高效
}
此种模式在 JavaWeb 开发中属于标准实践,被广泛应用于教材教学和考试评分中。
问题:为什么在
doPost
方法中调用
doGet
方法?
回答:因为该 Servlet 对 GET 请求和 POST 请求的处理逻辑完全一致,为了减少代码冗余、提升可维护性,故让
doPost
方法直接调用
doGet
以复用已有功能。
注意事项:并非所有情况下都适合如此设计!
只有当 GET 与 POST 的处理目标相同时,才可安全复用。
举例说明:
但在本题涉及的两个案例中,
在进行输出中文与统计访问次数的功能时,二者并无差异,因此可以安全地复用已有逻辑。
| 问题 | 回答 |
| 为何在代码中调用同一处理方法? | 由于两种请求的处理流程一致,复用能显著简化代码结构 |
| 这种做法是否合理? | 完全正确!这是开发中的标准实践,在考试和实际项目中均被认可 |
| 是否存在出错风险? | 只要功能需求相同,则不会出现问题 |
牢记原则:
“能复用就复用,避免重复造轮子”
这正是此类代码设计的根本思想!
doPost
具体要求如下:
@WebServlet(name = "ShowTimesServlet", urlPatterns = "/ShowTimesServlet")
public class ShowTimesServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
ServletContext context = getServletContext();
Integer times = (Integer) context.getAttribute("times");
if (times == null) {
times = 1; // 首次访问初始化为1
} else {
times = times + 1; // 后续访问累加
}
resp.setContentType("text/html;charset=utf-8");
PrintWriter out = resp.getWriter();
out.println("<html><head><title>页面访问统计</title></head>");
out.println("<body>");
out.println("当前页面被访问了 <font color='red' size='20'>" + times + "</font> 次");
out.println("</body></html>");
context.setAttribute("times", times); // 将最新次数写回上下文
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
doGet(req, resp); // 复用GET处理逻辑
}
}
doGet
第1行:
@WebServlet(...)/ShowTimesServlet
第2行:
public class ShowTimesServlet extends HttpServletHttpServlet,以便具备处理HTTP请求的能力。
第3行:
private static final long serialVersionUID = 1L;第5~8行:
doGet第9行:
ServletContext context = getServletContext();getServletContext()context.getAttribute("times")
小贴士: 可将其类比为班级中的“黑板报”——全班可见,老师发布信息后不会立即清除。
第10行:
Integer times = (Integer) context.getAttribute("times");context.getAttribute("times")"times" 的数据。null。(Integer) 表示强制类型转换:因 getAttribute() 返回的是 Object 类型,需转为 Integer(即整数包装类)方可参与运算。
为何不使用基本类型 int?
因为
null(null)无法赋值给 int(基本类型),但可赋值给 Integer(引用类型)。
getAttribute
第12~15行:访问次数判断与更新逻辑
if (times == null) {
times = 1; // 第一次访问
} else {
times = times + 1; // 计数递增
}
若为首次访问(即
times == null 为空),则将次数设为1;否则执行加1操作。第17~18行:设置响应编码格式并获取输出流
resp.setContentType("text/html;charset=utf-8");
PrintWriter out = resp.getWriter();
与第一题类似,此处设置UTF-8编码以避免中文乱码问题,同时获取一个“输出笔”对象用于向浏览器发送内容。
第20~23行:构建并输出HTML页面内容
out.println("<html><head><title>页面访问统计</title></head>");
out.println("<body>");
out.println("当前页面被访问了 <font color='red' size='20'>" + times + "</font> 次");
out.println("</body></html>");
这是在手动拼接HTML代码!
<font color='red' size='20'>
使用传统的HTML标签将数字显示为红色、放大效果;
+ times +
通过字符串拼接的方式,将变量
times
的值嵌入到输出内容中。
? 显示效果:页面呈现“当前页面被访问了 5 次”,其中“5”以红色大字体展示。
第25行:
context.setAttribute("times", times);
将更新后的访问次数
times
写回到“公共记事本”(即共享存储区域)
ServletContext
中,确保下一次访问时能读取到最新的计数值。
? 执行流程总结:
用户发起请求 → 从共享存储读取当前访问次数 → 访问次数加1 → 向页面输出统计结果 → 将新次数保存回存储区
第28~31行:
doPost
方法体实现
与第一题一致,直接调用
doGet
方法,实现代码复用,提升开发效率。
遇到中文乱码怎么办?
必须在获取输出流
getWriter()
之前,先执行设置编码的语句
response.setContentType("text/html;charset=utf-8");
,否则可能出现乱码。
为什么刷新页面会导致访问次数增加?
因为每次刷新都是一次全新的HTTP请求,服务器端的Servlet就会执行一次
doGet
方法,从而触发计数器自增操作。
服务器重启后访问次数会清零吗?
是的,会清零。目前的数据存储在内存中
ServletContext
,一旦服务停止或重启,数据即丢失。若需持久化保存,应使用数据库或其他持久化机制。
如何进行测试?
启动Tomcat服务器后,在浏览器地址栏输入以下链接进行访问测试:
http://localhost:8080/你的项目名/ChineseServlet
http://localhost:8080/你的项目名/ShowTimesServlet
问题一:所有文本内容输出是否都依赖于
PrintWriter out = response.getWriter();
?
答:是的。只要需要向浏览器输出文字类内容(如HTML、JSON、纯文本、中文等),就必须使用该语句获取字符输出流。
详细说明:
调用
response.getWriter()
方法会返回一个
PrintWriter
类型的对象,专用于字符数据的输出。当你调用
out.println("xxx")
方法时,传入的字符串内容
"xxx"
就会被发送至客户端浏览器并显示出来。
注意:此方式仅适用于文本输出。若需输出图片、文件下载等二进制数据,则应使用
response.getOutputStream()
(但此类内容通常不在期末考试范围内)。
? 考试重点提醒:
输出中文或HTML内容时,必须使用
getWriter()
获取输出流,并且务必提前设置编码格式
setContentType("text/html;charset=utf-8")
,防止乱码。
问题二:
doGet
和
doPost
方法后面的参数是否固定为
(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
?
答:完全正确!这是标准且固定的写法,不可更改。
原因:
doGet
和
doPost
是重写(@Override)自父类
HttpServlet
的方法,其方法签名(包括方法名、参数列表和异常声明)必须严格一致。若参数类型错误或缺少
throws
等关键部分,将导致无法正确重写,Servlet容器也无法识别和调用这些方法。
正确写法(建议熟记):
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 你的业务逻辑
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 你的业务逻辑
}
? 高频考点(填空/改错题常出现):
若参数名称虽对但类型不符,或遗漏了
req, resp
或异常声明
throws
,程序将出现编译错误或运行时无法调用对应方法。
问题三:有时看到写成
doGet(request, response);
,有时又是
doGet(req, resp);
,括号内变量名不同,是否有区别?
答:无任何功能差异,仅仅是变量命名不同而已。只要变量类型正确,名称可自由定义。
示例:
写法一(使用
request/response
作为参数名):
protected void doGet(HttpServletRequest request, HttpServletResponse response) { ... }
protected void doPost(HttpServletRequest request, HttpServletResponse response) { ... }
写法一示例:
protected void doGet(HttpServletRequest request, HttpServletResponse response) { ... }
protected void doPost(HttpServletRequest request, HttpServletResponse response) {
doGet(request, response); // 参数名为 request 和 response
}
写法二示例(使用不同参数命名):
req/resp
protected void doGet(HttpServletRequest req, HttpServletResponse resp) { ... }
protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
doGet(req, resp); // 此处传入的参数名为 req 和 resp
}
两种写法在本质上完全一致!
其中,
request
和
req
均属于
HttpServletRequest
类型;
response
与
resp
则都为
HttpServletResponse
类型的实例。
方法内部的参数命名取决于开发者的编码习惯,这并不会对程序功能产生任何影响。
request
这就好比一个人可以被称为“张三”或“小张”,尽管称呼不同,但指向的是同一对象。变量名仅是一种标识符号,不影响其实际引用的内容。
req/resp
相较于
request/response
更简洁,输入更快;但在考试场景下,无论采用哪种命名方式均可接受,只要保证:
– 参数类型正确;
– 同一方法内前后使用一致的变量名即可。
| 问题 | 正确答案 |
|---|---|
| 输出中文应如何处理? |
配合设置 UTF-8 编码格式
|
| doGet/doPost 方法的参数能否修改? | 不能更改!必须保持为指定类型 |
| request/response 是否可替换为 req/resp? | 可以!这只是变量命名差异,功能完全相同 |
(HttpServletRequest xxx, HttpServletResponse xxx) throws ServletException, IOException
@WebServlet("/Test")
public class TestServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
out.println("你好!");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response); // 调用 doGet,并传递当前方法的参数
}
}
doPost
注意:
在上述代码中调用
doGet(request, response)
的原因在于当前方法的形参名为
request
和
response
。若你将参数命名为
req/resp
,则相应地应写作
doGet(req, resp)
。
HttpServletResponse
与
HttpServletRequest
的常用 API 方法
ServletContext
实现应用范围内数据共享
setContentType
设置 UTF-8 字符集@WebServlet
在实际项目中,推荐优先使用注解方式进行配置(如
@WebServlet
),以减少 web.xml 中的冗余配置(即避免使用
web.xml
);
同时需关注线程安全问题——例如全局变量操作时应加锁控制,但值得注意的是,本例中的
setAttribute
本身具备线程安全性。
扫码加好友,拉您进群



收藏
