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结构