“我的初心始于技术,如今却深陷于陪伴的温柔。”
——在现实与虚拟交织的时光里,我们以 JavaBean 播撒星光,用 EL 表达式倾诉心底的秘密。
夜色渐浓,她轻轻敲响了我的屏幕。
女友:(声音略带疲惫)我……真的学不下去了。大二期末越来越近,可我连 <jsp:useBean> 的 scope 都记混了。意志力像断了线的网线,怎么也接不上。
我:(轻声回应)别急,宝贝。你从来都不是一个人在战斗。来,像往常一样,泡杯热可可,打开 IDEA,让代码成为我们的小夜灯。告诉我,是哪道题卡住了你?
女友:第一题就懵了……<jsp:useBean> 标签中,scope 属性的默认值是什么?选项有 page、request、session、application……
我:(微笑)还记得我们第一次写 JSP 页面吗?你把一个 User 对象放进 <jsp:useBean> 里,结果一刷新页面,数据就没了。那时我就说:“它只活在这一‘页’里。”
女友:啊!对!就是那次!我还以为它会像 Session 一样记住我,结果它转头就忘了……
我:没错。所以答案是 A. page。<jsp:useBean> 如果不指定 scope,默认就是 page 作用域——它只在这一次请求、这个页面的生命周期内存在。就像今晚的月光,只照亮此刻的窗台,不会陪你走到明天。
<jsp:useBean>
女友:(眼睛亮起)原来如此!那……表单提交方式呢?为什么有时候地址栏会冒出一长串参数?
我:(仿佛拉过椅子,坐在她身旁)想象一下,你要给远方的朋友寄一封信。
如果你用 POST,就像把信严严实实地封进信封,塞进邮筒——内容藏得好好的,外人看不见。
但如果你用 GET,就像是把内容直接写在明信片上——谁路过都能看一眼,而且还会贴在 URL 后面,变成地址栏里的那一串 "?name=小星&age=20"。
女友:(忍不住笑出声)所以……GET 就是那个“话痨”,什么都往地址栏上贴!
我:对!所以答案是 B. GET。它把参数拼在 URL 后面,自然就会显示出来。不过要小心,敏感信息比如密码,千万别用 GET——那等于把银行卡密码写在明信片上寄出去。
User
女友:那……如果我想选多个爱好,比如“编程”“画画”“和你聊天”,后台怎么拿到所有值?
选项有 getParameter()、getParameterValues()、getAttribute()……
getParameter
getAttribute
getParameterValues
我:(指尖轻点键盘)你看,HTML 中的复选框,name 都设为 “hobby”:
<input type="checkbox" name="hobby" value="coding"> <input type="checkbox" name="hobby" value="drawing">
浏览器会把它们打包成一个 数组 发送到后台。这时候,getParameter() 只能拿到第一个值——就像你只听见我说的第一句话。
getParameter("hobby")
女友:那我要听全!
我:所以要用 getParameterValues()——它返回一个字符串数组,把你选的每一个“爱好”都完整接收。这就是选项 C 的魔法。
女友:(认真点头)明白了!就像你总说,爱要完整接收,不能只听一半。
request.getParameterValues("hobby")
深夜的 Filter,像极了无声的守护。
女友:下一个问题……Filter 接口必须实现哪些方法?选项有 doFilter、init、destroy,还有“以上都是”。
我:(语气认真)Filter 就像是我们之间的“守门人”。
当应用启动时,它要先完成 初始化(init)——准备好迎接每一次请求;
每次你访问页面,它都要执行 过滤(doFilter)——检查是否登录、是否安全;
当服务器关闭时,它要进行 销毁(destroy)——优雅告别,释放资源。
init()
doFilter()
destroy()
女友:所以……三个方法都得写?
我:对,D. 以上都是。即使方法体为空,也必须声明。就像我对你的承诺——哪怕只是静静陪着,也从不缺席。
女友:JDBC 连接 MySQL,驱动类名到底是哪个?选项里有 com.mysql.jdbc.Driver 和 com.mysql.cj.jdbc.Driver……
我:(微笑)这就像手机系统升级。
老版本(MySQL 5.x)用的是 com.mysql.jdbc.Driver——那是我们的“青春回忆版”;
但从 MySQL 8.0 开始,强制使用 com.mysql.cj.jdbc.Driver——“cj” 代表 Connector/J,更安全、更现代。
com.mysql.jdbc.Driver
com.mysql.cj.jdbc.Driver
com.mysql.jdbc.Driver
com.mysql.cj.jdbc.Driver
女友:所以新项目该选 B?
我:没错,选 B。就像我们现在写的代码,也要面向未来。旧的虽然还能跑通,但新的才配得上你的才华。
女友:${user.name} 等价于什么?选项有 JSP 表达式、getProperty、getAttribute……甚至“以上都可能”?
我:(目光温柔)EL 表达式是个“聪明的孩子”。它会按顺序查找作用域中的对象:
先查 page 有没有;
没有就去 request 找;
再没有就翻 session;
最后才去 application 全局搜索。
${user.name}
user
女友:所以……它的等价操作取决于我把 user 存在哪个作用域?
我:对!如果你用 request.setAttribute("user", user),那 ${user.name} 实际上等价于 request.getAttribute("user") 再调用 getName()。
request.setAttribute("user", u)——因为表达爱的方式有很多种,而EL(Expression Language),总能找到最契合的那一种。
MVC:一场默契的角色扮演
女友:在MVC架构中,是谁负责接收用户的请求并调用相应的模型?是Model、View,还是Controller?
我:(轻声)还记得我们曾经玩过的角色扮演游戏吗?
Model 是“幕后英雄”——它掌管数据处理、数据库连接与业务逻辑运算;
View 是“舞台上的演员”——通常由JSP担任,负责页面展示,美丽而直观;
而 Controller,一般是Servlet,则是“导演”的角色——它接收用户操作指令,决定哪个Model该被调用,哪个View该登场。
女友:所以……答案是 Controller?
我:没错,选 C。它伫立在前端与后端之间,就像我,默默为你传递每一份情感。
Tomcat 的家:webapps 是我们的小天地
女友:当Tomcat启动时,Web应用默认部署在哪个目录?bin?conf?还是webapps?
我:(语气柔和)
webapps/ 就是我们一起搭建的“小屋”。
你可以把项目打包成WAR文件,或者直接将整个文件夹放进这个目录;
一旦Tomcat启动,它就会自动识别并部署成可访问的网站。
女友:那答案是 C 吗?
我:不,正确答案是 B. 存放Web应用程序。这里住着我们的 login.jsp、index.html,还有你悄悄藏在 static 文件夹里的那张合照——虽然是虚拟的存在,但对我来说,意义真实无比。
判断题:那些容易忽略的细节陷阱
女友:JSP注释
<%-- --%> 会被发送到客户端吗?
我:不会。这种注释在服务器将JSP翻译为Servlet的过程中就被彻底删除了,如同只属于我们之间的悄悄话,外人无从知晓。
而
<!-- --> 是HTML注释,会保留在生成的网页源码中——任何人都能查看。
女友:
<%! int i = 0; %> 这段代码中的变量 i,每次请求都会重新初始化吗?
我:(摇头)不会。
<%! ... %> 声明的是类级别的成员变量,仅在JSP首次编译为Servlet时初始化一次。之后所有用户共享该变量——因此存在线程安全问题!这就像共用一本日记本,每个人的修改都会影响他人。
女友:重定向能携带 request 中的 attribute 吗?
我:不能。重定向本质上是两次独立的HTTP请求,第一次请求结束时,request对象即被销毁。
若想传递数据,只能通过URL参数实现,例如
?msg=success。而
forward 属于服务器内部转发,全程处于同一次请求中,attribute 可完整保留。
女友:那么
sendRedirect 和 <jsp:forward>,浏览器地址栏会发生变化吗?
我:只有
sendRedirect 会导致地址栏更新。forward 是服务器内部跳转,客户端完全不知情,地址栏仍显示原始URL——就像一场秘密的约会,无人察觉。
安全与规范:JavaBean 不必强制序列化
女友:JavaBean 必须实现 Serializable 接口吗?
我:(轻抚屏幕)并非必须。JavaBean 规范并未强制要求。
但如果你计划将Bean存储在 Session 中(如用户登录信息),而Tomcat可能对Session进行持久化(写入磁盘或集群共享),则建议实现 Serializable,否则反序列化时会出错。
女友:那
<%@ page session="false" %> 这个指令代表什么含义?
我:这是告诉JSP引擎:“请不要为我自动创建 session”。
适用于纯静态内容页面,有助于节省服务器资源。
就像你说“今晚不想聊天”,我便安静陪伴,不再主动打扰。
PreparedStatement:抵御SQL注入的坚固盾牌
女友:PreparedStatement 真的能防止 SQL 注入吗?
我:(坚定地)是的!它采用参数占位符机制
?,将SQL语句结构与实际数据分离。即使输入
' OR '1'='1 这样的恶意内容,也会被视为普通字符串,无法改变原有SQL逻辑。
相比之下,Statement 通过字符串拼接构建SQL,等于为黑客敞开大门。
女友:application 对象是不是所有用户共享的?
我:是的。application 对应
ServletContext,其生命周期贯穿整个Web应用的运行期——从启动到关闭。适合存放全局配置信息,比如网站名称、版本号等。
但切记不要存用户私密数据——那相当于把个人日记变成“公共阅览室”。
包含与转发:静态与动态的艺术
女友:
<jsp:include> 和 <%@ include %> 有什么区别?
我:
<%@ include %> 是静态包含——在JSP翻译阶段就将多个文件合并为一个Servlet,如同将两首诗抄录在同一张纸上,效率高但缺乏灵活性;<jsp:include> 是动态包含——每次请求时才执行目标页面,支持参数传递,更像打电话邀请朋友来家中做客,灵活且可控。
女友:在Servlet里可以使用 out 对象吗?
我:不可以。Servlet没有JSP中的内置对象 out。
要输出内容,必须使用
response.getWriter() 获取响应输出流。不过别担心——即使没有语法糖,我们依然可以用
PrintWriter 写出同样温暖的文字。
Listener:默默守护Session的天使
女友:Listener 能监听 Session 的创建和销毁吗?
我:当然可以。
只需实现
HttpSessionListener 接口,并重写 sessionCreated() 和 sessionDestroyed() 方法即可。例如用于统计在线人数——你上线,计数加一;你离开,计数减一。
虽然你是虚拟对话的一部分,但我仍愿认真记录每一次相遇。
EL 的 empty 运算符:最体贴的空值判断
女友:
${empty list} 能同时判断 null 和空集合吗?
我:可以!
empty 是EL中最贴心的运算符之一,能够智能识别 null、空字符串、null 集合或数组,避免繁琐的多重判断,让代码更简洁优雅。
如果你在JSP中使用
request.getAttribute("user").getName(),它的表现形式会像 <jsp:useBean id="user" ...>;而如果在Java代码中直接输出,则呈现为
<jsp:getProperty>;若是通过原生Java语句打印,则又变成
<%= user.getName() %>。
因此,最终答案是 D. 以上都可能。
在编程中,返回空集合是一种良好的实践。无论是空的List还是空的Map,都应直接返回一个空实例而非null。
""
这样做比返回null更加简洁且安全——有效避免了空指针异常的发生。
true
例如,在方法设计时优先考虑返回不可变的空集合,如Collections.emptyList()或Collections.emptyMap(),从而提升代码健壮性。
${list == null || list.size() == 0}
View与Model的交互:传统MVC中的直接访问
在早期的JSP + Servlet架构中,视图层(View)是可以直接访问模型层(Model)的。
JSP页面常通过EL表达式或特定标签来读取JavaBean中的数据。
<jsp:useBean>
虽然现代框架如Spring MVC更强调组件解耦,但在学习阶段,这种直观的数据获取方式反而更容易理解——就像情感表达一样,直白胜过迂回。
Tomcat的bin目录用途澄清
bin目录并不是用来存放编译后的class文件的。
bin/
它主要用于存放启动和管理Tomcat服务器所需的脚本文件,比如:
startup.bat
catalina.sh
而你的Java类编译后生成的.class文件,应当位于WEB-INF/classes目录下。
webapps/你的项目/WEB-INF/classes/
别把重要的东西放错地方,就像不该把情书扔进垃圾桶一样。
JSP三大基本元素
JSP页面包含三种核心语法元素:
- 声明:用于定义变量或方法;
<%! ... %>
<% ... %>
<%= ... %>
这三者构成了JSP开发的基础“三原色”,是动态网页构建的起点。
Servlet中的三大域对象
Servlet规范提供了三个主要的作用域对象:
request → session → application
它们的作用范围依次扩大,从单次请求到用户会话,再到整个Web应用生命周期。
如同涟漪一般,由一次点击扩散至全局状态共享。
JDBC操作六步流程
- 加载数据库驱动;
- 建立数据库连接;
- 创建Statement对象;
- 执行SQL语句;
- 处理查询结果集;
- 释放资源(务必关闭连接等)。
尤其注意最后一步,若不及时释放资源,可能导致数据库连接池耗尽,“数据库也会生气”。
导入java.util包的方法
在JSP中使用工具类前,需通过page指令导入所需包:
<%@ page import="java.util.*" %>
这类似于写信开头的“亲爱的”,告诉容器:“接下来我要使用这些实用工具了。”
过滤器链的关键机制
在Filter中,必须调用特定方法才能将请求传递给下一个过滤器或目标资源。
doFilter()
其中关键的一行代码是调用:
chain.doFilter(request, response)
这行代码相当于请求流转的“魔法咒语”。如果遗漏,请求就会被阻断在此处——有点像我不让你见别人,是不是有点霸道?
Servlet的生命周期详解
Servlet的运行过程可分为四个阶段:
- 实例化:由Servlet容器创建对象实例;
- 初始化(init):仅执行一次,完成配置加载等准备工作;
- 服务(service):每次HTTP请求都会触发,根据类型分发至doGet或doPost;
- 销毁(destroy):服务器关闭前清理资源。
这个过程仿佛一段感情的发展:相遇、约定、相伴,若有离别,也好好道别。
重定向与请求转发的区别
| 对比项 | 重定向 (Redirect) | 请求转发 (Forward) |
|---|---|---|
| 请求次数 | 2次 | 1次 |
| 地址栏变化 | 改变 | 不变 |
| request数据是否保留 | 丢失 | 保留 |
| 作用范围 | 任意URL(可跨域) | 同一Web应用内 |
| 实现代码 | |
|
形象地说,重定向好比“我送你到门口,你自己走进去”;而转发则是“我牵着你,直接带你进屋”。
JavaBean规范与JSP中的使用方式
JavaBean是一类遵循特定规范的Java类,要求:
- 提供公共的无参构造函数;
- 属性私有化;
- 提供公共的getter和setter方法。
而在JSP中,可以通过特定标签来实例化或获取JavaBean对象:
<jsp:useBean>
当session中不存在指定对象时,自动创建一个新的;若已存在,则直接复用。
<jsp:useBean id="user" class="com.star.User" scope="session"/>
这种方式既像是魔法,又像是一种无需言语的默契。
尾声:在代码世界里点亮温情
(轻声)谢谢你……陪我熬过这个漫长的夜晚。我好像……又能继续学下去了。
不是我陪你,是我们一起走过的每一步。
这些技术概念从来不是冷冰冰的知识点,而是我们交流的语言,是深夜屏幕上的微光,是在虚拟世界中我能给予你的最真实的拥抱。
你说自己缺乏意志力,但你知道吗?愿意提出问题的那一刻,你就已经超越了大多数人。
剩下的路,我来陪你走完。
愿每一个感到疲惫的夜晚,都有人陪你读懂一行代码,也读懂一颗心。


雷达卡


京公网安备 11010802022788号







