目录
一. servlet
1.servlet的基础
1.1 servlet的概念
Servlet是javaWeb的三大组件之一 ,是线程不安全的组件 它属于动态资源,Servlet的作用是请求处理,服务器会把接受的请求交给servlet来处理,在servlet中通常需要:
- 接受请求数据
- 处理请求
- 完成响应
每个servlet都是唯一的,他们处理的请求是不同的
不同的servlet完成不同的功能
1.2 实现servlet的方式(由我们自己编写)
- 实现javax.servlet.Servlet接口
- 继承javax.servlet.GenericServlet类
- 继承javax.servlet.http.HttpServlet类
通常我们会继承HttpServlet类来完成我们学习的Servlet
Servlet的大多数方法必须由服务器(tomcat)来调用,大多数不由我们来调用servlet的对象也不由我们来创建 由服务器来创建。
1.2.1 init(ServletConfig servletConfig) 方法 :
在 Servlet 的生命期中,仅执行一次 init() 方法。它是在服务器装入 Servlet 时执行的。 可以配置服务器,以在启动服务器或客户机首次访问 Servlet 时装入 Servlet。 无论有多少客户机访问 Servlet,都不会重复执行 init()
1.2.2 service(HttpServletRequest request, HttpServletResponse response) 方法
service() 方法是 Servlet 的核心。每当一个客户请求一个HttpServlet 对象,该对象的service() 方法就要被调用,而且传递给这个方法一个"请求"(ServletRequest)对象和一个"响应"(ServletResponse)对象作为参数。
1.2.3 destroy() 方法
destroy() 方法仅执行一次,即在服务器停止且卸装Servlet 时执行该方法。也就是在关闭服务器的时候就会自动结束
如图:
1.3 如何应用浏览器调用servlet
- 给servletz指定一个路径(让servlet与一个路径绑定在一起)servlet 3.0以后不会在web.xml中自动配置 需要自己编写或者 使用注解的方法
- 如图:
如 @WebServlet("/Aservlet")
那么在浏览器访问的时候只需要
http://localhost:8080/项目名/Aservlet - 或者使用web,xml来配置
web.xml
<servlet>
<servlet-name>servlet的名字</servlet-name>
<servlet-class>servlet的包名/servlet的名字</servlet-class>
</servlet>
//由两部分组成 必须成对出现
<servlet-mapping>
<servlet-name>浏览器访问的名字(也就是刚才注释的名字)</servlet-name>
<url-pattern>/浏览器访问的名字(也就是刚才注释的名字)(必须以斜杠开头 “/”)</url-pattern>
</servlet-mapping>
特性:
- 单例,一个类只有一个对象,可以存在多个servlet类
- 线程不安全,所以他的效率很高
对象由我们创建 但是大部分由服务器调用
2. GenericServlet
2.1 GenericServlet概述:
GenericServlet是servlet接口的实现类,我们可以通过集成GenericServlet来编写自己的Servlet。
一个servlet的配置信息与一个ServletConfig对应
通过ServletConfig可以获取本servlet的配置相关信息
API中:
String getServletName():获取的是中的内容
ServletContext getServletContext():获取servlet上下文对象
ServletContext是一个接口 实现类由tomcat提供
Enumeration getInitParameterNames(String name);//返回的是一个迭代器
String getInitParameter(String name);//通过名称获取指定初始化参数的值
下面通过在servlet中使用方法 来获取p1 p2的值
使用String getInitParameter(String name);
Enumeration getInitParameterNames(String name);
servlet在GenericServlet进行了包装 需要在初始的时候调用或者执行任何代码 需要在子类中重新定义 init();
注意:是无参数的 因为在GenericServlet中,进行了一个init();方法的定义 但是没有任何代码 在带有参数的public void init(ServletConfig servletConfig) 中调用了init(),这就解决了在子类中重写init会将父类的init覆盖的问题
3. HttpServlet
服务器在进行请求的时候会自动创建HttpServlet对象,HttpServlet 然后进行强转与servlet进行信息互换
HttpServlet extends GenericServlet{
void service(ServletRequest,ServiceResponse)--->生命周期方法
强转两个参数为Http协议的相关类型
调用奔雷的service(HttpServletRequset,HttpServletReponse)
}
void service(HttpServletRequset,HttpServletReponse)-->参数已经是Http协议相关的,使用起来更加方便
它会通过request得到当前请求的请求方法 例如:Post 或者 get
根据请求方式在调用doPose() 或 doGET()0
如图:
3.1servlet的细节
- Servlet与线程安全.
因为一个类型的Servlet只有一个实例对象,那么就有可能会出现一个Servlet同时处理多个请求,Servlet不是线程安全的,这说明Servlet的工作效率会非常高,但是也存在线程安全问题。
所以我们不应该在Servlet中随便创建成员变量,因为可能会存在一个线程对这个成员变量进行写操作,另一个线程对这个成员变量进行读操作
解决的办法:
- 不要在Servlet中创建成员,创建局部变量即可;
- 可以创建无状态成员;
- 可以创建有状态的成员,但是状态必须是只读的
- 让服务器在启动的时候就创建Servlet
默认情况下,服务器会在某个Servlet第一次收到请求时创建它,也可以在web.xml中对servlet进行配置,使服务器启动时就创建Servlet
在服务器启动的时候就创建Servlet 第一次创建花费的时间比较长 ------第一次代价
<servlet>
<description></description>
<display-name>Bservlet</display-name>
<servlet-name>Bservlet</servlet-name>
<servlet-class>com.tjk.servlet.cn.Aservlet</servlet-class>
<init-param>
<param-name>p1</param-name><!--对应属性的名字 -->
<param-value>v1</param-value><!--对应属性的值 -->
</init-param>
<init-param>
<param-name>p2</param-name><!--对应属性的名字 -->
<param-value>v2</param-value><!--对应属性的值 -->
</init-param>
<!--这个标签是控制服务器启动时创建servlet对象的顺序 必须是非负整数-->
<!--小值先创建 大值后创建-->
<load-on-startup>1</load-on-startup>
</servlet>
- 中通配符的使用
所谓的通配符就是 * 星号可以匹配任何URL前缀或后缀,使用通配符可以命名一个servlet绑定一组URL,eg:
-
"<url-pattern>/servet/*</url-pattern>"
//路径匹配 -
"<url-pattern>*.do</url-pattern>"
//扩展名匹配 -
"<url-pattern>/*</url-pattern> 匹配所有的URL
匹配度越高优先级越高
请注意:
通配符要么为前缀,要么为后缀,不能出现在URL中间位置,也不能只有通配符
通配符是一种模糊匹配URL的方式如果存在更具体的 url-pattern 那么匹配路径会去匹配更具体的 -
web.xml文件的继承性:(了解)
每个完整的JavaWeb应用中都需有web.xml,且所有的web.xml有一个共同的父文件,在Tomcat的conf/web.xml
这里面的所有内容相当于直接写入到每个项目的web.xml中了当servlet的请求不存在的时候,就会调用默认的这个Defaultservlet 页面显示404 优先级最低 没有任何servlet处理就会调用
当请求jsp页面的时候会自动调用jspServlet将动态资源转换为静态资源 然后通过response进行响应
session的过期时间默认为30分钟
3.2 ServletContext
与天地同寿
当浏览器进行一个 http://localhost:8080/Day09/Bservlet请求时,后端会将路径与web.xml中的配置信息进行对比,判断应该响应哪个servlet,然后应用java反射机制classForName
一个javaWeb项目中只能有一个ServletContext对象
3.2.1. ServletContext概述:
服务器会为每一个应用创建一个ServletContext对象
- ServletContext对象的创建时在服务器启动时完成的
- ServletContext对象的销毁是在服务器关闭时完成的
ServletContext对象的作用是在整个Web应用的动态资源之间共享的数据!例如:在Aservlet中向ServletContext中保存一个值,可以在Bservlet中获取3.2.2 获取ServletContext
在Servlet中获取ServletContext对象: - void init(ServletConfig config)中: ServletContext context=servletConfig.getServletContext(); 可以获取ServletContext对象 - 在GenericServlet或HttpServlet中获取ServletContext对象 GenericServlet类中有getServletContext()方法,所以可以直接用this.getServletContext()来获取; - HttpSession中的 getServletContext(); - ServletContextEvent 中getServletContext();
3.2.3 域对象的功能
<hr>
域对象:就是用来在多个servlet中传递数据的
必须有存取数据的功能
ServletContext是JavaWeb四大域对象之一
- PageContext
- ServletRequest
- HttpSession
- ServletContext
所有的域对象都有存取数据的功能,因为域对象内部有一个Map,用来存储
数据。
- void setAttribute(String name ,Object value):用来存储一个对象,也可以称之为存储一个域属性,如果多次调用该方法,并且设置同一个name值,就会覆盖上一次设置的value值。
- Object getAttribute(String name):用来获取ServletContext中的数据,获取之前必须先进行存储
- void removeAttribut(String name):用来溢出ServletContext中的域属性,如果name不存在,那么本方法什么都不做
- Enumeration getAtributeNames():获取所有域属性de 名称
3.2.4 获取应用初始化参数
- Servlet 也可以获取初始化参数,但它是局部的参数,也就是说,一个Servlet只能获取自己的初始化参数,不能获取别人的,即初始化参数只为一个Servlet准备
- 可以配置公共的初始化参数,为所有Servlet而用,这些药ServletContext才能使用
web.xml 注意:这里的是在
<context-param>
<param-name>name</param-name>
<param-value>哈哈哈</param-value>
</context-param>
servlet:如下:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
ServletContext context=this.getServletContext();
String value=context.getInitParameter("name");
System.out.println(value);
}
console框如下:
3.2.5 利用ServletContext获取资源路径
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
String ip="http://localhost:8080/Day09/Dservlet";
/*
* 获取的路径是带盘符的;
*/
String ip1=this.getServletContext().getRealPath("/index.jsp");
//得到的是:ip1:F:\spring2\sts\.metadata\.plugins\org.eclipse.wst.server.core\tmp1\wtpwebapps\Day09\index.jsp
System.out.println("ip1:"+ip1);
InputStream inputStream=new FileInputStream(ip1);
//得到的是流对象: ip1转换为:java.io.FileInputStream@7e09740c
System.out.println("ip1转换为:"+inputStream);
//获取资源对象后 在创建流对象
InputStream input=this.getServletContext().getResourceAsStream("/index.jsp");
System.out.println("input:"+input);
//获取当前路径下的所有资源的路径
//这里用set集合是因为java.util.HashSet强制转换为java.util.List
Set<String> s1= this.getServletContext().getResourcePaths("/WEB-INF");
//得到的数据:[/WEB-INF/lib/, /WEB-INF/classes/, /WEB-INF/web.xml]
System.out.println(s1);
}
3.2.6 页面访问次数案例
所有的项目的资源被访问都必须给访问量进行累加
方法:
创建一个int 类型的变量 ,用来保存访问量进行统计,然后将它保存在ServletContext域中
- 最初时,ServletContext中没有保存访问量相关的属性,
- 当本站第一次被访问时,创建一个变量,设置其值为1;保存在ServletContext中
- 当以后访问时,就可以从ServletContext中获取这个变量,然后再其基础之上+1
获取ServletContext对象,查看是否存在名为count的属性,如果存在说明不是第一次访问,如果不存在,说明是第一次访问 - 第一次访问,调用Servletcontext的setAttribute传递一个属性,名为count值为1
- 第二次以上访问,调用ServletContext的getAttributre方法回去原来的访问量,给访问量+1,在调用ServletContext的setAttribute方法完成设置
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
response.getWriter().append("Served at: ").append(request.getContextPath());
/*
* 网站访问量的统计案例
*/
//创建servletContext对象
ServletContext app=this.getServletContext();
Integer count=(Integer)app.getAttribute("count");
if(count==null) {
app.setAttribute("count", 1);
}else {
app.setAttribute("count", count+1);
}
System.out.println("count:"+count);
PrintWriter pw=response.getWriter();
pw.print("<h1>"+count+"</h1>");
}
页面访问如图所示:
4 获取类路径下的资源
获取类路径资源,类路径对一个javaWeb项目而言,就是/WEB-INF/classes和WEB-INF/lib下的每一个jar包
/*
有两种方法
第一种: 使用classLoader
先得到class 在得到classLoader
再调用其getResourceAsStream()得到一个inputStream
第二种: 使用class
*/
ClassLoader c1=this.getClass().getClassLocder();//路径方式仅仅有一种
InputStream input=c1.getResourceAsStream("路径");//(绝对路径/../....)
//使用Class
Class c=this.getClass();//路径方式有两种
//相对于当前 .class所在的目录
inputStream input=c.getResourceAsStream("相对路径");//(“a.txt”)
/或者a.txt
//相对classes下!
String s=IOUtiles.toString(input);//读取输入流的内容,转换为字符串返回
二. request 和 response
服务器处理流程:
服务器每次收到请求时,都会为这个请求开辟一个新的线程
服务器会把客户端的请求数据封装到request对象中,request就是请求数据的载体
服务器还会创建response对象,这个对象与客户端连接在一起,它可以用来向客户端发送响应
1. response:其真实类型是**HttpServletResponse
HttpServletResponse---------->它是和http协议有关的
ServletResponse------------->它是和协议没有关系的
http协议中:包含:
- 状态码
200 | 成功 |
---|---|
302 | 重定向 |
404 | 客户端错误(访问资源不存在) |
500 | 服务器出错 |
方法:
sendError(int sc)(发送失败状态码的方法)
sendError(int sc ,String msg)(发送失败状态码的方法+错误信息)
setStatus(int sc)(成功的方法)
头:(是一对键值对)
响应头(头名) 响应头的值(头值)
Content-Type:text/html;charset=utf-8
案例:
发送404
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
response.sendError(404, "已经访问到_404_Practice但是不给你看滴滴滴");
}
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200120215152726.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM5NzU5NjY0,size_16,color_FFFFFF,t_70
1.1 响应头 Content-Type Refresh Location等等
头就是一个键值对,可能会存在一个头(一个名称,一个值),也可能存在一个头(一个名字,多个值)
setHeader(String name, String value) | 适用于单值得响应头 |
---|---|
addHeader(String name, String value) | 适用于多值的响应头 |
setIntHeader(String name, int value) | 适用于单值得int类型的响应头 |
addIntHeader(String name, int value) | 适用于多值int 类型的响应头 |
setDateHeader(name, long date) | 适用于单值得毫秒类型的响应头 |
addDateHeader(String name, long date) | 适用于多值的毫秒类型的响应头 |
eg: response.setHeader(“aaa”,“AAA”);
案例:
① 发送302,设置location头,完成重定向
② 定时刷新,设置refresh头—>可以理解为 定时的重定向
③ 禁用浏览器缓存,Cache-Control (no-cache)、pragma(no-cache)、expires(-1)
重定向:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
response.getWriter().print("Cservlet激发了");
response.setHeader("Location", "/Day10/Bservlet");//第一步:设置location 和跳转的URL
response.setStatus(302);//第二部发送 响应码
response.getWriter().print("激发完毕");
}
第二种快捷的重定向(直接跟要重定向的链接URL):
response.sendRedirect("http://www.baidu.com");//直接跟要重定向的链接URL
定时刷新:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
PrintWriter printWriter=response.getWriter();
printWriter.print("only has five seconds ");
response.setHeader("Refresh", "5,URL=/Day10/Eservlet");//标志头是refresh 5:五秒 URL是刷新的目的链接
}
禁用浏览器缓存:(这个东西在html的新建标签页上有可以看到 只是设置的地方不一样)
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
response.getWriter().append("Served at: 禁止缓存案例").append(request.getContextPath());
response.setHeader("Cache-Control", "no-cache");
response.setHeader("pragma", "no-cache");
response.setDateHeader("expires", -1);
}
标签可以代替响应头:
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
响应体:通常是Html 也可以是图片!
response的两个流: 两个流不能同时使用
ServletOutputStream | 用来向客户端发送字节数据 |
---|---|
PrintWrite: | 用来向客户端发送字符数据,需要设置编码 |
字节流是万能的,但是字符流不是的
例子:
字符流的:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
//response.getWriter().append("Served at:ServletOutputStream io测试 ").append(request.getContextPath());
ServletOutputStream output=response.getOutputStream();
String itString="这是ServletOutputStream流的字符流对象";
byte[] bytes=itString.getBytes();
response.getOutputStream().write(bytes);
}
发送图片数据 (必须是字节流的)
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
FileInputStream input=new FileInputStream("F:/tjk.png");
byte[] bytes=IOUtils.toByteArray(input);//(读取字符流中的数据到字符数组中去)
response.getOutputStream().write(bytes);
}
上面发送图片案例必须有:jar commen-io的包
链接地址:commen-io jar
2. request–>封装了客户端所有的请求数据
请求行
请求头
空行
请求体(GET没请求体)
-
获取常用信息
获取客户端IP 案例:封IP String getRemoteAddr();
请求方式 request.getMethod();可能是POST 或者GET -
获取请求头
String getHeader(String name) 适用于单值头 int getIntHeader(String name ) 适用于单值int 类型的请求头 long getDateHeader(String name), 适用于单值毫秒类型的请求头 Enumeration getHeaders(String name), 适用于多值请求头 - 案例:
- 通过User-Agent识别用户浏览器类型
- 防盗链:如果请求不是通过本站的超链接发出的,发送错误状态码404
案例一:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub response.getWriter().append("Served at: ").append(request.getContextPath()); String addrString = request.getRemoteAddr();// 获取访问的ip地址 System.out.println(addrString); System.out.println("请求方式:" + request.getMethod()); System.out.println("User-gent:" + request.getHeader("User-Agent")); //为了不区分大小写 但contains中必须写的书小写 if (request.getHeader("User-Agent").toLowerCase().contains("firefox")) { System.out.println("是火狐啊"); } else { System.out.println("不是啊"); } }
-
获取请求URL
String getScheme(): 获取协议 String getServerName() 获取服务器名 String getServerPort() 获取服务器端口 String getContextPath() 获取项目名 String getServletPath() 获取Servlet路径 String getQueryString() 获取参数部分,即问号后面的内容 String getRequestURL(); 获取请求URL,等于项目名+Servlet路径 String getRequestURL() 获取请求URL,等于不包含参数的整个请求路径
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
response.getWriter().append("Served at: ").append(request.getContextPath());
System.out.println("协议名:"+ request.getScheme());
System.out.println("获取服务器名"+ request.getServerName());
System.out.println("获取服务器端口"+ request.getServerPort());
System.out.println("获取项目名"+request.getContextPath());
System.out.println("获取servlet路径"+request.getServletPath());
System.out.println("获取参数部分"+request.getQueryString());
System.out.println("获取请求URI"+request.getRequestURI());
System.out.println("获取请求的URL"+request.getRequestURL());
}
运行结果:
案例二:
servlet:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
response.getWriter().append("Served at: ").append(request.getContextPath());
String referer=request.getHeader("Referer");//获取请求路径
System.out.println("referer: "+referer);
if(referer==null||referer.toLowerCase().contains("localhost")) {
System.out.println("本地请求");
}else {
System.out.println("非本地请求" );
}
}
html:
<body>
<a href="/Day10/ACservlet">222</a>
</body>
3 获取请求参数
获取请求参数,请求参数是由客户端放给服务器的!有可能是在请求体(post) 有可能是在URL之后 (GET)
String getParameter(String name); | 获取指定名称的请求参数值,适用于单值请求参数 |
Enumeration getParamterName(); | 获取所有的请求参数的名称 |
Map<String,String> getParameterMap() | 获取所有请求参数,其中Key为参数名,value为参数值 |
ADservlet:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
response.getWriter().append("Served at: ").append(request.getContextPath());
String name=request.getParameter("name");
String password=request.getParameter("password");
String[] hobby=request.getParameterValues("hobby");
System.out.println(name+"--"+password+"---"+hobby);
}
B.html
<h2>请求参数</h2>
<form action="/Day10/ADservlet" method="post">
姓名:<input type="text" name="name">
密码:<input type="text" name="password">
爱好:<input type="checkbox" name="hobby" value="篮球">篮球
<input type="checkbox" name="hobby" value="足球">足球
<input type="checkbox" name="hobby" value="羽毛球">羽毛球
<input type="submit" value="提交">
</form>
4.请求转发和响应重定向
在这个过程中实际只创建了一个request和response对象
RequestDispatcher rd=request.getRequestDispatcher("/AAservlet"); | 参数是被转发或被包含的servlet路径 |
---|---|
rd.forward(request, response);//请求转发 | |
rd.include(request, response);//请求包括 |
有时一个请需要多个Servlet写作才能完成 ,所以需要在一个servlet跳转到另一个servlet
- 一个请求夸多个servlet,需要使用转发和包含
- 请求转发:由下一个servlet完成响应体,当前servlet可以设置响应头(留头不留体)
- 请求包含:由两个servlet共同完成响应体(都留)
- 无论是请求转发还是请求包含,都在一个请求范围内!使用同一个request和response
请求转发:
OneServlet
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
System.out.println("这是oneServlet");
response.setHeader("AAA", "你妹啊"); //设置响应头
response.getWriter().print("Hello OneServlet");//设置响应体 响应体的最大容量24K内部缓存机制限定的 这个响应体会被覆盖 不会出现
request.getRequestDispatcher("/TwoServlet").forward(request, response);//请求转发
}
TwoServlet
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
//response.getWriter().append("Served at: ").append(request.getContextPath());
response.getWriter().print("TwoServlet---xixi");
String s1= response.getHeader("AAA");//这个东西放到哪个对象中就从那个对象去出来
System.out.println(s1);
}
请求包含:
IncludeOneServlet
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
System.out.println("这是oneIncludeServlet");
response.setHeader("AAA", "你妹啊"); //设置响应头
response.getWriter().print("Hello OneServlet");//设置响应体 响应体的最大容量24K 此处的响应体不会被覆盖
request.getRequestDispatcher("/IncludeTwoServlet").include(request, response);//请求转发
}
IncludeTwoServlet
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
response.getWriter().print("IncludeTwoServlet---xixi");
String s1= response.getHeader("AAA");
System.out.println(s1);
}
请求包含中第一个servlet的响应体不会被覆盖掉 都会显示出来
请求转发第一个servlet的响应体会被覆盖
5. request 域
有三个域:request session application 都有如下所有的方法:
void setAttribute(String name,Object value)
Object getAttribute(String name)
void removeAttribute(String name)
同一个请求范围内使用 requset.setAttribute() request.getAttribuye()来传值
请求转发和重定向的区别 :
- 请求转发是一个请求一次响应,而重定向是两次请求,两次响应
- 请求转发地址链不发生变化,而重定向会显示后一个请求的地址
- 请求转发只能转发到本项目其他servlet,而重定向不只能重定向到本项目的其他servlet,还能重定向到其他Servlet
- 请求转发是服务端行为,只需给转发的servlet路径,而重定向需要给出requestURI,即包含项目名
6. 路径
三. jsp基础
1. jsp的作用:
- Servlet:
缺点: 不适合设置html响应体,需要戴昂的response.getWrite().print(“html”)
优点:动态资源,可以编程 - html:
缺点:html是静态页面,不能包含动态信息
优点:不用为输出html标签而发愁 - jsp
优点:在原有的html的基础上添加java脚本,构成jsp页面
2. jsp和servlet的分工
- jsp:
作为请求发起页面:例如显示表单 超链接
作为请求结束页面,例如显示数据 - servlet
作为请求中处理数据的环节
3. jsp的组成
- jsp=html+java脚本+jsp标签(指令)
- jsp中无需创建即可使用的对象一共有九个,被称之为九大内置对象,例如request对象,out对象
- java脚本:
<%…%>:java 代码片段,用于定义java语句 方法里面些什么这里就可以写什么
<%=…%>:java表达式,用于输出,用于输出一条表达式(或变量)的结果
<%!..%>声明:用来创建类的成员变量和成员方法(基本不用,但容易被考)
4. jsp原理
jsp其实是一种特殊的Servlet
-
当jsp页面第一次被访问时,服务器会把jsp编译成java文件(这个java文件其实是一个Servlet类)
-
然后再把Java编译成.class文件然后创建该类对象
-
最后调用它的service()方法第二次氢气统一jsp时,直接调用service方法
- 在tomcat的work目录下可以找到哦啊jsp 对象的java源代码
- 查看jsp对象的java文件
java脚本
html
在jsp页面上java代码编译后还是原样,但是 html代码会变为字符串用 out.write(“…”)输出
- jsp注释
<%-- …–%>当服务器把jsp编译成java文件时已经忽略了注释部分
<%–…--%>这个标签在查看源代码时不会显示
<!- -->这个标签会在查看源代码的时候进行显示 并且会执行其中的代码 只是不进行显示而已
四. Cookie
cookie不能跨浏览器
1. Http协议与Cookie
- Cookie是HTTP协议制定的 ,先由夫妻保存Cookie到浏览器,再下次浏览器请求服务器时把上一次请求得到Cookie再归还给服务器
- 由服务器创建保存到哭护端浏览器的一个键值对,服务器保存Cookie的响应头:Set-Cookie:aaa=AAA; Set-Cookie:bbb=BBB;
- 当浏览器请求服务器时,会把该服务器保存的Cookie随请求发送给服务器,浏览器归还Cookie的请求头 Cookie:aaa=AAA;bbb=BBB
- Http协议规定(保证不给浏览器太大压力)
- 一个Cookie最大是4KB
- 一个服务器最多向一个浏览器保存20个Cookie
- 1个浏览器最多可以保存300个Cookie
- 浏览器大战:因为浏览器竞争很激烈,所以很多浏览器都会在一定范围内违反HTTP的对顶,但是也不会让一个Cookie的值为4GB
2. Cookie的用途:
- 服务器使用Cookir来追踪客户端状态
- 保存购物车(购物车中商品不能使用request保存,因为他是一个用户想服务器发送的多个请求信息)
- 显示上次登录名(也是一个用户多个请求)
3. JavaWeb中使用Cookie
- 原始方式
使用response发送Set-Cookie响应头
使用request获取Cookie请求头- 便捷方式(精通)
使用response.addCookie()方法想浏览器保存Cookie
使用request.getCookies()方法获取浏览器会还Cookie
设置Cookie
得到Cookie
- 便捷方式(精通)
4. Cookie详解
- Cookie不只有name和value两个属性
- Cookie的maxAge:Cookie可保存的最大时长,以秒为单位,例如cookie.setMaxAge(60)表示这个cookie会被浏览器保存到硬盘上
- maxAge>0 浏览器会把Cookie保存到客户机硬盘上,有效时长为maxAge的值决定
- maxAge<0 Cookie 只在浏览器内存中存在,当用户关闭浏览器时,浏览器进程结束 相应的Cookie也就死亡
- maxAge=0 浏览器会马上删除这个Cookie
- Cookie的path
- Cookie的path并不是设置这个Cookie在客户端的保存路径
- Cookie的path由服务器创建Cookie时设置
- 当浏览器访问服务器的某个路径时,需要归还那些Cookie给服务器呢?这由Cookie的path决定
- 浏览器访问服务器的路径,如果包含 Cookie的路径,那么就会归还那个Cookie
- Cooke 的path默认值,当前访问路径的父路径 降一级
例如: /day10/jsp/a.jsp响应Cookie那么这个cookie的路径就为/day10/jsp/ - Cookie的domain(域)
domain用来指定Cookie的域名,当多个二级域中共享Cookie时才有用
例如:www.baidu.com zhidao.baidu.com tjk.baidu.com 之前共享Cookie值可以使用domain- 设置domain为 cookie.setDomain(".baidu.com")
- 设置path为cookie.setPath("/");
五. HttpSession
1. HttpSession概述:
- HttpSession是由JavaWeb提供的,用来会话跟踪的类,Session是服务器对象,保存在服务器端
- HttpSession是servlet三大域对象之一,所以他也是Setttribute getAttribute removeAttribute
- HttpSession底层依赖Cookie 或是url重写
2. HttpSession的作用
- 会话范围:会话范围是某个用户从首次访问服务器开始,到该用户关闭浏览器结束
会话:一个用户对服务器的多次连贯性请求!所谓连贯性请求,就是该要不过户多次请求中间没有关闭浏览器- 服务器会对每个客户端创建一个session对象,session就好比客户在服务器端的账户,他们被服务器保存到一个Map中,这个Map被称为session缓存
- Servlet中得到session对象:HttpSession session=request.getSession();
- jsp中的得到session对象:session是jsp内置对象,不用创建就可以直接使用
- session域相关方法
- void setAttribute(String name,Object value);
- Object getAttribute(String name)
- void removeAttribute(String name)
3. HttpSession原理
- request.getSession()方法:
- 获取Cookie中的sessionId;
a. 如果sessionId不存在,创建session,把session保存起来,把新创建的sessionId保存在Cookie中
b. 如果sessionId存在,通过sessionId查找session对象,如果没哟查找到,创建session把session保存起来,把创建的sessionId保存到Cookie中
c.如果sessionId存在,通过sessionId查找到了session对象,那么就不会在创建session对象
- 返回session
如果创建了新的session,浏览器会得到一个包含sessionId的cookie,这个cookie的生命为-1,即只在浏览器内存中存在,如果不关闭浏览器,那么Cookie一直存在
如果在服务器不关闭的情况下,将浏览器关闭了 那么将会创建新的session 以前的那个sessionId 在最大有效时间过去后自动销毁
下次请求时,再次执行request.getSession()方法时,因为可以通过Cookie中的sessionId找到session对象,所以与上一次请求时获取的session是一个对象
服务器不会马上给你创建session,在第一次获取session时,才会创建!
request.getSession(flase); 如果session缓存中(如cookie不存在),不存在session,那么返回null,而不会创建session对象
request.getSession(true);//会返回session对象
request.getSession();//会返回session对象
- 获取Cookie中的sessionId;
4. HttpSession其他方法
- String getId(),获取sessionId;
- int getMaxInactiveInterval();获取session可以是最大不会动时间(秒),默认为30分钟,当session在30分钟内没有使用,那么Tomcat会在session池中移除
- void invalidate(),让session失效
- boolean isNew();查看session是否为新的
5. web.xml中配置session的的最大不活动时间
<session-config>
<session-timeout>30</session-timeout>
</session-config>
6. URL重写
就是把所有的页面的路径都使用response.encodeURL("…")处理一下;
原理是:将Cookie变为参数传递
- session依赖于Cookie,目的是让客户端发出请求时归还sessionId,这样才能找到对应的session
- 如果客户端禁用了Cookie,那么就无法得到sessionId,那么session也就无用了
- 也可以使用URL重写替代Cookie
- 让网站的所有超链接,表单中添加一个特殊的请求参数,即sessionId
- 这样服务器就可以通过获取请求桉树得到sessionId,从而找到sessionId对象
- response.encodeURL(String url)
<a href="/Asession;JSESSIONID=<%=session.getId() %>">点击这里</a>
<a href="/Asession;JSESSIONID=<%=session.getId() %>">点击这里</a>
<a href="/Asession;JSESSIONID=<%=session.getId() %>">点击这里</a>
<%=response.encodeURL("/Asession") %>>