Scott Johnson:JavaServer Pages 新手入门

JavaServer Pages (JSP) 技术深度解析手册 本文还有配套的精品资源,点击获取 简介:JSP,即JavaServer Pages,是一种用于创建动态网页的Java技术。本技术手册详细介绍了JSP的组成、生命周期、指令和内置对象等核心概念,并探讨了其在现代Web开发中的应用场景。内容涵盖了JSP的基本结构、页面生命周期、指令类型、内置对象、表达式语言、动作标签的使用,以及Servlet与JSP的关系。还讨论了会话管理、安... 阅读详情

评论专栏: Scott Johnson:JavaServer Pages 新手入门

developerWorks
文档选项
将此页作为电子邮件发送

将此页作为电子邮件发送


拓展 Tomcat 应用

下载 IBM 开源 J2EE 应用服务器 WAS CE 新版本 V1.1


级别: 初级

Scott Johnson (scottjoh@us.ibm.com), 软件工程师, IBM

2007 年 4 月 17 日

JavaServer Pages™ 技术已推出了多年,但对其的了解程度仍然不够。尽管本文针对初学者,其中对 JSP 容器如何工作的准确说明却对各个层次的读者都会有所帮助。

摘自 IBM WebSphere 开发者技术期刊。

历史回顾

JavaServer Pages 上个世纪就已推出,但我认为大家对其的了解仍然不够。作为 WebSphere® Application Server 的 JSP 容器的负责人,我非常关心是否有唾手可得的针对新手的信息,用以说明 JSP 容器如何工作。但我没有发现任何足够详细的东西,同时我也认为并非所有人都了解 JSP 技术。我撰写本文的目的就是为了填补这个空白:作为说明两个主要 JSP 处理阶段(转换和请求阶段)实践细节的初级读本,我希望这其中的信息对您有用,另外还希望您能从中得到一些意外的惊喜。本文甚至还可能会提高您的 JSP 的质量!

示例代码

本文最后提供了一个示例 JSP 文件 codegen.jsp,在本文中我将多次引用其中的内容。该 JSP 说明了两种在 Nameclass 类中设置 name 属性的不同方法。JSP 包含了各种 JSP 语法元素,这使得我们的讨论非常有意思。我对在本文中讨论的代码行进行了突出显示(以粗体显示)。如果您希望自己运行该 JSP,请在浏览器中使用与以下所示类似的 URL 调用 codegen.jsp(请求参数 nameParam 和 tableColor 是可选的):

 http://localhost:9080/yourapp/codegen.jsp?nameParam=Your Name&tableColor=red

如果使用此 URL 调用 codegen.jsp,浏览器将显示下图所示的内容:


图 1. 调用 codegen.jsp
图 1. 调用 codegen.jsp




回页首


转换阶段

那么,什么是 JSP 页?

JSP 技术从来不是为了支持二进制数据而提供的,无论在 JSP 页本身中还是在页生成的响应中均是如此。

在转换阶段,JSP 容器将对 JSP 页进行处理。JSP 页是一种文本文档。它可以完全由单个文本文件组成。它也可以包括一个主文本文件(“顶级”JSP 文件)和其他通过 JSP include 指令静态包括的文本文件。JSP include 指令是与以下内容类似的 JSP 语法元素:

 <%@ include file="relativeURL" %>

在本文最后的 codegen.jsp 代码示例中提供了一个示例 <%@ include file="nameclass.jspf" %>。“静态地包括”文件,指所包括的文件的实际内容(JSP include 指令中的“relativeURL”)准确放置在 JSP 页中 include 指令所在的位置,而 include 指令本身将被丢弃。从某种意义而言,JSP 页是内存中的构造,因为除非使用能识别 JSP 的特殊开发工具,能在相应的位置看到所包括的内容,否则在 JSP 中包含静态包括进来的文件时,就永远无法实际看到 JSP 页的整个内容。

JSP 文件中根本不需要任何 JSP 语法内容。它并不必包括特定于 JSP 文件的任何内容。有效的 JSP 文件甚至可以仅仅包括“Hi there!”。之所以它是 JSP 文件,是因为要将其交付给 JSP 容器进行处理。在应用服务器中,对任何带 jsp 或 jspx 扩展名的文件的请求都将发送到 JSP 容器进行处理,而不管其中的内容如何。不过,文件中的内容也很重要!并非所有采用 JSP 扩展名的文件都是有效的 JSP 文件。

在转换阶段会发生什么?

在转换期间,必须将 JSP 页(也称为转换单元)从文本转换为可执行形式,以便能在应用服务器内运行。JSP 页的可执行形式是实现 javax.servlet.Servlet 接口的 Java 类。这意味着会将 JSP 页转换为传统 Servlet(更具体一些,HttpServlet),以在应用服务器的 Web 应用程序内运行。在 JSP 术语中,此 Servlet 称为 JSP 页实现类。WebSphere Application Server 的 JSP 容器通过三个步骤执行此转换过程:

  1. 验证
  2. Java 源代码生成
  3. Java 源代码编译

JavaServer Pages 规范将此称为 JSP 处理的转换阶段。

1. 验证

JSP 容器确保 JSP 页的语法正确,当遇到错误时会生成提供相关信息的错误消息。为了验证 JSP 页语法是否正确,JSP 容器将逐字符读取页内容,对页的内容进行分析。JSP 容器将寻找其能识别的字符序列,此类序列指示其中存在需要进行处理的语法内容。

a. include 指令

例如,我在前面给出的 JSP include 指令以 <%@ 作为开头。这三个字符形成了 JSP 指令语法的开始序列。(JSP 总共定义了六个指令,而仅三个指令对 JSP 标记文件有效。)

以 codegen.jsp 中的 include 指令为例:

 <%@ include file="nameclass.jspf"%>

JSP 容器将识别 <%@,并将随后查找有效的 JSP 指令名,如“include”或“page”。在我们的示例中将找到“include”,JSP 容器知道下一个字符序列一定为“file=”,因为 include 指令只有一个有效属性。如果该指令最后以 %> 正确结束,且“file=”的值为 JSP 容器能够找到并读取的文件名(在我们的示例中为 nameclass.jspf),则会随后将该文件的内容包括在 JSP 页的相应位置中,其方式如我前面所述。对所包括的文本也会进行验证。必须对其进行验证,因为它现在是 JSP 转换单元的一部分,必须符合 JSP 语法规则。

如果静态包括的文件也通过 include 指令静态包括其他文件,则也会将其包括在相应的位置中。对于嵌套 include 的数量并没有实际限制(不过,如果嵌套过深,会非常容易混淆,难以理清关系)。唯一的限制是,不允许循环 include;即不能 JSP 文件 A 静态地包括 JSP 文件 B,然后 B 又静态地包括 A。JSP 容器会识别这种情况,如果出现,会挂起验证过程,并给出一条错误消息。

在 WebSphere Application Server 中,所有这些静态 include 都实际在验证真正开始前执行——以便在内存中具有完整的 JSP 页/转换单元,从而在确定最终的 JSP 页中包含了创建者希望包含的每个文件的情况下进行验证。

