JSP webshell免杀——JSP的基础

唉,每次开启JSP都要好一会儿。

话说我也不知道为啥,我的每次开启条件一次比一次苛刻。一开始必应就可以打开,再后来只能由谷歌打开,现在可好了得开着代理用谷歌才能进去。

一个JSP页面可由5种元素组合而成

 (1) 普通的HTML标记和JavaScript标记,CSS。

 (2) JSP标记,如指令标记、动作标记。<%@,<jsp: 

 (3) 变量和方法,类的声明。<%!

 (4) Java 程序片。<% (5) Java 表达式。<%=

原理 

★一个JSP页面被第一次请求执行时,Tomcat服务器首先将JSP页面文件转译成一个Java文件,再将这个Java文件编译生成字节码文件,然后通过执行字节码文件响应用户的请求。

★当多个用户请求一个JSP页面时,Tomcat服务器为每个用户启动一个线程,该线程负责执行常驻内存的字节码文件来响应相应用户的请求。这些线程由Tomcat服务器来管理,将CPU的使用权在各个线程之间快速切换,以保证每个线程都有机会执行字节码文件。

在<%!和%>标记符号之间声明变量,定义方法以及定义类。   <%!和%>标记符号的内容习惯上放在JSP 页面指令之后,<HTML>之前,也可以写在<HTML>与</HTML>之间。

扫描二维码关注公众号,回复: 14692496 查看本文章

<%!和%>之间声明的变量在整个JSP页面内都有效,与标记符在JSP页面中所在的书写位置无关,但习惯上把<%!、%> 标记符写在JSP页面的前面。

<%@ page contentType="text/html" %>   
<%@ page pageEncoding = "utf-8" %>  
<HTML><body bgcolor=yellow>
<%! int i=0;
%>
<% i++;
%>
<p style="font-family:宋体;font-size:36">
您是第<%= i %>个访问本站的用户。
</p>
</body></HTML>    
 

<%@ page contentType = "text/html" %>  
<%@ page pageEncoding = "utf-8" %>  
<HTML><body bgcolor = #ffccff>
<p style="font-family:宋体;font-size:36;color:blue">
<%! double multi(double x,double y){ //定义方法
        return x*y;
    }
    double div(double x,double y) { //定义方法
        return x/y;
    }
    class Circle { //定义类
        double r;
        double getArea(){
           return 3.1415926*r*r;
        }
    }
%>
<%  double x=8.79;
    double y=20.8;
    out.print("调用multi方法计算"+x+"与"+y+"之积:<br>");
    out.print(multi(x,y));
    out.print("<br>调用div方法计算"+y+"除以"+x+"的商:<br>");
    String s =String.format("小数点保留3位:%10.3f",div(y,x));
    out.println(s); 
    Circle circle = new Circle(); //用Circle类创建对象。
    circle.r = 3.6;
    out.print("<br>半径是"+circle.r+"的圆面积"+circle.getArea()); 
%>
</p></body></HTML>

 可以在<%和%>之间插入Java 程序片。

●一个JSP页面可以有许多程序片,这些程序片将被Tomcat服务器按顺序执行。 ●在程序片中声明的变量称作JSP页面的局部变量。局部变量的有效范围与其声明的位置有关,即局部变量在JSP页面后继的所有程序片以及表达式部分内都有效。

ynchronized是Java中的关键字,是一种同步锁。它修饰的对象有以下几种:
1. 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象;
2. 修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象;
3. 修改一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象;
4. 修改一个类,其作用的范围是synchronized后面括号括起来的部分,作用主的对象是这个类的所有对象。
 

<%@ page contentType = "text/html" %>  
<%@ page pageEncoding = "utf-8" %>  
<HTML><body>
<p style="font-family:宋体;font-size:36;color:blue">
<%! int count=0;                    //被用户共享的count。
     synchronized void setCount() {  //synchronized修饰的方法。
       count++;
     }
%>
<%  setCount();
    out.println("您是第"+count+"个访问本站的客户");   
%>
</p></body></HTML>
 

<%=和%>之间插入一个可求值的表达式(注意:不可插入语句, <%=是一个完整的符号,“<%”和“=”之间不要有空格)。

★表达式的值由服务器负责计算,并将计算结果用字符串形式发送到用户端显示。

★Java表达式可以写在<HTML>之前,也可以写在<HTML>和</HTML>之间或</HTML>之后。

<%@ page contentType="text/html" %>  
<%@ page pageEncoding = "utf-8" %> 
<HTML><body>
<p style="font-family:黑体;font-size:22">
  数学,英语和语文成绩单。<br>单科满分是150分。
</p>
<% int math = 98;
   int english = 90;
   int chinese = 110;
   int sum = math+english+chinese;
%>
<p style="font-family:宋体;font-size:20">
<table border = 2>
<tr>
  <td>姓名</td><td>数学成绩</td> <td>英语成绩</td> <td>语文成绩</td> <td>总成绩</td>
</tr>
<tr>
  <td>张三</td><td><%= math %></td> <td><%= english %></td> <td><%= chinese %></td>
  <td><%= sum %></td>
</tr>
<% math = 115;
   english = 70;
   chinese = 120;
   sum = math+english+chinese;
%>
<tr>  
 <td>李四</td><td><%= math %></td> <td><%= english %></td> <td><%= chinese %></td>
 <td><%= sum %></td>
<tr>
<% math = 88;
   english = 100;
   chinese = 98;
   sum = math+english+chinese;
%> 
<tr> 
 <td>王五</td><td><%= math %></td> <td><%= english %></td> <td><%= chinese %></td>
  <td><%= sum %></td>
</tr>
</table>
</p>
</body></HTML>
 

 

 注释

HTML注释:在标记符号“<!--”和“-->”之间加入注释内容:

<!--    注释内容     -->

JSP引擎把HTML注释交给用户,因此用户通过浏览器查看JSP页面的源文件时,能够看到HTML注释。

 JSP 注释:在标记符号“<%--”和“--%>”之间加入注释内容:

<%--  注释内容  --%>

  Tomcat服务器忽略JSP注释,即在编译JSP页面时忽略JSP注释。

page 指令标记

page 指令用来定义整个JSP页面的一些属性和这些属性的值。

<%@ page   属性1="属性1的值"  %>

<%@ page   属性2="属性2的值"  %> … … <%@ page   属性n="属性n的值"  %>

也可以用一个page指令指定多个属性的值,如: <%@ page   属性1="属性1的值"  属性2= "属性2的值"  ……%>

page指令的作用对整个JSP页面有效,与其书写的位置无关。习惯上把page指令写在JSP页面的最前面。

page 指令标记可以指定属性: contentType、import、language(略)、session(略)、buffer(略)、auotFlush(略) 、isThreadSafe、pageEncoding 、info

(1)contentType属性

JSP页面设置响应的MIME(Multipurpose Internet Mail Extention)类型,即设置contentType 属性的值。contentType属性值确定JSP页面响应的MIME类型。属性值的一般形式是: "MIME类型"

<%@ page contentType="text/html " %>

