---
# System prepended metadata

title: MVC & URL
tags: [Servlet&JSP]

---

###### tags: `Servlet&JSP`

# MVC & URL
## MVC
在 MVC 中，將 Web 應用程式劃分為模型、畫面與控制器：

* M模型（Model）的職責
  * 保存應用程式狀態
  * 執行應用程式商務邏輯（Business logic）
  * 只要跟資料庫有關
  * 細分成Dao、Bean、Servers 等等
* V畫面（View）的職責
  * 提取模型狀態
  * 執行呈現邏輯（Presentation logic）組織回應畫面
* C控制器（Controller）的職責
  * 接受請求
  * 驗證請求
  * 判斷要轉發請求給哪個模型
  * 判斷要轉發請求給哪個畫面
   


大致的流程示意如下所示：
![](https://i.imgur.com/lqsiuek.png)


例子:依使用者發送的名稱來提取個別訊息顯示。
```
package cc.openhome;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
    private Hello hello = new Hello();

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
                throws ServletException, IOException {
        String name = request.getParameter("user");
        String message = hello.doHello(name);
        request.setAttribute("message", message);
        request.getRequestDispatcher("hello.jsp").forward(request, response);
    }

}
```
其中 Hello 的職責劃分是模型，根據使用者的 user 請求參數不同，會取得不同的訊息給 message 參考：
```
package cc.openhome;

import java.util.*;

public class Hello {
    private Map<String, String> messages;

    public Hello() {
        messages = new HashMap<>();
        messages.put("caterpillar", "Hello");
        messages.put("Justin", "Welcome");
        messages.put("momor", "Hi");
    }

    public String doHello(String user) {
        return String.format("%s, %s!", messages.get(user), user);
    }
}
```
依上，如果 user 請求參數是 caterpillar 就會取得 "Hello" 字串，如果是 Justin，就會取得 "Welcome" 字串，在取得訊息之後，先前擔任控制器的 Servlet 會轉發給畫面：
```
<!DOCTYPE html>
<html>
    <head>
        <title>${param.user}</title>
    </head>
    <body>
        <h1>${message}</h1>
    </body>
</html>
```
畫面會取得使用者的訊息，並使用 HTML 來顯示，所以，如果你的請求是：
```
http://localhost:8080/ServletDemo/hello?user=caterpillar
```
得到以下的 HTML：
```
<!DOCTYPE html>
<html>
    <head>
        <title>caterpillar</title>
    </head>
    <body>
        <h1>Hello, caterpillar!</h1>
    </body>
</html>
```
經由適當的職責劃分，控制器與模型不用處理 HTML 的輸出，而 JSP 也不會被 Java 程式碼干擾，複雜的情境時MCV各司其責，使得程式更易於維護。

**注意** : 以上只是範例別直接放到你實際上線的程式之中，這個簡單的程式中，由於 JSP 頁面直接將使用者的請求參數輸出，如果使用者懷著惡意輸入了一些不該輸入的東西，例如 JavaScript 程式，就可以製造某種形式的攻擊了。


---


## URL模式
### 一個請求 URI 實際上是由三個部份所組成
```
requestURI = contextPath + servletPath + pathInfo
```
可以使用 HttpServletRequest 的 getRequestURI() 來取得。

其中 contextPath 是環境路徑（Context path），是容器用來決定該挑選哪個 Web 應用程式的依據（一個容器上可能部署多個Web應用程式），在 Servlet 4.0 之前，環境路徑的設定並沒有標準規範，而是依伺服器實作而有所不同。例如在 Tomcat 9 中，可以設定 context.xml 的 <Context path="xxxx"> 來決定，在 Servlet 4.0 中，可以於 web.xml 中使用 <default-context-path> 來設定預設路徑，然而，容器實作廠商可以覆蓋這個設定。

你可使用 HttpServletRequest 的 getContextPath() 來取得。如果應用程式環境路徑與 Web 伺服器環境根路徑相同，則應用程式環境路徑為空字串，如果不是，則應用程式環境路徑以 / 開頭，不包括 / 結尾。
    
一旦決定是哪個 Web 應用程式來處理請求，接下來就進行 Servlet 的挑選，Servlet 必須設定 URL 模式（URL pattern），可以設定的格式優先序如下：

### 1.Exact match 明確の對應關係(嚴格匹配)
    字串完全吻合且不含 * 號。
    
    例如若 URL 模式設定為/HelloWorld.do。
    servletPath為/HelloWorld.do。

### 2.Path mapping 前置路徑の對應關係
    / 開頭但 /* 結尾的 URL 模式。
    
    例如若設定 URL 模式為 /guest/*，則請求 URI 扣去環境路徑的部份若為/guest/test.view
    、/guest/home.view 等以 /guest/ 作為開頭的，都會交由該Servlet處理。
    
    servletPath為/guest。
    PathInfo為/*查到的東東。(只有Path mapping有PathInfo!)
    
    
### 3.Extension mapping 延伸檔名の對應關係
    以 *. 開頭的 URL 模式。
    
    例如若 URL 模式設定為 *.view，則所有以 .view 結尾的請求，都會交由該 Servlet 處理。
    
    servletPath為/guest/test.view。
    
### 4.Context root 預設の對應關係
    僅包括 / 的 URL 模式。
    
    當找不到適合的 URL 模式對應時，就才會使用預設 Servlet。
    
![](https://i.imgur.com/SEAvSsb.png)

    
在最上面的 requestURI 中，servletPath 的部份是指 Servlet 路徑（Servlet path），不包括路徑資訊（Path info）與請求參數（Request parameter）。Servlet 路徑直接對應至URL模式資訊，可使用 HttpServletRequest 的 getServletPath() 來取得，Servlet 路徑基本上是以 / 開頭，但 /* 與空字串的URL模式比對而來的請求除外，在 /* 與空字串的情況下，Servlet 路徑是 ""。

例如若某個請求是根據 /hello.do 對應至 Servlet，則 Servlet 路徑就是 "/hello.do"，如果是透過 /servlet/* 對應至 Servlet，則 Servlet 路徑就是 "/servlet"，但如果是透過 /* 或空字串，則 Servlet 路徑就是 ""。

requestURI 中 pathInfo 是指路徑資訊（Path info），路徑資訊不包括請求參數，指的是不包括 Context Path 與 Servlet Path 部份的額外路徑資訊。
    
可使用 HttpServletRequest 的 getPathInfo() 來取得。如果沒有額外路徑資訊，則為 null（延伸對應、預設 Servlet、嚴格匹配的情況下），如果有額外路徑資訊，則是個以 "/" 為開頭的字串。

好累剩下的翻這個後面:
https://openhome.cc/Gossip/ServletJSP/URLPattern.html
    
    
    
    
    
REST 全名 REpresentational State Transfer
直接翻譯:代表性的狀態轉移