寫這篇文章的原因是看到了Tomcat下面的Webapps下面的,就想看一下。
總結一下這篇文章的內容:
WEB-INF下面的內容都是只能由服務器級別才能訪問,客戶端並不能訪問。什么是客戶端級別?什么是服務器級別呢?
轉發就是服務器級別,瀏覽器的地址不會變,因為,客戶端發送一個請求,服務器受理之后,發現要請求內容還要再去別的請求,那么轉發就是服務器自己去處理完成。不麻煩客戶端(瀏覽器)了,所以客戶端上面的地址欄不會改變。
重定向:就是客戶端級別的。服務器收到請求后,發現還要去請求別的內容,但是服務器自己不想處理,那么就告訴客戶端,你自己去處理吧,那么客戶端就去請求那個別的內容了。所以客戶端(瀏覽器)地址欄就會改變了。
------------------------------------------------------------------------------------------------------------------------------------------------------
以下的內容來自:博客轉載自:http://ykyfendou.iteye.com/blog/2094317
在web項目中,為了安全,可能需要把jsp文件放在WEB-INF目錄下,這樣如果我們的頁面中出現超鏈接a標簽或者js的location.href去直接轉向到WEB-INF下的某一個jsp頁面,那么就會引用不到,因為這樣的請求方式是客戶端的請求,而WEB-INF頁面只對服務端開放,對客戶端是不可見的。這時候我們可以使用action,來進行轉向,我們先去請求一個action,然后由這個action分發到這個WEB-INF下的頁面就可以了。我們可以自己定義一個類似struts1的DispatcherAction的一個action來分發頁面。
由於WEB-INF下對客戶端是不可見的,所以相關的資源文件,如css,javascript和圖片等資源文件不能放在WEB-INF下,那么如何從WEB-INF下引用非WEB-INF下的文件,以及js,html的frame的框架如何去訪問WEB-INF下的jsp呢?
下面對WEB-INF目錄的一些問題進行詳細說明:
以一個項目為例:
如下這樣一個代碼目錄:我們把除index.jsp外其他的jsp文件放在WEB-INF下,把css,javascript,圖片放在了webRoot(WebContent)目錄下,然后main.jsp是一個frame的html框架,包含了main1.jsp和main2.jsp兩個文件。
1、index.jsp頁面訪問css,js,圖片等文件的時候,自然不用說,因為它不在WEB-INF下,正常的訪問即可:
Html代碼:
<link href="css/login_css.css" rel="stylesheet" type="text/css"> <script type="text/javascript" src="js/login_js.js"></script> <img alt="" src="image/1.jpg">
2、register.jsp頁面去訪問css,js和圖片的時候,也是不需要添加WEB-INF目錄的,也就是忽略WEB-INF目錄,訪問的時候和index.jsp頁面所在的路徑訪問資源文件是一樣的:
Html代碼:
<link href="css/register_css.css" rel="stylesheet" type="text/css"> <script type="text/javascript" src="js/register_js.js"></script> <img alt="" src="image/2.jpg">
3、register.jsp頁面去轉向index.jsp頁面,即注冊頁面有一個鏈接,轉向到登錄界面,由於index.jsp頁面沒有在WEB-INF下,所以可以直接訪問index.jsp頁面的路徑,
register.jsp:
html代碼:
<tr> <td></td> <td colspan="2" style="float: left; "> <button type="button" >注冊</button> <button type="button" onclick="goLogin()">去登錄</button> </td> </tr>
在register.jsp頁面中定義了一個botton,然后響應一個onclick事件,
我們在register_js.js中定義這個goRegister ()的js事件:
regitster_js.js:
js代碼:
function goLogin(){ location.href="index.jsp"; }
這樣就可以訪問到WebContent目錄中的index.jsp頁面了。
4、index.jsp(登錄頁面)有一個鏈接,指向register頁面,如果點擊鏈接,就跳轉到register.jsp中進行注冊,因為register.jsp在WEB-INF下,所以不可以直接使用a標簽去訪問WEB-INF路徑下的文件:
Html代碼:
<a href="WEB-INF/register/register.jsp">去注冊</a>
,或者js的location.href去訪問:
js代碼:
function goRegister(){ location.href="WEB-INF/register/register.jsp"; }
這樣兩種方式都是直接請求了WEB-INF路徑,都是無法跳轉的。
我們可以建立一個action,struts的action中沒有DispatcherAction,但是我們可以通過通配符來讓一個action的不同方法返回不同的頁面,然后我們去請求這個action中的相應方法即可由這個action從服務器端請求到WEB-INF下的頁面了:
下面詳細說明如果進行自定義的分發action來進行頁面的分發:
DispatcherAction.java:
package com.yun.test.webinf.action; import com.opensymphony.xwork2.ActionSupport; publicclass DispatcherAction extends ActionSupport{ public String goRegister(){ return"goRegister"; } }
這個action中,我們定義了一個goRegister的方法,這個方法沒有任何邏輯代碼,只是返回一個字符串,然后在struts.xml中我們讓這個字符串指向我們要訪問的WEB-INF下的register.jsp頁面:
struts.xml:
<action name ="dispatcher" class="com.yun.test.webinf.action.DispatcherAction" > <result name ="goRegister">WEB-INF/register/register.jsp</result > <result name ="input">/index.jsp</result > </action >
然后我們可以在頁面中進行請求DispatcherAction的goRegister方法,然后這個action的goRegister方法就會把頁面轉向到WEB-INF下的register.jsp頁面了:
我們在index.jsp中定義了一個botton,然后給這個botton注冊一個點擊事件:
index.jsp:
Html代碼:
<tr> <td></td> <td colspan="2" style="float: left; "> <button onclick="checkValues()">登錄</button> <button type="button" id="button1" onclick="goRegister()">去注冊</button> </td> </tr>
在index_js.js中定義這個點擊事件為location.href到定義的action的goRegister.action方法中:
login_js.js:
JS代碼:
function goRegister(){ location.href="dispatcher!goRegister.action"; }
當然,也可以直接在頁面中使用a標簽來請求這個action的goRegister方法:
<a href="dispatcher!goRegister.action">去注冊</a>
這樣我們就可以通過action的轉發,成功的請求道WEB-INF下的jsp文件了。
注意請求action的方式,dispatcher!goRegister.action 這個!是一個分發字符,!之前的部分是action的名字,!之后的部分是這個action的某個我們要請求的方法的名字。然后這個action中必須要定義一個同名的方法,就不需要使用execute方法了。然后這個同名方法,返回的是一個String字符串,這個字符串在struts.xml中指向為我們想要跳轉的路徑。這就是一個請求分發的action。
我們還可以自己定義分發的分隔符,可以是下划線等,分發action詳見Struts2實現分發的action一節
5、jsp頁面中的frame框架中想把多個WEB-INF下的頁面設置為框架的內容的時候,即使main.jsp和main1.jsp,main2.jsp同在WEB-INF目錄下,也不可以直接去指定WEB-INF路徑,如:
<frameset cols="30%,70%"> <frame src="main/main1.jsp"> <frame src="main/main1.jsp"> </frameset>
這樣還是不能訪問,也必須使用服務端的action分發的方式進行指定jsp文件的路徑。
代碼如下:
main.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>main</title> </head> <frameset cols="30%,70%"> <frame src="dispatcher!goMain1.action"> <frame src="dispatcher!goMain2.action"> </frameset> </html>
struts.xml:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd"> <struts > <package name ="test" extends ="struts-default" > <action name ="dispatcher" class ="com.yun.test.webinf.action.DispatcherAction" > <result name ="goRegister">WEB-INF/register/register.jsp</result > <result name ="goMain1">WEB-INF/main/main1.jsp</result > <result name ="goMain2">WEB-INF/main/main2.jsp</result > <result name ="input">/index.jsp</result > </action > <action name ="login" class ="com.yun.test.webinf.action.LoginAction" > <result name ="success">WEB-INF/main.jsp</result > <result name ="input">/index.jsp</result > </action > <action name ="register" class ="com.yun.test.webinf.action.RegisterAction" > <result name ="success">WEB-INF/main.jsp</result > <result name ="input">WEB-INF/register/register.jsp</result > </action > </package> <!-- 定義struts標簽為無默認樣式 --> <constant name="struts.ui.theme" value="simple" /> </struts>
DispatcherAction.java:
package com.yun.test.webinf.action; import com.opensymphony.xwork2.ActionSupport; publicclass DispatcherAction extends ActionSupport{ public String goRegister(){ return"goRegister"; } public String goMain1(){ return"goMain1"; } public String goMain2(){ return"goMain2"; } }
這樣,這個main頁面就可以通過action分發使用frame框架了。
6、同在WEB-INF目錄下的register.jsp和main.jsp中怎么跳轉呢?我們會在register.jsp中提交表單,然后在action中進行處理,如果注冊成功,會跳轉到main頁面,這時的跳轉也會涉及到WEB-INF目錄,因為目標路徑main.jsp也在WEB-INF下,所以我們在跳轉的時候也必須寫上WEB-INF的目錄路徑才可以,而且必須是請求分發,而不能是redirct的方式。
如代碼:
register.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>register</title> <link href="css/register_css.css" rel="stylesheet" type="text/css"> <script type="text/javascript" src="js/register_js.js"></script> </head> <body> <div id="content" > <form action="register.action" id="registerForm" method="post"> <table> <tr> <td width="150px;" style="text-align:center; ">注冊名</td> <td width="80px;" style="text-align: left;"><input type="text" name="user.username" id="username" ></td> <td width="400px;" style="text-align: left;"><font color="red">* 請輸入用戶名</font></td> </tr> <tr> <td width="100px;" style="text-align:center; ">注冊密碼</td> <td width="80px;" style="text-align: left;"><input type="password" name="user.password" size="22" id="password"></td> <td width="400px;" style="text-align: left;"><font color="red">* 請輸入密碼</font></td> </tr> <tr> <td></td> <td colspan="2" style="float: left; "> <button type="button" onclick="checkValues()">注冊</button> <button type="button" onclick="goLogin()">去登錄</button> </td> </tr> </table> </form> </div> <img alt="" src="image/2.jpg"> </body> </html>
struts.xml:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd"> <struts > <package name ="test" extends ="struts-default" > <action name ="dispatcher" class ="com.yun.test.webinf.action.DispatcherAction" > <result name ="goRegister">WEB-INF/register/register.jsp</result > <result name ="goMain1">WEB-INF/main/main1.jsp</result > <result name ="goMain2">WEB-INF/main/main2.jsp</result > <result name ="input">/index.jsp</result > </action > <action name ="login" class ="com.yun.test.webinf.action.LoginAction" > <result name ="success">WEB-INF/main.jsp</result > <result name ="input">/index.jsp</result > </action > <action name ="register" class ="com.yun.test.webinf.action.RegisterAction" > <result name ="success">WEB-INF/main.jsp</result > <result name ="input">WEB-INF/register/register.jsp</result > </action > </package> <!-- 定義struts標簽為無默認樣式 --> <constant name="struts.ui.theme" value="simple" /> </struts>
RegisterAction.java:
package com.yun.test.webinf.action; import com.opensymphony.xwork2.ActionSupport; import com.yun.test.webinf.entity.User; public class RegisterAction extends ActionSupport{ private User user; public void setUser(User user) { this.user = user; } public User getUser() { return user; } @Override public String execute() throws Exception { if("lisi".equals(user.getUsername())&&"lisi".equals(user.getPassword())){ return SUCCESS; } return INPUT; } }
接下來對WEB-INF頁面中的注意事項進行說明:
1. 把頁面資源文件只能放在WebContent目錄內,,如 CSS,JS,image等.不能放在WEB-INF下,因為WEB-INF是對客戶端隱藏的,所以放在WEB-INF下會造成頁面的布局等文件引用不到的情況。
2. 頁面文件一般放在WEB-INF目錄下面,這樣可以限制訪問,提高安全性.如JSP,html文件,放在WEB-INF目錄下就可以避免客戶端直接在地址欄上輸入路徑進行訪問了。基於不同的功能 ,把JSP 放置在WEB-INF下的不同的目錄中。
3. 只能用轉向方式來訪問WEB-INF目錄下的JSP,不用采用重定向的方式請求該目錄里面的任何資源。
4.轉向方式:
4.1、請求轉發:
如struts.xml文件中配置
<result name ="goMain2">WEB-INF/main/main2.jsp</result >
或在Action中寫
request.getRequestDispatcher("/WEB-INF/main/main2.jsp").forward(request, response);
的方式都是服務器讀取了該頁面內容,並發送到客戶端的,客戶端的地址不變,然后內容跳轉了。這樣的方式是可以訪問到WEB-INF目錄下的jsp文件的。
4.2、重定向方式:
如struts.xml文件中配置
<result name ="goMain2" type="redirect">WEB-INF/main/main2.jsp</result >
或在action中
response.sendRedirect("WEB-INF/main/main2.jsp ");
都屬於重定向的方式,重定向的含義就是服務器把地址發給客戶端,讓客戶端去訪問,這樣還是在客戶端訪問的WEB-INF目錄,所以是無法訪問到WEB-INF目錄下的jsp文件的。
5、有一些標簽,也是可以訪問到WEB-INF目錄中的文件的,如果符合要求的情況下也可以使用,如:
<jsp:forward page = "/WEB-INF/jsp/test/test.jsp" /> <a href="javascript:<jsp:forward page='WEB-INF/xxxx.jsp'/>"></a> <jsp:include page="WEB-INF/xxx.jsp">
都是可以訪問WEB-INF下的jsp文件的。但是局限性很大,還是建議使用action分發的方式。