浏览器启用HTML解析器来解析执行所接收到的信息。

如果希望用户的浏览器启用本地的MS-Word应用程序来解析执行收到的信息,就可以如下设置contentType属性的值: <%@ page contentType="application/msword" %>

可以使用page指令为contentType 属性指定的值有:text/html、text/plain、image/gif、 image/x-xbitmap、image/jpeg、image/pjpeg、application/x-shockwave-flash、application/vnd.ms-powerpoint、 application/vnd.ms-excel、application/msword等

page指令只能为contentType指定一个值,不允许两次使用page指令给contentType属性指定不同的属性值。

用page指令为contentType指定一个值的同时,也可以为contentType的附加属性charset指定一个值(默认值是iso-8859-1),例如: <%@ page contentType="text/html;charset=gb2312" %>

contentType的附加属性charset的值是通知用户浏览器用怎样的编码解析收到的字符, 当JSP页面用page指令指定设置charset的值是gb2312时,浏览器会将编码切换成gb2312。

但是,如果JSP页面用page指定了JSP的页面本身的编码,例如:<%@ page pageEncoding = "utf-8" %>,那么charset的值和JSP的页面编码保持一致,即也是utf-8(目前的浏览器都支持utf-8编码,所以一般不需要再指定charset的值,使其和JSP的页面编码保持一致即可)

(2)pageEncoding 属性

只能为pageEncoding指定一个值,不允许两次使用page指令给pageEncoding属性指定不同的或相同的属性值。

例如: <%@ page pageEncoding = "utf-8" %> 那么保存JSP页面应当将“编码”选择为“utf-8”

(3) language属性

language属性定义JSP页面使用的脚本语言,该属性的值目前只能取"java"。

为language属性指定值的格式是: <%@ page  language="java" %>

language属性的默认值是"java",即如果在JSP页面中没有使用page指令指定该属性的值的,那么,JSP页面默认有如下的page指令: <%@ page  language="java" %>

(4)import 属性

该属性的作用是为JSP页面引入Java运行环境提供的包中的类。

<%@ page  import="java.io.*", "java.time.LocalDate" %>

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

<%@ page  import="java.io.*"  %>

JSP页面默认有import属性已经如下的值: " java.lang.*"、 "javax.servlet.*"、"javax.servlet.jsp.*"、"javax.servlet.http.*"。

(5) session属性

session 属性用于设置是否需要使用内置的session对象。session的属性值可以是true或false。session属性默认的属性值是true。

(6)buffer属性

内置输出流对象out负责将服务器的某些信息或运行结果发送到用户端显示。buffer属性用来指定out设置的缓冲区的大小或不使用缓冲区。

例如: <%@ page buffer= "24kb" %> buffer属性的默认值是8kb 。

(7) autoFlush属性

autoFlush可以取值true或false。autoFlush属性的默认值是true。

(8)isThreadSafe 属性

isThreadSafe的属性值可取true或false。

isThreadSafe属性值为true时,CPU的使用权在各个线程间快速切换.

isThreadSafe属性值设置成false时,该JSP页面同一时刻只能响应一个用户的请求,其他用户须排队等待。也就是说,CUP要保证一个线程将JSP页面执行完毕才会把CPU使用权切换给其他线程。

(9)info 属性

info属性的属性值是一个字符串,其目的是为JSP页面准备一个常用但可能要经常修改的字符串。

例如, <%@ page info= "we are students" %>

可以在JSP页面中使用方法:

getServletInfo(); 获取info属性的属性值。

include 指令标记

如果需要在JSP页面内某处整体嵌入一个文件,就可以考虑使用include指令标记,其语法格式如下: <%@ include file= "文件的URL " %>

■ 嵌入的文件的编码必须和当前JSP页面一致,比如二者都是utf-8编码。

■ 所谓静态嵌入,就是当前JSP页面和嵌入的文件合并成一个新的JSP页面,然后Tomcat服务器再将这个新的JSP页面转译成Java文件。因此,嵌入文件后,必须保证新合并成的JSP页面符合JSP语法规则,即能够成为一个JSP页面文件。

■include指令可以实现代码的复用。比如,每个JSP页面上都可能都需要一个导航条,以便用户在各个JSP页面之间方便地切换,那么每个JSP页面都可以使用include指令在页面的适当位置整体嵌入一个相同的文件。

■允许被嵌入的文件使用page指令指定contentType属性的值,但指定的值要与嵌入该文件的JSP页面中的page指令指定的contentType属性的值相同。

include 动作标记语法格式为: <jsp:include page= "文件的URL" /> 或 <jsp:include page= "文件的URL" >    param子标记 </jsp:include>

nclude动作标记告诉JSP页面动态包含一个文件,即JSP页面运行时才将文件加入。与静态嵌入文件的include指令标记不同,当Tomcat服务器根据JSP页面产生成Java文件时,不把JSP页面中动作指令include所包含的文件与原JSP页面合并为一个新的JSP页面,而是告诉Java解释器,这个文件在JSP运行(Java文件的字节码文件被加载执行)时才包含进来。

如果包含的文件是普通的文本文件,就将文件的内容发送到用户端,由用户端的浏览器负责显示;如果包含的文件是JSP文件,Tomcat服务器就执行这个文件,然后将执行的结果发送到用户端,并由用户端的浏览器负责显示这些结果。

param动作标记

param标记以“名字—值”对的形式为其他标记提供附加信息,它不能独立使用,必须作为jsp:include,jsp:forward的子标记使用。

<jsp:param  name= "参数"  value= " 参数的值" />

<%@ page contentType="text/html" %>
<%@ page pageEncoding = "utf-8" %>
<HTML><body  bgcolor=cyan >
<% double a=6.12,b=7.08,c=9.22;
%>
<p style="font-family:宋体;font-size:36">
<br>加载triangle.jsp计算三边为<%=a%>,<%=b%>,<%=c%>的三角形面积.
   <jsp:include page="/triangle.jsp">//注意放的位置
     <jsp:param name="sideA" value="<%=a%>"/>
     <jsp:param name="sideB" value="<%=b%>"/>
     <jsp:param name="sideC" value="<%=c%>"/>
   </jsp:include>
</p></body></HTML>

<%@ page contentType="text/html" %> 
<%@ page pageEncoding = "utf-8" %>
<%! public String getArea(double a,double b,double c) {
       if(a+b>c&&a+c>b&&c+b>a) {
           double p=(a+b+c)/2.0;
           double area=Math.sqrt(p*(p-a)*(p-b)*(p-c)) ;
           String result = String.format("%.2f",area);//保留两位小数
           return result;
       }
       else { 
          return(""+a+","+b+","+c+"不能构成一个三角形,无法计算面积");
       }
    }
%>
<%   String sideA=request.getParameter("sideA");
     String sideB=request.getParameter("sideB");
     String sideC=request.getParameter("sideC");
     double a=Double.parseDouble(sideA);
     double b=Double.parseDouble(sideB);
     double c=Double.parseDouble(sideC);
