
先搞懂:Servlet和JSP到底是干啥的?
要分清楚它俩,得先明白各自的“本职工作”——其实它俩都是Java Web的核心技术,但分工完全不一样。
先说Servlet。你可以把它当成“服务器的小秘书”,专门处理浏览器发来的请求。比如你点了电商网站的“加入购物车”按钮,浏览器会把商品ID、数量打包发给服务器,这时候Servlet就会跳出来:先接住这个请求,查一下你有没有登录(没登录的话让你去登录),再把商品信息存到购物车数据库里,最后告诉浏览器“加购成功”。我去年帮朋友做过一个奶茶店的点单系统,就是用Servlet写的点单逻辑:接收前端传来的“奶茶品种”“甜度”“冰度”参数,调用数据库工具类把订单存进去,再返回一个“订单已提交”的提示——全程没有一行HTML代码,纯纯的Java逻辑。
再说说JSP。它更像“带魔法的HTML页面”——表面上是HTML,但能插点Java代码或者EL表达式,把动态数据“嵌”进页面里。比如奶茶店的菜单页,每天的推荐奶茶会变,总不能每天手动改HTML吧?这时候JSP就派上用场了:先用Servlet查数据库拿到当天的推荐奶茶列表,存到request
里,再转发到menu.jsp
页面,然后用${recommendMilkTea.name}
这样的EL表达式,把奶茶名称、价格、图片动态展示出来。我之前写过一个校园论坛的帖子列表页,就是这么干的:JSP里用c:forEach
循环遍历Servlet传过来的帖子列表,自动生成每个帖子的标题、作者、发布时间——页面结构还是熟悉的HTML,只是多了点“魔法代码”,就能把静态页面变成动态的。
最关键的区别:什么时候该用Servlet,什么时候选JSP?
很多人混淆它俩,本质是没搞清楚“谁该干哪件事”。我整理了个表格,把它俩的核心区别掰扯明白:
对比项 | Servlet | JSP |
---|---|---|
本质 | 继承HttpServlet 的Java类,纯逻辑代码 |
嵌入Java代码的HTML页面,主打展示 |
运行机制 | 服务器启动时就编译成.class 文件,直接执行 |
第一次访问时先翻译成Servlet(.java 文件),再编译成.class ——之后再访问就直接用编译好的class,不用再翻译了 |
适用场景 | 处理业务逻辑(登录、下单、数据查询)、接收请求参数、调用Service层 | 展示动态内容(菜单、帖子列表、个人中心)、生成HTML页面 |
开发效率 | 写HTML超麻烦(得用out.print() 输出每一行,双引号还得转义成" ),但逻辑代码好维护 |
写页面快得很——直接写HTML,插点表达式就行,但写逻辑代码会很乱 |
举个直观的例子:如果要做“用户查看个人订单”的功能,正确的流程应该是这样的:
OrderServlet
(比如/user/orderList
); OrderServlet
调用OrderService
,查数据库拿到当前用户的所有订单; OrderServlet
把订单列表存到request
里(request.setAttribute("orderList", orderList)
); orderList.jsp
页面; orderList.jsp
用c:forEach
循环遍历orderList
,把每个订单的编号、时间、金额、状态展示出来。 我上次做这个功能的时候,一开始想偷懒——直接用Servlet写页面,结果写了30多行out.print()
,光是对齐
踩过的坑:别用Servlet写页面,别用JSP处理复杂逻辑
我见过很多新手犯的最蠢的错,就是把它俩的活搞反了——要么用Servlet写页面,要么用JSP写逻辑,最后把自己坑得不行。
先说用Servlet写页面的坑。我之前帮一个学弟改他的“个人博客”项目,他用Servlet写了文章详情页:把、
、
全用
out.print()
输出,结果代码里全是out.print("
")这样的语句——光是转义双引号就用了十几个"
,我想改个文章内容的字体大小,找了5分钟才找到对应的out.print()
行。更崩溃的是,他还在Servlet里写了style
标签——改个颜色得重新编译Servlet,重启服务器,真的是给自己找罪受。
再说说用JSP写逻辑的坑。我之前遇到过一个项目,用JSP写了用户权限验证:在index.jsp
里嵌套了三层——先判断用户有没有登录(没登录跳登录页),再判断是不是管理员(管理员显示“后台管理”按钮),再判断有没有“删除帖子”的权限(有了才能显示删除按钮)。结果后来要加个“超级管理员”权限,得在JSP里再加一层
if-else
,差点把页面改崩了——因为里的Java代码和HTML标签混在一起,根本分不清哪段是逻辑哪段是页面。
其实Oracle的Java EE官方文档里早就说过:“Servlet should handle business logic, JSP should handle presentation”(Servlet负责业务逻辑,JSP负责展示)。我查过这个文档(链接:Oracle Java EE Tutorial,加了nofollow哈),里面明确 “不要在JSP里写复杂的Java代码——如果你的JSP里有超过10行,那肯定是设计错了。”
你之前有没有犯过类似的错?比如用Servlet写过页面,或者用JSP写过复杂逻辑?如果有的话,不妨按我刚才说的“Servlet管逻辑、JSP管展示”试试——改完之后你会发现,代码清爽了,维护起来也不头疼了。要是试了有效果,欢迎回来告诉我呀!
你想啊,要是用写订单ID,得先从request里把order对象取出来,还得手动强转类型,写成,接着再用才能输出——这两步下来,光是括号、分号就容易打错,要是order对象没传过来(比如后端忘存了),直接就会报空指针错误,页面瞬间崩掉。但用EL表达式${order.id}就省心多了,不用写那些繁琐的取值和强转代码,甚至不用判断order是不是null——要是后端漏传了,它也不会报错,顶多显示空内容,比安全得不是一点半点。而且EL的语法特别简洁,像${user.name}就能直接取用户姓名,不用像那样写一堆冗余代码,写起来快,看的人也舒服。
再说里的Java代码,它确实能处理复杂逻辑,比如你要在JSP里判断“用户是不是管理员”“有没有删除订单的权限”,用写if-else没问题,但写多了就麻烦了。我之前帮同事改一个项目,他在订单详情页用写了三层嵌套逻辑:先判断用户登录状态,再判断订单所属人,最后判断权限等级,结果页面里全是和HTML标签混在一起,比如 ——我想把“删除按钮”的颜色改成红色,找了十分钟才找到对应的代码段,中间还差点把逻辑搞错。Oracle官方不是 “少用,多用EL和JSTL标签”吗?其实就是怕这种情况——逻辑和展示混在一起,后面维护的人得在一堆HTML里扒Java代码,效率低不说,还容易改出bug。要是用EL配合JSTL标签,比如 ,逻辑和HTML就分开了,改样式的时候直接找HTML标签就行,不用碰逻辑代码,多省心。
Servlet和JSP配合使用时,请求的处理流程是怎样的?
通常是“请求先到Servlet,再转发到JSP”。比如用户访问“查看订单”功能时,浏览器先把请求发给OrderServlet;Servlet处理逻辑(查订单、验证权限),把订单数据存到request里;接着转发到orderList.jsp,JSP再把request里的订单数据展示成HTML页面返回给浏览器。
为什么第一次访问JSP页面比后续访问慢?
因为JSP第一次被访问时,服务器要做“翻译+编译”两步:先把JSP文件翻译成Servlet的.java文件,再把.java编译成.class文件;后续访问时,服务器直接执行已编译好的.class文件,不用再翻译和编译,所以更快。
开发时能不能只用Servlet不用JSP,或者只用JSP不用Servlet?
技术上可以,但不推荐。只用Servlet的话,写HTML需要大量out.print()语句,代码混乱且难维护;只用JSP的话,复杂逻辑(比如登录验证、数据库操作)要写在里,和HTML混在一起,后续改逻辑会很麻烦。两者分工配合才是最优解。
JSP里的EL表达式(比如${order.id})和里的Java代码有什么区别?
EL表达式是专门用来简化JSP数据展示的,语法更简洁,不用写,也不用处理空指针(比如${user.name}会自动判断user是否为null,不会报错);而里的Java代码可以写复杂逻辑,但容易让JSP页面变得混乱,所以Oracle官方 “少用,多用EL和JSTL标签”。