我对编写JSP / Servlet时使用的技巧很感兴趣。我将开始:
我最近发现了如何将一个JSP标记的输出包含在另一个标记的属性中:
<c:forEach items="${items}">
<jsp:attribute name="var">
<mytag:doesSomething/>
</jsp:attribute>
<jsp:body>
<%-- when using jsp:attribute the body must be in this tag --%>
</jsp:body>
</c:forEach>
#1 楼
注意:我发现很难想到JSP / Servlet的任何“隐藏功能”。我认为“最佳做法”是一个更好的措辞,我可以想到其中的任何一种。这实际上还取决于您对JSP / Servlet的经验。经过多年的发展,您不再看到那些“隐藏的功能”。无论如何,我将列出一些小小的“最佳实践”,这些年来,我发现许多入门者并未完全意识到这一点。在许多入门者看来,这些将被归类为“隐藏功能”。无论如何,这是列表:)从直接访问隐藏JSP页面
通过将JSP文件放置在
/WEB-INF
文件夹中,可以有效地将它们隐藏起来,例如通过http://example.com/contextname/WEB-INF/page.jsp
直接访问。这将导致404
。然后,您只能通过Servlet中的RequestDispatcher
或使用jsp:include
来访问它们。对JSP的预处理请求
大多数人都知道Servlet的
doPost()
可以对请求(表单提交)进行后处理,但是大多数人不知道您可以使用Servlet的doGet()
方法来预处理对JSP的请求。例如:protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
List<Item> items = itemDAO.list();
request.setAttribute("items", items);
request.getRequestDispatcher("/WEB-INF/page.jsp").forward(request, response);
}
,用于预加载一些表格数据,这些数据将借助JSTL的
c:forEach
显示:<table>
<c:forEach items="${items}" var="item">
<tr><td>${item.id}</td><td>${item.name}</td></tr>
</c:forEach>
</table>
将这样的servlet映射到
url-pattern
的/page
(或/page/*
),只需通过浏览器地址栏或简单的香草链接调用http://example.com/contextname/page
即可运行它。另请参见Servlet中的doGet和doPost。动态包含
您可以在
jsp:include
中使用EL:<jsp:include page="/WEB-INF/${bean.page}.jsp" />
bean.getPage()
只能返回有效的页面名称。EL可以访问任何getter
EL本身并不要求要访问的对象是完全有价值的Javabean。以
get
或is
为前缀的noarg方法的存在足以在EL中访问它。例如:${bean['class'].name}
这将返回
bean.getClass().getName()
的值,其中getClass()
方法实际上是从Object#getClass()
继承的。请注意,出于此处在EL表达式语言中检查实例的原因,使用“大括号符号” class
指定了[]
。${pageContext.session.id}
返回
pageContext.getSession().getId()
的值,该值在a.o中有用。小程序可以与Servlet实例进行通信。${pageContext.request.contextPath}
返回
pageContext.getRequest().getContextPath()
的值,该值在a.o中很有用。 EL也可以访问Maps
以下EL表示法
${bean.map.foo}
bean.getMap().get("foo")。如果
Map
键包含一个点,则可以将“大括号符号” []
与带引号的键一起使用:${bean.map['foo.bar']}
bean.getMap().get("foo.bar")。如果要使用动态键,也可以使用大括号表示法,但不要用大括号括起来:
${bean.map[otherbean.key]}
bean.getMap().get(otherbean.getKey())。
使用JSTL在Map上迭代
您可以也使用
c:forEach
迭代Map
。每次迭代都给出一个Map.Entry
,而后者又具有getKey()
和getValue()
方法(以便您可以通过${entry.key}
和${entry.value}
在EL中访问它)。示例:<c:forEach items="${bean.map}" var="entry">
Key: ${entry.key}, Value: ${entry.value} <br>
</c:forEach>
另请参见,例如用jstl调试-究竟是什么?
在JSP中获取当前日期
您可以使用
jsp:useBean
获取当前日期,并借助JSTL fmt:formatDate
<jsp:useBean id="date" class="java.util.Date" />
...
<p>Copyright © <fmt:formatDate value="${date}" pattern="yyyy" /></p>
进行格式化如下所示打印(到目前为止):“ Copyright©2010”。
易于使用的URL的一种简便方法是使用友好的URL是利用
HttpServletRequest#getPathInfo()
和隐藏在/WEB-INF
中的JSP: br /> protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.getRequestDispatcher("/WEB-INF" + request.getPathInfo() + ".jsp").forward(request, response);
}
如果将此servlet映射到例如
/pages/*
,则对http://example.com/contextname/pages/foo/bar
的请求将有效显示/WEB-INF/foo/bar.jsp
。您可以通过拆分/
上的pathinfo来走得更远,并且仅将第一部分作为JSP页面URL,将其余部分作为“业务操作”(让servlet充当页面控制器)。另请参见设计模式基于Web的应用程序。使用
${param}
重新显示用户输入引用
${param}
的隐式EL对象HttpServletRequest#getParameterMap()
可用于在JSP中提交表单后重新显示用户输入。 :<input type="text" name="foo" value="${param.foo}">
这与
request.getParameterMap().get("foo")
基本相同。另请参见向Servlet提交表单后,如何在JSP中保留HTML表单字段值?别忘了防止XSS!请参阅下一章。
防止XSS的JSTL
要防止站点受到XSS的干扰,您要做的就是使用JSTL
fn:escapeXml
或c:out
(重新)显示用户控制的数据。<p><input type="text" name="foo" value="${fn:escapeXml(param.foo)}">
<p><c:out value="${bean.userdata}" />
用
<table>
替换LoopTagStatus
行JSTL
varStatus
的c:forEach
属性为您提供LoopTagStatus
的背面,而后面又有几种吸气方法(可在EL中使用! )。因此,要检查偶数行,只需检查loop.getIndex() % 2 == 0
:<table>
<c:forEach items="${items}" var="item" varStatus="loop">
<tr class="${loop.index % 2 == 0 ? 'even' : 'odd'}">...</tr>
<c:forEach>
</table>
,它将有效地以
<table>
<tr class="even">...</tr>
<tr class="odd">...</tr>
<tr class="even">...</tr>
<tr class="odd">...</tr>
...
</table>
使用CSS为它们提供不同的背景色。
tr.even { background: #eee; }
tr.odd { background: #ddd; }
用
LoopTagStatus
填充列表/数组中的逗号分隔的字符串:另一个有用的
LoopTagStatus
方法是isLast()
:<c:forEach items="${items}" var="item" varStatus="loop">
${item}${!loop.last ? ', ' : ''}
<c:forEach>
结果类似
item1, item2, item3
的结果。 /> EL函数
您可以将
public static
实用程序方法声明为EL函数(例如JSTL函数),以便可以在EL中使用它们。例如,带有以下/WEB-INF/functions.tld
的package com.example;
public final class Functions {
private Functions() {}
public static boolean matches(String string, String pattern) {
return string.matches(pattern);
}
}
:
可用作
<?xml version="1.0" encoding="UTF-8" ?>
<taglib
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-jsptaglibrary_2_1.xsd"
version="2.1">
<tlib-version>1.0</tlib-version>
<short-name>Custom_Functions</short-name>
<uri>http://example.com/functions</uri>
<function>
<name>matches</name>
<function-class>com.example.Functions</function-class>
<function-signature>boolean matches(java.lang.String, java.lang.String)</function-signature>
</function>
</taglib>
<%@taglib uri="http://example.com/functions" prefix="f" %>
<c:if test="${f:matches(bean.value, '^foo.*')}">
...
</c:if>
获取原始请求URL和查询字符串
如果转发了JSP,则可以通过以下方式获取原始请求URL,
${requestScope['javax.servlet.forward.request_uri']}
和原始请求查询字符串由
${requestScope['javax.servlet.forward.query_string']}
到目前为止。也许我迟早会添加一些。
评论
这是Stackoverflow上最广泛的条目之一。正如您所说的,没有花招,但是值得任何食盐的人都应该知道良好的知识和常规做法。对于交替的表行,更好的方法是使用现代CSS语法并使用tr:nth-child(even)进行着色,这会使您的HTML输出更加清晰。
–Photodeus
2010年7月11日在15:12
永远完美的BalusC先生:)
–穆罕默德·休伊(Muhammad Hewedy)
2010年12月6日,7:01
太棒了,提供了很多有用的答案和良好的常规做法,这比BlausC多得多。
–palAlaa
2010-12-12在20:51
我听说使用Date获取年份已过时。我可以使用日历进行格式化吗?
–itsraja
2011年4月21日在9:42
+1是继BalusC在JDK中使用的“设计模式”之后的第二个最爱。
– Zawhtut
2011年4月29日在2:55