jsp内置对象,作用域(二)

一. 请求转发与重定向区别

请求转发 重定向
request.getRequestDispatcher("success.jsp") response.sendRedirect("success.jsp");
.forward(request,response);
地址栏是否改变 不变 改变
但是可以看出标题title是success.jsp的title
是否保留第一次请求时的数据 保留 不保留,获取不到
请求次数 1(服务器内部请求) 2
跳转发生的位置 服务器 客户端
不可以用于表单的提交(增删改),刷新造成重复提交
服务器内部的跳转。 只能跳转到服务器内部的资源,不可以跳转到服务器外部资源。 可以重定向到外部资源
request.getRequestDispatcher("https://www.baidu.com/")....失败 response.sendRedirect("https://www.baidu.com/"); 成功
在这里插入图片描述 在这里插入图片描述
张三(客户端)–>服务窗口1–>服务窗口2 张三(客户端)–>服务窗口1–>去找服务窗口2,,,,,,,, 张三(客户端)–>服务窗口2

简单登录页面,登录成功,转到欢迎页面(欢迎XX),请求转发(可以),重定向(不可以,数据丢失)登录失败,返回登录界面

  1. 登录页面 login.jsp
<head>
    <title>登录</title>
</head>
<body>
<form action="doLogin.jsp" method="post">
    姓名: <input type="text" name="username"><br>
    密码: <input type="password" name="password"><br>
    <input type="submit" value="提交">
</form>
</body>
  1. 验证页面 doLogin.jsp
<head>
    <title>验证</title>
</head>
<body>
    <%!
    //   模拟数据库
        String username = "李";
        String password = "123";
    %>
    <%
        request.setCharacterEncoding("utf-8");
        String name = request.getParameter("username");
        String pwd = request.getParameter("password");
        if (Objects.equals(username,name) && Objects.equals(password,pwd)){
//            请求转发
           request.getRequestDispatcher("success.jsp").forward(request,response);
        }else {
            request.getRequestDispatcher("login.jsp").forward(request,response);
        }
    %>
</body>
  1. 登录成功页面 success.jsp
<head>
    <title>登录成功</title>
</head>
<body>
<h1>request欢迎您: <%=request.getParameter("username")%></h1>
</body>
</html>

二. config,exception 对象

1. 配置欢迎界面

在WEB-INF下的web.xml里配置

<!--默认进入页面 依次往下找-->
    <welcome-file-list>
        <welcome-file>login.jsp</welcome-file>
        <welcome-file>index.jsp</welcome-file>
        <welcome-file>login.html</welcome-file>
    </welcome-file-list>

2. config 配置

config对象代表当前JSP配置信息,实质上是ServletConfig的一个实例,常用来获取Servlet的初始化参数。
用法: 用来获取web.xml中的配置参数
在WEB-INF下的web.xml里配置

<servlet>
        <servlet-name>initjsp</servlet-name>
        <jsp-file>/demo1/sum.jsp</jsp-file>
        <init-param>
            <param-name>initcount</param-name>
            <param-value>1000000</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>initjsp</servlet-name>
        <url-pattern>/demo1/sum.jsp</url-pattern>
    </servlet-mapping>

在项目下的demo1文件夹下sum.jsp里可以用config获取初始化参数:

String strInit = config.getInitParameter("initcount") ;
// strInit 取出为 1000000

3. exception 错误页面

  1. 为了防止页面出现错误,可以在页面里配置,当出现错误时,跳转到对应页面
    errorPage=".错误页面"
<%@ page contentType="text/html;charset=UTF-8" language="java" errorPage="../jsp/error.jsp" %>
  1. 错误页面可以不配置,但是需要使用exception对象,需要在page指令中设置,isErrorPage="true"
<%@ page contentType="text/html;charset=UTF-8" language="java" isErrorPage="true" %>
<html>
<head>
    <title>错误页面</title>
</head>
<body>
<!-- exception对象  默认exception不是隐式对象,除非配置当前页面isErrorPage="true" -->

