JSP入门详解
JSP
Servlet基本概念
1.Servlet是什么
Servlet是JavaEE Web组件,必须运行在Web容器(tomcat)中,需要容器为其提供运行的环境,课程中使用Tomcat作为容器。
本质上,Servlet就是一个Java类,不过这个Java类要遵守一定的规范,即继承HttpServlet类
HttpServlet类中定义了很多方法,自定义的Servlet类需要覆盖其中的方法,一般情况下,只覆盖doGet或doPost。使用GET方式访问时,自动调用doGet,使用POST方式访问时,自动调用doPost
2.HttpServletRequest (req) - 读数据
拿参数
String value = req.getParameter("name"); // 拿单个
String[] values = req.getParameterValues("hobby"); // 拿多个
看信息
String method = req.getMethod(); // GET/POST
String ip = req.getRemoteAddr(); // 客户端IP
String url = req.getRequestURI(); // 请求路径
存东西(请求域)
req.setAttribute("key", object); // 存
Object obj = req.getAttribute("key"); // 取
会话相关
HttpSession session = req.getSession(); // 获取Session
3.HttpServletResponse (resp) - 写响应
设响应头(防乱码必备)
resp.setContentType("text/html;charset=UTF-8");
写数据
PrintWriter out = resp.getWriter(); // 字符流(文本)
out.println("
内容
");
ServletOutputStream out = resp.getOutputStream(); // 字节流(文件)
重定向
resp.sendRedirect("新页面.html"); // 地址栏会变
设Cookie
Cookie cookie = new Cookie("name", "value");
resp.addCookie(cookie);
经典场景
登录验证:req.getParameter()拿账号密码 → 验证 → resp.sendRedirect()跳转
数据显示:查询数据 → req.setAttribute()存数据 → 转发到JSP显示
文件下载:resp.getOutputStream()写文件流
4.doGet 和 doPost 的区别与例子
特性doGetdoPostHTTP 方法处理 GET 请求处理 POST 请求参数传递参数附加在 URL 之后(如:?name=张三&age=20)参数放在 请求体 (Request Body) 中安全性差,参数在地址栏明文显示,可能被浏览器历史记录缓存较好,参数不在地址栏显示,也不会被缓存数据长度有限制(因浏览器和服务器对URL长度有限制)理论上无限制(实际上服务器可配置)幂等性幂等(多次执行同一请求,效果相同)不幂等(多次提交可能会产生不同效果,如重复下单)用途用于获取数据(如:搜索、查询页面)用于提交/修改数据(如:登录、注册、支付)
总结
你用 method="get",表单数据就会显示在地址栏(LoginServlet?username=admin&password=123456),非常不安全,且doGet方法会被调用。
你用 method="post",地址栏只有 LoginServlet,数据隐藏传输,doPost方法被调用。所以登录、注册等操作必须用POST。
5.HttpServletRequest (req) 和 HttpServletResponse (resp) 的作用与例子
可以把一次HTTP请求和响应想象成一次顾客和服务员的对话。
HttpServletRequest req (请求对象): 就像是顾客对服务员说的话。它包含了客户发来的所有信息。
HttpServletResponse resp (响应对象): 就像是服务员准备回复顾客的工具。你用它来组织你要返回给客户的内容。
总结
核心功能例子req顾客获取信息:参数、URL、IP等;传递数据String name = req.getParameter("name");resp服务员设置回应:内容类型、编码、状态码;发送数据resp.getWriter().println("Hello");
6.Servlet跳转到其他组件
1)第一种跳转方式:响应重定向
HttpServletResponse中定义了响应重定向的方法
– sendRedirect(String path)
响应重定向是向目标资源重新发送请求,生成新的响应
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
// 1. 获取参数
String username = req.getParameter("username"); // 这里能拿到 "admin"
String password = req.getParameter("password"); // 这里能拿到 "123456"
// 2. 验证登录(假设成功)
// 3. 重定向到欢迎页面
resp.sendRedirect("WelcomeServlet"); // 问题就出在这里!
}
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
// 尝试获取用户名
String username = req.getParameter("username"); // 这里得到的是 null!
resp.getWriter().println("欢迎你:" + username); // 显示"欢迎你:null"
}
为什么是 null?
1)因为 重定向的本质是让浏览器发起一个新的GET请求:
第一次请求:浏览器 POST 提交表单到 LoginServlet,携带参数 username=admin&password=123456
LoginServlet处理:收到参数,验证通过
响应重定向:LoginServlet 返回302状态码和 Location: WelcomeServlet 头信息
浏览器动作:浏览器看到302,自动发起一个新的GET请求到 WelcomeServlet
第二次请求:这个新请求没有任何参数,就是单纯的访问 WelcomeServlet
WelcomeServlet处理:req.getParameter("username") 自然就拿不到值了
2)第二种跳转方式:请求转发
请求转发
能够把当前的请求对象转发到目标资源,是最常用的跳转方法
使用步骤
先使用请求中getRequestDispatcher(String path)方法获得请求转发器对象RequestDispatcher
然后调用RequestDispatcher的forward(request,response)方法进行跳转 forward传参数
修改LoginServlet中的跳转方法
使用请求转发后,当前的请求对象被转发到下一个资源,因此可以得到请求对象中的数据,包括请求参数,请求方法等。在doPost中调用该方法,将调用下一个资源的doPost方法;在doGet方法中调用该方法,调用下一个资源的doGet方法
例子
请求转发简单例子
场景:用户登录成功后跳转到欢迎页面
LoginServlet.java
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// 1. 设置编码
req.setCharacterEncoding("UTF-8");
// 2. 获取参数
String username = req.getParameter("username");
String password = req.getParameter("password");
// 3. 模拟登录验证
if ("admin".equals(username) && "123456".equals(password)) {
// 登录成功,把用户名存到请求中
req.setAttribute("welcomeMsg", "欢迎回来," + username + "!");
// 4. 使用请求转发跳转到欢迎页面
RequestDispatcher rd = req.getRequestDispatcher("WelcomeServlet");
rd.forward(req, resp); // 关键代码!
} else {
// 登录失败
resp.getWriter().println("登录失败!");
}
}
WelcomeServlet.java
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.setContentType("text/html;charset=UTF-8");
PrintWriter out = resp.getWriter();
// 可以直接获取LoginServlet中设置的属性
String welcomeMsg = (String) req.getAttribute("welcomeMsg");
// 也可以直接获取原始请求的参数(因为是一次请求)
String username = req.getParameter("username"); // 这里能拿到值!
out.println("
" + welcomeMsg + "
");out.println("
用户名: " + username + "
");}
重定向 vs 转发(Forward)
特性重定向 (Redirect)转发 (Forward)请求次数2次1次地址栏变化(显示新URL)不变(显示原URL)数据传递丢失原始请求参数保留原始请求参数和属性实现方式resp.sendRedirect("url")req.getRequestDispatcher("url").forward(req, resp)
为什么浏览器地址栏显示的是 /login 而不是JSP路径?
因为:请求转发是服务器内部的行为,浏览器完全不知道发生了什么!
整个流程是这样的:
你在浏览器输入:http://localhost:8080/login(访问Servlet)
浏览器向服务器发送请求:GET /login
服务器收到请求:LoginServlet 的 doGet() 方法被执行
Servlet内部处理:验证登录、查询数据等
Servlet决定转发:req.getRequestDispatcher("welcome.jsp").forward(req, resp);
服务器内部跳转:服务器直接调用 welcome.jsp 来生成HTML内容
服务器返回响应:把JSP生成的HTML内容返回给浏览器
浏览器显示结果:显示JSP的内容,但地址栏仍然显示最初的 /login
这是正常且正确的行为!
优点:
隐藏技术细节:用户看不到JSP路径,更安全
保持URL整洁:逻辑URL(/login)和物理文件路径(welcome.jsp)分离
更好的SEO:统一的URL结构