Servlet
概念
Servlet就是一个接口,定义了Java被浏览器访问到(tomcat识别)的规则。
自定义一个类,实现Servlet接口,复写方法。
快速入门
- 创建JavaEE项目
- 定义一个类,实现Servlet接口
- 实现接口中的抽象方法
- 配置Servlet
在web.xml中配置:
<!-- 配置servlet-->
<servlet>
<servlet-name>demo1</servlet-name>
<servlet-class>nuc.servlet.ServletDemo1</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>demo1</servlet-name>
<url-pattern>/demo1</url-pattern>
</servlet-mapping>
Servlet中的生命周期:
- 被创建:执行init方法,只执行一次
- 提供服务:执行servlet方法,执行多次
- 被销毁:执行destroy方法,只执行一次
Servlet3.0:支持注解配置,不需要web.xml
- 在类上使用@webServlet注解,进行配置
@WebServlet("资源路径")
@WebServlet("/demo")
public class ServletDemo implements Servlet {
@Override
public void init(ServletConfig servletConfig) throws ServletException {
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("servlet4.0!");
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
HttpServlet
HttpServlet:对http协议的一种封装,简化操作
- 定义类继承HttpServlet
- 重写doGet / doPost方法
@WebServlet("/demo")
public class ServletDemo extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doGet(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
}
HTTP
概念:Hyper Text Transfer Protocol 超文本传输协议
传输协议:定义了客户端和服务端通信时,发送数据的格式
特点:
- 基于TCP / IP 的高级协议
- 默认端口号:80
- 基于请求 / 响应模型的:一次请求对应一次响应
- 无状态的:每次请求之间相互独立,不能交互数据
历史版本:
1.0:每一次请求响应都会建立新的连接
1.1:复用连接
请求消息数据格式
-
请求行
请求方式 请求url 请求协议/版本htmlGET / login.html HTTP/1.1
请求方式:
get:- 请求参数在请求行中,在url后
- 请求的url长度是有限的
- 不太安全
post:
- 请求参数在请求体中
- 请求的url长度没有限制
- 相对安全
-
请求头
请求头名称:请求头值
常见的请求头:-
user-agent
:浏览器告诉服务器,我访问你使用的浏览器版本信息可以在服务器端获取该头的信息,解决浏览器的兼容问题
String agent = request.getHeader("user-agent"); if (agent.contains("Chrome")){ // 谷歌浏览器的操作 System.out.println("谷歌来了..."); } else if (agent.contains("Chrome")){ // 火狐浏览器操作 }
-
referer
:告诉服务器,我(当前请求)从哪里来作用:防盗链,统计工作
-
login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>login</title>
</head>
<body>
<a href="/RequestDemo2"></a>
</body>
</html>
RequestDemo2.java
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String referer = request.getHeader("referer");
response.setContentType("text/html;charset=utf-8");
// 判断是否盗链
if (referer != null) {
if (referer.contains("/myapp")) {
response.getWriter().write("来看电影~");
} else {
response.getWriter().write("盗链可耻!");
}
}
}
- 请求空行
空行,就是用于分割POST请求的请求头,和请求体的 - 请求体
封装post请求消息的请求参数的
Request
request对象是来获取请求消息,response对象是来设置响应消息
获取请求消息
- 获取请求行数据
// 获取请求方式 GET String method = request.getMethod(); System.out.println(method); // (*)获取虚拟目录 /Servlet_war_exploded String contextPath = request.getContextPath(); System.out.println(contextPath); // 获取Servlet路径 /RequestDemo1 String servletPath = request.getServletPath(); System.out.println(servletPath); // 获取get方式请求参数 name=zhangsan String queryString = request.getQueryString(); System.out.println(queryString); // (*) 获取请求URI /Servlet_war_exploded/RequestDemo1 String requestURI = request.getRequestURI(); System.out.println(requestURI); // 获取请求URL http://localhost:8080/Servlet_war_exploded/RequestDemo1 StringBuffer requestURL = request.getRequestURL(); System.out.println(requestURL); // 获取协议及版本 HTTP/1.1 String protocol = request.getProtocol(); System.out.println(protocol); // 获取客户机的IP地址 0:0:0:0:0:0:0:1 String remoteAddr = request.getRemoteAddr(); System.out.println(remoteAddr);
- 获取请求头数据
// 演示获取请求头数据 Enumeration<String> headerNames = request.getHeaderNames(); // 获取所有的请求头名称 while(headerNames.hasMoreElements()){ String name = headerNames.nextElement(); String value = request.getHeader(name); // 通过请求头的名称获取请求头的值 System.out.println(name + ":" + value); }
- 获取请求体数据
请求体:只有post请求方式,才有请求体,在请求体中封装了post请求的请求参数
步骤:- 获取流对象
- 再从流对象中拿数据
regist.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>regist</title>
</head>
<body>
<form action="/demo" method="post">
用户名<input type="text" name="username"><br/>
密码<input type="text" name="password"><br/>
<input type="submit" value="提交"><br/>
</form>
</body>
</html>
demo.java
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
BufferedReader br = req.getReader();
String line = null;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
}
- 其他功能:不论还是post请求方式都可使用下列方法来获取请求参
获取请求参数通用方式
RequestDemo5.java
@WebServlet("/requestDemo5")
public class RequestDemo5 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// post 获取请求参数
request.setCharacterEncoding("utf-8");
// 根据参数名称获取参数值
String username = request.getParameter("username");
System.out.println(username);
System.out.println("------------------------");
// 根据参数名称获取参数值的数组
String[] hobbies = request.getParameterValues("hobby");
for (String hobby : hobbies) {
System.out.println(hobby);
}
System.out.println("-------------------------");
// 获取所有请求的参数名称
Enumeration<String> parameterNames = request.getParameterNames();
while (parameterNames.hasMoreElements()) {
String name = parameterNames.nextElement();
System.out.println(name);
}
System.out.println("-------------------------");
// 获取所有参数的map集合
Map<String, String[]> parameterMap = request.getParameterMap();
// 遍历
Set<String> keySet = parameterMap.keySet();
for (String name : keySet) {
// 获取键获取值
String[] values = parameterMap.get(name);
System.out.println(name);
for (String value :values) {
System.out.println(value);
}
System.out.println("----------------------------");
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
regist.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>regist</title>
</head>
<body>
<form action="/day15/requestDemo5" method="post">
用户名<input type="text" name="username"><br/>
密码<input type="text" name="password"><br/>
<input type="checkbox" name="hobby" value="game">游戏
<input type="checkbox" name="hobby" value="study">学习
<input type="submit" value="注册"><br/>
</form>
</body>
</html>
- 中文乱码问题:
get:tomcat 8 已经将get方式乱码问题解决了
pos:会乱码
解决:在获取参数前,设置request的编码:request.setCharacterEncoding("utf-8");
请求转发
请求转发:一种在服务器内部的资源跳转方式
RequestDemo3.java
@WebServlet("/RequestDemo3")
public class RequestDemo3 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("333被访问了");
// 转发到demo4资源
request.getRequestDispatcher("/RequestDemo4").forward(request,response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
}
}
RequestDemo4.java
@WebServlet("/RequestDemo4")
public class RequestDemo4 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("444被访问了");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
}
}
特点:
- 浏览器地址栏路径不发生变化
- 只能转发到当前服务器内部资源中
- 转发是一次请求
共享数据
域对象:一个有作用范围的对象,可以在范围内共享数据
request域:代表一次请求的范围,一般用于请求转发的多个资源中共享数据
RequestDemo3.java
@WebServlet("/RequestDemo3")
public class RequestDemo3 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 存储数据到request域中
request.setAttribute("msg", "hello");
// 转发到demo4资源
request.getRequestDispatcher("/RequestDemo4").forward(request,response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
}
}
RequestDemo4.java
@WebServlet("/RequestDemo4")
public class RequestDemo4 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 获取数据
Object msg = request.getAttribute("msg");
System.out.println(msg);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
}
}
获取ServletContext
ServletContext servletContext = request.getServletContext();
System.out.println(servletContext);
Response
HTTP协议
- 请求消息:客户端发送给服务器端的数据
数据格式:- 请求行
- 请求头
- 请求空行
- 请求体
- 响应消息:服务器端发送给客户端的数据
数据格式:- 响应行
- 组成:协议/版本 响应状态码 状态码描述
- 响应状态码:服务器告诉客户端浏览器本次请求和响应的一个状态
分类:- 1xx:服务器接收客户端信息,但没有接收完成,等待一段时间后,发送1xx多状态码
- 2xx:成功。200
- 3xx:重定向。302(重定向),304(访问缓存)
- 4xx:客户端错误。404(请求路径没有对应的资源),405(请求方式没有对应的doXxx方法)
- 5xx:服务器端错误。500(服务器内部出现异常)
- 响应头
- 格式:头名称:值
- 常见的响应头:
- content-type:服务器告诉客户端本次响应体数据格式以及编码格式
- content-disposition:服务器告诉客户端以什么格式打开响应体数据
in-line:默认值,在当前界面内打开
attachment;filename=xxx:以附件形式打开响应体。文件下载
- 响应空行
- 响应体
- 响应行
Response对象
功能:设置响应消息
-
设置响应行
- 格式:
HTTP/1.1 200 ok
- 设置状态码:
setStatus(itn sc)
- 格式:
-
设置响应头
setHeader(String name, String value)
-
设置响应体
步骤:- 获取输出流
- 使用输出流,将数据输出到客户端浏览器
案例
完成重定向
重定向:资源跳转的方式
@WebServlet("/responseDemo1")
public class ResponseDemo1 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("demo1...");
// 访问ResponseDemo1,直接跳转到responseDemo2
// 设置状态码为302
/*response.setStatus(302);
// 设置响应头为location
response.setHeader("location", "/day15/responseDemo2");*/
// 简单的重定向方法
response.sendRedirect("/day15/responseDemo2");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
}
}
重定向的特点:(redirect)
- 地址栏发生变化
- 重定向可以访问其他站点(服务器)的资源
- 重定向是两次请求
转发的特点:(forward)
- 转发地址栏路径不变
- 转发只能访问当前服务器下的资源
- 转发是一次请求
考点:
forward 和 redirect
的区别
路径的写法
路径分类:
- 相对路径:通过相对路径不可以确定唯一资源
如:./index.html
规则:找到当前资源和目标资源之间的相对位置关系
./
:当前目录
../
:后退一级目录 - 绝对路径:通过绝对路径可以确定唯一资源
如:http://localhost:8080/day15/responseDemo2
,/day15/responseDemo2
规则:判断定义的路径是给谁用的?判断请求将来从哪儿发出.-
给客户端浏览器使用:需要加虚拟目录(项目的访问路径)
建议虚拟目录动态获取:
request.getContextPath()
-
给服务器使用:不需要加虚拟目录(用于转发路径)
-
服务器输出字符数据到浏览器
@WebServlet("/responseDemo3")
public class ResponseDemo3 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 首先设置编码格式
response.setContentType("text/html;charset=utf-8");
// 1. 获取字符输出流
PrintWriter pw = response.getWriter();
// 2. 输出数据
pw.write("你好");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
}
}
注意:乱码问题
PrintWriter pw = response.getWriter();
获取的流的默认编码是ISO-8859-1
- 设置该流的默认编码
- 告诉浏览器响应体使用的编码:
response.setContentType("text/html;charset=utf-8");
服务器输出字节数据到浏览器
@WebServlet("/responseDemo4")
public class ResponseDemo4 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
// 1. 获取字节输出流
ServletOutputStream sos = response.getOutputStream();
// 2. 输出数据
sos.write("你好".getBytes("utf-8"));
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
}
}
验证码
register.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script>
/**
* 分析:
* 1. 给图片绑定单击事件
* 2. 重新设置图片的src属性值
*/
window.onload = function () {
var img = document.getElementById("checkCode");
img.onclick = function () {
// 加时间戳
var date = new Date().getTime();
img.src = "/day15/checkCodeServlet?"+date;
}
}
</script>
</head>
<body>
<img id="checkCode" src="/day15/checkCodeServlet"/>
</body>
</html>
CheckCodeServlet.java
import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;
@WebServlet("/checkCodeServlet")
public class CheckCodeServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
int width = 100;
int height = 50;
// 1. 创建一对象,在内存中图片
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
// 2. 美化图片
// 2.1 填充背景色
Graphics g = image.getGraphics();
g.setColor(Color.PINK);
g.fillRect(0,0,width,height);
// 2.2 画边框
g.setColor(Color.BLUE);
g.drawRect(0,0,width - 1, height - 1);
String str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
// 生成随机坐标
Random random = new Random();
for (int i = 1; i <=4 ; i++) {
int index = random.nextInt(str.length());
// 获取字符
char ch = str.charAt(index);
// 2.3 写验证码
g.drawString(ch + "", width / 5 * i, height / 2);
}
// 2.4 画干扰线
g.setColor(Color.GREEN);
// 随机生成坐标点
for (int i = 0; i < 10; i++) {
int x1 = random.nextInt(width);
int x2 = random.nextInt(width);
int y1 = random.nextInt(height);
int y2 = random.nextInt(height);
g.drawLine(x1,y1,x2,y2);
}
// 3. 将图片输出到页面展示
ImageIO.write(image,"jpg", response.getOutputStream());
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
ServletContext对象
概念:代表整个web应用,可以和程序的容器(服务器)来通信
获取:
// 1. 通过request对象获取
ServletContext context1 = request.getServletContext();
// 2. 通过HttpServlet获取
ServletContext context2 = this.getServletContext();
功能:
- 获取MIME类型
1. MIME类型:在互联网通信过程中定义的一种文件数据类型
2. 格式: 大类型 / 小类型text/html
,image/jpeg
3. 获取:
// 定义文件名称
String filename = "a.jpg";
// 获取MIME类型
String mimeType = context2.getMimeType(filename);
System.out.println(mimeType); // image/jpeg
- 域对象:共享数据
ServletContextDemo2.java
@WebServlet("/servletContextDemo2")
public class ServletContextDemo2 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 通过HttpServlet获取
ServletContext context = this.getServletContext();
// 设置数据
context.setAttribute("msg", "haHa");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
ServletContextDemo3.java
@WebServlet("/servletContextDemo3")
public class ServletContextDemo3 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 通过HttpServlet获取
ServletContext context = this.getServletContext();
// 获取数据
Object msg = context.getAttribute("msg");
System.out.println(msg);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
- ServletContext对象范围:所有用户所有请求的数据
- 获取文件的真实(服务器)路径
// 通过HttpServlet获取
ServletContext context = this.getServletContext();
// 获取文件的服务器路径
String realPath = context.getRealPath("/b.txt"); // web目录下资源访问
System.out.println(realPath);
String realPath1 = context.getRealPath("/WEB-INF/c.txt"); // WEB-INF目录下的资源访问
System.out.println(realPath1);
String realPath2 = context.getRealPath("/WEB-INF/classes/a.txt"); // src目录下的资源访问
System.out.println(realPath2);
以上为个人学习笔记,参考自黑马教程,若有雷同,纯属巧合。