个人主页:Hello Code.
本文专栏:《Java WEB从入门到实战》
Java WEB完整内容请点击前往Java WEB从入门到实战 查看
如有问题,欢迎指正,一起学习~~
文章目录
请求对象
请求: 获取资源。在BS架构中,就是客户端浏览器向服务端发出询问。
请求对象: 就是在项目中用于发送请求的对象(ServletRequest
和HttpServletRequest
)
ServletRequest 和 HttpServletRequest 都是接口,但是Tomcat 服务器会帮我们处理好实现类的赋值等工作,我们不需要关心这些
获取各种路径
返回值 | 方法名 | 说明 |
---|---|---|
String | getContextPath() | 获取虚拟目录名称 |
String | getServletPath() | 获取Servlet映射路径 |
String | getRemoteAddr() | 获取访问者ip地址 |
String | getQueryString() | 获取请求的消息数据 |
String | getRequestURI() | 获取统一资源标识符 |
StringBuffer | getRequestURL() | 获取统一资源定位符 |
package study.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;
@WebServlet("/request")
public class RequestDemo extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String contextPath = req.getContextPath();
String servletPath = req.getServletPath();
String remoteAddr = req.getRemoteAddr();
String queryString = req.getQueryString();
String requestURI = req.getRequestURI();
StringBuffer requestURL = req.getRequestURL();
PrintWriter pw = resp.getWriter();
pw.println("contextPath= " + contextPath);
pw.println("servletPath= " + servletPath);
pw.println("remoteAddr= " + remoteAddr);
pw.println("queryString= " + queryString);
pw.println("requestURI= " + requestURI);
pw.println("requestURL= " + requestURL);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
获取请求头
返回值 | 方法名 | 说明 |
---|---|---|
String | getHeader(String name) | 根据请求头名称获取一个值 |
Enumeration | getHeaders(String name) | 根据请求头名称获取多个值 |
Enumeration | getHeaderNames() | 获取所有请求头名称 |
package study.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;
import java.util.Enumeration;
@WebServlet("/request2")
public class RequestDemo2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println(req.getHeader("host"));
System.out.println(req.getHeader("user-agent"));
Enumeration<String> headers = req.getHeaders("user-agent");
while(headers.hasMoreElements()){
String s = headers.nextElement();
System.out.println(s);
}
System.out.println("===============");
Enumeration<String> names = req.getHeaderNames();
while(names.hasMoreElements()){
System.out.println(names.nextElement());
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
获取请求参数信息
返回值 | 方法名 | 说明 |
---|---|---|
String | getParameter(String name) | 根据名称获取数据 |
String[] | getParameterValues(String name) | 根据名称获取所有数据 |
Enumeration | getParameterNames() | 获取所有名称 |
Map<String,String[]> | getParameterMap() | 获取所有参数的键值对 |
package study.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 javax.swing.*;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Map;
import java.util.Set;
@WebServlet("/request3")
public class RequestDemo3 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println(req.getParameter("username"));
System.out.println("================");
for (String hobby : req.getParameterValues("hobby")) {
System.out.println(hobby);
}
System.out.println("===================");
Enumeration<String> parameterNames = req.getParameterNames();
while(parameterNames.hasMoreElements()){
String name = parameterNames.nextElement();
for (String value : req.getParameterValues(name)) {
System.out.println(value);
}
}
System.out.println("===================");
Map<String, String[]> parameterMap = req.getParameterMap();
for (String key : parameterMap.keySet()) {
String[] value = parameterMap.get(key);
System.out.println(key + " === " + value);
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
获取请求参数并封装对象
- 手动封装方式
成员变量名称和参数name属性值保持一致 - 反射封装方式
属性描述器:PropertyDescriptor
(根据名称获取到对象中对应的get和set方法) - 工具类封装方式
beanutils
工具类,populate
方法
在发布之前,还需要进入File-Project Structure
package study.servlet;
import study.servlet.bean.Student;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
/*
* 封装对象------反射方式
* */
public class RequestDemo5 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取所有数据
Map<String, String[]> map = req.getParameterMap();
// 封装学生对象
Student stu = new Student();
// 遍历集合
for(String name : map.keySet()){
String[] value = map.get(name);
try {
// 获取Student对象的属性描述器
PropertyDescriptor pd = new PropertyDescriptor(name, stu.getClass());
// 获取对应的set方法
Method writeMethod = pd.getWriteMethod();
// 执行方法
writeMethod.invoke(stu,value);
} catch (IntrospectionException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
package study.servlet;
import org.apache.commons.beanutils.BeanUtils;
import study.servlet.bean.Student;
/*
* 封装对象------工具类方式
需要导包:BeanUtils
* */
public class RequestDemo6 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取所有数据
Map<String, String[]> map = req.getParameterMap();
// 封装学生对象
Student stu = new Student();
try {
BeanUtils.populate(stu, map);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
流对象获取请求信息
返回值 | 方法名 | 说明 |
---|---|---|
BufferedReader | getReader() | 获取字符输入流 |
ServletInputStream | getInputStream() | 获取字节输入流 |
用IO流获取请求信息时,不支持get方式,只支持post提交方式
获得到的流对象都不是自己new出来的,不需要close释放资源,会由请求对象处理并释放
package study.servlet;
import org.apache.commons.beanutils.BeanUtils;
import study.servlet.bean.Student;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
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.Map;
/*
* 流对象获取数据
* */
@WebServlet("/request7")
public class RequestDemo7 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 字符流(必须是post请求方式)
BufferedReader br = req.getReader();
String line;
while((line = br.readLine()) != null) System.out.println(line);
// 字节流
ServletInputStream is = req.getInputStream();
byte[] arr = new byte[1024];
int len;
while((len = is.read(arr)) != -1){
System.out.println(new String(arr, 0, len));
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
中文乱码问题
- GET方式
没有乱码问题,在Tomcat 8 版本后已经解决 - POST方式
有乱码问题,可以通过 setCharacterEncoding() 方法来解决(编码格式要和页面编码格式一致)
package study.servlet;
/*
* 中文乱码问题
* */
@WebServlet("/request8")
public class RequestDemo8 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
String name = req.getParameter("name");
System.out.println(name);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
请求域
- 请求域(request域):可以在一次请求范围内进行共享数据。
- 一般用于请求转发的多个资源中共享数据
- 请求对象操作共享数据方法
返回值 方法名 说明 void setAttribute(String name, Object value) 向请求域对象中存储数据 Object getAttribute(String name) 通过名称获取请求域对象中的数据 void removeAttribute(String name) 通过名称移除请求域对象中的数据
请求转发
- 请求转发:客户端的一次请求到达以后,发现需要借助其他 Servlet 来实现功能(浏览器请求,A发现做不了,转发给B去做)
- 特点
- 浏览器地址栏不变
- 域对象中的数据不丢失
- 负责转发的Servlet 转发前后的响应正文会丢失
- 由转发的目的地来响应客户端
返回值 | 方法名 | 说明 |
---|---|---|
RequestDispatcher | getRequestDispatcher(String name) | 获取请求调度对象 |
void | forward(ServletRequest req, ServletResponse resp) | 实现转发(用请求调度对象调用) |
package study.servlet.request;
/*
* 请求转发
* */
@WebServlet("/request9")
public class RequestDemo9 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 设置共享数据
req.setAttribute("name","张三");
// 获取请求调度对象
RequestDispatcher rd = req.getRequestDispatcher("/request10");
// 请求转发
rd.forward(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
package study.servlet.request;
/*
* 转发目的
* */
@WebServlet("/request10")
public class RequestDemo10 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取共享数据
System.out.println(req.getAttribute("name"));
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
请求包含
- 请求包含:可以合并其他Servlet 中的功能一起响应给客户端(浏览器请求,A只能做一半,另一半让B做)
- 特点
- 浏览器地址栏不变
- 域对象中的数据不丢失
- 被包含的 Servlet 响应头会丢失
返回值 | 方法名 | 说明 |
---|---|---|
RequestDispatcher | getRequestDispatcher(String name) | 获取请求调度对象 |
void | include(ServletRequest req, ServletResponse resp) | 实现包含 |
package study.servlet.request;
/*
* 请求包含
* */
@WebServlet("/request11")
public class RequestDemo11 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 设置共享数据
req.setAttribute("name","张三");
// 获取请求调度对象
RequestDispatcher rd = req.getRequestDispatcher("/request10");
// 请求转发
rd.include(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
响应对象
- 响应:回馈结果。在 BS 架构中,就是服务器给客户浏览器反馈结果
- 响应对象:就是在项目中用于发送响应的对象
ServletResponse
(接口)
HttpServletResponse
(继承自ServletResponse,基于http协议的接口)和请求对象一样,不需要我们去写实现类,在Tomcat 服务器创建好,在执行
doGet
或者doPost
方法时,服务器会把相应的实现类对象传递
常见状态码
状态码 | 说明 |
---|---|
200 | 成功 |
302 | 重定向 |
304 | 请求资源未改变,使用缓存 |
400 | 请求错误,常见于请求参数错误 |
404 | 请求资源未找到 |
405 | 请求方式不支持 |
500 | 服务器错误 |
字节流响应消息
返回值 | 方法名 | 说明 |
---|---|---|
ServletOutputStream | getOutputStream() | 获取响应字节输出流对象 |
void | setContentType(“text/html;charset=UTF-8”) | 设置响应内容类型,解决中文乱码问题 |
步骤:
- 获取字节输出流对象
- 定义一个消息(一个字符串)
- 通过字节流对象输出
获取到的字节输出流对象不需要close释放,会由响应对象处理并释放
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取字节输出流
ServletOutputStream os = resp.getOutputStream();
String s = "字节输出流响应消息";
os.write(s.getBytes());
}
未出现乱码问题:浏览器默认gbk编码,idea默认UTF-8编码;但是
getBytes
方法在将字符串转为字节数组时,如果不传递参数指定编码,就会根据当前系统平台默认编码进行转换,Windows系统默认编码为gbk,和浏览器一致,故未出现乱码
// 统一编码格式为UTF-8并解决乱码问题
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 设置相应内容类型,并设置编码格式(告知浏览器应该采用的编码格式)
resp.setContentType("text/html;charset=UTF-8");
// 获取字节输出流
ServletOutputStream os = resp.getOutputStream();
String s = "字节输出流响应消息";
os.write(s.getBytes("UTF-8"));
}
字符流响应消息
返回值 | 方法名 | 说明 |
---|---|---|
PrintWriter | getWriter() | 获取响应字符输出流对象 |
void | setContentType(“text/html;charset=UTF-8”) | 设置响应内容类型,解决中文乱码问题 |
步骤和上面字节流一样,同样不需要自己close释放资源
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 设置相应内容类型,并设置编码格式(告知浏览器应该采用的编码格式)
resp.setContentType("text/html;charset=UTF-8");
// 获取字符输出流对象
PrintWriter pw = resp.getWriter();
pw.write("字符输出流响应消息");
}
响应图片
- 通过文件的相对路径获取绝对路径(getRealPath)
- 创建字节输入流对象,关联读取的图片路径
- 通过响应对象获取字节输出流对象
- 循环读取和写出图片
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String realPath = getServletContext().getRealPath("/img/tx.png");
// 创建字节输入流对象,关联图片
BufferedInputStream is = new BufferedInputStream(new FileInputStream(realPath));
// 获取字节输出流对象,响应图片
ServletOutputStream os = resp.getOutputStream();
// 循环读写
byte[] arr = new byte[1024];
int len;
while((len = is.read(arr)) != -1){
os.write(arr, 0, len);
}
// 释放资源
is.close();
}
设置缓存
- 缓存:对于不经常变化的数据,我们可以设置合理的缓存时间,以避免浏览器频繁请求服务器。以此来提高效率
返回值 | 方法名 | 说明 |
---|---|---|
void | setDateHeader(String name,long time) | 设置消息头添加缓存 |
例:
resp.setDateHeader("Expires",System.currentTimeMillis() + 1*60*60*1000);
设置一个小时缓存时间
Expires 就是过期的意思
时间单位为毫秒,1秒等于1000毫秒
定时刷新
- 定时刷新:过了指定时间后,页面自动进行跳转
返回值 | 方法名 | 说明 |
---|---|---|
void | setHeader(String name,String value) | 设置消息头定时刷新 |
例:
resp.setHeader("Refresh","3;URL=要跳转的路径")
单位为秒
请求重定向
- 请求重定向:客户端的一次请求到达后,发现需要借助其他Servlet 来实现功能
- 特点:浏览器地址栏会发生改变,两次请求,请求域对象中不能共享数据,可以重定向到其他服务器
- 重定向实现原理
- 设置响应状态码为302:
resp.setStatus(302);
- 设置响应的资源路径(响应到哪里去,通过响应消息头 location 来指定):
resp.setHeader("location","/response/responseDemo")
- 设置响应状态码为302:
- 响应对象重定向方法
返回值 方法名 说明 void sendRedirect(String name) 设置重定向
文件下载
- 创建字节输入流,关联读取的文件
- 设置响应消息头支持的类型:
resp.setHeader("Content-Type","application/octet-stream")
Content-Type:消息头名称,代表所支持的类型
application/octet-stream:消息头参数,代表应用的类型为字节流 - 设置响应消息头以下载方式打开资源:
resp.setHeader("Content-Disposition","attachment;filename=下载的文件名称")
Content-Disposition:消息头名称,代表处理形式
attachment;filename=xxx:消息头参数,代表附件的形式进行处理,filename代表指定下载文件的名称 - 通过响应对象获取字节输出流对象
- 循环读写
- 释放资源
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 创建字节输入流,关联读取的文件
String realPath = req.getServletContext().getRealPath("/img/tx.png");
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(realPath));
// 设置响应消息头支持的类型
resp.setHeader("Content-Type", "application/octet-stream");
// 设置响应消息头以下载方式打开资源
resp.setHeader("Content-Disposition","attachment;filename=file.png");
// 通过响应对象获取字节输出流对象
ServletOutputStream os = resp.getOutputStream();
int len;
byte[] arr = new byte[1024];
while((len = bis.read(arr)) != -1){
os.write(arr, 0, len);
}
// 释放资源
bis.close();
}
学生管理系统2
- 创建一个 web 项目
- 在web 目录下创建一个 index.html,包含两个超链接标签(添加学生、查看学生)
- 在 web目录下创建一个 addStudent.html,用于实现添加功能的表单页面
- 在 src 下创建一个 Student 类,用于封装学生信息
// list.java
package studentServlet;
import studentServlet.bean.Student;
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.*;
import java.util.ArrayList;
@WebServlet("/list")
public class list extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
BufferedReader br = new BufferedReader(new FileReader("E:\\Java\\code\\StudentServlet\\stu.txt"));
ArrayList<Student> list = new ArrayList<>();
String str;
while((str = br.readLine()) != null){
String[] split = str.split(",");
Student stu = new Student(split[0], Integer.parseInt(split[1]), Integer.parseInt(split[2]));
list.add(stu);
}
resp.setContentType("text/html;charset=UTF-8");
PrintWriter pw = resp.getWriter();
for(Student student : list){
pw.write(student.getUsername() + "," + student.getAge() + "," + student.getScore());
pw.write("<br>");
}
br.close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
<!--index.html-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>学生信息管理系统</title>
</head>
<body>
<h1>学生信息管理系统</h1>
<hr>
<a href="/studentAdd.html">添加学生信息</a>
<a href="/list">查看学生信息</a>
</body>
</html>