# 0518 Spring 動態網站開發 (重點是降低依賴) ==spring 的功用是降低依賴,降低物件間的依賴,只是把依賴轉移出去== ``` //jsp存在這,但是大小寫不能改,會找不到, 誰找不到? C:\Action\workspace\.metadata\.plugins \org.eclipse.wst.server.core\tmp0 \work\Catalina\localhost\HibernateWebProject ``` logprovider被依賴(dao明星,明星自己可以做事) 誰new 表示誰依賴另一個人,他靠另一個人做事(service助理) 叫別人做事表示依賴類別 --- 幫你new的方式 1. 呼叫setter di 2. constructor 再透過@Autowired自動搜尋 --- AOP機制,在不更動原來程式碼之下,透過spring框架特性,間接把程式碼嵌入進去 出問題不會影響到原來的程式碼,只是把功能刪除 --- ![](https://hackmd.io/_uploads/r1tjerEr3.png) javax是tomcat 9.0版本以前 hibernate 和mybatis都是透過ORM SSH: Spring + Struts(MVC)+ Hibernate Struts 以前習慣用.do當進入點 新的SSH: SSH: Spring + SpringMVC+ Hibernate SpringBoot(內崁入tomcat +hibernate) i18 處理時區跟編碼 spring framework讓你不用再用servlet,只要用單純java i18n處理時間/編碼/資料連結、轉換,AOP https://spring.io/projects/spring-framework 查全世界熱門的前10大程式 不要學錯 學錯後悔終生 ![](https://hackmd.io/_uploads/HJDyWHNrn.png) 可以活5-10年 --- message queue sender->line server(queue)->接收者 --- firebase 訊息推撥 --- ![](https://hackmd.io/_uploads/B1hXbr4H2.png) Google Maps JavaScript API openstreetmap api 免費 老師會建議使用OpenStreetApi google map api 要收費 map 可以用在美食地圖、經銷商地點、服務地點,維修地點,點進去後發通知 --- 攔截器就像是fliter --- 透過IoC把依賴轉移到組態設定程式上 --- 透過公司/專案特性來決定回答,合作還是獨立作業,先熟悉公司文化,再被派駐到外地 --- DAO不應該依賴service 因為想換service就換 Ioc 轉移依賴 P.14 高層模組不應該依賴低層 ![](https://hackmd.io/_uploads/HyVd-HVSn.png) ![](https://hackmd.io/_uploads/HJXqbBESn.png) 路徑,jsp會存在那,但是大小寫不能改 為啥不能改? server會找不到 ``` jsp檔案產生的地方 //plugins下面,wrok 下面的地方 C:\Action\workspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\work\Catalina\localhost\HibernateWebProject ``` 利用建構子的方式controller DI 用Set方式給的就是set DI https://1drv.ms/f/s!Ans47I9-Pkiv9X3Nsy0R5XKL8ile ![](https://hackmd.io/_uploads/Sy5xHBNr2.png) ![](https://hackmd.io/_uploads/BJFWSrEH2.png) 為啥要裝這個? 組態設定 @ + xml Java組態 key.value ![](https://hackmd.io/_uploads/r1xmXSSNS2.png) new java project 之後轉換成maven project ![](https://hackmd.io/_uploads/BkHVBrNBn.png) 1.4 改成17 專案右鍵/properties/project facts ![](https://hackmd.io/_uploads/Sk8SHrNB3.png) bean 標籤就等於直接幫你建立好一個物件 ![](https://hackmd.io/_uploads/B1PUSH4S3.png) 打CPX快速提示ClassPathXmlApplicationContext 用工具建fliter會跟@webfliter衝突,只能用其中一個 ![](https://hackmd.io/_uploads/SJfKBBEHn.png) 2. 透過這行 LogProvider logprovider = (LogProvider)context.getBean("logProvider"); getBean間接取得物件 ClassPath Xml ApplicationContext 這三個分別是什麼? ![](https://hackmd.io/_uploads/rk0TSHEB2.png) ![](https://hackmd.io/_uploads/H1WyISEH2.png) ![](https://hackmd.io/_uploads/S1I1Ir4B2.png) 上課常用的API spring 6.0 版本是分界線, 要馬就用5.0版本以下 xml 發展成熟、集中管理, 以前這些是優點, 之後改用annotation各別寫 在之後完全捨去xml 1. ...代表不知道個數,但都是同型別 2.逗點隔開就代表陣列 3. ...代表不帶參數也對 可以代用多個組態設定檔來讀取文件 ![](https://hackmd.io/_uploads/B1K-LHNH3.png) p.61 根據你檔案放的位置去決定你("")的路徑 放在src就直接寫檔案名 ![](https://hackmd.io/_uploads/Skg7LrEHh.png) 改xml 註解顏色 ![](https://hackmd.io/_uploads/SJjNIHVBh.png) p.23 String 只存唯一且不相同的一份 ![](https://hackmd.io/_uploads/By3LLrNH3.png) 顏色差別 ![](https://hackmd.io/_uploads/rJsDUBVBn.png) ClassPathXmlApplicationContext ClassPathXmlApplicationContext 是 Spring Framework 提供的一個應用程式上下文(Application Context)實現之一。 它是 Spring 的一個類別,用於從 classpath 中載入 XML 格式的配置文件,並創建並管理相應的 bean。這個類別可以解析 XML 配置文件,並根據配置文件中的定義創建相應的 bean 物件。 以下是使用 ClassPathXmlApplicationContext 的基本步驟: 在專案的 classpath 中準備一個 XML 格式的 Spring 配置文件。 創建一個 ClassPathXmlApplicationContext 物件,並將配置文件的路徑作為參數傳遞給它的建構子。 使用 getBean() 方法從 ClassPathXmlApplicationContext 中獲取需要的 bean 物件,並進行後續操作。 這樣,你就可以使用 ClassPathXmlApplicationContext 載入和管理 Spring 配置文件中定義的 bean,並在應用程式中使用它們。 --- string0:類別為 java.lang.String 的 bean。這個 bean 的 ID 是 "string0",同時也指定了 "string1" 和 "string2" 作為別名。這個 bean 使用了建構子依賴注入(Constructor Dependency Injection),並將字串 "Hello,amigo!!!" 傳遞給建構子。 哪裡有依賴注入? >將字串 "Hello,amigo!!!" 傳給 string0 和"string1" 和 "string2" property name="loginDao" 參考到 private LoginDao loginDao; //loginDao 屬性名稱 ref="loginDao" 參考到 bean id="loginDao" --- ``` <bean id="loginService2" class="tw.leonchen.model.LoginService"> <property name="loginDao" ref="loginDao"></property> </bean> ``` 剛寫上面這個幹嘛? 現在才用到 ![](https://hackmd.io/_uploads/HkaRUSNH3.png) 以後黑底用黃色的字註解好了,看得比較舒服 紅色框,黃色顏色文字 ![](https://hackmd.io/_uploads/HyGbDH4r2.png) 箭頭是把框改成線去拉的 --- <!-- 利用屬性,呼叫setter方法 --> ![](https://hackmd.io/_uploads/ryAMwHVB3.png) 利用建構子給值,照index順序把值帶進去 ![](https://hackmd.io/_uploads/SJnQvSVr3.png) index順序哪來的ㄚ ![](https://hackmd.io/_uploads/Hkc4wHNr2.png) ![](https://hackmd.io/_uploads/Sy1SPHEH3.png) 應該是把值帶進去index ![](https://hackmd.io/_uploads/rkorDH4Sn.png) --- getBean預設回傳Object 利用static block來初始化 HashMap value 是TruckBean, 所以map.put 時候new 一個 TruckBean把值放進去 ![](https://hackmd.io/_uploads/S1oEHYESn.png) 開始要記老師的順序 bean -> 然後啥 ->去組態設定檔註冊 ![](https://hackmd.io/_uploads/r1XFSKNrh.png) 先建TruckBean -> TruckBeanStaticFactory ->xml設置bean TruckBeanStaticFactory 這個要幹嘛阿 xml設置bean 這個後面要備註我的解釋 ![](https://hackmd.io/_uploads/By6iBt4r3.png) 在xml設定好value 帶入factory-method TruckBeanStaticFactory 當呼叫getTruckBean 方法時, 會去static帶入key 得到 TruckBean的key和value ![](https://hackmd.io/_uploads/B1zarYEH2.png) ![](https://hackmd.io/_uploads/SJOpBF4Bn.png) ![](https://hackmd.io/_uploads/SJfCSYNH2.png) ![](https://hackmd.io/_uploads/r1HJUYVr2.png) static { map.put(1, new TruckBean(3, "nissan")); map.put(2, new TruckBean(4, "toyota")); } 可以在裡面new喔? 直接new 建構子,把值帶進去 ![](https://hackmd.io/_uploads/HklZUtNS2.png) @Autowired 會自動搜尋 ![](https://hackmd.io/_uploads/Ske3bItNB3.png) 在class上面加對應的annotation 分別是bean /dao /service 等於自動幫你註冊 ![](https://hackmd.io/_uploads/SkizIKEr3.png) --- true 代表一定要有,一定要找到他,沒找到會發生exception ![](https://hackmd.io/_uploads/S1gX5LFErh.png) nullable代表允許空值出現 ![](https://hackmd.io/_uploads/SJTcLFVrh.png) @Autowired(required = true)@Nullable 這個註解組合的效果是,當 @Autowired(required = true) 被應用時,Spring 將自動尋找相應的 bean 並注入到變數中。如果找不到相應的 bean,或者找到多個相容的 bean,且沒有其他方式可以解決注入衝突,則將拋出異常。如果同時使用了 @Nullable,則該依賴項可以為 null,而不會拋出異常。 --- 因為worker bean 有再cfg設定, 所以不用加@repository ![](https://hackmd.io/_uploads/BkSpIKVS3.png) javabean最好要有不帶參數的建構子,以避免程式發生錯誤的困擾 利用qualifier去切換你要搜尋的worker @Autowired @Qualifier("") 寫在屬性上會比較簡單 (setter di) 相較於constructor di,@Qualifier寫在參數前面,寫法比較複雜一點 ![](https://hackmd.io/_uploads/ryPJPYVB2.png) ![](https://hackmd.io/_uploads/H1J8wtEHn.png) --- bug Buster蟲蟲剋星 寫在建構子,要設定全域 ![](https://hackmd.io/_uploads/Sk-Rg5HB3.png) ![](https://hackmd.io/_uploads/Sk20ecHrh.png) 就設置一個東西能找到檔案位置 (p.121) ![](https://hackmd.io/_uploads/Sy4MZcSH3.png) https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/config/PropertiesFactoryBean.html class="org.springframework.beans.factory.config.PropertiesFactoryBean"> 我們哪來這個class library提供的 沒有建立這個class也可以使用 那我怎麼知道這個從哪來 PropertiesFactoryBean 是一個 Spring Framework 提供的類別 --- 他剛剛說甚麼用地一種寫法就好 p127頁 用()內是class的寫法 她說她會示範第一種 常用就是前兩種 ![](https://hackmd.io/_uploads/Hyy0-cHBn.png) ![](https://hackmd.io/_uploads/HkeWG5rrn.png) 右邊應該是說id 因為變成自訂 就不是他原本方法名 ![](https://hackmd.io/_uploads/BJk7G5SSh.png) ![](https://hackmd.io/_uploads/ryWVz9HS2.png) ![](https://hackmd.io/_uploads/BkuVG9rH3.png) init方法會在乎叫建構子之後還有XX之後執行 destroy方法必須在 scope =singleton才能執行 ![](https://hackmd.io/_uploads/H1mIM9rrh.png) 變數名.hashCode() 能測試兩物件是不是同一個東西 java 和mysql連線的maven dependency 讓java 和mysql建立連線 ![](https://hackmd.io/_uploads/S1PuN5SB3.png) https://mvnrepository.com/artifact/mysql/mysql-connector-java/8.0.33 ``` <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.33</version> </dependency> ``` 新增四個jar ![](https://hackmd.io/_uploads/SkS5E5rBh.png) jdbc都要自己塞值 --- api https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/jdbc/datasource/DriverManagerDataSource.html ![](https://hackmd.io/_uploads/ryBuR-qSn.png) ![](https://hackmd.io/_uploads/r1aORbqBh.png) ResultSet 物件 rs 包含從資料庫獲取的結果集。 getInt(1) 方法從 rs 獲取結果集中的第一個欄位的整數值。 House 物件 hBean 是一個 House 類別的實例,它具有 houseid 屬性。 setHouseid(rs.getInt(1)) 方法將從結果集中獲取的整數值設定為 hBean 的 houseid 屬性。 這樣,程式碼的執行將從結果集中取得第一個欄位的整數值,並將該值設定為 hBean 物件的 houseid 屬性值。這樣,hBean 物件就具有了從資料庫中獲取的房屋ID的值,以便後續使用。 --- service 呼叫dao時候會拋出sql Exception ![](https://hackmd.io/_uploads/rJf1fM9Hh.png) ## JdbcTemplate https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/jdbc/core/JdbcTemplate.html setValue是針對設定問號用的 extractData是對取資料用的 //直接new 直接override //new PreparedStatementSetter 或是new ResultSetExtractor時 //add umimplemented method,會產生一個override的存取資料的方法 ![](https://hackmd.io/_uploads/S12zfzqS3.png) 不叫那名稱就另外指定位置和名稱 ![](https://hackmd.io/_uploads/SJqXMMqSh.png) ![](https://hackmd.io/_uploads/Byg4MM9rh.png) ![](https://hackmd.io/_uploads/SkUNGGqSn.png) 如果不小心刪除web.xml可以透過這方法新增 專案右鍵/javaEE tools/ --- 不能直接把java專案的pom.xml直接丟到web專案的web.xml 會出問題 --- session.beginTransaction(); session.getTransaction().commit(); factory.close(); 都不用加這些ㄇ 他說透過filter 還是listener去管, 那些一樣要加 切換畫面都會開交易關交易 我們的程式碼不就都沒加? 原本/* 也可以自己定義指定路徑 --- ![](https://hackmd.io/_uploads/r1aFMMqHn.png) 設定改 ![](https://hackmd.io/_uploads/Bkqcff9Bn.png) 設定改之後要確認版本 ``` <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> <release>17</release> </configuration> </plugin> ``` ![](https://hackmd.io/_uploads/HJx2MM5Hh.png) 設定檔放在web-inf下 https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/context/package-summary.html ![](https://hackmd.io/_uploads/Hylx7fcSn.png) value 是server裡面context.xml的name 前面+java:comp/env/ web.xml ![](https://hackmd.io/_uploads/SJO-mz5r2.png) jndi ![](https://hackmd.io/_uploads/SJB7XM9B3.png) config只有加這段 ![](https://hackmd.io/_uploads/rygSmfqB3.png) 怎突然就註解上面兩個連線ㄌ 因為變成Web 原本是直接讀取,現在變成間接讀取server裡面的context.xml檔案 原本是datasource.DriverManagerDataSource改成jndi 一個連線改成蓋橋,讀取連線池 --- ![](https://hackmd.io/_uploads/H1TIXGcBh.png) null 不能去get HouseId 和 Housename 所以會拋出exception 這個是說甚麼 就是在講那個try catch p.171 new servlet 時候 1.更改urlpattern新增.do 2.勾選init ![](https://hackmd.io/_uploads/H1wCXfqHh.png) ![](https://hackmd.io/_uploads/r1GkEzcrh.png) --- ![](https://hackmd.io/_uploads/B1JxNM5Bn.png) 怎麼會印出這句啊 因為妳其他專案放一起 --- 要改寫的是不帶參數的建構子 init 不然servlet會無法執行到doget dopost 不要改寫帶servletconfig參數的init() p.174 用第二種方法,取代xml ![](https://hackmd.io/_uploads/BJAQ4fqHn.png) ![](https://hackmd.io/_uploads/S1N44McH2.png) 怎麼又講到hibernateㄌ 因為目前要結合spring 和hibernate了 --- ![](https://hackmd.io/_uploads/r162NG5S2.png) dataSource 改寫成hibernate 寫法,簡潔很多 ![](https://hackmd.io/_uploads/HJJkBM5Bh.png) 取代cfg.xml裡面的mapping class https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/orm/hibernate5/LocalSessionFactoryBean.html (https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/jndi/package-summary.html) jndi int 的i 代表更新幾筆 ![](https://hackmd.io/_uploads/SkZ68MqHn.png) ![](https://hackmd.io/_uploads/SkupIfqBn.png) 都是老師講的嗎 他說明明沒做甚麼也會跑開交易或關交易 就是因為選擇過濾/* 所有 實際上要過濾的應該只有servlet 指定有用到的servlet檔案嗎 對啊 作會員的人應該都會幫大家指定 直接在/* 那裏加 ,分隔全組用到的servlet 有用到filter 功能的servlet在標住在()內 ![](https://hackmd.io/_uploads/r1VgwfqSn.png) --- servlet 的init () 空的 filter init () 放FilterConfig conifg getCurrentSession commit和rollback時會關閉連線 ![](https://hackmd.io/_uploads/rkxEwzqH2.png) ![](https://hackmd.io/_uploads/H14rPz9rn.png) ``` <!-- spring 的scan --> <!-- 讀取annotation設定的標籤 --> <context:annotation-config /> <context:component-scan base-package="tw.leonchen" /> <!-- 寫上一層,確保都搜尋的到 --> ``` ``` //hibernate 的scan <bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="packagesToScan" value="tw.leonchen"/> <property name="hibernateProperties"> <props> <!-- 註解來切換資料庫 --> <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop> <!-- <prop key="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</prop>--> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.format_sql">true</prop> <prop key="hibernate.current_session_context_class">thread</prop> </props> </property> </bean> ``` jdbc不會再console印出sql語法 hibernate會印出 ![](https://hackmd.io/_uploads/Hy-kKf9rh.png) JNDI那是spring的,要用getBean同時就會連線 剛才是測試hibernate的 JNDI那是spring的,要用getBean同時就會連線 都有用到 原本是用jdbc連線目前用jndi ![](https://hackmd.io/_uploads/SywZsfqS2.png) ref 為啥要換JNDI 啊? web都要用連線池 --- 只要網址出現整個Package name就是沒有mapping或是annotation @(/Servlet) jdbc 只有單一個連線 每次都要new @WebServlet("/DemoHouseJndiServlet.play") 這是urlpattern ![](https://hackmd.io/_uploads/SJTBozcSn.png) ![](https://hackmd.io/_uploads/rJBIiMcrn.png) ![](https://hackmd.io/_uploads/Syi8jzcB2.png) https://mvnrepository.com/artifact/org.aspectj/aspectjweaver/1.9.19 ``` <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.19</version> <scope>runtime</scope> </dependency> ``` https://mvnrepository.com/artifact/aopalliance/aopalliance/1.0 ![](https://hackmd.io/_uploads/rJkcoG5Sh.png) 主要功能 Hibernate - 簡化JDBC的工作 Spring - 降低依賴, 只要bean註冊好, 去找ID就好 多筆刪除可以寫迴圈抓多個ID List去裝