Servlet & HTTP & Request
1、Servlet 体系结构
Servlet -- 接口
|
GenericServlet -- 抽象类
|
HttpServlet -- 抽象类
-
GenericServlet:将 Servlet 接口中其他的方法做了默认空实现,只将 service() 方法作为抽象 将来定义 Servlet 类时,可以继承 GenericServlet,实现 service() 方法即可。 package com.example.servlet_http;
import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebServlet;
import java.io.IOException;
@WebServlet("/demo02")
public class ServletDemo2 extends GenericServlet {
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("demo02...");
}
}
-
HttpServlet:对 http 协议的一种封装,简化操作
- 定义类继承 HttpServlet
- 复写
doGet/doPost 方法 package com.example.servlet_http;
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;
@WebServlet("/demo03")
public class ServletDemo3 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......");
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/li/demo03" method="post">
<input name="username">
<input type="submit" value="提交">
</form>
</body>
</html>
2、HTTP
2.1、概念
Hyper Text Transfer Protocol 超文本传输协议
- 传输协议:定义了,客户端和服务器端通信时,发送数据的格式
- 特点:
- 基于 TCP/IP 的高级协议
- 默认端口号:80
- 基于请求/响应模型的:一次请求对应一次响应
- 无状态的:每次请求之间相互独立,不能交互数据
- 历史版本
- 1.0:每一次请求响应都会建立新的连接
- 1.1:复用连接
2.2、请求消息数据格式
字符串形式:
POST /login.html HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Referer: http://localhost/login.html
Connection: keep-alive
Upgrade-Insecure-Requests: 1
username=zhangsan
2.2.1、请求行
请求方式 请求url 请求协议/版本
GET /login.html HTTP/1.1
2.2.2、请求头:客户端浏览器告诉服务器一些信息
请求头名称: 请求头值
-
常见的请求头:
-
User-Agent:浏览器告诉服务器,我访问你使用的浏览器版本信息 可以在服务器端获取该头的信息,解决浏览器的兼容性问题 -
Referer:http://localhost/login.html 告诉服务器,我(当前请求)从哪里来? 作用:
- 防盗链;
- 统计工作。
2.2.3、请求空行
空行,就是用于分割 POST 请求的请求头,和请求体的。
2.2.4、请求体(正文)
封装 POST 请求消息的请求参数的。
3、Request
3.1、request 对象和 response 对象的原理
- request 和 response 对象是由服务器创建的。我们来使用它们;
- request 对象是来获取请求消息,response 对象是来设置响应消息。
3.2、request 对象继承体系结构
ServletRequest -- 接口
| 继承
HttpServletRequest -- 接口
| 实现
org.apache.catalina.connector.RequestFacade 类(tomcat)
3.3、request 功能
3.3.1、获取请求消息数据
-
获取请求行数据 GET /day14/demo1?name=zhangsan HTTP/1.1 方法:
-
获取请求方式 :GET String getMethod() -
(*)获取虚拟目录:/day14 String getContextPath() -
获取 Servlet 路径: /demo1 String getServletPath() -
获取 get 方式请求参数:name=zhangsan String getQueryString() -
(*)获取请求 URI:/day14/demo1 String getRequestURI() :/day14/demo1 StringBuffer getRequestURL() :http://localhost/day14/demo1
- URL:统一资源定位符 : http://localhost/day14/demo1 范围更小
- URI:统一资源标识符 : /day14/demo1 范围更大
-
获取协议及版本:HTTP/1.1 String getProtocol() -
获取客户机的 IP 地址: String getRemoteAddr() package com.example.request;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
@WebServlet(name = "RequestDemo1", value = "/RequestDemo1")
public class RequestDemo1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String method = request.getMethod();
System.out.println(method);
String contextPath = request.getContextPath();
System.out.println(contextPath);
String servletPath = request.getServletPath();
System.out.println(servletPath);
String queryString = request.getQueryString();
System.out.println(queryString);
String requestURI = request.getRequestURI();
System.out.println(requestURI);
StringBuffer requestURL = request.getRequestURL();
System.out.println(requestURL);
String protocol = request.getProtocol();
System.out.println(protocol);
String remoteAddr = request.getRemoteAddr();
System.out.println(remoteAddr);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
GET
/li
/RequestDemo1
null
/li/RequestDemo1
http://localhost/li/RequestDemo1
HTTP/1.1
127.0.0.1
-
获取请求头数据 方法:
package com.example.request;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
import java.util.Enumeration;
@WebServlet(name = "RequestDemo2", value = "/RequestDemo2")
public class RequestDemo2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()){
String name = headerNames.nextElement();
String value = request.getHeader(name);
System.out.println(name + "---"+ value);
}
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
host---localhost
user-agent---Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:93.0) Gecko/20100101 Firefox/93.0
accept---text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,* 更具体的演示: package com.example.request;
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.util.Enumeration;
@WebServlet(name = "RequestDemo3", value = "/RequestDemo3")
public class RequestDemo3 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String agent = request.getHeader("user-agent");
if (agent.contains("Chrome")){
System.out.println("谷歌来了...");
}else if (agent.contains("Firefox")){
System.out.println("火狐来了...");
}
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
package com.example.request;
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;
@WebServlet(name = "RequestDemo4", value = "/RequestDemo4")
public class RequestDemo4 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String referer = request.getHeader("referer");
System.out.println(referer);
if (referer != null){
if (referer.contains("/li")){
System.out.println("正常访问,播放电影...");
}else {
System.out.println("想看电影吗?");
}
}
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
-
获取请求体数据 请求体:只有 POST 请求方式,才有请求体,在请求体中封装了 POST 请求的请求参数。 步骤:
-
获取流对象 BufferedReader getReader() :获取字符输入流,只能操作字符数据 ServletInputStream getInputStream() :获取字节输入流,可以操作所有类型数据 -
再从流对象中拿数据 package com.example.request;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.BufferedReader;
import java.io.IOException;
@WebServlet(name = "RequestDemo5", value = "/RequestDemo5")
public class RequestDemo5 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
BufferedReader br = request.getReader();
String line = null;
while ((line = br.readLine()) != null){
System.out.println(line);
}
}
}
3.3.2、其他功能
-
获取请求参数通用方式:不论 get 还是 post 请求方式都可以使用下列方法来获取请求参数
String getParameter(String name) :根据参数名称获取参数值 username=zs&password=123 String[] getParameterValues(String name) :根据参数名称获取参数值的数组 hobby=xx&hobby=game Enumeration<String> getParameterNames() :获取所有请求的参数名称Map<String,String[]> getParameterMap() :获取所有参数的 map 集合 <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>注册页面</title>
</head>
<body>
<form action="/li/RequestDemo6" method="get">
<input type="text" placeholder="请输入用户名" name="username"><br>
<input type="text" placeholder="请输入密码" name="password"><br>
<input type="checkbox" name="hobby" value="game">游戏
<input type="checkbox" name="hobby" value="study">学习
<br>
<input type="submit" value="注册">
</form>
</body>
</html>
package com.example.request;
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.BufferedReader;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Map;
import java.util.Set;
@WebServlet(name = "RequestDemo6", value = "/RequestDemo6")
public class RequestDemo6 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = request.getParameter("username");
String[] hobbies = request.getParameterValues("hobby");
Enumeration<String> parameterNames = request.getParameterNames();
Map<String, String[]> parameterMap = request.getParameterMap();
Set<String> keySet = parameterMap.keySet();
for (String name :
keySet) {
String[] values = parameterMap.get(name);
for (String value :
values) {
System.out.println(value);
}
System.out.println("-----------------------");
}
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = request.getParameter("username");
String[] hobbies = request.getParameterValues("hobby");
for (String hobby:hobbies
) {
System.out.println(hobby);
}
Enumeration<String> parameterNames = request.getParameterNames();
while (parameterNames.hasMoreElements()){
String name = parameterNames.nextElement();
System.out.println(name);
String value = request.getParameter(name);
System.out.println(value);
System.out.println("----------------------");
}
Map<String, String[]> parameterMap = request.getParameterMap();
Set<String> keySet = parameterMap.keySet();
for (String name :
keySet) {
String[] values = parameterMap.get(name);
for (String value :
values) {
System.out.println(value);
}
System.out.println("-----------------------");
}
}
}
中文乱码问题:
-
请求转发:一种在服务器内部的资源跳转方式
- 步骤:
- 通过 request 对象获取请求转发器对象:
RequestDispatcher getRequestDispatcher(String path) - 使用 RequestDispatcher 对象来进行转发:
forward(ServletRequest request, ServletResponse response) - 特点:
- 浏览器地址栏路径不发生变化;
- 只能转发到当前服务器内部资源中;
- 转发是一次请求。
-
共享数据: 域对象:一个有作用范围的对象,可以在范围内共享数据。 request 域:代表一次请求的范围,一般用于请求转发的多个资源中共享数据。 方法:
void setAttribute(String name,Object obj) :存储数据Object getAttitude(String name) :通过键获取值void removeAttribute(String name) :通过键移除键值对 package com.example.request;
import javax.servlet.RequestDispatcher;
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.util.Enumeration;
import java.util.Map;
import java.util.Set;
@WebServlet(name = "RequestDemo8", value = "/RequestDemo8")
public class RequestDemo8 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("demo88888被访问了......");
request.setAttribute("msg", "hello");
request.getRequestDispatcher("/RequestDemo9").forward(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("demo88888被访问了......");
request.setAttribute("msg", "hello");
request.getRequestDispatcher("/RequestDemo9").forward(request, response);
}
}
package com.example.request;
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.util.Enumeration;
import java.util.Map;
import java.util.Set;
@WebServlet(name = "RequestDemo9", value = "/RequestDemo9")
public class RequestDemo9 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Object msg = request.getAttribute("msg");
System.out.println(msg);
System.out.println("demo99999被访问了......");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Object msg = request.getAttribute("msg");
System.out.println(msg);
System.out.println("demo99999被访问了......");
}
}
-
获取 ServletContext: ServletContext getServletContext() package com.example.request;
import javax.servlet.ServletContext;
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;
@WebServlet(name = "RequestDemo10", value = "/RequestDemo10")
public class RequestDemo10 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletContext servletContext = request.getServletContext();
System.out.println(servletContext);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletContext servletContext = request.getServletContext();
System.out.println(servletContext);
}
}
4、用户登录
4.1、需求分析
-
编写 login.html 登录页面; username & password 两个输入框 -
使用 Druid 数据库连接池技术,操作 mysql,day14 数据库中USER 表; -
使用 JdbcTemplate 技术封装 JDBC; -
登录成功跳转到 SuccessServlet 展示:登录成功!用户名,欢迎您; -
登录失败跳转到 FailServlet 展示:登录失败,用户名或密码错误!
4.2、分析
4.3、开发步骤
4.3.1、创建项目,导入 html 页面,配置文件,jar 包
…
4.3.2、创建数据库环境
CREATE DATABASE day14;
USE day14;
CREATE TABLE USER(
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(32) UNIQUE NOT NULL,
PASSWORD VARCHAR(32) NOT NULL
);
4.3.3、创建包 domain,创建类 User
package domain;
public class User {
private int id;
private String username;
private String password;
public int getId() {
return id;
}
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
public void setId(int id) {
this.id = id;
}
public void setUsername(String username) {
this.username = username;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
4.3.4、创建包 util,编写工具类 JDBCUtils
package util;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
public class JDBCUtils {
private static DataSource ds;
static {
try {
Properties pro = new Properties();
InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties");
pro.load(is);
ds = DruidDataSourceFactory.createDataSource(pro);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
public static DataSource getDataSource(){
return ds;
}
public static Connection getConnection() throws SQLException {
return ds.getConnection();
}
}
4.3.5、创建包 dao,创建类 UserDao,提供 login 方法
package dao;
import domain.User;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import util.JDBCUtils;
public class UserDao {
private JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
public User login(User loginUser){
try {
String sql = "select * from USER where username = ? and password = ?";
User user = template.queryForObject(sql, new BeanPropertyRowMapper<User>(User.class),
loginUser.getUsername(), loginUser.getPassword());
return user;
} catch (DataAccessException e) {
e.printStackTrace();
return null;
}
}
}
测试类 Test
package test;
import dao.UserDao;
import domain.User;
import org.junit.Test;
public class UserDaoTest {
@Test
public void testLogin(){
User loginuser = new User();
loginuser.setUsername("superbaby");
loginuser.setPassword("123");
UserDao dao = new UserDao();
User user = dao.login(loginuser);
System.out.println(user);
}
}
|