JSP/Servlet的隐藏功能 [英] Hidden features of JSP/Servlet
问题描述
我对编写JSP/Servlet时使用的技巧很感兴趣.我将开始:
I am interested in your tricks etc used when writing JSP/Servlet. I will start:
我最近发现了如何将一个JSP标记的输出包含在另一个标记的属性中的方法:
I somewhat recently found out how you can include the output of one JSP tag in an attribute of another tag:
<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>
推荐答案
注意:我发现很难想到任何隐藏功能".用于JSP/Servlet.我认为,最佳做法"是一个更好的措词,我可以想到其中的任何一个.这实际上还取决于您对JSP/Servlet的经验.经过多年的开发,您看不到那些隐藏的功能"不再.无论如何,我都会列出其中一些最佳做法",我多年以来发现其中的许多入门者并没有完全意识到这一点.这些将被归类为隐藏特征".在许多初学者眼中.无论如何,这是列表:)
通过将JSP文件放置在/WEB-INF
文件夹中,可以有效地将它们隐藏起来,例如通过http://example.com/contextname/WEB-INF/page.jsp
直接访问它们.这将导致404
.然后,您只能通过 RequestDispatcher
访问它们在Servlet中或使用 jsp:include
.
By placing JSP files in /WEB-INF
folder you effectively hide them from direct access by for example http://example.com/contextname/WEB-INF/page.jsp
. This will result in a 404
. You can then only access them by a RequestDispatcher
in Servlet or using jsp:include
.
大多数人都了解Servlet的 doGet()
方法来预处理JSP请求.例如:
Most are aware about Servlet's doPost()
to post-process a request (a form submit), but most don't know that you can use Servlet's doGet()
method to pre-process a request for a JSP. For example:
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
的帮助下显示:
which is used to preload some tabular data which is to be displayed with help of JSTL's c:forEach
:
<table>
<c:forEach items="${items}" var="item">
<tr><td>${item.id}</td><td>${item.name}</td></tr>
</c:forEach>
</table>
将这样的servlet映射到/page
(或/page/*
)的url-pattern
上,只需通过浏览器地址栏或简单的香草链接调用http://example.com/contextname/page
即可运行它.另请参见 Servlet中的doGet和doPost .
Map such a servlet on an url-pattern
of /page
(or /page/*
) and just invoke http://example.com/contextname/page
by browser address bar or a plain vanilla link to run it. See also e.g. doGet and doPost in Servlets.
您可以在 jsp:include
中使用EL:
You can use EL in jsp:include
:
<jsp:include page="/WEB-INF/${bean.page}.jsp" />
bean.getPage()
只能返回有效的页面名称.
The bean.getPage()
can just return a valid pagename.
EL本身并不要求要访问的对象是完全有价值的 Javabean.前缀为get
或is
的noarg方法的存在足以在EL中访问它.例如:
EL does not per-se require the object-to-be-accessed to be a fullworthy Javabean. The presence of a no-arg method which is prefixed with get
or is
is more than sufficient to access it in EL. E.g.:
${bean['class'].name}
这将返回 bean.getClass().getName()
,其中getClass()
方法实际上是从[]由于此处提到的原因 EL表示语言中的检查实例.
This returns the value of bean.getClass().getName()
where the getClass()
method is actually inherited from Object#getClass()
. Note that class
is specified using "brace notation" []
for reasons mentioned here instanceof check in EL expression language.
${pageContext.session.id}
这将返回 pageContext.getSession().getId()
在ao中很有用小程序可以与Servlet实例进行通信.
${pageContext.request.contextPath}
这将返回 pageContext.getRequest().getContextPath()
在ao中很有用如何使用相对路径而不包含上下文根名字?
以下EL符号
${bean.map.foo}
解析为bean.getMap().get("foo")
.如果Map
键包含一个点,则可以使用大括号符号"来表示. []
,带引号的键:
resolves to bean.getMap().get("foo")
. If the Map
key contains a dot, you can use the "brace notation" []
with a quoted key:
${bean.map['foo.bar']}
解析为bean.getMap().get("foo.bar")
.如果要使用动态键,请同时使用大括号符号,但不要用引号将其括起来:
which resolves to bean.getMap().get("foo.bar")
. If you want a dynamic key, use brace notation as well, but then unquoted:
${bean.map[otherbean.key]}
解析为bean.getMap().get(otherbean.getKey())
.
您可以使用 c:forEach
以及在Map
上进行迭代.每次迭代都会给出 Map.Entry
依次具有getKey()
和getValue()
方法(以便您可以通过${entry.key}
和${entry.value}
在EL中访问它).示例:
You can use c:forEach
as well to iterate over a Map
. Each iteration gives a Map.Entry
which in turn has getKey()
and getValue()
methods (so that you can just access it in EL by ${entry.key}
and ${entry.value}
). Example:
<c:forEach items="${bean.map}" var="entry">
Key: ${entry.key}, Value: ${entry.value} <br>
</c:forEach>
另请参见使用jstl进行调试-具体如何?
您可以使用 jsp:useBean
和格式来获取当前日期借助JSTL fmt:formatDate
You can get the current's date with jsp:useBean
and format it with help of JSTL fmt:formatDate
<jsp:useBean id="date" class="java.util.Date" />
...
<p>Copyright © <fmt:formatDate value="${date}" pattern="yyyy" /></p>
(目前)打印如下:"Copyright©2010".
This prints (as of now) like follows: "Copyright © 2010".
An easy way to have friendly URL's is to make use of HttpServletRequest#getPathInfo()
and JSP's hidden in /WEB-INF
:
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的应用程序.
If you map this servlet on for example /pages/*
, then a request on http://example.com/contextname/pages/foo/bar
will effectively display /WEB-INF/foo/bar.jsp
. You can get a step further by splitting the pathinfo on /
and only take the first part as JSP page URL and the remnant as "business actions" (let the servlet act as a page controller). See also e.g. Design Patterns web based applications.
The implicit EL object ${param}
which refers to the HttpServletRequest#getParameterMap()
can be used to redisplay user input after a form submit in JSP:
<input type="text" name="foo" value="${param.foo}">
这基本上与request.getParameterMap().get("foo")
相同.另请参见如何提交表单到Servlet之后,我在JSP中保留HTML表单字段值吗?
别忘了阻止XSS!参见下一章.
This basically does the same as request.getParameterMap().get("foo")
. See also e.g. How can I retain HTML form field values in JSP after submitting form to Servlet?
Don't forget to prevent from XSS! See following chapter.
要防止您的网站 XSS ,您要做的就是(re )使用JSTL fn:escapeXml
或
To prevent your site from XSS, all you need to do is to (re)display user-controlled data using JSTL fn:escapeXml
or c:out
.
<p><input type="text" name="foo" value="${fn:escapeXml(param.foo)}">
<p><c:out value="${bean.userdata}" />
用LoopTagStatus
替换<table>
行
JSTL的varStatus
属性 c:forEach
为您提供了 LoopTagStatus
后面有几种吸气方法(可以在EL中使用!).因此,要检查偶数行,只需检查loop.getIndex() % 2 == 0
:
Alternating <table>
rows with LoopTagStatus
The varStatus
attribute of JSTL c:forEach
gives you a LoopTagStatus
back which in turn has several getter methods (which can be used in EL!). So, to check for even rows, just check if 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为他们提供不同的背景颜色.
Use CSS to give them a different background color.
tr.even { background: #eee; }
tr.odd { background: #ddd; }
使用LoopTagStatus
从列表/数组中填充逗号分隔的字符串:
另一个有用的 LoopTagStatus
方法是 isLast()
:
Populate commasepared string from List/Array with LoopTagStatus
:
Another useful LoopTagStatus
method is the isLast()
:
<c:forEach items="${items}" var="item" varStatus="loop">
${item}${!loop.last ? ', ' : ''}
<c:forEach>
其结果类似于item1, item2, item3
.
您可以将public static
实用程序方法声明为EL函数(例如
You can declare public static
utility methods as EL functions (like as JSTL functions) so that you can use them in EL. E.g.
package com.example;
public final class Functions {
private Functions() {}
public static boolean matches(String string, String pattern) {
return string.matches(pattern);
}
}
带有/WEB-INF/functions.tld
的
如下所示:
with /WEB-INF/functions.tld
which look like follows:
<?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>
获取原始请求网址和查询字符串
如果已转发JSP,则可以通过以下方式获取原始请求URL,
Get the original request URL and query string
If the JSP has been forwarded, you can get the original request URL by,
${requestScope['javax.servlet.forward.request_uri']}
和原始请求查询字符串,
and the original request query string by,
${requestScope['javax.servlet.forward.query_string']}
到目前为止.也许我迟早会添加一些.
这篇关于JSP/Servlet的隐藏功能的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!