JavaWeb開發遇到的細節問題彙總

----------------------------------------------------------------------------------------------------------
css,js等資源路徑配置的問題
----------------------------------------------------------------------------------------------------------
切記不要以相對路徑來配置例如<link href="../css/ui-dialog.css" rel="stylesheet" type="text/css" />
應當以絕對路徑匹配<link href="css/ui-dialog.css" rel="stylesheet" type="text/css" />


如果是以絕對路徑匹配,假如我們的url爲lcoalhost:8080/BoxingPlan/user/login.do
則資源的訪問路徑爲http://localhost:8080/BoxingPlan/user/css/ui-dialog.css


顯然這樣的路徑是找不到資源的。這裏我給出兩種解決方案。


方案一:使用絕對路徑
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://"
+ request.getServerName() + ":" + request.getServerPort()
+ path + "/";
%>




<head>
<base href="<%=basePath %>">
</head>


這樣瀏覽器默認的訪問路徑將會以base的href爲前綴。


方案二:去除項目路徑。這裏我們在Eclipse的tomcat server設置中
將項目的訪問路徑設置爲'/',這樣我們的資源配置就可以設置成
<link href="/css/ui-dialog.css" rel="stylesheet" type="text/css" />
<link href="/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
<link href="/css/main/main.css" rel="stylesheet" type="text/css" />




----------------------------------------------------------------------------------------------------------
web.xml中 url-pattern問題
----------------------------------------------------------------------------------------------------------


一,servlet容器對url的匹配過程: 


當 一個請求發送到servlet容器的時候,容器先會將請求的url減去當前應用上下文的路徑作爲servlet的映射url,比如我訪問的是 http://localhost/test/aaa.html,我的應用上下文是test,容器會將http://localhost/test去掉, 剩下的/aaa.html部分拿來做servlet的映射匹配。這個映射匹配過程是有順序的,而且當有一個servlet匹配成功以後,就不會去理會剩下 的servlet了(filter不同,後文會提到)。其匹配規則和順序如下: 


