JSP内置对象的那些事

0x01 什么是内置对象?

JSP(Java Server Pages/Java服务器页面)中,所谓的内置主要指对象不用再由用户自己进行对象的实例化操作(new),从而可以直接进行使用。

No.内置对象类型描述
1pageContextjavax.servlet.jsp.PageContextJSP的页面容器
2requestjavax.servlet.http.HttpServletRequest得到用户的请求信息
3responsejavax.servlet.http.HttpServletResponse服务器向客户端的回应信息
4sessionjavax.servlet.http.HttpSession用来保存每一个用户的信息
5applicationjavax.servlet.ServletContext表示所有用户的共享信息
6configjavax.servlet.ServletConfig服务器配置,可以取得初始化参数
7outjavax.servlet.jsp.JspWrite页面输出
8pagejava.lang.Object表示从该页面中表示出来的一个Servlet实例
9exceptionjava.lang.Throwable表示JSP页面所发生的异常,在错误页中才起作用

(注意:内置对象一定要记清楚其对应的类型以方便进行文档的查阅)

J2EE5.0手册 密码:7aqn

0x02 四种属性的范围

  • 在JSP中提供了四种属性的保存范围,所谓的属性保存范围,指的就是一个设置的对象可以在多少个页面保存并可以继续使用
  • 四种属性范围:

    • pageContext:只是在一个页面中保存属性,跳转之后无效;
    • request:只在一次请求中保存,服务器跳转后依然有效;
    • session:在一次会话范围中,无论何种跳转都可以使用,但是新开浏览器无法使用;
    • application:在整个服务器上保存,所有用户都可以使用;
    • 还不太理解?OK,一张图让你明白

    四种属性范围

    属性操作方法:

    No.方法类型描述
    1public void setAttribute(String name,Object o)普通方法设置属性的名称及内容
    2public Object getAttribute(String name)普通方法根据属性名称取得属性
    3public void removeAttribute(String name)普通方法删除指定的属性
  • page属性范围

    • page属性范围(使用pageContext表示,但是一般都习惯于将这种范围称为page范围),表示将一个属性设置在本页上,跳转之后无法取得。
      page范围

    • Case

    <body>
    <%
        // 设置属性
        pageContext.setAttribute("Name","Charles");
        pageContext.setAttribute("Birthday",new Date());
    %>
    <%
        String username = (String)pageContext.getAttribute("Name");
        Date Birthday = (Date)pageContext.getAttribute("Birthday");
    %>
    <h2>姓名:<%=username %></h2>
    <h2>生日:<%=Birthday %></h2>

    四种属性demo

    • Case_forward
    <body>
    <%
    // 设置属性
    pageContext.setAttribute("Name","Charles");
    pageContext.setAttribute("Birthday",new Date());
    %>
    <jsp:forward page="pageforward.jsp"></jsp:forward>
    </body>
    <body>
    <%
        String username = (String)pageContext.getAttribute("Name");
        Date Birthday = (Date)pageContext.getAttribute("Birthday");
    %>
    <h2>姓名:<%=username %></h2>
    <h2>生日:<%=Birthday %></h2>
    </body>

    forward

  • 深入研究page属性范围

    • 上面研究过的page属性范围中使用的是pageContext进行属性设置的,但是从javax.servlet.jsp.PageContext类中可以发现,有以下的一种设置属性的方法
      • public void setAttribute(String name,Object value,int scope)
      • 在PageContext类中存在四个表示属性范围的常量,可以通过这些常量指定scope的内容:
        • public static final int PAGE_SCOPE
        • public static final int REQUEST_SCOPE
        • public static final int SESSION_SCOPE
        • public static final int APPLICATION_SCOPE
    • Case_pageContext_Scope
    <body>
    <%
        // 将pageContext属性范围设为request
        pageContext.setAttribute("Name","Charles",PageContext.REQUEST_SCOPE);
        pageContext.setAttribute("Address", "中国光谷",PageContext.REQUEST_SCOPE);
    %>
    <jsp:forward page="pagescopeRequest.jsp"></jsp:forward>
    </body>
    <body>
    <%
        /*
        获取指定属性的值(如果设定属性的时候,指定有属性范围,则在获取时,
        也需要指定获取的范围,获取的属性范围与设置的属性范围要一致)
        */
        String name = (String)pageContext.getAttribute("Name",PageContext.REQUEST_SCOPE);
        String address = (String)pageContext.getAttribute("Address",PageContext.REQUEST_SCOPE);
    %>
    <h2>姓名:<%=name %></h2>
    <h2>地址:<%=address %></h2>
    </body>

    pageContextScope

  • request属性范围

    • 如果希望要在服务器跳转之后属性可以继续保存下来,则可以使用request属性范围操作,request属性范围表示的是在服务器跳转之后,所有设置的内容依然会被保留

    request属性范围

    • Case_request_forward
    <body>
    <%
        // 设置属性
        request.setAttribute("Name","Charles");
        request.setAttribute("Birthday",new Date());
    %>
    <jsp:forward page="requestforward.jsp"></jsp:forward>
    </body>
    <body>
    <%
        String username = (String)request.getAttribute("Name");
        Date Birthday = (Date)request.getAttribute("Birthday");
    %>
    <h2>姓名:<%=username %></h2>
    <h2>生日:<%=Birthday %></h2>
    </body>

    requestforward

    上述案例中,页面跳转之后,request设置的属性可以取得了,如果一直有服务器端跳转,则可以一直传递过去,但是如果使用超链接跳转,首先地址栏会发生改变(地址栏发生改变的跳转,统称为客户度跳转,客户度跳转是无法传递request属性的),然后属性会变成null。

    • 关于request属性范围的理解
      • request表示的是客户度的请求,正常情况下,一次请求(request)服务器只会给与一次回应(response),那么这个时候如果是服务器端跳转,请求的地址栏没有改变,所以也就相当于回应了一次,而如果地址栏改变了,就相当于是发出了第二次请求,则第一次请求的内容肯定就已经消失了,所以无法取得。
      • 这里用一张图再说明一下

    关于request属性范围的理解

  • session属性范围

    • 如果希望一个属性设置之后,可以在任何一个与设置页面相关的页面中取得的话,则就可以使用session属性范围,使用session设置属性之后,不管是客户端跳转还是服务器端跳转,只要属性设置了就都可以取得

    Session属性范围

    • Case_session_forward
    <body>
    <%
        // 设置属性
        session.setAttribute("Name","Charles");
        session.setAttribute("Birthday",new Date());
    %>
    <jsp:forward page="sessionforward.jsp"></jsp:forward>
    </body>
    <body>
    <%
        String username = (String)session.getAttribute("Name");
        Date Birthday = (Date)session.getAttribute("Birthday");
    %>
    <h2>姓名:<%=username %></h2>
    <h2>生日:<%=Birthday %></h2>
    </body>

    sessionforward

    此时的客户端跳转/服务端跳转都可以取得,但如果此时,再打开一个新的浏览器的话,则就无法取得前面设置的session了,因为每一个session只保存在当前的浏览器之中。对于服务器而言,每一个连接到它的客户端都是一个session。

  • application属性范围

    • 如果希望设置一个属性,可以让所有的用户(每一个session)都能看得见的话,则可以将属性范围设置成application,这样属性就保存在了服务器之上

    application属性范围

    • Case_Applicatioin_forward
    <body>
    <%
        // 设置属性
        application.setAttribute("Name","Charles");
        application.setAttribute("Birthday",new Date());
    %>
    <jsp:forward page="applicationforward.jsp"></jsp:forward>
    </body>
    <body>
    <%
        String username = (String)application.getAttribute("Name");
        Date Birthday = (Date)application.getAttribute("Birthday");
    %>
    <h2>姓名:<%=username %></h2>
    <h2>生日:<%=Birthday %></h2>
    </body>

    applicationforward

    所有的application属性直接保存在服务器上,所有的用户(每一个session)都可以直接访问。但是如果服务器重新启动了,则就无法获取了,因为关闭后属性消失,若想再次取得,则需要重新设置属性。

  • 属性设置原则

    • application属性范围的内容都是保存在服务器上,如果同时要设置多个application,服务器的性能肯定会有所降低,而且以上四种属性范围的内容都是保存在服务器上的,这时就给出了一个原则:

      • 能使用page范围的就不要使用request;
      • 能使用request的就不要使用session;
      • 能使用session的就不要使用application;

      因为属性保存的范围越小,对于服务器的压力就越低!

  • 注意:

    • 四种属性范围是整个WEB的核心操作
    • 属性范围规定了属性的有效范围
    • PageContext对象可以直接操作四种属性范围

