深入JSP学习
常规JSP
- JSP页面最终会由容器来生成Servlet类的,比如Tomcat容器生成JSP的Servlet类放在work目录里。因此在JSP里可以用很多简化的语法供容器使用,这篇就来整理一下。
JSP语法
- scriptlet:<% %>
可以在里面写Java代码,如<%out.print("27");%>; -
指令:<%@ %>
可以在页面转换时向容器给出特殊的指示;它有三个指令:page、include和taglib;而指令又有很多属性如import是page的属性:<%@ page import="foo.*,java.util.*"%>; -
表达式:<%= %>
表达式会成为out.println()或out.print()的参数,因此<%=27%>等价于<%out.print(27);%>; -
声明:<%! %>
是JSP转换成Servlet类的声明,因此可以声明类变量(静态变量)、实例变量、方法等; -
注释:<%-- %>
就像Java代码中的注释一样,在把JSP转换成Servlet时会把注释去掉;
- scriptlet:<% %>
- 隐式对象
JSP的隐式对象不仅仅有out,还有一些其他的:
final javax.servlet.jsp.PageContext pageContext; javax.servlet.http.HttpSession session; final javax.servlet.ServletContext application; final javax.servlet.ServletConfig config; javax.servlet.jsp.JspWriter out; final java.lang.Object page = this; final javax.servlet.http.HttpServletRequest request; final javax.servlet.http.HttpServletResponse response;
在Tomcat的work目录里我们可以看到由JSP生成的Servlet类,该类继承org.apache.jasper.runtime.HttpJspBase,其中有以下三个方法
_jspInit() _jspDestroy() _jspService()
<%! public void _jspDestroy(){ int i=5; }%>
org.apache.jasper.JasperException: Unable to compile class for JSP:
- 初始化JSP
通常,我们会把初始化参数分配给单独的servlet或JSP页面。这个指定的servlet或者JSP页面通过ServletConfig的 getInitParameter方法来读取这些参数。但在某些情况下,需要提供系统范围内的初始化参数,任何servlet或者JSP页面可以通过 ServletContext的getInitParameter方法来读取这些初始化参数。但并不推荐这样做,通常是使用MVC架构,在C中非常合适。
为JSP配置初始化参数是在<servlet>标记中增加一个<jsp-file>元素
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" > <web-app> <display-name>Archetype Created Web Application</display-name> <context-param> <param-name>qq</param-name> <param-value>38602359</param-value> </context-param> <servlet> <servlet-name>index</servlet-name> <!-- 与Servlet的不同,使用的是jsp-file和URL --> <jsp-file>/index.jsp</jsp-file> <init-param> <param-name>email</param-name> <param-value>kevin@oseye.net</param-value> </init-param> </servlet> </web-app>
<%@page import="java.util.Enumeration"%> <html> <body> <h2>Hello World!</h2> <%=config.getInitParameter("email")%><br> <%=getServletConfig().getInitParameter("email")%><br> <%=application.getInitParameter("qq")%><br> <%=getServletContext().getInitParameter("qq")%> </body> </html>
Hello World!
null
null
38602359
38602359<servlet-mapping> <servlet-name>index</servlet-name> <url-pattern>/index.jsp</url-pattern> </servlet-mapping>
-
JSP属性
JSP比普通的Servlet多了一个作用域,共有4个作用域
而pageContext的setAttribute和getAttribute都有重载,就多了一个int类型的作用域设置
public static final int PAGE_SCOPE = 1; public static final int REQUEST_SCOPE = 2; public static final int SESSION_SCOPE = 3; public static final int APPLICATION_SCOPE = 4;
<html> <body> <h2>Hello World!</h2> <%pageContext.setAttribute("name", "kevin",PageContext.REQUEST_SCOPE); %> pageContext: <%=pageContext.getAttribute("name") %><br> session: <%=session.getAttribute("name") %><br> application: <%=application.getAttribute("name") %><br> request: <%=request.getAttribute("name") %><br> find: <%=pageContext.findAttribute("name") %><br> </body> </html>
Hello World!
pageContext: null
session: null
application: null
request: kevin
find: kevin - page指令
page指令的属性有import、contentType、isThredSafe、Sessioin、buffer、autoflush、extends、info、errorpage、isErrorPage、language、pageEncoding等。格式:
<%@ page page_directive_attr_list %>
- import属性指定由Servlet导入的package。
<%@ page import="package.class" %>
- isThreadSafe属性控制从JSP页中产生的Servlet是否将实现SingleThreadModel接口。isThreadSafe属性的使用采用以下两种格式之一,前者是缺省的:
<%@ page isThreadSafe = "True" %> <%@ page isThreadSafe = "false" %>
- session属性控制页面是否参与HTTP会话。
–缺省值true,表明页面将加入一个HTTPsession;
–设置为false,表明不会自动使用任何会话; - buffer属性指明JspWriter的缓冲区大小。buffer属性采用以下两种格式之一:
<%@ page buffer="sizekb" %> <%@ page buffer="none" %>
- autoFlush属性配合输出缓冲区 buffer属性使用。控制输出缓冲区在装满时是否应该清除,或者当缓冲区溢出时是否应给出异常处理。
- extends属性指定为JSP页生成的Servlet的超类。
<%@ page extends= "package.class" %>
- info属性定义一个通过getServletInfo方法可以从Servlet中检索到的串。
<%@ page info= "some infomation" %>
- isErrorpage属性指明当前页是否能充当其他JSP页面的错误页。缺省值为false。
- errorpage属性指明如果抛出一个异常,而异常没有被捕获时,此错误处理所指向的URL。
- contentType属性指明字符编码和JSP响应的MIME类型。contentType属性的缺省值为text/html ;charset属性的缺省值为 ISO-8859-1
<%@ page contentType="TYPE" %> <%@ page contentType="TYPE; charset=CHARSET" %>
- pageEncoding属性定义了页的编码字符。除非指定page指令的contentType属性,否则缺省值为 ISO-8859-1。
- language属性指定将要使用的程序设计语言。
- import属性指定由Servlet导入的package。
无脚本JSP
使用scriptlet、表达式和声明不仅代码混了难以维护,而且不利于页面设计人员和服务器开发人员的分工合作,因此这里介绍EL(表达式语言)、标准动作和JSTL。
- 标准动作
JSP动作使用格式为:<jsp:标记名>,利用XML语法格式的标记来控制Servlet引擎的行为。这些jsp标签动作元素是在用户请求阶段执行的,这些标准动作元素是内置在jsp文件中的,所以可以直接使用。有以下动作元素<jsp:useBean> //定义jsp页面使用一个JavaBean实例; <jsp:setProperty> //设置一个JavaBean中的属性值; <jsp:getProperty> //从JavaBean中获取一个属性值; <jsp:include> //在JSP页面包含一个外在文件; <jsp:forward> //清空缓冲区把到达的请求转发另一个页面进行处理; <jsp:param> //用于传递参数值; <jsp:plugin> //用于指定在客户浏览器中插入插件的属性; <jsp:params> //用于向HTML页面的插件传递参数值; <jsp:fallback> //指定如何处理客户端不支持插件运行的情况;
就是遵循”古老“JavaBeans规范的法则。我们说的是JavaBean,而不是企业JavaBean(EJB),这两个东西完全不相干(要搞清楚)。普通的非企业JavaBean规范定义了一个类怎么才算是JavaBean。尽管这个规范确实很复杂,不过,结合JSP和servlet使用bean时,你只要知道以下规则就行了(只列出了与使用servlet和JSP相关的规则):- 必须有一个无参公共构造函数;
- 必须按命名约定来命名公共的获取方法和设置方法,首先是"get"(或者如果是一个布尔性质,获取方法的前缀是"is")和"set",如getName何setName。要获得性质名,先去掉get和set,并把首字母小写。
- 设置方法的参数类型和获取方法的返回类型必须一样,如String getName()和void setName(String name)。
- 性质名和类型是由get和set方法推导得出,而不是得自于类中的一个成员。
- 结合JSP使用时,性质类型必须是String,或者是一个基本类型。如果不是这样,尽管也许是一个合法的bean,可如此一来,你可能还得使用脚本。
package net.oseye; public class Person{ private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
Person p=new Person(); p.setName("kevin"); p.setAge(22); request.setAttribute("person", p); RequestDispatcher view=request.getRequestDispatcher("/index.jsp"); view.forward(request, response);
<% Person p=(Person)request.getAttribute("person"); if(p!=null){ out.print(p.getName()); }else{ out.print("null"); } %>
<jsp:useBean id="person" class="net.oseye.Person" scope="request" /> <jsp:getProperty property="name" name="person"/>
<jsp:useBean id="person" class="net.oseye.Person" scope="request" />
- id为属性名,class为属性值的类型,scope为属性作用域;
- 如果属性不存在person,则创建一个新的属性,是class的示例对象;因此它也可以有体来设置性质值
<jsp:useBean id="person2" class="net.oseye.Person" scope="request"> <jsp:setProperty property="name" name="person2" value="kevin2"/> </jsp:useBean> <%=((Person)request.getAttribute("person2")).getName()%>
- 如果建立多态JavaBean的话使用type属性,含义是
type id=new class();
- scope默认为“page”。
<jsp:param>
<form method="get" action="http://localhost:8080/mytest/Index"> <input name="username" type="text" value="Anders" /> <input type="submit" name="Submit" value="提交" /> </form>
<jsp:useBean id="person" class="net.oseye.Person" scope="request"> <jsp:setProperty property="name" name="person" param="username" /> </jsp:useBean>
<jsp:useBean id="person" class="net.oseye.Person" scope="request"> <jsp:setProperty property="*" name="person" /> </jsp:useBean>
- EL
如在表中动作中所说,如果JavaBean的性质类型不是String的话,尽管它是一个合法的JavaBean但仍需要使用脚本,其实还有一种方式就是EL(express language)。EL语法相当简单,格式是:${firstThing.secondThing}
pageScope属性、requestScope属性、sessionScope属性、applicationScope属性。
访问映射值或性质时可以使用点号(.),但除了性质和映射值外还有很多的其他特殊的,随意最通用的是中括号([]),如在servlet中Person p=new Person(); p.setName("kevin"); p.setAge(22); request.setAttribute("person", p); RequestDispatcher view=request.getRequestDispatcher("/index.jsp"); view.forward(request, response);
<%@page isELIgnored="false" %> <html> <body> ${person.name}<br> ${person["name"]}<br> ${10+10 } </body> </html>
- JSTL
JSTL全名为JavaServer Pages Standard Tag Library。JSLT标签库,是日常开发经常使用的,也是众多标签中性能最好的。需要添加JSTL的JAR包<dependency> <groupId>jstl</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<c:out value="dddd"></c:out>
- 常用的标签:如<c:out>、<c:remove>、<c:catch>、<c:set>等;
- 条件标签:如<c:if><c:when>、<c:choose>、<c:otherwise>等;
- URL标签:如<c:import>、<c:redirect>和<c:url>等;
- XML标签:如<xml:out>等;
- 国际化输出标签:如<fmt:timeZone>等;
- SQL标签:如<sql:query>、<sql:update>、<sql:transaction>等;
PS:include指令、<jsp:include>标准动作和JSTL的不同:前者是在编译期复制,后者是在执行期复制。