b. 自定义标记验证(使用属性中的表达式语言表达式)

任何人都可以编写 JSP 自定义标记,然后以标记库的形式将其提供给 JSP 创建者使用。标记库是自定义标记实现的集合。JavaServer 标准标记库(JavaServer Pages Standard Tag Library,JSTL) out 标记之类的自定义标记将具有一些必选属性和一些可选属性。以下是 codegen.jsp 中的 JSTL out 标记示例用法:

 <c:out value='Just set the name from request!
[${nameBean.name}]' default="null"/>

JSTL out 标记只具有一个必选属性,即 value 属性。如果 value 属性及其值未出现,则 JSP 容器将生成错误。在此示例中,value 属性是一些文本的组合内容:

 Just set the name from request! []

在文本中嵌入了一个表达式语言(Expression Language,EL)表达式:

 ${nameBean.name}
对于 JSP 2.1 和 JavaServer Faces 1.2,统一表达式语言 (Unified Expression Language) 使用语法 #{expr} 定义了一种表达式类型。

EL 表达式以“${”开头,以“}”结束。在我们的示例中,JSP 容器必须验证表达式 ${nameBean.name} 的语法。在这种情况下,该表达式语法有效。不过请注意,如果创建者犯了错误(例如 nameBean 上没有 name 属性),表达式可能会无法成功执行。我们到目前为止所进行的全部工作都是对表达式的语法进行验证,而不是验证逻辑。

在缺省情况下,我们遇到的其他属性会被视为有效属性,但这些属性是可选的,其值可以为字符串常量(在我们的示例中就是如此)。因此这个自定义标记的示例用法通过了验证。我们将稍后看到在实现 Servlet 中生成的 Java 代码的情况。

c. 标记库描述符中的代码片段

JSP 容器如何知道自定义标记的哪些属性是必选的哪些是可选的?它通过读取标记的元数据来确定需要知道自定义标记的哪些信息。元数据位于标记库描述符(Tag Library Descriptor,TLD)文件中,自定义标记实现的创建者必须提供此文件。(上面的示例是 out 标记在 JSP 页中的用法,另外存在实际进行此工作的 out 标记的实现。)

以下说明 JSP 容器要读取和分析什么内容来知道哪些属性在 out 标记中有效。出于篇幅考虑,我省略了一些内容,并将相关的部分用粗体加以突出显示。


清单 1
                
<tag>
  <description>
     Like <%= ... >, but for expressions.
  </description>
  <name>out</name>
                <tag-class>org.apache.taglibs.standard.tag.rt.core.OutTag</tag-class>
                This is the implementation class for the out tag.	
  <body-content>JSP</body-content>
  <attribute>
     <description>
        Expression to be evaluated.
     </description>
     <name>value</name>
                The value attribute is required...
                <required>true</required>
     <rtexprvalue>true</rtexprvalue>
		
                    ...and it is allowed to contain a 'runtime
                
                
                    expression value', like our EL expression.
                
  </attribute>
  <attribute>
     <description>
        Default value if the resulting value is null.
     </description>
     <name>default</name>
                The default attribute is not required.
                <required>false</required>
     <rtexprvalue>true</rtexprvalue>
  </attribute>
  <attribute>
     <name>escapeXml</name>
		The escapeXml attribute is not required.
     <required>false</required>
     <rtexprvalue>true</rtexprvalue>
  </attribute>
</tag>

d. jsp:useBean 验证

另一个例子是对强大的 jsp:useBean 标准操作的验证。验证 jsp:useBean 标记时,如以下标记:

 <jsp:useBean id="nameBean"
class="codegen.Nameclass" scope="request" />
JSP 标准操作与自定义标记非常相似,不过它是直接构建到 JSP 技术中的。有近 20 个标准操作,包括 <jsp:setProperty>、<jsp:include>、<jsp:forward> 和 <jsp:param>。

JSP 容器必须验证很多东西。每个属性具有自己的验证规则,另外还有关于如何处理属性组合的规则。与自定义标记不同,jsp:useBean 之类的 JSP 标准操作并不具有类似 TLD 的元数据文件。相反,关于哪个属性是必选属性的规则(可以为运行时表达式等等)要由容器的创建者写入到 JSP 容器的验证代码中(当然,创建者需要已经阅读并全面了解 JSP 规范关于 jsp:useBean 操作规则的六页详细说明)。

在这个简单的示例中,JSP 容器验证所需的 ID 属性的值“nameBean”在转换单元中是唯一的。例如,如果此 JSP 页中的另一个 jsp:useBean 标记也使用“nameBean”作为 ID,则 JSP 容器将生成错误。jsp:useBean 操作要求必须给出 class 或 type 属性,本例中给出了 class。最后,容器将验证可选的 scope 属性的值是允许的四个值之一:“page”、“request”、“session”或“application”。这个 useBean 标记通过了验证,我们将稍后讨论生成的代码。

e. 模板文本

JSP 页的验证期间,如果 JSP 容器并不能识别文本序列,则不会尝试对其进行处理,而是准确地按照其在 JSP 页中出现的样子直接将其放入 JSP 页实现类中。

例如,仅包含“Hi there!”的简单 JSP 文件并不具有 JSP 容器需要进行处理的任何文本序列。这样的序列称为模板文本或模板数据。JSP 规范按以下方式对其进行处理:

JSP 页具有元素和模板数据。元素是 JSP 容器已知的元素类型的实例。其他的都是模板数据,即所有 JSP 转换器不知道的内容。

HTML 是模板文本;JSP 技术并不知道如何解析或验证 HTML 标记(如 codegen.jsp 中的 <html><head><title>)。这意味着可以将 HTML 嵌入到 JSP 页,会在页执行时直接将此内容发送到浏览器。(事实上,这是在二十世纪九十年代发明 JSP 技术时的初衷之一。)另外,还可以将 HTML 与表达式组合,从而得到动态 HTML。以 codegen.jsp 的代码为例:

 <table bgcolor=${tableColorVar} border="0" width="25%">

JSP 容器解析此文本时,会将 HTML 文本 <table bgcolor= 直接发送到实现 Servlet。但它会将 ${tableColorVar} 识别为 EL 表达式,并验证其语法是否正确(正确)。正如我们将要在 Java 源代码生成主题中看到的,容器将为 EL 表达式生成特殊的 Java 代码。不会对此行剩下的内容 border="0" width="25%"> 进行验证,将按原样置于实现 Servlet 中。

f. 脚本元素

JSP 中的脚本元素包括声明、scriptlet 和表达式。(JSP 脚本元素与 JSP EL 表达式差别很大。)在脚本元素内放置的是 Java 代码。声明语法为 <%!... %>,scriptlet 语法为 <% ...%>,表达式语法为 <%= ... %>。

JSP 容器并不验证这三个元素内的内容。JSP 容器并不知道如何解析 Java 代码。无论在声明、scriptlet 或表达式中是什么内容,都必须为有效的 Java,否则就无法成功编译实现类中的 Java 代码。从这个方面来说,脚本元素与模板文本非常相似,因为 JSP 容器并不会对其中的内容进行验证,而会直接将这些内容传递到 JSP 页实现类中。我在脚本元素的代码生成主题中对此进行了说明。