%>
<p style="font-family:黑体;font-size:36;color:blue">
<br><b>我是被加载的文件,负责计算三角形的面积<br>
    给我传递的三边是:<%=sideA%>,<%=sideB%>,<%=sideC%></b>
<br><b><i>三角形的面积(保留2位小数):<%= getArea(a,b,c)%></i></b></i>
</p>

 forward 动作标记

<jsp:forward page="要转向的页面" /> 或 <jsp:forward page="要转向的页面" >    param子标记 </jsp:forward>

指令的作用是:

从该指令处停止当前页面的执行,而转向执行page属性指定的JSP页面。需要注意的是,当前页面使用forward动作标记转向后,尽管用户看到了转向后的页面的效果,但浏览器地址栏中显示的仍然是转向前的JSP页面的URL地址,因此,栏如果刷新浏览器的显示,将再次执行当前浏览器地址中显示的JSP页面。

<%@ page contentType="text/html" %>  
<%@ page pageEncoding = "utf-8" %>  
<HTML><body>
<h1> 产生一个1-10之间的随机数
<%  double i=(int)(Math.random()*10)+1;
    if(i<=5) {
%>      <jsp:forward page="example2_12_a.jsp" >
            <jsp:param name="number" value="<%= i %>" />
        </jsp:forward> 
<%  }
    else {
%>     <jsp:forward page="example2_12_b.jsp" >
           <jsp:param name="number" value="<%= i %>" />
       </jsp:forward> 
<%  }
%>
</body></HTML>
 

<%@ page contentType="text/html" %>  
<%@ page pageEncoding = "utf-8" %>  
<HTML><body bgcolor=cyan>
<p style="font-family:宋体;font-size:36">
<% String s=request.getParameter("number");
    out.println("传递过来的值是"+s);
%>
<br><img src=/tomcat-power.gif width=300 height=280/>
</p></body></HTML>

<%@ page contentType="text/html" %>  
<%@ page pageEncoding = "utf-8" %>  
<HTML><body bgcolor=yellow>
<p style="font-family:宋体;font-size:36">
<% String s=request.getParameter("number");
    out.println("传递过来的值是"+s);
%>
<br><img src=/tomcat.gif width=300 height=280 />
</p></body></HTML>

Tag文件

Tag文件和JSP文件很类似,可以被JSP页面动态加载调用,实现代码的复用(但用户不能通过该Tag文件所在Web服务目录直接访问Tag文件)。 

 Tag文件是扩展名为.tag的文本文件,其结构和JSP文件类似。一个Tag文件中可以有普通的HTML标记符、某些特殊的指令标记(tag) 、成员变量声明和方法的定义、Java程序片和Java表达式。

Tag标记与Tag文件

<标记库名:Tag标记 参数。。。 /> 或 <标记库名:Tag标记> 其他内容(称为标体内容)</标记库名:Tag标记>

一个Tag文件对应着一个Tag标记,把全体Tag标记称之为一个自定义标记库或简称为标记库.

Tag标记的使用

JSP页在使用Tag标记来调用一个Tag文件之前,必须首先使用taglib指令标记引入该Web服务目录下的标记库,只有这样,JSP页面才可以使用Tag标记调用相应的Tag文件。

taglib指令的格式如下:

<%@ taglib tagdir="标记库的位置" prefix="前缀">

例如: <%@ taglib tagdir="/WEB-INF/tags" prefix="computer"%> 

引入标记库后,JSP页面就可以使用带前缀的Tag标记调用相应的Tag文件,其中的前缀由<taglib>指令中的prefix属性指定。例如JSP如下使用Tag标记调用相应的Tag文件: <computer:oddNumberSum />

Tag标记的运行原理

Tomcat服务器处理JSP页面中的Tag标记的原理如下:

(1)如果该Tag标记对应的Tag文件是首次被JSP页面调用,那么Tomcat服务器会将Tag文件转译成一个java文件,并编译这个java文件生成字节码文件,然后执行这个字节码文件(这和执行JSP页面的原理类似)。

(2)如果该Tag文件已经被转编译为字节码文件,Tomcat服务器将直接执行这个字节码文件。

(3)如果对Tag文件进行了修改,那么Tomcat服务器会重新将Tag文件转译成一个java文件,并编译这个java文件生成字节码文件,然后执行这个字节码文件。

类似于JSP文件中的page指令。Tag文件通过使用tag指令可以指定某些属性的值,<%@ tag 属性1="属性值" 属性2="属性值" …属性n="属性值"%> 在一个Tag文件中可以使用多个tag指令,因此我们经常使用多个tag指令为属性指定需要的值: <%@ tag 属性1="属性值"%> <%@ tag 属性2="属性值"%> …… <%@ tag 属性n="属性值"%>

language属性 。只能取值java,其默认值就是java,没有必要使用tag指令指定language属性的值。

import属性。import属性的作用是为Tag文件引入包中的类import属性默认已经有如下值:"java.lang.*"、 "javax.servlet.*"、"javax.servlet.jsp.*"、"javax.servlet.http.*"。  

pageEncoding属性。该属性指定Tag文件的字符编码,其默认值是ISO-8859-1。目前,为了避免显示信息出现乱码现象,Tag文件需要将该属性值设置为utf-8。

include指令

Tag文件中也有和JSP文件类似的include指令标记,其使用方法和作用与JSP文件中的include指令标记类似。

attribute指令

一个Tag文件允许使用它的JSP页面向该Tag文件传递数据。在Tag文件中通过使用attribute指令让使用它的JSP页面向该Tag文件传递需要的数据。

<%@ attribute name="对象名字" required="true"|"false" type="对象的类型"%> 例如Tag文件myTag.tag中有如下attribute指令: <%@ attribute name="result" required="true" type="java.lang.Double"%> 那么就相当于Tag文件中有了一个名字是result的对象,但Tag文件不需要创建该对象result,而是等待JSP页面将一个Double型的对象的引用传递给result。

JSP页面使用Tag标记向所调用的Tag文件中name指定的对象传递一个引用,方式如下: <前缀:Tag文件名字 对象名字="对象的引用" /> 比如,JSP页面使用Tag标记(假设标记的前缀为computer)调用myTag.tag: <computer:myTag  result= "new Double(3.1415926)" />

variable指令

Tag文件通过使用variable指令可以将Tag文件中的对象返回给调用该Tag文件的JSP页面。

<%@ variable name-given=“对象名" variable-class="对象的类型" scope="有效范围"%>

scope的值可以取:AT_BEGIN、NESTED和AT_END。

taglib指令

<%@ taglib tagdir="自定义标记库的位置" prefix="前缀"> 一个Tag文件也可以使用几个taglib指令标记引入若干个标记库,例如: <%@ taglib tagdir="/WEB-INF/tags" prefix="beijing"%> <%@ taglib tagdir="/WEB-INF/tags/tagsTwo" prefix="dalian"%

 JSP 内置对象

HTTP通信协议是用户与服务器之间一种提交(请求)信息与响应信息(request/response)的通信协议。在JSP中,内置对象request封装了用户提交的信息,那么该对象调用相应的方法可以获取封装的信息,即使用该对象可以获取用户提交的信息。 内置对象request是实现了ServletRequest接口类的一个实例,可以在Tomcat服务器的webapps\tomcat-docs\servletapi中查找ServletRequest接口的方法。

