文章目录
- 前言
- 一、servlet是什么?(运行于服务器上)
- 使用servlet之前需要导入servlet-api.jar包
- servlet是运行在web服务器中的一小段java程序,它能够通过web服务器接受并处理浏览器发送的http请求,并能够通过web服务器将动态生成的结果应答给客户端,从而实现动态网页的功能。
- 从servlet3.0版本开始用注解标识servlet类处理的请求地址,之前版本需要在web.xml文件中配置
- 通过自定义servlet类名,对应上请求地址"/login",当我们在请求Url地址栏请求"/login"时,服务器能够找到对应上的我们自定义的TestServlet类
- 通过自定义servlet类名,对应上请求地址"/test",当我们通过表单请求形式请求/test时,服务器能够找到对应上的我们自定义的TestServlet类
- 二、页面的请求转发和重定向
- 页面重定向通过response对象下的sendRedirect("")方法传入要指定到的页面,相当于重新访问一个新的地址页面----url是能够明显的发生改变的,相当于一次超链接跳转
- 页面请求转发是通过request对象中的getRequestDispatcher("")中传入转发到下一个请求相对地址名标记,在其方法下的forward(request,response)方法和include(request,response)方法就可以实现请求转发,后面的forward(request,response)和include(request,response)是为了保证是同一次请求的标记,把前一次的request请求对象都得到,在下一次请求中就可以获取(也就是同一个请求对象中的转发,两个servlet可以共享request对象中的数据)-------***把请求转发到某一个请求地址,客户端浏览器显示的还是第一个请求地址,请求转发是发生在服务器内部,客户端是不知道的***,所以url是不会发生改变的
- 三.利用请求转发、重定向和session会话机制实现简单的登录验证
- 四、上下文ServletContext类使用
- 五、servlet的生命周期的几个阶段
- 六、session和cookie
- 七、验证servlet是单例模式
- 八、过滤器(Filter)的使用
- 九、监听器(listener)
前言
Servlet相关的原理以及具体使用
一、servlet是什么?(运行于服务器上)
使用servlet之前需要导入servlet-api.jar包
(1)servlet定义
servlet是运行在web服务器中的一小段java程序,它能够通过web服务器接受并处理浏览器发送的http请求,并能够通过web服务器将动态生成的结果应答给客户端,从而实现动态网页的功能。
- 自定义的servlet类需要继承一个HttpServlet的类,其实HttpServlet继承了GenericServlet类,而GenericServlet类最终是继承了Servlet类
- 服务器端运行的servlet类,继承HttpServlet抽象类,重写类中的方法,用来处理客户端不同的请求,该类的对象是由服务器负责创建,类中的方法都是有服务器自动调用:重写里面的doGet和doPost方法,或者直接重写里面的service方法代替前面的两个方法也得
(2)servlet的一些配置
从servlet3.0版本开始用注解标识servlet类处理的请求地址,之前版本需要在web.xml文件中配置
两种方式实现servlet标注
- 以/@WebServlet("/test")形式对应前端发来的请求,请求地址的相对路径是"/test"命名,通过请求地址栏参数传入-----客户端参数传递格式为:/test?name=zhangsan&age=20形式进行请求
需要注意的是: Get方式传入的参数是在请求url地址栏上是可见的,且对于请求的数据不需要进行编码格式处理,由于Get方式的编码格式是取决于Tomcat的默认URLencoding的编码,所以在tomcat设置过编码格式做过处理了,Get方式的请求就不需要设置请求编码格式了;然而对于响应对象,设置响应对象输出内容格式及编码,必须在获取输出流之前设置----- response.setContentType(“text/html;charset=utf-8”);
@WebServlet("/test")
public class TestServlet extends HttpServlet {
/**
* 处理客户端get方式发生过来的请求
* get方式:
* 1、直接在浏览器url输入地址
* 2、a标签超链接方式
* 3、form表单默认方式,method="get"方式
* @param request 客户端请求对象,跟请求相关的内容都封装在此对象中
* @param response 服务端响应对象,跟响应相关的内容都封装在此对象中
* @throws ServletException
* @throws IOException
*/
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("当前请求方式为get方式");
//获取客户端传递过来的参数,根据参数名称获取参数值,客户端参数传递格式为:/test?name=zhangsan&age=20
String name = request.getParameter("name");
String age = request.getParameter("age");
//设置响应对象输出内容格式及编码,必须在获取输出流之前设置
// response.setContentType("text/html");
// response.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
out.write("Hello World!");
out.write("<h3>Hello World!</h3>");
out.write("<h3>你好,世界!</h3>");
out.write("<h3>姓名:"+name+",年龄:"+age+"</h3>");
out.flush();
out.close();
}
}
- 以/@WebServlet("/test")形式对应前端发来的请求,请求地址的相对路径是"/test"命名,处理客户端post方式发过来的请求------post方式:form表单method=“post“方式
需要注意的是: Post方式传入的参数是通过表单形式,在请求url地址栏上是不可见的,且对于请求的数据需要进行编码格式处理,需要设置请求对象编码格式,解决post方式传递中文参数乱码问题--------request.setCharacterEncoding(“utf-8”);
@WebServlet("/test")
public class TestServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("当前请求方式为post方式");
//设置响应对象编码格式
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
//设置请求对象编码格式,解决post方式传递中文参数乱码问题
request.setCharacterEncoding("utf-8");
String username = request.getParameter("username");
String password = request.getParameter("password");
//查询数据库
if(username.equals("zhangsan")&&password.equals("123456")){
//创建一个会话,保存用户登录信息
HttpSession session = request.getSession();
//设置会话有效期,单位是秒,默认有效期是30分钟
session.setMaxInactiveInterval(60);
//保存用户账号
session.setAttribute("username",username);
out.write("<h3>登录成功,欢迎:"+username+",<a href=\"index\">主页面</a></h3>");
}else{
out.write("<h3 style=\"color:red;\">用户名或者密码错误</h3>");
}
out.flush();
out.close();
}
}
- 以web.xml配置文件形式进行标识
通过自定义servlet类名,对应上请求地址"/login",当我们在请求Url地址栏请求"/login"时,服务器能够找到对应上的我们自定义的TestServlet类
servlet标签中:
(1)servlet-name标签: 为一个Servlet定义一个名字,这个名字就是这个servlet在文本应用中的唯一标识
(2)servlet-class标签:用于指定Servlet由哪个类实现,在这个配置选项中,必须填写类的全名,即包名加类名
servlet-mapping标签中:
(1)servlet-name标签:前面定义过的servlet的名字,与之对应
(2)url-pattern标签:用于指定servlet对应的URL,url-pattern的值以”/”开头,代表web应用的根,如果一个servlet对应的url为:
http://localhost:8080/myapp/time ,在url-pattern中应当配置为 /time
<!--配置servlet名称和对应的类-->
<servlet>
<servlet-name>TestServlet</servlet-name>
<servlet-class>com.entor.servlet.TestServlet</servlet-class>
</servlet>
<!--配置servlet名称和对应的请求地址-->
<servlet-mapping>
<servlet-name>TestServlet</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
通过自定义servlet类名,对应上请求地址"/test",当我们通过表单请求形式请求/test时,服务器能够找到对应上的我们自定义的TestServlet类
表单中的action=""就是要指定到标签url-pattern的请求名称相对地址
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户登录</title>
</head>
<body>
<form method="post" action="login">
账号:<input type="text" name="username"><br/>
密码:<input type="password" name="password"><br/>
<input type="submit" value="登录"><br/>
</form>
</body>
</html>
二、页面的请求转发和重定向
- 页面的重定向(相当于间接请求转发----相当于发了两次请求):重定向要返回客户端,由浏览器发起第二次请求,重定向时地址栏的地址会发生变化,而且重定向时两个servlet处于两个不同的请求当中,不共享一个request对象;重定向可以定向到其他应用中
页面重定向通过response对象下的sendRedirect("")方法传入要指定到的页面,相当于重新访问一个新的地址页面----url是能够明显的发生改变的,相当于一次超链接跳转
- 页面的请求转发(相当于直接请求转发-----相当于发了一次请求):请求转发是在服务器内部实现的,请求转发时,浏览器的地址不会变,而且请求转发时两个servlet处于一个请求当中,使用的是一个request对象;请求转发只能在相同应用中使用
页面请求转发是通过request对象中的getRequestDispatcher("")中传入转发到下一个请求相对地址名标记,在其方法下的forward(request,response)方法和include(request,response)方法就可以实现请求转发,后面的forward(request,response)和include(request,response)是为了保证是同一次请求的标记,把前一次的request请求对象都得到,在下一次请求中就可以获取(也就是同一个请求对象中的转发,两个servlet可以共享request对象中的数据)-------把请求转发到某一个请求地址,客户端浏览器显示的还是第一个请求地址,请求转发是发生在服务器内部,客户端是不知道的,所以url是不会发生改变的
- 代码案列
@WebServlet("/test1")
public class Test1Servlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setAttribute("name","张三");
//把请求转发到/test2,客户端浏览器显示的还是第一个请求地址,请求转发是发生在服务器内部,客户端是不知道的
//是同一个请求对象中的转发,两个servlet可以共享request对象中的数据
// RequestDispatcher requestDispatcher = request.getRequestDispatcher("/test2");
// requestDispatcher.forward(request,response);
request.getRequestDispatcher("/test2").forward(request,response);
}
}
@WebServlet("/test2")
public class Test2Servlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("姓名:"+request.getAttribute("name"));
//调用Test3Servlet的service方法,两个servlet公用同一个request对象
request.getRequestDispatcher("/test3").include(request,response);
System.out.println("年龄:"+request.getAttribute("age"));
}
}
@WebServlet("/test3")
public class Test3Servlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setAttribute("age",20);
}
}
三.利用请求转发、重定向和session会话机制实现简单的登录验证
- 前端html表单获取用户名和密码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户登录</title>
</head>
<body>
<form method="post" action="login">
账号:<input type="text" name="username"><br/>
密码:<input type="password" name="password"><br/>
<input type="submit" value="登录"><br/>
</form>
</body>
</html>
- 后台servlet请求地址为login的servlet处理
@WebServlet("/login")
public class TestServlet extends HttpServlet {
/**
* 处理客户端post方式发过来的请求
* post方式:form表单method=“post“方式
* @param request
* @param response
* @throws ServletException
* @throws IOException
*/
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("当前请求方式为post方式");
//设置响应对象编码格式
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
//设置请求对象编码格式,解决post方式传递中文参数乱码问题
request.setCharacterEncoding("utf-8");
String username = request.getParameter("username");
String password = request.getParameter("password");
//查询数据库
if(username.equals("zhangsan")&&password.equals("123456")){
//创建一个会话,保存用户登录信息
HttpSession session = request.getSession();
//设置会话有效期,单位是秒,默认有效期是30分钟
session.setMaxInactiveInterval(60);
//保存用户账号
session.setAttribute("username",username);
out.write("<h3>登录成功,欢迎:"+username+",<a href=\"index\">主页面</a></h3>");
}else{
out.write("<h3 style=\"color:red;\">用户名或者密码错误</h3>");
}
out.flush();
out.close();
}
}
- 如果验证成功则通过超链接形式,再一次请求到"/index"的servlet
@WebServlet("/index")
public class IndexServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
HttpSession session = request.getSession();
// Object username = session.getAttribute("username");
if(session.getAttribute("username")==null){
out.write("请先登录,<a href=\"login.html\">登录</a>");
}else{
out.write("欢迎:"+session.getAttribute("username")+",<a href=\"logout\">注销</a>");
}
out.flush();
out.close();
}
}
- 如果session在有效期中还有值,那么该页面附着者注销退出的功能(该功能主要是为了清除用户曾经存放在session机制中的信息)------主要是用到了session中的invalidate()方法,这样保证了用户的信息安全
@WebServlet("/logout")
public class LogoutServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession session = request.getSession();
//清空会话对象中保存的所有数据
session.invalidate();
//如果想移除单个数据可以使用removeAttribute方法
// session.removeAttribute("username");
//重定向到登录页面
response.sendRedirect("login.html");
}
}
四、上下文ServletContext类使用
- 通过request.getServletContext()获取上下文对象,并往上下文对象中设置参数值
@WebServlet("/demo1")
public class Demo1Servlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取上下文对象,该对象在服务器启动时候创建,关闭时销毁
ServletContext context = request.getServletContext();
//在上下文对象中设置值,全体所有servlet对象都可以取到
context.setAttribute("phone","13812345678");
context.setAttribute("address","南宁市西乡塘区");
}
}
- 通过request.getServletContext()获取上下文对象,由于在上下文对象中设置值,全体所有servlet对象都可以取到,并往上下文对象中获取之前设置过的参数值
@WebServlet("/demo2")
public class Demo2Servlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取上下文对象,该对象在服务器启动时候创建,关闭时销毁
ServletContext context = request.getServletContext();
//在上下文对象中获取值
System.out.println("手机:"+context.getAttribute("phone"));
System.out.println("地址:"+context.getAttribute("address"));
}
}
五、servlet的生命周期的几个阶段
- 单例模式,当用户第一次请求时创建对象,之后请求都是使用原有对象
- servlet对象生命周期三个方法
- 0、对象创建,默认是客户端第一次请求,
- 也可以通过web.xml中标签或者注解属性loadOnStartup设置加载顺序,数字越小加载越早
- 可以设置服务器启动时就创建
- 1、init,初始化对象,执行一次
- 2、service,提供服务,每次请求都执行
- 3、destroy,销毁对象,执行一次
servlet对象初始化参数有两种形式
- 通过注解@WebServlet里的参数设置
@WebServlet(value = "/count",loadOnStartup = 1,initParams = {
@WebInitParam(name = "name",value = "张三"),//servlet对象初始化参数,私有参数,其中loadOnStartup是加载顺序,默认是-1,数字越小加载越早
@WebInitParam(name = "sex",value = "男")
})
相当于
- 在web.xml文件中的servlet标签中的配置
<servlet>
//serlvet对象创建的时机,数字越小越早
<load-on-startup>0</load-on-startup>
servlet对象初始化参数,参数名称,参数值,通过ServletConfig对象调用
<init-param>
<param-name>name</param-name>
<param-value>张三</param-value>
</init-param>
<init-param>
<param-name>sex</param-name>
<param-value>男</param-value>
</init-param>
</servlet>
- servlet案列
/**
* 单例模式,当用户第一次请求时创建对象,之后请求都是使用原有对象
* servlet对象生命周期三个方法
* 0、对象创建,默认是客户端第一次请求,
* 也可以通过web.xml中标签<load-on-startup>或者注解属性loadOnStartup设置加载顺序,数字越小加载越早,
* 可以设置服务器启动时就创建
* 1、init,初始化对象,执行一次
* 2、service,提供服务,每次请求都执行
* 3、destroy,销毁对象,执行一次
*/
@WebServlet(value = "/count",loadOnStartup = 1,initParams = {
@WebInitParam(name = "name",value = "张三"),//servlet对象初始化参数,私有参数
@WebInitParam(name = "sex",value = "男")
})
public class CountServlet extends HttpServlet {
private int count;
/**
* 对象创建,只创建一次
*/
public CountServlet(){
System.out.println("servlet对象创建");
}
/**
* 多次调用,提供处理请求服务
* @param request
* @param response
* @throws ServletException
* @throws IOException
*/
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("servlet对象提供请求服务");
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
out.write("<h3>当前计数器:"+(count++)+"</h3>");
/**
*其中的count是单一变量,当我们通过本浏览器不同请求去访问时,count的值是会在原有基础上递增的
*/
out.flush();
out.close();
}
/**
* 对象销毁之前调用,只执行一次
*/
@Override
public void destroy() {
System.out.println("servlet对象销毁");
}
/**
* 初始化方法,只执行一次
* @param config
* @throws ServletException
*/
@Override
public void init(ServletConfig config) throws ServletException {
System.out.println("servlet对象初始化");
//获取servlet初始化参数值
String name = config.getInitParameter("name");
String sex = config.getInitParameter("sex");
System.out.println("姓名:"+name);
System.out.println("性别:"+sex);
}
}
六、session和cookie
(1)session会话的创建,其主要是调用HttpServletRequest下的getSession()方法进行创建获得HttpSession对象,其语法是
- public HttpSession getSession();
public HttpSession getSession(boolean value);
1、如果没有与当前请求关联的会话,则 getSession() 方法用于创建会话。
2、如果布尔值为 true 且当前没有与请求关联的会话,则使用 getSession(boolean value) 创建会话。如果布尔值为 false,且没有与当前请求关联的会话,返回null。
(2)会话对象的一些特性
- HttpSession是tomcat在服务器端为每个浏览器准备的私人储物箱,每个浏览器在tomcat里都有一个属于自己的HttpSession对象,用于存储私人数据
- 在Servlet中可以通过request.getSession(true)方法来获得session对象,这个方法总是返回与发送请求的浏览器对应的session对象-------这就体现了session的私有的性质,主要体现在每个浏览器的每一次请求没结束期间的多次访问,该浏览器的session的id,也就是cookie的jsessionid值是一样的
(3)session对象存取数据的方法
- 存数据:session.setAttribute( “name”, object );
name : 数据的别名
object:存储的数据本身 - 取数据:session.getAttribute(“name”);
name :要获取的数据别名
返回值:与name对应的数据对象
(4)session的作用(解决登录问题-------从服务器内部进行判断)
- 借助用户用户名是否存在会话中进行判断(在会话结束之前)
- 如果sessoin保存了用户名:说明该用户已经登陆过
- 如果sesson没有保存用户名:说明该用户没有登陆
(5)session对象的生命周期(session是多例模式):客户端请求服务器时调用getSession方法时由服务器创建,有效期超时后自动销毁,或者服务器关闭销毁
- 创建 : 当用户第一次调用getSession(true)方法
- 销毁 : 用户长时间没有执行操作(timeout),默认30分钟;;或者服务器关闭
- 设置session对象时间
第一种:可以在web.xml中设定session超时的时间
<session-config>
<session-timeout>10</session-timeout>
</session-config>
第二种:调用session对象中的setMaxInactiveInterval()方法,里面的参数是以秒为单位
- session对象的钝化和锐化现象
钝化:当服务器内存空间紧张或tomcat关闭时,tomcat会将不活跃的session保存到磁盘中
锐化:当需要使用时或tomcat重新启动时再次加载到内存中来
(7)session与request对象的区别
request对象:命名属性可以在由forward连接的多个servlet之间共享
生命周期较为短暂:当请求到达服务器时创建,当应答送回到浏览器时销毁
session对象:命名属性可以在同一个浏览器的多次请求之间共享
生命周期较长:在调用request.getSession(true)时被创建,在超时之后被销毁
(8)session与cookie的联系
- Tomcat会为每个拥有session的浏览器设置一个特别的Cookie,称作会话Cookie.会话Cookie的名字固定叫做 “JSESSIONID”, Cookie的值就是该浏览器对应的session ID号(这是session请求处理时自带的),其生命周期为-1
- 当调用getSession(true)时,他首先检查用户的会话Cookie是否存在
如果不存在 : 为其创建新的session对象,将session对象的ID保存到新建的会话Cookie中,并将会话cookie送回浏览器 。
如果存在 : 则按照会话Cookie 的值找到对应的session对象返回
(9)什么是cookie:是服务器保存在用户浏览器上的一段字符串
- 当浏览器向服务器发送请求时,会自动将这些浏览器存储的字符串发送到服务器,然后与服务器端的session的ID进行比对,判断是否是曾经访问过
- 我们可以利用这些字符串记录用户的重要状态,如是否登录,用户权限等
- 在服务器端的Servlet中,通过检查这些字符串来判断用户的状态(从浏览器客户端之前请求过的保存在浏览器cookie中,再次访问时,客户端会把之前的cookie(Jsessionid,这是服务器响应给客户端浏览器携带的字符串,也可以把其他参数的值,以变量-值的形式添加到cookie中,随着服务器响应给客户端就携带返回了)的值一起发送至请求中,等待服务器端处理
- cookie的生命周期
1.通过new Cookie创建属性名和对应的属性值
2.通过Cookie对象中的setMaxAge()方法设置生命周期,单位是秒;当cookie生命周期结束时,客户端浏览器会自动删除该cookie-----setMaxAge的特殊值:
-1 :会话Cookie,浏览器关闭时自动删除
0 : 表示要删除一个cookie
如果没有调用setMaxAge()方法,默认值为-1
3.将Cookie存储在用户的浏览器中,通过response的addCookie()方法进行响应之后,随着应答内容被携带到浏览器中
4.Cookie是否被正确的添加到浏览 器中,可以通过浏览器的查看Cookie功能进行验证
5.获取客户端cookie信息,通过request的getCookies()方法,其返回类型是Cookie数组,通过遍历就可以把它输出出来。通过cookie对象中的getName()方法获取属性名,getValue()方法获取对应的属性值 - cookie的一些特征
1.采用字符串形式存储数据,简单灵活
2.存储在用户的浏览器上,减少对服务器的压力
3.对于重要数据而言,数据存储在浏览器上不安全的
4.无法存储格式复杂的数据格式,如对象和集合等
(10)session与cookie使用的代码实例
@WebServlet("/session")
public class SessionServlet extends HttpServlet {
/**
* servlet生命周期的方法,可以处理所有方式的请求
* @param request
* @param response
* @throws ServletException
* @throws IOException
*/
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//创建会话对象,如果会话存在,使用原来的,如果不存在,则创建新的对象
//同时创建会话Cookie,固定名称是jsessionid,值是session的id,写入客户端浏览器返回,浏览器下次访问时带上Cookie
HttpSession session = request.getSession();
// boolean aNew = session.isNew();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
out.write("会话ID:"+session.getId()+"<br>");
out.write("会话创建时间:"+sdf.format(new Date(session.getCreationTime()))+"<br>");
out.write("系统当前时间:"+sdf.format(new Date())+"<br>");
out.write("系统当前时间:"+sdf.format(new Date(session.getLastAccessedTime()))+"<br>");
//创建Cookie对象
Cookie username = new Cookie("username", "zhangsan");
Cookie password = new Cookie("password", "123456");
//设置有效时间,单位是秒,默认不设置,有效期-1,关闭浏览器则删除cookie
username.setMaxAge(60);
//把cookie写入浏览器,返回给客户端,只有当服务器成功响应结束之后cookie才写入到浏览器
response.addCookie(username);
response.addCookie(password);
//获取客户端浏览器的cookie
Cookie[] cookies = request.getCookies();
Arrays.stream(cookies).forEach(cookie->{
System.out.println(cookie.getName()+"="+cookie.getValue());
});
out.flush();
out.close();
}
}
七、验证servlet是单例模式
单例模式:当用户第一次请求时创建对象,之后请求都是使用原有对象
下面的count属性,在不同的请求中,count的值是连续的
public class CountServlet extends HttpServlet {
private int count;
/**
* 多次调用,提供处理请求服务
* @param request
* @param response
* @throws ServletException
* @throws IOException
*/
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("servlet对象提供请求服务");
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
out.write("<h3>当前计数器:"+(count++)+"</h3>");
out.flush();
out.close();
}
八、过滤器(Filter)的使用
过滤器:如果一个Servlet配置了过滤器,那么请求在到达Servlet之前先要经过过滤器的处理,需要实现Filter接口,实现重写该接口中的三个无返回值的三个方法,分别是init(初始化)、doFilter(过滤操作,主要是通过这个进行过滤操作)、destroy(销毁)
过滤器的生命周期(单例模式)
- 0、对象创建,创建一次,服务器启动时执行
- 1、对象初始化,执行一次
- 2、对象过滤服务,每次过滤都执行,根据条件判断是否放行请求
- 3、对象销毁,执行一次,服务器关闭时执行
Filter一些配置有两种形式
- 注解形式:自定义的Filter类需要加上@WbFilter注解标识这是一个过滤器类,形如@WebFilter(value = “/*”),其中的/*对所有请求都过滤
- web.xml配置文件形式,只有满足过滤条件的请求才能到达servlet服务
<filter>
<filter-name>EncodingFilter</filter-name>
<filter-class>com.entor.filter.EncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>EncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
代码如下(示例):
@WebFilter(value = "/*")
public class EncodingFilter implements Filter {
/**
* 创建对象
*/
public EncodingFilter(){
System.out.println("EncodingFilter对象创建");
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("EncodingFilter对象初始化");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("EncodingFilter对象过滤服务");
HttpServletRequest request = (HttpServletRequest)servletRequest;
HttpServletResponse response = (HttpServletResponse)servletResponse;
//统一设置请求对象和响应对象的字符编码格式
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
//放行请求
filterChain.doFilter(request,response);
}
@Override
public void destroy() {
System.out.println("EncodingFilter对象销毁");
}
}
如果存在多个过滤器处理的情况下注意的问题
如果存在多个过滤器,执行的顺序:
- 1、如果在web.xml配置文件中,根据配置的先后顺序执行
- 2、如果是注解方式,根据类名字母asci码先后顺序
- 3、配置文件和注解两种方式都有,先执行配置文件的,再执行注解的
过滤器的作用于对非法的url请求地址进行过滤,除非是先登录后或者其他条件执行后才给放行
代码示例----设置了用户可以访问相对路径是/index和/login的请求都放行,都可以访问到页面,在地址栏中输入;如果都不是就会设置重定向到登录页面
web.xml配置
<!--配置过滤器,多个过滤器根据配置文件先后顺序加载过滤-->
<filter>
<filter-name>SessionFilter</filter-name>
<filter-class>com.entor.filter.SessionFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>SessionFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
java代码
public class SessionFilter implements Filter {
private String allow;
public SessionFilter(){
System.out.println("SessionFilter过滤器对象创建");
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("SessionFilter过滤器对象初始化");
Properties p = new Properties();
try {
p.load(SessionFilter.class.getResourceAsStream("/static.properties"));
allow = p.getProperty("allow");
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("SessionFilter过滤器对象过滤服务");
HttpServletRequest request = (HttpServletRequest)servletRequest;
HttpServletResponse response = (HttpServletResponse)servletResponse;
String url = request.getRequestURL().toString();// 获取请求的url: 统一资源定位符 http://localhost:8084/servlet_0316/任意输入的请求相对servlet地址
if(request.getQueryString()!=null){
url += "?"+request.getQueryString();
}
/*
System.out.println("url:"+request.getRequestURL().toString());
System.out.println("uri:"+request.getRequestURI());
System.out.println("contextPath:"+request.getContextPath());
System.out.println("scheme:"+request.getScheme());
System.out.println("serverName:"+request.getServerName());
System.out.println("serverPort:"+request.getServerPort());
System.out.println("queryString:"+request.getQueryString());
//url = scheme+serverName+serverPort+uri
//地址栏=url+queryString
*/
if(request.getSession().getAttribute("username")==null&&!isExist(url)){//没有登录
//重定向到login.html
response.sendRedirect("login.html");
return;
}
filterChain.doFilter(request,response);
}
@Override
public void destroy() {
System.out.println("SessionFilter过滤器对象销毁");
}
/**
* 判断url是否包括白名单关键字
* @param url
* @return
*/
public boolean isExist(String url){
String[] keys = allow.split(",");
for(int i=0;i<keys.length;i++){
if(url.contains(keys[i])){
return true;
}
}
return false;
}
}
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
warnings.filterwarnings('ignore')
import ssl
ssl._create_default_https_context = ssl._create_unverified_context
九、监听器(listener)
定义:当web应用中某一特定事件发生时,会调用相关的listener
常用的listener
- ServletContextListener:监听ServletContext(上下文)的创建和销毁
- HttpSessionListener : 监听HttpSession对象的创建和销毁
两种方式使用监听器
- 配置web.xml文件
<listener>
<listener-class>监听器类全路径名</listener-class>
</listener>
- 添加注解@WebListener标识
代码实例
监听会话对象
public class MyHttpSessionListener implements HttpSessionListener {
@Override
public void sessionCreated(HttpSessionEvent se) {
System.out.println("会话对象创建");
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
System.out.println("会话对象销毁");
}
}
监听上下文对象
@WebListener
public class MyServletContextListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("服务器启动初始化");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("服务器关闭");
}
}