0x03 request内置对象

  • request内置对象是JSP中使用最多的一个对象,主要作用是用来接收客户端发送过来的请求信息,request是javax.servlet.http.HttpServletRequest接口的实例化对象,表示此对象主要是应用在HTTP协议上。
  • 对应接口:public interface HttpServletRequest extends ServletRequest
No.方法类型描述
1public String getParameter(String name)普通方法接收客户端发来的请求参数内容
2public String[] getParameterValues(String name)普通方法取得客客户端发来的一组请求参数内容
3public Enumeration getParameterNames()普通方法取得全部请求参数的名称
4public String getRemoteAddr()普通方法得到客户端的IP地址
5void setCharacterEncoding(String env) throws UnsupportedEncodingException普通方法设置统一的请求编码
6public boolean isUserInRole(String role)普通方法进行用户身份的验证
7public HttpSession getSession()普通方法取得当前的session对象
8public StringBuffer getRequestURL()普通方法返回正在请求的路径
9public Enumeration getHeaderNames()普通方法取得全部请求的头信息的名称
10public String getHeader(String name)普通方法根据名称取得头信息的内容
11public String getMethod()普通方法取得用户的提交方式
12public String getServletPath()普通方法取得访问的路径
13public String getContextPath()普通方法取得上下文资源路径
  • 乱码解决

    • Code
    <form action="request02.jsp" method="post">
        请输入内容<input type="text" name="context"/>
        <input type="submit" value="Submit">
    </form>
    </head>
    <body>
    <%
        String context = request.getParameter("context");
    %>
    Context:<%=context %>
    </body>

