---
# System prepended metadata

title: servlet & jsp

---

# servlet & jsp

程度=學習力
* 專注力
* 理解力
* 記憶力
課後複習+作業
老師則授課+解惑

系統程式:非客製化  c/c++不處理資料庫資料
應用程式:客製化 Java,C#,Python,Javascript

1. window app: pc
* javax.swing.*
* java.awt.* 
* java.awt.event
2. mobile app:mobile device
3. web app:server (我們在學的)

自學=程式設計的能力(資訊之母)

get 查詢/刪除
post 新增/修改

---

GET請求用於獲取資源，而POST請求用於向服務器提交數據。需要注意的是，POST請求可以用於執行CRUD操作中的"創建（Create）"、"更新（Update）"和"刪除（Delete）"


---

get有cache，查詢時候會出現舊資料，透過程式關掉cache就能立即秀出新資料。
直接從database抓資料，client透過server跟database抓資料再回傳給client。

出現問題就refresh 網頁

• GET
GET的請求應用於從後端取得資料。
• POST
• POST 的請求用於提交資料至後端。
PATCH
PATCH 的請求用於套用資料至後端修改。
• DELETE
DELETE 的請求用於刪除後端指定資料。


HTTP要求(HTTP request)
當我們在瀏覽器發出HTTP要求，就會用到在HTTP協定的規範中定義的不同HTTP請求方法，最常見的有：

GET(最常用)：請求特定資料
POST：提交資料(例子：註冊帳戶、驗證資料等)
PUT：取代特定資料，通常是更新整個資料
PATCH：修改特定資料，通常是更新部分資料
DELETE：刪除特定資料

另外注意，HTML的的表單只能用GET或POST方法，不能以此兩個以外的方法。
```
瀏覽器 ----(HTTP request)----> 伺服器 <--> 資料庫
瀏覽器 <----(HTTP response)---- 伺服器 <--> 資料庫
```

---

* forward
```
client---req-->server(servlet1--req->servlet2)--res-->clint
```

* include
```
client---req-->server
(servlet1--req->servlet2--req->servlet1)--res-->clint
```

---

* 我的網頁可以用Facebook登入，於是我去串接Facebook提供的API
* 我的網頁要加入客製化的Google Map，於是我去串接Google Map提供的API


我們可以利用這些狀態碼來做錯誤處理。例如在學習XMLhttpresquest時，我們常常會透過if...else判斷status === 200，從而處理錯誤情況：

```=javascript
const xhr = new XMLHttpRequest();
xhr.open('get','https://randomuser.me/api/',true);
xhr.send(null);

//狀態碼:200代表成功。我們利用此狀態碼去做判斷，做到錯誤處理
xhr.onload = () => {
    if(xhr.status === 200){
        console.log(JSON.parse(xhr.responseText)); 
    }else{
        console.log('請求失敗!')
    }
}
```

AJAX基本概念：

AJAX是一個非同步執行的技術
不用刷新頁面就能更新網頁資料，不能中斷使用者瀏覽網頁

API意思：

程式與程式之間的串接

API接口是一個網址

HTTP協定：

客戶端與伺服器之間傳輸資料的規範
瀏覽器向伺服器提出HTTP要求(GET、POST、DELETE...)
伺服器除了回傳相應資料，也會回傳HTTP狀態碼

```
<load-on-startup></load-on-startup>
等於
<load-on-startup/>
```

get 透過cache存在browser,不用透過server抓資料，所以速度很快。

---

沒有初始參數值，不需要寫init()
init()生命週期的方法
tomcat關掉的時候執行destroy()

分為有傳ServletConfig config
參數和沒有傳參數的init()

String getInitParameter(String name)

第一次呼叫會產生實例
只有生和死時候會呼叫init()
第二次開始不會呼叫，

參數值是String 字串
把參數值(name(key)/value)放到ServletConfig的實例
每一個Servlet對應一個ServletConfig的實例

---

annotation 與 web.xml差別(p.30)
什麼情況用什麼
針對所有用web.xml
針對個別用annotation

