<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Rising Sun

      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
      148 隨筆 :: 0 文章 :: 22 評論 :: 0 Trackbacks

    #

    filter的用法,的確是比較有擴展性的一種方法...可以通過filter結合讀取web.xml中的filter參數來完成一系列的動作,做法如下:

    首先,實現javax.servlet.Filter接口,編寫一個處理request編碼的過濾器類...

    package?tutorial.struts.filter;
    import?javax.servlet.Filter;
    import?javax.servlet.FilterConfig;
    import?javax.servlet.ServletException;
    import?javax.servlet.ServletRequest;
    import?javax.servlet.ServletResponse;
    import?javax.servlet.FilterChain;
    import?java.io.IOException;
    public?class?SetCharacterEncodingFilter?implements?Filter?{
    ??protected?FilterConfig?filterConfig;
    ??protected?String?encodingName;
    ??protected?boolean?enable;
    ??public?SetCharacterEncodingFilter()?{
    ????this.encodingName?=?"UTF-8";
    ????this.enable?=?false;
    ??}
    ??public?void?init(FilterConfig?filterConfig)?throws?ServletException?{
    ????this.filterConfig?=?filterConfig;
    ????loadConfigParams();
    ??}
    ??private?void?loadConfigParams()
    ?{
    ????//encoding
    ????this.encodingName?=?this.filterConfig.getInitParameter("encoding");
    ????//filter?enable?flag...
    ????String?strIgnoreFlag?=?this.filterConfig.getInitParameter("enable");
    ????if?(strIgnoreFlag.equalsIgnoreCase("true"))
    ?{
    ??????this.enable?=?true;
    ????}
    ?else
    ?{
    ??????this.enable?=?false;
    ????}
    ??}
    ??public?void?doFilter(ServletRequest?request,?ServletResponse?response,
    ???????????????????????FilterChain?chain)?throws?IOException,?ServletException
    ?{
    ????if(this.enable)?
    {
    ??????request.setCharacterEncoding(this.encodingName);
    ????}
    ????chain.doFilter(request,?response);
    ??}
    ??public?void?destroy()
    ?{
    ??}
    }
    ?

    然后,需要在web.xml中注冊我們的過濾器類:

    ??<filter>
    ????<filter-name>Set?Character?Encoding</filter-name>
    ????<filter-class>tutorial.struts.filter.SetCharacterEncodingFilter</filter-class>
    ????<init-param>
    ??????<param-name>encoding</param-name>
    ??????<param-value>UTF-8</param-value>
    ????</init-param>
    ????<init-param>
    ??????<param-name>enable</param-name>
    ??????<param-value>true</param-value>
    ????</init-param>
    ??</filter>
    ??<filter-mapping>
    ????<filter-name>Set?Character?Encoding</filter-name>
    ????<servlet-name>Action?Servlet</servlet-name>
    ??</filter-mapping>
    ??<filter-mapping>
    ????<filter-name>Set?Character?Encoding</filter-name>
    ????<servlet-name>Faces?Servlet</servlet-name>
    ??</filter-mapping>
    ?

    這樣,任何通過Struts,或是JSF的Controller?Servlet處理的request,都會在過濾器中先行處理,才把控制權交還給Struts或是JSF,而且Filter中有一個Process?Chain的概念,是一個很吸引人的東東~~!
    posted @ 2006-07-27 15:14 brock 閱讀(368) | 評論 (0)編輯 收藏

    ?1 package?cn.com.jsp;
    ?2
    ?3 import?java.io.IOException;
    ?4 import?javax.servlet.Filter;
    ?5 import?javax.servlet.FilterChain;
    ?6 import?javax.servlet.FilterConfig;
    ?7 import?javax.servlet.ServletException;
    ?8 import?javax.servlet.ServletRequest;
    ?9 import?javax.servlet.ServletResponse;
    10 import?javax.servlet.UnavailableException;
    11
    12 public ? class ?SetCharacterEncodingFilter?implements?Filter? {
    13 ???? protected ?String?encoding? = ? null ;
    14 ???? protected ?FilterConfig?filterConfig? = ? null ;
    15 ???? protected ?boolean?ignore? = ? true ;
    16
    17 ???? public ? void ?destroy()? {
    18 ???????? this .encoding? = ? null ;
    19 ???????? this .filterConfig? = ? null ;
    20 ????}

    21
    22 ???? public ? void ?doFilter(ServletRequest?request,?ServletResponse?response,
    23 ?????????????????????????FilterChain?chain)?throws?IOException,
    24 ????????????ServletException? {
    25
    26 ???????? // ?Conditionally?select?and?set?the?character?encoding?to?be?used
    27 ???????? if ?(ignore? || ?(request.getCharacterEncoding()? == ? null ))? {
    28 ????????????String?encoding? = ?selectEncoding(request);
    29 ???????????? if ?(encoding? != ? null )? {
    30 ????????????????request.setCharacterEncoding(encoding);
    31 ????????????}

    32 ????????}

    33
    34 ???????? // ?Pass?control?on?to?the?next?filter
    35 ????????chain.doFilter(request,?response);
    36
    37 ????}

    38
    39 ???? public ? void ?init(FilterConfig?filterConfig)?throws?ServletException? {
    40
    41 ???????? this .filterConfig? = ?filterConfig;
    42 ???????? this .encoding? = ?filterConfig.getInitParameter( " encoding " );
    43 ????????String?value? = ?filterConfig.getInitParameter( " ignore " );
    44 ???????? if ?(value? == ? null )? {
    45 ???????????? this .ignore? = ? true ;
    46 ????????}
    ? else ? if ?(value.equalsIgnoreCase( " true " ))? {
    47 ???????????? this .ignore? = ? true ;
    48 ????????}
    ? else ? if ?(value.equalsIgnoreCase( " yes " ))? {
    49 ???????????? this .ignore? = ? true ;
    50 ????????}
    ? else ? {
    51 ???????????? this .ignore? = ? false ;
    52 ????????}

    53
    54 ????}

    55
    56 ???? protected ?String?selectEncoding(ServletRequest?request)? {
    57 ???????? return ?( this .encoding);
    58 ????}

    59
    60 }


    相應的web.xml文件里的配置如下:

    ?1<web-app>
    ?2??<display-name>wwwrootSPAN style="COLOR: #800000">display-name>
    ?3??<description>MySQL?Test?AppSPAN style="COLOR: #800000">description>
    ?4??<filter>
    ?5????<filter-name>setCharacterEncodingFilterSPAN style="COLOR: #800000">filter-name>
    ?6????<display-name>setCharacterEncodingFilterSPAN style="COLOR: #800000">display-name>
    ?7????<description>setCharacterEncodingFilterSPAN style="COLOR: #800000">description>
    ?8????<filter-class>cn.com.jsp.SetCharacterEncodingFilterSPAN style="COLOR: #800000">filter-class>
    ?9????<init-param>
    10??????<param-name>encodingSPAN style="COLOR: #800000">param-name>
    11??????<param-value>GBKSPAN style="COLOR: #800000">param-value>
    12????SPAN style="COLOR: #800000">init-param>
    13??SPAN style="COLOR: #800000">filter>
    14??<filter-mapping>
    15????<filter-name>setCharacterEncodingFilterSPAN style="COLOR: #800000">filter-name>
    16????<url-pattern>/*SPAN style="COLOR: #800000">url-pattern>
    17??SPAN style="COLOR: #800000">filter-mapping>
    18……
    19SPAN style="COLOR: #800000">web-app>

    上面的代碼我也沒更改什么,看了后,了解了其中的些許流程。放入blog,留以備學吧
    posted @ 2006-07-27 15:11 brock 閱讀(369) | 評論 (0)編輯 收藏

         摘要: 將此頁作為電子郵件發送'); //--> ? ?未顯示需要 JavaScript 的文檔選項 ...  閱讀全文
    posted @ 2006-07-27 13:33 brock 閱讀(176) | 評論 (0)編輯 收藏

    JDOM是一個開源項目,它基于樹型結構,利用純JAVA的技術對XML文檔實現解析、生成、序列化以及多種操作。

    一、JDOM 簡介

    JDOM是一個開源項目,它基于樹型結構,利用純JAVA的技術對XML文檔實現解析、生成、序列化以及多種操作。

    JDOM 直接為JAVA編程服務。它利用更為強有力的JAVA語言的諸多特性(方法重載、集合概念以及映射),把SAX和DOM的功能有效地結合起來。

    在使用設計上盡可能地隱藏原來使用XML過程中的復雜性。利用JDOM處理XML文檔將是一件輕松、簡單的事。

    JDOM 在2000年的春天被Brett McLaughlin和Jason Hunter開發出來,以彌補DOM及SAX在實際應用當中的不足之處。

    這些不足之處主要在于SAX沒有文檔修改、隨機訪問以及輸出的功能,而對于DOM來說,JAVA程序員在使用時來用起來總覺得不太方便。

    DOM的缺點主要是來自于由于Dom是一個接口定義語言(IDL),它的任務是在不同語言實現中的一個最低的通用標準,并不是為JAVA特別設計的。JDOM的最新版本為JDOM Beta
    ?9。最近JDOM被收錄到JSR-102內,這標志著JDOM成為了JAVA平臺組成的一部分。

    二、JDOM 包概覽

    JDOM是由以下幾個包組成的
    org.jdom??????????????? 包含了所有的xml文檔要素的java類

    ?

    org.jdom.adapters???????? 包含了與dom適配的java類

    ?

    org.jdom.filter??????????? 包含了xml文檔的過濾器類

    ?

    org.jdom.input??????????? 包含了讀取xml文檔的類

    ?

    org.jdom.output?????????? 包含了寫入xml文檔的類

    ?

    org.jdom.transform??????? 包含了將jdom xml文檔接口轉換為其他xml文檔接口

    ?

    org.jdom.xpath??????????? 包含了對xml文檔xpath操作的類三、JDOM 類說明

    1、org.JDOM這個包里的類是你J解析xml文件后所要用到的所有數據類型。

    Attribute

    CDATA

    Coment

    DocType

    Document

    Element

    EntityRef

    Namespace

    ProscessingInstruction

    Text

    2、org.JDOM.transform在涉及xslt格式轉換時應使用下面的2個類

    JDOMSource

    JDOMResult

    org.JDOM.input

    3、輸入類,一般用于文檔的創建工作

    SAXBuilder

    DOMBuilder

    ResultSetBuilder

    org.JDOM.output

    4、輸出類,用于文檔轉換輸出

    XMLOutputter

    SAXOutputter

    DomOutputter

    JTreeOutputter

    使用前注意事項:

    1.JDOM對于JAXP 以及 TRax 的支持

    JDOM 支持JAXP1.1:你可以在程序中使用任何的parser工具類,默認情況下是JAXP的parser。

    制定特別的parser可用如下形式

    SAXBuilder parser

    ? = new SAXBuilder("org.apache.crimson.parser.XMLReaderImpl");

    ?Document doc = parser.build("

    ?// work with the document...

    JDOM也支持TRaX:XSLT可通過JDOMSource以及JDOMResult類來轉換(參見以后章節)

    2.注意在JDOM里文檔(Document)類由org.JDOM.Document 來表示。這要與org.w3c.dom中的Document區別開,這2種格式如何轉換在后面會說明。

    以下如無特指均指JDOM里的Document。

    四、JDOM主要使用方法

    1.Ducument類

    (1)Document的操作方法:

    Element root = new Element("GREETING");

    Document doc = new Document(root);

    root.setText("Hello JDOM!");

    或者簡單的使用Document doc = new Document(new Element("GREETING").setText("Hello JDOM!t"));

    這點和DOM不同。Dom則需要更為復雜的代碼,如下:

    DocumentBuilderFactory factory =DocumentBuilderFactory.newInstance();

    DocumentBuilder builder =factory.newDocumentBuilder();

    Document doc = builder.newDocument();

    Element root =doc.createElement("root");

    Text text = doc.createText("This is the root");

    root.appendChild(text);

    doc.appendChild(root);

    注意事項:JDOM不允許同一個節點同時被2個或多個文檔相關聯,要在第2個文檔中使用原來老文檔中的節點的話。首先需要使用detach()把這個節點分開來。

    (2)從文件、流、系統ID、URL得到Document對象:

    DOMBuilder builder = new DOMBuilder();

    Document doc = builder.build(new File("jdom_test.xml"));

    SAXBuilder builder = new SAXBuilder();

    Document doc = builder.build(url);

    在新版本中DOMBuilder 已經Deprecated掉 DOMBuilder.builder(url),用SAX效率會比較快。

    這里舉一個小例子,為了簡單起見,使用String對象直接作為xml數據源:

    ?public jdomTest() {

    ??? String textXml = null;

    ??? textXml = "<note>";

    ??? textXml = textXml +

    ??????? "<to>aaa</to><from>bbb</from><heading>ccc</heading><body>ddd</body>";

    ??? textXml = textXml + "</note>";

    ??? SAXBuilder builder = new SAXBuilder();

    ??? Document doc = null;

    ??? Reader in= new StringReader(textXml);

    ??? try {

    ????? doc = builder.build(in);

    ????? Element root = doc.getRootElement();

    ????? List ls = root.getChildren();//注意此處取出的是root節點下面的一層的Element集合

    ????? for (Iterator iter = ls.iterator(); iter.hasNext(); ) {
    ?/*for(int i=0;i<ls.size; i++)
    ?Element el = (Element) list.get(i);
    ?*/
    ??????? Element el = (Element) iter.next();

    ??????? if(el.getName().equals("to")){

    ???????? System.out.println(el.getText());

    ??????? }

    ????? }

    ??? }

    ??? catch (IOException ex) {

    ????? ex.printStackTrace();

    ??? }

    ??? catch (JDOMException ex) {

    ????? ex.printStackTrace();

    ??? }

    ? }

    (3)DOM的document和JDOM的Document之間的相互轉換使用方法,簡單!

    DOMBuilder builder = new DOMBuilder();

    org.jdom.Document jdomDocument = builder.build(domDocument);

    DOMOutputter converter = new DOMOutputter();// work with the JDOM document…

    org.w3c.dom.Document domDocument = converter.output(jdomDocument);

    // work with the DOM document…

    2.XML文檔輸出

    XMLOutPutter類:

    JDOM的輸出非常靈活,支持很多種io格式以及風格的輸出

    Document doc = new Document(...);

    XMLOutputter outp = new XMLOutputter();

    outp.output(doc, fileOutputStream); // Raw output

    outp.setTextTrim(true); // Compressed output

    outp.output(doc, socket.getOutputStream());

    outp.setIndent(" ");// Pretty output

    outp.setNewlines(true);

    outp.output(doc, System.out);

    詳細請參閱最新的JDOM API手冊

    3.Element 類:

    (1)瀏覽Element樹

    Element root = doc.getRootElement();//獲得根元素element

    List allChildren = root.getChildren();// 獲得所有子元素的一個list

    List namedChildren = root.getChildren("name");// 獲得指定名稱子元素的list

    Element child = root.getChild("name");//獲得指定名稱的第一個子元素

    JDOM給了我們很多很靈活的使用方法來管理子元素(這里的List是java.util.List)

    List allChildren = root.getChildren();

    allChildren.remove(3); // 刪除第四個子元素

    allChildren.removeAll(root.getChildren("jack"));// 刪除叫“jack”的子元素

    root.removeChildren("jack"); // 便捷寫法

    allChildren.add(new Element("jane"));// 加入

    root.addContent(new Element("jane")); // 便捷寫法

    allChildren.add(0, new Element("first"));

    (2)移動Elements:

    在JDOM里很簡單

    Element movable = new Element("movable");

    parent1.addContent(movable); // place

    parent1.removeContent(movable); // remove

    parent2.addContent(movable); // add

    在Dom里

    Element movable = doc1.createElement("movable");

    parent1.appendChild(movable); // place

    parent1.removeChild(movable); // remove

    parent2.appendChild(movable); // 出錯!

    補充:糾錯性

    JDOM的Element構造函數(以及它的其他函數)會檢查element是否合法。

    而它的add/remove方法會檢查樹結構,檢查內容如下:

    1.在任何樹中是否有回環節點

    2.是否只有一個根節點

    3.是否有一致的命名空間(Namespaces)

    (3)Element的text內容讀取

    <description>

    A cool demo

    </description>

    // The text is directly available

    // Returns "\n A cool demo\n"

    String desc = element.getText();

    // There's a convenient shortcut

    // Returns "A cool demo"

    String desc = element.getTextTrim();

    (4)Elment內容修改

    element.setText("A new description");

    3.可正確解釋特殊字符

    element.setText("<xml> content");

    4.CDATA的數據寫入、讀出

    element.addContent(new CDATA("<xml> content"));

    String noDifference = element.getText();

    混合內容

    element可能包含很多種內容,比如說

    <table>

    <!-- Some comment -->

    Some text

    <tr>Some child element</tr>

    </table>

    取table的子元素tr

    String text = table.getTextTrim();

    Element tr = table.getChild("tr");

    也可使用另外一個比較簡單的方法

    List mixedCo = table.getContent();

    Iterator itr = mixedCo.iterator();

    while (itr.hasNext()) {

    Object o = i.next();

    if (o instanceof Comment) {...}

    // 這里可以寫成Comment, Element, Text, CDATA,ProcessingInstruction, 或者是EntityRef的類型

    }

    // 現在移除Comment,注意這里游標應為1。這是由于回車鍵也被解析成Text類的緣故,所以Comment項應為1。

    mixedCo.remove(1);

    4.Attribute類

    <table width="100%" border="0"> </table>

    String width = table.getAttributeValue("width");//獲得attribute

    int border = table.getAttribute("width").getIntValue();

    table.setAttribute("vspace", "0");//設置attribute

    table.removeAttribute("vspace");// 刪除一個或全部attribute

    table.getAttributes().clear();

    5.處理指令(Processing Instructions)操作

    一個Pls的例子

    <?br?>

    <?cocoon-process type="xslt"?>

    ????????? |??????? |

    ????????? |??????? |

    ??????? 目標???? 數據

    處理目標名稱(Target)

    String target = pi.getTarget();

    獲得所有數據(data),在目標(target)以后的所有數據都會被返回。

    String data = pi.getData();

    String type = pi.getValue("type");獲得指定屬性的數據

    List ls = pi.getNames();獲得所有屬性的名稱

    6.命名空間操作

    <xhtml:html

    ?xmlns:xhtml="

    <xhtml:title>Home Page</xhtml:title>

    </xhtml:html>

    Namespace xhtml = Namespace.getNamespace("xhtml", "

    List kids = html.getChildren("title", xhtml);

    Element kid = html.getChild("title", xhtml);

    kid.addContent(new Element("table", xhtml));

    7.XSLT格式轉換

    使用以下函數可對XSLT轉換

    最后如果你需要使用w3c的Document則需要轉換一下。

    public static Document transform(String stylesheet,Document in)

    ??????????????????????????????????????? throws JDOMException {

    ???? try {

    ?????? Transformer transformer = TransformerFactory.newInstance()

    ???????????????????????????? .newTransformer(new StreamSource(stylesheet));

    ?????? JDOMResult out = new JDOMResult();

    ?????? transformer.transform(new JDOMSource(in), out);

    ?????? return out.getDeocument();

    ???? }

    ???? catch (TransformerException e) {

    ?????? throw new JDOMException("XSLT Trandformation failed", e);

    ???? }

    ?? }

    五、用例:

    1、生成xml文檔:

    ?

    ?

    public class WriteXML{

    ??? public void BuildXML() throws Exception {

    ??????? Element root,student,number,name,age;????????

    ??????? root = new Element("student-info"); //生成根元素:student-info

    ??????? student = new Element("student"); //生成元素:student(number,name,age)????????????????????????????

    ??????? number = new Element("number");

    ??????? name = new Element("name");

    ??????? age = new Element("age");

    ??????? Document doc = new Document(root); //將根元素植入文檔doc中

    ??????? number.setText("001");

    ??????? name.setText("lnman");

    ??????? age.setText("24");

    ??????? student.addContent(number);

    ??????? student.addContent(name);

    ??????? student.addContent(age);

    ??????? root.addContent(student);

    ??????? Format format = Format.getCompactFormat();

    ??????? format.setEncoding("gb2312"); //設置xml文件的字符為gb2312

    ??????? format.setIndent("??? "); //設置xml文件的縮進為4個空格

    ??????? XMLOutputter XMLOut = new XMLOutputter(format);//元素后換行一層元素縮四格

    ??????? XMLOut.output(doc, new FileOutputStream("studentinfo.xml"));?

    }

    ??? public static void main(String[] args) throws Exception {

    ??????? WriteXML w = new WriteXML();

    ??????? System.out.println("Now we build an XML document .....");

    ??????? w.BuildXML();

    ??????? System.out.println("finished!");

    }

    }

    生成的xml文檔為:

    <?xml version="1.0" encoding="gb2312"?>

    <student-info>

    ??? <student>

    ??????? <number>001</number>

    ??????? <name>lnman</name>

    ??????? <age>24</age>

    ??? </student>

    </student-info>

    ?

    ?

    創建XML文檔2:

    ?public class CreateXML {

    ? public void Create() {

    ?? try {

    ??? Document doc = new Document();??

    ??? ProcessingInstruction pi=new ProcessingInstruction("xml-stylesheet","type="text/xsl" href="test.xsl"");

    ??? doc.addContent(pi);???

    ??? Namespace ns = Namespace.getNamespace("

    ??? Namespace ns2 = Namespace.getNamespace("other", "

    ??? Element root = new Element("根元素", ns);

    ??? root.addNamespaceDeclaration(ns2);

    ??? doc.setRootElement(root);

    ??? Element el1 = new Element("元素一");

    ??? el1.setAttribute("屬性", "屬性一");???

    ??? Text text1=new Text("元素值");

    ???????????? Element em = new Element("元素二").addContent("第二個元素");

    ??? el1.addContent(text1);

    ???????????? el1.addContent(em);????????????

    ???????????? Element el2 = new Element("元素三").addContent("第三個元素");

    ???????????? root.addContent(el1);

    ???????????? root.addContent(el2);????????????

    ???????????? //縮進四個空格,自動換行,gb2312編碼

    ???????????? XMLOutputter outputter = new XMLOutputter("? ", true,"GB2312");

    ???????????? outputter.output(doc, new FileWriter("test.xml"));

    ???????? }catch(Exception e)? {

    ????????? System.out.println(e);

    ???????? }

    ???? }????

    ???? public static void main(String args[]) {

    ????? new CreateXML().Create();

    ???? }????

    ?}

    2、讀取xml文檔的例子:

    import org.jdom.output.*;

    import org.jdom.input.*;

    import org.jdom.*;

    import java.io.*;

    import java.util.*;

    public class ReadXML{

    ??? public static void main(String[] args) throws Exception {

    ??????? SAXBuilder builder = new SAXBuilder();

    ??????? Document read_doc = builder.build("studentinfo.xml");

    ??????? Element stu = read_doc.getRootElement();

    ??????? List list = stu.getChildren("student");

    ??????? for(int i = 0;i < list.size();i++) {

    ??????????? Element e = (Element)list.get(i);

    ??????????? String str_number = e.getChildText("number");

    ??????????? String str_name = e.getChildText("name");

    ??????????? String str_age = e.getChildText("age");

    ??????????? System.out.println("---------STUDENT--------------");

    ??????????? System.out.println("NUMBER:" + str_number);

    ??????????? System.out.println("NAME:" + str_name);

    ??????????? System.out.println("AGE:" + str_age);

    ??????????? System.out.println("------------------------------");

    ??????????? System.out.println();

    ??????? }?

    ?????? }

    }

    3、DTD驗證的:

    ?public class XMLWithDTD {

    ? public void validate()? {

    ?? try {

    ??? SAXBuilder builder = new SAXBuilder(true);

    ??? builder.setFeature(");

    ??? Document doc = builder.build(new FileReader("author.xml"));???

    ??? System.out.println("搞掂");

    ??? XMLOutputter outputter = new XMLOutputter();

    ??? outputter.output(doc, System.out);

    ?? }catch(Exception e) {

    ??? System.out.println(e);

    ?? }??

    ? }

    ? public static void main(String args[]) {

    ?? new XMLWithDTD().validate();

    ? }?

    ?}

    ?  需要說明的是,這個程序沒有指明使用哪個DTD文件。DTD文件的位置是在XML中指定的,而且DTD不支持命名空間,一個XML只能引用一個DTD,所以程序直接讀取XML中指定的DTD,程序本身不用指定。不過這樣一來,好象就只能使用外部式的DTD引用方式了?高人指點。

    ?

    ?

    4、XML Schema驗證的:

    ?public class XMLWithSchema {

    ? String xml="test.xml";

    ? String schema="test-schema.xml";

    ? public void validate() {

    ?? try {

    ??? SAXBuilder builder = new SAXBuilder(true);

    ??? //指定約束方式為XML schema

    ??? builder.setFeature("

    ??? //導入schema文件

    builder.setProperty(");

    ??? Document doc = builder.build(new FileReader(xml));???

    ??? System.out.println("搞掂");

    ??? XMLOutputter outputter = new XMLOutputter();

    ??? outputter.output(doc, System.out);

    ?? }catch(Exception e) {

    ??? System.out.println("驗證失敗:"+e);

    ?? }?

    ? }

    ?}

    ?上面的程序就指出了要引入的XML Schema文件的位置。

    ?

    ?

    ?系統默認輸出是UTF-8,這有可能導致出現亂碼。

    5、Xpath例子:

    JDOM的關于XPATH的api在org.jdom.xpath這個包里。這個包下,有一個抽象類XPath.java和實現類JaxenXPath.java,
    使用時先用XPath類的靜態方法newInstance(String xpath)得到XPath對象,
    然后調用它的selectNodes(Object context)方法或selectSingleNode(Object context)方法,
    前者根據xpath語句返回一組節點(List對象);后者根據一個xpath語句返回符合條件的第一個節點(Object類型)。
    請看jdom-1.0自帶的范例程序:

    ???? 它分析在web.xml文件中的注冊的servlet的個數及參數個數,并輸出角色名。

    web.xml文件:

    <?xml version="1.0" encoding="ISO-8859-1"?>

    <!--

    <!DOCTYPE web-app

    ??? PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"

    ??? "

    -->

    <web-app>

    ??? <servlet>

    ??????? <servlet-name>snoop</servlet-name>

    ??????? <servlet-class>SnoopServlet</servlet-class>

    ??? </servlet>

    ??? <servlet>

    ??????? <servlet-name>file </servlet-name>

    ??????? <servlet-class>ViewFile</servlet-class>

    ??????? <init-param>

    ??????????? <param-name>initial</param-name>

    ??????????? <param-value>1000</param-value>

    ??????????? <description>The initial value for the counter? <!-- optional --></description>

    ??????? </init-param>

    ??? </servlet>

    ??? <servlet-mapping>

    ??????? <servlet-name>mv</servlet-name>

    ??????? <url-pattern>*.wm</url-pattern>

    ??? </servlet-mapping>

    ??? <distributed/>

    ??? <security-role>

    ????? <role-name>manager</role-name>

    ????? <role-name>director</role-name>

    ????? <role-name>president</role-name>

    ??? </security-role>

    </web-app>

    處理程序:

    import java.io.*;

    import java.util.*;?

    public class XPathReader {?????

    ??? public static void main(String[] args) throws IOException, JDOMException {

    ??????? if (args.length != 1) {

    ??????????? System.err.println("Usage: java XPathReader web.xml");

    ??????????? return;

    ??????? }

    ??????? String filename = args[0];//從命令行輸入web.xml

    ??????? PrintStream out = System.out;

    ??????? SAXBuilder builder = new SAXBuilder();

    ??????? Document doc = builder.build(new File(filename));//得到Document對象

    ?

    ?

    ??????? // Print servlet information

    ??????? XPath servletPath = XPath.newInstance("http://servlet");//,選擇任意路徑下servlet元素

    ??????? List servlets = servletPath.selectNodes(doc);//返回所有的servlet元素。

    ??????? out.println("This WAR has "+ servlets.size() +" registered servlets:");

    ??????? Iterator i = servlets.iterator();

    ??????? while (i.hasNext()) {//輸出servlet信息

    ??????????? Element servlet = (Element) i.next();

    ??????????? out.print("\t" + servlet.getChild("servlet-name")

    ??????????????????????????????????? .getTextTrim() +

    ????????????????????? " for " + servlet.getChild("servlet-class")

    ?????????????????????????????????????? .getTextTrim());

    ??????????? List initParams = servlet.getChildren("init-param");

    ??????????? out.println(" (it has " + initParams.size() + " init params)");?

    ??????? }?????????????

    ??????? // Print security role information

    ??????? XPath rolePath = XPath.newInstance("http://security-role/role-name/text()");

    ??????? List roleNames = rolePath.selectNodes(doc);//得到所有的角色名

    ??????? if (roleNames.size() == 0) {

    ??????????? out.println("This WAR contains no roles");

    ??????? } else {

    ??????????? out.println("This WAR contains " + roleNames.size() + " roles:");

    ??????????? i = roleNames.iterator();

    ??????????? while (i.hasNext()) {//輸出角色名

    ??????????????? out.println("\t" + ((Text)i.next()).getTextTrim());

    ??????????? }

    ??????? }

    ??? }????

    }

    ?

    ?

    輸出結果:

    C:\java>java?? XPathReader web.xml

    This WAR has 2 registered servlets:

    ??????? snoop for SnoopServlet (it has 0 init params)

    ??????? file for ViewFile (it has 1 init params)

    This WAR contains 3 roles:

    ??????? manager

    ??????? director

    ??????? president

    ?

    ?

    6、數據輸入要用到XML文檔要通過org.jdom.input包,反過來需要org.jdom.output。如前面所說,關是看API文檔就能夠使用。

    我們的例子讀入XML文件exampleA.xml,加入一條處理指令,修改第一本書的價格和作者,并添加一條屬性,然后寫入文件exampleB.xml:

    //exampleA.xml

    <?xml version="1.0" encoding="GBK"?>

    <bookList>

    <book>

    <name>Java編程入門</name>

    <author>張三</author>

    <publishDate>2002-6-6</publishDate>

    <price>35.0</price>

    </book>

    <book>

    <name>XML在Java中的應用</name>

    <author>李四</author>

    <publishDate>2002-9-16</publishDate>

    <price>92.0</price>

    </book>

    </bookList>

    //testJDOM.java

    import org.jdom.*;

    import org.jdom.output.*;

    import org.jdom.input.*;

    import java.io.*;

    public class TestJDOM{

    public static void main(String args[])throws Exception{

    SAXBuilder sb = new SAXBuilder();

    //從文件構造一個Document,因為XML文件中已經指定了編碼,所以這里不必了

    Document doc = sb.build(new FileInputStream("exampleA.xml"));

    ProcessingInstruction pi = new ProcessingInstruction//加入一條處理指令

    ("xml-stylesheet","href=\"bookList.html.xsl\" type=\"text/xsl\"");

    doc.addContent(pi);

    Element root = doc.getRootElement(); //得到根元素

    java.util.List books = root.getChildren(); //得到根元素所有子元素的集合

    Element book = (Element)books.get(0); //得到第一個book元素

    //為第一本書添加一條屬性

    Attribute a = new Attribute("hot","true");

    book.setAttribute(a);

    Element author = book.getChild("author"); //得到指定的字元素

    author.setText("王五"); //將作者改為王五

    //或 Text t = new Text("王五");book.addContent(t);

    Element price = book.getChild("price"); //得到指定的字元素

    //修改價格,比較郁悶的是我們必須自己轉換數據類型,而這正是JAXB的優勢

    author.setText(Float.toString(50.0f));

    String indent = " ";

    boolean newLines = true;

    XMLOutputter outp = new XMLOutputter(indent,newLines,"GBK");

    outp.output(doc, new FileOutputStream("exampleB.xml"));

    }

    };

    執行結果exampleB.xml:

    <?xml version="1.0" encoding="GBK"?>

    <bookList>

    <book hot=”true”>

    <name>Java編程入門</name>

    <author>50.0</author>

    <publishDate>2002-6-6</publishDate>

    <price>35.0</price>

    </book>

    <book>

    <name>XML在Java中的應用</name>

    <author>李四</author>

    <publishDate>2002-9-16</publishDate>

    <price>92.0</price>

    </book>

    </bookList>

    <?xml-stylesheet href="bookList.html.xsl" type="text/xsl"?>

    在默認情況下,JDOM的Element類的getText()這類的方法不會過濾空白字符,如果你需要過濾,用setTextTrim() 。


    1. /*
    2. ?*?QuickExcel.java
    3. ?*?作者:楊慶成
    4. ?*?Created?on?2004年11月22日,?下午4:05
    5. ?*?在實際應用中經常要將數據庫中的表導入Excel
    6. ?*?本人在Apache的POI基礎上寫了一個簡單的類
    7. ?*?有不當指出請指正,謝謝!
    8. ?*?
    9. ?*/
    10. package ?yqc.poi;
    11. import ?java.sql.*;
    12. import ?java.util.*;
    13. import ?java.io.*;
    14. import ?java.io.ByteArrayInputStream;
    15. import ?java.io.FileInputStream;
    16. import ?java.io.FileOutputStream;
    17. import ?java.io.IOException;
    18. import ?org.apache.poi.hssf.usermodel.*;
    19. import ?org.apache.poi.poifs.filesystem.POIFSFileSystem;
    20. import ?org.apache.poi.hssf.record.*;
    21. import ?org.apache.poi.hssf.model.*;
    22. import ?org.apache.poi.hssf.usermodel.*;
    23. import ?org.apache.poi.hssf.util.*;import?yqc.sql.*;
    24. /**
    25. ?*
    26. ?*?@author??Administrator
    27. ?*/
    28. public ?class?QuickExcel?{
    29. ????
    30. ????/**?Creates?a?new?instance?of?QuickExcel?*/
    31. ????private?QuickExcel(String?file){
    32. ????????_file=file;
    33. ????}
    34. ????
    35. ????private?void?open()throws?IOException{
    36. ????????InputStream?stream?=?null;
    37. ????????Record[]?records?=?null;
    38. ????????POIFSFileSystem?fs?=
    39. ????????????new?POIFSFileSystem(new?FileInputStream(_file));
    40. ????????_wb?=?new?HSSFWorkbook(fs);
    41. ????}
    42. ????
    43. ????private?void?create(){
    44. ????????_wb=new?HSSFWorkbook();
    45. ????}
    46. ????
    47. ????public?static?QuickExcel?newInstance?(String?file){
    48. ????????QuickExcel?qe=new?QuickExcel(file);
    49. ????????qe.create();
    50. ????????return?qe;
    51. ????}
    52. ????
    53. ????public?static?QuickExcel?openInstance(String?file)?throws?IOException?{
    54. ????????QuickExcel?qe=new?QuickExcel(file);
    55. ????????qe.open();
    56. ????????return?qe;
    57. ????}
    58. ????
    59. ????public?void?close(){
    60. ????????try{
    61. ????????????FileOutputStream?fileOut?=?new?FileOutputStream(_file);
    62. ????????????_wb.write(fileOut);//把Workbook對象輸出到文件workbook.xls中
    63. ????????????fileOut.close();
    64. ????????}
    65. ????????catch?(Exception?ex){
    66. ????????????System.out.println(ex.getMessage());
    67. ????????}
    68. ????}
    69. ????
    70. ????private?void?removeSheet(String?sheetName){
    71. ????????int?i=_wb.getSheetIndex("sheetName");
    72. ????????if?(i>=0)?_wb.removeSheetAt(i);
    73. ????}
    74. ????
    75. ????public?int?fillSheet?(ResultSet?rs,String?sheetName)throws?SQLException?{
    76. ????????HSSFSheet?st=?_wb.createSheet(sheetName);
    77. ????????ResultSetMetaData?rsmd=?rs.getMetaData();
    78. ????????int?index=0;
    79. ????????int?result=0;
    80. ????????HSSFRow?row=st.createRow(index++);
    81. ????????for(int?i=1;i<=rsmd.getColumnCount();++i){
    82. ????????????HSSFCell?cell=row.createCell((short)(i-1));
    83. ????????????cell.setCellValue(rsmd.getColumnName(i));
    84. ????????}
    85. ????????while(rs.next())?{
    86. ????????????result++;
    87. ????????????row=st.createRow(index++);
    88. ????????????for(int?i=1;i<=rsmd.getColumnCount();++i){
    89. ????????????????HSSFCell?cell=row.createCell((short)(i-1));
    90. ????????????????cell.setEncoding(cell.ENCODING_UTF_16);
    91. ????????????????cell.setCellValue(rs.getString(i));
    92. ????????????}
    93. ????????}
    94. ????????return?result;
    95. }
    96. ????
    97. ????public?static?void?main(String[]?args){
    98. ????????try{
    99. ????????????QuickConnection?qc=new?MssqlConnection("jdbc:microsoft:sqlserver://192.168.0.100:1433;DatabaseName=ls");
    100. ????????????QuickExcel?qe=QuickExcel.newInstance("a.xls");
    101. ????????????qc.connect();
    102. ????????????String?sql="select?*?from?ls.dbo.radio1_emcee";
    103. ????????????ResultSet?rs=qc.getStatement().executeQuery(sql);
    104. ????????????qe.fillSheet(rs,"MT");
    105. ????????????qe.close();
    106. ????????????qe=QuickExcel.openInstance("a.xls");
    107. ????????????qe.fillSheet(rs,"MO");
    108. ????????????qe.close();
    109. ????????????qc.close();
    110. ????????}
    111. ????????catch?(SQLException?ex){
    112. ????????????System.out.println(ex.getMessage());
    113. ????????}
    114. ????????catch?(IOException?ex){
    115. ????????????System.out.println(ex.getMessage());
    116. ????????}
    117. ????}
    118. ????
    119. ????HSSFWorkbook?_wb;
    120. ????String?_file="new.xls";
    121. }
    posted @ 2006-07-26 15:30 brock 閱讀(455) | 評論 (0)編輯 收藏

    摘要:

    Apache的Jakata項目的POI子項目,目標是處理ole2對象。目前比較成熟的是HSSF接口,處理MS Excel(97-2002)對象
    微軟在桌面系統上的成功,令我們不得不大量使用它的辦公產品,如:Word,Excel。時至今日,它的源代碼仍然不公開已封鎖了我們的進一步應用和開發。然而在要求更高的服務器領域,微軟本身的產品移植性不好,??
    性能不佳。在我們實際的開發中,表現層的解決方案雖然有多樣,但是Ie瀏覽器已成為最多人使用的瀏覽器,因為大家都用Windows。在企業辦公系統中,常常有客戶這樣子要求:你要把我們的報表直接用Excel打開。或者是:我們已經習慣用Excel打印。這樣子如果用.net開發是沒有問題的,但是有j2ee這個比.net更有前途的開放式的開發環境,難道我為了解決打印的要求去另寫客戶端的控件?或者在服務器端使用本地代碼?第一種方案的問題是關鍵數據的處理有時候不能在客戶端做,第2種方案的問題是犧牲了代碼的可移植性和穩定性。如果讓客戶端只負責處理生成好的報表,那將是一種誘人的選擇。

    Apache的Jakata項目的POI子項目,目標是處理ole2對象。目前比較成熟的是HSSF接口,處理MS Excel(97-2002)對象。它不象我們僅僅是用csv生成的沒有格式的可以由Excel轉換的東西,而是真正的Excel對象,你可以控制一些屬性如sheet,cell等等。這是一個年輕的項目,所以象HDF這樣直接支持Word對象的好東西仍然在設計中。其它支持word格式的純java方案還有itext,不過也是仍在奮斗中。但是HSSF已經成熟到能夠和足夠我們使用了。另外,無錫永中Office的實現方案也是純java的解決方案,不過那也是完全商業的產品,并不是公開代碼項目。其實,從開發歷史的角度講,在80年代中期starOffice的原作者在德國成立了StarOffice suite公司,然后到1999年夏天starOffice被sun收購,再到2000年6月starOffice5.2的發布;并且從starOffice6.0開始,starOffice建立在OpenOffice的api的基礎上,這個公開代碼的office項目已經進行了很長的時間。雖然那是由C++寫的,但是POI的代碼部分也是由openOffice改過來的。所以,應該對POI充滿足夠的信心。國內已經有部分公司在他們的辦公自動化等Web項目中使用poi了,如日恒的ioffice,海泰的HTOffice等。

    java當初把核心處理設成Unicode,帶來的好處是另代碼適應了多語言環境。然而由于老外的英語只有26個字母,有些情況下,一些程序員用8位的byte處理,一不小心就去掉了CJK的高位。或者是由于習慣在程序中采用硬編碼,還有多種原因,使得許多java應用在CJK的處理上很煩惱。還好在POI HSSF中考慮到這個問題,可以設置encoding為雙字節。

    POI可以到www.apache.org下載到。編譯好的jar主要有這樣4個:poi包,poi Browser包,poi hdf包,poi hssf例程包。實際運行時,需要有poi包就可以了。如果用Jakarta ant編譯和運行,下載apache Jakarta POI的release中的src包,它里面已經為你生成好了build文件了。只要運行ant就可以了(ant 的安裝和使用在此不說了)。如果是用Jbuilder 運行,請在新建的項目中加入poi包。以Jbuilder6為例,選擇Tools菜單項的config libraries...選項,新建一個lib。在彈出的菜單中選擇poi包,如這個jakarta-poi-1.5.1-final-20020820.jar,把poi添加到jbuilder中。然后,右鍵點擊你的項目,在project的properties菜單中path的required Libraries中,點add,添加剛才加入到jbuilder中的poi到你現在的項目中。如果你僅僅是為了熟悉POI hssf的使用,可以直接看POI的samples包中的源代碼,并且運行它。hssf的各種對象都有例程的介紹。hssf提供的例程在org.apache.poi.hssf.usermodel.examples包中,共有14個,生成的目標xls都是workbook.xls。如果你想看更多的例程,可以參考hssf的Junit test cases,在poi的包的源代碼中有。hssf都有測試代碼。

    這里只對部分例程的實現做介紹。

    HSSF提供給用戶使用的對象在org.apache.poi.hssf.usermodel包中,主要部分包括Excell對象,樣式和格式,還有輔助操作。有以下幾種對象:

    HSSFWorkbook excell的文檔對象

    HSSFSheet excell的表單

    HSSFRow excell的行

    HSSFCell excell的格子單元

    HSSFFont excell字體

    HSSFName 名稱

    HSSFDataFormat 日期格式

    在poi1.7中才有以下2項:

    HSSFHeader sheet頭

    HSSFFooter sheet尾

    和這個樣式

    HSSFCellStyle cell樣式

    輔助操作包括

    HSSFDateUtil 日期

    HSSFPrintSetup 打印

    HSSFErrorConstants 錯誤信息表

    仔細看org.apache.poi.hssf包的結構,不難發現HSSF的內部實現遵循的是MVC模型。

    這里我用Rose把org.apache.poi.hssf.usermodel包中的對象反向導入并根據相互關系作了整理,詳見下面兩圖:

    ??IMG ../upload/article/a2005512101549.jpg[/IMG]

    圖1 基本對象

    從中不難可以發現每一個基本對象都關聯了一個Record對象。Record對象是一個參考Office格式的相關記錄。

    ?? IMG ../upload/article/2005512101631.jpg[/IMG]


    圖2 HSSFWorkbook

    HSSFWorkbook即是一個Excell對象。這幅類圖體現的是HSSFWorkbook和基本對象的相互關系。可見,許多對象中也建立了Workbook的引用。還需要注意的是在HSSFWorkbook和HSSFSheet中建立了log機制POILogger,而且POILogger也是使用apache Log4J實現的。

    先看poi的examples包中提供的最簡單的例子,建立一個空xls文件。

    import org.apache.poi.hssf.usermodel.HSSFWorkbook;

    import java.io.FileOutputStream;

    import java.io.IOException;

    public class NewWorkbook

    {

    public static void main(String[] args)

    throws IOException

    {

    HSSFWorkbook wb = new HSSFWorkbook();//建立新HSSFWorkbook對象

    FileOutputStream fileOut = new FileOutputStream("workbook.xls");

    wb.write(fileOut);//把Workbook對象輸出到文件workbook.xls中

    fileOut.close();

    }

    }

    通過這個例子,我們建立的是一個空白的xls文件(不是空文件)。在此基礎上,我們可以進一步看其它的例子。


    import org.apache.poi.hssf.usermodel.*;

    import java.io.FileOutputStream;

    import java.io.IOException;

    public class CreateCells

    {

    public static void main(String[] args)

    throws IOException

    {

    HSSFWorkbook wb = new HSSFWorkbook();//建立新HSSFWorkbook對象

    HSSFSheet sheet = wb.createSheet("new sheet");//建立新的sheet對象


    // Create a row and put some cells in it. Rows are 0 based.

    HSSFRow row = sheet.createRow((short)0);//建立新行

    // Create a cell and put a value in it.

    HSSFCell cell = row.createCell((short)0);//建立新cell

    cell.setCellValue(1);//設置cell的整數類型的值


    // Or do it on one line.

    row.createCell((short)1).setCellValue(1.2);//設置cell浮點類型的值

    row.createCell((short)2).setCellValue("test");//設置cell字符類型的值

    row.createCell((short)3).setCellValue(true);//設置cell布爾類型的值

    HSSFCellStyle cellStyle = wb.createCellStyle();//建立新的cell樣式

    cellStyle.setDataFormat(HSSFDataFormat.getFormat("m/d/yy h:mm"));//設置cell樣式為定制的日期格式

    HSSFCell dCell =row.createCell((short)4);

    dCell.setCellValue(new Date());//設置cell為日期類型的值

    dCell.setCellStyle(cellStyle); //設置該cell日期的顯示格式

    HSSFCell csCell =row.createCell((short)5);

    csCell.setEncoding(HSSFCell.ENCODING_UTF_16);//設置cell編碼解決中文高位字節截斷

    csCell.setCellValue("中文測試_Chinese Words Test");//設置中西文結合字符串

    row.createCell((short)6).setCellType(HSSFCell.CELL_TYPE_ERROR);//建立錯誤cell


    // Write the output to a file

    FileOutputStream fileOut = new FileOutputStream("workbook.xls");

    wb.write(fileOut);

    fileOut.close();

    }

    }

    我稍微修改了原來的examples包中的CreateCells類寫了上面的功能測試類。通過這個例子,我們可以清楚的看到xls文件從大到小包括了HSSFWorkbook HSSFSheet HSSFRow HSSFCell這樣幾個對象。我們可以在cell中設置各種類型的值。尤其要注意的是如果你想正確的顯示非歐美的字符時,尤其象中日韓這樣的語言,必須設置編碼為16位的即是HSSFCell.ENCODING_UTF_16,才能保證字符的高8位不被截斷而引起編碼失真形成亂碼。

    其他測試可以通過參考examples包中的測試例子掌握poi的詳細用法,包括字體的設置,cell大小和低紋的設置等。需要注意的是POI是一個仍然在完善中的公開代碼的項目,所以有些功能正在不斷的擴充。如HSSFSheet的getFooter() getHeader()和setFooter(HSSFFooter hsf) setHeader(HSSFHeader hsh)是在POI1.7中才有的,而POI1.5中就沒有。運行測試熟悉代碼或者使用它做項目時請注意POI的版本。

    另外需要注意的是HSSF也有它的對xls基于事件的解析。可以參考例程中的EventExample.java。它通過實現HSSFListener完成從普通流認知Xls中包含的內容,在apache Cocoon中的org.apache.cocoon.serialization.HSSFSerializer中用到了這個解析。因為Cocoon2是基于事件的,所以POI為了提供快速的解析也提供了相應的事件。當然我們自己也可以實現這個事件接口。

    因為POI還不是一個足夠成熟的項目,所以有必要做進一步的開發和測試。但是它已經為我們用純java操作ole2對象提供了可能,而且克服了ole對象調用的缺陷,提供了服務器端的Excel解決方案。

    ?

    posted @ 2006-07-26 15:29 brock 閱讀(316) | 評論 (0)編輯 收藏

    where 1=1有什么用?在SQL語言中,寫這么一句話就跟沒寫一樣。

    select * from table1 where 1=1與select * from table1完全沒有區別,甚至還有其他許多寫法,1<>2,'a'='a','a'<>'b',其目的就只有一個,where的條件為永真,得到的結果就是未加約束條件的。

    在SQL注入時會用到這個,例如select * from table1 where name='lala'給強行加上select * from table1 where name='lala' or 1=1這就又變成了無約束的查詢了。

    最近發現的妙用在于,在不定數量查詢條件情況下,1=1可以很方便的規范語句。例如一個查詢可能有name,age,height,weight約束,也可能沒有,那該如何處理呢?

    String sql=select * from table1 where 1=1

    為什么要寫多余的1=1?馬上就知道了。

    if(!name.equals("")){
    ?sql=sql+"name='"+name+"'";
    }
    if(!age.equals("")){
    ?sql=sql+"age'"+age+"'";
    }
    if(!height.equals("")){
    ?sql=sql+"height='"+height+"'";
    }
    if(!weight.equals("")){
    ?sql=sql+"weight='"+weight+"'";
    }

    如果不寫1=1呢,那么在每一個不為空的查詢條件面前,都必須判斷有沒有where字句,否則要在第一個出現的地方加where

    posted @ 2006-07-26 14:24 brock 閱讀(412) | 評論 (0)編輯 收藏

    泛型是J2SE 5.0最重要的特性。他們讓你寫一個type(類或接口)和創建一個實例通過傳遞一個或多個引用類型。本文將教你如何操作泛型。它的第一部分是“沒有泛型的日子”,先讓我們回憶老版本JDK的不便。然后,舉一些泛型的例子。在討論完語法以及有界泛型的使用之后,文章最后一章將解釋如何寫泛型。
    J2SE 5.0中的泛型

    作者:Budi Kurniawan

    翻譯:RR00

    email:di_feng_ro@hotmail.com


    版權聲明:可以任意轉載,轉載時請務必以超鏈接形式標明文章原始出處和作者信息及本聲明
    英文原文地址:
    http://www.onjava.com/pub/a/onjava/2005/07/06/generics.html
    中文地址:
    http://www.matrix.org.cn/resource/article/43/43634_java_generics.html
    關鍵詞: java generics java5

    摘要
    ?????? 泛型是J2SE 5.0最重要的特性。他們讓你寫一個type(類或接口)和創建一個實例通過傳遞一個或多個引用類型。這個實例受限于只能作用于這些類型。比如,在java 5,java.util.List 已經被泛化。當建立一個list對象時,你通過傳遞一個java類型建立一個List實例,此list實例只能作用于所傳遞的類型。這意味著如果你傳遞一個String ,此List實例只能擁有String對象;如果你傳遞一個Integer,此實例只能存貯Integer對象。除了創建參數化的類型,你還能創建參數化的函數。
    ???? 泛型的第一個好處是編譯時的嚴格類型檢查。這是集合框架最重要的特點。此外,泛型消除了絕大多數的類型轉換。在JDK 5.0之前,當你使用集合框架時,你不得不進行類型轉換。
    ???? 本文將教你如何操作泛型。它的第一部分是“沒有泛型的日子”,先讓我們回憶老版本JDK的不便。然后,舉一些泛型的例子。在討論完語法以及有界泛型的使用之后,文章最后一章將解釋如何寫泛型。
    ??

    沒有泛型的日子
    ???? 所有的java類都源自java.lang.Object,這意味著所有的JAVA對象能轉換成Object。因此,在之前的JDK的版本中,很多集合框架的函數接受一個Object參數。所以,collections是一個能持有任何對象的多用途工具,但帶來了不良的后果。

    ???? 舉個簡單的例子,在JDK 5.0的之前版本中,類List的函數add接受一個Object參數:

    public boolean add(java.lang.Object element)


    ????????所以你能傳遞任何類型給add。這是故意這么設計的。否則,它只能傳遞某種特定的對象,這樣就會出現各種List類型,如,StringList, EmployeeList, AddressList等。
    ???? add通過Object傳遞能帶來好處,現在我們考慮get函數(返回List中的一個元素).如下是JDK 5之前版本的定義:

    public java.lang.Object get(int index) throws IndexOutOfBoundsException


    get返回一個Object.不幸的事情從此開始了.假如你儲存了兩個String對象在一個List中:

    List stringList1 = new ArrayList();
    stringList1.add("Java 5");
    stringList1.add("with generics");


    當你想從stringList1取得一個元素時,你得到了一個Object.為了操作原來的類型元素,你不得不把它轉換為String。

    String s1 = (String) stringList1.get(0);


    但是,假如你曾經把一個非String對象加入stringList1中,上面的代碼會拋出一個ClassCastException. 有了泛型,你能創建一個單一用途的List實例.比如,你能創建一個只接受String對象的List實例,另外一個實例只能接受Employee對象.這同樣適用于集合框架中的其他類型.


    泛型入門

    ?? 像一個函數能接受參數一樣,一個泛型也能接受參數.這就是一個泛型經常被稱為一個參數化類型的原因.但是不像函數用()傳遞參數,泛型是用<>傳遞參數的.聲明一個泛型和聲明一個普通類沒有什么區別,只不過你把泛型的變量放在<>中.
    ???? 比如,在JDK 5中,你可以這樣聲明一個java.util.List :??List<E> myList;
    E 稱為類型變量.意味著一個變量將被一個類型替代.替代類型變量的值將被當作參數或返回類型.對于List接口來說,當一個實例被創建以后,E 將被當作一個add或別的函數的參數.E 也會使get或別的參數的返回值.下面是add和get的定義:

    boolean add<E o>
    E get(int index)


    NOTE:一個泛型在聲明或例示時允許你傳遞特定的類型變量: E.除此之外,如果E是個類,你可以傳遞子類;如果E是個接口,你可以傳遞實現接口的類;

    -----------------------------譯者添加--------------------
    List<Number> numberList= new ArrayList<Number>();
    ?? numberList.add(2.0);
    ?? numberList.add(2);
    -----------------------------譯者添加--------------------


    如果你傳遞一個String給一個List,比如:

    List<String> myList;


    那么mylist的add函數將接受一個String作為他的參數,而get函數將返回一個String.因為返回了一個特定的類型,所以不用類型轉化了。

    NOTE:根據慣例,我們使用一個唯一的大寫字目表示一個類型變量。為了創建一個泛型,你需在聲明時傳遞同樣的參數列表。比如,你要想創建一個ArrayList來操作String ,你必須把String放在<>中。如:

    List<String> myList = new ArrayList<String>();


    再比如,java.util.Map 是這么定義的:

    public interface Map<K,V>


    K用來聲明map鍵(KEY)的類型而V用來表示值(VALUE)的類型。put和values是這么定義的:

    V put(K key, V value)
    Collection<V> values()


    NOTE:一個泛型不準直接的或間接的是java.lang.Throwable的子類。因為異常是在運行時拋出的,所以它不可能預言什么類型的異常將在編譯時拋出.

    列表1的例子將比較List在JDK 1.4 和JDK1.5的不同

    package com.brainysoftware.jdk5.app16;
    import java.util.List;
    import java.util.ArrayList;

    public class GenericListTest {
    ??public static void main(String[] args) {
    ????// in JDK 1.4
    ????List stringList1 = new ArrayList();
    ????stringList1.add("Java 1.0 - 5.0");
    ????stringList1.add("without generics");
    ????// cast to java.lang.String
    ????String s1 = (String) stringList1.get(0);
    ????System.out.println(s1.toUpperCase());

    ????// now with generics in JDK 5
    ????List<String> stringList2 = new ArrayList<String>();
    ????stringList2.add("Java 5.0");
    ????stringList2.add("with generics");
    ????// no need for type casting
    ????String s2 = stringList2.get(0);
    ????System.out.println(s2.toUpperCase());
    ??}
    }


    在列表1中,stringList2是個泛型。聲明List<String>告訴編譯器List的實例能接受一個String對象。當然,在另外的情況中,你能新建能接受各種對象的List實例。注意,當從List實例中返回成員元素時,不需要對象轉化,因為他返回的了你想要的類型,也就是String.

    NOTE:泛型的類型檢查(type checking)是在編譯時完成的.

    ??????最讓人感興趣的事情是,一個泛型是個類型并且能被當作一個類型變量。比如,你想你的List儲存lists of Strings,你能通過把List<String>作為他的類型變量來聲明List。比如:

    List<List<String>> myListOfListsOfStrings;


    要從myList中的第一個List重新取得String,你可以這么用:

    String s = myListOfListsOfStrings.get(0).get(0);


    下一個列表中的ListOfListsTest類示范了一個List(命名為listOfLists)接受一個String List作為參數。

    package com.brainysoftware.jdk5.app16;
    import java.util.ArrayList;
    import java.util.List;
    public class ListOfListsTest {
    ??public static void main(String[] args) {
    ????List<String> listOfStrings = new ArrayList<String>();
    ????listOfStrings.add("Hello again");
    ????List<List<String>> listOfLists = new ArrayList<List<String>>();
    ????listOfLists.add(listOfStrings);
    ????String s = listOfLists.get(0).get(0);
    ????System.out.println(s); // prints "Hello again"
    ??}
    }


    另外,一個泛型接受一個或多個類型變量。比如,java.util.Map有兩個類型變量s。第一個定義了鍵(key)的類型,第二個定義了值(value)的類型。下面的例子講教我們如何使用個一個泛型Map.

    package com.brainysoftware.jdk5.app16;
    import java.util.HashMap;
    import java.util.Map;
    public class MapTest {
    ??public static void main(String[] args) {
    ????Map<String, String> map = new HashMap<String, String>();
    ????map.put("key1", "value1");
    ????map.put("key2", "value2");
    ????String value1 = map.get("key1");
    ??}
    }


    在這個例子中,重新得到一個key1代表的String值,我們不需要任何類型轉換。

    沒有參數的情況下使用泛型

    ????既然在J2SE 5.0中收集類型已經泛型化,那么,原來的使用這些類型的代碼將如何呢?很幸運,他們在JAVA 5中將繼續工作,因為你能使用沒有參數的泛型。比如,你能繼續像原來一樣使用List接口,正如下面的例子一樣。

    List stringList1 = new ArrayList();
    stringList1.add("Java 1.0 - 5.0");
    stringList1.add("without generics");
    String s1 = (String) stringList1.get(0);


    一個沒有任何參數的泛型被稱為原型(raw type)。它意味著這些為JDK1.4或更早的版本而寫的代碼將繼續在java 5中工作。

    盡管如此,一個需要注意的事情是,JDK5編譯器希望你使用帶參數的泛型。否則,編譯器將提示警告,因為他認為你可能忘了定義類型變量s。比如,編譯上面的代碼的時候你會看到下面這些警告,因為第一個List被認為是原型。

    Note: com/brainysoftware/jdk5/app16/GenericListTest.java
    ????????uses unchecked or unsafe operations.
    Note: Recompile with -Xlint:unchecked for details.

    當你使用原型時,如果你不想看到這些警告,你有幾個選擇來達到目的:
    1.編譯時帶上參數-source 1.4
    2.使用@SupressWarnings("unchecked")注釋
    3.更新你的代碼,使用List<Object>. List<Object>的實例能接受任何類型的對象,就像是一個原型List。然而,編譯器不會報錯。

    使用 ? 通配符
    ?? 前面提過,如果你聲明了一個List<aType>, 那么這個List對aType起作用,所以你能儲存下面這些類型的對象:
    1.一個aType的實例
    2.它的子類的實例(如果aType是個類)
    3.實現aType接口的類實例(如果aType是個接口)
    但是,請注意,一個泛型本身是個JAVA類型,就像java.lang.String或java.io.File一樣。傳遞不同的類型變量給泛型可以創建不同的JAVA類型。比如,下面例子中list1和list2引用了不同的類型對象。

    List<Object> list1 = new ArrayList<Object>();
    List<String> list2 = new ArrayList<String>();


    list1指向了一個類型變量s為java.lang.Objects 的List而list2指向了一個類型變量s為String 的List。所以傳遞一個List<String>給一個參數為List<Object>的函數將導致compile time錯誤。下面列表可以說明:
    package com.brainysoftware.jdk5.app16;
    import java.util.ArrayList;
    import java.util.List;

    public class AllowedTypeTest {
    ??public static void doIt(List<Object> l) {
    ??}
    ??public static void main(String[] args) {
    ????List<String> myList = new ArrayList<String>();
    ????// 這里將產生一個錯誤
    ????doIt(myList);
    ??}
    }

    上面的代碼無法編譯,因為你試圖傳遞一個錯誤的類型給函數doIt。doIt的參數是List<Object>二你傳遞的參數是List<String>。
    可以使用 ? 通配符解決這個難題。List<?> 意味著一個對任何對象起作用的List。所以,doIt可以改為:

    public static void doIt(List<?> l) {}


    ????在某些情況下你會考慮使用 ? 通配符。比如,你有一個printList函數,這個函數打印一個List的所有成員,你想讓這個函數對任何類型的List起作用時。否則,你只能累死累活的寫很多printList的重載函數。下面的列表引用了使用 ? 通配符的printList函數。
    package com.brainysoftware.jdk5.app16;
    import java.util.ArrayList;
    import java.util.List;

    public class WildCardTest {

    ??public static void printList(List<?> list) {
    ????for (Object element : list) {
    ??????System.out.println(element);
    ????}
    ??}
    ??public static void main(String[] args) {
    ????List<String> list1 = new ArrayList<String>();
    ????list1.add("Hello");
    ????list1.add("World");
    ????printList(list1);

    ????List<Integer> list2 = new ArrayList<Integer>();
    ????list2.add(100);
    ????list2.add(200);
    ????printList(list2);
    ??}
    }


    這些代碼說明了在printList函數中,List<?>表示各種類型的List對象。然而,請注意,在聲明的時候使用 ? 通配符是不合法的,像這樣:

    List<?> myList = new ArrayList<?>(); // 不合法


    如果你想創建一個接收任何類型對象的List,你可以使用Object作為類型變量,就像這樣:

    List<Object> myList = new ArrayList<Object>();


    在函數中使用界限通配符
    在之前的章節中,你學會了通過傳遞不同的類型變量s來創建不同JAVA類型的泛型,但并不考慮類型變量s之間的繼承關系。在很多情況下,你想一個函數有不同的List參數。比如,你有一個函數getAverage,他返回了一個List中成員的平均值。然而,如果你把List<Number>作為getAverage的參數,你就沒法傳遞List<Integer> 或List<Double>參數,因為List<Number>和List<Integer> 和List<Double>不是同樣的類型。

    你能使用原型或使用通配符,但這樣無法在編譯時進行安全類型檢查,因為你能傳遞任何類型的List,比如List<String>的實例。你可以使用List<Number>作為參數,但是你就只能傳遞List<Number>給函數。但這樣就使你的函數功能減少,因為你可能更多的時候要操作List<Integer>或List<Long>,而不是List<Number>。

    J2SE5.0增加了一個規則來解決了這種約束,這個規則就是允許你定義一個上界(upper bound) 類型變量.在這種方式中,你能傳遞一個類型或它的子類。在上面getAverage函數的例子中,你能傳遞一個List<Number>或它的子類的實例,比如List<Integer> or List<Float>。

    使用上界規則的語法這么定義的:GenericType<? extends upperBoundType>. 比如,對getAverage函數的參數,你可以這么寫List<? extends Number>. 下面例子說明了如何使用這種規則。
    package com.brainysoftware.jdk5.app16;
    import java.util.ArrayList;
    import java.util.List;
    public class BoundedWildcardTest {
    ??public static double getAverage(List<? extends Number> numberList)
    ??{
    ????double total = 0.0;
    ????for (Number number : numberList)
    ??????total += number.doubleValue();
    ????return total/numberList.size();
    ??}

    ??public static void main(String[] args) {
    ????List<Integer> integerList = new ArrayList<Integer>();
    ????integerList.add(3);
    ????integerList.add(30);
    ????integerList.add(300);
    ????System.out.println(getAverage(integerList)); // 111.0
    ????List<Double> doubleList = new ArrayList<Double>();
    ????doubleList.add(3.0);
    ????doubleList.add(33.0);
    ????System.out.println(getAverage(doubleList)); // 18.0
    ??}
    }

    由于有了上界規則,上面例子中的getAverage函數允許你傳遞一個List<Number> 或一個類型變量是任何java.lang.Number子類的List。

    下界規則
    關鍵字extends定義了一個類型變量的上界。通過使用super關鍵字,我們可以定義一個類型變量的下界,盡管使用的情況不多。比如,如果一個函數的參數是List<? super Integer>,那么意味著你可以傳遞一個List<Integer>的實例或者任何java.lang.Integer的超類(superclass)。

    創建泛型

    前面的章節主要說明了如何使使用泛型,特別是集合框架中的類。現在我們開始學習如何寫自己的泛型。

    基本上,除了聲明一些你想要使用的類型變量s外,一個泛型和別的類沒有什么區別。這些類型變量s位于類型后面的<>中。比如,下面的Point就是個泛型。一個Point對象代表了一個系統中的點,它有橫坐標和縱坐標。通過使Point泛型化,你能定義一個點實例的精確程度。比如,如果一個Point對象需要非常精確,你就把Double作為類型變量。否則,Integer 就夠了。
    package com.brainysoftware.jdk5.app16;
    public class Point<T> {
    ??T x;
    ??T y;
    ??public Point(T x, T y) {
    ????this.x = x;
    ????this.y = y;
    ??}
    ??public T getX() {
    ????return x;
    ??}
    ??public T getY() {
    ????return y;
    ??}
    ??public void setX(T x) {
    ????this.x = x;
    ??}
    ??public void setY(T y) {
    ????this.y = y;
    ??}
    }


    在這個例子中,T是Point的類型變量 。T是getX和getY的返回值類型,也是setX和setY的參數類型。此外,構造函數結合兩個T參數。
    使用point類就像使用別的類一樣。比如,下面的例子創建了兩個Point對象:ponint1和point2。前者把Integer作為類型變量,而后者把Double作為類型變量。

    Point<Integer> point1 = new Point<Integer>(4, 2);
    point1.setX(7);
    Point<Double> point2 = new Point<Double>(1.3, 2.6);
    point2.setX(109.91);


    總結
    泛型使代碼在編譯時有了更嚴格的類型檢查。特別是在集合框架中,泛型有兩個作用。第一,他們增加了對集合類型在編譯時的類型檢查,所以集合類所能持有的類型對傳遞給它的參數類型起了限制作用。比如你創建了一個持有strings的java.util.List實例,那么他就將不能接受Integers或別的類型。其次,當你從一個集合中取得一個元素時,泛型消除了類型轉換的必要。
    泛型能夠在沒有類型變量的情況下使用,比如,作為原型。這些措施讓Java 5之前的代碼能夠運行在JRE 5中。但是,對新的應用程序,你最好不要使用原型,因為以后Java可能不支持他們。

    你已經知道通過傳遞不同類型的類型變量給泛型可以產生不同的JAVA類型。就是說List<String>和List<Object>的類型是不同的。盡管String是java.lang.Object。但是傳遞一個List<String>給一個參數是List<Object>的函數會參數會產生編譯錯誤(compile error)。函數能用 ? 通配符使其接受任何類型的參數。List<?> 意味著任何類型的對象。
    最后,你已經看到了寫一個泛型和別的一般JAVA類沒有什么區別。你只需要在類型名稱后面的<>中聲明一系列的類型變量s就行了。這些類型變量s就是返回值類型或者參數類型。根據慣例,一個類型變量用一個大寫字母表示。
    posted @ 2006-07-26 13:30 brock 閱讀(108) | 評論 (0)編輯 收藏

         摘要: 利用 Java 的 Properties 類讀取配置文件信息 ...  閱讀全文
    posted @ 2006-07-26 12:50 brock 閱讀(1453) | 評論 (0)編輯 收藏

    Eclipse快捷鍵指南


    Eclipse 快捷鍵指南
    本文檔從Eclipse軟件上整理,是列出了標準的快捷鍵,未列出Emacs快捷鍵。
    轉貼請注明作者和出處。
    ?
    編輯
    作用域
    功能
    快捷鍵
    全局
    查找并替換
    Ctrl+F
    文本編輯器
    查找上一個
    Ctrl+Shift+K
    文本編輯器
    查找下一個
    Ctrl+K
    全局
    撤銷
    Ctrl+Z
    全局
    復制
    Ctrl+C
    全局
    恢復上一個選擇
    Alt+Shift+↓
    全局
    剪切
    Ctrl+X
    全局
    快速修正
    Ctrl1+1
    全局
    內容輔助
    Alt+/
    全局
    全部選中
    Ctrl+A
    全局
    刪除
    Delete
    全局
    上下文信息
    Alt+?
    Alt+Shift+?
    Ctrl+Shift+Space
    Java編輯器
    顯示工具提示描述
    F2
    Java編輯器
    選擇封裝元素
    Alt+Shift+↑
    Java編輯器
    選擇上一個元素
    Alt+Shift+←
    Java編輯器
    選擇下一個元素
    Alt+Shift+→
    文本編輯器
    增量查找
    Ctrl+J
    文本編輯器
    增量逆向查找
    Ctrl+Shift+J
    全局
    粘貼
    Ctrl+V
    全局
    重做
    Ctrl+Y
    ?
    查看
    作用域
    功能
    快捷鍵
    全局
    放大
    Ctrl+=
    全局
    縮小
    Ctrl+-
    ?
    窗口
    作用域
    功能
    快捷鍵
    全局
    激活編輯器
    F12
    全局
    切換編輯器
    Ctrl+Shift+W
    全局
    上一個編輯器
    Ctrl+Shift+F6
    全局
    上一個視圖
    Ctrl+Shift+F7
    全局
    上一個透視圖
    Ctrl+Shift+F8
    全局
    下一個編輯器
    Ctrl+F6
    全局
    下一個視圖
    Ctrl+F7
    全局
    下一個透視圖
    Ctrl+F8
    文本編輯器
    顯示標尺上下文菜單
    Ctrl+W
    全局
    顯示視圖菜單
    Ctrl+F10
    全局
    顯示系統菜單
    Alt+-
    ?
    導航
    作用域
    功能
    快捷鍵
    Java編輯器
    打開結構
    Ctrl+F3
    全局
    打開類型
    Ctrl+Shift+T
    全局
    打開類型層次結構
    F4
    全局
    打開聲明
    F3
    全局
    打開外部javadoc
    Shift+F2
    全局
    打開資源
    Ctrl+Shift+R
    全局
    后退歷史記錄
    Alt+←
    全局
    前進歷史記錄
    Alt+→
    全局
    上一個
    Ctrl+,
    全局
    下一個
    Ctrl+.
    Java編輯器
    顯示大綱
    Ctrl+O
    全局
    在層次結構中打開類型
    Ctrl+Shift+H
    全局
    轉至匹配的括號
    Ctrl+Shift+P
    全局
    轉至上一個編輯位置
    Ctrl+Q
    Java編輯器
    轉至上一個成員
    Ctrl+Shift+↑
    Java編輯器
    轉至下一個成員
    Ctrl+Shift+↓
    文本編輯器
    轉至行
    Ctrl+L
    ?
    搜索
    作用域
    功能
    快捷鍵
    全局
    出現在文件中
    Ctrl+Shift+U
    全局
    打開搜索對話框
    Ctrl+H
    全局
    工作區中的聲明
    Ctrl+G
    全局
    工作區中的引用
    Ctrl+Shift+G
    ?
    文本編輯
    作用域
    功能
    快捷鍵
    文本編輯器
    改寫切換
    Insert
    文本編輯器
    上滾行
    Ctrl+↑
    文本編輯器
    下滾行
    Ctrl+↓
    ?
    文件
    作用域
    功能
    快捷鍵
    全局
    保存
    Ctrl+X
    Ctrl+S
    全局
    打印
    Ctrl+P
    全局
    關閉
    Ctrl+F4
    全局
    全部保存
    Ctrl+Shift+S
    全局
    全部關閉
    Ctrl+Shift+F4
    全局
    屬性
    Alt+Enter
    全局
    新建
    Ctrl+N
    ?
    項目
    作用域
    功能
    快捷鍵
    全局
    全部構建
    Ctrl+B
    ?
    源代碼
    作用域
    功能
    快捷鍵
    Java編輯器
    格式化
    Ctrl+Shift+F
    Java編輯器
    取消注釋
    Ctrl+\
    Java編輯器
    注釋
    Ctrl+/
    Java編輯器
    添加導入
    Ctrl+Shift+M
    Java編輯器
    組織導入
    Ctrl+Shift+O
    Java編輯器
    使用try/catch塊來包圍
    未設置,太常用了,所以在這里列出,建議自己設置。
    也可以使用Ctrl+1自動修正。
    ?
    運行
    作用域
    功能
    快捷鍵
    全局
    單步返回
    F7
    全局
    單步跳過
    F6
    全局
    單步跳入
    F5
    全局
    單步跳入選擇
    Ctrl+F5
    全局
    調試上次啟動
    F11
    全局
    繼續
    F8
    全局
    使用過濾器單步執行
    Shift+F5
    全局
    添加/去除斷點
    Ctrl+Shift+B
    全局
    顯示
    Ctrl+D
    全局
    運行上次啟動
    Ctrl+F11
    全局
    運行至行
    Ctrl+R
    全局
    執行
    Ctrl+U
    ?
    重構
    作用域
    功能
    快捷鍵
    全局
    撤銷重構
    Alt+Shift+Z
    全局
    抽取方法
    Alt+Shift+M
    全局
    抽取局部變量
    Alt+Shift+L
    全局
    內聯
    Alt+Shift+I
    全局
    移動
    Alt+Shift+V
    全局
    重命名
    Alt+Shift+R
    全局
    重做
    Alt+Shift+Y
    ?
    posted @ 2006-07-26 10:18 brock 閱讀(115) | 評論 (0)編輯 收藏

    僅列出標題
    共15頁: First 上一頁 7 8 9 10 11 12 13 14 15 下一頁 
    主站蜘蛛池模板: 十八禁的黄污污免费网站| 久久久久免费视频| 亚洲午夜无码片在线观看影院猛| 99精品视频在线观看免费| 99ri精品国产亚洲| 国产嫩草影院精品免费网址| 拍拍拍无挡免费视频网站| 亚洲综合无码无在线观看| 亚洲精品网站在线观看不卡无广告 | 精品免费视在线观看| 亚洲国产成人va在线观看网址| 国产男女猛烈无遮挡免费视频网站 | 亚洲国产精品13p| 91福利免费视频| 黄色一级毛片免费看| 91亚洲国产成人精品下载| 免费h黄肉动漫在线观看| 2020因为爱你带字幕免费观看全集| 噜噜综合亚洲AV中文无码| 亚洲人成电影在在线观看网色| 暖暖免费高清日本一区二区三区 | 国产精品免费观看调教网| 亚洲精品国产suv一区88| 亚洲电影一区二区三区| 国产免费牲交视频| 7723日本高清完整版免费| 国产精品综合专区中文字幕免费播放 | 边摸边吃奶边做爽免费视频99| 亚洲欧洲精品久久| 亚洲黄色免费网站| 无码欧精品亚洲日韩一区| 一个人免费高清在线观看| 18级成人毛片免费观看| 日韩在线不卡免费视频一区| 日本高清免费观看| 日韩精品无码专区免费播放| 免费观看91视频| 日韩av无码久久精品免费| 免费国产污网站在线观看15| 日韩内射激情视频在线播放免费| 一个人看的www免费视频在线观看|