6 ,Servlet
Servlet 接口在 sun 公司有两个默认的实现类: HttpServlet,GenericServlet
6.1 Servlet简介
- servlet 就是 sun 公司开发动态 web 的一门技术
- Sun 公司在这些 API 中提供了一个接口:Servlet:
- 编写一个类,实现 Servlet 接口
- 把开发好的 Java 类部署到 web 服务器中
把实现了 Servlet 接口的 Java程序 叫做 Servlet
6.2 Hello Servlet
构建一个普通的 maven 项目,删掉 src 目录,
关于 maven 父子工程的理解:
父项目中会有:
<modules> <module>servlet-01</module> <module>servlet-02</module> <module>response</module> <module>request</module> </modules>
子项目中会有:
maven 环境优化:
修改 web.xml 为最新的
将 maven 结构搭建完整
- 编写一个 servlet 程序
编写一个普通类
实现 Servlet 接口,这里直接继承 HttpServlet
编写 Servlet 的映射
为什么需要映射,Java 程序 需要浏览器访问,浏览器需要连接 web 服务器,所以需要在 web 服务中心注册写的 Servlet ,还需要给他一个浏览器能够访问的 路径
<!--注册 servlet-->
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.kuang.servlet.HelloServlet</servlet-class>
</servlet>
<!--Servlet 的请求路径-->
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
配置 Tomcat
启动测试
6.3 Servlet 原理
Servlet 是由 Web 服务器调用,web服务器 在收到浏览器请求后,会:
6.4 Mapping 问题
- 一个servlet 可以指定一个映射路径
- 一个servlet 可以指定多个映射路径
- 一个servlet 可以指定通用映射路径
6.5 ServletContext
web 容器在启动的时候,他会为每个web程序都创建一个对应的 ServletContext 对象,他代表了当前的 web 应用
1 ,共享数据
在这个 servlet 中保存的数据,可以再另外一个 servlet 中拿到;
放置数据的类:
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// this.getInitParameter() 初始化参数
// this.getServletConfig() Servlet配置
// this.getServletContext() Servlet上下文
ServletContext context = this.getServletContext();
String username = "姚明"; // 数据
context.setAttribute("username",username); // 将一个数据保存在了 ServletContext 中,名字为:username 值:username
System.out.println("hello");
}
}
读取数据的类:
public class GetServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context = this.getServletContext();
String username =(String) context.getAttribute("username");
resp.setContentType("text/html");
resp.setCharacterEncoding("utf-8");
resp.getWriter().println("名字"+username);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0"
metadata-complete="true">
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.kuang.servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>getc</servlet-name>
<servlet-class>com.kuang.servlet.GetServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>getc</servlet-name>
<url-pattern>/getc</url-pattern>
</servlet-mapping>
</web-app>
启动测试:
2 ,获取初始化参数
配置初始化参数
<!--配置 web 应用的初始化参数-->
<context-param>
<param-name>url</param-name>
<param-value>jdbc:mysql://localhost:3306/mybatis</param-value>
</context-param>
拿到参数:
package com.kuang.servlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class ServletDemo03 extends HelloServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context = this.getServletContext();
String url = context.getInitParameter("url");
resp.getWriter().println(url);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
注册:
<servlet>
<servlet-name>url</servlet-name>
<servlet-class>com.kuang.servlet.ServletDemo03</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>url</servlet-name>
<url-pattern>/urls</url-pattern>
</servlet-mapping>
启动测试
3 ,请求转发
package com.kuang.servlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class ServletDemo04 extends HelloServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context = this.getServletContext();
System.out.println("进入了ServletDemo04");
// RequestDispatcher requestDispatcher = context.getRequestDispatcher("urls");// 转发的请求路径
// requestDispatcher.forward(req,resp); // 调用 forward 方法 实现请求转发
context.getRequestDispatcher("/urls").forward(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
4 ,读取资源文件
Properties 类:
- 在 java 目录下新建 properties
- 在 resources 目录下新建 properties
都被打包在了 classes 路径下
思想:需要一个文件流
username=root
password=root
package com.kuang.servlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class PropertiesServlet extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context = this.getServletContext();
// 把资源变成一个流 返回一个 is 流 /WEB-INF 代表当前 web 项目
InputStream is = context.getResourceAsStream("/WEB-INF/classes/com/kuang/servlet/aa.properties");
Properties properties = new Properties();
properties.load(is); // 把流加载进去
// 获取属性
String user = properties.getProperty("username");
String pwd = properties.getProperty("password");
resp.getWriter().println(user+pwd); // 输出到前端
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
访问测试即可
6.6 HttpServletResponse
响应
web 服务器 接收到客户端的 http 请求,针对这个请求,分别创建一个代表请求的 HttpServletRequest 对象,代表响应的一个 HttpServletResponse 对象;
- 如果要获取客户端请求过来的参数,找 HttpServletRequest
- 如果要给客户端响应一些参数:找 HttpServletResponse
1 ,简单分类
负责向浏览器发送数据的方法
ServletOutputStream getOutputStream() throws IOException; PrintWriter getWriter() throws IOException;
负责向浏览器发送一些响应头的方法
void setCharacterEncoding(String var1);
void setContentLength(int var1);
void setContentLengthLong(long var1);
void setContentType(String var1);
void setDateHeader(String var1, long var2);
void addDateHeader(String var1, long var2);
void setHeader(String var1, String var2);
void addHeader(String var1, String var2);
void setIntHeader(String var1, int var2);
void addIntHeader(String var1, int var2);
响应状态码:
int SC_CONTINUE = 100;
int SC_SWITCHING_PROTOCOLS = 101;
int SC_OK = 200;
int SC_CREATED = 201;
int SC_ACCEPTED = 202;
int SC_NON_AUTHORITATIVE_INFORMATION = 203;
int SC_NO_CONTENT = 204;
int SC_RESET_CONTENT = 205;
int SC_PARTIAL_CONTENT = 206;
int SC_MULTIPLE_CHOICES = 300;
int SC_MOVED_PERMANENTLY = 301;
int SC_MOVED_TEMPORARILY = 302;
int SC_FOUND = 302;
int SC_SEE_OTHER = 303;
int SC_NOT_MODIFIED = 304;
int SC_USE_PROXY = 305;
int SC_TEMPORARY_REDIRECT = 307;
int SC_BAD_REQUEST = 400;
int SC_UNAUTHORIZED = 401;
int SC_PAYMENT_REQUIRED = 402;
int SC_FORBIDDEN = 403;
int SC_NOT_FOUND = 404;
int SC_METHOD_NOT_ALLOWED = 405;
int SC_NOT_ACCEPTABLE = 406;
int SC_PROXY_AUTHENTICATION_REQUIRED = 407;
int SC_REQUEST_TIMEOUT = 408;
int SC_CONFLICT = 409;
int SC_GONE = 410;
int SC_LENGTH_REQUIRED = 411;
int SC_PRECONDITION_FAILED = 412;
int SC_REQUEST_ENTITY_TOO_LARGE = 413;
int SC_REQUEST_URI_TOO_LONG = 414;
int SC_UNSUPPORTED_MEDIA_TYPE = 415;
int SC_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
int SC_EXPECTATION_FAILED = 417;
int SC_INTERNAL_SERVER_ERROR = 500;
int SC_NOT_IMPLEMENTED = 501;
int SC_BAD_GATEWAY = 502;
int SC_SERVICE_UNAVAILABLE = 503;
int SC_GATEWAY_TIMEOUT = 504;
int SC_HTTP_VERSION_NOT_SUPPORTED = 505;
2 ,常见应用:
1.向浏览器输送消息
2.下载文件
- 要获取文件下载的路径
- 下载的文件名是啥
- 设置想办法让浏览器支持下载我们需要的东西
- 获取下载文件的输入流
- 创建缓冲区
- 获得 OutputStream 对象
- 将 FileOutputStream 流写入到 buffer 缓冲区
- 使用 OutputStream 将缓冲区中的数据输出到客户端
3 ,验证码功能
验证怎么来?
- 前端实现
- 后端实现,需要用到 java 的图片类,生成一个图片
4 ,实现重定向
*提交路径:action="${pageContext.request.contextPath}/se"
<form action="${pageContext.request.contextPath}/se" method="get">
用户名:<input type="text" name="username"></br>
密码 :<input type="password" name="password"><br>
<input type="submit">
</form>
B 一个 web 资源受到客户端 A 的请求后,B 会通知 A 客户端去访问另外一个 web 资源C,这个过程叫做重定向
常见场景:页面跳转
用户登录
void sendRedirect(String var1) throws IOException;
测试:
登录页面:
<html> <body> <h2>Hello World!</h2> <form action="${pageContext.request.contextPath}/se" method="get"> 用户名:<input type="text" name="username"></br> 密码 :<input type="password" name="password"><br> <input type="submit"> </form> </from> </body> </html>
跳转页面:
<%-- Created by IntelliJ IDEA. User: 小狂神 Date: 2021/7/29 Time: 9:31 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <h1>success</h1> </body> </html>
java 代码:
package com.kuang.servlet; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class RedirectServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 获取前端参数 String username = req.getParameter("username"); String password = req.getParameter("password"); // 将参数输出到后台 System.out.println(username+":"+password); // 重定向 resp.sendRedirect("/r/success.jsp"); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }
面试题:重定向和转发的区别?
相同点:页面都会实现跳转
不同点:请求转发的时候,URL 不会发生变化,重定向的时候,URl 地址栏会发生变化
6.7 HttpServletRequest
HttpServletRequest 代表客户端的请求,用户通过 http 协议访问服务器,http 请求中的所有信息会被封装到 HttpServletRequest,通过这个HttpServletRequest 的方法 获得客户端的所有信息
1 ,获取前端传递的参数,请求转发
前端的 index
<%--
Created by IntelliJ IDEA.
User: 小狂神
Date: 2021/7/29
Time: 11:12
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登录</title>
</head>
<body>
<h1>登录页面</h1>
<div style="text-align: center">
<%--这里表单表示的意思:以 post 方式提交表单,提交到我们的 login 请求--%>
<form action="${pageContext.request.contextPath}/login" method="post">
用户名:<input type="text"name="username"><br>
密码 :<input type="password" name="password"><br>
爱好 :
<input type="checkbox" name="hobby" value="男">男
<input type="checkbox" name="hobby" value="女">女
<input type="checkbox" name="hobby" value="打球">打球
<input type="checkbox" name="hobby" value="唱歌">唱歌
<br>
<input type="submit">
</form>
</div>
</body>
</html>
前端的跳转页面 success
<%--
Created by IntelliJ IDEA.
User: 小狂神
Date: 2021/7/29
Time: 11:22
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>登陆成功</h1>
</body>
</html>
java 代码:
package com.kuang.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 解决乱码问题
req.setCharacterEncoding("utf-8");
resp.setCharacterEncoding("utf-8");
// 获取参数
String username = req.getParameter("username");
String password = req.getParameter("password");
// req.getParameterValues() 获取多个参数值
String[] hobbies = req.getParameterValues("hobby");
System.out.println("===========================================");
// 后台接收中文乱码问题
System.out.println(username);
System.out.println(password);
System.out.println(Arrays.toString(hobbies)); // 打印数组元素
System.out.println("===========================================");
System.out.println(req.getContextPath());
// 通过请求转发
// 这里的 / 代表当前的 web 应用
req.getRequestDispatcher("/success.jsp").forward(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
- 注册 servlet
- 启动 Tomcat 测试
面试题:重定向和转发的区别?
相同点:页面都会实现跳转
不同点:请求转发的时候,URL 不会发生变化,307 重定向的时候,URl 地址栏会发生变化 302