获取用户提交的信息

用户通常使用HTML的form表单: <form  action= "请求访问的页面或Servlet"  method= get | post  >     提交内容 </form>

<form action="tom.jsp" method= "post" >      <input type="text" name="boy" value= "ok" />      <input type="submit" name="submit" value="提交"/> </form>

获取用户提交的信息

request对象获取用户提交信息的最常用的方法是getParameter(String s)

<%@ page contentType="text/html" %>
<%@ page pageEncoding = "utf-8" %> 
<HTML><body bgcolor = #ffccff> 
   <form action="example4_1_computer.jsp" method=post >
       <input type="text" name="sizeA" value=9 size=6 />
       <input type="text" name="sizeB" value=8 size=6 /> 
       <input type="text" name="sizeC" value=8 size=6 />
       <input type="submit" name="submit" value="提交"/>
   </form> 
</body></HTML>
 

<%@ page contentType="text/html" %>
<%@ page pageEncoding = "utf-8" %> 
<HTML><body bgcolor = #ccffff>
<p style="font-family:黑体;font-size:36;color:blue">
<%  
    String sideA=request.getParameter("sizeA");
    String sideB=request.getParameter("sizeB");
    String sideC=request.getParameter("sizeC");
    try {  double a=Double.parseDouble(sideA);
           double b=Double.parseDouble(sideB);
           double c=Double.parseDouble(sideC);
           double p=(a+b+c)/2,area=0;
           area=Math.sqrt(p*(p-a)*(p-b)*(p-c));
           String result = String.format("%.2f",area);
           out.println("<BR>三边:"+sideA+","+sideB+","+sideC);
           out.println("<BR>三角形面积(保留2位小数):"+result);
    }
    catch(NumberFormatException ee){
          out.println("<BR>请输入数字字符");
    } 
%>
</p></body></HTML> 

 

 request对象获取用户提交信息的最常用的方法是getParameter(String s)

<%@ page contentType="text/html" %>
<%@ page pageEncoding = "utf-8" %> 
<%@ page import="java.util.regex.Pattern" %>
<%@ page import="java.util.regex.Matcher" %>
<style>
   #tom{
      font-family:宋体;font-size:22;color:blue 
   }
</style> 
<HTML><body id ="tom" bgcolor = #ffccff>
输入购物小票内容(显示的是默认内容):
<%
   String content = "牛奶:12.68元,面包:6.6元,"
                    +"苹果:28元,香皂:6.58元";
%>
<form  action =""  method="post" id ="tom">
   <textArea  name="shopping" rows=5 cols=32 id ="tom">
      <%= content %>
   </textArea>
   <input type="submit" id ="tom" name="submit" value="提交"/>
</form>  
<%   String shoppingReceipt=request.getParameter("shopping");
     if(shoppingReceipt==null) {
        shoppingReceipt="0";
     }
     Pattern pattern;          //模式对象
     Matcher matcher;          //匹配对象
     String regex="-?[0-9][0-9]*[.]?[0-9]*" ;//匹配数字,整数或浮点数的正则表达式。
     pattern = Pattern.compile(regex); //初试化模式对象。
     matcher =
     pattern.matcher(shoppingReceipt); //matcher检索shoppingReceipt。
     double sum = 0;
     while(matcher.find()) {
       String str = matcher.group(); 
       sum += Double.parseDouble(str);
     } 
     out.print("购物小票消费总额:"+sum);
%>
</body></HTML>
 

如果form表单中的action请求的页面是当前页面,可以用双引号""或单引号代替当前页面,即写成action=""或action ='',注意双引号或单引号中不能含有空格。也可省略action参数,即不显式写出action参数。

 String shoppingReceipt=request.getParameter("shopping"); 时得到的shoppingReceipt就是空对象。如果程序使用了空对象,Java解释器就会提示出现了NullPointerException异常。因此,在上述例子2中为了避免在运行时出现NullPointerException异常,使用了如下代码: String shoppingReceipt=request.getParameter("shopping"); if(shoppingReceipt==null) {          shoppingReceipt="0"; }

处理汉字信息

用户提交的信息中如果含有汉字字符或其他非ASCII字符的信息,就必须进行特殊的处理方式,防止出乱码现象。

处理汉字信息 JSP页面文件的编码为utf-8编码。 内置对象request在获取信息之前调用setCharacterEncoding方法设置编码为utf-8(默认是iso-8859-1)就可以避免乱码现象。

request.setCharacterEncoding("utf-8");

<%@ page contentType="text/html" %>
<%@ page pageEncoding = "utf-8" %> 
<style>
   #tom{
      font-family:宋体;font-size:26;color:blue 
   }
</style> 
<HTML><body id="tom" bgcolor = #ffccff>
可以输入各种语言的文字,单击提交键:
<%
   String content = "早上好,Good morning,อรุณสวัสดิ์ค่ะ(泰语),"+
                  " おはよう,Доброе утро,좋은 아침";
%>
<form  action="" method='post' >
   <textArea  name="language" id="tom" rows=3 cols=50>
      <%= content %>
   </textArea>
   <input type="submit" id="tom" name="submit" value="提交"/>
</form>  
<%   request.setCharacterEncoding("utf-8");
     String variousLanguages=request.getParameter("language");
     out.print(variousLanguages);
%>
</p></body></HTML>
 

 request的getParameter方法获取form表单提交的有关信息,但实际上,request对象调用相关方法可以获取请求的许多细节信息。内置对象request常用方法如下:

1) String getProtocol()  获取用户向服务器提交信息所使用的通信协议,比如http/1.1等。

2) String getServletPath()  获取用户请求的JSP页面文件的名字(带目录符号\,例如\hello.jsp)。

3) String getContextPath() 获取用户请求的当前Web服务目录(例如ch4)。

4) int getContentLength()  获取用户提交的整个信息的长度。

5) String getMethod()  获取用户提交信息的方式,比如:post或get.

6) String getRemoteAddr()  获取用户的IP地址。

7) String getRemoteHost()  获取用户机的名称(如果获取不到,就获取IP地址)。

8) String getServerName()  获取服务器的名称。

9) String getServerPort()  获取服务器的端口号。

<%@ page contentType="text/html" %>
<%@ page pageEncoding = "utf-8" %> 
<HTML><body bgcolor = #ffccff>
<p style="font-family:宋体;font-size:36;color:blue"> 
   <% request.setCharacterEncoding("utf-8");
      String jsp=request.getServletPath();    //请求的JSP页面
      jsp = jsp.substring(1); //去掉JSP页面名称前面的目录符号/
      String webDir = request.getContextPath();//获取当前Web服务目录的名称
      webDir = webDir.substring(1); //去掉Web服务目录的名称前面的目录符号/
      String  clientIP=request.getRemoteAddr();//用户的IP地址
      int serverPort=request.getServerPort(); // 服务器的端口号
      out.print("<br>shenme:"+request.getServerName());
    %> 
