Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit d7041c2

Browse filesBrowse files
committed
新增"如何避免在JSP文件中使用Java代码"
1 parent f756ffa commit d7041c2
Copy full SHA for d7041c2

File tree

Expand file treeCollapse file tree

3 files changed

+175
-1
lines changed
Filter options
Expand file treeCollapse file tree

3 files changed

+175
-1
lines changed

‎README.md

Copy file name to clipboardExpand all lines: README.md
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ stackoverflow-Java-top-qa
4646
* [Java中打印一个数组最简单的方法是什么](https://github.com/giantray/stackoverflow-java-top-qa/blob/master/contents/What's-the-simplest-way-to-print-a-Java-array.md)
4747
* [为什么以下用随机生成的文字会得出 “hello world”?](https://github.com/giantray/stackoverflow-java-top-qa/blob/master/contents/why-does-this-code-using-random-strings-print-hello-world.md)
4848
* [什么在java中存放密码更倾向于char[]而不是String](https://github.com/giantray/stackoverflow-java-top-qa/blob/master/contents/why-is-cha[]-preferred-over-String-for-passwords-in-java.md)
49+
* [如何避免在JSP文件中使用Java代码](https://github.com/giantray/stackoverflow-java-top-qa/blob/master/contents/how-to-avoid-java-code-in-jsp-files.md)
4950

5051
> 网络
5152
@@ -72,7 +73,6 @@ stackoverflow-Java-top-qa
7273
- [Creating a memory leak with Java [closed]](http://stackoverflow.com/questions/6470651/creating-a-memory-leak-with-java)
7374
- [Why is printing “B” dramatically slower than printing “#”?](http://stackoverflow.com/questions/21947452/why-is-printing-b-dramatically-slower-than-printing)
7475
- [How can I create an executable jar with dependencies using Maven?](http://stackoverflow.com/questions/574594/how-can-i-create-an-executable-jar-with-dependencies-using-maven)
75-
- [How to avoid Java code in JSP files?](http://stackoverflow.com/questions/3177733/how-to-avoid-java-code-in-jsp-files)
7676
- [Why is executing Java code in comments with certain Unicode characters allowed?](http://stackoverflow.com/questions/30727515/why-is-executing-java-code-in-comments-with-certain-unicode-characters-allowed)
7777
- [Dealing with “java.lang.OutOfMemoryError: PermGen space” error](http://stackoverflow.com/questions/88235/dealing-with-java-lang-outofmemoryerror-permgen-space-error)
7878
- [“implements Runnable” vs. “extends Thread”](http://stackoverflow.com/questions/541487/implements-runnable-vs-extends-thread)
+173Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
##如何避免在JSP文件中使用Java代码
2+
3+
###问题
4+
如何避免在JSP文件中使用Java代码?
5+
6+
我对Java EE不是很熟悉,我知道类似如下的三行代码
7+
```jsp
8+
<%= x+1 %>
9+
<%= request.getParameter("name") %>
10+
<%! counter++; %>
11+
```
12+
这三行代码是学校教的老式代码。在JSP 2,存在一些方法可以避免在JSP文件中使用Java代码。有人可以告诉我在JSP 2中如何避免使用Java代码吗,这些方法该如何使用?
13+
14+
###回答
15+
在大约十年前,taglibs(比如JSTL)和EL(EL表达式,`${}`)诞生的时候,在JSP中使用scriptlets(类似`<% %>`)这种做法,就确实已经是不被鼓励使用的做法了。
16+
17+
scriptlets 主要的缺点有:
18+
1. **重用性** :你不可以重用scriptlets
19+
2. **可替换性** :你不可以让scriptlets抽象化
20+
3. **面向对象能力** :你不可以使用继承或组合
21+
4. **调试性** :如果scriptlets中途抛出了异常,你只能获得一个空白页
22+
5. **可测试性** :scriptlets不能进行单元测试
23+
6. **可维护性** :(这句有些词语不确定)需要更多的时间去维护混合的/杂乱的/冲突的 代码逻辑
24+
25+
Oracle自己也在 [JSP coding conventions](http://www.oracle.com/technetwork/articles/javase/code-convention-138726.html)一文中推荐在功能可以被标签库所替代的时候避免使用scriptlets语法。以下引用它提出的几个观点:
26+
27+
> 在JSP 1.2规范中,强烈推荐使用JSTL来减少JSP scriptlets语法的使用。一个使用JSTL的页面,总得来说会更加地容易阅读和维护。
28+
29+
>...
30+
31+
>在任何可能的地方,当标签库能够提供相同的功能时,尽量避免使用JSP scriptlets语法。这会让页面更加容易阅读和维护,帮助将 业务逻辑 从 表现层逻辑 中分离,也会让页面往更符合JSP 2.0风格的方向发展(JSP 2.0规范中,支持但是极大弱化了JSP scriptlets语法)
32+
33+
>...
34+
35+
>本着适应 模型-显示层-控制器(MVC) 设计模式中关于减少业务逻辑层与显示层之间的耦合的精神,**JSP scriptlets语法不应该**被用来编写业务逻辑。相应的,JSP scriptlets语法在传送一些服务端返回的处理客户端请求的数据(也叫做 声明对象?。这里翻译得不清楚)的时候会被使用。尽管如此,使用一个controller servlet来处理或者用自定义标签来处理会更好。
36+
37+
-----------
38+
39+
**如何替换scriptlets语句,取决于代码/逻辑的目的。更常见的是,被替换的语句会被放在另外的一些更值得放的Java类里**(这里翻译得不一定清楚)
40+
41+
* 如果你想在每个请求运行**相同的**Java代码,less-or-more regardless of the requested page(不会翻译),比如说 检查一个用户是否在登录状态,就要实现一个 过滤器,在doFilter()方法中编写正确的代码,例如
42+
43+
```java
44+
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
45+
if (((HttpServletRequest) request).getSession().getAttribute("user") == null) {
46+
((HttpServletResponse) response).sendRedirect("login"); // Not logged in, redirect to login page.
47+
} else {
48+
chain.doFilter(request, response); // Logged in, just continue request.
49+
}
50+
}
51+
```
52+
当你在`<url-pattern>`中做好恰当的地址映射,覆盖所有应该被覆盖的JSP文件,也就不需要再JSP文件中添加这些相同的Java代码
53+
54+
----------------
55+
56+
* 如果你想执行一些Java代码来**预处理**一个请求,例如,预加载某些从数据库加载的数据来显示在一些表格里,可能还会有一些查询参数,那么,实现一个Servlet,在doGet()方法里编写正确的代码,例如
57+
58+
```java
59+
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
60+
try {
61+
List<Product> products = productService.list(); // Obtain all products.
62+
request.setAttribute("products", products); // Store products in request scope.
63+
request.getRequestDispatcher("/WEB-INF/products.jsp").forward(request, response); // Forward to JSP page to display them in a HTML table.
64+
} catch (SQLException e) {
65+
throw new ServletException("Retrieving products failed!", e);
66+
}
67+
}
68+
```
69+
这个方法能够更方便地处理异常。The DB is not accessed in the midst of JSP rendering, but far before the JSP is been displayed.(不会翻译)在数据库抛出异常的时候,你还是有改变response的可能。在上面的例子,默认的500页会显示,你还可以改变`web.xml``<error-page>`来自定义异常处理错误页。
70+
71+
----------
72+
73+
* 如果你想执行一些Java代码来**后置处理(postprocess)**一个请求,例如处理表单提交,那么,实现一个Servlet,在doPost()里写上正确的代码:
74+
75+
```java
76+
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
77+
String username = request.getParameter("username");
78+
String password = request.getParameter("password");
79+
User user = userService.find(username, password);
80+
81+
if (user != null) {
82+
request.getSession().setAttribute("user", user); // Login user.
83+
response.sendRedirect("home"); // Redirect to home page.
84+
} else {
85+
request.setAttribute("message", "Unknown username/password. Please retry."); // Store error message in request scope.
86+
request.getRequestDispatcher("/WEB-INF/login.jsp").forward(request, response); // Forward to JSP page to redisplay login form with error.
87+
}
88+
}
89+
```
90+
这个处理不同目标结果页的方法会比原来更加简单: 可以显示一个带有表单验证错误提示的表单(在这个特别的例子中,你可以用EL表达式`${message}`来显示错误提示),或者仅仅跳转到成功的页面
91+
92+
---------
93+
94+
* 如果你想执行一些Java代码来**控制**执行计划(control the execution plan) 和/或 request和response的目标,用[MVC模式](http://stackoverflow.com/questions/3541077/design-patterns-web-based-applications/3542297#3542297)实现一个Servlet,例如:
95+
```java
96+
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
97+
try {
98+
Action action = ActionFactory.getAction(request);
99+
String view = action.execute(request, response);
100+
101+
if (view.equals(request.getPathInfo().substring(1)) {
102+
request.getRequestDispatcher("/WEB-INF/" + view + ".jsp").forward(request, response);
103+
} else {
104+
response.sendRedirect(view);
105+
}
106+
} catch (Exception e) {
107+
throw new ServletException("Executing action failed.", e);
108+
}
109+
}
110+
```
111+
或者使用一些MVC框架例如[JSF](http://stackoverflow.com/tags/jsf/info), [Spring MVC](http://stackoverflow.com/tags/spring-mvc/info), [Wicket](http://stackoverflow.com/tags/wicket/info) end up with just a JSP/Facelets page and a Javabean class without the need for a custom servlet.(不知道如何翻译准确)
112+
113+
---------
114+
115+
* 如果你想执行一些Java代码来**控制JSP页面的执行流程(control the flow inside a JSP page)**,那么你需要使用一些(已经存在的)流程控制标签库,比如[JSTL core](http://docs.oracle.com/javaee/5/jstl/1.1/docs/tlddocs/c/tld-summary.html),例如,在一个表格显示`List<Product>`
116+
117+
```java
118+
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
119+
...
120+
<table>
121+
<c:forEach items="${products}" var="product">
122+
<tr>
123+
<td>${product.name}</td>
124+
<td>${product.description}</td>
125+
<td>${product.price}</td>
126+
</tr>
127+
</c:forEach>
128+
</table>
129+
```
130+
这些XML风格的标签可以很好地适应HTML代码,代码变得更好阅读(也因此更好地维护),相比于杂乱无章的scriptlets 的分支大括号(Where the heck does this closing brace belong to?"(到底这个结束大括号是属于哪个代码段的?))。一个简单的设置可以配置你的Web程序让在使用scriptlets 的时候自动抛出异常
131+
132+
```xml
133+
<jsp-config>
134+
<jsp-property-group>
135+
<url-pattern>*.jsp</url-pattern>
136+
<scripting-invalid>true</scripting-invalid>
137+
</jsp-property-group>
138+
</jsp-config>
139+
```
140+
141+
在JSP的继承者[Facelets](http://stackoverflow.com/tags/facelets/info)里(Java EE提供的MVC框架[JSF](http://stackoverflow.com/tags/jsf/info)),已经**不**可能使用scriptlets语法了。这是一个让你强制使用“正确的方法”的方法
142+
143+
-----------
144+
145+
* 如果你想执行一些Java代码来在JSP中 **访问和显示** 一些“后端”数据,你需要使用EL(表达式),`${}`,例如,显示已经提交了的数值:
146+
147+
```jsp
148+
<input type="text" name="foo" value="${param.foo}" />
149+
```
150+
151+
`${param.foo}`会显示`request.getParameter("foo")`这句话的输出结果。
152+
153+
--------------
154+
155+
* 如果你想在JSP直接执行一些工具类Java代码(典型的,一些public static方法),你需要定义它,并使用EL表达式函数。这是JSTL里的标准函数标签库,但是你也可以[轻松地创建自己需要的功能](http://docs.oracle.com/javaee/5/tutorial/doc/bnahq.html#bnaiq),下面是一个使用有用的`fn:escapeXml`来避免XSS攻击的例子。
156+
157+
```java
158+
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
159+
...
160+
<input type="text" name="foo" value="${fn:escapeXml(param.foo)}" />
161+
```
162+
163+
注意,XSS并不是Java/JSP/JSTL/EL/任何技术相关的东西,这个问题是**任何**Web应用程序都需要关心的问题,scriptlets 并没有为这个问题提供良好的解决方案,至少没有标准的Java API的解决方案。JSP的继承者Facelets内含了HTML转义功能,所以在Facelets里你不用担心XSS攻击的问题。
164+
165+
See Also:
166+
* [JSP, Servlet, JSF的不同点在哪里?](http://stackoverflow.com/questions/2095397/what-is-the-difference-between-jsf-servlet-and-jsp/2097732#2097732)
167+
* [Servlet, ServletContext, HttpSessionHttpServletRequest/Response 是如何工作的?](http://stackoverflow.com/questions/3106452/java-servlet-instantiation-and-session-variables/3106909#3106909)
168+
* [JSP, Servlet and JDBC的基本MVC例子](http://stackoverflow.com/questions/5003142/jsp-using-mvc-and-jdbc)
169+
* [Java Web应用程序中的设计模式](http://stackoverflow.com/questions/3541077/design-patterns-web-based-applications/)
170+
* [JSP/Servlet中的隐藏功能](http://balusc.blogspot.com/2010/01/hidden-features-of-jspservlet.html)
171+
172+
173+
stackoverflow原址:http://stackoverflow.com/questions/3177733/how-to-avoid-java-code-in-jsp-files

‎contents/why-is-cha[]-preferred-over-String-for-passwords-in-java.md

Copy file name to clipboardExpand all lines: contents/why-is-cha[]-preferred-over-String-for-passwords-in-java.md
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,6 @@ String是不可变的。虽然String加载密码之后可以把这个变量扔
1515

1616
**stackoverflow链接**
1717
http://stackoverflow.com/questions/8881291/why-is-char-preferred-over-string-for-passwords-in-java
18+
1819
**知乎上也有相关讨论**
1920
https://www.zhihu.com/question/36734157

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.