web.xml比較易懂易讀

---

`@WebServlet 指到urlParttern`
@WebServlet(==第一個屬性==urlParttern="/ServletInitParams" ,
==第二個屬性==initParams = { 
==第一個初始參數值的屬性==@WebInitParam(name="greeting",value="Have a nice day!"),
==第二個初始參數值的屬性==@WebInitParam(name="count",value="3")})

```
@WebServlet(urlPatterns="/ServletInitParams" ,
initParams = { 
@WebInitParam(name="greeting",value="Have a nice day!"),
@WebInitParam(name="count",value="3")})
```

---

csv, json, xml

server---->jsno--->>client(JS)
跨公司用xml,而不是json

---

<display-name>Servlet 3.0 Web Application</display-name>
<context-param>
<param-name>centerFile</param-name>
<param-value>/res/TrainingCenters.csv</param-value>
</context-param>

public InitTrainingCenters(){
}

public void contextDestroyed(ServletContextEvent sce){}

public void contextInitialized(ServletContextEvent sce){}

---

public void contextInitialized(ServletContextEvent sce){
ServletContext
}


---
@SuppressWarnings("unchecked")

---

Listener 頃聽/監聽事件的發生，ServletContext物件的生命週期，也就是Web App的生命週期。

把Listener換成Event
onclick

Listener要怎麼把資料傳給Servlet?
先把資料放在context裡面，用.setAttribute()

---

 ✏ServletConfig 跟ServletContext 之間的關聯

當tomcat 第一次開啟時，會建立servlet物件，同時也會建立context物件，接著會調用intit有參數的方法，(參數是servletConfig)，來初始化


---

src/main/java和webapp是對應的
webapp路徑跟java的urlpattern路徑是相對應的

uniform resource locator (URL)

---

Filter 瀏覽器與Servlet/JSP間的仲介者，

client端向server端request之前叫做前置
server 向client response之後叫做後置

* Authentication filters 身分驗證
適合用在下request之前 驗證，跟錢有關
* Logging and auditing filters流水帳和監察
Logging 屬於後置，跟錢有關-銀行，記錄到log上，為每一筆交易紀錄log，時間地點做了什麼事，
audit把log拿來auditing，
auditing用來災害復原、稽核。
* image conversion filters
可以是前置或後置，
* data compression filters
資料壓縮，後置
* Encryption filters
亂碼，可以是前置或後置

在資料夾裡面誰在上面誰就先做(先執行)
filter間不能有任何關係

如果有邏輯就寫在do/get

---

EncodingFilter
EncodingFilterDemo (servlet)

用filter解決編碼問題(亂碼)

---

## session 與cookie

p.21
一個request + 一個response= 一個生命週期
HTTP = stateless形式的通訊協定

兩種放資料方式:request(太短) /context(太長)跟應用程式同壽，但是太佔空間拉。
購物車:不斷來回才能完成任務，所以有第三種方式，叫做session。

session: C->S端不間斷的一連串的請求與回應組合的
session 產生於於client端第一次向server的請求request，session由server端產生。
session ID是唯一值，且不會重複。
避免跟其他使用者ID重複，避免送錯資訊

---

### session終止時機:
- 30分鐘session就會timeout，想延長session，client端就要再發出請求requst
- 利用程式終止session進行:how?


client第一次提出需求request>產生session並給他一個ID
server回傳時，ID也要跟著傳回去client端
browser要想辦法把ID記錄下來，
client第二次提出需求時，ID隨附在舊session上，只要不要超過30分鐘。
不同ID時，server會拒絕存取。
透過ID來判斷是不是同一個session。

---

* boolean is New()
true:first time
false: 第二次開始
* void invalidate()
讓session失效
* long getCreationTime()
取得session建立的時間
long 表示日期時間(毫秒)
new Date 來轉換日期
* long getLasAccessedTime()
取得用戶上次上網(存取)的時間


---

session則是負責暫存client資料

servlet -Listener 就是紀錄和共享資料的功能，根據生命週期分為三種，request, session, 和context