requestCode

requestCode2

此时输入的英文字符,浏览器正常解释,但如果是**中文字符**呢?

requestCode03

requestCode04

就出现了所谓的“网页乱码”,由于现在的request属于接收客户端的参数,所以必然有其默认的语言编码(request获取请求的默认编码是ISO-8859-1),之所以会这样,主要是由于浏览器的默认编码是UTF-8,而中文编码是GBK,这两种编码是不一样的,打个比喻吧:你只会说中文,老外只会说英语,他说的你听不懂,你说的他也听不懂,就认为对方是在“鸟叫”,浏览器也是一样的,所以就造成了网页的乱码现象。

想要解决这种乱码问题,就必须使用request提供的统一设置编码的方法。

void setCharacterEncoding(String env) throws UnsupportedEncodingException
<body>
<%
    request.setCharacterEncoding("UTF-8");  // 设置的是统一编码(默认为ISO-8859-1)
    String context = request.getParameter("context");
%>
Context:<%=context %>
</body>

requestCode05

此时,网页中文乱码问题已经解决了。
  • 接收参数

    • Case Code
    <body>
    <form action="request04.jsp" method="post">
        请输入姓名:<input type="text" name="name"/><br/>
        请输入爱好:<input type="checkbox" name="hobby" value="电子竞技">电子竞技
                    <input type="checkbox" name="hobby" value="游泳">游泳
                    <input type="checkbox" name="hobby" value="爬山">爬山
                    <input type="checkbox" name="hobby" value="旅游">旅游
        <br/><input type="hidden" name="id" value="3">  <!-- 表单隐藏域 id为编号 -->
        <input type="submit" value="Submit">
        <input type="reset" value="Reset">
    </form>
    </body>
    <body>
    <%
        request.setCharacterEncoding("UTF-8");  // 设置的是统一编码(默认为ISO-8859-1)
        String name = request.getParameter("name"); // 获取姓名
        String[] hobbys = request.getParameterValues("hobby");  // 获取爱好,用数组接收
        String id = request.getParameter("id"); // 获取编号
    %>
    <h3>
        编号:<%=id %><br/>
        姓名:<%=name %><br/>
            爱好:
        <%
        /*
            表单中爱好传递的是一个复选框(checkbox),所谓的复选框实际上是一个数组,
            既然是一个数组,则肯定要同时接受一组数据,所以使用for循环进行遍历输出
        */
            if(hobbys!=null){   // 判断爱好是否为空,防止抛出空指针异常
                for(int i=0;i<hobbys.length;i++){   // 循环遍历数组,输出数组内容
                    out.write(hobbys[i]+" ");   // 每循环一个后,输出一个空格符" ",以隔开属性内容
                }
            }else{  // 如果hobbys数组为空,提示“无爱好”
                out.write("无爱好");
            }
        %>
    </h3>
    </body>

    requestCode06

    requestCode07

    姓名,爱好为空情况下

    requestCode08

    requestCode09

  • URL地址重写

    • 在WEB的开发中,所有的参数不一定一定要由表单传递过来,也可以使用地址重写的方式进行传递,地址重写的格式如下:

      • 动态页面地址:?参数名称1=参数内容1&参数名称2=参数2&… (注意:多个参数之间用&进行分隔)

      例:http://localhost/login.jsp?count=china&city=武汉

      • Case Code:
      <body>
      <%
          request.setCharacterEncoding("UTF-8");  // 设置的是统一编码(默认为ISO-8859-1)
          String count = request.getParameter("count");
          String city = request.getParameter("city");
      %>
      Count:<%=count %><br/>
      City:<%=city %>
      </body>

      URL重写

    • POST、GET两种提交方式的区别?

      • POST提交:提交后的地址栏不会附加目标地址的其他内容,是只能用在表单上的一种提交形式;
      • GET提交:提交后的地址栏是会改变的,而且会使用地址重写的方式完成。如果所有的内容都要显示,则传递时,肯定受到地址栏长度的限制;
      <body>
      <form action="request02.jsp" method="get">
          请输入内容<input type="text" name="context"/>
          <input type="submit" value="Submit">
      </form>
      </body>

      getSubmit

      getSubmit02

  • request.getParameterNames获取全部属性名称及内容

    • Case Code
    <body>
    <form action="request07.jsp" method="post">
        姓名: <input type="text" name="uname"><br>
        性别: <input type="radio" name="sex" value="男" CHECKED>男
                <input type="radio" name="sex" value="女">女<br>
        城市: <select name="city">
                    <option value="北京">北京</option>
                    <option value="天津">天津</option>
                    <option value="洛阳">洛阳</option>
                </select><br>
        兴趣: <input type="checkbox" name="**hobby" value="唱歌">唱歌
                <input type="checkbox" name="**hobby" value="跳舞">跳舞
                <input type="checkbox" name="**hobby" value="游泳">游泳
                <input type="checkbox" name="**hobby" value="看书">看书
                <input type="checkbox" name="**hobby" value="旅游">旅游<br>
        自我介绍:<textarea cols="30" rows="3" name="note"></textarea><br>
        <input type="hidden" name="uid" value="1">
        <input type="submit" value="提交">
        <input type="reset" value="重置">
    </form>
    </body>
    <body>
    <%
        request.setCharacterEncoding("utf-8") ;// 设置的是统一编码
        Enumeration<String> enu = request.getParameterNames() ;
    %>
    <table border="1">
        <tr>
            <td>参数名称</td>
            <td>参数内容</td>
        </tr>
    <%
        while(enu.hasMoreElements()){
            String paramName = (String) enu.nextElement() ;
    %>
            <tr>
                <td>
                <%
                    if(paramName.startsWith("**")){ // 判断参数名称是否以"**"开头
                        out.write(paramName.toString().substring(2, paramName.length()));   // 截取从2开始到字符串的最大长度(去掉"**"")
                    }else{  // 不是则直接输出参数名称
                        out.write(paramName);
                    }
                %>
                </td>
                <td>
                <%
                    if(paramName.startsWith("**")){     // 是以**开头
                        String paramValue[] = request.getParameterValues(paramName) ;
                        for(int x=0;x<paramValue.length;x++){
                            out.write(paramValue[x].toString()+" ");    // 遍历输出paramValues内容,内容之间用" "隔开
                        }
                    } else {    // 不是则直接输出
                        String paramValue = request.getParameter(paramName) ;
                        out.write(paramValue);
                    }
                %>
                </td>
            </tr>
    <%
        }
    %>
    </table>
    </body>

    requestGetParameterNames

    requestGetparameterNames02

  • 显示全部的头信息

    • JAVA的WEB开发使用的是HTTP协议,主要的操作就是基于请求和响应,但是在请求和响应的同时也会包含一些其他的信息(例如:客户端的IP、cookie、语言等),那么这些信息就称为头信息。
    • 要想取得头信息的名称可以直接通过request内置对象的getHeaderNames(),而要想取出每一个头信息的内容,则需要使用getHeader()方法。
    • Case Code
    <body>
    <form action="request08.jsp" method="post">
        姓名: <input type="text" name="uname"><br>
        性别: <input type="radio" name="sex" value="男" CHECKED>男
                <input type="radio" name="sex" value="女">女<br>
        城市: <select name="city">
                    <option value="北京">北京</option>
                    <option value="天津">天津</option>
                    <option value="洛阳">洛阳</option>
                </select><br>
        兴趣: <input type="checkbox" name="**hobby" value="唱歌">唱歌
                <input type="checkbox" name="**hobby" value="跳舞">跳舞
                <input type="checkbox" name="**hobby" value="游泳">游泳
                <input type="checkbox" name="**hobby" value="看书">看书
                <input type="checkbox" name="**hobby" value="旅游">旅游<br>
        自我介绍:<textarea cols="30" rows="3" name="note"></textarea><br>
        <input type="hidden" name="uid" value="1">
        <input type="submit" value="提交">
        <input type="reset" value="重置">
    </form>
    </body>
    <body>
    <%
        Enumeration<String> enu = request.getHeaderNames(); // 取得全部头信息
        while(enu.hasMoreElements()){
            String headerName = (String) enu.nextElement();
            String headerValue = request.getHeader(headerName);
    %>
        <h5><%=headerName%>===><%=headerValue%></h5>
    <%
        }
    %>
    </body>

    请求头信息01

    请求头信息02

    • 其他重要方法
    <body>
    <%
        String method = request.getMethod();    // 获取请求方式
        String ip = request.getRemoteAddr();    // 获取请求的IP地址
        String path = request.getServletPath(); // 获取请求路径
        String contextPath = request.getContextPath();  // 获取上下文名称
    %>
    <h3>
        请求方式:<%=method %><br/>
        请求IP:<%=ip %><br/>
        请求路径:<%=path %><br/>
        上下文名称:<%=contextPath %>
    </h3>
    </body>

    请求头信息03

