java - 在JSP-Files如何避免Java Code?

  显示原文与译文双语对照的内容

我是 Java EE新手,我知道类似以下三行的东西


<%= x+1 %>
<%= request.getParameter("name") %>
<%! counter++; %>

是一种oldschool编码方式,在JSP版本 2中存在一个方法,可以在JSP文件中避免Java代码。 有人可以告诉我其他的JSP 2行,以及这个技术是如何被调用的?

时间:

的使用 scriptlet JSP中( 那些 <% %>的东西) 确实是极其不鼓励使用这里作为一类独立的标记库 ( 像 JSTL ) 和 e1 ( 表达式语言,那些 ${} ) 过十年前。

的主要缺点是:

  1. 可以重用性: 你不能重用脚本 Fragment 。
  2. 可以替换性: 你不能让脚本Fragment抽象。
  3. OO-ability: 你不能使用继承/组合。
  4. Debuggability: 如果scriptlet在中途引发异常,你只需要一个空白页面。
  5. 可以测试性: scriptlet不是 unit-testable 。
  6. 每个 saldo 可维护性: 更多时间是必要的,以保持 mingled/cluttered/duplicated 代码逻辑。

阳光 Oracle本身同时建议 JSP中的编码约定 的方法,以避免使用 scriptlet 每当相同的功能很可能由( 标记) 类。 以下是一些相关的内容:

于你的pages,从JSP中 JSP scriptlet 相关 1.2在JSP标准标记库规范,强烈建议( JSTL ) 被用在你的网页应用,以帮助降低使用要购买 通常,使用JSTL的页面更易于阅读和维护。

在可能的情况下,避免JSP脚本 Fragment 每当标记库提供等效的功能。 这使得页面更易于阅读和维护,有助于将业务逻辑与表示逻辑分离,并使你的页面更易于演变到 JSP 2.0 -style页面( JSP 2.0规范支持但deemphasizes的使用) 。

于编写业务相关的精神中logic,采用上述 model-view-controller ( MVC ) 设计模式,以减少耦合之间的表现层从业务逻辑。JSP脚本Fragment不应使用. 相反,如果需要将数据( 也称为"值对象") 转换为适当的client-ready格式,则使用 JSP scriptlet来转换数据值。 即便如此,最好使用前端控制器servlet或者自定义标记。


在代码的唯一目的/logic, 如何替换 scriptlet 完全要看了。 上代码通常被放置在 fullworthy Java类中:

  • 如果你想调用的相同 Java代码,less-or-more 每个请求,而不管所请求的页面上,如果一个用户已经登录,然后实现一个筛选 比如 检查并相应地编写代码在 doFilter() 方法。 比如:

    
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
     if (((HttpServletRequest) request).getSession().getAttribute("user") == null) {
     ((HttpServletResponse) response).sendRedirect("login");//Not logged in, redirect to login page.
     } else {
     chain.doFilter(request, response);//Logged in, just continue request.
     }
    }
    
    

    当映射到一个合适的<url-pattern> 页面的时候,你不需要在所有的JSP页面上都使用相同的代码。


  • 如果你想调用一些Java代码来 一个请求进行预处理,比如 预载一些中列出要显示数据库中的一些表,如有必要基于一些查询参数,那么实现一个 servlet 并相应地编写代码在 doGet() 方法。 比如:

    
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
     try {
     List<Product> products = productService.list();//Obtain all products.
     request.setAttribute("products", products);//Store products in request scope.
     request.getRequestDispatcher("/WEB-INF/products.jsp").forward(request, response);//Forward to JSP page to display them in a HTML table.
     } catch (SQLException e) {
     throw new ServletException("Retrieving products failed!", e);
     }
    }
    
    

    这种方式处理异常比较容易。 在JSP呈现过程中没有访问数据库,但在显示JSP之前。 你仍然有可能在数据库访问引发异常时更改响应。 在上面的示例中,将显示默认错误 500页面,你可以通过 <error-page>web.xml 中自定义。


  • doPost() method,如果希望调用一些Java代码来 postprocess 一个请求( 表单提交,那么实现一个 比如 处理servlet.具体信息和写代码 比如:

    
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
     String username = request.getParameter("username");
     String password = request.getParameter("password");
     User user = userService.find(username, password);
    
     if (user!= null) {
     request.getSession().setAttribute("user", user);//Login user.
     response.sendRedirect("home");//Redirect to home page.
     } else {
     request.setAttribute("message","Unknown username/password. Please retry.");//Store error message in request scope.
     request.getRequestDispatcher("/WEB-INF/login.jsp").forward(request, response);//Forward to JSP page to redisplay login form with error.
     }
    }
    
    

    这样处理不同的结果页目的更容易: 在出现错误( 在这个示例中,你可以使用 ${message}EL 中重新显示它) 时重新显示带有验证错误的表单,或者在成功的情况下直接转到所需目标页。


  • 如果你想调用一些Java代码来控制 在请求与应答的的执行计划和/或者目标,然后实现一个 servlet 按mvc的前端控制器模式 比如:

    
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
     try {
     Action action = ActionFactory.getAction(request);
     String view = action.execute(request, response);
    
     if (view.equals(request.getPathInfo().substring(1)) {
     request.getRequestDispatcher("/WEB-INF/" + view +".jsp").forward(request, response);
     } else {
     response.sendRedirect(view);
     }
     } catch (Exception e) {
     throw new ServletException("Executing action failed.", e);
     }
    }
    
    

    于自定义servlet,或者只是。采用MVC框架像 JSF相关Spring MVC蜡芯等,以便最终得到的只是一个 jsp/facelets页面和一个 java bean类不使用要购买


  • 如果你想调用一些Java代码来控制水流 留在了一个页面,然后你需要取回一个( 现有现有) 流控制JSTL标签库类似于核心 比如 在表格中显示 List<Product>:

    
    <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
    ...
    <table>
     <c:forEach items="${products}" var="product">
     <tr>
     <td>${product.name}</td>
     <td>${product.description}</td>
     <td>${product.price}</td>
     </tr>
     </c:forEach>
    </table>
    
    

    使用XML-style标签配合很好地在所有的HTML,使用代码将被更好的可以读的比一堆脚本Fragment与各种左大括号和右大括号( 从而更好的维护) ( 宋体"关系阿这个右括号属于哪" ) 。 一种简单的援助是配置你的网络程序,从而引发异常每当 scriptlet 仍被用于通过将下列内容添加到 web.xml: Fragment

    
    <jsp-config>
     <jsp-property-group>
     <url-pattern>*.jsp</url-pattern>
     <scripting-invalid>true</scripting-invalid>
     </jsp-property-group>
    </jsp-config>
    
    

    Facelets的JSP的后续产品,它是j2ee的一部分提供的MVC框架,JSF,它已经能够使用 scriptlet 。 这样你就会被迫做"正确的方式"。


  • 如果你想调用一些Java代码来访问和显示 "后端"数据,那么你需要使用一个JSP页面 EL ( 表达式语言) 内部,那类 ${} 信息。 比如 重新显示提交的输入值:

    
    <input type="text" name="foo" value="${param.foo}"/>
    
    

    ${param.foo} 显示 request.getParameter("foo")的结果。


  • 如果你想调用一些实用程序( 通常 public static 方法) Java代码直接在JSP页面,那么你需要将它们定义为EL函数。 在JSTL中有一个标准的函数 taglib,但是也可以自己创建函数。 下面是一个示例,JSTL fn:escapeXml 是如何帮助防止 XSS攻击的。

    
    <%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
    ...
    <input type="text" name="foo" value="${fn:escapeXml(param.foo)}"/>
    
    

    请注意,XSS灵敏度是决不是专门针对 Java/JSP/JSTL/EL/whatever, 中这个问题都需要考虑到每个 web application 你开发。 的问题是它不提供内置的预防措施,至少不使用标准的javaapi 。 jsp Facelets的后继者已经有了隐式的HTML转义,所以你不需要担心Facelets中的XSS漏洞。