---

### 設定session 有效時間

void setMaxInactiveInterval(int seconds)
個別設定session的有效時間:
只能設定這一次，下一個session又回到預設值30分鐘。

---

ID:6DBA9D12B9E4EED474713F309615F71F  
Created : Fri Apr 21 09:29:51 CST 2023  
Last Accessed : Fri Apr 21 09:29:51 CST 2023

name = pan

---

```
ID : E588CEE70CAAFA63ADF15C242FAAD56C
Created : Fri Apr 21 09:43:03 CST 2023  
Last Accessed : Fri Apr 21 09:43:03 CST 2023
name = pan  
age = 44
```

```
ID : E588CEE70CAAFA63ADF15C242FAAD56C
Created : Fri Apr 21 09:43:03 CST 2023
Last Accessed : Fri Apr 21 09:43:21 CST 2023
name = pan
age = 44
height = 177

```

getSessionInfo.java
```java=
@WebServlet("/GetSessionInfo")
public class GetSessionInfo extends HttpServlet {
	private static final long serialVersionUID = 1L;
	
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		//設定編碼(萬用寫法)
		request.setCharacterEncoding("UTF-8");
		//取得session
		HttpSession session = request.getSession(true);
		//取得資料
		String attName = request.getParameter("attrName");
		//attName != null表示有名子，attName.length()>0表示有輸入資料
		if (attName != null && attName.length() > 0) {
			String attValue = request.getParameter("attrValue");
			//setAttribute把資料存起來
			session.setAttribute(attName, attValue);
		}
		//MIME 
		response.setContentType("text/html;charset=UTF-8");
		PrintWriter out = response.getWriter();
		//第一次產生時間
		Date created = new Date(session.getCreationTime());
		//最後一次存取時間
		//new Date 透過建構子產生毫秒時間的日期
		Date accessed = new Date(session.getLastAccessedTime());
		//印出標籤內容
		//現在不用out.write寫法，因為IO次數太多，而是用串接寫法 .append()?
		out.write("<html><body><h2>Session資訊</h2>");
		out.write("ID : " + session.getId() + "<br>");
		out.write("Created : " + created + "<br>");
		out.write("Last Accessed : " + accessed + "<p>");
		//getAttributeNames抓session名子和她所有資訊傳到names，Enumeration不能用for each
		
		Enumeration<String> names = session.getAttributeNames();
		//不知道集合裡面個數所以用while
		//names.hasMoreElements() 判斷還有沒有元素，取得布林值
		while (names.hasMoreElements()) {   //hasNext() 是目前用法
			//取得下一個Element
			String name = names.nextElement();  //現在 names.next()
			//先getAttribute取得Object，再用toString()轉成字串String
			String value = session.getAttribute(name).toString();
			out.write(name + " = " + value + "<br>");
		}
		out.write("</body></html>");
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response)
		 throws ServletException, IOException {
		 doGet(request, response);
	}
}
```


---

### cookie

session 存在server 端

cookie存在client 端(browser)

* 存放位置
記憶體:網頁關掉就消失
硬碟:存在檔案裏面(會有過期時間)

可有可無資料才存放在cookie
主要還是靠Listener>session

* cookie以key/value形式儲存

存/紀錄你購物車上收藏的商品

透過cookie來實現客製化服務
記錄使用者喜好來推送廣告，像是商品推薦、對個別使用者打招呼，
client端也能把cookie功能關閉

---


傳回資料像是html，額外資訊放在header

* 沒session會顯示The request has no cookies

執行cookie 會抓取上一次session輸入的資訊

步驟:
先run session 取得JSESSIONID = BBCF267B0B55715283B0A4133983BB82

run html 設定key value
再run一次 html顯示上一次輸入的值