0x04 repsonse对象

  • response对象的主要作用是用于对客户端的请求进行回应,将WEB服务器处理后的结果发回给客户端。response对象属于javax.servlet.http.HttpServletResponse接口的实例,HttpServletResponse接口的定义如下:
    • public interface httpServletResponse extends ServletResponse
  • response对象的常用方法
No.方法类型描述
1public void addCookie(Cookie cookie)普通方法向客户端增加Cookie
2publlc void setHeader(String name,String value)普通方法设置回应的头信息
3public void sendRedirect(String location) throws IOException普通方法页面跳转
  • 设置头信息
    • 所有的头信息都是随着请求(request)和回应(response)自动发送到服务器端(客户端);
    • Cookie定义的常用方法
No.方法类型描述
1public Cookie(String name,String value)构造方法实例化Cookie对象,同时设置名字和内容
2public String getName()普通方法取得Cookie的名字
3public String getValue()取得Cookie的内容
4public void setMaxAge(int expiry)普通方法设置Cookie的保存时间,以秒为单位
  • Case 页面定时刷新的实现

    <body>
    <%
        // 定义全局变量,用来存储刷新次数
        int count = 1;
    %>
    <%
        response.setHeader("refresh","2");  // 页面每2秒一刷新
    %>
    <h3>已经访问了<%=count++%>次!</h3>
    </body>

    ResponseRefresh

    • Case 页面跳转的实现
    <body>
    <%
        response.sendRedirect("refresh.html");  // 跳转到refresh.html页面
    %>
    </body>
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>跳转成功</title>
    </head>
    <body>
    <h3>跳转成功!</h3>
    </body>
    </html>

    Refresh

    • 与response.sendRedirect()两种跳转语句的区别

      • 跳转:
        • 服务器端跳转,跳转之后地址栏不会改变,可以传递request的属性;
        • 属于无条件的跳转,执行到之后立刻跳转。跳转之前的语句会执行,跳转之后的语句不会执行;
          -response.sendRedirect()跳转:
        • 客户端跳转,跳转之后地址栏会改变,不可以传递request属性;
        • 是在所有的语句都执行完之后才完成的跳转操作;
    • 操作Cookie

      • Cookie实际上是一小段的文本信息。客户端请求服务器,如果服务器需要记录该用户状态,就使用response向客户端浏览器颁发一个Cookie。客户端浏览器会把Cookie保存起来。当浏览器再请求该网站时,浏览器把请求的网址连同该Cookie一同提交给服务器。服务器检查该Cookie,以此来辨认用户状态。但是由于Cookie是服务器端保存在客户端的信息,所以其安全性也是很差的。
      • 在JSP中专门提供了javax.servlet.http.Cookie的操作类。
      • Case 使用Cookie和查看Cookie
    <body>
    <%
        request.setCharacterEncoding("utf-8");
        Cookie cookieName = new Cookie("Name","Charles-Yeoung");
        Cookie cookieValue = new Cookie("Job","JavaStudent");
        response.addCookie(cookieName);
        response.addCookie(cookieValue);
    %>
    </body>
    <body>
    <%
        Cookie cookie[] = request.getCookies(); // 取得客户端的全部Cookie
        // 遍历Cookie
        for(int i=0;i<cookie.length;i++){
    %>
    <h3><%=cookie[i].getName()%>====><%=cookie[i].getValue()%></h3>
    <%
        }
    %>
    </body>

    CooieUse

    现在为止的Cookie由于没有设置保存的时间,所以默认是在一个浏览器上保存的,如果当前浏览器关闭了,则Cookie消失,那么想要真正的保存在客户端上一段时间,则必须使用Cookie类中提供的setMaxAge()方法完成。

    <body>
    <%
        request.setCharacterEncoding("utf-8");
        Cookie cookieName = new Cookie("Name","Charles-Yeoung");
        Cookie cookieValue = new Cookie("Job","JavaStudent");
        cookieName.setMaxAge(120);  // 设置Cookie过期时间(单位为秒);
        cookieValue.setMaxAge(120);
        response.addCookie(cookieName);
        response.addCookie(cookieValue);
    %>
    </body>

