概念:Hyper Text Transfer Protocol 超文本传输协议
传输协议:定义了客户端和服务器端通信时,发送数据的格式
区别(最大区分点):
客户端发送给服务器端的数据
| 请求方式 | 请求 URL | 请求协议/版本 |
|---|---|---|
| GET 或 POST | /login.html(资源路径) | HTTP/1.1 |
客户端浏览器告诉服务器一些信息
| 请求头名称 | 请求头值 |
|---|
举例:
你使用正版视频网站的首页跳转到被电影出版商认证的你选择播放的电影页面,可以正常播放
如果你自己写出一个盗版的视频网站首页,采用盗链的方式也可以跳转到该认证播放地址中选择的电影播放页面,这就是盗链行为
如果官方在播放页面中加入 Referer 判断,使得非授权授权页面主页跳转到此播放地址的行为无法播放,这就是防盗链
类似的:如果网站进行广告推广,可以使用 Referer 统计,哪个广告位跳转到该页面的次数多,进行定向投资广告业务
空行,用于分割 POST 请求的请求头和请求体
| 空行 |
|---|
请求体(正文)是用来封装 POST 请求消息的请求参数
空行之后属于请求体
POST /login.html HTTP/1.1
Host: localhost
User-Agent: ……
Accept: ……
Accept-Language: ……
Accept-Encoding: ……
Referer: http://localhost/login.html
Connection: ……
Upgrade-Insecure-Requests: ……
username=zhangsan
工作原理过程:
客户端浏览器通过:http://localhost:端口号/虚拟目录/资源路径向服务器请求发出请求消息:之后
- Tomcat 服务器会根据请求 URL 中的资源路径,(以创建 ServletTest 类并实现 Servlet 接口重写方法的实现类为例)创建对应的 ServletTest 对象
- Tomcat 服务器,会创建 Request 对象和 Response 对象,Request 对象中封装请求消息数据
- Tomcat 服务器将 Request 对象和 Response 对象传递给 service 方法,并且调用 service 方法
在创建的 ServletTest 类并实现 Servlet 接口重写方法的实现类中:之后
- 程序员可以通过 Request 对象获取请求消息数据,通过 Response 对象设置响应消息数据
之后服务器向客户端浏览器响应,进行响应消息:之后
- 服务器在浏览器做出响应之前,会从 Response 对象中拿程序员设置的响应消息数据
获取请求消息数据
其他功能
String getMethod()String getContextPath()String getServletPath()String getQueryString()String getRequestURI()StringBuffer getRequestURL()String getProtocol()String getRemoteAddr()URL :统一资源定位符
URI :统一资源标识符(范围较大)
代码演示:
doGet() 方法
@WebServlet(name = "ServletTest07", value = "/ServletTest07")
public class ServletTest07 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1. 获取请求方式 GET
String method = request.getMethod();
System.out.println(method);
// 2. 获取虚拟目录 /tomcat_test
String contextPath = request.getContextPath();
System.out.println(contextPath);
// 3. 获取 Servlet 路径 /ServletTest07
String servletPath = request.getServletPath();
System.out.println(servletPath);
// 4. 获取 get 方式请求参数 name=zhangsan
String queryString = request.getQueryString();
System.out.println(queryString);
// 5. 获取请求 URI /tomcat_test/ServletTest07
String requestURI = request.getRequestURI();
System.out.println(requestURI);
// 6. 获取请求 URL http://localhost:8080/tomcat_test/ServletTest07
StringBuffer requestURL = request.getRequestURL();
System.out.println(requestURL);
// 7. 获取协议及版本 HTTP/1.1
String protocol = request.getProtocol();
System.out.println(protocol);
// 8. 获取客户机的 IP 地址 0:0:0:0:0:0:0:1(由于是自己访问自己)
String remoteAddr = request.getRemoteAddr();
System.out.println(remoteAddr);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
String getHeader(String name) : 通过请求头的名称获取请求头的值Enumeration getHeaderNames() :获取所有的请求头名称代码演示:
@WebServlet(name = "ServletTest08", value = "/ServletTest08")
public class ServletTest08 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 {
}
}
@WebServlet(name = "ServletTest09", value = "/ServletTest09")
public class ServletTest09 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 演示获取请求头数据:user-agent 不区分大小写
String agent = request.getHeader("User-Agent");
// 判断 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 {
}
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 演示获取头数据:referer
String referer = request.getHeader("Referer");
System.out.println(referer);
// 防盗链
if (referer!=null){
if (referer.contains("tomcat_test")){ // 是否直接通过浏览器的规定虚拟目录位置访问
// 正常访问
System.out.println("正常访问!");
// 浏览器页面显示
response.setContentType("text/html;charset=utf-8");
response.getWriter().write("正常访问!");
}else {
// 盗链
System.out.println("盗链!");
// 浏览器页面显示
response.setContentType("text/html;charset=utf-8");
response.getWriter().write("盗链行为!");
}
}
}
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>主页title>
head>
<body>
<a href="http://localhost:8080/tomcat_test/ServletTest09">正常访问a>
body>
html>
BufferReader getReader() :获取字符输入流,只能操作字符数据ServletInputStream getInputStream() :获取字节输入流,可以操作所有数据类型代码演示:
@WebServlet(name = "ServletTest10", value = "/ServletTest10")
public class ServletTest10 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 reader = request.getReader();
// 读取数据
String line=null;
while((line= reader.readLine())!=null){
System.out.println(line);
}
}
}
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>注册页面title>
head>
<body>
<form action="http://localhost:8080/tomcat_test/ServletTest10" method="post">
<input type="text" placeholder="请输入用户名" name="username"><br>
<input type="text" placeholder="请输入密码" name="password"><br>
<input type="submit" value="注册">
form>
body>
html>
不论是 GET 还是 POST 请求方式都可以使用下列方法来获取请求参数
String getParameter(String name) :根据参数名称获取参数值(username=zhangsan&password=123456)String[] getParameterValues(String name) :根据参数名称获取参数值的数组(hobby=xxxx&hobby=game)Enumeration getParameterNames() :获取所有请求的参数名称Map getParameterMap() :获取所有参数的 Map 集合代码演示:第一个方法
@WebServlet(name = "ServletTest11", value = "/ServletTest11")
public class ServletTest11 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// get 获取请求参数
// 根据参数名称获取参数值
String username = request.getParameter("username");
System.out.println("get");
System.out.println(username);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// post 获取请求参数
// 根据参数名称获取参数值
// String username = request.getParameter("username");
// System.out.println("post");
// System.out.println(username);
// 既然两个方法的业务逻辑相同,没必要再写一遍,只需要调用即可
this.doGet(request,response);
}
}
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>注册页面title>
head>
<body>
<form action="http://localhost:8080/tomcat_test/ServletTest11" method="post">
<input type="text" placeholder="请输入用户名" name="username"><br>
<input type="text" placeholder="请输入密码" name="password"><br>
<input type="submit" value="注册">
form>
body>
html>
代码演示:第二个方法
@WebServlet(name = "ServletTest11", value = "/ServletTest11")
public class ServletTest11 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 根据参数名称获取参数值的数组
String[] hobbies = request.getParameterValues("hobby");
for (String hobby : hobbies) {
System.out.println(hobby);
}
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request,response);
}
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>注册页面title>
head>
<body>
<form action="http://localhost:8080/tomcat_test/ServletTest11" method="post">
<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="sports">运动
<input type="checkbox" name="hobby" value="music">音乐
<input type="checkbox" name="hobby" value="study">学习<br>
<input type="submit" value="注册">
form>
body>
html>
代码演示:第三个方法
@WebServlet(name = "ServletTest11", value = "/ServletTest11")
public class ServletTest11 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 获取所有请求的参数名称
Enumeration<String> parameterNames = request.getParameterNames();
while (parameterNames.hasMoreElements()){
String name = parameterNames.nextElement();
System.out.println(name);
String[] values = request.getParameterValues(name);
for (String value : values) {
System.out.println(value);
System.out.println("------");
}
}
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request,response);
}
}
代码演示:第四个方法
@WebServlet(name = "ServletTest11", value = "/ServletTest11")
public class ServletTest11 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 获取所有参数的 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("------");
}
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request,response);
}
}
request.setCharacterEncoding("utf-8"); ,即此时设置的编码格式与所编写的 HTML 页面编写的编码相同@WebServlet(name = "ServletTest11", value = "/ServletTest11")
public class ServletTest11 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 获取请求参数 username
// 设置流的编码
request.setCharacterEncoding("utf-8");
String username = request.getParameter("username");
System.out.println(username);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request,response);
}
}
一种在服务器内部的资源跳转方式
RequestDispatcher getRequestDispatcher(String path)forward(ServletRequest request,ServletRequest response)代码演示:
@WebServlet(name = "ServletTest12", value = "/ServletTest12")
public class ServletTest12 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("ServletTest12 被访问了!");
// 转发到 ServletTest13 资源
request.getRequestDispatcher("/ServletTest13").forward(request,response);
// 由于该对象的该种方法一般只使用一次,所以采用链式编程
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
@WebServlet(name = "ServletTest13", value = "/ServletTest13")
public class ServletTest13 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("ServletTest13 被访问了!");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request,response);
}
}
采用这种请求转发的方式,只使用浏览器访问 ServletTest12 这一个类,同时达到访问 ServletTest12 和 ServletTest13 两个类的效果
域对象:一个有作用范围的对象,可以在范围内共享数据
Request 域:代表一次请求的范围,一般用于请求转发的多个资源中共享数据
方法:
void setAttribute(String name,Object obj) :存储数据Object getAttribute(String name) :通过键获取值void removeAttribute(String name) :通过键移除键值对@WebServlet(name = "ServletTest12", value = "/ServletTest12")
public class ServletTest12 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("ServletTest12 被访问了!");
// 存储数据到 Request 域中
request.setAttribute("share","Hello!");
// 转发到 ServletTest13 资源
request.getRequestDispatcher("/ServletTest13").forward(request,response);
// 由于该对象的该种方法一般只使用一次,所以采用链式编程
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
@WebServlet(name = "ServletTest13", value = "/ServletTest13")
public class ServletTest13 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 获取数据
Object share = request.getAttribute("share");
System.out.println(share);
System.out.println("ServletTest13 被访问了!");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request,response);
}
}
方法:
ServletContext getServletContext() 获取ServletContext 对象@WebServlet(name = "ServletTest14", value = "/ServletTest14")
public class ServletTest14 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 {
this.doGet(request,response);
}
}
login.html 登陆界面:包含 username&password 两个输入框登陆界面:
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登录界面title>
head>
<body>
<form action="" method="post">
用户名:<input type="text" name="username"><br>
密码:<input type="password" name="password"><br>
<input type="submit" value="登录">
form>
body>
html>
MySQL 数据库连接池(Druid 连接池)配置文件:
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql:///test
username=root
password=root
initialSize=5
maxActive=10
maxWait=3000
login.htmlLoginServlet 类
UserDao 类的 login 方法查询,获取返回值 User 对象FailServlet 类 ② 登陆成功 → 将用户信息存到 Request 域,转发到 SuccessServlet 类UserDao 操作数据库的类开发步骤:
webapp 目录下,编写登陆界面(注意:不要误放到 WEB-INF 目录下)druid.properties 放到 resource (资源)目录下pom.xml 中导入所需要的 jar 包和插件
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>com.examplegroupId>
<artifactId>login_testartifactId>
<version>1.0-SNAPSHOTversion>
<name>login_testname>
<packaging>warpackaging>
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<maven.compiler.target>1.8maven.compiler.target>
<maven.compiler.source>1.8maven.compiler.source>
<junit.version>5.8.1junit.version>
properties>
<dependencies>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>4.0.1version>
<scope>providedscope>
dependency>
<dependency>
<groupId>org.junit.jupitergroupId>
<artifactId>junit-jupiter-apiartifactId>
<version>${junit.version}version>
<scope>testscope>
dependency>
<dependency>
<groupId>org.junit.jupitergroupId>
<artifactId>junit-jupiter-engineartifactId>
<version>${junit.version}version>
<scope>testscope>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.32version>
dependency>
<dependency>
<groupId>commons-logginggroupId>
<artifactId>commons-loggingartifactId>
<version>1.2version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
<version>1.1.12version>
dependency>
<dependency>
<groupId>com.mchangegroupId>
<artifactId>mchange-commons-javaartifactId>
<version>0.2.12version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-beansartifactId>
<version>5.3.6version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-coreartifactId>
<version>5.3.6version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jdbcartifactId>
<version>5.3.6version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-txartifactId>
<version>5.3.6version>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-war-pluginartifactId>
<version>3.3.2version>
plugin>
plugins>
build>
project>
create table user(
id int primary key auto_increment,
username varchar(32) unique not null ,
password varchar(32) not null
);
insert into user values (1,'张三','123');
insert into user values (2,'李四','234');
insert into user values (3,'王五','345');
public class User {
private int id;
private String username;
private String password;
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
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 {
/**
* JDBC 工具类,使用 Druid 连接池
*/
private static DataSource dataSource;
static {
try {
// 加载配置文件
Properties properties = new Properties();
// 使用 ClassLoader 加载配置文件,获取字节输入流
InputStream resourceAsStream = JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties");
properties.load(resourceAsStream);
// 初始化连接池对象
dataSource= DruidDataSourceFactory.createDataSource(properties);
}catch (IOException e){
e.printStackTrace();
}catch (Exception e){
e.printStackTrace();
}
}
// 获取连接池对象
public static DataSource getDataSource(){
return dataSource;
}
// 获取连接 Connection 对象
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
}
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
public class UserDao {
/**
* 操作数据库中 User 表的类
*/
// 声明 JDBCTemplate 对象共用
private JdbcTemplate jdbcTemplate=new JdbcTemplate(JDBCUtils.getDataSource());
/* 登陆方法:loginUser:只有用户名和密码,user:包含用户全部数据,没有查询都,返回 null */
public User login(User loginUser){
try {
String sql="select * from user where username = ? and password = ?";
// 调用 query 方法
User user = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<User>(User.class), loginUser.getUsername(), loginUser.getPassword());
return user;
} catch (DataAccessException e) {
e.printStackTrace(); // 一般在这里写入日志
return null;
}
}
}
@Test
public void testLogin(){
User loginUser = new User();
loginUser.setUsername("李四");
loginUser.setPassword("234");
UserDao dao = new UserDao();
User user = dao.login(loginUser);
System.out.println(user);
}
login.html 中的 表单中 action 路径的写法:虚拟目录 + Servlet 类的资源路径(例如此处应为:)
编辑配置 Tomcat 服务器,部署项目【Tomcat 服务器安装及基础配置使用】

