2013-01-14 61 views
1

我目前正在開發一個使用servlets & spring框架的網站。像往常一樣,它包含大量的文件(jsp,js,css,圖像,各種資源等)。 我試圖避免編寫任何硬編碼的路徑或任何文件中的域...消除web開發中的硬編碼文件路徑和url

例如,您可能知道何時處理請求,您'轉發'到一個jsp頁面(它的路徑可能會硬編碼)。其他的例子是在jsp文件中導入圖像/ css/js等...

是否有任何通用的方法(或工具)來避免硬編碼路徑/ url,以便重構不會導致麻煩?

編輯
我使用NetBeans 7.1.2。可惜的NetBeans只能用純Java代碼幫助。在使用jsp文件時,事物是有限的,如果您添加自定義標記文件並且Jsp 2.0 EL就像在控制檯模式下編程:p

+0

你可以使用'Source'測試項目時運行。 – madhead

+0

@madhead我更新了我的帖子...我是netbeans粉絲:) – ApollonDigital

回答

0

其實我只是想出了一個主意。由於netbeans會分析並顯示對java代碼的依賴關係,所以最好將所有路徑作爲java變量來處理域&。

我在我的項目中創建了一個名爲FileResolver的包,裏面我有一個類用於項目上的每個文件類型(例如一個類用於Jsp文件,一個用於Css文件等)。在這些文件中,我將記錄&硬編碼公共靜態最終字符串變量中所有文件的所有路徑。示例:

public class Jsps { 

    public class layouts{ 
     public static final String main =  "layouts/main.jsp"; 
    } 

    public class pages{ 
     public static final String error =  "pages/error.jsp"; 
     public static final String login =  "pages/login.jsp"; 
     public static final String register = "pages/register.jsp"; 
    } 
    ... 
} 

遍佈我的項目我應該使用變量而不是路徑。然後任何時候我重構一個文件,我只有一個文件要改變是這些變量的映射值... 如果有時我需要改變這個變量,NetBeans會一次性重構項目中的所有文件。 我認爲這樣做會很好,因爲我保持項目對文件路徑的乾淨,我唯一需要擔心的是該文件中的變量映射到適當的文件路徑。

編輯
我會寫一個簡單的解析器手動創建這些Java文件而不是書面方式對所有文件...我會更新,當我完成它


UPDATE
這裏是我的FileResolverGenerator

public class FileResolverGenerator { 

    private static final String newFilePath = "C:/Users/Foo/Desktop/Jsps.java"; 
    private static final String scanRootFolder = "C:/Users/Foo/Desktop/myProject/web/WEB-INF/jsp"; 

    private static final String varValueReplaceSource = "C:/Users/Foo/Desktop/myProject/web/WEB-INF/jsp/"; 
    private static final String varValueReplaceTarget = ""; 

    private static final boolean valueAlign = true; 
    private static final int varNameSpaces = 15; 


    public static void main(String[] args){ 
     try { 
      // Create file and a writer 
      File f = new File(newFilePath); 
      f.createNewFile(); 
      bw = new BufferedWriter(new FileWriter(f)); 
      // Execute 
      filesParser(new File(scanRootFolder)); 
      // 'Burn' file 
      bw.close(); 
     } catch (FileNotFoundException ex) { 
      Logger.getLogger(ResolverGenerator.class.getName()).log(Level.SEVERE, null, ex); 
     } catch (IOException ex) { 
      Logger.getLogger(ResolverGenerator.class.getName()).log(Level.SEVERE, null, ex); 
     } 

    } 

    // ================================================================================================ // 
    // ============================================= WORK ============================================= // 
    // ================================================================================================ // 

    private static void filesParser(File rootFolder) throws FileNotFoundException, IOException{ 

     folderIn(rootFolder); 
     // Files first 
     if(!rootFolder.exists()) throw new FileNotFoundException(); 
     for(File f : rootFolder.listFiles()){ 
      if(f==null){ return; } 
      if(f.isDirectory()){ continue; } 
      else if(f.isFile()){ writeFileVariable(f); } 
     } 
     // Folders next 
     for(File f : rootFolder.listFiles()){ 
      if(f==null){ return; } 
      if(f.isDirectory()){ filesParser(f); } 
      else if(f.isFile()){ continue; } 
     } 
     folderOut(rootFolder); 
    } 


    // ================================================================================================ // 
    // ============================================ PRINTS ============================================ // 
    // ================================================================================================ // 
    private static BufferedWriter bw; 
    private static int tabCount = 0; 


    private static void folderIn(File f) throws IOException{ 
     bw.append("\n\n"); 
     for(int i=0; i<tabCount; i++) 
      bw.append("\t"); 
     bw.append("public class "+f.getName()+"{\n"); 
     tabCount++; 
    } 

    private static void folderOut(File f) throws IOException{ 
     tabCount--; 
     for(int i=0; i<tabCount; i++) 
      bw.append("\t"); 
     bw.append("}\n"); 
    } 

    private static void writeFileVariable(File f) throws IOException{ 
     String varName = f.getName().split("\\.")[0].replaceAll("-", ""); 
     String varValue = f.getPath().replaceAll("\\\\","/") 
      .replace(varValueReplaceSource.replaceAll("\\\\","/"),varValueReplaceTarget.replaceAll("\\\\","/")); 

     for(int i=0; i<tabCount; i++) 
      bw.append("\t"); 
     bw.append("public static final String "+varName+" = "); 
     if(valueAlign){ 
      for(int i=0; i<varNameSpaces-varName.length(); i++) bw.append(" "); 
      bw.append("\t"); } 
     bw.append("\""+varValue+"\";\n"); 
    } 


} 

