第1章 設置環境
安裝操作系統,安裝備份(鏡像):
- JDK: 設置環境變量
- Eclipse:解壓即可
- Eclipse自身解壓目錄不包括中文
- 代碼工作空間目錄不包括中文
- Tomcat:解壓不要包含中文目錄
- MySql:安裝: 選擇編碼utf8
設置Eclipse
- 1_關聯TOMCAT
- 開發過程中,環境發生變化(重新關聯tomcat),
- 刪除servers窗口下的tomcat
- Project Explorer 窗口下的server
- 重新關聯window—>preferences–>servers—>runtime–>tomcat
第2章 自定義註解
2.1 什麼是註解?
註解和接口,類一樣,都是屬於數據類型.
2.2 註解作用
- 1_編譯檢查
- 2_配置 (後期使用最多)
- 3_生成幫助文檔
2.3 註解的特點
-
註解可以在變量,方法,類之上加載
-
註解可以有屬性也可以沒有屬性
- @Override
- @Test(timeout=1000):執行時間超過一秒報錯
-
註解有作用範圍(源碼,編譯期間,運行期間)
- 源碼期間有效: String類之上@Author,@Since,@See
作用:使用命令javadoc命令將當前的源碼生成幫助文件, 可以識別String類上的相關的註解 - 編譯期間有效: @Override @Deprecated @Suppresswarning
作用:告訴編譯器部分信息 - 運行期間有效: @Test
作用:當我們再當前代碼上以Junit方式運行時,Junit會運行方法上包含@Test註解的方法
- 源碼期間有效: String類之上@Author,@Since,@See
2.4 回顧JDK中出現的3種註解
@Override @Deprecated @Suppresswarning
- @override:此註解的含義是申明當前的方法是重寫父類的方法
- @Suppresswarning:抑制編譯器發生警告信息
@Suppresswarning{“unused”,“rawtypes”} 屬性一變量未使用,屬性二語句沒有加泛型 - @Deprecated:聲明以下的方法是過時的方法,不建議大家使用
2.5 自定義註解
- 格式:
public @interface 註解名稱{
public 屬性類型 屬性名稱1();
public 屬性類型 屬性名稱2() default 默認值;
}
-
自定義註解屬性支持的類型:
- 基本數據類型(4類8種),String,Class,Annotation(註解類型),枚舉類型,
以及以上類型的一維數組類型
- 基本數據類型(4類8種),String,Class,Annotation(註解類型),枚舉類型,
-
註解作用: 配置作用
- 配置:開發的時候部分信息不希望寫死在程序中,例如數據庫的用戶名和密碼,可以將用戶名和密碼存放在.txt , .properties , .xml文件中,利用程序來讀取文件中的內容
-
框架:一大堆工具類組合,目的:加速項目開發
- 後期的學習中,框架部分hibernate,spring,struts2很多信息需要配置,提供了2種形式配置 (xml,註解)
-
什麼時候用註解來做配置?
- 如果配置信息不會發生的修改,例如servlet路徑,建議使用註解的形式
- 如果配置信息需要發生頻繁的修改,例如數據庫的用戶名和密碼信息,
建議採用傳統方法 (.txt , .properties , .xml)
<students>
<stu>
<stuNum>s002</stuNun>
<stuPhone>
<stuHomePhone>124324</stuHomePhone>
<stuCmpPhone>12342143</stuCmpPhone>
</stuPhone>
</stu>
</students>
- 測試使用自定義註解
@MyAnno01(timeout=100,c=java.util.Date.class,strs={"aaa","bbb"})
public void test01(){
}
- 通過反射讀取字節碼上的註解信息
md.isAnnotationPresent(MyTest.class)
2.6 案例:模擬Junit
- 1_自定義註解@MyTest
- 通過元註解@Rentention @Target聲明當前註解作用域以及目標對象,如果沒有聲明,在運行期間是無法獲取到註解的信息
- 2_定義UserDao
- 創建4個方法addUser delUser uptUser getUser ,在前三個方法上加載註解
- 3_定義類MyJunit ,模擬JUnit
- 將UserDao.class文件加載到內存,
- 獲取到字節碼文件上所有的方法
- 遍歷方法,判斷每個方法上是否加載了@MyTest註解
- 如果當前方法上設置@MyTest,執行當前的方法
註解要求:
聽懂,實現上課代碼.
開發中地位:類似dom4j解析XML文件. XML文件的解析程序員不會去解析,配置XML文件
後期的開發中不會自定義註解,反射讀取註解信息.
第3章 使用動態代理解決網站的字符集編碼問題
3.1 設計模式
軟件開發過程中,遇到相似問題,將問題的解決方式抽取模型(套路)
單例,工廠,適配器,裝飾者,動態代理
3.2 谷歌汽車場景
-
java設計了汽車開發約定
interface ICar{ start run stop}
class GoogleCar implements ICar{} -
希望在將谷歌Car接入到生態圈平臺時,增強汽車啓動功能
-
裝飾者模式
- 場景:二次開發的時候,無法獲取到源碼,無法使用繼承前提下,要對已經存在對象上的功能進行增強.
- 前提: 可以獲取到被裝飾的對象GoogleCar實現的所有接口
- 實現思路: 自定定義裝飾類實現ICar接口,爲自定義裝飾類傳遞被裝飾的對象
- 弊端:如果被實現的接口中的方法過多,裝飾類中的方法過多冗餘
-
動態代理模式
- 原理:通過虛擬機在內存中創建類似MyCar.class文件
- 要創建MyCar.class文件告訴虛擬機:
- 1_被創建的字節碼文件上應該有多少方法
- 2_被創建的字節碼上的方法如何來實現
-
字節碼加載器:
- jdk有一些程序,專業將各種字節碼文件加載到內存.這類程序簡稱爲字節碼加載器
- 如何將字節碼文件class文件加載到內存?
底層實現過程,利用IO流技術,獲取到文件中的數據加載到內存 - 字節碼加載器:3種
引導類加載器,擴展類加載器,應用類加載器
public class TestClassLoader {
public static void main(String[] args) {
//獲取String類的加載器
ClassLoader classLoader = String.class.getClassLoader();
System.out.println(classLoader);
//由於String.class ,int.class等字節碼文件需要頻繁的被加載內存,速度必須快,底層用其他語言來實現c c++
//獲取ext(extendtion)包下的某個類的字節碼加載器 ExtClassLoader:擴展類加載器
ClassLoader classLoader2 = sun.net.spi.nameservice.dns.DNSNameService.class.getClassLoader();
System.out.println(classLoader2);
//應用類:程序員實現的所有的類都屬於應用類
//獲取應用類加載器 AppClassLoader
ClassLoader classLoader3 = TestClassLoader.class.getClassLoader();
System.out.println(classLoader3);
}
}
3.3 案例:動態代理解決全站亂碼問題
步驟
- 1_new DynamicWeb Project -->Index.html
<h1>post方式提交中文</h1>
<form action="/day18_v3/ServletDemo" method="post">
User:<input type="" name="username"/><br/>
<input type="submit"/>
</form>
<h1>get方式提交中文</h1>
<form action="/day18_v3/ServletDemo" method="get">
User:<input type="" name="username"/><br/>
<input type="submit"/>
</form>
- 2_ServletDemo
- 無論是在post/get方法,執行以下語句不存在中文亂碼問題
String um=request.getParameter("username");
System.out.println(um);
- 3_過濾器中,爲request上的getParameter()功能進行增強
- 思路:
判斷當前的請求是get/post request.getMethod(); 如果是post, 設置一句話: request.setCharacterEncoding(“utf-8”); ,放行 如果是get,調用原先的String v=request.getParameter(name); 將v進行轉碼,放行
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
public class EncodingFilter implements Filter {
public EncodingFilter() {
}
public void destroy() {
}
public void init(FilterConfig fConfig) throws ServletException {
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
//將request對象轉換爲HttpServletRequest
final HttpServletRequest req=(HttpServletRequest)request;
//讓JDK在內存中生成代理對象:增強了req對象上的getParameter(name);API
HttpServletRequest myReq=(HttpServletRequest)Proxy.newProxyInstance(EncodingFilter.class.getClassLoader(), req.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object obj=null;
if(method.getName().equalsIgnoreCase("getParameter")){
//獲取本次請求方式
String md=req.getMethod();
if("get".equalsIgnoreCase(md)){
//get方式的請求
//調用req對象上的getParameter方法
String v=(String)method.invoke(req, args);
//轉碼
String vv=new String(v.getBytes("iso-8859-1"),"utf-8");
return vv;
}else{
//post方式的請求
req.setCharacterEncoding("utf-8");
obj=method.invoke(req, args);
}
}else{
obj=method.invoke(req, args);
}
return obj;
}
});
//打印代理對象哈希碼
System.out.println(myReq.hashCode());
//將代理對象放行
chain.doFilter(myReq, response);
}
}