一、Http协议
HTTP协议:超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议。所有的WWW文件都必须遵守这个标准。
HTTP协议规定 浏览器(客户端)向服务器发送 何种格式的数据. 服务器 会处理数据. 向浏览器(客户端)作出响应.(向客户端发送何种格式的数据)
HTTP协议的特点:
- HTTP协议遵守一个请求响应模型.
- 请求和响应必须成对出现.
- 必须先有请求后有响应.
- HTTP协议默认的端口:80
1. HTTP协议的请求部分
客户端向服务器发送的数据的格式:
GET请求方式的抓包:
GET /WEB09/demo1/subSucc.html?username=aaa&password=123 HTTP/1.1
Accept: text/html, application/xhtml+xml, */*
X-HttpWatch-RID: 63397-10023
Referer: http://localhost:8080/WEB09/demo1/demo1.html
Accept-Language: zh-Hans-CN,zh-Hans;q=0.5
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko
Accept-Encoding: gzip, deflate
Host: localhost:8080
Connection: Keep-Alive
POST方式的抓包:
POST /WEB09/demo1/subSucc.html HTTP/1.1
Accept: text/html, application/xhtml+xml, */*
X-HttpWatch-RID: 63397-10049
Referer: http://localhost:8080/WEB09/demo1/demo1.html
Accept-Language: zh-Hans-CN,zh-Hans;q=0.5
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip, deflate
Host: localhost:8080
Content-Length: 25
Connection: Keep-Alive
Cache-Control: no-cache
username=aaa&password=123
请求行
请求方式 请求路径 协议版本
- 请求方式:请求方式有很多种 常用的是GET和POST.
- GET和POST区别?
- GET:请求参数会显示到地址栏.GET方式有大小的限制.GET方式没有请求体
- POST:请求参数不会显示到地址栏.在请求体中.POST没有大小限制.POST方式有请求体.
- 只有表单设置为method=”post”才是post请求.其他的都是get请求
请求头
请求头通常都是key:value的键值对的形式.一般情况下一个key对应一个value但也有一个key对应多个value的情况.
- Referer :网站的来源.防盗链.
- User-Agent :获得客户端浏览器的信息.(文件下载:IE:URL编码 火狐Base64)
- If-Modified-Since :和响应中一个头一起使用 完成本地缓存的查找.
请求体
POST方式 提交的请求参数
常用请求头信息:
请求头
Accept: text/html,image/* --支持数据类型
Accept-Charset: ISO-8859-1 --字符集
Accept-Encoding: gzip --支持压缩
Accept-Language:zh-cn --语言环境
Host: www.itcast.cn:80 --访问主机
If-Modified-Since: Tue, 11 Jul 2000 18:23:51 GMT --缓存文件的最后修改时间
Referer: http://www.itcast.com/index.jsp --来自哪个页面、防盗链
User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0)
Cookie
Connection: close/Keep-Alive --链接状态
Date: Tue, 11 Jul 2000 18:23:51 GMT --时间
2. HTTP协议的响应部分
服务器向客户端发送的数据的格式:
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Accept-Ranges: bytes
ETag: W/"147-1455670867735"
Last-Modified: Wed, 17 Feb 2016 01:01:07 GMT
Content-Type: text/html
Content-Length: 147
Date: Wed, 17 Feb 2016 01:17:06 GMT
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>鎻愪氦鎴愬姛</h1>
</body>
</html>
响应行
协议版本 状态码 状态码描述
200:响应成功
302:重定向
304:查找本地缓存
404:浏览资源不存在.
500:服务器内部错误.
响应头
一个key对应一个value,也有一个key对应多个value的头.
Last-Modified :最后的修改文件的事件.与If-Modified-Since一起使用.
Refresh :定时刷新.
Location :重定向的路径.
Content-Disposition:文件下载的时候使用的头信息.
禁用浏览器缓存:
Pragma
Expires
Cache-Control
响应体
页面要显示的内容.
常用响应头信息:
响应头
Location: http://www.it315.org/index.jsp --跳转方向
Server:apache tomcat --服务器型号
Content-Encoding: gzip --数据压缩
Content-Length: 80 --数据长度
Content-Language: zh-cn --语言环境
Content-Type: text/html; charset=GB2312 --数据类型
Last-Modified: Tue, 11 Jul 2000 18:23:51 GMT --最后修改时间
Refresh: 1;url=http://www.it315.org --定时刷新
Content-Disposition: attachment; filename=aaa.zip --下载
Set-Cookie:SS=Q0=5Lb_nQ; path=/search
Expires: -1 --缓存
Cache-Control: no-cache --缓存
Pragma: no-cache --缓存
Connection: close/Keep-Alive --连接
Date: Tue, 11 Jul 2000 18:23:51 GMT
二、Servlet
1.概述
运行在服务器端的一小的Java程序,接收和响应从客户端发送请求.
Servlet的作用:
处理客户端的请求,并且对请求作出响应.
a. 客户端发送请求至服务器端;
b. 服务器将请求信息发送至 Servlet;
c. Servlet 生成响应内容并将其传给服务器。响应内容动态生成,通常取决于客户端的请求;
d. 服务器将响应返回给客户端。
一个 Servlet 就是 Java语言中的一个类,它被用来扩展服务器的性能,服务器上驻留着可以通过“请求-响应”编程模型来访问的应用程序。虽然 Servlet 可以对任何类型的请求产生响应,但通常只用来扩展 Web 服务器的应用程序。
我们通过tomcat上提供的案例来看下servlet的写法:
如图:
启动tomcat服务器,访问examples工程,查看其下的servlets。
点击Servlets examples,我们可以看到下图
查看一个示例,例如Hello World这个示例。
这是Hello World这个示例的源代码,我们可以很清楚的知道,servlet其实就是一个java类,这个类继承了HttpServlet,注意,HttpServlet是java servlet api下的一个类,它不在我们的jdk中,所以使用时我们需要单独导入这个jar包,我们可以在tomcat中的lib下找到这个包.
路径: ***\apache-tomcat-7.0.42\lib\servlet-api.jar
那么我们在浏览器上输入一个路径后,怎样就可以访问到这个servlet呢?
我们来查看examples这个工程的配置文件web.xml,在这个文件中有下面这段内容:
<servlet>
<servlet-name>HelloWorldExample</servlet-name>
<servlet-class>HelloWorldExample</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloWorldExample</servlet-name>
<url-pattern>/servlets/servlet/HelloWorldExample</url-pattern>
</servlet-mapping>
其实这段内容就是对我们访问的HelloWorld这个servlet在tomcat服务器上的一个配置路径,简单说,当我们访问 http://localhost:8080/examples/servlets/servlet/HelloWorldExample时,就会通过<url-pattern>映射的路径查找到对应的servlet 类。
对于一个servlet来说,我们要创建它的步骤如下:
1.创建一个类,继承HttpServlet
2.重写doGet(和doPost)方法
3.在web.xml文件中配置servlet。
2. Servlet体系结构与api详解
Javax.servlet.http.HttpServlet类,是一个抽象类,它的作用是提供将要被子类以创建适用于web 站点的Http servlet的抽象类。而对于HttpServlet的子类,一般需要重写以下方法。
•doGet,如果 servlet 支持 HTTP GET 请求
•doPost,用于 HTTP POST 请求
•init 和 destroy,用于管理 servlet 的生命周期内保存的资源
•getServletInfo,servlet 使用它提供有关其自身的信息
我们在操作中一般重写doPost或doGet方法就可以。
GenericServletd类
这个类是HttpServlet的父类,它也是一个抽象类,它主要是处理一般的,与协议无关的servlet,如果,要编写关于http协议请使用HttpServlet。
对于我们创建一个servlet,也可以直接继承GenericServlet,虽然这种方式不常见,但也是创建servlet的一种方式。
对于GenericServlet,它实现了一个Servlet接口,这个接口定义了所有的servlet都必须实现的方法。Servlet接口
定义所有 servlet 都必须实现的方法。
servlet 是运行在 Web 服务器中的小型 Java 程序。servlet 通常通过 HTTP(超文本传输协议)接收和响应来自 Web 客户端的请求。
要实现此接口,可以编写一个扩展 javax.servlet.GenericServlet 的一般 servlet,或者编写一个扩展 javax.servlet.http.HttpServlet 的 HTTP servlet。
此接口定义了初始化 servlet 的方法、为请求提供服务的方法和从服务器移除 servlet 的方法。这些方法称为生命周期方法,它们是按以下顺序调用的:
1.构造 servlet,然后使用 init 方法将其初始化。
2.处理来自客户端的对 service 方法的所有调用。
3.从服务中取出 servlet,然后使用 destroy 方法销毁它,最后进行垃圾回收并终止它。
除了生命周期方法之外,此接口还提供了 getServletConfig 方法和 getServletInfo 方法,servlet 可使用前一种方法获得任何启动信息,而后一种方法允许 servlet 返回有关其自身的基本信息,比如作者、版本和版权。
接下来,我们通过一个图来将上述内容总结一下:
3. Servlet的生命周期
加载和实例化 Servlet。这项操作一般是动态执行的。然而,Server 通常会提供一个管理的选项,用于在 服务器启动时强制装载和初始化特定的 Servlet。
- Server 创建一个 Servlet的实例
- 第一个客户端的请求到达服务器
- 服务器调用 Servlet 的 init() 方法(可配置为 服务器 创建 Servlet 实例时调用,在 web.xml 中 <servlet> 标签下配置 <load-on-startup> 标签,配置的值为整型,值越小 Servlet 的启动优先级越高),一个客户端的请求到达 服务器, 服务器实例化一个 Servlet的实例
- 服务器创建一个请求对象,处理客户端请求
- 服务器创建一个响应对象,响应客户端请求
- 服务器激活 Servlet 的 service() 方法,传递请求和响应对象作为参数
service() 方法获得关于请求对象的信息,处理请求,访问其他资源,获得需要的信息 - service() 方法使用响应对象的方法,将响应传回Server,最终到达客户端。service()方法可能激活其它方法以处理请求,如 doGet() 或 doPost() 或程序员自己开发的新的方法。
对于更多的客户端请求,服务器创建新的请求和响应对象,仍然激活此 Servlet 的 service() 方法,将这两个对象作为参数传递给它。如此重复以上的循环,但无需再次调用 init() 方法。一般 Servlet 只初始化一次(只有一个对象),当 服务器不再需要 Servlet 时(一般当 服务器关闭时),服务器 调用 Servlet 的 destroy() 方法。
简单描述如下:
1.客户端请求该 Servlet;
2.加载 Servlet 类到内存;
3.实例化、初始化该 Servlet;
4.init() 初始化参数;
5.service()(doGet() 或者 doPost());
6.destroy()。
web.xml中配置:
<servlet>
<servlet-name>LifeServlet</servlet-name>
<servlet-class>com.yzy.loginservlet.servlet.LifeServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LifeServlet</servlet-name>
<url-pattern>/life</url-pattern>
</servlet-mapping>
注意:我们在重写init方法是,不需要重写带参数的,只需要重写无参数的init方法就可以。
原因: 在GenericServlet中已经将有参数的init方法重写,并调用了一个无参数的init,所以我们在重写时,不需要在重写有参数init方法
客户端第一次访问该Servlet的时候才会创建一个Servlet的对象,那么Servlet中的init方法就会执行.任何一次从客户端发送的请求,那么服务器创建一个新的线程执行Servlet中service方法为这次请求服务.
service方法的内部根据请求的方式的不同调用不同doXXX的方法.当Servlet从服务器中移除或者关闭服务器的时候Servlet对象就会被销毁.destroy的方法就会执行.
Servlet的接口的实现:
Servlet 接口
|
GenericServlet 通用的Servlet
|
HttpServlet HttpServlet
配置Servlet的启动时加载
在web.xml中<servlet>标签中配置
<load-on-startup>2</load-on-startup>
4. 配置url-pattern
我们在创建servlet后,如果想要这个servlet可以被我们访问到,必须在web.xml文件中对其进行配置。
在其中有一个<url-pattern>这个标签是用于确定我们访问一个servlet的路径,接下来,我们详细介绍一下关于这个标签的配置
<url-pattern>它是用于确定我们访问一个servlet的路径.
一个servlet可以被不同的路径映射,换句话说多个不同配置可以映射同一个servlet.我们可以通过下面的示例来说明上面的问题
<servlet>
<servlet-name>LoginServlet</servlet-name>
<servlet-class>com.yzy.loginservlet.servlet.LoginServlet</servlet-class>
<!--<load-on-startup>2</load-on-startup>-->
</servlet>
<servlet-mapping>
<servlet-name>LoginServlet</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>LoginServlet</servlet-name>
<url-pattern>/login2</url-pattern>
</servlet-mapping>
上面是关于LifeServlet的配置,大家发现我们对于LoginServlet它有两个<servlet-mapping>与其映射,那么这时当我们访问
http://localhost:8080/login
http://localhost:8080/login2
时都可以访问到LgoinServlet.
那么对于<url-pattern>我们在值的写法到底应该怎样处理哪?
对于<url-pattern>我们在开发中它的写法有以下几种:
【完全路径匹配】
* 以/开头 如:/aaa /aaa/bbb
【目录匹配】
* 以/开头 以*结尾 如:/* /aaa/* /aaa/bbb/*
【扩展名匹配】
* 不能以/开始的 需要以*开始 如:*.jsp *.do *.action
优先级:完全路径匹配 > 目录匹配 > 扩展名匹配
我们现在查看几个例子,我们找到tomcat/conf/web.xml ,在这个文件中配置的所有内容,其实是被我们自己的工程中的web.xml文件继承了,在这个配置文件中有以下几段内容:
对于这段配置,只要访问时后缀名是jsp或jspx就会执行名称叫jsp的servlet内容,这是一个很典型的扩展名匹配效果
在tomcat/conf/web.xml中还有这样一段配置
注意:这时<url-pattern>它的值就是”/”那么这时它就是一个默认(缺省)的servlet.。
默认的servlet其作用是用于处理其它的servlet处理不了的请求。
5. load-on-startup
上面我们提到过<load-on-startup>,它可以让我们在服务器实例化servlet时就调用这个servlet,简单说就是可以让一个servlet可以在服务器启动时,就加载这个servlet。
我们以LoginServlet类为例来说明一下:
<servlet>
<servlet-name>LoginServlet</servlet-name>
<servlet-class>com.yzy.loginservlet.servlet.LoginServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>LoginServlet</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
我们在<servlet>标签中添加了一个<load-on-startup>,它的值为2,那么这时LifeServlet就会在服务器启动时,跟随启动。
注意:<load-on-startup>的值越小代表的是优先级越高。
6. 客户端访问servlet路径问题
我们在开发中,经常在页面上通过表单或超连接向服务器发送请求,如果我们访问的是一个servlet,那么这时访问servlet的路径应该如何书写?接下来我们就介绍一下,关于在客户端访问servlet的路径问题.
在介绍之前,我们先看一下,现阶段我们有多少种方式可以访问服务器端的一个资源
- 在地址栏上直接输入url
- 超连接的方式
- 通过表单方式
- 通过js的location.href方式
- 通过js的window.open()方法
对于以上方式,只有表单提交的方式才可能有POST请求,其它的都是GET请求。
客户端访问servlet的路径问题:
相对路径:不是以 / 开始的路径.
localhost:8080/WEB/servletDemo5
localhost:8080/WEB/demo2/demo1.html绝对路径:
通常都是以 / 开始的路径.
带工程名的路径(客户端的路径)
不带工程名的路径(服务器端路径)
我们使用绝对路径会比较多一些,而在使用绝对路径时,我们主要使用的是不带协议的绝对路径,而带协议的绝对路径只要在访问站外资源时才会使用。对于相对路径,我们需要分析它们的相对关系,所以不建议大家使用。
7. ServletConfig
ServletConfig是javax.servlet包下的一个接口,它是由servlet容器(tomcat)创建,并封装了servlet相关配置信息的对象,并在servlet容器初始化期间传递给了servlet. 通过init(ServletConfig config)方法传递。
关于有参数init(ServletConfig config)与无参数init()方法关系:
有参数的init方法,是servlet接口中定义的。
而无参数的init方法是GenericServlet中定义的。
在GenericServlet中重写了有参数的init方法,并在其中调用了无参数的init方法。
那么,我们在创建一个servlet时,如果是继承了HttpServlet,在重写init方法时,就可以只重写无参数init就可以。
在web.xml文件中我们可以对servlet进行配置,在<servlet>配置标签内可以有以下这样的子标签
<init-param>
<param-name>参数名称</param-name>
<param-value>参数值</param-value>
</init-param>
这就是用于声明servlet的初始化参数
这个对象可以获得Servlet的配置信息:
- 获取当前servlet的名称 getServletName()
- 获取当前servlet的初始化参数
getInitParameter()
getInitParameterNames() - 获取全局管理者 getServletContext()
方法:
String getServletName()
:获取当前servlet的名称(web.xml配置的servlet-name)
String getInitParameter(String key)
:通过名称获取指定的参数值,如果不存在,返回null
Enumeration getInitParameterNames()
:获取所有初始化参数的名称,以 String 对象的 Enumeration 的形式返回
初始化参数是放在 web.xml文件
servlet标签下子标签 init-param
★getServletContext()
:获取全局管理者
servletconfig是由服务器创建的,在创建servlet的同时也创建了它,通过servlet的init(ServletConfig config)将config对象传递给servlet,由servlet的getServletConfig方法获取
- 获取servletConfig
对于ServletConfig对象,我们在自己的servlet中如果想要获取到,可以通过getServletConfig()对象来获取。这个方法是在javax.servlet.Servlet接口中定义的,在GenericServlet中对getServletConfig()方法进行了实现。在servlet中以过下面代码就可以获取ServletConfig对象。
ServletConfig config=this.getServletConfig();
8. ServletContext
ServletContext它是javax.servlet.包下的一个接口。
WEB容器在启动时,它会为每个WEB应用程序都创建一个对应的ServletContext对象,它代表当前web应用。
ServletConfig对象中维护了ServletContext对象的引用,开发人员在编写servlet时,可以通过ServletConfig.getServletContext方法获得ServletContext对象。
由于一个WEB应用中的所有Servlet共享同一个ServletContext对象,因此Servlet对象之间可以通过ServletContext对象来实现通讯。ServletContext对象通常也被称之为context域对象。
它代表的是web应用上下文(全局管理者)
一个项目的引用.代表了当前项目.
当项目启动的时候,服务器为每一个web项目创建一个servletcontext对象.
当项目被移除的时候或者服务器关闭的时候servletcontext销毁
作用:
1.获取全局的初始化参数
2.共享资源(xxxAttribute)
3.获取文件资源
4.其他操作
获取servletcontext:
方式1:
getServletConfig().getServletContext()
方式2:
getServletContext()
常用方法:
String getInitParameter(String key)
:通过名称获取指定的参数值
Enumeration getInitParameterNames()
:获取所有的初始化参数名称
在根标签下有一个 context-param子标签 用来存放初始化参数
<context-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</context-param>
xxxAttribute
:存取域对象
String getRealPath(String path)
:获取文件部署到tomcat上的真实路径(带tomcat路径)
getRealPath("/")
:获取文件绝对路径
D:\javaTools\apache-tomcat-7.0.52\webapps\day09
InputStream getResourceAsStream(String path)
:以流的形式返回一个文件
String getMimeType(String file)
可以获取一个文件的mimeType类型.
URL getResource(String path)
它返回的是一个资源的URL
还提供 log(String msg),getRequestDispatcher(String path)
等这样的方法,可以做日志与转向操作
- servletContext实现servlet共享
ServletContext对于一个web应用只有一个,所有的servlet使用的就是同一个ServletContext。
ServletContext提供以下方法用于在域中进行数据操作
Object getAttribute(String name)
返回具有给定名称的 servlet 容器属性,如果不具有该名称的属性,则返回 null。
void setAttribute(String name,Object object)
将对象绑定到此 servlet 上下文中的给定属性名称。如果已将指定名称用于某个属性,则此方法将使用新属性替换具有该名称的属性。
void removeAttribute(String name)
从 servlet 上下文中移除具有给定名称的属性。
应用场景:统计访问站点的人数
三、Classpath
java project----所有class都在bin目录下
web project-----所有的class都在classes目录下
Class获取
Class.getResource("/").getPath();
获取classes目录的绝对磁盘路径
Class.getResource("").getPath();
获取的是当前Class对象代表的类所在的包的路径。ClassLoader获取
Class.getClassLoader().getResource("/").getPath();
获取的是classes目录的绝对磁盘路径
Class.getClassLoader().getResource("").getPath();
获取的是classes目录的绝对磁盘路径
这两个getResource()是使用当前ClassLoader加载资源(即资源在 Class path中),这样资源和class直接打在jar包中,避免文件路径问题.
两者不同是Class的getResource()方法是从当前.class 文件路径查找资源,ClassLoader则是从jar包根目录查找.。
简单归纳:
通过类加载器获取文件的路径(处于classes目录下的文件)
类.class.getClassLoader().getReource("文件路径").getPath()
类.class.getClassLoader().getReourceAsStream("文件路径")
四、实例:完成系统的登录功能,登录后页面定时跳转,并记录系统被访问多少次
技术要点:
- 页面跳转所用技术
【Refresh的响应头】
HttpServletResponse的操作响应头的方法:
* addHeader(String name,String value); --针对一个key对应多个value头的设置
* addDateHeader(String name,long value);
* addIntHeader(String name,int value);
* setHeader(String name,String value); --针对一个key对应一个value
* setDateHeader(String name,long value);
* setIntHeader(String name,int value);
简单实例:
response.setContentType("text/html;charset=UTF-8");
response.getWriter().println("<h1>登录成功!页面将在5秒后跳转</h1>");
response.setHeader("Refresh", "5;url=/WEB09/loginSucc.html");
另一种方法,在jsp页面设置定时跳转:
可以通过html页面中的一个标签设置头信息<meta>标签.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="Refresh" content="5;url=/WEB09/succ.html">
<script type="text/javascript" src="/WEB09/js/jquery-1.11.3.min.js"></script>
<title>Insert title here</title>
<script type="text/javascript">
$(function(){
setInterval("changeTime()", 1000);
});
var i = 5;
function changeTime(){
// 获得id为s1的元素:
i--;
$("#s1").html(i);
}
</script>
</head>
<body>
<h1>登录成功!!!页面将在<span id="s1">5</span>秒后跳转!</h1>
</body>
</html>
统计访问次数用到的技术:
【ServletContext*****】
ServletContext :Servlet中全部的内容ServletContext都了解.一个WEB应用只有一个ServletContext对象.服务器启动的时候,服务器为每个WEB工程创建一个属于自己项目的ServletContext对象.服务器关闭的时候或者项目从服务器中移除ServletContext才会被销毁.如果将值保存在ServletContext中.值就有一个作用的范围.所以这个对象称为”域对象”.-
保存全局性信息和数据:
- 网站的访问次数:
- 聊天室:
-
在Servlet中获得ServletContext:
- ServletContext getServletContext();
-
操作这个对象的方法:
- void setAttribute(String name,Object value);
- Object getAttribute(String name);
- void removeAttribute(String name);
简单实现:
- 编写一个Servlet中的init方法.在init方法中初始化一个被登录次数0.将这个值存入到ServletContext域中.配置Servlet的load-on-startup.
- 在登录成功代码中获得原来的次数+1.存回到ServletContext域中.
- 在5秒后跳转的Servlet中,从ServletContext域中获得次数,并且显示到页面上.
配置SErvlet为启动时加载:
<servlet>
<servlet-name>UserServlet</servlet-name>
<servlet-class>com.itheima.servlet.demo2.UserServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>UserServlet</servlet-name>
<url-pattern>/userServlet</url-pattern>
</servlet-mapping>
在Servlet的init方法中初始化次数为0
@Override
public void init() throws ServletException {
// super.init();
// 获得ServletContext对象.初始化一个值为0.
ServletContext servletContext = this.getServletContext();
servletContext.setAttribute("count", 0);
}
在登录成功的代码中获得原来的次数并且+1,存回到SErvletContext域中。
// 登录成功的时候 获得原来的次数 + 1
Integer count = (Integer) this.getServletContext().getAttribute("count");
// 存回到ServletContext域中
this.getServletContext().setAttribute("count", ++count);
在CountServlet中获得次数并且显示:
response.setContentType("text/html;charset=UTF-8");
// 获得次数:
Integer count = (Integer) this.getServletContext().getAttribute("count");
response.getWriter().println("<h1>您是第"+count+"位登录成功的用户!</h1>");
案例代码实现:
步骤一:设计一个登录页面.
注意:如果html页面改成jsp页面需要在顶部加上
<%@ page pageEncoding="utf-8"%>
然后保存,否则会有乱码错误。
注意修改登录页面对应的name属性值
如果想使用el表达式,首先需要导入jstl的jar包:
<!-- https://mvnrepository.com/artifact/jstl/jstl -->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
然后在相应的页面导入jstl标签:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
使用el表达式显示次数:
步骤二:在登录页面上点击登录按钮.提交到Servlet.
修改form表单的action和method属性值:
action地址和web.xml里面的<servlet-mapping>下的地址对应。
另需要与数据库进行交互,注意导包:
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.30</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.mchange/c3p0 -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.mchange/mchange-commons-java -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>mchange-commons-java</artifactId>
<version>0.2.11</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-dbutils/commons-dbutils -->
<dependency>
<groupId>commons-dbutils</groupId>
<artifactId>commons-dbutils</artifactId>
<version>1.6</version>
</dependency>
步骤三:后端核心代码
Servlet类
package com.yzy.loginservlet.servlet;
import com.yzy.loginservlet.domain.User;
import com.yzy.loginservlet.service.UserService;
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;
import java.sql.SQLException;
public class LoginServlet extends HttpServlet {
@Override
//初始化登录次数
public void init() throws ServletException {
//获取全局管理者
ServletContext context = getServletContext();
//初始化次数
context.setAttribute("count", 0);
System.out.println("初始化次数成功");
}
@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 {
//0.设置编码
resp.setContentType("text/html;charset=utf-8");
req.setCharacterEncoding("utf-8");
//1.接受用户名和密码
String username=req.getParameter("name");
String password=req.getParameter("password");
System.out.println(username);
//2.调用userservice 里的login(username,password) 返回值:User user
User user = null;
try {
user = new UserService().login(username,password);
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException("网络异常,请稍后再试!");
}
//3.判断user是否为空
if(user==null){
//3.1若为空 写"用户名和密码不匹配"
resp.getWriter().print("用户名和密码不匹配,3秒之后跳转");
//案例2-定时跳转
resp.setHeader("refresh", "3;url=/login.jsp");
}else{
//3.2若不为空 写"xxx:欢迎回来"
resp.getWriter().print(user.getUname()+":欢迎回来");
resp.setHeader("refresh", "1;url=/index.jsp");
//4.获取全局管理者
ServletContext context = this.getServletContext();
//5.获取总次数
Integer cishu = (Integer) context.getAttribute("count");
//6.将次数+1
cishu++;
//7.将次数再次放入域对象中
context.setAttribute("count", cishu);
System.out.println(cishu);
}
}
}
DAO层代码:
package com.yzy.loginservlet.dao;
import java.sql.SQLException;
import com.yzy.loginservlet.domain.User;
import com.yzy.loginservlet.utils.DataSourceUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
public class UserDao {
/**
* 登录
* @param username 用户名
* @param password 密码
* @return 用户
* @throws SQLException
*/
public User getUserByUsernameAndPwd(String username, String password) throws SQLException {
//创建queryrunner
QueryRunner qr = new QueryRunner(DataSourceUtils.getDataSource());
//编写sql
String sql="select * from userinfo where uname = ? and upsw = ?";
//执行sql
User user = qr.query(sql, new BeanHandler<>(User.class), username,password);
System.out.println(user);
return user;
}
}
web.xml代码:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<servlet>
<servlet-name>LoginServlet</servlet-name>
<servlet-class>com.yzy.loginservlet.servlet.LoginServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>LoginServlet</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
</web-app>
效果: