学Servlet
之前,我们首先得学Tomcat
服务器。Tomcat
是一个Web服务器(同时也是Servlet
容器),通过它我们可以很方便地接收和返回到请求。可以结合下面两篇文章一起看
Tomcat
基本认识:https://blog.csdn.net/qq_47256069/article/details/117199512
IDEA
配置Maven
+Tomcat
构建Web项目:https://blog.csdn.net/qq_47256069/article/details/116140082
什么是Servlet?
Servlet
是JavaEE规范之一,规范就是接口。Servlet
是JavaWeb
三大组件之一,三大组件分别是:Servlet程序、Filter过滤器和Listener监听器。它是一个能够实现动态web页面,在 JavaWeb 项目中,它可以接受客户端发过来得请求,并响应数据给客户端,Servlet
其实就是一个遵循Servlet
开发的java
类,Serlvet
是由服务器调用的,运行在服务器端(例如Tomcat
服务器上)
在开始之前先了解一下/
(斜杠)路径的问题(所有的相对路径在工作时候都会参照当前浏览器地址栏中的地址来进行跳转)
第一种
/
如果被浏览器解析,得到的地址是http://ip:port/
(例如表单、还有a标签、请求重定向等)
<a href="/">a标签a>
...
第二种
/
如果被服务器解析,得到的地址是http://ip:port/工程路径/
(且映射到IDEA
就是Web工程
,这里的Web工程
就是webapp目录
)
//例如Servlet程序的
req.getRequestDispatcher("/logout.html").forward(req,resp);//‘/’后面的内容表示的是webapps的子目录即某一项目名称
...
或者是…(下面例子)等
<url-pattern>/showurl-pattern>
Servlet
的核心技术是Servlet
,我们编写Servlet
程序必须直接或者间接实现的一个接口。在学Servlet
的时候,我们先了解一下Servlet
的生命周期和继承体系
Servlet生命周期大致可以分为4个步骤
Servlet
构造器方法,加载Servlet
的时候。如果Tomcat第一次访问Servlet
的时候,Tomcat会负责创建Servlet
的实例(第一次访问Servlet程序的时候,构造器、init()
和service()
都被调用了)init()
初始化方法,init
英译过来是初始化的意思,当Servlet
被实例化后,Tomcat会调用init()
方法初始化这个对象。service()
方法,所有的请求都是service()
方法处理的,当浏览器访问Servlet
程序的时候,Servletservice()
方法处理请求(第二次访问Servlet程序的时候,service()
被调用了,每次访问都会调用)destroy()
销毁方法,当web工程停止的时候会自动调用destroy()
方法(注意:一个Servlet如果长时间不被使用的话,也会被Tomcat自动销毁)package javax.servlet;
//Servlet容器将Servlet类载入内存,并产生Servlet实例和调用它具体的方法。但是要注意的是,在一个应用程序中,每种Servlet类型只能有一个实例。
public interface Servlet {
//第一次访问Servlet程序的时候,init()和service()都被调用了
void init(javax.servlet.ServletConfig servletConfig) throws javax.servlet.ServletException;
//GetServletConfig():返回一个ServletConfig对象,该对象中包含了web.xml文件中元素初始化参数信息(例如你想获取当前Servlet在web.xml文件中的配置名,那么可以使用servletConfig.getServletName()方法来获取!)
javax.servlet.ServletConfig getServletConfig();
//service方法是专门用来处理请求和响应的,ServletRequest中封装了当前的Http请求。ServletResponse表示当前用户的Http响应,我们只需直接操作ServletResponse对象就能把响应给用户。
void service(javax.servlet.ServletRequest servletRequest, javax.servlet.ServletResponse servletResponse) throws javax.servlet.ServletException, java.io.IOException;
//getServletInfo():返回一个字符串,在该字符串中包含 servlet 的创建者,版本和版权等信息
java.lang.String getServletInfo();
//当Servlet调用完destroy()方法后,等待垃圾回收。下次需要使用这个Servlet程序的时候,会重新调用init()方法进行初始化操作。
void destroy();
}
使用IDEA+Maven配置Tomcat服务器然后编写一个Servlet程序(具体看下面这篇文章)
https://blog.csdn.net/qq_47256069/article/details/116140082
上面这篇文章没有说到基于父模块创建子模块(这里简单说一下),但创建过程都一样,先构建一个普通的
Maven
项目(没有骨架的),然后删除里面的src
目录,然后在里面建立子Moudel
(主工程导依赖,子Moudel
用骨架生成,然后补全目录)只不过pom.xml
文件有点不同,在主模块创建子模块,创建好后每个模块中的pom.xml
文件都会生成下面的依赖(没有的话请自行添加,要不然会报错)为了方便理解,下面有个例子
工程构建完成后,主工程的pom.xml有
上图
父Moudel
里面有两个Moudel
,对应的pom.xml
文件也不一样
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>com.cjjygroupId>
<artifactId>Web-Maven-0artifactId>
<packaging>pompackaging>
<version>1.0-SNAPSHOTversion>
<modules>
<module>Servlet_0module>
<module>Servlet_1module>
modules>
<properties>
<maven.compiler.source>11maven.compiler.source>
<maven.compiler.target>11maven.compiler.target>
properties>
project>
子模块的pom.xml有
<parent>
<groupId>com.cjjygroupId>
<artifactId>Web-Maven-0artifactId>
<version>1.0-SNAPSHOTversion>
parent>
然后在主工程导入程序所需要的依赖
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>4.0.1version>
dependency>
更换IDEA的xml文件
为了让实验环境达到最佳,
Maven
环境优化,所以把IDEA
的web.xml
替换成外部Tomcat
目录下的web.xml
文件(保持一致,都是4.0)还有一些不必要的东西都可以删了,下面是web.xml
文件的模板
<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"
metadata-complete="true">
web-app>
还有pom.xml
文件,有些东西可以删了,不会影响运行环境
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>com.cjjygroupId>
<artifactId>Servlet_0artifactId>
<version>1.0-SNAPSHOTversion>
<packaging>warpackaging>
project>
还有就是添加项目所需要的依赖
<dependencies>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>4.0.1version>
dependency>
<dependency>
<groupId>javax.servlet.jspgroupId>
<artifactId>javax.servlet.jsp-apiartifactId>
<version>2.2.1version>
dependency>
dependencies>
在一个应用程序中,每种
Servlet
类型只能有一个实例。Servlet
容器是将Servlet
类载入内存,并产生Servlet
实例和调用它具体的方法。下面是一个简单的实例
package com.cjjy.test;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
public class ServletDemo implements Servlet {
/*
* 1、编写一个类实现Servlet接口
* 2、实现service方法,处理请求,并响应数据
* 3、到web.xml中配置servlet程序的访问地址(映射)
*/
@Override
public void init(ServletConfig servletConfig) throws ServletException {
System.out.println("初始化");
}
@Override
public ServletConfig getServletConfig() {
return null;
}
//service方法是专门用来处理请求和响应的,只要访问ServletDemo这个程序,它就会执行这个方法
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
//因为我们页面get请求和post请求都会走这个service()方法,但由于servletrequest没有getmethod()这个方法,所以得向下转型(也就是去找子接口HttpServletRequest)才有,所以我们必须向下转型得到HttpServletResponse对象,然后就可以获取请求的方式(public interface HttpServletResponse extends ServletResponse)
System.out.println("service:我被访问了");
HttpServletRequest httpServletRequest = (HttpServletRequest) req;
//获取请求方式
String method = httpServletRequest.getMethod();
if ("GET".equals(method)){
System.out.println("get请求");
}else if ("POST".equals(method)){
System.out.println("post请求");
}
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
System.out.println("销毁");
}
}
/*
输出结果:初始化
service:我被访问了
post请求
*/
HTML提交页面
注意:网页不要写到这个目录(WEB-INF)去(WEB-INF目录是一个受服务器保护的目录,浏览器无法直接访问到此目录的内容)
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<form action="/cjjy/show" method="post">
<input type="submit" value="登录">
form>
body>
html>
到web.xml中配置Servlet程序的访问地址(映射)
<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"
metadata-complete="true">
<servlet>
<servlet-name>ServletDemoservlet-name>
<servlet-class>com.cjjy.test.ServletDemoservlet-class>
servlet>
<servlet-mapping>
<servlet-name>ServletDemoservlet-name>
<url-pattern>/showurl-pattern>
servlet-mapping>
web-app>
javax.servlet.http大致继承关系
一般在实际项目开发中,都是使用继承
HttpServlet
类的方式去实现Servlet
程序,在上面我们实现Servlet
接口,要实现5个方法。HttpServlet
类已经实现了Servlet
接口的所有方法,编写Servlet
程序的时候,只需要继承HttpServlet
,重写doGet()
和doPost()
方法即可,并且它在原有Servlet
接口上添加了一些与HTTP
协议处理方法,它比Servlet
接口的功能还要强大
继承
GenericServlet
抽象类,只需要重写一个方法,底层其他的方法都做了空实现(仅声明了方法,方法体内没有内容)只有service()
方法做了抽象(abstract
)需要其他方法时重写就行,一般项目开发也不用这个,上面继承图我们可以看到HttpServlet
继承了GenericServlet
抽象类,为了屏蔽get
请求和post
请求方式处理逻辑(继承HttpServlet
,复写方法doGet()
和dopost()
方法)。因为将来都是调用service()
方法,service()
做一个方法分发,是哪个方式就调用哪个方法(简单来说就是HttpServlt
已经帮我们分发好了get
请求和post
请求)
这里使用了尚硅谷老师的图(方便理解)
HttpServlt已经帮我们分发好了get请求和post请求
上面我们说了所有的请求都是
service()
方法处理,一般来说这个方法是不需要重写的,因为在HttpServlet
中已经有了很好的实现,它会根据请求的方式,调用doGet()
,doPost()
以及其他的doXXX()
方法,也就是说service
是用来转向的,所以我们一般写一个Servlet
程序继承HttpServlet
抽象类,只需要重写doGet()
和doPost()
方法即可!
import javax.servlet.*;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class ServletDemo extends HttpServlet {
//doGet()在get请求的时候调用
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doGet(req, resp);
}
//doPost()在post请求的时候调用
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
}
ServletConfig
是Servlet
规范中的一个规则,它是一个接口.ServletConfig
有两个实现类:一个是GenericServlet
,另一个是HttpServlet
。Servlet
程序和ServletConfig
对象都是由Tomcat负责创建的,我们负责使用;Servlet
程序默认是第一次访问的时候创建,ServletConfig
是每个Servlet
程序创建的时候,每个Servlet
对象对应的也都有一个封装Servlet
配置的ServletConfig
对象
ServletConfig作用
ServletConfig
对象对应web.xml
文件中的
元素(例如
的值)那么可以使用servletConfig.getServletName()
方法获取init-param
ServletContext
对象package com.cjjy.test;
import javax.servlet.*;
import java.io.IOException;
public class ServletDemo implements Servlet {
// Servlet容器初始化Servlet时,Servlet容器会给Servlet的init()方法的参数就是ServletConfig类型的。也就是说Tomcat在调用init()方法时,会传递ServletConfig对象
@Override
public void init(ServletConfig servletConfig) throws ServletException {
//可以获取Servlet程序的别名servlet-name的值
System.out.println(servletConfig.getServletName());//输出结果:ServletDemo
//获取初始化参数init-param
System.out.println(servletConfig.getInitParameter("url"));//输出结果:jdbc:mysql://localhost:3306/bank
//获取ServletContext对象
System.out.println(servletConfig.getServletContext());//输出结果:org.apache.catalina.core.ApplicationContextFacade@75b9e42f
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
web.xml映射
因为我们编写一个类实现
Servlet
接口,下面我们直接继承HttpServlet
,然后进行类操作;为什么需要映射呢?因为我们写的Java程序,但是通过浏览器访问,而浏览器需要连接web服务器,所以我们需要再Web服务器中注册我们写的Servlet
,还需给他一个浏览器能够访问的路径
<servlet>
<servlet-name>ServletDemoservlet-name>
<servlet-class>com.cjjy.test.ServletDemoservlet-class>
<init-param>
<param-name>usernameparam-name>
<param-value>rootparam-value>
init-param>
<init-param>
<param-name>urlparam-name>
<param-value>jdbc:mysql://localhost:3306/bankparam-value>
init-param>
<servlet-mapping>
<servlet-name>ServletDemoservlet-name>
<url-pattern>/showurl-pattern>
servlet-mapping>
servlet>
补充
package com.cjjy.test;
import javax.servlet.*;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class ServletDemo extends HttpServlet {
//这里有个注意点就是如果在这里重写void init(ServletConfig config)这个方法的话,因为底层GenericServlet类持有一个的ServletConfig接口的引用【private transient ServletConfig config】,且底层GenericServlet类提供的getServletConfig()方法返回的是ServletConfig config这个对象,底层GenericServlet类的init()方法是保存ServletConfig config这个对象的【底层GenericServlet类也有init这个方法{this.config=config;this.init();}】,而这个对象我们上面说了封装了初始化参数,如果重写的话,没有添加这个super.init(config);语句的话,会报空指针异常【因为当子类和父类都有init()这个方法,当调用init的时候,调用的是子类的,父类的保存操作就会消失】(简单来说就是这个config是父类中init方法中赋值的)
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
System.out.println("重写init方法");
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletConfig servletConfig = getServletConfig();
System.out.println(servletConfig.getServletName());
System.out.println(servletConfig.getInitParameter("username"));
System.out.println(servletConfig.getInitParameter("url"));
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
servletContext
接口是Servlet
中最大的一个接口,呈现了Web应用的Servlet
视图。ServletContext
实例是通过getServletContext()
方法获得的,由于HttpServlet
继承GenericServlet
的关系,GenericServlet
类和HttpServlet
类同时具有该方法。ServletContext
它表示Servlet
上下文对象,这个对象中封装了上下文(应用程序)的环境详情。一个Web工程,只有一个ServletContext
对象实例(简单来说对于每一个应用程序,Servlet容器会创建一个ServletContext对象,每个应用程序只有一个ServletContext。每个Servlet对象也都有一个封装Servlet配置的ServletConfig对象)ServletContext
是在web工程部署启动的时候创建,在web工程停止的时候销毁。ServletContext
对象是一个域对象。ServletContext
和ServletConfig
都是由项目所拥有的,但是区别就是ServletContext
内的数据类似于整个域共享,但是ServletConfig
内拥有整个项目中对每个类的个性化配置
ServletContext作用
web.xml
中配置的上下文参数context-param
/工程路径
Map
一样存储数据
Map
一样存取数据的对象,叫域对象。这里的域指的是存取数据的操作范围,指的是整个Web工程package com.cjjy.test;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class ServletContext extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取web.xml中配置的上下文参数context-param
javax.servlet.ServletContext servletContext = getServletConfig().getServletContext();
String username = servletContext.getInitParameter("username");
System.out.println(username);//输出结果:root
//获取当前的工程路径,格式:/工程路径
System.out.println(servletContext.getContextPath());//getContextPath()获得的是当前的项目名 /cjjy,拿到的是你的web工程的根路径,就是webRoot。
//获取工程部署后在服务器硬盘上的绝对路径(/ 斜杠表示被服务器解析地址为:http://ip:port/工程名/ 映射到IDEA代码的Web目录)
System.out.println(servletContext.getRealPath("/"));//输出结果:D:\IDEA\Maven-Web-0\Servlet_0\target\Servlet_0-1.0-SNAPSHOT\(整个工程的路径)
//像Map一样存储数据
servletContext.setAttribute("namme","Mike");
System.out.println(servletContext.getAttribute("name"));
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
web.xml配置参数信息
<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"
metadata-complete="true">
<context-param>
<param-name>usernameparam-name>
<param-value>rootparam-value>
context-param>
<context-param>
<param-name>passwordparam-name>
<param-value>111param-value>
context-param>
web-app>
package com.cjjy;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/*
* 实现共享数据
*
* */
public class WebTest_0 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext servletContext = this.getServletContext();
String username="张三";
servletContext.setAttribute("username",username);
}
}
这里就省略了web.xml映射(自行去映射),然后启动Tomcat
package com.cjjy;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class WebTest_1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
ServletContext servletContext = this.getServletContext();
//这里注意的是ServletContext是在web工程部署启动的时候创建,在web工程停止的时候销毁,也就是说如果重新部署项目后,直接访问WebTest_1是取不到值的
String username = (String)servletContext.getAttribute("username");
System.out.println(username);
}
//所有的请求都是service方法处理的,service方法会转发给dopost,doget,dodelete(请求相关都在httpservletrequest对象里)所有的请求方式都是等价的(方法复用)
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
用户通过
HTTP
协议访问服务器,服务器会把HTTP
请求中的所有的信息会被封装到Request
对象中去。然后传递到service()
方法(doGet和doPost)中给我们使用,可以获取客户端的所有的信息。我们可以通过HttpServletRequest
对象,获取到所有请求的信息。
HttpServletRequest类的常用方法
HttpServletRequest常用方法 | 说明 |
---|---|
getRequestURI() | 获取请求的资源路径 |
getRequestURL() | 获取请求的统一资源定位符(绝对路径) |
getServletPath() | 可以获取与url-pattern 中匹配的路径(注意是完全匹配的部分)*的部分不包括 |
getRemoteHost() | 获取客户端的ip地址 |
getHeader() | 获取请求头 |
getParameter() | 获取请求的参数 |
getParameterValues() | 获取请求的参数(多个值的时候使用) |
getMethod() | 获取请求的方式 |
setAttribute(key,value) | 设置域数据 |
getAttribute(key) | 获取域数据 |
getRequestDispatcher() | 获取请求转发对象 |
常用方法
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class HttpServletDemo extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println(req.getRequestURI());// /cjjy/show
System.out.println(req.getRequestURL());// http://localhost:8081/cjjy/show
/*
注意:使用localhost访问的时候,得到的客户端ip地址是127.0.0.1
使用127.0.0.1访问的时候,得到的客户端ip地址是127.0.0.1
使用真实的ip地址访问的时候,得到的客户端ip地址是真实的客户端ip地址
*/
System.out.println(req.getRemoteHost());// 0:0:0:0:0:0:0:1
System.out.println(req.getHeader("User-Agent"));// Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
获取前端表单传递进来的参数
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
public class RequestDemo extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置请求体的字符集为utf-8(要在获取请求参数之前调用)
req.setCharacterEncoding("utf-8");
resp.setCharacterEncoding("utf-8");
String username = req.getParameter("username");
String password = req.getParameter("password");
String[] hobbys = req.getParameterValues("hobbys");
System.out.println(username);
System.out.println(password);
System.out.println(Arrays.toString(hobbys));
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
表单
<html>
<body>
<div class="gobal">
<form action="${pageContext.request.contextPath}/requesttest" method="post">
<div class="login-0">
<div class="account">用户名div>
<input type="text" name="username">
div>
<div class="logi-1">
<div class="pwd">密码div>
<input type="password" name="password">
div>
<div class="checkbox">
<input type="checkbox" name="hobbys" value="唱歌"><span>唱歌span>
<input type="checkbox" name="hobbys" value="跳舞"><span>跳舞span>
<input type="checkbox" name="hobbys" value="学习"><span>学习span>
<input type="checkbox" name="hobbys" value="代码"><span>代码span>
div>
<div class="commit">
<input type="submit" value="Login">
div>
form>
div>
body>
html>
web.xml映射
<servlet>
<servlet-name>requesttestservlet-name>
<servlet-class>com.cjjy.RequestDemoservlet-class>
servlet>
<servlet-mapping>
<servlet-name>requesttestservlet-name>
<url-pattern>/requesttesturl-pattern>
servlet-mapping>
什么是请求转发?
请求转发是指服务器收到请求后,从一次资源跳转到另一个资源的操作叫请求转发
请求转发的特点?
浏览器的地址栏不会改变
它们是一次请求,且共享Request域中的数据
可以转发到WEB-INF
目录下
req.getRequestDispatcher("/WEB-INF/logout.html").forward(req,resp);
package com.cjjy.test;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class RequestForward extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//请求转发,必要要以‘/’开头,这里的‘/’代表http://ip:port/工程名/(也就是当前的web工程)
req.getRequestDispatcher("/logout.html").forward(req,resp);
//request.getRequestDispatcher(url).forward(request,response)请求转发,在跳转页面的时候是带着原来页面的request和response跳转,request对象始终存在,不会重新创建。转发数据不会丢失,forward 就是转寄的意思,就是把客户端第一次请求在服务器内部完成,带着之前的请求request 和服务器解析成response 一并转发过去。
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
表单页面
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<form action="/cjjy/show" method="post">
<div class="user">
<label>用户:label>
<input type="text">
div>
<div class="pwd">
<label>密码:label>
<input type="password">
div>
<div class="commit">
<input type="submit" value="登录">
div>
form>
body>
html>
web映射
<servlet>
<servlet-name>HttpServletDemoservlet-name>
<servlet-class>com.cjjy.test.RequestForwardservlet-class>
servlet>
<servlet-mapping>
<servlet-name>HttpServletDemoservlet-name>
<url-pattern>/showurl-pattern>
servlet-mapping>
Web服务器接收客户端的http请求,针对这个请求,会分别创建一个代表请求
HttpServletRequest
对象和一个代表响应的HttpServletResponse
对象。HttpServletRequest
表示请求过来的信息,HttpServletResponse
表示所有响应的信息。如果需要设置返回给客户端的信息,可以通过HttpServletResponse
对象来进行设置
HttpServletResponse常用方法
HttpServletResponse常用方法 | 说明 |
---|---|
getCharacterEncoding() | 响应对象采用的编码格式(Java的默认编码是ISO-8859-1) |
setHeader(name, value) | 设置响应头信息 |
setCharacterEncoding(java.lang.String s) | 设置服务器字符集编码 |
setContentLength(int len) | 设置响应中的内容长度。在HTTP servlet 中,这个方法就是设置HTTP Content-Length header |
setContentType(java.lang.String s) | 设置正被发往客户端的响应的内容类型。 内容类型可以包括所用的字符编码类型,例如, text/html; charset=ISO-8859-4 |
响应流
响应流分为字节流和字符流,在使用的过程中只能使用一个。如果使用了字节流,则不能使用字符流
javax.servlet.ServletOutputStream getOutputStream() throws java.io.IOException;//常用于下载(传递二进制数据)
java.io.PrintWriter getWriter() throws java.io.IOException;//常用于回传字符串(比较常用)
package com.cjjy.test;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class PracticeDemo extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置服务器字符集为utf-8
resp.setCharacterEncoding("utf-8");
//通过响应头,设置浏览器也使用utf-8
resp.setHeader("Content-Type","text/html;charset=utf-8");
//往客户端回传数据
PrintWriter writer = resp.getWriter();
writer.write("come om!!!!");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
public class DownloadDemo extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//下载文件
String realPath = "D:\\IDEA\\JavaWeb_Skeleton\\Web-Maven-0\\Servlet_0\\target\\classes\\cxy.jpg";
//要获取下载文件的路径
String fileName = realPath.substring(realPath.lastIndexOf("\\")+1);//获取要下载的文件名
//让浏览器支持下载我们需要的东西;设置content-disposition响应头控制浏览器以下载的形式打开文件,中文文件名要使用URLEncoder.encode方法进行编码,否则会出现文件名乱码(//想办法让浏览器支持下载我们需要的东西)
//attachment表示附件,表示下载使用;filename表示指定下载的文件名
resp.setHeader("content-disposition", "attachment;filename="+ URLEncoder.encode(fileName, "UTF-8"));
//获取下载文件的输入流
InputStream in = new FileInputStream(realPath);
//创建缓冲区
int len = 0;
byte[] buffer = new byte[1024];
//获取OutputStream对象
OutputStream out = resp.getOutputStream();
while ((len = in.read(buffer)) > 0) {
//将OutputStream流写入到buffer缓冲区
out.write(buffer,0,len);
}
out.close();
in.close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
什么是重定向?
重定向(Redirect)就是通过各种方法将各种网络请求重新定个方向转到其它位置(如:网页重定向、域名的重定向、路由选择的变化也是对数据报文经由路径的一种重定向)(A去访问B,B告知A去C找)
重定向特点?
Request
域中数据WEB-INF
目录下的资源HttpServletResponse实现重定向
这里就不写配置信息或者页面了,无非就是启动服务器后,访问某个网页,然后请求登录或者跳转,通过web.xml
映射找到类的所在,实现重定向
package com.cjjy;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class RedirectDemo extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//重定向时候一定要注意,路径问题,不然的话会404
resp.sendRedirect ("/cjjy/demotest");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
重定向和转发区别
相同点:都是转发
不同点:请求转发的时候,url不会产生变化(响应状态码:307);重定向的时候,url地址栏会发生(响应状态码:302)并且通知新的地址(Location响应头:新地址)请求转发可以访问
WEB-INF
目录下的资源,且不能访问工程外的资源,相反重定向可以
什么是Cookie?
Cookie
(监视器)翻译过来是饼干的意思。Cookie
是服务器通知客户端保存键值对的一种技术。客户端有了Cookie
后,每次请求都发送给服务器。每个Cookie
大小限制4kb
下面是百度百科介绍
Cookie
,有时也用其复数形式Cookies
。类型为“小型文本文件”,是某些网站为了辨别用户身份,进行Session
跟踪而储存在用户本地终端上的数据(通常经过加密)由用户客户端计算机暂时或永久保存的信息。
Cookie的创建
package com.cjjy.cookie;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class CookieDemo extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//创建cookie对象
Cookie cookie1 = new Cookie("key1","values1");
//通知客户但保存cooike(通过响应头Set-Cookie: key1=values1,服务器给客户端响应(发送)一个cookie)
resp.addCookie(cookie1);//且cookie是保存在客户端
resp.getWriter().println("cookie创建成功");
//Cookie值的修改有两种,一种是创建同名的cookie对象。然后进行覆盖操作进行赋值;另一种则是查找要修改的cookie对象,去调用setValue()方法去赋值
Cookie cookie2 = new Cookie("key1","values2");
//通知客户端去保存修改
resp.addCookie(cookie2);
//第二种
Cookie cookie1 = new Cookie("key1","values1");
cookie1.setValue("values2");
//通知客户端去保存修改
resp.addCookie(cookie1);
//cookie服务器端从客户端获取;返回数组,说明cookie可能存在多个。遍历cookie获取值
Cookie[] cookies = req.getCookies();
for (Cookie cookie1 : cookies) {
System.out.print(cookie1.getName()+"=");//获取cookie的key
System.out.println(cookie1.getValue());//获取cookie的value
}
}
}
/*
key1=values1
JSESSIONID=BEA296E3424D851A79EE535900F38256
Idea-b1c127b7=3607ec9c-a179-44b3-8c60-36f7ccf2151c
*/
Cookie
生命控制指的是Cookie
什么时候被销毁(删除)如果不设置过期时间,则表示这个Cookie
生命周期为浏览器会话期间,只要关闭浏览器窗口,Cookie
就会自动失效。所以我们可以设置Cookie
对象的有效时间,setMaxAge()
方法便可以设置Cookie
对象的有效时间。正数表示指定秒数后过期;负数则表示浏览器关闭时,Cookie
就会被删除(默认值是-1);0表示马上删除Cookie
package com.cjjy.cookie;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class CookieDemo extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//创建cookie对象
Cookie cookie1 = new Cookie("key1","values1");
//设置cookie的有效期
cookie1.setMaxAge(24*60*60);
//创建一个cookie,显示最后一次登录的时间
Cookie cookie2 = new Cookie("LastLoginTime", System.currentTimeMillis()+"");
//服务器给客户端响应(发送)一个cookie
resp.addCookie(cookie2);
}
}
Cookie
的路径可通过setPath("/xxx")
方法来进行设置,这个路径可以过滤决定服务器的请求是否会从浏览器中加载某些Cookie
package com.cjjy.cookie;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class CookieDemo extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//创建cookie对象
Cookie cookie1 = new Cookie("key1","values1");
//req.getContextPath()得到工程路径,也就是这个路径下的文件的cookie才会保存到浏览器
cookie1.setPath(req.getContextPath()+"/static");
resp.addCookie(cookie1);
}
}
Cookie特点
Cookie
:一般会保存在本地的,用户目录下appdata
;Cookie
只能保存一个信息;web
站点可以给浏览器发送多个Cookie
,每个站点最多可以存放20个Cookie;Cookie
大小限制4kb;Cookie
是浏览器的上限(这里好像不同浏览器是有点不同的)Cookie的删除有两种方式
一种是不设置有效期,关闭浏览器,自动失效 ;另一种则是设置有效期为0
Session
:表示会话的意思,它是一个接口(HttpSession
),简单理解就是用户打开一个浏览器,点击了许多的超链接,访问了多个网站资源,关闭浏览器,这个过程可以称为会话(它是用来维护一个客户端和服务器之间关联的一种技术)每个客户端都有自己的一个Session
会话;Session
会话常用来保存用户登录之后的信息。Session
使用场景可以是登录用户的信息、购物车信息等。在整个网站中会使用的数据,我们将它保存在Session
中
百度百科
Session
(会话):在计算机中,尤其是在网络应用中,称为“会话控制”。Session对象存储特定用户会话所需的属性及配置信息。这样,当用户在应用程序的Web页之间跳转时,存储在Session
对象中的变量将不会丢失,而是在整个用户会话中一直存在下去。当用户请求来自应用程序的 Web页时,如果该用户还没有会话,则Web服务器将自动创建一个Session
对象。当会话过期或被放弃后,服务器将终止该会话。Session
对象最常见的一个用法就是存储用户的首选项。例如,如果用户指明不喜欢查看图形,就可以将该信息存储在Session
对象中。有关使用Session 对象的详细信息,请参阅“ASP应用程序”部分的“管理会话”。注意会话状态仅在支持Cookie
的浏览器中保留。
Session创建或者获取id的方法举例
package com.cjjy.session;
import javax.servlet.ServletException;
import javax.servlet.http.*;
import java.io.IOException;
public class SessionDemo extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//创建Session会话对象(第一次调用创建Session会话,之后都是获取前面已经创建好的Session会话对象,注意只有访问JSP、Servlet等程序时才会创建Session,只访问HTML、IMAGE等静态资源并不会创建Session)Session会话是存储在服务器端,一般为了防止在服务器的内存中(为了高速存取)
HttpSession session = req.getSession();
//设置属性
session.setAttribute("name","张三");
//isNew():判断是不是新建的出来的,返回的是boolean类型
boolean aNew = session.isNew();
//判断session是不是新创建的
if (aNew){
resp.getWriter().write("session创建成功,id为:"+id);
}else {
resp.getWriter().write("已经创建,id为:"+id);
}
//获取Session的唯一标识的id,每个会话都有一个类似身份证的id
String id = session.getId();
}
}
服务器会把长时间没有活动的
Session
从服务器内存中清除,如果超过指定的时长,Session
就会被销毁。值为正数的时候,设定超时的时长;值为负数的时候表示永不超时,这里没有0,只有invalidate()
这个方法可以马上让Session
会话无效。getMaxInactiveInterval()
可以获取Tomcat中Session的默认超时时长为30分钟
public void setMaxInactiveInterval(int interval);//可以设置默认Session的超时时间,值为正数的时候,设定超时的时长;值为负数的时候表示永不超时,这里没有0,只有invalidate()这个方法可以马上让Session会话无效
<session-config>
<session-timeout>15session-timeout>
session-config>
Session删除的方式
在web.xml
配置文件设置Session
配置文件
关闭浏览器
session.invalidate();//调用invalidate(),可以手动注销session
客户端第一次访问服务器(此时没有
Cookie
信息),客户端发送请求,然后服务器会创建一个Session
(通过getSession()
获取Session
对象)和一个Cookie
对象,(这个cookie对象上面说了,用来存储键值对,key是用来存储JSESSIONID,而这个ID会在随后的请求中被用来重新获得已经创建的Session(除非关闭浏览器或者通过invalidate()
方法超时,使得不能被重新使用;服务器端会把这个session对象存储在本地内存中) 之后客户端想要访问服务器都会带着这个Cookie
对象(请求头中),这也就是服务器端可以根据Session
可以来区分不同用户的原因。
Session特点
Session
对象Session
独占一个浏览器,只要浏览器没有关闭,这个Session
就存在Cookie和Session区别?
Cookie
是保存在客户端,而Session
是保存在服务器端;存储数据量大小不同,Cookie
有限,不超过4k;Session
无限Session
把用户的数据写到用户独占Session
中,服务端保存(保存重要的信息,减少服务器资源的浪费)Session
对象由服务创建
Filter
过滤器是JavaWeb三大组件之一,三大组件分别是:Servlet程序、Filter过滤器和Listener监听器。且Filter
过滤器它也是JavaEE的规范。也是接口。Filter
用来过滤网站的数据(通过web.xml 注册了一个Filter
来对某个Servlet
程序进行拦截处理时,它可以决定是否将请求继续传递给Servlet
程序,以及对请求和响应消息是否进行修改) 例如可以处理乱码、权限检查、日记操作、事务管理等。Filter
程序是一个实现了特殊接口的 Java 类,与Servlet
类似,也是由Servlet
容器进行调用和执行的。
注意在多个Filter过滤器执行的时候,它们执行的优先顺序是由它们在web.xml中从上到下配置顺序决定的,且request域对象共享,而且执行在用一个线程中
import javax.servlet.*;
import java.io.IOException;
//导包认准:javax.servlet
/*
* Filter生命周期:构造器》init()(前面两步在Web工程启动的时候执行;Filter已经创建)》doFilter()(每次拦截到请求就会执行)》destroy()(停止Web工
* 程就会执行销毁过滤器)
*/
public class FilterDemoTest implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
//初始化:web服务器启动,就被初始化了,随时等待过滤对象出现
System.out.println("初始化");
}
//当 Servlet 容器开始调用某个 Servlet 程序时,如果发现已经注册了一个 Filter 程序来对该 Servlet 进行拦截,那么容器不再直接调用 Servlet 的 service()方法,而是调用 Filter 的 doFilter()方法,再由 doFilter()方法决定是否去激活 service()方法。
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
/*
* filterChain:链
* doFilter()方法,专门用于拦截请求
* 1、过滤中的所有代码,在过滤特定请求的时候都会执行
* 2、必须要让过滤器继续同行(filterChain.doFilter(servletRequest,servletResponse);)
*/
servletRequest.setCharacterEncoding("utf-8");
servletResponse.setCharacterEncoding("utf-8");
servletResponse.setContentType("text/html,charset=utf-8");
System.out.println("执行前");
//让程序继续往下访问用户的目标资源(执行下一个过滤器(如果有过滤器的话)或者调用service()方法),否则程序到这里就被拦截停止了。如果没有过滤器的话,Filter.doFilter 方法中不能直接调用 Servlet 的 service()方法,而是调用 FilterChain.doFilter()方法来激活目标 Servlet 的 service()方法,FilterChain 对象时通过 Filter.doFilter()方法的参数传递进来的。
filterChain.doFilter(servletRequest,servletResponse);
System.out.println("执行后");
}
@Override
public void destroy() {
//web服务器关闭的时候,过滤会销毁
System.out.println("销毁");
}
}
映射
<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">
<filter>
<filter-name>filteringfilter-name>
<filter-class>com.cjjy.FilterDemoTestfilter-class>
filter>
<filter-mapping>
<filter-name>filteringfilter-name>
<url-pattern>/show/*url-pattern>
<url-pattern>/test/*url-pattern>
filter-mapping>
web-app>
原本我们登录成功后,拿着登录成功后的地址,然后注销登录,本来注销后是不可以直接登录的,我们可以利用过滤器避免二次登录,也就是登录成功(注销后)后拿着登录成功后的地址进行二次登录
下面是简单的一个实例(以下有Servlet程序自行在web.xml配置)
简单的登录页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登录title>
head>
<body>
<form action="/servlet/login" method="post">
<input type="text" name="username">
<input type="submit">
form>
body>
html>
登录成功页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登录成功title>
head>
<body>
<h1>主页h1>
<h2>恭喜你登录成功h2>
<p>
<a href="/servlet/logout">注销a>
p>
body>
html>
登录失败页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>错误title>
head>
<body>
<h1>错误404h1>
<h2>权限不够,不是管理员h2>
<p>
<a href="/Login.jsp">注销a>
p>
body>
html>
定义一个常量类
package com.cjjy.servlet;
public class Constant {
public final static String USER_NAME="USER_NAME";
}
LoginServlet程序
登录如果不是
admin
就返回失败页面,成功就重定向到成功页面
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取前端请求的参数
String username = req.getParameter("username");
if (username.equals("admin")){
//登录成功的话,把某个信息放在某个地方(一般把信息放在session里)
req.getSession().setAttribute(Constant.USER_NAME,req.getSession().getId());
resp.sendRedirect("/sys/success.jsp");
}else {
resp.sendRedirect("/error.jsp");
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
LogoutServlet
注销(但注销后还能登录成功,得实现过滤器)
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class LogoutServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Object user_name = req.getSession().getAttribute(Constant.USER_NAME);
if (user_name!=null){
req.getSession().removeAttribute(Constant.USER_NAME);
//请求转发因为共享request域中数据,所以会出现表单重复提交的bug;重定向不共享request域中数据(两次请求)所以再次提交请求时,不会出现重复提交表单请
resp.sendRedirect("/Login.jsp");
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
LoginDemo过滤器
用来登录成功后注销,拿着登录成功的地址搜索后返回错误页面
import com.cjjy.servlet.Constant;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class LoginDemo implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain filterChain) throws IOException, ServletException {
//ServletRequest HttpServletRequest
HttpServletRequest request=(HttpServletRequest)req;
HttpServletResponse response=(HttpServletResponse)resp;
if (request.getSession().getAttribute(Constant.USER_NAME)==null){
response.sendRedirect("/error.jsp");
}
filterChain.doFilter(request,response);
}
@Override
public void destroy() {
}
}
Tomcat
每次创建Filter的时候,Servlet
规范将代表ServletContext
对象和Filter
的配置参数信息都封装到一个称为FilterConfig
的对象中。FilterConfig
接口则用于定义FilterConfig
对象应该对外提供的方法,以便在Filter
程序中可以调用这些方法来获取ServletContext
对象,以及获取在web.xml
文件中为Filter
设置的友好名称和初始化参数。
FilterConfig接口定义的各个方法
FilterConfig接口定义方法 | 说明 |
---|---|
getFilterName() | 返回 元素的设置值。 |
getServletContext() | 返回 FilterConfig 对象中所包装的 ServletContext 对象的引用。 |
getInitParameter() | 返回在 web.xml 文件中为 Filter 所设置的某个名称的初始化的参数值。 |
getInitParameterNames() | 返回一个 Enumeration 集合对象。 |
什么是监听器?
Listener
监听器是JavaWeb的三大组件之一。上面我们说了三大组件分别是:Servlet程序、Filter过滤器和Listener监听器。Listener
它是JavaEE的规范,也是接口。Listener
监听器,可以监听某种事物的变化。然后通过回调函数,反馈给程序或者客户,去做一些相应的处理
ServletContextListener
它可以监听ServletContext
对象的创建和销毁。ServletContext
对象在Web工程启动的时候创建,在Web工程停止的时候销毁
public interface ServletContextListener extends EventListener {
public default void contextInitialized(ServletContextEvent sce) {
//在ServletContext对象创建之后马上调用,做初始化
}
public default void contextDestroyed(ServletContextEvent sce) {
//在ServletContext对象销毁之后调用
}
}
package com.cjjy.test;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class ServletContextListenerDemo implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("ServletContext对象启动");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("ServletContext对象销毁");
}
}
web.xml配置
<listener>
<listener-class>com.cjjy.test.ServletContextListenerDemolistener-class>
listener>
HttpSessionListener
是个监听器,看方法可以知道sessionCreated()
和sessionDestroyed()
。就是当session
被创建和被销毁的时候执行相应的方法。
实现一个HttpSessionListener监听接口统计人数
package com.cjjy;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
//在线人数监听,统计session
public class OnlineCountListener implements HttpSessionListener {
@Override
public void sessionCreated(HttpSessionEvent se) {
//创建session监听:查看你的一举一动
//一旦创建session就会触发一次这个事件
ServletContext sc = se.getSession().getServletContext();
Integer onlineCount = (Integer) sc.getAttribute("OnlineCount");
if (onlineCount==null){
onlineCount=new Integer(1);
}else {
int count =onlineCount.intValue();
onlineCount=new Integer(count+1);
}
sc.setAttribute("OnlineCount",onlineCount);
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
//销毁session监听
//一旦销毁session就会触发一次这个事件!
ServletContext sc = se.getSession().getServletContext();
Integer onlineCount = (Integer) sc.getAttribute("OnlineCount");
if (onlineCount==null){
onlineCount=new Integer(0);
}else {
int count =onlineCount.intValue();
onlineCount=new Integer(count-1);
}
sc.setAttribute("OnlineCount",onlineCount);
}
}
映射监听器
<listener>
<listener-class>com.cjjy.OnlineCountListenerlistener-class>
listener>
xml是什么?
可扩展标记语言(标准通用标记语言的子集)是一种简单的数据存储语言。使用一系列简单的标记描述数据,而这些标记可以用方便的方式建立,虽然可扩展标记语言占用的空间比二进制数据要占用更多的空间,但可扩展标记语言极其简单易于掌握和使用。
xml的主要作用
xml命名规则
注意
和转义字符
有时候我们写xml
文件,如果想在xml
中使用特殊符号(如”<”
、”>”
、”&”
),必须将其转义为实体,这样才能保存进xml
文档。
<name>张<三name>
<name>张<三name>
<servlet-mapping>
<servlet-name>testservlet-name>
<url-pattern>/testurl-pattern>
servlet-mapping>
<servlet-mapping>
<servlet-name>testservlet-name>
<url-pattern>/testurl-pattern>
servlet-mapping>
<servlet-mapping>
<servlet-name>testservlet-name>
<url-pattern>/test1url-pattern>
servlet-mapping>
<servlet-mapping>
<servlet-name>testservlet-name>
<url-pattern>/test2url-pattern>
servlet-mapping>
<servlet-mapping>
<servlet-name>testservlet-name>
<url-pattern>/test/*url-pattern>
servlet-mapping>
<servlet-mapping>
<servlet-name>testservlet-name>
<url-pattern>/*url-pattern>
servlet-mapping>
<servlet-mapping>
<servlet-name>testservlet-name>
<url-pattern>*.htmlurl-pattern>
servlet-mapping>
这里有个细节,可以自定义后缀实现请求映射,*前面不能加项目映射的路径。还有就是比如有2个类,添加了2个映射,一个通配符 / * 一个是另一个类的映射名字。也就是说指定了固有的映射路径优先级最高,如果找不到就会走默认的处理请求。还有一个注意点映射的顺序是按从上到下,前提是拦截方式都是url的方式,如果含有拦截名称的方式,则拦截名称方式的过滤器在url拦截方式之后执行