JSP实习报告拆解:从页面输出到登录跳转的完整链路与避坑指南

发布时间:2026/10/15 13:06:43
JSP实习报告拆解:从页面输出到登录跳转的完整链路与避坑指南 简介JSP开发技术课程上机实习报告汇编面向正在学习JSP与JavaBean的初学者或高校信息管理类学生展示多个典型上机题的完整实现过程。报告涵盖用Java表达式在JSP页面完成加法计算并输出结果、创建包含名称、价格、库存、作者四个字符串属性的图书信息JavaBean、编写工具类转义尖括号字符以及实现一个校验指定用户名与密码的简单登录流程代码与页面跳转逻辑对应清晰适合对照练习。压缩包内仅含一个doc文档大小约38KB内容完整、可直接阅读目前已有102人浏览学习。对于想快速上手JSP页面输出、JavaBean封装及基础请求处理的读者来说这份报告既能作为课前预习参考也能在期末复习时快速回顾关键代码心得总结部分还点出了调试中遇到的困难与解决思路具备较强的实操参考价值。1. 一份 JSP 实习报告能拆出什么从 11 的页面输出到登录跳转的完整链路拿到这份 JSP 上机实习报告时我第一反应是“这不就是课程作业嘛”但细看之后发现里边的六道题恰好串起了一条 JSP 入门最核心的技能链路页面输出计算表达式、JavaBean 封装数据、表单参数接收、字符串转义、登录判定与页面跳转。这份文档资料的价值不在于题目有多难而在于它把 JSP 开发里最容易出错的那几个节点——编码设置、JavaBean 规范、request 参数传递、forward 与 redirect 的选择——全部用作业题的形式逼着你走了一遍。适合正在学 JSP 开发技术、需要一份可运行的上机代码做参照的同学也适合刚学完 Java SE 想快速建立 Web 开发基本盘的人。下面我按“环境与页面输出 → JavaBean → 留言板表单 → 登录跳转 → 避坑排查”的顺序把它拆开讲透。2. JSP 运行环境与页面输出从 11 那道题看 JSP 的编译模型很多人写第一个 JSP 页面时最大的困惑不是代码写不对而是搞不清“页面里的 Java 代码到底跑在哪”。JSP 本质上是一个被容器通常是 Tomcat动态编译的 Servlet第一次访问某个 .jsp 文件时Tomcat 会把它翻译成一个 .java 文件再编译成 .class 执行。这意味着 JSP 里能写的 Java 代码其实是在服务器端运行的最终输出的是纯 HTML 字符串。理解了这个模型再看那道“在 JSP 中利用 Java 代码计算 11 的结果”思路就清晰了你要做的不是在页面上写死“2”而是让服务器在运行时把计算结果输出到响应流里。2.1 环境准备动态 Web 项目里哪个目录放什么在 Eclipse 里创建一个 Dynamic Web Project 时项目结构会分成两个核心区域src目录存放 Java 源码WebContent 目录存放 JSP、HTML、CSS 和 WEB-INF 配置文件。很多新手把 JavaBean 类直接丢进 WebContent 里这是错的——Java 类必须放在src下由容器编译进WEB-INF/classes。在 Eclipse 中创建 JSP 文件时建议直接右键 WebContent 选择 New → JSP File这样生成的页面会自动带上 JSP 指令头。提示Tomcat 版本建议用 8.5 或 9.x配合 JDK 1.8 及以上。Eclipse 里配置 Tomcat runtime 时如果遇到端口被占用可以在 Server 视图双击服务器把 HTTP port 从 8080 改成 8081这是实践中最常见的启动报错原因。一个合格的动态 Web 项目目录结构大概是这样的src下放包名目录比如com.demoWebContent 下直接放 JSP 文件WEB-INF 里有 web.xml 和编译后的 class。lib 目录如果存在放第三方 jar 包。这个结构关系到后面的 JavaBean 能不能被 JSP 页面正确引用先立住。2.2 在页面里写 Java脚本片段与表达式的边界第一题的原始代码里用了% 1 1 %这种写法它是 JSP 的表达式标签括号里的 Java 表达式会被计算结果转成字符串后直接输出到页面。这个写法适合“计算并输出”这种简单场景。但如果你想在页面里写多行逻辑比如定义变量、做判断、写循环那就要用到脚本片段% %。% page languagejava contentTypetext/html; charsetUTF-8 pageEncodingUTF-8% !DOCTYPE html html head title第一题计算11/title /head body p使用表达式标签输出/p p1 1 % 1 1 %/p p使用脚本片段输出/p % int result 1 1; out.println(1 1 result); % /body /html上面的代码展示了两种写法。% %里不能写带分号的完整语句它只能是一个表达式% %里则可以写完整的 Java 语句。out.println()里的out是 JSP 内置对象类型是 JspWriter它负责把内容写进响应流。两段代码最终输出到浏览器的是同一行 HTML。注意JSP 的表达式标签和脚本片段在 Servlet 3.1 规范之后依然有效但现代项目普遍用 EL 表达式和 JSTL 替代脚本片段原因是脚本片段会让页面逻辑混乱、难以维护。课程作业里把脚本片段练明白是必要的真实项目里要逐渐过渡到 EL JSTL。2.3 page 指令与编码一份报告里两个 pageEncoding 混用的后果翻看原始报告时我发现一个很典型的错误开头的 page 指令写的是pageEncodingISO-8859-1后面又有pageEncodingutf-8同一份文档里两种编码混着出现。ISO-8859-1 是西欧单字节编码根本不支持中文字符如果 JSP 页面里有中文用这种编码保存后运行时要么直接编译报错要么页面显示乱码。% page languagejava contentTypetext/html; charsetUTF-8 pageEncodingUTF-8%这是我在实际项目中固定的 JSP 页头写法。pageEncoding告诉容器这个 .jsp 文件本身是以什么编码保存的容器读取文件时按它来解码contentType则告诉浏览器响应内容的编码。这两个值必须一致且都设为 UTF-8。就这一条能解决 90% 的 JSP 中文乱码问题。注意编码乱码的另一个隐藏点在页面的保存格式。Eclipse 默认的文本文件编码可能是 GBK 或系统默认编码如果代码里写了 UTF-8文件却按 GBK 保存运行照样乱码。把项目级编码统一设置为 UTF-8再逐文件确认右下角编码标识能省掉很多排查时间。3. JavaBean 规范落地BookInfo 值对象与 DoString 工具类的两种用法实习报告里的第四题和第五题分别要求写一个 BookInfo 的 JavaBean 和一个 DoString 的工具类。前者是典型的“值对象”JavaBean用来承载图书的名称、价格、库存、作者数据后者是“工具类”JavaBean用来做字符串中 HTML 特殊字符的转义。两者共用同一套 JavaBean 规范但在设计取向上有本质差别一个以数据为核心一个以行为为核心。搞清楚这种差别你在写自己的类时就知道该把重心放在哪里。3.1 JavaBean 规范速查属性、构造器与 getter/setter 的约定JavaBean 不是一种新技术而是一套约定。它要求类必须有一个公共的无参构造器、属性私有化、每个属性提供公共的 getter/setter 方法。这套约定的目的是让外部工具比如 JSP 的动作标签、各种框架能通过反射机制统一操作对象。JSP 里的jsp:useBean标签创建对象时依赖的就是这个无参构造器jsp:setProperty标签自动赋值时依赖的是 setter 方法命名规则。规范项要求说明类声明公共类类名首字母大写源文件名必须与类名一致构造器必须有一个公共的无参构造器如果定义了带参构造器无参的也要显式写出来属性用 private 修饰外部不能直接访问属性名首字母小写getter命名规则get 属性名首字母大写布尔属性可以用is前缀setter命名规则set 属性名首字母大写返回值必须为 void序列化实现 Serializable 接口规范要求作业场景不强求注意一个细节getter 方法名不是随便起的。比如私有属性namegetter 必须叫getName()而不是name()setter 必须叫setName(String name)而不是setNameValue(...)。jsp:setProperty标签通过属性名找到对应的 setter命名错了它会直接报错跳不出值。3.2 BookInfo 值对象为什么四个属性全用 String第四题要求 BookInfo 具有 name、price、stock、author 四个简单属性且属性类型为 String。原始代码里全部用的是 String 类型这在作业场景里是合理的因为表单提交过来的参数经过request.getParameter()取出来时本身就是 String直接用 String 承接可以省去类型转换。但这也埋了一个坑——如果你想判断库存是否大于 0、对图书价格做排序String 类型会给出反直觉的结果因为字符串比较的是字典序而不是数值大小。后面避坑章节会具体展开。package hbe; public class BookInfo { private String name; private String price; private String stock; private String author; public String getName() { return name; } public void setName(String name) { this.name name; } public String getPrice() { return price; } public void setPrice(String price) { this.price price; } public String getStock() { return stock; } public void setStock(String stock) { this.stock stock; } public String getAuthor() { return author; } public void setAuthor(String author) { this.author author; } }代码逻辑很简单四个私有属性八个公共方法。setPrice(String price)接收外界传入的字符串getPrice()返回当前值。这种类就是你用来在页面和业务逻辑之间搬运数据的。如果后续要做金额计算我会在代码里补一个重载的getPriceForCalculate()方法内部用BigDecimal解析字符串并返回数值而不是直接改属性类型——因为改类型会破坏现有表单传值链路。3.3 DoString 工具类静态方法与转义 HTML 的应用场景第五题要求把字符串里的和转换成 HTML 实体lt;和gt;防止用户输入被浏览器当成标签解析。这道题本质上是在做 XSS 防御的最基础动作。原始代码里写的是str(,lt;)我猜它是被 OCR 识别坏了实际应该是str.replace(, lt;)下面的代码是按正确逻辑补全的版本。package hby; public class DoString { public static String change(String str) { if (str null) { return ; } str str.replace(, lt;); str str.replace(, gt;); return str; } }这里有两个设计点值得说。第一方法被声明为static意味着你可以直接用DoString.change(str)调用不需要先new一个对象——对于没有成员变量的工具类来说静态方法是对的取向。第二我补了一个 null 判断表单里某个参数没传时request.getParameter()返回的是 null直接调replace()会抛空指针异常页面直接 500。作业里不写这行也能跑通但真实业务里这行能救你一命。3.4 在 JSP 页面里装配 JavaBeanuseBean 与 setProperty 的工作机制JavaBean 写好了怎么在 JSP 里用常见做法是用动作标签让容器帮你实例化和赋值比手写脚本片段更干净。% page languagejava contentTypetext/html; charsetUTF-8 pageEncodingUTF-8% jsp:useBean idbook classhbe.BookInfo scoperequest / jsp:setProperty namebook property* / html body p书名% book.getName() %/p p作者% book.getAuthor() %/p p价格% book.getPrice() %/p p库存% book.getStock() %/p /body /htmljsp:useBean做的事情是先从指定 scope这里为 request里查找有没有 id 为 book 的实例没有就反射创建并把实例放到该作用域。property*是通配符容器会遍历请求参数只要参数名和 Bean 的属性名匹配就自动调用对应的 setter 完成赋值。这个机制非常省事但它要求属性名必须和表单里的name属性严格一致比如input namebookName是匹配不到BookInfo里的name属性的。提示property*的自动类型转换只支持 String、基本类型及其包装类。如果 Bean 里有一个Date createTime属性请求参数传过来的字符串它转不了会直接报转换异常。遇到这种情况要么手动写jsp:setProperty指定 property 并自己转换要么在 Servlet 里完成对象组装JSP 只负责展示。4. 留言板完整链路表单提交、参数接收与中文乱码处理第二题是留言板原始报告的 OCR 内容只剩“言输入”和“留言展示”几个残词代码部分基本丢了。但题目本身的意图很明确用户输入一段留言提交后在页面上展示出来。这是一个非常典型的“表单 → JSP → 回显”练习覆盖的知识点包括 form 标签的 action 和 method 属性、request.getParameter()接收参数、以及字符串过滤。4.1 表单到 JSP 的参数传递name 属性是参数名的唯一来源在 HTML 表单里每个输入控件都有一个name属性它是服务端接收参数时的唯一标识。用户提交表单时浏览器会收集表单控件里的keyvalue对拼成请求体JSP 里通过request.getParameter(key)取值。如果某个控件没有写name属性它的值不会被发送。form actionleaveMessage.jsp methodpost label你的昵称/label input typetext namenickname / label留言内容/label textarea namecontent rows4 cols40/textarea input typesubmit value提交留言 / /formmethodpost表示请求体放在 HTTP 消息体里传输不会暴露在 URL 上适合留言这种会持久化的数据。action指向处理请求的 JSP 页面。注意这里和 GET 的差别GET 会把参数拼在 URL 问号后面比如leaveMessage.jsp?nicknameabccontenthello刷新页面时会重复发送请求。4.2 留言板代码补全接收参数、过滤关键字、页面回显下面是一份补全后的留言板页面代码同一份 JSP 文件既负责接收参数也负责展示留言列表。用一个 application 作用域的 List 存放留言这样不同用户提交的留言都能看到。% page languagejava contentTypetext/html; charsetUTF-8 pageEncodingUTF-8% % page importjava.util.List, java.util.ArrayList % % page importhby.DoString % jsp:useBean idmsgList classjava.util.ArrayList scopeapplication / % request.setCharacterEncoding(UTF-8); String nickname request.getParameter(nickname); String content request.getParameter(content); if (nickname ! null content ! null !content.trim().isEmpty()) { String safeNickname DoString.change(nickname); String safeContent DoString.change(content); String message safeNickname 说 safeContent; msgList.add(message); } % html body h2留言板/h2 form actionleaveMessage.jsp methodpost p昵称input typetext namenickname //p p留言textarea namecontent rows4 cols40/textarea/p pinput typesubmit value提交 //p /form hr / h3历史留言/h3 % if (msgList.isEmpty()) { out.println(p还没有留言快来抢沙发。/p); } else { for (int i 0; i msgList.size(); i) { out.println(p msgList.get(i) /p); } } % /body /html这段代码的关键点有三个。一是request.setCharacterEncoding(UTF-8)必须放在第一次调用getParameter()之前容器读请求体时用什么编码解码取决于这个设置放后面就无效了。二是DoString.change()对昵称和内容做了 HTML 转义避免用户输入script标签时浏览器执行脚本。三是留言列表存在 application 作用域的msgList里所有会话共享这个列表刷新页面数据不丢。注意这里的留言板是纯演示实现服务器一重启数据就清空了。真实项目要用文件或数据库存储。作业版的好处是逻辑完整、依赖少适合新手读懂参数传递的完整路径坏处是不能作为业务系统直接上生产这点要清楚。4.3 中文乱码的成因从 request 编码到页面编码的一整套配置中文乱码是 JSP 上机实习里翻车率最高的问题而且往往页面显示正常、后台处理乱成一团。它分两种场景POST 提交乱码和 GET 提交乱码。POST 的场景浏览器把用户输入的内容按页面编码UTF-8编码后放进请求体但 Tomcat 默认按 ISO-8859-1 解码请求体于是 UTF-8 的中文字节被拆成单个字符并组合错误产生乱码。解决办法就是上面代码里的request.setCharacterEncoding(UTF-8)它告诉 Tomcat 用 UTF-8 解码请求体。这行代码必须抢在第一次getParameter()之前执行否则 Tomcat 已经完成解码再设置也晚了。GET 的场景参数拼在 URL 上Tomcat 对 URL 的解码用的是 server.xml 里 Connector 的 URIEncoding 属性。Tomcat 8 以上版本默认已经是 UTF-8不需要额外配置老版本往往要手动加URIEncodingUTF-8。提示排查乱码问题的顺序建议是先确认所有 JSP 文件顶部都写了pageEncodingUTF-8和contentTypetext/html; charsetUTF-8再确认 JSP 文件本身是以 UTF-8 保存的最后再检查接收参数前有没有调用setCharacterEncoding。多数情况下前三步做对了乱码就已经解决了。5. 登录判定与常见问题排查怎么选跳转方式以及五个必踩的坑第六题是一个完整的登录程序用户输入用户名和密码用 JavaBean 接收数据判断用户名是否为 admin、密码是否为 000然后转发到不同的页面显示“欢迎登录”或“登录失败”。这道题把所有基础知识点串在一起了——表单、请求参数、字符串比较、条件分支、页面转发。同时它也是互联网上各种课程设计里被抄得最多的一段逻辑也因此藏着不少从网上流传下来的坏习惯。5.1 登录程序的完整代码JavaBean 接参、字符串判定、页面分流下面给出一个补全后的登录实现。为了贴近题目“应用 JavaBean 接受用户输入的用户名和密码”的要求首先需要一个承载登录信息的 UserBean。package hbu; public class UserBean { private String username; private String password; public String getUsername() { return username; } public void setUsername(String username) { this.username username; } public String getPassword() { return password; } public void setPassword(String password) { this.password password; } }然后是处理登录判定的 JSP 页面。登录页 login.jsp 提交表单到 doLogin.jspdoLogin.jsp 里通过 useBean 自动接参再判断用户名密码是否匹配。% page languagejava contentTypetext/html; charsetUTF-8 pageEncodingUTF-8% jsp:useBean iduser classhbu.UserBean scoperequest / jsp:setProperty nameuser property* / % request.setCharacterEncoding(UTF-8); String username user.getUsername(); String password user.getPassword(); if (username ! null password ! null username.equals(admin) password.equals(000)) { request.setAttribute(message, 欢迎登录管理员); request.getRequestDispatcher(success.jsp).forward(request, response); } else { request.setAttribute(message, 登录失败用户名或密码错误); request.getRequestDispatcher(fail.jsp).forward(request, response); } %success.jsp 和 fail.jsp 都很简单只负责从 request 作用域里取出 message 属性并显示% page languagejava contentTypetext/html; charsetUTF-8 pageEncodingUTF-8% html body h3% request.getAttribute(message) %/h3 a hreflogin.jsp返回登录页/a /body /html判断处的逻辑先用username ! null排除未传参的情况因为request.getParameter()取不到值时返回 nullnull 直接调用equals会抛空指针异常。实际校验时用username.equals(admin)也可以用admin.equals(username)这种写法来彻底避免空指针问题。注意密码不能写成password 000比较的是引用地址而不是字面值这在后面避坑章节里会专门说。5.2 页面跳转怎么选forward、redirect 与超链接的差别题目要求用“转发”代码里用的是request.getRequestDispatcher(success.jsp).forward(request, response)。实际开发中很多人分不清转发和重定向这里列一个对比表维度forward 转发redirect 重定向地址栏不变显示原请求地址变为新 URL请求次数服务器内部一次请求浏览器发两次请求request 作用域保留能通过getAttribute取值丢失新请求没有原属性跳转范围只能站内跳转可以跳到站外典型场景Servlet 查完数据传给 JSP登录成功后防重复提交课程作业里写 forward 是因为题目明确要求“转发到页面显示”。实际业务里登录成功我一般用 redirect 而不是 forward原因是浏览器地址栏还停在 doLogin.jsp 时用户按一次 F5 就会重新提交一次表单造成重复登录。forward 的场景更适合“查询完数据带过去展示”因为 request 属性可以直接在下一个页面读出来。注意这两种跳转方式对 request 属性的影响是完全相反的。如果你在登录成功后用redirect跳转到 success.jsprequest.getAttribute(message)会拿到 null因为这是一次全新的请求。要跨重定向传数据就得用 session 或者 URL 参数。5.3 五个必踩的坑现象、原因、解决坑一getAttribute 返回值没有强转编译直接报错现象代码写String msg request.getAttribute(message);Tomcat 编译时报Object cannot be converted to String。原因request.getAttribute()的返回值类型是 ObjectJSP 脚本片段是强类型编译的编译器不会自动把 Object 转成 String。解决写成String msg (String) request.getAttribute(message);。如果你往 request 里放的是自己定义的类强转时要确保类型匹配否则运行时会抛 ClassCastException。坑二页面中文乱码改了 pageEncoding 也没用现象页面显示一堆问号或菱形字符文件里明明写的 UTF-8。原因原始报告里pageEncodingISO-8859-1和pageEncodingutf-8混用的现象就是典型诱因。另一个隐蔽原因是文件实际保存格式和 pageEncoding 声明的编码不一致Eclipse 里文件编码显示 GBK代码里写 UTF-8运行时两边对不上。解决把页头统一写成contentTypetext/html; charsetUTF-8 pageEncodingUTF-8再确认项目级编码和文件编码都是 UTF-8。接收参数前调用request.setCharacterEncoding(UTF-8)且必须放在首次 getParameter 之前。坑三字符串比较用了账号密码明明正确却登录失败现象输入 admin 和 000页面还是跳到“登录失败”。原因比较的是两个对象的内存地址。JSP 里request.getParameter(username)返回的 String 是容器新建或从请求体中解码的实例和代码里写的字符串字面量admin不是同一个对象结果永远为 false。解决用username.equals(admin)比较内容。更稳妥的写法是admin.equals(username)即使 username 为 null这个表达式也只会返回 false不会抛空指针。坑四BookInfo 的 price 和 stock 用 String比较库存时逻辑全错现象想判断库存是否大于 09.compareTo(10)结果大于 0意味着 9 比 10 大想按价格排序结果排出一堆反直觉的顺序。原因String 的compareTo()按字典序比较字符不是按数值大小。库存 9 的首字符是9库存 10 的首字符是19在字典序中排在1后面所以 9 “大于” 10。解决JavaBean 里数值语义的字段换成int或BigDecimal表单传入时手动转换。如果作业有框架限制必须用 String就在 Bean 里加一个计算辅助方法内部用Integer.parseInt()或BigDecimal重新解析再比较。数值计算永远不要信任字符串类型。坑五留言板提交后一刷新就重复添加或者数据全丢现象点一次提交留言多一条按 F5 刷新又多一条。原因forward 转发会导致浏览器保留原请求刷新时重新提交表单。另一方面如果留言数据放在 request 作用域刷新后新请求里没有原数据列表就空了。解决演示版用 application 作用域存储列表前面留言板的做法正式项目让提交处理完返回redirect刷新时只会重新 GET 结果页不会重发 POST 请求。这是防重复提交最常见的手段之一。6. 报告之外把它改造成自己项目前的四件事这份实习报告最需要补充的部分是数据持久化。整套代码跑下来留言存在内存、登录用硬编码的 admin 和 000没有数据库参与。如果你想把它扩展成能拿得出手的课程设计或毕设模块我建议按下面四个方向动手。第一接入数据库。登录用户从 user 表里查留言写入 message 表用 JDBC 加连接池实现。不要用DriverManager.getConnection()每次新建连接这在并发场景下会拖垮数据库。第二密码存哈希不存明文。作业里的 000 是明文真实系统里至少要加盐后用 SHA-256 或 BCrypt保证数据库泄露时密码不裸奔。第三包名从 hbe、hby 改成你自己的项目命名空间比如com.yourname.jspdemo避免和网上流传版本撞名也方便你理解每个包的分工。第四加一个 Filter 拦截未登录访问把登录态判断从每个 JSP 里抽出来这也是 Java Web 面试里必问的过滤器应用场景。至于验证方法把项目部署到 Tomcat 后按三条路径走一遍正常登录到 success.jsp、错误密码到 fail.jsp、未登录直接访问 success.jsp 检查拦截逻辑。用浏览器开发者工具的 Network 面板能看到转发时地址栏不变、重定向时分两步请求把这两种跳转的实际网络行为看一遍比背十遍对比表都有用。我见过太多把 JavaBean 当普通类用、把转发当重定向使的同学问题不是代码写错了而是没搞清容器替我们做了什么。从那以后我每次拿到这类实习文档都强制自己先在本地跑通一遍、把所有编码统一成 UTF-8再谈能不能改造。希望帮到你。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询