另请参见:

为代价:禁用Scriptlets以获得良好的

讨论你 web.xml 网页应用descriptor,作为 另一个问题是,你可以并始终应该禁用 scriptlets.

为了防止任何开发人员添加 scriptlet,我总是这样做,尤其是在更大的公司中,你迟早会失去概述。 web.xml 设置如下所示:


<jsp-config>
 <jsp-property-group>
 <url-pattern>*.jsp</url-pattern>
 <scripting-invalid>true</scripting-invalid>
 </jsp-property-group>
</jsp-config>

JSTL 提供了条件,循环,集合,获取和 等等的标记,例如:


<c:if test="${someAttribute == 'something'}">
. . .
</c:if>

中设置动态标签库可以处理的请求属性- 它们最常见的请求由一个 Servlet,它 转发给 JSP 。

我不确定我是否得到了正确的结果。

你应该读读关于MVC的东西。 Spring MVC & Struts 2是两个最常用的解决方案。

你可以使用JSTL标记和EL表达式来避免混合Java和HTML代码:


<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<html>
<head>
</head>
<body>

<c:out value="${x + 1}"/>
<c:out value="${param.name}"/>
//and so on

</body>
</html>

于you,相关也有component-based框架,比如蜡芯,会生成大量的HTML 在HTML中结束的标记是非常基本的,实际上没有任何逻辑可以混合在一起。 结果几乎是 empty-like HTML页面,带有典型的HTML元素。 缺点是,在的Wicket API中有很多组件,在这些约束下很难实现。

经验表明,jsp有一些缺点,其中之一是很难避免将标记与实际代码混淆。

如果你能,那么考虑使用专门的技术来做你需要做的事情。 在 Java EE 6中,有一个 JSF 2.0,它提供了许多不错的特性,包括通过 #{bean.method(argument)} 方法将 Java bean和JSF页面结合起来。

并很少对这些软件other,蜡芯也是另一替代其中完全分隔的开发从 html,所以,可以实时地协同工作,并在不同的code.集

看看 Wicket 。

如果你只想避免JSP中Java编码的缺点,即使使用scriplets也可以这样做。 只要遵循一些规程,JSP中的Java就最少,并且JSP页面中几乎没有计算和逻辑。


<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
//instantiate a JSP controller
MyController clr = new MyController(request, response);

//process action if any
clr.process(request);

//process page forwaring if necessary

//do all variable assignment here
String showMe = clr.getShowMe();

%>

<html>
<head>
</head>
<body>
<form name="frm1">
<p>
<%= showMe %>

<p>
<% for(String str : clr.listOfStrings()) { %>
<p>
<%= str %>

<% } %>

//and so on

</form>
</body>
</html>

在MVC设计模式中,jsp页面代表视图层。 在jsp页面中嵌入java代码是一个糟糕的实践。 通过 JSTL jsp页面作为你可以使用 freeMarker速度. 这些标记的数据provioder取决于你正在处理的框架。 Struts为MVC模式使用 2和webwork作为一个实现 OGNL"非常有趣的技术暴露 bean Proprities将JSP页面"

...