相关学习资料
http://my.oschina.net/chape/blog/170247 http://docs.oracle.com/cd/E13222_01/wls/docs81/webapp/web_xml.html http://blog.csdn.net/liaoxiaohua1981/article/details/6761053 http://computer.c.blog.163.com/blog/static/102524482012314537670/ http://www.blogjava.net/w2gavin/articles/358641.html http://www.douban.com/note/310522851/ http://mianhuaman.iteye.com/blog/1105522 http://blog.csdn.net/li_jinjian2005/article/details/2915462 http://210.44.193.6/JSP/07.htm http://www.ibm.com/developerworks/cn/java/j-lo-servlet30/
目录
1. J2EE WEB应用文件目录结构 2. web.xml基础语法 3. JSP基础语法 4. Servlet基础语法
1. J2EE WEB应用文件目录结构
Java Web应用由一组静态HTML页、Servlet、JSP和其他相关的class组成,它们一起构成一个大的工程项目。每种组件在Web应用中都有固定的存放目录。Web应用的配置信息存放在web.xml文件中。在发布某些组件(如Servlet)时,必须在web.xml文件中添加相应的配置信息
Java Web应用程序必须使用规范的目录结构
1. 应用程序根目录,可以取任意的名字,所有的HTML、JSP文件都放在这个目录下 1.1 WEB-INF目录: 必须目录 1.1.1 web.xml: Web应用部署描述文件,必须文件 1.1.2 classes目录: 1) 用于存放单个*.classes字节码文件,Servlet类文件也存放在这个目录下 1.1.3 lib目录: 1) 存放第三方类库文件,即打包后的JAR文件 1.1.4 TLD文件: 标签库描述文件 1.2 其他静态文件: 1.2.1 HTML 1.2.2 CSS 1.2.3 javascript 1.2.4 图片等 1.3 *.jsp: 存放任意多个JSP页面
2. web.xml基础语法
位于每个WEB应用的的WEB-INF路径下的web.xml文件被称为配置描述符,这个web.xml文件对于Java Web应用十分重要,总体来说,web.xml主要负责以下内容:
1. JSP环境参数初始化 2. 配置和管理Servlet 3. 配置和管理Listener 4. 配置和管理Filter 5. 配置和管理JNDI 6. Session配置 7. MIME TYPE配置 8. 错误处理 9. 配置标签库 10. 配置JSP属性 11. 配置和管理JAAS授权认证 12. 配置和管理资源引用 13. WEB应用默认首页(welcome文件)的设置
下面我尽量列出了一个完整的web.xml的结构,我使用了/**/注释符来说明某个项目的说明,要明白的是,在真实的web.xml中不允许使用/**/注释符的,只是我觉得直接在web.xml中插入解释说明能更好的说明问题
/* <?xml version="1.0" encoding="GBK"?>是一个基本的XML文件的框架,不管是什么配置文件,只要是基于XML的,它的基本结构都是这样 */ <?xml version="1.0" encoding="GBK"?> /* web.xml文件的根元素是<web-app.../>元素,整个web.xml只有这个根元素,每个web.xml必须以这个<web-app>根元素作为开头,在Servlet 3.0规范中,该元素新增了
metadata-complete属性,当该属性值为true时,该web应用"不会"加载Annotation配置的WEB组件(如Servlet、Filter、Listener等),反之则加载 */ <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0"> /* 1. icon信息: 用来指定web站点中小图标和大图标的路径 1) small-icon: 大小为16 X 16 pixel,但是图象文件必须为GIF或JPEG格式,扩展名必须为:.gif或 .jpg. 2) large-icon: 大小为32 X 32 pixel,但是图象文件必须为GIF或JPEG的格式,扩展名必须为; gif 或jpg. */ <small-icon>/路径/smallicon.gif</small-icon> <large-icon>/路径/largeicon-jpg</large-icon> /* 2. 描述信息 display-name: 定义站点的名称 description: 对站点的描述 */ <display-name>站点名称</display-name> <description>站点描述</discription> /* 3. distributable distributable元素为空标签,它的存在与否可以指定站台是否可分布式处理.如果web.xml中出现这个元素,则代表站台在开发时已经被设计为能在多个JSP Container之间分散执行 */ <distributable/> /* 4. JSP环境参数: context-param context-param元素用来设定web站台的环境参数(context),它包含两个子元素: 1) param-name: 参数名称 2) param-value: 值 此所设定的参数,在JSP网页中可以使用下列方法来取得: ${initParam.param_name} 若在Servlet可以使用下列方法来获得: String param_name=getServletContext().getInitParamter("param_name"); */ <context-param> <param-name>param_name</param-name> <param-value>param_value</param-value> </context-param> /* 5. filter过滤器、filter-mapping 用于指定WEB容器的过滤器,在请求和响应对象在Servlet处理之前和之后,可以通过此过滤器对这两个对象进行处理 filter-class 中指定的过滤器类须继承 javax.servlet.Filter具有须有以下三种方法 init(FilterConfig filterConfig):初始化;一般情况下时读取配置文件中的init-param参数值 如 filterConfig.getInitParameter("encoding") doFilter(...):用于对request,response进行处理,并能过chain.doFilter(...) 交过下一个控制器 destroy():资源销毁 filter-mapping则指示需要进行过滤器处理的URL访问模式,可以理解为当我们的URL匹配到指定的模式后,则对这个请求执行指定的"过滤处理流程"(可以把它理解为一种路由机制) */ <filter> <small-icon>/路径/smallicon.gif</small-icon> <large-icon>/路径/largeicon-jpg</large-icon> <filter-name>encodingfilter</filter-name> <display-name>站点名称</display-name> <description>站点描述</discription> <filter-class>com.my.app.EncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>encodingfilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> /* 6. servlet、servlet-mapping 和filter过滤器类似,servlet也是用来配置映射处理机制的 和filter-mapping的作用类似,servlet-mapping用来定义servlet所对应URL. */ <servlet> <small-icon>/路径/smallicon.gif</small-icon> <large-icon>/路径/largeicon-jpg</large-icon> <servlet-name>MyServletName</servlet-name> <display-name>站点名称</display-name> <description>站点描述</discription> /* servlet-class、jsp-file有且只能出现一个 */ <servlet-class>com.Little.MyServlet</servlet-class> <jsp-file>/path/index.jsp</jsp-file> <init-param> <param-name>name1</param-name> <param-value>value1</param-value> </init-param> /* 指定当Web应用启动时,装载Servlet的次序 1) 当值为正数或零时: 容器在应用启动时就加载这个servlet,Servlet容器先加载数值小的servlet,再依次加载其他数值大的servlet 2) 当值为负或未定义: 容器在该servlet被选择时才加载,即Servlet容器将在Web客户首次访问这个servlet时加载它 */ <load-on-startup></load-on-startup> /* 设定运行时角色,可以使当前Servlet以一个特定的角色运行,有利于安全权限控制 */ <run-as> <description>Security role for anonymous access</description> <role-name>tomcat</role-name> </run-as> /* security-role-ref子元素提供出现在服务器专用口令文件中的安全角色名的一个别名。例如,假如编写了一个调用 request.isUserInRole("boss")的servlet,
但后来该servlet被用在了一个其口令文件调用角色manager而不 是boss的服务器中。下面的程序段使该servlet能够使用这两个名称中的任何一个 */ <security-role-ref> <role-name>boss</role-name> <!-- New alias --> <role-link>manager</role-link> <!-- Real name --> </security-role-ref> </servlet> <servlet-mapping> <servlet-name>LoginChecker</servlet-name> <url-pattern>/LoginChecker</url-pattern> <servlet-name>MyServletName</<servlet-name> </servlet-mapping> /* 7. security-role(虚拟安全用户) 给出安全角色的一个列表,这些角色将出现在servlet元素内的security-role-ref元素的role-name元素中。分别声明角色可使高级IDE处理安全信息更为容易。 */ <security-role> <description>安全账户描述</discription> <role-name>admin</role-name> </security-role> /* 8. listener 监听器也叫Listener,是Servlet的监听器,它可以监听客户端的请求、服务端的操作等。通过监听器,可以自动激发一些操作,Servlet本身在一些特定的关键处理流程节点上增加Hook
回调机制,使得我们可以在这些节点位置配置监听器 常见的监听器如下: Listener接口 1) ServletContextListener: ServletContextEvent 2) ServletContextAttributeListener: ServletContextAttributeEvent 3) HttpSessionListener: HttpSessionEvent 4) HttpSessionActivationListener: HttpSessionAttributeListener 5) HttpSessionBindingEvent: HttpSessionBindingListener 6) ServletRequestListener: ServletRequestEvent 7) ServletRequestAttributeListener: ServletRequestAttributeEvent */ <listener> <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class> </listener> /* 9. session配置 session-config包含一个子元素session-timeout.定义web站台中的session参数,定义这个web站台所有session的有效期限.单位为分钟 */ <session-config> <session-timeout>20</session-timeout> </session-config> /* 10. mime-mapping mime-mapping包含两个子元素extension和mime-type.定义某一个扩展名和某一MIME Type做对映,和apache中的文件扩展处理器原理类似,对指定的扩展名指定相应的处理程序 */ <mime-mapping> <extension>doc</extension> <mime-type>application/vnd.ms-word</mime-type> </mime-mapping> <mime-mapping> <extension>xls</extension> <mime-type>application/vnd.ms-excel</mime-type> </mime-mapping> /* 11. welcome-file-list welcome-file-list包含一个子元素welcome-file.用来定义首页列单,即当客户端的请求没有指定具体的页面时,服务区器默认指定的首页脚本 */ <welcome-file-list> <welcome-file>index.jsp</welcome-file> <welcome-file>index.htm</welcome-file> </welcome-file-list> /* 12. error-page 错误处理机制,error-page元素包含三个子元素error-code,exception-type和location.将错误代码(Error Code)或异常(Exception)的种类对应到web站点资源路径。
简单来说就是返回特定HTTP状态代码或者特定类型的异常被抛出时,制定响应将要显示的页面。 */ <error-page> <error-code>404</error-code> <exception-type>java.lang.Exception</exception-type> <location>/error404.jsp</location> </error-page> <error-page> <exception-type>java.lang.Exception</exception-type> <exception-type>java.lang.NullException</exception-type> <location>/except.jsp</location> </error-page> /* 13. jsp-config JSP相关配置 */ <jsp-config> <taglib> /* taglib-uri定义TLD文件的URI,JSP网页的taglib指令可以经由这个URI存取到TLD文件 */ <taglib-uri>Taglib</taglib-uri> /* taglib-location定义TLD文件对应Web站台的存放位置 */ <taglib-location>/WEB-INF/tlds/MyTaglib.tld</taglib-location> </taglib> <jsp-property-group> <description> Special property group for JSP Configuration JSP example. </description> <display-name>JSPConfiguration</display-name> /* 设定值所影响的范围,如:/CH2 或者/*.jsp */ <uri-pattern>/*</uri-pattern> /* 若为true,表示不支持EL语法 */ <el-ignored>true</el-ignored> /* 设定JSP网页的编码 */ <page-encoding>GB2312</page-encoding> /* 若为true表示不支持<%scription%>语法. */ <scripting-inivalid>true</scripting-inivalid> /* 设置JSP网页的结尾,扩展名为.jspf */ <include-coda>.jspf</include-coda> /* 设置JSP网页的抬头,扩展名为.jspf */ <include-prelude>.jspf</include-prelude> </jsp-property-group> </jsp-config> /* 14. resource-ref、resource-env-ref resource-ref声明资源工厂使用的外部资源 resource-env-ref声明与资源相关的管理对象 */ <resource-ref> <description>JNDI JDBC DataSource of JSPBook</description> <!-- 资源说明 --> <res-ref-name>jdbc/sample_db</res-ref-name> <!-- 资源名称 --> <res-type>javax.sql.DataSoruce</res-type> <!-- 资源种类 --> <res-auth>Container</res-auth> <!-- 资源由Application或Container来许可 --> <res-sharing-scope>Shareable|Unshareable</res-sharing-scope> <!-- 资源是否可以共享.默认值为 Shareable --> </resource-ref> <resource-env-ref> <resource-env-ref-name>jms/StockQueue</resource-env-ref-name> </resource-env-ref> /* 15. EJB配置 ejb-ref用于声明一个EJB的主目录的引用 用于声明一个EJB的本地主目录的应用。 */ <ejb-ref> <description>Example EJB reference</decription> <ejb-ref-name>ejb/Account</ejb-ref-name> <ejb-ref-type>Entity</ejb-ref-type> <home>com.mycompany.mypackage.AccountHome</home> <remote>com.mycompany.mypackage.Account</remote> </ejb-ref> <ejb-local-ref> <description>Example Loacal EJB reference</decription> <ejb-ref-name>ejb/ProcessOrder</ejb-ref-name> <ejb-ref-type>Session</ejb-ref-type> <local-home>com.mycompany.mypackage.ProcessOrderHome</local-home> <local>com.mycompany.mypackage.ProcessOrder</local> </ejb-local-ref> /* 16. WEB应用环境参数配置 */ <env-entry> <description>环境参数说明</description> <env-entry-name>minExemptions</env-entry-name> <env-entry-value>1</env-entry-value> <env-entry-type>java.lang.Integer</env-entry-type> </env-entry> /* 17. 安全配置、资源限制访问配置 在Web应用程序的web.xml中创建security-constraint、login-config和security-role元素 */ /* 配置对指定资源、指定角色的访问权限 */ <security-constraint> <web-resource-collection> <web-resource-name>HelloServlet</web-resource-name> <url-pattern>/HelloServlet</url-pattern> <http-method>GET</http-method> <http-method>POST</http-method> </web-resource-collection> <auth-constraint> <description>This applies only to the "tomcat" security role</description> <role-name>admin</role-name> </auth-constraint> <user-data-constraint> <transport-guarantee>NONE</transport-guarantee> </user-data-constraint> </security-constraint> /* auth-method的方法有: 1) BASIC BASIC是一种常见的Web认证方式,浏览器给用户提示一个对话框,要求输入用户名和密码,随后Tomcat将给出的用户名和密码与tomcat-users.xml中的用户名和密码进行比较,
然后使用前面的security-constraint配置来确定用户是否可访问受保护的servlet 2) FORM 3) CLIENT-CERT 4) DIGEST */ <login-config> <realm-name>在HTTP验证返回包中的显示名称</<realm-name> <auth-method>BASIC</auth-method> <form-login-config>如果auth-method采用FORM,则这里填写form-login-config名称</form-login-config> </login-config> /* 关于security-role,在前面的servlet已经说明过,这里要强调一下: web.xml中的HTTP认证方法实际上有两个步骤: 1) 检查提供的用户名和密码是否正确。 2) 判断用户是否映射到特定的安全角色。例如,用户可能提供了正确的用户名和密码,但没有映射到特定的安全角色,也将被禁止访问特定的Web资源。 */ <security-role> <role-name>admin</role-name> </security-role> </web-app>
以上就是web.xml的完整结构,需要注意的是,web.xml中有一些环境参数的加载配置,它们之间存在优先级的关系,我们在编写配置的时候需要注意这一点
web.xml 的加载顺序是:context-param -> listener -> filter -> servlet ,而相同类型节点之间的程序调用的顺序是根据对应的mapping的顺序进行调用的
3. JSP基础语法
JSP的本质是Servlet,当用户向指定Servlet发送请求时,Servlet利用输出流动态生成HTML页面,包括每一个静态的HTML标签和所有在HTML页面中出现的内容
JSP页面由如下两部分组成
1. 静态部分: 标准的HTML标签、静态的页面内容,也就是普通的HTML代码 2. 动态部分: 受java程序控制的内容,这些内容由Java程序来动态生成
/* 1. JSP的编译指令 */ <%@ page contentType="text/html; charset=GBK" language="java" errorPage="" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>learn j2ee</title> /* 2. JSP注释 */ </head> /* 3. JSP声明 */ <body> /* 4. JSP表达式 */ /* 5. JSP脚本 */ /* 6. JSP的动作指令 */ /* 7. JSP脚本中的内置对象 */ </body> </html>
0x1: JSP的编译指令
JSP的编译指令是通过JSP引擎的消息,它不直接生成输出。编译指令都有默认值,我们并不需要为每个指令设置值。它的格式如下 <%@ 编译指令名 属性名="属性值"...%>(不同属性名之间用空格分开) 1) page: Page指令为容器提供当前页面的使用说明。一个JSP页面可以包含多个page指令 1.1) buffer: 指定缓冲区的大小。缓冲区是JSP内部对象"out",它用于缓存JSP页面对客户端浏览器的输出,默认值为8KB,可以设置为none,也可以设置为其他的值,单位为Kb 1.2) autoFlush: 当缓冲区即将满而溢出时,是否需要强制输出缓冲区的内容: 1.2.1) 如果设置为true则正常输出 1.2.2) 如果设置为false,则会在buffer溢出时产生一个异常 1.3) contentType: 用于设定生成网页的文件格式(MIME类型)、和编码字符集(页面字符集类型)(text/html;charSet=ISO-8859-1) 1.3.1) 默认的MIME类型是text/html 1.3.2) 默认的字符集类型为ISO-8859-1 1.4) errorPage: 指定错误处理页面,如果本页面产生了异常或错误,而该JSP页面没有对应的错误处理代码(没有用try、catch机制捕捉异常),则会自动调用该属性所指定的JSP
页面。值得注意的是,为页面指定错误发生时的错误提示页面是一种安全的做法,能够在一定程度上组织error-based-sql-injection的攻击 1.5) isErrorPage: 指定当前页面是否可以作为另一个JSP页面的错误处理页面 1.6) extends: JSP程序编译时所产生的Java类,需要继承的父类,或者需要实现的接口的全限定类名(即包含包名在内的完整路径) 1.7) import: 用来导入包。默认自动导入的包(参数之间用逗号分隔)(java.lang.*,javax.servlet.*) 1.7.1) java.lang.* 1.7.2) javax.servlet.* 1.7.3) javax.servlet.jsp.* 1.7.4) javax.servlet.http.* 1.8) info: 定义JSP页面的描述信息 1.9) isThreadSafe: 指定对JSP页面的访问是否为线程安全 1.10) language: 定义JSP页面所用的脚本语言,默认是Java 1.11) session: 指定JSP页面是否使用session 1.12) isELIgnored: 指定是否执行EL表达式 1.13) isScriptingEnabled: 确定脚本元素能否被使用 2) include: 用于指定包含另一个页面 <%@include file="file.jsp"%> 可以将外部文件嵌入到当前JSP文件中,同时解析这个页面中的JSP语句(如果有的话),也就是说,它既可以包含静态的文本,也可以包含动态的JSP页面。包含页面在编译时将完全包含了被包
含页面的代码,融合成一个页面。作用和php中的inlcude、require类似。 需要注意的是,要指出的是,静态包含还会将被包含页面的编译指令也包含进来,如果两个页面的编译指令冲突,那么页面就会出错(即被包含的页面中不能重复定义
page、include、taglib) 3) taglib: 用于定义和访问自定义标签 自定义标签库是一种非常优秀的表现层组件技术。通过使用自定义标签库,可以在简单的标签中封装复杂的功能,在JSP2中使用自定义标签需要以下步骤 1) 开发自定义标签处理类 在JSP页面使用一个标签时,底层实际上由标签处理类提供支持,从而可以通过简单的标签来封装复杂的功能,从而使团队更好地协作开发。自定义标签类应该继承一个父类:
javax.servlet.jsp.tagext.SimpleTagSupport,除此之外,JSP自定义标签类还有如下要求(通过接口来强制性保证): 1) 如果标签包含属性,每个属性都有对应的getter、setter方法 2) 重写doTag()方法,这个方法负责生成页面内容 example1: 无属性、无标签体的最简单的标签处理类 package lee; import javax.servlet.jsp.tagext.*; import javax.servlet.jsp.*; import java.io.*; public class HelloWorldTag extends SimpleTagSupport { //重写doTag方法,该方法在标签结束生成页面内容 public void doTag()throws JspException, IOException { //获取页面输出流,并输出字符串 getJspContext().getOut().write("Hello World " + new java.util.Date()); } } 这个标签处理类继承了SimpleTagSupport父类,并重写了doTag()方法,doTag()负责输出页面内容(即标签代表的内容) example2: 带属性的标签处理类 package lee; import javax.servlet.jsp.tagext.*; import javax.servlet.jsp.*; import java.io.*; import java.sql.*; public class QueryTag extends SimpleTagSupport { //标签的属性 private String driver; private String url; private String user; private String pass; private String sql; //driver属性的setter和getter方法 public void setDriver(String driver) { this.driver = driver; } public String getDriver() { return this.driver; } //url属性的setter和getter方法 public void setUrl(String url) { this.url = url; } public String getUrl() { return this.url; } //user属性的setter和getter方法 public void setUser(String user) { this.user = user; } public String getUser() { return this.user; } //pass属性的setter和getter方法 public void setPass(String pass) { this.pass = pass; } public String getPass() { return this.pass; } //sql属性的setter和getter方法 public void setSql(String sql) { this.sql = sql; } public String getSql() { return this.sql; } //conn属性的setter和getter方法 public void setConn(Connection conn) { this.conn = conn; } public Connection getConn() { return this.conn; } //stmt属性的setter和getter方法 public void setStmt(Statement stmt) { this.stmt = stmt; } public Statement getStmt() { return this.stmt; } //rs属性的setter和getter方法 public void setRs(ResultSet rs) { this.rs = rs; } public ResultSet getRs() { return this.rs; } //rsmd属性的setter和getter方法 public void setRsmd(ResultSetMetaData rsmd) { this.rsmd = rsmd; } public ResultSetMetaData getRsmd() { return this.rsmd; } //执行数据库访问的对象 private Connection conn = null; private Statement stmt = null; private ResultSet rs = null; private ResultSetMetaData rsmd = null; public void doTag()throws JspException, IOException { try { //注册驱动 Class.forName(driver); //获取数据库连接 conn = DriverManager.getConnection(url,user,pass); //创建Statement对象 stmt = conn.createStatement(); //执行查询 rs = stmt.executeQuery(sql); rsmd = rs.getMetaData(); //获取列数目 int columnCount = rsmd.getColumnCount(); //获取页面输出流 Writer out = getJspContext().getOut(); //在页面输出表格 out.write("<table border=\'1\' bgColor=\'#9999cc\' width=\'400\'>"); //遍历结果集 while (rs.next()) { out.write("<tr>"); //逐列输出查询到的数据 for (int i = 1 ; i <= columnCount ; i++ ) { out.write("<td>"); out.write(rs.getString(i)); out.write("</td>"); } out.write("</tr>"); } } catch(ClassNotFoundException cnfe) { cnfe.printStackTrace(); throw new JspException("自定义标签错误" + cnfe.getMessage()); } catch (SQLException ex) { ex.printStackTrace(); throw new JspException("自定义标签错误" + ex.getMessage()); } finally { //关闭结果集 try { if (rs != null) rs.close(); if (stmt != null) stmt.close(); if (conn != null) conn.close(); } catch (SQLException sqle) { sqle.printStackTrace(); } } } } example3: 带标签体的标签处理类 带标签体的标签可以在标签内嵌入其他内容(包括静态HTML、动态JSP内容),通常用于完成一些逻辑运算 package lee; import javax.servlet.jsp.tagext.*; import javax.servlet.jsp.*; import java.io.*; import java.sql.*; import java.util.*; public class IteratorTag extends SimpleTagSupport { //标签属性,用于指定需要被迭代的集合 private String collection; //标签属性,指定迭代集合元素,为集合元素指定的名称 private String item; //collection属性的setter和getter方法 public void setCollection(String collection) { this.collection = collection; } public String getCollection() { return this.collection; } //item属性的setter和getter方法 public void setItem(String item) { this.item = item; } public String getItem() { return this.item; } //标签的处理方法,简单标签处理类只需要重写doTag方法 public void doTag() throws JspException, IOException { //从page scope中获取属性名为collection的集合 Collection itemList = (Collection)getJspContext().getAttribute(collection); //遍历集合 for (Object s : itemList) { //将集合的元素设置到page 范围 getJspContext().setAttribute(item, s); //输出标签体 getJspBody().invoke(null); } } } example4: 以"页面片段"作为属性的标签处理类 package lee; import javax.servlet.jsp.tagext.*; import javax.servlet.jsp.*; import java.io.*; public class FragmentTag extends SimpleTagSupport { private JspFragment fragment; //fragment属性的setter和getter方法 public void setFragment(JspFragment fragment) { this.fragment = fragment; } public JspFragment getFragment() { return this.fragment; } @Override public void doTag() throws JspException, IOException { JspWriter out = getJspContext().getOut(); out.println("<div style=\'padding:10px;border:1px solid black\'>"); out.println("<h3>下面是动态传入的JSP片段</h3>"); //调用、输出“页面片段” fragment.invoke( null ); out.println("</div"); } } 上面的程序定义了JspFragment类型的fragment属性,该属性代表了使用该标签时的"页面片段" example5: 动态属性的标签处理类 在某些特殊情况下,我们需要传入自定义标签的属性个数是不确定的、属性名也是不确定的,这就需要使用到动态属性的标签 package lee; import javax.servlet.jsp.tagext.*; import javax.servlet.jsp.*; import java.io.*; import java.util.*; public class DynaAttributesTag extends SimpleTagSupport implements DynamicAttributes { //保存每个属性名的集合 private ArrayList<String> keys = new ArrayList<String>(); //保存每个属性值的集合 private ArrayList<Object> values = new ArrayList<Object>(); @Override public void doTag() throws JspException, IOException { JspWriter out = getJspContext().getOut(); //此处只是简单地输出每个属性 out.println("<ol>"); for( int i = 0; i < keys.size(); i++ ) { String key = keys.get( i ); Object value = values.get( i ); out.println( "<li>" + key + " = " + value + "</li>" ); } out.println("</ol>"); } /* 实现DynamicAttributes接口必须实现setDynamicAttribute,该方法用于为该标签处理类动态添加属性名、属性值 */ @Override public void setDynamicAttribute( String uri, String localName, Object value) throws JspException { //添加属性名 keys.add( localName ); //添加属性值 values.add( value ); } } 2) 建立一个*.tld文件,每个*.tld文件对应一个标签库,每个标签库可包含多个标签 TLD(Tag Library Definition 标签库定义)的根元素是taglib,它可以包含多个tag子元素,每个tag元素都定义一个标签 taglib结构如下 1) tlib-version: 指定该标签库实现的内部版本号 2) short-name: 该标签库的默认短名 3) uri: 指定该标签库的唯一标识URI,JSP页面中使用标签库就是根据该URI属性来定位标签库的 4) tag: 每个tag元素定义一个标签 4.1) name: 该标签的名字 4.2) tag-class: 该标签的处理类 4.3) body-content: 指定标签体内容 4.3.1) tagdependent: 标签处理类自己负责处理标签体 4.3.2) empty: 该标签只能作为空标签使用 4.3.3) scriptless: 该标签可以是静态HTML元素、表达式语言,但不允许JSP脚本 4.3.4) JSP: 该标签可以使用JSP脚本 4.3.5) dynamic-attributes: 该标签是否支持动态属性 JSP2规范的自定义标签还允许直接将一段"页面代码"作为属性,这种方式给自定义标签提供了更大的灵活性,它和普通标签的区别并不大,对于以"页面代码"作为属性的自定义标签来
说,需要注意的是: 1) 标签处理类中定义类型为JspFragment的属性,该属性代表了"页面片段" 2) 使用标签库时,通过<jsp:attribute../>动作指令为标签库属性指定值 除此之外,还可以动态属性的标签 <?xml version="1.0" encoding="GBK"?> <taglib xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee web-jsptaglibrary_2_0.xsd" version="2.0"> <tlib-version>1.0</tlib-version> <short-name>mytaglib</short-name> <!-- 定义该标签库的URI --> <uri>http://littlehann.cnblogs.com/mytaglib</uri> <!-- 定义第一个标签 --> <tag> <!-- 定义标签名 --> <name>helloWorld</name> <!-- 定义标签处理类 --> <tag-class>lee.HelloWorldTag</tag-class> <!-- 定义标签体为空 --> <body-content>empty</body-content> </tag> /* 定义第二个标签,对于有属性的标签,需要为<tag../>元素增加<attribute../>子元素,每个attribute子元素定义一个标签元素。<attribute../>子元素通常还需要指定
如下子元素 1) name: 属性名,子元素的值是字符串内容 2) required: 该属性是否为必须属性,true or false 3) fragment: 该属性是否支持JSP脚本、表达式等动态内容,true or false */ <tag> <!-- 定义标签名 --> <name>query</name> <!-- 定义标签处理类 --> <tag-class>lee.QueryTag</tag-class> <!-- 定义标签体为空 --> <body-content>empty</body-content> <!-- 配置标签属性:driver --> <attribute> <name>driver</name> <required>true</required> <fragment>true</fragment> </attribute> <!-- 配置标签属性:url --> <attribute> <name>url</name> <required>true</required> <fragment>true</fragment> </attribute> <!-- 配置标签属性:user --> <attribute> <name>user</name> <required>true</required> <fragment>true</fragment> </attribute> <!-- 配置标签属性:pass --> <attribute> <name>pass</name> <required>true</required> <fragment>true</fragment> </attribute> <!-- 配置标签属性:sql --> <attribute> <name>sql</name> <required>true</required> <fragment>true</fragment> </attribute> </tag> <!-- 定义第三个带标签体的标签 --> <tag> <!-- 定义标签名 --> <name>iterator</name> <!-- 定义标签处理类 --> <tag-class>lee.IteratorTag</tag-class> <!-- 定义标签体不允许出现JSP脚本 --> <body-content>scriptless</body-content> <!-- 配置标签属性:collection --> <attribute> <name>collection</name> <required>true</required> <fragment>true</fragment> </attribute> <!-- 配置标签属性:item --> <attribute> <name>item</name> <required>true</required> <fragment>true</fragment> </attribute> </tag> <tag> <!-- 定义以"页面片段"作为属性的标签名 --> <name>fragment</name> <!-- 定义标签处理类 --> <tag-class>lee.FragmentTag</tag-class> <!-- 指定该标签不支持标签体 --> <body-content>empty</body-content> <!-- 定义标签属性:fragment --> <attribute> <name>fragment</name> <required>true</required> <fragment>true</fragment> </attribute> </tag> <!-- 定义接受动态属性的标签 --> <tag> <name>dynaAttr</name> <tag-class>lee.DynaAttributesTag</tag-class> <body-content>empty</body-content> <!-- 指定支持动态属性 --> <dynamic-attributes>true</dynamic-attributes> </tag> </taglib> 定义了上面的标签库定义文件之后,将标签库文件放在WEB应用的WEB-INF路径下,WEB容器会自动加载该文件,则该文件定义的标签库也将生效 3) 在JSP文件中使用自定义标签 在JSP页面中使用标签库步骤 1) 导入标签库: 使用taglib编译指令导入标签库,由URI唯一标识指定标签库,并将标签库和指定前缀关联起来(即所有使用该前缀的标签将由此标签库处理) <%@ taglib uri="tagliburi" prefix="tagPrefix" %> 2) 使用标签: 在JSP页面中使用自定义标签 <tagPrefix:tagName tagAttribute="tagValue" ..> <tagBody/> </tagPrefix:tagName> example1: helloWorld标签使用 <%@ taglib uri="http://littlehann.cnblogs.com/mytaglib" prefix="mytag"%> <mytag:helloWorld></mytag:helloWorld> example2: QueryTag标签使用 <%@ taglib uri="http://littlehann.cnblogs.com/mytaglib" prefix="mytag"%> <mytag:query driver="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/javaee" user="root" pass="32147" sql="select * from news_inf"/> 可以看出自定义标签库的作用,以简单的标签,隐藏复杂的逻辑 example3: IteratorTag标签使用 <%@ taglib uri="http://littlehann.cnblogs.com/mytaglib" prefix="mytag"%> <% //创建一个List对象 List<String> a = new ArrayList<String>(); a.add("疯狂Java"); a.add("www.crazyit.org"); a.add("java"); //将List对象放入page范围内 pageContext.setAttribute("a" , a); %> <table border="1" bgcolor="#aaaadd" width="300"> <!-- 使用迭代器标签,对a集合进行迭代 --> <mytag:iterator collection="a" item="item"> <tr> <td>${pageScope.item}</td> <tr> </mytag:iterator> </table> 可以看到,使用iterator标签遍历集合元素比使用JSP脚本遍历集合元素要优雅,这也是自定义标签的优势 example4: fragment标签使用 <%@ taglib uri="http://littlehann.cnblogs.com/mytaglib" prefix="mytag"%> <mytag:fragment> <!-- 使用jsp:attribute标签传入fragment参数 --> <jsp:attribute name="fragment"> <!-- 下面是动态的JSP页面片段 --> <mytag:helloWorld/> </jsp:attribute> </mytag:fragment> <mytag:fragment> <jsp:attribute name="fragment"> <!-- 下面是动态的JSP页面片段 --> ${pageContext.request.remoteAddr} </jsp:attribute> </mytag:fragment> example5: dynaAttr标签使用 <%@ taglib uri="http://littlehann.cnblogs.com/mytaglib" prefix="mytag"%> <mytag:dynaAttr name="crazyit" url="crazyit.org"/> <mytag:dynaAttr 书名="疯狂Java讲义" 价格="99.0" 出版时间="2008年" 描述="Java图书"/> 可以看到,不管传入多少属性,这个标签都可以处理 JSTL是Sun提供的一套标签库,DisplayTag是Apache组织下的一套开源标签库,主要用于生成页面并显示效果
2. JSP注释
<%-- 注释内容 --%> JSP注释用于标注在程序开发过程中的开发提示,"不会"输出到客户端,即客户端连注释符号都看不到
3. JSP声明
JSP声明用于声明变量和方法,值得注意的是,JSP声明将会转换成对应的Servlet(.java文件)的成员变量或成员方法(牢记这点,后因为我们还会看到在<%..%>中声明的是局部成员),
因此JSP声明依然符合java语法。 <%! 声明部分 %> 关于JSP的变量声明 梳理一下,在JSP中声明变量总共有2中情况: 1) 局部变量 <% 在JSP(本质是java代码)中声明变量 %>,又因为JSP代码是会被Tomcat翻译成Servlet的面向对象的java代码,所以在<% %>中声明的变量全都是局部变量(即在代码块中声明的变量),
它们不能使用private、public、static等修饰 2) 类变量 <%! %> 用这种方式声明的变量是在类的范围域中声明的,属于类变量,它们可以使用private、public、static等修饰
使用的使用一定要注意
example: <%! //声明一个整形变量 public int count; //声明一个方法 public String info() { return "hello"; } %>
4. JSP表达式
JSP提供了一种输出表达式值的简单方法 <%=表达式%>
example: <%! public int count; %> <%=count++%>
5. JSP脚本
所有可执行性java代码都可以通过JSP脚本嵌入HTML页面
example: <% out.println(new java.util.Date()); %>
6. JSP的动作指令
动作指令与编译指令不同: 1) 编译指令是通知Servlet引擎的处理消息,是在将JSP编译成Servlet时起作用 2) 动作指令只是运行时的动作,通常可替换成JSP脚本,它只是JSP脚本的标准化写法 JSP的动作指令主要有如下7个: 1) jsp:forward: 执行页面转向,将请求的处理转发到下一个页面,可以转发到: 1) 静态HTML页面 2) 动态的JSP页面 3) 容器中的Servlet 语法1: <jsp:forward page="{relativeURL|<%=expression%>}"/> 语法2: <jsp:forward page="{relativeURL|<%=expression%>}"> {<jsp:param.../>} </jsp:forward> 第二种语法用于在转发时增加额外的请求参数。增加的请求参数的值可以通过HttpServletRequest类的getParameter()方法获取 request.getParameter(""); 从本质上来说,jsp:forward这个动作指令只是一个内部转发,即<jsp:forward../>并没有重新向新页面发送了请求,它只是完全采用了新页面来对用户生成响应(内部转发),请求依然是一次
请求,所以请求参数、请求属性都不会丢失 2) jsp:include: 动态引入一个JSP页面,它不会导入被include页面的编译指令,仅仅将被导入页面的body内容插入本页面中 <jsp:include page="{relativeURL|<%=expression%>}" flush="true"/> 或者 <jsp:include page="{relativeURL|<%=expression%>}" flush="true"> <jsp:param name="parameterName" value="parameerValue"/> </jsp:include> 这里要注意和编译指令的inlcude进行区分 1) 静态引入(编译指令) <%@include file="file.jsp"%> 可以将外部文件嵌入到当前JSP文件中,同时解析这个页面中的JSP语句(如果有的话),也就是说,它既可以包含静态的文本,也可以包含动态的JSP页面。包含页面在编译时将完全包含了被包含
页面的代码。需要指出的是,静态包含还会将被包含页面的编译指令也包含进来,如果两个页面的编译指令冲突,那么页面就会出错 2) 动态引入(动作指令) <jsp:include> 归纳起来,动态导入和静态导入的区别有 1. 静态导入是将被导入页面的代码完全融入,两个页面融合成一个整体Servlet 2. 动态导入则在Servlet中使用include方法来引入被导入页面的内容 3. 静态导入时被导入页面的编译指令会起作用。 4. 动态导入时被导入页面的编译指令则失去作用,只是插入被导入页面的body内容 5. 动态导入可以增加额外的参数 实际上,forward动作指令和include动作指令(动态引入)十分相似,它们都采用方法来引入目标页面 forward指令使用_jspx_page_context.forward()方法来引入目标页面 include指令使用org.apache.jasper.runtime.JspRuntimeLibrary.include()方法来引入目标页面 区别在于,执行forward时,被forward的页面将完全代替原有的页面,而执行include时,被include的页面只是插入原有页面 即forward拿目标页面代替原有页面,而include则拿目标页面插入原有页面 3) JavaBean相关 3.1) jsp:useBean: 在JSP页面中初始化一个JavaBean的实例 <jsp:useBean id="name" class="Classname" scope="page|request|session|application"/> 3.1.1) id: JavaBean的实例名 3.1.2) class: 确定JavaBean的实现类 3.1.3) scope: 指定JavaBean实例的作用范围 3.1.3.1) page: 该JavaBean实例仅在该页面有效 3.1.3.2) request: 在本次请求有效 3.1.3.3) session: 在本次session内有效 3.1.3.4) application: 在本应用中一直有效 3.1.4) 3.2) jsp:setProperty: 设置JavaBean实例的属性值 <jsp:setProperty name="BeanName" property="propertyName" value="value" /> 3.2.1) name: JavaBean的实例名 3.2.2) property: 确定需要设置的属性名 3.2.3) value: 确定需要设置的属性值 3.3) jsp:getProperty: 输出JavaBean实例的属性值 <jsp:getProperty name="BeanName" property="propertyName" /> 3.3.1) name: 确定需要输出的JavaBean实例名 3.3.2) property: 确定需要输出的属性名 这三个指令都是与JavaBean相关的指令,如果多个JSP页面中需要重复使用某段代码,我们可以把这段代码定义成java类的方法,然后让多个JSP页面调用该方法即可,这样可以达到较好的代码
复用 在.jsp页面中我们可以这样编码 <!-- 创建lee.Person的实例,该实例的实例名为p1 --> <jsp:useBean id="p1" class="lee.Person" scope="page"/> <!-- 设置p1的name属性值 --> <jsp:setProperty name="p1" property="name" value="wawa"/> <!-- 设置p1的age属性值 --> <jsp:setProperty name="p1" property="age" value="23"/> <!-- 输出p1的name属性值 --> <jsp:getProperty name="p1" property="name"/><br/> <!-- 输出p1的age属性值 --> <jsp:getProperty name="p1" property="age"/> 从代码中可以看到,我们使用了useBean、setProperty、getProperty来操作JavaBean的方法,同时我们需要明白的是,对于property="name",在JavaBean中提供了setName()、
getName()方法来操作,property="age"也是同理 代码中对应的JavaBean的Person类源代码如下 package lee; public class Person { private String name; private int age; //无参数的构造器 public Person() { } //初始化全部属性的构造器 public Person(String name , int age) { this.name = name; this.age = age; } //name属性的setter和getter方法 public void setName(String name) { this.name = name; } public String getName() { return this.name; } //age属性的setter和getter方法 public void setAge(int age) { this.age = age; } public int getAge() { return this.age; } } 4) plugin指令 plugin指令主要用于下载服务器端的JavaBean、或Applet到客户端执行。由于程序在客户端执行,因此客户端必须安装虚拟机 5) param指令 param指令用于设置参数值,这个指令本身不能单独使用,因为单独的param没有实际意义。param指令可以与以下三个指令结合使用 5.1) jsp:include 当与include指令结合使用时,param指令用于将参数值传入被导入的页面 5.2) jsp:forward 当与forward指令结合使用时,param指令用于将参数值传入被转向的页面 5.3) jsp:plugin 当与plugin指令结合使用时,用于将参数传入页面中的JavaBean实例或Applet实例 <jsp:param name="paramName" value="paramValue"/> */
7. JSP脚本中的内置对象
JSP脚本中包含内置对象,这些内置对象都是Servleet API接口的实例,JSP规范对它们进行了默认初始化(由JSP页面对应的Servlet的_jspService()方法来创建这些实例)。即它们已经是对
象了,可以直接在JSP脚本中使用了 内置对象依次如下: 1) application: javax.servlet.ServletContext的实例,该实例代表JSP所属的WEB应用本身,因此可以使用application来操作WEB相关的数据,application对象通常有如下两个作用: 1.1) 在整个WEB应用的多个JSP、Servlet之间共享数据 application通过setAttribute(String attrName, Object value)方法将一个值设置成application的attrName属性,该属性的值对整个WEB应用有效,因此该WEB应用的每
个JSP页面或Servlet都可以访问该属性,访问属性的方法为getAttribute(String attrName) 1) put-application.jsp <% application.setAttribute("counter",String.valueOf(++i)); %> 2) get-application.jsp <%=application.getAttribute("counter")%> 3) GetApplication.java ServletContext sc = getServletConfig().getServletContext(); out.println(sc.getAttribute("counter")); 因为application代表的是整个WEB应用,因此可以在JSP、Servlet之间共享数据,由于在Servlet中并没有application内置对象,所以需要获取该web应用的ServletContext
实例,每个web应用只有一个ServletContext实例,而在JSP中可以直接通过application内置对象访问该实例 1.2) 访问WEB应用的配置参数 除了共享数据,application还可用于从web.xml中获得WEB应用的配置参数 //从配置参数中获取驱动 String driver = application.getInitParameter("driver"); 从以上的代码可以看到,可以使用application的getInitParameter(String paramName)来获取WEB应用的配置参数,这些参数应该在web.xml文件中使用context-param元素
配置,每个<context-param../>元素配置一个参数 <context-param> <param-name>driver</param-name> <param-value>com.mysql.jdbc.Driver</param-value> </context-param> 2) config对象 javax.servlet.ServletConfig类的实例,config对象代表当前JSP配置信息 <%=config.getServletName()%> 因为所有的JSP页面都有相同的名字: jsp,所以这段JSP代码永远输出jsp 实际上,我们也可以在web.xml文件中配置JSP,这样就可以为JSP页面指定配置信息,并为JSP页面指定一个虚拟路径 1) configTest2.jsp <!-- 输出该JSP名为name的配置参数 --> name配置参数的值:<%=config.getInitParameter("name")%><br/> <!-- 输出该JSP名为age的配置参数 --> age配置参数的值:<%=config.getInitParameter("age")%> 2) web.xml <servlet> <!-- 指定Servlet名字 --> <servlet-name>config</servlet-name> <!-- 指定将哪个JSP页面配置成Servlet --> <jsp-file>/configTest2.jsp</jsp-file> <!-- 配置名为name的参数,值为yeeku --> <init-param> <param-name>name</param-name> <param-value>yeeku</param-value> </init-param> <!-- 配置名为age的参数,值为30 --> <init-param> <param-name>age</param-name> <param-value>30</param-value> </init-param> </servlet> <servlet-mapping> <!-- 指定将config Servlet配置到/config URL--> <servlet-name>config</servlet-name> <url-pattern>/config</url-pattern> </servlet-mapping> 3) exception对象 exception对象是Throwable的实例,代表JSP脚本中产生的错误和异常,是JSP异常机制的一部分。在JSP脚本中无须处理异常,即使该异常是checked异常,JSP脚本包含的异常都可以交
给错误处理页面处理,exception对象也仅在异常处理页面中才有效。 打开普通的JSP页面所生成的Servlet类,可以看到如下代码段 public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response) throws java.io.IOException, javax.servlet.ServletException { .. try { response.setContentType("text/html; charset=GBK"); .. out.write(\' \'); } catch (java.lang.Throwable t) { .. if (_jspx_page_context != null) _jspx_page_context.handlePageException(t); else throw new ServletException(t); } finally { _jspxFactory.releasePageContext(_jspx_page_context); } } 从以上代码可以看出,JSP脚本和静态HTML部分都已经转换成_jspService()方法里的执行型代码,这就是JSP脚本无须处理异常的原因,因为这些脚本都已经被包含在try块中了。一旦try
块中捕捉到JSP脚本的异常,并且_jspx_page_context不为null,就会由该对象来处理异常。_jspx_page_context对异常的处理也非常简单: 如果该页面的page指令指定了errorPage属性
,则将请求forward到errorPage属性指定的页面,否则使用系统页面来输出异常信息 4) out对象 out对象代表一个页面输出流,通常用于在页面删输出变量值、及常量。所有使以上是关于JSP/Servlet基础语法的主要内容,如果未能解决你的问题,请参考以下文章