一、初识Servlet
1.1简介
Servlet是一种使用Java语言来开发动态网站的技术。Servlet是运行在Web服务器或应用服务器上的程序,它是作为来自Web浏览器或其他HTTP客户端的请求和HTTP服务器上的数据库或应用程序之间的中间层。Servlet可以收集来自网页表单的用户输入,呈现来自数据库或者其他源的记录,还可以动态创建网页
1.2步骤
Sun在这些API中提供一个接口叫做: Servlet, 如果你想开发一个Servlet程序, 只需要完成两个小步骤:
- 编写一个类,实现Servlet接口
- 把开发好的Java类部署到web服务器中。
1.3Servlet映射
Servlet映射是指将Servlet类与URL(前端访问服务器的链接)一一对应的过程。Servlet映射可以通过XML文件或注解的方式进行配置
XML文件方式
XML文件方式:在web.xml文件中,使用<servlet>元素和<servlet-mapping>元素来定义Servlet类和URL的对应关系
<servlet>
<servlet-name>MyServlet</servlet-name>
<servlet-class>com.example.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyServlet</servlet-name>
<url-pattern>/myServlet</url-pattern>
</servlet-mapping>
这样就将com.example.MyServlet类映射到了/myServlet这个URL上,客户端可以通过http://localhost:8080/myServlet来访问这个Servlet
注解方式
注解方式:在Servlet类上,使用@WebServlet注解来指定URL的对应关系
@WebServlet("/myServlet")
public class MyServlet extends HttpServlet {
// ...
}
这样就将MyServlet类映射到了/myServlet这个URL上,客户端可以通过http://localhost:8080/myServlet来访问这个Servlet
多重映射
注意,一个Servlet可以被映射到多个URL上,也就是多重映射
<servlet>
<servlet-name>MyServlet</servlet-name>
<servlet-class>com.example.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyServlet</servlet-name>
<url-pattern>/myServlet</url-pattern>
<url-pattern>/myServlet2</url-pattern>
</servlet-mapping>
或者
@WebServlet({"/myServlet", "/myServlet2"})
public class MyServlet extends HttpServlet {
// ...
}
这样就将MyServlet类映射到了/myServlet和/myServlet2两个URL上,客户端可以通过http://localhost:8080/myServlet或http://localhost:8080/myServlet2来访问这个Servlet
1.4Servlet原理
Servlet和容器:
Servlet是一个Java类,它实现了javax.servlet.Servlet接口,用来处理客户端的请求和响应。Servlet需要运行在一个支持Java Servlet规范的容器中,例如Tomcat、Jetty等。容器负责加载、初始化、调用和销毁Servlet,以及提供一些服务和资源给Servlet
Servlet生命周期:
Servlet的生命周期是指从Servlet被创建到被销毁的过程,它包括以下几个阶段:
初始化:当容器第一次收到对某个Servlet的请求时,它会加载并实例化这个Servlet,并调用它的init()方法进行初始化工作。这个方法只会被调用一次,在整个生命周期中。
服务:当容器收到对某个Servlet的请求时,它会调用它的service()方法来处理这个请求,并生成一个响应。这个方法会被调用多次,每次请求都会执行这个方法。service()方法会根据请求的HTTP方法(GET、POST、PUT、DELETE等)来调用相应的doGet()、doPost()、doPut()、doDelete()等方法。
销毁:当容器决定卸载某个Servlet时,它会调用它的destroy()方法来释放资源并执行清理工作。这个方法只会被调用一次,在整个生命周期的最后。
Servlet映射:
Servlet映射是指将Servlet类与URL(前端访问服务器的链接)一一对应的过程
Servlet映射可以通过XML文件或注解的方式进行配置
注意
Servlet请求和响应:
当客户端发送一个HTTP请求到服务器时,容器会创建一个javax.servlet.ServletRequest对象和一个javax.servlet.ServletResponse对象,并传递给对应的service()方法。
ServletRequest对象封装了客户端发送的数据,包括参数、属性、头信息、cookie等。
ServletResponse对象封装了服务器返回的数据,包括状态码、头信息、cookie、输出流等。
如果是HTTP协议,那么ServletRequest和ServletResponse对象会被转换为javax.servlet.http.HttpServletRequest和javax.servlet.http.HttpServletResponse对象,提供更多的HTTP相关的方法和属性
1.5Log(日志)
Log(日志),记录应用运行的事件信息,统计系统运行情况,高效定位追踪问题,等等
- 执行状态的变化
- 系统入口/出口
- 业务异常
- 非预期执行
- 特定程序运行时间
- 执行进度
- … …
java.util.logging.Logger,Java提供的简单日志工具,仅会使用info()方法即可。后期课程使用功能更强大的日志框架
1.6@WebServlet
二、Servlet入门
2.0GET与POST
post请求以相同的语法提供参数,只是它位于请求的“body”部分,因此用户很难看到 Post请求,参数封装在请求体,而非请求地址
2.1ServletContext
共享数据·
我在这个Servlet中保存的数据,可以在另外一个servlet中拿到;
获取初始化参数
请求转发
读取资源文件
2.2HttpServletResponse响应
HttpServletResponse是一个接口,它用于封装HTTP响应消息,简称response对象。它有一些方法可以设置响应的状态码,响应头,响应正文和重定向等功能。
负责向浏览器发送数据的方法
- 可以使用response.getWriter()方法来获取一个PrintWriter对象,用于向客户端发送字符文本,例如HTML标签或纯文本。
- 也可以使用response.getOutputStream()方法来获取一个ServletOutputStream对象,用于向客户端发送字节数据,例如图片,音频,视频等二进制文件。
负责向浏览器发送响应头的方法
- 设置响应的字符集,可以使用response.setContentType()方法来指定content-type响应头,例如response.setContentType(“text/html;charset=utf-8”)。
- 实现页面的自动刷新或跳转,可以使用response.setHeader()方法来设置Refresh响应头,例如response.setHeader(“Refresh”,“5;URL=www.baidu.com”)。
Response下载文件
Servlet部分
package com.web;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
@WebServlet("/down")
public class Servlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取下载文件的路径
String filename = req.getParameter("filename");
System.out.println(filename);
String path = this.getServletContext().getRealPath("/dowmload/" + filename);
// 获取下载文件的文件名
filename = URLEncoder.encode(filename, "UTF-8"); // 处理中文文件名乱码问题
// 设置响应头,告诉浏览器要以下载的形式打开文件
resp.setHeader("content-disposition", "attachment;filename=" + filename);
// 设置响应内容类型为二进制流
resp.setContentType("application/octet-stream");
// 获取下载文件的输入流
FileInputStream in = new FileInputStream(path);
// 创建缓冲区
byte[] buffer = new byte[1024];
int len = 0;
// 获取输出流
OutputStream out = resp.getOutputStream();
// 将输入流中的数据写入缓冲区,再从缓冲区写入输出流
while ((len = in.read(buffer)) != -1) {
out.write(buffer, 0, len);
}
// 关闭输入流和输出流
in.close();
out.close();
}
}
JSP部分
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>下载</title>
</head>
<body>
<a href=${pageContext.request.contextPath}/down?filename=1.jpg>1.jpg</a><br>
<a href=${pageContext.request.contextPath}/down?filename=2.txt>2.txt</a><br>
</body>
</html>
href属性应该是"/down?filename=文件名",而不是"dowmload/文件名",这样才能调用你的Servlet类
/down?是一个URL,它表示要访问的Servlet类的路径和参数。/down表示你的Servlet类的注解@WebServlet(“/down”),它告诉服务器这个类的映射路径。?表示后面跟着的是参数,比如filename=文件1.txt,这个参数会被传递给你的Servlet类的doGet方法,然后你可以通过req.getParameter(“filename”)获取这个参数的值。
Response验证码
package com.web;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;
@WebServlet("/img")
public class Servlet extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//如何让浏览器5秒刷新一次?
resp.setHeader("refresh","3");
//在内存中创建图片
BufferedImage image = new BufferedImage(200,200,BufferedImage.TYPE_INT_RGB);
//开始画图
Graphics2D g=(Graphics2D) image.getGraphics();
//设置图片背景颜色
g.setBackground(Color.white);
g.fillRect(0,0,100,50);
//写入验证码
g.setColor(Color.GREEN);
g.setFont(new Font(null, Font.PLAIN,20));
g.drawString(makeNumber(),0,25);
//高速浏览器,这个请求用图片的方式打开
resp.setContentType("image/png");
//设置不让浏览器缓存图片
resp.setDateHeader("expires",-1);
resp.setHeader("Cache-Control","no-cache");
resp.setHeader("Program","no-cache");
//把图片写给浏览器
boolean write = ImageIO.write(image,"png", resp.getOutputStream());
}
//生成随机数
private String makeNumber(){
Random r = new Random();
String num=r.nextInt(99999999)+"";
StringBuffer sBuffer = new StringBuffer();
for (int i = 0; i < 8-num.length(); i++) {
sBuffer.append("x");
}
return sBuffer.toString()+num;
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
}
Response实现重定向
重定向的概念是指通过各种方法将网络请求重新定向到其他位置,比如网页重定向、域名重定向等。重定向的原理是服务器向请求发送一个特殊的响应,包含一个状态码和一个新的URL。浏览器收到响应后,会自动加载新的URL。重定向有不同的类型和应用场景,比如永久重定向、临时重定向、域名别称、站点迁移等
public class RedirectServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.sendRedirect("/r/img");//重定向
//拆分
/*
resp.setHeader("Location","/r/img");
resp.setStatus(302);
*/
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
补充
登录判断
package com.web;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import jakarta.servlet.annotation.*;
import java.io.IOException;
@WebServlet("/login")
public class Servlet1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("进入这个请求");
//处理请求
String username = req.getParameter("username");
String password = req.getParameter("password");
System.out.println(username+":"+password);
//重定向一定要注意路径问题
if (username.equals("admin") && password.equals("123456")){
System.out.println("登陆成功");
//请求转发
//转发:服务器把这个请求转向另外一个Servlet去处理; (地址栏不会变)
//RequestDispatcher ,需要使用RequestDispatcher来进行处理,我们需要获得这个类,参数为要转发到的页面
req.getRequestDispatcher("/success.jsp").forward(req,resp);
}else {
req.getRequestDispatcher("/fail.jsp").forward(req,resp);
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
}
面试题:重定向与转发的区别
- 相同点
页面都会跳转- 不同点
请求转发的时候,url不会产生变化
重定向的时候,url地址栏会发生变化
2.3会话
-
概念
在Web中,会话表示从浏览器打开某个网站,在这个网站中无论操作了什么,直到关闭浏览器,这一个过程,称之为一个会话。
-
怎样算会话结束
- 客户端关闭了
- 服务器销毁了
-
为什么要处理会话
长期保持会话,无论用户关闭多少次浏览器,这个会话都存在(如虎牙的一个月免登录)
-
保存会话的两种机制
-
Cookie:
Cookie是客户端机制,程序把每个用户的数据以cookie的形式写给用户各自的浏览器。当用户使用浏览器再去访问服务器中的web资源时,就会带着各自的数据去。这样,web资源处理的就是用户各自的数据了
好比超市给用户的会员卡,下次带去就知道之前来过
-
Session
Session是服务器端技术,利用这个机制,服务器在运行时可以为每一个用户的浏览器创建一个其独享的session对象,由于session为用户浏览器独享,所以用户在访问服务器的web资源时,可以把各自的数据放在各自的session中,当用户再去访问服务器中的其它web资源时,其它web资源再从用户各自的session中取出数据为用户服务。
好比超市在自己的系统上保存了用户的信息,用户下次去直接说会员名就行
-
2.3.1Cookie
cookie: - -般会保存在本地的用户目录下appdata;
构造器:
Cookie cookie = new Cookie(String name,String value);
服务器响应Cookie给客户端:
response.addCookie(Cookie);
服务器查看用户带来的请求是否有Cookie
Cookie[] cookies = Request.getCookie();
//可以使用cookie来验证用户是否来过
//判断cookies是否为空,然后遍历即可
Cookie.getName();
Cookie.getValue();
Cookie测试用户是否来过
package com.example01;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import jakarta.servlet.annotation.*;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
@WebServlet("/c1")
public class ResponseHTMLServlet extends HttpServlet {
Boolean flag = false;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//避免乱码问题:
req.setCharacterEncoding("UTF-8");
resp.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=UTF-8");
PrintWriter out = resp.getWriter();
System.out.println("1");
//通过请求获取用户的Cookie
Cookie[] cookies = req.getCookies();
if (flag){
//flag=true,表示用户不是第一次访问该url
if (cookies!=null){
//你有cookie
for (int i = 0; i < cookies.length ; i++) {
Cookie cookie = cookies[i];
if (cookie.getName().equals("lastLoginTime")){
long lastLoginTime = Long.parseLong(cookie.getValue());
Date date = new Date(lastLoginTime);
resp.getWriter().println("你上一次来的时间为:"+cookie.getValue());
out.write(date.toString());
}
}
}
}else {
//flag=false,表示用户是第一次访问该url
out.write("这是您第一次访问该页面");
}
//建立一个cookie,并把这个cookie发给客户端
resp.addCookie(new Cookie("lastLoginTime",System.currentTimeMillis()+""));
//将flag置为true,当用户再次访问该url时,会直接进入读取cookie的逻辑
flag = true;
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
}
2.3.2Session
Session
是服务器端技术,默认情况下,一个浏览器独占一个session
对象。因此,在需要保存用户数据时,服务器程序可以把用户数据写到用户浏览器独占的session
中,当用户使用浏览器访问其它程序时,其它程序可以从用户的session
中取出该用户的数据,为用户服务。可以通俗的理解为,一个用户可以通过一个Session
访问多个Web资源,且各个Web资源可以通过Session
读取保存的用户数据。
Session
实现原理:服务器创建session
出来后,会把session
的id号,以cookie
的形式回写给客户机,这样,只要客户机的浏览器不关,再去访问服务器时,都会带着session
的id
号去,服务器通过识别客户机浏览器的session_id
,就会使用内存中与之对应的session
为之服务。事实上,只要客户端一旦连接上服务器,服务器就会自动产生Session,Session可以在一个会话中传递数据(即多个程序通过session获取数据),如果服务器重启,存储在session中的数据就会丢失。
获取Session对象
如何注销Session?
session对象默认30分钟没有使用,则服务器会自动销毁session
可以使用以下两种方式注销Session:
- 需要在程序中手动设置Session失效时,通过invalidate();注销当前Session。
request.getSession().invalidate();
- 在
web.xml
文件中配置session的失效时间 :<!-- 设置Session的有效时间:以分钟为单位--> <session-config> <session-timeout>15</session-timeout> </session-config>
使用场景:
●保存一个登录用户的信息;
●购物车信息;
●在整个网站中经常会使用的数据,我们将它保存在Session中;
Session和cookie的区别
Cookie
是把用户的数据写给用户的浏览器,属于客户端技术。
Session
是把用户的数据写到用户独占的session
中,属于服务端技术。
Session
对象由服务器创建,开发人员可以调用request
对象的getSession
方法得到session
对象。
2.3.3作用域
2.4PrintWriter
PrintWriter是一个用于创建和写入文件的 Java 类。它可以用来输出不同类型的数据,从基本类型如数字、文本,到数组和对象
package com.example01;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/example01/responsehtml")
public class ResponseHTMLServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setCharacterEncoding("UTF-8");
resp.getWriter()
.append("<!DOCTYPE html>\n")
.append("<html\">\n")
.append("<head>\n")
.append("<meta charset=UTF-8>\n")
.append("<title>Web开发技术</title>\n")
.append("</head>\n")
.append("<body><h1>Web开发技术</h1></body></html>");
}
}
举例
package com.example01;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@WebServlet("/responsehtml")
public class ResponseHTMLServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setCharacterEncoding("UTF-8");
PrintWriter writer = resp.getWriter();
writer.print("hello");
}
}