1.     精確路徑匹配。例子:比如servletA 的url-pattern爲 /test,servletB的url-pattern爲 /* ,這個時候,如果我訪問的url爲http://localhost/test ,這個時候容器就會先進行精確路徑匹配,發現/test正好被servletA精確匹配,那麼就去調用servletA,也不會去理會其他的 servlet了。 


2.     最長路徑匹配。例子:servletA的url-pattern爲/test/*,而servletB的url-pattern爲/test/a/*,此 時訪問http://localhost/test/a時,容器會選擇路徑最長的servlet來匹配,也就是這裏的servletB。 


3.     擴展匹配,如果url最後一段包含擴展,容器將會根據擴展選擇合適的servlet。例子:servletA的url-pattern:*.action 


4.     如果前面三條規則都沒有找到一個servlet,容器會根據url選擇對應的請求資源。如果應用定義了一個default servlet,則容器會將請求丟給default servlet(什麼是default servlet?後面會講)。 


     根據這個規則表,就能很清楚的知道servlet的匹配過程,所以定義servlet的時候也要考慮url-pattern的寫法,以免出錯。 


      對於filter,不會像servlet那樣只匹配一個servlet,因爲filter的集合是一個鏈,所以只會有處理的順序不同,而不會出現只選擇一 個filter。Filter的處理順序和filter-mapping在web.xml中定義的順序相同。 
   


二,url-pattern詳解 


         在web.xml文件中,以下語法用於定義映射: 


l. 以”/’開頭和以”/*”結尾的是用來做路徑映射的。 


2. 以前綴”*.”開頭的是用來做擴展映射的。 


3. “/” 是用來定義default servlet映射的。 


4. 剩下的都是用來定義詳細映射的。比如: /aa/bb/cc.action 


所以,爲什麼定義”/*.action”這樣一個看起來很正常的匹配會錯?因爲這個匹配即屬於路徑映射,也屬於擴展映射,導致容器無法判斷。
----------------------------------------------------------------------------------------------------------
sendRedirect和forward的區別
----------------------------------------------------------------------------------------------------------
一、原理. 
1、 Forward 
      這種方式是在服務器端作的重定向。服務器往client發送數據的過程是這樣的:服務器在向客戶端發送數據之前,是先將數據輸出到緩衝區,然後將緩衝區中數據發送給client端。什麼時候將緩衝區裏的數據發送給client端呢? 


(1)當對來自client的request處理完,並把所有數據輸出到緩衝區 
(2)當緩衝區滿 
(3)在程序中調用緩衝區的輸出方法out.flush()或response.flushbuffer(),web container纔將緩衝區中的數據發送給client。 


      這種重定向方式是利用服務器端的緩衝區機制,在把緩衝區的數據發送到客戶端之前,原來的數據不發送,將執行轉向重定向頁面,發送重定向頁面的數據,重定向調用頁的數據將被清除。如果在<JSP:FORWORD>之前有很多輸出,前面的輸出已使緩衝區滿,將自動輸出到客戶端,那麼這種重定向方式將不起作用,這一點應該特別注意。 


public void doPost(HttpServletRequest request,HttpServletResponse response) throws ServletException,IOException 

response.setContentType("text/html; charset=UTF-8"); 
ServletContext sc = getServletContext(); 
RequestDispatcher rd = null; 
rd = sc.getRequestDispatcher("/index.jsp"); 
rd.forward(request, response); 



2、 sendRedirect 
      這種方式是在客戶端作的重定向處理。該方法通過修改HTTP協議的HEADER部分,對瀏覽器下達重定向指令的,讓瀏覽器對在location中指定的URL提出請求,使瀏覽器顯示重定向網頁的內容。該方法可以接受絕對的或相對的URLs。如果傳遞到該方法的參數是一個相對的URL,那麼Web container在將它發送到客戶端前會把它轉換成一個絕對的URL。 


public void doPost(HttpServletRequest request,HttpServletResponse response) throws ServletException,IOException 

response.setContentType("text/html; charset=UTF-8"); 
response.sendRedirect("/index.jsp"); 



二、區別. 
      1、forward重定向是在容器內部實現的同一個Web應用程序的重定向,所以forward方法只能重定向到同一個Web應用程序中的一個資源,重定向後瀏覽器地址欄URL不變,而sendRedirect方法可以重定向到任何URL, 因爲這種方法是修改http頭來實現的,URL沒什麼限制,重定向後瀏覽器地址欄URL改變。 
      2、forward重定向將原始的HTTP請求對象(request)從一個servlet實例傳遞到另一個實例,而採用sendRedirect方式兩者不是同一個application。 
      3、基於第二點,參數的傳遞方式不一樣。forward的form參數跟着傳遞,所以在第二個實例中可以取得HTTP請求的參數。sendRedirect只能通過鏈接傳遞參數,response.sendRedirect(“login.jsp?param1=a”)。 
      4、sendRedirect能夠處理相對URL,自動把它們轉換成絕對URL,如果地址是相對的,沒有一個‘/’,那麼Web container就認爲它是相對於當前的請求URI的。比如,如果爲response.sendRedirect("login.jsp"),則會從當前servlet 的URL路徑下找login.jsp: http://10.1.18.8:8081/dms/servlet/Servlet 重定向的URL: http://10.1.18.8:8081/dms/servlet/login.jsp,如果爲response.sendRedirect("/login.jsp")則會從當前應用徑下查找url:http://10.1.18.8:8081/login.jsp。而forward不能這樣處理相對路徑。 


他們的區別是: 
response.sendRedirect是向客戶瀏覽器發送頁面重定向指令,瀏覽器接收後將向web服務器重新發送頁面請求,所以執行完後瀏覽器的url顯示的是跳轉後的頁面。跳轉頁面可以是一個任意的url(本服務器的和其他服務器的均可)。 


RequestDispatcher.forward則是直接在服務器中進行處理,將處理完後的信息發送給瀏覽器進行顯示,所以完成後在url中顯示的是跳轉前的頁面。在forward的時候將上一頁面中傳送的request和response信息一同發送給下一頁面(而response.sendRedirect不能將上一頁面的request和response信息發送到下一頁面)。由於forward是直接在服務器中進行處理,所以forward的頁面只能是本服務器的。
----------------------------------------------------------------------------------------------------------
springMVC多個VieResolver的問題
----------------------------------------------------------------------------------------------------------
在springMVC.xml文件中可以配置多個VieResolver


spring容器會加載所有的解析器。


作爲所有請求入口的DispatchServlet他繼承HttpServlet需要實現init方法
調用方法如下


init->initServletBean->initWebApplicationContext->onRefresh->initStrategies->


>initStrategies方法如下
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);


其中有個initViewResolvers
DispatchServet會去匹配所有的ViewResolver的類型
顯然所有的視圖解析器都必須實現該接口。




當所有的DispatchServlet通過路徑的匹配,獲取到相應的Controller(處理器),
並執行相應的方法後,會返回一個ModelAndView


會去調用所有所有的解析器來解析ModelAndView的getViewName()
如果有匹配則會返回view。


for (ViewResolver viewResolver : this.viewResolvers) {
View view = viewResolver.resolveViewName(viewName, locale);
if (view != null) {
return view;
}
}


----------------------------------------------------------------------------------------------------------
類屬性和對象屬性的初始化順序
----------------------------------------------------------------------------------------------------------
對於變量或方法或代碼塊。。。在static的表現上爲 類與對象的區別,即static爲類變量,類方法,類代碼塊。


對於static{}和{}中定義的代碼。。我們稱爲類的代碼塊,和對象代碼塊。


當類初始化時,會遵循 變量優先和static優先。


即優先初始化static的變量。(對象變量不可被調用)
然後調用類的代碼塊static{}


如果通過類創建了對象。
優先創建對象變量
之後調用對象代碼塊{}
最後才調用對象的構造方法






① 類屬性 (靜態變量) 定義時的初始化,如上例的 static String a = "string-a";
② static 塊中的初始化代碼,如上例 static {} 中的 b = "string-b";
③ 對象屬性 (非靜態變量) 定義時的初始化,如上例的 String c = "stirng-c";
④ 構造方法 (函數) 中的初始化代碼,如上例構造方法中的 d = "string-d";


public class Main {


static String a = "string-a";
    static String b;
    String c = "stirng-c";
    String d;

    
public Main(){
print("before constructor");
        d = "string-d";
        print("after constructor");
}
static{
printStatic("before static");
        b = "string-b";
        printStatic("after static");
}
{
print("before none static");
        d = "string-d";
        print("after none static");
}

public static void main(String[] args) {
new Main();
}

public static void printStatic(String title) {
        System.out.println("---------" + title + "---------");
        System.out.println("a = \"" + a + "\"");
        System.out.println("b = \"" + b + "\"");
    }
    
    public void print(String title) {
        System.out.println("---------" + title + "---------");
        System.out.println("a = \"" + a + "\"");
        System.out.println("b = \"" + b + "\"");
        System.out.println("c = \"" + c + "\"");
        System.out.println("d = \"" + d + "\"");
    }


}




----------------------------------------------------------------------------------------------------------
Java中getResourceAsStream的用法
----------------------------------------------------------------------------------------------------------
首先,Java中的getResourceAsStream有以下幾種: 
1. Class.getResourceAsStream(String path) : path 不以’/'開頭時默認是從此類所在的包下取資源,以’/'開頭則是從


ClassPath根下獲取。其只是通過path構造一個絕對路徑,最終還是由ClassLoader獲取資源。


2. Class.getClassLoader.getResourceAsStream(String path) :默認則是從ClassPath根下獲取,path不能以’/'開頭,最終是由


ClassLoader獲取資源。


3. ServletContext. getResourceAsStream(String path):默認從WebAPP根目錄下取資源,Tomcat下path是否以’/'開頭無所謂,


當然這和具體的容器實現有關。


4. Jsp下的application內置對象就是上面的ServletContext的一種實現。


其次,getResourceAsStream 用法大致有以下幾種:


第一: 要加載的文件和.class文件在同一目錄下,例如:com.x.y 下有類me.class ,同時有資源文件myfile.xml


那麼,應該有如下代碼:


me.class.getResourceAsStream("myfile.xml");


第二:在me.class目錄的子目錄下,例如:com.x.y 下有類me.class ,同時在 com.x.y.file 目錄下有資源文件myfile.xml


那麼,應該有如下代碼:


me.class.getResourceAsStream("file/myfile.xml");


第三:不在me.class目錄下,也不在子目錄下,例如:com.x.y 下有類me.class ,同時在 com.x.file 目錄下有資源文件myfile.xml


那麼,應該有如下代碼:


me.class.getResourceAsStream("/com/x/file/myfile.xml");


總結一下,可能只是兩種寫法


第一:前面有 “   / ”


“ / ”代表了工程的根目錄,例如工程名叫做myproject,“ / ”代表了myproject


me.class.getResourceAsStream("/com/x/file/myfile.xml");


第二:前面沒有 “   / ”


代表當前類的目錄


me.class.getResourceAsStream("myfile.xml");


me.class.getResourceAsStream("file/myfile.xml");


----------------------------------------------------------------------------------------------------------













































發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章