只是要具體...這將掃描「/ WEB-INF/jsp /」下的所有文件,並創建一個java文件,其中包含所有jsp文件「註冊」到每個路徑的公共靜態最終字符串變量...想法是使用生成的java文件作爲所有jsps在項目中的參考...始終使用這些變量而不是硬編碼路徑.. 這與項目或任何項目無關。這只是一個工具,它可以節省您的時間,而不是手動爲項目中的每個文件執行此操作。

我還創建了另一個ResolverConsistencyChecker類,它接受所有變量並檢查文件路徑是否正確(文件存在)...因爲我們沒有對文件名和文件路徑進行任何更改,所有測試都通過了。 >`在Eclipse外部化strings` -
此方法應爲 '錯誤'

public class ResolverConsistencyChecker { 

    private static Class checkClass = Jsps.class; 
    private static String fullPathPrefix = "C:/Users/Foo/Desktop/myProject/web/WEB-INF/jsp/"; 


    public static void main(String[] args){ 
     try { 
      filesChecker(checkClass); 
      System.out.println("Tests passed. All files locations are valid"); 
     } catch (FileNotFoundException ex) { 
      Logger.getLogger(ResolverConsistencyChecker.class.getName()).log(Level.SEVERE, null, ex); 
     } catch (IOException ex) { 
      Logger.getLogger(ResolverConsistencyChecker.class.getName()).log(Level.SEVERE, null, ex); 
     } 

    } 

    // ================================================================================================ // 
    // ============================================= WORK ============================================= // 
    // ================================================================================================ // 

    private static void filesChecker(Class rootClass) throws FileNotFoundException, IOException{ 

     // Check file paths in current class depth 
     for(Field f : rootClass.getFields()){ 
      try { 
       String fullFilePath = fullPathPrefix+f.get(f.getName()).toString(); 
       File file = new File(fullFilePath); 
       if(!file.exists()) 
        throw new FileNotFoundException("Variable: '"+f.getName()+"'\nFile "+fullFilePath); 
      } catch (IllegalArgumentException ex) { 
       Logger.getLogger(ResolverConsistencyChecker.class.getName()).log(Level.SEVERE, null, ex); 
      } catch (IllegalAccessException ex) { 
       Logger.getLogger(ResolverConsistencyChecker.class.getName()).log(Level.SEVERE, null, ex); 
      } 
     } 
     // Check for embedded classes 
     for(Class c : rootClass.getClasses()){ 
      filesChecker(c); 
     } 
    } 

} 
+0

它看起來像我試圖接近Android SDK在eclipse上處理資源的方式。 'res'文件夾下的每個文件都會自動在R.java文件中生成一個變量:) – ApollonDigital

1

在JSP文件本身中,您可以通過使用JSTL來避免幾乎所有的硬編碼域/ url

例如,創建一個鏈接到另一個頁面時,你會做這樣的:

<a href="<c:url value="/referrals/send.html"/>" target="_blank">Refer an Entrepreneur!</a> 

這意味着,無論在哪裏,你的web應用是,該鏈接將始終具有正確的網址。舉例來說,在我的開發這個環節是:

http://localhost:8080/accounts/referrals/send.html 

但我的生產服務器上,它正確地解析爲:

http://wwww.mydomain.com/referrals/send.html 

你可以看到,在我的開發服務器,web應用程序上下文under/accounts,但是在生產機器上,它只是在/下,因爲webapp在根上下文中。

你可以閱讀一個小教程here

+0

我已經在幾個星期前檢查過JSTL ...當然,因爲你的路徑是相對的,所以有一個增益,但是「/referrals/send.html」仍然是硬編碼的...如果由於某種原因你重命名/重構send.html,你將在你的應用中運行你的jsp頁面...我使用它但它不能解決主要問題... – ApollonDigital

1

如果您要引用任何靜態內容(JS,圖片,CSS等),你不必硬編碼整個文件路徑。相反,你可以這樣做: -

<img src="${pageContext.request.contextPath}/resources/images/test.jpg"/> 

的文件路徑的其餘部分(休眠域映射,在春季控制器轉發頁等)應該是相對於你的項目結構,和大多數IDE是足夠聰明的重構他們沒有問題...或者至少在我的情況下,IntelliJ似乎處理所有這些對我來說。

在某個時間點,您需要問自己,硬編碼有多少可以接受而不可接受?此外,我不會試圖偏離Spring/Hibernate推薦的解決方案。如果你把所有東西都抽象化了,你就會遇到一系列不同的問題,而且對於其他未來可能繼承你的項目的同行來說,這會產生反作用。

+0

「如果你把所有的東西都抽象化,你就會遇到一些不同的問題來處理「......什麼樣的問題?你可以說得更詳細點嗎? – ApollonDigital

+0

您需要問自己的問題是,如果將來將項目傳遞給其他人,他們是否能夠維持您的聰明的本土解決方案?您將多少次改變文件名稱和位置以證明本土解決方案的合理性? 5%的時間? 90%的時間?你的同事能夠理解你在這裏實施什麼嗎?你能從現在起3個月瞭解你自己的實現代碼嗎? – limc

+0

由於項目正在開發中,文件名,網址和位置經常發生變化......我總是添加,刪除,重構周圍的東西..我想隨着項目的增長,事情會變得更加「穩定」...... 我的實現是基本上把所有我的路徑作爲一個java變量。java文件,而不是xmls和properties,因爲java變量很容易在IDE內處理/維護/重構。 我不會那麼難以猜測我在做什麼...... – ApollonDigital

1

屬性文件始終是一個不錯的選擇,因此您必須在一個點上進行更改。