• 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中没有任何的方法,称为“标识”接口(作用和序列化接口一样)。

  • 相关阅读:
    [saiku] 系统登录成功后查询Cubes
    216. Combination Sum III
    215. Kth Largest Element in an Array
    214. Shortest Palindrome
    213. House Robber II
    212. Word Search II
    211. Add and Search Word
    210. Course Schedule II
    分硬币问题
    开始学习Python
  • 原文地址:https://www.cnblogs.com/qin-derella/p/6747730.html
Copyright © 2020-2023  润新知