用户请求的页面:<%= jsp %>
<br>Web服务目录的名字:<%= webDir %>
<br>用户的IP地址:<%= clientIP %>
<br>服务器的端口号:<%= serverPort %>
</p></body></HTML>

处理HTML标记(不区分大小写)

input标记

<input type="GUI对象" name= "GUI对象的名子" value="GUI中的默认值"/>

Tom服务器的内置对象request通过name指定的名字来获取GUI对象中提交的数据

(1)文本框text <input type="text" name="m" value="h" size="8" algin="left" maxlength="9"/> 如果用户没有在text输入任何信息,就单击form表单中的submit提交键,request对象调用getParameter方法将获取由value指定的默认值(text中显示的默认值),如果value未指定任何值,getParameter方法获取的字符串的长度为0,即该字符串为""。

(2)单选框radio <input type="radio" name="hi" value="男" algin= "top" checked="ok" />男生 <input type="radio" name="hi" value="女" algin= "top"  />女生 其中value指定radio的值,如果几个单选键的name取值相同,那么同一时刻只能有一个被选中。 request对象调用getParameter方法获取被选中的radio中value属性指定的值。checked如果取值是一个非空的字符串,那么该单选框的初始状态就是选中状态。   <input type="radio" name="R" value="on" />打开   <input type="radio" name="R" value="off" checked="default">关闭

 (3)复选框checkbox <input type="checkbox" name= "item" value="A"  algin= "top" checked="ok" />足球 <input type="checkbox" name= "item" value="B"  algin= "top"  />围棋 <input type="checkbox" name= "item" value="C"  algin= "top" checked="ok" />乒乓球 <input type="checkbox" name= "item" value="D"  algin= "top"  />篮球 其中value指定checkbox的值。复选框与单选框的区别就是可以多选,即如果几个checkbox的name取值相同,那么同一时刻可有多个chekbox被选中。这时,request对象需调用getParameterValues方法(不是getParameter方法)获取被选中的多个checkbox中value属性指定的值。checked如果取值是一个非空的字符串,那么该复选框的初始状态就是选中状态。

(4)口令框password <input type= "password"  name= "me"  size= "12"  maxlength="30" /> 用户在口令框中输入tiger,单击提交键,tiger将被提交给form表单请求的页面,请求的页面的内置对象request调用getParameter方法获取password提交的值tiger(password仅仅起着不让别人偷看的作用,不提供加密措施)。

(5)隐藏hidden <input type= "hidden"  name="nogui"  value= "hello"  /> 用户单击form表单中的submit提交键,那么form表单所请求的页面的内置对象request调用getParameter方法将获取由value指定的值hello。

(6)提交键submit 为了能把form表单的数据提交给服务器,一个form表单至少包含一个提交键(可以有多个提交键,见稍后的例子10),例如: <input type= "submit"  name="me"  value="确定"  size="12"  /> 单击提交键后,form表单请求的页面才有机会获取form表单提交的各个数据。

(7)重置键:reset 重置键将表单中输入的数据清空,以便重新输入数据,例如: <input type="reset" value="重置"/>

<%@ page contentType="text/html" %>
<%@ page pageEncoding = "utf-8" %> 
<style>
   #tom{
      font-family:宋体;font-size:26;color:blue 
   }
</style> 
<HTML><body id="tom" bgcolor = #ffccff>
<form action="example4_5_receive.jsp" method=post id=tom>
   密码:<input type= "password"  name= "me"  size= "12"  maxlength="30" />

  <br>音乐:
  <input type="radio" name="R" value="on" />打开 
  <input type="radio" name="R" value="off" checked="default">关闭 
<br>哪些是奥运会项目:<br> 
  <input type="checkbox" name= "item" value="A"  algin= "top"  />足球
  <input type="checkbox" name= "item" value="B"  algin= "top"  />围棋
  <input type="checkbox" name= "item" value="C"  algin= "top"  />乒乓球
  <input type="checkbox" name= "item" value="D"  algin= "top"  />篮球
  <input type="hidden" value="我是球迷,但不会踢球" name="secret"/>
  <br><input type="submit" id="tom" name="submit" value="提交"/>
  <input type="reset" id="tom" value="重置" />
</form> 
</body></HTML>
 

<%@ page contentType="text/html" %>
<%@ page pageEncoding = "utf-8" %> 
<%@ page import  = "java.util.Arrays" %> 
<%! public boolean isSame(String []a,String [] b){
         Arrays.sort(a); 
         Arrays.sort(a);
         return Arrays.equals(a,b);
    }
%>
<HTML><body bgcolor = white >
<p style="font-family:宋体;font-size:36;color:blue"> 
<%   String answer[] = {"A","C","D"};
     request.setCharacterEncoding("utf-8");  
     String onOrOff=request.getParameter("R"); //获取radio提交的值
     String secretMess=request.getParameter("secret");//获取hidden提交的值
     String itemName[]=request.getParameterValues("item"); //获取checkbox提交的值
     out.println("<br> 是否打开音乐:"+onOrOff);
     out.println("<br> 您的答案:");
     if(itemName==null) {
          out.print("没给答案");
     } 
     else {
         for(int k=0;k<itemName.length;k++) {
           out.print(" "+itemName[k]);
         }
         if(isSame(itemName,answer)){
           out.print("<br>回答正确。");
         }
     }
     out.println("<br> 提交的隐藏信息:"+secretMess);
     if(onOrOff.equals("on")) {
%>       <br><embed src="sound/back.mp3" />
<%   } 
%>
</p></body></HTML>
 

 select、option标记(下拉列表或滚动列表)

Tom服务器的内置对象request通过name指定的名字来获取GUI对象中提交的数据.

<select  name="myName">   <option  value="item1">文本描述</option>   <option  value="item2">文本描述</option>    … … </select>

 <%@ page contentType="text/html" %>
<%@ page pageEncoding = "utf-8" %>
<style>
   #tom{
      font-family:宋体;font-size:26;color:blue 
   }
</style> 
<%   String music = request.getParameter("music");
     String pic = request.getParameter("pic");
     String onOrOff=request.getParameter("R"); 
     if(music==null) music = "";
     if(pic==null)   pic = "";
     if(onOrOff==null) onOrOff = "off";
%>
<HTML><body id=tom background="image/<%= pic %>" >
<form action=""  method=post >
   <b>选择音乐:<br>
   <select id=tom name="music" >
      <Option selected value="back1.mp3">绿岛小夜曲</option>
      <Option value="back2.mp3">我是一片云</option>
      <Option value="back3.mp3">红河谷</option>
   </select> 
   <input type="radio" name="R" value="on" />打开 
   <input type="radio" name="R" value="off" />关闭 
   <br><b>选择背景图像:<br>
   <select id=tom name="pic" size = 2>
      <option value="back1.jpg">荷花图</option>
      <option value="back2.jpg">玫瑰图</option>
      <option value="back3.jpg">校园图</option>
   </select> <br> 
   <input id=tom type="submit"  name="submit" value="提交"/>
