JSP/Servlet 的隐藏特性 [英] Hidden features of JSP/Servlet

查看:22
本文介绍了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 的 doPost() to post-处理请求(表单提交),但大多数不不知道你可以使用 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/a>:

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.以 getis 为前缀的无参数方法的存在足以在 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}

这将返回<的值code>bean.getClass().getName() 其中 getClass() 方法实际上是从 Object#getClass().请注意,class 是使用大括号表示法"指定的.[] 这里提到的原因 instanceof check inEL 表达语言.

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}

这将返回<的值code>pageContext.getSession().getId() 这在ao中很有用小程序能否与 servlet 的实例通信.

${pageContext.request.contextPath}

这将返回<的值code>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() 方法(这样您就可以在 EL 中通过 ${entry.key}${entry.value}).示例:

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

<jsp:useBean id="date" class="java.util.Date" />
...
<p>Copyright &copy; <fmt:formatDate value="${date}" pattern="yyyy" /></p>

打印(截至目前)如下:Copyright © 2010".

This prints (as of now) like follows: "Copyright © 2010".

获得友好 URL 的一种简单方法是使用 HttpServletRequest#getPathInfo()和隐藏在/WEB-INF中的JSP:

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.您可以通过拆分 / 上的路径信息来更进一步,只将第一部分作为 JSP 页面 URL,将剩余部分作为业务操作".(让 servlet 充当页面控制器).另见例如设计模式基于网络的应用程序.

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.

隐式 EL 对象 ${param} 指的是 HttpServletRequest#getParameterMap() 可用于在 JSP 中提交表单后重新显示用户输入:

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,您需要做的就是(重新) 使用 JSTL 用户控制数据rel="noreferrer">fn:escapeXmlc:out.

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

交替

JSTL 的 varStatus 属性 c:forEach 给你一个 LoopTagStatus 返回,它又具有几个 getter 方法(可以在 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 为它们提供不同的背景颜色.

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 函数(例如 JSTL 函数),以便您可以在 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 如下所示:

<?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已经转发,可以通过,


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']} 

和原始请求查询字符串by,

and the original request query string by,

${requestScope['javax.servlet.forward.query_string']}


到此为止.也许我迟早会添加更多.

这篇关于JSP/Servlet 的隐藏特性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