Servlet核心技术
C/S架构的概念------------------------------
C/S架构(Client/Server,客户端/服务器模式),是一种比较早的软件体系结构,也是生活中很常见的结构
这种结构将需要处理的业务合理地分配到客户端和服务器端,客户端通常负责完成与用户的交互任务,服务器通常负责数据的管理
C/S架构的主要优点如下:
客户端的界面和功能可以很丰富,应用服务器的负荷较轻
响应速度较快
C/S架构的主要缺点如下:适用面窄,用户群固定
维护和升级的成本高,所有的客户端都需要更新版本
B/S架构的概念----------------------------------
B/S架构(Browser/Server,浏览器/服务器模式),是互联网兴起后的软件体系结构
该结构将系统功能实现的主要业务逻辑集中到服务器端,极少数业务逻辑在浏览器实现
浏览器通常负责完成与用户的交互任务,服务器通常负责数据的管理
B/S架构的主要优点如下:
无需安装客户端,只要有浏览器即可
适用面广,用户群不固定。通过权限控制实现多客户访问的目的,交互性较强
维护和升级的成本低,无需更新所有客户端版本
B/S架构的主要缺点如下:
应用服务器的负荷较重
浏览器的界面和功能想要达到客户端的丰富程度需要花费大量的成本
在跨浏览器上不尽如人意,适配比较麻烦
JavaWeb的概念----------------------------------
Web本意为网页的含义,这里表示互联网上供外界访问的资源
互联网上供外界访问的资源主要分为以下两种:
静态资源:主要指Web页面中供人们浏览的数据始终是不变
动态资源:主要指Web页面中供人们浏览的数据由程序产生,不同时间点访问页面看到的内容各不相同
JavaWeb主要指使用Java语言进行动态Web资源开发技术的统称,是解决相关Web互联网领域的技术总和
早期的B/S架构:
后来的B/S架构:
可以理解为:客户端和服务端的cs架构,就是下载的客户端里有先存好的页面,然后服务端只要对数据操作即可
而浏览器和服务端的bs架构,就是服务端一直给你页面数据,基本上你刷新一次我就要给你一次
所以我不止需要操作数据,还要操作页面
HTTP协议的概念-----------------------------
HTTP协议(HyperText Transfer Protocol,超文本传输协议)是由W3C(万维网联盟)组织制定的一种应用层协议
是用来规范浏览器与Web服务器之间如何通讯的数据格式,主要涉及浏览器的发请求格式和服务器的响应格式
HTTP协议通常承载于TCP协议之上,而承载于TLS或SSL协议层之上的协议就是常说的HTTPS协议
HTTP默认的端口号为80,HTTPS默认的端口号为443
HTTP请求格式:
客户端发送一个HTTP请求到服务器的请求消息主要包括:请求行、请求头、空白行和请求体
HTTP响应格式:
通常情况下服务器接收并处理客户端发过来的请求后会返回一个HTTP的响应消息,主要包括:响应行、响应头、空白行和响应体
若要看具体情况,在浏览器中打开F12(检查,或者开发者工具),找到Network(网络)
注意:不同的浏览器的功能(网络)不同
然后刷新页面或者去其他页面使得地址请求,就知道了具体情况了
其中在左边的名字那里点击一个东西,可以看出他的相关信息,消息头最上面是请求行和响应行放一起的信息
实际上每个东西都会请求过去,因为这些东西都是服务器响应给你的(如图片等等)
而每个东西都有对应的请求和响应,右边的就是他们的相关信息
Tomcat服务器(重点):
Tomcat本意为公猫的含义,最初是由Sun公司的软件架构师詹姆斯·邓肯·戴维森开发的
后来他帮助将其变为开源项目并由Sun公司贡献给Apache软件基金会
Tomcat 服务器是一个开源的轻量级Web应用服务器,在中小型系统和并发量小的场合下被普遍使用
是开发和调试Servlet、JSP 程序的首选
安装方式:
下载地址:http://tomcat.apache.org/
目录结构:
bin 主要存放二进制可执行文件和脚本
conf 主要存放各种配置文件
lib 主要用来存放Tomcat运行需要加载的jar包
logs 主要存放Tomcat在运行过程中产生的日志文件
temp 主要存放Tomcat在运行过程中产生的临时文件
webapps 主要存放应用程序,当Tomcat启动时会去加载该目录下的应用程序
work 主要存放tomcat在运行时的编译后文件,例如JSP编译后的文件
启动和关闭:
启动方式:使用bin目录下的批处理文件startup.bat来启动Tomcat服务器,若出现一个毫秒数说明启动成功
若再次启动,那么再次启动的会自动关闭,不起作用,关闭窗口可以关闭启动的tomcat,也可以使用下面的关闭方式
关闭方式:使用bin目录下的批处理文件shutdown.bat来关闭Tomcat服务器
在这里说明一下,mysql和tomcat的服务启动时,都会有一个默认的端口,mysql我们可以去连接,因为有mysql管道来传输信息
若用浏览器去连接
则需要开启mysql的http协议管道,因为要进行数据交互,因为要进行连接,就需要一个方式,即数据的交互
平常我们浏览器不能访问到mysql
因为mysql还没有设置网页上的http之间的管道交互,就如网络编程类似,需要一个IO流去操作
当设置后,可以通过默认端口进行请求,就可以看到网页版了,有默认地址
而tomcat我们也可以去连接,自带http的管道交互,且默认端口有设置默认地址(设置的,即默认请求该地址)
所以可以请求到,即可以看到tomcat的网页版(若看到了,相当于tomcat基本启动成功),在一个网络下
mysql默认端口3306
tomcat默认端口8080
http默认端口80,当然,进行连接时端口是可以改变的,只是默认端口代表默认开放的端口对于http来说,只是偏向于输出的意思,当然,对方要返回,自然是通过80的
注意:他们只是访问时的请求而已,而不是他们本身占用,这里要明白哦,所以tomca是可以操作80的,因为只有程序占用端口,而不是访问,要不然你浏览器多次的访问80不就不行了吗,而正是因为可行,所以他并没有占用
实际上http只是一个具体说明方式(协议),就如TCP协议和UDP协议类似,用程序进行数据操作
mysql里面包含mysql通讯协议来进行传输,所以代码需要驱动包来进行这样的连接(使得可以通过这个方式来进行数据传输)
协议就是一种方式,如代码方式,可以理解为一个管道的操作,不同管道有不同规定
就如规定xml书写的Schema和DTD类似
不是具体存在的,但端口也是,即要让两者进行传输,则需要都有这样的方式才可进行
如mysql没设置http,那么你发送http得不到响应
注意事项:
启动之前首先安装JDK并配置环境变量JAVA_HOME(通常tomcat需要这个,因为是java写的,所以需要环境)
若希望Tomcat服务器可以在任意路径启动,则需要配置环境变量CATALINA_HOME
注意:这个名称不能改变,虽然Path设置的是全局的命令参数
但使用全局的启动时(对应目录要正确,否则全局找不到对应命令),是需要这个名称的,也就是说
虽然你设置了全局命令参数,但是使用全局命令参数时,若不是这个名称,那么就不会执行
所以启动时会先判断是否是全局启动,若是,如果不是这个名称,那么不执行
若不是全局启动,若有这个名称,那么就操作这个名称所对应的tomcat的启动,若不是这个名称,那么就是对应的tomcat的启动
若是这个名称,但是对应的目录的最终指向,不是对应的存在的tomcat的目录(里面就是tomcat的文件了),那么就会直接退出启动,注意,直接的点击相当于利用命令,但要知道,他们只是针对我们手动的执行,因为我们手动的执行,是按照对应配置的
若是idea的执行,则不会操作这个名称,即idea操作哪个tomcat,那么就是哪个tomcat(二进制是可以实现的,实际上可能是特别的启动,自己看看他的指向就知道了,具体可以百度)
这里就知道为什么java的环境变量需要JAVA_HOME了,虽然你可以改变这个名字
但其他的服务或者软件有些需要这个名字的,若你改变,则可能会出现一些错误
当然,环境变量名的大小写是忽略的(最好不要),因为这样也会导致其他服务或者软件的需要
所以最好用JAVA_HOME这个变量名,防止其他服务或者软件出错
所以在网上找资料时,通常都会教你配置JAVA_HOME这个变量名,而不是其他变量名
启动信息乱码的处理方式:logging.properties文件修改为java.util.logging.ConsoleHandler.encoding = GBK
前面我们说过文件是可以使用\ \,因为目录用的就是\
所以一般操作不是本地的基本用/,而操作本地的基本用\,但/无论是在不是本地的还是本地的都可以用
配置文件配好后,就可以使用startup或者startup.bat开启tomcat了
也可以使用shutdown和shutdown.bat关闭了,其中shutdown可能会与其他的程序冲突,使得他不是关闭,而是一个命令提示
配置文件:
在当你修改端口时,若出错,大概是端口被占用的问题(如改成80端口)
使用netstat -ano列出所有端口情况,若修改80端口,则找到最后为80的端口,查看PID是多少,如 0.0.0.0:80样子的
停止PID对应的服务就可以了(使用taskkill /F /PID 对应PID,来sha si进程),这里用拼音,是怕被河蟹(和谐),如taskkill /F /PID 80
若关闭(sha si)不了(有可能是系统占用)
则去注册表里的(计算机\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\HTTP)
修改Start变为4,重启电脑可以,若实在不行,你就在服务里找到对应PID,进行手动关闭吧
对于注册表,它里面是用来控制软硬件的一些重要数据,可以看成一个数据库,如上面的改变,是对于http协议的改变
如0,1,2,3,4等等,你可以理解为我改变一些东西,使得80端口不被占用(就算是系统占用也会不占用)
最后:最好不要更改,因为80端口可能会有其他程序会要占用
使得有些程序或者tomcat不可启动或者使用(互相占用,一个停止,另外一个占用,然后再停,再占,非常麻烦)
所有还是改回来8080吧(不想改也可以)
server.xml文件是服务器的主配置文件,可以设置端口号、设置域名或IP、默认加载的项目、请求编码等
tomcat-users.xml文件用来配置管理Tomcat服务器的用户与权限
开启服务器后,到网页上进入tomcat默认网址localhost:8080
右边的:
Server Status:服务器的状态信息
Manager App:应用程序的管理界面
Host Manager:主机的管理
进入都需要用户名和密码
我们的根目录默认是webapps目录,即localhost:8080/就是这个目录下的地址,这是默认的地址
当请求时,会默认访问ROOT文件的index.jsp文件,若index.html和index.jsp他们单独存在时,没有指定的话,都会默认访问他们
若两者都存在,则访问index.html(优先访问)
而当你去指定请求时,不指定文件,如localhost:8080/hello/,就会默认请求hello当前目录下的index.html文件和index.jsp,同样的html优先
上述都是默认的,而指定了文件后,当前会去请求你指定的文件,因为不是默认了
注意:浏览器会默认给没有加" / “的地址加上” / ",如localhost:8080/hello就是localhost:8080/hello/
创建javaweb工程
其中Application Server是指定服务器,即这里指定tomcat服务器,右边可以新建一个服务器地址,指定Tomcat Server
然后指定服务器目录地址,点击ok
在中间找到,这个Web Application,web工程,勾选,因为我们要写web程序,然后直接下一步
src我们知道是写java代码的,而web则是写一些网页资源的,但不识别java代码,即规定了一些资源的存放和运行
而src基本都可以执行,如网页资源等等,基本没有限制
而web下的WEB-INF主要放的是配置文件,当然也可以放网页资源
上面的主要放的资源最好这样放,虽然可以不这样放,但他们这样放容易观察和维护
安装了服务器的电脑也可以叫做服务器,如mysql服务器,tomcat服务器等等,或者两者结合
我们可以配置服务器在idea里的设置
点击Run下的Edit Configurations…,进入服务器的配置,也可在右上角直接点击服务器也可进入配置
这些配置并没有对tomcat的配置文件进行修改,而是复制一些配置文件和一些程序进行操作,修改的是复制的
在idea启动时使用的也是复制的(外面启动是使用tomcat的),即一个服务器配置就有以下内容
将复制的文件放在这里,所以idea在运行时,即启动服务器时,是使用这些配置文件
Server里:
右上面是名称,即配置的名称,当需要多个不同配置时,可以改变这个名字
再下面就是可以设置默认浏览器
然后下面就是能访问到这个项目里的路径,默认就是项目里的index.html或者index.jsp文件
实际上8080/后面的是一个简写,即对应当前项目的out的项目路径,在后面的Deployment里有介绍
然后On ‘Update’ action(注意:他的对应的选项出现,需要部署的是war exploded才行,可以自行测试,比如上面图片的选项) 后面就是当你修改资源文件和类文件时
更新服务器会将对应class文件和资源文件进行更新(保存时,就更新)
再下面就是失去焦点后,要干什么,也可以进行更新,且是实时更新,不用重新更新服务器
对于服务器来说,右上角的重新执行是更新的意思,对于类来说,是停止再执行
所以这个最好设置上面的将对应class文件和资源文件进行更新(保存时,就更新),但就是耗内存
然后就可以刷新网页显示新的结果了(启动只是启动服务器,在服务器上运行而已,访问路径还是这个,相当于你重新请求一下)
服务器运行可以理解为提供了http的管道连接,即可以接收http的信息,远程访问
也是访问资源,且有响应时,将数据放入浏览器
文件的访问,在本地上,也是直接访问资源,且将数据放入浏览器
一个是http直接的传输数据,一个是文件的传输数据,但本质都是传输数据的一种方式而已,且有相应的管道传输
而tomcat服务器就有http协议的方式,即有http传输的管道,mysql没有自带,即没有管道
注意HTTP port端口号的设置
注意:配置了上面,那么就需要访问时,加上他,才可以访问到对应项目的内容
Deployment里:
这个tomcat配置默认给当前项目部署起来,可以添加对不同项目的部署
再下面就是该项目路径的,用来表示当前项目路径,如图
部署在这里的项目,都会有一个配置文件,指定对应地址,即一个服务器可以访问这些添加的配置文件的项目,加一个
就多出来一个配置文件,但都在这个服务器配置里,即一个服务器配置,可以有多个不同项目
路径:C:\Users\用户名\ .IntelliJIdea2019.3\system\tomcat\Tomcat_8_5_55_javaweb_3\conf\Catalina\localhost
不同idea版本,位置可能不同
他将下面的表示为访问的最终目录,即简写
所以当你改变下面的这个路径时,前面Server的也会进行改变,使得访问时是后面真正路径下的文件,该文件下
就是web目录下的文件,web和src一样是特定文件,即他们的内容直接放在项目路径下(默认index的jsp和html)
所以前面的默认实际上就是配置文件的设置
那么总体意思就是说,一个服务器的配置可以操作多个项目(但默认地址只有一个,所以基本上要新建服务器配置)
当需要改变时,可以新建一个配置,新建的可以配置不同的
使得不用重新配置,并会将操作的项目进行存放且更新
上面只是配置,并没有进行操作,记得关闭开启过的服务器,否则运行时,会冲突,即运行不了
点击主界面右上角的启动服务器,来启动运行这个项目,即这里默认运行index.jsp
所以idea实际上是一个新的配置文件的作用
注意:上面的是启动时,idea自动使用浏览器来进行请求的,而不是服务器的操作,服务器基本只是用来响应,来存放项目的
Servlet的概念和使用(重点)-----------------------------
Servlet(Server Applet)是Java Servlet的简称,称为小服务程序或服务连接器
是Java语言编写的服务器端程序,换句话说,Servlet就是运行在服务器上的Java类
Servlet用来完成B/S架构下客户端请求的响应处理,也就是交互式地浏览和生成数据,生成动态Web内容
因为无论是请求还是响应,实际上底层都有代码完成的
对于浏览器来说一个" / “或者” \ “就可以了,但是若写多个连起来的” / “或者” \ “,最后都会默认为一个” / ",一开始的http后面可能是//
Servlet的编程步骤:
Servlet的编程步骤:
建立一个Java Web Application项目并配置Tomcat服务器
自定义类实现Servlet接口或继承 HttpServlet类(推荐) 并重写service方法
将自定义类的信息配置到 web.xml文件并启动项目,配置方式如下:
<?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">
<servlet>
<servlet-name>HelloServlet</servlet-name>
<servlet-class>com.lagou.demo02.HelloServlet3</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>Parameter</servlet-name>
<servlet-class>com.lagou.demo02.ParameterServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Parameter</servlet-name>
<url-pattern>/Parameter</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>ConfigServlet</servlet-name>
<servlet-class>com.lagou.demo02.ConfigServlet</servlet-class>
<init-param>
<param-name>username</param-name>
<param-value>admin</param-value>
</init-param>
<init-param>
<param-name>password</param-name>
<param-value>123456</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>ConfigServlet</servlet-name>
<url-pattern>/config</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>Context</servlet-name>
<servlet-class>com.lagou.demo02.ContextServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Context</servlet-name>
<url-pattern>/Context</url-pattern>
</servlet-mapping>
<context-param>
<param-name>param1</param-name>
<param-value>value1</param-value>
</context-param>
<context-param>
<param-name>param2</param-name>
<param-value>value2</param-value>
</context-param>
</web-app>
前面注释中需要的图:
默认的资源:
<%--
Created by IntelliJ IDEA.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
</head>
<body>
$END$
</body>
</html>
后续都是如此,除非你改变
Servlet接口:
javax.servlet.Servlet接口用于定义所有servlet必须实现的方法
package com.lagou.demo02;
import javax.servlet.*;
import java.io.IOException;
public class HelloServlet implements Servlet {
@Override
public void init(ServletConfig servletConfig) throws ServletException {
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws
ServletException, IOException {
System.out.println("接收到了浏览器的请求并做出了响应!");
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
GenericServlet类
javax.servlet.GenericServlet类主要用于定义一个通用的、与协议无关的servlet,该类实现了Servlet接口
若编写通用servlet,只需重写service抽象方法即可
package com.lagou.demo02;
import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;
public class HelloServlet2 extends GenericServlet {
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws
ServletException, IOException {
System.out.println("继承GenericServlet类的方式来创建Servlet");
}
}
HttpServlet类:
javax.servlet.http.HttpServlet类是个抽象类并继承了GenericServlet类,用于创建适用于网站的HTTP Servlet
该类的子类必须至少重写一个方法
package com.lagou.demo02;
import com.sun.net.httpserver.HttpServer;
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 HelloServlet3 extends HttpServlet {
public HelloServlet3() {
System.out.println("构造方法调用了");
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException,
IOException {
System.out.println("这是采用继承HttpServlet类的方式创建,以后的开发中推荐该方式!");
}
@Override
public void destroy() {
System.out.println("销毁操作开始喽...");
}
@Override
public void init() throws ServletException {
System.out.println("初始化操作开始喽...");
}
}
Servlet 的生命周期:
构造方法只被调用一次,当第一次请求Servlet时调用构造方法来创建Servlet的实例
init方法只被调用一次,当创建好Servlet实例后立即调用该方法实现Servlet的初始化
这里需要注意:服务器自身的底层中,init真正被调用的是这样的:
void init(ServletConfig var1) throws ServletException;
并且他的子类也只有一个直接的处理,所以任何的关于初始化都是这样的处理:
public void init(ServletConfig config) throws ServletException {
this.config = config;
this.init();
}
public void init() throws ServletException {
}
这也是为什么执行有参数的和无参数的都可以进行处理,当你覆盖有参数的,那么自然init进行处理(默认情况下,servlet其实默认执行的是有参数的),没有时,由于对应的有参数的会执行无参数的,所以相当于也进行处理初始化了
service方法被多次调用,每当有请求时都会调用service方法来用于请求的响应
destroy方法只被调用一次,当该Servlet实例所在的Web应用被卸载前调用该方法来释放当前占用的资源
如停止服务器,即关闭服务器
package com.lagou.demo02;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(name = "HelloServlet4", urlPatterns = "/hello4")
public class HelloServlet4 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
System.out.println("Post请求方式...");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
System.out.println("Get请求方式...");
this.doPost(request, response);
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>请求方式的测试</title>
</head>
<body>
<a href="hello4">测试Get请求</a>
<form action="hello4" method="post">
<input type="submit"/>
</form>
</body>
</html>
POST和GET请求(重点)---------------------------
GET请求:
POST请求:
ServletRequest接口:
基本概念:
javax.servlet.ServletRequest接口主要用于向servlet提供客户端请求信息,可以从中获取到任何请求信息
Servlet容器创建一个ServletRequest对象,并将其作为参数传递给Servlet的service方法
HttpServletRequest接口:
javax.servlet.http.HttpServletRequest接口是ServletRequest接口的子接口,主要用于提供HTTP请求信息的功能
不同于表单数据,在发送HTTP请求时,HTTP请求头直接由浏览器设置
可直接通过HttpServletRequest对象提供的一系列get方法获取请求头数据
ServletResponse接口:
javax.servlet.ServletResponse接口用于定义一个对象来帮助Servlet向客户端发送响应
Servlet容器创建ServletResponse对象,并将其作为参数传递给servlet的service方法
这些类是在服务器操作的,所以有请求信息和响应信息
HttpServletResponse接口:
javax.servlet.http.HttpServletResponse接口继承ServletResponse接口,以便在发送响应时提供特定于HTTP的功能
void sendRedirect(String location),使用指定的重定向位置URL向客户端发送临时重定向响应
package com.lagou.demo02;
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;
import java.util.Enumeration;
import java.util.Map;
import java.util.Random;
import java.util.Set;
public class ParameterServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
request.setCharacterEncoding("utf-8");
String name = request.getParameter("name");
System.out.println("获取到的姓名为:" + name);
String[] hobbies = request.getParameterValues("hobby");
System.out.print("获取到的爱好有:");
for (String ts : hobbies) {
System.out.print(ts + " ");
}
System.out.println();
System.out.println("-------------------------------------------------------");
Enumeration<String> parameterNames = request.getParameterNames();
System.out.print("获取到的所有参数名称为:");
while (parameterNames.hasMoreElements()) {
System.out.print(parameterNames.nextElement() + " ");
}
System.out.println();
System.out.println("-------------------------------------------------------");
Map<String, String[]> parameterMap = request.getParameterMap();
Set<Map.Entry<String, String[]>> entries = parameterMap.entrySet();
for (Map.Entry<String, String[]> me : entries) {
System.out.print(me.getKey() + "对应的数值有:");
for (String ts : me.getValue()) {
System.out.print(ts + " ");
}
System.out.println();
}
System.out.println("-------------------------------------------------------");
System.out.println("发送请求的客户端IP地址为:" + request.getRemoteAddr());
System.out.println("发送请求的客户端端口号为:" + request.getRemotePort());
System.out.println("请求资源的路径为:" + request.getRequestURI());
System.out.println("请求资源的完整路径为:" + request.getRequestURL());
System.out.println("请求方式为:" + request.getMethod());
System.out.println("请求的附带参数为:" + request.getQueryString());
System.out.println("请求的Servlet路径为:" + request.getServletPath());
System.out.println("-------------------------------------------------------");
String characterEncoding = response.getCharacterEncoding();
System.out.println("服务器响应数据的默认编码方式为:" + characterEncoding);
response.setContentType("text/html;charset=UTF-8");
PrintWriter writer = response.getWriter();
Random ra = new Random();
int num = ra.nextInt(100) + 1;
writer.write("<h1>" + num + "</h1>");
System.out.println("服务器发送数据成功!");
writer.close();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
this.doPost(request, response);
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>请求参数的获取和测试</title>
</head>
<body>
<form action="Parameter" method="post">
姓名:<input type="text" name="name"/><br/>
年龄:<input type="text" name="age"/><br/>
爱好:<input type="checkbox" name="hobby" value="Java"/>Java
<input type="checkbox" name="hobby" value="C"/>C
<input type="checkbox" name="hobby" value="C++"/>C++<br/>
<input type="submit" value="提交"/>
</form>
</body>
</html>
Servlet接收中文乱码(重点)-------------------------
接收乱码原因:
浏览器在提交表单时,会对中文参数值进行自动编码
当Tomcat服务器接收到浏览器请求后自动解码,当编码与解码方式不一致时,就会导致乱码(servlet虽然也是一个框架,但是与tomcat结合的,并且本质是tomcat接收数据给servlet的,所以tomcat才是本质的编码设置者)
解决POST接收乱码:
解决GET接收乱码:
这里是相对底层的编码处理了,无论是jsp还是其他的如mvc框架,最终都是处理这里的编码的,当然,可能还会有隐藏的编码,但是一般我们也很难碰到(框架可能存在,在以后遇到会说明的,比如:68章博客说明的全局编码)
当然,无论是什么编码问题,只需要解码和编码一致即可,一开始的编码格式或者显示(统一编码作为称呼的)由当前写上的数(或者说文本)和当前编码影响的,也更加证明编码一致即可
ServletConfig接口(熟悉):
基本概念
javax.servlet.ServletConfig接口用于描述Servlet本身的相关配置信息,在初始化期间用于将信息传递给Servlet配置对象
即只针对一个,相当于在反射中又读取了xml出现的读取信息,即< init-param >
可以使用这个接口来获得对象,该信息在反射时赋值了
并当成参数,进行初始化,使得只作用于反射的类,差不多是当前类
可以看到他的配置在servlet里面
配置方式:
<servlet>
<servlet-name>ConfigServlet</servlet-name>
<servlet-class>com.lagou.demo02.ConfigServlet</servlet-class>
<init-param>
<param-name>username</param-name>
<param-value>admin</param-value>
</init-param>
<init-param>
<param-name>password</param-name>
<param-value>123456</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>ConfigServlet</servlet-name>
<url-pattern>/config</url-pattern>
</servlet-mapping>
package com.lagou.demo02;
import javax.servlet.*;
import java.io.IOException;
import java.util.Enumeration;
public class ConfigServlet implements Servlet {
@Override
public void init(ServletConfig servletConfig) throws ServletException {
System.out.println("初始化操作执行了...");
System.out.println("Servlet的别名是:" + servletConfig.getServletName());
System.out.println("-----------------------------------------------");
String userName = servletConfig.getInitParameter("userName");
System.out.println("获取到的初始化用户名为:" + userName);
Enumeration<String> initParameterNames = servletConfig.getInitParameterNames();
while (initParameterNames.hasMoreElements()) {
System.out.println("初始化参数名为:" + initParameterNames.nextElement());
}
System.out.println("-----------------------------------------------");
ServletContext servletContext = servletConfig.getServletContext();
System.out.println("获取到的ServletContext引用为:" + servletContext);
}
@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() {
}
}
ServletContext接口(熟悉):
基本概念
javax.servlet.ServletContext接口主要用于定义一组方法,Servlet使用这些方法与它的Servlet容器通信
服务器容器在启动时会为每个项目创建唯一的一个ServletContext对象,用于实现多个Servlet之间的信息共享和通信
在Servlet中通过this.getServletContext()方法可以获得ServletContext对象
由于一个服务器里可以有多个项目,那么服务器自动的会对这些项目创建对象一个全局对象,本身自带的类型(底层)
使得让多个通过反射的类之间的通信,其中创建后,会读取xml配置信息,没有对应的,不会读取
可以看到他的配置不在servlet里面
package com.lagou.demo02;
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.util.Enumeration;
public class ContextServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
ServletContext servletContext = getServletConfig().getServletContext();
Enumeration<String> initParameterNames = servletContext.getInitParameterNames();
while (initParameterNames.hasMoreElements()) {
String s = initParameterNames.nextElement();
System.out.println( s + "对应的值为:" + servletContext.getInitParameter(s));
}
System.out.println("----------------------------------------------------------");
String contextPath = servletContext.getContextPath();
System.out.println("获取上下文关联的路径信息为:" + contextPath);
String realPath = servletContext.getRealPath("/");
System.out.println("获取到的实际路径信息为:" + realPath);
System.out.println("----------------------------------------------------------");
servletContext.setAttribute("key", "value");
Object key = servletContext.getAttribute("key");
System.out.println("根据参数指定的属性名获取到的属性值为:" + key);
servletContext.removeAttribute("key");
key = servletContext.getAttribute("key");
System.out.println("根据参数指定的属性名获取到的属性值为:" + key);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
this.doPost(request, response);
}
}
servlet 英文意思:小服务程序,注解对应class文件
Servlet+JDBC应用(重点)-----------------------
在Servlet中可以使用JDBC技术访问数据库,常见功能如下:
查询DB数据,然后生成显示页面,例如:列表显示功能
接收请求参数,然后对DB操作,例如:注册、登录、修改密码等功能
为了方便重用和便于维护等目的,经常会采用DAO(Data Access Object)模式对数据库操作进行独立封装
<?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">
<servlet>
<servlet-name>RegisterServlet</servlet-name>
<servlet-class>com.lagou.demo01.servlet.RegisterServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>RegisterServlet</servlet-name>
<url-pattern>/register</url-pattern>
</servlet-mapping>
</web-app>
package com.lagou.demo01.servlet;
import com.lagou.demo01.dao.UserDao;
import com.lagou.demo01.model.User;
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 RegisterServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
String userName = request.getParameter("userName");
System.out.println("获取到的用户名为:" + userName);
String password = request.getParameter("password");
System.out.println("获取到的密码为:" + password);
User user = new User(userName, password);
UserDao userDao = new UserDao();
int res = userDao.createUser(user);
response.setContentType("text/html;charset=utf-8");
PrintWriter writer = response.getWriter();
if (1 == res) {
System.out.println("注册成功!");
writer.write("<h1>注册成功!</h1>");
} else {
writer.write("<h1>注册失败!</h1>");
}
writer.close();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
this.doPost(request, response);
}
}
DAO工厂(工厂模式) 工厂类:封装了对象的创建细节,为调用者提供符合要求的对象
package com.lagou.demo01.model;
public class User {
private int id;
private String userName;
private String password;
public User() {
}
public User(String userName, String password) {
this.userName = userName;
this.password = password;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User{" +
"userName='" + userName + '\'' +
", password='" + password + '\'' +
'}';
}
}
package com.lagou.demo01.util;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class DbUtil {
private static String jdbcName;
private static String dbUrl;
private static String dbUserName;
private static String dbPassword;
static {
jdbcName = "com.mysql.jdbc.Driver";
dbUrl = "jdbc:mysql://localhost:3306/db_web";
dbUserName = "root";
dbPassword = "123456";
try {
Class.forName(jdbcName);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static Connection getConnection() throws SQLException {
Connection con = DriverManager.getConnection(dbUrl, dbUserName, dbPassword);
return con;
}
public static void closeConnection(Connection con, PreparedStatement psts) throws SQLException {
if (null != con) {
con.close();
}
if (null != psts) {
psts.close();
}
}
}
在项目右键,找到Open Module Settings打开项目的模块设置,可以直接定位,不用再打开总模块设置了
package com.lagou.demo01.test;
import com.lagou.demo01.util.DbUtil;
import java.sql.Connection;
import java.sql.SQLException;
public class DbUtilTest {
public static void main(String[] args) {
Connection connection = null;
try {
connection = DbUtil.getConnection();
System.out.println("连接数据库成功!");
} catch (SQLException e) {
e.printStackTrace();
} finally {
}
}
}
其实若有相同的类,那么这两个类一定是不同包,用静态时,会提示包的路径,即其实静态是根据包来找类的
package com.lagou.demo01.dao;
import com.lagou.demo01.model.User;
import com.lagou.demo01.util.DbUtil;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class UserDao {
public int createUser(User user) {
Connection connection = null;
PreparedStatement preparedStatement = null;
try {
connection = DbUtil.getConnection();
String sql = "insert into t_user values(null, ?, ?)";
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1, user.getUserName());
preparedStatement.setString(2, user.getPassword());
int row = preparedStatement.executeUpdate();
return row;
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
DbUtil.closeConnection(connection, preparedStatement);
} catch (SQLException e) {
e.printStackTrace();
}
}
return 0;
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>实现简单的注册功能</title>
</head>
<body>
<form action="register" method="post">
用户名:<input type="text" name="userName"/><br/>
密 码:<input type="text" name="password"/><br/>
<input type="submit" value="注册"/>
</form>
</body>
</html>
实际上根据这个案例,可以知道,Servlet中的Http对应的接口是能操作请求信息和响应信息的接口
反射中获取能操作这些请求信息和响应信息的接口及其对象
而Servlet是用来处理这些操作的
重定向和转发(重点):
重定向的概念:
首先客户浏览器发送http请求,当web服务器接受后发送302状态码响应及对应新的location给客户浏览器
客户浏览器发现是302响应(302基本是请求重定向的状态码),则自动再发送一个新的http请求,请求url是新的location地址(一般是重定向给的)
服务器根据此请求寻找资源并发送给客户
重定向的实现:
实现重定向需要借助javax.servlet.http.HttpServletResponse接口中的以下方法:
void sendRedirect(String location),使用指定的重定向位置URL向客户端发送临时重定向响应
注意:在java代码里,虽然请求地址信息放到了响应体中,但最后只有执行完对应Servlet程序后,才会发送响应体
并且当你设置了重定向地址后,后面不可再写重定向代码,否则报错
重定向的原理:
重定向的特点:
重定向之后,浏览器地址栏的URL会发生改变
重定向过程中会将前面Request对象销毁,然后创建一个新的Request对象,即原来的请求对象被销毁(原来的请求信息没了)
重定向的URL可以是其它项目工程
<?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">
<servlet>
<servlet-name>RedirectServlet</servlet-name>
<servlet-class>com.lagou.demo02.servlet.RedirectServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>RedirectServlet</servlet-name>
<url-pattern>/redirectServlet</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>ForwardServlet</servlet-name>
<servlet-class>com.lagou.demo02.servlet.ForwardServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ForwardServlet</servlet-name>
<url-pattern>/forwardServlet</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>TargetServlet</servlet-name>
<servlet-class>com.lagou.demo02.servlet.TargetServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>TargetServlet</servlet-name>
<url-pattern>/targetServlet</url-pattern>
</servlet-mapping>
</web-app>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>重定向后的页面</title>
</head>
<body>
<h1>服务器重新指定位置后的页面</h1>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>重定向的测试</title>
</head>
<body>
<form action="redirectServlet" method="post">
<input type="submit" value="重定向"/>
</form>
</body>
</html>
package com.lagou.demo02.servlet;
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 RedirectServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
System.out.println("接收到了浏览器的请求...");
response.sendRedirect("https://www.baidu.com/index.php?tn=monline_3_dg");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
this.doPost(request, response);
}
}
转发的概述-------------------------------------
转发的概念:
个Web组件(Servlet/JSP)将未完成的处理通过容器转交给另外一个Web组件继续处理
转发的各个组件会共享Request和Response对象
可以理解为当前的Servlet给另外一个Servlet
转发与重定向的区别就是:
转发是浏览器请求后,Web组件将帮你再次请求一次
也可以说是将路径给反射出来的对象,不用浏览器来给了,相当于重新请求
即给另外一个Web组件处理,即跳过去了
与重定向一样,只有执行完对应Servlet才会进行响应,转发到其他Servlet里,且不可再次转发,否则报错
重定向是Web组件要你重新请求一次
注意:实际上HttpRequest和HttpResponse只是中间操作,存放对应数据
即request对象是服务器对浏览器请求的封装,而response是服务器对服务器响应的封装,即信息是由他们的对象接收的
当程序执行完后,发送对应的对象信息
即可以说是请求信息给值(地址)给HttpRequest,加数据(HttpResponse)给响应信息
对中间后台程序内存或者响应信息进行操作而已,若没有写,也不会对路径造成影响
该显示的显示(即没有对其对象进行操作,那么就是原来对应的信息)
可以看出他们是对信息的扩展
而对于重定向和转发,实际上最后都是操作路径,但重定向若在转发前面
在转发时,会被重定向阻塞,最后重定向的响应信息就会保存错误信息,交给页面,然后浏览器就会显示,这是响应信息
且会使得重定向没有操作,使得页面没有进行跳转(没有302状态码了,即没有跳转,还是路径的响应信息)
若转发在重定向前面,那么由于转发是交给其他Web组件(即Servlet),相当于隔离的操作,即他会显示页面,且它会阻塞重定向
使得报错而结束程序,最后再操作新的Servlet
最后使用写入数据时,每个Servlet都会有对应的一个空文档,因为请求的路径就是请求的一个文件,若没有对应文件
则是添加一个该文件的空的文档(读取就会创建,IO流的读取会创建没有对应地址的文件)
且一个路径对应一个Servlet,所以才说每个Servlet都会有对应的一个空文档
若有资源,也会被输入流进行消除,所以基本上是空文档,当Servlet被销毁时,创建的文档也会删除
最后:转发的请求响应也是原来路径的请求响应,即原来路径的地址还是原来的,不是服务器转发的,而重定向则会改变原来的
可以理解为,转发不变原路径,重向改变原路径,浏览器请求时可以观察到
转发的实现:
package com.lagou.demo02.servlet;
import javax.servlet.RequestDispatcher;
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 ForwardServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
System.out.println("接收到了浏览器的请求...");
request.setAttribute("key1", "value1");
RequestDispatcher requestDispatcher = request.getRequestDispatcher("https://www.baidu.com/");
requestDispatcher.forward(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
this.doPost(request, response);
}
}
package com.lagou.demo02.servlet;
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 TargetServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
System.out.println("转发过来了...");
Object key1 = request.getAttribute("key1");
System.out.println("获取到的属性值为:" + key1);
response.setContentType("text/html;charset=utf-8");
response.getWriter().write("<h1>转发成功!</h1>");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
this.doPost(request, response);
}
}
转发的特点:
转发之后浏览器地址栏的URL不会发生改变
转发过程中共享Request对象和Response对象
转发的URL不可以是其它项目工程
重定向和转发的比较:
重定向:外部
转发:内部
Servlet线程安全(重点)------------------------------
服务器在收到请求之后,会启动一个线程来进行相应的请求处理
默认情况下,服务器为每个Servlet只创建一个对象实例
当多个请求访问同一个Servlet时,会有多个线程访问同一个Servlet对象,此时就可能发生线程安全问题(这就需要考虑公共资源的影响了,特别的如静态,或者公共map集合等等)
多线程并发逻辑,需要使用synchronized对代码加锁处理,但尽量避免使用
package com.lagou.demo02.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@WebServlet(name = "ThreadServlet", urlPatterns = "/thread")
public class ThreadServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
String name = request.getParameter("name");
System.out.println("获取到的name数值为:" + name);
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
PrintWriter writer = response.getWriter();
writer.write("<h1>" + name + "</h1>");
writer.close();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
this.doPost(request, response);
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Servlet线程安全的测试</title>
</head>
<body>
<iframe width="600px" height="100px" src="thread?name=zhangfei"></iframe><br/>
<iframe width="600px" height="100px" src="thread?name=guanyu"></iframe><br/>
<iframe width="600px" height="100px" src="thread?name=liubei"></iframe><br/>
</body>
</html>
重定向和转发的地址可以加斜杠也可不加,反正会默认加,即多余的斜杠会变成一个,一般代表中间的
无论是重定向还是转发,当前程序都会执行,其中Servlet执行完,就会响应,对应相同的Response就不可响应了
状态管理(重点)-----------------------
Web程序基于HTTP协议通信,而HTTP协议是"无状态"的协议,一旦服务器响应完客户的请求之后
就断开连接,而同一个客户的下一次请求又会重新建立网络连接
服务器程序有时是需要判断是否为同一个客户发出的请求,比如客户的多次选购商品
因此,有必要跟踪同一个客户发出的一系列请求
把浏览器与服务器之间多次交互作为一个整体,将多次交互所涉及的数据保存下来,即状态管理
多次交互的数据状态可以在客户端保存,也可以在服务器端保存,状态管理主要分为以下两类:
客户端管理:将状态保存在客户端。基于Cookie技术实现
服务器管理:将状态保存在服务器端。基于Session技术实现
Cookie技术(重点):
基本概念:
Cookie本意为"饼干"的含义,在这里表示客户端以"名-值"形式进行保存的一种技术
浏览器向服务器发送请求时,服务器将数据以Set-Cookie消息头的方式响应给浏览器
然后浏览器会将这些数据以文本文件的方式保存起来
当浏览器再次访问服务器时,会将这些数据以Cookie消息头的方式发送给服务器
package com.lagou.demo03.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(name = "CookieServlet", urlPatterns = "/cookie")
public class CookieServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
System.out.println("看看有没有执行到这里哦!");
Cookie cookie = new Cookie("name", "zhangfei");
response.addCookie(cookie);
System.out.println("创建Cookie成功!");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
this.doPost(request, response);
}
}
package com.lagou.demo03.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(name = "CookieServlet2", urlPatterns = "/cookie2")
public class CookieServlet2 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
Cookie[] cookies = request.getCookies();
System.out.println("获取到的Cookie信息有:");
for (Cookie tc : cookies) {
System.out.println(tc.getName() + "对应的值为:" + tc.getValue());
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
this.doPost(request, response);
}
}
package com.lagou.demo03.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(name = "CookieServlet3", urlPatterns = "/cookie3")
public class CookieServlet3 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
Cookie[] cookies = request.getCookies();
for (Cookie tc : cookies) {
if ("name".equalsIgnoreCase(tc.getName())) {
tc.setValue("guanyu");
response.addCookie(tc);
break;
}
}
System.out.println("修改Cookie信息成功!");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
this.doPost(request, response);
}
}
Cookie的生命周期:
默认情况下,浏览器会将Cookie信息保存在内存中,只要浏览器关闭,Cookie信息就会消失
如果希望关闭浏览器后Cookie信息仍有效,可以通过Cookie类的成员方法实现
package com.lagou.demo03.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(name = "CookieServlet4", urlPatterns = "/cookie4")
public class CookieServlet4 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
Cookie cookie = new Cookie("name", "liubei");
int maxAge = cookie.getMaxAge();
System.out.println("该Cookie的默认使用期限是:" + maxAge);
cookie.setMaxAge(0);
response.addCookie(cookie);
System.out.println("设置Cookie的生命周期成功!");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
this.doPost(request, response);
}
}
使用了上述期限,必须要满足对应条件,操作做,如我10*60分钟失效,那么就是你关闭浏览器他也会在那里
这时看Cookie时,后面有个过期时间(具体是那一个,可以百度,当然,可以看到会话二字的那么他就是在过期时间属性的地方),浏览器会检查这个时间,而进行操作,过了这个时间,那么就删除
而负数的就是会话时间,即关闭浏览器删除,而0则看不到,因为立即删除了
但是浏览器主动的清理缓存Cookie的话,还是会删除的(无视过期时间)
Cookie的路径问题:
浏览器在访问服务器时,会比较Cookie的路径与请求路径是否匹配,只有匹配的Cookie才会发送给服务器
Cookie的默认路径等于添加这个Cookie信息时的组件路径
例如:/项目名/目录/add.do请求添加了一个Cookie信息,则该Cookie的路径是 /项目名/目录
访问的请求地址必须符合Cookie的路径或者其子路径时,浏览器才会发送Cookie信息(注意:也包括域名,除非通过某些设置)
package com.lagou.demo03.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(name = "CookieServlet5", urlPatterns = "/cookie5")
public class CookieServlet5 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
Cookie cookie = new Cookie("name", "huangzhong");
cookie.setPath(request.getContextPath() + "/hello");
response.addCookie(cookie);
System.out.println("设置Cookie路径成功!");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
this.doPost(request, response);
}
}
实际上Cookie会在对应的请求信息和响应信息中,即不管怎么操纵,就是请求和响应之间的操作
Cookie的特点:
Cookie技术不适合存储所有数据,程序员只用于存储少量、非敏感信息,原因如下:
将状态数据保存在浏览器端,不安全
保存数据量有限制,大约4KB左右
只能保存字符串信息
可以通过浏览器设置为禁止使用,因为有些网站必须要Cookie才可进行操作
即必须要有Cookie数据给他的服务器,这是他们页面的设置
这个禁止,可以理解为就是禁止发送Cookie,和接收Cookie
Session技术(重点)-------------------------------
基本概念:
Session本意为"会话"的含义,是用来维护一个客户端和服务器关联的一种技术
浏览器访问服务器时,服务器会为每一个浏览器(因为Cookie是浏览器里的)都在服务器端的内存中分配一个空间
用于创建一个Session对象
该对象有一个id属性且该值唯一,我们称为SessionId,并且服务器会将这个SessionId以Cookie方式发送给浏览器存储
只发送一次,除非造成Session销毁的操作,那时就会再次发送
id就是上面的JSESSIONID(名称)对应的值,即值唯一,除非重新启动服务器,就是销毁原来的Session内存
那么这个值会改变,但名称不会变,不同服务器可能名称不同
或者删除对应的Cookie的值,因为没有发送对应SessionId的Cookie给服务器
那么就会销毁原来的Session内存
那么这个值会改变,但名称不会变,不同服务器可能名称不同
浏览器再次访问服务器时会将SessionId发送给服务器,服务器可以依据SessionId查找相对应的Session对象
package com.lagou.demo03.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet(name = "SessionServlet", urlPatterns = "/session")
public class SessionServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
HttpSession session = request.getSession();
System.out.println(session.isNew()? "新创建的Session对象": "已有的Session对象");
String id = session.getId();
System.out.println("获取到的Session编号为:" + id);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
this.doPost(request, response);
}
}
package com.lagou.demo03.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet(name = "SessionServlet2", urlPatterns = "/session2")
public class SessionServlet2 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
HttpSession session = request.getSession();
session.setAttribute("name", "machao");
System.out.println("获取到的属性值为:" + session.getAttribute("name"));
session.removeAttribute("name");
System.out.println("获取到的属性值为:" + session.getAttribute("name"));
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
this.doPost(request, response);
}
}
Session的生命周期:
为了节省服务器内存空间资源,服务器会将空闲时间过长的Session对象自动清除掉,服务器默认的超时限制一般是30分钟
package com.lagou.demo03.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet(name = "SessionServlet3", urlPatterns = "/session3")
public class SessionServlet3 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
HttpSession session = request.getSession();
int maxInactiveInterval = session.getMaxInactiveInterval();
System.out.println("获取到的失效时间为:" + maxInactiveInterval);
session.setMaxInactiveInterval(1200);
maxInactiveInterval = session.getMaxInactiveInterval();
System.out.println("获取到的失效时间为:" + maxInactiveInterval);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
this.doPost(request, response);
}
}
可以配置web.xml文件修改失效时间:
<?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">
<session-config>
<session-timeout>10</session-timeout>
//会将默认改为600秒,即10*60,10分钟
</session-config>
</web-app>
Session的特点:
数据比较安全
能够保存的数据类型丰富,而Cookie只能保存字符串
能够保存更多的数据,而Cookie大约保存4KB
数据保存在服务器端会占用服务器的内存空间,如果存储信息过多、用户量过大,会严重影响服务器的性能
Cookie与Session,一个是通行证,一个是记录者,前者数据走动,但不存,后者不走动,但存
最后要说明的是:
我们知道一般情况下,你可能认为请求后,回退是回退,而不会再次的请求,但是这里就要颠覆了,实际上post再回退时,会重新操作当前的访问(回退的),注意:是资源的访问,也就是说,get是操作缓存的,而post不是,与页面无关哦,是资源哦,这是缓存的问题,具体可以百度,比如:https://ask.csdn.net/questions/7518088,对应的get和post的区别:https://mp.weixin.qq.com/s?__biz=MzI3NzIzMzg3Mw==&mid=100000054&idx=1&sn=71f6c214f3833d9ca20b9f7dcd9d33e4#rd