</form> 
<%   if(onOrOff.equals("on")) {
%>       <br><embed src="sound/<%= music %>" height=50 />
<%   } 
%>
</body></HTML> 

textArea标记

Tom服务器的内置对象request通过name指定的名字来获取GUI对象中提交的数据.

<textArea  name="名字"  rows= "文本可见行数"  cols= "文本可见列数" >   提交或显示的数据 </textArea>

style样式标记

style标记可用于定义HTML其他标记中的字体样式,如,style标记给出样式:

<style>    

#textStyle{       font-family:宋体;font-size:18;color:blue    }    

#tom{       font-family:黑体;font-size:16;color:black    }

</style>

其中,#字符之后的字符序列是样式名称,例如#textStyle给出的样式名称是textStyle(起一个自己喜欢且容易理解的名字),其它html标记可以让其id属性值是样式名称来使用这个样式。例如,段落标记p就可以如下使用textStyle样式:

table标记(主要用于显示数据,不能提交数据)

<table  border ="边框的宽度">    

<tr  width="该行的宽度">        

<th  width="单元格的宽度" >单元格中的数据</th>  

       …         <td  width= "单元格的宽度" >单元格中的数据</td> …    

</tr> … …. </table>

<%@ page contentType="text/html" %>
<%@ page pageEncoding = "utf-8" %>
<style>
   #textStyle{
      font-family:宋体;font-size:28;color:blue 
   }
</style> 
<HTML><body id = textStyle bgcolor = #ffccff>  
<form action="example4_7_showCalendar.jsp" method=post >
输入日期的年份选择月份查看日历.<br>
年份:<input type="text" name="year" id = textStyle value=2022 size=12 />
月份 <select name="month" id = textStyle size =1>
  <option value="1">1月</option>
  <option value="2">2月</option>
  <option value="3">3月</option>
  <option value="4">4月</option>
  <option value="5">5月</option>
  <option value="6">6月</option>
  <option value="7">7月</option>
  <option value="8">8月</option>
  <option value="9">9月</option>
  <option value="10">10月</option>
  <option value="11">11月</option>
  <option value="12">12月</option>
</select><br>  
<input type="submit" id = textStyle value="提交"/>
</form> 
</body></HTML>

<%@ page import="java.time.LocalDate" %>
<%@ page import="java.time.DayOfWeek" %>
<%
    request.setCharacterEncoding("utf-8");  
    String year=request.getParameter("year"); 
    String month=request.getParameter("month");
    int y = Integer.parseInt(year);
    int m = Integer.parseInt(month);
    LocalDate date = LocalDate.of(y,m,1);
    int days = date.lengthOfMonth(); //得到该月有多少天。
    int space = 0;                   //存放空白字符的个数
    DayOfWeek dayOfWeek = date.getDayOfWeek(); //得到1号是星期几
    switch(dayOfWeek) {
          case SUNDAY:    space = 0;
                          break;
          case MONDAY:    space = 1;
                          break;
          case TUESDAY:   space = 2;
                          break;
          case WEDNESDAY: space = 3;
                          break;
          case THURSDAY:  space = 4;
                          break;
          case FRIDAY:    space = 5;
                          break;
          case SATURDAY:  space = 6;
                          break;
   }
   String [] calendar = new String[space+days]; //用于存放日期和1号前面的空白
   for(int i=0;i<space;i++)
       calendar[i]="--";
   for(int i = space,n=1;i<calendar.length;i++){
       calendar[i] = String.valueOf(n) ;
       n++;
   }  
%>
<HTML><body bgcolor = #ffccff>
<h3> <%=year %>年<%=month %>月的日历:</h3>
<table  border=0>
  <tr><th>星期日</th><th>星期一</th><th>星期二</th><th>星期三</th>
      <th>星期四</th><th>星期五</th><th>星期六</th>
  </tr>
<% 
   int n = 0;
   while(n<calendar.length){
       out.print("<tr>");
       int increment = Math.min(7,calendar.length-n);
       for(int i=n;i<n+increment;i++) {
         out.print("<td align= center>"+calendar[i]+"</td>");
       }
       out.print("</tr>");
       n = n+increment;
   }
%> 
</table></body></HTML>
 

<image>标记

不能用于提交数据,用于显示图像。 <image  src="图像文件的URL" >描述文字</image>

embed标记

不能用于提交数据。使用embed标记可以播放音乐和视频,当浏览器执行该标记时,会把浏览器所在机器上的默认播放器嵌入到浏览器中,以便播放音乐或视频文件。embed标记的基本格式为: <embed  src="音乐或视频文件的URL" >描述文字</embed > 或 <embed  src="音乐或视频文件的URL" />

属性值格式的说明

许多HTML标记的中都有属性,并指定属性的值,例如: <input type="text" name="testAmount" value=10 /> 中的type,name ,value都是input标记的属性, 属性值可以用双引号括起, 也可以用单引号括起, 或者不用任何符号.      比如type属性的值可以用双引号括起"text",也可以用单引号括起'text'或者不用任何符号text,一个好的习惯是用单引号括起。 例如,下列超链接标记中的href的属性值用单引号括起。 <a href = ’example4_1.jsp’>超链接</a>

处理超链接

超链接标记 <a href=链接的页面地址 >文字说明</a> 是一个常用标记。例如: <a href ="example4_9_receive.jsp>购买</a> 用户单击超链接标记的文字说明,可以访问超链接给出的链接页面。

使用超链接标记时还可以增加参数,以便向所链接的页面传递值,格式如下: <a href=链接的页面地址?参数1=字符串1&参数2=字符串2… >文字说明</a> 例如: <a href ="example4_9_receive.jsp?id=A1001&price=8765">购买</a> 超链接所链接的页面,使用request调用getParameter("参数")获得超链接的参数传递过来的参数的值,即字符串。例如: String idStr = request.getParameter("id"); 需要注意的是,超链接标记向所链接的页面传递的参数的值,即字符串中不允许含有非ASCII字符(例如汉字等)。

动态响应contentType属性

■页面用page指令设置页面的contentType属性的值,那么Tomcat服务器将按着这种属性值作出响应,将页面的静态部分返回给用户,用户浏览器接收到该响应就会使用相应的手段处理所收到的信息。

■page指令只能为contentType指定一个值来决定响应的MIME类型,如果想动态的改变这个属性的值来响应用户,就需要使用response对象的setContentType(String s)方法来改变contentType的属性值

■当用setContentType(String s)方法动态改变了contentType的属性值,即响应的MIME类型,Tomcat服务器就会按着新的MIME类型将JSP页面的输出结果返回给用户。

session对象

Tomcat服务器可以使用内置session对象(会话)记录用户的信息。内置对象session由Tomcat服务器负责创建。

■当一个用户首次访问web服务目录中的一个JSP页面时,Tomcat服务器产生一个session对象,这个session对象调用相应的方法可以存储用户在访问该web服务目录中各个页面期间提交的各种信息。