0x05 session对象

  • 在开发中session对象最主要的用处就是完成用户的登录(login)、注销(logout)等常见功能的,每一个session对象都表示不同的访问用户,session对象是javax.servlet.http.HttpSession接口的实例化对象,所以session只能应用在HTTP协议中。
  • HttpSession接口的主要方法
No.方法类型描述
1.public String getId()普通方法取得Session ID
2.public long getCreationTime()普通方法取得session的创建时间
3.public long getLastAccessedTime()普通方法取得session的最后一次操作时间
4.public boolean isNew()普通方法判断是否是新的Sessioin(新用户)
5.public void invalidate()普通方法让session失效
6.public Enumeration getAttributeNames()普通方法得到全部属性的名称
  • SESSION ID

    • 对于每一个用户而言,实际上都表示一个个不同的SESSION,那么服务器是靠什么来区分这些用户呢?靠的就是sessionID,即:每一个通过浏览器连接到服务器上的用户都会由服务器自动的分配一个唯一的不会重复的编号(session id)。
    <body>
    <%
        String id = session.getId();    // 获取session id
    %>
    <h3>Session ID:<%=id %></h3>
    <h3>Session ID长度:<%=id.length() %></h3>
    </body>

    session01

    如果服务器关闭了,则Session ID肯定需要重新分配。原本的session ID根本就不会保留,服务器关闭之后session id也就没了。

  • 登录及注销(重要)

    • session在所有的项目开发中用的最多的地方就是登录验证及注销操作功能。
    • 程序列表
