一、JSP(java server pages) 介绍
JSP是一项开发动态网络应用的技术,属于java EE 组件;
具有以下几个特点:
能够在任何web 应用服务器上运行;
能够将程序逻辑和页面显示分开开发;
采用标签简化页面开发;
组件可重用(javaBean),即允许访问组件;
二、JSP的常用实践
不管是JSP还是Servlet,虽然都可以用于开发动态web资源,但是由于这两门技术各自的特点,在长期的软件实践中,
人们逐渐把servlet作为web应用中的控制器组件来使用,
而把JSP技术作为数据显示模板来使用。
原因在于,程序的数据通常要美化后再输出。让JSP既用java代码产生动态数据,又做美化会导致页面难以维护;
让Servlet既产生数据,又在里面嵌套html代码美化数据,同样也会导致程序可读性差,难以维护;
因此最好的办法就是让Servlet负责相应请求产生的数据,并把数据通过转发技术带给JSP,JSP用来做数据的显示。
三、JSP的组成
JSP由五个部分组成:
1. HTML页面内容
2. JSP注释(<!-- 这部分会在客户端页面显示的注释-->
,<%--这部分不会在客户端显示--%>
)
3. JSP指令(page指令<%@page 属性1=“属性值1” 属性2=“属性值2”%>
,include指令,taglib指令)
4. JSP脚本元素(申明语句,表达式,JSP Scriptlet)来使用Java语言
5. JSP动作元素
四、JSP的原理
JSP处理过程:JSP源文件处理分成二个阶段:
1) JSP页面转译阶段:
服务器首先将JSP翻译为一个Servlet(_jsp.java),翻译过后的Servlet可以在\tomcat主目录\work\Catalina\localhost\工程名\org\apache\jsp目录下查看,这是服务器的工作目录。打开相应的Servlet可以看到,翻译过后的servlet继承了org.apache.jasper.runtime.HttpJspBase,而HttpJspBase继承了HttpSerrvlet。说到这里,我们就明白了,其实JSP就是一个Servlet,访问jsp即访问一个Servlet。
浏览JSP翻译过后的Servlet,里面有个service方法_jspService(request, response),在该方法中可以看到,JSP中的所有内容都会翻译到service方法中,html代码会通过out输出,就像学习JSP之前,在Servlet中用out输出html语句一样,java部分代码会原封不动的搬到service方法中。
此时JSP页面被编译成一个Java类,所有的HTML标记和JSP标记都被转换创建一个Servlet。这时,脚本和表达式还没有被执行;
2) 请求处理阶段:发生在服务器,将一个客户端请求指向JSP页面。一个请求对象创建、解析以及提交给编译好的JSP对应的servlet。
当这个servlet处理请求的时候它执行先前在JSP中定义的处理脚本小程序和表达式
如果该JSP页面为第一次执行,那么会经过这两个阶段,而如果不是第一次执行,那么将只会执行请求阶段。这也是为什么第二次执行JSP页面时明显比第一次执行要要快的原因。
如果修改了JSP页面,那么服务器将发现到该修改,并重新执行转译阶段和请求阶段。这也是为什么修改页面后访问速度变慢的原因。
五、JSP语法
基本语法
一、JSP的声明(statement)
用来定义在产生的类文件中的类的属性和方法(成员变量)。可声明类(即是内部类)。
由于servlet是工作在多线程环境下,所以尽量不要在service方法体外声明成员变量。
<%!.....%> //声明时要加"!",属于类成员,最先加载,可写于任何位置;不加则是脚本的局部变量,必须调用前写。
如:
<%!String hello="Hello, World!";%> //变量的声明
<%=hello%> //变量的调用
<%! private int counter=0; public int count(){ return ++counter;} %> //函数的声明
<h1><%=count()%></h1> //函数的调用
声明规则:
1) JSP中声明的变量和方法对应于Servlet中的实例方法和实例变量。这些将被同时请求该页面的所有用户所共享;
2) 在使用变量或方法前须先定义(不是说声明变量的位置在页面中要处于使用变量的前面,而是指变量不声明不能使用);
3) 声明的变量或方法的作用域为当前页面或包含的页面;
4) 语句间以分号分隔。
二、JSP代码段(Scriptlet)
<% java代码 %>
是一段可以在处理请求时间执行的Java代码。可以产生输出,也可以是一些流程控制语句。
在代码段中定义的变量为service方法中的局部变量。
1._jspService()中的局部代码:
<% System.out.println("Hi,I like JSP."); %> //在控制台打印出,网页上没显示
<% out.println("Hi,I like JSP."); %> //打印在网页上
<% Connection conn=DriverManager.getConnection(); Statement st=conn.createStatement();
String sql="select * from users";
ResultSet rs=st.executeQuery(sql);
//……
%>
问:能否在JSP脚本里定义方法?答:不能!
//脚本相当于方法,不能在方法里定义方法
<%!public void helloworld(){}%> //可以声明方法
<% public void helloworld(){}%> //编译出错;脚本不能定义方法
2.比较:
<%! int i=100;%> //成员变量
<% int i=101;%> //_jspService()方法中的局部变量
<%=i%> //同一文件里,局部变量优先
3.脚本小程序规则:1) 你使用的脚本语言决定了脚本小程序的规则;
2) 语句间以分号分隔;
3) 可以使用默认的对象、import进的类、declaration声明的方法和对象以及useBean tag中声明的对象。
三、JSP表达式(expression)
<%=……%> // "="号
在JSP请求处理阶段计算他的值,表达式生成的代码是Service方法中的一个代码片断。
JSP对于声明的处理:1、计算表达式的值
2、将值转换成String
3、用out.println发送标签;把数据输出至页面的当前位置
<%="Hello,JSP world!"%> //out.println("Hello,JSP world");
<%=name%> //<%!String name="GiGi";%> out.println(name);
<%=new java.util.Date()%> //out.println(new java.util.Date());
表达式规则:
1) 你使用的脚本语言决定了脚本小程序的规则;
2) 执行的顺序为从左到右;
3) 分号不能用于表达式。
四、JSP指令(direction)
指令用于从JSP发送信息到容器上。用来设置全局变量,声明类,要实现的方法和输出内容等。
指令在JSP整个文件内有效。它为翻译阶段提供了全局信息。
<%@......%> // "@"符号
指令包括:page、include、taglib
1.page指令
import、session、errorPage、isThreadSafe
页面的语言、内容类型、字符集、页面编码
<%@page language="java" contentType="text/html; charset=gbk" pageEncoding="gbk"%>
language:java唯一值,表示脚本中使用的编程语言
contentType:设置了内容的类型和静态页面的编码 (告诉浏览器以什么编码显示)
pageEncoding:页面本身的编码格式 (写页面时用的编码格式)
上面的代码等价于servlet里: response.setContentType("text/html; charset=gbk");
import:导入其他的包和类; 其中,JSP默认导入的包是java.lang.*
<%@page import="java.util.Date"%> //具体的包和类
<%@page import="java.sql.*"%> //包下的所有类
<%@page import="java.util.*, java.io.*, java.net.*"%> //连写,逗号分隔
Session:指示当前的jsp是否参与会话 (默认为true; 参与会话)
通过指令使当前页面与session不可会话: <%@page session="false"%>
session="true"时,可用内建对象session直接访问会话,例如:
<% session.setAttribute("username","maxwell");
String name = (String)session.getAttribute("username"); %>
<%=name%>
errorPage:
isErrorPage:Jsp页面中出现异常的处理方式
对于有可能出现异常的页面:
<%@page errorPage="error.jsp"%> //异常时会跳转到处理异常的页面;这页面自己写
在有可能异常的地方打印原因: throw new Exception("数据库连接出错");
对于处理异常的页面(error.jsp)里:
<%@page isErrorPage="true"%>,其中使用<%=exception.getMessage() %>把异常信息打印出来
isThreadSafe——此属性已经不再使用(已废弃)
当前Jsp页面是否线程安全 default--->true
<%@page isThreadSafe="true"%> //普通的Servlet,可以并发处理用户请求
<%@page isThreadSafe="false"%> //相当于Servlet实现了SingleThreadModel
2.include指令
把目标页面的内容包含到当前页面,产生页面叠加以后的输出效果 //相当于将两个页面合并;编译时就包含进来
<%@include file="foot.jsp"%> //可插入任意位置
3.taglib指令
留在JSTL里讲解。
五、JSP中的注释
1.java格式注释
编译器会忽略掉此类注释中的内容(客户端的源码看不见)
<%-- JSP注释;可多行 --%>
<%// java 单行注释 %>
<%/* java multi lines comments */%>
<%/**java 特有的注释*/%>
2.html风格注释
编译器会执行此类注释中的代码(客户端的源码看得见)
<!-- html风格注释 --> 等价于out.println("<!-- html风格注释 -->")
这种注释方式不好的地方就是当页面注释信息太多的时候会增大服务器的负荷。
还有注释信息需要在网络上传输,从而降低效率;内部程序员的测试数据一般不能写在这种注释中,以免泄露。
六、动作(Action)
<jsp:actionName attributeName=attributeValue/>
JSP的动作包括:
forward、include、useBean、setProperty、getProperty
1.forward动作
形式:<jsp:forward page="another.jsp"/>
等价于 Servlet中通过RequestDispatcher.forward();
可以传参数
<jsp:forward page="another.jsp">
<jsp:param name="name" value="maxwell"/>
<jsp:param name="age" value="20" />
</jsp:forward>
2.Include动作
形式:<jsp:include page="another.jsp"/>
等价于 Servlet中通过RequestDispatcher.include();
Include动作也可以传参数
<jsp:include page="b.jsp" flush="true">
<jsp:param name="name" value="narci"/>
</jsp:include>
与<%@include file=""%>比较:
include动作在运行期处理(include指令编译期),jsp:include包含的是所包含URI的响应,而不是URI本身。
这意味着:jsp:include 对所指出的 URI 进行解释,因而包含的是生成的响应。
对于页面是静态内容,这没有太大的关系。但如果是动态内容,include动作可传参数。
flush 属性
flush 指示在读入包含内容之前是否清空任何现有的缓冲区。
JSP 1.1 中需要 flush 属性,因此,如果代码中不用它,会得到一个错误。
但是,在 JSP 1.2 中, flush 属性缺省为 false。
建议:由于清空大多数时候不是一个重要的问题,因此,对于 JSP 1.1,将 flush 设置为 true;
而对于 JSP 1.2 及更高版本,将其设置为 false 或不设置(用默认值)。