Servlet:javascript
1)servlet : servlet是一個特殊的java程序,須要在web服務器上運行,並接收和響應客戶端的請求,遵循http協議.css
2)Servlet;做用: 主要用於控制層. html
3)Servlet;實現方式:java
3.1實現接口servlet,複寫全部的方法;node
3.2在web.xml文件中配置servlet內容.mysql
>>在web.xml文件中的配置,目的是通知Web服務器,Servlet的存在和訪問路徑jquery
>>程序員寫的每個Servlet程序(普通類實現了Servlet接口)被Web服務器調用,叫反調,即main方法在Web服務中程序員
實現servlet的三種方式:web
1)類implementServlet接口,複寫其中的方法面試
2)類extendsGenericServlet類
public class GenericServlet extends HttpServlet {
public void doGet(HttpServletRequestrequest, HttpServletResponse response)
throws ServletException, IOException {
//獲取字符輸出流對象
PrintWriter pw = response.getWriter();
//將數據輸出到瀏覽器
pw.write("<h1>servlet first methodgenericServlet</h1>");
}
public void doPost(HttpServletRequestrequest, HttpServletResponse response)
throws ServletException, IOException {
}
}
3)類extendsHttpServlet類
HttpServlet指可以處理HTTP請求的servlet,它在原有Servlet接口上添加了一些與HTTP協議處理方法,它比Servlet接口的功能更爲強大。所以開發人員在編寫Servlet時,一般應繼承這個類,而避免直接去實現Servlet接口。
HttpServlet在實現Servlet接口時,覆寫了service方法,該方法體內的代碼會自動判斷用戶的請求方式,如爲GET請求,則調用HttpServlet的doGet方法,如爲Post請求,則調用doPost方法。所以,開發人員在編寫Servlet時,一般只須要覆寫doGet或doPost方法,而不要去覆寫service方法。
因爲客戶端是經過URL地址訪問web服務器中的資源,因此Servlet程序若想被外界訪問,必須把servlet程序映射到一個URL地址上,這個工做在web.xml文件中使用<servlet>元素和<servlet-mapping>元素完成。
<servlet>元素用於註冊Servlet,它包含有兩個主要的子元素:<servlet-name>和<servlet-class>,分別用於設置Servlet的註冊名稱和Servlet的完整類名。
一個<servlet-mapping>元素用於映射一個已註冊的Servlet的一個對外訪問路徑,它包含有兩個子元素:<servlet-name>和<url-pattern>,分別用於指定Servlet的註冊名稱和Servlet的對外訪問路徑。
例: <servlet>
<servlet-name>MyServlet</servlet-name>
<servlet-class>cn.web.servlet.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyServlet</servlet-name>
<url-pattern>/MyServlet</url-pattern>
</servlet-mapping>
*3 Servlet生命週期和工做原理
1)工做原理
默認狀況下,在用戶第一次訪問時
空參構造方法():1次
init()方法():1次
doGet()/doPost()每次請求都執行一次:n次
當Web應用從新部署/加載到Web服務器時,Web服務器移除原Web應用,此時調用destory()方法:1次.每次請求,都由同一個Servlet來服務,該Servlet是一個單例模式
2)工做原理
*1)應用能過URL訪問某個Servlet,Web服務端根據URL中在web.xml文件中查詢是有對應的<url-pattern/>存在,若是沒有,Web服務器返回404頁面;若是有,則進入2)。
*2)Web服務器在Servlet實例緩存池中根據<url-pattern/>這個鍵,查詢對應的Servlet實例,若是找到了,則進入3)。如要沒找到,則進入4)。
*3)Web服務端,調用該Servlet中的doGet()或doPost()或service(),建立一個用於封裝HTTP請求消息的HttpServletRequest對象和一個表明HTTP響應消息的HttpServletResponse對象,而後調用Servlet的service()方法並將請求和響應對象做爲參數傳遞進去。這個實現對象與具體Web服務器有關,只須要基於接口編程
*4)Web服務器解析web.xml文件,經過反射方式建立該Servlet實例,初始化Servlet實例,而後將該Servlet實例,放入Servlet實例緩存池中,由Web服務器維護,以備下次重用,(這也是爲何Servlet是單例的緣由)
5)執行doGet()或doPost()或service()方法中的業務操做,執行完後,返回Web服務器
6)當Web服務器收到返回請求後,將返回數據取出,造成html網頁,發送到瀏覽器
7)當Web服務器決定銷燬該Servlet時(從新部署Web應用或中止Web服務器或者設置servlt的存活時間),會在真正銷燬前,調用該Servlet實例的destory()方法
*4 Servlet細節
1)Servlet的訪問路徑,只是一個以/槓開頭的字符串而以,不能以擴展判段是一個什麼資源,當靜態資源和動態資源訪問URL一至的狀況下,動態優先
2)一個Servlet能夠映射到多個URL路徑上,至少一個.
訪問URL的路徑只有二種:
*.擴展名
/*,*表示通配符
3)多個Servlet訪問,按照最像原則,有擴展名的最後考慮
4)程序員寫的Servlet,是被Web服務器調用, 主要願因是:Servlet是一個供其餘Java程序(Servlet引擎)調用的Java類,它不能獨立運行,它的運行徹底由Servlet引擎來控制和調度
5)<load-on-startup/>可讓Servlet在第一次訪問之間建立並初始化
但數字最小爲0,若是寫成負數,至關於不用<load-on-starup/>標籤,在用戶首次訪問該Servlet時建立並初始
舉例:
<servlet>
<servlet-name>invoker</servlet-name>
<servlet-class>
org.apache.catalina.servlets.InvokerServlet
</servlet-class>
<load-on-startup>2</load-on-startup>數值小的先加載/正整數
</servlet>
用途:爲web應用寫一個InitServlet,這個servlet配置爲啓動時裝載,爲整個web應用建立必要的數據庫表和數據。
6)當用戶的URL訪問路徑在web.xml的全部servlet中不存在時,由這個url-pattern爲/的缺省servlet來處理
其實Web服務器已有一個url-pattern爲/的缺省Servlet,它叫DefaultServlet,像404頁面/a.jpg/post.html,等都是由這個缺省的Servlet來處理的
7)Servlet中線程安全問題:
當多個客戶端併發訪問同一個Servlet時,web服務器會爲每個客戶端的訪問請求建立一個線程,並在這個線程上調用Servlet的service方法,所以service方法內若是訪問了同一個資源的話,就有可能引起線程安全問題。
8)構成線程安全的三要素
>>單例
>>實例變量
>>對實例變量更新(關鍵)
5 ServletConfig對象
1)用Servlet讀取在web.xml文件中,爲該Servlet配置的參數,注意,針對的是該Servlet
2)Web服務器會建立實現ServletConfig接口的實現類傳入,該接口主要用於讀取配置文件中的數據.
在Servlet的配置文件中,能夠使用一個或多個<init-param>標籤爲servlet配置一些初始化參數。
當servlet配置了初始化參數後,web容器在建立servlet實例對象時,會自動將這些初始化參數封裝到ServletConfig對象中,並在調用servlet的init方法時,將ServletConfig對象傳遞給servlet。進而,程序員經過ServletConfig對象就能夠獲得當前servlet的初始化參數信息。
3)經常使用的API:
getInitParameter(String參數):String返回值
getInitParameterNames():Enumeration枚舉
<!--做用域整個web.xml -->
<context-param>
<param-name>filePath</param-name>
<param-value>/file.properties</param-value>
</context-param>
<servlet>
<servlet-name>Demo5</servlet-name>
<servlet-class>cn.itcast.web.servlet.Demo5</servlet-class>
<!-- 如下初始化參數只能由Demo5訪問 -->
<init-param>
<param-name>email</param-name>
<param-value>jack2012@163.com</param-value>
</init-param>
<init-param>
<param-name>tel</param-name>
<param-value>13512344321</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
public classDemo5 extends HttpServlet {
//讀取web.xml文件中的內容
public void init(ServletConfigservletConfig) throws ServletException {
//取得初始化參數
Enumeration<String> enums =servletConfig.getInitParameterNames();
//迭代枚舉
while(enums.hasMoreElements()){
//取得鍵
String key =enums.nextElement();
//取得值
String value =servletConfig.getInitParameter(key);
//顯示
System.out.println(key +"<-->" + value);
}
System.out.println("Servlet實例名爲:" + servletConfig.getServletName());
String email =servletConfig.getInitParameter("email");
String tel =servletConfig.getInitParameter("tel");
//判段
if(email!=null &&tel!=null){
System.out.println("郵箱:" + email);
System.out.println("電話:" + tel);
}else{
System.out.println("查無此信息");
}
}
}
*1 ServletContext對象
1)當某個Web應用部署到Web服務器中,Web服務器爲該Web應用建立一惟一的ServletContext對象
2)Web應用和ServletContext對象一一對應
3)Web應用中的全部Servlet都有訪問或共享該ServletContext對象中的信息
4)若是要在多個Servlet之間共享數據,此時能夠使用ServletContext
5)經常使用的API
setAttribute(String,Object):void
getAttribute(String):Object
//獲取文件的路徑名
String path = this.getServletContext().getRealPath("/1231321.jpg");
//D:\apache-tomcat-6.0.33\webapps\WebTest\1231321.jpg
6)瀏覽器以GET方式發送請求,在服務端爲轉發的狀況下,此時服務端無需通知瀏覽器,是服務端內部行爲,因此依然是GET方式的請求,此時的request和response與先前的同樣
7)能夠經過ServletContext讀取位於web應用中的全部資源文件
8)能夠經過ServletContext讀取位於web.xml文件中的初始化參數,該參數針對整個web應用,而不是針對某個servlet。
例: 經過ServletContex讀取配置文件中的全部信息
public class MyContextServlet extends HttpServlet {
public void doGet(HttpServletRequestrequest, HttpServletResponse response)
throws ServletException, IOException {
//建立ServletContext對象
ServletContext context = this.getServletContext();
//獲取web.xml文件中的參數filePath 對應的路徑
String filePath = context.getInitParameter("filePath");
//獲取輸入流對象,該方法適用於整個web.xml文件中
InputStream inStream = context.getResourceAsStream(filePath);
//建立Properties對象
Properties p = new Properties();
//讓Properties對象與文件關聯
p.load(inStream);
//讀取該文件中的鍵.並經過鍵查找對應的值.
String name = p.getProperty("name");
String password = p.getProperty("password");
String role = p.getProperty("role");
//設置屬性,並存儲到域對象中
context.setAttribute("name", name);
context.setAttribute("password",password);
context.setAttribute("role", role);
//獲取RequestDispatcher(傳發)對象,此處"/"表示當前的目錄day06
RequestDispatcher disp = context.getRequestDispatcher("/MyContext");
//轉發至MyContext(302轉向)
disp.forward(request, response);
}
}
public class MyContext extends HttpServlet {
public void doGet(HttpServletRequestrequest, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
//建立ServletContext對象
ServletContext context = this.getServletContext();
//獲取指定的屬相鍵對應的value值
String name = (String)context.getAttribute("name");
String password =(String)context.getAttribute("password");
String role = (String) context.getAttribute("role");
response.getWriter().write(name+": "+password+" ,"+role);
}
}
*2 緩存應用
1)在默認狀況下,瀏覽器訪問某個靜態資源時,若是瀏覽器的緩存有該資源,則找緩存;若是無該資源,則首次找服務端,以後將其緩存,以提升效率。
1 設置緩存的兩種場景:
場景一:對於不常常變化的數據,在servlet中能夠爲其設置合理的緩存時間值,以免瀏覽器頻繁向服務器發送請求,提高服務器的性能。
場景二:若是要實現一種高級功能,即客戶端請求動態web資源時,動態web資源發現發給客戶端的數據更新了,就給客戶端發送最新的數據,若是發現數據沒有更新,則動態web資源就要客戶端就去訪問它本身緩存的數據。此種狀況能夠經過覆寫動態web資源(即servlet)的getLastModify方法予以實現。
2)服務端和瀏覽器能過If-Modified-Since和Last-Modified二個頭相互通訊,來判段請求資源的新舊,這就是底層原理。
13 getLastModified方法由service方法調用,默認狀況下,getLastModified方法返回一個負數,開發人員在編寫servlet時,若是不覆蓋getLastModified方法,則每次訪問servlet時,service方法發現getLastModified方法返回負數,它就會調用doXXX方法向客戶端返回最新的數據。此種狀況下,服務器在向客戶端返回doXXX方法返回的數據時,不會在數據上加Last-Modified頭字段。
8 若是編寫servlet時,覆蓋了getLastModified方法,並返回某一個時間值,則客戶端訪問Servlet時,service方法首先會檢查客戶端是否經過If-Modified-Since頭字段帶一個時間值過來。若是沒有的話,則service方法會調用doXXX方法向客戶端返回最新的數據。在返回數據時,service方法還會調用getLastModified方法獲得一個時間值,並以這個時間值在數據上加上一個Last-Modified頭字段。(即通知客戶端緩存數據)
13 客戶端在訪問servlet時,若是經過If-Modified-Since頭字段帶了一個時間值過來,則service方法在調用doXXX方法以前,它會先調用getLastModified方法,獲得一個時間值,並與客戶端帶過來的時間值進行比較,若是比客戶端的時間值要新,則service方法調用doXXX方法向客戶端返回最新的數據。若是要舊,則service方法而不會調用doXXX方法向客戶端返回數據,而是返回一個304的狀態碼給客戶端,通知客戶端在拿它緩存中的數據。
例1:設置資源文件的修改時間
public class LastModified extends HttpServlet {
protected longgetLastModified(HttpServletRequest req) {
ServletContext context = this.getServletContext();
//獲取文件路徑
String filepath = context.getRealPath("/temp.html");
//設置資源文件最後修改時間
return newFile(filepath).lastModified();
}
public void doGet(HttpServletRequestrequest, HttpServletResponse response)
throws ServletException, IOException {
ServletContext context = this.getServletContext();
//讀取temp.html文件中的內容輸到瀏覽器
InputStream in = context.getResourceAsStream("/temp.html");
ServletOutputStream out =response.getOutputStream();
byte[] buf = new byte[1024];
int len = 0;
while((len = in.read(buf))>0)
{
out.write(buf, 0, len);
}
}
}
*3 response的應用
1)用字節方式輸出[數字],該數字須要查詢ISO8859-1編碼表,將查詢後的結構取出,存放響應體中
2)用字節方式輸出[字符串],則直接將該字符串存放響應體中
3)用字符方式輸出[數字],則直接將該字數字存放響應體中,原樣輸出
4)以採用二種方式設置瀏覽器解析的編碼方式時,後者起決定做用
>>response.setCharacterEncoding("GB2312");
>>response.setContentType("text/html;charset=UTF-8");
>>//重定向302請求的資源被修改了,須要從新訪問新的地址
response.sendRedirect("/myday06/Demo1");/斜槓表明當前web工程/myday06
5)response.setContentType("text/html;charset=UTF-8");位置很重要,在默認狀況下,response.getWriter()返回的PrintWriter對象,採用ISO8859-1的方式進行編碼,即存入到PrintWriter對象中的一切數據都要採用ISO8859-1方式進行編碼
6)字節 vs 字符
>>輸出字符串(不論中文或英文),此時使用字符(response.getWriter())
>>輸出多媒體數據(圖片), 此時使用字節(response.getOutputSteram())
4 response的細節
1)轉發:/表示day06(虛擬路徑)
重定向:/表示webapps
表單提交的action屬性:/表示webapps
<a href=""/>,/表示webapps
2)能夠採用字符或字節方式輸出中文數據
3)response對象只能使用一種方式進行輸出,要麼字節,要麼字符,不能同時使用
4)response對象不關閉流也不要緊,由web服務器在適當的時候關閉;若是你想當即關閉,建議手工關閉
5)在重定向或轉發的狀況下,設置的請求頭,後者起決定做用
案例1:圖片下載: 中文圖片名字的轉換: URLEncoder.encode(file.getName(),"UTF-8")
public class Dowload extends HttpServlet {
public void doGet(HttpServletRequestrequest, HttpServletResponse response)
throws ServletException, IOException {
//獲取ServletContext對象
ServletContext context = this.getServletContext();
//獲取圖片路徑
String url = context.getRealPath("/123.jpg");
File file = new File(url);
response.setHeader("content-disposition","attachment;filename="+ URLEncoder.encode(file.getName(),"UTF-8"));
InputStream in = new FileInputStream(file);
OutputStream out = response.getOutputStream();
byte[] by = new byte[1024];
int len = 0;
while((len=in.read(by))>0){
out.write(by,0,len);
}
}
}
案例2:生成一個帶驗證碼圖片的表單:
public class CheckOutCode extends HttpServlet {
//隨機生成校驗碼
public void doGet(HttpServletRequestrequest, HttpServletResponse response)
throws ServletException, IOException {
//設置禁止瀏覽器進行頁面緩存
response.setHeader("expires","-1");
response.setHeader("cache","no-cache");
response.setHeader("pragram","no-cache");
//在內存中建立一個圖片對象,並指定其x,y軸的座標,並指定圖片的類型
BufferedImage img = new BufferedImage(70,30,BufferedImage.TYPE_INT_RGB);
//獲取畫圖的對象
Graphics g = img.getGraphics();
Random r = new Random();
for(int x=0;x<10;x++)
{
//隨機生成一些數字
int x1 = r.nextInt(100);
int x2 = r.nextInt(100);
int y1 = r.nextInt(30);
int y2 = r.nextInt(30);
g.setColor(new Color(r.nextInt(256),r.nextInt(256),r.nextInt(256)) );
//在此圖片上下文的座標系中,使用當前顏色在點 (x1, y1) 和(x2, y2) 之間畫一條線。
g.drawLine(x1, y1, x2,y2);
}
g.setColor(Color.yellow);
//使用此圖形上下文的當前字體和顏色繪製由指定 string 給定的文本
g.drawString(getRandom(), 20, 20);
//圖片輸出流,寫會瀏覽器
ImageIO.write(img,"JPG",response.getOutputStream());
}
//隨機生成一個0-999的隨機數字
public String getRandom()
{
return (int)Math.ceil((Math.random()*10000))+"";
}
}
例3: 設置靜態資源的緩存時間:
public class Expires extends HttpServlet {
public void doGet(HttpServletRequestrequest, HttpServletResponse response)
throws ServletException, IOException {
//獲取靜態資源的uri路徑
String uri = request.getRequestURI();
int end = uri.indexOf("/");
String path = uri.substring(end);
//建立ServletContext對象,加載靜態資源
ServletContext context = this.getServletContext();
//獲取輸入流對象
InputStream input=context.getResourceAsStream(path);
BufferedReader bufr = new BufferedReader(new InputStreamReader(input));
String line = bufr.readLine();
if(line!=null && line.contains("html"))
{ //設置臨時文件的存儲時間
long time = System.currentTimeMillis()*1*24*60*60*1000;
response.setDateHeader("expires",time);
}
}
}
例4:設置請求頭referer
public class RefererServlet extends HttpServlet {
public void doGet(HttpServletRequestrequest, HttpServletResponse response)
throws ServletException, IOException {
//獲取請求頭(地址欄,主要做用是防止用戶在經過url訪問時間接訪問)
String referer =request.getHeader("referer");
if(referer!=null && referer.equals("http://localhost:8080/myday07/page.html"))
{//轉發至success.html
this.getServletContext().getRequestDispatcher("/success.html").forward(request, response);
}else{
this.getServletContext().getRequestDispatcher("/failure.html").forward(request, response);
}
}
}
*1 request對象經常使用API
//建立每一個瀏覽器對應的HttpSession
HttpSessionsession = request.getSession();
獲取每一個瀏覽器對應的HttpSession的編號
String id =session.getId();
String ip =request.getRemoteAddr();///獲取每一個瀏覽器的IP////127.0.0.1
String method =request.getMethod();//取得客戶端提交請求的方式//get,post
取得客戶端提交請求的URL和URI //http://localhost:8080/myday07/ResquestMethod
String url =request.getRequestURL().toString();
String uri = request.getRequestURI();//myday07/ResquestMethod
String path =request.getContextPath();//取得客戶端訪問的虛擬路徑,即/day07
String query =request.getQueryString();//取得客戶端傳入的參數(查詢字符串)
String username= request.getParameter("username");//取得客戶端傳入的值單個值
String [] likes= request.getParameterValues("like");//取得客戶端傳入的值多個值
//從HttpSession域對象中取得IP/ID/用戶名
String id =(String) session.getAttribute("id");
String ip =(String) session.getAttribute("ip");
得到客戶機請求頭信息:
getHeader(stringname)方法:String
String encoding = request.getHeader("Accept-Encoding");
String agent = request.getHeader("user-agent");
得到客戶機請求體信息(客戶端提交的數據)
getParameterNames方法+BeanUtils框架
*2 基於MVC的request應用
request對象也能實現請求轉發:請求轉發指一個web資源收到客戶端請求後,通知服務器去調用另一個web資源進行處理。
請求轉發的應用場景:MVC設計模式
request對象也提供了一個getRequestDispatcher方法,該方法返回一個RequestDispatcher對象,調用這個對象的forward方法能夠實現請求轉發。
request對象同時也是一個域對象,開發人員經過request對象在實現轉發時,把數據經過request對象帶給其它web資源處理。
setAttribute方法 getAttribute方法
//轉發307
ServletContext context = this.getServletContext();
RequestDispatcher rd =context.getRequestDispatcher("/Demo1");
rd.forward(request, response);
1)POST請求
>>1箇中文----3個%----按照UTF-8編碼----------瀏覽器
>>1箇中文----2個%----按照GB2312或GBK編碼----瀏覽器
2)HTTP協議特色所決定在HTTP協議中只能明文傳遞英文和數字,其它字符都須要按照必定方式編碼
3)request.getParameter("username"),默認狀況下,採用ISO的方式取得username的值,必須在該代碼[以前]使用request.setCharacterEncoding("UTF-8")方式,設置request採用UTF-8取得表單參數的值
4)編碼和解碼的方式要一致
5)request.setCharacterEncoding只能針對[請求體post]中的數據有效,對GET無效
6)GET請求
>>必定要對URL的字符進行編碼,好比UTF-8
>>在接收方,必定要對URL字符進行手工解碼,好比UTF-8
>>編碼和解碼雙方要一致
doget() 請求:
dopost() 請求:
7)請求和轉發的區別:
一個web資源(servlet實例對象)收到客戶端請求後,通知[服務器]去調用另一個web資源進行處理,稱之爲請求轉發。
一個web資源(servlet實例對象)收到客戶端請求後,通知[瀏覽器]去訪問另一個web資源進行處理,稱之爲請求重定向。
*3 基於request的轉發
>>request請求對象
MVC是(模型-視圖-控制器)的一種簡稱,主要用於一種架構設計模式,MVC是獨立於任何語言
MVC三層結構的內部關係
MVC把應用程序的開發分爲3個層面:視圖層、控制層和模型層。其中視圖層負責從用戶獲取數據和向用戶展現數據,在這層中不負責對業務邏輯的處理和數據流程的控制。
而模型層負責處理業務邏輯和數據庫的底層操做,其中視圖層和模型層之間沒有直接的聯繫。控制層主要負責處理視圖層的交互,控制層從視圖層接受請求,而後從模型層取出
對請求額處理結果,並把結果返回給視圖層。在控制層中只負責數據的流向,並不涉及具體的業務邏輯處理。
從圖中能夠看出,Servlet在MVC開發模式中承擔着重要的鉅額收入。在MVC結構中,控制層就是依靠Servlet實現的,Servlet能夠從流量拿起端接受請求,而後從模型層取出處理結果,而且把處理結果返回給瀏覽器端的用戶。在整個結構中,Servlet負責數據流向控制的功能。
雖然如今利用不少開源框架都能很好地實現MVC的開發模式,且這些開源框架對MVC的實現都是很是出色的,可是在這些框架中處理數據控制流向的時候,採用的仍是servlet。
request也具備轉發功能
request.getRequestDispatcher().forward(request,response);
>>request域對象
由於該request對象有對應的存取方式
setAttribute()和getAttribute()
405錯誤:某個URL請求是GET/POST,但對應的Servlet沒有提交doGet()/doPost()方式,
在轉發狀況下,request域對象,二個Servlet的數據共享
在重定向狀況下,request域對象,二個Servlet的數據不共享,
>>何時用ServletContext域對象,何時用HttpServletRequest域對象
ServletContext:
(1)當須要保存的內容在重定向的狀況下依然存在,比較適合使用ServletContext域對象
(2)當須要保存的內容時間長時,比較適合使用ServletContext域對象
(3)公共聊天室,就應該使用ServletContext進行保存
HttpServletRequest:
(1)當須要保存的內容在轉發的狀況下依然存在,[比較適合]使用HttpServletRequest域對象,但此時若是使用, ServletContext也是能夠的
(2)當須要保存的內容只要在一次請求中可見,[比較適合]使用HttpServletRequest域對象
(3)查詢某個新聞信息,就應該使用HttpServletRequest進行保存
#4 轉發 vs 重定向
(1)URL地址攔
轉發: 地址攔不變
重定向: 地址攔變化
(2)代碼
轉發:
>>this.getServletContext().getRequestDispatcher(html/jsp/servlet).foward(*,*);
>>request.getRequestDispatcher(html/jsp/servlet).foward(*,*);
重定向:
>>response.sendRedirect("html/jsp/servlet");
(3)同一個Web仍是在不一樣的Web應用中
轉發:只能在當前Web應用中導航
重定向:能夠在當前Web應用中,或非當前Web應用中導航,也能夠導航外網
轉發: 能訪問WEB-INF/目錄的全部資源
重定向:不能訪問WEB-INF/目錄的全部資源
(4)/的含義
轉發:/表示當前web應用名,虛擬路徑,即/day07
重定向:/表示webapps
(5)內部或外部行爲
轉發:服務器內部行爲
重定向:服務器與瀏覽器的外部行爲
(6)request的數據共享能力
轉發:reques共享數據
重定向:request不共享數據
5 include包含方法:
RequestDispatcher.include方法用於將RequestDispatcher對象封裝的資源內容做爲當前響應內容的一部分包含進
來,從實現可編程的服務器端包含功能。被包含的Servlet程序不能改變響應消息的狀態碼和響應頭,若是它
裏面存在這樣的語句 這些語句的執行結果將被忽略。
1)必定在要IncludeServlet中設置response的輸出編碼方式,不能在只在所包含的Servlet中,由於做用域的問題
2)先輸出的,決定輸出編碼方式,默認爲ISO
3)若是在IncludeServlet中設置response的輸出編碼方式,被包含的Servlet無需設置編碼方式
4)最後編碼方式由IncludeServlet決定
COOKE入門
什麼是cookie: Cookie是客戶端技術,服務器把每一個用戶的數據以cookie的形式寫給用戶各自的瀏覽器。當用戶使用瀏覽器再去訪問服務器中的web資源時,就會帶着各自的數據去。這樣,web資源處理的就是用戶各自的數據了。
1)cookie是存於瀏覽器緩存中的數據集合
2)可以解決多個web應用之間或同一個web應用多個動態資源之間的數據交互,例如:day08web應用和day09web應用之間交互數據
3)用戶打開瀏覽器,在該瀏覽器中的一系列超連接操做後,再關閉該瀏覽器的過程,叫會話
4)瀏覽器和服務器交互的過程當中,是經過響應頭set-cookie和請求頭cookik來完成整個會話交互數據的
2 cookie經常使用api
>>new Cookie("名","值")://構造函數
>>cookie.setMaxAge(秒鐘);//設置cookie的存活時間
>>response.addCookie(cookie);//將cookie寫入到瀏覽器中
>>request.getCookies()//獲取瀏覽器全部的cookie,返回的是一個數組cookie[]
>>cookie.getName()//獲取cookie的名字
>>cookie.getValue()//獲取cookie的值
>>cookie.setPath("/day08-2")//設置cookie的路徑
*3 cookie的細節
1)cookie的更新就是再向瀏覽器寫入一個與原cookie名字同樣的cookie,後者替換前者;若是cookie的名字不同,則向瀏覽器添加新的cookie。
2)cookie產生於服務端,存於瀏覽器,能夠人工刪除
3)cookie的存與不存,能夠由瀏覽器自已設置,服務端沒法管理是否將cookie存於瀏覽器
4)一個cookie只能存放一種類型的信息,若是要存多個信息,得用多個cookie完成
5)一個瀏覽器可以存儲多個網站的cookie信息,每一個cookie的數量和大小受限,瀏覽器通常只容許存放300個Cookie,每一個站點最多存放20個Cookie,每一個Cookie的大小限制爲4KB
6)若是不設置cookie的有效存活時間,默認cookie只在內存中有效,當程序結束後,內存中的cookie銷燬,不會寫入瀏覽器的緩存中,所以,須要爲cookie設置一個有效的時間,當程序運行完畢後,會將該cookie寫入瀏覽器的緩存中,即硬盤中保留。若是cookie的存活時間爲0,就至關於瀏覽器將刪除cookie刪除或無效
7)在默認狀況下,day08web應用的cookie只能被day08web應用的動態資源訪問,若是要讓其它的web資源訪問,得設置cookie.setPath("/day08-2"),默認cookie的path爲當前web應用。
8)cookie是以文本文件的方式存於瀏覽器緩存中,並且裏面的內容明碼.
例: cookie的使用
public class ClientCount extends HttpServlet {
public void doGet(HttpServletRequestrequest, HttpServletResponse response)
throws ServletException, IOException {
// 通知瀏覽器以UTF-8的方式解碼
response.setContentType("text/html;charset=UTF-8");
// 獲取瀏覽器全部的Cookie
Cookie[] cookie = request.getCookies();
// 獲取printWrite流對象
PrintWriter pw = response.getWriter();
Cookie newCookie = null;
// 判斷是否爲空
if (cookie != null && cookie.length > 0) {
for (Cookie c : cookie) {
if (c.getName().contains("counter")) {
newCookie = c;
break;
}
}
if (newCookie != null) {
String value = newCookie.getValue();
int num = Integer.parseInt(value);
// 建立Cookie對象
Cookie cookies = new Cookie("counter", (num++) + "");
// 設置cookies的存活時間
cookies.setMaxAge(1 * 24 * 60 * 60);
// 將cookies寫入瀏覽器中
response.addCookie(cookies);
pw.write("當前在線" + num + "人");
}
} else { // 建立Cookie對象
Cookie cookies = new Cookie("counter", "1");
// 設置cookies的存活時間
cookies.setMaxAge(1 * 24 * 60 * 60);
// 將cookies寫入瀏覽器中
response.addCookie(cookies);
pw.write("當前在線1人");
}
}
}
4 httpSession入門
1)session是服務端建立的一個爲每一個瀏覽器所[獨享]的容器對象,存在服務端。
2)若是項目中須要多個動態資源找到同一個瀏覽器所須要的數據,例如:購物車
瀏覽器禁用cookie後的session處理
解決方案:URL重寫
String url = response. encodeRedirectURL(java.lang.String url)
response. sendRedirect(url)
用於對sendRedirect方法後的url地址進行重寫。
String url = response.encodeURL(url);
pw.write("<a href='"+url+"'>繼續購物</a>");
用於對錶單action和超連接的url地址進行重寫
注:
session的失效(默認30分鐘)
web.xml文件配置session失效時間
5 httpSession經常使用api
>>request.getSession()//獲取全部的HttpSesseion對象
>>session.getId()
>>session.setAttribute(String,Object)
>>session.getAttribute(String):Object
*6 httpSession細節(上)
1)IE高版本瀏覽器,須要打開瀏覽器-[文件]-[新建會話],這樣才能啓動一個新會話,不然依然是原會話
2)context和session和request域對象的比較
>>在哪一個域對象中放的數據,只能在哪一個域對象中取
>>request只能在轉發狀況下,共享數據;重定向不共享數據
session在轉發或重定向狀況下,都共享數據;
context在轉發或重定向狀況下,都共享數據;
>>session建立的條件以下三個,缺一不可
(1)打開瀏覽器
(2)訪問某一個Servlet
(3)request.getSession(),必需要用執行這個API
>>session銷燬
>>當從新部署web應用
>>停此服務器
>>多個動態資源須要共享[同一個瀏覽器]的數據,能夠使用HttpSession
一次HTTP請求中須要共享數據,但下一次請求無需共享上一次數據,能夠使用HttpServletRequest
一個web應用中的全部動態資源都須要共享[全部瀏覽器]的數據時,能夠使用ServletContext
>>購物車:HttpSession
公共聊天室:ServletContext
顯示某條新聞的信息: HttpServletRequest
3)request.getSession()具備二層含義:
>>建立(無-有)
>>獲取(有-有),關鍵是看代碼流程
4)session底層是用cookie技術,經過響應頭set-cookie和請求頭cookie來維護瀏覽器與服務端的數據交互,以致於不會出錯,徹底由服務端負責維護,與瀏覽器無關
5)cookie和session的比較
>>cookie建立於服務端,存於瀏覽器;session建立於服務端,存於服務端
>>cookie是有文本文件存入相關的數據而且存入的數據若是是中文須要編碼(BASE64),但session沒有
>>cookie是使用set-cookie響應頭和cookie請求頭交換數據,session同樣
6)session位於服務端,其大小受web服務器的限制,所以session主要存放web應用中核心的數據,而將非核心的數據放在cookie中。
*1 httpSession細節(下)
1)若是經過超連接點擊購買圖書,會有"referer"這個請求頭;反之若是經過在地址欄直接輸入URL購買圖書,則無"referer"。
2)httpSession在維護瀏覽器和服務端的會話中,使用了一個特殊的cookie,它的名字叫JSESSIONID,其值就是httpSession.getId()
3)若是咱們強行建立一個cookie,名叫JSESSIONID,其它是httpSession.getId(),那麼服務端會認爲是同一個用戶
4)當瀏覽器禁用cookie時,能夠使用URL重寫來達到服務端和瀏覽器維持通訊的能力
5)url = response.encodeURL(url);將url重寫,即加上jsessionid這個參數,該方法適合於
超連接,或者表表單<form action=""屬性/>
6)url = response.encodeRedirectURL(url);
response.sendRedirect(url);
上述API針對只針對重定向
7)不論當瀏覽器禁用或不由用cookie,服務端均可以使用URL重寫技術來達到瀏覽器和服務端維護的方式,由於這二個API可以智能判段瀏覽器是否禁用cookie,從而採用對應的處理方式
*2 銷燬httpSession的幾種方法
1)從新部署web應用
2)中止web服務器,
3)httpSession一旦建立,就會在web服務器中,默認停留30個分鐘,30分鐘後,由web服務器銷燬,什麼時候銷燬,由web服務器決定,相似GC(垃圾回收處理機制)。
*4)經過在web.xml文件中,配置session的有效時間,單位分鐘,關閉瀏覽器,在默認狀況下,沒有銷燬session。
*5)session.invalidate(),當即立刻銷燬session,將session中綁定的全部信息清空,例如:安全退出
例: <session-config>
<session-timeout>5</session-timeout>
</session-config>
*3 httpSession應用
1)判段是不是新/舊會話,session.isNew():true表示新會話
2)用戶登陸[v1版]
3)防止表單重複提交
>>表單須要動態產生一個惟一的隨機值,該隨機值須要在服務端保存一份,客戶端隱蔽域的造成提交
>>服務端在比較的過程當中,相同則表示提交成功;成功後,刪除服務端的隨機值
>>項目中多用於註冊,登陸等場景
4)一次性驗證碼
public class ServletCheckcode extends HttpServlet {
public void doGet(HttpServletRequestrequest, HttpServletResponse response)
throws ServletException, IOException {
//設置瀏覽器不緩存
response.setHeader("expires","-1");
response.setHeader("cache-control","no-cache");
response.setHeader("pragma","no-cache");
//獲取驗證碼
String checkcode = this.getRandom();
//綁定到HttpSession中
request.getSession().setAttribute("checkcode",checkcode);
//在內存中建立一個圖片
Buffered-image img = new BufferedImage(80, 30, BufferedImage.TYPE_INT_RGB);
//獲取畫筆
Graphics g = img.getGraphics();
g.drawString(checkcode, 30, 20);
//輸出到瀏覽器
ImageIO.write(img,"JPG",response.getOutputStream());
}
//產生一個1000-9999的隨機數
private String getRandom(){
Random r = new Random();
int num = r.nextInt(9000) + 1000;
return num + "";
}
}
什麼是JavaBean
JavaBean是一個遵循特定寫法的Java類,它一般具備以下特色:
這個Java類必須具備一個無參的構造函數
屬性必須私有化。
私有化的屬性必須經過public類型的方法暴露給其它程序,而且方法的命名也必須遵照必定的命名規範。
JavaBean的屬性
4 JavaBean的屬性能夠是任意類型,而且一個JavaBean能夠有多個屬性。每一個屬性一般都須要具備相應的setter、 getter方法,setter方法稱爲屬性修改器,getter方法稱爲屬性訪問器。
5 屬性修改器必須以小寫的set前綴開始,後跟屬性名,且屬性名的第一個字母要改成大寫,例如,name屬性的修改器名稱爲setName,password屬性的修改器名稱爲setPassword。
6 屬性訪問器一般以小寫的get前綴開始,後跟屬性名,且屬性名的第一個字母也要改成大寫,例如,name屬性的訪問器名稱爲getName,password屬性的訪問器名稱爲getPassword。
7 一個JavaBean的某個屬性也能夠只有set方法或get方法,這樣的屬性一般也稱之爲只寫、只讀屬性。
在JSP中使用JavaBean
4 JSP技術提供了三個關於JavaBean組件的動做元素,即JSP標籤,它們分別爲:
5 <jsp:useBean>標籤:用於在JSP頁面中查找或建立一個JavaBean組件。
6 <jsp:setProperty>標籤:用於在JSP頁面中設置一個JavaBean組件的屬性。
7 <jsp:getProperty>標籤:用於在JSP頁面中獲取一個JavaBean組件的屬性。
8 <jsp:useBean>標籤用於在指定的域範圍內查找指定名稱的JavaBean對象:
• 若是存在則直接返回該JavaBean對象的引用。
• 若是不存在則實例化一個新的JavaBean對象並將它以指定的名稱存儲到指定的域範圍中。
經常使用語法:
<jsp:useBeanid="beanName" class="package.class"
scope="page|request|session|application"/>
id屬性用於指定JavaBean實例對象的引用名稱和其存儲在域範圍中的名稱。
class屬性用於指定JavaBean的完整類名(即必須帶有包名)。
scope屬性用於指定JavaBean實例對象所存儲的域範圍,其取值只能是page、request、session和application等四個值中的一個,其默認值是page。
<jsp:setProperty>標籤用於設置和訪問JavaBean對象的屬性。
語法格式:
<jsp:setProperty name="beanName"
{
property="propertyName"value="{string | <%= expression %>}" |
property="propertyName"[ param="parameterName" ] |
property= "*" }/>
name屬性用於指定JavaBean對象的名稱。
property屬性用於指定JavaBean實例對象的屬性名。
value屬性用於指定JavaBean對象的某個屬性的值,value的值能夠是字符串,也能夠是表達式。爲字符串時,該值會自動轉化爲JavaBean屬性相應的類型,若是value的值是一個表達式,那麼該表達式的計算結果必須與所要設置的JavaBean屬性的類型一致。
param屬性用於將JavaBean實例對象的某個屬性值設置爲一個請求參數值,該屬性值一樣會自動轉換成要設置的JavaBean屬性的類型。
<jsp:getProperty>標籤用於讀取JavaBean對象的屬性,也就是調用JavaBean對象的getter方法,而後將讀取的屬性值轉換成字符串後插入進輸出的響應正文中。
語法:
<jsp:getPropertyname="beanInstanceName" property="PropertyName" />
name屬性用於指定JavaBean實例對象的名稱,其值應與<jsp:useBean>標籤的id屬性值相同。
property屬性用於指定JavaBean實例對象的屬性名。
JSP開發模式
4 SUN公司推出JSP技術後,同時也推薦了兩種web應用程序的開發模式,一種是JSP+JavaBean模式,一種是Servlet+JSP+JavaBean模式。
5 JSP+JavaBean模式適合開發業務邏輯不太複雜的web應用程序,這種模式下,JavaBean用於封裝業務數據,JSP即負責處理用戶請求,又顯示數據。
6 Servlet+JSP+JavaBean(MVC)模式適合開發複雜的web應用,在這種模式下,servlet負責處理用戶請求,jsp負責數據顯示,javabean負責封裝數據。 Servlet+JSP、JavaBean模式程序各個模塊之間層次清晰,web開發推薦採用此種模式。
4 什麼是JSP
1)爲何說,HTML是一個靜態Web開發技術呢?
由於HTML沒有表明客戶端和服務端的一個對象
2)爲何說,Servlet是一個動態Web開發技術呢?
由於Servlet有表明客戶端和服務端的一個對象,分別request和response對象,
3)SUN公司還定義了一種動態開發技術規則,叫JSP(Java Server Pages)
4)JSP主要解決頁面須要動態從服務端獲取的數據,例如:(從request/session/servletContext)
5)JSP的特色:
>>與HTML具備相似的風格,原HTML怎麼寫,JSP就能夠怎麼寫
>>爲了取得動態的效果,能夠在JSP頁面中,使用JSP特有的語言規則嵌入Java代碼
5 JSP+Servlet最佳配合體驗
1)Servlet能夠完成頁面輸出,但效果較差,不便於難護,比較適合作控制器
2)JSP比較適合作頁面輸出
*6 JSP工做原理
1)Web服務器是如何調用並執行一個jsp頁面的?
>>date.jsp文件,會被web服務器翻充成date_jsp.java源代碼,本質就是一個servlet,也與servlet同樣,有着相似的生命週期方法,即jsp本質上就是一個servlet,servlet能作的事情,jsp也能作到,jsp和servlet決不能替代,只是一個互相補充的關係
2)Jsp頁面中的html排版標籤是如何被髮送到客戶端的?
全部靜態數據經過write()方法輸出
3)Jsp頁面中的java代碼服務器是如何執行的?
全部動態數據經過print()方法輸出
4)Web服務器在調用jsp時,會給jsp提供一些什麼java對象?
Web服務器在將date.jsp文件翻譯成date_jsp.java源代碼時,會自動建立[看得見]的8個內置對象,所以在jsp面頁中能夠直接使用這8個內置對象
5)工做原理
1)若是訪問的是jsp,那麼web服務器就會將請求的資源交由jsp引擎來處理
2)若是是第一次訪問jsp,那麼jsp引擎會將jsp翻譯成servlet源碼
3)jsp引擎將servlet源碼交由servlet引擎來處理,參見<<servlet工做原理>>
4)若是第一次訪問jsp,時間會相對較長,由於jsp引擎在作翻譯成servlet工做
5)若是再次訪問相同的jsp,若是內容沒有改變,這時jsp引擎不作翻譯,直接交由servlet引擎處理
6)若是再次訪問的jsp,但內容更新了,這時jsp引擎又會將新的jsp作翻譯
7 JSP語法
1)JSP模版元素
就是在JSP頁面中的HTML標籤,例如:<body>,<font>,...
2)JSP表達式
語法:<%="須要輸出的字符常量或變量"%>,
相似於response.getWriter().write("當前時間");
輸出表達式中不能含有分號
3)JSP腳本片段
語法:<% JSP腳本代碼,以分號結束,即Java代碼 %>
多個腳本片斷之間徹底能夠訪問,由於這些片斷中的代碼,最終都被翻譯到_jspService()方法中,成爲局部變量
4)JSP聲明
語法:<%! Java代碼,會被翻譯成實例變量%>
5)JSP註釋
語法:
XML: <!-- xxxxx -->
Java: //單行
/* */多行
/**
* 文檔註釋
*
*/
JS: //單行
/* */多行
HTML:<!-- xxxx -->
JSP:<%-- xxxxxx --%>
若是你使用JSP特有的註釋,JSP引擎不會將其翻譯到Servlet源碼中,除此以外,就要翻譯到Servlet源碼中
註釋不容許嵌套
Day10:
1 JSP中指令
1)JSP指令有三類
>>page指令
>>include指令
>>taglib指令
2)JSP指令的做用:針對JSP引擎來設計,通知JSP引擎應該針對該JSP頁面如何處理
*3)page指令的屬性含義
格式一:<%@ 指令名 屬性名1="屬性值1" 屬性名2="屬性值2"%>
格式二:<%@ 指令名 屬性名1="屬性值1"%>
<%@ 指令名 屬性名2="屬性值2"%>
[ language="java" ] 指明JSP腳本〈%%>中的語言是java,默認也是java語言
*[ import="{package.class | package.*},..." ] 指明讓JSP引擎導入的相關包,有些包不須要導,javax.servlet.*,javax.servlet.http.*
[ session="true | false" ] 在servlet中,產生HttpSession必須要有以下代碼:request.getSession(),沒有的話,不會產生當咱們訪問的任何一個jsp頁面時,在默認狀況下,web服務器[必定]都會幫咱們產生HttpSession 指明讓JSP引擎產生HttpSession,true表示產生HttpSession,false表示不產生HttpSession,默認true
[ buffer="none | 8kb | sizekb" ] 指明讓JSP引擎建立緩存池的大小,默認有,且8kb
[ autoFlush="true | false" ] 指明讓JSP引擎自動監視緩存池的數據刷新狀況,
>>當緩存池滿,自動刷新,將數據輸出到瀏覽器
>>當緩存池未滿,但整個jsp執行完畢,將數據輸出到瀏覽器
若是設置爲false,則不讓JSP引擎自動刷新,只有人工經過API刷新,默認true.
[ isThreadSafe="true | false" ]
jsp本質就是一個servlet,jsp與servlet同樣具備安全問題,若是須要讓JSP引擎解決安全問題,則選中true;若是選中false,則自已解決安全問題,即加鎖,默認true。[ info="text" ] 指明JSP引擎,該JSP頁面的做者,版本,時間,等等相關信息
*[errorPage="relative_url" ] 出錯後,轉發的頁面,路徑能夠是相對或絕對路徑,
*[isErrorPage="true | false" ] 出錯面頁,若是選用true表示該jsp爲出錯後轉發的頁面,JSP引擎自動產生exception對象,若是選用false,JSP引擎不會自動產生exception對象能夠在web.xml文件中配置全局的錯誤出錯處理頁面,也能夠在jsp文件中配置局部的錯誤出錯處理頁面,當兩者衝突時,局部優先當全局異常中,出現代碼和類型時,類型優先默認false,即不能使用exception內置對象
*[contentType="text/html ; charset=UTF-8" ] , [pageEncoding="UTF-8" ]
上述兩者等價,但若是衝突,contentType優先
*[isELIgnored="true | false" ]
false指明JSP引擎支持EL,true不支持EL,默認是支持的,爲false
4)include指令的屬性含義
當在一個jsp頁面中包含N個子頁面時,能夠採用include指令,最終的編碼方式由總的頁面決定
對於子jsp頁面,並無翻譯成servlet,都在翻譯時,包含在總的jsp所翻譯的servlet中,結構不清淅將include指令所包含的jsp稱作"靜態包含"
*2 JSP中九大內置對象
request/response
session/application
config/out
注意:out對應的類型是JspWriter類型,它是比PrintWriter更高級的對象,至關於將PrintWriter的緩存做用out對象的緩存用
exception:只有當該JSP爲錯誤處理頁時,才能使用
3. PageContext對象做用
1)PageContext是一個域對象(setAttribute/getAttribute/removeAttribute),有且只有在當前jsp頁面中有效也能夠經過PageContext將信息綁定任意域對象中
(page/request/session/application),默認page
2)PageContext能夠取得其它8個內置對象
3)且有轉發和包含操做
4 JSP中四個域對象彙總
1)生命週期:
從生命週期的小到大:pageContext->request->session->application
page域:是JSP特有的,當前頁面中共資源
request域:一次請求中的全部servlet和jsp共享資源
session域:整個會話中的全部servlet和jsp共享資源
application域:整個web應用中的全部servlet和jsp共享資源
2)案例
page域:在當前頁面中使用
request域:讀取內容顯示,錯誤消息顯示
session域:購物車,用戶登陸,註冊
application域:在線訪問計數器
5 JSP內置[非JavaBean]標籤
1)JSP標籤是一種替代JSP腳本的技術
2)JSP標籤能夠達到美化頁面,又且有業務邏輯流程控制的功能
3)<jsp:forward page=」url」>標籤
轉發:<%pageContext.forward()%>
4)<jsp:include>標籤
包含:<%pageContext.include()%>
<%@ include file%>
<jsp:include page flush/>
>>有N個jsp,則翻譯成N個servlet源碼
>>總的jsp頁面結構清晰
>>是一個動態包含的過程,執行時,臨時加載,所以叫動態包含
flush表示表示是否先將include頁面的信息輸出,false表示不先輸出,true表示先輸出
5)<jsp:param>標籤
帶參轉發或包含?name=jack&pass=123
6)JSP錯誤有三類
>>JSP表面語言錯誤
>>翻譯成Servlet源碼有誤
>>JSP運行過程當中出錯,邏輯錯誤爲主
JSP內置[JavaBean]標籤
什麼是JavaBean
JavaBean是一個遵循特定寫法的Java類,它一般具備以下特色:
這個Java類必須具備一個無參的構造函數
屬性必須私有化。
私有化的屬性必須經過public類型的方法暴露給其它程序,而且方法的命名也必須遵照必定的命名規範。
1)JavaBean分二類;
>>狹義JavaBean/實體/域對象/值對象(今天特指)
1)私有字段
2)公有的構造器
3)公有的set(存)/get(取)方法
>>廣義JavaBean(模型)
普通類,含普通方法
2)JavaBean有做用?
存取程序員的數據,
3)JavaBean的命名規則
private String name;
存:setName()
取:getName();
JavaBean的屬性
JavaBean的屬性能夠是任意類型,而且一個JavaBean能夠有多個屬性。每一個屬性一般都須要具備相應的setter、 getter方法,setter方法稱爲屬性修改器,getter方法稱爲屬性訪問器。
屬性修改器必須以小寫的set前綴開始,後跟屬性名,且屬性名的第一個字母要改成大寫,例如,name屬性的修改器名稱爲setName,password屬性的修改器名稱爲setPassword。
屬性訪問器一般以小寫的get前綴開始,後跟屬性名,且屬性名的第一個字母也要改成大寫,例如,name屬性的訪問器名稱爲getName,password屬性的訪問器名稱爲getPassword。
一個JavaBean的某個屬性也能夠只有set方法或get方法,這樣的屬性一般也稱之爲只寫、只讀屬性
4)在JSP中如何使用JavaBean
1)<jsp:useBean/>
>>首先在指定的域對象中[查詢]是否有對應的JavaBean存在,若是有的話,直接取得該JavaBean;
若是沒有的話,則建立該JavaBean,而後自動綁定到指定的域對象中,默認page域
>>標籤體的內容,只有新會話首次訪問時,纔會執行,不然不執行
2)<jsp:setProperty/>
>>爲JavaBean設置值
>>自動將String類型,轉成8種基本類型
>>當參數名和字段名一致的狀況下,能夠使用下列代碼
<jsp:setPropertyname="user" property="*"/>
3)<jsp:getProperty/>
>>從JavaBean中取出值
例: <body>
<!-- 建立javaBean -->
<jsp:useBean id="User" class="cn.web.servlet.JSP.User"/>
<!-- 設置javaBean中的屬性 1-->
<jsp:setProperty property="name" name="User" value="張三"/>
<jsp:setProperty property="id" name="User" value="12334"/>
<jsp:setProperty property="salary" name="User" value="4500"/>
<!-- 設置javaBean中的屬性2 -->
<jsp:setProperty property="name" name="User" param="username"/>
<jsp:setProperty property="id" name="User" param="userid"/>
<jsp:setProperty property="salary" name="User" param="usersalary"/>
<!-- 設置javaBean中的屬性3 -->
<jsp:setProperty property="*" name="User"/>
<!-- 取出javaBean中的屬性 -->
用戶名:<jsp:getProperty property="name" name="User"/>
編號:<jsp:getProperty property="id" name="User"/>
薪水:<jsp:getProperty property="salary" name="User"/>
</body>
在JSP中使用JavaBean
JSP技術提供了三個關於JavaBean組件的動做元素,即JSP標籤,它們分別爲:
<jsp:useBean>標籤:用於在JSP頁面中查找或建立一個JavaBean組件。
<jsp:setProperty>標籤:用於在JSP頁面中設置一個JavaBean組件的屬性。
<jsp:getProperty>標籤:用於在JSP頁面中獲取一個JavaBean組件的屬性。
<jsp:useBean>標籤用於在指定的域範圍內查找指定名稱的JavaBean對象:
若是存在則直接返回該JavaBean對象的引用。
若是不存在則實例化一個新的JavaBean對象並將它以指定的名稱存儲到指定的域範圍中。
經常使用語法:
<jsp:useBeanid="beanName" class="package.class"scope="page|request|session|application"/>
id屬性用於指定JavaBean實例對象的引用名稱和其存儲在域範圍中的名稱。
class屬性用於指定JavaBean的完整類名(即必須帶有包名)。
scope屬性用於指定JavaBean實例對象所存儲的域範圍,其取值只能是page、request、session和application等四個值中的一個,其默認值是page。
<jsp:setProperty>標籤用於設置和訪問JavaBean對象的屬性。
語法格式:
<jsp:setProperty name="beanName"
{
property="propertyName"value="{string | <%= expression %>}" |
property="propertyName"[ param="parameterName" ] |
property= "*" }/>
name屬性用於指定JavaBean對象的名稱。
property屬性用於指定JavaBean實例對象的屬性名。
value屬性用於指定JavaBean對象的某個屬性的值,value的值能夠是字符串,也能夠是表達式。爲字符串時,該值會自動轉化爲JavaBean屬性相應的類型,若是value的值是一個表達式,那麼該表達式的計算結果必須與所要設置的JavaBean屬性的類型一致。
param屬性用於將JavaBean實例對象的某個屬性值設置爲一個請求參數值,該屬性值一樣會自動轉換成要設置的JavaBean屬性的類型。
<jsp:getProperty>標籤用於讀取JavaBean對象的屬性,也就是調用JavaBean對象的getter方法,而後將讀取的屬性值轉換成字符串後插入進輸出的響應正文中。
語法:
<jsp:getProperty name="beanInstanceName"property="PropertyName" />
name屬性用於指定JavaBean實例對象的名稱,其值應與<jsp:useBean>標籤的id屬性值相同。
property屬性用於指定JavaBean實例對象的屬性名。
JSP開發模式
Jsp(v)+jsp(c)+javaBean
Jsp(v)+Servlet(c)+javaBean
SUN公司推出JSP技術後,同時也推薦了兩種web應用程序的開發模式,一種是JSP+JavaBean模式,一種是Servlet+JSP+JavaBean模式。
JSP+JavaBean模式適合開發業務邏輯不太複雜的web應用程序,這種模式下,JavaBean用於封裝業務數據,JSP即負責處理用戶請求,又顯示數據。
Servlet+JSP+JavaBean(MVC)模式適合開發複雜的web應用,在這種模式下,servlet負責處理用戶請求,jsp負責數據顯示,javabean負責封裝數據。Servlet+JSP、JavaBean模式程序各個模塊之間層次清晰,web開發推薦採用此種模式。
* Web開發中的二種模式
1 EL和JSTL簡介和快速入門
1)Java Standard Taglib Language
JSTL是一種SUN公司提供的外置標籤,目的是替代原JSP中的腳本符號
JSTL和JSP內置標籤是一個互補的關係
2)使用JSTL是補充JSP內置標籤的功能不足
3)Expression Language表達式語言,主要是配合JSTL的使用
4)開發JSTL應用的步驟:
>>導入jstl.jar和Standard.jar二個jar包,若是工具自帶就不用導入
>>在須要使用jstl的jsp面頁,經過<%taglib%>指令聲明
<%@ tagliburi="http://java.sun.com/jsp/jstl/core" prefix="c" %>
>>使用相關的jstl外置標籤
<c:forEach var/items的值必定要配合EL使用>
數據類型:
tinyint/smallint/mediumint/int/bigint-->1B/2B/3B/4B/8B
float/double-->單精度/雙精度浮點型
decimal-->不會產生精度丟失的單精度/雙精度浮點型
date-->日期類型
time-->時間類型
datetime-->日期時間類型
year-->年類型
char-->定長字符串類型
varchar-->可變長字符串類型(65535字符)
BLOB類別類型
tinyblob/blob/mediumblob/longblob-->255B/64K/16M/4G大小的圖片/音樂等二進行數據(JDBC中講)
text類別類型
tinytext/text/mediumtext/longtext-->255B/64K/16M/4G大小的文本數據(JDBC中講)
1 什麼是數據庫
1)SQL=Struture [Query] Language 結構化的查詢語言
2)存放有必定規則的數據的容器
3)文件自己並無一種機制去檢測數據是否合法,所以須要一種新的技術去替代文件做數據的容器
4)文件內容若是過大,打開相對較慢,所以須要一種新的技術去替代文件做數據的容器
5)MySQL-軟件-
2 各類經常使用數據庫簡介
1)Oracle&Unix/MySQL&Linux/SQLServer&Window(我的推薦,不能固定)
3 SQL[通用/專用]與數據庫的關係
1)SQL是Java應用程序操做數據庫的工具之一
2)若是某個SQL可以操不各類各樣的數據庫,這樣的SQL叫作"通用SQL"(重點)
3)若是某個SQL只可以操一種數據庫,這樣的SQL叫作"專用SQL"
*4 MySQL數據庫的卸載,安裝,設置,進入和退出
1)進入MySQL數據庫:c:\>mysql -u root -p回車
entry password:****回車
2)退出MySQL數據庫:mysql:>exit回車
8 修改、備份、恢復數據庫中的數據
alter database 數據名
mysqldump -u root -p 須要備份的數據庫名 > *.sql文件的路徑(須要在window環境中運行,專用於mysql)
source *.sql文件的路徑(須要mysql環境中運行,專用於mysql)
9 MySQL支持的經常使用數據類型簡介
1)日期時間(date/datetime/timestamp),其它date/datetime必須給定值,而timestamp能夠不給定值,默認爲當前時間
2)文本數據和多媒體數據(varchar/text/blob)
3)數值型(TINYINT/SMALLINT/MEDIUMINT/INT(默認是11個位數/BIGINT)
4)數值型默認有符號,INT型能存多大的值,不是看位數,而是看INT類型的最大有效值
*10 建立/查看/修改/刪除表
create table 表名
desc 表名
11 MySQL解決插入中文亂碼問題(WindowXP/7平臺)
set character_set_client=gbk;(window平臺默認字符集)
set character_set_results=gbk;(window平臺默認字符集)
*12 表的增刪改操做
1)刪除數據能夠使用如下二種方式:
>>delete from 表名
都能刪除表中的全部記錄,保留表結構
一行一行的刪除
項目中數據量相對小時,推薦使用delete刪除全部數據
能夠按條件刪除
>>truncate table 表名
都能刪除表中的全部記錄,保留表結構
複製原表結構->刪除整個表->自動建立表結構
項目中數據量至關大時,推薦使用trancate刪除全部數據
不能夠按條件刪除
>>drop table 表名
不光表數據刪除,表結構也刪除,不能夠按條件刪除
2)insert into 表名(字段) values(對應的字段值)
3)update table 表名 set 字段1=值1,字段2=值2 where 字段 = 條件
1. 建立一個數據庫。
2. 顯示數據庫語句:
3. SHOW DATABASES
4. 顯示數據庫建立語句:
5. SHOW CREATE DATABASE db_name
6. 使用數據庫
7. USE db_name
8. 數據庫刪除語句:
9. DROP DATABASE [IF EXISTS] db_name
10. 查看指11. 定的庫下全部的表
Show tables;
CHARACTER SET:指定數據庫採用的字符集
COLLATE:指定數據庫字符集的比較方式、規則,好比排序
建立一個名稱爲mydb1的數據庫。
create databaseif not exists mydb1;
若是在建立數據庫時,沒有指明編碼方式,默認和配置數據庫時採用的編碼方式一致
if not exists 表示先查詢在數據庫服務器中是否有數據庫存在,若是沒有,才建立;若是有,則直接使用
建立一個使用utf8字符集的mydb2數據庫。
create databasemydb2 character set utf8;
//準意,MySQL編碼集中沒有UTF-8,只有UTF8
//MySQL的SQL命令,大小寫不敏感
建立一個使用utf8字符集,並帶校對規則的mydb3數據庫。
create databasemydb3 character set utf8 collate utf8_general_ci;
查看當前數據庫服務器中的全部數據庫
show databases;
查看前面建立的mydb2數據庫的定義信息
show createdatabase mydb2;
刪除前面建立的mydb1數據庫
drop databaseif exists mydb1;
使用mydb2數據庫
use mydb2;
查看服務器中的數據庫,並把其中mydb3庫的字符集修改成gbk。
alter databasemydb3 character set gbk;
備份mydb2庫中的數據,並恢復。
use mydb2;
create tableuser(
name varchar(20)
);
insert intouser(name) values('jack');
insert intouser(name) values('marry');
select * fromuser;
備份:c:\>mysqldump -u root -p mydb2 > d:\xx.sql回車
//mysqldump命令須要在window環境中運行,而不是mysql環境中運行
//mysqldump命令是mysql提供的專用sql命令
//mysqldump命令是將數據庫中表數據備份到*.sql文件中
恢復:mysql>source d:\xx.sql回車
//source命令須要在mysql環境中運行,而不是window環境中
//source命令是mysql提供的專用sql命令
//source命令是將硬盤中的*.sql文件中的內容恢復到數據庫中
建立一個user表,包含id/name/password/birthday
drop table ifexists user;
create tableuser(
id int(5),
name varchar(20),
password varchar(6),
salary float(6,2),//6表示整個數值的位數,2表示小數點後的位數,不包含小數點自己
birthday timestamp
);
insert intouser(id,name,password,salary) values(1,'jack','123456',9999.99);
查詢user表的結構desc user
建立employee表
create table ifnot exists employee(
id int,
name varchar(20),
gender varchar(6),
birthday timestamp,
entry_date timestamp,
job varchar(20),
salary float,
resume text
);
在上面員工表的基本上增長一個image列。
alter tableemployee add image blob;
修改job列,使其長度爲60。
alter tableemployee modify job varchar(60);
刪除gender列。
alter tableemployee drop gender;
表名改成staff。
rename tableemployee to staff;
修改表的字符集爲utf8。
alter tablestaff character set utf8;若是在建立表時不指定,默認和數據庫的編碼方式一致
列名name修改成username。
alter tablestaff change column name usernamevarchar(40);
刪除表
drop table ifexists user;
1.增長數據(使用 INSERT 語句向表中插入數據)
插入的數據應與字段的數據類型相同。
數據的大小應在列的規定範圍內,例如:不能將一個長度爲80的字符串加入到長度爲40的列中。
在values中列出的數據位置必須與被加入的列的排列位置相對應。
字符和日期型數據應包含在單引號中。
插入空值,不指定或insert into table value(null)
insert intoemployee values(1,'jack','male','engineer',5500,'16K','2012-7-14 15:15:15');
insert intoemployee(id,name,gender,job,salary,resume) values(2,'tom','male','engineer',5500,'16K');
insert intoemployee(name,id,gender,job,salary,resume) values('marry',3,'female','engineer',5500,'16K');
insert intoemployee(id,name,gender,job,salary,resume) values(4,'sisi','female','engineer',5500,NULL);
insert intoemployee(id,name,gender,job,salary) values(5,'soso','female','engineer',5500);
insert intoemployee(id,name,gender,job,salary) values(6,'xx','xxxxxx','engineer',5500);
insert intoemployee(id,name,gender,job,salary) values(7,'傑克','男','工程師',5500);
2.使用 update語句修改表中數據。
SET子句指示要修改哪些列和要給予哪些值。
WHERE子句指定應更新哪些行。如沒有WHERE子句,則更新全部的行。
將全部員工薪水修改成6000元。
update employeeset salary = 6000;
update employeeset salary=6500,resume='16K' where name='xx';
將姓名爲’傑克’的員工薪水修改成7000元。
update employeeset salary=7000 where name='傑克';
將’馬利’的薪水在原有基礎上增長1000元。
update employeeset salary=salary+1000 where name='馬利';
使用 delete語句刪除表中數據。
若是不使用where子句,將刪除表中全部數據。delete語句不能刪除某一列的值(可以使用update),使用delete語句僅刪除記錄,不刪除表自己。如要刪除表,使用drop table語句。同insert和update同樣,從一個表中刪除記錄將引發其它表的參照完整性問題,在修改數據庫數據時,頭腦中應該始終不要忘記這個潛在的問題。刪除表中數據也可以使用TRUNCATE TABLE 語句,它和delete有所不一樣。
TRUNCATE(複製表結構->銷燬表->重建表結構)
DELETE(逐行刪除記錄)
刪除表中名稱爲’xx’的記錄。
delete fromemployee where name='xx';
刪除表中全部記錄。
delete fromemployee;
使用truncate刪除表中記錄。
truncate tableemployee
查詢表中全部學生的信息。
selectid,name,chinese,english,math from student;
selectname,id,chinese,english,math from student;
簡化
select * fromstudent;
查詢表中全部學生的姓名和對應的英語成績。
selectname,english from student;
基本select語句
Select 指定查詢哪些列的數據。
column指定列名。
*號表明查詢全部列。
From指定查詢哪張表。
DISTINCT可選,指顯示結果時,是否剔除重複數據
過濾表中重複數據。
select distinctchinese from student;
在全部學生分數上加10分特長分。
加分前:select name,chinese,math,english from student;
加分後:select name,chinese+10,math+10,english+10 from student;
統計每一個學生的總分。
selectname,chinese+math+english from student;
使用別名表示學生分數。
select name as 姓名,chinese+math+english as 總分 from student;
查詢姓名爲’張小明’的學生成績
select * fromstudent where name = '張小明';
查詢英語成績大於90分的同窗
selectname,english from student where english > 90;
查詢總分大於200分的全部同窗
select name as 姓名,chinese+math+english as 總分
from student
wherechinese+math+english > 200;
查詢英語分數在 80-90之間的同窗。
selectname,english
from student
whereenglish>=80 and english <=90;
或
selectname,english
from student
where englishbetween 80(小) and 90(大);
查詢數學分數爲89或者90或者91的同窗。
selectname,math
from student
where math=89or math=90 or math=91;
或
select name,math
from student
where mathin(89,90,91);
查詢全部姓’李’的學生成績。
select name
from student
where name like'李%';//模糊查詢
查詢全部名’李’的學生成績。
select name
from student
where name like'%李';
查詢全部姓名中包含’李’的學生成績。
select name
from student
where name like'%李%';
select name
from student
where name like'%%';
等價於
select name
from student;
查詢全部姓’李’的學生成績,但姓名必須是三個字
select name
from student
where name like'李__';
查詢數學分>80且語文分>80的同窗。
selectname,math,chinese
from student
wheremath>80 and chinese>80;
使用order by 子句排序查詢結果。
對數學成績排序(降序)後輸出。
selectname,math
from student
order by mathdesc;
或
selectname,math
from student
order by mathasc;//默認升序
對總分排序(降序)後輸出。
select name as 姓名,chinese+math+english as 總分
from student
order bychinese+math+english desc;
對姓’李’的學生總分排序(降序)輸出。
select name as 姓名,chinese+math+english as 總分
from student
where name like'李%'
order bychinese+math+english desc;
統計一個班級共有多少學生?
select count(*)as 學生總人數 from student;
selectcount(math) as 學生總人數 from student;
統計數學成績大於80的學生有多少個?
select count(*)as 學生總人數
from student
where math >80;
統計總分大於250的人數有多少?
select count(*)as 學生總人數
from student
wherechinese+math+english>250;
統計一個班級數學總成績。
selectsum(math) as 數學總分 from student;
統計一個班級語文、英語、數學各科的總成績。
selectsum(math) as 數學總分,sum(english) as 英語總分,sum(chinese) as 語文總分
from student;
統計一個班級語文、英語、數學的成績總和。
selectsum(math+english+chinese) as 班級總分
from student;
統計一個班級語文成績平均分。
selectsum(chinese)/count(chinese) as 語文成績平均分
from student;
求一個班級數學平均分。
selectavg(math) as 數學平均分
from student;
求一個班級總分平均分。
select avg(math+english+chinese)as 班級總平均分
from student;
求班級最高分和最低分數學。
selectmax(math) as 最高數學分,min(math) as 最低數學分
from student;
對訂單表中商品歸類後,顯示每一類商品的總價
select productas 商品,sum(price) as 總價
from orders
group byproduct;
查詢購買了幾類商品,而且每類總價大於100的商品
select productas 商品,sum(price) as 總價
from orders
group byproduct
having sum(price) > 100;
查詢購買了幾類商品,而且每類總價大於100的商品,同時按照總價的降序排列
select productas 商品,sum(price) as 總價
from orders
group byproduct
having sum(price) > 100
order bysum(price) desc;
1 表的完整性
(1)實體完整性:每條記錄有一個惟一標識符,一般用無任何業務含義的字段表示
(2)參照完整性:一張表的某個字段必須引用另外一張表的某個字段值(外健),主要針對多張表
(3)域完整性:域即單元數據,域中的數值必須符合必定的規則
2 鍵的概念
(1)單一主鍵:只有惟一字段(推薦)
(2)組合主鍵:由多個字段組合起來,造成惟一字段
(3)外鍵:針對多張表之間的關聯
3 主鍵的特色
1)定義主鍵的語法:id int primary key
2)主鍵值不能爲NULL
3)主鍵值不能重複
4)刪除已存在的主鍵的語法:alter table person drop primary key
5)當刪除已存在的主鍵後,可插入重複制,但不容許爲NULL或者‘NULL’空串
6)主鍵能夠由MySQL數據庫系統自動產生一個惟一的值,語法以下:id int primary key auto_increment,MySQL特有
7)這個惟一的值,只在要表結構刪除時清0,不然不會清0,繼承累加,可能出現主鍵值不連續的狀況,但必定惟一
8)項目中,主鍵不採用MySQL特有的auto_increment方式,而是採用UUID或自定義算法來產生惟一的主鍵,這樣當多表中
的數據合起來時,主鍵重複的機會至關小
4 惟一約束的特色
1)定義惟一約束的語法:name varchar(20) unique
2)不能二次插入同一具體值
3)但能夠插入NULL值,而不是’NULL‘串
5 非空約束特色
1)定義非空約束的語法:name varchar(20) unique notnull
2)不能插入NULL值,而不是’NULL‘串
3)以上約束的目的是確保數據的安全性,即可以存入到表中的數據,必定在符合安全約束的
6 外健特色
1)外鍵體現多表關聯,
2)外鍵的值一般來自於另外一張表的主鍵值
3)在對象世界中,有一對一單向和一對一雙向
4)在關係世界中,只有一對一單向關聯,緣由在於刪除操做
5)外鍵的語法:constraint pid_FK(給MySQL系統) foreign key(pid) references person(id)
測試MySQL特有的函數
使用MySQL特有函數舉例:
1)到年末還有幾少天[datediff]
select datediff('2012-6-2','2012-12-31');
2)截取字符串[substring]
select substring('abcdef',1,5);
3)保留小數點後2位(四捨五入)[format]
select format(2.333,1);
4)向下取整[floor]
select floor(2.5621);
5)取隨機值[rand] 0~1
select rand();
6)取1-6之間的隨機整數值[floor和rand]
select floor(rand()*6)+1;
7)截取字符串長度和去空格
select trime(" jack ");
8)字符比較
select strcmp('a','w');
JDBC全稱爲:Java Data Base Connectivity(java數據庫鏈接),它主要由接口組成。
組成JDBC的2個包:java.sql javax.sql
編寫一個程序,這個程序從user表中讀取數據,並打印在命令行窗口中。
1、搭建實驗環境:
一、在mysql中建立一個庫,並建立user表和插入表的數據。
二、新建一個Java工程,並導入數據驅動。
2、編寫程序,在程序中加載數據庫驅動
DriverManager. registerDriver(Driver driver)
3、創建鏈接(Connection)
Connection conn =DriverManager.getConnection(url,user,pass);
4、建立用於向數據庫發送SQL的Statement對象,併發送sql
Statement st = conn.createStatement();
ResultSet rs = st.excuteQuery(sql);
5、從表明結果集的ResultSet中取出數據,打印到命令行窗口
6、斷開與數據庫的鏈接,並釋放相關資源
4祥解JDBC鏈接數據庫的各個步驟
1)JDBC開發的步驟
>>導入mysql驅動jar包(mysql-connector-java-5.1.7-bin.jar,每種數據庫都會有自動的JDBC實現jar包)
>>使用JDBC規則中的接口或類來操做全部關係型數據庫
2)祥解
>>DriverManager(類)是管理一組具體數據庫的驅動
>>Drvier(接口)須要被DriverManager管理的驅動,必須實現java.sql.Driver接口DriverManager會試圖用URL和每一個數據庫驅動嘗試進行鏈接
底層方法:
boolean acceptsURL(String url):可以鏈接返回true;不可以鏈接返回false ,若是返回true的狀況下,DriverManager再調用Connectionconnect(String url, Properties info)返回真正的鏈接對象
>>Connection(接口)表示與特定數據庫鏈接的對象(會話) ,在完成業務操做後,該對象越早關閉越好,必定要關閉,先關閉輕量有資源Statement和Resulset,後關係重量級資源Connection
>>Statement(接口)表示封裝SQL命令對象,並執行SQL命令,取得返回值
>>ResultSet(接口)表示根據查詢SQL命令獲得的結果集,相似於一個List集合
初始狀況下,位於第一行記錄以前,須要經過next()方法將光標下移來取值
5 JDBC的六個固定步驟(以查詢爲例)
>>向DriverManager註冊數據庫驅動
>>取得Connection重量級鏈接對象
>>建立封裝SQL命令的對象Statement
>>執行SQL命令,返回結果集ResultSet
>>處理結果集ResultSet
>>先輕後重,關閉結果集
Statement對象的executeUpdate方法,用於向數據庫發送增、刪、改的sql語句,executeUpdate執行完後,將會返回一個整數(即增刪改語句致使了數據庫幾行數據發生了變化)。
Statement.executeQuery方法用於向數據庫發送查詢語句,executeQuery方法返回表明查詢結果的ResultSet對象。
數據庫分頁:
MySQL分頁的實現:
select * from table limit M,N
M:記錄開始索引位置
N:取多少條記錄。
完成WEB頁面的分頁顯示, 先得到需分頁顯示的記錄總數,而後在web頁面中顯示頁碼。
根據頁碼,從數據庫中查詢相應的記錄顯示在web頁面中。以上兩項操做一般使用Page對象進行封裝。
使用JDBC處理大數據
在實際開發中,程序須要把大文本或二進制數據保存到數據庫。
基本概念:大數據也稱之爲LOB(Large Objects),LOB又分爲:
clob和blob
clob用於存儲大文本
blob用於存儲二進制數據
對MySQL而言只有blob,而沒有clob,mysql存儲大文本採用的是text,text和blob分別又分爲:
TINYTEXT、TEXT、MEDIUMTEXT和LONGTEXT
TINYBLOB、BLOB、MEDIUMBLOB和LONGBLOB
MySQL中的Text類型
PreparedStatement.setCharacterStream(index, reader, length);
//注意length長度須設置,而且設置爲int型
reader = resultSet. getCharacterStream(i);
reader = resultSet.getClob(i).getCharacterStream();
string s = resultSet.getString(i);
對於MySQL中的BLOB類型
文件的存儲
PreparedStatement. setBinaryStream(i, inputStream, length);
//字節字符流輸出文件
InputStream in =resultSet.getBinaryStream(i);
InputStream in =resultSet.getBlob(i).getBinaryStream();
批處理:
1 批處理
1)當須要向表中插入不少SQL命令時,能夠使用批處理
2)對於[相同結構]的SQL命令來講,能夠使用PreparedStatement對象,
緣由:
>>只需一次性對SQL命令進行編譯,之後凡是相同的SQL無需編譯
>>只後的每次只是參數不一樣,
以上這種情部況,叫作預編譯
3)對於[不相同結構的SQL命令來講,能夠使用Statement對象,
緣由:
>>每條不一樣的SQL命令,都須要進行編譯,再到數據庫執行
4)項目中,相同結構的SQL命令,建議使用PreparedStatement;不相同結構的SQL命令,建議使用Statement;但不表示,不能使用其它的對象。
5)批對象經常使用的API
>>stmt.addBatch(sqlA);
>>int[] ints = stmt.executeBatch();//若是執行100次,成功的話,數組中包含100個1
>>stmt.clearBatch();
>>pstmt.addBatch();
>>int[] ints = pstmt.executeBatch();
>>pstmt.clearBatch();
6)若是批處理的數據量較大,不要一次性執行多個SQL命令,而應該分次執行SQL命令
7)Statement對象:不具備預編譯功能
PreparedStatement對象:具備預編譯功能,能夠使用佔位符,能夠防止SQL注入
2 獲取主鍵值
1)須要使用外鍵關聯別一張表的主鍵時,這時能夠使用獲取主鍵值
2)獲取主鍵值專用於針對insert操做,由於insert操做才能產生主鍵值
3)經常使用的API:
pstmt =conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
Statement.RETURN_GENERATED_KEYS表示在完成insert操做後,保留主鍵值,以備程序獲取
rs = pstmt.getGeneratedKeys(); 獲取插入記錄的主鍵值
3 事務概述
1)事務指邏輯上的一組操做,組成這組操做的各個單元,要麼所有成功,要麼所有不成功。相似於&&操做
2)事務是每一個數據庫都具備的特色,只是強度不一樣而以。
3)MySQL經常使用事務控制命令
start transaction;//顯示開始事務,其它每條SQL命令都有事務存在,只是之前咱們使用隱式開始事務
commit;//提交事務,之前每條SQL命令執行結束後,數據庫幫咱們自動隱式提交事務,
在start transaction和commit這二個命令之間的SQL命令,都位於一個事務之間
rollback;//回滾事務,回滾到start transaction以前
4)事務可讓某些程序功能更加安全可靠
5)經常使用的JDBCAPI:
conn.setAutoCommit(false);等價於start transaction;
conn.commit();等價於commit;
conn.rollback();等價於rollback;
注意:回滾後,也要提交事務
*6)要肯定事務成功,就必須操做的是同一個connection對象,才能回滾成功,不能操做不一樣的connection對象,這一點很是重要
*4 事務的特性(ACID vs CURD)
原子性(A)
>>事務中的各個組成部份是一個總體,不可再分,要麼成功,要麼失敗。
一致性(C)
>>以轉賬爲例,轉賬先後,兩者的餘額總數不變
隔離性(I)
>>一個用戶操做表的某條記錄時,應該加鎖,不影響其它用戶同時使用該張表的某條記錄,相似於Java中的同步操做
持久性(D)
>>當用戶對錶中的數據進行更新後,一旦確認後,就不該該非人爲更新,應當永久保存
*5 事務的三個缺點
若是沒有遵循「隔離性」原則,就會產生以下錯誤:
1)髒讀
一個事務看到了另外一個事務未提交的數據,強調[未提交],但數量不變
2)不可重複讀
屢次查詢,結果不相同,強調[已提交],但數量不變
3)幻讀/虛讀
屢次查詢,結果不相同,強調[數量變化]
4)由輕到重:髒讀->不可重複讀->幻讀/虛讀
*6 事務的隔離級別
查看當前事務隔離級別
select @@tx_isolation;
修改當前事務隔離級別:
set transaction isolation level read uncommitted;
set transaction isolation level read committed;
set transaction isolation level repeatable read;
set transaction isolation level serializable;
啓動事務: start transaction;
提交事務: commit;
回滾事務: rollback
1)事務的隔離級別可以解決[髒讀/不可重複讀/幻讀]
2)事務的隔離級別有三類:
>>readcommitted:不能解決任何事物
>>read committed:只能解決髒讀
>>repeatable read:只能解決髒讀/不可重複讀,MySQL默認
>>serializable:可以解決髒讀/不可重複讀/幻讀,但效率超低,由於在查詢表時,都會將表鎖住,以致於其它用戶沒法操做
3)在serializable隔離級別,兩者均可以查詢操做,但對方不能作非查詢操做,即[insert/update/delete]
4)項目中,查詢無需事務,但非查詢操做得須要事務幫助,更安全
5)設置事務隔離級別的API:
conn.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
*7 轉賬
1)必定在確保Service和Dao層,用的都是同一個Connection對象
2)不要將Dao的Api引用到Serivce層,要作到解耦
3)使用ThreadLocale<Connection>將每一個線程和Connection對象綁定在一塊兒,相似於一個Connection複本。
鏈接池
DBCP----DATABASE CONNECTIONPOOL tomcat內置
C3P0---hibernate內置
使用的.jar
commons-dbcp.jar:鏈接池的實現
commons-pool.jar: 鏈接池實現的依賴類
commons-collections.jar :鏈接池實現的集合類
DBCP:
static{
InputStream in =JdbcUtil.class.getClassLoader().
getResourceAsStream("dbcp.properties");
Propertiesprop = new Properties();
prop.load(in);
BasicDataSourceFactory factory = newBasicDataSourceFactory();
dataSource =factory.createDataSource(prop);
}
C3P0 數據源:
元數據- DataBaseMetaData:
Api:
Connection.getMetaData()
DataBaseMetaData對象
getURL():返回一個String類對象,表明數據庫的URL。
getUserName():返回鏈接當前數據庫管理系統的用戶名。
getDatabaseProductName():返回數據庫的產品名稱。
getDatabaseProductVersion():返回數據庫的版本號。
getDriverName():返回驅動驅動程序的名稱。
getDriverVersion():返回驅動程序的版本號。
isReadOnly():返回一個boolean值,指示數據庫是否只容許讀操做。
元數據- ParameterMetaData:
PreparedStatement.getParameterMetaData() 得到表明PreparedStatement元數據的ParameterMetaData對象。
ParameterMetaData對象 getParameterCount() 得到指定佔位符?參數的個數
元數據- ResultSetMetaData
ResultSet.getMetaData() 得到表明ResultSet對象元數據的ResultSetMetaData對象。
ResultSetMetaData對象 getColumnCount() 返回resultset對象的列數
getColumnName(int column) 得到指定列的名稱
getColumnTypeName(int column) 得到指定列的類型(Types類)
經常使用O-R Mapping映射工具
Hibernate(全自動框架)
Ibatis(半自動框架/SQL)
CommonsDbUtils(只是對JDBC簡單封裝)
API介紹:
org.apache.commons.dbutils.QueryRunner(類)
org.apache.commons.dbutils.ResultSetHandler(接口)
工具類
org.apache.commons.dbutils.DbUtils。
QueryRunner類
須要一個 javax.sql.DataSource 來做參數的構造方法。
public Object query(Connection conn, Stringsql, Object[] params, ResultSetHandler rsh) throws SQLException:執行一個查詢操做,在這個查詢中,對象數組中的每一個元素值被用來做爲查詢語句的置換參數。該方法會自行處理PreparedStatement 和 ResultSet 的建立和關閉。
public Object query(String sql, Object[]params, ResultSetHandler rsh) throws SQLException: 幾乎與第一種方法同樣;惟一的不一樣在於它不將數據庫鏈接提供給方法,而且它是從提供給構造方法的數據源(DataSource) 或使用的setDataSource方法中從新得到 Connection。
public Object query(Connection conn, Stringsql, ResultSetHandler rsh) throws SQLException : 執行一個不須要置換參數的查詢操做。
public int update(Connection conn, Stringsql, Object[] params) throws SQLException:用來執行一個更新(插入、更新或刪除)操做。
public int update(Connection conn, Stringsql) throws SQLException:用來執行一個不須要置換參數的更新操做。
ResultSetHandler接口
BeanHandler:將結果集中的第一行數據封裝到一個對應的JavaBean實例中。
BeanListHandler:將結果集中的每一行數據都封裝到一個對應的JavaBean實例中,存放到List裏。
ArrayHandler:把結果集中的第一行數據轉成對象數組。
ArrayListHandler:把結果集中的每一行數據都轉成一個對象數組,再存放到List中
MapHandler:將結果集中的第一行數據封裝到一個Map裏,key是列名,value就是對應的值。
MapListHandler:將結果集中的每一行數據都封裝到一個Map裏,而後再存放到List。
calarHandler:結果集中只有一行一列數據。
2012-7-22day17:
使用文檔 JSPAPI
<%=request.getrRemoteAdd() %>
標籤: <simple: ip/> 獲取客戶端ip地址
自定義標籤: 1.實現simpleTag 接口.
2)在WEB-INF/*.tld,目的是通知Web服務器自定義標籤對應的處理類
<tlib-version>1.0(標籤的版本號)</tlib-version>
<short-name>simple(標籤的前綴)</short-name>
<uri>http://java.sun.com/jsp/jstl/simple(標籤從自於哪一個包,相似於類來源於哪一個包)</uri>
<tag>
<name>ip(標籤的名字)</name>
<tag-class>cn.itcast.web.jsp.tag.IpTag(標籤對應的底層處理類全路徑)</tag-class>
<body-content>empty(該標籤是一個空標籤)</body-content>
<attribute>
<name>count(屬性名)</name>
<required>true(屬性是否必須,true必須)</required>
<rtexprvalue>true(屬性值是否接收動態值,true表示可接收動態值)</rtexprvalue>
</attribute>
</tag>
3)在須要使用該自定義標籤的JSP面頁中,經過<%@taglib%>導入
<%@ page language="java" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/simple" prefix="simple"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01Transitional//EN">
<html>
<body>
客戶端IP是:<simple:ip/>
</body>
</html>
Jsp - Jstl:
JSTL: javastandar taglib language: java標準標籤語言
Out:標籤: <c:out> 標籤用於輸出一段文本到瀏覽器中
例:
<% request.setAttribute("role","管理員"); %>
<c:out value="${roles}"default="<a href='/myday18/index.jsp'><font color='red'>遊客</font></a>" escapeXml="false"/>
Value : 表示輸出的值.
default : 表示指定若是value屬性的值爲null/」」時所輸出的默認值
escapeXml : 表示輸出的內容,是否將>、<、&、'、" 等特殊字符進行HTML編碼轉換後再進行輸出。默認值爲true
<c:set>標籤
<c:set>標籤用於把某一個對象存在指定的域範圍內,或者設置Web域中的java.util.Map類型的屬性對象或JavaBean類型的屬性對象的屬性。
例:
<jsp:useBean id="user" class="cn.web.User" scope="page"/>
<c:set target="${user}"property="password" value="123456"/>
<c:set var="username"value="張三" scope="session"/>
用戶名:<c:out value="${user.username}"/><br/>
Value; 用於指定屬性值 var : 用於指定要設置的Web域屬性的名稱
Target : 用於指定要設置屬性的對象,這個對象必須是JavaBean對象或java.util.Map對象
property : 用於指定當前要爲對象設置的屬性名稱
<c:remove>標籤 : 用於刪除各類Web域中的屬性。
例: <% request.setAttribute("name", "哈哈哈"); %>
<c:remove var="name"/> var : 表示須要刪除的屬性名
用戶名:<c:out value="${name}"/> 輸出爲空白字符串 「」
<c:catch>標籤:用於捕獲嵌套在標籤體中的內容拋出的異常
例:
<%try{
int a = 10/0;
}catch(Exception e)
{
e.printStackTrace();
}%>
<c:catch var="exce">
<% int a = 10/0;%>
</c:catch>
<c:out value="${exce.message}"/>
<c:if test=「」>標籤 :能夠構造簡單的「if-then」結構的條件表達式
Test : 表示決定是否處理標籤體中的內容的條件表達式
var :用於指定將test屬性的執行結果保存到某個Web域中的某個屬性的名稱
<c:forEach>標籤:用於對一個集合對象中的元素進行循環迭代操做,或者按指定的次數重複迭代執行標籤體中的內容。
Var : 指定將當前迭代到的元素保存到page這個Web域中的屬性名稱
items : 將要迭代的集合對象
VarStatus : 指定將表明當前迭代狀態信息的對象保存到page這個Web域中的屬性名稱
begin : 若是指定items屬性,就從集合中的第begin個元素開始進行迭代,begin的索引值從0開始編號;若是沒有指定items屬性,就從begin指定的值開始迭代,直到end值時結束迭代 .
Step: 指定迭代的步長,即迭代因子的迭代增量(默認爲1)
<c:param>標籤
在JSP頁面進行URL的相關操做時,常常要在URL地址後面附加一些參數。<c:param>標籤能夠嵌套在<c:import>、<c:url>或<c:redirect>標籤內,爲這些標籤所使用的URL地址附加參數。<c:param>標籤在爲一個URL地址附加參數時,將自動對參數值進行URL編碼,例如,若是傳遞的參數值爲「中國」,則將其轉換爲「%d6%d0%b9%fa」後再附加到URL地址後面,這也就是使用<c:param>標籤的最大好處。
http://localhost:808/servlet/MyServlet?name=「中國」
示例:<c:param name=「name」 value=「中國" />
<c:url>標籤:用於在JSP頁面中構造一個URL地址,其主要目的是實現URL重寫。URL重寫就是將會話標識號以參數形式附加在URL地址後面
例:
<body>
<a href='/day18/result.jsp?name=<%=URLEncoder.encode("中文","UTF-8")%>'>
傳中文(腳本版)
</a>
<hr/>
<c:url value="/result.jsp"var="myURL">
<c:param name="name" value="中文"/>
</c:url>
<a href="${myURL}">
傳中文(標籤版)
</a>
</body>
Value ; 指定要構造的URL,/表示dayXX(web工程名)
Var:指定將構造出的URL結果保存到Web域中的屬性名稱
Scope: 指定將構造出的URL結果保存到哪一個Web域中
<c:redirect>標籤:用於將當前的訪問請求轉發或重定向到其餘資源,它能夠根據url屬性所指定的地址,執行相似<jsp:forward>這個JSP標準標籤的功能,將訪問請求轉發到其餘資源;或執行response.sendRedirect()方法的功能,將訪問請求重定向到其餘資源。
例:<c:redirect url="/c_forEach.jsp"/>
url : 指定要轉發或重定向到的目標資源的URL地址
JSTL自定義標籤:
a.配置*.tld文件。
b.定義一個類繼承SimpleTagSupport,重寫doTag()方法。
c.經過jsp頁面輸出到瀏覽器。
d.
EL 全名爲ExpressionLanguage
EL表達式主要用於替換JSP頁面中的腳本表達式,以從各類類型的web域中檢索java對象、獲取數據。(某個web域中的對象,訪問javabean的屬性、訪問list集合、訪問map集合、訪問數組)
獲取路徑如: myday8(web應用工程名) ${pageContext.request.contextPath}
<a href="${pageContext.request.contextPath}/jstl/froeach.jsp">
下載
</a>
EL表達式語言中定義了11個隱含對象,
語法:${隱式對象名稱} :得到對象的引用
pageContext 對應於JSP頁面中的pageContext對象(注意:取的是pageContext對象。)
pageScope 表明page域中用於保存屬性的Map對象
requestScope 表明request域中用於保存屬性的Map對象
sessionScope 表明session域中用於保存屬性的Map對象
applicationScope 表明application域中用於保存屬性的Map對象\
param 表示一個保存了全部請求參數的Map對象
paramValues
表示一個保存了全部請求參數的Map對象,它對於某個請求參數,返回的是一個string[],從0開始
${paramValues.like[0]}
header 表示一個保存了全部http請求頭字段的Map對象
headerValues
同上,返回string[]數組。注意:若是頭裏面有「-」 ,例Accept-Encoding,則要headerValues[「Accept-Encoding」]
cookie 表示一個保存了全部cookie的Map對象
initParam 表示一個保存了全部web應用初始化參數的map對象
測試headerValues時,若是頭裏面有「-」 ,例Accept-Encoding,則要headerValues[「Accept-Encoding」]
測試cookie時,例${cookie.key}取的是cookie對象,如訪問cookie的名稱和值,須${cookie.username.name}或${cookie.username.value}
new Cookie(「username」,」jack」);
EL自定義函數開發:
步驟:
1.編寫一個Java類的靜態方法。
2.編寫標籤庫描述符(tld)文件,在tld文件中描述自定義函數,在WEB-INF/目錄下。
3.在JSP頁面中導入和使用自定義函數。
4. 編寫完標籤庫描述文件後,須要將它放置到<web應用>\WEB-INF目錄中或WEB-INF目錄下的除了classes和lib目錄以外的任意子目錄中。
5. TLD文件中的<uri>元素用指定該TLD文件的URI,在JSP文件中須要經過這個URI來引入該標籤庫描述文件。
6. <function>元素用於描述一個EL自定義函數,其中:
<name>子元素用於指定EL自定義函數的名稱。
<function-class>子元素用於指定完整的Java類名。
<function-signature>子元素用於指定Java類中的靜態方法的簽名,方法簽名必須指明方法的返回值類型及各個參數的完整類型,各個參數之間用逗號分隔。
*.TLD:文件配置
1)寫一個普通類,無需擴展類或現實接口
publicstatic String filter(String message) {}
2)在WEB-INF/目錄下寫一個*.tld文件,目的是通知Web服務器有一個自定義函數,在部署時通知
<tlib-version>1.0</tlib-version>(函數的版本號)
<short-name>el</short-name>(函數的前綴名)
<uri>http://java.sun.com/jsp/jstl/el</uri>(函數來自到哪裏)
<function>
<name>filterString</name>(在JSP頁面中出現的函數名)
<function-class>cn.itcast.web.jsp.el.FilterFunction</function-class>(函數對應的處理類全路徑)
<function-signature>java.lang.Stringfilter(java.lang.String)</function-signature>
(處理類中函數的簽名,引用類型須要使用全路徑,基本類型不須要全路徑名)
</function>
3)在JSP中引用函數
<%@ pagelanguage="java" pageEncoding="UTF-8"%>
<%@ tagliburi="http://java.sun.com/jsp/jstl/el" prefix="el" %>
<!DOCTYPE HTMLPUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<body>
${el:filterString("<a href='#'>點點</a>")}<br/>
</body>
</html>
JSP-國際化
i18n:internationalization
建立資源包和資源文件:
1.中文、英文環境相對應的資源文件名則爲:
「myproperites_zh_CN.properties」
「myproperites_en_US.properties」
2.實現方式:
ResourceBundle類提供了一個靜態方法getBundle,該方法用於裝載資源文件,並建立ResourceBundle實例:
Locale currentLocale = Locale.getDefault();
ResourceBundle myResources =
ResourceBundle.getBundle(basename, currentLocale);
basename爲資源包基名(且必須爲完整路徑)。
若是與該locale對象匹配的資源包子類找不到。通常狀況下,則選用默認資源文件予以顯示。
加載資源文件後,程序就能夠調用ResourceBundle 實例對象的 getString 方法獲取指定的資源信息名稱所對應的值。
Stringvalue = myResources.getString(「key");
3.國際化標籤:
<%@taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
<fmt:setLocale value=「${pageContext.request.locale}」/>(頁面的Locale)
<fmt:setBundle basename=「cn/itcast/web/jsp/config/hello」/>(資源文件基名)
<fmt:message
key=「itcast.hello」>(資源文件key)
<fmt:param>
value=「itcast.name」/>(資源文件佔位符)
設置POST請求消息的字符集編碼
<fmt:requestEncodingvalue="UTF-8"/>
動態數據的國際化:
使用的包java.util 包和java.text 包
Locale 類
Locale 實例對象表明一個特定的地理,政治、文化區域。
DateFormat類能夠將一個日期/時間對象格式化爲表示某個國家地區的日期/時間字符串,項目中不提倡用Date類型,能夠使用Calendar類, 它還定義了一些用於描述日期/時間的顯示模式的 int 型的常量,包括FULL, LONG, MEDIUM, DEFAULT, SHORT,實例化DateFormat對象時,能夠使用這些常量,控制日期/時間的顯示長度
實例化DateFormat類方式
getDateInstance(intstyle, Locale aLocale):以指定的日期顯示模式和本地信息來得到DateFormat實例對象,該實例對象不處理時間值部分。
getTimeInstance(int style, Locale aLocale):以指定的時間顯示模式和本地信息來得到DateFormat實例對象,該實例對象不處理日期值部分。
getDateTimeInstance(int dateStyle, int timeStyle, Locale aLocale):以單獨指定的日期顯示模式、時間顯示模式和本地信息來得到DateFormat實例對象。
2.DateFormat對象的方法:
format:將日期/時間對象格式化爲符合某個本地環境習慣的字符串。
parse:將符合某個本地環境習慣的日期/時間字符串解析爲日期/時間對象
注意:parse和format徹底相反,一個是把date時間轉化爲相應地區和國家的顯示樣式,一個是把相應地區的時間日期轉化成date對象,該方法在使用時,解析的時間或日期要符合指定的國家、地區格式,不然會拋異常
國際化標籤:
<jsp:useBean id="time"class="java.util.Date" scope="page"/>
中國:
<fmt:formatDatevalue="${time}" type="both" dateStyle="Full"timeStyle="default" timeZone="GMT+08:00"/>
美國:
<fmt:formatDatevalue="${time}" type="both" dateStyle="Full"timeStyle="default" timeZone="GMT-06:00"/>
NumberFormat類
NumberFormat 能夠將一個數值格式化爲符合某個國家地區習慣的數值字符串,也能夠將符合某個國家地區習慣的數值字符串解析爲對應的數值
方法:
getIntegerInstance(Localelocale):以參數locale對象所標識的本地信息來得到處理整數的NumberFormat實例對象
getCurrencyInstance(Localelocale):以參數locale對象所標識的本地信息來得到處理貨幣的NumberFormat實例對象
getPercentInstance(Localelocale):以參數locale對象所標識的本地信息來得到處理百分比數值的NumberFormat實例對象
國際化標籤:
<body>
將字符串轉成整型: <fmt:formatNumber type="number" value="3.555" pattern=".0"/>
<hr/>
將字符串轉成貨幣: <fmt:formatNumber type="currency"value="3.555"/>
<hr/>
將字符串轉成百分比:<fmt:formatNumber type="percent"value="3.555"/>
<hr/>
</body>
文件上傳概述:
如何在web頁面中添加上傳輸入項?
<input type=「file」>標籤用於在web頁面中添加文件上傳輸入項,設置文件上傳輸入項時須注意:
一、必需要設置input輸入項的name屬性,不然瀏覽器將不會發送上傳文件的數據。
2、必須把form的enctype屬值設爲multipart/form-data.設置該值後,瀏覽器在上傳文件時,將把文件數據附帶在http請求消息體中,並使用特定的格式對上傳的文件進行描述,以方便接收方對上傳數據進行解析和處理。
實現步驟
1、建立DiskFileItemFactory對象,設置緩衝區大小和臨時文件目錄
2、使用DiskFileItemFactory 對象建立ServletFileUpload對象,並設置上傳文件的大小限制。
3、調用ServletFileUpload.parseRequest方法解析request對象,獲得一個保存了全部上傳內容FileItem的List對象。
4、對list進行迭代,每迭代一個FileItem對象,調用其isFormField方法判斷是不是上傳文件
爲普通表單字段,則調用getFieldName、getString方法獲得字段名和字段值
爲上傳文件,則調用getName、 getInputStream方法獲得數據輸入流,從而讀取上傳數據。
須要使用的類和方法:
1.DiskFileItemFactory是建立 FileItem 對象的工廠,這個工廠類經常使用方法:
public voidsetSizeThreshold(int sizeThreshold) 設置內存緩衝區的大小,默認值爲10K。當上傳文件大於緩衝區大小時, fileupload組件將使用臨時文件緩存上傳文件。
public void setRepository(java.io.File repository) 指定臨時文件目錄,默認值爲System.getProperty("java.io.tmpdir").
2.ServletFileUpload 負責處理上傳的文件數據,並將表單中每一個輸入項封裝成一個 FileItem 對象中。經常使用方法有:
booleanisMultipartContent(HttpServletRequest request)判斷上傳表單是否爲multipart/form-data類型
List parseRequest(HttpServletRequest request)解析request對象,並把表單中的每個輸入項包裝成一個fileItem 對象,並返回一個保存了全部FileItem的list集合。
setHeaderEncoding(java.lang.String encoding)
設置編碼格式,解決上傳中文名文件的問題
3.中文文件名亂碼問題
文件名中文亂碼問題,可調用ServletFileUpload的setHeaderEncoding方法,或者設置request的setCharacterEncoding屬性
4.臨時文件的刪除問題
因爲文件大小超出DiskFileItemFactory.setSizeThreshold方法設置的內存緩衝區的大小時,commons-fileupload組件將使用臨時文件保存上傳數據,所以在程序結束時,務必調用FileItem.delete方法刪除臨時文件。
delete方法的調用必須位於流關閉以後,不然會出現文件佔用,而致使刪除失敗的狀況。
Filter: 過濾器
1)Filter是位於服務器中,用於攔截客戶端和Web資源之間的訪問
2)Filter能夠客戶端訪問的Web資源做預先處理,若是符合要求,則將請求交給Web資源;若是不符合要求,則不將請求交給Web資源,相似於一個判段角色
3)將Web請求返回時,也會通過Filter,此時能夠經過Filter對該請求作後備處理
Filter開發分爲二個步驟:
1.編寫java類實現Filter接口,並實現其doFilter方法。
2.在 web.xml 文件中使用<filter>和<filter-mapping>元素對編寫的filter類進
行註冊,並設置它所能攔截的資源。
Filter鏈:
1.在一個web應用中,能夠開發編寫多個Filter,這些Filter組合起來稱之爲一個Filter鏈。
2.web服務器根據Filter在web.xml文件中的註冊順序,決定先調用哪一個Filter,當第一個Filter的doFilter方法被調用時,web服務器會建立一個表明Filter鏈 FilterChain對象傳遞給該方法。在doFilter方法中,開發人員若是調用了FilterChain對象的doFilter方法,則web服務器會檢查FilterChain對象中是否還有filter,若是有,則調用第2個filter,若是沒有,則調用目標資源。
Filter生命週期
1)Filter是一個單例的,每一個用戶訪問的都是同一個Filter過濾器實例
2)防止線程安全問題,線程安全有三要素
>>單例
>>實例變量
>>對實例變量的更新操做
若是以上三個問題[同時]知足,就要用"加鎖"來解決
3)部署Web應用時,執行空參構造方法(),再執行初始化方法
第一,二,N次請求,執行doFilter()方法,
當從新部署web應用時,由web服務器先銷燬原Filter實例,在銷燬[以前]執行destory()方法,而後當即建立新的Filter實例。
4)注意:過濾器,是不可以直接訪問的
FilterConfig接口
1.在配置filter時,能夠使用<init-param>爲filter配置一些初始化參數,當web容器實例化Filter對象,調用其init方法時,會把封裝了filter初始化參數的filterConfig對象傳遞進來。所以開發人員在編寫filter時,經過filterConfig對象的方法,就可得到:
String getFilterName():獲得filter的名稱。
String getInitParameter(String name): 返回在部署描述中指定名稱的初始化參數的值。若是不存在返回null.
Enumeration getInitParameterNames():返回過濾器的全部初始化參數的名字的枚舉集合。
public ServletContext getServletContext():返回Servlet上下文對象的引用。
Filter常見應用
1. 禁止瀏覽器緩存全部動態頁面的過濾器:
response.setDateHeader("Expires",-1); Expires數據頭:值爲GMT時間值,爲-1指瀏覽器不要緩存頁面
response.setHeader("Cache-Control","no-cache");
response.setHeader("Pragma","no-cache");
Cache-Control響應頭有兩個經常使用值:
no-cache指瀏覽器不要緩存當前頁面。
max-age:xxx指瀏覽器緩存頁面xxx秒
Filter的部署—映射Filter
1.<filter-mapping>元素用於設置一個 Filter 所負責攔截的資源。
2.一個Filter攔截的資源可經過兩種方式來指定:Servlet名稱和資源訪問的請求路徑
3.<filter-name>子元素用於設置filter的註冊名稱。該值必須是在<filter>元素中
明過的過濾器的名字
4.<url-pattern>設置 filter 所攔截的請求路徑(過濾器關聯的URL樣式)
5.<servlet-name>指定過濾器所攔截的Servlet名稱。
6.<dispatcher>指定過濾器所攔截的資源被 Servlet 容器調用的方式,能夠是REQUEST,INCLUDE,FORWARD和ERROR之一,默認REQUEST。用戶能夠設置多個<dispatcher> 子元素用來指定 Filter 對資源的多種調用方式進行攔截
1 映射Filter的細節
1)在默認狀況下,Filter只過濾用戶直接請求的Web資源,例如在地欄直接訪問,重定向,超連接。
除此以外,不會被過濾,例如:轉發
Filter映射有四個種方式
>>REQUEST:默認(地欄直接訪問,重定向,超連接)
>>FORWARD:專用於Web資源之間的轉發
>>INCLUDE:專用於Web資源之間的包含
>>ERROR:專用於Web資源的[出錯]狀況,一般不單獨使有,要配REQUEST/FORWARD/INCLUDE使用
若是沒有出錯,ERROR不會執行,項目中能夠使用單獨的ERROR過濾器
注意:ERROR過濾方式,須要適合在web.xml文件中的全局錯誤聲明
3)一旦在<filter-mapping>中顯示配置<dispatcher>,那麼默認不會存在,相似於空參構造方法
裝飾設計模式
1)當一個類的某個或某些方法不能知足應用的需求,此時能夠繼承該類,重寫對應的方法,前提是該類非final類型
2)裝飾設計模式主要運用在對某個不知足應用需求的類的方法而產生的
3)開發步驟:
>>普通類繼承須要被裝飾的類,例如:BufferedReader,哪一個類的方法不知足需求,該類就叫作須要被裝飾的類
>>用實例變量的方式記住須要被裝飾的類
>>經過構造方式爲實例變量覆值
>>爭對不知足需求的方法重寫
>>對於知足需求的方法,直接調用須要被裝飾的類的相關方法[可省]
4 總結Servlet和Filter
1)Servlet和Filter是一個互補的技術
2)Servlet比較適合作核心的業務控制
Filter比較適合作預先處理後後備處理
3)Servlet和Filter在細粒度分層結構中,位於控制層,能夠調用業務層
Servlet監聽器
監聽的事件源分別爲 ServletContext,HttpSession 和 ServletRequest 這三個域對象
監聽器劃分爲三種類型。
監聽三個域對象建立和銷燬的事件監聽器
監聽域對象中屬性的增長和刪除的事件監聽器
監聽綁定到HttpSession域中的某個對象的狀態的事件監聽器。
監聽ServletContext域對象建立和銷燬
1.ServletContextListener接口用於監聽 ServletContext 對象的建立和銷燬事件。
2.當 ServletContext 對象被建立時,激發contextInitialized(ServletContextEvent sce)方法
當 ServletContext 對象被銷燬時,激發contextDestroyed(ServletContextEvent sce)方法。
3.和編寫其它事件監聽器同樣,編寫servlet監聽器也須要實現一個特定的接口,並針對相應動做覆蓋接口中的相應方法。
4.和其它事件監聽器略有不一樣的是,servlet監聽器的註冊不是直接註冊在事件源上,而是由web容器負責註冊,開發人員只需在web.xml文件中使用<listener>標籤配置好監聽器,web容器就會自動把監聽器註冊到事件源中(即:經過反射機制)。
5.一個 web.xml 文件中能夠配置多個Servlet 事件監聽器,web 服務器按照它們在 web.xml 文件中的註冊順序來加載和註冊這些 Serlvet 事件監聽器。
ServletContext事件源
建立初始化銷燬:ServletContextListener
屬性變化:ServletContextAttributeListener
什麼時候產生:部署Web應用時
什麼時候銷燬:從新部署Web應用時,或Web服務器中止再從新啓動
3)ServletRequest事件源
建立初始化銷燬:ServletRequestListener
屬性變化:ServletRequestAttributeListener
什麼時候產生:同一個客戶端第一次請求會產生一個ServletRequest,該客戶端隨後屢次請求,都是同一個ServletRequest對象別一個客戶端訪問,會產生不一樣的ServletRequest對象
什麼時候數據銷燬:每次請求的數據不能被第二次請求共享,只能在當次請求中取得數據,這也是爲何重定向狀況下,request域中的數據不能共享的緣由屢次請求request域中的數據不共享
4)HttpSession事件源
建立銷燬:HttpSessionListener
屬性變化:HttpSessionAttributeListener
什麼時候產生:新會話,首次訪問jsp;在原會話中,屢次請求,不會建立新HttpSession
當關閉瀏覽器後,不會銷燬原HttpSession
什麼時候銷燬:
>>在web.xml文件中,配置HttpSession的有效生命時間,當有效生命時間完成後,Web服務器會依次刪除位於Web服務器中的HttpSession,可是刪除的時間不精確
>>自已定義一個HttpSession掃描器,來較精確的控制HttpSession的銷燬時間
>>當session.invalidate()方法執行時,會被執行attributeRemoved()和sessionDestroyed()
>>當session.removeAttribute()方法執行時,會被執行attributeRemoved()
Session 綁定的事件監聽器
保存在 Session 域中的對象能夠有多種狀態:綁定到 Session 中;從 Session 域中解除綁定;隨 Session 對象持久化到一個存儲設備中[鈍化];隨 Session 對象從一個存儲設備中恢復[激活]
Servlet 規範中定義了兩個特殊的監聽器接口來幫助 JavaBean 對象瞭解本身在 Session 域中的這些狀態:HttpSessionBindingListener接口和HttpSessionActivationListener接口 ,實現這兩個接口的類不須要 web.xml 文件中進行註冊,由於事件源和監聽器都是JavaBean自身
實現了HttpSessionBindingListener接口的JavaBean 對象能夠感知本身被綁定到 Session 中和從 Session 中刪除的事件
當對象被綁定到HttpSession 對象中時,web 服務器調用該對象的 void valueBound(HttpSessionBindingEventevent) 方法
當對象從HttpSession 對象中解除綁定時,web 服務器調用該對象的 voidvalueUnbound(HttpSessionBindingEvent event)方法
HttpSessionActivationListener接口
實現了HttpSessionActivationListener接口的JavaBean 對象能夠感知本身被激活和鈍化的事件
當綁定到HttpSession 對象中的對象將要隨 HttpSession 對象被鈍化以前,web 服務器調用以下方法sessionWillPassivate(HttpSessionBindingEventevent) 方法
當綁定到HttpSession 對象中的對象將要隨 HttpSession 對象被活化以後,web 服務器調用該對象的void sessionDidActive(HttpSessionBindingEvent event)方法
案例1:手動銷燬session
public class MyservletHttpSession implements HttpSessionListener, ServletContextListener{
private List<HttpSession> sessionlist = newArrayList<HttpSession>();
private Timer timer= new Timer();
public voidsessionCreated(HttpSessionEvent arg0) {
System.out.println("session的建立");
//獲取每一個用戶的session域對象
HttpSession session = arg0.getSession();
//獲取每個回話的id
String id = session.getId();
//查看session的建立時間
System.out.println(id+","+ newDate(session.getCreationTime()));
synchronized (MyservletHttpSession.class) {
//將用戶的session加入集合中
sessionlist.add(session);
}
}
public voidsessionDestroyed(HttpSessionEvent arg0) {
System.out.println("session的銷燬");
HttpSession session = arg0.getSession();
//獲取每個回話的id
String id = session.getId();
//查看session的銷燬時間
System.out.println(id+","+ new Date().toLocaleString());
}
public voidcontextInitialized(ServletContextEvent arg0) {
//初始化定時器
timer.schedule(new MyTimer(sessionlist),5000,1000);
}
public voidcontextDestroyed(ServletContextEvent arg0) {
}
}
//定時器類(做用:每一個1分鐘在集合中查找session一次,並判斷session的建立時間與當前時間只差是否大於1分鐘,大於1分鐘,銷燬session)
class MyTimer extends TimerTask
{
private List<HttpSession> sessionlist;
public MyTimer(List<HttpSession> sessionlist){
this.sessionlist =sessionlist;
}
public void run() {
if(sessionlist.size()>0)
{
synchronized (MyservletHttpSession.class) {
//迭代取出集合中的每個HttpSession
Iterator<HttpSession> it = sessionlist.iterator();
while(it.hasNext())
{
HttpSession session = it.next();
//獲取session的最後一次的訪問時間
long end = session.getLastAccessedTime();
//獲取當前時間
long currnet = System.currentTimeMillis();
//判斷session的存儲時間,若是大於1分鐘,即銷燬該session
long result = currnet-end;
if(result>5000)
{
it.remove();
//銷燬session
session.invalidate();
}
}
}
}
}
}
案例2: ServletContextListener
//建立表
public class SystemDao {
public void createTable() throws SQLException
{
String sql = "create table if not exists systemdao(idint primary key auto_increment,name varchar(20) not null)";
QueryRunner runner = new QueryRunner(C3P0Util.getDataSource());
runner.update(sql);
}
public void updateTable() throws SQLException
{
String sql = "update systemdao set name ='你好' where id=1";
QueryRunner runner = new QueryRunner(C3P0Util.getDataSource());
runner.update(sql);
}
public void dropTable() throws SQLException
{
String sql = "drop table if exists systemdao";
QueryRunner runner = new QueryRunner(C3P0Util.getDataSource());
runner.update(sql);
}
public void insertTable() throws SQLException
{
String sql = "insert into systemdao(name) value('呵呵')";
QueryRunner runner = new QueryRunner(C3P0Util.getDataSource());
runner.update(sql);
}
}
測試類: SystemListener
public class SystemListener implements ServletContextListener {
private Timer timer = new Timer();
public void contextInitialized(ServletContextEventarg0) {
//啓動定時器
timer.schedule(new TimerTask(){
public void run() {
DateFormat dataformat = DateFormat.getDateTimeInstance(DateFormat.FULL,DateFormat.DEFAULT,Locale.CHINA);
String time = dataformat.format(new Date());
System.out.println(time);
}
}, 5000, 1000);
//建立表進行數據的初始化
SystemDao dao = new SystemDao();
try {
dao.createTable();
dao.insertTable();
dao.updateTable();
} catch (SQLException e) {
e.printStackTrace();
}
}
public void contextDestroyed(ServletContextEventarg0) {
SystemDao dao = new SystemDao();
try {
//刪除表
dao.dropTable();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
Base64編碼
BASE64Encoderencoder = new BASE64Encoder();
加密:
encoder.encode(username.getBytes());
encoder.encode(password.getBytes());
Base64解碼
BASE64Decoderdecoder = new BASE64Decoder();
解密:
new String(decoder.decodeBuffer(username))
new String(decoder.decodeBuffer(password))
案例1: 加密和解密
//BASE64加密和解密過程
public class Demo1 {
public static void main(String[] args) throws IOException {
String username = "bbb";
String password = "123456";
//加密
BASE64Encoder encoder = new BASE64Encoder();
String usrename64 =encoder.encode(username.getBytes());
String password64 =encoder.encode(password.getBytes());
System.out.println(usrename64);
System.out.println(password64);
//解密
BASE64Decoder decoder = new BASE64Decoder();
byte[] name = decoder.decodeBuffer(usrename64);
byte[] pass = decoder.decodeBuffer(password64);
System.out.println(new String(name));
System.out.println(new String(pass));
}
}
案例2:使用cookie存儲用戶信息
public class CookieBASE64Servletextends HttpServlet {
public void doGet(HttpServletRequestrequest, HttpServletResponse response)
throws ServletException, IOException {
/* Stringusername = "李四";
//加密,cookie中所存儲的中文只能是以base64進行加密和解密
BASE64Encoder encoder = newBASE64Encoder();
username =encoder.encode(username.getBytes());
//建立cookie
Cookie cookie = new Cookie("username",username);
//設置cookie的存活時間
cookie.setMaxAge(1*60*60);
//將cookie寫入瀏覽器中
response.addCookie(cookie);
*/
//取出cookie
Cookie[] cookies = request.getCookies();
Cookie newCookie = null;
for(Cookie cookie : cookies)
{
if(cookie.getName().contains("username"))
{
newCookie = cookie;
}
}
if(newCookie!=null)
{ //獲取cookie的名字
String name = newCookie.getName();
String value = newCookie.getValue();
//解密
BASE64Decoder decoder = new BASE64Decoder();
byte[] buf = decoder.decodeBuffer(value);
System.out.println(name +":"+ new String(buf));
}
}
}
案例3:使用文件存儲用戶信息
public class Demo2 {
//將用戶信息加密後寫入文件中
public static void main(String[] args) throws Exception {
File file = new File("e:/base64.text");
//FileOutputStream有自動建立文件的功能
FileOutputStream out= new FileOutputStream(file);
PrintWriter pw = new PrintWriter(out);
pw.write("username=哈哈\r\n");
pw.write("password=123456");
pw.flush();
pw.close();
}
}
JavaMail開發
1.郵件服務器:要在Internet上提供電子郵件功能,必須有專門的電子郵件服務器
2. 電子郵箱: 電子郵箱(E-mail地址)的得到須要在郵件服務器上進行申請 ,確切地說,電子郵箱其實就是用戶在郵件服務器上申請的一個賬戶。
郵件傳輸協議和郵件服務器類型
1.SMTP協議(SimpleMail Transfer Protocol): 一般咱們也把處理用戶smtp請求(郵件發送請求)的郵件服務器稱之爲SMTP服務器。(25端口)
2.POP3協議POP3(PostOffice Protocol 3): 一般咱們也把處理用戶pop3請求(郵件接收請求)的郵件服務器稱之爲POP3服務器。(110端口)
SMTP協議
WindowXP平臺下,進入cmd命令狀態:
------------------------------------aaa@zhaojun.com向bbb@zhaojun.com手工發送郵件步驟:
相同域:
telnet 127.0.0.1 25 (SMTP服務器固定端口號)<回車>
ehlo 用戶名/可任意 <回車\r\n>
auth login <回車>通過base64編碼後的用戶名和密碼
YWFh 通過Base64加密後的用戶名aaa<回車>
MTIzNDU2 通過Base64加密後的密碼123456<回車>
mail from:<aaa@wang.com> <回車>
rcpt to:<bbb@wang.com> <回車>
data <回車>
from:aaa@wang.com <回車>
to:bbb@wang.com <回車>
subject:test <回車>
Hello! How are you doing! <回車> 發送的內容
. <回車>點號表明郵件內容的結束
quit <回車> 退出
POP3協議
------------------------------------bbb@zhaojun.com手工接收郵件
相同域
telnet 127.0.0.1 110 (POP3服務器固定端口號)<回車>
user bbb <回車>
pass 123456 <回車>
stat <回車> 返回郵箱的統計信息(字節數)
list 2 <回車> 返回某一封郵件的統計信息
retr 1 <回車>
quit <回車>
JavaMail經常使用API
1)MimeMessagemessage = new MimeMessage(Session.getDefaultInstance(new Properties()));
Session表示發送到郵件服務器的相關屬性<後面繼續講>
2)message.setFrom(new InternetAddress("aaa@zhaojun.com"));
3)message.setRecipient(RecipientType.TO,newInternetAddress("bbb@zhaojun.com"));
4)message.setSubject("bbs");
5)message.setContent("郵件內容","text/html;charset=ISO8859-1");
6)message.writeTo(new FileOutputStream("d:/demo1.eml"));
7)DataHandler dh= new DataHandler(newFileDataSource("src/cn/itcast/web/config/photo.jpg"));
讀取附件或圖片
8)圖片:image.setContentID("imageAID");設置編號
9)附件:append.setFileName(dh.getName());設置附件的名字
10)MimeMultipartmm = new MimeMultipart();
11)mm.addBodyPart(text);
12)mm.setSubType("related");只適合於文本+圖片,不限文本和圖片的數量
mm.setSubType("mixed");只適合到文本+附件,不限文本和附件的數量
13)message.setContent(mm);必定要將關係設置到郵件中,不然郵件就是空郵件
5 建立簡單郵件
>>直接在message對象中設置內容,即MimeMessage.setContent()
6 建立複雜郵件
>>一封郵件有多少個部分組成,就有多少個BodyPart
>>無論是文本前,仍是圖片,最終加入到MimeMultipart關係中的順序必定是:[文本先,圖片後],關係名字叫"related"
>>圖片設置編號,附件設置名字
>>無論是文本前,仍是附件前,最終加入到MimeMultipart關係中的順序[任意],關係名字叫"mixed"
案例1:
//JAVAMail建立郵件
public class MessageMail {
public static void main(String[] args) throws Exception{
//建立一個郵件
MimeMessage message = new MimeMessage(Session.getInstance(new Properties()));
//設置mail: from
message.setFrom(new InternetAddress("bbb@wang.com"));
//設置mail: to
message.setRecipient(RecipientType.TO, new InternetAddress("ahha@wang.com"));
//設置發送發送方式 cc,bcc
message.setSubject("cc");
//設置發送的內容
message.setContent("<font color='red'>建立一個郵件</font>","text/html;charset=UTF-8");
//將內存中的message寫入硬盤中
message.writeTo(new FileOutputStream(new File("e:/mail.eml")));
}
}
案例2.
//建立複雜郵件(文本+圖片)
public class Demo2 {
public static void main(String[] args)throws Exception {
MimeMessage message = new MimeMessage(Session.getDefaultInstance(new Properties()));
message.setFrom(new InternetAddress("aaa@zhaojun.com"));
message.setRecipient(RecipientType.TO,new InternetAddress("bbb@zhaojun.com"));
message.setSubject("text+img");
//文本
MimeBodyPart text = new MimeBodyPart();
text.setContent("<imgsrc='cid:imageBID'><br/>this is aphoto<br/><imgsrc='cid:imageAID'><br/>","text/html;charset=ISO8859-1");
//圖片A
MimeBodyPart imageA = new MimeBodyPart();
//採用類去加載圖片
DataHandler dh = new DataHandler(new FileDataSource("src/cn/itcast/web/config/photo.jpg"));
//設置圖片加載器爲DataHandler
imageA.setDataHandler(dh);
//設置圖片的編碼,該編號是整個郵件中的惟一標識符
imageA.setContentID("imageAID");
//圖片B
MimeBodyPart imageB = new MimeBodyPart();
//採用類去加載圖片
dh = new DataHandler(new FileDataSource("src/cn/itcast/web/config/zgl.jpg"));
//設置圖片加載器爲DataHandler
imageB.setDataHandler(dh);
//設置圖片的編碼,該編號是整個郵件中的惟一標識符
imageB.setContentID("imageBID");
//設置文本和圖片的關係,MimeMultipart相關於他們的關係,相似於容器
MimeMultipart mm = new MimeMultipart();
//將文本和圖片加入到關係中
mm.addBodyPart(text);//文本
mm.addBodyPart(imageA);//圖片A
mm.addBodyPart(imageB);//圖片B
mm.setSubType("related");
//設置郵件的內容
message.setContent(mm);
//將郵件輸出到硬盤
message.writeTo(new FileOutputStream("d:/demo2.eml"));
}
}
RFC822文檔規定了如何編寫一封簡單郵件
郵件頭和郵件體,二者使用空行分隔
郵件頭
from字段
to字段
subject字段
cc、bcc字段
郵件體
郵件內容
建立郵件—— MIME協議
1.JavaMail經常使用API
//發送郵件採用的協議(小寫smtp)
props.put("mail.transport.protocol","smtp");
//發送到哪臺郵件服務器的IP地址
props.put("mail.host","192.168.10.176");
>>Sessionsession = Session.getDefaultInstance(props);
>>Transport transport =session.getTransport();
>>transport.connect("aaa@zhaojun.com","123456");
>>transport.send(messsage);
>>transport.close();
發送郵件步驟:
1,建立properties Properties p = new Properties()
2.設置發送郵件的協議:
p.put("mail.transport.protocol", "smtp");
p.put("mail.host", "127.0.0.1");
3.建立session 對象: Session session =Session.getInstance(p)
4.創建鏈接:
Transport transport = session.getTransport();
transport.connect("1057718341@qq.com", "123456");
5.發送郵件 : 建立郵件
5.1 :建立郵件 : MimeMessage message = new MimeMessage(session)
5.2:設置郵件的 from , to ,主題,內容(設置編碼方式)
message.setFrom(new InternetAddress("1057718341@qq.com"));
message.setRecipient(RecipientType.TO,new InternetAddress(email));
message.setSubject("歡迎光臨");
message.setContent("註冊成功碼:","text/html;charset=UTF-8");
6.發送: transport.send(message);
7.關閉資源: transport.close();
例:
public class MailUtil {
public static void send(String username, String password,String email) throws Exception { //建立properties
Properties p = new Properties();
//設置發送郵件的協議
p.put("mail.transport.protocol", "smtp");
p.put("mail.host", "127.0.0.1");
//建立session
Session session = Session.getInstance(p);
//創建鏈接
Transport transport = session.getTransport();
transport.connect("1057718341@qq.com", "123456");
//發送郵件
Message message = cteateMessage(session,username, password,email);
transport.send(message);
transport.close();
}
public static MessagecteateMessage(Session session,String username, String password, String email) throws Exception, MessagingException
{ //建立郵件
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress("1057718341@qq.com"));//158409270@163.com
message.setRecipient(RecipientType.TO, new InternetAddress(email));
message.setSubject("歡迎光臨");
message.setContent("註冊成功<br/>用戶名:"+username+"<br/>密碼:"+password+"<br/>郵箱:"+email, "text/html;charset=UTF-8");
return message;
}
}
例: MD5: 加密和解密
public class Md5Util {
private static String[] hex = { "0", "1", "2", "3", "4", "5", "6", "7",
"8", "9", "A", "B", "C", "D", "E", "F" };
public static String encoder(Stringpassword) throws Exception {
//建立MD5加密
MessageDigest md5 =MessageDigest.getInstance("md5");
// 將原碼進行加密
byte[] byteArray =md5.digest(password.getBytes());
// 將字節轉換爲十六進制數
String passwordMD5 =byteArrayToString(byteArray);
return passwordMD5;
}
// 將byte[]數組轉換爲Stirng類型
private static String byteArrayToString(byte[] byteArray) {
StringBuffer sb = new StringBuffer();
for (byte b : byteArray) {
sb.append(byteToHexChar(b));
}
return sb.toString();
}
private static Object byteToHexChar(byte b) {
int n = b;
if (n < 0)
n = n + 256;
return hex[n / 16] + hex[n % 16];
}
}
泛型自定義,註解,代理
1. 泛型(Generic):
注意:泛型是提供給javac編譯器使用的,它用於限定集合的輸入類型,讓編譯器在源代碼級別上,即擋住向集合中插入非法數據。但編譯器編譯完帶有泛形的java程序後,生成的class文件中將再也不帶有泛形信息,以此使程序運行效率不受到影響,這個過程稱之爲「擦除」。
泛形的基本術語,以ArrayList<E>爲例:<>念着typeof
ArrayList<E>中的E稱爲類型參數變量
ArrayList<Integer>中的Integer稱爲實際類型參數
整個稱爲ArrayList<E>泛型類型
整個BaseDao<Type>ParameterizedType/Type
例:自定義泛型
//父類(不能含有具體類型)
public class BaseDao<T> {
//即BaseDao<T>類型叫泛型類型,注意是一個總體,
//也能夠叫作「參數據類型」,用ParameterizedType接口來表示,它是
//Type接口中子接口
private String tableName;
private Class clazz;
public BaseDao() {
//取得BaseDao類的字節碼對象,即Class
Class baseDaoClass = this.getClass();
//取得子類型的參數據類型
Type type =baseDaoClass.getGenericSuperclass();
//將父接口強轉成子接口,即只表示"參數據類型(BaseDao<Type>)"
ParameterizedType pt = (ParameterizedType)type;
//取得"參數據類型(BaseDao<Type>)"中的實際類型,即Type類型
Type[] types = pt.getActualTypeArguments();
//取得第一個實際類型,即Type類型
type = types[0];
//class也是一種數據類型
this.clazz = (Class) type;
//取得表名
int index = this.clazz.getName().lastIndexOf(".");
this.tableName = this.clazz.getName().substring(index+1).toLowerCase();
}
//根據編號查詢內容
public T findById(int id) throws SQLException{
T t = null;
QueryRunner runner = new QueryRunner(JdbcUtil.getDataSource());
String sql = "select * from " + tableName + " where id=?";
t = (T)runner.query(sql,id,new BeanHandler(clazz));
return t;
}
}
繼承類:
public class TopicDao extends BaseDao<Topic> {
}
public class TypeDao extends BaseDao<Type> { //"參數化類型"
}
測試類:
public static void main(String[] args) throws Exception {
//子類
TypeDao typeDao = new TypeDao();
Type type = typeDao.findById(1);
System.out.println(type.getId()+":"+type.getTitle());
System.out.println("-------------------------------");
TopicDao topicDao = new TopicDao();
Topic topic = topicDao.findById(1);
System.out.println(topic.getId()+":"+topic.getTitle());
}
2,JDK5中內置註解:
>>@Override: 限定重寫父類方法, 該註解只能用於方法
>>@Deprecated: 用於表示某個程序元素(類, 方法等)已過期
>>@SuppressWarnings: 抑制編譯器警告.
元註解:被註解修飾的註解的註解稱爲原註解
1.元 Annotation指修飾Annotation的Annotation。JDK中定義了以下元Annotation:
@Retention:只能用於修飾一個 Annotation 定義, 用於指定該 Annotation 能夠保留的域, @Rentention 包含一個 RetentionPolicy 類型的成員變量, 經過這個變量指定域。
RetentionPolicy.CLASS:編譯器將把註解記錄在 class 文件中. 當運行 Java 程序時, JVM 不會保留註解. 這是默認值
RetentionPolicy.RUNTIME:編譯器將把註釋記錄在 class 文件中. 當運行 Java 程序時, JVM 會保留註解. 程序能夠經過反射獲取該註釋
RetentionPolicy.SOURCE:編譯器直接丟棄這種策略的註釋
@Target:指定註解用於修飾類的哪一個成員. @Target 包含了一個名爲 value,類型爲ElementType(JDK6)的成員變量。
@Documented:用於指定被該元 Annotation 修飾的 Annotation 類將被 javadoc 工具提取成文檔。
@Inherited:被它修飾的 Annotation 將具備繼承性.若是某個類使用了被 @Inherited 修飾的Annotation, 則其子類將自動具備該註解。
例:自定義註解
//自定義註解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DbInfo {
String driver() default "com.mysql.jdbc.Driver";
String url() default "jdbc:mysql://127.0.0.1:3306/bbs";
String username() default "root";
String password() default "root";
}
測試類:
public class Demo3 {
@DbInfo
public Connection getConnection() throws Exception{
//取得Demo3的字節碼對象Class
Class clazz = Demo3.class;
//取得getConnection()方法
Method method = clazz.getMethod("getConnection",null);
System.out.println(method.getName());
//取得DbInfo註解,註解也是一個類型,即DbInf.class是能夠的
DbInfo dbInfo = method.getAnnotation(DbInfo.class);
//取得註解中的屬性
String driver = dbInfo.driver();
String url = dbInfo.url();
String username = dbInfo.username();
String password = dbInfo.password();
//再經過DriverManager取得鏈接
Class.forName(driver);
Connection conn =DriverManager.getConnection(url,username,password);
return conn;
}
public static void main(String[] args) throws Exception {
Demo3 demo = new Demo3();
Connection conn = demo.getConnection();
if(conn!=null){
System.out.println("取得鏈接");
conn.close();
}
}
}
3 自定義註解和反射註解
1)註釋有三種生命週期
>>SOURCE:有且只有在源碼級別可見,(不推薦使用)
>>CLASS: 有且只有在源碼和字節碼級別可見,(默認),但在運行時,不可見
>>RUNTIME:在整個類的運行期周,均可見。(即源碼,字節碼,運行時)
2)經過反射註解在運行級別獲取該註解中的屬性值,以替換配置文件
3)元註解:修飾其它註解的註解,注意:元註解也能夠被其它註解修飾
>>@Retention(RetentionPolicy.RUNTIME)
>>@Target(ElementType.METHOD):表示該註解能夠運在哪些地方,默認狀況下,該註解能夠出在在任意地方
代理(proxy):
代理模式的做用
爲其餘對象提供一種代理以控制對目標對象的訪問。某些狀況下客戶不想或不能直接引用另外一個對象,而代理對象可在客戶端和目標對象間起到中介做用
1.靜態代理:
優勢
不須要修改目標對象就實現了功能的增長
缺點
真實角色必須是事先已經存在的,並將其做爲代理對象的內部屬性。若是事先並不知道真實角色則沒法使用
一個真實角色必須對應一個代理角色,若是大量使用會致使類的急劇膨脹
2.動態代理: java.lang.reflect
InvocationHandler接口
Proxy類
InvocationHandler接口僅定義了一個方法
public objectinvoke(Object obj,Method method, Object[] args)
obj通常是指代理類
method是被代理的方法
args爲該方法的參數數組
這個抽象方法在代理類中動態實現
Proxy類即爲動態代理類,主要方法包括
Object newProxyInstance(ClassLoader loader, Class[ ] interfaces,InvocationHandler h)
返回代理類的一個實例
loader是類裝載器
interfaces是真實類所擁有的所有接口的數組
h - 指派方法調用的調用處理程序
靜態代理和動態代理的比較
1,靜態代理類確實存在,動態代理類在運行期動態生成
2,一個真實角色必須對應一個靜態代理角色,而動態代理大大減小了代理類的數量
3,動態代理類不會做實質性的工做,在生成它的實例時必須提供一個handler,由它接管實際的工做(會自動執行handler的invoke方法)
如何代理
調用任務業務方法,都會被代理類攔截,從而調用invoke()方法
動態代理的步驟:
NO1:寫一個普通類
NO2:寫一個實例變量,記錄代理誰
NO3:使用構造方法爲上述實例變量設置值
NO4:寫一個普通方法,返回接口,該方法的返回值就是動態代理對象,該動態代理對象也實現了這個接口,該方法內部使用Proxy.newProxyInstance()來動態建立代理對象
例:1
//實現類:過濾器
public class EncodingFilter implements Filter {
public void destroy() {
}
public void doFilter(ServletRequestreq, ServletResponse res,FilterChain chain) throws IOException, ServletException {
//目標對象
HttpServletRequest request =(HttpServletRequest) req;
HttpServletResponse response =(HttpServletResponse) res;
//建立代理類
MyRequest myRequest = new MyRequest(request);
//動態產生代理對象
HttpServletRequest httpServletRequestProxy =myRequest.getProxy();
//放行請求時,傳入代理對象
chain.doFilter(httpServletRequestProxy,response);
}
public void init(FilterConfigfilterConfig) throws ServletException {
}
}
自定義代理類:
class MyRequest{//NO1
private HttpServletRequest request; //NO2
public MyRequest(HttpServletRequest request) {//NO3
this.request =request;}
public HttpServletRequest getProxy() {//NO4(核心)
return (HttpServletRequest)Proxy.newProxyInstance(
MyRequest.class.getClassLoader(),
request.getClass().getInterfaces(),
newInvocationHandler(){
public Object invoke(Object proxy, Methodmethod,Object[] args) throws Throwable {
//若是調用是的getParameter方法
if(method.getName().equals("getParameter")){
//取得請求的類型
String methodType = request.getMethod();
//若是是POST
if(methodType.equals("POST")){
//設置request的解碼方式爲UTF-8
request.setCharacterEncoding("UTF-8");
//取得表單參數
String username = (String) args[0];
//正確編碼
String value = request.getParameter(username);
//將值返回
return value;
//若是是GET
}else if(methodType.equals("GET")){
//取得表單參數
String username = (String) args[0];
//亂碼
String value = request.getParameter(username);
//還原
byte[] buf = value.getBytes("ISO8859-1");
//正碼
value = new String(buf,"UTF-8");
return value;
}
}else{
return method.invoke(request,args);
}
return null;
}
});
}
}
javaScript加強:
1.window : alert(‘信息’) :消息框 open( ) : 打開一個新窗口
2.Form表單對象:
訪問表單的方式:
document.forms[n]
document.表單名字
3.定義函數的三種方式
<script type="text/javascript">
函數定義方式一
function add(num1,num2){
returnnum1 + num2;
}
document.write("100+200的值爲:" + add(100,200) + "<br/>");
函數定義方式二
varadd = new Function("num1","num2","returnnum1+num2;");
document.write("300+400的值爲:" + add(300,400) + "<br/>");
函數定義方式三
varmul = function(num1,num2){
returnnum1 * num2;
}
window.alert("100*2的值爲:" + mul(100,2));
</script>
4.經常使用API
>>getElementById(),其中id的值,在整個html頁面中必須惟一,大小寫不敏感,只能在document對象中使用
>>getElmenetsByName(),其中name的屬性name的值,返回一個數組
>>getElemnetsByTagName()
>>hasChildNodes();innerHTML取得的是文本值,便是一個字符串,不是元素
>>firstChild取得是是元素,不是字符串
>>nodeName_nodeType_nodeValue:其中nodeValue是可讀可寫的屬性,其它二個屬性只可讀
>>replaceChild()
>>getAttrbuteNode():返回屬性節點,便是一個對象
>>getAttribute():返回屬性值,便是一個字符串
>>setAttribute():建立/更新屬性的值,更新要確保name一致
>>removeAttribute()
>>innerHTML:不是DOM的標準,即就是可能在某些瀏覽器上運行不支持,但各主要的瀏覽器均支持
>>createTextNode():是DOM的標準
>>appendChild()
>>insertBefore()
>>removeChild(),刪除子元素時,必定要從直接父元素中刪除,不能自刪
>>parentNode
>>childNodes:將空白字符也會看成一個子元素,不一樣的瀏覽器會有差異
>>showModelessDialog()打開窗口後,[容許]操做該窗口的其它地方,叫非模式
>>showModalDialog()打開窗口後,[不容許]操做該窗口的其它地方,叫模式
6)dom的api一樣適用於xml文件,但有些在html文件中的非標準的api在xml文件中不有執行,例如
options和innerHTML。
例2:
<meta http-equiv="content-type"content="text/html; charset=UTF-8">
</head>
<!-- 需求:在點擊生效按鈕後,使該按鈕變成失效,而後點擊恢復按鈕時,使其恢復爲生效按鈕 -->
<body>
<input type="button" value="生效" style="font-size:111px" />
<input type="button" value="恢復" />
<script type="text/javascript">
//獲取標籤元素的第一個元素
var inputElement =window.document.getElementsByTagName("input")[0];
//給該元素綁定時間監聽
inputElement.onclick = function()
{
//方式一:
//設置屬性值
inputElement.disabled= "disabled";
inputElement.value="失效";
//方式二:
inputElement.setAttribute("disabled","disabled");
inputElement.setAttribute("value","失效");
};
//獲取標籤元素的第-個元素
var input2Element =window.document.getElementsByTagName("input")[1];
input2Element.onclick= function()
{ inputElement.removeAttribute("disabled");
inputElement.setAttribute("value","生效");
};
</script>
</body>
</html>
例3:設置圖片的顯示和隱藏
<!DOCTYPE HTML PUBLIC "-//W3C//DTDHTML 4.01 Transitional//EN">
<html>
<head>
<title>form.html</title>
<meta http-equiv="content-type"content="text/html; charset=UTF-8">
</head>
<body onload="init()">
<div style="position:absolute;top:60px;left:400px;border-style:outset">
<img src="zgl.jpg"id="imgID"/>
</div>
<div style="position:absolute;top:300px;left:450px">
<input type="button" value="隱藏" id="hideID"/>
<input type="button" value="顯示" id="showID"/> CSS + DIV
</div>
<scripttype="text/javascript">
//單擊隱藏按鈕
document.getElementById("hideID").onclick=function(){
//將圖片隱蔽
imgHide("imgID");
//將隱藏按鈕失效
btnAbled("hideID");
//將顯示按鈕生效
btnEnabled("showID");
};
//單擊顯示按鈕
document.getElementById("showID").onclick=function(){
//將圖片顯示
imgShow("imgID");
//將顯示按鈕失效
btnAbled("showID");
//將隱蔽按鈕生效
btnEnabled("hideID");
};
//初始化
function init(){
//將按鈕失效
btnAbled("showID");
}
//將按鈕生效
function btnEnabled(id){
varidElement = document.getElementById(id);
idElement.disabled=false;
}
//將按鈕失效
function btnAbled(id){
varidElement = document.getElementById(id);
idElement.disabled=true;
}
//將圖片隱蔽
function imgHide(id){
varidElement = document.getElementById(id);
idElement.style.visibility="hidden";
}
//將圖片顯示
function imgShow(id){
varidElement = document.getElementById(id);
idElement.style.visibility="visible";
}
</script>
</body>
</html>
AJAX包含的技術:
什麼是Ajax: Ajax被認爲是(AsynchronousJavaScript And Xml的縮寫)。如今,容許瀏覽器與服務器通訊而無須刷新當前頁面的技術都被叫作Ajax.
工做原理:
Ajax的核心是JavaScript對象XMLHttpRequest。
該對象在Internet Explorer 5中首次引入,它是一種支持異步請求的技術。簡而言之,XMLHttpRequest使您能夠使用JavaScript向服務器提出請求並處理響應,而不阻塞用戶。
AJAX採用異步交互過程。AJAX在用戶與服務器之間引入一箇中間媒介,從而消除了網絡交互過程當中的處理—等待—處理—等待缺點。
用戶的瀏覽器在執行任務時即裝載了AJAX引擎。AJAX引擎用JavaScript語言編寫,它負責用戶界面及與服務器之間的交互。
AJAX引擎容許用戶與應用軟件之間的交互過程異步進行,獨立於用戶與網絡服務器間的交流。如今,能夠用Javascript調用AJAX引擎來代替產生一個HTTP的用戶動做,內存中的數據編輯、頁面導航、數據校驗這些不須要從新載入整個頁面的需求能夠交給AJAX來執行。
AJAX:(AsynchronousJavaScript and XML)並非一項新技術,實際上是多種技術的綜合,包括Javascript、HTML和CSS、DOM、XML和XMLHttpRequest.
服務器端語言:服務器須要具有向瀏覽器發送特定信息的能力。Ajax與服務器端語言無關。
XML (extensible Markup Language,可擴展標記語言) 是一種描述數據的格式。AJAX 程序須要某種格式化的格式來在服務器和客戶端之間傳遞信息,XML 是其中的一種選擇
HTML(Hypertext Markup Language,使用超文本標記語言)和 CSS(Cascading Style Sheet,級聯樣式單)標準化呈現;
DOM(Document Object Model,文檔對象模型)操做頁面規則;
使用XMLHttpRequest對象進行異步數據讀取;使用JavaScript實現動態顯示和交互;
2 AJAX的特色
1)AJAX是一個多種技術的綜合體現
2)AJAX和服務端的技術無關
3)AJAX給用戶體驗是C/S(桌面應用),但[本質]是仍是B/S(Web應用)
4)AJAX和服務端技術無關,它位於瀏覽器端
5)AJAX的不足:
>>早期瀏覽器兼容不統一
>>它是局部刷新,致使瀏覽器的前進和後退按鈕無效
>>一些手持設備(iPad/PAD)支持不佳
*3 AJAX開發步驟及詳解
Ajax建立:
1,建立XMLHttpRequest異步對象(AJAX引擎對象)
早期IE瀏覽器: var xhr = new ActiveXObject("microsoft.xmlhttp");
晚期主流瀏覽器 :var xhr = new XMLHttpRequest();
注意:早期不一樣的瀏覽器建立方式不同。晚期主流瀏覽器都統一,直接new XMLHttpRequest()就能夠建立AJAX引擎,不須要引入第三方的jar包。
2,爲AJAX引擎設置監聽器
1)xhr.onreadystatechange = function(){}
onreadystatechange: 該事件處理函數由服務器觸發,而不是用戶.
在 Ajax 執行過程當中,服務器會通知客戶端當前的通訊狀態。這依靠更新 XMLHttpRequest 對象的 readyState 來實現。改變readyState 屬性是服務器客戶端鏈接操做的一種方式。
每次 readyState 屬性的改變都會觸發 readystatechange事件
2)AJAX狀態的幾種變化
0:表示未初始化,即剛建立完畢
1:表示準備發送請求,即open()方法已經調用,但未調用send()方法
2:表示正在發送請求中,即send()方法已經調用,請求正發往服務端
3:表示AJAX引擎和服務端交互中,即AJAX引擎正在接收服務端的響應,但未完畢
*4:表示AJAX引擎徹底接收到了服務端的響應,注意:4號狀態是每種瀏覽器通用的
3)AJAX在收到URL請求後,會和原URL進行比較,若是不相同,則將該請求發送到服務器,獲取新內容,再加以緩存。若是相同的URL時,直接取得緩存中的內容。只有當每次請求的URL不同時,AJAX引擎就會將請求發給到服務端,以獲取最新內容.
4)通知AJAX引擎接收HTML字符串
response.setContentType("text/html;charset=UTF-8");
通知AJAX引擎接收XML文件
response.setContentType("text/xml;charset=UTF-8");
以上代碼在服務端寫
5)AJAX接收HTML字符串
xhr.responseText
AJAX接收XML文件
xhr.responseXML
以上代碼在客戶端寫
6)AJAX發送GET請求時,對於中文須要程序員手工編碼
username = encodeURI(username)
AJAX發送POST請求時,對於中文由AJAX引擎負責編碼,但須要通知AJAX引擎,設置以POST方式提交數據,讓AJAX引擎自動進行URL編碼
xhr.setRequestHeader("content-type","application/x-www-form-urlencoded");
該代碼只能出如今xhr.open()以後,xhr.send()以前
4 XMLHttpRequest(AJAX引擎)方法或屬性的小結
屬性:
xhr.onreadystatechange = function(){無名處理函數}
xhr.readyState==0,1,2,3,4
xhr.status==200或404或500或304
xhr.responseText(有且只能接收服務端響應的字符串)
xhr.responseXML(有且只能接收服務端響應的XML文件)
方法:
xhr.open(method,url) //準備發送請求
xhr.send(若是是GET請求,就寫null) //真正發送異步請求(請求體)
xhr.setRequestHeader("content-type","application/x-www-form-urlencoded");
open(method, url, asynch)
XMLHttpRequest 對象的 open 方法容許程序員用一個Ajax調用向服務器發送請求。
method:請求類型,相似 「GET」或」POST」的字符串。若只想從服務器檢索一個文件,而不須要發送任何數據,使用GET(能夠在GET請求裏經過附加在URL上的查詢字符串來發送數據,不過數據大小限制爲2000個字符)。若須要向服務器發送數據,用POST。
在某些狀況下,有些瀏覽器會把多個XMLHttpRequest請求的結果緩存在同一個URL。若是對每一個請求的響應不一樣,這就會帶來很差的結果。把當前時間戳追加到URL的最後,就能確保URL的唯一性,從而避免瀏覽器緩存結果。
url:路徑字符串,指向你所請求的服務器上的那個文件。能夠是絕對路徑或相對路徑。
asynch:表示請求是否要異步傳輸,默認值爲true(異步)。指定true,在讀取後面的腳本以前,不須要等待服務器的相應。指定false,當腳本處理過程通過這點時,會停下來,一直等到Ajax請求執行完畢再繼續執行。
send(data):
open 方法定義了 Ajax 請求的一些細節。send方法可爲已經待命的請求發送指令
data:將要傳遞給服務器的字符串。
若選用的是 GET 請求,則不會發送任何數據, 給 send 方法傳遞 null 便可:request.send(null);
當向send()方法提供參數時,要確保open()中指定的方法是POST,若是沒有數據做爲請求體的一部分發送,則使用null.
HTML 小結
優勢:
JavaScript 進行解析。
HTML 的可讀性好。
HTML 代碼塊與 innerHTML 屬性搭配,效率高。
缺點:
若須要經過AJAX 更新一篇文檔的多個部分,HTML 不合適,innerHTML 並不是 DOM 標準
XML小結
優勢:
XML 是一種通用的數據格式。
沒必要把數據強加到已定義好的格式中,而是要爲數據自定義合適的標記。利用 DOM 能夠徹底掌控文檔。
缺點:
若是文檔來自於服務器,就必須得保證文檔含有正確的首部信息。若文檔類型不正確,那麼 responseXML 的值將是空的。
當瀏覽器接收到長的 XML文件後, DOM 解析可能會很複雜
AJAX不是完美的技術。也存在缺陷:
1.AJAX大量使用了JavaScript和AJAX引擎,而這個取決於瀏覽器的支持。IE5.0及以上、Mozilla1.0、NetScape7及以上版本才支持,Mozilla雖然也支持AJAX,可是提供XMLHttpRequest的方式不同。因此,使用AJAX的程序必須測試針對各個瀏覽器的兼容性。
2.AJAX更新頁面內容的時候並無刷新整個頁面,所以,網頁的後退功能是失效的;有的用戶還常常搞不清楚如今的數據是舊的仍是已經更新過的。這個就須要在明顯位置提醒用戶「數據已更新」。
3 對流媒體的支持沒有FLASH好。
4. 一些手持設備(如手機、PDA等)如今還不能很好的支持Ajax。
JSON對象
JSON(JavaScript Object Notation)一種簡單的數據格式,比xml更輕巧。JSON是JavaScript原生格式,這意味着在JavaScript中處理JSON數據不須要任何特殊的API或工具包。
JSON的規則很簡單:對象是一個無序的「‘名稱:值’對」集合。一個對象以「{」(左括號)開始,「}」(右括號)結束。每一個「名稱」後跟一個「:」(冒號);「‘名稱/值’對」之間使用「,」(逗號)分隔。
規則以下:
1)映射用冒號(「:」)表示。名稱:值
2)並列的數據之間用逗號(「,」)分隔。名稱1:值1,名稱2:值2
3) 映射的集合(對象)用大括號(「{}」)表示。{名稱1:值1,名稱2:值2}
4) 並列數據的集合(數組)用方括號(「[]」)表示。
[
{名稱1:值,名稱2:值2},
{名稱1:值,名稱2:值2}
]
5 元素值可具備的類型:string, number,object, array, true, false, null
*5 JSON的使用
1)JSON是JavaScript的原生態對象,即JavaScript能夠不須要任務第三的jar包直接操做JSON對象
2)默認狀況下,JS不能直接解析Java的String類型,須要經過eval()函數轉換成JS能夠直接解析的JSON字符串
3)三種數據載體的對比
數據載體:服務端發送信息到AJAX引擎,數據用什麼容器裝。這個容器就叫作數據載體
>>HTML:傳輸數據小,結構不復雜,不重用,不解析
*>>XML:不一樣系統之間的大量信息傳遞,結構相對複雜,不能重用,須要解析
*>>JSON:傳遞數據量小,有必定結構,須要重用,須要解析,注意:JSON只是一個字符串而以,但該語法相關複雜,能夠經過第三方工具自動生成。
例:ajax對象 :
<%@ pagelanguage="java" import="java.util.*"pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01Transitional//EN">
<html>
<body>
輸入用戶名:
<input type="text" value="哈哈"id="usernameID" maxlength="2"/>
<input type="button" value="檢查"id="buttonID"/>
單擊檢查按鈕後,當即檢查結果
<hr/>
<div id="divID"></div>
<scripttype="text/javascript">
//取得input元素
var inputElement =window.document.getElementById("buttonID");
//綁定事件
inputElement.onclick = function()
{//獲取用戶名
var username = window.document.getElementById("usernameID").value;
//建立引擎ajax對象
var xhr = createXHR();
//設置監聽時間
xhr.onreadystatechange = function()
{
if(xhr.readyState==4)
{ //判斷服務端響應是否正確
if(xhr.status==200)
{//ajax取得響應xml文件
var xmlDoc = xhr.responseXML;
var resElementXML =xmlDoc.getElementsByTagName("res")[0];
//取得值
var msg =resElementXML.firstChild.nodeValue;
//取得divID元素
var divIDElement = window.document.getElementById("divID");
//將msg添加div中
divIDElement.innerHTML = msg;
}
}
};
var method = "POST";
var url ="/myday29/CheckoutServlet?time="+new Date().toLocaleString();
xhr.open(method,url);
//設置以POST方式提交數據,讓AJAX引擎自動進行URL編碼
xhr.setRequestHeader("content-type","application/x-www-form-urlencoded");
//真正發送請 求體的數據
var sendData = "username="+username;
xhr.send(sendData);
};
//建立ajax引擎對象
function createXHR(){
var xhr =null;
try{
xhr = newActiveXObject("microsoft.xmlhttp");
}catch(e){
xhr = newXMLHttpRequest();
}
return xhr;
}
</script>
</body>
</html>
JSON建立對象步驟:
<!-- 建立對象的方法一-->
例2:json2.jsp
<%@ page language="java"import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01Transitional//EN">
<html>
<body>
<!-- 建立對象的方法第一種: -->
<script type="text/javascript">
var p ={
tel:[
{no:13579343798},
{no:13734544655},
{no:15032454645}
]
};
window.document.write("共有"+p.tel.length+"學員"+"<br/><hr/>");
//取出每一個號碼
for(var x=0;x<p.tel.length;x++){
document.write("號碼:"+p.tel[x].no+"<br/>");
}
</script>
<!-- 第二種:-->
<script type="text/javascript">
var p = {
"city":["北京","上海","廣州","重慶"]
};
document.write("共有:" +p.city.length + "個城市<br/>");
document.write("最閒的城市是:" + p.city[p.city.length-1]);
</script>
<!--第三種: -->
<script type="text/javascript">
var p = {
china:[
{city:"北京"},
{city:"上海"},
{city:"廣州"}
],
usa:[
{city:"舊金山"},
{city:"紐約"},
]
};
document.write("你目前在:"+ p.china[2].city + "<br/>");
document.write("你最想去:"+ p.usa[1].city + "<br/>");
</script>
</body>
</html>
例3:二級聯動:xml版本
<html>
<body>
<selectid="provinceID">
<option>選擇省份</option>
<option>選擇省份</option>
<option>吉林省</option>
<option>遼寧省</option>
<option>山東省</option>
<option>廣東省</option>
</select>
<selectid="cityID" style="width:220px">
<option>選擇城市</option>
</select>
<scripttype="text/javascript">
//取得select元素
var selectElement =window.document.getElementById("provinceID");
//綁定事件
selectElement.onchange = function()
{ //取得cityid標籤元素
var citySelectElement =window.document.getElementById("cityID");
//取得子元素非個數
var size = citySelectElement.options.length;
//清空option元素
for(var x=size-1;x>0;x--)
{
citySelectElement.removeChild(citySelectElement.options[x]);
}
//取得選中的城市
var index = selectElement.selectedIndex;
//取得選中的option選項
var optionElement = this[index];
//取得值
var province = optionElement.innerHTML;
//建立ajax引擎對象
var xhr = createXHR();
//設置監聽器
xhr.onreadystatechange = function()
{ //判斷服務端響應狀態
if(xhr.readyState==4)
{
if(xhr.status==200)
{
//取得響應的文本字符串
var msg = xhr.responseText;
//將java中的String類型字符串轉換爲json中的能解析的字符串
var jsonString = eval(msg);
//取得城市的個數
var size = jsonString.length;
for(varx=0;x<size;x++)
{//取得每一個城市
var city = jsonString[x].name;
//建立<option>節點
var cityIDoptionElement =window.document.createElement("option");
//設置值
cityIDoptionElement.innerHTML= city;
//添加到cityID的<select>標籤中
citySelectElement.appendChild(cityIDoptionElement);
}
}
}
};
//設置發送請求方式
var method = "post";
varurl = "/myday29/JsoncityServlet?time="+new Date().toLocaleString();
//準備發送
xhr.open(method,url);
////設置以POST方式提交數據,讓AJAX引擎自動進行URL編碼
xhr.setRequestHeader("content-type","application/x-www-form-urlencoded");
vardatePronvince = "province="+province;
//發送請求
xhr.send(datePronvince);
};
//建立AJAX異步對象
function createXHR(){
varxhr = null;
try{
xhr= new ActiveXObject("microsoft.xmlhttp");
}catch(e){
xhr= new XMLHttpRequest();
}
returnxhr;
}
</script>
</body>
服務端響應 Servlet
public class CityServletJson extends HttpServlet {
public void doPost(HttpServletRequestrequest, HttpServletResponse response)throws ServletException,IOException {
request.setCharacterEncoding("UTF-8");
String province = request.getParameter("province");
List<City> cityList = new ArrayList<City>();
//模擬調用業務層
if("吉林省".equals(province)){
cityList.add(new City(1,"長春[吉林省]"));
cityList.add(new City(2,"吉林市[吉林省]"));
cityList.add(new City(3,"松原[吉林省]"));
cityList.add(new City(4,"通化[吉林省]"));
}else if("遼寧省".equals(province)){
cityList.add(new City(1,"瀋陽[遼寧省]"));
cityList.add(new City(2,"大連[遼寧省]"));
cityList.add(new City(3,"鞍山[遼寧省]"));
cityList.add(new City(4,"撫順[遼寧省]"));
cityList.add(new City(5,"鐵嶺[遼寧省]"));
}else if("山東省".equals(province)){
cityList.add(new City(1,"濟南[山東省]"));
cityList.add(new City(2,"青島[山東省]"));
cityList.add(new City(3,"威海[山東省]"));
}else if("廣東省".equals(province)){
cityList.add(new City(1,"廣州[廣東省]"));
cityList.add(new City(2,"深圳[廣東省]"));
}
//經過第三方工具,將集合轉成JSON字符串
JsonConfig jsonConfig = new JsonConfig();
String[] params = {"id"};
jsonConfig.setExcludes(params);
JSONArray jsonArray =JSONArray.fromObject(cityList,jsonConfig);
String jsonString =jsonArray.toString();
System.out.println("jsonString="+jsonString);
//將JSON字符串輸出到AJAX引擎
response.setContentType("text/html;charset=UTF-8");
response.getWriter().write(jsonString);
}
}
JQuery: javaScript Query
javaScript庫:jQuery[JS標準],MooTools, Prototype, Dojo, YUI, EXT_JS, DWR
jQuery由美國人John Resig建立
1.jQuery是繼prototype以後又一個優秀的JavaScript框架。其宗旨是——WRITELESS,DO MORE,寫更少的代碼,作更多的事情。
2.它是輕量級的js庫(壓縮後只有20k左右) ,這是其它的js庫所不及的,它兼容CSS3,還兼容各類瀏覽器 (IE 6.0+, FF 1.5+, Safari 2.0+, Opera 9.0+)。
jQuery是一個快速的,簡潔的javaScript庫,使用戶能更方便地處理HTML/CSS DOM、事件、實現動畫效果,而且方便地爲網站提供AJAX交互。
3.jQuery還有一個比較大的優點是,它的文檔說明很全,並且各類應用也說得很詳細,同時還有許多成熟的插件可供選擇。
4.jQuery可以使用戶的html頁保持代碼和html內容分離,也就是說,不用再在html裏面插入一堆js來調用命令了,只需定義id便可。
1 什麼是jQuery?什麼要使用jQuery?
1)第三方開源組織提供的實用函數庫,大多[主流]的瀏覽器均支持
2)jQuery可以讓程序員寫少代碼,作多事情,它也是JS標準推薦的實用JS函數庫
3)jQuery可以操做HTML/CSS/DOM/動畫/事件/AJAX操做
4)jQuery文檔豐富,祥細
5)[建議]爲每一個<html標籤>定義一個id屬性,該id屬性在整個html文件中惟一
2 DOM對象和jQuery對象相互轉換
1)經過原始domapi獲得的對象,叫dom對象,例如:document.getElementById("id");
自定義規則:dom對象--domElement,例如divElement,tableElement
文本值---dom,例如div,input,span
2)經過jqueryapi獲得的對象,叫jquery對象,例如:$("#div")
自定義規則:jquery對象--$dom,例如$div,$input,$table
文本值---dom,例如div,input,span
3)jquery對象是對原始dom對象的封裝,原始dom對象中有什麼方法或屬性,jquery對象就有與之對應的方法(通常以方法爲主)
4)dom原始對象轉成jquery對象
jquery對象 = $(dom對象);
5)jquery對象轉成dom原始對象
一切jquery對象都是數組,每一個dom對象位於數據中,下標從0開始
方式一:dom對象 = jquery對象[0]
方式二:dom對象 = jquery對象.get(0)
注意:dom對象只能調用dom對象的api,jquery對象也只能調用jquery對象的api,不能混用
3 DOM操做與jQuery操做對錯誤的處理方式的比較
1)dom在查找不到元素的狀況下,無任何提示;因此項目中,最好自行判段元素是否爲null
1)jquery在查找不到元素的狀況下,有提示;
*4 jQuery九類選擇器(參見jQueryAPI.chm手冊)
1)基本選擇器
$("#id") 根據id匹配一個元素
$("div") 根據標籤名匹配一個元素
$(".myClass")根據給定的類匹配元素
$("#id,div,.myClass")將每個選擇器匹配到的元素合併後一塊兒返回
例:
<scripttype="text/javascript">
//1)查找ID爲"div1ID"的元素個數
alert($("#div1ID").length);
//2)查找DIV元素的個數
alert($("div").size());
//3)查找全部樣式是"myClass"的元素的個數
alert($(".myClass").html());
//4)查找全部DIV,SPAN,P元素的個數
alert($("div,span,p").size());
//5)查找全部ID爲div1ID,CLASS爲myClass,P元素的個數
alert($("#div1ID,.myClass,p").size());
</script>
2)層次選擇器
$("forminput")[祖先和後代]
$("form>input")[父子關係]
$("form+input")[同一級第一個兄弟關係]
$("form~input")[同一級全部兄弟關係]
例1:
<body>
<form>
<inputtype="text" value="a"/>
<table>
<tr>
<td><inputtype="checkbox" value="b"/></td>
</tr>
</table>
</form>
<inputtype="radio" value="c"/>
<inputtype="radio" value="d"/>
<input type="radio"value="e"/>
<scripttype="text/javascript">
//1)找到表單form下全部的input元素的個數[祖先和後代的關係]
//alert($("forminput").size());
//alert($("forminput:first").size());
//2)找到表單form下全部的子級input元素個數[父子關係]
alert($("form >input").size());
alert($("form >input").val());
//3)找到表單form同級第一個input元素的value屬性值[兄弟關係]
alert($("form + input").val());
alert($("form + input").size());
//4)找到全部與表單form同級的input元素個數[兄弟關係]
alert($("form ~ input").size());
</script>
</body>
3)加強型基本選擇器
$("ulli:first") 第一個元素
$("ulli:last") 最後一個元素
$("input:checked"):表示<input/>選中的元素,即含有"checked"屬性值的<input/>標籤
$("input:not(:checked)"):表示<input/>未選中的元素,即不含有"checked"屬性值的<input/>標籤
$("tabletr:even")索引爲爲奇數,從0開始
$("tabletr:odd")索引爲爲偶數,從0開始
$("tabletr:eq(1)")第二行,第一行也能夠使用:eq(0)等價於:first
$("tabletr:gt(0)") 查找第二第三行,即索引值是1和2,也就是比0大
$("tabletr:lt(2)") 查找第一第二行,即索引值是0和1,也就是比2小
$(":header")
4)內容選擇器
$("div:contains('John')") 匹配包含給定文本的元素
$("p:empty") 匹配全部不包含子元素或者文本的空元素
$("div:has('p')") 給全部包含 p 元素的 div元素添加一個 text 類
$("p:parent") 匹配含有子元素或者文本的元素
例1:
<styletype="text/css">
.myClass{font-size:44px;color:blue}
</style>
<div><p>JohnResig</p></div>
<div><p>GeorgeMartin</p></div>
<div>MalcomJohn Sinclair</div>
<div>J.Ohn</div>
<div></div>
<scripttype="text/javascript">
//1)查找全部包含文本"John"的div元素的個數
//alert($("div:contains('John')").size());
//2)查找全部p元素爲空的元素個數
//alert($("div ~p:empty").size());
//alert($("body>p:empty").size());
//alert($("bodyp:empty").size());
// alert($("p:empty").size());
//3)給全部包含p元素的div元素添加一個myClass樣式
//alert($("div:has(p)").addClass("myClass"));
//4)查找全部含有子元素或者文本的p元素個數,即p爲父元素
alert($("p:parent").size());
</script>
5)可見性選擇器
$("tabletr:hidden")匹配全部不可見元素,或者type爲hidden的元素
$("tabletr:visible") 匹配全部的可見元素
6)屬性選擇器
$("div[name]") 匹配包含給定name屬性的元素。
$("div[name='xx']") 查找全部 name 屬性是 xx 的 input 元素
$("div[name!='xx']") 查找全部 name 屬性不包含 xx 的div元素
$("div[name^='xx']")以xx開頭
$("div[name$='xx']")以xx結束
$("div[id*='xx']") 查找全部name 包含 'xx' 的 input元素
$("input[id][name$='letter']")同時有id和name屬性包含letter的 input元素
例1:
<body>
<div><p>Hello!</p></div>
<divid="test2"></div>
<inputtype="checkbox" name="newsletter" value="HotFuzz" />
<inputid="myID" type="checkbox" name="newsletter"value="Cold Fusion" />
<inputtype="checkbox" name="newsaccept" value="EvilPlans" />
<scripttype="text/javascript">
//1)查找全部含有id屬性的div元素個數
alert($("div[id]").size());
//2)查找全部name屬性是newsletter的input元素,並將其選中
alert($("input[name='newsletter']").size());
//3)查找全部name屬性不是newsletter的input元素,並將其選中
//alert($("input[name!='newsletter']").size());
//4)查找全部name以'news'開始的input元素,並將其選中
alert($("input[name^='news']").size());
//5)查找全部name 以'letter'結尾的input元素,並將其選中
alert($("input[name$='letter']").size());
//6)查找全部name包含'news'的input元素,並將其選中
alert($("input[name*=news]").size());
//7)找到全部含有id屬性,而且它的name屬性是以"letter"結尾的,並將其選中
alert($("input[id][name$=letter]").size());
</script>
</body>
7)子元素選擇器
$("ulli:first-child"):全部的ul中li的第一個元素的數組
數組.each();迭代方法,有且只能使用jquery對象調用,不能使用dom對象調用,相似於java中的加強for循環它會自動將數組中的每個元素覆給each()參數,咱們在each中,經過this來獲取該參數
$("ul li:last-child")':last'只匹配一個元素,而此選擇符將爲每一個父元素匹配一個子元素
$("ulli:only-child") 在 ul 中查找是惟一子元素的 li
$("ulli:nth-child(1)") 匹配其父元素下的第N個子或奇偶元素
注意: ':eq(index)' 只匹配一個元素,而這個將爲每個父元素匹配子元素。:nth-child從1開始的,而:eq()是從0算起的!能夠使用:
nth-child(even)
:nth-child(odd)
:nth-child(3n)
:nth-child(2)
:nth-child(3n+1)
:nth-child(3n+2)
8)表單屬性選擇器
:input包含input/textarea/button/select
9)表單對象屬性
$("input:enabled") 匹配全部可用元素
$("input:disabled")匹配全部不可用元素
$(":checkbox:checked")或$(":radio:checked")
$("selectoption:selected")下拉框選中
$("selectoption:not(:selected)")下拉框未選中
例1:
<body>
<form>
<input name="email" disabled="disabled" />
<input name="password" disabled="disabled" />
<input name="id" />
<input type="checkbox" name="newsletter" checked="checked"value="Daily" />
<input type="checkbox" name="newsletter"value="Weekly" />
<input type="checkbox" name="newsletter"checked="checked" value="Monthly" />
<select>
<option value="1">Flowers</option>
<option value="2" selected="selected">Gardens</option>
<option value="3">Trees</option>
</select>
</form>
<scripttype="text/javascript">
//1)查找全部可用的input元素的個數
//alert($("input:enabled").size());
//2)查找全部不可用的input元素的個數
//alert($("input:disabled").size());
//3)查找全部選中的複選框元素的個數
//alert($("input:checked").size());
//4)查找全部未選中的複選框元素的個數
//alert($("input[checked!='checked']").size());
//alert($("input:not(:checked)").size());
//5)查找全部選中的選項元素的個數
//alert($("selectoption:selected").size());
</script>
</body>
總結案例:
二級連動:jquery版本;
<body>
<selectid="provinceID" name="pname">
<option>選擇省份</option>
<option>陝西省</option>
<option>遼寧省</option>
<option>山東省</option>
<option>廣東省</option>
</select>
<selectid="cityID" style="width:100px"name="cname">
<option>選擇城市</option>
</select>
<selectid="areaID" style="width:100px">
<option>選擇地區</option>
</select>
<scripttype="text/javascript">
//取得cityID下拉選項元素
$("#cityID").change(function(){
//取得區域<selsect>不包含第一個選項的元素,並清空其餘的選項
$("#areaID option:not(:contains('選擇地區'))").remove();
var url ="${pageContext.request.contextPath}/JqueryCityServlet?time="+newDate().toLocaleString();
//var city =$("#cityID option:selected").html();
//varsendData ={city:city};
//收集表單參數
var sendData = $("#cityID").serialize();
$.get(url,sendData,function(backData,textStatus,xhr){
//取得響應的文本內容
var msg = xhr.responseText;
varjsonString = eval(msg);
varsize = jsonString.length;
for( var i = 0; i < size; i++) {
//取得對應的區域
var area = jsonString[i].name;
//建立option標籤
var $option =$("<option>"+area+"</option>");
$("#areaID").append($option);
}
});
});
//給<province>綁定事件
$("#provinceID").change(function(){
//取得城市<selsect>不包含第一個選項的元素,並清空其餘的選項
$("#cityID option:gt(0)").remove();
$("#areaIDoption:gt(0)").remove();
var url ="${pageContext.request.contextPath}/JqueryCityServlet?time="+newDate().getTime();
var province= $("#provinceID option:selected").html();
alert(province);
var sendData= {province:province};
$.post(url,sendData,function(backData,textStatus,xhr)
{ //取得響應的文本內容
var msg = xhr.responseText;
//將Java中的String類型轉成JS中的json類型(JS類型的字符串)
varjsonString = eval(msg);
//取得城市個數
var size = jsonString.length;
//迭代
for ( var i = 0; i < size; i++)
{ //取得每個城市
var city = jsonString[i].name;
//建立<option>元素
var $option = $("<option>" + city +"</option>");
//添加節點<option>
$("#cityID").append($option);
}
});
});
public class JqueryCityServlet extends HttpServlet {
public void doGet(HttpServletRequestrequest, HttpServletResponse response)
throws ServletException, IOException {
this.findAreaByCity(request, response);
}
public void doPost(HttpServletRequestrequest, HttpServletResponse response)
throws ServletException, IOException {
this.findCityByProvince(request, response);
}
private voidfindAreaByCity(HttpServletRequest request,
HttpServletResponse response) throws IOException {
String city = request.getParameter("cname");
PCAService pcaService = new PCAService();
List<Area> areaList =pcaService.findAreaByCity(city);
//將集合裝換爲json
JsonConfig jsonConfig = new JsonConfig();
String [] param = {"id"};
jsonConfig.setExcludes(param);
JSONArray jsonArray =JSONArray.fromObject(areaList, jsonConfig);
String jsonString = jsonArray.toString();
System.out.println("地區:"+jsonString);
PrintWriter pw = response.getWriter();
pw.write(jsonString);
}
public voidfindCityByProvince(HttpServletRequest request,
HttpServletResponse response) throws IOException {
//取得參數
String province = request.getParameter("province");
System.out.println(province);
//調用業務層查詢城市
PCAService pcaService = new PCAService();
List<City> cityList =pcaService.findCityByProvince(province);
//將集合裝換爲json
JsonConfig jsonConfig = new JsonConfig();
String [] param = {"id"};
jsonConfig.setExcludes(param);
JSONArray jsonArray =JSONArray.fromObject(cityList, jsonConfig);
String jsonString =jsonArray.toString();
System.out.println("城市:"+jsonString);
PrintWriterpw = response.getWriter();
pw.write(jsonString);
}
}
Jquery基本操做方法:
添加節點:
append(content):父子關係 父.append(子),插入到父元素以後
向每一個匹配的元素內部追加內容。這個操做與對指定的元素執行appendChild方法
preappend(content): 父子關係 ,插入到父元素以前
插入節點:
after(content):兄弟關係 ,插入到兄弟元素以後
before(contect): 兄弟關係,插入到兄弟元素以前
查找屬性
attr(name):查找元素的屬性值
例:取得form下第一個input元素的type屬性
$(":text").attr("type")
attr(key,value):設置屬性值
例:設置form下最後個input元素的爲只讀文本框
$(":password").attr("readonly","readonly")
刪除屬性:
RemoveaAttr(「name」);刪除指定的屬性
注:刪除指定的屬性,能夠聯級刪除,
例如:刪除table元素的屬性爲align/border
$table.removeAttr("align").removeAttr("border");
建立元素的節點:
$(「html代碼」): jquery自動將html代碼轉成dom對象,最後以jquery對象的形式返回,html代碼中,能夠寫N個屬性值,外面雙引,內部單引
例: //建立div元素,添加"哈哈"文本,ID屬性,並添加到文檔中
Var $div = $(「<div id=’2012’>哈哈</div>」)
$(「body」).append($div);
刪除節點元素:
Empty(); 把全部段落的子元素(包括文本節點)刪除
例: $("#secondID").empty();刪除id爲#secondID下的子元素,而#secondID自己不刪除
Remove();刪除指定的節點(連同本身也刪除)
例: $(「#secondID」).remove(); 刪除id爲secondID的元素
remove([expre]);從DOM中刪除全部匹配的元素
例:$(「div」).remove(「#secondID」)刪除指定id爲#secondID的元素
複製元素:
clone():複製對象,不復制行爲
clone(true):複製對象,也複製行爲例: 克隆全部b元素(並選中這些克隆的副本),而後將它們前置到全部段落中。
<b>Hello</b><p>, howare you?</p>
例: $("b").clone().prependTo("p");
替換節點:
replacewith(): 將全部匹配的元素替換成指定的HTML或DOM元素
例: <div style="width:165px;height:23px">
雙擊會被替換成文本框 </div>
<scripttype="text/javascript">
//雙擊<div>中的文本,用文本框替換文本
$("div").dblclick(function(){
//建立文本框
var $text = $("<inputtype='text'/>");
//用文本框替換<div>標籤
$(this).replaceWith($text);
//文本框失去焦點
$text.blur(function(){
//取得文本框的value屬性
var username = $(this).val();
//用<div>標籤替換文本框
$(this).replaceWith("<div>"+username+"</div>");
});
});
</script>
添加樣式:
addClass(「樣式名或者類名」);爲無樣式的DIV添加樣式
例:$("div:first").addClass("myClass");爲無樣式的DIV添加樣式
removeClass(「樣式名或者類名」);移除樣式
例:爲有樣式的DIV刪除樣式
$(".myClass").removeClass("myClass")
hasClass(「樣式名或者類名」): 判斷元素是否有樣式
例:最後一個DIV是否有樣式
$(".myClass").hasClass("myClass")
toggleClass(「樣式名或者類名」): 給沒有樣式的元素添加樣式,有樣式的元素取出樣式.
例:有樣式的變成無樣式,無樣式的變成有樣式
$("div").toggleClass("myClass");
文檔的加載:
$(document).Ready()
查找元素:
children():取得一個包含匹配的元素集合中每個元素的全部子元素的元素集合
例: $("div span").html() : 取得div元素的直接子元素內容, 只包含直接子元素,不包含後代
next(): 查找下一個元素
例:$("div").next().html():取得div元素的下一個同級的兄弟元素內容
prev():查找上一個元素
例:$("div").prev().html() :取得div元素的上一個同級的兄弟元素內容
注: 只有緊鄰的同輩元素會被匹配到,而不是前面全部的同輩元素。
siblings(): 取得一個包含匹配的元素集合中每個元素的全部惟一同輩元素的元素集合
例: 依次取得div元素的上下一個同級的全部兄弟元素的個數
$("div").siblings().size()
注意:是不包含自已的同級兄弟集合
圖片顯示:
$("p").show(): 顯示隱藏的匹配元素
$("img").show(5000,function(){})在動畫完成時執行的函數,每一個元素執行一次。
三種預約速度之一的字符串("slow","normal", or "fast")或表示動畫時長的毫秒數值(如:1000).
hide() : 隱藏匹配元素
例:$("img"). hide(5000,function(){})該方法在調用函數時只執行一次
淡入淡出:
fadeOut() :淡出隱蔽圖片(循環顯示,隱藏)
例:$("img").fadeIn(5000); 用緩慢的動畫將隱藏的圖片顯示,歷時5秒。
fadeIn() :淡入顯示圖片(循環顯示, 隱藏)
例: $("img").fadeOut(5000); 用緩慢的動畫將隱藏的圖片顯示,歷時5秒。
滑動:
jquery對象.slideUp(「slow」):向上滑動
例: <div>
中國0<br/>
中國1<br/>
中國2<br/>
中國3<br/>
</div>
$(":button").click(function(){
$("div").slideUp("slow");
});
jquery對象.slideDown():向下滑動
例:$(":button").click(function (){
$("div").slideDown("slow");
});
三種預約速度之一的字符串("slow","normal", or "fast")或表示動畫時長的毫秒數值(如:1000)
jquery對象.toggle() : 切換元素的可見狀態 ,若是元素是可見的,切換爲隱藏的;若是元素是隱藏的,切換爲可見的.
Strust2開發 :
建立步驟:1.導包
struts2-core-2.1.8.1.jar:Struts 2框架的核心類庫
xwork-core-2.1.6.jar :XWork類庫,Struts2在其上構建
ognl-2.7.3.jar :對象圖導航語言(Object Graph Navigation Language),struts2框架經過其讀寫對象的屬性
freemarker-2.3.15.jar :Struts 2的UI標籤的模板使用FreeMarker編寫
commons-logging-1.1.x.jar :ASF出品的日誌包,Struts2框架使用這個日誌包來支持Log4J和JDK 1.4+的日誌記錄。
commons-fileupload-1.2.1.jar 文件上傳組件,2.1.6版本後須要加入此文件
commons-io-1.3.2.jar,上傳文件依賴的jar包
1.配置web.xml文件.
即:<!--配置過濾器-->
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
過濾器文件路徑:
E:\java\開發類庫\struts-2.3.1.1\src\apps\blank\src\main\webapp\WEB-INF
2. 配置struts.xml文件放在src目錄下:經過struts.xm文件通知struts框架的進行業務處理.
同web.xml文件通知web服務器.
struts.xml文件路徑E:\java\開發類庫\struts-2.3.1.1\src\core\src\test\resources
即: <!--聲明惟一的包名,主要用戶裝配aciton類 -->
<struts>
<package name="default"/> <!—包名-->
<action name="HelloWorldAction" class="cn.web.itcast.HelloWorldAction " method="helloMethod"/> <!—加載時所需的類的名稱及類所在的路徑-->
</struts>
3.部署web服務器,通知瀏覽器訪問.
4.部署web應用時, StrutsPrepareAndExecuteFilter類就已經被實例化,相關的文件也加載造成javaBean對象Struts-default.xml(框架),struts.xml,每次部署web應用時,都會加載最新的xml到內存中的javaBean對象中,javaBean主要封裝的是配置strust.xml文件中的屬性如(<action>標籤中的name,method,class屬性).
訪問方式: /Package中的namespace屬性值/action中name屬性
配置名稱空間namespace
<constant name="struts.action.extension"value="action,qq,xx,,"/>
例如:http://127.0.0.1:8080/day32/xx/yy/zz/TestAction回車,且namespace="/"(默認)
>>去/xx/yy/zz的name包名下查詢是否有HelloWorldAction存在,若是不存在,
>>若是再找不到,返回404面頁
例:http://127.0.0.1:8080/day32/xx/yy/zz/HelloWorldAction回車,
且namespace="/xx/yy/zz"(自定義)
那麼訪問該Action有且只能一種方式
:http://127.0.0.1:8080/day32/xx/yy/zz/HelloWorldAction回車
5,若是項目中,你要使用框架默認的Action,
struts2的默認action是ActionSupport類,若是要用它,必須繼承struts2的"struts-default"包
即:須要繼承struts-default包.此時調用的是struts-default包中默認的excecut()方法,經過success.jsp頁面回顯示信息. 此時須要配置<result>,並指明屬性name=」execute()的返回字符串」,訪問路徑
須要在struts.xml文件中配置以下信息:
<package name = 「default」 extends="struts-default">
<action name=」HelloWorldAction(類名)」/>
<result name="success(方法名)" type="dispatcher(跳轉頁面方式)">
/WEB-INF/success.jsp(訪問路徑)
</result>
</package>
此時能夠直接訪問: http://127.0.0.1:8080/day32/HelloWorldAction
6.轉發:在struts.xml文件中配置以下代碼:
<struts><!-- 聲明惟一的包名,主要用戶裝配aciton類 namespace爲包名的命名空間-->
<package name="default"namespace="/" extends="struts-default">
<default-action-refname="HelloWorldAction"/><!—錯誤utl處理路徑-->
<action name=" HelloWorldAction">
<result name="success(轉發的文件名)" type="dispatcher(跳轉頁面的方式)">
/WEB-INF/success.jsp(轉發的頁面)
</result>
</action>
</package>
</struts>
7.配置錯誤URL路徑的處理方式:
<default-action-refname="HelloWorldAction"/>,相似於缺省Servlet。
默認的url路徑主要是在當訪問的路徑不存在是,經過默認的路勁找到默認的類,而後經過<result name=」success」type=」dispater」>標籤中指定的路徑名和路徑訪問seccess.jsp顯示信息.
1).若是不配置method屬性,默認是execute()方法,前提是在程序員本身定義的Action類中有excetue()方法若是沒有該方法則會出錯(404),是由於在訪問時默認的類找不到方法. 若是定義的類中沒有該方法execute()方法,則在<action>標籤中必定要寫屬性method=」方法名」 .
2) <result>標籤中type屬性能夠不寫,默認是轉發dispater
3) <result>標籤中不配置name屬性,默認是success
8訪問Action能夠有擴展名,擴展名默認是.action(小寫),也能夠使用無擴展名的訪問路徑.
能夠經過本身手動在struts.xml中配置標籤的擴展名:以下
<constantname="struts.action.extension" value="action,qq,xx,,"/>
能夠在src/目錄下,寫一個名字struts.properties的必屬性文件,去[覆蓋]系統default.properties文件中的屬性參數 , 屬性文件配置: struts.action.extension=」action,aa,bb,,」
當strust.properties文件和default.properties文件內容突衝時,strtus.properties起決定做用
9項目中,能夠使用strust.properties或struts.xml文件,配置擴展名等相關屬性參數,struts.properties文件起決定做用
程序員自定的文件,會覆蓋框架的默認配置文件(default.properties)
10. strust2框架中,能夠經過總的struts.xml文件,加載各個模塊的分xml文件,總的struts.xml文件有且必須放在src目錄下,其它xml文件,放置任意類路徑下,即src目錄下。
例: <include file="cn/itcast/web/struts2/config/default_struts.xml"/>
<include file="cn/itcast/web/struts2/config/user_struts.xml"/>
<include file="cn/itcast/web/struts2/config/both_struts.xml"/>
11.struts2中的action採用非單例模式(原型模式),每次請求,都會產生一個實例。
ActionContext:數據中心
Api:
ServletActionContext.getRequest();取得request域對象:
servletActionContext.getRequest().getMethod();取得提交方式
servletActionContext.getRequest(); 取得HttpServletrequest
servletActionContext.getSession(),取得HttpSession
Map<String, Object> sessionMap =ActionContext.getContext().getSession();
經過session域對象取得map集合
6 struts2數據格式驗證----手工驗證篇
1)類繼承ActionSupport類,重寫validate()方法或添加validateLoginMethod()方法
2)在struts.xml文件的某個<action/>標籤中,配置input屬性值,表示出錯後,轉在的頁面
3)在頁面中經過以下二種方法將,錯誤消息按指定的格式輸出
>><s:fielderrors/>
>><s:form/>和<s:textfield/>和<s:password/>(推薦)
Action:特有的標籤校驗表單提交的數據
<s:form action="/RegisterAction"method="post">
<s:textfield label="用戶名" name="username"/>
<s:password label="密碼" name="password"/>
<s:submit value="註冊"/>
</s:form>
4)validate()方法,是檢證UserAction中全部的業務方法,即與execute()一樣簽名的方法,例如registerMethod()
5)validateLoginMethod()方法,能夠爭對UserAction中的loginMethod()業務方法驗證,其它方法不驗證
6)當validate()和validateLoginMethod()方法同時存在時,先執行validateLoginMethod()方法,再執行validate()方法,若是驗證成功,到達值得的LoginMethod()方法的中的return 「success」 返回文件名,過濾器根據該文件名查找顯示信息的文件路徑(如:/WEB-INF/success.jsp),最終以標籤<s: property value=」username」>獲取顯示信息,
7)只有當validateLoginMethod()方法和validate()方法驗證都成功了,才能執行UserAction的業務方法loginMethod()到達指定的頁面顯示結果,不然都會轉發到struts.xml中的<result>標籤的input屬性所指明的頁面
例:
<result name="input" type="dispatcher">
/WEB-INF/success.jsp
</result>
7 struts2經常使用標籤總結
<s:property value="ip"/> 從request域對象中獲取校驗信息
<s:fielderrors/> 從數據校驗中心獲取顯示錯誤信息,即ActionContext中
<s:form/> 表單提交標籤
<s:textfield/> 該標籤提交文本數據
<s:submit/>經過配合使用 ,判斷提交的數據是否符合指定的規則,是返回true, 非返回false
例:
<body>
<s:form action="UploadAction"method="post" enctype="multipart/form-data">
<s:textfield label="上傳用戶" name="username"/>
<s:file label="上傳文件1" name="uploadFile"/>
<s:file label="上傳文件2" name="uploadFile"/>
<s:submit value="上傳"/>
</s:form>
</body>
<s:text/>國際化
<s:param/>國際化
例:
<s:text name="hello">
<s:param>傑克</s:param> //設置配置文件(*.properties)中的屬性值
<s:param>北京</s:param>
</s:text>
<s:file/>選擇文件
8 struts.xml文件中的屬性總結
<package
name="user(包名,在整個web應用是惟一,必須)"
namespace="/(包所在的訪問空間,可選,默認/)"
extends="struts-default(擴展框架內置包,可選)">
<!-- 配置RegisterAction -->
<action
name="RegisterAction(訪問的路徑,必選)"
class="cn.itcast.web.struts2.action.RegisterAction(處理類的全路徑,可選,默認ActionSupport)"
method="registerMethod(類的須要執行的方法,可選,默認execute)">
<result
name="success(Action類中方法返回值,可選,默認success)"
type="dispatcher(跳轉的方式,重定向或轉發,可選,默認轉發">
/WEB-INF/success.jsp(跳轉的真實路徑)
</result>
</action>
</package>
虛擬目錄的配置:
1. 在server.xml中配置,增長一個<host></host>標籤,即該server.xml文件中的<host>,而後對其修改屬性.
2必須修改該標籤中的屬性name =」虛擬路徑名」appBase=」工程所放置的位置」.
配置<Contextpath=」/工程所映射的URL路徑(可選若是不寫,默認爲映射的URL路徑)」 docBase=」工程所存放的實際路徑」 /> 標籤,
例如:在瀏覽器中訪問的域名www.bbs.com. , 工程存放在e盤下的bbs文件夾下的day25.
<Host name="www.bbs.com" appBase="E:\bbs"
unpackWARs="true"autoDeploy="true"
xmlValidation="false"xmlNamespaceAware="false">
<Context path=""docBase="E:\bbs\myday25"/>
</Host>
3.在system32--->divers-àextà host文件中配置域名對應的訪問主機 例如: www.bbs.com.對應的主機 127.0.0.1
4.在web.xml中配置須要訪問的首頁例如:
<web-app>
<welcome-file-list>
<welcome-file>welcome.jsp</welcome-file>
</welcome-file-list>
</web-app>
配置完畢,此時能夠直接訪問www.bbs.com
文件上傳
1)上傳表單的三要素:
>>enctype="multipart/form-data":表示將上傳的文件,隨請求體,一塊兒傳到服務端
>>method="post"
>>name="uploadFile"爲每一個表單項,取個名字,便於Action收集
2)框架自身有fileUpload文件上傳攔截器,但無文件下載攔截器
框架使用jakarta commons fileupload開源上傳類來完成文件上傳
框架默認的上傳文件[總]大小爲2M
3)fileUpload攔截器,自動注入三個參數,
>>uploadFile 臨時文件
>>uploadFileFileName真實文件名 定義方式是jsp頁面file組件的名稱+FileName
>>uploadFileContentType上傳文件類型, 定義方式是jsp頁面file組件的名稱+ContentType,
注意:uploadFile爲表單上傳項的名字,<s:file name="uploadFile"/>
4)上傳文件細節
如下上傳文件中參數查找: struts2-core-2.3.1.1.jar-àstruts-default.xml (包含文件的大小,類型,後綴)
總的文件大小及國際化文件的查找: struts2-core-2.3.1.1.jar-à org.apache.struts2 à static àdefault.properties
<constant name="struts.multipart.maxSize"value="15728640"/>
<constantname="struts.custom.i18n.resources"value="cn/web/struts/fileload/file"/>
<package name="fileload"namespace="/" extends="struts-default">
<action name="UploadAction"class="cn.web.struts.fileload.UploadAction" method="uploadMethod">
<result name="SUCCESS"type="dispatcher">
/WEB-INF/success.jsp
</result>
<result name="input" type="dispatcher"><!—錯誤時,同過input標籤找到顯示錯誤信息的路徑->
/WEB-INF/message.jsp
</result><!—臨時文件的存儲路徑-->
<param name="uploadPath">d:\</param>
<interceptor-ref name="fileUpload">
<!-- 上傳單個文件的大小 -->
<param name="maximumSize">307200</param>
<!-- 文件的擴展名 -->
<param name="allowedExtensions">.jsp</param>
<!-- 文件的類型 -->
<param name="allowedTypes">image/pjpeg</param>
</interceptor-ref><!—默認的攔截器-->
<interceptor-ref name="defaultStack"/>
</action>
</package>
>>上傳文件的臨時文件存放和刪除
在try..catch..finally中經過uploadFile.delete();
>>上傳文件總大小限制
<constant name="struts.multipart.maxSize"value="15728640"/> 15M
>>上傳文件單大小限制
<!-- 上傳單個文件大小不得超過2M -->
<param name="maximumSize">2097152</param>
>>上傳文件擴展名限制
<!-- 上傳單個文件的擴展名爲.jpg或.txt -->
<param name="allowedExtensions">.jpg,.txt</param>
>>上傳文件類型限制
<param name="allowedTypes">image/pjpeg</param>
*5)在默認的狀況下,每一個<action/>標籤都有一個默認的defaultStack攔截器棧(18個攔截器),
若是你顯示聲明瞭使用某個攔截器,那麼攔截器棧將不會被引用,相似於類的空參構造方法
6)在默認的狀況下,框架會自動找框架默認的屬性資源文件的提示信息,若是你讓框架找自定義的屬性資源文件信息,要覆蓋系統的:
(1)<constant name="struts.custom.i18n.resources"value="cn/itcast/web/struts/upload/xx"/>
(2)在任意目錄下,寫一個*.properties的資源文件,裏面覆蓋框架的提示信息,注意,key不能修改
(從struts2-core-2.3.1.1.jar包下的default.properties文件中粘貼)
2欄截器,欄截器棧,相似於Filter
定義自定義攔截器的步驟
1.自定義攔截器類實現Interceptor
2.在 struts.xml 文件中配置自定義的攔截器
例:
<package name="login" namespace="/" extends="struts-default">
<interceptors > //攔截器的聲明
<interceptorname="LoginInterceptor"class="cn.web.struts.login.LoginInterceptor"/>
</interceptors>
<action name="LoginAction"class="cn.web.struts.login.LoginAction" method="loginMethod">
<result name="success">
/WEB-INF/success.jsp
</result>
<result name="input">
/WEB-INF/message.jsp //錯誤轉到的頁面
</result>
<interceptor-ref name="defaultStack"/> //默認攔截器
<interceptor-refname="LoginInterceptor"></interceptor-ref>//攔截器的引用,必須在action標籤中
</action>
</package>
自定義攔截器類:
public class LoginInterceptor implements Interceptor{
public String intercept(ActionInvocationinvocation) throws Exception {
System.out.println(invocation.getAction());
System.out.println(invocation.invoke());
//取得攔截器所攔截的action類
Object obj = invocation.getAction();
if(obj instanceof LoginAction){
//經過ActionContext取得sessionMAp
Map<String, Object> sessionMap = invocation.getInvocationContext().getSession();
String username = (String) sessionMap.get("username");
if(username!=null){
return "success";//至關於執行了一次loginmethod()方法
}else{
return "loginJsp";
}
}
return null;
}
}
1)框架defaultStack中有18個攔截器,選引用的攔截器先被執行,若是第一個攔截器未能過,是否會進行第二個攔截器
2)若是要引用defaultStack外的攔截器,須要在<action/>標籤內經過以下代碼聲明:
<interceptor-refname="攔截器的類名"/>
3)攔截器相似於Filter,能夠進行預處理和後處理
4)攔截器在部署web應用是建立並初始化攔截器,
每請求一次LoginAction,都會被攔截攔截
攔截器須要攔截哪一個Action,就只須要在該<action/>標籤中引用便可(重點)
從新部署時,框架會先銷燬原攔截器,再建立新的攔截器
5)攔截器是惟一的一個實例爲每一個客戶端服務,單例模式
6)經常使用的API
>>Object obj =invocation.getAction();返回攔截的Action類名
>>invocation.getInvocationContext();返回ActionContext對象,從而能夠取得HttpSesison,ServletContext等域對象
>>String msg = invocation.invoke();返回攔截Action中業務方法的返回值,例如"success"字符串
ActionInvocation: 表明一個給定動做的執行狀態, 攔截器能夠從該類的對象裏得到與該動做相關聯的 Action 對象和 Result 對象. 在完成攔截器本身的任務以後, 攔截器將調用 ActionInvocation 對象的 invoke 方法前進到 Action 處理流程的下一個環節,相似於chain.doFilter()。
注意:攔截器中的"字符串"相似於Filter中的chain.doFiter()
3 國際化: 配置.properties文件,將須要改變的值經過建和值的關係在該文件中寫出,中文時須要編碼(utf-8),當部署web引用時,該文件會自動加載,在訪問的頁面中只須要經過鍵引入便可. 注:在配置屬性文件時不能有空格.
例: 鍵=值
username=\u7528\u6237\u540D
password=\u5BC6\u7801
4 結果類型和異常處理
1)經常使用的結果類型;
>>dispatcher //轉發到指定的頁面
>>redirect //重定向到指定的頁面
>>redirectAction //重定向到其餘的Action
2)當每一個<action/>標籤中,都有相同時結果類型,能夠將其配置成全局結果類型;
3)當局部結果類型和全局結果類型衝突時,局部結果類型優先(在<action/>標籤中配置的<result/>叫局部結果類型),在<global-results>標籤中配置的<result/>叫,全局結果類型.
4)當異常發生時,捕獲的是子異常,若是無子異常,捕獲的是父異常.
5)當局部異常類型和全局異常類型衝突時,局部異常類型優先.
6)若是局部異常是父類,全局異常是子類,此時捕獲的全局異常
7)在異常體系中,子異常優先。
<package name="result" namespace="/" extends="struts-default">
<!-- 配置全局結果 -->
<global-results>
<result name="success"type="dispatcher">
/WEB-INF/result_success.jsp
</result>
<result name="sonResultInner"type="dispatcher">
/WEB-INF/son.jsp
</result>
<result name="sonResultOutter"type="dispatcher">
/WEB-INF/father.jsp
</result>
</global-results>
<!-- 配置全局異常 -->
<global-exception-mappings>
<exception-mapping result="sonResultOutter"exception="java.lang.ArithmeticException"/>
</global-exception-mappings>
<!-- FromAction配置 -->
<action name="FromAction"class="cn.itcast.web.struts.result.FromAction">
<result name="goToAction"type="redirectAction">
<!-- 須要重定向到另外一個action標籤的name屬性值 -->
<paramname="actionName">ToAction</param>
<paramname="namespace">/</param>
<paramname="method">execute</param>
</result>
</action>
<!-- ToAction配置 -->
<action name="ToAction"class="cn.itcast.web.struts.result.ToAction">
<!-- 配置局部結果 -->
<result name="success"type="dispatcher">
/WEB-INF/local_success.jsp
</result>
<!-- 配置局部異常-->
<exception-mapping result="sonResultInner"exception="java.lang.Exception"/>
</action>
</package>
類型轉換器
1)HTTP請求,只有String或String[]類型,無其它類型,例如沒有Integer,Address類型
2)在默認狀況下,攔截器自動將String或String[]類型,轉成8種類型數據類型,例如String轉成Float類型
3)在默認狀況下,框架支持String類型轉成日期類型,但字符串格式必須是yyyy-MM-dd這種形式。框架也能
驗證輸入日期字符串的合法性
自定義類型轉換器
1)可以決定String轉成任意JavaBean類型。
自定義轉換器步驟:
1.1類 繼續 StrutsTypeConverter類 , 複寫該類中的方法
public Object convertFromString(Map context,String[] values, Class toClass) {};
values:表示表單提交時傳入須要轉換的字符串
例如: 在表中提交的地址:
<s:textfield label="地點" name="address"value="廣州-越秀-越秀路"/>"廣州-天河-越秀路"
toClass: 表示須要轉換的類的字節碼.例如:"cn.itcast.web.type.Address"
public String convertToString(Map context,Object obj) {}
obj:表示通過轉換後的javaBean實例 : 例如: "cn.itcast.web.type.Address"
例: 地址的轉換器
public class AddressConverter extends StrutsTypeConverter{
public Object convertFromString(Map context,String[] values, Class toClass) {
System.out.println("字符串轉換JavaBean");
//System.out.println(context);
//System.out.println(values[0]);"廣州-天河-東圃"
//System.out.println(toClass);"cn.itcast.web.type.Address"
if(toClass == Address.class){
String msg = values[0];
//以"-"拆分字符串
String[] all = msg.split("-");
String city = all[0];
String area = all[1];
String brt = all[2];
//封裝成JavaBean對象
Address address = new Address(city,area,brt);
return address;
}
return null;
}
public String convertToString(Map context,Object obj) {
System.out.println("JavaBean轉換字符串");
//System.out.println(context);
//System.out.println(obj);"cn.itcast.web.type.Address"
if(obj instanceof Address){
//將obj強轉成Address類
Address address = (Address) obj;
//將Address轉成String
return address.toString();
}
return null;
}
}
1.2.在IDE工具的src目錄下新建一個xwork-conversion.properties文件,裏面的內容爲:
JavaBean的全路徑=自定義類型轉換器的全路徑,例如
cn.itcast.web.struts2.type.Address=cn.itcast.web.struts2.type.AddressConverter
驗證的xml文件的規範在xwork-core-2.1.6.jar包下的:xwork-validator-1.0.2.dtd
驗證文件的命名
在這個校驗文件中,對action中字符串類型的username屬性進行驗證,首先要求調用trim()方法去掉空格,而後判斷用戶名是否爲空。該文件須要和action類放在同一個包下,文件的取名應遵照ActionClassName-validation.xml規則,其中ActionClassName爲action的簡單類名,-validation爲固定寫法。
2 基於XML文件的聲明式驗證
1)可以解決用聲明式方式替換手工validate()和validateLoginMethod()這二個方法
2)validate()等價於UserAction-validation.xml文件,其中User Action是類名
validateLoginMethod()等價到UserAction-Login-validation.xml文件,其中Login爲<action/>標籤的name屬性
3)規則這二個xml文件,必須放置在與UserAction類同級的目錄下
4)先執行UserAction-validation.xml文件,再執行UserAction-Login-validation.xml文件,不是後者替換前者,
而是二個驗證文件共同做用的結果(交集)。
5)UserAction-validation.xml爭對該Action中全部的業務方法驗證,所以該xml文件中出現全部業務方法的共同字段
UserAction-Login-validation.xml爭對該Action中登陸業務方法驗證,所以該xml文件中出現登陸的特有字段
<validators>:根元素
<field>:指定action中要校驗的屬性,name屬性指定將被驗證的表單字段的名字
<field-validator>:指定校驗器, type 指定驗證規則
上面指定的校驗器requiredstring是由系統提供的,系統提供了能知足大部分驗證需求的校驗器,這些校驗器的定義能夠在xwork-2.x.jar中的com.opensymphony.xwork2.validator.validators下的default.xml中找到。
<param>:子元素能夠向驗證程序傳遞參數
<message>:子元素爲校驗失敗後的提示信息,若是須要國際化,能夠爲message指定key屬性,key的值爲屬性文件中的key。
例如: UserAction-Register-validation.xml文件中的校驗方式:
<!-- 只爭對UserAction中註冊業務方法進行驗證 -->
<validators>
<field name="username">
<field-validator type="regex">
<param name="trim">true</param>
<param name="expression">^[\u4E00-\uFA29]+$</param>
<message>[用戶名必填是中文]</message>
</field-validator>
</field>
<field name="password">
<field-validator type="regex">
<param name="trim">true</param>
<param name="expression">^[0-9]{8}$</param>
<message>[密碼必須是8位數字]</message>
</field-validator>
</field>
<field name="salary">
<field-validator type="required">
<param name="trim">true</param>
<message>[薪水必填]</message>
</field-validator>
<field-validator type="int">
<param name="trim">true</param>
<param name="min">4000</param>
<param name="max">6000</param>
<message>[薪水必須介於${min}到${max}之間]</message>
</field-validator>
</field>
</validators>
驗證規則:
2 required: 確保某給定字段的值不是空值 null
3 requiredstring: 確保某給定字段的值既不是空值 null, 也不是空白.
• trim 參數. 默認爲 true, 表示 struts 在驗證該字段值以前先剔除先後空格.
4 stringlength: 驗證一個非空的字段值是否是有足夠的長度.
• minLength: 相關字段的最小長度. 若沒有給出這個參數, 該字段將沒有最小長度限制
• maxLength:相關字段的最大長度. 若沒有給出這個參數, 該字段將沒有最大長度限制
• trim: 在驗證以前是否去除先後空格
5 int: 檢查給定字段的值是否能夠被轉換爲一個整數
• min: 相關字段的最小值. 若沒給出這個參數, 該字段將沒有最小值限制
• max: 相關字段的最大值. 若沒給出這個參數, 該字段將沒有最大值限制
6 date: 確保某給定日期字段的值落在一個給定的範圍內
• max:相關字段的最大值. 若沒給出這個參數, 該字段將沒有最大值限制
• min:相關字段的最小值. 若沒給出這個參數, 該字段將沒有最小值限制
7 email: 檢查給定 String 值是不是一個合法的 email
8 url: 檢查給定 String 值是不是一個合法的 url
9 regex: 檢查某給定字段的值是否與一個給定的正則表達式模式相匹配.
• expression: 用來匹配的正則表達式
• caseSensitive: 是否區分字母的大小寫. 默認爲 true
• trim: 是否去除先後空格. 默認爲 true
當校驗文件的取名爲ActionClassName-validation.xml時,會對 action中的全部處理方法實施輸入驗證。
若是你只須要對action中的某個action方法實施校驗,那麼,校驗文件的取名應爲ActionClassName-ActionName-validation.xml,其中ActionName爲struts.xml中action的name屬性值
UserAction中有如下兩個處理方法:
public Stringadd() throws Exception{
....
}
public Stringupdate() throws Exception{
....
} <action的name屬性值/>
要對add()方法實施驗證,校驗文件的取名爲: UserAction-addAction(<action的name屬性值/>)-validation.xml
要對update()方法實施驗證,校驗文件的取名爲: UserAction-updateAction(<action的name屬性值/>)-validation.xml
OGNL表達式語言:
OGNL是ObjectGraphic Navigation Language(對象圖導航語言)的縮寫,它是一個開源項目。Struts2框架使用OGNL做爲默認的表達式語言,而不是EL。
OGNL表達式能夠完成:
一、訪問OGNL上下文(OGNL context)和Action Context;
二、操做集合對象
3 理解OGNL(對象圖導航語言)
1)EL只能在JSP中使用。一般EL可取域對象中的屬性值,例如${sessionScope.username}
2)OGNL(對象圖導航語言),成爲struts2的默認導航語言,相似於EL。
3)ValueStack是一個接口,OGNLValueStack是實現類,
4)valueStack是每個Action的數據中心,一旦Action建立,ValueStack就建立了,放在request域對象中,
一旦Action銷燬,ValueStack就銷燬,Action和ValueStack隨request的結束而銷燬
5)值棧分爲二部分,一部分是裝List類型的數據,一部份裝Map類型的數據
在 ValueStack 對象的內部有兩個邏輯部分:
• ObjectStack: Struts把動做和相關對象壓入 ObjectStack 中--List
• ContextMap: Struts把各類各樣的映射關係(一些 Map 類型的對象) 壓入 ContextMap 中
Struts 會把下面這些映射壓入 ContextMap 中
• parameters: 該 Map 中包含當前請求的請求參數
• request: 該 Map 中包含當前 request 對象中的全部屬性
• session: 該 Map 中包含當前 session 對象中的全部屬性
• application:該 Map 中包含當前 application 對象中的全部屬性
• attr: 該 Map 按以下順序來檢索某個屬性: request, session, application
6)<s:property/>在默認狀況下,只取值棧中的內容
7)非值棧中取值,須要經過#域對象的名字
attr去如下域對象中查詢,找到即此:
page->request->valuestack->session->application->空白字符串
例: 從不一樣的域對象中取值username,此時若是須要在每一個域中都查詢,須要加#查找.
ServletActionContext.getRequest().setAttribute("username","request_username");
ActionContext.getContext().getSession().put("username","session_username");
ServletActionContext.getServletContext().setAttribute("username","context_username");
ActionContext.getContext().getValueStack().set("username","value_username");
reqeust: <s:property value="#request.username"/><br/>
valuestack: <s:propertyvalue="#attr.username"/><br/>
session: <s:propertyvalue="#session.username"/><br/>
appliaction:<s:property value="#application.username"/><br/>
8)非值棧中取得,加#,就算是JavaBean對應,也須要經過#來取值
9)#號的語法: 如#{‘foo1’:‘bar1’,‘foo2’:‘bar2’}。
集合的過濾
1) 集合的過濾有如下三種方式:
a.「?#」:過濾全部符合條件的集合,如:users.{?# this.age > 19};
b.「^#」:過濾第一個符合條件的元素,如:users.{^# this.age > 19};
c.「$#」:過濾最後一個符合條件的元素,如:users.{$# this.age > 19} 。
.2) this 表示集合中的元素;
語法一: 從list集合中取出名username的全部用戶
<s:iterator var="username"value="#request.userList.{username}">
<s:propertyvalue="#username"/>
</s:iterator>
語法二:從list集合中取出年齡大於30的全部用戶
<s:iterator var="username"value="#request.userList.{?#this.age>=30}">
表示只輸入age>=30的用戶,
?#表示輸出全部用戶
^#表示輸出第一行用戶
$#表示輸出最後行用戶
this表示當前須要迭代的JavaBean
<s:propertyvalue="#username"/>
</s:iterator>
語法三:從list集合中取出年齡大於30的第一個用戶
<s:iterator var="user"value="#request.userList.{^#this.age>=30}[1]">
[0]表示第一行記錄
[n]表示第n+1行記錄
<s:propertyvalue="#user.username"/>---->
<s:propertyvalue="#user.age"/><br/>
</s:iterator>
語法四:從list集合中取出最後一個用戶
<s:iterator var="user" value="#request.userList.{$#this.age>=30}">
[0]表示第一行記錄
[n]表示第n+1行記錄
<s:propertyvalue="#user.username"/>---->
<s:propertyvalue="#user.age"/><br/>
</s:iterator>
10)%號語法
「%」符號的用途是在標籤的屬性值被理解爲字符串類型時,告訴執行環境%{}裏的是OGNL表達式。
語法一:
ActionContext.getContext().getValueStack().set("usernameTip","[用戶名]");
<s:textfield label="%{usernameTip}"name="username"/>
語法二:
<s:textfieldlabel="%{'usernameTip'}" name="username"/>此時usernameTip爲常量
11)$號語法
語法一:
${}能夠出如今xml文件中
<param name="min">1000</param>
<paramname="max">5000</param>
<message>薪水必須是${min}-${max}</message>
property標籤用於輸出指定值:
<s:property value=「#name"default="a default value" />
default:可選屬性, 若是須要輸出的屬性值爲null,則顯示該屬性指定的值
escape:可選屬性,指定是否格式化HTML代碼。
value: 可選屬性,指定須要輸出的屬性值,若是沒有指定該屬性,則默認輸出ValueStack棧頂的值。
例:
<%
pageContext.setAttribute("username","<a href='/myday34/login.jsp'>超連接</a>");
%> <!—從context域對象中取出用戶信息,設置不轉義-->
<s:property value="#attr.username"default="訪問頁面不存在" escapeHtml="false"/>
Set 語法:
set標籤用於將某個值放入指定範圍。
var:變量的名字,name,id和var表達的含義是同樣的,name,id被var替代
scope:指定變量被放置的範圍,該屬性能夠接受application、session、request、 page。若是沒有設置該屬性,則默認放置在action中,即值棧。
value:賦給變量的值.若是沒有設置該屬性,則將ValueStack棧頂的值賦給變量
例:
<%
request.setAttribute("password", "654321");
%>
<s:set var="code" value="#request.password" scope="session"/>
密碼:<s:property value="#session.code"/>
Iterator:語法:
Iterator:標籤用於對集合進行迭代,這裏的集合包含List、Set,Map和數組。
value:可選屬性,指定被迭代的集合,若是沒有設置該屬性,則使用ValueStack棧頂的集合。
var: 可選屬性,引用變量的名稱.
status:可選屬性,該屬性指定迭代時的IteratorStatus實例。該實例包含以下幾個方法:
int getCount(),返回當前迭代了幾個元素。
int getIndex(),返回當前迭代元素的索引。
boolean isEven(),返回當前被迭代元素的索引是不是偶數
boolean isOdd(),返回當前被迭代元素的索引是不是奇數
boolean isFirst(),返回當前被迭代元素是不是第一個元素。
boolean isLast(),返回當前被迭代元素是不是最後一個元素。
<body>
<%
List<User> userList = new ArrayList<User>();
userList.add(new User("張三",13));
userList.add(new User("李四",25));
userList.add(new User("王五",27));
userList.add(new User("哈哈",30));
session.setAttribute("userList",userList);
%>
<table border="1" align="center">
<tr >
<td>序號</td>
<td>索引號</td>
<td>用戶名</td>
<td>年齡</td>
<td>最後一行</td>
<td>第一行</td>
</tr>
<s:iterator var="user" value="#session.userList" status="sta" begin="0" end="2">
<tr style='color:<s:property value="#sta.odd?'red':'blue'"/>'>
<td><s:property value="#sta.count"/></td>
<td><s:property value="#sta.index"/></td>
<td><s:property value="#user.username"/></td>
<td><s:property value="#user.age"/></td>
<td><s:property value="#sta.last"/></td>
<td><s:property value="#sta.first"/></td>
<td>
<s:if test="#user.age<20">
少年
</s:if>
<s:elseif test="#user.age>20&& #user.age<40">
中年
</s:elseif>
<s:else>
老年
</s:else>
</td>
</tr>
</s:iterator>
</table>
List 語法:
<%
List<User> userList = new ArrayList<User>();
userList.add(new User("張三",13));
userList.add(new User("李四",25));
pageContext.setAttribute("userList",userList);
%>
集合是否爲空: <s:property value="#attr.userList.isEmpty"/><br/>
集合的長度: <s:property value="#attr.userList.size"/>
<hr/>
<s:iterator var="list" value="{'one','tow','three'}">
<s:property value="list"/><br/>
</s:iterator>
全部使用到的標籤總結:
textfield 標籤將被呈現爲一個輸入文本字段, password 標籤將被呈現爲一個口令字段,hidden 標籤將被呈現爲一個不可見字段
password 標籤擴展自 textfield 標籤, 多了一個 showPassword 屬性.該屬性是布爾型.
默認值爲 false, 它決定着在表單回顯時是否顯示輸入的密碼. true顯示密碼
<body>
<s:form method="post" action="#" theme="xhtml">
<s:textfield label="用戶名" name="username"/>
<s:password label="密碼" name="password"/>
<s:radio label="性別" name="gender" list="{'男','女'}" value="'女'"></s:radio>
<s:checkboxlist label="愛好" name="like"
list="#{'sing':'唱歌','dance':'跳舞','play':'打球' }"listKey="key" listValue="value" value="{'play','sing'}"/>
<s:select label="省份" name="province"list="{'廣東省','陝西省'}" value="'廣東省'"/>
<s:select label="城市" name="city" list="{'西安市','廣州市'}" value="'廣州市'"/>
<%
List<Area> areaList = new ArrayList<Area>();
areaList.add(new Area(1,"天河區"));
areaList.add(new Area(2,"越秀區"));
pageContext.setAttribute("areaList", areaList);
%>
<s:select label="地區" name="area" list="#attr.areaList" listKey="id" listValue="area" value="'2'"/>
<s:textarea label="文本框" name="留言板"/>
<s:submit value="確認"/>
<s:reset value="重置"/>
</s:form>
</body>
5 Struts2主題更換
1)有四種不一樣的風格:
>>simple(無table>
>>xhtml(默認)(有table)
>>css_xhtml(無table有div+css)
>>ajax
2)局部優先
一、simple: 把 UI 標籤翻譯成最簡單的 HTML 對應元素, 並且會忽視行標屬性
二、xhtml: xhtml 是默認的主題. 這個主題的模板經過使用一個佈局表格提供了一種自動化的排版機制.
三、css_xhtml: 這個主題裏的模板與xhtml 主題裏的模板很類似, 但它們將使用 css 來進行佈局和排版
四、ajax: 這個主題裏的模板以xhtml 主題裏德模板爲基礎, 但增長了一些 Ajax 功能.
修改主題:
A、經過 UI 標籤的theme屬性(只適用於當前的標籤)
<s:textfieldname="username" label="用戶名「theme="simple"></s:textfield>
B、在一個表單裏, 若沒有給出某個 UI 標籤的 theme 屬性, 它將使用這個表單的主題
(適用於整個form標籤)
<s:form action="" method="post"namespace="/ui「 theme="simple">
C、修改 struts.properties 文件中的 struts.ui.theme 屬性. (適用整個環境)
<!-- 設置ui標籤的主題-->
<constant name="struts.ui.theme"value="simple"></constant>
優先級:A > B > C
*6 Struts2表單重複提交
1)在表單中使用<s:token/>這個標籤,來產生客戶端和服務端session中惟一的編號
2)在<action/>標籤中顯示引用token攔截器,由於token攔截器不是默認棧中的攔截器,
同時最好顯示引用defaultStack攔截器棧。
例: token_struts.xml文件配置
<s:form action="TokenAction"method="post">
<s:token />
<s:textfield label="用戶名" name="username"/>
<s:password label="密碼" name="password"/>
<s:submit value="token表單重複提交驗證"/>
</s:form>
</body>
<!—配置token_struts.xml文件 -->
<struts>
<package name="token" namespace="/" extends="struts-default">
<action name="TokenAction"class="cn.itcast.web.struts2.token.TokenAction" method="execute">
<result name="success"type="dispatcher">
/WEB-INF/token_success.jsp
</result><!—防止表單重複提交token配置 -->
<result name="invalid.token"type="dispatcher">
/WEB-INF/bad.jsp
</result> <!—顯示引用默認攔截器 -->
<interceptor-ref name="defaultStack"/>
<!-- 引用token攔截器 -->
<interceptor-ref name="token"/>
</action>
</package>
</struts>
Hibernate:
1 ORM思想與hibernate實現
1)JDBC或DBUtils框架有何缺點?
jdbc/dbutil/hibernate主要解決持久層的常見問題
jdbc不足:
原jdbc代碼中,出現了面向關係的代碼,例如:String sql = "select * from customers表";
原jdbc代碼中,關係數據(表名或列名)須要不段變化,不能靈活對待,即[動態生成SQL代碼]
原jdbc代碼中,對象(O)和關係(R)的操做須要程序員自行解決
dbutil框架不足:
原dbutil代碼中,出現了面向關係的代碼,例如:String sql = "select * from customers表";
原dbutil代碼中,關係數據(表名或列名)須要不段變化,不能靈活對待,即[動態生成SQL代碼]
hibernate框架:
不出現全部的面向關係的代碼,即sql語句
將面向對象的代碼轉換成面向關係的SQL語句,由於關係型數據庫只識別SQL語句,可以動態生成SQL語句
*2 hibernate快速入門
1)開發步驟:
>>導入hibernate相關的10個jar包.
>>建立表:customers.sql
>>建立實體:Customer.java
>>配置過濾器
文件路徑:E:\java\開發類庫\struts-2.3.1.1\src\apps\blank\src\main\webapp\
WEB-INF\web.xml
>>建立Customer.hbm.xml映射文件,目的是通知hibernate框架,如何將實體和表關聯起來
>>建立hibernate.cfg.xml配置文件, 目的是通知hibernate框架,如何鏈接不一樣的數據庫和產生不一樣數據庫的SQL命令
>>測試類:CURD操做(CustomerService)
2具體步驟詳解
>>jar 包:
antlr-2.7.6.jar 一個語言轉換工具,Hibernate利用它實現 HQL 到 SQL 的轉換
commons-collections-3.1.jar collections Apache 的工具集,用來加強Java對集合的處理能力
dom4j-1.6.1.jar dom4j XML 解析器
hibernate3.jar 核心包
javassist-3.9.0.GA.jar 代碼生成工具, Hibernate用它在運行時擴展 Java類
jta-1.1.jar 標準的 JAVA 事務處理接口
log4j.jar 日誌包
mysql-connector-java-5.1.7-bin.jar mysql驅動包
slf4j-api-1.5.8.jar slf4j-log4j12.jar hibernate使用的一個日誌系統
>>建立sql表
例: drop database if exists hibernate;
create database if not exists hibernate;
use hibernate;
drop table if exists customer;
create table if not exists customer(
id int primary key auto_increment,
name varchar(20) default "小小",
age int default 21,
des varchar(100) default "文雅"
);
select * from customer;
>>Customer.hbm.xml文件
1.Hibernate 採用 XML 格式的文件來指定對象和關係數據之間的映射. 在運行時 Hibernate 將根據這個映射文件來生成各類 SQL 語句, 映射文件的擴展名爲 .hbm.xml 如;Customer.hbm.xml文件. 如: 以上Customer.hbm.xml文件是Customer類和customers表的對應關係。該文件前綴必須和類名一致,後綴必須是.hbm.xml。文件位置任意
2. property元素:設定持久化類的屬性和表字段映射
name屬性:指定持久化類的屬性的名字
column屬性:指定表中字段的名稱
type屬性指定Hibernate映射類型 Hibernate映射類型是java類型與SQL類型的橋樑
*.hbm.xml文件的來源:
hibernate-distribution-3.5.6-Final-dist.zip\hibernate-distribution-3.5.6-Final\project\tutorials\web\src\main\resources\org\hibernate\tutorial\domain......
注:該映射文件的規範在org.hibernate.hibernate-mapping-3.0.dtd文件中
例:
Customer.hbm.xml文件的屬性含義:
<hibernate-mappingpackage="cn.itcast.web.hibernate.character0(實體對象的包名)">
<classname="Customer(類名)" table="CUSTOMERS(表名)">
<idname="id" column="ID" type="integer">
<generator class="increment"/>
</id>
<propertyname="name(屬性名)" column="NAME(列名)" type="string(hibernate類型)"/>
<propertyname="age(屬性名)" column="AGE(列名)" type="integer(hibernate類型)"/>
<propertyname="des(屬性名)" column="DES(列名)" type="string(hibernate類型)"/>
</class>
</hibernate-mapping>
>>hibernate.cfg.xml文件
建立 Hibernate 配置文件,Hibernate 從其配置文件中讀取和數據庫鏈接的有關信息, 這個文件應該位於應用的 classpath 下.文件名必須是hibernate.cfg.xml,文件位置任意, 除了使用xml做爲配置文件之除,還能夠使用hibernate.properties文件(項目中不提倡)。
注:該映射文件的規範在org.hibernate.hibernate-configuration-3.0.dtd文件中,文件的來源: hibernate-distribution-3.5.6-Final-dist.zip\hibernate-distribution-3.5.6-Final\project\tutorials\web\src\main\resources
例:
hibernate.cfg.xml文件的屬性含義:
<hibernate-configuration>
<session-factory>
<!-- 配置鏈接數據庫的相關屬性 -->
<propertyname="connection.driver_class">com.mysql.jdbc.Driver(驅動類名)</property>
<propertyname="connection.url">jdbc:mysql://127.0.0.1:3306/hibernate(URL)</property>
<propertyname="connection.username">root(訪問數據庫的用戶名)</property>
<propertyname="connection.password">root(訪問數據庫的密碼)</property>
<!-- 通知hibernate動態生成哪一個數據庫的SQL命令 -->
<propertyname="dialect">org.hibernate.dialect.MySQL5Dialect(數據庫的方言)</property>
<!-- 顯示hibernate動態生成的SQL命令,true表示顯示 -->
<propertyname="show_sql">true(須要顯示sql命令)</property>
<!-- 加載對象和關係的映射文件-->
<mappingresource="cn/itcast/web/hibernate/character0/Customer.hbm.xml(映射文件的類路徑)"/>
</session-factory>
</hibernate-configuration>
>>Configuration類:
是hibernate中一個用於加載hibernate.cfg.xml文件的類,config .config(「xml文件的類路徑」)方法可以加載指定目錄下的hibernate.cfg.xml文件,config.buildSessionFactory()建立一個SessionFactory工廠。該工廠有大量空閒的session.
Configuration 類負責管理Hibernate 的配置信息。包括以下內容:
Hibernate運行的底層信息:數據庫的URL、用戶名、密碼、JDBC驅動類,數據庫Dialect,數據庫鏈接池等(對應 hibernate.cfg.xml 文件)。持久化類與數據表的映射關係(*.hbm.xml 文件).
建立 Configuration 的兩種方式
• 屬性文件(src/hibernate.properties):
Configuration cfg = new Configuration();
• Xml文件(src/hibernate.cfg.xml)推薦
Configuration cfg = newConfiguration().configure();
Configuration cfg = newConfiguration().configure(「目錄」);
>>SessionFactory接口
保存了當前的數據庫配置信息和全部映射關係以及預約義的SQL語句。同時,SessionFactory還負責維護Hibernate的二級緩存,有且只放置一種類型數據庫的相關信息 , 重量級,即建立須要大量時間和資源,所以將建立SessionFactory的工做,放在static塊中,只建立一個,便於重用 , SessionFactory是一個線程安全的,因此能夠定義成實例變量,無需加synchronized。
建立方式:
Configurationcfg = new Configuration().configure();
SessionFactory sf =cfg.buildSessionFactory();
>>Session
SessionFactory.openSession() ;
Session是由SessionFactory獲取而來,它是輕量級,即建立須要少許時間和資源,每次數據庫的操做(CURD)都須要一個Session的綁助,沒有Session就沒法與數據庫表操做。
Session 是應用程序與數據庫之間交互操做的一個單線程對象,是 Hibernate 運做的中心,全部持久化對象必須在 session 的管理下才能夠進行持久化操做。此對象的生命週期很短。Session 對象有一個一級緩存,顯式執行 flush 以前,全部的持久層操做的數據都緩存在 session 對象處。至關於 JDBC 中的 Connection.
Session經常使用的API
session.save(對象) //向數據庫插入數據
session.update(對象) //更新數據
session.delete(對象) //刪除數據
session.get(對象的字節碼class文件,序號) //查詢數據
Query query =session.createQuery("hibenate query language語句,不是sql語句")
List<類> list = query.list()
Session是不安全的,不要定義成實例變量,除非加synchronized。
將Session定義成局部變量,即在某個方法內部,就無需加synchronized。
>>Transaction接口(事物)
經過session.getTransaction()取得事務對象,在應用時,除查詢外,其它都須要事務的支持,查詢對事務的要求不限(可要可不要),
開始事務:t.begin()
提交事務:t.commit()
回滾事務:t.rollback()
顯示try..catch...finally...
例:
public void saveCustomer(){
//建立customer對象,並設置屬性值
Customer cus = new Customer();
cus.setName("思思");
cus.setAge(21);
cus.setDes("文靜");
//建立confingration對象
Configuration config = new Configuration();
//加載配置文件,鏈接驅動 com.mysql.jdbc.driver,jdbc:mysql//127.0.0.1:3306/hibernate
config.configure("cn/web/hibernate/hibernate.cfg.xml");
//建立sessionfactory
SessionFactory sessionfactory =config.buildSessionFactory();
//建立session
Session session = sessionfactory.openSession();
//建立事物
Transaction transaction=session.getTransaction();
try {
//事物開始
transaction.begin();
//保存實體域對象到表中
session.save(cus);
} catch (HibernateException e) {
//錯誤的狀況下事物恢復到原有的狀態
transaction.rollback();
}finally{
//事務結束
transaction.commit();
}
session.close();
}
Hibernate運行過程
Hibernate的運行過程以下:
一、應用程序先調用Configuration類,該類讀取Hibernate配置文件(hibernate.cfg.xml)及映射文件(customer.hbm.xml)中的信息,
二、並用這些信息生成一個SessionFactory對象,
三、而後從SessionFactory對象生成一個Session對象,
四、並用Session對象生成Transaction對象;
A、可經過Session對象的get(),load(),save(),update(),delete()和saveOrUpdate()等方法對PO進行加載、保存、更新、刪除、等操做;
B、在查詢的狀況下,可經過Session對象生成一個Query對象,而後利用Query對象執行查詢操做;若是沒有異常,Transaction對象將提交這些操做到數據庫中。
Hibernate是什麼
是指面向java環境的對象/關係數據庫映射工具。
1.開源的持久層框架.
2.ORM(Object/RelationalMapping)映射工具,創建面向對象的域模型和關係數據模型之間的映射.
3.鏈接java應用和數據庫的中間橋樑.
4.對JDBC進行復雜封裝,負責java對象的持久化(CURD).
5.在分層結構中處於持久化層,封裝對數據庫的訪問細節,使業務邏輯層更專一於實現業務邏輯
爲何要用Hibernate
一、Hibernate對JDBC訪問數據庫的代碼作了封裝,動態產生SQL, 大大簡化了數據訪問層繁瑣的重複性代碼。
二、Hibernate是一個基於jdbc的主流持久化框架,是一個優秀的orm實現,它很大程度的簡化了dao層編碼工做。
三、Hibernate使用java的反射機制加強程序類實現透明性
四、Hibernate的性能很是好,由於它是一個輕量級框架。映射的靈活性很出色。它支持不少關係型數據庫,從一對一到多對多的各類複雜關係。
Java對象持久化概念
(1)hibernate是持久層一個開源框架,可以將Java對象與記錄一一對應轉換,它封裝了JDBC的具體細節,讓程序更專一於具體業務的開發,更加面向對象。
(2)Hibernate不和特定的業務領域相關,可以把任意一個Java應用與數據庫系統鏈接,能夠理解爲是一種中間件。
(3)hibernate對jdbc進行復雜封裝,可以動態產生SQL代碼,無需程序員自行編寫SQL代碼
(4)持久層中間件:
1.代碼重用性高,可完成全部的數據訪問操做。
2.若是須要的話,可以支持多種數據庫平臺。
3.具備相對獨立性,當持久化層變化時,不會影響上層實現。
概念模型:模擬問題域中的真實實體。描述每一個實體的概念和屬性及實體間關係。不描述實體行爲。實體間的關係有一對1、一對多和多對多.
關係數據模型:在概念模型的基礎上創建起來的,用於描述這些關係數據的靜態結構。有如下內容組成:
1.若干表
2.表與表之間的參照完整性
域模型:在軟件的分析階段建立概念模型,在軟件設計階段建立域模型。
組成部分:
1.具備狀態和行爲的域對象。
2.域對象之間的關聯
域對象(domain object):構成域模型的基本元素就是域對象。對真實世界的實體的軟件抽象,也叫作業務對象(Business Object(BO)).域對象可表明業務領域中的人、地點、事物或概念。
域對象分爲如下幾種:
實體域對象:一般是指業務領域中的名詞。(pojo) (plain old java object)。--映射數據庫中的表即Customer)
過程域對象:應用中的業務邏輯或流程。依賴於實體域對象,業務領域中的動詞。如發出訂單、登錄等。(對pojo操做的方法,即CustomerDao)
域對象間的關係
1.關聯:類間的引用關係。以屬性定義的方式表現
2.依賴:類之間訪問關係。無需定義成屬性。在A中訪問B中的方法或屬性,或者A負責實例化B。
3.彙集(Aggregation):總體與部分的關係。例人與手的關係。部分類的對象不能單獨存在,他的生命週期依賴於總體類的對象的生命週期,即總體消失時,部分也隨之消失。
4.通常化(Generalization):類之間繼承關係
域對象的持久化概念
域對象在內存中建立後,不能永久存在。將域對象永久保存起來,就是持久化的過程。一般只有域對象須要持久化,過程域對象和事件域對象通常不須要持久化。廣義持久化指增、刪、改、查。
將實體域對象,永久保留到數據庫表的過程,叫實體域對象的持久化,例如:Customer對象存到數據庫表中內存->表
ORM:(Object/Relation Mapping): 對象/關係映射主要解決對象-關係的映射
1.將關係數據庫中表中的記錄映射成爲對象,以對象的形式展示,程序員能夠把對數據庫的操做轉化爲對對象的操做。所以ORM的目的是爲了方便開發人員以面向對象的思想來實現對數據庫的操做。 ORM 一般採用 XML 格式, 而且存放在專門的對象-關係映射文件中.
2.ORM只是一個思想,DBUtils/Hibernate等都是該思想的一個實現者,只是優良程度,靈活程度不一樣而以
3.ORM(Hibernate)是業務層和數據層的一箇中間件(橋樑)
對象-關係映射基礎
1.propertye 默認值:代表hibernate經過getXxx和setXxx來訪問類屬性,推薦使用,提升域對象透明性
<property> insert屬性 ,若爲false,在insert語句中不包含該字段,該字段永遠不能被插入。默認值true。
2. <property> update屬性 若爲false,update語句不包含該字段,該字段永遠不能被更新。默認值爲true。
3.<class> mutable屬性 若爲false,等價於全部的<property>元素的update屬性爲false,整個實例不能被更新。默認爲true。
4. <class> dynamic-insert屬性 若爲true,等價於全部的<property>元素的insert爲true,保存一個對象時,動態生成insert語句,語句中僅包含取值不爲null的字段。默認false。
5.<class> dynamic-update屬性 若爲true,等價於全部的<property>元素的update爲true,更新一個對象時,動態生成update語句,語句中僅包含取值不爲null的字段。默認false。
6:設置類的包名 ,若是在一個映射文件中包含多個類,而且這些類位於同一個包中,能夠設置<hibernate-mapping>元素的package屬性,避免爲每一個類提供完整的類名.
映射對象標識符
1.Java按地址區分同一個類的不一樣對象.
2.關係數據庫用主鍵區分同一條記錄.
3. Hibernate使用OID來創建內存中的對象和數據庫中記錄的對應關係。對象的OID和數據庫的表的主鍵對應。爲保證OID的惟一性,應該讓Hibernate來爲OID覆值。
鍵爲分二類:
把主鍵定義爲自動增加類型
在my SQL中,把字段設爲auto_increment類型,數據庫會自動爲主鍵賦值。
在ms SQL server中,把字段設爲identity類型,數據庫會自動爲主鍵賦值. oracle從序列(sequence)中獲取自動增加的描述符 insert into customers values(seq_customer.curval,’..’)
>>天然主鍵:就是表中含有業務性質的列名,例如:name,age,des等,不提倡使用天然主鍵
>>[代理主鍵]:就是表中無業務性質的列名,例如:id,提倡使用代理主鍵
4)hibernate的主鍵生成策略
>>increment:是經過[算法]獲得的,不是mysql的auto_increment,底層數據庫是否有auto_increment機制,對於increment來講,無所謂。
算法:先查詢最大的id,再在原有基礎上+1,最後的值作爲主鍵值
缺點:在單線中不會有問題,但在多線程併發狀況下,會出如今插入主鍵衝突問題,項目中不提倡使用increment
*>>identity
算法:直接在原有基礎上+1,再將新值取走,最後的新值作爲主鍵值
缺點:必須依懶於底層數據庫的自動增加機制。若是底層數據庫無自動增加機制,則不能使用identity策略
在多線程狀況下,能夠使用,提倡使用
*>>native:hibernate將自已選擇合適底層數據庫的ID自動增加策略,程序員無控制權。
>>assigned:解決天然是單個且主鍵爲string類型的問題,此時就不能使用increment,identity,native
>>composite-id:解決天然主鍵爲聯合主鍵且都是string類型的問題
Increment 適用於代理主鍵。由hibernate自動以遞增的方式生成表識符,每次增量爲1
Identity 適用於代理主鍵。由底層數據庫生成表識符。條件是數據庫支持自動增加數據類型。
Sequence 適用於代理主鍵。Hibernate根據底層數據庫序列生成標識符。條件是數據庫支持序列。
Hilo 適用於代理主鍵。Hibernate根據hign/low算法生成標識符。Hibernate把特定表的字段做爲「hign」值。默認狀況下,採用hibernate_unique_key表的next_hi字段。
Native 適用於代理主鍵。根據底層數據庫對自動生成表示符的能力來選擇identity、sequence、hilo
Uuid.hex 適用於代理主鍵。Hibernate採用128位的UUID算法來生成標識符。該算法可以在網絡環境中生成惟一的字符串標識符,這種策略並不流行,由於字符串類型的主鍵比整數類型的主鍵佔用更多的數據庫空間。
Assigned 適用於天然主鍵。由java程序負責生成標識符。儘可能避免使用天然主鍵。
映射一對多[雙向]關聯關係:
1 多對一[單向]關聯關係
>>對於多對一[單向]關聯,最好先保存單方(客戶),後保存多方(訂單),提升性能
>>當訂單關聯客戶時,在保存訂單時,能夠級聯cascade客戶,此時訂單所關聯的客戶一塊兒保存,
當訂單和客戶沒有關聯關係時,保存的只有訂單,而此時所引用的外鍵爲null
>>若是一個實體域對象想與數據庫交互,必須位於session一級緩存中
>>設置代碼以下:
<many-to-one
name="customer"
class="Customer"
column="customers_id"
cascade="save-update"能夠級聯保存和更新
cascade="delete"能夠級聯保存和更新/>
>>若是須要將一個客戶下的訂單更新到新的客戶,此時能夠只須要查詢所須要更新的定單和更新到那個客戶便可,此操做不會更新原有的客戶,只是訂單的更新.
>>若是刪除一個訂單,相級聯刪除該訂單所關聯的客戶,能夠使用cascade="delete",(前提,無外鍵引用),能夠沒有使用cascade="delete",只刪除訂單,不刪除客戶
例:
use hibernate;
drop table if exists orders;
drop table if exists customers;
create table if not exists customers(
id int primary key auto_increment,
name varchar(20)
);
create table if not exists orders(
id int primary key auto_increment,
orderNUM varchar(20),
cid int,
constraint cid_FK foreign key(cid) references customers(id)
);
select * from customers;
select * from orders;
//單方
public class Customer {
private Integer id;//主鍵
private String name;//用戶名
}
<!-- 配置對象/關係映射文件 -->
<hibernate-mapping package="cn.web.hibernate.single">
<class name="Customer"table="customers">
<id name="id" column="id" type="integer">
<!-- native表示更具底層的數據庫自動增加標示符id -->
<generator class="native"/>
</id>
<property name="name" column="name" type="string"/>
</class>
</hibernate-mapping>
//多方
public class Order {
private Integer id;//主鍵
private String orderNUM;//編號
private Customer customer;//用戶
}
<!-- 配置對象/關係映射文件 order.hbm.xml-->
<hibernate-mapping package="cn.web.hibernate.single">
<class name="Order" table="orders">
<id name="id" column="id" type="integer">
<generator class="native"/>
</id>
<property name="orderNUM"column="orderNUM" type="string"/>
<!-- 在多對一單向關聯的多方使用該標籤, name:表示多方中引用的單方的屬性, class:表示多方的屬性類型 ,column:表示多方表引用的外鍵, cascade;表示在刪除關聯的多方的同時連同單方一塊兒刪除
cascade="save-update:表示更新保存客戶"-->
<many-to-one name="customer"class="Customer" column="cid" cascade="delete"/>
</class>
</hibernate-mapping>
2 一對多[雙向]關聯關係
>>在對象導航中,保存哪一個實體域對象,該實體域對象和其所關聯的全部實體域對象,都會被保存,前提是在對應的hbm.xml文件中配置了cascade="save-update",若是沒有配置cascade,則不會保存實體域對象,並會出現異常發生
>>位於session一級緩存中的實體域對象有會一個快照(複本),當提交後,會將新舊快照進行比較,不一樣則更新;相同則不更新。
>> 若是須要經過單方查詢全部信息,此時須要配置cascade=」save-update」,例如:經過Customer.中,查詢一個客戶的全部訂單信息,此時須要配置
>>若是須要更新訂單爲其餘客戶時,,須要配置inverse:false表示單方來維護關係,無inverse,就各自管理true表示由多方來維護關係
>>若是須要解除訂單的關聯關係,不刪除訂單(未配置cascade="delete-orphan"),此時直接查詢須要刪除的訂單和訂單對應的客戶,設置訂單中引用客戶的屬性爲空,並去除客戶端的訂單便可.若是配置了cascade="delete-orphan",在解除訂單的同時把訂單一塊兒刪除.
>>刪除客戶聯級刪除訂單
>>單方控制多方的生命週期,即單方銷燬,多方能夠沒有;反之,多方銷燬了,單方能夠存在。
例:
use hibernate;
drop table if exists orders;
drop table if exists customers;
create table if not exists customers(
id int primary key auto_increment,
name varchar(20)
);
create table if not exists orders(
id int primary key auto_increment,
orderNUM varchar(20),
constraint cid_FK foreign key(cid) references customers(id)
);
//單方(雙向關聯)
public class Customer {
private Integer id;
private String name;
private Set<Order> orderset=new HashSet<Order>();
}
<!-- 配置對象/關係映射文件Customer.hbm.xml -->
<hibernate-mapping package="cn.web.hibernate.tabledouble">
<!-- name:表示實體域對象的類名, table:表示表名, name=id:表示實體域對象的屬性
column="id":表示表中的列名, type="integer":表示hibernate對應的id類型-->
<class name="Customer"table="customers">
<id name="id" column="id" type="integer">
<!-- native:表示選擇合適底層數據庫的ID自動增加 -->
<generator class="native"/>
</id>
<!-- 在多對一雙向或着一對多單向關聯的單方使用<set>該標籤,name:表示單方中的的集合屬性,table:多方的實體所對應的表名, cascade="save-update":更新並保存 ,column="cid":多方引用的外鍵,class:多方的類名 ,inverse:false表示單方來維護關係,無inverse,就各自管理,true表示由多方來維護關係(推薦),cascade:all-delete-orphan表示分離訂單時,同時刪除該訂單 -->
<set name="orderset"table="orders" cascade="delete-orphan">
<key column="cid"/>
<one-to-many class="Order"/>
</set>
<property name="name" column="name" type="string"/>
</class>
</hibernate-mapping>
//多方(雙向關聯)
public class Order {
private Integer id;
private String orderNUM;
private Customer customer;
}
<!-- 配置對象/關係映射文件Order.hbm.xml-->
<hibernate-mapping package="cn.web.hibernate.tabledouble">
<class name="Order" table="orders">
<id name="id" column="id" type="integer">
<generator class="native"/>
</id>
<property name="orderNUM"column="orderNUM" type="string"/>
<!-- 在多對一雙向關聯的多方使用該標籤, name:表示多方中引用的單方的屬性, class:表示多方的屬性類型,column:表示多方表引用的外鍵, cascade;表示在刪除關聯的多方的同時連同單方一塊兒刪除
cascade="save-update:表示更新並保存數據"-->
<many-to-one name="customer"class="Customer" column="cid" cascade="save-update" />
</class>
</hibernate-mapping>
3 映射一對一[雙向]關聯關係
>>一對一關係,須要自已管理自已
use hibernate;
drop table if exists person;
drop table if exists cards;
create table if not exists cards(
id int primary key auto_increment,
location varchar(50) not null default"廣州"
);
create table if not exists person(
id int primary key auto_increment,
name varchar(20) not null default"哈哈",
c_id int,
constraint c_id_FK foreign key(c_id) references cards(id)
);
public class Card {//單方
private int id;//編號
private String location;//地址
private Person person;//人}
<!-- 配置對象/關係映射文件 -->
<hibernate-mapping package="cn.web.hibernate.one2one">
<class name="Card" table="cards">
<id name="id" column="id" type="integer">
<generator class="native"/>
</id>
<property name="location"column="location" type="string"/>
<!--
在一對一雙向關聯中非外健方使用<one-to-one>標籤
name :所關聯的屬性
class :所關聯的屬性的類型
property-ref:對方關聯的屬性,即card
-->
<one-to-one name="person" class="Person" property-ref="card" />
</class>
</hibernate-mapping>
public class Person {//單方
private int id;//編號
private String name;//用戶名
private Card card;//身份證}
<!-- 配置對象/關係映射文件 -->
<hibernate-mapping package="cn.itcast.web.hibernate.chapter6.one2onedouble">
<class name="Person" table="PERSONS">
<id name="id" column="ID" type="integer">
<generator class="native"/>
</id>
<property name="name" column="NAME" type="string"/>
<!--
一對一雙向關聯在含有外健對象的一方使用<many-to-one>標籤
name:關聯的屬性
class :關聯的屬性的類型
column:外健列
unique:外健列惟一
-->
<many-to-one name="card" class="Card" column="cards_id"unique="true"/>
</class>
</hibernate-mapping>
4 映射多對多[雙向]關聯關係
>>多對多關係,必須有一方管理,不能各自管理,即必定要寫inverse=」true」屬性
>>刪除管理方容許,但非管理方不能刪除
use hibernate;
drop table if exists middles;
drop table if exists teachers;
drop table if exists students;
create table if not exists teachers(
id int primary key auto_increment,
name varchar(20) not null
);
create table if not exists students(
id int primary key auto_increment,
name varchar(20) not null
);
create table if not exists middles(
tid int,
sid int,
primary key(tid,sid),
constraint tid_FK foreign key(tid) references teachers(id),
constraint sid_FK foreign key(sid) references students(id)
);
select * from teachers;
select * from students;
select * from middles;
//多方
public class Student {
private int id;
private String name;
private Set<Teacher> teacherSet = newHashSet<Teacher>();//老師方集合
}
<!-- 配置對象/關係映射文件 student.hbm.xml-->
<hibernate-mapping package="cn.web.hibernate.many2many">
<class name="Student"table="students">
<id name="id" column="id" type="integer">
<generator class="native"/>
</id>
<property name="name" column="name" type="string"/>
<!--
多對多雙向關聯的多方set屬性用<set>標籤
name:關聯的屬性
table:中間表
key-column:學生表外鍵
class:老師方類
many-to-many-column:老師表外健
inverse:true表示由老師方管理
-->
<set name="teacherSet"table="middles" inverse="true">
<key column="sid"/>
<many-to-many column="tid" class="Teacher"/>
</set>
</class>
</hibernate-mapping>
//多方
public class Teacher {
private int id;//編號
private String name;//姓名
private Set<Student> studentSet= new HashSet< Student>();//學生方集合
}
<!-- 配置對象/關係映射文件 teacher.hbm.xml-->
<hibernate-mapping package="cn.web.hibernate.many2many">
<!-- name:實體域對象的類名,
table:表名
name=id:實體域對象的屬性
column="id":表中的列名
type="integer":表示hibernate對應的id類型-->
<class name="Teacher"table="teachers">
<id name="id" column="id" type="integer">
<!-- native表示根據底層的數據庫自動增加標示符id -->
<generator class="native"/>
</id>
<property name="name" column="name" type="string"/>
<!--
多對多雙向關聯的多方set屬性用<set>標籤
name:關聯的屬性
table:中間表
key-column:老師表外鍵
class:學生方類
many-to-many-column:學生表外健
cascade="delete" 表示級聯刪除
-->
<set name="studentSet"table="middles" cascade="delete">
<key column="tid"/>
<many-to-many column="sid" class="Student"/>
</set>
</class>
</hibernate-mapping>
<set>中inverse屬性(反轉): 在hibernate中經過對 inverse屬性的值決定是由雙向關聯的哪一方來維護表和表之間的關係.inverse=false 的爲主動方,inverse=true 的爲被動方, 由主動方負責維護關聯關係,在沒有設置 inverse=true 的狀況下,父子兩邊都維護父子關係 , 在 1-n 關係中,將 n 方設爲主控方將有助於性能改善(若是要國家元首記住全國人民的名字,不是太可能,但要讓全國人民知道國家元首,就容易的多), 在 1-N 關係中,若將 1 方設爲主控方 會額外多出 update 語句。
結論:
1.在映射一對多的雙向關聯關係時,應該在one方把inverse屬性設爲true ,這能夠提升性能。
2.在創建兩個對象的關聯時,應該同時修改關聯兩端的相應屬性:
customer.getOrders().add(order);
order.setCustomer(customer);
這樣纔會使程序更加健壯,提升業務邏輯層的獨立性,使業務邏輯層的程序代碼不受Hibernate實現類的影響。同理,當刪除雙向關聯的關係時,也應該修改關聯兩端的對象的相應屬性:
Customer.getOrders().remove(order);
Order.setCustomer(null);
解除關聯關係並刪除
當customer.hbm.xml的<set>元素的cascade屬性取值爲all-delete-orphan,
Hibernate會按照以下方式處理customer對象:
1.當保存或更新customer對象時,級聯保存或更新全部關聯的order對象,至關於save-update.
2.當刪除customer對象時,級聯刪除全部的order對象,至關於delete。
3.刪除再也不和customer對象關聯的全部order對象。
當關聯雙方存在父子關係時,就能夠把父方的cascade屬性設爲all-delete-orphan.
Cascade 屬性:
操縱持久化對象
1.當某個堆中對象要被GC回收的前提是:該對象無任何引用,只要有對象引用,那麼該對象就不會被GC回收
2.Session 接口是Hibernate 嚮應用程序提供的操縱對數據庫的最主要的接口, 它提供了基本的保存, 更新, 刪除和加載Java 對象的方法.
session的緩存
1.在 Session 接口的實現中包含一系列的 Java 集合, 這些 Java 集合構成了 Session 緩存. 只要 Session 實例沒有結束生命週期, 存放在它緩存中的對象也不會結束生命週期
2.當session的save()方法持久化一個對象時,該對象被載入緩存,之後即便程序中再也不引用該對象,只要緩存不清空,該對象仍然處於生命週期中。當試圖load()對象時,會判斷緩存中是否存在該對象,有則返回。沒有在查詢數據庫
3 .load()方法,會事先去session緩存中查詢一下是否有該持久化對象存在,若是有就直接返回該持久化對象; 若是沒有,此時再去查找數據庫,加載新的持久化對象。
清理session的緩存
1.flush: 進行清理緩存(此時緩存中的數據並不丟失)的操做,讓緩存和數據庫同步執行一些列sql語句,至關於發送sql語句,但不提交事務;
2.commit:先調用flush() 方法,而後提交事務. 則意味着提交事務意味着對數據庫操做永久保存下來;
3. clear: 清空緩存,即將session中的持久化對象[移出]session緩存,並非刪除持久化對象等價於list.removeAll();
4. session.close(),只是將session緩存銷燬,但並無將緩存中的持久化對象刪除
5.session能夠利用快照功能,來更新某個持久化對象所對應的記錄,這就是快照功能,主要是:當session加載了customer對象後,會爲customer對象的值類型的屬性複製一份快照。當清理緩存時,經過比較對象的當前屬性和快照,來判斷對象的那些屬性發生了變化。發生變化的執行sql語句, 沒有發生變化再也不執行語句
java對象在hibernate中會有四種不一樣的狀態
>>臨時對象[經過new產生的對象]
(1)OID爲null,由於hibernate還沒有分配OID給該對象
(2)沒有在session緩存中
(3)數據庫沒有該記錄存在
*>>持久化對象[經過save等方法能夠將臨時對象轉成持久化對象]
(1)OID非null,由於hibernate已分配OID給該對象
(2)在session緩存中
(3)數據庫有該記錄存在
*>>遊離化對象[經過clear等方法能夠將持久對象轉成遊離化對象]
(1)OID非null,由於遊離對象是從持久化對象轉換而來
(2)不在session緩存中
(3)數據庫可能有該記錄存在
>>刪除化對象[經過delete等方法能夠將持久對象轉成刪除化對象]
(1)OID非null
(2)不在session緩存中
(3)數據庫可能有該記錄存在
hibernate檢索方式:
Hibernate 提供瞭如下幾種檢索對象的方式
導航對象圖檢索方式: 根據已經加載的對象導航到其餘對象
OID 檢索方式: 按照對象的 OID 來檢索對象
HQL 檢索方式: 使用面向對象的 HQL 查詢語言
HQL(Hibernate Query Language) 是面向對象的查詢語言, 它和 SQL 查詢語言有些類似. 在 Hibernate 提供的各類檢索方式中,HQL 是使用最廣的一種檢索方式.
HQL 檢索方式包括如下步驟:
1.經過 Session 的 createQuery() 方法建立一個 Query 對象, 它包括一個 HQL 查詢語句. HQL 查詢語句中能夠包含命名參數
動態綁定參數
2調用 Query 的 list() 方法執行查詢語句. 該方法返回 java.util.List 類型的查詢結果, 在 List 集合中存放了符合查詢條件的持久化對象.
3.Qurey 接口支持方法鏈編程風格,它的 setXxx() 方法返回自身實例, 而不是 void 類型
HQL vs SQL:
HQL 查詢語句是面向對象的, Hibernate 負責解析 HQL 查詢語句, 而後根據對象-關係映射文件中的映射信息, 把 HQL 查詢語句翻譯成相應的 SQL 語句. HQL 查詢語句中的主體是域模型中的類及類的屬性
SQL 查詢語句是與關係數據庫綁定在一塊兒的. SQL 查詢語句中的主體是數據庫表及表的字段.
1.根據編號查詢客戶 :Object obj = session.get(類名.class,編號)
或者: Objectobj = session.load(類名.class,編號)
例: Customer c= (Customer)session.get(Customer.class, 1);
2.批量插入: Object obj = session.save(Object)
例: 設置session清理緩存的時機,該時機只在顯示調用flush方法時清理
session.setFlushMode(FlushMode.NEVER);
Customer c = newCustomer(); session.save(c);
注: 級聯保存客戶和訂單 ;須要設置cascade=」save-update」管理方:invers=」true」
3.根據姓名查詢客戶: Stringhql = "from 類名別名 where 別名.屬性='字段'";
例: String hql = "from Customer c where c.name='呵呵'";
Query query = session.createQuery(hql);
List<Customer> list = query.list();
4.查詢全部客戶和全部訂單 : String hql = "from java.lang.Object o";
例: String hql = "fromjava.lang.Object o";
Query query = session.createQuery(hql);
List<Customer> list = query.list ();
5.按編號降序查詢全部全部訂單 : String hql = "from 類名別名 order by 別名.屬性 desc";
例: String hql = "fromOrder o order by o.id desc";
Query query = session.createQuery(hql);
List<Order> list = query.list();
15.分頁查詢全部全部訂單 : String hql = "from 類名別名";
setFirstResult(int firstResult): 設定從哪個對象開始檢索, 參數 firstResult 表示這個對象在查詢結果中的索引位置, 索引位置的起始值爲 0. 默認狀況下,Query 從查詢結果中的第一個對象開始檢索
setMaxResult(int maxResults): 設定一次最多檢索出的對象的數目.
例: String hql = "fromOrder o";
Query query = session.createQuery(hql);
//從第幾條記錄的索引號開始
query.setFirstResult(3);
//每頁顯示三條記錄
query.setMaxResults(3);
List<Order> list = query.list();
7.根據姓名查詢用戶,經過索引號綁定參數 :String hql = "from類名別名 where
別名.屬性='字段'";
例 ; String hql = "from Customer c where c.name=?";
Query query = session.createQuery(hql);
//綁定?所對應的值,?號索引從0開始
query.setString(0,"思思");
List<Customer> list = query.list();
8.根據姓名查詢用戶,經過別名綁定參數
例: Stringhql = "from Customer c wherec.name=:cname";
Query query = session.createQuery(hql);
//綁定:xx所對應的值
query.setString("cname","三藏");
List<Customer> list = query.list();
9. 根據姓名和編號查詢用戶:
例: String hql = "from Customer c where c.id=? andc.name=?";
Query query = session.createQuery(hql);
query.setInteger(0,1);//索引號從0開始,查詢一條記錄
query.setString(1,"悟空");//設置所查詢記錄的字段
List<Customer> list = query.list();
10.根據姓名和編號查詢用戶,HQL語句位於Customer.hbm.xml文件中
例: Query query = session.getNamedQuery("findCustomerByIdAndName");
query.setInteger(0,2);
query.setString(1,"八戒");
List<Customer> list = query.list();
注: 該查詢須要在*.hbm.xml中設置該標籤與<class>同級
<!-- query標籤是用於綁定HQL語句 name屬性:表示該HQL語句的名字-->
<query name="findCustomerByIdAndName">
from Customer c where c.id=? and c.name=?
</query>
11. 鏈接查詢姓名和訂單號
例: String hql = "fromCustomer c left outer join c.orderSet o where c.id=1";
Query query = session.createQuery(hql);
List<Customer> list = query.list();
12.投影查詢姓名和訂單號
例: String hql = "selectc.name,o.orderNum from Customer c left outer join c.orderSet o where c.id=1";
Query query = session.createQuery(hql);
List<Customer> list = query.list();
13.獲取訂單的個數
例: String hql = "select count(*) from Order o";
Query query = session.createQuery(hql);
query.setMaxResults(1);
long sum = (Long) query.uniqueResult();
14.求和
例: String hql = "selectsum(o.id) from Order o";
Query query = session.createQuery(hql);
query.setMaxResults(1);
double avg = (Double) query.uniqueResult();
15.分組查詢
例: 按customers_id分三組
Stringsql = "select count(*) from orders group by customers_id";
String hql = "select count(*) from Order o group byo.customer.id";
Query query = session.createQuery(hql);
List<Long> orderList = query.list();
其餘查詢:
from Customer c where 1 < (select count(o) from c.orders o);
hibernate的檢索策略
1)檢索策略有二種:
>><class lazy=false/>當即檢索
session.load()時,查詢數據庫
>><class lazy=true/>延時檢索
session.load()時,不查詢數據庫,但對象非空,是一個hibernate產生的動態代碼對象
2)類當即檢索,集合延遲檢索,這是項目中[推薦]使用,由於有時查詢出對象後,不須要立刻取得對應的集合。
例: 類延遲[lazy="true"]+集合延遲[lazy="true"]
當類延遲檢索時,在須要取得屬性時才查詢數據庫
當集合延遲檢索時,在須要取得屬性時才查詢數據庫
映射繼承關係
Hibernate支持三種繼承映射策略:
1.每一個具體類一張表(table per concrete class) 將域模型中的每個實體對象映射到一個獨立的表中。
2.每一個類分層結構一張表(table per class hierarchy) 對於繼承關係中的子類使用同一個表,這就須要在數據庫表中增長額外的區分子類類型的字段。
3.每一個子類一張表(table per subclass) 域模型中的每一個類映射到一個表,經過關係數據模型中的外鍵來描述表之間的繼承關係。這也就至關於按照域模型的結構來創建數據庫中的表,並經過外鍵來創建表之間的繼承關係。
採用 subclass 元素的繼承映射策略
1).採用subclass 的繼承映射能夠實現對於繼承關係中父類和子類使用同一張表,由於父類和子類的實例所有保存在同一個表中,所以須要在該表內增長一列,使用該列來區分每行記錄究竟是哪一個類的實例這個列被稱爲辨別者列(discriminator).
2).在這種映射策略下,使用subclass來映射子類,使用 class 或 subclass的 discriminator-value屬性指定辨別者列的值
3).全部子類定義的字段都不能有非空約束。若是爲那些字段添加非空約束,那麼父類的實例在那些列其實並無值,這將引發數據庫完整性衝突,致使父類的實例沒法保存到數據庫中
1. 繼承映射
第一種策略: 全部類對應一張表使用的<subclass>
例:
use hibernate;
drop table if exists employees;
create table if not exists employees(
emp_id int primary key auto_increment,
emp_eType archer(20),
empennage archer(20),
emp_salary double,
emp_hour double
)
//員工(父類)
public class Employee {
public Integer id;//編號
public String name;//姓名
}
//小時員工(子類)
public class HourEmployee extends Employee{
private Double rate;//時薪
}
//月薪員工(子類)
public class SalaryEmployee extends Employee{
private Double salary;//月薪
}
<!-- 配置對象/關係映射文件 Employee.hbm.xml-->
<hibernate-mapping package="cn.web.hibernate.type">
<class name="Employee"table="employees"discriminator-value="employee" >
<id name="id" column="emp_id" type="integer">
<generator class="native" />
</id>
<!-- 區分員工的字符串,只能放在id的後面 -->
<discriminator column="emp_eType"type="string"/>
<property name="name" column="emp_name" type="string" />
<!-- 定義子類小時員工 ,name:小時員工類的類名, discriminator-value:區分小時員工的字符串 lazy=」false」:當即查詢,true,延時查詢-->
<subclass name="HourEmployee"discriminator-value="hour" lazy="false">
<property name="rate" column="emp_hour" type="double"/>
</subclass>
<!-- 定義子類月薪員工 ,name:月薪員工類的類名, discriminator-value:區分月薪員工的字符串-->
<subclass name="SalaryEmployee"discriminator-value="salary" lazy="false">
<property name="salary" column="emp_salary" type="double"/>
</subclass>
</class>
</hibernate-mapping>
採用 union-subclass 元素的繼承映射
1.採用union-subclass 元素能夠實現將每個實體對象映射到一個獨立的表中。
2.子類增長的屬性能夠有非空約束 --- 即父類實例的數據保存在父表中,而子類實例的數據保存在子類表中。
3.子類實例的數據僅保存在子類表中, 而在父類表中沒有任何記錄
4.在這種映射策略下,子類表的字段會比父類表的映射字段要多,由於子類表的字段等於父類表的字段、加子類增長屬性的總和
5.在這種映射策略下,既不須要使用鑑別者列,也無須使用 key 元素來映射共有主鍵.
6.使用union-subclass 映射策略是不可以使用 identity 的主鍵生成策略, 由於同一類繼承層次中全部實體類都須要使用同一個主鍵種子, 即多個持久化實體對應的記錄的主鍵應該是連續的. 受此影響, 也不應使用 native 主鍵生成策略, 由於 native 會根據數據庫來選擇使用 identity 或 sequence.
第二種策略: 每一個類映射到不一樣的表<union-subclass>
例: use hibernate;
drop table if exists hourEmployees;
drop table if exists salaryEmployees;
drop table if exists employees;
create table if not exists employees(
eid int primary key auto_increment,
name varchar(20)
);
create table if not exists hourEmployees(
hid int primary key auto_increment,
name varchar(20),
rate double,
constraint hid_FK1 foreign key(hid) references employees(eid)
);
create table if not exists salaryEmployees(
sid int primary key auto_increment,//sid 便是主鍵又是外鍵
name varchar(20),
salary double,
constraint sid_FK2 foreign key(sid) references employees(eid)
);
select * from employees;
select * from hourEmployees;
select * from salaryEmployees;
//員工(父類)
public class Employee {
public Integer id;//編號
public String name;//姓名
}
//小時員工(子類)
public class HourEmployee extends Employee{
private Double rate;//時薪
}
//月薪員工(子類)
public class SalaryEmployee extends Employee{
private Double salary;//月薪
}
<!-- 配置對象/關係映射文件Employee.hbm.xml -->
<hibernate-mapping package="cn.web.hibernate.type1">
<class name="Employee"table="employees" >
<id name="id" column="eid" type="integer">
<generator class="increment"/>
</id>
<property name="name" column="name" type="string" />
<!-- 映射SalaryEmployee子類,name:子類類名 , table:子類映射的表名-->
<union-subclass name="SalaryEmployee"table="salaryEmployees">
<property name="salary" column="salary" type="double"/>
</union-subclass>
<!-- 映射HourEmployee子類,name:子類類名 ,table:子類映射的表名-->
<union-subclass name="HourEmployee"table="hourEmployees">
<property name="rate" column="rate" type="double"/>
</union-subclass>
</class>
</hibernate-mapping>
採用 joined-subclass 元素的繼承映射
1.採用 joined-subclass 元素的繼承映射能夠實現每一個子類一張表
2.採用這種映射策略時,父類實例保存在父類表中,子類實例由父類表和子類表共同存儲。由於子類實例也是一個特殊的父類實例,所以必然也包含了父類實例的屬性。因而將子類和父類共有的屬性保存在父類表中,子類增長的屬性,則保存在子類表中。
3.在這種映射策略下,無須使用鑑別者列,但須要爲每一個子類使用key 元素映射共有主鍵,該主鍵必須與父類標識屬性的列名相同。但若是繼承樹的深度很深,可能查詢一個子類實例時,須要跨越多個表,由於子類的數據一次保存在多個父類中。
4.子類增長的屬性能夠添加非空約束。由於子類的屬性和父類的屬性沒有保存在同一個表中
第三種策略: 每一個子類各自對應一張表<joined-subclas>
例:
Sql及各種的建立如上第二種策略
<!-- 經過映射文件自動產生sql hibernate.hbm.xml-->
<property name="hbm2ddl.auto">create</property>
<!-- 配置對象/關係映射文件 -->
<hibernate-mapping package="cn.web.hibernate.type2">
<class name="Employee"table="employees" >
<id name="id" column="eid" type="integer">
<generator class="increment"/>
</id>
<property name="name" column="name" type="string" />
<!-- 映射SalaryEmployee子類
name:子類類名
table:子類映射的表名-->
<joined-subclass name="SalaryEmployee"table="salaryEmployees">
<key column="sid"/>
<property name="salary" column="salary" type="double"/>
</joined-subclass>
<!-- 映射HourEmployee子類
name:子類類名
table:子類映射的表名-->
<joined-subclass name="HourEmployee"table="hourEmployees">
<key column="sid"/>
<property name="rate" column="rate" type="double"/>
</joined-subclass>
</class>
</hibernate-mapping>
繼承映射使用的主要標籤:
<property name="hbm2ddl.auto">create</property>
在運行時,老是建立新的表,若是原來有,則刪除
<propertyname="hbm2ddl.auto">update</property>(推倡)
(1)若是原來無,則建立
(2)若是原有有,則插入
<propertyname="hbm2ddl.auto">none</property>
(1)真接插入數據
>>將繼承結構中的全部子類都定義在各自不一樣的表中,主鍵不一至,但主鍵又是一個外健,能夠看做(二張表)
總結:
1)每一個類對應一張表:
表數目多,不便於查詢,維護較差
2)全部類對應一張表:
表數目少,表中數據混亂,不符合設計原則,咱們但願將相關的數據放入在不一樣的表中
3)每一個[子類]對應一張表:
表數目中等,表中有且中包含該子類的信息,且經過外鍵關聯其它表
1.配置C3P0鏈接池
在hibernate.cfg.xml文件中增長以下配置
1,在該配置文件中查找對應的c3p0資源:
hibernate-distribution-3.5.6.jar\project\etc\hibernate.properties
2,查看c3p0鏈接狀態的日誌文件:主要顯示記錄信息 log4j.propertie
E:\java\開發類庫\hibernate-distribution-3.5.6-Final\project\etc
3,導入c3p0.jar包 , E:\java\開發類庫\c3p0-0.9.1.2\lib\ c3p0-0.9.1.2.jar
<!-- C3P0鏈接池設定-->
<!-- 使用c3po鏈接池 配置鏈接池提供的供應商-->
<propertyname="connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider/>
<!--在鏈接池中可用的數據庫鏈接的最少數目 -->
<propertyname="c3p0.min_size">5</property>
<!--在鏈接池中全部數據庫鏈接的最大數目 -->
<propertyname="c3p0.max_size">20</property>
<!--設定數據庫鏈接的過時時間,以秒爲單位,
若是鏈接池中的某個數據庫鏈接處於空閒狀態的時間超過了timeout時間,就會從鏈接池中清除 -->
<propertyname="c3p0.timeout">120</property>
<!--每3000秒檢查全部鏈接池中的空閒鏈接 以秒爲單位-->
<propertyname="c3p0.idle_test_period">3000</property>
<!-- 設置自動提交 -->
<propertyname="connection.autocommit">true</property>
2 配置隔離級別
<!-- 事務的隔離級別爲Readcommitted (能夠解決髒讀,其它的沒法解決)-->
<property name="connection.isolation">2</property>
<!-- 事務提交後,自動關閉session -->
<propertyname="transaction.auto_close_session">true</property>
隔離級別
read_uncommited 1: 容許你讀取還未提交的改變了的數據。可能致使髒、幻、不可重複讀
read_committed 2:容許在併發事務已經提交後讀取。可防止髒讀,但幻讀和 不可重複讀仍可發生
repeatable_read4:對相同字段的屢次讀取是一致的,除非數據被事務自己改變。可防止髒、不可重複讀,但幻讀仍可能發生。(數據庫默認)
serializable 8:徹底服從ACID的隔離級別,確保不發生髒、幻、不可重複讀。這在全部的隔離級別中是最慢的,它是典型的經過徹底鎖定在事務中涉及的數據表來完成的。
3 .session管理和本地線程的綁定
管理:
Session 對象的生命週期與本地線程綁定
Session 對象的生命週期與 JTA 事務綁定
Hibernate 委託程序管理Session 對象的生命週期
線程的綁定配置:
在hibernate.cfg.xml文件中增長
<!-- 配置session的線程本地化threadLocal -->
<propertyname="current_session_context_class">thread</property>
不是調用sessionFactory.openSession().而是調用
sessionFactory. getCurrentSession().獲取session對象.從當前的線程提取session, 當前線程若是存在session對象,取出直接使用.
當前線程若是不存在session對象,獲取一個新的session對象和當前的線程綁定
1)默認的狀況下,從sessionFactory中取得的session,每一個都不相同
2)每一個線程從始到終都和各自的session綁定在一塊兒,直到線程銷燬,才分離session
3)hibernate有二個級別的緩存
Hibernate中提供了兩個級別的緩存
第一級別的緩存是 Session 級別的緩存,它是屬於事務範圍的緩存。這一級別的緩存由 hibernate 管理的,通常狀況下無需進行干預,
第二級別的緩存是 SessionFactory 級別的緩存,它是屬於進程範圍的緩存
SessionFactory 的緩存能夠分爲兩類:
內置緩存: Hibernate自帶的, 不可卸載. 一般在 Hibernate 的初始化階段, Hibernate 會把映射元數據和預約義的 SQL 語句放到SessionFactory 的緩存中, 映射元數據是映射文件中數據的複製, 而預約義 SQL 語句時 Hibernate 根據映射元數據推到出來的. 該內置緩存是隻讀的. 注:程序讀取的hibernate.cfg.xml文件和全部的*.hbm.xml文件都存於二級緩存中.
外置緩存(二級緩存): 一個可配置的緩存插件. 在默認狀況下, SessionFactory 不會啓用這個緩存插件. 外置緩存中的數據是數據庫數據的複製, 外置緩存的物理介質能夠是內存或硬盤,
注:ehcache外置,能夠經過以配置的方式,插入到hibernate中,此時hibernate就能夠使用外置二級緩存了.
Oracle簡介:
2008年1月,Sun收購MySql(10億美圓);
2008年1月,Oracle收購BEA(WebLogic)85億美圓
2009年04月下旬,Oracle收購Sun(74億美圓);
經常使用數據庫:
美國Sybase:Sybase( PowerBuilder+Sybase)
Sun:My SQL(曾經是瑞典AB公司)
美國Oracle:Oracle
微軟:SQL Server及Access
IBM:DB2,Informix
分類:
根據 負載/成本/安全/應用平臺
小型:access
中型:mysql/sql server/informix
大型:sybase/oracle/db2
數據庫的概念: 數據庫(DB)是一個按數據結構來存儲和管理數據的計算機軟件系統。
1. 數據庫管理系統(Database Management System)
數據庫管理系統(DBMS)是專門用於管理數據庫的計算機系統軟件。數據庫管理系統可以爲數據庫提供數據的定義、創建、維護、查詢和統計等操做功能,並完成對數據完整性、安全性進行控制的功能。
2. 數據庫應用系統(Database Application System)
數據庫應用系統:就是使用數據庫技術的系統; 數據庫應用系統有不少,基本上全部的信息系統都是數據庫應用系統。它一般由軟件、數據庫和數據管理員組成
3. 數據庫管理員(DBA)
數據管理員負責建立、監控和維護整個數據庫,使數據能被任何有權使用的人有效使用。數據庫管理員通常是由業務水平較高,資歷較深的人員擔任 。
4. 數據庫系統
一個數據庫系統應由計算機硬件、數據庫(DB)、數據庫管理系統(DBMS)、數據庫應用系統(DAS)和數據庫管理員(DBA)五部分構成 。
Oracle數據庫的特色
支持大數據量、多用戶的高性能的事務處理
Oracle遵照數據存取語言、操做系統、用戶接口和網絡通訊協議的工業標準
實施安全性控制和完整性控制
支持分佈式數據庫和分佈處理
具備可移植性、可兼容性和可鏈接性
全球化、跨平臺的數據庫
本機安裝:
Enterprise Manager Database Control URL - (orcl) :http://PP:1158/em 數據庫配置文件已經安裝到 D:\oracle\product\10.2.0,同時其餘選定的安裝組件也已經安裝到 D:\oracle\product\10.2.0\db_1。 iSQL*Plus URL 爲: http://PP:5560/isqlplus iSQL*Plus DBA URL 爲:http://PP:5560/isqlplus/dba
數據庫的操做:
1.登陸網頁版的OEM http://daxia:1158/em/ --à該網頁只能是管理員登錄
用戶名: system 密碼: oracle
2. iSQL*Plus URL 爲: http://PP:5560/isqlplus
3. Oracle安裝成功後的服務
OracleServiceORCL--->Orcalce服務(一個數據庫實例) 能夠不啓動
OracleOraDb10g_home1iSQL*Plus--->運營網頁版本的sqlplus的web服務器。能夠不啓動
OracleOraDb10g_home1TNSListener--->讓其它程序鏈接數據庫,必須取另。監聽服務(必須開啓)
OracleDBConsoleorcl--->網頁版的OEM的web服務器及相同控制檯的功能。(必須開啓)
4. 鏈接Oracle的幾種方式 :
Sqlplus : dos命令行鏈接數據庫
Sqlplusw : 圖行化界面鏈接數據庫
oracle sql developer-oracle官方免費
Oracle客戶機OEM
pl/sql developer
五、使用sqlplus鏈接oracle數據庫
sqlplus 用戶名 : scott /密碼 :oracle (查看oracle提供的表)
show user //使用oracle提供的use表
desc emp; //查看錶的結構
select * from emp; //查看整個表中的數據
退出:exit
鏈接其它服務器上的Oracle數據庫:sqlplus 用戶名/密碼@服務器ip:端口號/數據庫服務名
好比:sqlplusscott/tiger@127.0.0.1:1521/orcl
6, dos操做 :
(1)Dos窗口調整—打開dos窗口-à點擊左上角按鈕-à選中快速編輯模式(主要做用是在複製和粘貼) /
調整屏幕大小-à佈局中設置快讀和高度。
(2)忘記的解鎖及密碼:(次修改是scott的設置, 若是在安裝時設置了用戶名和密碼,無需設置,直接登陸便可)
操做管理員登陸 sqlplus 用戶名/密碼 as sysdba 或者sqlplus / as sysdba
解鎖用戶 : alter user 用戶名 accountunlock;
修改密碼: alter user 用戶名identified by 新密碼;
3) 記錄日誌 : spool , spool 文件名 .操做的內容 .
操做結束使用spool off(表示將全部的操做的容寫入到指定的文件中).
例如 : spool c:\ oracle.text spool off
(4)、註釋 : 單行註釋: --
多行註釋:/* 註釋的內容 */
(5)、基本命令
清屏:host cls =>host 後面是操做系統的命令。
保存sql語句:save 文件名
加載一個已有的sql文件:@ 文件名
查看用戶有哪些表:
select * from tab;
(7)、環境設置-(set及show命令)
set linesize 100 //設置行間距
set pagesize 30 //設置頁面的顯示大小
(8)、修改sql
直接改某一行:
輸行號:2
輸入命令:c /form/from
打開系統的文件編輯器來改:ed。
設置某列的寬度:
column job format a15 或 簡寫: col job for a15
column SAL format 9999 或 col sal for 9999
格式:
col[umn] 列名 for[mat] 格式
對於字符串:
A15,15是一個數據,表示15個字符的寬度。
對於數字:
9表示一位,有幾個,就是多寬。
若是實際值小於所設置的寬度,就顯示原值。
若是實際值超出所設置的寬度,就會顯示若干個'#'號。
0表示一位,有幾個,就是多寬。
若是實際值小於所設置的寬度,前面用0補足到指定的寬度。
若是實際值超出所設置的寬度,就會顯示若干個'#'號。
若是是00.00或是99.00: 均表示小數點後面有兩位,若是不夠,則後面補0;若是超過,則會四捨五入。
(8)、修改sql
1,若是在dos命令行中輸入的語句錯誤,此時能夠直接輸入行號進行更改錯誤信息.
2, 直接輸入ed : 該命令會彈出一個編輯框,直接值編輯框中修改,保存關閉,此時更正後的數據會自動出如今dos命令行。
9)查詢當前的日期格式
select sysdate from dual; 或者 select * fromv$nls_parameters;
alter session setNLS_DATE_FORMAT='yyyy-mm-dd'; 設置日期的格式
修改當前session的一些參數(v$nls_parameters:語言,貨幣,日期等格式)
alter session setnls_date_format='yyyy-mm-dd';
也能夠加到glogin.sql中,注意最後要有分號。
查詢語句:
Select 列名 from 表名
Select :表示查詢哪一個列 from : 查詢那張表
例: select * from emp : 查詢全部
select ename,job,hiredate,sal,comm,deptno from emp; 查詢表中的詳細信息,在少許的查詢中最好使用全名,此方法查詢速度最快,
對於多表查詢 ,則使用表的別名查詢: select e.ename,e.sal from emp e;
例如: select ename as 姓名,job as 工做,hiredate as 日期,sal as 薪水,comm as 年薪,deptno as 僱員 from emp;
算術運算符: + - * /
例: select 1+2,3*5,8/2 fromdual;
1+2 3*5 8/2
------ ---------- ----------
3 15 4
在表達式中要注意處理null值.
1. null <> null ,比較時不相等
2.null在算法運算中返回null.
3.is null,is not null是對空值進行比較的方法
關於null值的查詢
---任何值與null進行比較都不相等,null與null比較也不相等.
例; select * from emp wherecomm is null; //查詢獎金不爲空的的全部用戶
select * from emp where comm is not null;//查詢獎金爲空的的全部用戶
鏈接字符查詢: 函數:select concat(「 」,」 」) from 表名
鏈接符mysql中的鏈接函數concat('hello','world')
例: select concat(ename,job)from emp;
Oracle中提供 || 表明鏈接符,用來鏈接字符串
例: selectename||job from emp;
注: 在鏈接查詢中,若是有中文或者字符串時, 須要使用單引號將字符串引在單引號中間
日期查詢:
select sysdate from dual; //24-月-12
select '今天是:'||sysdatefrom emp; //今天是:24-8月 -12
刪除重複行
在 SELECT 子句中使用關鍵字‘DISTINCT’ 刪除重複行
例: select distinct ename,deptno,job from emp; //查詢去除重複的用戶名
顯示錶結構
使用 DESCRIBE 命令,表示表結構
desc tableName(表名)
過濾和排序數據
使用WHERE 子句,將不知足條件的行過濾掉, where 語句跟在from後面
例: select * from emp where deptno=20;
字符和日期
字符和日期要包含在單引號中。
字符大小寫敏感,日期格式敏感。
默認的日期格式是 DD-MON-RR
例: select * from emp where hiredate!='20-2月-81';
select * from emp where ename='SMAME';
比較運算符
大於 > , 小於 < , 大於等於>= , 小於等於<= , 不等於<> (或者!=)
例: select * from emp where sal>1500;
1.查詢在必定範圍內的值:
BETWEEN ...AND... 即: select * from 表名 where 列名 between 值 and 值或者 and
例; select * from emp where sal>1500 andsal<5000;// 查詢在薪水在1500-5000的全部用戶
或者; select * from emp where sal between 1500 and5000; // 查詢在薪水在1500-5000的全部用戶
2.-between and對日期型的支持
select * from emp where hiredatebetween '01-1月-81' and '31-12月-82';
3. between對字符串的處理
select * from emp where job between 'm' and 's';
注: between and 在查詢字符串和日期是必須使用單引號引發來, 該查詢包含開始和結束
2. IN(set) 等於值列表中的一個或者使用 or
例: select * from emp where sal in(1500,3000); //查詢薪水爲1500 和3000 的用戶
查詢10號及20號部門的員工
select * from emp where (deptno=20 or deptno=10);
Not(Set) in不是集合中任何元素
例; select* from emp where deptno not in(10,20);
3. LIKE 模糊查詢 : Select 列名 from 表名 where 列名 like ‘_%’
主要用字符數據.
%表明0或多個任意字符; _表明任意一個字符 ,下劃線和%能夠同時使用
例: select* from emp where ename like 'M%'; //查詢用戶名爲M的用戶
select * from emp where deptnolike '3%';
注: 在模糊查詢中無論是數字仍是字符, 須要使用單引號將所要查詢的內容引發來.
轉義字符:ESCAPE
迴避特殊符號的:使用轉義符。例如:將[%]轉爲[\%]、[_]轉爲[\_],而後再加上[ESCAPE ‘\’] 便可
例: select* from emp2 where ename like 'He\_w%' escape '\';
建立表:
createtable emp2 as select * from emp; //經過查詢其餘表建立一張新表
create table emp3 as select * from emp3; //循環成倍數增長複製一張表中的數據
4. 多個列排序:ORDER BY
Select 列名 from 表名 order by 列名 desc; desc升序, asc : 降序
按照ORDER BY 列表的順序排序
SELECT last_name, department_id, salary(列名)
FROM employees(表名)
ORDER BY department_id, salary DESC;(升序)
例: selectename,sal from emp order by sal desc; //對用戶名和薪水進行排序
select ename,sal from emp order by sal DESC,ename; // 只是針對sal薪水排序
select ename,sal from emp order by 2ASC; // 對用戶薪水排序, 2 表示第二列即sal
select ename,sal 工資 from emporder by 工資;
5.排序中空值的使用:
SQL> ---在排序中使用添加nullslast把含null的行放到最後去;
例: select * from emp order by comm DESC nullslast; ..將爲空的用戶放在最後
SQL> --nulls first,這是默認值,把null值放前面.
例: select * from emp order by comm DESC nullsfirst;
TO_CHAR 函數對日期的轉換
格式: TO_CHAR(date,'format_model')
SELECT 表名TO_CHAR(hire_date, 'DD Month YYYY') AS HIREDATE FROM 表名;
注:
必須包含在單引號中並且大小寫敏感。
能夠包含任意的有效的日期格式。
日期之間用逗號隔開
TO_CHAR 函數中常用的幾種格式:
數字0 , 9 $美圓符 L本地貨幣 . 小數點 , 千分位符號
例: select ename,to_char(hiredate,'yyyy-mm-dd')from emp; //將日期格式化爲指定的模式
日期的格式:
HH24:MI:SS AM
日期中添加字符:
DD "of" MONTH
SQL> select to_char(sysdate,'YYYY-MM-DD hh24:mi:ss') from dual;
To_char() 對數字的轉換:
SELECT TO_CHAR(salary, '$99,999.00') SALARY
FROM employees
WHERE last_name = 'Ernst';
SQL> select ename,to_char(sal,'L9,999.99') from emp;
ENAME TO_CHAR(SAL,'L9,999
---------- -------------------
SMITH ¥800.00
ALLEN ¥1,600.00
4. 字符轉換
大寫:Upper() 小寫: lower() 首字母大寫: initcap()
例: SQL> select upper('Helloworld') 大寫,lower('Hello world') 小寫,initcap('Hello world') 首字母大寫 from dual;
大寫 小寫 首字母大寫
----------- ----------- ----------- ----------------------
HELLO WORLD hello world Hello World
5. 截取字符串: substr(「字符串 」, 角標位置)
concat()等於|| :鏈接字符串
SQL> select substr('Hello world',3) 從第三個字符截, substr('Hello world',3,5) from dual;
從第三個 SUBST
--------- -----
llo world llo w
6. length()--返回字符數
lengthb()--返回字節數
例:
select length('你好 word') L,lengthb('你好 world') B from dual;
L B
------ ----------
7 10
7. instr()查找一個字符串的,返回找到的位置,若是找不到返回0
SQL> select instr('Helloworld','l') l1,instr('Hello world','o',5) l2from dual;
L1 L2
---------- ----------
3 11
select ename from emp where instr(ename,'I')>0; // 查找eaname列中 ,字段中包含’I’的字段.
8. lpad()左填充,
rpad()右填充.
SQL> select lpad('hello',10) 填充空格,lpad('hello',10,'*') from dual;
填充空格 LPAD('HELL
---------- ----------
hello *****hello
SQL> select lpad('hello',10) 左填充空格,lpad('hello',10,'*') 左填充星號,rpad('hello',10)右填充空格 ,rpad('hello',10,'*') 右填充星號 from dual;
左填充空格 左填充星號 右填充空格 右填充星號
---------- ---------- ---------- ----------
hello *****hellohello hello*****
9. trim()去除兩邊的空格或者其它字符
SQL> select trim(' hello') 去除左右空格,trim('hello') 去除左右指定的字符 from dual;
去除 去除
----- -----
hello hello
SQL> select trim(' hello') 去除左右空格,trim('h' from 'hello') 去除左右指定的字符 from dual;
去除 去除
----- ----
hello ello
去除左右指定的字符:tirm(‘指定的去除字符’ from ‘ 字符串’)
SQL> select trim(' hello') 去除左右空格,trim('h' from'hhellohh') 去除左右指定的字符 from dual;
去除 去除
----- ----
hello ello
10. -replace替換字符串
SQL> select replace('hello world','ell','hide') from dual;
REPLACE('HEL
------------
hhideo world
10. Round():
四捨五入,截斷到指定的位數,若是後面的值大於5,就+1,
TRUNC()直接截斷
SQL> select round(45.926,2) 兩位小數,round(45.926,1) 一位小數,round(45.926,0)零位小數,round(45.926,-1) 負一,round(45.926,-2) 負二 from dual;
兩位小數 一位小數 零位小數 負一 負二
---------- ---------- ---------- ---------- ----------
45.93 45.9 46 50 0 (是由於-2值得的位數是4,小於5,因此爲0)
11. 用 TO_DATE 函數將字符轉換成日期:
格式: TO_DATE(char[, 'format_model'])
日期數據類型的加減運算
日期能夠加減數字,表示在日期的後面加減多少天
日期能夠減日期,表示兩個日期相關的天數
SQL> select round(to_date('7-7月 -12'),'YEAR') from dual;
SQL> select sysdate-1 昨天,sysdate 今天,sysdate+1明天 from dual;
日期的格式化:
SQL> select to_char(sysdate,'YYYY-MM-DD hh12:mi:ss DY') fromdual;
12. add_months(); 向指定日期中加上若干月數
next_day(); 指定日期的下一個日期
last_day(); 本月的最後一天
SQL> select add_months(sysdate,30)"30個月後日期",next_day(sysdate,'星期三') 下個星期三,last_day(sysdate) 本月的最後一天 from dual;
13. 四捨五入用在日期型數
在日期上加上或減去一個數字結果仍爲日期。
兩個日期相減返回日期之間相差的天數。
能夠用數字除24來向日期中加上或減去小時
SQL> select round(to_date('10-5月 -12'),'MONTH') from dual;
ROUND(TO_DATE(
--------------
01-5月 -12
注:在四捨五入日時,若是指定了月份,則主要看日期的變化,日期大於月中旬的,則月份加1,小於則日期爲1
SQL> select round(to_date('7-7月 -12'),'YEAR') from dual;
ROUND(TO_DATE(
--------------
01-1月 -13
指定年的主要看月份的變化, 月份大於7,則年份加1 ,不然
14 . Months_between(); 兩個日期相差的月數
SQL> select ename,hiredate,sysdate-hiredate 工做天數,months_between(sysdate,hiredate)工做大約月數,months_between(sysdate,hiredate)/12年 from emp;
子符串與日期的鏈接:
SQL> select 'hell'|| to_char(sysdate) from dual;
'HELL'||TO_CHAR(SY
------------------
hell24-8月 -12
通用函數
1.NVL (expr1, expr2) 若是e1爲空則輸出e2,不然返回e1
NVL2 (expr1, expr2, expr3) 若是e1爲空,返回e2,不然返回e3.
NULLIF (expr1, expr2) 相等返回NULL,不等返回expr1
COALESCE (expr1, expr2, ..., exprn) 返回第一個不爲空的值
例: SQL> selectename,sal*12,sal*12+nvl(comm,0) 年薪 from emp; // 獎金和年薪之和不爲空
2.COALESCE的特色:
COALESCE 與 NVL 相比的優勢在於 COALESCE 能夠同時處理交替的多個值。
若是第一個表達式爲空,則返回下一個表達式,對其餘的參數進行COALESCE 。
即:找第一個不爲空的值。
SQL> select ename,sal*12,sal*12+coalesce(comm,null,0)年薪 from emp;
select語句中使用表達式
使用if then elseif
方式1;CASE 表達式,SQL99
方式2:decode函數,Oracle自帶.
3. CASE expr WHEN comparison_expr1 THENreturn_expr1
[WHEN comparison_expr2 THEN return_expr2
WHEN comparison_exprn THEN return_exprn
ELSE else_expr]
END
DECODE(col|expression, search1, result1
[, search2, result2,...,]
[, default])
例:
SQL> ---漲工資:job爲SALESMAN的漲500,爲MANAGER漲800,其它漲300
SQL> ---查出員工的姓名,當前工資,及漲後工資
1 select ename 姓名,sal 月薪 ,(case job when 'SALESMAN'then 500
2 when 'MANAGER' then 800 else 300 end)每一個員工漲的工資,sal+(case job when 'SALESMAN' then 500
3 when 'MANAGER' then 800 else 300 end)漲後的工資
4* from emp
SQL> /
姓名 月薪 每一個員工漲的工資 漲後的工資
---------- ---------- ---------------- ---------- ---------------- ----------------
SMITH 800 300 1100
ALLEN 1600 500 2100
WARD 1250 500 1750
JONES 2975 800 3775
例: decode() 至關於if else //查詢全部獎金不爲空的,漲工資工資的員工
SQL> select ename,job,sal,comm,deptno,decode(job,'CLERK',500,'MANAGER',800,300)漲後的工資 from emp where comm is not null;
2012-8-25 day40:
分組函數: 分組函數做用於一組數據,並對一組數據返回一個值。
求總數: count() , 求平均值:avg() 求和:sum()
SQL> select count(*) 員工的總數 ,sum(sal),avg(sal)平均工資,sum(sal)/count(*)from emp;
員工的總數 SUM(SAL) 平均工資 SUM(SAL)/COUNT(*)
---------- ---------- ---------- ----------------- ----------------- -----------------
14 29025 2073.21429 2073.21429
注: 分組函數不會把帶有null 值的統計計算
分組查詢 grounp by
1.SQL> select deptno,sum(sal) from empgroup by deptno; //按照員工的部門進行分組查詢計算總工資
2.多條件分組查詢:
統計出員工部門,職位所對應的工資的總和,並排序
SQL> select deptno,job,sum(sal) from emp group by deptno,joborder by deptno;
3.在分組函數中, where 語句中不能使用別名查詢, 組函數不能使用.
查詢語句中,where裏面的內容不能包含別名
select * from 表名 where 條件 group by 分組 having 過濾分組結果
例: SQL> select deptno ,avg(sal) from empgroup by deptno having avg(sal)>2000;
SQL> select deptno,avg(sal) from emp group by deptno having deptno<>20; //部門編號不等於20的全部員工
having子句中出現的過濾條件只能是group by中的分組列及其它分組函數
例:1 查詢各部門中的信息:部門編號、總人數、最大薪水、最小薪水、平均薪水、薪水總和,不顯示不屬於任何部門的信息。
SQL> select deptno,count(*),max(sal),min(sal),sum(sal) from empwhere deptno is not null group by deptno;
或者:
SQL> select deptno, count(*) ,max(sal) ,min(sal) ,sum(sal) fromemp group by deptno having deptno is not null;
例:2:--查詢各部門的信息:部門編號、其中的員工數,只顯示人數大於2的結果,而且按人數升序排序。
Select deptno,count(*) from emp group by deptno having count(*)>2order by count(*) desc;
DEPTNO COUNT(*)
------ ---------------- ----------
30 6
20 5
10 3
5) 使用加強查詢groupby rollup(「 」,」 」)
sqlplus表報表查詢:
Break on 列名 skip 行; 例; break on deptno skip1;
SQL> selectdeptno,job,sum(sal) from emp group by rollup(deptno,job);
SQL> ---使用sqlplus提供報表功能生成結果
break on deptno skip 2;
取消設置
break on null;
結果:
DEPTNO JOB SUM(SAL)
----------------- ----------
10 CLERK 1300
MANAGER 2450
PRESIDENT 5000
8750
20 CLERK 1900
ANALYST 6000
MANAGER 2975
10875
多表查詢:
Oracle 鏈接:
Equijoin:等值鏈接 , Non-equijoin:不等值鏈接 , Outer join:外鏈接 ,Self join:自鏈接
1.笛卡爾集合查詢;
2. 使用鏈接在多個表中查詢數據。(多表中的操做)
語法:
SELECT table1.column,table2.column
FROM table1, table2
WHERE table1.column1 =table2.column2;
在 WHERE 字句中寫入鏈接條件。
在表中有相同列時,在列名以前加上表名前綴
例:SQL> select e.ename,e.deptno,e.sal,d.deptno,d.dname from mep4e,dept d;
若是要返回的列中包含兩個表都具備列名,就須要指定列時,須要指定完整表名
等值鏈接: 查詢員工信息,要求顯示員工的編號,姓名,月薪和部門名稱
例: selectempno,ename,sal,dname from emp,dept whereemp.deptno=dept.deptno;
當表名比較多時,能夠給表取別名
例: SQL> select e.empno,e.ename,e.sal,e.deptno,d.dname from emp e,dept d where e.deptno=d.deptno;
非等值鏈接 : 查詢員工的工資級別:編號 姓名 月薪和級別
例: SQL> select e.empno,e.ename,e.sal,g.grade from emp e,salgrade g
EMPNO ENAME SAL GRADE
---------- -------------------- ----------
7369 SMITH 800 1
7499 ALLEN 1600 1
例:經過不一樣的表查詢部門名稱及平均工資
SQL> selectd.dname,avg(sal) from emp,dept d group by d.dname;
2.外鏈接語法
外鏈接的符號是 (+)。
SQL> ---左外,右外,全鏈接
SQL> --左外(左鏈接)---左邊的表裏面不符合鏈接條件的數據也要出來
SQL> --右外(右鏈接)---右邊的表裏面不符合鏈接條件下數據也要到結果集中
SQL> --全鏈接---左右兩邊表裏面不符合鏈接條件,均放到結果集中
左鏈接:
例:---查出姓名,工資,部門編號,部門名稱
SQL> selectename,sal,d.deptno,d.dname from emp e, dept d where d.deptno=e.deptno(+);
右鏈接:
SQL> selectename,sal,d.deptno,d.dname from emp e, dept d where d.deptno(+)=e.deptno;
內鏈接寫法:select *from emp e join dept on e.deptno=d.deptno;
外鏈接,(左外鏈接) select 列名 from 表名left join表名 on 條件
使用 emp e outer left|right join dept d on....
SQL> selecte.ename,d.dname from emp e left join dept d on e.deptno=d.deptno;
右外鏈接: select 列名 from 表名 right join 表名 on 條件
SQL> selecte.ename,d.dname from emp e right join dept d on e.deptno=d.deptno;
全鏈接: select 列名 from 表名full join 表名 on 條件
SQL> selecte.ename,d.dname from emp e full join dept d on e.deptno=d.deptno;
自鏈接:
SQL> --顯示員工的姓名及他的上級的姓名
select e.empno,e.ename,e.mgr,m.ename from emp e,emp m wheree.mgr=m.empno;
層次查詢
SQL> selectempno,ename,mgr from emp connect by prior empno=mgr start with mgris null;
子查詢:
特色:1、子查詢使用(括起來)
二、子查詢位位置select from where having 放子查詢。
三、不能夠在主查詢的group by 放子查詢
四、主查詢和子查詢能夠不是用一張表,只要子查詢返回的結果主查詢能夠使用便可
5. 單行操做符對應單行子查詢,多行操做符對應多行子查詢。
單行子查詢:使用的運算符:大於> , 小於 < ,大於等於>= , 小於等於 <= ,不等於!= 或者 <>
例:查出比Scott工資高的員工?
SQL> ---一、先查出SCOTT的工資是多少
SQL>--select sal from emp where ename='SCOTT';
SQL> --二、select * from emp where sal>scott的工資
SQL> select* from emp where sal>(select sal from EMP where ename='SCOTT');
例;10號部門的員工姓名、工資及部門名稱
SQL> select ename,sal,dname from emp e join dept d on e.deptno=d.deptno and e.deptno=10 //方法1; 使用鏈接查詢
SQL> selectename,sal ,(select dname from dept where deptno=10) fromemp where deptno=10;
1.from 後面放子查詢:
例:查詢員工的編號和姓名
SQL> select* from (select ename,deptno from emp); //次查詢沒有意義,只是爲了說明子查詢的放置位置。
2. 主查詢和子查詢能夠不是用一張表,只要子查詢返回的結果主查詢能夠使用便可
SQL> --查詢部門名稱爲ACCOUNTING的員工信息
SQL>1.查詢名稱爲ACCOUNTING的部門
SQL> 2.根據部門查詢員工的信息
SQL> select* from emp e where e.deptno=(select deptno from dept dwhere d.dname='ACCOUNTING');
子查詢中使用子函數:
例;查詢工資大於平均工資的員工
SQL> select* from emp where sal>(select avg(sal) from emp);
例:查詢每個部門的最低工資,要求最低工資大於20號部門的最低工資
Sql>select deptno,min(sal) from emp group by deptno havingmin(sal)>(select min(sal) from emp where deptno=20);
多行子查詢
1.子查詢返回的結果是多行數據
2.IN==等於列中的一個值
3.ANY---和子查詢返回的任意一個值比較
4. ALL--和子查詢返回的全部值比較
例:查詢部門名稱爲A"CCOUTING"、SALES的員工信息
select * fromemp where deptno in (select deptno from dept where dname='ACCOUNTING' ordname='SALES');
-any用在小於,小於集合中最大值 , 用在大於,大於集合中的最小值
SQL> ---any用於大於,
例:查詢工資比10號部門任意一個員工工資低的員工信息
SQL>Select *from emp where sal< any (select sal from empwhere deptno=10)
-all用在大於,大於最大的 ,all用在小於,小於最小的
QL> --all: 和子查詢中全部值比較
SQL> --查詢工資比10號部門全部員工工資低的員工信息
1 select * from emp where sal< all (select sal from emp where deptno=10)
使用not in時,後面的子查詢返回的結果中不能有null值,不然找不到。
SQL> ----查詢不是經理的員工信息
SQL> select* from emp where empno not in(select mgr fromemp where mgr is not null);
//查詢各部門員工的工資大於任何一個部門的平均工資.
SQL> selecte.ename,e.sal,ae.deptno,ae.avgsal from emp e,(select deptno,avg(sal) avgsalfrom emp group by deptno) ae wheree.deptno=ae.deptno and e.sal>ae.avgsal
rownum做<=比較,不能做>比較(隱式於表中,做爲表中編號的)
注意1:
在rownum以前不能加上表的別名,如 from emp e whre e.rownum<=3,這是錯誤的。
注意2:
rownum是在where過濾後返回符合條件的結果生成的,第一個返回的爲1,第二個爲2...。
但要注意,是先生成rownum,而後再進行order by操做。
注意3:
rownum是在符合條件後返回時生成的一個行號。
但若是在where中判斷時用到了rownum時,會使用這個值:若是本條記錄符合條件能返回,則rownum應該是多少,用這個值參與判斷。若是不成立,就對下一條記錄也這樣作。若是寫成whererownum>1,則不會有結果。
語法:SELECT [column_list], ROWNUM
FROM (SELECT [column_list]
FROM table
ORDER BY Top-N_column)
WHERE ROWNUM <= N;
SQL> select rownum,ename,job,sal,comm,deptno from emp wheresal>1500;
ROWNUM ENAME JOB SAL COMM DEPTNO
-------------------- --------- ---------- ---------- ----------
1 ALLEN SALESMAN 1600 300 30
2 JONES MANAGER 2975 20
3 BLAKE MANAGER 2850 30
TOP-IN
分頁
若是不須要排序:
第一頁:
select * from emp where rownum<=10;
之後頁:
select * from (select rownum rn,e.* from emp e) where rn>=? and rn<=?
通用:
select * from (select rownum rn,e.* from emp e) where rn>=? and rn<=?
若是須要排序:
第一頁:
select * from (select * from emporder by sal) where rownum<=10;
之後頁:
select * from (select rownum rn,e.* from (select * from emp order by sal) e) where rn<=? and rn>=?;
內:負責排序
中:負責生成行號
外:負責過濾出結果
通用:
select * from (select rownum rn,e.* from (select * from emp order by sal) e) where rn<=? and rn>=?;
集合運算:
union all 並集 :返回兩個集合中全部記錄,包括重複元素
Union並集:返回兩個集合中的去除重複元素的全部記錄
INTERSECT 交集:返回同時屬於兩個集合的全部記錄
MINUS 差集: MINUS返回屬於第一個集合,但不屬於第二個集合的記錄
Union all用法; 返回兩個集合中全部記錄,包括重複元素
例:查詢10號部門及20號部門的員工
SQL> Select * from emp where deptno=10 unionselect * from emp where deptno=20;
union all 並集:返回兩個集合中全部記錄,包括重複元素
SQL> Select * from emp where deptno=10 union all select * from emp where deptno=20;
INTERSECT 交集:返回同時屬於兩個集合的全部記錄
SQL> Selectjob from emp where deptno=10 intersect selectjob from emp where deptno=20;
例;顯示薪水同時位於級別1(700~1300)和級別2(1201~1400)的員工信息。
Sql>select *from emp where sal between 700 and 1300 intersect select* from emp where sal between 1200 and 1500
MINUS 差集: MINUS返回屬於第一個集合,但不屬於第二個集合的記錄
SQL> Select* from emp where deptno=10 minus select * fromemp where deptno=20;
能夠使用括號改變集合執行的順序
1 select job from emp where deptno=10
2 union
3 (select job from emp where deptno=20
4 minus
5* select job from emp where deptno=30)
以上執行順序:首先是進行差集運算,即即結果爲 deptno=20的部門,而後在於deptno=10的集合求並集
若是有order by子句,必須放到最後一個查詢語句後
Sql>select job from emp wheredeptno=20
union (selectjob from emp where deptno=10) order by job;
集合中的報表查詢:
1 select deptno,job,sum(sal)from emp group by deptno,job
2 union
3 select deptno,to_char(null),sum(sal) from emp group by deptno
4 union
5* selectto_number(null),to_char(null),sum(sal) from emp
Break on deptnoskip 1;
取消 break on null;
查看sql語句執行時間:
Set timing on 結束: set timing off;
數據控制語言
1.DML(Data Manipulation Language – 數據操做語言) 能夠在下列條件下執行:
向表中插入數據,修改現存數據 , 刪除現存數據
2.事務是由完成若干項工做的DML語句組成的
INSERT 語句語法
INSERT INTO table [(column [, column...])] VALUES (value[, value...]);
特色:爲每一列添加一個新值。
按列的默認順序列出各個列的值。
在 INSERT 子句中隨意列出列名和他們的值。
字符和日期型數據應包含在單引號中。
例:SQL> insert 表名(‘ename’,’deptno’)values('aaa',555);
Delete語句語法
1.DELETE [FROM] table [WHERE condition];
2.在 DELETE 中使用子查詢,使刪除基於另外一個表 中的數據。
DELETE FROM employees
WHERE department_id =
(SELECTdepartment_id
FROM departments
WHERE department_name LIKE'%Public%');
例: delete from emp4 where sal>(select avg(sal) from emp);
注:Delete刪除表中的全部數據,他是一條DML語句,支持事務。 而Truncatetable達到清空表數據的效果.他是一條DDL語句. 清空的數據不能閃回
Update語句語法
UPDATE table SET column = value [, column = value, ...] [WHERE condition];
SQL> update 表名 set 列名=值,列2=值2 where 過濾
例: update emp4 set sal=(select avg(sal) fromemp) where ename='CLARK';
複製表:
Insert into empselect * from emp; //循環成倍數的複製表中的數據
建立表:
SQL> createtable emp4 as select * from emp where deptnoin(10,20);
Sql> createtable emp2 as select distinct * from emp;
注在建立表,複製表,更新表,等只要是符合完整的語句,在該語句中能夠使用任何操做
& :地址符號的使用:
例 :插入數據:SQL> insert into emp4(empno,ename,sal)values(&empno,&ename,&sal);
查詢數據:SQL> select * fromemp4 where deptno=&deptno;
數據庫事務
事物的提交:Commit 事物的回滾:rollback
數據庫事務由如下的部分組成:
1.一個或多個DML 語句
2.一個 DDL(Data DefinitionLanguage – 數據定義語言) 語句
3.一個 DCL(Data Control Language –數據控制語言) 語句
COMMIT和ROLLBACK語句的優勢
1.確保數據完整性。
2.數據改變被提交以前預覽。
3.將邏輯上相關的操做分組
回滾點:
1.使用 SAVEPOINT 語句在當前事務中建立保存點。
2.使用 ROLLBACK TO SAVEPOINT 語句回滾到建立的保存點。
事物的隔離機制:
1.髒讀: 對於兩個事物 T1, T2, T1 讀取了已經被 T2 更新但尚未被提交的字段. 以後, 若 T2 回滾, T1讀取的內容就是臨時且無效的.
2.不可重複讀: 對於兩個事物 T1, T2, T1 讀取了一個字段, 而後 T2 更新了該字段. 以後, T1再次讀取同一個字段, 值就不一樣了.
3.幻讀: 對於兩個事物 T1, T2, T1 從一個表中讀取了一個字段, 而後 T2 在該表中插入了一些新的行. 以後, 若是 T1 再次讀取同一個表, 就會多出幾行
Oracle 中事物的隔離級別:
1. Oracle 支持的 2 種事務隔離級別:READ COMMITED, SERIALIZABLE. Oracle 默認的事務隔離級別爲:READ COMMITED
2. Mysql 支持 4 中事務隔離級別. Mysql 默認的事務隔離級別爲:REPEATABLE READ
相關子查詢 :
特色: 1.先執行主查詢,返回一行數據,2.把一行的數據放到子查詢中,讓子查詢運行, 3.再把子查詢的結果放回到主查詢中進行運算,依次循環,
例1: 查找每一個部門中薪水最高的僱員,顯示姓和薪水。
SQL> select ename,sal from emp e wheresal=(select max(sal) from emp m where e.deptno=m.deptno);
2.查詢各部門中工資比本部門平均工資高的員工的員工號, 姓名和工資。
SQL> selecte.deptno,e.ename,e.sal from emp e where sal>(select avg(sal) from emp mwhere e.deptno=m.deptno);
面試題1,第二行數據的工資等於上一行數據的工資
SQL> selectename,sal,(select sal from emp where id=e.id-1 ) from emp e;
Wm_concat(列) : 將列轉換成行
例:對各部門的員工進行分組,
SQL> Selectwm_concat(deptno) d from emp group by deptno;
例2: 刪除表中的重複數據
第一種: 1.複製原有的表,並刪除表中的數據, 2.在查詢原有表中取出重複數據的數據, 3. 將去除重複的數據插入到複製的表中.
Sql> createtable copyEmp as select * from emp ;
Sql> deletefrom copyEmp;
Sql> insertinto copyEmp select distinct * from emp;
Rowid :是一個物理層在一個列,用來記錄每一行數據的地址;
第二種: 使用相關子查詢: 經過找rowid最大值進行排除重複元素,
Sql>select rowid,name,age fromt_student t1 where rowid in(select max(rowid) fromt_student
where name=t1.name and age=t1.age);
第三種: 直接刪除表中取出重複數據的幾條外
Sql> delete from t_student t1 where rowid not in(select max(rowid) fromt_student
where name=t1.name and age=t1.age)
Oracle中用戶權限系統:
1. 權限的基本應用
1) 建立用戶
Create user test identifiedby test
Alter user test account lock // 對用戶加鎖
Alter user test account unlock // 解鎖
2.受權:
Grant createsession to test //將建立會話的權限付給test用戶
Grant createsession, create any table to test
3.回收權限:
Revoke createsession from test
Revoke createsession,create any table from test;
4.設置用戶的表空間訪問配額
Alter user testquota unlimited on userts ;
注: 在oem建立用戶時,會給用戶添加一個connect角色,從而具備createsession的權限.
5.用戶權限:
1)系統權限: grant create table to test
2)對象權限: grant select on soctt.emp;
3)權限的級聯: grant create table to testwith admin option
Grant select onscott.emp to test with grant option
注: 系統權限不會級聯回收.WIDTH ADMIN OPTION讓用戶能夠把權限繼續授給其它人
對象權限會級聯回收。WITH GRANT OPTION來讓用戶把對象權限授予其它用戶
6.角色: 用來定義相同功能的集合
Create rolerole //建立角色;
添加角色的權限:
Grant alteruser to role
grant createsession to role // 將建立會話的權限付給角色
grant select onscott.emp to role;
表空間(tablespace)
1.表空間:數據庫的邏輯組成部分;數據庫是存放在表空間中,一個表空間由一個或多個物理文件組成。
2.Oracle表空間的邏輯結構:庫->表空間->段->區和塊
3.表空間的做用:一、控制數據庫佔用的磁盤空間;二、Dba能夠將不一樣類型的數據對象部署到不一樣的位置,這樣有利於提升i/0性能,並有得於備份和恢復管理
創建表空間:Createtablespace
Create tablespace data01 datafile 'd:\test\data01.dbf' size 20muniform size 128k(文件的儲存位置)
Uniform表示區的大小爲128K。
每一個文件有必定的限制,不要超過500M。
1.使用表空間:
Create table test001(id number(4),name varchar2(50)) tablespacedata01;
二、表空間及表的查詢
A、查找表空間中的表
Select * from all_tables where tablespace_name='DATA01';
B、查看一個表在哪一個表空間
Select tablespace_name from user_tables where table_name='EMP';
C.修改表空間中數據文件的位置
host move f:\test\*.* d:\test
Alter tablespace data01 rename datafile 'F:\TEST\DATA02.DAT' to 'D:\TEST\DATA02.DAT';
使表空間脫機:
Alter tablespace data01 offline; // 脫機
Alter tablespace data01 online; //上線
Alter tablespace data01 read only;//只讀
Alter tablespace data01 read write//讀寫
三、表空間的擴展
A、增長數據文件
Alter tablespace data01 add datafile 'd:\test\data0102.dat' size20m;
B、把已有的數據文件內容加大
alter database datafile'd:\test\data0102.dat' resize 50m;
表的建立
Create table 表名(‘字段’ ‘類型’);
例: create table tmp (id number(5), name varchar(20));
表中插入數據:
Insert into 表名 values(‘字段’,.......);
增長一列:
alter table test add (name varchar2(20));
刪除表:
Drop table 表名 例: drop table test;
Drop table testpurge //永久刪除
alter table test drop column name; // 刪除一列
修改表:
alter table test modify name varchar2(50);
修改變名
Rename 表名 to 新表名; ..給Oracle中的數據庫對象改名都可以使用
清空表
TRUNCATE TABLE 表名
表中的數據類型:
Varchr2(size) 可變長度數據
Char(size) 定長字符數據
Number 可變數值數據
Date 日期類型
Long 可變長字符數據,最大可達到2G
CLOB 字符數據,最大可達到4G
RAW and LONG RAW 原始的二進制數據
BLOB 二進制數據,最大可達到4G
BFILE 存儲外部文件的二進制數據,最大可達到4G
ROWID 行地址
表定義約束
約束是一種數據庫對象,他是做用於表的數據庫對象
約束主要做用是用來維護表數據的完整性,合法性。
約束類型:
NOT NULL,UNICODE,PRIMARY KEY,FORGIN KEY,CHECK
例:建立一個表使用幾個約束
create table dept(deptno NUMBER(4) primarykey,name varchar2(100) not null);
constraint使用:
alter table emp add constraint FK_000004 foreign key (deptno)references dept(deptno); //給emp表增長一個外鍵
CHECK使用:
alter table emp add sal number(4) CHECK(sal>2000);
視圖
1.視圖是一種虛表.
2.視圖創建在已有表的基礎上, 視圖賴以創建的這些表稱爲基表。
3.向視圖提供數據內容的語句爲SELECT 語句, 能夠將視圖理解爲存儲起來的 SELECT 語句.
4.視圖向用戶提供基表數據的另外一種表現形式
A. 試圖就是將咱們常常須要使用到的查詢語句進行封裝起來,一邊在下次查詢是不用寫太多的代碼.方便操做
例: 建立一個可以查到各部門比部門平均工資高的員工的工號姓名及工資的視圖
create orreplace view emp_avgsal_higer as select e.empno,e.ename,e.sal,e.deptno from empe,(select deptno,avg(sal) avgsal from emp group by deptno) a where e.deptno=a.deptno ande.sal>a.avgsal;
b.試圖也能夠使用select語句直接查詢: 例: select * from 視圖名稱
c. 往視圖中執行dml語句
例: insert into emp20(empno,ename,job) values(8766,'dddd','ddd');
D. 建立不容許執行DML語句的視圖
SQL> createor replace view emp20 as select * from emp where deptno=20 with read only;
建立序列
create sequencemysequence;
使用序列
序列的兩個屬性NEXTVAL(產生下一個值,返回當前值);CURRVAL(得到當前的值)
SQL> selectmysequence.nextval from dual;
清空回收站: purge recyclebin
永久性刪除表: drop table 表名 purge;
數據庫的導入和導出:
Exp : 導出: exp 用戶名/密碼導出的文件路徑表名=(列名1,列名2,.....n);
例:exp scott/oracle file=f:/test/1.dmp log=f:/test/1.log tables=(emp,dept);
emp: 導入: emp 用戶名/密碼導入的文件路徑
例: imp scott/oracle file=f:/test/1.dmp
導入到其它用戶(DBA操做) :
imp system/orcl file=f:/test/1.dmp fromuser=scott touser=test//從一個用戶導入到另一個用戶
閃回:flashback
1.傳統方式: 備份:增量備份|所有備份,恢復的數據文件比較大,時間長了
2.oracle9àflashback
a. 對錶中的數據進行一些Dml操做,並且每一次的操做都已經提交,而在一個時間段內的數據錯誤,須要把數據回到指定的回滾點,
b. 把數據誤刪除,並且還可能有另外建立一個同名的表.
C.須要查看之前的記錄
D.執行不少事物,而其中的一個事物發生錯誤,此時須要修改出錯的數據
閃回表(Flashback):
閃回表語法:
FLASHBACK TABLE[schema.]<table_name> TO
{[BEFORE DROP [RENAME TO table]] [SCN|TIMESTAMP]expr [ENABLE|DISABLE]TRIGGERS}
schema:模式名,通常爲用戶名。
TO TIMESTAMP:系統郵戳,包含年、月、日、時、分、秒。
TO SCN:系統更改號,
ENABLE TRIGGERS:表示觸發器恢復之後爲enable狀態,而默認爲disable狀態。
TO BEFORE DROP:表示恢復到刪除以前。
RENAME TO table:表示更換表名。
閃回表: 其實是將表中的數據快速回復到過去的一個焦點或者系統的改變號scn .
Show recyclebin :顯示回收站刪除的內容
a.在刪除表的狀況下,
b.查看回收站中的內容:show show recycle;
c.查看回收站中刪除的表數據 :例: select *from 「BIN$VYLpw5k/QpiNpWp5a/2IIg」==$0」
d.閃回刪除的表: 使用表的原始名字及回收站中的名稱都可以閃回 flashbacktable 刪除的表名 tobefore drop. 或者 Flashbacktable 回收站中表名稱 tobefore drop rename to 表名
例: flashback table temp to to beforedrop; 或者 flashbacktable 「BIN$VYLpw5k/QpiNpWp5a/2IIg」==$0」 to before drop;
c.查看閃回的結果 :select * from 表名; 例: select * from temp;
閃回刪除(to beforedrop[reneme to])
a.Show parameter undo //查看撤銷表空間
b. 對一張表進行一系列的操做(增,刪,該,查) ;
c. 查詢Scn系統該編號: selectsysdate,to_char(sysdate,’yyyy-mm-dd hh24:mi:ss’) scn from dudal;
d. 啓動行移動: altertable temp enable row movement;
e. Flashback table 表名 to scn scn編號; 例: Flashback table temp to scn65970;
閃回版本的查詢
: 語法:select column_name[,column_name,...] from table_name
versions between [SCN|TIMESTAMP][expr|MINVALUE]
and [epxr|MAXVALUE] as of [SCN|TIMESTAMP] expr;
其中:column_name列名;table_name表名;between...and時間段;SCN系統改變號;TIMESTAMP時間戳;AS OF表示恢復單個版本;MAXVALUE最大值;MINVALUE最小值;expr指定一個值或者表達式。
a.建立一張新表 :create table temp2(vid int,name,varchar2(20));
b. 對錶進行操做,
如: insert into temp2values(1,'aaa'); commit
insert into temp2values(2,'bbb'); commit;
c.desc flashback_transaction_query; //查看事物歷史記錄
d.查詢一個表中的操做歷史:
Select column(列名......n)from 表名 versionbetween scn minvalue and maxvalue;
對版本進行查詢是,能夠增長一個僞列查詢版本操做的詳細信息
例: selectvid,name,versions_xid,versions_operation from temp2 versions between scnminvalue and maxvalue;
閃回事物:(Flashacktransaction query):
a.flashback_transaction_query視圖,從該視圖中能夠獲取事務的歷史操做記錄以及撤銷語句(UNDO_SQL)。
b.對版本進行查詢是經過查詢版本得到事務id,也就是versions_xid詳細信息,
例: select vid,name,versions_xid,versions_operation from temp2 versionsbetween scn minvalue and maxvalue;
注: 事物查詢中能夠增長一個僞列查詢版本操做的
c.執行閃回版本, 根據xid的值來查看undo_sql的列的值,利用UNDO_SQL撤銷事務操做
select undo_sql from flashback_transaction_query wherexid='02001B007B01000002001B007B010000';
commit;
PL/SQL(Procedure Language/SQL) :
指在SQL命令語言中增長了過程處理語句(如分支、循環等),使SQL語言具備過程處理能力
1.PL/SQL的結構:
declare
說明部分 (變量說明,光標申明,例外說明 〕
begin
語句序列 (DML語句,if , for ,while〕…
exception
異常處理語句
end;
2.變量的聲明:
setserveroutput on; --設置輸出語句
declare
v_name varchar2(20);
v_now datedefault sysdate;
v_salnumber(4);
v_enameemp.ename%TYPE; --引用型變量
rec_empemp%ROWTYPE; --記錄型變量
setserveroutput on; --設置輸出語句
declare
v_namevarchar2(20);
v_now datedefault sysdate;
v_salnumber(4);
v_enameemp.ename%TYPE; --引用型變量
rec_empemp%ROWTYPE; --記錄型變量
begin
--給變量賦值
v_name:='helloworld';
select avg(sal)into v_sal from emp; --經過查詢emp表中的平均並付給v_sal
select enameinto v_ename from emp where empno=7369; 經過查詢emp表將值付給v_ename;
dbms_output.put_line(v_name);--輸出語句
dbms_output.put_line('平均工資sal='||v_sal);
select * intorec_emp from emp where empno=7521; //查詢的多值付給指定的變量rec_emp
dbms_output.put_line('工號empno:'||rec_emp.empno||', 姓名:'||rec_emp.ename||', 工資:'||rec_emp.sal);
end;
begin
--給變量賦值
v_name:='helloworld';
select avg(sal)into v_sal from emp; --經過查詢emp表中的平均並付給v_sal
select enameinto v_ename from emp where empno=7369;
dbms_output.put_line(v_name);--輸出語句
dbms_output.put_line('平均工資sal='||v_sal);
select * intorec_emp from emp where empno=7521;
dbms_output.put_line('工號empno:'||rec_emp.empno||', 姓名:'||rec_emp.ename||', 工資:'||rec_emp.sal);
end;
IF語句:
1. If 條件 then
語句1;
語句2;.......語句n;
End if
2. If 條件 then 語句;
Elsif 條件 then語句;
Else 語句;
End if ;
3. IF 條件 THEN 語句序列1;
ESLE 語句序列 2;
END IF;
從鍵盤輸入:accept num prompt '請輸入數字:';
取得輸入的值: v_num number(5) :=#
例:
setserveroutput on;
accept numprompt '請輸入數字:';
declare
v_num number(5) :=#
begin
if(v_num=0) then
dbms_output.put_line('輸入的是零');
elsif(v_num<0) then
dbms_output.put_line('輸入的是負數');
else
dbms_output.put_line('輸入的是正數');
end if;
end;
循環語句:
1. While 條件 loop 語句;
End loop;
2. loop 語句;
exit when 條件;
end loop;
3. for 變量 in 語句序列 loop 語句;
end loop;
例:
setserveroutput on;
declare
v_i number(5);
begin
v_i:=1;
for v_i in 1..5loop
dbms_output.put_line(v_i);
end loop;
end;
光標(cursor)==resultSet
語法:
CURSOR 光標名 [ (參數名 數據類型[,參數名 數據類型]...)] IS SELECT 語句;
例: cursor curs is select ename from emp;
做用: 主要用於儲存查詢返回的多行數據.
遊標的屬性:
%ISOPEN BooLEAN 打開遊標則爲true
%NOTFOUND Boolean 若是提取的記錄沒有返回值,則爲true
%FOUND Boolean 一直爲true,知道沒有返回值
%ROWCOUNT Number 提取的總行數
打開光標執行查詢: open curs
取一行光標的值: fetch curs into 引用型變量(e_job emp.job%type);
關閉光標: close curs
例: set serveroutput on;
declare
--帶參數的遊標
cursor c_emp isselect deptno,job,avg(sal) from emp group by deptno,job;
--引用型變量的聲明
v_deptnoemp.deptno%TYPE;
v_jobemp.job%TYPE;
v_avgsalemp.sal%TYPE;
begin
--打開遊標
open c_emp;
loop
--取出一行數據
fetch c_emp into v_deptno,v_job,v_avgsal;
dbms_output.put_line('工號:'||v_deptno||', 職位:'||v_job||', 薪水:'||v_avgsal);
exit when c_emp%NOTFOUND;--只到沒有值爲至
end loop;
end;
Oracle的異常處理
系統內部定義的異常:
NO_data_found(沒有找到數據);;
Too_many_rows (select ...into 語句匹配多個行)
Zero_Divide ( 被零除)
Value_error (算術或轉換錯誤)
Timeout_on_resource (在等待資源時發生超時)
例: set serveroutput on;
declare
v_i number(5);
v_ename varchar(20);
begin
v_i:=5/0;
select ename into v_ename from emp;
dbms_output.put_line('除數爲零了');
exception
when Too_many_rows then
dbms_output.put_line('行數太多了');
when others then
dbms_output.put_line('除數爲零了');
end;
自定義異常步驟:
a.在declare中定義 如: out_of exception;
b.在可行的語句begin中使用raise引用 如: raise out_of;
c.在exception中處理異常 如:; when out_of then 語句:
存儲過程
語法:create [or replace] PROCEDURE 過程名(參數列表) AS PLSQL子程序體;
例如1:
create or replace PROCEDURE raisesal(v_deptno in number) ---- v_deptno innumber傳入的參數
as
cursor c_emp is select * from emp;
rec_emp emp%ROWTYPE;
v_sal emp.sal%TYPE;
v_total emp.sal%TYPE:=0;
begin
open c_emp;
loop
fetch c_emp into rec_emp;
exit when c_emp%notfound;
v_sal:=rec_emp.sal*0.3;
v_total:=v_total+v_sal;
exit when v_total>3000;
dbms_output.put_line('empno:'||rec_emp.empno||', 工資:'||rec_emp.sal||', 張後:'||(v_sal+rec_emp.sal));
update emp set sal=sal+v_sal whereempno=rec_emp.empno;
end loop;
close c_emp;
end raisesal;
1.存儲過程的調用: 在dos窗口使用: set serveroutput on;
exec 過程名(參數列表) 如: exec raisesal(20);
存儲函數:
創建存儲函數的語法:
CREATE [OR REPLACE] FUNCTION 函數名(參數列表)
RETURN 函數值類型
AS PLSQL子程序體;
1.sqldevloper中--à點擊函數à新建-à給函數起一個名字-à參數設置(類型,參數名)-à肯定-à自動生成一個模板
例: CREATE OR REPLACE FUNCTION MAXSAL
(
V_DEPTNO IN NUMBER
) RETURN NUMBERAS
v_maxsalemp.sal%TYPE; --聲明一個引用型變量
BEGIN
select max(sal) into v_maxsal from emp wheredeptno=v_deptno; //查詢語句
RETURN v_maxsal;
END MAXSAL;
2.存儲函數的調用: 在dos窗口: select 函數名(參數) from dual; 如: select maxsal(20) from dual;
JAVA中存儲過程的調用:
1.導入jar包; 該jar包在安裝目錄下:D:\oracle\10.2.0\db_1\jdbc\lib\ classes12.jar
2.註冊驅動在該jar包下: oracle.jdbc.driver.OracleDriver
例: 存儲過程如上例1, 經過程序調用存儲過程以下:
public class OracleFunction {
private String driverClass="oracle.jdbc.driver.OracleDriver";
private String url="jdbc:oracle:thin:@localhost:1521:orcl";
private String username="scott";
private String password="oracle";
@Test
public void call(){
try {
Class.forName(driverClass);
Connection conn =DriverManager.getConnection(url, username,password);
CallableStatement cstmt = conn.prepareCall("{call raisesal(?)}");
//設置調用函數佔位符?的參數
cstmt.setObject(1, 20);
int result = cstmt.executeUpdate();
System.out.println(result);
} catch (Exception e) {
e.printStackTrace();
}
}
}
3.以上代碼直接運行便可調用callraisesal(參數)進行增刪該查.
例2: 多個參數的存儲過程的調用
1).儲存過程:
CREATE OR REPLACE PROCEDURE DEPTSAL
(
V_DEPTNO IN NUMBER
, V_NAME IN OUT VARCHAR2
, V_AVGSAL IN OUT NUMBER
) AS
BEGIN
select dname into v_name from dept wheredeptno=V_DEPTNO;
select avg(sal) into v_avgsal from emp wheredeptno=V_DEPTNO;
END DEPTSAL;
2).Java程序的調用多個參數過程以下:
@Test
public void paramFunction(){
try {
Class.forName(driverClass);
Connection conn = DriverManager.getConnection(url, username,password);
CallableStatement cstmt = conn.prepareCall("{call DEPTSAL(?,?,?)}");
//設置調用函數佔位符?的參數
cstmt.setObject(1, 20);
cstmt.registerOutParameter(2,OracleTypes.CHAR);
cstmt.registerOutParameter(3,OracleTypes.NUMBER);
int result = cstmt.executeUpdate();
System.out.println(result);
} catch (Exception e) {
e.printStackTrace();
}
}
JAVA中函數的調用:
例:存儲函數如上例1,程序的方式調用函數以下:
@Test
public void callFunction(){
try {
Class.forName(driverClass);
Connection conn =DriverManager.getConnection(url, username,password);
CallableStatement cstmt = conn.prepareCall("{?=call maxsal(?)}");
//設置調用函數的參數
cstmt.registerOutParameter(1,OracleTypes.NUMBER);
cstmt.setObject(2, 20);//第二個參數
int result = cstmt.executeUpdate();
System.out.println(result);
} catch (Exception e) {
e.printStackTrace();
}
}
觸發器:
數據庫觸發器是一個與表相關聯的、存儲的PL/SQL程序。每當一個特定的數據操做語句(Insert,update,delete)在指定的表上發出時,Oracle自動地執行觸發器中定義的語句序列
分類: 語句觸發器和行觸發器(foreach row)
語法: CREATE [or REPLACE] TRIGGER 觸發器名
{BEFORE | AFTER}
{DELETE | INSERT | UPDATE [OF 列名]}
ON 表名
[FOR EACH ROW [WHEN(條件) ] ]
PLSQL 塊
觸發語句: :old :new
insert 全部字段都是空(null) 將要插入的數據
Update 更新之前該行的值 更新後的值
Delete 刪除之前該行的值 全部字段都是空(null)
例: 1.使用plsqldepevloper 在觸發器中建立à點擊觸發器,右鍵-à新建-à填寫表名,選擇表--à選擇須要的操做(增,刪改查)àok
CREATE ORREPLACE TRIGGER UPDATESAL
BEFORE UPDATEON EMP for each row
BEGIN
dbms_output.put_line('準備更新數據');
if(:new.sal<3000) then
raise_application_error(-20000,'工資小於2000不能更新');
end if;
END;
注:
raise_application_error是關鍵字, -20000 到 -20999
Spring:應用於開發
Spring: 開源框架.他是即IOC(依賴注入)和AOP(面向切面技術)等分層架構的系統框架,爲框架的開發而簡化代碼的書寫.
Spring框架:
資源包:
dist--spring發佈包,jar包,能夠分模塊存放。
lib---Spring所依賴的第三方包
samples--spring框架一些應用示例。
docs--文檔目錄
spring 開發過程:
1,導入相關的jar包.
A、Spring的基本jar包
commons-logging.jar---日誌
org.springframework.core-3.1.1.RELEASE.jar--spring核心
org.springframework.asm-3.1.1.RELEASE.jar --
org.springframework.beans-3.1.1.RELEASE.jar--bean工廠
2.寫一個業務接口
public interfaceITempSpring {
public abstract void syaHello();
}
3.定義一個實現該業務接口的類.
public class TempSpring implements ITempSpring {
private String msg;
private int time=1;
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public int getTime() {
return time;
}
public void setTime(int time) {
this.time = time;
}
@Override
public void syaHello(){
for(int i=0;i<time;i++){
System.out.println(msg);
}
}
}
1. 寫一個測試類.
public class SpringMain {
public static void main(String[] args) {
//取得資源文件
Resource resource = new ClassPathResource("beans.xml");
//根據xml文件加載spring容器
BeanFactory beanFactory = new XmlBeanFactory(resource);
//經過spring容器獲取組建
ITempSpring it = (ITempSpring)beanFactory.getBean(TempSpring.class);
it.syaHello();
}
}
xmlBeanFactory: 根據xml文件讀取配置信息的加載.
2. 配置beans.xml文件:
配置*.xml文件的來源:spring-beans-3.0.xsd ,主要
配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!-- 經過setter注入屬性 class:類名 ,<property>表籤 name: 屬性名,value:屬性值-->
<bean class="cn.spring.TempSpring">
<property name="msg" value="spring第一節"/>
<property name="time" value="5"/>
</bean>
</beans>
配置文件的規範形式:
<?xml version="1.0"encoding="UTF-8"?>
<beansxmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
.....配置相關bean信息
</beans>
配置信息能夠從spring的參考手冊或spring的例子中獲得。配置文件的取名能夠任意,文件能夠存放在任何目錄下,但考慮到通用性,通常放在類路徑下。
E:\java\開發工具\spring\spring-framework-2.5.5\docs\reference\html_single\index.xml中
3.3.2.6. Shortcuts and other convenience options forXML-based configuration metadata獲取配置信信息
IOC容器原理及依賴注入
容器的發展:
舊EJB容器時代(EJB容器)
輕容器時代(PicoContainer、Spring、Apache HiveMind、Guice)
新EJB時代EJB3.0
容器展望(中庸理論)
1、Bean概述
一切都是Bean
每個Bean都有一個惟一的名字
二、spring容器工做的過程--Bean的生命週期(singleton類型)
A、解析資源文件(xml/properties...),把文件中相關bean的定義信息BeanDefinition。===提供合法的xml文件
B、根據BeanDefinition建立Bean的實例.
C、裝配並注入Bean所依賴的對象。(規則很是多,能夠是自動注入,能夠按用戶指定的名字,類型等來注入)---經過配置文件來注入
D、給用戶提供Bean。調用容器中所提供的查詢Bean的方法。
E、Spring容器中止時銷燬Bean
三、BeanFactory及應用上下文ApplicationContext
A、BeanFactory,定義了Spring容器最基本的功能
ObjectgetBean(String name)--根據Bean名稱(包括別名)得到Bean
<T> TgetBean(Class<T> requiredType) --根據類型得到Bean
<T> TgetBean(String name, Class<T> requiredType)--返回指定類型的Bean,注意容器中有多個該類型的確Bean時,將出現異常。
booleancontainsBean(String name);
booleanisSingleton(String name); //是單例
booleanisPrototype(String name);
String[]getAliases(String name);
使用
BeanFactoryfactory=new XmlBeanFactory(new ClassPathResource("/bean.xml"));
Person p=factory.getBean(Person.class)
System.out.println(p);
BeanFactory,當調用getBean時實例化。
B、ApplicationContext--應用上下文件--以在應用使用Spring通常用他,由於能夠加載應用有關資源信息。
位於org.springframework.context-3.1.1.RELEASE.jar包
在使用ApplicationContext需要用el的jar,org.springframework.expression-3.1.1.RELEASE.jar
使用
ApplicationContextac=new ClassPathXmlApplicationContext("/bean.xml");
Person p=ac.getBean(Person.class);
System.out.println(p);
ApplicationContext在加載Bean定義信息就會實例化singleton的Bean.
4、Spring中Bean實例化的方式
A. 使用構造函數
配置文件: person.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!-- 使用無參數的構造函數注入 -->
<bean id="person1"class="cn.itcast.spring.Person">
<property name="name" value="王五"></property>
<property name="age" value="23"></property>
</bean>
<!-- 使用構造函數注入屬性 -->
<bean id="person2"class="cn.itcast.spring.Person">
<!-- <constructor-argvalue="李四"/>
<constructor-argvalue="23"/> -->
</bean>
</beans>
測試代碼:
@Test//經過構造函數初始化屬性
public void beanConstrouctor(){//注:ApplicationContext在加載bean時,就實例化
ApplicationContext ac = new ClassPathXmlApplicationContext("/person.xml");
Person p = (Person) ac.getBean("person2");
System.out.println(p);
}
B. 靜態工廠的方法:
工廠代碼:
public class PersonFactory {
public static Person createPerson()
{ //調用靜態工廠方法來返回
System.out.println("靜態工廠方法初始化person");
return new Person();
}
public static Person createPerson(Stringname,int age)
{ //調用靜態工廠方法來返回
System.out.println("帶參數靜態工廠方法初始化person");
return new Person(name,age);
}
}
Person.xml文件的配置:
<!-- 使用不帶參數的靜態工廠方法 -->
<bean id="person3"class="cn.itcast.spring.PersonFactory" factory-method="createPerson"/>
<!-- 使用帶參數的靜態工廠進行屬性注入 -->
<bean id="person4"class="cn.itcast.spring.PersonFactory" factory-method="createPerson">
<constructor-arg value="張三"/>
<constructor-arg value="22"/>
</bean>
測試代碼: @Test//經過靜態工廠初始化屬性
public void personFactory(){//注:ApplicationContext在加載bean時,就進行bean的實例化
ApplicationContext ac = new ClassPathXmlApplicationContext("/person.xml");
Person p3 = (Person) ac.getBean("person3");
Person p4 = (Person) ac.getBean("person4");
System.out.println(p3);
System.out.println(p4);
}
C.動態工廠方法:
Person.xml文件的配置:
<!-- 使用動態工廠方法 -->
<bean id="personFactory"class="cn.itcast.spring.PersonFactoryFamily">
<property name="family" value="李"/>
</bean>
<bean id="person5"factory-method="createPerson" factory-bean="personFactory">
<constructor-arg value="四"/>
<constructor-arg value="23"/>
</bean>
動態工廠類代碼:
public class PersonFactoryFamily {
private String family;
public void setFamily(String family) {
this.family = family;
}
public Person createPerson()
{ //調用靜態工廠方法來返回
System.out.println("動態工廠方法初始化person");
Person p = new Person();
p.setName(family);
return p;
}
public Person createPerson(String name,int age)
{ //調用靜態工廠方法來返回
System.out.println("帶參數動態工廠方法初始化person");
System.out.println(name+":"+age);
return new Person(family+name,age);
}
}
測試代碼: @Test//經過動態工廠初始化屬性
public void personFactory(){//注:ApplicationContext在加載bean時,就實例化
ApplicationContext ac = new ClassPathXmlApplicationContext("/person.xml");
Person p5= (Person) ac.getBean("person5");
System.out.println(p5);
}
Bean的做用域
singleton(默認值)
singleton--整個容器中只建立一次這個Bean實例.
默認狀況下會在容器啓動時初始化bean,但咱們能夠指定Bean節點的lazy-init=「true」來延遲初始化bean,這時候,只有第一次獲取bean會才初始化bean。如:
<bean id="xxx"class="cn.itcast.OrderServiceBean" lazy-init="true"/>
若是想對全部bean都應用延遲初始化,能夠在根節點beans設置default-lazy-init=「true「,以下:
<beansdefault-lazy-init="true「 ...>
Person.xml文件的配置:
<beanid="person1" class=" cn.itcast.spring.Person">
<property name="name"value="哈哈"/>
</bean>
B、prototpye--每次找容器的時候都會建立這個Bean。
Person.xml文件的配置:
<!-- scope爲prototype的Bean -->
<bean id="person2"class=" cn.itcast.spring.Person" scope="prototype">
<property name="name"value="莉莉"></property>
</bean>
C、request--在Web環境中,針對每次請求只產生一次。
Person.xml文件的配置:
<bean id="person2" class="cn.itcast.spring.Person" scope="request">
<property name="name"value="莉莉"></property>
</bean>
D. session--在Web環境中,針對一個會話(用戶)產生一次。當從新打開新的瀏覽器則會產生一個新會話,關閉會話session銷燬.
Bean的初始化及銷燬方法
A、業務類
public class PersonService {
public void init() {
System.out.println("初始化bean........");
}
public void shutdown() {
System.out.println("bean的銷燬.......");
}
public void addPerson() {
// 業務操做
}
}
B、配置person.xml
<!-- 指定初始化方法,也就是在Bean實例的,裝配好之後,執行的方法 ,使用init-method屬性-->
<!-- bean的初始化和銷燬方式 ,在標籤中配置使用屬性:init-method, destroy-method -->
<bean id="personService"class="cn.itcast.spring.PersonService"
init-method="init" destroy-method="shutdown"/>
Bean的名稱:
配置文件: person.xml
<!-- 使用id指定bean的名稱 -->
<bean id="person6"class="cn.itcast.spring.Person">
<!-- 使用setter方法注入屬性 -->
<property name="name" value="小龍女"/>
<property name="age" value="23"/>
</bean>
<!--給bean指定別名 -->
<alias name="person6"alias="p6"/>
<!-- 使用name指定bean的名稱 -->
<bean id="ps" name="/persons" class="cn.itcast.spring.Person">
<property name="name" value="楊過"/>
<property name="age" value="23"/>
</bean>
注: 在同時使用屬性id和name時,須要在name屬性的前面加上反斜槓」 / 」, 測試類中若是經過name屬性訪問時,
也須要前面加上反斜槓」 / 」,若是隻是用單個屬性,則不須要增長反斜槓」 / 」
測試代碼: @Test
public void beanName(){
ApplicationContext ac=new ClassPathXmlApplicationContext("/person.xml");
System.out.println(ac.getBean("person6"));
System.out.println(ac.getBean("/persons"));
System.out.println(ac.getBean("p6"));
System.out.println(ac.getBean("ps"));
}
Spring IoC容器詳解
依賴注入:
支持注入類型:設值方法setter方法注入(屬性注入)/構造函數(方法)注入/字段Field注入(註解)
1.setXxx()方法注入:
經過setter方法注入依賴<bean>元素的< property >子元素指明瞭使用它們的set方法來注入。能夠注入任何東西,從基本類型到集合類,甚至是應用系統的bean。
<!--經過標籤<property>注入,即setXxx方法注入屬性 -->
<bean id="personServices"class="cn.itcast.dao.PersonServiceImpl">
<property name="dao" value="dao"/>
</bean>
業務類代碼:
public class PersonServiceImpl implements IpersonService{
private IpersonDao dao;
public void setDao(IpersonDao dao) {
this.dao= dao;
}
public void addPerson() {
dao.addPerson();
}
}
2.構造函數注入
配置:beans.xml
<!-- 經過標籤<property>注入,即setXxx方法注入屬性 -->
<bean id="personDao"class="cn.itcast.dao.PersonDaoImpl">
<property name="tag" value="dao1"/>
</bean>
<bean id="personService"class="cn.itcast.dao.PersonServiceImpl">
<constructor-arg value="dao" ref="personDao"/>
</bean>
業務類代碼:
public class PersonServiceImpl implements IpersonService{
private IpersonDao dao;
public PersonServiceImpl(IpersonDao dao){
this.dao = dao;
}
@Override
public void addPerson() {
dao.addPerson();
}
}
3.字段的注入,即便用註解注入屬性
Dao層代碼:
public class PersonDaoImpl implements IpersonDao{
private String tag;
public void setTag(String tag) {
this.tag = tag;
}
@Override
public void addPerson() {
System.out.println("增長person......"+tag);
}
}
業務層代碼:
public class PersonServiceImpl implements IpersonService{
@Autowired
private IpersonDao dao;
public void setDao(IpersonDao dao){
this.dao = dao;
}
public PersonServiceImpl(IpersonDao dao){
this.dao = dao;
}
@Override
public void addPerson() {
dao.addPerson();
}
}
配置文件:
<!-- 經過標籤<property>注入,即setXxx方法注入屬性-->
<beanid="personDao" class="cn.itcast.dao.PersonDaoImpl">
<property name="tag"value="dao1"/>
</bean>
<!-- 構造函數注入屬性 -->
<beanid="personService"class="cn.itcast.dao.PersonServiceImpl">
<constructor-arg value="dao"ref="personDao"/>
</bean>
<bean id="personServices"class="cn.itcast.dao.PersonServiceImpl">
<property name="dao"value="dao"/>
</bean>
</beans>
測試代碼: @Test
public void annotationAndXml(){
ApplicationContext ac = new ClassPathXmlApplicationContext("/beans.xml");
PersonServiceImpl p =(PersonServiceImpl)ac.getBean("personService");
p.addPerson();
}
裝配的方式:手動裝配/自動裝配
自動裝配中autowire屬性取值以下
* byType:按類型裝配,能夠根據屬性的類型,在容器中尋找跟該類型匹配的bean。若是發現多個,那麼將會拋出異常。若是沒有找到,即屬性值爲null。
* byName:按名稱裝配,能夠根據屬性的名稱,在容器中尋找跟該屬性名相同的bean,若是沒有找到,即屬性值爲null。
* constructor與byType的方式相似,不一樣之處在於它應用於構造器參數。若是在容器中沒有找到與構造器參數類型一致的bean,那麼將會拋出異常。
* autodetect :首先嚐試使用constructor來自動裝配,而後使用byType方式。不肯定性的處理與constructor方式和byType方式一致。
(1)、按名稱自動裝配
業務類代碼:
public class PersonServiceImpl implements IpersonService{
private IpersonDao dao;
public void setDao(IpersonDao dao) {
this.dao= dao;
}
public void addPerson() {
dao.addPerson();
}
}
配置文件:
<bean id="dao"class="cn.itcast.gz.springioc.PersonDaoImpl"></bean>
<!--定義personService -->
<!--autowire屬性用來指定自動裝配,
EnumeratedValues :
- default
- no
- byName-按名稱,按屬性名稱
- byType-按類型,按屬性類型
- constructor-構造方法(類型)
-->
<bean id="personService"class="cn.itcast.gz.springioc.PersonServiceImpl2" autowire="byName" />
(2)、按類型自動裝配---要求只能有一個要裝配類型的Bean.在系統中找到依賴對象相同類型的Bean,若是找到則裝配。參考(1)
(3)、按構造函數--按構造函數參數的類型進行裝配。
public class PersonServiceImpl implements IpersonService{
private IpersonDao dao;
public PersonServiceImpl(IpersonDao dao){
this.dao= dao;
}
@Override
public void addPerson() {
dao.addPerson();
}
}
配置文件:
<bean id="personService"class="cn.itcast.gz.springioc.PersonServiceImpl2" autowire="constructor"/>
一.Spring IOC容器: 在屬性注入時必定要提供相應的setter方法.
1.裝配各類類型的屬性須要在 *.xml文件中的配置
private String name;
private Integer age;
private boolean married;
A、簡單bean配置-使用value屬性或者標籤來指定屬性值,Spring進行自動類型轉換;
配置: <bean id="person"class="cn.itcast.springioc.Person">
<!-- setter方式注入屬性值 -->
<property name="name" value="李四"/>
<property name="age" value="20"/>
<property name="married" value="true"/>
<bean >
B、外部引用其它Bean,使用ref屬性或者ref標籤。
使用ref標籤首找bean(直接找一個Bean,先在當前容器中找,找不到則到父容器中找),local(引用一個在當前容器中的bean),parent(引應父級容器中的
private Person parent;
配置: <property name="parent" ref="person2"/>或者將ref直接做爲標籤使用
<property name="parent"><refbean="person2"/></property>
<bean id="person2"class="cn.itcast.springioc.Person">
<property name="name" value="張三"/>
<property name="age" value="23"/>
</bean>
測試代碼:: @Test
public void simpleType(){//經過ApplicationContext加載資源文件
ApplicationContext ac = newClassPathXmlApplicationContext("/parent.xml");
Person p = (Person) ac.getBean("person");
System.out.println(p);
}
2.內部引用其餘bean
配置: <bean id="person2" class="cn.itcast.springioc.Person">
<property name="parent">
<beanid="person3" class="cn.itcast.springioc.Person">
<propertyname="name" value="王五"></property>
</bean>
</property>
</bean>
</bean>
測試代碼::
@Test
public void mulitiConfigFiles(){
ApplicationContext ac = new ClassPathXmlApplicationContext("/parent.xml");
Person p = (Person) ac.getBean("person");
System.out.println(p);
}
C. 裝配set類型的集合--使用set標籤
private Set<String> edus=new HashSet<String>();
配置: <property name="edus">
<!-- 使用set標籤來裝配set類型的集合 -->
<set><!-- setter注入,使用value屬性 -->
<value>本科學歷</value>
<value>專科學歷</value>
</set>
</property>
測試代碼: @Test
public void collection(){
//加載資源文件並注入屬性值
ApplicationContext ac = new ClassPathXmlApplicationContext("/collection.xml");
Person p = (Person) ac.getBean(Person.class);
System.out.println(p);
}
D.使用list標籤配置list類型的屬性
private List<Person> friends;
配置: <property name="friends">
<list><!-- 使用list標籤來裝配list類型的集合 -->
<bean id="person4"class="cn.itcast.springioc.Person">
<property name="name" value="小娟"></property>
</bean>
</list>
</property>
D.使用map標籤配置map類型的屬性
private Map<String,Double> scores=new HashMap<String,Double>();
配置:
<property name="scores">
<map><!-- 使用map標籤來裝配map類型的集合 -->
<entry key="英語" value="85"/>
<entry key="數學" value="90"/>
</map>
</property>
測試代碼:
public void collection(){
//加載資源文件並注入屬性值
ApplicationContext ac = new ClassPathXmlApplicationContext("/collection.xml");
Person p = (Person) ac.getBean(Person.class);
System.out.println(p);
}
E.使用屬性文件進行配置
private Properties setting;
配置: <property name="setting">
<props><!-- 使用屬性文件標籤來裝配 -->
<prop key="username">李四</prop>
<prop key="password">123456</prop>
</props>
</property>
二、構造函數注入, 裝配的元素的類型與setter方法注入一致. 構造參數的個數必須與Bean構造函數一致。
當構造函數的個數比較複雜,參數類型及順序有岐義,用戶想要指定一個具體的構造函數,能夠使用index/type/name來指定參數構造參數類型,及順序等。
代碼:
publicPerson(Integer age, String name) {}
配置:
<bean id="person"class="cn.itcast.springioc.Person">
<constructor-rag value="李四" index="0" type="java.lang.Interger"/>
<constructor-rag value="23" index="1" type="java.lang.String"/>
</bean>
構造函數代碼:
publicPerson(String name, Person parent) {}
配置:
<bean id="person2"class="cn.itcast.gz.springioc.Person">
<!-- constructor-arg表示構造參數 -->
<constructor-arg value="abc"></constructor-arg>
<!--
<constructor-arg ref="person1"></constructor-arg>
-->
<!-- 構造參數的值能夠寫在constructor-arg的子元素中 -->
<constructor-arg>
<ref bean="person1"/>
</constructor-arg>
<property name="age" value="67"></property>
</bean>
測試代碼: @Test
public void constroctuor(){
//加載資源文件並注入屬性值
ApplicationContext ac = new ClassPathXmlApplicationContext("/constructor.xml");
Person p = (Person) ac.getBean("person");
System.out.println(p);
}
3.註解注入:
使用註解裝配
在java代碼中使用@Autowired或@Resource註解方式進行裝配,這兩個註解的區別是:@Autowired 默認按類型裝配,@Resource默認按名稱裝配,當找不到與名稱匹配的bean纔會按類型裝配。
@Resource註解和@Autowired同樣,也能夠標註在字段或屬性的setter方法上.
@Resource註解默認按名稱裝配。
名稱能夠經過@Resource的name屬性指定,若是沒有指定name屬性,
當註解標註在字段上,即默認取字段的名稱做爲bean名稱尋找依賴對象
當註解標註在屬性的setter方法上,即默認取屬性名做爲bean名稱尋找依賴對象。
注意:若是沒有指定name屬性,而且按照默認的名稱找不到依賴對象時, @Resource註解會回退到按類型裝配。但一旦指定了name屬性,就只能按名稱裝配了。
Dao層代碼:
@Repository("personDao")//給bean指定名稱
@Scope("prototype")
public class PersonDaoImpl2 implements IpersonDao{
private String tag;
public void setTag(String tag) {
this.tag = tag;
}
@Override
public void addPerson() {
System.out.println("增長person......"+tag);
}
}
業務類代碼:(要注入的依賴對象須要在Field上加@Autowired等標籤)
@Autowired註解是按類型裝配依賴對象,默認狀況下它要求依賴對象必須存在,若是容許null值,能夠設置它required屬性爲false。 @Autowired(required=false)
@Service("personService")//給bean指定名稱
public class PersonServiceImpl implements IpersonService{
@Autowired
private IpersonDao dao;//用於字段上
@Autowired //用在屬性的set方法上
public void setDao(IpersonDao dao) {
this.dao = dao;
}
@Override
public void addPerson() {
dao.addPerson();
}
}
配置文件 beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
<!—此處引入context命名空間主要是在操做時標籤能顯示提示信息-->
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<!-- 表示當前容器須要使用註解來進行裝配 -->
<context:annotation-config/>
<bean id="personDao"class="cn.itcast.dao.PersonDaoImpl"></bean>
<!-- 經過property元素來指定設值方法注入 -->
<bean id="personService"class="cn.itcast.dao.PersonServiceImpl"></bean>
或者使用如下方式:,讓Spring容器去掃描一些包
<bean id="personDao"class="cn.itcast.dao.PersonDaoImpl"></bean>
<!-- 經過property元素來指定設值方法注入 -->
<bean id="personService"class="cn.itcast.dao.PersonServiceImpl"></bean>
<!--指定讓Spring容器去掃描一些包,多個包 -->
<context:component-scanbase-package="cn.itcast"/>
經過在classpath自動掃描方式把組件歸入spring容器中管理
1. 若是要用註解裝配,則須要引入context命名空間),而且在配置文件中加上<context:annotation-config/>。
2. 在配置文件中添加context:component-scan標籤<context:component-scanbase-package="cn.itcast"/>
其中base-package爲須要掃描的包(含子包)。
3.若是須要標籤提示信息: 可在編輯器中(eclipse) 增長spring-context-3.0.xsd進行規範,
打開window-àpreferences(參數配置)-à搜索xml-à選擇xmlcatalog-àuser specified entries-à
AddàfileSystem-à找到spring-context-3.0.xsd-àkey type:選擇urlàkey:填寫http://www.springframework.org/schema/context/spring-context-3.0.xsd(spring參考手冊中查找)--->ok,此時就能夠使用標籤提示信息了.
注:
一、在使用組件掃描元素時,AutowiredAnnotationBeanPostProcessor和CommonAnnotationBeanPostProcessor會隱式地被包括進來。 也就是說,連個組件都會被自動檢測並織入 - 全部這一切都不須要在XML中提供任何bean配置元數據。
二、功能介紹
@Service用於標註業務層組件、
@Controller用於標註控制層組件(如struts中的action)、
@Repository用於標註數據訪問組件,即DAO組件。
而@Component泛指組件,當組件很差歸類的時候,咱們能夠使用這個註解進行標註。
2、Spring IOC擴充
A、spring除了簡單類型int...Spring還能幫助把value裏面字符串直接轉換成特定的對象。好比URL類的屬性,能夠使用value="http://www.itca..."來注入。
B、若是是經過value來注入自定義類型的對象,則要求bean中必須提供一個空參數的構造函數。
Bean代碼:
public class Person {
private String name;
private Integer age;
private Person parent;
private Date bornDate;
private URL url;
public Person() {
super();
System.out.println("構造Person()..");
}
//必須提供setXxx(), getXxx()方法
}
配置文件: bean.xml
<bean id="person1"class="cn.itcast.gz.springioc.Person">
<property name="name" value="李四"></property>
<property name="age" value="100"></property>
<property name="url"value="http://www.itcast.cn">
</property>
<property name="parent" value="李四"></property>
</bean>
測試代碼: @Test
public void simpleType() {
ApplicationContext ac = new ClassPathXmlApplicationContext("/bean.xml");
System.out.println(ac.getBean("person1"));
}
C. 複雜的類型轉換
Spring的類型轉換均是經過javaBean中的PropertyEditorSupport類來實現,咱們能夠本身擴展這個類。並注使用CustomEditorConfigurer類註冊到Spring容器容器
自定義轉換器步驟:
A. 寫一個類繼承PropertyEditorSupport自定義的編輯器,重寫setAsText()等方法,在該該方法中實現須要的操做.
B.使用org.springframework.beans.factory.config.CustomEditorConfigurer類型的Bean來加載咱們自定義編輯器
3.0中只要有一個帶字符串的構造函數,他會自動調用Bean帶字符串的構造函數自動轉換。
1.自定義一個類繼承PropertyEditorSupport類,.
//自定義一個屬性轉換器
public classMyDatePropertyEditorSupport extends PropertyEditorSupport {
@Override
public void setAsText(String text) throws IllegalArgumentException {
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
Date d;
try {
d = sdf.parse(text);
super.setValue(d);
} catch (ParseException e) {
e.printStackTrace();
};
}
}
2.在配置文件中配置,經過CustomEditorConfigurer類注入到spring容器中.
配置文件:bean.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="person1"class="cn.itcast.gz.springioc.Person">
<bean id="person1"class="cn.itcast.gz.springioc.Person">
<property name="name" value="李四"></property>
<property name="age" value="100"></property>
<property name="url"value="http://www.itcast.cn">
</property>
<property name="parent" value="李四"></property>
<!—日期格式的字符串轉換-->
<property name="bornDate"value="2012-01-03"/>
</bean>
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="java.util.Date"value="cn.itcast.gz.springioc.MyDatePropertyEditorSupport"></entry>
</map>
</property>
</bean>
</beans>
測試代碼:
@Test
public void simpleType() {
ApplicationContext ac = new ClassPathXmlApplicationContext("/bean.xml");
System.out.println(ac.getBean("person1"));
// PropertyEditorSupport pe;
// CustomEditorConfigurer b;
// b.setCustomEditors(customEditors)//點擊該類,按f4查看該類的屬性和方法
}
2、工廠bean-FactoryBean接口:
是用來生產具體產品的特殊的Bean。一個Bean要是實現了FactoryBean接口。那麼在容器中的Bean的實例就是由FactoryBean裏面的getObject()方法所返回的對象。
public interface FactoryBean{
public Object getObject();
public Class getObjectType() ;
public booleanisSingleton();
}
1.實現FactoryBean接口:
public class PersonFactoryBean implements FactoryBean {
@Override
public Object getObject() throws Exception {
System.out.println("建立getObject()...");
return new Person("dddd");//產生一個person實例
}
@Override
public Class getObjectType() {
return null;
}
@Override
public booleanisSingleton() {
return true;
}
}
配置文件:factorybean.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!—經過factorybean產生person對象-->
<bean id="person1"class="cn.itcast.gz.springioc.PersonFactoryBean">
</bean>
</beans>
測試代碼: @Test
public void factoryBean() {
ApplicationContext ac = new ClassPathXmlApplicationContext("/factorybean.xml");
System.out.println(ac.getBean("person1"));
System.out.println(ac.getBean("person1"));
}
三、容器擴展點應用-
Spring提供了不少容器擴展點供咱們使用,咱們經過這些擴展點來擴充Spring的功能。用法是讓咱們寫一個Bean去實現Spring所提供的擴展點的接口,得到容器相關的一些資源,從而達到擴充容器的功能。
A、BeanPostProcessor
B、BeanFactoryPostProcessor--在容器初始化,在Bean建立以前使用,會調用擴展點中的postProcessBeanFactory方法,能夠在該方法中加入對Bean定義信息的處理,好比過濾或替換等。
代碼:
public class MyBeanFactoryPostProcessorimplements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(
ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("配置文件加載完成....");
//從容器中讀出Bean配置信息
for(StringbeanName:beanFactory.getBeanDefinitionNames()){
BeanDefinition bd = beanFactory.getBeanDefinition(beanName);
System.out.println(beanName+":"+bd.getClass());
if(bd instanceof GenericBeanDefinition){
GenericBeanDefinition bd0=(GenericBeanDefinition)bd;
MutablePropertyValues mvp= bd0.getPropertyValues();
for(PropertyValue mv:mvp.getPropertyValues()){
Objectov= mv.getValue();
if(ov instanceof TypedStringValue){
//替換配置文件中的value屬性值
( (TypedStringValue)ov).setValue(( (TypedStringValue)ov).getValue().replaceAll("你好", "XXX"));
}
}
}
}
}}
配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="person1"class="cn.itcast.gz.springioc.Person" >
<property name="name" value="你好"></property>
</bean>
<bean class="cn.itcast.gz.springioc.MyBeanProcesser"></bean>
<bean class="cn.itcast.gz.springioc.MyBeanFactoryPostProcessor"></bean>
</beans>
測試代碼: @Test
public void containerextend() {
ApplicationContext ac = new ClassPathXmlApplicationContext("/containerextend.xml");
System.out.println(ac.getBean("person1"));
}
4、屬性文件的配置:
屬性文件db.properties
username=root
password=abc;
配置文件 : properties.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="person1"class="cn.itcast.gz.springioc.Person" >
<property name="name" value="${username}"></property>
<property name="name"value="${password}"></property>
</bean>
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="db.properties"></property>
</bean>
</beans>
//自定義屬性
@Test
public void customproperties() {
ApplicationContextac = new ClassPathXmlApplicationContext("/properties.xml");
System.out.println(ac.getBean("person1"));
//org.springframework.beans.factory.config.PropertyPlaceholderConfigurerpp;
//pp.setLocation(location)
}
5、簡化屬性配置:
配置文件;namespace.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!-- 寫法1 使用set方法注入屬性-->
<bean id="person1"class="cn.itcast.gz.springioc.Person" >
<property name="name" value="楊過"></property>
<property name="age" value="100"></property>
<property name="parent" ref="person3"></property>
</bean>
<!-- 使用p命名空間之後 -->
<beanid="person2" class="cn.itcast.gz.springioc.Person"
p:name="小龍女" p:age="20"p:parent-ref="person3">
</bean>
<!-- 使用構造函數注入屬性 -->
<bean id="person3"class="cn.itcast.gz.springioc.Person" >
<constructor-arg value="楊過"></constructor-arg>
<constructor-arg value="20"></constructor-arg>
</bean>
<!-- 使用c命名空間後 -->
<beanid="person4" class="cn.itcast.gz.springioc.Person" c:name="小龍女"
c:age="22"/>
</beans>
注: 在使用簡化屬性文件配置時,須要引入約束文件.
測試代碼:
@Test
public void pAndCNamesapce() {
ApplicationContext ac = new ClassPathXmlApplicationContext("/namespace.xml");
System.out.println(ac.getBean("person1"));
System.out.println(ac.getBean("person2"));
System.out.println(ac.getBean("person3"));
System.out.println(ac.getBean("person4"));
}
3、代理模式-
1、使用JDK動態代理來建立代理對象
//實現類
public class HelloImpl implements IHello {
@Override
public void sayHello() {
System.out.println("你們好!當前時間:"+new Date());
}
}
//代理對象
public class JDKProxy implements InvocationHandler {
private Object realObject;
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//加入代理本身的代碼,日誌
System.out.println(method.getName()+"方法調用,時間:"+new Date());
Object obj = method.invoke(realObject, args);
return obj;
}
//建立一個真實對象的代理對象
public Object createProxyObject(Object realObject){
this.realObject =realObject;
return Proxy.newProxyInstance(this.getClass().getClassLoader(),
realObject.getClass().getInterfaces(), this);
}
public static void main(String[] args) {
//建立一個HelloImpl的代理對象
IHello hello=(IHello) new JDKProxy().createProxyObject(new HelloImpl());
//全部對代理對象上的調用,都會發給InvocationHandler對象來執行。
hello.sayHello();
}
注: Jdk中的代理只能是代理接口,而不能代理類
2、使用CGlib框架來建立針對類的代理對象
public class CglibTest {
public static void main(String[] args) {
//若是一個對象沒有實現任何接口,要建立其代理對象,則必須依賴第三方框架,好比cglib
final HelloImpl2 realObject= new HelloImpl2();
/*HelloImpl2hello=(HelloImpl2)Enhancer.create(HelloImpl2.class, new InvocationHandler(){
@Override
public Object invoke(Object arg0, Methodarg1, Object[] arg2)
throws Throwable {
return arg1.invoke(realObject, arg2);
}
});*/
Enhancer en=new Enhancer();
en.setSuperclass(HelloImpl2.class);
en.setCallback(new InvocationHandler(){
@Override
public Object invoke(Object arg0, Method arg1,Object[] arg2)
throws Throwable {
return arg1.invoke(realObject, arg2);
}
});
HelloImpl2 hello=(HelloImpl2)en.create();
hello.sayHello();
//session.load(Person.class,1L);
}
}
3、使用AOP的解決方案
接口:
public interfaceIPersonService {
void addPerson(Person p);
void deletePerson(Long id);
void updatePerson(Long id, Person p);
}
業務代碼:
public class PersonServiceImpl implements IPersonService {
@Override
public void addPerson(Person p) {
System.out.println("addPerson()...業務邏輯省略...");
//...
}
@Override
public void deletePerson(Long id) {
System.out.println("deletePerson()...業務邏輯省略...");
//...
}
@Override
public void updatePerson(Long id,Person p) {
System.out.println("updatePerson()...業務邏輯省略...");
///..
}
}
//寫日誌的切面,專門解決寫日誌的問題
public class LogAspect {
public void writeBeforeLog(Method m){
//切面2:日誌的功能
System.out.println(UserContext.getUser()+"調用"+m.getName()+"方法,時間:"
+new Date());
}
public void writeAfterLog(Method m){
//切面3:審計的功能
System.out.println(UserContext.getUser()+"成功調用"+m.getName()+"方法,時間:"+new Date());
}
}
//驗證權限的切面
public class SecurityAspect {
public void checkPermission(Method m){
// 切面1:加入檢查權限的代碼
System.out.println("權限檢查");
if (!"admin".equals(UserContext.getUser())) {
throw new RuntimeException("沒有權限");
}
}
}
//用戶
public class UserContext {
public static String getUser() {
return "admin";
}
}
容器中實現aop代碼:
public classContainerImpl implements Container {
private Map<String, Object> beans =new HashMap<String, Object>();
public ContainerImpl() {
init();
aop();
}
//初始化
public voidinit() {
// 去一個指定的配置文件加載關於要放置到容器中的類的相關信息
// *.xml,properties
Properties p = new Properties();
try {
p.load(this.getClass().getResourceAsStream("/bean.properties"));
// 初始化Bean,屬性名稱不能包含.
for (Object o : p.keySet()) {
String beanName =o.toString();
// zwj
if(beanName.indexOf('.') < 0) {
StringclzName = p.getProperty(beanName);
// 初始化
Object bean =Class.forName(clzName).newInstance();
beans.put(beanName,bean);
}
}
} catch (Exception e) {
e.printStackTrace();
}
injectByField();
}
/**
* 依賴注入,採用setter設值方法注入
*/
public void injectByField() {
Properties p = new Properties();
try {
p.load(this.getClass().getResourceAsStream("/bean.properties"));
// 初始化Bean,屬性名稱不能包含.
for (Object o : p.keySet()){
String key =o.toString();
//zwj.name
if (key.indexOf('.')> 0) {
StringbeanName=key.substring(0,key.indexOf('.'));
String pname=key.substring(key.indexOf('.')+1);
//屬性的值
Stringvalue=p.getProperty(key);
Objectbean=getBean(beanName);
//查找到bean的pname屬性
//System.out.println(beanName+":"+pname);
Field field=bean.getClass().getDeclaredField(pname);
field.setAccessible(true);
//調用屬性的setter方法來注入內容
if(field.getType()==String.class){
field.set(bean,value);
}
else {
//就是Bean
field.set(bean,getBean(value));
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void inject() {
Properties p = new Properties();
try {
p.load(this.getClass().getResourceAsStream("/bean.properties"));
// 初始化Bean,屬性名稱不能包含.
for (Object o : p.keySet()){
String key =o.toString();
//zwj.name
if (key.indexOf('.')> 0) {
StringbeanName=key.substring(0,key.indexOf('.'));
Stringpname=key.substring(key.indexOf('.')+1);
//屬性的值
Stringvalue=p.getProperty(key);
Objectbean=getBean(beanName);
//查找到bean的pname屬性
//System.out.println(beanName+":"+pname);
PropertyDescriptor[]pds=java.beans.Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors();
for(PropertyDescriptorpd:pds){
if(pd.getName().equals(pname)){