No.表达式描述
1login.jsp完成登录表单的显示,同时向页面本身进行数据提交,以完成登录的验证,如果登录成功,则保存属性;如果登录失败,则显示登录失败的信息。
2welcome.jsp要求在用户登陆完成之后才可以显示登陆成功的信息,如果没有登录,则要给出未登录的提示,同时给出一个登录的连接地址。
3logout.jsp此功能完成登陆的注销,注销之后,页面要跳转回login.jsp,等待用户再次登陆。
  • login.jsp code

    <body>
    <form action="login.jsp" method="post">
    <table>
        <tr>
            <td>用户名:</td>
            <td><input type="text" name="uname" /></td>
        </tr>
        <tr>
            <td>密&nbsp;&nbsp;&nbsp;码:</td>
            <td><input type="password" name="upassword" /></td>
        </tr>
        <tr>
            <td align="center" colspan="2">
                <input type="submit"  value="登陆"/>&nbsp;&nbsp;
                <input type="reset" value="重置" />
            </td>
        </tr>
    </table>
    </form>
    
    <!-- 验证用户名密码 -->
    <%
        String uname = request.getParameter("uname");   // 用户名
        String upasw = request.getParameter("upassword");   // 密码
        if(!(uname==null||upasw==null||"".equals(uname)||"".equals(upasw))){
            if("admin".equals(uname)&&"password".equals(upasw)){
                // 如果登录成功,则设置session属性范围
                session.setAttribute("uname", uname);
                response.setHeader("refresh", "2;URL=welcome.jsp");
    %>
                <h3>用户登陆成功,两秒后调整至欢迎页...</h3>
                <h3>如果跳转不成功,请点击<a href="welcome.jsp">这里!!!</a></h3>
    <%
            }else{
    %>
                <h3>用户名或密码错误!!!</h3>
    <%
            }
        }
    %>
    </body>
  • welcome.jsp code

    <body>
    <%
        // 如果已经设置过了session属性,则肯定不为空
        if(session.getAttribute("uname")!=null){
    %>
            <h3>欢迎<font color="red"><%=session.getAttribute("uname") %></font>光临本系统!!!</h3>
            <h3><a href="logout.jsp">注销登录</a></h3>
    <%
        }else{  // 如果session为空,则表示用户没有登录,应先登录
    %>
            <h3>请先进行系统的<a href="sessionlogin.jsp">登录</a></h3>
    <%
        }
    %>
    </body>
  • logout.jsp code

    <body>
    <%
        response.setHeader("refresh", "3;URL=login.jsp");
        session.invalidate();   // 注销,表示所有的session失效
    %>
    <h3>您已成功退出本系统,两秒后跳转回首页!</h3>
    <h3>如果没有跳转,请点击<a href="login.jsp">这里</a>!!</h3>
    </body>
  • 登录 –>登录成功 –>注销操作

session-login

session-login-true

session-login-true-02

session-logout-true

  • 登录失败操作

LoginFailure

  • 非法登录操作

非法登录操作

  • 判断新用户