GetCookieInfo.java
```java=
@WebServlet("/GetCookieInfo")
public class GetCookieInfo extends HttpServlet {
	private static final long serialVersionUID = 1L;
	
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
			
      	request.setCharacterEncoding("UTF-8");
		response.setContentType("text/html;charset=UTF-8");
		PrintWriter out = response.getWriter();		
		out.write("<html><body><h2>Cookie資訊</h2>");
		//使用者連上網頁就先取cookie
		Cookie[] cookies = request.getCookies();
		//先判斷是不是null
		if (cookies != null)  //表示cookie內有東西
			for (Cookie c : cookies)
				out.write(c.getName() + " = " + c.getValue() + "<br>");
		else //表示cookie內沒有東西
			out.write("The request has no cookies");
		out.write("</body></html>");	
		
		String name = request.getParameter("cookieName");
		if (name != null && name.length() > 0) {
			String value = request.getParameter("cookieValue");
			//產生cookie
			Cookie c = new Cookie(name, value);
			response.addCookie(c);
		}
	} // end of doGet()

	protected void doPost(HttpServletRequest request, HttpServletResponse response)
		 throws ServletException, IOException {
		 doGet(request, response);
	} // end of doPost()
}
```
---

### JSP =JavaServer Pages
用java幫助你產生網頁
JSP 抄襲ASP

JSP: 主要是html再崁入script，來產生動態網頁

一個JSP page包括:
* html +JS
* jsp elements產生動態內容(以<%%>包起來，並以.jsp命名)
p.86 網頁內容 String html=

直接拉到對應資料夾>overwrite

---

servlet -Listener 就是紀錄和共享資料的功能，根據生命週期分為三種，request, session, 和context

而JSP多一個page,第四種放資料的方式

```
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>


page 屬性名稱="屬性的值"
=左右不要有空白

```

---
### JSP directive elements
* page
* include:
include 每一個網頁都有(共同)的內容
* taglib:

先有servlet才有jsp
所以才會import  java.servlet

---
```
page里的变量没法从index.jsp传递到test.jsp。只要页面跳转了，它们就不见了。
request里的变量可以跨越forward前后的两页。但是只要刷新页面，它们就重新计算了。
[session]和application里的变量一直在累加，开始还看不出区别，只要关闭浏览器，再次重启浏览器访问这页，session里的变量就重新计算了。
application里的变量一直在累加，除非重启tomcat，否则它会一直变大。
```

declaration: <%!
scriptlets: <%
expression: <%=

<% , <%= 寫在doGet()裡面
<%! 寫在doGet()外面

第一次產生實例(new)時是0，之後每run一次+1
有+!和沒有的差別?

有!每次都+1，想重置就重啟tomcat
沒!就維持count=1，

```java=
<%@ page language="java" contentType="text/html; charset=BIG5"
    pageEncoding="BIG5"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="BIG5">
<title>Insert title here</title>
</head>
<body>
<%--JSP element demo-- --%>
<%int count=0; %>
<%count++; %>
Welcome,your visitor number is
//上面這行是template text，放在out.write()引數中
<%=count %>
</body>
</html>

```

<%%>裡面不能再有<%%>


<%=   name%>=<%=value%><br>
<%=   name +"="+ value%><br>

---

### javabean
bean=咖啡豆=建立bean類別的物件來存取資料

1. 實做序列化介面
2. 可以有多個建構子，但一定要有一個沒參數的public建構子
3. 類別不會宣告為public，會宣告為private
4. public 的getter/setter方法
bean是在處理java的一個類別
private封裝後寫getter跟setter方法

serializable序列化介面:把大分子轉成小分子。
組合回去叫做deserializable:把小分子轉成大分子。
只能序列化實例變數。

//轉成物件
//把資料轉成字串
//java傳輸資料給javascript，


String sb =new StringBean();
sb.setAttribute("sb",sb);

>為了要會什麼，就要練習什麼。
---

### action elements

action elements目的是減少jsp scriptlet上的使用，不要用<%，不要混搭

<%=stringBean.getMessage()%>
等於
<jsp:getProperty name="stringBean" property="message" />

<%stringBean.setMessage("Learning JSP is wonderful");%>
等於
<jsp:setProperty name="stringBean" property="message" value="This is a test" />

---

private屬性叫做attribute


