下面就是浏览器的请求内容
package com.qfedu.http.response;
import jdk.internal.util.xml.impl.Input;
import java.io.*;
import java.net.Socket;
/**
* @Description
* @Author 千锋涛哥
* 公众号: Java架构栈
*/
public class MyBrowser {
public static void main(String[] args) throws IOException {
//将上一个案例中浏览器发送给 MyHttpServer的 http请求内容,发送给百度
// 1.向百度服务器发送链接请求
Socket socket = new Socket("www.baidu.com", 80);
// 2.通过链接中的输出流,将HTTP请求内容发送给百度
OutputStream outputStream = socket.getOutputStream();
PrintWriter out = new PrintWriter(outputStream);
out.println("GET /s HTTP/1.1");
out.println("Host: www.baidu.com:80");
out.println("Connection: keep-alive");
out.println("sec-ch-ua: \"Google Chrome\";v=\"95\", \"Chromium\";v=\"95\", \";Not A Brand\";v=\"99\"");
out.println("sec-ch-ua-mobile: ?0");
out.println("sec-ch-ua-platform: \"Windows\"");
out.println("Upgrade-Insecure-Requests: 1");
out.println("User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36");
out.println("Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9");
out.println("Sec-Fetch-Site: none");
out.println("Sec-Fetch-Mode: navigate");
out.println("Sec-Fetch-User: ?1");
out.println("Sec-Fetch-Dest: document");
out.println("Accept-Encoding: gzip, deflate, br");
out.println("Accept-Language: zh-CN,zh;q=0.9");
out.println("");
out.flush();
//3.通过输入流接受百度的响应数据(HTTP响应规则)
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String responseContent = null;
while( (responseContent = reader.readLine())!=null){
System.out.println(responseContent);
}
}
}
HTTP响应内容
如果创建项目的时候已经配置了,web服务器者可以直接按照上面的步骤执行即可,如果没有配置服务器则需要按照下面的方法配置服务器
通过浏览器发送请求,访问tomcat中web项目的servlet类
实现代码:
package com.qfedu.test1.dto;
/**
* @Description 图书实体类
* @Author 千锋涛哥
* 公众号: Java架构栈
*/
public class Book {
private String bookId;
private String bookName;
private String bookAuthor;
private double bookPrice;
private String bookImgPath;
//无参构造器
//全参构造器
//get 和 set方法
}
package com.qfedu.test1;
import com.qfedu.test1.dto.Book;
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.HashMap;
import java.util.Map;
/**
* @Description 根据图书ID查询一个图书信息
* @Author 千锋涛哥
* 公众号: Java架构栈
*/
@WebServlet("/book-query")
public class BookQueryServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("BookQueryServlet--------doPost");
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("BookQueryServlet--------doGet");
//动态生成HTML
// 1.接收到浏览器请求时传递的图书ID (bookId)
String bid = request.getParameter("bookId");
// 2.根据bid查询数据库图书表(伪代码)
Map<String, Book> bookMap = new HashMap<>();
bookMap.put("1001",new Book("1001","Java","张三",55.66,""));
bookMap.put("1002",new Book("1002","C++","李四",33.44,""));
bookMap.put("1003",new Book("1003","Python","王五",44.55,""));
// book就是根据用户请求查询到的动态数据
Book book = bookMap.get(bid);
// 3.将查询到图书信息生成网页,将网页响应给浏览器:通过IO流(输出流)向浏览器响应一个网页数据
// 这个out对象,就是用于响应浏览器的输出流,通过这个输出流写出什么数据,浏览器就可以接受到什么数据
// a.设置响应头
response.setCharacterEncoding("utf-8");
response.setContentType("text/html");
// b.通过输出流响应网页数据
PrintWriter out = response.getWriter();
out.println("");
out.println("");
out.println("这是Servlet响应的网页 ");
out.println("");
out.println("");
out.println("图书编号 图书名称 图书作者 图书价格 图书封面 ");
out.println("");
out.println(""+book.getBookId()+" ");
out.println(""+book.getBookName()+" ");
out.println(""+book.getBookAuthor()+" ");
out.println(""+book.getBookPrice()+" ");
out.println(""+book.getBookImgPath()+" ");
out.println(" ");
out.println("
");
out.println("");
out.println("");
out.flush();
out.close();
}
}
也就是说我们向服务器发送的请求会被封装成一个对象,所以我们下面要学的就是如何从这个对象中获取我们想要的信息
图书添加操作:需要从图书添加页面提交数据到Servlet
book-add.html
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>提交图书title>
head>
<body>
<form action="http://localhost/demo3/BookAddServlet" method="get">
<p>图书编号:<input type="text" name="bookId"/>p>
<p>图书名称:<input type="text" name="bookName"/>p>
<p>图书作者:<input type="text" name="bookAuthor"/>p>
<p>图书价格:<input type="text" name="bookPrice"/>p>
<p><input type="submit" value="Get提交"/>p>
form>
<hr/>
<form action="http://localhost/demo3/BookAddServlet" method="post">
<p>图书编号:<input type="text" name="bookId"/>p>
<p>图书名称:<input type="text" name="bookName"/>p>
<p>图书作者:<input type="text" name="bookAuthor"/>p>
<p>图书价格:<input type="text" name="bookPrice"/>p>
<p><input type="submit" value="Post提交"/>p>
form>
body>
html>
BookAddServlet
package com.qfedu.servlets;
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.io.InputStreamReader;
/**
* @Description 添加图书
* @Author 千锋涛哥
* 公众号: Java架构栈
*/
@WebServlet("/BookAddServlet")
public class BookAddServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//getParameter 方法参数字符串 必须要和 form表单中输入框的name属性一致
// 此方法获取的客户端提交的数据一律为String类型,根据需要可以进行类型转换
int id = Integer.parseInt(request.getParameter("bookId"));//5
String name = request.getParameter("bookName");
String author = request.getParameter("bookAuthor");
double price = Double.parseDouble(request.getParameter("bookPrice"));
System.out.println("图书编号:"+id);
System.out.println("图书名称:"+name);
System.out.println("图书作者:"+author);
System.out.println("图书价格:"+price);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 如果页面采用form表单post方式提交数据,数据是通过 请求正文 传递的
// 1.我们可以通过请求正文获取数据
//ServletInputStream inputStream = request.getInputStream();
//BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
//String s = reader.readLine();
//System.out.println("请求正文数据:"+s);
// 2.form表单post方式提交的数据,也可以通过request对象的getParameter方法接收,
// 之前是不能打开request输入流
int id = Integer.parseInt(request.getParameter("bookId"));//5
String name = request.getParameter("bookName");
String author = request.getParameter("bookAuthor");
double price = Double.parseDouble(request.getParameter("bookPrice"));
System.out.println("图书编号:"+id);
System.out.println("图书名称:"+name);
System.out.println("图书作者:"+author);
System.out.println("图书价格:"+price);
}
}
相应的环境搭建代码:
properties
# 数据库连接信息
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/test?characterEncoding=utf8
username=root
password=235374Hh
# 连接池属性
# 连接池的初始化连接数<创建数据库连接池时默认初始化的连接的个数>
initialSize=10
# 连接池的最大连接数
maxActive=50
# 最小空闲连接数(当数据库连接使用率很低时,连接池中的连接会被释放一部分)
minIdle=5
# 超时等待时间(单位:ms)
maxWait=30000
DruidUtils
public class DruidUtils {
//1.定义DruidDataSource对象:表示Druid数据库连接池(数据源)
private static DruidDataSource druidDataSource;
//2.静态代码块初始化定义DruidDataSource对象
static{
try {
//读取druid.properties文件中配置的属性
InputStream is = DruidUtils.class.getResourceAsStream("druid.properties");
Properties properties = new Properties();
properties.load(is);
//使用属性文件初始化DruidDataSource对象
druidDataSource =
(DruidDataSource) DruidDataSourceFactory.createDataSource(properties);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
//3.创建静态方法,从连接池对象中获取连接
public static Connection getConnection(){
Connection connection = null;
try {
connection = druidDataSource.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
return connection;
}
}
剩下的那些就不搞了,跟我们平时项目的思路不太一致
在ServletA中: |
---|
request.getRequestDispatcher(“ServletB的URL ”).forward(request,response); |
//ServletA:在转发操作之前,将需要传递给ServletB的参数设置到request对象中,可以传递不同类型数据
//设置转发传递的数据
request.setAttribute("stuNum","10001");
request.setAttribute("stuAge",21); //如果直接给简单类型数据,则会自动装箱为对应的封装类对象
request.setAttribute("stu",new Student(...));
//转发
request.getRequestDispatcher("ServletB的URL").forward(request,response);
//ServletB:在ServletB的doGet/doPost方法中,通过request对象获取ServletA传递的参数
//Object obj = request.getAttribute(String key);
String snum = (String)request.getAttribute("stuNum");
int sage = (Integer)request.getAttribute("stuAge");
Student stu = (Studennt)request.getAttribute("stu");
重定向是客户端的行为
浏览器对服务器发送了两次请求;
重定向是由浏览器再次发送请求,浏览器地址会改变为转发的地址;
不能通过request对象将ServletA中的数据传递给ServletB
如果ServletA重定向到ServletB的时候有数据要传递到ServletB该如何实现?——url传值
在ServletA中 |
---|
response.sendRedirect(“ServletB访问URL ”); |
//ServletA:在响应浏览器重定向地址的时候,在URL声明参数
response.sendRedirect("ServletB?key=value");
//ServletB: 获取浏览器请求的参数
String value = request.getParameter("key");
-创建两个Servlet类,分别为FirstServlet
和SecondServlet
Cookie cookie = new Cookie("key1", "value1");
cookie.setMaxAge(24*60*60);
response.addCookie(cookie);
package com.qfedu.servlets;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
* @Description 写Cookie
* @Author 千锋涛哥
* 公众号: Java架构栈
*/
@WebServlet("/FirstServlet")
public class FirstServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//向浏览器存储一个Cookie
// 1. 创建Cookie对象 (javax.servlet.http.Cookie)
Cookie cookie = new Cookie("key1", "value1");
// 设置cookie生命周期
// 情况1:如果设置>0的值,表示设置cookie有效时间(单位s)
// 情况2:如果参数=0,表示浏览器关闭销毁cookie
// 情况3:如果参数=-1,表示内存存储
cookie.setMaxAge(24*60*60);
// 2. 将cookie对象添加到HTTP响应头,写Cookie到客户端
response.addCookie(cookie);
//响应浏览器一个界面
//a.设置响应头
response.setStatus(200);
response.setContentType("text/html;charset=utf-8");
response.setCharacterEncoding("utf-8");
//b.响应正文
PrintWriter out = response.getWriter();
out.println("");
out.println("");
out.println("");
out.println("");
out.println(" ");
out.println("");
out.println("请求SecondServlet");
out.println("");
out.println("");
out.println("");
out.flush();
out.close();
}
}
Cookie[] cookies = request.getCookies();
String key = cookie.getName();
String value = cookie.getValue();
package com.qfedu.servlets;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @Description 读Cookie
* @Author 千锋涛哥
* 公众号: Java架构栈
*/
@WebServlet("/SecondServlet")
public class SecondServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 读取cookie: 当客户端再次请求服务器时,通过request将cookie传递到服务器
// 通过request对象获取浏览器传递的cookie
Cookie[] cookies = request.getCookies();
for (Cookie cookie: cookies) {
String key = cookie.getName();
String value = cookie.getValue();
System.out.println(key+"对应的值:"+value);
}
// SecondServlet暂时不响应浏览器
}
}
优点:
限制:
request中数据间可以流通的方式
在doFilter编写过滤业务规则,如果允许继续访问,则通过
filterChain.doFilter(servletRequest,servletResponse);
让客户端请求继续访问;如果不允许通行则可以通过servletResponse直接响应客户端(转发、重定向)。
package com.qfedu.filters;
import javax.servlet.*;
import java.io.IOException;
/**
* @Description
* @Author 千锋涛哥
* 公众号: Java架构栈
* 1.创建一个类实现javax.servlet.Filter接口
* 2.实现Filter接口中的init、doFilter、destroy抽象方法
* init 是过滤器初始化方法,用于获取过滤器的初始化参数等
* destory 是过滤器的销毁方法,用以释放资源
* doFilter 方法 用于定义过滤器的业务
* 3.在doFilter实现过滤器业务
*/
public class MyFilter01 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
System.out.println("~~~~~~MyFilter01");
//放行:运行继续执行浏览器请求的目标资源
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
}
}
配置过滤器拦截哪些服务器资源
<filter>
<filter-name>MyFilter01filter-name>
<filter-class>com.qfedu.filters.MyFilter01filter-class>
filter>
<filter-mapping>
<filter-name>MyFilter01filter-name>
<url-pattern>/FirstServleturl-pattern>
filter-mapping>
@WebFilter
注解 @WebFilter("/*")
public class MyFilter01 implements Filter {
//...
}
精确过滤: 配置过滤器拦截指定的请求url
例如:/FirstServlet,/index.html
后缀过滤: 配置过滤器拦截指定的后缀的请求url
例如:*.jpg 、 *.html
通配符过滤:
demo8/aaa/bbb/FirstServlet
或者 demo8/aaa/bbb/a.html
代码如下:
package com.qfedu.sgms.utils;
import com.qfedu.sgms.dto.Student;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
/**
* @Description 登录验证过滤器
* @Author 千锋涛哥
* 公众号: Java架构栈
*/
@WebFilter("/*")
public class LoginFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//1.因为此过滤器会拦截所有用户请求(包括受限资源和非受限资源)
// 所以当一个用户请求被拦截之后,我们需要知道这个请求的路径
// a.将ServletRequest转换成 HttpServletRequest
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
// b.通过request对象获取用户的请求路径
String uri = request.getRequestURI(); // ---- /demo4/IndexPageServlet
// c.截取uri最后一个/后的路径,即为请求路径
String requestPath = uri.substring( uri.lastIndexOf("/")+1 );
System.out.println("requestPath:"+requestPath);
//2.判断:如果请求路径是非受限资源则直接放行,如果是受限资源则需要验证用户是否登录
if("CheckServlet".equals(requestPath) || "login".equals(requestPath)){
//放行
filterChain.doFilter(servletRequest, servletResponse);
}else{
//进入else代码,表示此请求是受限资源,需要验证用户是否登录
//3.判断session中是否有用户信息,如果有则表示用户已经登录——放行
// 如果没有则表示用户未登录,转发到登录页面,提示请先登录
HttpSession session = request.getSession();
Student stu = (Student) session.getAttribute("stu");
if(stu != null){
filterChain.doFilter(servletRequest, servletResponse);
}else{
//转到到登录页面
request.setAttribute("tips","请先登录!");
request.getRequestDispatcher("login").forward(request,response);
}
}
}
@Override
public void destroy() {
}
}
表单post方式提交数据
设置表单的enctype=“multipart/form-data”,不对表单数据进行编码
<form action="BookSaveServlet" method="post" enctype="multipart/form-data">
<p>图书编号:<input type="text" name="bookId"/>p>
<p>图书名称:<input type="text" name="bookName"/>p>
<p>图书封面:<input type="file" name="bookImg"/>p>
<p><input type="submit" value="提交"/>p>
form>
在Servlet类前添加@MultipartConfig
注解,赋予当前Servlet类处理未编码提交的数据的能力;
通过request对象调用getPart(key)
或者getParts()
方法接收文件
package com.qfedu.servlets;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
import java.io.IOException;
import java.util.Collection;
/**
* @Description 接收图书信息并保存
* @Author 千锋涛哥
* 公众号: Java架构栈
*/
@WebServlet("/BookSaveServlet")
@MultipartConfig
public class BookSaveServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//1.设置utf-8编码
request.setCharacterEncoding("utf-8");
//2.接收普通文本
//当网页提交数据的表单设置了enctype="multipart/form-data"之后不能直接使用getParameter接收文本数据
//需要在当前serlvet类添加 @MultipartConfig 用于处理非压缩提交的数据
String id = request.getParameter("bookId");
String name = request.getParameter("bookName");
System.out.println("id:"+id );
System.out.println("name:"+name );
//3. 接收表单提交的图片
// getPart("输入框name属性"): 接收表单中的文件
Part bookImg = request.getPart("bookImg");
System.out.println(bookImg);
// getParts(): 接收表单中所有文件
//Collection parts = request.getParts();
//4.保存图片
}
}
在web工程的web目录下新建一个files
目录(保存文件的目录如果不在web服务器上,用户将无法访问)
在files
目录先放一个任意的文件(空的目录在进行项目部署的时候不会在web服务器中创建)
//4.保存图片
// a.获取files目录在web服务器上的路径(不是工作空间的路径)
ServletContext servletContext = getServletContext();
String dir = servletContext.getRealPath("/files");
// b.给上传的文件重命名 (不同用户有可能上传相同名称的图片,如果不重命名将导致文件覆盖)
// 文件重命名后缀名不能改变
String header = bookImg.getHeader("Content-Disposition"); //form-data; name="bookImg"; filename="千锋武汉(横版).jpg"
// 截取上传的文件的后缀名
int begin = header.lastIndexOf(".");
int end = header.lastIndexOf("\"");
String ext = header.substring(begin, end);
// 取名(时间毫秒数、UUID、雪花算法)
String fileName = UUID.randomUUID().toString()+ext;
//c.存储文件到目录
bookImg.write(dir+"\\"+fileName);
//5.将图书信息保存到数据库: 保存到数据库的是图片的访问路径(不是绝对路径)
Book book = new Book(id, name, "files/" + fileName);
//调用BookDAO 将book对象保存到数据库
在项目的files
目录添加几个待下载的图片
创建文件下载的Servlet类FileDownloadServlet
创建文件列表的静态网页:在web目录下创建file-list.html
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<img src="files/img01.png" height="100"/><br/>
<a href="FileDownloadServlet?fileName=img01.png">下载a><br/>
<img src="files/img02.png" height="100"/><br/>
<a href="FileDownloadServlet?fileName=img02.png">下载a><br/>
<img src="files/img03.png" height="100"/><br/>
<a href="FileDownloadServlet?fileName=img03.png">下载a><br/>
body>
html>
package com.qfedu.servlets;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.IOException;
/**
* @Description
* @Author 千锋涛哥
* 公众号: Java架构栈
*/
@WebServlet("/FileDownloadServlet")
public class FileDownloadServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//1.接收客户端传递过来的文件名(即为要下载的文件)
String fileName = request.getParameter("fileName"); //img01.png
//2.获取存储文件的files目录路径
ServletContext servletContext = getServletContext();
String dir = servletContext.getRealPath("/files");
// 拼接要下载的文件路径
String filePath = dir+"\\"+fileName;
//3.设置响应头
//设置响应的类型如果浏览器无法识别则会提示另存为
response.setContentType("application/image");
response.addHeader("Content-Disposition","attachment; fileName="+fileName);
//4. 通过IO流将文件数据响应给浏览器(文件是二进制数据,所以获取字节流)
ServletOutputStream outputStream = response.getOutputStream();
// 读取服务文件,写给客户端
FileInputStream fis = new FileInputStream(filePath);
byte[] bs = new byte[1024];
int len = -1;
while( (len = fis.read(bs))!=-1){
outputStream.write(bs,0,len);
}
outputStream.close();
fis.close();
}
}