<body>
<%
    if(session.isNew()){
%>
        <h3>欢迎新用户</h3>
<%
    }else{
%>
        <h3>您是老用户了</h3>
<%
    }
%>
</body>

判断是否为新用户

  • 获取session的操作时间
<body>
<%
    long start = session.getCreationTime(); // 获取session的创建时间
    long end = session.getLastAccessedTime();   // 获取session最后一次的操作时间
    long time = (end - start)/1000;         // 获取当前session的操作时间(秒)
%>
<h3>您已经停留了<%=time%>秒!</h3>
</body>

GetTime

0x06 application对象

  • application对象是javax.servlet.ServletContext接口的实例化对象,从单词上翻译表示的是整个Servlet的上下文,ServletContext代表了整个容器的操作。
  • 常用方法

    No.方法类型描述
    1String getRealPath(String path)普通方法得到虚拟目录对应的绝对路径
    2public Enumeration getAttributeNames()普通方法得到所有属性的名称
    3public String getContextPath()普通方法取得当前的虚拟路径名称
  • 取得绝对路径(重点)(取得一个虚拟目录对应的绝对路径)

<body>
<%
    // 获取路径
    String path = application.getRealPath("/");
%>
<h3>真实路径:<%=path %></h3>
</body>

取得虚拟目录的绝对路径

application的操作本身是ServletContext接口的实例,但是在JSP之中,有一个方法的功能可以完全与之对应:getServletContext()方法。

<body>
<%
    // 获取物理路径,this.表示表示当前容器
    String path = this.getServletContext().getRealPath("/");
%>
<h3>真实路径:<%=path %></h3>
</body>

getServletContext

  • 文件读写
<body>
<form action="input_content.jsp" method="post">
    <table>
        <tr>
            <td>输入文件名称:</td>
            <td><input type="text" name="filename"/></td>
        </tr>
        <tr>
            <td>输入文件内容:</td>
            <td><textarea name="filecontext" cols="30" rows="3"></textarea></td>
        </tr>
        <tr>
            <td align="center" colspan="2">
                <input type="submit" value="保存">&nbsp;&nbsp;
                <input type="reset" value="重置">
            </td>
        </tr>
    </table>
</form>
</body>
<body>
<%
    /*
        获取表单中的文件名(filename)和内容filecontext,写入到文件中
    */
    request.setCharacterEncoding("utf-8");  // 解决中文乱码问题
    String name = request.getParameter("filename");
    String filecontent = request.getParameter("filecontext");
    // 操作文件的绝对路径
    String filename = this.getServletContext().getRealPath("/")+"note" + File.separator + name;
    File file = new File(filename); // 实例化File对象
    if(!file.getParentFile().exists()){ // 判断父目录文件夹是否存在
        file.getParentFile().mkdir();   // 建立一个目录
    }
    PrintStream ps = null;
    ps = new PrintStream(new FileOutputStream(file));
    ps.println(filecontent);
    ps.close();
%>
<%
    /*
        完成写入文件的读取操作
    */
    Scanner scan = new Scanner(new FileInputStream(file));
    scan.useDelimiter("\n");
    StringBuffer buf = new StringBuffer();
    while(scan.hasNext()){
        buf.append(scan.next()).append("<br/>");
    }
    scan.close();
%>
<%=buf %>
</body>

filewrite

filewrite02

  • 网站计数器的实现

    • 在一些互联网站点中,经常会看见网站计数器(访问人数)这样的操作,那么下面就简单通过以上的技术内容,来实现一个这样的功能,但是在编写逻辑之前,必须注意以下的几个问题:
      1. 网站的访问人数可能会很多,可能是一个很大的数字,所以必须使用大整数类(BigInteger java.math)完成;
      2. 用户只有在第一次访问的时候(新用户)才需要进行计数的操作,在执行计算之前首先必须使用isNew()判断是否为新用户;
      3. 在进行更改、保存的时候需要进行同步的操作;
    • Code实现
    <body>
    <%!
        BigInteger count = null ;
    %>
    <%!
        public BigInteger load(File file){
            BigInteger count = null ;   // 接收数据
            try{
                if(file.exists()){
                    Scanner scan = new Scanner(new FileInputStream(file)) ;
                    if(scan.hasNext()){
                        count = new BigInteger(scan.next()) ;
                    }
                    scan.close() ;
                } else {    // 应该保存一个新的,从0开始
                    count = new BigInteger("0") ;
                    save(file,count) ;  // 保存一个新的文件
                }
            }catch(Exception e){
                e.printStackTrace() ;
            }
            return count ;
        }
        public void save(File file,BigInteger count){
            try{
                PrintStream ps = null ;
                ps = new PrintStream(new FileOutputStream(file)) ;
                ps.println(count) ;
                ps.close() ;
            }catch(Exception e){
                e.printStackTrace() ;
            }
        }
    %>
    <%
        String fileName = this.getServletContext().getRealPath("/") + "count.txt";  // 这里面保存所有的计数的结果
        File file = new File(fileName) ;
        if(session.isNew()){
            synchronized(this){
                count = load(file) ;    // 读取
                count = count.add(new BigInteger("1")) ;    // 再原本的基础上增加1。
                save(file,count) ;
            }
        }
    %>
    <h2>您是第<%=count==null?0:count%>位访客!</h2>
    </body>

    Count前

    Count后

  • 获取全部属性