property屬性指的是setter getter的方法，比方說會去找你的setMessage()
並去掉set 再把M轉成小寫->得到message

public double getSubTotal()
->subTotal

表格欄位名稱跟屬性和getter/setter方法屬性對應

ORM=object, relational database 要一對一對應, mapping 映射

真正接輸入資料的是servlet而不是JSP
真實事件要要分工的，
![](https://i.imgur.com/5RjDPuW.png)
Servlet充当Controller , jsp 充当 View 
Java bean 当然就是Model 了！

---

### JSP的運作機制

-   特性
    
    -   1.translate & complie  
        Container會將JSP中的內容轉譯(translate)成servlet的java檔  
        再將它編譯(complie)成servlert的.class  
        後續就同一個servlet的步驟去完成初始化以及針對每個request產生一個獨立的thread
        
        **流程如下:**  
        _myJsp.jsp -> (translate) -> myJsp\_jsp.java -> (complie) -> myJsp\_jsp.class -> myJsp_jsp_
        
        如同servlet只要初始化後,就會針對request去使用thread配置  
        因此JSP的translate和complie只會發生一次,之後就如同servlet來運作
        
    -   2.更新方式  
        但JSP較servlet方便的部分為  
        servlet修改或需要重啟server,但JSP不用  
        因為JSP受Web Containe所監控
        
    -   3.DD設定  
        JSP不須像servlet要設定DD  
        除非有需要orverride init()
        
-   生命週期(即translate後的Servlet API)
    
    -   jspInit()  
        如同servlet的init(),可以orverride
        
    -   jspDestroy()  
        同servlet的destroy(),可以orverride
        
    -   __jspService()  
        同servlet的service(),因此不能orverride
        
-   JSP元素類型  
    JSP提供了下列的表示法,減少了網頁設計者及開發人員的困難  
    大概分為下列:
    
    -   Scrriptlet
    -   Java運算式
    -   宣告
    -   指令
    -   EL表達式
    -   action

---

四種認證型式  
剛剛講到的login-config  
是認證的一種型式  
種共有四種:

-   1.BASIC  
    以base64編碼格式去做encoded,安全性較弱
-   2.DIGEST  
    使用DIGEST較安全的方式登入,但J2EE不完全支援
-   3.CLIENT-CERT  
    非常安全的機制,但需要公私鑰,通常應用在B2B
-   4.FORM  
    使用合法的HTML建立自訂表單,認證方式最不安全,也沒有提供加密方式

除了FORM之外,其他方式是只要有設定在DD的login-config  
自動就會去實作彈出標準的表單登入

---

### javabean

除了getter/setter/還可以包含boolean isxxx()
```java=
//判斷使用者輸入的帳號密碼是不是符合註冊的資料
    public boolean isValid() {
        return "caterpillar".equals(name) && "123456".equals(password);
    }

```



JSP 網頁最終將轉換為 Servlet，所謂的 JavaBean，實際上也是 Servlet 中的一個物件實例，當你使用 `<jsp: useBean>` 時，實際上就是在宣告一個 JavaBean 的物件，`id` 屬性即是用以指定參考名稱，而 `class` 屬性則是型態名稱。例如若你在 JSP 的頁面中撰寫以下的內容：

```
<jsp:useBean id="user" class="cc.openhome.User" />
```

實際在轉譯為 Servlet 之後，會產生以下的程式碼片段：
```
cc.openhome.User user = null; // id="user" 就是產生這邊的user參考名稱
synchronized (request) {
    user = (cc.openhome.User) _jspx_page_context.getAttribute(
                  "user", PageContext.PAGE_SCOPE);
    if (user == null){
        user = new cc.openhome.User();
        _jspx_page_context.setAttribute(
                    "user", user, PageContext.PAGE_SCOPE);
    }
}
```

---

一個servlet至少會有三個名稱：類別名稱、註冊的servlet名稱、與URI pattern名稱。

---


4/27

servelet: 負責前端跟server的溝通

MVC 讓你不用jsp/servlet二選一，讓你取他們雙方的優點

商業邏輯:bean :把運算結果讓人用getter存取，但會讓bean太龐大
目前bean只是封裝你要處理的資料。

* model
  - JavaBean:封裝你要處理的資料
  - dao:資料處理 (一個表格寫一個dao)
  - service:商業邏輯放在裡面(一個功能寫一個service類,一個service可能用到兩個dao)
* view
* controller (小專案dao /service暫時先放在controller)

DB接到資料先回傳到javabean，再傳回servlet

servlet forward資料 to jsp ，再丟給client端

---

老師會教查詢(單筆/多筆)
作業:新增/修改/刪除

多筆資料>ListBean

早上是用寫死在程式上，如何連接到db.property?

- 改用連線池方式
跟jdbc課差別?

![](https://i.imgur.com/cRWyY2v.png)

DB城堡/護城河(蓋橋拆橋)/橋上限量-->用連線池取代

- 蓋橋拆橋的動作->  conn=DriverManager.getConnection(DB_URL,   USER,   PASSWORD);


- 連線池是先把橋蓋好了，
一開始工作是先把東西生出來，
後續幾年開始追求資料庫效能

![](https://i.imgur.com/Xv1wH3U.png)






---

private 是只有這個類可以用

static 表示不需要實體化就能用，有「共享」的特性。
比較有static跟沒有static的差異，一個決定性的不同是**載入記憶體的時機**。
因為一開始就存在於記憶體之中，所以稱為**靜態**(static)。

final 是變成常數，表示不能更改。

>老師是因為只有自己能用才這樣宣告，讓屬性變成常數

>老師都用private static final宣告常數

![](https://i.imgur.com/Uwxm65A.png)


---

# JNDI


![](https://i.imgur.com/h8x1XBL.png)

跟程式要連線,不是跟DB
跟datasource要連線池已經蓋好的橋
程式關掉 =  一口氣把橋拆掉


只要是資料的來源，就是DataSource。

Java 透過JNDI將 DataSource記錄到server上，

JNDI是紀錄資訊的地方，

透過查JNDI就能找到DataSource。

使用DataSource就是使用連線池
![](https://i.imgur.com/VCuB8lD.png)

datasource 跟jdbc都是介面

---

javax.sql.DataSource (extension)

---

## Tomcat 設定JNDI DataSource

- context.xml在終止標籤前打 (這裡context指的是JNDI)
透過JNDI去找DataSource (JNDI lookup)
   - "java:/comp/env/jdbc/xxx" 
   - xxx你取的名子，是對應context.xml和server.xml裡面的name="jdbc/xxx"
   - context.xml 裡面的global應該也要一一樣


![](https://i.imgur.com/Bh6pQ9z.png)

* context.xml 在context結束標籤前面新增ResourceLink標籤
```
    <ResourceLink type="javax.sql.DataSource" 
    global="jdbc/servdb" 
    name="jdbc/servdb" />
```


-  server.xml 在GlobalNamingResources標籤內，另一個Resource上打

```
 <Resource auth="Container" driverClassName="com.microsoft.sqlserver.jdbc.SQLServerDriver" initialSize="5" maxIdle="5" maxTotal="8" maxWaitMillis="-1" name="jdbc/servdb" password="sa1234" poolPreparedStatements="true" type="javax.sql.DataSource" url="jdbc:sqlserver://localhost:1433;databaseName=servdb;TrustServerCertificate=True" username="sa" validationQuery="select 1"/>
```


![](https://i.imgur.com/0xFHWCh.png)


# 匯入匯出
新建資料夾裡面再新建一個workspace資料夾 /新建server/新建 new dynamic project /新建 new servlet測試後 /就能更改server.xml 和context.xml，之後再匯入專案

---

xml規定 根源只能有一個

webxml ->web-app標籤
context ->context標籤
server->server標籤

---

- 單筆執行html檔
- 多筆直接執行servlet檔

---

作業:  empDao 
另外產生專案放作業，把單筆和多筆的放進去
一個表格一個bean，一個表格一個dao



package
com.lcpan.bean
com.lcpan.dao  (所有sql指令+連線)
至少五個方法 取得所有資料    新增修改刪除查詢兩種(五種)
com.lcpan.controller
com.lcpan.service


![](https://i.imgur.com/XwtcJc7.jpg)



- insert
  - insert.html->insert.java(servlet)用getParam去接->insert.jsp(網頁上顯示新增成功的訊息->基本)，

加分題:

上面顯示新增的欄位
頁面最下面
新增(submit->送進資料庫)/取消按鈕(reset清空)
最下面顯示新增成功

新增不成功:primary key ...
紅字顯示新增不成功

- delete
   - delete.html->delete.java->delete.jsp

- update: update就是先查詢再update
   - getUpdate.html (update哪一筆資料)->getUpdate.java(servlet查詢)->UpdateData.jsp(不能只顯示，還要有輸入功能:)->update.java(serverlet update)->UpdateData.jsp
   - 設計那些能改那些不能改，不能改就不要有input輸入框，可以改才有框能輸入，
   - 除了某幾個，但實際上是全改
   - 全set=萬用，有更新沒更新都送到後端

>路徑有關的bug要注意

 ---
 
 # debug
 寫作業就是練習debug的能力
 
1. complier error (syntax error)
IDE上的小紅叉
2. rumtime error
   *  exception error (500最好除錯)
   * logical error ->trace 追蹤法來除錯
   * environment error


---

M: 邏輯處理(對業務熟的)又會java(強的人做)
V: 前端
C: java

各種action:
useBean產生物件


![](https://i.imgur.com/mOcG9UO.png)

EL
只有取，沒有存
用來處理在JSP容器中的資料
JSP只取資料
servlet---(controller)--->JSP
controller負責傳資料
request--> C接使用者需求-->M -->D
                 C<--<--M <--D
            C-->V (
            傳java bean /map 用.或[]
                傳list 用[] 
資料只分bean和list bean兩種

C扮演dispatch角色
![](https://i.imgur.com/tjilRe4.png)

---

![](https://i.imgur.com/bkcQqWk.png)


![](https://i.imgur.com/Z1F0de0.png)

request.setAttribute("",)
""裡面的對應識別名稱 ，取字串物件的方式


---

.java
int rs=0  //rs是顯示更新幾筆

.jsp
if(Integer.parseInt(request.getAttribute("rs").toString())==1
新增一筆

.jsp
if(Integer.parseInt(request.getAttribute("rs").toString())>=1
新增多筆

---


![](https://i.imgur.com/XXseLeH.png)


打錯字直接不印出來，不會報錯。
"0" EL會把你轉成int，如果不能轉，會出現error
java不能這樣寫"0"

javascript 數字0和字串0是同個意思
"12" /4 =3，javascript會幫你轉換


El不能跟jqeury混用

---

![](https://i.imgur.com/jWCoacJ.png)


![](https://i.imgur.com/PLWmh2n.png)


MVC純放在JSP


headerValues.xxx[0] 陣列



---


p.168 
${sessionScope}
sessionScope 其他三個scope都空的情況下，sessionScope可以不用寫，

對應p.175
![](https://i.imgur.com/UWSU3k2.png)

如果都有相同屬性，且沒寫scope就會先抓page
```
customer 屬性的值：${customer}<p>
```

要用下面方式標註scope
```
pageContext.customer = ${pageScope.customer}<br>
request.customer = ${requestScope.customer}<br>
session.customer = ${sessionScope.customer}<br>
application.customer = ${applicationScope.customer}
```

---

p153
![](https://i.imgur.com/Fo2Mepl.png)

p177
EL 不用寫usebean /scope
![](https://i.imgur.com/MwRf0FX.png)


---

p167
![](https://i.imgur.com/7rSh7Q3.png)

## JSTL

p157
![](https://i.imgur.com/ypTJ9g3.png)

<% %>不能跟EL混用

![](https://i.imgur.com/8adxO1Z.png)

之後才新增JSTL
jstl jar

taglib p123
![](https://i.imgur.com/74KC5AV.png)


![](https://i.imgur.com/e7kr6MB.png)

不再使用<% %>

---

p181
![](https://i.imgur.com/Ewqv2t8.png)

只有變數(x)可以更改
prefix="x"
只要確保變數名不要重複

---

JSP裡面JS的script內，可以location.href("/html路徑"
)可以把網頁跳轉到html頁面讓使用者再次確認，

- 作業
delete和update
html一個(讓使用者輸入資料，只有第一個servlet會用到) ，jsp/servlet都建立兩個檔案


---

![](https://i.imgur.com/tdoxui1.png)


![](https://i.imgur.com/5McEm5F.png)


![](https://i.imgur.com/ZSO2YFF.png)


if.jsp
```
http://localhost:8080/JSP/m13/If.jsp?user=pan&password=1234

網址後面新增?user=pan&password=1234
就能直接跳轉到正確的頁面(歡迎光臨)
```


![](https://i.imgur.com/mXMFB6S.png)

上面這寫法是錯誤的，執行結果一樣維持錯誤，
密碼正確也是沒反應。
除了${param.password}，運算式也要寫在{}裡面
param.password叫做? 


![](https://i.imgur.com/1vr8lT4.png)
可以用多個c:when 來代替else if


p190  JSTL+EL
![](https://i.imgur.com/YTWautU.png)

p172
![](https://i.imgur.com/p9g7PbI.png)

for (資料型態 變數  : arr/list的變數名稱)


![](https://i.imgur.com/gnZAvkY.png)
被切割完的字串String，叫做token
把字元分隔成小字串，用逗點、空格、或其他東西分割
，像是split

處理模式跟forEach標籤一樣

---

老師示範寫code


<c:set var="count" value/>

${emp.count}


![](https://i.imgur.com/v2WUNwp.png)


變數status是區域變數，所以只存在foreach標籤內
```
<c:forEach items="${emps}" var="emp" varStatus="status">
<tr><td>${emp.empno}
	<td>${emp.ename}
	<td>${emp.hiredate}
	<td>${emp.salary}
	<td>${emp.deptno}
	<td>${emp.title}
	<c:set var="count" value="${status.count}"></c:set>
    //沒寫scope 所以count是page變數,
套用至這個jsp網頁
</c:forEach>
</table>
<h3>共${count}筆員工資料</h3>
```

---

作業升級
![](https://i.imgur.com/McjmyLq.png)

![](https://i.imgur.com/lNopxAG.png)

![](https://i.imgur.com/0w9CzJG.png)

讓JSP顯示所有欄位，不用動bean，取資料時候，在servlet要呼叫dao時(指令後面+join)

單筆資料page 名子做超連結，一樣是單筆查詢，用編號去查詢   *最難 要怎讓名子對應到編號?

新增首頁main page

查詢所有員工資料->模糊查詢  =% 
=?
姓名關鍵字查詢:
這兩個都跳到右邊的頁面

insert page-insert.html

多兩個欄位:更新和刪除(做成button)
按鈕對應到員工編號

update page-
delete page-詢問是否要刪除 (用alert做)

員工姓名:按了跑出編號單比查詢的
page-select單比

部門名稱不能只顯示編號要確切的
要join部門的表

---

Servlet是透過何種介面的何種方法將request傳給JSP網頁
>RequestDispatcher的forward()


---

windows +v 儲存你曾經複製過的東西

---


- html 路徑是寫servlet action=路徑
- jsp 路徑是寫html。

- servlet路徑是寫jsp
- @WebServlet("/Insert") 對應html-裡面form的action


servlet getParameter
像是String empno=request.getParameter("empno")


dao -> stmt.set (rs.get(getter))

Servelet 之間才通過 request來傳

dao直接把參數放在方法裡面來存取，不要通過request
dao參數不要放request,response

把servlet裡面dao分離出來 

---

<a> ${/servelet路徑}

button在form裡面，所以自然能連到其他地方，透過action