一.Servlet技术
Java Servlet 是运行在 Web 服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层。
第一个Servlet程序
- 创建HelloServlet类
package com.atguigu.servlet;
import javax.servlet.*;
import java.io.IOException;
public class HelloServlet implements Servlet{
@Override
public void init(ServletConfig servletConfig) throws ServletException {
}
@Override
public ServletConfig getServletConfig() {
return null;
}
/*service方法专门用来处理请求和响应*/
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("Hello Servlet 被访问了");
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
- 修改web.xml文件
<?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">
<!--servlet标签给Tomcat配置Servlet程序-->
<servlet>
<!--servlet-name标签给程序起一个别名(一般为类名)-->
<servlet-name>HelloServlet</servlet-name>
<!--servlet-class是Servlet程序的全类名-->
<servlet-class>com.atguigu.servlet.HelloServlet</servlet-class>
</servlet>
<!--servlet-mapping标签给servlet程序配置访问地址-->
<servlet-mapping>
<!--servlet-name标签告诉服务器,当前配置的地址是给哪个Servlet程序使用-->
<servlet-name>HelloServlet</servlet-name>
<!--url-pattern配置访问地址-->
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>
- 运行
在 http://localhst:8080/工程名 后加入/hello
控制台输出 Hello Servlet 被访问了
二.Servlet生命周期
三.Servlet表单数据
很多情况下,需要传递一些信息,从浏览器到 Web 服务器,最终到后台程序。浏览器使用两种方法可将这些信息传递到 Web 服务器,分别为 GET 方法和 POST 方法。
1.GET和POST的请求分发处理
- GET方法:
GET 方法是默认的从浏览器向 Web 服务器传递信息的方法,它会产生一个很长的字符串,出现在浏览器的地址栏中。如果您要向服务器传递的是密码或其他的敏感信息,请不要使用 GET 方法。GET 方法有大小限制:请求字符串中最多只能有 1024 个字符。
这些信息使用 QUERY_STRING 头传递,并可以通过 QUERY_STRING 环境变量访问,Servlet 使用 doGet() 方法处理这种类型的请求。 - POST方法:
另一个向后台程序传递信息的比较可靠的方法是 POST 方法。POST 方法打包信息的方式与 GET 方法基本相同,但是 POST 方法不是把信息作为 URL 中 ? 字符后的文本字符串进行发送,而是把这些信息作为一个单独的消息。消息以标准输出的形式传到后台程序,您可以解析和使用这些标准输出。Servlet 使用 doPost() 方法处理这种类型的请求。
/*service方法专门用来处理请求和响应*/
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("Hello Servlet 被访问了");
// 类型转换(因为它有getMethod()方法)
HttpServletRequest httpServletRequest=(HttpServletRequest) servletRequest;
// 获取请求方式
String method =httpServletRequest.getMethod();
if ("GET".equals(method)){
// doGet();
}else if("POST".equals(method)){
// doPost();
}
}
2.继承HttpServlet类
package com.atguigu.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 HelloServlet2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("doGet方法");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("doPost方法");
}
}
3.IDEA快速创建Servlet
包 -> New -> Servlet
没有Servlet的话打开项目结构的Facets勾选Source Root
四.Servlet继承体系
- Servlet接口负责定义Servlet程序的访问规范
- GenericServlet类实现了Servlet接口,做了很多空实现,并持有一个ServletConfig类的引用,并对其的使用做了一些方法
- HttpServlet类实现了service方法,并实现了请求的分发处理
1.ServletConfig类
Servlet程序和ServletConfig对象都是由Tomcat负责创建,我们负责使用。
Servlet程序默认是第一次访问的时候创建,ServletcConfig是每个Servlet程序创建时,就创建一个对应的ServletConfig对象
@Override
public void init(ServletConfig servletConfig) throws ServletException {
System.out.println("HelloServlet的别名:"+servletConfig.getServletName());
// HelloServlet的别名:HelloServlet
System.out.println("初始化参数username的值:"+servletConfig.getInitParameter("username"));
System.out.println("初始化参数url的值:"+servletConfig.getInitParameter("url"));
// 初始化参数username的值:root
// 初始化参数url的值:jdbc://localhost:3306/test
System.out.println(servletConfig.getServletContext());
// org.apache.catalina.core.ApplicationContextFacade@56e41fc7
}
<servlet>
<servlet-name>HelloServlet</servlet-name>
<servlet-class>com.atguigu.servlet.HelloServlet</servlet-class>
<!--<init-param>初始化参数-->
<init-param>
<param-name>username</param-name>
<param-value>root</param-value>
</init-param>
<init-param>
<param-name>url</param-name>
<param-value>jdbc://localhost:3306/test</param-value>
</init-param>
</servlet>
注意:extends HttpServlet时,若重写init方法,必须super.init(config);
2.ServletContext类
- 四个常见作用
五.HTTP协议
HTTP 协议一般指 HTTP(超文本传输协议)。
超文本传输协议(英语:HyperText Transfer Protocol,缩写:HTTP)是一种用于分布式、协作式和超媒体信息系统的应用层协议,是因特网上应用最为广泛的一种网络传输协议,所有的 WWW 文件都必须遵守这个标准。
HTTP是一个基于TCP/IP通信协议来传递数据(HTML 文件, 图片文件, 查询结果等)。
1.的HTTP协议格式
客户端发送一个HTTP请求到服务器的请求消息包括以下格式:请求行(request line)、请求头部(header)、空行和请求数据四个部分组成
常见的请求头:
2.GET和POST请求的使用
3.响应的HTTP协议
HTTP响应也由四个部分组成,分别是:状态行、消息报头、空行和响应正文。
常见响应码
4.MIME类型说明
MIME是HTTP协议中数据类型
HTTP content-type 对照表
六.HttpServletRquest类
作用:每次只要有Tomcat服务器,Tomcat服务器就会把请求过来的HTTP协议信息解析好封装到Request对象中。然后传递到service方法中给我们使用,我们可以通过HttpServletRquest对象,获取到所有请求的信息。
常用方法:
- getRequestURI() - 该方法用于获取请求的资源路径
- getRequestURL() - 该方法用于获取请求的统一资源定位符(绝对路径)
- getRemoteHost() - 该方法用于获取请求客户端的完整主机名,其格式类似于pcl.mengma.com。需要注意的是,如果无法解析出客户机的完整主机名,那么该方法将会返回客户端的 IP 地址。
- getHeader(String name) - 该方法用于获取一个指定头字段的值,如果请求消息中没有包含指定的头字段,则getHeader() 方法返回 null;如果请求消息中包含多个指定名称的头字段,则 getHeader() 方法返回其中第一个头字段的值。
- getParameter() - 获取请求的参数
- getParameterValues() - 获取请求的参数(多个值的时候使用)
- getMethod() - 该方法用于获取 HTTP 请求消息中的请求方式(如 GET、POST 等)
- setAttribute(key,value) - 设置域数据
- getAttribute(key) - 获取域数据
- getRequestDispatcher() - 获取请求转发对象
1.获取请求的参数值
form.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="http://localhost:8080/servlet_war_exploded/parameterServlet" method="get">
用户名:<input type="text" name="username"><br>
密码:<input type="text" name="password"><br>
兴趣爱好:<input type="checkbox" name="hobby" value="cpp">C++
<input type="checkbox" name="hobby" value="java">Java
<input type="checkbox" name="hobby" value="js">JavaScript
<br>
<input type="submit">
</form>
</body>
</html>
ParameterServlet.java
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 ParameterServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取请求的参数
System.out.println("用户名:"+req.getParameter("username"));
System.out.println("密码:"+req.getParameter("password"));
String[] hobby=req.getParameterValues("hobby"); // 多个参数
System.out.println("兴趣爱好:"+ Arrays.asList(hobby));
}
}
输出:
- POST请求中文乱码问题
如果使用doPost方法,则会出现中文乱码问题
req.setCharacterEncoding("UTF-8"); // 在获取所有请求之前调用
使用上述代码后问题解决
2.请求的转发
Servlet1.java
public class Servlet1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("柜台1 中查看参数"+req.getParameter("username"));
req.setAttribute("key","柜台1的章");
//请求转发必须要以斜杠打头
RequestDispatcher requestDispatcher=req.getRequestDispatcher("/servlet2");
requestDispatcher.forward(req,resp);
}
}
Servlet2,java
public class Servlet2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("柜台2 中查看参数"+req.getParameter("username"));
Object key = req.getAttribute("key");
System.out.println("柜台1 是否有章"+key);
System.out.println("Servlet2处理自己的业务");
}
}
访问:http://localhost:8080/servlet_war_exploded/servlet1?username=zzz
输出:
3.Servlet-base标签
base标签可以设置当前页面中所有相对路径工作时,参照哪个路径进行跳转
请求转发:
ForwardC.java
public class ForwardC extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.getRequestDispatcher("/a/b/c.html").forward(req,resp);
}
}
web/a/b/c.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>c</title>
<base href="http://localhost:8080/servlet_war_exploded/a/b/c">
</head>
<body>
这是a下的b下的c.html页面 <br>
<a href="../../index.html">回到首页</a>
</body>
</html>
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
这是Web下的index.html <br>
<a href="a/b/c.html">c.html</a><br>
<a href="http://localhost:8080/servlet_war_exploded/forwardC">请求转发:a/b/c.html</a>
</body>
</html>
- web中斜杠的不同意义
特殊情况:
response.senRediect("/"); 把斜杠发送给浏览器解析,得到http://ip:port/
七.HttpServletResponse类
每次请求进来,Tomcat服务器都会创建一个Response对象传递给Servlet程序使用。HttpServletRequest表示请求过来的信息,HttpServletResponse表示所有响应的信息,我们如果需要设置返回给客户端的信息,都可以通过Response对象设置。
1.两个输出流
字节流,常用于传递二进制数据
字符流,常用于回传字符串
两个流同时只能使用一个,否则就会报错。
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter(); // 字符流
resp.getOutputStream(); // 字节流
}
2.客户端回传字符串数据
方法一:
public class ResponseIOServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setCharacterEncoding("UTF-8"); // 服务器中文编码
resp.setHeader("Content-Type","text/html;Charset=UTF-8"); // 通过响应头设置浏览器也使用UTF-8
PrintWriter writer=resp.getWriter();
writer.write("先生请出山");
}
}
方法二:
resp.setContentType("text/html;charset=UTF-8");
// 同时设置服务器和客户端都使用UTF-8字符集,还设置了响应头
注意:此方法一定要在获取流对象之前调用才有效
3.请求重定向
客户端给服务器发请求,服务器告诉客户端,我给你一个新地址,你去新地址访问(因为之前的地址可能已经被废弃)。
特点:
1.浏览器地址栏会发生变化
2.两次请求
3.不共享Request域中的数据
4.不能访问WEB-INF下的资源
5.可以访问工程外的资源
实现方法一:
public class Response1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("到此一游 Response1");
// 设置响应状态码302
resp.setStatus(302);
resp.setHeader("Location","http://localhost:8080/servlet_war_exploded/response2");
}
}
public class Response2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("response's result!");
}
}
实现方法二:
resp.sendRedirect("http://localhost:8080/servlet_war_exploded/response2");