<%=exception.getMessage()%>
<h1>对不起,服务器忙,请稍后再试!</h1>
</body>
</html>
  1. 但是单独给每个页面配置,太麻烦 ,可以在WEB-INF下的web.xml里统一配置
    <error-page>
        <error-code>500</error-code>
        <location>/jsp/error.jsp</location>
    </error-page>
    <error-page>
        <error-code>404</error-code>
        <location>/jsp/notfound.jsp</location>
    </error-page>

4. jsp:useBean ,和jsp:setProperty简化操作

之前,我们对于表单提交的数据,要new 出对象,然后将一个个属性放进去,这太过麻烦

 User user = new User();
 user.setUsername(request.getParamenter("username")

所以,
<jsp:useBean>:jsp中使用此标签有四个属性,id指定Bean的对象名class指定Bean的完成包名,说明了类型。type指定将引用该对象变量的类型。beanName通过java.beans.Beans的instantiate()方法指定Bean的名字

// 相当于实例化对象
<jsp:useBean id="user" class="com.wdzl.entity.User"></jsp:useBean>

jsp:setProperty , 对于赋值操作: 把request中名字为name的参数的值设置到名字为user的bean的userName属性中。


<jsp:setProperty name="user" property="userName" param="name"/>

还可以:统一赋值,自动给实体类对象所有的属性赋值:前提是页面表达名字和实体类属性一致

<jsp:setProperty property="*" name="user"/>

三. 作用域对象

1. pageContext,request

构造一个页面放入值,在不同范围内取出,看是否可以得到

1.1 包含,超链接跳转,与请求转发

set.jsp

<body>
    <%
        /*
        pageContext,当前页面有效,范围是当前页面,注意:使用指令包含时,
        被包含页面和包含页面使用的是同一个pageContext对象
        */
        //作用域不同的   在此页面放入值
        pageContext.setAttribute("key", "PageValue");  //当前页面有效
        request.setAttribute("key", "RequestValue");
        session.setAttribute("key", "SessionValue");
        application.setAttribute("key", "ApplicationValue");
    %>
    <h1>当前页面</h1>
	    <p>pageContext : <%=pageContext.getAttribute("key") %></p>
	    <p>request : <%=request.getAttribute("key") %></p>
	    <p>session : <%=session.getAttribute("key") %></p>
	    <p>application : <%=application.getAttribute("key") %></p>
	 <hr>

    <h1>指令包含</h1>
     <%@include file="include.jsp" %>
    <hr>

    <h1>动作包含</h1>
    <jsp:include page="include.jsp"></jsp:include>

    <h1>链接</h1>
    <a href="request.jsp">去请求页面</a>
</body>

include.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <p>pageContext:<%=pageContext.getAttribute("key") %></p>
    <p>request:<%=request.getAttribute("key") %></p>
    <p>session:<%=session.getAttribute("key") %></p>
    <p>application:<%=application.getAttribute("key") %></p>

request.jsp

<body>
    <p>pageContext:<%=pageContext.getAttribute("key") %></p>
    <p>request:<%=request.getAttribute("key") %></p>
    <p>session:<%=session.getAttribute("key") %></p>
    <p>application:<%=application.getAttribute("key") %></p>
</body>

结果:

set.jsp 点击链接:request.jsp
在这里插入图片描述 在这里插入图片描述

请求转发

<body>
    <%
        pageContext.setAttribute("key", "PageValue");  //当前页面有效
        request.setAttribute("key", "RequestValue");
        session.setAttribute("key", "SessionValue");
        application.setAttribute("key", "ApplicationValue");
    %>

    <h1>请求转发</h1>
    <%
        request.getRequestDispatcher("request.jsp").forward(request, response);
    %>
</body>

在这里插入图片描述

是否可以取到值 pageContext request
静态包含 可以 可以
动态包含 可以
同一次请求转发 可以
超链接跳转

说明了静态包含页面是直接插入进来的

2. session 与application

session application
同一次会话有效 全局变量在服务器端
无论怎样跳转,都有效;从登录–>退出期间全都有效 整个项目运行期间 都有效(切换/关闭浏览器 仍然有效)
关闭/切换浏览器后无效; 关闭服务后重启,在其他项目无效;
多个项目共享,重启后仍然有效:JNDI可以实现

3. 四种比较

pageContext request session appliation
JSP页面容器(page对象) 请求对象 会话对象 全局对象

以上范围对象,尽量使用最小的范围。因为 对象的范围越大,造成的性能损耗越大。

Object   getAttribute(String name) 根据属性名,获取属性值
Void    setAttribute(String name,object obj): 设置属性值(新增,修改)
	     setAttribute("a","c")如果a对象之前不存在,则新建对象a
						如果a对象已经存在,则将a的值该为b
Void   removeAttribute(String  name)  根据属性名,删除对象

4. pageContext.findAttribute()的穿透

Searches for the named attribute in page, request, session (if valid), and application scope(s) in order and returns the value associated or null.

依次在page,request,session(如果有效的话)和application Scope(范围)查找以name为名的Attribute,找到就返回对象,都找不到返回null。

源码

public Object findAttribute (String name)
  {
    if (mPage.containsKey (name)) {
      return mPage.get (name);
    }
    else if (mRequest.containsKey (name)) {
      return mRequest.get (name);
    }
    else if (mSession.containsKey (name)) {
      return mSession.get (name);
    }
    else if (mApp.containsKey (name)) {
      return mApp.get (name);
    }
    else {
      return null;
    }
  }

四.cookie

Cookie(客户端,不是内置对象,需要new):
Cookie 是服务端产生,再发送给客户端保存

相当于缓存: 客户端(A.MP3)–>服务端(A.MP3)
A.Mp3电影由客户端产生,发送给客户端,客户端下一次可以自己在手机观看
提高访问服务器端效率
可以放任何东西(音乐,密码,),但是安全性差

Cookie : name=value

	Javax.servlet.http.Cookie
	Public 		Cookie(String name,String value)
	String 		getName();获取name
	String 		getValue();获取value
	Void 		setMaxAge(int expiry):获取有效期(秒),文件失效期,为了安全
  1. 服务端准备Coolie
    response.addCookie(Cookie cookie)
  2. 页面跳转(转发,重定向)
  3. 客户端获取cookie
    Request.getCookies();
    必须获取全部cookie,不能获取一部分cookie
<body>
<%
//    服务端
    Cookie cookie1 = new Cookie("name", "zs");
    Cookie cookie2 = new Cookie("pwd", "abc");
//    准备Cookie
    response.addCookie(cookie1);
    response.addCookie(cookie2);
//    跳转
    response.sendRedirect("two.jsp");
%>
</body>
<body>
    <%
        Cookie[] cookies = request.getCookies();
        for (Cookie cookie : cookies) {
            out.print(cookie.getName()+" "+ cookie.getValue()+" "+cookie.getMaxAge()+"<br/>");
        }
    %>
</body>

在这里插入图片描述
4. 可以看出多了两个cookie:JSESSIONID,Idea-905113b0(这个应该是idea自带的)
5. 建议cookie 只保存 英文 ,数字,否则(可能)需要进行编码,解码
6. 我们可以通过浏览器看到cookie的path属性,代表着cookie的使用范围
在这里插入图片描述

int maxAge

该Cookie失效的时间,单位秒。
如果为正数,则该Cookie在maxAge秒之后失效。
如果为负数,该Cookie为临时Cookie,关闭浏览器即失效,浏览器也不会以任何形式保存该Cookie。表示仅当前浏览器内有效,并且各浏览器窗口间不共享,
如果为0,表示删除该Cookie。默认为–1

1. cookie修改,删除

Cookie并不提供修改、删除操作。如果要修改某个Cookie,只需要新建一个同名的Cookie,添加到response中覆盖原来的Cookie。

如果要删除某个Cookie,只需要新建一个同名的Cookie,并将maxAge设置为0,并添加到response中覆盖原来的Cookie。注意是0而不是负数。负数代表其他的意义。读者可以通过上例的程序进行验证,设置不同的属性。

注意:修改、删除Cookie时,新建的Cookie除value、maxAge之外的所有属性,例如name、path、domain等,都要与原Cookie完全一样。否则,浏览器将视为两个不同的Cookie不予覆盖,导致修改、删除失败。

4.1 用cookie记住用户名密码功能

  1. 登录界面
<head>
    <title>登录</title>
</head>
<body>
    <%
        String username = "";
        String password = "";
        String checked = "";
        Cookie[] cookies = request.getCookies();
        for (Cookie cookie : cookies) {
            if (cookie.getName().equals("username")){
                username = cookie.getValue();
            }else if (cookie.getName().equals("password")){
                password = cookie.getValue();
            }
        }
        if (!username.equals("") && !password.equals("")){
            checked = "checked";
        }
    %>
    <form action="doregistered.jsp" method="post">
        姓名<input name="username" type="text" value=<%=username%>><br>
        密码<input name="password" type="password" value=<%=password%>><br>
        记住用户名及密码<input name="remember" type="checkbox" value="1" <%=checked%> ><br>
        <input type="submit" value="提交">
    </form>
    <%--显示错误--%>
    <h3 style="color: red"><%=request.getAttribute("error")==null ? "" : request.getAttribute("error")%></h3>
</body>
  1. 判断是否登录
<head>
    <title>判断</title>
</head>
<body>
    <%
        request.setCharacterEncoding("UTF-8");
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String[] remember = request.getParameterValues("remember");
        User user = new User(username, password);
        UserService userService = new UserService();
        boolean login = userService.login(user); // 数据库是存在这个用户
        if (login){
            Cookie username1 = new Cookie("username", username);
            Cookie password1 = new Cookie("password", password);
//            需要记住
            if (remember != null){
                username1.setMaxAge(24*60*60);
                password1.setMaxAge(24*60*60);
            }else {  //不需要记住,时间为零
                username1.setMaxAge(0);
                password1.setMaxAge(0);
            }
            response.addCookie(username1);
            response.addCookie(password1);
    %>
            <h1>登录成功,5s后跳转首页,<a href="hello.jsp">点击此处直接跳转</a></h1>
    <%
            session.setAttribute("loginUser",user);  // 把用户信息放入session属性里
            request.setAttribute("error","");
            response.setHeader("refresh","5;hello.jsp");
        }else {
            /*没有用户,返回,并把错误信息带回*/
            request.setAttribute("error","密码或用户名错误");
            request.getRequestDispatcher("registered.jsp").forward(request,response);
        }
    %>
</body>
  1. 欢迎页面
<body>
<%
    // 判断登录状态
    User loginUser = (User)session.getAttribute("loginUser");
    if (loginUser == null){
%>
        <%--未登录状态--%>
        <div>您还没登录,请先<a href="login.jsp">登录</a></div>
<%
    }else {
        /*登录状态*/
%>
        <div>欢迎您:<%=loginUser.getUsername()%>
            <a href="logout.jsp" onclick="return confirm('您确定要注销吗')">注销</a>
        </div>
<%
    }
%>
</body>
  1. 注销
<body>
    <%
        session.removeAttribute("loginUser");  // 1. 可以移除对应session的属性 2. session.invalidate(); 销毁session
        response.sendRedirect("hello.jsp");
    %>
</body>

五. session

1,浏览网站:开始–关闭
1. 购物: 浏览,付款,退出
2. 电子邮件: 浏览,写邮件,退出
开始-----结束

  1. 客户端第一次请求服务端时(jessionid-sessionid,每一次都匹配,第一次没有匹配成功),服务端会产生一个session对象(用于保存该客户的信息)
  2. 并且每个session 对象都会有唯一的 sessionID(用于区分其他的session);
  3. 服务器 在会产生一个cookie,并且该cookie 的 name = JSESSSIONID,value =服务端sessionID的值
  4. 然后,服务端会在 响应客户端的同时 将该cookie发送给客户端,至此,客户端就有了一个cookie(JSESSIONID),因此,客户端的cookie就可以和服务端的session一一对应(JSESSIONID--sessionID
  5. 客户端第二次/n 次请求服务端时:服务端会先用客户端cookie中的JSESSIONID 去和服务端的session 中匹配sessionID
在这里插入图片描述 在这里插入图片描述

同一个浏览器,之间的session是共享的
谷歌里登录京东,在谷歌重新打开一个标签到京东,京东直接登录;
再打开一个new谷歌浏览器,依然有效,
但是换一个浏览器,就不行,需要重新登录

session

  1. 存储在服务器端
  2. 是在同一个用户(客户)请求时共享
  3. 实现机制:第一次客户请求时,产生一个sesssionid 并复制给jessionid 然后发送给客户端,最终通过sesionid—jessioid
String 		getid() :	获取sessionid
Boolean 	isNew();	判断是否是新用户(第一次访问)
Void 		invalidate():  使session失效(退出登录。注销)

Void      setAttribute()
Object    GetAttribute()

Void setMaxInactiveInterval():设置最大有效  非活动间隔时间  (默认1800)
Int getMaxInactiveInterval() : 获取最大有效  非活动间隔时间 

long getLastAccessedTime()    上次访问时间
long getCreationTime()         创建时间

cookie

  1. 不是内置对象,必须要new
  2. 但是,服务端会自动生成一个(服务端自动new 一个cookie)Name = JSESIONID 的cookie 并返回给客户端, 服务端只会new 这一个cookie

5.1 session,cookie区别

session cookie
保存的位置 服务端 客户端
安全性 较安全 较不安全
保存内容的形式 Object String
session实现,基于cookie

我才知道原来session就是基于cookie!
Cookie机制详解

5.2 session失效

  1. 调用session的invalidate()方法
  2. 超时(最大非活动间隔时间)
    关闭浏览器(本质是超时)你可以记下你的sessionID那串字符串,关闭浏览器,打开,把sessionID自己替换,你就可以恢复刚才的会话了

5.3 url重写

当客户的浏览器禁止了cookie,这时候,服务器仍会将sessionId以cookie的方式发送给浏览器,但是,浏览器不再保存这个cookie(即sessionId)了。服务器会认为客户第一次登录,无法保存登录状态
例如:<a href="session.jsp">测试URL重写</a>
每一次跳转后,SessionID都在改变
如何重写

response.encodeRedirectURL(java.lang.String url)   用于对sendRedirect方法后的url地址进行重写。重定向地址
response.encodeURL(java.lang.String url)           用于对表单action和超链接的url地址进行重写

<a href="<%=response.encodeURL("session.jsp")%>">测试URL重写</a>

所以,当浏览器禁用了cookie后,就可以用URL重写这种解决方案解决Session数据共享问题。而且response. encodeRedirectURL(java.lang.String url) 和response. encodeURL(java.lang.String url)是两个非常智能的方法,当检测到浏览器没有禁用cookie时,那么就不进行URL重写了。

  1. URL地址重写的原理是:将该用户Session的id信息重写到URL地址中。服务器能够解析重写后的URL获取Session的id。这样即使客户端不支持Cookie,也可以使用Session来记录用户状态。HttpServletResponse类提供了encodeURL(Stringurl)实现URL地址重写
  2. 即在文件名的后面,在URL参数的前面添加了字符串“;jsessionid = XXX” 。其 中XXX为Session的id。增添的jsessionid字符串既不会影响请求的文件名,也不会影响提交的地址栏参数。用户单击这个链接的时候会把Session的id通过URL提交到服务器上,服务器通过解析URL地址获得Session的id。

六. 会话跟踪

  1. 有状态的协议:TCP/IP,自从客户端与服务器连接上以后,这个连接会一直保持畅通,持续保持连接状态。
  2. 无状态的协议:HTTP,这是一种请求/响应模式的协议,当浏览器发起请求那一刻,与服务器建立了连接,当服务器给客户端浏览器做出响应后,连接就中断了。
    http是一个无状态的协议,服务器不会自动保存每次请求的的状态信息
    实现技术:1. session, 2. 隐藏域(<input type="text" name="…" value="…">),3. 重写URL, 4. cookie
发布了22 篇原创文章 · 获赞 2 · 访问量 759

猜你喜欢

转载自blog.csdn.net/qq_43542795/article/details/105650013