g. 二进制数据试验

前面我说过,JSP 页是可阅读的文本文档。如果在文本文件编辑器查看二进制文件,会看到类似于 PyY y? üüy÷÷ùyì 之类的字符。此数据可能在图形交换格式(Graphics Interchange Format,GIF)文件中有意义,但在 JSP 文件中就没有意义了。不过,作为试验,请尝试将 GIF 文件更名为带 .jsp 扩展名的文件,在 WebSphere Application Server 中请求该文件,看看会发生什么情况。尽管 GIF 是二进制文件类型,GIF 图像仍然很可能在浏览器中正常显示。这可能有效的原因是,如果 JSP 容器在转换阶段未找到任何可识别的字符序列,会直接将所有数据按原样包含在其创建的 JSP Servlet 中。Servlet 将执行并将输出数据,而数据是 GIF 文件的原始内容。浏览器将接受响应数据,并将其重新组织为 GIF,然后显示图像。不过,如果文件碰巧包含 JSP 容器在转换期间识别的字符序列(例如 <%@),则会尝试处理后续字符,而这些后续字符很可能在 JSP 语法中无效。JSP 容器将引发转换异常,甚至都不会继续创建页实现 Servlet。

h. 验证完成时

当 JSP 容器确定 JSP 页的语法有效时,会进入下一个处理阶段:代码生成。容器在验证阶段会实际收集大量的信息,现在将使用这些信息来恰当地生成 Java 代码。

2. Java 源代码生成

如果 JSP 页有效,JSP 容器会将 JSP 页中的文本转换为 Java 源代码,而此源代码将成为 JSP 页实现类。在本文最后提供了实际 .java 代码一个非常详细的 _codegen.java,此文件是由 WebSphere Application Server 为 codegen.jsp 示例所生成的。在此代码中,将看到 out.write() 和 out.print() 的很多实例。这些 Java 方法是向浏览器发送响应数据供显示的方法。

a. 自定义标记属性中的 EL 表达式的代码生成

以下面的代码为例,这是我们在前面了解自定义标记验证如何工作时所涉及的内容。现在我们将讨论 JSP 容器生成的 Java 代码。

 <c:out value='Just set the name from request!
[${nameBean.name}]' default="null"/>

前面我说过,此示例说明了 JSTL out 标记的用法,存在实际进行此工作的标记的实现。JSP 容器生成的 Java 代码必须能够在运行时调用该实现类。JSP 容器需要发现实现 out 标记的类的名称。它在标记库描述符中查找此信息。out 标记的实现类的名称位于以下位置:

 <tag-class>org.apache.taglibs.standard.tag.rt.core.OutTag</tag-class>
this is the implementation class for the out tag

获得此信息后,容器将生成以下 Java 代码,此代码位于 _codegen.java 中的方法 _jspx_meth_c_out_1() 内。


清单 2
                
