zoukankan      html  css  js  c++  java
  • JSP

    JSP

    1、什么是jsp?

    (java server page: java服务器端页面技术)

    sun公司制订的一种服务器端动态页面生成技术规范。

        因为直接使用servlet虽然也可以生成动态页面,但是过于繁琐(需要使用out.println输出),并且难

    以维护(如果要修改页面,就必须修改java源代码),所以,sun公司制订了一种新的规范专门用于生成动

    态页面,即jsp。

        jsp其实就是一个以.jsp为后缀的文件,该文件当中主要包含html和java代码。容器会将.jsp文件

    转换成.java文件(其实就是一个servlet),然后调用。

    2、如何写一个jsp文件?

            写一个以.jsp为后缀的文件,然后在该文件中,添加html和java代码。编写完成之后不需要编译,

         当客户端请求访问某个.jsp文件,服务器会自动将.jsp文件转换成一个.java文件。(该.java文件其实

         就是一个servlet)。

    3、jsp是如何执行的?

    阶段一:容器要将jsp文件转换成对应的servlet类。(该类可在tomcat的work文件中查看)

                 如何转换成servlet类?

                 1) html(css,javascript)  ---->service方法里,使用out.write输出

                 2)<% java代码片断 %>---->service方法里,照搬

                 3)<%=java表达式  %> ---->service方法里,使用out.print输出

                 4)<%! java声明 %>    ----->给servlet添加新的属性或者方法

                 5)out.write方法会将null转换成””,而且write方法不能输出对象只能输出字符串和基本类型

     out.println()可以输出对象

    阶段二:容器会将servlet类编译实例化,初始化,然后执行service方法。

       注意:第一次访问jsp文件时,会执行阶段一步骤,之后访问不再执行阶段一步骤。

             直接访问转换好的servlet类。

    案例:hello.jsp

                     <%@ page language="java" contentType="text/html; charset=utf-8"   pageEncoding="utf-8"%>

    <html>

    <head>

    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">

    </head>

    <body style="font-size:30px;">

                                        <%

                                                 for(int i=0;i<100;i++){

                                        %>

                                                          helloWorld!<br/>

                                        <%

                                                 }

                                       %>

    </body>

    </html>

    转换成的java文件hello_jsp.java

    public final class hello_jsp extends org.apache.jasper.runtime.HttpJspBase..{

    public void _jspInit(){ .... }

    public void _jspDestroy(){ ..... }

    public void _jspService(HttpServletRequest request, HttpServletResponse response){ .... }

    }

    1)类HttpJspBase继承了HttpServlet。覆盖了HttpServlet的service方法,覆盖的service方法中

                调用了_jspService方法,HttpJsPBase中的_jspService方法是空的(钩子方法,要求被覆盖),

                在hello_jsp类中重写了_jspService方法。

         2)当有请求时,容器会去调用HttpServlet的service方法,但这个方法被HttpJspBase覆盖了,

            所以会去调用HttpJspBase类中的service方法,这个方法又去调用_jspService方法,而

            hello_jsp覆盖了_jspService方法,所以去调用hello_jsp类中的_jspService方法,完成业务逻

            辑。

    4jsp文件的组成

       1)html(包括css、javascript)直接写在.jsp文件里即可。

    (2)java代码

         第一种形式:java代码片断   语法:<% java代码 %>

         第二种形式:java表达式      语法:<%= java 表达式 %>

         第三种形式:java声明<%!  %>

      <body style="font-size:30px;font-style:italic;">

                                                 <%!

                                                          int i = 100;

                                                          int sum(int a1,int a2){

                                                                   return a1 + a2;

                                                          }

                                                %>

                                                <%=i%><br/>

                                                <%=sum(1,1)%>

                </body>

    (3)指令

             a、什么是指令?    

           所谓指令,就是告诉jsp引擎(容器),在将.jsp文件转换成.java文件时,做一些额外的处理。

           比如导包。

           jsp引擎:容器当中负责将.jsp文件转换成.java文件。并在运行时为jsp提供一些辅助支持的

                    模块。

        b、指令语法

      <% @指令名 属性名=属性值   %>

        c、主要的指令

          1page指令:

              1)import属性:用于导包。

                 比如<%@page import="java.util.*,java.text.* "  %>

              2)contentType属性:等价于response.setContentType();

                     <%@page import="java.util.*,java.text.*" %>

                     3)pageEncoding属性

                 告诉容器, jsp文件的编码格式是什么。因为容器需要读取jsp文件的内容

                 (也就是解码: 本地编码格式 --->unicode),

                 有些容器不能够正确识别jsp文件的编码格式,所以最好加上该属性。

                 <%@page  pageEncoding="utf8" %>

     4)session属性

        true(缺省)/false,当值为false时,容器不再添加获得session对象

                      <%@page session=”false” %>

     5)errorPage属性

        指定一个错误处理页面<%@page errorPage="a4.jsp" %>

     6)isErrorPage属性

        true/false(缺省),如果值为true,表示这是一个错误处理页面。

        只有当isErrorPage属性等于true,才能使用exception隐含对象。

        <%@page isErrorPage="true" %>

        案例

        a3.jsp

    //当访问a3.jsp页面报错时,跳到指定的错误页面a4.jsp

                                             <%@page errorPage="a4.jsp" pageEncoding="utf-8" %>

    <html>

                                                          <body style="font-size:30px;font-style:italic;">

                                                          <%

                                                                   String num = request.getParameter("num");

                                                                   out.println(Integer.parseInt(num) + 100);

                                                         %>

                                                 </body>

    </html>

    a4.jsp

    <%@page isErrorPage="true" pageEncoding="utf-8" %>

    <html>

                                                          <body style="font-size:30px;font-style:italic;">

                                                                   发生了错误: <%=exception.getMessage()%>

                                                          </body>

    </html>

         2include指令:

              对于页面的公共部分,我们可以使用相同的jsp文件,并使用include指令导入,

              如此可以实现代码的优化。

              1)file属性:告诉容器,在将.jsp文件转换成.java文件时,在指令所在的位置插入file指

                          定的文件的内容。

                               <%@include  file="head.jsp"  %>

         3taglib属性

              用于导入书签

              1)prefix属性:命名空间的前缀

                         <%@taglib uri="http://java.sun.com/jsp/jstl/core"  prefix="c" %>

    (4)隐含对象

    a、什么是隐含对象?

            所谓隐含对象,指的是在.jsp文件当中,不用声明和创建该对象,就可以直接使用的对象。

    b、为什么可以直接使用这些隐含对象?

       .jsp文件对应的.java文件当中,因为容器会自动添加创建或者获得这些对象的语句。  

              out  request  response   session    application

     c、九种隐含对象

    out

    request

    response

    session

    application(就是servletContext,servlet上下文)

                1exception

                   必须设置isErrorPage=”true”才能使用这个隐含对象。可以通过该对象获得jsp页面运行的错

                   误信息。

                               <%@page isErrorPage="true"%>

                 2config

                   就是ServletConfig,可以读取jsp的配置参数。

     案例:为jsp配置初始化参数

     web.xml

                                       <servlet>

                                               <servlet-name>a7</servlet-name>

                                               <jsp-file>/a7.jsp</jsp-file>

                                               <init-param>

                                                        <param-name>company</param-name>

                                                        <param-value>北京达内</param-value>

                                               </init-param>

                                      </servlet>

                                      <servlet-mapping>

                                               <servlet-name>a7</servlet-name>

                                               <url-pattern>/abc.html</url-pattern>//可以随便写

    </servlet-mapping>

    a7.jsp

                                       <body style="font-size:30px;font-style:italic;">

                                                 公司名称:<%=config.getInitParameter("company") %>

                                        </body>

    发送请求:

    http://localhost:8088/web10/abc.html

                  3pageContext

                  是PageContext类的实例,容器会为每一个jsp实例(指的是jsp对应的那个servlet对象)创建一

                  个符合PageContext接口要求的对象,一般称之为page上下文。

    两个特点:

    1)唯一性

       一个jsp实例对应唯一一个page上下文

    2)一直存在

       只要jsp实例没有被容器销毁,则page上下文就一直存在。

    作用

    1)绑定数据

       setAttribute、getAttribute、removeAttribute

    2)提供了相应的方法来获得其他八个隐含对象。对象

               4page

                   表示jsp实例本身 。相当于this。

                   如下jsp隐含对象访问范围从小到大

                  pageContext     只有对应的JSP实例自己可以访问,生命周期从JSP对象创建到JSP对象消亡。

            request              一次请求能访问,生命周期在一起请求和响应期间。

            session              一次会话期间能访问,多次请求和响应期间都存在。

            ServletContext 整个应用内部所有组件都能访问,除非服务器关闭,否则一直存在。

    (5)注释

          a,  <!--  注释的内容 -->

            允许注释的内容是java代码,如果是java代码,容器会执行。

            但是执行的结果浏览器不会显示。

              b,  <%--   注释的内容 -->

            不允许出现java代码。如果是java代码,会被容器忽略。

    a8.jsp

    <html>

                               <body style="font-size:30px;font-style:italic;">

                                        当前系统时间:<!-- <%=new Date()%> -->

                                        当前系统时间:<%--<%=new Date()%>--%>

                               </body>

    </html>

    发送请求:http://localhost:8088/web10/a8.jsp,页面上都没有时间数据

    查看页面源代码

    <html>

             <head></head>

             <body style="font-size:30px;font-style:italic;">

                      当前系统时间:<!-- Sat Oct 26 15:11:33 CST 2013 -->

                      当前系统时间:

             </body>

    </html>

    5、案例empList.jsp

    localhost:8080/emp/empList.jsp(empList.jsp是放在webRoot下面的)

    <%@ page language="java" contentType="text/html; charset=utf-8"   pageEncoding="utf-8"%>

    <%@page import="dao.EmployeeDAO"%>

    <%@page import="util.Factory"%>

    <%@page import="java.util.List"%>

    <%@page import="entity.Employee"%>

    <html>

    <head>

    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">

    <style type="text/css">

             .row1{       background-color: red;           }

                                        .row2{       background-color: yellow;     }

    </style>

    </head>

    <body style="font-size:30px;">

                               <table cellpadding="0" cellspacing="0" border="1" width="60%">

                                        <tr style="">

                                                 <td>ID</td>

                                                 <td>姓名</td>

                                                 <td>薪水</td>

                                                 <td>年龄</td>

                                                 <td>操作</td>

                                        </tr>

                               <%

                                        EmployeeDAO dao=(EmployeeDAO)Factory.getInstance("EmployeeDAO");

                                        List<Employee> employees=dao.findAll();

                                        for(int i=0;i<employees.size();i++){

                                                 Employee e=employees.get(i);

                               %>

                                                 <tr class="row<%=(i%2+1) %>">

                                                          <td><%=e.getId() %></td>

                                                          <td><%=e.getName() %></td>

                                                          <td><%=e.getSalary() %></td>

                                                          <td><%=e.getAge() %></td>

                                                          <td><a href="">删除</a>&nbsp;&nbsp;<a href="">修改</a></td>

                                                 </tr>

                               <%

                                        }

                               %>

                               </table>

    </body>

    </html>

    6、转发

    1) 什么是转发?

    一个web组件(jsp/servlet)将未完成的处理通过容器转交给另一个web组件继续处理。转发的各个

             组件会共享request和response对象。

    最常见的情况是:一个servlet 将数据转交给一个jsp,由该jsp生成相应的页面。

    2) 如何转发?

       step1 先绑订数据 request.setAttribute(String name,Object obj);

                   跟绑订相关的另外两个方法 (如果name对应的值不存在,返回null。)

                   Object request.getAttribute(String name); 取出数据,然后进行下一步的处理。

                    request.removeAttribute(String name);

       step2 获得转发器,转发

     RequestDispatcher rd = request.getRequestDispatcher(String uri);

     rd.forward(request,response);

    3) 编程中要注意的问题

       转发之前,不能够执行out.close或者out.flush。(容器不允许发送两个数据包)

       转发之前,会将response中缓存的数据先清空。

    4) 转发的特点

    a. 转发的目的地只能是同一个应用内部的某个组件

    b. 转发之后,浏览器地址栏的地址没有变化

    c. 转发所涉及的各个组件可以共享同一个request,response对象

    7、转发与重定向的区别

    (1)转发所涉及的各个web组件(servlet和jsp)会共享request对象和response对象;重定向不行。

                     因为转发是一次请求,重定向是两次请求。

    request和response对象的生存时间:

    当请求到达容器,容器创建这两个对象,当响应发送完毕,容器会立即删除这两个对象。

    (2)转发的地址必须是同一个应用内部的某个组件,重定向的地址是任意的。

    (3)转发共享request,重定向不行。转发之后浏览器地址不变,重定向会变

    (4)转发是一件事没做完,让给其他组件做。重定向是一件事已经做完。

    8、表单中的中文问题

    表单中文处理步骤 

    step1、jsp文件,要添加

    <%@page pageEncoding="utf-8" contentType="text/html;charset=utf-8"%>

    表单设置method="post"。

    step2、在servlet类当中,添加request.setCharacterEncoding("utf-8");

    step3 如果要访问数据库:

     a. 保证数据库能够正常地保存中文。

    对于mysql数据库 create database dbname default character set utf8;

     b. 使用jdbc访问数据库时,必须要保证jdbc驱劢程序能够识别数据库中保存数据的编码。

                      jdbc:mysql://localhost:3306/jd1109db2? useUnicode=true&characterEncoding=utf8

    9、如何处理servlet产生的系统异常?

    方式1: 使用转发(更灵活一些,会绑定错误提示)

                      step1, 绑订错误提示信息。

                      step2, 转发到某个错误处理页面(比如,error.jsp)。

    servlet

    try {

                                                          dao.delete(id);

                                                  } catch (Exception e) {

                                                          e.printStackTrace();

                                                          request.setAttribute("error", "系统异常,稍后重试!");

                                                          request.getRequestDispatcher("error.jsp").forward(request, response);

                       }

    error.jsp

    <body  style="font-size:30px;color:red;">

                                                                   <%=request.getAttribute("error")%>

    </body>

    方式2: 让容器来处理

                      step1, 编写一个错误处理页面(error.jsp)

                      step2, 将异常抛出给容器   throw new ServletException(e)

                      step3, 配置错误处理页面,让容器知道出现异常后,应该调用哪一个页面。

    servlet

    try {

                                                          dao.modify(e);

                                                          response.sendRedirect("/emp/list.do");

                                                 } catch (Exception e1) {

                                                          e1.printStackTrace();

                                                          //将异常抛给容器(容器调用这个servlet方法,有异常,容器解决)

                                                          throw new ServletException(e1);

    }

    web.xml

    <web-app version="2.4" ....>

                                                        <servlet>

                                                                 <servlet-name>action</servlet-name>

                                                                 <servlet-class>web.ActionServlet</servlet-class>

                                                        </servlet>

    <servlet-mapping>

                                                                 <servlet-name>action</servlet-name>

                                                                 <url-pattern>*.do</url-pattern>

                                                        </servlet-mapping>

    <error-page>

                                                                 <exception-type>javax.servlet.ServletException</exception-type>

                                                                 <location>/error.jsp</location>

                                                        </error-page>

    </web-app>

    10、路径问题

       1) 链接地址、表单提交、重定向、转发的路径应该如何写?

    a. 链接地址: <a href=""></a>

    b. 表单提交: <form action="">

    c. 重定向: response.sendRedirect("");

    d. 转发: getRequestDispatcher("");

    2) 相对路径不绝对路径

    相对路径: 不以"/"开头的路径,比如:<a href="del.do"></a> 在当前路径下进行跳转

    绝对路径: 以"/"开头的路径,比如:<a href="/appname/del.do"></a>

    建议:因为相对路径较易出错,建议在实际开发中尽量使用绝对路径

    3) 怎样写绝对路径?

    链接、表单提交、重定向,绝对路径要从应用名开始写。 转发要从应用名之后开始写。

    获得实际部署时的应用名 /appname

    String request.getContextPath()

    response.sendRedirect(request.getContextPath() + "/app3/sub/some.jsp");

    <body style="font-szie:30px;">

                               a1....<br>

                               <a href="<%=request.getContextPath() %>/a2.jsp">a2.jsp</a>

    </body>

    <body style="font-size:30px;">

                               a2.jsp<br>

                               <a href="<%=request.getContextPath() %>/app/a1.jsp">a1.jsp</a>

    </body>

    转发:request.getRequestDispatcher("/emplist.jsp").forward(request, response);

    10、状态管理

       1)什么是状态管理?

     将客户端与服务器之间的多次交互当作一个整体来看待,并且将多次操作所涉及的数据记录下

     来。(状态管理就是这些数据的管理)

       2)怎样进行状态管理?

          第一种方式:将状态保存在客户端:cookie(在客户端管理用户的状态)

          第二种方式:将状态保存在服务器端:session(在服务器端管理用户的状态)

    11Cookie

      1)什么是cookie

                    浏览器在向服务器发送请求时,服务器将少量的数据以set-cookie消息头的形式发送给浏

           览器。浏览器会将这些数据(key-value形式)保存起来(可能保存在内存里,也可能保存在

           硬盘里)。当浏览器再次访问服务器时,会将这些数据以cookie消息头的形式发送给服务器。

           通过这种方式,可以管理用户的状态。

     服务器发送给浏览器端的形式:Set-Cookie: username=zhangsan

     浏览器发送给服务器的形式:Cookie: username=zhangsan; userpwd=1234

         (2)cookie适合放什么数据?

              这个取决于网站自身,有的说网站会存储一些重要的用户信息(什么用户名、密码、浏览记录、

              IP地址什么的)到Cookie里。事实上:

              普通网站都不会存重要的信息,它们仅仅存一个你的登陆状态,也就是你拿用户名密码换取的

              令牌,还有就是网站针对你的判定(比如你在这个网站上的唯一标识是什么,你访问的是我们的

              哪台服务器,你使用的是我们的哪个版本的产品),这些信息你都不需要关心,它和你的隐私一

              点关系都没有。

              文艺一点的网站会将这些信息进行加密,目的是防止别人伪造这些信息欺骗网站。

              在Cookie里存用户名、密码的,也许是央视网的做法在互联网上是极其极其少见的,可能只有

              外行或者刚学网络开发的学生会这么做,这种网站是极其不安全的,你的信息很容易就泄漏了,

              所以还是少去访问。

     网站的一些为你推荐的产品,您可能会喜欢的宝贝等等功能都是把用户经常浏览信息记录下

     来,用户再次登录根据信心返回相应的一些数据给客户。

     淘宝显示浏览过的商品的功能就是使用cookie技术:

     用户浏览淘宝页面时,服务器将items=1,3,4,5,6,7(商品的id值)这样的数据以cookie的形式

     发送给浏览器并且设置cookie的保存时间比较长,用户之后再访问淘宝页面时,将intems=1,2..

     发送给服务器,服务器根据这个id值查询出商品信息显示在页面上。

      2)创建cookie

           Cookie  cookie=new Cookie(String name,String value);

           response.addCookie(cookie);

      3)查询cookie(如果没有cookie,则返回null

           Cookie[ ]  cookies= request.getCookies( ); 注意:该方法有可能返回null

           String name=cookie.getName();

           String value=cookie.getValue();

          案例:创建和查询cookie

     <web-app version="2.4" ...>

                               <servlet>

                                        <servlet-name>addCookie</servlet-name>

                                        <servlet-class>web.AddCookieServlet</servlet-class>

                               </servlet>

                               <servlet-mapping>

                                        <servlet-name>addCookie</servlet-name>

                                        <url-pattern>/addCookie</url-pattern>

                               </servlet-mapping>

                               <servlet>

                                        <servlet-name>getCookie</servlet-name>

                                        <servlet-class>web.GetCookieServlet</servlet-class>

                               </servlet>

                               <servlet-mapping>

                                        <servlet-name>getCookie</servlet-name>

                                        <url-pattern>/getCookie</url-pattern>

                               </servlet-mapping>

     </web-app>

     AddCookieServlet

    public class AddCookieServlet extends HttpServlet{

                                        protected void service(HttpServletRequest request, HttpServletResponse response)

                                                          throws ServletException, IOException {

                                                 Cookie cookie=new Cookie("username","zhangsan");

                                                 Cookie cookie2=new Cookie("userpwd","1234");

                                                 response.addCookie(cookie);

                                                 response.addCookie(cookie2);

                                        }

    }

     GetCookieServlet

    public class GetCookieServlet extends HttpServlet{

                                        protected void service(HttpServletRequest request, HttpServletResponse response)

                                                                   throws ServletException, IOException {

                                                 Cookie[] cookies=request.getCookies();

                                                 for(Cookie cookie:cookies){

                                                          System.out.println(cookie.getName());

                                                          System.out.println(cookie.getValue());

                                                 }

                                        }

    }

     在地址栏发送请求:http://localhost:8888/web/setCookie时,服务器向浏览器发送两个Cookie

     以Set-Cookie: username=zhangsan,Set-Cookie: userpwd=1234形式发送给浏览器。

     在地址栏发送请求:http://localhost:8888/web/getCookie时,浏览器将cookie发送给服务器,

     以Cookie: username=zhangsan; userpwd=1234的形式发送给服务器

     4cookie保存时的编码问题

          cookie的值只能是ascii字符,如果是中文,需要将中文转换成ascii字符串形式。

     可以使用URLEncoder.encode()方法和URLDecoder.decode()方法来进行这种转换。

     java.net.URLEncoder.encode()可以对要传递的中文进行编码

                      /**

                       * encode方法先把字符串按照指定的编码格式(比如:utf-8),

              * 然后将编码之后得到的字节数组转换成一个ascii字符串

                       */

                       String str=URLEncoder.encode("过儿","utf-8");

                       System.out.println(str);

                       String str2=URLDecoder.decode(str,"utf-8");

     System.out.println(str2);

                      案例:cookie中保存中文

      AddCookieServlet

    public class AddCookieServlet extends HttpServlet{

                                        protected void service(HttpServletRequest request, HttpServletResponse response)

                                                          throws ServletException, IOException {

                                                 Cookie cookie=new Cookie("username",URLEncoder.encode("张三丰","utf-8"));

                                                 Cookie cookie2=new Cookie("userpwd","1234");

                                                 response.addCookie(cookie);

                                                 response.addCookie(cookie2);

                                        }

    }

     GetCookieServlet

    public class GetCookieServlet extends HttpServlet{

                                        protected void service(HttpServletRequest request, HttpServletResponse response)

                                                                   throws ServletException, IOException {

                                                 Cookie[] cookies=request.getCookies();

                                                 for(Cookie cookie:cookies){

                                                          System.out.println(cookie.getName());

                                                          System.out.println(URLDecoder.decode(cookie.getValue(), "utf-8"));

                                                 }

                                        }

    }

             5cookie的保存时间

     cookie.setMaxAge(int seconds); 单位是秒

                  seconds > 0 :浏览器会将cookie以文件的方式保存在硬盘上。

                           在超过指定的时间以后,会删除该文件。

                  seconds < 0 :默认值,浏览器会将cookie保存在内存里面。只有当浏览器关闭之后才会删除。

                  seconds = 0 :立即删除该Cookie

     AddCookieServlet

    public class AddCookieServlet extends HttpServlet{

                                        protected void service(HttpServletRequest request, HttpServletResponse response)

                                                          throws ServletException, IOException {

                                                 Cookie cookie=new Cookie("username",URLEncoder.encode("张三丰","utf-8"));

                                                 Cookie cookie2=new Cookie("userpwd","1234");

    //cookie会在60秒之后被删除

    cookie.setMaxAge(60);

    //cookie会在浏览器关闭时被删除

                                                 cookie2.setMaxAge(-1);

                                                 response.addCookie(cookie);

                                                 response.addCookie(cookie2);

                                        }

    }

             6删除cookie

            比如要删除一个name为"username"的cookie。

            Cookie c = new Cookie("username","");

    c.setMaxAge(0);

            response.addCookie(c);

      DelCookieServlet

    protected void service(HttpServletRequest request, HttpServletResponse response)

                                                                                                       throws ServletException, IOException {

                                        Cookie cookie=new Cookie("username","");

                                        cookie.setMaxAge(0);

                                        response.addCookie(cookie);

                      }

    (7)练习:查询名称为username的cookie,如果找不到,就添加名为username的cookie

                  public class FindCookieServlet extends HttpServlet{

                               protected void service(HttpServletRequest request, HttpServletResponse response)

                                                                                                       throws ServletException, IOException {

                                        response.setContentType("text/html;charset=utf-8");

                                        PrintWriter out=response.getWriter();

                                        Cookie[] cookies=request.getCookies();

                                        if(cookies!=null){

                                                 boolean flag=false;

                                                 for(Cookie cookie:cookies){

                                                          if(cookie.getName().equals("username")){

                                                                   out.println(URLDecoder.decode(cookie.getValue(),"utf-8"));

                                                                   flag=true;

                                                                   break;

                                                          }

                                                 }

                                                 if(!flag){

                                                          Cookie cookie=new Cookie("username",URLEncoder.encode("张三","utf-8"));

                                                          response.addCookie(cookie);

                                                 }

                                        }else{

                                                          Cookie cookie=new Cookie("username",URLEncoder.encode("张三","utf-8"));

                                                          response.addCookie(cookie);

                                                 }

                                        out.close();

                               }

    }

    7 cookie的路径问题

     1)什么是cookie的路径问题?

    浏览器在向服务器上的某个地址发送请求时, 会先比较cookie的路径与向访问的路径

    (地址)是否匹配,只有匹配的cookie,才会发送。

     2)cookie的默认路径

             cookie的路径默认等于创建这个cookie的组件的路径

    比如:/web07/app01/addCookie.jsp创建了一个cookie,则该cookie的路径等于"/web07/app01"。

     3)匹配规则

        要访问的服务器的地址必须是cookie的路径或者是其子路径,浏览器才会发送该cookie。

        http://localhost:8080/web07/findCookie1.jsp                              error

        http://localhost:8080/web07/app01/findCookie2.jsp                    ok

        http://localhost:8080/web07/app01/sub/findCookie3.jsp    ok

     4)修改cookie的路径

    cookie.setPath(String path);           比如:cookie.setPath("/web07");

    经常将cookie的路径设置为应用名,这样可以保证该cookie可以被该应用的其它组件都能访

    问到。

     5)要添加一个cookie,一般需要这样写

        Cookie cookie=new Cookie(“username”,URLEncoder.encode(“李白”,”utf-8”));

        cookie.setMaxAge(3600);

        cookie.setPath(“/web07”);

        response.addCookie(cookie);

    (8) cookie的限制

     1)不安全

        因为cookie存放在浏览器端,可以很容器被查看到,所以,如果有敏感数据,一定需要加密。

     2)cookie可以被用户禁止

     3)cookie的大小有限制(大约只能存放4k左右的数据,具体大小跟浏览器有关系)

     4)cookie的个数也有限制(浏览器大约只能保存300个左右的cookie)。

     5)cookie只能保存字符串,并且,需要考虑编码问题。

    (9)小知识

    浏览器有保存密码的功能,存在安全隐患。密码信息将很容器被他人窃取。

    安全建议:

    OWASP建议网站设计者应该禁止浏览器保存用户登录密码,实现方法如下面的html标签。

    <input type=”password” autocomplete=”offf”>      autocomplete属性是html5后新增的属性

    有了autocomplete属性的输入框,浏览器就不会记录密码了,Yahoo登陆页面就是这样的。

    12session

     1)什么是session?

     session是一种服务器端的状态管理技术。

     浏览器访问服务器时,服务器会创建一个session对象(该对象有一个id属性,其值是唯一的, 一

     般称为sessionId)。

     服务器在缺省情况下,会将sessionId以cookie机制(将sessionId放到set-cookie消息头)发送给浏

     览器(浏览器把sessionId放入内存中)。

     当浏览器再次访问服务器时,会将sessionId发送给服务器。服务器依据sessionId就可以找到对应

     的session对象。通过这种方式,就可以管理用户的状态。

     比如:

     jsp页面在转成java文件时有:HttpSession  session=pageContext.getSession()。

     这个方法里实际调用了request.getSession()方法。

     所以发送一个jsp的请求就会创建一个session对象。所以在jsp页面中可以直接使用session对象

     a、浏览器发送请求:http://localhost:8088/emp/list.do

        查询数据时还没有创建session对象,转发到emplist.jsp时,jsp对应的java文件中创建了一个

        session对象,发送响应时服务器将session对象的sessionId以cookie的形式发送给浏览器

        Set-Cookie: JSESSIONID=70C101358F84CEF4A63B3EAFCCF1BC52; Path=/emp

        该cookie的路径是/应用名

     b、浏览器再次发送请求:http://localhost:8088/emp/addEmp.jsp时,会把sessionId再以cookie的形

        式发送给浏览器

        Cookie: JSESSIONID=70C101358F84CEF4A63B3EAFCCF1BC52

     注意浏览器保存的cookie JSESSIONID在浏览器关闭时就被删除了。过期时间为浏览会话结束时

     也就是说,每次关闭浏览器后所有的session不可用。再次访问服务器都是重新创建session对象

    2)如何获得session对象

    方式一: HttpSession session = request.getSession(boolean flag);

           1)当flag = true:

              服务器会先查看请求中是否包含sessionId, 如果没有,则创建一个session对象。

              如果有,则依据sessionId去查找对应的session对象,如果找到,则返回。

              如果找不到(可能被容器删除了),则创建一个新的session对象。

           2)当flag = false:

              服务器会先查看请求中是否包含sessionId, 如果没有,返回null。

              如果有,则依据sessionId去查找对应的session对象,如果找到,则返回。

              如果找不到,返回null。

    方式二:HttpSession session = request.getSession(); 与request.getSession(true)等价。

    3HttpSession接口提供的一些方法

    1)获得sessionId。

       String session.getId();

    2)绑订数据

       session.setAttribute(String name,Object obj); 绑定数据

       Object session.getAttribute(String name); 如果name对应的值不存在,返回null。

       session.removeAttribute(String name); 解除绑定

    3)案例:计算用户是第几次访问?

       web.xml

    <servlet>

                                        <servlet-name>count</servlet-name>

                                        <servlet-class>session.CountServlet</servlet-class>

                               </servlet>

                               <servlet-mapping>

                                        <servlet-name>count</servlet-name>

                                        <url-pattern>/count</url-pattern>

    </servlet-mapping>

       CountServlet

    protected void service(HttpServletRequest request, HttpServletResponse response)

                                                                                                                throws ServletException, IOException {

                                        response.setContentType("text/html;charset=utf-8");

                                        PrintWriter out = response.getWriter();

                                        HttpSession session = request.getSession();

                                        //session.setMaxInactiveInterval(35);

                                        String sessionId = session.getId();

                                        System.out.println("sessionId:" + sessionId);

                                        Integer count = (Integer)session.getAttribute("count");

                                        if(count == null){

                                                 //第一次访问

                                                 count = 1;

                                        }else{

                                                 //不是第一次,在原有值的基础上加1

                                                 count ++;

                                        }

                                        session.setAttribute("count", count);

                                        out.println("你是第:" + count + " 次访问");

                                        //session.invalidate();把session对象内容清空

                               }

    (4)session超时

    1)什么是session的超时?

       session对象不是一直存在的。

       服务器会将超过指定时间的session对象删除(在指定的时间内,该session对象没有使用)。

       原因是,过多的session对象会占用服务器过多的内存空间。

       大部分服务器都会有一个缺省的超时限制,一般是30分钟。

    2)修改服务器缺省的session超时限制。

       方式一: session.setMaxInactiveInterval(int seconds);单位是秒

       方式二: 服务器有一个缺省的超时限制,可以通过相应的配置文件来重新设置。

                比如可以修改tomcat的web.xml(tomcat_home/conf下面)。

                <session-config> <session-timeout>30</session-timeout> </session-config>

                修改完之后,需要重新启动服务器。

                另外,也可以将以上配置放在某个应用的web.xml文件当中。

               (这样修改的内容只针对当前应用)

    5)立即删除session

      session.invalidate(); 把session对象内容清空

    6session的优缺点

    优点:

             session相对安全

             session能够保存的数据类型更丰富

             session能够保存的数据大小更大

    缺点:

             session需要将所有数据写在服务器端,所以,服务器会占用过多的内存空间。

         可以考虑使用cookie来代替或者使用数据库来保存状态(即数据)。

    注意:无论是cookie还是session都不能永久保存数据,要想永久保存数据就把数据插入到数据库里。

    (7)session里通常存些什么值?

    session通常用来保存与用户信息相关的:身份信息、登陆状态,用户的个性设置、权限列表,

    其他的一些通用数据(比如购物车)

    原则是把通用的,频繁存取的、小数据量的跟用户相关的数据放入session,视场景而定。

         session就相当于一个缓存,放在内存中,避免多次存取而效率低下。但是

         如果存放的数据比较多的话,会占用过多的内存

    11、用户禁止cookie以后,如何继续使用session

      当用户禁止cookie以后,服务器仍然会发送sessionId(以set-cookie消息头的方式)。但是,浏览器

           会拒绝接受,这样,session机制会失效。

    1)解决方式

       使用url重写机制

    2)什么是url重写?

            如果要访问的web组件(jsp/servlet)需要session机制的支持,那么不能够直接输入该web组件

            的地址,而应该使用服务器生成的包含有的sessionId的地址。

           3)如何生成包含有sessionId的地址?

       方式1(适用于链接、表单提交)

    response.encodeURL(String url); 等价于 response.encodeUrl(String url)(不常用)

       方式2(适用于重定向)

    response.encodeRedirectURL(String url);

       转发不需要、转发和session无关,是服务器内部完成,没有和浏览器进行交互

    session没有被禁止时

    <a href="count">vist countServlet</a>

    访问countServlet步骤:

    ① 浏览器访问test.jsp

    ② 服务器为该浏览器用户创建一个Session对象,用于保存此次会话的数据

    ③ 服务器将sessionId返回给浏览器&&返回生成的显示给用户的页面

    ④ 浏览器将服务器传回的sessionId保存到内存中

    ⑤ 当用户点击“链接”<a href="count">时,浏览器发送带sessionId的请求给服务器

    ⑥ 服务器中的CountServlet通过该sessionId找到该用户对应的Session并做计数操作

    ⑦ CountServlet将计数结果和页面返回给用户浏览器

    session被禁止时:

    <a href="<%=response.encodeURL("count")%>">vist countServlet</a>

    访问countServlet步骤:

    ① 浏览器访问test.jsp

    ② 服务器创建Session对象

    ③ test.jsp将页面和SessionId返回给浏览器

       因为浏览器禁用了Cookie,所以浏览器并不保存sessionId, 为了能继续使用Session,

       我们在test.jsp中重写了URL, 所以此时test.jsp返回给浏览器一个带有sessionId的地址:

                     http://localhost:8080/web08_session/count;jsessionid=596A1BC51F79553E341AF3B

    ④ 当用户点击“链接”,向服务器发送的请求中包含了sessionId

    ⑤ 服务器通过这个sessionId可以找到对应的Session

    ⑥ CountServlet将计数结果和页面返回给用户浏览器

    12、过滤器

    (1)什么是过滤器?

         servlet规范当中定义的一种特殊的类,用于对servlet容器的调用过程进行拦截。

         执行步骤:

    1) 浏览器发送请求给服务器

    2) 服务器的Servlet引擎创建Request对象&&Response对象

    3) Servlet引擎先调用过滤器的doFilter方法,该方法有两个参数request和response,

    (在过滤器中可以访问到Request对象&&Response对象)

    4) 过滤器对拦截的内容进行处理

    5) 之后调用SomeServlet的service方法

    6) service方法执行

    7) service方法执行结束后,将结果返回到过滤器

    8) 过滤器将service方法返回的结果再次进行过滤

    9) 最后,Servlet引擎将结果返回给浏览器

        (2)怎样写一个过滤器?

        step1、写一个java类,实现一个Filter接口

        step2、在doFilter方法里,实现过滤的逻辑

        step3、配置(web.xml)

        案例:对用户的评论过滤

                    jsp页面

    <body style="font-size:30px;">

                                        <form action="<%=request.getContextPath() %>/comment" method="post">

                                                 评论:<input type="text" name="content"><br>

                                                 <input type="submit" value="发表">

                                        </form>

    </body>

    web.xml文件

    <filter>

                                        <filter-name>filter1</filter-name>

                                        <filter-class>web.Filter1</filter-class>

                               </filter>

                               <filter-mapping>

                                        <filter-name>filter1</filter-name>

                                        <url-pattern>/comment</url-pattern>

    </filter-mapping>

    <servlet>

                                        <servlet-name>comment</servlet-name>

                                        <servlet-class>web.CommentServlet</servlet-class>

                               </servlet>

                               <servlet-mapping>

                                        <servlet-name>comment</servlet-name>

                                        <url-pattern>/comment</url-pattern>

    </servlet-mapping>

    Filter1

                          public class Filter1 implements Filter{

                           //容器再删除过滤器对象之前,会调用destory方法

                                        public void destroy() {

                                                 System.out.println("过滤器被销毁");

                                        }

    //类似于servlet的service方法,请求到达时容器会调用doFilter方法来处理请求

    // servletrequest是容器创建的request对象,servletresponse是response对象

    //容器会将request对象和response对象作为参数传给doFilter方法

    //FilterChain:过滤器链

    // FilterChain 对象有一个doFilter方法,如果该方法调用了,

    //表示让容器继续向后调用过滤器或者servlet

    public void doFilter(ServletRequest servletrequest,ServletResponse servletresponse,

    FilterChain filterchain)throws IOException, ServletException {

    //HttpServletRequest是sun公司过度设计的产物

                                                 HttpServletRequest request=(HttpServletRequest) servletrequest;

                                                 HttpServletResponse response=(HttpServletResponse) servletresponse;

                                                 request.setCharacterEncoding("utf-8");

                                                 response.setContentType("text/html;charset=utf-8");

                                                 PrintWriter out=response.getWriter();

                                                 String str=request.getParameter("content");

                                                 if(str.lastIndexOf("dog")!=-1){

                                                          out.println("评论当中包含了敏感字!");

                                                 }else{

                                                          filterchain.doFilter(servletrequest, servletresponse);

                                                 }

                                       //容器启动之后,会立即创建过滤器对象

    //接下来,会调用init方法.在调用init方法之前,容器会先创建好一个符合FilterConfig

    //接口要求的对象。该对象可以用来访问过滤器的初始化参数

                     (getInitParamter(String paraname))

                                        public void init(FilterConfig filterconfig) throws ServletException {

                                                 //FilterConfig相当于ServletConfig,用来读取初始化参数

                                                 System.out.println("过滤器被初始化");

                                        }

                               }

    CommentServlet

    protected void service(HttpServletRequest request, HttpServletResponse response)

                                                                                                       throws ServletException, IOException {

                                        request.setCharacterEncoding("utf-8");

                                        response.setContentType("text/html;charset=utf-8");

                                        PrintWriter out=response.getWriter();

                                        String str=request.getParameter("content");

                                        out.println("您的评论是:"+str);

    }

        (3)配置初始化参数

        step1、web.xml中,使用<init-para>元素来配置初始化参数

        step2、在Filter类中,使用FilterConfig.getInitParamter(String paraName);获得初始化参数

        案例:将敏感字写在配置文件里

    web.xml文件

    <filter>

                               <filter-name>filter1</filter-name>

                               <filter-class>web.Filter1</filter-class>

    <!-- 初始化参数 -->

    <init-param>

           <param-name>illegalStr</param-name>

           <param-value>cat</param-value>

    </init-param>

                      </filter>

                      <filter-mapping>

                               <filter-name>filter1</filter-name>

                               <url-pattern>/comment</url-pattern>

    </filter-mapping>

    Filter1

    public class  Filter1 implements Filter{

             private FilterConfig config;

             public  Filter1(){

                      System.out.println("Filter1's constructor...");

             }

             public void destroy() {

                      System.out.println("Filter1's destroy...");

             }

             public void doFilter(ServletRequest arg0,

                               ServletResponse arg1, FilterChain arg2) throws IOException, ServletException {

                      System.out.println("Filter1's doFilter begin...");

                      HttpServletRequest request = (HttpServletRequest)arg0;

                      HttpServletResponse response = (HttpServletResponse)arg1;

                      request.setCharacterEncoding("utf-8");

                      String content = request.getParameter("content");

                      response.setContentType("text/html;charset=utf-8");

                      PrintWriter out = response.getWriter();

                      //读过滤器的初始化参数

                      String illegalStr = config.getInitParameter("illegalStr");

                      if(content.indexOf(illegalStr) != -1){

                               out.println("评论当中包含了敏感字");

                      }else{

                               //调用后续的过滤器或者servlet

                               arg2.doFilter(arg0, arg1);

                      }

                      System.out.println("Filter1's doFilter end.");

             }

             public void init(FilterConfig arg0) throws ServletException {

                      System.out.println("Filter1's init...");

                      config = arg0;

             }

    }

        (4)过滤器的优先级

             当有多个过滤器都满足过滤的条件时,依据<filter-mapping>的先后顺序依次执行。

        (5)过滤器的优点

        a、可以将多个web组件相同的处理逻辑集中写在一个过滤器中,方便代码的维护

        b、可实现代码的“可插拔性”

      给一个软件增加或者减少某个模块,不会影响程序的正常运行

    13ServletContext接口servlet上下文)

        (1)什么是ServletContext(servlet上下文)

         context:环境 上下文 。

         web服务器在启动时,会为每一个已经部署的应用创建唯一的一个ServletContext实例。 该实例

         会一直存在,除非服务器关闭或者应用被删除。

         可以把ServletContext看成是一个web应用的服务端组件的一个共享内存,在ServletContext中可以

         存放共享数据。整个应用内部所有组件都能访问ServletContext的内容。

         servlet上下文有两个特点:

         1)唯一性

       一个应用对应一个servlet上下文(有且只有一个)

    2)一直存在

       只要容器不关闭或者应用不卸载,servlet上下文就一直存在。

       (2)如何获得ServletContext实例。

             1)GenericServlet提供了getServletContext()方法

             2)ServletConfig提供了getServletContext()方法

             3)HttpSession提供了getServletContext()方法

             4)FilterConfig提供了getServletContext()方法

        以上几种方式都是得到同一个ServletContext对象。tomcat容器的ApplicationContext类实现了

        ServletContext接口。以上方法最终是

        ServletContext application = new ApplicationContext();

       (3)servlet上下文的作用

       1)绑定数据

     setAttribute(String name,Object obj);

     getAttribute(String name);

     removeAttribute(String name);

     注意:request对象、session对象、servlet上下文都有绑定数据的挡风区别如下:

     a、request对象的生存时间是一次请求与响应期间,

        session对象的生存时间是多次请求与响应期间(用户与服务器的一次会话)

        servlet上下文是一直存在的。

        所以,在满足使用条件的情况下,应该优先使用生命周期短的。

                 比如转发,选择用request,转发结束后,绑定的数据就没有用了,随着request对象的销毁,

                 数据也被销毁,这样会比较节省内存。如果转发使用servlet上下文时,转发结束后,数据还

                 保留着,这样会浪费内存空间。

     b、request对象上面绑定的数据只能是同一个请求所涉及的组件可以访问,

        session对象上面绑定的数据是同一个会话当中所涉及的组件可以访问,

        servlet上下文上面绑定的数据是同一个应用当中的所有组件都可以访问。

         2)配置全局的初始化参数

                      step1 在web.xml中,使用<context-param>配置的参数,可以被所有的servlet共享。

     step2 使用String ServletContext.getInitParameter(String paraName);

     web.xml配置时一般都有一定的顺序(约定俗成)

    <web-app version="2.4" ...>

                     <!-- 全局的初始化参数 -->

    <context-param>

                              <param-name>company</param-name>

                              <param-value>北京达内</param-value>

     </context-param>

                     <!-- 过滤器的配置 -->

                     <!-- 监听器的配置 -->

    <!-- servlet的配置 -->

    </web-app>

     Servlet代码

     ServletContext sctx = getServletContext();

     String company = sctx.getInitParameter("company");

     System.out.println("  " + company);

           3)依据逻辑路径获得实际部署时的物理路径。

     String ServletContext.getRealPath(String url);

    14、监听器 **

    1) 什么是监听器?

    servlet规范当中定义的一种特殊的类,作用是监听容器当中产生的一些事件并进行相应的处理。

    容器产生的事件指的是两大类事件:

    1)生命周期相关的事件

       指的是当容器创建或者销毁request,session,ServletContext对象时产生的事件。

    2)绑订事件

       指的是当调用request,session,ServletContext对象的setAttribute,removeAttribute时产生的事件。

    2) 如何写监听器

    step1 写一个java类,实现特定的监听器接口类(依据要监听的事件类型)。

    step2 在接口声明的方法中,实现监听的逻辑。

    step3 配置(web.xml)。

    3) 案例

       a、统计在线人数

          CountListener

    public class CountListener implements HttpSessionListener{

             private int count = 0;//计数器

             /**

              * session对象被创建后,容器会调用这个方法

              */

             public void sessionCreated(HttpSessionEvent httpsessionevent) {

                      System.out.println("session被创建");

                      count++;

                      //将在线人数绑定到servlet上下文对象上

                      HttpSession session=httpsessionevent.getSession();

                      ServletContext application=session.getServletContext();

                      application.setAttribute("count", count);        

             }

             /**

              * 当session对象被销毁后,容器会调用这个方法

              */

             public void sessionDestroyed(HttpSessionEvent httpsessionevent) {

                      System.out.println("session被销毁");

                      count--;

                      HttpSession session=httpsessionevent.getSession();

                      ServletContext application=session.getServletContext();

                      application.setAttribute("count", count);

             }

    }

    web.xml

    <web-app version="2.4" ...>

                               <listener>

                                        <listener-class>web.CountListener</listener-class>

                               </listener>

    //index.jsp首页的意思

    //当发送请求时(只到应用名)

     如:http://localhost:8080/web09时,会自动定位到index.jsp

                               <welcome-file-list>

                                      <welcome-file>index.jsp</welcome-file>

                               </welcome-file-list>

    </web-app>

    index.jsp

    <html>

                             <body>

                                      当前系统在线人数是:<!--application隐含对象就是ServletContext对象  -->

                                      <%=application.getAttribute("count") %>

                               </body>

    </html>

     b、容器开启时,每隔5秒输出当前系统时间。容器关闭或应用卸载时,停止。

        TaskListneer类

                 public class TaskListneer implements ServletContextListener{

                               private Timer timer=new Timer();

    public void contextDestroyed(ServletContextEvent servletcontextevent) {

                                        System.out.println("任务停止");

                                        timer.cancel();

                               }

    public void contextInitialized(ServletContextEvent servletcontextevent) {

                                        System.out.println("任务开始");

                                        timer.schedule(new TimerTask(){

                                                 public void run() {

                                                          SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");

                                                          System.out.println(sdf.format(new Date()));

                                                 }

                                        }, 0,5000);

                               }

    }

    web.xml

    <listener>

                               <listener-class>web.CountListener</listener-class>

    </listener>

    15、上传文件(扩展)

      (1)在form中,设置method="post",设置enctype="multipart/form-data"。

           enctype属性用于设置表单的编码方式,按照http协议,

           对于文件上传,必须设置成"multipart/form-data"。

           比如:

                      <form enctype="multipart/form-data" method="post">

                      "multipart/form-data":用来设置浏览器上传文件的格式。

      (2)在服务器端读取文件的内容,并保存到相应的文件夹底下

      如果enctype=”multipart/form-data”,则服务器不再解析请求数据包,也就是说

      request.getParamter()方法返回null。

      要使用 InputStream request.getInputStream();获得一个输入流,

      然后分析InputStream流来获得参数值。

      直接分析InputStream比较复杂,一般使用一些封装好的工具

      (比如apache提供的 commons-fileupload.jar)来获得参数值。

    16、servlet线程安全问题

    1)servlet为什么会有线程安全问题?

    a、servlet容器在默认情况下只会创建一个servlet实例

      (比如SomeServlet在容器里面,只有一个SomeServlet对象)

    b、当容器收到请求之后,会启动一个线程来处理

    c、如果有多个请求同时访问某个servlet实例,即有多个线程调用同一个servlet实例的方法,

       就有可能产生线程安全问题。(比如,这些线程同时去修改servlet属性)

    2)如何解决

       a、使用synchronized对整个service方法或者代码块加锁(建议使用代码块加锁)

       b、让servlet实现SingleThreadModel接口

          容器会为每一个实现了该接口的servlet创建多个实例(一个线程创建一个servlet对象)。

     不建议使用,因为会创建过多的servlet对象。

     SingleThreadModel中没有任何的方法,称为“标识”接口(作用和序列化接口一样)。

  • 相关阅读:
    spring源码阅读(一)
    多线程学习(十)
    多线程学习(九)
    多线程学习(八)
    多线程学习(七)
    多线程学习(六)
    多线程学习(五)
    多线程学习(四)
    matlab-table
    Matlab
  • 原文地址:https://www.cnblogs.com/qin-derella/p/6747730.html
Copyright © 2011-2022 走看看