■这个session对象被分配了一个String类型的id号,Tomcat服务器同时将这个id号发送到用户端,存放在用户(浏览器)的Cookie中。这样,session对象和用户之间就建立起一一对应的关系,即每个用户都对应着一个session对象(称作用户的会话),不同用户(不同浏览器)的session对象互不相同,具有不同的id号码。

■当用户再访问该Web服务目录的其它页面时,Tomcat服务器不再分配给用户的新session对象,而是使用完全相同的一个,直到session对象达到了最大生存时间或用户关闭自己的浏览器或Tomcat服务器关闭,Tomcat服务器将销毁用户的session对象

★简单地说,用户(浏览器)在访问一个Web服务目录期间,服务器为该用户分配一个session对象(称作和该用户的会话),服务器可以在各个页面使用这个session记录当前用户的有关信息。而且服务器保证不同用户的session对象互不相同。 注--- 同一个用户在不同的Web服务目录中的session是互不相同的。

application对象

1)public void setAttribute(String  key ,Object  obj)。application对象可以调用该方法将参数Object 指定的对象 obj添加到application对象中,并为添加的对象指定了一个索引关键字,如果添加的两个对象的关键字相同,则先前添加对象被清除。

2)public Object getAttibute(String key)。获取application对象含有的关键字是key的对象。由于任何对象都可以添加到application对象中,因此用该方法取回对象时,应显式转化为原来的类型。

out对象

out对象是一个输出流,用来向用户端输出数据。在前面的许多例子里曾多次使用out对象进行数据的输出。out对象可调用如下的方法用于各种数据的输出, 例如: out.print(boolean)或out.println(boolean) 用于输出一个布尔值。 out.print(char) 或out.println(char) 输出一个字符。 out.print(double) 或out.println(double)输出一个双精度的浮点数。 out.print(float) 或out.println(float)用于输出一个单精度的浮点数。 out.print(long) 或out.println(long)输出一个长整型数据。 out.print(String) 或out.println(String)输出一个String对象的字符序列。 方法println和print的区别是:println会向缓存区写入一个换行,而print不写入换行。但是浏览器的显示区域目前不识别println写入的换行,如果希望浏览器显示换行,应当向浏览器写入"<br>"实现换行。

编写Javabean

编写Javabean就是编写一个Java的类,所以只要会写类就能编写一个Javabean。这个类创建的一个对象称为一个Javabean,简称bean,分配给bean的变量(成员变量),也称bean的属性。为了能让使用bean的应用程序构建工具(比如Tomcat服务器)使用JSP动作标记知道bean的属性和方法,只须在类的方法命名上遵守以下规则:

(1)如果类的成员变量,也称bean的属性的名字是xxx,那么为了获取或更改bean的属性的值,类中必须提供两个方法: getXxx(),用来获取属性xxx。 setXxx(),用来修改属性xxx.。 也就是方法的名字用get或set为前缀,后缀是将属性(成员变量)名字的首字母大写的字符序列。

(2)类中定义的方法的访问权限都必须是public的。

(3)类中定义的构造方法必须是public、无参数的。

getProperty动作标记

使用getProperty动作标记可以获得bean的属性值,并将这个值用串的形式发送给用户的浏览器。 <jsp:getProperty  name="bean的id " property="bean的属性" /> 或 <jsp:getProperty  name="bean的id "  property="bean的属性"> </jsp:getProperty> 其中,name取值是bean的id,用来指定要获取哪个bean的属性的值,property取值是该bean的一个属性的名字。 当JSP页面使用getProperty标记获取属性xxx的值时,必须保证bean有相应的getXxx方法,即对方法的名字的命名有特殊的要求。

让request调用setCharacterEncoding方法设置编码为utf-8,以避免显示bean的属性值出现乱码现象。

setProperty动作标记

(1)将bean属性的值设置为一个表达式的值或字符序列。 <jsp:setProperty name="bean的id " property="bean的属性"                                                                   value= "<%=expression%>"/> <jsp:setProperty name="bean的id " property="bean的属性"                                                                   value= "字符序列" /> value给出的值的类型要和bean的属性的类型一致。

(2)通过HTTP表单的参数的值来设置bean的相应属性的值。 ● 用form表单的所有参数的值设置bean相对应的属性值的使用格式如下: <jsp:setProperty  name= "bean的id的名字"  property="*" /> 在setProperty标记的上述用法中不具体指定bean属性的值将对应form表单中哪个参数指定的值,系统会自动根据名字进行匹配对应,但要求bean属性的名字必须在form表单中有名称相同的参数名字相对应,Tomcat服务器会自动将参数的字符串值转换为bean相对应的属性的值 ● 用form表单的某个参数的值设置bean的某个属性值的使用格式如下: <jsp:setProperty  name= "bean的名字"  property="属性名"  param= "参数名" /> setProperty标记的上述用法具体指定了bean属性的值将对应表单中哪个参数名(param)指定的值,这种设置bean的属性值的方法,不要求property给出的bean属性的名字和param给出的参数名一致,即不要求bean属性的名字必须和表单中某个参数。

Java Servlet基础

有些Web应用可能只需要JSP+Javabean就能设计得很好,但是有些Web应用,就可能需要JSP+Javabean+servlet来完成,即需要服务器再创建一些servlet,配合JSP页面来完成整个Web应用程序的工作。

Servlet类

写一个创建servlet的类就是编写一个特殊类的子类,这个特殊的类就是javax.servlet.http包中的HttpServlet类。HttpServlet实现了Servlet接口,实现了响应用户的方法(这些方法将在后续内容中讲述)。HttpServlet的子类被习惯地称作一个Servlet类,这样的类创建的对象习惯地被称作一个servlet。

编写部署文件web.xml

■Servlet类的字节码文件保存到指定的目录后,必须为Tomcat服务器编写一个部署文件,只有这样,Tomcat服务器才会用Servlet类创建servlet对象。

■部署文件是一个XML文件,名字必须是web.xml。

■web.xml由Tomcat服务器负责管理,Tomcat服务器配有内置的解析器,可以解析XML文件的标记中的数据。

■编写的web.xml文件必须保存到Web服务目录的WEB-INF子目录中

★Web服务目录的WEB-INF子目录下的web.xml文件负责管理当前Web服务目录下的全部servlet,当该Web服务目录需要提供更多的servlet时,只要在web.xml文件中增加servlet和servlet-mapping子标记即可。

★对于webapps下的Web服务目录,如果修改并重新保存web.xml文件,Tomcat服务器就会立刻重新读取web.xml文件,因此,修改web.xml文件不必重新启动Tomcat服务器。但是,如果修改导致web.xml文件出现错误,Tomcat服务器就会关闭当前Web服务目录下的所有servlet的使用权限。所以必须保证web.xml文件正确无误,才能成功启动Tomcat服务器。但是,对于不是webapps下的Web服务目录,如果新建或修改了相应的web.xml文件,需要重新启动Tomcat服务器。

servlet的创建与运行

■用户就可以根据web.xml部署文件来请求Tomcat服务器创建并运行一个servlet