<body>
<%
    Enumeration enu = this.getServletContext().getAttributeNames(); // 取得全部的属性
    while(enu.hasMoreElements()){
        String name = (String)enu.nextElement();
%>
        <p>
            <%=name %>====><%=this.getServletContext().getAttribute(name)%>
        </p>
<%
    }
%>
</body>

allAttribute

0x07 WEB安全性与config对象

  • 在Tomcat服务器的站点目录中,必须存在有一个WEB-INF目录,但是这个目录不会显示出来,那么既然这个目录无法被外部(客户端)所看见,既然无法被外部所看见,则安全性肯定是最高的。如果需要让客户端(浏览器)可以访问到的话,则必须进行web.xml的映射。

web-inf

  <servlet>
    <servlet-name>indexSite</servlet-name>
    <jsp-file>/WEB-INF/index.jsp</jsp-file>
  </servlet>
  <servlet-mapping>
    <servlet-name>indexSite</servlet-name>
    <url-pattern>/index.site</url-pattern>
  </servlet-mapping>

(web.xml文件修改后,必须重启Tomcat服务器,才可以使修改的内容生效)

index.site

  • config对象是javax.servlet.ServletConfig接口的实例化对象,主要的功能是取得一些初始化的配置信息
  • 常用方法

    • public String getInitParameter(String name)
    • public Enumeration getInitParameterNames()
  • 通过config对象取得初始化参数

<servlet>
    <servlet-name>initSite</servlet-name>
    <jsp-file>/WEB-INF/init.jsp</jsp-file>
    <init-param>
        <param-name>Driver</param-name>
        <param-value>com.microsoft.sqlserver.jdbc.SQLServerDriver</param-value>
    </init-param>
    <init-param>
        <param-name>url</param-name>
        <param-value>jdbc:sqlserver://localhost:1433</param-value>
    </init-param>
  </servlet>
  <servlet-mapping>
    <servlet-name>initSite</servlet-name>
    <url-pattern>/init.site</url-pattern>
  </servlet-mapping>
<body>
<%
    String DBDriver = config.getInitParameter("Driver");
    String DBURL = config.getInitParameter("url");
%>
<h3>驱动程序:<%=DBDriver %></h3>
<h3>连接地址:<%=DBURL %></h3>
</body>

init-param

0x08 out对象

  • out对象是javax.servlet.jsp.JspWriter类的实例化对象,主要的功能就是完成页面的输出操作,使用println()或print()方法输出,但是从实际的开发来看,直接使用out对象的几率较少,都会使用表达式完成输出的操作。
  • out对象定义了如下的几个操作:
    • public int getBufferSize()
    • public int getRemaining()
<body>
<%
    int buffer = out.getBufferSize();   // 获取缓冲区大小
    int avaliable = out.getRemaining(); // 可用的缓冲区大小
    int use = buffer - avaliable;       // 使用中的缓冲区大小
%>
<h3>缓冲区大小:<%=buffer %></h3>
<h3>可用缓冲区大小:<%=avaliable %></h3>
<h3>已使用的缓冲区大小:<%=use %></h3>
</body>

out

0x09 pageContext对象

  • pageContext对象是javax.servlet.jsp.PageContext类的实例,主要表示的是一个JSP页面的上下文,此类除了上面介绍过的属性操作之外,还定义了以下的一些操作方法:

    • public abstract void forward(String relativeUrlPath) throws ServletException,IOException
    • public void include(String relativeUrlPath) throws ServletException,IOException
    • public ServletConfig getServletConfig()
    • public ServletContext getServletContext()
    • public ServletRequest getRequest()
    • public ServletResponse getResponse()
    • public HttpSession getSession()
  • pageContext跳转实现

<body>
<%
    request.setCharacterEncoding("utf-8");
    pageContext.forward("pageContextForward.jsp?info=Java学员");
%>
</body>
<body>
<%
    // 从pageContext对象中取得了request的属性
    String info = pageContext.getRequest().getParameter("info");
%>
<h3>info:<%=info %></h3>
</body>

pageContext01

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值