Line 1	private boolean _jspx_meth_c_out_1(JspTag _jspx_th_c_when_0, 
		PageContext pageContext) throws Throwable {
Line 2		org.apache.taglibs.standard.tag.rt.core.OutTag _jspx_th_c_out_1 = new OutTag();
Line 3		_jspx_th_c_out_1.setValue((Object) PageContextImpl.proprietaryEvaluate("Just 
			set the name from request![${nameBean.name}]"));
Line 4		_jspx_th_c_out_1.setDefault("null");


清单 2 的表
代码行描述
2创建 c:out 标记的实现类的实例,并将其放入变量 _jspx_th_c_out_1 中。
3对该实例变量调用 setValue() 方法,以设置我们希望 out 标记根据浏览器返回的值。不过此值包含一个 EL 表达式 ${nameBean.name}。EL 表达式要求特殊处理,因为其表示的是运行时动态发现的值,与从来不会改变的静态文本不同。WebSphere Application Server 用于支持运行 nameBean.name 值的运行时发现的机制是调用 proprietaryEvaluate() 方法。在运行时执行 OutTag 类时,它将使用 proprietaryEvaluate() 来查找 nameBean.name 的当前值,并会将表达式 ${nameBean.name} 替换为当前值,然后将文本字符串返回给浏览器。
4调用 setDefault() 来设置 default 属性的值。

b. 另一个自定义标记代码生成示例

codegen.jsp 文件中下面的代码片段检查是否存在名为 tableColor 的请求参数。如果该参数存在,它会将 tableColorVar 变量设置为该请求参数的值。(将在下面看到如何使用 tableColorVar。)


清单 3
                
<c:if test='${not empty param.tableColor}'>
   <c:set var="tableColorVar" value="${param.tableColor}"/>
</c:if>

这些操作是通过 _codegen.java 的 _jspService() 方法中的单个方法调用来调用的。

 if (_jspx_meth_c_if_0(pageContext)) return;

方法 _jspx_meth_c_if_0() 包含对 JSTL c:if 标记的实现的调用。以下是对该方法最重要的部分的说明:


清单 4
                
Line 1	private boolean _jspx_meth_c_if_0(PageContext pageContext) throws Throwable {
Line 2		org.apache.taglibs.standard.tag.rt.core.IfTag _jspx_th_c_if_0 = new IfTag();
Line 3		_jspx_th_c_if_0.setPageContext(pageContext);
Line 4		_jspx_th_c_if_0.setParent(null);
Line 5		_jspx_th_c_if_0.setTest(((Boolean) PageContextImpl.proprietaryEvaluate("${not 
			empty param.tableColor}")).booleanValue());
Line 6		int _jspx_eval_c_if_0 = _jspx_th_c_if_0.doStartTag();
Line 7		if (_jspx_eval_c_if_0 != Tag.SKIP_BODY) {
Line 8			do {
Line 9				if (_jspx_meth_c_set_1(_jspx_th_c_if_0, pageContext)) return true;


清单 4 的表
代码行描述
2创建 c:if 标记的实现类的实例,并将其放入变量 _jspx_th_c_if_0 中。
5对该实例变量调用 setValue() 方法,以设置我们希望在方法执行时评估运行时的测试条件。对于上面的 c:out 示例,EL 表达式 ${not empty param.tableColor} 将由 proprietaryEvaluate() 方法进行评估。
6c:if 标记实现类通过 doStartTag() 方法执行。doStartTag() 将在 _jspx_eval_c_if_0 中返回一个值。
7如果 _jspx_eval_c_if_0 不等于常量值 Tag.SKIP_BODY,则意味着 EL 表达式计算结果为 true:存在名为 tableColor 的请求参数!
9将执行另一个方法:_jspx_meth_c_set_1()。可以在 _codegen.java 代码片段中看到此方法。此方法检索请求参数 tableColor 的值(我们现在已经知道存在此参数),并将该值放入 tableColorVar 变量中(我们将稍后使用)。

c. jsp:useBean 操作的代码生成

我们在前面讨论模板文本的验证时使用了这个模板文本示例:

 <jsp:useBean id="nameBean"
class="codegen.Nameclass" scope="request" />

JSP 规范对 jsp:useBean 操作的描述如下:

jsp:useBean 操作相当灵活;其准确语义取决于所给定的属性。基本语义尝试使用 id 和 scope 找到现有对象。如果未找到对象,将会尝试使用其他属性创建对象。

我们的 jsp:useBean 用法满足上面描述的“基本语义”。WebSphere Application Server 生成以下代码:


清单 5
                
Line 1	codegen.Nameclass nameBean = null;  
Line 2	synchronized (pageContext) {	
Line 3		nameBean = (codegen.Nameclass) pageContext.getAttribute("nameBean", 
			PageContext.REQUEST_SCOPE);
Line 4		if (nameBean == null) {
Line 5			nameBean =  new codegen.Nameclass();
Line 6			pageContext.setAttribute("nameBean", nameBean, PageContext.REQUEST_SCOPE);
Line 7		}
Line 8	}


清单 5 的表
代码行描述
1定义在 class="codegen.Nameclass" 中给定的类型的 nameBean 变量
2同步对 pageContext 的访问,因为可以并发执行其他线程。
3在“request”范围中获得名为“nameBean”的对象。
4-6如果未找到 nameBean,使用“request”范围创建它并存储。

此生成的代码直接遵循 JSP 规范为这个简单的 jsp:useBean 用法描述的规则。

d. 包含嵌入 EL 表达式的模板文本的代码生成

我们在前面讨论模板文本的验证时使用了这个模板文本示例:

 <table bgcolor=${tableColorVar} border="0" width="25%">

WebSphere Application Server 从此示例生成以下代码:


清单 6
                
Line 1	out.write("/r/n<table bgcolor=");
Line 2	out.write((java.lang.String) 
		PageContextImpl.proprietaryEvaluate("${tableColorVar}"));
Line 3	out.write(" border=/"0/" width=/"25%/">);


清单 6 的表
代码行描述
1JSP 容器在遇到 ${tableColorVar} 前并未发现任何需要处理的语法。因此第一部分将按原样输出到 _codegen.java 中(包括回车和换行)。
2但 ${tableColorVar} 是 EL 表达式,直接将 out.write("${tableColorVar}"); 放置到 _codegen.java 中将无法完成 JSP 页的创建者希望进行的工作。创建者希望 ${tableColorVar} 为动态运行时值。与上面描述的 c:out 标记生成类似,JSP 容器将生成对 proprietaryEvaluate() 的调用,而后者将为 tableColorVar 发现运行时值。
3模板文本的最后一部分将按原样输出到 _codegen.java 中——JSP 容器会添加反斜杠,以便将引号作为文本输出。

此模板文本示例的代码生成结果为实现类中的三行 Java 代码。浏览器中所得到的 HTML 将与以下所示类似:

 <table bgcolor=blue border="0"
width="25%">

HTML 表将在浏览器中以蓝色背景显示。

上面的示例假定,与以下类似的请求 URL 导致 ${tableColorVar} 在运行时解析得到的值为“blue”:

 http://localhost:9080/yourapp/codegen.jsp?nameParam=Your Name&tableColor=blue

e. 脚本元素的代码生成

JSP 容器对 scriptlet、表达式和声明的处理各不相同。

表达式(如 codegen.jsp 中的 <%=nameClass.getName()%>)转换为 _codegen.java 中与以下所示类似的 Java 代码:

 out.print(nameClass.getName());

<%=nameParam%> 之类的表达式转换为与以下所示类似的 Java 代码:

 out.print(nameParam);

在这两个示例中,无论在表达式中找到什么,都会将其作为页实现类的服务方法内的 out.print() 语句(有时候也可以是 out.write())参数。

有效声明(如 nameclass.jsp 中 Nameclass 的声明)将不加修改地放入 _codegen.java 中的页实现类的类级别,而不是在服务方法内。这是 _codegen.java 的一部分,以下面的代码开头:

 public class Nameclass {
private String name="";

我们在前面将 nameclass.jsp 以静态方式包括到 JSP 页中 JSP include 指令所在的位置。在 Java 代码生成期间,JSP 容器接受此代码块,根据声明 JSP 规则将其移动到一个完全不同的地方(在类级别)。

<% if (nameParam != null){nameClass.setName(nameParam);%> 之类的有效 scriptlet 将直接被发送到实现类的服务方法中:

 if (nameParam != null){nameClass.setName(nameParam);

请记住,JSP 容器将以逐个字符的方式对页进行解析。标识了这三个脚本元素之一的开头部分后,还必须确定其结束位置。因此,如果碰巧错误理解了 scriptlet 的工作方式,并尝试在 scriptlet 中使用表达式来动态地初始化 Java 变量,将会失败。下面的示例说明了这个错误:


清单 7
                
<% if (nameParam != null){nameClass.setName(nameParam);
   String theName=new String("<%=nameParam%>");
//   trying to instantiate a Java variable called theName
   out.print(theName);
//   using a JSP expression inside a scriptlet.
%>

新手可能认识不到脚本并非设计用于处理三个元素的任何组合,从而不能编写出正常的代码。在本例中,JSP 容器识别到 scriptlet 的开始部分 (<% if (nameParam != null){...),但随后遇到 %>(表达式 <%=nameParam%> 的结尾)时会将其视为 scriptlet 的结尾。这会导致生成的 Java 代码无效。

多年前,JSP 2.0 规范建议避免脚本元素。为何我(以及其他很多人)反对在 JSP 内使用 Java 代码呢?

  1. 这非常危险。我最近花了很多时间对客户的故障应用程序进行调试。开发人员迷失了方向。我们对他们的所有 JSP 进行了分析。最后,我发现他们通过声明元素声明了很多全局变量(类实例变量)。当 JSP 在多用户环境中执行时,一个特别重要的变量被一个用户的请求线程更改了,而此时正在处理另一个用户的请求线程。这样做的结果是,响应输出被严重地破坏了。这些开发人员非常尴尬,但我告诉他们这是一个很常见的错误,特别在没有注意到是单个 Servlet 处理所有请求时更容易出现这样的问题!如果选择采用脚本元素则很容易犯这样的错误,因此最好彻底避免使用脚本元素。

  2. 它使得 JSP 难以阅读和调试。通常将看到与 codegen.jsp 中类似的语法,after <!-- ***** but scripting is used here ***** -->.分析这个微型 JSP 中的脚本代码并不容易。零散的大括号(例如 <%}%>)很容易混淆,但在 JSP 中嵌入 Java 时需要此类括号来让 Java 代码保持有效和完整。当 JSP 包含数百或数千行 HTML、JSP 语法和 Java 脚本的混合代码时,将很容易成为您的维护与调试的拦路虎。

f. jspInit() 与 jspDestroy()

如果 JSP 页创建者希望 JSP 页具有 init 和 destroy 方法时,必须使用脚本。具体来说,必须在 JSP 页中包含声明这些方法的 JSP 声明。此类 JSP 页必须与以下所示类似:


清单 8
                
<%!
public void jspInit()
{
  // do some initialization work
}
public void jspDestroy()
{
  // do some finalization work
}
%>
<HTML>
  <BODY>
      Your JSP stuff here!
  </BODY>
</HTML>

g. 一首打油诗

我在这里给出了一首关于 JSP 脚本元素的打油诗(虽然有点不押韵),虽不太出名但非常切题。

There once was a coder from France(法国有个程序员)
Who wrote by the seat of his pants(每天编码轮轴转)
When his JSPs broke(他的 JSP 崩溃后)
He collapsed, and then spoke:(他也崩溃着忍不住低声吼:)
“I used scriptlets in my ignorance!”(使用 scriptlet 真是难!)

h. 代码生成完成时

当 JSP 容器完成 .java 文件生成后,将进入下一个处理阶段:Java 编译。

3. Java 源代码编译

* 实现类并不必驻留在磁盘上。WebSphere Application Server 将来版本中的 JSP 容器将支持 JSP 的可选内存中的转换与编译。在此操作模式中,JSP 实现类(生成的 .java 和 .class 文件)将永远不会保存到磁盘,从而节约了磁盘 I/O 周期和磁盘资源。

JSP 容器编译其生成的 .java 文件。Java 编译工作将创建二进制类(JSP 页实现类),这些二进制类将作为 .class 文件驻留在磁盘上。* 如果出现 Java 编译错误,将生成标识错误的错误消息、JSP 行号以及出现错误的对应 .java 源文件行号。

WebSphere Application Server 和大多数 JSP 容器一样,支持 Eclipse Java Development Tools (JDT) 编译器和 JDK 的 javac。WebSphere Application Server 从 V6.1 开始支持 JDT 编译器。JDT 编译器是 JSP 容器的缺省 Java 编译器,因为该编译器在开放服务网关协议(Open Services Gateway Initiative,OSGi)环境中可非常高效地操作。





回页首


请求阶段

当在运行的应用服务器中请求 JSP 时,会调用其页实现 Servlet 类。对于每个请求,Servlet 的服务方法将在自己的线程(即执行请求的线程)上执行。这样,单个 JSP Servlet 可以处理多个并发请求。

WebSphere JSP 容器通过两种方式参与请求阶段的工作:

  1. 运行时支持:提供 Servlet 所使用的类和方法。这称为运行时支持。例如,我们前面看到的 proprietaryEvaluate() 方法就是一个运行时支持方法。
  2. 重载:检查以确定用于创建 Servlet 的 JSP 源文件是否被修改而需要进行重新转换。请参见下面的 JSP 重载。

可在此处找到关于 WebSphere JSP 容器在请求阶段的角色的详细讨论。

JSP Servlet 的性能障碍

尽管 JSP Servlet 只是一个普通 Servlet,但永远不会像不采用 JSP 技术而手动编写的等价 Servlet 那样执行。这是因为 JSP 容器生成的 JSP Servlet 必须满足很多使 JSP 技术更为强大和易用的要求。

例如,生成的 JSP Servlet 必须提供名为 pageContext 的 Java 对象(将在下面说明),每个 _jspService() 方法调用必须获得此对象并初始化一些其他变量:


清单 9
                
pageContext = _jspxFactory.getPageContext(this, request, response, null, true, 
	8192, true);
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();

以下的 pageContext 对象的说明摘自 JSP 规范:

PageContext 可为页/组件创建者和页实现人员提供一系列机制,包括:

  • 用于管理各种范围的命名空间的单个 API
  • 用于访问各种公共对象的一系列使用方便的 API
  • 获取 JspWriter 进行输出的机制
  • 用于通过页管理会话用法的机制
  • 用于将页指令属性公开给脚本环境的机制
  • 用于转发或将对其他活动组件的当前请求包括到应用程序中的机制
  • 用于处理 errorpage 异常处理的机制

如果要在不使用 JSP 技术的情况下编写 _codegen.java Servlet,则编写 codegen.jsp 并让 JSP 容器生成 Servlet 的工作将更为困难。但如果手动编写的 Servlet 并不需要上面所述的机制,则不必提供这些东西,得到的 Servlet 将比生成的 Servlet 更为轻量,执行的速度更快。

JSP 重载

当 JSP 源文件被修改且随后被请求时,可以对其进行重载。重载涉及到对请求的 JSP 执行整个转换阶段,从而生成新的 JSP 实现类。这个新类反映对 JSP 源代码的修改,将随后被重载并调用。

JSP 规范并不强制 JSP 容器在 JSP 正在运行的 Web 应用程序中被修改时转换和重载 JSP。不过,所有的 JSP 容器均提供此功能。运行时 JSP 重载是 JSP 源代码频繁更改的环境中一项非常方便的功能。

WebSphere Application Server 提供了多种方式来配置 JSP 重载。

静态 include 与动态 include

JSP 技术提供两种 include(静态与动态)。这两种 include 类型经常彼此混淆。

我们已经看到过以下的静态 include 示例:

 <%@ include file="nameclass.jspf" %>

静态 include 由 JSP 容器在转换阶段进行处理(此时 JSP 容器正在内存中构造 JSP 页)。

动态 include(称为 jsp:include 标准操作)在请求阶段执行。

动态 include 的语法如下:

 <jsp:include page="urlSpec"
flush="true|false"/>

如果 JSP 包含以下 include 操作:

 <jsp:include page="myInclude.jsp" flush="true "/>

则 JSP 容器将生成以下 Java 代码:

 JspRuntimeLibrary.include(request, response, "myInclude.jsp", out, true);

在请求阶段执行此代码行时,将调用 myInclude.jsp,且将其输出包含在当前 JSP 的输出中。JSP 规范这样描述 include 操作:

include 操作将 JSP 页之类的资源视为动态对象;即请求将被发送到该对象,且将包含处理的结果。





回页首


结束语

我希望本文能帮助您了解 JSP 容器如何验证 JSP 页、为页的实现 Servlet 生成 Java 代码以及参与请求处理。请研究下面的示例代码和生成的源代码,通过实际的例子巩固本文讨论的内容。





回页首


示例 A


清单 10. codegen.jsp(顶级 JSP 文件)
                
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html><head><title>Code Validation and Generation Sample</title></head>
<body>

<!-- ***** no scripting is used here ***** -->
<jsp:useBean id="nameBean" class="codegen.Nameclass" scope="request" />
<table>
<tr><td><c:out value='Checking to see if name is given in the request...'/></td></tr>
<c:choose>
    <c:when test='${not empty param.nameParam}'>
        <jsp:setProperty name="nameBean" property="name" value='${param.nameParam}'/>
        <tr><td><c:out value='Just set the name from request! [${nameBean.name}]'
                default="null"/></td></tr>
    </c:when>
    <c:otherwise>
        <tr><td><c:out value='Name not supplied on request...'/></td></tr>
        <jsp:setProperty name="nameBean" property="name" value="J. Doe"/>
        <tr><td><c:out value='... so we set it to [${nameBean.name}]'/></td></tr>
    </c:otherwise>
</c:choose>
</table>
</br>

<!-- ***** but scripting is used here ***** -->
<%@ include file="nameclass.jspf" %>
<%Nameclass nameClass = null;String nameParam=(String)request.getParameter("nameParam");%>
<%nameClass=new Nameclass();%>
<table>
<tr><td>Checking to see if name is given in the request...</td></tr>
<% if (nameParam != null){nameClass.setName(nameParam);%>
   <tr><td>Just set the name from request! [<%=nameParam%>]</td></tr>
<%}else{ %>
   <tr><td>Name not supplied on request...</td></tr>
   <% nameClass.setName("J. Doe");%>
   <tr><td>...so we set it to [<%=nameClass.getName()%>]</td></tr>
<%}%>
</table>
</br>

<!-- ***** results table ***** -->
<c:set var="tableColorVar" value="blue" scope="request" />   
	<!-- ***** blue is the default table color ***** -->
<c:if test='${not empty param.tableColor}'>
                <c:set var="tableColorVar" value="${param.tableColor}"/>
                </c:if>
                <table bgcolor=${tableColorVar} border="0" width="25%">
<tr><td bgcolor="lightgray">Name from EL expression <b>(/${nameBean.name})</b></td>
<td><font color="white">${nameBean.name}</font></td></tr>
<tr><td bgcolor="lightgray">Name from JSP expression <b>(</%=nameClass.getName()%>)
	</b></td>
<td><font color="white"><%=nameClass.getName()%></font></td></tr>
</table>
</body></html>

------------------- nameclass.jspf  (statically included in codegen.jsp and used in 
	the scriptlet <%nameClass=new Nameclass();%>) -------------------
<%!
// This class will be statically included in codegen.jsp,
//    and will be placed in the class section of the generated code, _codegen.java, 
//    because it is enclosed in a JSP declaration.
public class Nameclass {
    private String name="";
    public Nameclass() {
    }
    public Nameclass(String name) {
        this.name=name;
    }
    public void setName(String name) {
        this.name=name;
    }
    public String getName() {
        return this.name;
    }
}
%>
------------------- Nameclass.java  (must be compiled into a .class file;  Nameclass is 
	used by the <jsp:useBean> element in codegen.jsp) -------------------
package codegen;
public class Nameclass {
    private String name="";
    public Nameclass() {
    }
    public Nameclass(String name) {
        this.name=name;
    }
    public void setName(String name) {
        this.name=name;
    }
    public String getName() {
        return this.name;
    }
}





回页首


示例 B

(此代码片段中的详细代码只是用于演示目的;将无法对其进行编译。)


清单 11. 示例生成代码
                
------------------- _codegen.java -------------------
public final class _codegen extends com.ibm.ws.jsp.runtime.HttpJspBase {
  private static final JspFactory _jspxFactory = JspFactory.getDefaultFactory();

  // This declaration of the class called Nameclass was statically included from 
  // nameclass.jspf where it is defined as a JSP declaration  (<%! ... %>).  Because 
  // it was defined as a JSP declaration, it is placed in _codegen.java at the class 
  // level (as opposed to inside the _jspService() method).
  public class Nameclass {
        private String name="";
        public Nameclass() {
        }
        public Nameclass(String name) {
              this.name=name;
        }
        public void setName(String name) {
              this.name=name;
        }
        public String getName() {
              return this.name;
        }
  }

  // this _jspService() method is invoked when a request for codegen.jsp is received by 
  // the application server
  public void _jspService(HttpServletRequest request, HttpServletResponse  response)
      throws java.io.IOException, ServletException {

    PageContext pageContext = null;
    ServletContext application = null;
    ServletConfig config = null;
    JspWriter out = null;

    try {
      pageContext = _jspxFactory.getPageContext(this, request, response, null, true, 
	8192, true);

      application = pageContext.getServletContext();
      config = pageContext.getServletConfig();
      out = pageContext.getOut();

      out.write("/r/n<html><head><title>Code Validation and Generation Sample</title>
	</head>/r/n<body>/r/n/r/n");

      out.write("<!-- ***** no scripting is used here ***** -->");

      // This is code generated from the jsp:useBean statement in codegen.jsp
      codegen.Nameclass nameBean = null;
      synchronized (pageContext) {
        nameBean = (codegen.Nameclass) pageContext.getAttribute("nameBean", 
		PageContext.REQUEST_SCOPE);
        if (nameBean == null) {
          nameBean =  new codegen.Nameclass();
          pageContext.setAttribute("nameBean", nameBean, PageContext.REQUEST_SCOPE);
        }
      }
      out.write("/r/n<table>/r/n<tr><td>");

      // This is code generated from the <c:choose> custom tag in codegen.jsp
      if (_jspx_meth_c_choose_0(pageContext)) return;
      out.write("/r/n</table>/r/n</br>/r/n/r/n");

      out.write("<!-- ***** but scripting is used here ***** -->");

      Nameclass nameClass = null;String nameParam=(String)request.getParameter
	("nameParam");

      nameClass=new Nameclass();
      out.write("/r/n<table>/r/n<tr><td>Checking to see if name is given in the 
	request...</td></tr>/r/n");
       if (nameParam != null){nameClass.setName(nameParam);
        out.write("/r/n   <tr><td>Just set the name from request! [");
        out.print(nameParam);
        out.write("]</td></tr>/r/n");
      }else{
        out.write("/r/n   <tr><td>Name not supplied on 
		request...</td></tr>/r/n   ");
        nameClass.setName("J. Doe");
        out.write("/r/n   <tr><td>...so we set it to [");
        out.print(nameClass.getName());
        out.write("]</td></tr>/r/n");
      }
      out.write("/r/n</table>/r/n</br>/r/n/r/n");
      out.write("<!-- ***** results table ***** -->");

      // This is code generated from the first <c:set> custom tag in codegen.jsp
      if (_jspx_meth_c_set_0(pageContext)) return;

      // This is code generated from the <c:if> custom tag in codegen.jsp
      if (_jspx_meth_c_if_0(pageContext)) return;
      out.write("/r/n<table bgcolor=");
      out.write((String) PageContextImpl.proprietaryEvaluate("${tableColorVar}"));
      out.write(" border=/"0/" width=/"25%/">/r/n<tr><td bgcolor=/"lightgray/">Name from 
	EL expression
                  <b>(${nameBean.name})</b></td>/r/n<td><font color=/"white/">");
      out.write((String) PageContextImpl.proprietaryEvaluate("${nameBean.name}"));
      out.write("</font></td></tr>/r/n<tr><td bgcolor=/"lightgray/">Name from JSP 
	expression 
                  <b>(<%=nameClass.getName()%>)</b></td>/r/n<td><font color=/"white/">");
      out.print(nameClass.getName());
      out.write("</font></td></tr>/r/n</table>/r/n</body></html>/r/n/r/n");

    } finally {
      _jspxFactory.releasePageContext(pageContext);
    }
  }

  private boolean _jspx_meth_c_out_1(JspTag _jspx_th_c_when_0, PageContext pageContext) 
	throws Throwable {
    org.apache.taglibs.standard.tag.rt.core.OutTag _jspx_th_c_out_1 = new OutTag();
    _jspx_th_c_out_1.setValue((Object) PageContextImpl.proprietaryEvaluate("Just set the 
	name from request! [${nameBean.name}]"));
    _jspx_th_c_out_1.setDefault("null");
    int _jspx_eval_c_out_1 = _jspx_th_c_out_1.doStartTag();
    if (_jspx_th_c_out_1.doEndTag() == Tag.SKIP_PAGE) {
      return true;
    }
    return false;
  }

  private boolean _jspx_meth_c_set_1(JspTag _jspx_th_c_if_0, PageContext pageContext) 
	throws Throwable {
    org.apache.taglibs.standard.tag.rt.core.SetTag _jspx_th_c_set_1 = new SetTag();
    _jspx_th_c_set_1.setPageContext(pageContext);
    _jspx_th_c_set_1.setParent((Tag) _jspx_th_c_if_0);
    _jspx_th_c_set_1.setVar("tableColorVar");
    _jspx_th_c_set_1.setValue(new JspValueExpression("/codegen.jsp(42,4)
                 '${param.tableColor}'",_el_expressionfactory.createValueExpression(new
                  ELContextWrapper(pageContext.getELContext(),_jspx_fnmap),
		 "${param.tableColor}",Object.class))
                  .getValue(pageContext.getELContext()));
    int _jspx_eval_c_set_1 = _jspx_th_c_set_1.doStartTag();
    if (_jspx_th_c_set_1.doEndTag() == Tag.SKIP_PAGE) {
      return true;
    }
    return false;
  }

  private boolean _jspx_meth_c_if_0(PageContext pageContext) throws Throwable {
    org.apache.taglibs.standard.tag.rt.core.IfTag _jspx_th_c_if_0 = new IfTag();
    _jspx_th_c_if_0.setPageContext(pageContext);
    _jspx_th_c_if_0.setParent(null);
    _jspx_th_c_if_0.setTest(((Boolean) PageContextImpl.proprietaryEvaluate("${not 
	empty param.tableColor}")).booleanValue());
    int _jspx_eval_c_if_0 = _jspx_th_c_if_0.doStartTag();
    if (_jspx_eval_c_if_0 != Tag.SKIP_BODY) {
      do {
        if (_jspx_meth_c_set_1(_jspx_th_c_if_0, pageContext)) return true;
        int evalDoAfterBody = _jspx_th_c_if_0.doAfterBody();
        if (evalDoAfterBody != BodyTag.EVAL_BODY_AGAIN) break;
      } while (true);
    }
    if (_jspx_th_c_if_0.doEndTag() == Tag.SKIP_PAGE) {
      return true;
    }
    return false;
  }
}



参考资料



关于作者

Author photo

Scott Johnson 已从事了 24 年软件开发工作。他于 2000 年加入 IBM Research Triangle Park Lab,担任 WebSphere Application Server JSP 处理程序的团队负责人兼架构师达六年之久。Scott 目前是 IBM 在 JSR 245 (JavaServer Pages 2.1) 专家组的代表。


原文地址:点击进入
 
HyperMesh实战:用Field工具搞定复杂载荷映射(附TCL脚本示例) 本文深入探讨了HyperMesh中Field工具在复杂载荷映射中的高级应用,包括从CSV到有限元网格的温度场映射全流程、稀疏数据处理技巧及TCL自动化脚本示例。通过Field工具,工程师可以高效实现CFD温度场到结构网格的精准映射,显著提升有限元分析的精度与效率。 阅读详情

相关推荐

嵌入式学习之QT学习---14 QT跨平台运行之把QT程序交叉编译到ARM开发板

想要把qt工程放到开发板上运行,就需要用到交叉编译。由于qt是跨平台的,所以只需要换个编译器编译一下就可以。 以“定时器”的例子为例,在移植之前还需要进行一个准备工作,在windows下运行的时候,电脑屏幕很大,但是运行的窗口只有一点点大,开发板也有外接屏幕,如何让运行窗口自动适配开发板的外接屏幕呢?令其占满屏幕显示,而不是一小块。 第一步:需要设置一下,先给ui布局,如果不布局,控件就不会随着屏幕的大小的变化而变化。 第二步:利用代码来获取屏幕的大小,给widget.cpp文件下添加如下代码 #inclu

qq_42822743的博客 5457

jsp(Java Server Pages)

1. JSP=Java Server Pages java服务器端页面2. 程序员在开发过程中,发现Servlet做界面非常不方便,所以产生了jsp技术,JSP其实是对Servlet进行了包装而已。3.jsp底层是基于Servlet封装, jsp + java类(service、javabean)+ servlet,就会构成mvc的开发模式,mvc模式是目前软件公司中相当通用的开发模式。

qq_53464269的博客 1824

全志T113 Tina5.0开发:(一)添加自己的板级支持包

3.验证 先执行 source build/envsetup.sh ,然后lunch,下图可见9就是我们自己添加的板子。2. 1)修改 t113-evb1.mk重命名为t113-ws_devboard。我使用的spinand,只需要修改openwrt里面的文件即可。以下内容仅作为自己笔记,如果错误欢迎留言指出。修改t113-ws_devboard。

u014428915的博客 1165

Java Server Pages

Java Server Pages JSP全称是Java Server Pages,它和servle技术一样,都是SUN公司定义的一种用于开发动态web资源的技术。   JSP这门技术的最大的特点在于,写jsp就像在写html,但: 它相比html而言,html只能为用户提供静态数据,而Jsp技术允许在页面中嵌套java代码,为用户提供动态数据。 相比servlet而言,servlet很

Walden_tinghou的专栏 2429

AI驱动的研发流程:定义高度专业和系统化的规划基准

在人工智能(AI)浪潮席卷全球的今天,软件研发的范式正经历着一场深刻而迅速的变革。AI技术的渗透,从最初的辅助工具角色,正逐步演变为驱动整个研发流程的核心引擎。传统的研发流程和项目管理方法论,在面对AI带来的高效率、高智能以及高复杂性挑战时,显得力不从心。企业对快速交付高质量软件产品、有效控制风险、并保证全流程可追溯性的需求日益迫切。

形上得其象,形下合于数;阴阳自济,玄理自明。 2182

U8 API接口开发踩过的坑

U8 API接口开发踩过的坑

haiyang5233233的专栏 1657

什么是Java Server Pages?

JSP全称Java Server Pages,是一种动态网页开发技术。它使用JSP标签在HTML网页中插入Java代码。标签通常以结束。JSP是一种Java servlet,主要用于实现Java web应用程序的用户界面部分。网页开发者们通过结合HTML代码、XHTML代码、XML元素以及嵌入JSP操作和命令来编写JSP。JSP通过网页表单获取用户输入数据、访问数据库及其他数据源,然后动态地创建网页。JSP标签有多种功能,比如访问数据库、记录用户选择信息、访问JavaBeans组件等,还可以在

weixin_62458944的博客 700

Visual Studio调试时遇到ntdll.dll的PDB文件缺失?别慌,这3个方法帮你搞定(附详细步骤)

本文详细解析了Visual Studio调试时ntdll.dll的PDB文件缺失问题,提供了3种实用解决方案:调整调试设置、配置符号服务器与缓存目录、手动下载管理符号文件。通过分步指导和高级技巧,帮助开发者快速恢复完整的调试功能,特别适用于Windows平台下的C++项目开发。

weixin_42537919的博客 514

JSP(全称:Java Server Pages):Java 服务端页面

JSP(全称:Java Server Pages):Java 服务端页面

城下深蓝的博客 1786

AgentScope 实战训练营-A2UI的完整实现:从概念到部署全流程

本文详细介绍了如何在AgentScope框架中实现Google的A2UI(Agent-to-Agent UI)协议,构建一个能生成可交互UI的智能体应用。文章涵盖了从环境准备、架构设计、核心代码实现到测试部署的完整流程,包括A2UI协议解析、技能系统、客户端实现、通信机制等核心技术点,适合AI Agent和前端开发人员学习参考。

program哲学 206

光学传播仿真软件:ASAP_(1).ASAP软件介绍与安装

ASAP(Advanced System for Analysis and Propagation)是一款强大的光学传播仿真软件,广泛应用于光学系统的设计、分析和优化。它提供了丰富的建模工具和仿真功能,可以帮助用户从简单的光学元件到复杂的光学系统进行仿真。:支持光学、机械、热学等多物理场的联合仿真。:采用高精度的算法,确保仿真结果的准确性。:内置了大量的光学元件,如透镜、反射镜、棱镜、光栅等。:提供直观的用户界面,支持多种建模和仿真方式。:支持使用脚本语言进行二次开发,增强软件的定制能力。

kkchenjj的博客 1601

JSP(Java Server Pages)

JSP

墨染的博客 758

第四节:Vben Admin登录对接后端getUserInfo接口

上一节,我们完成了/api/auth/login接口的创建,通过login接口,我们完成了登录和Token的生成。但是登陆还是报404返回,发现是Vben Admin又请求了一个/api/getUserInfo接口,本节我们就来分析完成这个接口本节,我们完成了getUserInfo接口,完成了登录操作,成功的进入到工作台页面。

cuiwin的专栏 2846

9.25

JSP(全称JavaServer Pages)是由Sun Microsystems公司主导创建的一种动态网页技术标准。JSP部署于网络服务器上,可以响应客户端发送的请求,并根据请求内容动态地生成HTML、XML或其他格式文档的Web网页,然后返回给请求者。JSP技术以Java语言作为脚本语言,为用户的HTTP请求提供服务,并能与服务器上的其它Java程序共同处理复杂的业务需求。 JSP将Java代...

SelfishGhost的博客 779

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

Java Server Pages(JSP)

JSP,即Java服务端页面,是一种动态网页技,其中既可以定义HTML、JS、CSS等静态内容,还可以定义JAVA代码的动态内容。

qq_44708895的博客 1124

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

JSP-----Java Server Pages

一.基础 1. 概念 Java Server Pages:java服务器端页面 * 可以理解为:一个特殊的页面,其中既可以指定定义html标签,又可以定义java代码 * 用于简化书写!!! * JSP本质上就是一个Servlet 2. 脚本 JSP定义Java代码的方式 <% 代码 %>:定义的java代码,在service方法中,service方法中可以定义什么,该脚本中就可以定义什么。 <%! 代码 %>:定义的java代码,在jsp转换后的java类的成员位

Tommy·Shelby的博客 439

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

【Java 进阶篇】Java中的 JSP(JavaServer Pages)

JSP是JavaServer Pages的缩写,它是一种用于创建动态Web页面的服务器端技术。JSP页面允许在HTML页面中嵌入Java代码,使得开发者可以使用Java的各种功能来动态生成页面内容。除了使用内置的JSP标签外,开发者还可以创建自定义标签来扩展JSP的功能。自定义标签可以用于封装特定的功能,使得页面更加模块化和易于维护。上面的例子中,就是一个自定义标签的使用方式。在本文中,我们深入了解了JavaServer Pages(JSP)的概念、基本语法、内置对象、控制流程和自定义标签。

繁依Fanyi的博客 630

JSP(Java Server Pages)是一种基于Java的服务器端编程技术,用于动态生成HTML页面

里面要考虑的包括,网站风格、域名、logo、空间大小、广告位、页面数量、数据库结构、维护需求、人力成本等内容,如果要自己制作的话多参考别人的东西,如果只是做个策划具体交给别人做那就主要确定网站的定位和基本风格要求,与技术人员做好沟通。空间:有免费和付费的,(当然也可以自己建服务器啊)如果是个人,刚开始尝试,建议使用免费空间,这个可以到Baidu上去找一下.你用的是JSP的网页,需要找一个支持Jsp的服务器。互连网的交互性和信息传播的迅捷性,使得网络用户可以根据自己的需求,轻松地得到自己需要的信息。

[Blog][Domain] programb.blog.youkuaiyun.com 534

JSP

1. 什么是JSP JSP全名为Java Server Pages,中文名叫java服务器页面,其根本是一个简化的Servlet设计,它 是由Sun Microsystems公司倡导、许多公司参与一起建立的一种动态网页技术标准。JSP技术有点类似ASP技术,它是在传 统的网页HTML文件(.htm,.html)中插入Java程序段(Scriptlet)和JSP标记(tag),从而形成JSP文件,后缀名为(*.jsp)。 用JSP开发的Web应用是跨平台的,既能在Linux下运行,也能在其他操作系统上运行。

lzy520o的博客 660

javaserver_什么是JSP? JavaServer页面简介

javaserver JavaServer Pages(JSP)是一种Java标准技术,使您能够为Java Web应用程序编写动态的,数据驱动的页面。 JSP建立在Java Servlet规范之上。 两种技术通常可以协同工作,尤其是在较旧的Java Web应用程序中。 从编码的角度看,它们之间最明显的区别是,使用servlet编写Java代码,然后将客户端标记(如HTML)嵌入到该代码中,而使用...

cxu0262的博客 1188

JSP(Java Server Pages)基础使用一

然而我们新建的这个jsp文件的命名不是index而是别的名字所以我们就要在网址上修改为正确的网址在默认的后面加上这个jsp文件的名字。新建过后会出现一个这种的文件内容,和html很类似但是不同的是,在html中只可以使用前端代码进行编写页面内容,可是在jsp中是都可以写的。这段代码最终可以出现这样的页面,注意这个页面的网址,默认是localhost:8080这个很重要。今天说的就是jsp中的一些常见的问题后续内容会尽快补上。但是前端的内容就要在这个形式之外的地方来编写了,在jsp中编写后端代码时要使用

2302_80464795的博客 797

JSP:Java Server Pages

在 Java 中,JSP(Java Server Pages)是一种用于创建动态网页的技术。它允许将 Java 代码与 HTML 代码相结合,从而在服务器端生成动态页面,并将其发送到客户端浏览器。在本文中,我们将简要介绍 JSP 的基本概念、工作原理和常用语法,并附上一些简单的代码示例。

隐风的博客 485
上一篇: 来自SUN实验室的Java最新技术进展
下一篇: JMF---Java媒体架构
SunnyJavaMoon
博客等级 码龄21年 20粉丝 36原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值