编写 LoginServlet 类
@WebServlet("/loginServlet")
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 设置编码
request.setCharacterEncoding("utf-8");
// 获取请求参数
String username = request.getParameter("username");
String password = request.getParameter("password");
// 封装为 User 对象
User loginUser = new User();
loginUser.setUsername(username);
loginUser.setPassword(password);
// 调用 UserDao 的 login 方法
UserDao dao = new UserDao();
User user = dao.login(loginUser);
// 判断 user
if (user==null){
// 登陆失败
request.getRequestDispatcher("/failServlet").forward(request,response);
}else {
// 登陆成功
// 存储数据
request.setAttribute("user",user);
//转发
request.getRequestDispatcher("successServlet").forward(request,response);
}
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
@WebServlet("/failServlet")
public class FailServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 页面显示
// 设置编码
response.setContentType("text/html;charset=utf-8");
response.getWriter().write("登录失败,用户名或密码错误!");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
@WebServlet("/successServlet")
public class SuccessServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 获取 Request 域中共享的 User 对象
User user = (User) request.getAttribute("user");
if (user!=null){
// 页面显示
response.setContentType("text/html;charset=utf-8");
// 设置编码
response.getWriter().write("登陆成功!"+user.getUsername()+",欢迎您!");
}
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request,response);
}
}
BeanUtils 工具类,简化数据封装,用于封装 JavaBean
JavaBean :标准的 Java 类,用于封装数据
要求:
- 类必须被 public 修饰
- 类必须提供空参的构造器
- 成员变量必须使用 private 修饰
- 提供公共的 setter 和 getter 方法
方法:
setProperty()getProperty()populate(Object obj,Map map) :将 Map 集合的键值对信息,封装到对应的 JavaBean 对象中使用 Maven 框架导入 jar 包
<dependency>
<groupId>commons-beanutilsgroupId>
<artifactId>commons-beanutilsartifactId>
<version>1.9.4version>
dependency>
@WebServlet("/loginServlet")
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 设置编码
request.setCharacterEncoding("utf-8");
// 获取所有的请求参数
Map<String, String[]> map = request.getParameterMap();
// 创建 User 对象
User loginUser = new User();
// 使用 BeanUtils 封装
try {
BeanUtils.populate(loginUser,map);
}catch (IllegalAccessException e){
e.printStackTrace();
}catch (InvocationTargetException e){
e.printStackTrace();
}
// 调用 UserDao 的 login 方法
UserDao dao = new UserDao();
User user = dao.login(loginUser);
// 判断 user
if (user==null){
// 登陆失败
request.getRequestDispatcher("/failServlet").forward(request,response);
}else {
// 登陆成功
// 存储数据
request.setAttribute("user",user);
//转发
request.getRequestDispatcher("successServlet").forward(request,response);
}
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
概念区分:
getUsername() → Username → username)setXingbie(String gender); getXingbie(); ,此时 xingbie 这个词组就成为了属性,而不是 gender,属于 xingbie 这个属性操作 gender 这个值服务器端发送给客户端的数据
| 协议/版本 | 响应状态码 | 状态码描述 |
|---|
doXxx() 方法)重定向解释:假设浏览器向服务器发送请求,服务器中有 A B C 三类资源,为做出响应服务器先找到 A 类资源,但是 A 类资源无法解决问题,随后 A 类资源认为 C 类资源可以解决问题,响应浏览器响应状态码:302 ,并提出去找 C 类资源并且附有 C 类的资源路径,最后 C 类资源做出响应,这里 C 类资源是否解决问题,仍不确定。(相当于一次请求,请求到了两次资源)
访问缓存解释:假设服务器中有一张图片,浏览器请求这张图片,请求完成后,服务器将图片响应给浏览器,浏览器进行图片展示。但是由于该图片一般不会发生变化,图片数据已经固定,这时浏览器会自动将图片的数据缓存到本地,浏览器下一次再来请求相同的图片数据资源时,服务器发现图片并没有发生变化,而且浏览器本地缓存中有该图片,服务器告诉浏览器去访问本地的图片数据缓存,服务器响应状态码:304,去访问缓存(因为服务器与浏览器数据交互,发送图片方式为二进制数据,占用通信时间长),提升了整个请求和响应的速度,减轻了服务器的压力。如果图片更改,服务器会自动刷新图片,正常响应浏览器。
格式:
| 头名称 : | 值 |
|---|
常见的响应头:
in-line :默认值,在当前页面内打开attachment;filename=xxx :以附件形式打开响应体,一般用于文件下载| 空行 |
|---|
传输的对象
空行之后属于响应体
HTTP/1.1 200 OK
Content - Type: text/html;charset=UTF-8
Content - Length: 101
Date: ……
页面
Hello,Response!
setStatus(int sc)setHeader(String name,String value)PrintWriter getWriter()ServletOutputStream getOutputStream()重定向:资源跳转的方式
重定向解释:假设浏览器向服务器发送请求,服务器中有 A B C 三类资源,为做出响应服务器先找到 A 类资源,但是 A 类资源无法解决问题,随后 A 类资源认为 C 类资源可以解决问题,响应浏览器响应状态码:302 ,并提出去找 C 类资源并且附有 C 类的资源路径,最后 C 类资源做出响应,这里 C 类资源是否解决问题,仍不确定。(相当于一次请求,请求到了两次资源)
实现步骤:
@WebServlet("/responseTest01")
/**
* 重定向
*/
public class ResponseTest01 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("Test01 被访问了!");
// 访问 /responseTest01,会自动跳转到 /responseTest02 资源
// 设置状态码为302
response.setStatus(302);
// 设置响应头 location
response.setHeader("location","/response_test/responseTest02");
// 由于上述三个参数有两个是固定不变的,所以 API 提供了一种简单的方法
// 简单的重定向方法
response.sendRedirect("/response_test/responseTest02");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request,response);
}
}
@WebServlet("/responseTest02")
public class ResponseTest02 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("Test02 被访问了!");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request,response);
}
}
相对路径:通过相对路径不可以确定唯一资源(如:
./index.html,简易判断:不以/开头,而以.开头的路径)
./ :当前目录../ :后退一级目录(多了一个句点)(就是向上翻阅一个目录)绝对路径:通过绝对路径可以确定唯一资源(如:
http://localhost:8080/虚拟目录/资源路径或/虚拟目录/资源路径,简易判断:以/开头的路径)
@WebServlet("/responseTest01")
/**
* 重定向
*/
public class ResponseTest01 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("Test01 被访问了!");
// 动态获取虚拟目录
String contextPath = request.getContextPath();
// 简单的重定向方法
response.sendRedirect(contextPath+"/responseTest02");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request,response);
}
}
步骤:
@WebServlet("/responseTest03")
public class ResponseTest03 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 获取字符输出流
PrintWriter printWriter = response.getWriter();
// 输出数据
printWriter.write("Hello,Response!
");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
@WebServlet("/responseTest03")
public class ResponseTest03 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 获取流对象之前,设置流的默认编码,ISO-8859-1,变化为 UTF-8
// response.setCharacterEncoding("utf-8");
// 告诉浏览器,服务器发送的消息体数据的编码,建议浏览器使用该编码解码
// response.setHeader("content-type","text/html;charset=utf-8");
// 简单形式,代替上述两行代码
response.setContentType("text/html;charset=utf-8");
// 获取字符输出流
PrintWriter printWriter = response.getWriter();
// 输出数据
printWriter.write("你好,Response!
");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
步骤:
@WebServlet("/responseTest04")
public class ResponseTest04 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html; charset=UTF-8");
// 获取字节输出流
ServletOutputStream servletOutputStream = response.getOutputStream();
// 输出数据
servletOutputStream.write("你好!".getBytes("utf-8"));
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
本质:图片
目的:防止恶意表单注册
@WebServlet("/checkCodeServlet")
public class CheckCodeServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
int width=100;
int height=50;
// 创建一个对象,在内存中的验证码图片对象
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
// 美化图片
// 填充背景色
Graphics graphics = image.getGraphics(); // 画笔对象
graphics.setColor(Color.CYAN); // 设置画笔颜色
graphics.fillRect(0,0,width,height);
// 画边框
graphics.setColor(Color.BLUE);
graphics.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 charAt = str.charAt(index);
graphics.drawString(charAt+"",width/5*i,height/2);
}
// 画干扰线
graphics.setColor(Color.pink);
// 随机生成坐标点
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);
graphics.drawLine(x1,x2,y1,y2);
}
// 将图片输出到页面展示
ImageIO.write(image,"jpg",response.getOutputStream());
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
<script>
// 点击超链接或者图片更换图片
// 给超链接和图片绑定单击事件
// 重新设置图片的 src 属性
window.onload=function () {
// 获取图片对象
var img = document.getElementById("checkCode");
// 绑定单击事件
img.onclick=function () {
// 加入时间戳,欺骗服务器,防止浏览器缓存图片后,不进行更新
var data=new Date().getTime();
img.src="/response_test/checkCodeServlet?"+data;
}
}
script>
head>
<body>
<img id="checkCode" src="/response_test/checkCodeServlet">
<a id="change" href="">看不清,换一张!a>
body>
html>
概念:代表整个 Web 应用,可以和程序的容器(服务器)进行通信
request.getServletContext();this.getServletContext();@WebServlet("/servletContextTest01")
public class ServletContextTest01 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1. 通过 Request 对象获取
ServletContext servletContext01 = request.getServletContext();
// 2. 通过 HttpServlet 类获取
ServletContext servletContext02 = this.getServletContext();
System.out.println(servletContext01);
System.out.println(servletContext02);
// 判断两者是否相同
System.out.println(servletContext01==servletContext02); // true
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
MIME 类型:在互联网通信过程中定义的一种文件数据类型
text/html 、image/jpeg)String getMimeType(String file)@WebServlet("/servletContextTest02")
public class ServletContextTest02 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 通过 HttpServlet 类获取
ServletContext servletContext = this.getServletContext();
// 定义文件名称
String fileName="a.jpg";
// 获取 MIME 类型
String mimeType = servletContext.getMimeType(fileName);
System.out.println(mimeType);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
setAttribute(String name,Object value)getAttribute(String name)removeAttribute(String name)@WebServlet("/servletContextTest03")
public class ServletContextTest03 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 通过 HttpServlet 获取
ServletContext servletContext = this.getServletContext();
// 设置数据
servletContext.setAttribute("msg","存储数据!");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
@WebServlet("/servletContextTest04")
public class ServletContextTest04 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 通过 HttpServlet 获取
ServletContext servletContext = this.getServletContext();
// 获取数据
Object msg = servletContext.getAttribute("msg");
System.out.println(msg);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
首先了解:编写的 Web 项目,具有两份,一份存储在 Tomcat 服务器中,另一份在本地工作空间中,而客户端浏览器访问的肯定是 Tomcat 服务器中的那一份 Web 项目。
所以一切的路径都是指的服务器端路径(或者称为真实路径或者文件运行的路径)
String getRealPath(String path)@WebServlet( "/servletContextTest05")
public class ServletContextTest05 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletContext servletContext = this.getServletContext();
// 获取文件的服务器路径
String realPath01 = servletContext.getRealPath("/index.jsp"); // webapp 目录下资源访问
System.out.println(realPath01);
File file = new File(realPath01);
String realPath02 = servletContext.getRealPath("/WEB-INF/web.xml"); // WEB-INF 目录下的资源访问
System.out.println(realPath02);
String realPath03 = servletContext.getRealPath("/WEB-INF/classes/a.txt"); // src 目录下的资源访问
System.out.println(realPath03);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
ClassLoader 类加载器,只能加载 src 目录下的文件地址,无法加载 web(webapp)目录下的文件地址,具有局限性content-disposition:attachment;filename=xxxcontent-disposition:attachment;filename=xxx@WebServlet("/downloadServlet")
public class DownloadServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1. 获取请求参数,文件名称
String filename = request.getParameter("filename");
// 2. 使用字节输入流加载文件进入内存
// 找到文件的服务器真实路径
ServletContext servletContext = this.getServletContext();
String realPath = servletContext.getRealPath("/img/" + filename);
// 使用字节流关联
FileInputStream fileInputStream = new FileInputStream(realPath);
// 3. 设置 Response 对象的响应头
// 设置响应头类型:contest-type
String mimeType = servletContext.getMimeType(filename); // 获取文件的 MIME 类型
response.setHeader("content-type",mimeType);
// 设置响应头打开方式:content-disposition
response.setHeader("content-disposition","attachment;filename="+filename);
// 4. 将输出流的数据写出到输出流中
ServletOutputStream servletOutputStream = response.getOutputStream();
byte[] bytes = new byte[1024 * 8];
int length=0;
while ((length=fileInputStream.read(bytes))!=-1){
servletOutputStream.write(bytes,0,length);
}
fileInputStream.close();
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<a href="/response_test/picture.jpg">图片下载a>
<a href="/response_test/video.avi">视频下载a>
<hr>
<a href="/response_test/downloadServlet?filename=picture.jpg">图片下载a>
<a href="/response_test/downloadServlet?filename=video.avi">视频下载a>
body>
html>
中文文件问题解决:
工具类:DownLoadUtils
import sun.misc.BASE64Encoder;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
public class DownLoadUtils {
public static String getFileName(String agent,String filename) throws UnsupportedEncodingException {
if (agent.contains("MSIE")){
// IE 浏览器
filename = URLEncoder.encode(filename, "utf-8");
filename=filename.replace("+"," ");
}else if (agent.contains("Firefox")){
// 火狐浏览器
BASE64Encoder base64Encoder = new BASE64Encoder();
filename="=?utf-8?B"+base64Encoder.encode(filename.getBytes("utf-8"))+"?=";
}else {
// 其他浏览器
filename=URLEncoder.encode(filename,"utf-8");
}
return filename;
}
}
@WebServlet("/downloadServlet")
public class DownloadServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1. 获取请求参数,文件名称
String filename = request.getParameter("filename");
// 2. 使用字节输入流加载文件进入内存
// 找到文件的服务器真实路径
ServletContext servletContext = this.getServletContext();
String realPath = servletContext.getRealPath("/img/" + filename);
// 使用字节流关联
FileInputStream fileInputStream = new FileInputStream(realPath);
// 3. 设置 Response 对象的响应头
// 设置响应头类型:contest-type
String mimeType = servletContext.getMimeType(filename); // 获取文件的 MIME 类型
response.setHeader("content-type",mimeType);
// 解决中文文件名问题
// 获取 user-agent 请求头
String agent = request.getHeader("user-agent");
// 使用工具类方法编码文件名即可
filename=DownLoadUtils.getFileName(agent,filename);
// 设置响应头打开方式:content-disposition
response.setHeader("content-disposition","attachment;filename="+filename);
// 4. 将输出流的数据写出到输出流中
ServletOutputStream servletOutputStream = response.getOutputStream();
byte[] bytes = new byte[1024 * 8];
int length=0;
while ((length=fileInputStream.read(bytes))!=-1){
servletOutputStream.write(bytes,0,length);
}
fileInputStream.close();
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}