zoukankan      html  css  js  c++  java
  • htmlparser源码简单分析

    Htmlparser源代码分析

    一.根目录下的类

    1.Attribute.java

    属性类,四个field:mName,mAssignment,mValue,mQuote;

    空白标签时:mName=null

    除了',"两引号和自定义参数字符表示的分隔号外,mQuote的值都以 char类型的0字符表示。

    其中的getName(StringBufferbuffer)等方法,意思是将所获得的结果存入buffer内。

    如果使用setRawValue()方法进行对mQuote,和,mValue赋值的时候,首尾都是双引号或者单引号则将单引号或双引号作为mQuote,字符串的其他部分作为mValue.如果首尾不同时为一种引号则对mQuote用双引号赋值,字符其他部分作为mValue.如果字符串中没有引号,并且所有字符都是由-,_,:,.和字母与数字组成,则mQuote会被用char类型的0赋值。即为空

    例如:

    "abcdefg"-------------------->mQuote:" mValue: abcdefg

    'abcdefg'---------------------->mQuote:' mValue: abcdefg

    'abcdefg"---------------------->mQuote:" mValue: 'abcdefg"

    abc-defg---------------------->mQuote:(空格) mValue: abc-defg

    如果字符串中有非首尾的引号或者只有首或者尾的引号,或者有除了-,_,:,.这几个符号以及数字和字母外的其他符号会被补上引号(字符串中没有单引号就补单引号,没有双引号就补双引号,如果都有则补双引号,并且字符串中的双引号被替换为")。

    例如:

    abc'de"fg---------------------->mQuote:" mValue: abc'de"fg

    &abcdefg--------------------->mQuote:" mValue: &abcdefg

    %a'bcd"efg-------------------->mQuote:" mValue: %a'bcd"efg

    %abcd"efg--------------------->mQuote:' mValue: %abcd"efg

    by 蛰伏神兽;http://hi.csdn.net/space-8079523.html;

    2.Node.java (interface) extendsCloneable

    StringtoPlainTextString();

    StringtoHtml();

    StringtoHtml(booleanverbatim);//如果verbatim为true相比上面一个会更接近源 page。但是通过这个工具库对这个方法的实现情况来看,以上三个方法完全一致verbatim并不起到任何作用。

    voidcollectInto(NodeListlist,NodeFilterfilter);

    //将这个Node以及它的所有子Node都用filter过滤器过滤后放入list.中

    intgetStartPosition();//获取该node的起始mPosition

    voidsetStartPosition();//设置

    voidaccept(NodeVisitorvisitor);//为这个node添加一个visitor

    voidsetParent();

    voidsetChildren(NodeListchildren);//还可以通过getLastChildren等等获取第一个或者最后一个child,但是设置就不可以。可以通过getPreviousSibling()这个node前后的兄弟姐妹node。

    voiddoSemanticAction();//Performthemeaningofthistag.执行这个标签的所表达的意思。执行该node(TagNode)的语义动作。

    3.NodeFactory (interface) Thisinterfacedefinesthemethodsneededtocreatenewnodes.

    Text creatStringNode(Pagepage,intstart,intend);//创建textnode

    Remark creatRemarkNode(Pagepage,intstart,intend);//创建remarknode

    Tag creatTagNode(Pagepage,intstart,intend,Vectorattributes);//创建tagnode

    Attributes为这个标签的所有属性

    4.PrototypicalNodeFactory

    这个类实现了NodeFactory接口,具备创建原型node的能力,这个类还有一个Map用来存储注册的各种Tag.

    5.Remark(interface)

    6.Text(interface)

    这个接口比较复杂,内容较多.因为html里面大都是Tag

    7.Tag (interface)

    这3个接口用来确定3种node的行为特征

    8.NodeFilter(interface) extends Serializable,Cloneable

    可序列化

    唯一一个方法boolean accept(Nodenode);决定是否保留所给的这个node

    即过滤器!

    9.Parser implements Serializable,ConnectionMonitor

    语义分析核心类,也是这个工具库的核心应用类

    二.http目录

    1.HttpHeader UtilitymethodstodisplayHTTPheaders.

    所有方法都是静态的。

    获取要发送请求的header:getRequestHeader(HttpURLConnectionconnection);static

    获取接受到的请求的headergetResponseHeader(HttpURLConnectionconn);static

    三.Lexer目录

    1.Page RepresentsthecontentsofanHTMLpage.

    用Source作为buffer存储结构用来存储数据

    Source与Reader类似。InputStreamSource与InputStreamReader类似。

    StringSource与StringReader类似。

    2.Cursor Abookmarkinapage.

    implementsSerializable,Ordered,Cloneable接口

    总共有2个Field:intmPosition;PagemPage;后者表示所在的页面,前者表示所在该页面中的具体position。Ordered接口排序是通过mPosition大小进行排序。

    这个类除了这两个Field的set/get方法外还有以下几个方法,功能如下:

    Voidadvance(); //mPosition++;向前进一步

    Voidretreat(); //mPosition--;后撤一步,当mPosition小于0的时候则令mPosition=0;

    Cursordup() ;//返回Cursor的克隆实例。如果不支持克隆就创建一个新的Cursor实例Field值与源实例相同。

    3.PageIndex Asortedarrayofintegers,thepositionsofthefirstcharactersofeachline.

    这个类的核心字段int[]mIndices;用来存储对应Page的每行的index和该行末尾字符的mPosition的值之间的对应关系

    除了一些对这个数组元素的普通操作方法之外还有row();和column();方法用来获取位置具体信息。elementAt(index);能够获取index表示的那一行最后一个字符的mPosition信息。

    4.PageAttribute (extendsAttribute)

    比Attribute多了5个Field,分别为mNameStart,mNameEndmValueStartmValueEnd;这4个字段作用于自身的Page字段。相对于Attribute类,我们可以通过mNameStart,mNameEnd来获取某个Attribute的name信息,我们可以通过mNameEnd,mValueStart来获取Attribute的Assignment信息,我们还可以通过mValueStart,mValueEnd来获取Attribute的value信息,当然这都是建立在Page存在的基础之上。如果page为null那么自然就无法根据这些字段来获取相应信息了。大体方法与Attribute一致。只不过在内部调用了super()而已。

    5.lexer ThisclassparsestheHTMLstreamintonodes(threetypeofnodes).{Remark,Text,Tag}

    四.Util目录

    1.NodeIterator

    接口,节点迭代器。有2个未实现方法

    booleanhasMoreNodes();

    NodenextNode();

    该迭代器的实现类:IteratorImpl

    该迭代器的继承接口:SimpleNodeIterator

    2.IteratorImpl

    3.ParserFeedback

    接口,Parser的反馈机制

    Info,error,warning

    4.DefaultParserFeedback

    ParserFeedback的默认实现类,可序列化。

    能表示3种模式,分别为QUIET,NORMAL,DEBUG

    无参数构造器默认构造为NORMAL模型

    5.FeedbackManager

    DefaultParserFeedback的一个代理

    6.Sort

    提供快速排序以及2分查找。

    7.CharacterReference

    实现序列化接口。实现Ordered接口,可用Sort进行排序和查找

    8.Translate

    Translatenumericcharacterreferencesandcharacterentityreferencestounicodecharacters.)

    Lookup();2分查找。decode()解码。encode()编码

    都为static方法。

    9.NodeList

    主要字段nodeData[],这个List中Node是存在数组中的

    添加node时可以选择add();也可以选择prepend();前者添加在尾部,后者添加在头部。可以获取部分Node:extractAllNodesThatMatch(NodeFilter,boolean);也可以保留一部分Node(源List中删除一些Node):keepAllNodesThatMatch(NodeFilter).

    10.NodeTreeWalker

    可以将Node集合构建成树形然后通过树形的方法来获取Node

    11.ParserUtil

    静态实用工具类

    1.removeChars(String,char),移除指定字符串中的字符

    2.removeEscapeCharacters(StringinputString);移除指定字符串中的' ',' ',' '字符

    3.removeTrailingBlanks(String);移除指定字符串末尾的空白符

    4.findTypeInNode(Node,Class);返回指定Node中所有符合Class的子类的数组

    5.splitButDigits(String,String);

    6.trimButDigits(String,String);除了数字和需要的字符集合以外的字符都清空

    7.trimButDigitsBeginEnd(String,String);和上一个差不多,只不过是取出头尾部分

    8.splitSpaces(String,String);trimSpaces(String,String);第二个参数是需要删除的而不 是保留的

    9.其他的和之前两个差不多,方法里面有But则第二个参数为需要保留的,否则为需 要删除的

    10.createParserParsingAnInputString(String);根据字符串返回parser

    五.Nodes目录

    1.AbstractNode (abstract) implementsNode,Serializable

    对Node接口中的抽象方法部分进行了简单实现。

    除了一下几个:

    StringtoPlainTextString();

    StringtoHtml(booleanverbatim);

    StringtoString();

    voidaccept(NodeVisitorvisitor);

    2.TextNode extendsAbstractNodeimplementsText

    对AbstractNode抽象类中的上述没有实现的方法进行了实现,其中toPlainTextString();与toHtml(booleanverbatim)与toHtml();3个方法等价。Verbatim

    不起作用

    主要方法:setText();getText();accept();

    3.RemarkNode extendsAbstractNodeimplementsRemark

    继承了AbstractNode实现了其中toPlainTextString();方法,但是只是返回一个空字符串;实现了toHtml(booleanverbatim)方法,verbatim仍然不起作用,这个方法返回的是html的注释形式:<!——mText——>其中mText为这个类的Field

    Accept()方法也被实现了,与TextNode实现之前的区别是visitor使用了与Text,Remark对应的不同的方法。

    4.TagNode extendsAbstractNodeimplementsTag

    Field:

    A).finalstaticString[]NONE;

    a)//Anemptysetoftagnames.

    B).ScannermScanner;

    a)//这个标签的扫描器

    C).finalstaticScannermDefaultScanner=newTagScanne();

    a)//非复合标签的默认扫描器

    D).VectormAttributes;

    a)//这个Tag的属性集合

    E).staticHashtablebreakTags;

    a)//Hashtable<K,V>,用来记录标签:

    static

    {

    breakTags=newHashtable(30);

    breakTags.put("BLOCKQUOTE",Boolean.TRUE);

    breakTags.put("BODY",Boolean.TRUE);

    breakTags.put("BR",Boolean.TRUE);

    breakTags.put("CENTER",Boolean.TRUE);

    breakTags.put("DD",Boolean.TRUE);

    breakTags.put("DIR",Boolean.TRUE);

    breakTags.put("DIV",Boolean.TRUE);

    breakTags.put("DL",Boolean.TRUE);

    breakTags.put("DT",Boolean.TRUE);

    breakTags.put("FORM",Boolean.TRUE);

    breakTags.put("H1",Boolean.TRUE);

    breakTags.put("H2",Boolean.TRUE);

    breakTags.put("H3",Boolean.TRUE);

    breakTags.put("H4",Boolean.TRUE);

    breakTags.put("H5",Boolean.TRUE);

    breakTags.put("H6",Boolean.TRUE);

    breakTags.put("HEAD",Boolean.TRUE);

    breakTags.put("HR",Boolean.TRUE);

    breakTags.put("HTML",Boolean.TRUE);

    breakTags.put("ISINDEX",Boolean.TRUE);

    breakTags.put("LI",Boolean.TRUE);

    breakTags.put("MENU",Boolean.TRUE);

    breakTags.put("NOFRAMES",Boolean.TRUE);

    breakTags.put("OL",Boolean.TRUE);

    breakTags.put("P",Boolean.TRUE);

    breakTags.put("PRE",Boolean.TRUE);

    breakTags.put("TD",Boolean.TRUE);

    breakTags.put("TH",Boolean.TRUE);

    breakTags.put("TITLE",Boolean.TRUE);

    breakTags.put("UL",Boolean.TRUE);

    }

    toPlainTextString();方法返回的是空字符串,和RemarkNode一样。toHtml()

    中的参数也和RemarkNode一样不起作用。这里有几个方法是需要注意区分

    getAttribute(Stringname);//通过属性名获取这个属性的值。

    getAttributeEx(Stringname)//通过属性名获取整个属性对象Attribute

    getAttributesEx();//获取所有属性对象Attributes,返回值是Vector

    ------------------------------------------------------------------------------------------

    String[]getIds();

    String[]getEnders();

    String[]getEndTagEnders();

    3者一致,返回的都是NONE字段,以后具体Tag类型的继承TagNode的时候会用各自的方法把它们覆盖掉。

    //原创地址:

    http://write.blog.csdn.net/postedit;转载请注明出处,蛰伏神兽

    六.Tags目录

    1.CompositeTag extendsTagNode

    Thebaseclassfortagsthathaveanendtag.

    这个类囊括了Tag标签的几乎所有操作。除了一般的获取孩子标签:children();getChild();;getChildrenAsNodeArray();elements();移除孩子标签:removeChild();将所有孩子以字符串形式返回toPlainTextString();或者以字符串形式导入到缓存buffer:putChildrenInto();获取具体位置的子标签Node:childAt();以及将所有孩子标签通过filter过滤器存入NodeList中:collectInto(NodeList,NodeFilter);等等方法外,还有些比较重要的方法:

    A).TagsearchByName(Stringname);

    //用来在孩子标签中查找拥有name(这个name是参数)属性的第一个标签。

    B).NodeListsearchFor(StringsearchString,booleancaseSensitive,Localelocale);

    //在孩子标签中查找包含searchString字符串的Node,并将这些Node都放入NodeList中,然后返回NodeList;

    C).intfindPositionOf(Stringtext,Localelocale);

    //返回在孩子标签中第一个包含text字符串的标签的具体位置(在NodeList中的Index位置,而不是Cursor类中那样的mPosition位置)

    D).Text[]digupStringNode(StringsearchText);

    //首先通过searchText找出子标签中包换这个字符串的所有标签。然后再从这些标签中挑出属于Text的节点组成Text[]返回

    这个类算是Tags目录中最重要的一个类。所有的复合标签都需要继承这个类。

    1.BodyTag===========>"BODY";//getBody();内部调用额是toPlainTextString();

    2.Bullet==============>"LI"

    3.BulletList===========>"UL","OL"

    4.Div===============>"DIV"

    5.HeadingTag=========>"H1","H2","H3","H4","H5","H6"

    6.HeadTag===========>"HEAD"

    7.Html==============>"HTML"

    8.InputTag===========>"INPUT"

    9.JspTag============>"%","%=","%@"

    10.LabelTag===========>"LABEL"

    11.ParagraphTag========>"P"

    12.ProcessingInstructionTag==>"?"

    13.SelectTag===========>"SELECT"

    14.Span===============>"SPAN"

    15.StyleTag============>"STYLE"

    16.TableColumn=========>"TD"

    17.TableHeader==========>"TH"

    18.TableRow============>"TR"

    19.TableTag===============>"TABLE"

    20.TextAreaTag============>"TEXTAREA"

    21.TitleTag================>"TITLE"

    22.DoctypeTag=============>"!DOCTYPE"

    23.DefinitionListBullet========>"DD","DT"

    24.DefinitionList=============>"DL"

    以上的24个标签都相对比较简单。内部有2个或者3个字段,之中一个String[]ids就是箭头右边的那个字符串。另外一个或者2个字段是终结各自的终结符。

    ----------------------------------------------------------------------------------------------------

    1.BaseHrefTag "BASE";

    //setBaseUrl();getBaseUrl();对href属性取赋值

    //对doSemanticAction()的实现也是如此:page.setBaseUrl(getBaseUrl());

    2.OptionTag "OPTION"

    //setValue();getValue();对value属性取赋值

    //getOptionText();通过调用toPlainTextString()实现

    3.FrameTag "FRAME"

    //setFrameLocation();getFrameLocation();对src属性取赋值

    4.FormTag "FORM"

    //有POST,GET两静态字段来表示FORM传递数据的方式

    //getFormInputs();抓取子标签中的所有InputTag并打包以NodeList返回。

    //getFormTextareas();抓取子标签中的所有TextAreaTag并打包以NodeList返回。

    //getFormMethod();对method属性取值

    //getFormName();对name属性取值

    //setFormLocation();getFormLocation();extractFormLocn()对action属性取赋值

    //getInputTag(Stringname);找出name属性为提供参数的InputTag.

    5.ImageTag "IMG"

    //字段imageUrl表示String类型的image地址

    //extractImageLocn();获取相对/绝对地址SRC的属性取值

    //getImageUrl();获取绝对地址SRC的属性取值

    //setImageUrl();设置绝对地址SRC的属性赋值

    6.FrameSetTag "FRAMESET"

    //getFrames(),setFrames();对该标签的孩子标签取赋值

    //getFrame(Stringname,Localelocale);通过名字从Tag孩子中找出符合要求的//FrameTag

    //原创地址:

    http://hi.csdn.net/space-8079523.html;转载请注明出处,蛰伏神兽

    7.MetaTag "META"

    //setHttpEquiv();getHttpEquiv();对HTTP-EQUIV属性的取赋值

    //setMetaTagContents();getMetaContent();对CONTENT属性的取赋值

    //setMetaTagName();getMetaTagName();对NAME属性的取赋值

    //doSemanticAction();的实现:(设置了一下编码)

    //if("Content-Type".equalsIgnoreCase(httpEquiv)){

    //charset=getPage().getCharset(getAttribute("CONTENT"));

    //getPage().setEncoding(charset);

    //}

    8.ScriptTag "SCRIPT"

    //字段mCode表示Script的编码

    //getLanguage();setLanguage();对LANGUAGE属性的取赋值

    //setType();getType();对TYPE属性的取赋值

    //putChildrenInto(StringBuffersb,booleanverbatim);把所有孩子节点都存入sb中.

    9.LinkTag "A"

    //字段mLink;表示这个link的URL值

    //字段mailLink,如果为true,则表示这个link为邮件地址

    //字段javascriptLink,如果为true,则表示这个link为javascript文件地址

    //getAccessKeyt();对ACCESSKEY属性的取值

    //extractLink();获取URL值

    //getLink();获取URL值,与上一个方法的区别是这个值将会把"mailto:","javascript:"

    //去掉。并且对mailLink或者javascriptLink字段进行设置。setLink();对href赋值

    //getLinkText();如果标签有孩子,就会返回所有孩子的字符串形式。

    //isFTPLink();isIRCLink();isHTTPLink();isHTTPSLink();isHTTPLikeLink();按字面意//思理解实现的话都是通过字符串匹配实现的。

    //其中isHTTPSLikeLink()=isHTTPSLink()||isHTTPLink();

    10.AppletTag "APPLET"

    //HashtablecreateAppletParamsTable();param标签的name属性和value属性

    //setAppletClass();getAppletClass();对CODE属性取赋值

    //setArchive();getArchive();对ARCHIVE属性取赋值

    //setCodeBase();getCodeBase();对CODEBASE属性取赋值

    11.ObjectTag"OBJECT"

    //setObjectClassId();getObjectClassId();对CLASSID属性的取赋值

    //setObjectCodeBase();getObjectCodeBase();对CODEBASE属性的取赋值

    //setObjectCodeType();getObjectCodeType();对CODETYPE属性的取赋值

    //setObjectData();getObjectData();对DATA属性的取赋值

    //setObjectHeight();getObjectHeight();对HEIGHT属性的取赋值

    //setObjectStandby();getObjectStandby();对STANDBY属性的取赋值

    //setObjectType();getObjectType();对TYPE属性的取赋值

    //setObjectWidth();getObjectWidth();对WIDTH属性的取赋值

    //setObjectParams();设置对象属性;

    七.filters目录

    这个目录中的类都实现了NodeFilter接口。这个接口只有一个方法accept(Nodenode);

    1.IsEqualFilter Thisclassacceptsonlyonespecificnode.

    booleanaccept(Nodenode);如果相等返回true,不相等返回false

    2.AndFilter Acceptsnodesmatchingallofitspredicatefilters(ANDoperation).

    //字段mPredicates存放被用于过滤的所有过滤器,这个类其实就是多个过滤

    //器的集合,只不过通过它需要通过所有mPredicates存放的过滤器而已。

    //当然他提供了相应的方法来获取和设置存储的过滤器

    3.OrFilter Acceptsnodesmatchinganyofitspredicatesfilters(ORoperation).

    //与AndFilter过滤器基本一致。只是accept()的实现中把false改成了true。功能显 //而易见

    4.NotFilter Acceptsallnodesnotacceptabletoit'spredicatefilter.

    //字段mPredicate 存放过滤器

    //accept();实现return((null!=mPredicate)&&!mPredicate.accept(node));

    5.XorFilter

    //和or基本一致,只是or是只需在所有filter里面有一个匹配就行,而xor则是需//要奇数个匹配。

    6.HasChildFilter//这个Node的孩子能够通过指定Filter

    7.HasParentFilter//这个Node的父亲能够通过指定Filter

    8.HasSiblingFilter//这个Node的兄弟能够通过指定Filter

    9.HasAttributeFilter//这个Node需要有指定的Attribute包括name,value

    10.NodeClassFilter

    //这个Node需要与指定class相关,就是说class可能是这个Node的父类//或者父接口的class,或者是这个类本身的class

    11.TagNameFilter

    //这个Node只有是TagNode,并且不是EndTag,并且是指定名字的才能通过

    12.LinkStringFilter

    //这个Node只有是LinkTag或者继承LinkTag的类,并且URL中需要包含指定字 //符串才能通过,可以设定大小写敏感

    13.LinkRegexFilter

    //有个PatternmRegex字段,存放需要匹配的Pattern

    //这个Node只有是LinkTag或者继承LinkTag的类,并且URL必须与给定的Pattern //匹配才能通过(部分匹配,使用的是Matcher的find()方法)。可以设置大小写敏感

    14.StringFilter

    //这个Node只有是Text,并且内容必须包含指定字符串才能通过,可以设置大小 //写敏感

    15.RegexFilter

    //有3中策略MATCH,LOOKINGAT,FIND.分别代表Matcher类的3个方法

    //Matcher.matches();匹配整个字符串

    //Matcher.lookingAt();从头开始匹配,如果匹配则true,不用扫描整个字符串

    //Matcher.find();只要有子序列匹配返回true

    16.CssSelectorNodeFilter

    //css选择器过滤器比较复杂,用到的时候再看。

    //原创地址:http://hi.csdn.net/space-8079523.html;转载请注明出处,蛰伏神兽

    八.visitors 这些visitor意思就是在给定的字符序列或者数组中查找需要的内容并且 记录找到的个数

    1.NodeVisitor

    //这个包的基础Visitor定义visitor的基本动作:

    //voidbeginParsing()

    //voidvisitTag(Tagtag)

    //voidvisitEndTag(Tagtag)

    //voidvisitStringNode(Textstring)

    //voidvisitRemarkNode(Remarkremark)

    //voidfinishedParsing()

    //以及两个递归的执行与否

    2.TagFindingVisitor

    //一个参数的构造器默认不检查结束标签(endTag)

    //在传入的一个待查找TagName数组中找出指定Tag以及这个Tag的个数(指定后//endTag也可以查)

    3.StringFindingVisitor

    //Field:

    //StringstringToFind;

    //boolean multipleSearchesWithinStrings;

    //visitorStringNode(Text stringNode);

    //在TextNode的text中查找stringToFind的个数

    //如果multipleSearchesWithinStrings字段为false那么一次只能查到一个,查到后立//即返回了.如果为True那么一次visitor就能把text包含的stringToFind都招出来例//如:stringToFind=aaa;

    Text=aaaaaaaaa;

    那么能找到3个。(注意不是7个)

    4.ObjectFindVisitor

    //查找与指定class一直的tag对象;一次比较一个tag对象

    5.LinkFindVisitor

    //和StringFindVisitor差不多只不过只能访问Tag对象

    6.TextExtractingVisitor

    //在Text中提取text内容

    7.UrlModifyingVisitor

    //给相应Node添加url前缀。

    8.HtmlPage

    //

    九.scanner目录

    1.Scanner (interface)

    publicTagscan(Tagtag,Lexerlexer,NodeListstack)throwsParserException;

    2.TagScanner

    //scan的实现:

    //tag.doSemanticAction();

    //returntag;

    3.JspScanner (extends)TagScanner

    //比前者多了一个无参数构造器

    4.StyleScanner

    //

    5.ScriptDecoder

    //为script解码

    因为小弟是初次使用htmlparser所有职能简单的分析源代码,也没有什么创新的见解。权当备案,以后用多了在来补充编辑。大家勿喷

  • 相关阅读:
    JavaWeb学习总结(五十)——文件上传和下载
    JavaWeb学习总结(四十九)——简单模拟Sping MVC
    JavaWeb学习总结(四十八)——模拟Servlet3.0使用注解的方式配置Servlet
    javaweb学习总结(四十七)——监听器(Listener)在开发中的应用
    javaweb学习总结(四十六)——Filter(过滤器)常见应用
    javaweb学习总结(四十五)——监听器(Listener)学习二
    javaweb学习总结(四十四)——监听器(Listener)学习
    javaweb学习总结(四十三)——Filter高级开发
    javaweb学习总结(四十二)——Filter(过滤器)学习
    javaweb学习总结(四十一)——Apache的DBUtils框架学习
  • 原文地址:https://www.cnblogs.com/Alex80/p/4973512.html
Copyright © 2011-2022 走看看