servlet:
什么是servlet?
Servlet是用来处理客户端请求并产生动态网页内容的Java类
- 概念:Java Servlet 是运行在 Web 服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层。
- 定位:Java Servlet用Java编写的服务器端程序(web application)。
- 作用:其主要功能在于交互式地浏览和修改数据,生成动态Web内容。
- 理解:狭义的Servlet是指Java语言实现的一个接口,广义的Servlet是指任何实现了这个Servlet接口的类,一般情况下,我们将Servlet理解为后者。
注意IDEA中web项目部署中tomcat的配置,配置成功后,使用debug方式启动tomcat,同时也可以使用一些抓包工具,例如谷歌浏览器自身的抓包工具(开发者工具),postman,fiddler等
servlet对象的生命周期:
tomcat和servlet的关系tomcat属于web服务器,也称为servlet容器
如何定位后端资源?
url查找过程?(假设要去北京某个银行的某个营业厅办理转账业务)
- ip对应主机地址(对应北京)
- port对应进程(对应某个楼)
- 应用上下文路径对应项目(对应营业厅)
- uri对应项目中的资源(对应营业厅中多个窗口提供的服务)
浏览器向web服务器发送请求,首先根据ip、端口号找到远程某一台主机上tomcat进程,根据应用上下文路径去访问某一个对应项目,再根据uri定位到项目中提供的某个资源,找到后向浏览器返回资源
服务端: 存在服务器(软件系统、提供服务的程序),如数据库服务器、web服务器
用途:提供服务功能(服务器不同提供的功能不同)
- 数据库服务器:提供数据存储,数据处理操作的服务
- web服务器:提供http服务
提供服务的方式:通过网络(可以远程、也可以是本机)
存在请求、处理、响应
uri映射资源:
1.静态资源文件2.程序提供的资源(servlet的路径及http请求响应资源)
转发和重定向:
1. 重定向:返回3xx状态码+Location响应头,表示要跳转的路径,浏览器接收到响应数据后自动跳转2 .转发:一次请求,后端接收直接把转发路径的资源作为响应体返回
区别:
1.看url路径是否改变:重定向会改变,转发不会2.看网络发起请求的次数:重定向两次,转发一次
if ("abc".equals(u) && "123".equals(p)) {
//发送重定向:http响应状态码设置为301/302/307/,响应头为Location
resp.sendRedirect("home.html"); //返回当前请求的响应数据
} else if ("abc".equals(u)) {
//转发
req.getRequestDispatcher("home.html").forward(req,resp);
}
- 在登录页面输入账号密码,当账号密码都输入正确时进入重定向代码块发起两次请求,路径改变
- 当只是输入正确的账号时,进入转发代码块,发起一次请求,路径不改变
实现页面不跳转的刷新(home.html),刷新后隐藏登录框
代码实现:
home.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>home</title>
<script src="js/jquery@3.3.1/jquery.js"></script>
<script>
$(function () { //页面加载完成后开始执行
$("#loginBtn").click(function () { //按钮绑定点击事件
$.ajax({
type:"post",
url:"loginJSON",
dataType:"json", //响应体中的数据格式 json格式
data:{ //提交的请求数据
username:$("#username").val(),
password:$("#password").val(),
},
success(r) {
//alert(JSON.stringify(r))
if (r.success) { //如果成功就隐藏
$("#container").hide();
} else { //提示错误
alert("用户名或密码错误")
}
}
})
})
});
</script>
</head>
<body>
<div id="container">
<!--文本框 type="text" name表示请求数据的键-->
用户名: <input id="username" type="text" name="username"><br>
密码: <input id="password" type="password" name="password"><br>
<!--submit 提交按钮 button 普通按钮-->
<input id="loginBtn" type="button" value="登录"><br>
</div>
<p>第一篇文章</p>
<p>第二篇文章</p>
</body>
</html>
LoginJSONServlet:
package org.example.servlet;
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.io.IOException;
import java.io.PrintWriter;
//注解 后面一定要加上属性,属性名为value时可以不写
//小括号包裹多个属性,属性名=属性值,多个之间逗号间隔
//例如:@WebServlet(value={"",""},name="")
//Servlet定义服务:注意服务路径必须时 / 开头,否则tomcat启动会报错 -- 对应uri
@WebServlet("/loginJSON")
public class LoginJSONServlet extends HttpServlet {
//重写方法 提供服务
//注意get和post的区别
/**
* 每次http请求映射到某个Servlet的资源路径,都会调用service生命周期方法
* 如果请求方法没有重写,就调用父类的doXX方法(对应的请求方法),返回405
* 如果重写,会将请求数据包装为Request对象,这时候虽然还没有响应,但是也包装了一个Response响应对象
*/
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置响应请求,响应编码及响应数据类型(为响应体设置Content-Type数据类型)
req.setCharacterEncoding("UTF-8"); //设置请求体编码
resp.setCharacterEncoding("UTF-8");
resp.setContentType("application/json"); //响应格式
//解析请求数据
//req.getParameter()方法获取请求数据:url和请求体,数据格式为k1=v1&k2=v2
String u = req.getParameter("username");
String p = req.getParameter("password");
System.out.printf("===================用户名(%s) 密码(%s) %n",u,p);
//返回响应数据
PrintWriter pw = resp.getWriter(); //response获取io输出流
if ("abc".equals(u) && "123".equals(p)) {
pw.println("{\"success\":true}");
} else {
pw.println("{\"success\":false}");
}
pw.flush(); //有缓冲的io操作,需要刷新缓冲区,才会真正的发送数据 缓冲刷新
pw.close(); //io流操作完,一定要记得关闭资源
}
}
实现的页面结果
代码
Servlet:
Login301Servlet:
package org.example.servlet;
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.io.IOException;
import java.io.PrintWriter;
//注解 后面一定要加上属性,属性名为value时可以不写
//小括号包裹多个属性,属性名=属性值,多个之间逗号间隔
//例如:@WebServlet(value={"",""},name="")
//Servlet定义服务:注意服务路径必须时 / 开头,否则tomcat启动会报错 -- 对应uri
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
//重写方法 提供服务
//注意get和post的区别
/**
* 每次http请求映射到某个Servlet的资源路径,都会调用service生命周期方法
* 如果请求方法没有重写,就调用父类的doXX方法(对应的请求方法),返回405
* 如果重写,会将请求数据包装为Request对象,这时候虽然还没有响应,但是也包装了一个Response响应对象
*/
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置响应请求,响应编码及响应数据类型(为响应体设置Content-Type数据类型)
req.setCharacterEncoding("UTF-8"); //设置请求体编码
resp.setCharacterEncoding("UTF-8");
resp.setContentType("text/html");
//解析请求数据
//req.getParameter()方法获取请求数据:url和请求体,数据格式为k1=v1&k2=v2
String u = req.getParameter("username");
String p = req.getParameter("password");
System.out.printf("===================用户名(%s) 密码(%s) %n",u,p);
//返回响应数据
PrintWriter pw = resp.getWriter(); //response获取io输出流
pw.println("登录成功");
pw.println("<h3>欢迎您, " + u +"</h3>");
pw.flush(); //有缓冲的io操作,需要刷新缓冲区,才会真正的发送数据 缓冲刷新
pw.close(); //io流操作完,一定要记得关闭资源
}
}
LoginServlet:
package org.example.servlet;
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.io.IOException;
import java.io.PrintWriter;
//注解 后面一定要加上属性,属性名为value时可以不写
//小括号包裹多个属性,属性名=属性值,多个之间逗号间隔
//例如:@WebServlet(value={"",""},name="")
//Servlet定义服务:注意服务路径必须时 / 开头,否则tomcat启动会报错 -- 对应uri
@WebServlet("/login301")
public class Login301Servlet extends HttpServlet {
//重写方法 提供服务
//注意get和post的区别
/**
* 每次http请求映射到某个Servlet的资源路径,都会调用service生命周期方法
* 如果请求方法没有重写,就调用父类的doXX方法(对应的请求方法),返回405
* 如果重写,会将请求数据包装为Request对象,这时候虽然还没有响应,但是也包装了一个Response响应对象
*/
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置响应请求,响应编码及响应数据类型(为响应体设置Content-Type数据类型)
req.setCharacterEncoding("UTF-8"); //设置请求体编码
resp.setCharacterEncoding("UTF-8");
resp.setContentType("text/html");
//解析请求数据
//req.getParameter()方法获取请求数据:url和请求体,数据格式为k1=v1&k2=v2
String u = req.getParameter("username");
String p = req.getParameter("password");
System.out.printf("===================用户名(%s) 密码(%s) %n",u,p);
if ("abc".equals(u) && "123".equals(p)) {
//发送重定向:http响应状态码设置为301/302/307/,响应头为Location
resp.sendRedirect("home.html"); //返回当前请求的响应数据
} else if ("abc".equals(u)) {
//转发
req.getRequestDispatcher("home.html").forward(req,resp);
} else {
//返回响应数据
PrintWriter pw = resp.getWriter(); //response获取io输出流
pw.println("登录失败");
pw.println("<h3>用户名: " + u +"或密码错误</h3>");
pw.flush(); //有缓冲的io操作,需要刷新缓冲区,才会真正的发送数据 缓冲刷新
pw.close(); //io流操作完,一定要记得关闭资源
}
}
}
HTML:
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<!--页面跳转-->
<a href="login.html">注册/登录</a><br>
<a href="home.html">跳转到主页</a><br>
哈喽
</body>
</html>
login.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登录</title>
</head>
<body>
<hr> <!--分割线-->
请求login<br>
<form method="post" action="login">
<!--文本框 type="text" name表示请求数据的键-->
用户名: <input type="text" name="username"><br>
密码: <input type="password" name="password"><br>
<!--submit 提交按钮 button 普通按钮-->
<input type="submit" value="登录"><br>
</form>
<hr>
请求/login301<br>
<form method="post" action="login301">
<!--文本框 type="text" name表示请求数据的键-->
用户名: <input type="text" name="username"><br>
密码: <input type="password" name="password"><br>
<!--submit 提交按钮 button 普通按钮-->
<input type="submit" value="登录"><br>
</form>
<hr>
</body>
</html>
Servlet依赖包配置:
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>