■如果Tomcat服务器没有名字为hello的servlet,就会根据web.xml文件中servlet标记的子标记servlet-class指定的Servlet类创建一个名字为hello的servlet。因此,如果名字是hello的servlet被创建之后,又修改Java源文件、编译得到新的Servlet类,并希望Tomcat服务器用新的Servlet类创建servlet,那么就要重新启动Tomcat服务器。根据6.1.2中的web.xml文件,用户需在浏览器输入: http://127.0.0.1:8080/ch6/lookHello 请求Tomcat服务器运行名字是hello的servlet。

 servlet 对象的生命周期

servlet由Tomcat服务器负责创建并完成初始化工作。当多个用户请求一个servlet时,服务器为每个用户启动一个线程。 一个servlet的生命周期主要有下列三个过程组成: (1) servlet第一次被请求加载时,服务器创建servlet,servlet调用init方法完成必要的初始化工作。 (2) 新诞生的servlet再调用service方法响应用户的请求。 (3) 当服务器关闭时,调用destroy方法销毁servlet。 init方法只被调用一次。当后续的用户请求servlet服务时,Tomcat服务器将启动一个新的线程,在该线程中,servlet调用service方法。也就是说,每个用户的每次请求都导致service方法被调用执行,其执行过程分别运行在不同的线程中。

init方法

public void init(ServletConfig  config) throws ServletException servlet第一次被请求加载时,服务器创建一个servlet,这个对象调用init方法完成必要的初始化工作。该方法在执行时,服务器会把一个SevletConfig类型的对象传递给init()方法,这个对象就被保存在servlet中,直到servlet被销毁。

service方法

public void service(HttpServletRequest request  HttpServletResponse  response)throw ServletException,IOException Tomcat服务器将两个参数传递给该方法。和init方法不同的是,init方法只被调用一次,而service方法可能被多次的调用。当后续的用户请求该servlet时,Tomcat服务器将启动一个新的线程,在该线程中servlet调用service方法响应用户的请求,调用过程运行在不同的线程中,互不干扰。因此,不同线程的service方法中的局部变量互不干扰,一个线程改变了自己的service方法中局部变量的值不会影响其他线程的service方法中的局部变量。

destroy方法

public destroy() 当Tomcat服务器终止服务时,destroy()方法会被执行,销毁servlet.子类可直接继承这个方法,一般不需要重写。

共享变量

■Servlet类是HttpServlet的一个子类,在编写子类时就可以声明某些成员变量,那么,请求servlet的用户将共享该servlet的成员变量。

■service方法可能被多次的调用。也就是说,当后续的用户请求该servlet时,Tomcat服务器将启动一个新的线程,在该线程中servlet调用service方法响应用户的请求,即每个用户的请求都导致service方法被调用执行,调用过程运行在不同的线程中,互不干扰。因此,不同线程的service方法中的局部变量互不干扰,一个线程改变了自己的service方法中局部变量的值不会影响其他线程的service方法中的局部变量。

doGet和doPost方法

■HttpServlet类除了init、service、destroy方法外,该类还有两个很重要的方法:doGet和doPost,用来处理用户的请求并作出响应。

■实际上HttpServlet类所给出的service方法的功能是检查HTTP请求类型(get、post),并在service方法中根据用户的请求方式,在service方法中对应地再调用doGet或doPost方法。

■因此,在编写的Servlet类(HttpServlet类的一个子类)时,也可以不重写service方法来响应用户,直接继承service方法即可。

■如果不重写service方法,就需要在Servlet类中重写doPost或doGet方法来响应用户的请求。如果不论用户请求类型是post还是get,Tomcat服务器的处理过程完全相同,那么可以只在doPost方法中编写处理过程,而在doGet方法中再调用doPost方法即可,或只在doGet方法中编写处理过程,而在doPost方法中再调用doGet方法。如果根据请求的类型进行不同的处理,就要在两个方法中编写不同的处理过程(这一点比service方法更为灵活)

重定向与转发

重定向的功能是将用户从当前页面或servlet定向到另一个JSP页面或servlet。转发的功能是将用户对当前JSP页面或servlet的请求转发给另一个JSP页面或servlet。本节学习在Servlet类中使用HttpServletResponse类的sendRedirect重定向方法,以及RequestDispatcher类的forward转发方法,并指出二者的区别。

sendRedirect方法

重定向方法void sendRedirect(String location) 将用户重新定向到另一个JSP页面或servlet。重定向方法仅仅是将用户从当前页面或servlet定向到另一个JSP页面或servlet,但不能将用户对当前页面或servlet的请求(HttpServletRequest对象)转发给所定向的资源。即重定向的目标页面或servlet无法使用request获取用户提交的数据。

执行sendRedirect方法(重定向,也见4.2.3)时,Tomcat服务器还是要把当前的servlet代码执行完毕后才实施重定向(跳转)操作,但Tomcat服务器不再给用户看当前servlet代码的执行效果。如果在执行sendRedirect(URL url)方法后,servlet紧接着执行了return返回语句,那么Tomcat服务器会立刻结束当前servlet的执行。

forward方法

⑴   RequestDispatcher dispatcher =   request.getRequestDispatcher(JSP页面的URL或servlet的url-pattern); 例如: RequestDispatcher dispatcher = request.getRequestDispatcher("target.jsp");

⑵ 转发。在步骤(1)中获取的RequestDispatcher对象调用 void forward(ServletRequest request,ServletResponse response)             throws ServletException,ava.io.IOException 方法可以将用户对当前JSP页面或servlet的请求转发给RequestDispatcher对象所指定的JSP页面或servlet,例如: dispatcher.forward (request,response); 把用户对当前JSP页面或servlet的请求转变为对转发到的JSP页面或servlet的请求。

RequestDispatcher对象可以把用户对当前JSP页面或servlet的请求转发给另一个JSP页面或servlet,而且将用户对当前JSP页面或servlet的请求传递给转发到的JSP页面或servlet。也就是说,当前页面所转发到的标页面或servlet可以使用request获取用户提交的数据。

二者的区别

■转发(forwar)和重定向方法(sendRedirect)不同的是,用户可以看到转发到的JSP页面或servlet的运行效果,但是,在浏览器的地址栏中不能看到forward方法转发到的JSP页面的地址或servlet的地址,用户在浏览器的地址栏中所看到的仍然是当前JSP页面的URL或servlet的url-pattern。如果此时刷新浏览器,那么请求将是当前的JSP页面或servlet。所转发到的标页面或servlet可以使用request获取用户提交的数据。而重定向的目标页面或servlet无法使用request获取用户提交的数据。

■另外,当servlet中执行forward方法实施转发操作时,Tomcat会立刻结速当前servlet的执行。而servlet中执行sendRedirect方法(重定向,也见4.2.3)时,Tomcat服务器还是要把当前的servlet代码执行完毕后才实施重定向(跳转)操作,但Tomcat服务器不再给用户看当前servlet代码的执行效果。如果在执行sendRedirect(URL url)方法后,servlet紧接着执行了return返回语句,那么Tomcat服务器会立刻结束当前servlet的执行

猜你喜欢

转载自blog.csdn.net/weixin_46601374/article/details/125439209
jsp