xi## web服务与web浏览器
1、Web服务器用于存储网站的所有信息和数据;而Web浏览器是用来访问和定位这些信息和数据。
2、Web浏览器发送HTTP请求,获取HTTP响应,并显示Web文档,而Web服务器获取HTTP请求,生成响应,并接受客户端数据。
3、Web浏览器用于通过网络与Web服务器链接。
4、Web服务器的主要组件是服务器核心,服务器核心64位二进制文件,应用程序,管理命令行界面等;而Web浏览器的组件是用户界面,UI后端,布局和渲染引擎,以及网络和数据持久性零件。
web服务器只起存储功能,web浏览器获取文档并展示,通过http协议通信。
静态网页与动态网页
如浏览器存储的静态网页,那么用户只能获取特定的一些网页,都是静态填充好的。如果存储的是动态网页,动态网页是需要汇编语言解析的。页面会动态的发生变化,就是服务器对用户行为做出相应的反应。汇编语言的运行需要相应的运行时环境如java的jre,而且数据也是汇编语言从数据库中获取的。
总结来说,web服务器就是搭载汇编语言运行时环境的,具有存储功能的,能提供http服务的软件。
web容器
处理动态网页的汇编语言有多种如java,python,js等,如果服务器存储多种不同的动态网页,就需要不同的运行时环境,所以就要有不同的线程来处理不同的内容。这就是web容器,不同容器中处理不同的动态网页。web容器并不直接对接http服务,而是web服务器解析后将文档共享给web容器,web容器随数据生成动态网页后将文档返回给web服务器,再由起封装http协议。而servlet就是java处理动态网页的容器
servlet简介
servlet就是一个web容器,其主要功能就是解析动态网页。同时Servlet 也是运行在带有支持 Java Servlet 规范的解释器的 web 服务器上的 Java 类。(也就是说,编写一个servlet类,存储在web服务器中,那么它就成为服务器处理java web的web容器)再这个类中解析动态网页。其通过 javax.servlet 包创建。servlet运行在服务器端,需要服务器软件。创建一个web容器就是创建一个servlet类,然后编写处理动态网页的代码。
访问一个动态网页的过程,实际上是将对应的 Servlet 类加载、实例化的过程。
servlet生命周期
Servlet 生命周期可被定义为从创建直到毁灭的整个过程。以下是 Servlet 遵循的过程:
- Servlet 通过调用 init () 方法进行初始化。
init 方法被设计成只调用一次。它在第一次创建 Servlet 时被调用,在后续每次用户请求时不再调用。
Servlet 创建于用户第一次调用对应于该 Servlet 的 URL 时,也可以指定 Servlet 在服务器第一次启动时被加载。当用户调用一个 Servlet 时,就会创建一个 Servlet 实例,每一个用户请求都会产生一个新的线程,适当的时候移交给 doGet 或 doPost 方法。init() 方法简单地创建或加载一些数据,这些数据将被用于 Servlet 的整个生命周期。
- Servlet 调用 service() 方法来处理客户端的请求并返回数据。
Servlet 容器调用 service() 方法来处理的请求,并把格式化的响应返回。每次服务器接收到一个 Servlet 请求时,服务器会产生一个新的线程并调用服务。service() 方法检查 HTTP 请求类型(GET、POST、PUT、DELETE 等),调用 doGet、doPost、doPut,doDelete 等方法。
- Servlet 通过调用 destroy() 方法终止,servelt不要响应,动态页面无法访问。
Servlet 容器关闭、重启或移除 Servlet 实例时,容器就会调用 destory() 方法,释放该实例使用的资源,例如:关闭数据库连接,关闭文件的输入流和输出流等。
- 最后,Servlet 是由 JVM 的垃圾回收器进行垃圾回收的。
servlet实现类
Servlet 规范的最顶级是一javax.servlet.Servlet 的接口,所有的 Servlet 类都要直接或者间接地实现该接口。Servlet 接口 又内置了两个接口的实现类(抽象类),分别为 GenericServlet 和 HttpServlet。
- 如果直接实现 javax.servlet包下的Servlet 接口,就要重写其全部方法。
//导入javax.servlet包下的Servlet接口
import javax.setvlet.Servlet
public class MyMervlet implements Servlet{
//Servlet 实例被创建后,调用 init() 方法进行初始化,该方法只能被调用一次
@Override
public void init(ServletConfig servletConfig) throws ServletException {
}
//每次请求,都会调用一次 service() 方法
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
//设置字符集
servletResponse.setContentType("text/html;charset=UTF-8");
//使用PrintWriter.write()方法写入文档,由web服务器封装http包响应浏览器
PrintWriter writer = servletResponse.getWriter();
writer.write("Hello Servlet");
writer.close();
//浏览器接收http包后解析,导出文档,当作html运行,Hello Servlet就打印了
}
//Servelet 被销毁时调用
@Override
public void destroy() {
}
//返回 ServletConfig 对象,该对象包含了 Servlet 的初始化参数
@Override
public ServletConfig getServletConfig() {
return null;
}
//返回关于 Servlet 的信息,例如作者、版本、版权等
@Override
public String getServletInfo() {
return null;
}
}
- 继承 GenericServlet 抽象类创建 Servlet,只重写service方法
import javax.setvlet.Servlet.GenericServlet
//其他的方法官方已经编写,如果不满足需要也可以重写
public class ServletDemo extends GenericServlet {
@Override
public void service(ServletRequest arg0, ServletResponse arg1)
throws ServletException, IOException {
......
}
}
GenericServlet实现类除了继承Servlet的方法外还实现了新的方法:
- javax.servlet.http.HttpServlet 抽象类,继承了GenericServlet抽象类,它只需要重写service中针对http服务的那部分。在GenericServlet抽象类需要在service方法中写判断逻辑是get还是post等方法,然后再去写对应的处理逻辑,但是在.HttpServlet 抽象类,不需要在写判断逻辑,继承的service方法中已经写好了判断的逻辑而且调用了对应的处理逻辑的方法,(方法写在serice外部,在serice中调用)这些方法是抽象方法没有方法体,只需要在器继承类中重写的处理逻辑就可以了。如下图
Servlet、GenericServlet和HttpServlet之间的关系感谢作者的图@Lin_Dong_Tian
在继承类的对应的请求方法内部写处理逻辑就可以了。实例开发中请求的方法一般都是get或post,其他比较少用
public class MyServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//设置处理请求的编码格式
request.setCharacterEncoding("utf-8");
//设置响应文档的编码格式
response.setContentType("text/html;charset=UTF-8");
//IO输出流输出处理后的文档
PrintWriter writer = resp.getWriter();
writer.write("Hello World");
writer.close();
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//一次请求不管请求方法是什么,处理逻辑都是相同的
doGet(request, response);
}
}
构建工程化项目结构
在编写servlet容器时,IDE中肯定不会只放servlet,如果需要访问数据路,还需要orm模型,需要jdbc的的开发工具包,配置servlet的路径的配置文件web.xml,java源码等,那么这些都该放在什么地方呢?那个目录下呢?这就需要构建工程化的项目了,对应的文件放在对应的目录才不会出错。
- 在eclispe中:
选择 Dynomic web project动态网页项目
点击Target runtime行末的New Runtime,选择Apache下的相应的Tomcat服务器版本,创建的目录如下:
src中存放java源码,WEB-INF存放编译后的.class文件,lib存放需要的jar工具包(后俩不需要管),主要把要用的包导入到lib下就可以了。build时写完后打包存放的目录。src的mvc架构需要自己建。当然也可以学maven,直接建maven project更方便。
在package中新建可以直接建servlet,运行时需要配置Tomcat
点击add,查找下载的路径到如下的目录即可
package controller;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/Servlet_01")
public class Servlet_01 extends HttpServlet {
private static final long serialVersionUID = 1L;
public Servlet_01() {
super();
// TODO Auto-generated constructor stub
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
response.getWriter().write("Hello World");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
//继承httpservlet之前有一个注解@WebServlet(“/Servlet_01”)这是对servlet的路径配置。
也可以建web.xml配置。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0" metadata-complete="true">
<servlet>
<servlet-name>MyServlet</servlet-name>
<servlet-class>controller.Servlet_01</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyServlet</servlet-name>
<url-pattern>/controller</url-pattern>
</servlet-mapping>
</web-app>
<web-app>: 根元素。
<servlet> :用于注册 Servlet,即给 Servlet 起一个独一无二的名字。
<servlet> 包含两个主要的子元素 <servlet-name> 和 <servlet-class>,分别用于指定 Servlet 的名称和 Servlet 的完整限定名(包名+类名)。
<servlet-mapping> :用于定义 Servlet 与 URL 之间的映射。
<servlet-mapping> 包含两个子元素 <servlet-name> 和 <url-pattern>,分别用于指定 Servlet 的名称和虚拟路径。
load-on-startup 是 web.xml 中的一个节点,是 servlet 元素的子元素,用来标记 Servlet 容器启动时是否初始化当前 Servlet,以及当前 Servlet 的初始化顺序。
- 在idea中:
idea和eclipse原理都一样,都是那几个目录,自行参考把,也可以看之前的文章iead创建web工程化项目。
处理请求逻辑的对象 HttpServletRequest
http携带的参数被处理后封装在 HttpServletRequest对象中,对该对象解析可以获取客户端信息以及请求的相关信息。
HTTP 请求消息分为请求行、请求消息头和请求消息体三部分,所以 HttpServletRequest 接口中定义了获取请求行、请求头和请求消息体的相关方法。
- 获取请求行信息
HTTP 请求的请求行中包含请求方法、请求资源名、请求路径等信息,HttpServletRequest 接口定义了一系列获取请求行信息的方法,如下表。
用于获取参数的方法:
- 获取请求行GET方法的数据
😒
😮
😒
😐
- a标签的超链接发送get请求,参数直接传递给url,再由浏览器封装http协议。
- form表单发送get请求,再由浏览器封装http协议。
- 调用Javascript的xmlhttprequest对象发送get请求。
get请求只能发送application/x- www-form-urlencoded格式的数据,像form表单和a标签都是这种类型。该类型的请求内容提供了request.getParameter()方法来获取请求参数值。
- 获取请求头信息
当浏览器发送请求时,需要通过请求头向服务器传递一些附加信息,例如客户端可以接收的数据类型、压缩方式、语言等。HttpServletRequest 接口定义了一系列用于获取 HTTP 请求头字段的方法。
- 获取请求体信息获取POST请求数据
请求体主要是封装请求携带的数据的,请求体的数据一般没有大小限制(请求行有限制)。而且不想get有数据类型的限制,post方法可以发送多种数据类型的数据,也更安全。请求体的内容发送到服务器后会直接通过IO输入流写入缓冲区。HttpServletRequest 接口定义了一系列用于获取 HTTP 请求体内容的方法。
返回值类型 | 方法声明 | 描述 |
---|---|---|
BufferedReader | getReader() | 该方法用于获取写入请求体写入缓冲区中的字符流数据 |
InputStream | getInputStream() | 该方法用于获取请求体传递的字节流数据 |
- 设置请求信息
方法声明 | 描述 |
---|---|
setCharacterEncoding() | 该方法用于设置解析请求数据的编码格式 |
处理响应逻辑的对象HttpServletResponse
Servlet 容器会针对每次请求创建一个 response 对象,并把它作为参数传递给 Servlet 的 service 方法。Servlet 处理请求后,会将响应信息封装到 response 对象中,并由容器解析后返回给客户端。
返回类型 | 方法声明 | 描述 |
---|---|---|
OutputStream | getOutputStream() | 该方法用于创建文件并存储二进制数据 |
PrintWriter | getWriter() | 该方法用于创建文件并存储字符数据 |
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/Servlet_01")
public class Servlet_01 extends HttpServlet {
private static final long serialVersionUID = 1L;
public Servlet_01() {
super();
// TODO Auto-generated constructor stub
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
request.setCharacterEncoding("utf-8");
PrintWriter out=response.getWriter();
out.write("Hello World");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
servlet转发与重定向
请求转发就是将该页面的请求和响应对象转发到其他servlet中,实现共用一次http请求。如果需要添加其他数据servlet也提供了域对象用于存储额外数据。
方法声明 | 描述 |
---|---|
getRequestDispatcher().forward(req,res) | 该方法将域对象转发到其它servlet中,参数是路径 |
setAttribute() | 该方法用于将请求信息存储到请求域中,其功能是实现servlet之间的通信(servlet之间传递数据) |
getAttribute() | 该方法用于获取存储在请求域的数据 |
removeAttribute() | 该方法用于删除域对象的数据 |
getAttributeNames() | 该方法用于返回 request 对象中的所有属性名的枚举集合 |
request.getRequestDispatcher("/servlet_01").forward(req,res);
响应重定向就是跳转到其他网页,重定向请求数据就都丢失了。
方法声明 | 描述 |
---|---|
sendRedirect() | 该方法用于让浏览器访问新的 URL |
response.sendRedirect("www.baidu.com");
Session与Cookie
- 会话技术
从打开浏览器访问某个网站,到关闭浏览器的过程,称为一次会话。会话技术是指在会话中,帮助记录用户状态和数据的技术。
常用的会话技术分为两种:
- Cookie :客户端会话技术
- Session :服务端会话技术
Cookie
Cookie分为两种:
- 会话级别 Cookie(默认):Cookie 保存到浏览器的内存中,浏览器关闭则 Cookie 失效。
- 持久的 Cookie:Cookie 以文本文件的形式保存到硬盘上。
会话级别的Cookie用于服务器识别不同的浏览器,持久Cookie用于保存用户状态或用户数据。例如当你关闭浏览器后,便于服务器断开连接session销毁了,但再打开发现仍然处于登录状态,这就是持久的cookie的将用户信息存储在cookie中,发送到服务器直接用cookie中的信息登录,然后返回登录状态。
- servlet提供Cookie的API用于操作cookie
Cookie cookie = new Cookie("key","value");
javax.servlet.http 包中定义了一个 Cookie 类,利用它的带参构造方法,可以创建 Cookie 对象。第一会话是没有发送cookie的,因为cookie再服务器生成,并响应增加到http响应头中。
javax.servlet.http.Cookie 类中提供了一系列获取或者设置 Cookie 的方法:
Session
Session 是服务器端会话技术。当浏览器访问 Web 服务器的资源时,服务器可以为每个用户浏览器创建一个 Session 对象,每个浏览器独占一个 Session 对象。
session与cookie是相辅相成的,浏览器第一次访问服务器会自动生成session,返回个浏览器作为浏览器的cookie,之后再带cookie发送浏览器就能识别是哪个了。
session只有会话级别,存储再服务器端的内存中,随服务器的关闭而销毁,当也可以编程式销毁。
- servlet提供Session API用于操作session
HttpSession session=request.getSession();
+URL 重写维持服务器端会话
如果cookie被禁用的话,浏览器无法接收cookie对象,可以通过url重写来维持会话状态。在每个 URL 末尾追加一些额外的数据来标识 session 会话,服务器会把该 session 会话标识符与已存储的有关 session 会话的数据相关联。例如,http://w3cschool.cn/file.htm;sessionid=12345,session 会话标识符被附加为 sessionid=12345,标识符可被 Web 服务器访问以识别客户端。
URL 重写是一种更好的维持 session 会话的方式,它在浏览器不支持 cookie 时能够很好地工作
servlet处理文件上传
<input type="file" accept=".doc,.docx,.pdf,.txt,.htm,.html" />
当type类型为file时,浏览器会调用系统的文件资源管理器,打开文件夹选择文件然后上传资源。
一般上传的资源有: 文件,文件夹,图片,视频等 对于文件,图片,视频必须先解析为二进制流,再传递,然后再合成。例如图片也可以在上传时解析为base64的字符串传递,文件也可以。Apache提供了专业的工具来完成这一过程。FileUpload工具,有了这个神奇的工具,我们只需要选择要上传的文件,交由工具处理,然后在web容器(Servlet)按照官方提供的方法获取它并存储到指定位置就可以了,两款强有力的工具包。commons-fileupload-1.4-bin.zip和commons-io-2.11.0-bin.zip。
对于文件夹的话就需要先压缩了了,将压缩包传给服务器。
文件上传的流程:
- 前端接口
<form action="/ServletDemo/FileUpload" method="post" enctype="multipart/form-data">
<input type="file" name="file" size="50" />
<br />
<input type="submit" value="上传文件" />
</form>
//action是要提交的地址用同一个ide开发就是相对路径,分离就是绝对路径
//方法必须是post文件一般很大,只能由post
//enctype必须是multipart/form-data,它不对字符进行编码,用于发送二进制的文件。
//application/x-www-form-urlencoded只用于发送key-value的字符类型数据。
//text/plain用于发送纯文本内容。
2 . 引入工具包
引入到WEN-IN的lib目录下,没有就新建。
右键点击Build Path
在Referrenced Libraries中出现同样的jar包后即可了,目的是配置路径需要调用的时候知道工具包在哪。
- 根据根据工具包提供的类获取并解析上传的文件。
FileUpload 对象
在 HTML 文档中<input type="file">
标签每出现一次,一个 FileUpload 对象就会被创建。
该元素包含一个文本输入字段,用来输入文件名,还有一个按钮,用来打开文件选择对话框以便图形化选择文件。
该元素的 value 属性保存了用户指定的文件的名称,但是当包含一个 fileupload 元素的表单被提交的时候,浏览器会向服务器发送选中的文件的内容而不仅仅是发送文件名。可以通过遍历表单的 elements[] 数组,或者通过使用 document.getElementById()来访问 FileUpload 对象。
Apache提供的两个工具包就是来解析发送的文件的。工具包提供了:
顶级类
org.apache.commons.fileupload类来处理HTML文件上传的组件。
子类及接口
org.apache.commons.fileupload.disk接口的基于磁盘的实现。
org.apache.commons.fileupload.servletFileUpload在servlet中使用的实现
还有另一个包的io流处理工具
org.apache.commons.io.*
//引入工具包,确保classpth中有响应的环境
import org.apache.commons.fileupload.disk.*;
import org.apache.commons.fileupload.servlet.*;
import org.apache.commons.io.*;
//servlet处理文件
public class UploadServlet extends HttpServlet {
//文件上传只能用post方法
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, java.io.IOException {
//调用工具包的servlet的实现类ServletFileUpload,用于获取前端的FileUpload对象
//isMultipartContent()用于判断是否为文件上传
private boolean isFileUpload=ServletFileUpload.isMultipartContent(request);
//true···false 的判断逻辑就不写了,只写上传的主体
//fileUpload的最终实现类,获取的文件以这个类接收并处理处理
DiskFileItemFactory factory = new DiskFileItemFactory();
//上面接收的文件需要io流输出但前提是先配置好其基本信息
/*默认输出流在内存中接收,如果文件过大损耗服务器资源,
setSizeThreshold()设置写入内存的阈值,大于会创建临时文件写入磁盘
()中是字节 100*1024=100 kb
1 B=8bit (1 字节= 8 比特)
*/
//返回用于临时存储大于配置大小阈值的文件的目录。
factory.setSizeThreshold(100*1024);
//设置临时文件
factory.setRepository(new File("c:\\Tomcat\\webapps\\data"));
//文件对象及配置信息返回到servlet,由其处理
/*
上面对文件的处理只是工具包在完成,需要上传到服务器就要用servlet接口的ServletFileUpload的实现来处理
*/
ServletFileUpload upload = new ServletFileUpload(factory);
//允许文件上传的最大值
upload.setSizeMax( 1024*1024 );
//ServletFileUpload实现类的parseRequest(request)用于处理 multipart/form-data 类型的表单数据流,返回类型为List
// 解析请求,获取文件项
List fileItems = upload.parseRequest(request);
/*经过上面的解析以及获取到了文件的字节流数据并用List存储起来,
那么那些是文件的信息那些是内容呢?还需要对List解析提出文件信息和文件内容
*/
/*
<input type="file">提交的是一个fileUpload类型,和工具包fileupload下的FileItem是同一数据类型,接收的文件或表单项。该类中提供了许多方法来获取表单项或数据。
*/
//Iterator循环List提出文件内容的字节流写入文件
Iterator i = fileItems.iterator();
while ( i.hasNext () ) {
//将元素强转FileItem类调用isFormField ()判断是否为表单项
FileItem fi = (FileItem)i.next();
if ( !fi.isFormField () ){
// 获取后缀名
String fieldName = fi.getFieldName(); //
//获取文件名
String fileName = fi.getName();
//回由浏览器传递的内容类型,如果未定义则为空。
String contentType = fi.getContentType();
//提供关于是否将从内存读取文件内容的提示。
boolean isInMemory = fi.isInMemory();
//获取文件大小
long sizeInBytes = fi.getSize();
//根据获取的参数创建文件写入内容
//判断结尾
if( fileName.lastIndexOf("\\") >= 0 ){
//创建文件对象
file = new File( filePath +
fileName.substring( fileName.lastIndexOf("\\"))) ;
}else{
file = new File( filePath +
fileName.substring(fileName.lastIndexOf("\\")+1)) ;
}
//FileItem的write方法将内容写入磁盘,这里判断是内容后才写入的磁盘
fi.write( file ) ;
//打印成功
out.println("Upload Successfull: " + fileName + "<br>");
}
}
}
//doGet方法直接返回错误
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, java.io.IOException {
response.getWriter().write("POST method required !");
}
}
过滤器 Servlet Filter
filter简介
过滤器能够对传给 Servlet 容器的Web 资源的 request 对象和 response 对象进行检查和修改。
主要有以下功能:
- 在客户端的请求访问后端资源之前,拦截这些请求。
- 在服务器的响应发送回客户端之前,处理这些响应。
其具体实现又有不同的类型:
- 身份验证过滤器(Authentication Filters)。
- 数据压缩过滤器(Data compression Filters)。
- 加密过滤器(Encryption Filters)。
- 触发资源访问事件过滤器。
- 图像转换过滤器(Image Conversion Filters)。
- 日志记录和审核过滤器(Logging and Auditing Filters)。
- MIME-TYPE 链过滤器(MIME-TYPE Chain Filters)。
- 标记化过滤器(Tokenizing Filters)。
- XSL/T 过滤器(XSL/T Filters),转换 XML 内容。
过滤器被部署在部署描述符文件 web.xml 中,然后映射到您的应用程序的部署描述符中的 Servlet 名称或 URL 模式。当 Web 容器启动 Web 应用程序时,它会为您在部署描述符中声明的每一个过滤器创建一个实例。该过滤器执行的顺序是按它们在部署描述符中声明的顺序。
filter实现类及方法
过滤器要实现 javax.servlet.Filter 接口,并定义了 3 个方法,如下:
返回值类型 | 方法 | 描述 |
---|---|---|
void | init (FilterConfig filterConfig) | 该方法用于初始化过滤器。 |
void | doFilter(ServletRequest request,SeivletResponse response, FilterChain chain) | 当客户端请求的 URL 与过滤器映射的 URL 匹配时,容器会先调用该方法对请求进行拦截。对参数 request 和 response 进行处理,参数 chain 代表当前 Filter 链对象,在该方法内部,调用 chain.doFilter() 方法,才能把请求交付给 Filter 链中的下一个 Filter 或者 Web 资源。 |
void | destroy() | 销毁 Filter 对象释放被占用的资源 |
//注册过滤器
<filter>
<filter-name>MyFilter</filter-name>
<filter-class>controller.MyFilter</filter-class>
<init-param>
//初始化参数
<param-name>prop</param-name>
//参数值
<param-value>Hello Filter</param-value>
</init-param>
</filter>
//配置映射
<filter-mapping>
<filter-name>MyFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
//Filter 的 init 方法中提供了一个 FilterConfig 对象,来获取初始化参数值。
public void init(FilterConfig config) throws ServletException {
// 获取初始化参数
String prop = config.getInitParameter("prop");
// 输出初始化参数
System.out.println(prop);
}
web.xml配置后就可以写处理逻辑了:
// 实现 Filter 类
public class MyFilter implements Filter {
static String username;
Static String password;
public void init(FilterConfig config)
throws ServletException{
// 获取初始化参数
String prop = config.getInitParameter("prop");
// 密码加上初始化参数值用于加密,存储数据库的话
password=password+prop;
}
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain)
throws java.io.IOException, ServletException {
//传递加密后的密码
request.setAttribute("username",username);
request.setAttribute("password",password);
// 把请求传回过滤链
chain.doFilter(request,response);
}
public void destroy( ){
/* 在 Filter 实例被 Web 容器从服务移除之前调用 */
}
}
监听器 Servlet Listener
监听器 Listener 是一个实现特定接口的 Java 程序,这个程序专门用于监听另一个 Java 对象的方法调用或属性改变,当被监听对象发生上述事件后,监听器某个方法将立即自动执行。
- 监听对象
Servlet 规范中定义了 8 个监听器接口,用于监听ServletContext、HttpSession 和 ServletRequest 对象的生命周期和属性变化事件 - 监听器分类
监听对象创建和销毁的监听器
- 监听器注册
监听器的注册同样有两种方式,在 web.xml 中注册监听器;使用 @WebListener 注册监听器。
在 web.xml 中使用 标签配置监听器,Web 容器会自动把监听器注册到事件源中
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<listener>
<listener-class>controller.Servlet</listener-class>
</listener>
</web-app>
@WebListener 注解,可以将该 Java 类注册为一个监听器
利用Servlet和Filter统计网站访问量
原理:对于网站的访问不仅仅限于登录,未登录的访问也要统计。进入一个网页首先肯定会跳转到首页,在首页之前写一个servlet,然后跳转到首页,在servlet的路径下创建一个txt文件为一个时间和同一时间下访问次数(2022-02-120),在servlet的doGet方法或doPost方法中获取通过IO读取文件把0解析出来,通过与当前时间判断,相同就加一,不同就把旧的值写入到数据库,把新时间写入并赋值为1,然后再写入文件。这样每发送一个处理一个请求就相当于访问了一次。数据库也记录了每日的访问量。
//处理逻辑
Date time=new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String timeFormat = sdf.format(time);
//System.out.println(timeFormat);
String path=getServletConfig().getServletContext().getRealPath("/");
File file=new File(path+"total.txt");
BufferedReader reader= null;
reader = new BufferedReader(new FileReader(file));
int result=0;
String shijian="";
String params;
while ((params=reader.readLine())!=null){
result=result+Integer.parseInt(params.substring(10));
shijian=shijian+params.substring(0,10);
}
//System.out.println(result);
reader.close();
result=result+1;
//System.out.println(result);
FileWriter writer=new FileWriter(path+"total.txt");
if(shijian.equals(timeFormat)){
writer.write(String.valueOf(timeFormat)+String.valueOf(result));
}
else {
writer.write(String.valueOf(timeFormat)+"0");
}
writer.flush();
writer.close();
SqlSessionFactory sqlSessionFactory11=new SqlsessionFactory().SqlsessionFactory();
SqlSession session11=sqlSessionFactory11.openSession();
BrwoerMapper mapper11=session11.getMapper(BrwoerMapper.class);
List<String> list11=mapper11.selectIf(timeFormat);
if (list11.size()==0){
//System.out.println("no...");
mapper11.insertOne(result, timeFormat);
}
else {
//System.out.println("yes...");
mapper11.updateOne(result, timeFormat);
}
session11.commit();
session11.close();
文件
这端字符按String存储再解析程int类型,时间xxxx-xx-xx的格式是固定的,确保其后面的都是次数。注意代码上是时间不同就会插入到数据库,再初始化,不同是累加,所以第二天才会把前一天的访问量插入到数据库中。
filter原理一样,就不需要新建一个servlet直接再doFilter方法中写处理逻辑。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/156318.html