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

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

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

    2011年2月21日

    (轉(zhuǎn)貼)數(shù)據(jù)庫(kù)連接(內(nèi)連接,外連接,交叉連接)

    數(shù)據(jù)庫(kù)連接分為:內(nèi)連接,外連接(左、右連接,全連接),交叉連接
    文章地址 : http://www.zxbc.cn/html/20080527/51189.html
    轉(zhuǎn)載 
    內(nèi)連接:把兩個(gè)表中數(shù)據(jù)對(duì)應(yīng)的數(shù)據(jù)查出來(lái) 
    外連接:以某個(gè)表為基礎(chǔ)把對(duì)應(yīng)數(shù)據(jù)查出來(lái)(全連接是以多個(gè)表為基礎(chǔ)) 
    student表 
    no name 
    1     a 
    2     b 
    3     c 
    4     d 
    grade表 
    no grade 
    1     90 
    2     98 
    3     95 
    內(nèi)連接 inner join(查找條件中對(duì)應(yīng)的數(shù)據(jù),no4沒(méi)有數(shù)據(jù)不列出來(lái)) 
    語(yǔ)法:select * from student inner join grade on student.no = grade.no 
    結(jié)果 
    student.no name grade.no grade 
    1             a             1         90 
    2             b             2         98 
    3             c             3         95 
    左連接(左表中所有數(shù)據(jù),右表中對(duì)應(yīng)數(shù)據(jù)) 
    語(yǔ)法:select * from student left join grade on student.no = grade.no 
    結(jié)果: 
    student.no name grade.no grade 
    1                 a         1         90 
    2                 b         2         98 
    3                 c         3         95 
    4                 d     
    右連接(右表中所有數(shù)據(jù),左表中對(duì)應(yīng)數(shù)據(jù)) 
    語(yǔ)法:select * from student right join grade on student.no = grade.no 
    結(jié)果: 
    student.no name grade.no grade 
    1                 a         1         90 
    2                 b         2         98 
    3                 c         3         95 
    全連接 
    語(yǔ)法:select * from student full join grade on student.no = grade.no 
    結(jié)果: 
    no name grade 
    1     a     90 
    2     b     98 
    3     c     95 
    4     d 
    1     a     90 
    2     b     98 
    3     c     95 
    注:access 中不能直接使用full join ,需要使用union all 將左連接和右連接合并后才可以

    交叉連接
    將兩個(gè)表所有行組合,連接后的行數(shù)為兩個(gè)表行數(shù)的乘積(笛卡爾積)
    語(yǔ)法,借用上面的例子應(yīng)該是
    select * from student cross join grade

    行數(shù)應(yīng)該為12行 :
    no name grade 
    1     a     90 
    2     b     98 
    3     c     95 
    4     d  
    1     a     90 
    2     b     98 
    3     c     95 
    4     d 
    1     a     90 
    2     b     98 
    3     c     95 
    4     d 

    posted @ 2011-11-30 17:24 AK47 閱讀(489) | 評(píng)論 (0)編輯 收藏

    JAXB向Xml非根節(jié)點(diǎn)添加一個(gè)或多個(gè)屬性

    JAXB 向Xml非根節(jié)點(diǎn)添加一個(gè)或多個(gè)屬性,直接上代碼,關(guān)于JAXB的相關(guān)注解可查閱JAVA API。

    原創(chuàng)文章,轉(zhuǎn)載請(qǐng)注明出處。http://www.tkk7.com/kangdy/archive/2011/11/23/364635.html

    code1: colors類  根節(jié)點(diǎn)
    code1
    package com.kangdy.test;

    import javax.xml.bind.annotation.XmlAccessType;
    import javax.xml.bind.annotation.XmlAccessorType;
    import javax.xml.bind.annotation.XmlElement;
    import javax.xml.bind.annotation.XmlRootElement;

    @XmlRootElement(name = "Colors")
    @XmlAccessorType(XmlAccessType.FIELD)
    public class Colors {
        
        @XmlElement(name = "red",nillable=true)
        private Red red;
        
        @XmlElement(name = "blue",nillable=true)
        private Blue blue;

        public Red getRed() {
            return red;
        }

        public Blue getBlue() {
            return blue;
        }

        public void setRed(Red red) {
            this.red = red;
        }

        public void setBlue(Blue blue) {
            this.blue = blue;
        }
    }

    code2:  Red類  子節(jié)點(diǎn)
    code2package com.kangdy.test;

    import javax.xml.bind.annotation.XmlAccessType;
    import javax.xml.bind.annotation.XmlAccessorType;
    import javax.xml.bind.annotation.XmlAttribute;
    import javax.xml.bind.annotation.XmlRootElement;

    @XmlRootElement(name = "red")
    @XmlAccessorType(XmlAccessType.FIELD)
    public class Red {
        
        private String value;
        
        @XmlAttribute(name = "att1")
        private String att;
        
        public String getValue() {
            return value;
        }
        
        public void setValue(String value) {
            this.value = value;
        }

        public String getAtt() {
            return att;
        }

        public void setAtt(String att) {
            this.att = att;
        }
        
    }


    code3:  類 Blue 子節(jié)點(diǎn)
    code3
    package com.kangdy.test;

    import javax.xml.bind.annotation.XmlAccessType;
    import javax.xml.bind.annotation.XmlAccessorType;
    import javax.xml.bind.annotation.XmlAttribute;
    import javax.xml.bind.annotation.XmlRootElement;

    @XmlRootElement(name = "blue")
    @XmlAccessorType(XmlAccessType.FIELD)
    public class Blue {
        private String value;
        
        @XmlAttribute(name = "att2")
        private String att2;
        
        @XmlAttribute(name = "att1")
        private String att;
        
        public String getAtt() {
            return att;
        }

        public void setAtt(String att) {
            this.att = att;
        }

        public String getValue() {
            return value;
        }

        public void setValue(String value) {
            this.value = value;
        }

        public String getAtt2() {
            return att2;
        }

        public void setAtt2(String att2) {
            this.att2 = att2;
        }
    }

    code4: main類
    code4
    package com.kangdy.test;

    import java.io.StringWriter;

    import javax.xml.bind.JAXBContext;
    import javax.xml.bind.Marshaller;

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

            StringWriter writer = new StringWriter();
            JAXBContext jc = JAXBContext.newInstance(Colors.class);
            Marshaller ma = jc.createMarshaller();
            ma.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
            
            Colors colors = new Colors();
            Red red = new Red();
            red.setAtt("att-red");
            red.setValue("red");
            Blue blue = new Blue();
            blue.setValue("blue");
            blue.setAtt("att-blue");
            blue.setAtt2("blue-att2");
            colors.setRed(red);
            colors.setBlue(blue);
            
            ma.marshal(colors, writer);
            System.out.println(writer.toString());

        }
    }

    運(yùn)行結(jié)果:
    結(jié)果
    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <Colors>
        <red att1="att-red">
            <value>red</value>
        </red>
        <blue att1="att-blue" att2="blue-att2">
            <value>blue</value>
        </blue>
    </Colors>

    posted @ 2011-11-23 14:33 AK47 閱讀(10126) | 評(píng)論 (4)編輯 收藏

    (轉(zhuǎn)載)關(guān)于paramsPrepareParamsStack

    原帖地址:
    http://hi.baidu.com/%CC%AB%C6%BD%D1%F31986/blog/item/110b13b1384e805e08230259.html
    轉(zhuǎn)貼

    paramsPrepareParamsStack在Struts 2.0中是一個(gè)很奇妙的interceptor stack,以至于很多人疑問(wèn)為何不將其設(shè)置為默認(rèn)的interceptor stack。paramsPrepareParamsStack主要解決了ModelDriven和Preparable的配合問(wèn)題,從字面上理解來(lái)說(shuō), 這個(gè)stack的攔截器調(diào)用的順序?yàn)椋菏紫萷arams,然后prepare,接下來(lái)modelDriven,最后再params。Struts 2.0的設(shè)計(jì)上要求modelDriven在params之前調(diào)用,而業(yè)務(wù)中prepare要負(fù)責(zé)準(zhǔn)備model,準(zhǔn)備model又需要參數(shù),這就需要在 prepare之前運(yùn)行params攔截器設(shè)置相關(guān)參數(shù),這個(gè)也就是創(chuàng)建paramsPrepareParamsStack的原因。流程如下:
       1. params攔截器首先給action中的相關(guān)參數(shù)賦值,如id  
       2. prepare攔截器執(zhí)行prepare方法,prepare方法中會(huì)根據(jù)參數(shù),如id,去調(diào)用業(yè)務(wù)邏輯,設(shè)置model對(duì)象
       3. modelDriven攔截器將model對(duì)象壓入value stack,這里的model對(duì)象就是在prepare中創(chuàng)建的
       4. params攔截器再將參數(shù)賦值給model對(duì)象
       5. action的業(yè)務(wù)邏輯執(zhí)行 依據(jù)此stack,一個(gè)action的代碼通常如下

    public class UserAction extends ActionSupport implements ModelDriven, Preparable {
        private User user;
        private int id;
        private UserService service; // user business service

        public void setId(int id) {
            this.id = id;
        }

        /**
         * create a new user if none exists, otherwise load the user with the
         * specified id
         */
        public void prepare() throws Exception {
            if (id == 0) {
                user = new User();
            } else {
                user = service.findUserById(id);
            }
        }

        public Object getModel() {
            return user;
        }

        /**
         * create or update the user and then view the created user
         */
        public String update() {
            if (id == 0) {
                service.create(user);
            } else {
                service.update(user);
            }
            return "redirect";
        }

        /**
         * delete the user and go to a default home page
         */
        public String delete() {
            service.deleteById(id);
            return "home";
        }

        /**
         * show the page allowing the user to view the existing data
         */
        public String view() {
            return "view";
        }

        /**
         * show the page allowing the user to view the existing data and change the
         * values
         */
        public String edit() {
            return "input";
        }

    在上述代碼中,edit和view都不需要根據(jù)id再為界面準(zhǔn)備數(shù)據(jù),因?yàn)閜repare方法已經(jīng)準(zhǔn)備好了model,這些方法很簡(jiǎn)單。對(duì)于update 方法,prepare首先會(huì)從數(shù)據(jù)庫(kù)中加載數(shù)據(jù),然后params攔截器會(huì)將參數(shù)值付給model,在update直接更新就可以,不會(huì)出現(xiàn)數(shù)據(jù)被亂更新 的情況。象Hibernate框架,會(huì)判斷哪些字段更新了,然后進(jìn)行更新,性能也不會(huì)損失。
    通過(guò)paramsPrepareParamsStack可以讓流程更明確,代碼更簡(jiǎn)潔,也更利于大家的交流。

    posted @ 2011-11-16 15:39 AK47 閱讀(439) | 評(píng)論 (0)編輯 收藏

    (轉(zhuǎn)載) Struts 2雜談(1):ValueStack對(duì)象的傳送帶機(jī)制

    Struts 2雜談(1):ValueStack對(duì)象的傳送帶機(jī)
    作者:nokiaguy  原文地址:http://blog.csdn.net/nokiaguy/article/details/4684750
    轉(zhuǎn)貼
       眾所周知,Strut 2的Action類通過(guò)屬性可以獲得所有相關(guān)的值,如請(qǐng)求參數(shù)、Action配置參數(shù)、向其他Action傳遞屬性值(通過(guò)chain結(jié)果)等等。要獲得 這些參數(shù)值,我們要做的唯一一件事就是在Action類中聲明與參數(shù)同名的屬性,在Struts 2調(diào)用Action類的Action方法(默認(rèn)是execute方法)之前,就會(huì)為相應(yīng)的Action屬性賦值。
        要完成這個(gè)功能,有很大程度上,Struts 2要依賴于ValueStack對(duì)象。這個(gè)對(duì)象貫穿整個(gè)Action的生命周期(每個(gè)Action類的對(duì)象實(shí)例會(huì)擁有一個(gè)ValueStack對(duì)象)。當(dāng) Struts 2接收到一個(gè).action的請(qǐng)求后,會(huì)先建立Action類的對(duì)象實(shí)例,并且將Action類的對(duì)象實(shí)例壓入ValueStack對(duì)象中(實(shí)際 上,ValueStack對(duì)于相當(dāng)一個(gè)棧),而ValueStack類的setValue和findValue方法可以設(shè)置和獲得Action對(duì)象的屬性 值。Struts 2中的某些攔截器正是通過(guò)ValueStack類的setValue方法來(lái)修改Action類的屬性值的。如params攔截器用于將請(qǐng)求參數(shù)值映射到相 應(yīng)成Action類的屬性值。在params攔截器中在獲得請(qǐng)求參數(shù)值后,會(huì)使用setValue方法設(shè)置相應(yīng)的Action類的屬性。
        從這一點(diǎn)可以看出,ValueStack對(duì)象就象一個(gè)傳送帶,當(dāng)客戶端請(qǐng)求.action時(shí),Struts 2在創(chuàng)建相應(yīng)用Action對(duì)象后就將Action對(duì)象放到了ValueStack傳送帶上,然后ValueStack傳送帶會(huì)帶著Action對(duì)象經(jīng)過(guò) 若干攔截器,在每一攔截器中都可以通過(guò)ValueStack對(duì)象設(shè)置和獲得Action對(duì)象中的屬性值。實(shí)際上,這些攔截器就相當(dāng)于流水線作業(yè)。如果要對(duì) Action對(duì)象進(jìn)行某項(xiàng)加工,再加一個(gè)攔截器即可,當(dāng)不需要進(jìn)行這項(xiàng)工作時(shí),直接將該攔截器去掉即可。
        下面我們使用一個(gè)例子來(lái)演示這個(gè)過(guò)程。在這個(gè)例子中實(shí)現(xiàn)了一個(gè)攔截器,該攔截器的功能是將一個(gè)屬性文件中的key-value對(duì)映射成相應(yīng)的屬性的值。如下面是一個(gè)屬性文件的內(nèi)容:

        name = 超人
        price = 10000

        我們可以在Action類中定義name和price屬性,在Action中引用這個(gè)攔截器后,就會(huì)自動(dòng)為屬性賦值。
        在使用該攔截器有如下規(guī)則:
        1.  攔截器讀取的屬性文件路徑由path參數(shù)指定。
        2.  屬性文件的編碼格式由encoding參數(shù)指定,默認(rèn)值是UTF-8。
        3.  如果某個(gè)key中包含有“.”(該符號(hào)不能出現(xiàn)在標(biāo)識(shí)符中),則有如下處理方法:
        (1)將Action類的屬性名定義為去掉“.”的key。例如,key為person.name,而屬性名可定義為personname。
        (2)將Action類的屬性名定義為將“.”替換成其他字符的表示符號(hào)。例如,key為person.name,而屬性名可定義為person_name,其中“_”由separator參數(shù)指定。
        4.  如果key太長(zhǎng),也可以直接使用Action參數(shù)進(jìn)行映射,例如,key為country.person.name,可做如下映射:
          <param name="countrypersonname">name</param>
          要注意的是,name屬性值不能包含“.”,因此,應(yīng)將key值中的“.”去掉。現(xiàn)在就可以直接在Action類中定義名為name的屬性的,name屬性的值會(huì)與key值相同。
        5.  上面所有的規(guī)則可以同時(shí)使用。

    攔截器的源代碼:

    package interceptors;

    import java.util.Enumeration;
    import java.util.Map;
    import java.util.Properties;
    import java.io.InputStream;
    import java.io.FileInputStream;
    import com.opensymphony.xwork2.ActionContext;
    import com.opensymphony.xwork2.ActionInvocation;
    import com.opensymphony.xwork2.config.entities.ActionConfig;
    import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
    import com.opensymphony.xwork2.util.ValueStack;

    public class PropertyInterceptor extends AbstractInterceptor
    {
        
    private static final String DEFAULT_PATH_KEY = "path";
        
    private static final String DEFAULT_ENCODING_KEY = "encoding";
        
    private static final String DEFAULT_SEPARATOR_KEY = "separator";

        
    protected String pathKey = DEFAULT_PATH_KEY;
        
    protected String encodingKey = DEFAULT_ENCODING_KEY;
        
    protected String separatorKey = DEFAULT_SEPARATOR_KEY;

        
    public void setPathKey(String pathKey) 
        {
            
    this.pathKey = pathKey;
        }

        
    public void setEncodingKey(String encodingKey)
        {
            
    this.encodingKey = encodingKey;
        }

        
    public void setSeparatorKey(String separatorKey)
        {
            
    this.separatorKey = separatorKey;
        }

        @Override
        
    public String intercept(ActionInvocation invocation) throws Exception
        {
            ActionConfig config 
    = invocation.getProxy().getConfig();

            Map
    <String, String> parameters = config.getParams();
            
    if (parameters.containsKey(pathKey))
            {
                String path 
    = parameters.get(pathKey);
                String encoding 
    = parameters.get(encodingKey);
                String separator 
    = parameters.get(separatorKey);
                
    if (encoding == null)
                    encoding 
    = "UTF-8";
                
    if (separator == null)
                    separator 
    = "";
                path 
    = invocation.getAction().getClass().getResource(path)
                        .getPath();
                Properties properties 
    = new Properties();
                InputStream is 
    = new FileInputStream(path);
                java.io.Reader reader 
    = new java.io.InputStreamReader(is, encoding);
                
                properties.load(reader);
                ActionContext ac 
    = invocation.getInvocationContext();
                ValueStack stack 
    = ac.getValueStack();
                System.out.println(stack.hashCode());
                Enumeration names 
    = properties.propertyNames();
                
    while (names.hasMoreElements())
                {
                    
    //  下面會(huì)使用setValue方法修改ValueStack對(duì)象中的相應(yīng)屬性值
                    String name = names.nextElement().toString();
                    
    if (!name.contains("."))
                        stack.setValue(name, properties.get(name)); 

                    String newName 
    = null;
                    newName 
    = parameters.get(name.replaceAll("//."""));
                    
    if (newName != null)
                        stack.setValue(newName, properties.get(name));

                    
    if (!separator.equals(""))
                    {
                        newName 
    = name.replaceAll("//.""");
                        stack.setValue(newName, properties.get(name));
                    }               
                    newName 
    = name.replaceAll("//.", separator);
                    stack.setValue(newName, properties.get(name));
                } 
            }
            
    return invocation.invoke();
        }
    }

    用于測(cè)試的Action類的源代碼:

    package actions;

    public class MyAction
    {
        
    private String name;
        
    private Integer price;
        
    private String log4jappenderstdout;
        
    private String log4j_rootLogger;
        
    private String conversionPattern;

        
    public String getName()
        {
            
    return name;
        }

        
    public void setName(String name)
        {
            
    this.name = name;
        }

        
    public Integer getPrice()
        {
            
    return price;
        }

        
    public void setPrice(Integer price)
        {
            
    this.price = price;
        }

        
    public String getLog4jappenderstdout()
        {
            
    return log4jappenderstdout;
        }

        
    public void setLog4jappenderstdout(String log4jappenderstdout)
        {
            
    this.log4jappenderstdout = log4jappenderstdout;
        }

        
    public String getLog4j_rootLogger()
        {
            
    return log4j_rootLogger;
        }

        
    public void setLog4j_rootLogger(String log4j_rootLogger)
        {
            
    this.log4j_rootLogger = log4j_rootLogger;
        }

        
    public String getConversionPattern()
        {
            
    return conversionPattern;
        }

        
    public void setConversionPattern(String conversionPattern)
        {
            
    this.conversionPattern = conversionPattern;
        }

        
    public String execute()
        {
            System.out.println(
    "name:" + name);
            System.out.println(
    "price:" + price);
            System.out.println(
    "log4jappenderstdout:" + log4jappenderstdout);
            System.out.println(
    "log4j_rootLogger:" + log4j_rootLogger);
            System.out.println(
    "conversionPattern:" + conversionPattern);
            
    return null;
        }
    }

    Action類的配置代碼如:

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN"
        "http://struts.apache.org/dtds/struts-2.1.dtd"
    >
    <struts>
        
    <package name="struts" extends="struts-default">

            
    <interceptors>
                
    <interceptor name="property"
                    class
    ="interceptors.PropertyInterceptor" />
                
    <interceptor-stack name="myStack">
                    
    <interceptor-ref name="defaultStack" />
                    
    <interceptor-ref name="property" />
                
    </interceptor-stack>
            
    </interceptors>
            
    <action name="test" class="actions.MyAction">
                
    <interceptor-ref name="myStack" />
                
    <param name="path">/log4j.properties</param>
                
    <param name="encoding">UTF-8</param>
                
    <param name="separator">_</param>
                
    <param name="log4jappenderstdoutlayoutConversionPattern">
                    conversionPattern
                
    </param>

            
    </action>
        
    </package>
    </struts>

      請(qǐng)將log4j.properties文件復(fù)制到WEB-INF/classes目錄,并在該文件中加入name和price屬性。

    測(cè)試結(jié)果:

    name:中國(guó)
    price:
    34
    log4jappenderstdout:org.apache.log4j.ConsoleAppender
    log4j_rootLogger:error
    , stdout
    conversionPattern:%d{ABSOLUTE} %5p %c{
    1}:%L - %m%n

        由于property攔截器在defaultStack后引用,因此,在該攔截器中設(shè)置的屬性值是最終結(jié)果,如果將property攔截器放在 defaultStack前面(將兩個(gè)<interceptor-ref>元素掉換一下),就可以通過(guò)同名勝Action配置參數(shù)或請(qǐng)求參數(shù) 來(lái)干預(yù)最終究輸出結(jié)果了。

    posted @ 2011-11-11 17:21 AK47 閱讀(372) | 評(píng)論 (0)編輯 收藏

    (轉(zhuǎn)貼)Struts2數(shù)據(jù)傳輸?shù)谋澈髾C(jī)制:ValueStack(值棧)

         摘要: (轉(zhuǎn))Struts2數(shù)據(jù)傳輸?shù)谋澈髾C(jī)制:ValueStack(值棧)原文地址 :http://blog.csdn.net/li_tengfei/article/details/6098134轉(zhuǎn)載 1.     數(shù)據(jù)傳輸背后機(jī)制:ValueStack(值棧)   在這一切的背后,是因?yàn)橛辛薞alueStack(值棧)!   Valu...  閱讀全文

    posted @ 2011-11-11 16:19 AK47 閱讀(818) | 評(píng)論 (0)編輯 收藏

    structs2配置UrlRewriteFilter

    轉(zhuǎn)載每個(gè)網(wǎng)頁(yè)或請(qǐng)求都是一個(gè)url地址,一般,這個(gè)地址可能是.do,.page,.action之類的并加上'?'號(hào)、'&'號(hào)查詢串等構(gòu)成的一個(gè)長(zhǎng)長(zhǎng)的的url。很urgly。

    一般的url----------------------------------------------------------較好的url
    http://www.xxx.net/user/profile.do?id=20001   ====> http://www.xxx.net/user/20001
    http://www.xxx.net/forum/board.do?name=java   ====> http://www.xxx.net/forum/java
    http://www.xxx.net/forum/thread.do?id=29923   ====> http://www.xxx.net/thread/29923

    后者明顯較為直觀和漂亮。

    使用url rewrite可以很好的改善這個(gè)狀況。網(wǎng)站url rewrite應(yīng)用是非常廣泛的,良好的url設(shè)計(jì)給用戶帶來(lái)的非常好的體驗(yàn),同時(shí)也能吸引搜索引擎的注意。
    原文地址:http://www.iteye.com/topic/53834
    使用方式:
    1 配置web.xml文件
    樣例:
        <listener>
            <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
        </listener>
        <filter>
            <filter-name>encodingFilter</filter-name>
            <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
            <init-param>
                <param-name>encoding</param-name>
                <param-value>UTF-8</param-value>
            </init-param>
        </filter>
        <filter-mapping>
            <filter-name>encodingFilter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
        <filter>
            <filter-name>osivFilter</filter-name>
            <filter-class>
                org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
        </filter>
        <listener>
            <listener-class>
                org.springframework.web.context.request.RequestContextListener</listener-class>
        </listener>
        <filter-mapping>
            <filter-name>osivFilter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
        <!--配置UrlRewriteFilter過(guò)濾器-->
        <filter>
            <filter-name>UrlRewriteFilter</filter-name>
            <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
        </filter>
        <filter-mapping>
            <filter-name>UrlRewriteFilter</filter-name>
            <url-pattern>*.html</url-pattern>
            <dispatcher>REQUEST</dispatcher>
            <dispatcher>FORWARD</dispatcher>
            <dispatcher>INCLUDE</dispatcher>
        </filter-mapping>
        <filter>
            <filter-name>struts-prepare</filter-name>
            <filter-class>
                org.apache.struts2.dispatcher.ng.filter.StrutsPrepareFilter</filter-class>
            <init-param>
                <param-name>actionPackages</param-name>
                <param-value>com.secneo.action.*.*</param-value>
            </init-param>
        </filter>
        <filter>
            <filter-name>struts2</filter-name>
            <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
        </filter>

        <filter>
            <filter-name>struts-execute</filter-name>
            <filter-class>
                org.apache.struts2.dispatcher.ng.filter.StrutsExecuteFilter</filter-class>
        </filter>
        <filter>
            <filter-name>struts-cleanup</filter-name>
            <filter-class>org.apache.struts2.dispatcher.ActionContextCleanUp</filter-class>
        </filter>
        <filter-mapping>
            <filter-name>struts2</filter-name>
            <url-pattern>*.jsp</url-pattern>
        </filter-mapping>
        <!--在structs2中使用UrlRewriteFilter過(guò)濾器-->
        <filter-mapping>
            <filter-name>struts2</filter-name>
            <url-pattern>*.action</url-pattern>
            <dispatcher>REQUEST</dispatcher>
            <dispatcher>FORWARD</dispatcher>
            <dispatcher>INCLUDE</dispatcher>
        </filter-mapping>
        <filter-mapping>
            <filter-name>struts2</filter-name>
            <url-pattern>*.tld</url-pattern>
        </filter-mapping>
        <filter-mapping>
            <filter-name>struts2</filter-name>
            <url-pattern>*.tag</url-pattern>
        </filter-mapping>

        <filter-mapping>
            <filter-name>struts-prepare</filter-name>
            <url-pattern>*.jsp</url-pattern>
        </filter-mapping>
        <filter-mapping>
            <filter-name>struts-prepare</filter-name>
            <url-pattern>*.action</url-pattern>
        </filter-mapping>
        <filter-mapping>
            <filter-name>struts-prepare</filter-name>
            <url-pattern>*.tld</url-pattern>
        </filter-mapping>

        <filter-mapping>
            <filter-name>struts-execute</filter-name>
            <url-pattern>*.jsp</url-pattern>
        </filter-mapping>
        <filter-mapping>
            <filter-name>struts-execute</filter-name>
            <url-pattern>*.action</url-pattern>
        </filter-mapping>
        <filter-mapping>
            <filter-name>struts-execute</filter-name>
            <url-pattern>*.tld</url-pattern>
        </filter-mapping>

        <filter-mapping>
            <filter-name>struts-cleanup</filter-name>
            <url-pattern>*.jsp</url-pattern>
        </filter-mapping>
        <filter-mapping>
            <filter-name>struts-cleanup</filter-name>
            <url-pattern>*.action</url-pattern>
        </filter-mapping>
        <filter-mapping>
            <filter-name>struts-cleanup</filter-name>
            <url-pattern>*.tld</url-pattern>
        </filter-mapping>
        <listener>
            <listener-class>
                org.springframework.web.util.IntrospectorCleanupListener</listener-class>
        </listener>
    2  在WEB-INF目錄下添加urlrewrite.xml 文件,根據(jù)具體需要寫(xiě)規(guī)則
    樣例:
    <?xml version="1.0" encoding="utf-8"?>
    <urlrewrite>
        <rule>
            <from>^/(.*).html$</from>
            <to type="forward">/$1.action</to>
        </rule>
        <rule>
            <from>^/(.*).html?(.*)$</from>
            <to type="forward">/$1.action?$2</to>
        </rule>
    </urlrewrite>

    posted @ 2011-11-09 17:22 AK47 閱讀(1776) | 評(píng)論 (0)編輯 收藏

    structs2 filter的執(zhí)行順序

    根據(jù)servlet2.3規(guī)范filter執(zhí)行是按照web.xml配置的filter-mapping先后順序進(jìn)行執(zhí)行。
    所以自己配置的過(guò)濾器放在structs2的過(guò)濾器之前。

    posted @ 2011-11-09 15:44 AK47 閱讀(374) | 評(píng)論 (0)編輯 收藏

    structs2攔截器

    深入struct2攔截器  這篇文章很好,細(xì)致講解了structs2和攔截器的原理。
    http://zhanghong.iteye.com/blog/452465
    轉(zhuǎn)載在每次對(duì)你的 Action的 execute()方法請(qǐng)求時(shí),系統(tǒng)會(huì)生成一個(gè) ActionInvocation對(duì)象,這個(gè)對(duì)象保存了 action和你所配置的所有的攔截器以及一些狀態(tài)信息。比如你的應(yīng)用使用的是 defaultStack,系統(tǒng)將會(huì)以攔截器棧配置的順序?qū)⒚總€(gè)攔截器包裝成一個(gè)個(gè) InterceptorMapping(包含攔截器名字和對(duì)應(yīng)的攔截器對(duì)象 )組成一個(gè) Iterator保存在 ActionInvocation中。在執(zhí)行 ActionInvocation的 invoke()方法時(shí)會(huì)對(duì)這個(gè) Iterator進(jìn)行迭代,每次取出一個(gè) InterceptorMapping,然后執(zhí)行對(duì)應(yīng) Interceptor的 intercept(ActionInVocation inv)方法,而 intercept(ActionInInvocation inv)方法又包含當(dāng)前的 ActionInInvcation對(duì)象作為參數(shù),而在每個(gè)攔截器中又會(huì)調(diào)用 inv的 invoke()方法,這樣就會(huì)進(jìn)入下一個(gè)攔截器執(zhí)行了,這樣直到最后一個(gè)攔截器執(zhí)行完,然后執(zhí)行 Action的 execute()方法 (假設(shè)你沒(méi)有配置訪問(wèn)方法,默認(rèn)執(zhí)行 Action的 execute()方法 )。在執(zhí)行完 execute()方法取得了 result后又以相反的順序走出攔截器棧,這時(shí)可以做些清理工作。最后系統(tǒng)得到了一個(gè) result,然后根據(jù) result的類型做進(jìn)一步操作。

    配置攔截器:Struts2中提供了大量的攔截器,多個(gè)攔截器可以組成一個(gè)攔截器棧,系統(tǒng)配置了一個(gè)默認(rèn)的攔截器棧 defaultStack,具體包括那些攔截器以及順序可以在struts-default.xml中找到。
    1)
    <package name="default" extends="struts-default">
       <interceptors>
           <interceptor name="timer" class=".."/>
           <interceptor name="logger" class=".."/>
       </interceptors>

       <action name="login"
          class="tutorial.Login">
            <interceptor-ref name="timer"/>
            <interceptor-ref name="logger"/>
             <result name="input">login.jsp</result>
             <result name="success"
                type="redirectAction">/secure/home</result>
       </action>
    </package>

    2)
    <package name="default" extends="struts-default">
       <interceptors>
            <interceptor name="timer" class=".."/>
            <interceptor name="logger" class=".."/>
            <interceptor-stack name="myStack">
               <interceptor-ref name="timer"/>
               <interceptor-ref name="logger"/>
           <interceptor-ref name="defaultStack"/>    
            </interceptor-stack>
        </interceptors>

    <action name="login"
         class="tutuorial.Login">
             <interceptor-ref name="myStack"/>
             <result name="input">login.jsp</result>
             <result name="success"
                 type="redirectAction">/secure/home</result>
    </action>
    </package>

    攔截器執(zhí)行順序:
    <interceptor-stack name="xaStack">
      <interceptor-ref name="thisWillRunFirstInterceptor"/>
      <interceptor-ref name="thisWillRunNextInterceptor"/>
      <interceptor-ref name="followedByThisInterceptor"/>
      <interceptor-ref name="thisWillRunLastInterceptor"/>
    </interceptor-stack>

    執(zhí)行順序:
    thisWillRunFirstInterceptor
      thisWillRunNextInterceptor
        followedByThisInterceptor
          thisWillRunLastInterceptor
            MyAction1
            MyAction2 (chain)
            MyPreResultListener
            MyResult (result)
          thisWillRunLastInterceptor
        followedByThisInterceptor
      thisWillRunNextInterceptor
    thisWillRunFirstInterceptor


    自定義攔截器:必須實(shí)現(xiàn) com.opensymphony.xwork2.interceptor.Interceptor 也可以繼承 AbstractInterceptor

    攔截器要保證線程安全。因?yàn)閟tructs2中攔截器會(huì)在請(qǐng)求間共享

    posted @ 2011-11-08 18:35 AK47 閱讀(1443) | 評(píng)論 (0)編輯 收藏

    (轉(zhuǎn)貼)struts2 工作原理圖

         摘要: 原貼地址:http://blog.csdn.net/qjyong/article/details/1795833轉(zhuǎn)貼 最近學(xué)習(xí)struts2,其實(shí)它就是webwork2.2的升級(jí)版,現(xiàn)附上原理圖 上圖來(lái)源于Struts2官方站點(diǎn),是Struts 2 的整體結(jié)構(gòu)。一個(gè)請(qǐng)求在Struts2框架中的處理大概分為以下幾個(gè)步驟1 客戶端初始化一個(gè)指向Servlet容器(例如Tomcat)的請(qǐng)求2 ...  閱讀全文

    posted @ 2011-11-08 15:10 AK47 閱讀(1636) | 評(píng)論 (0)編輯 收藏

    重新認(rèn)識(shí)Java finally

    關(guān)于java finally 網(wǎng)上有2篇文章個(gè)人認(rèn)為相當(dāng)不錯(cuò)
    以下是轉(zhuǎn)貼內(nèi)容:

    1 . JAVA finally字句的異常丟失和返回值覆蓋解析
    原帖地址 :
    http://blog.csdn.net/sureyonder/article/details/5560538
    轉(zhuǎn)貼
    Java虛擬機(jī)在每個(gè)try語(yǔ)句塊和與其相關(guān)的catch子句的結(jié)尾 處都會(huì)“調(diào)用”finally子句的子例程。實(shí)際上,finally子句在方法內(nèi)部的表現(xiàn)很象“微型子例程”。finally子句正常結(jié)束后-指的是finally子句中最后一條語(yǔ)句正常執(zhí)行完畢,不包括拋出異常,或執(zhí)行return、continue、break等情況,隸屬于這個(gè)finally子句的微型子例程執(zhí)行“返回”操作。程序在第一次調(diào)用微型子例程的地方繼續(xù)執(zhí)行后面的語(yǔ)句。

    finally“微型子例程”不等同于方法函數(shù)的調(diào)用,finally子句都是在同一個(gè)棧內(nèi)執(zhí)行的,微型子例程的“返回”操作也不會(huì)涉及到方法退棧,僅僅是使程序計(jì)數(shù)器pc跳轉(zhuǎn)到同一個(gè)方法的一個(gè)不同的位置繼續(xù)執(zhí)行。
    一 異常丟失
        public static void exceptionLost()  
         {  
           try  
           {  
             try  
             {  
               throw new Exception( "exception in try" );  
             }  
             finally  
             {  
               throw new Exception( "exception in finally" );  
             }  
           }  
           catch( Exception e )  
           {  
             System.out.println( e );  
           }  
         }  

    exceptionLost()的輸出結(jié)果是“exception in finally”,而不是try塊中拋出的異常,這是JAVA異常機(jī)制的一個(gè)瑕疵-異常丟失。

    在字節(jié)碼中,throw語(yǔ)句不是原子性操作。在較老的JDK中,exceptionLost()中try塊的throw語(yǔ)句分解為幾步操作:
    1) 把Exception("exception in try")對(duì)象引用存儲(chǔ)到一個(gè)局部變量中
      astore_2  // pop the reference to the thrown exception, store into local variable 2
    2) 調(diào)用finally微型子程序
    3) 把局部變量中的Exception("exception in try")對(duì)象引用push到操作數(shù)棧頂,然后拋出異常
      aload_2  // push the reference to the thrown exception from local variable 2

      athrow   // throw the exception

    如果finally通過(guò)break、return、continue,或者拋出異常而退出,那么上面的第3步就不會(huì)執(zhí)行。

    在JDK1.6中,通過(guò)字節(jié)碼我們可以看到,finally子句作為一種特殊的catch來(lái)實(shí)現(xiàn)的,下面是exceptionLost()方法的異常表:

    Exception table:
      from   to   target  type
       0     10    10     any
     0     21    21     Class java/lang/Exception

    finally可以捕獲從0行到9行之間拋出的任何類型(any)的異常,并重新拋出捕獲的異常,或者拋出一個(gè)自己構(gòu)造的新異常,這個(gè)新異常就會(huì)覆蓋try語(yǔ)句塊中的異常。
    二 返回值覆蓋

        public static int getValue()  
         {  
           int value = 0;  
             
           try  
           {  
             value = 100;  
               
             return value;  
           }  
           finally  
           {  
             value = 200;  
           }  
         }  

    這個(gè)方法的返回值是100還是200?結(jié)果是100。
    在字節(jié)碼中,return語(yǔ)句不是原子性操作,它會(huì)把getValue()中的return語(yǔ)句分解為幾步操作:
    1) 把value值存儲(chǔ)到一個(gè)局部變量(這里命名為temp)中:
       iload_0   // push local variable 0 - the 100
       istore_2   //  pop an int (the 100), store into local varaible 2
    2) 調(diào)用finally微型子程序
    3) 把局部變量(指temp)的值push到操作數(shù)棧頂,然后返回到調(diào)用方法
         iload_2  // push local varaible 2 - the 100
       ireturn      // return int on top of the stack - the 100: return 100

    由于return語(yǔ)句在返回之前會(huì)把返回值保存到一個(gè)臨時(shí)的局部變量中,所以在finally子句內(nèi)對(duì)value重新賦值不會(huì)影響返回值。

    了解finally子句內(nèi)在的一些知識(shí),我們能夠了解finally能夠做什么和不能夠做什么,這樣會(huì)幫助我們正確使用finally子句。

    2 . 關(guān)于 Java 中 finally 語(yǔ)句塊的深度辨析
    原帖地址 :
    http://www.ibm.com/developerworks/cn/java/j-lo-finally/index.html?ca=drs-
    轉(zhuǎn)貼
    關(guān)于 Java 虛擬機(jī)是如何編譯 finally 語(yǔ)句塊的問(wèn)題,有興趣的讀者可以參考《 The JavaTM Virtual Machine Specification, Second Edition 》中 7.13 節(jié) Compiling finally。那里詳細(xì)介紹了 Java 虛擬機(jī)是如何編譯 finally 語(yǔ)句塊。實(shí)際上,Java 虛擬機(jī)會(huì)把 finally 語(yǔ)句塊作為 subroutine(對(duì)于這個(gè) subroutine 不知該如何翻譯為好,干脆就不翻譯了,免得產(chǎn)生歧義和誤解。)直接插入到 try 語(yǔ)句塊或者 catch 語(yǔ)句塊的控制轉(zhuǎn)移語(yǔ)句之前。但是,還有另外一個(gè)不可忽視的因素,那就是在執(zhí)行 subroutine(也就是 finally 語(yǔ)句塊)之前,try 或者 catch 語(yǔ)句塊會(huì)保留其返回值到本地變量表(Local Variable Table)中。待 subroutine 執(zhí)行完畢之后,再恢復(fù)保留的返回值到操作數(shù)棧中,然后通過(guò) return 或者 throw 語(yǔ)句將其返回給該方法的調(diào)用者(invoker)。請(qǐng)注意,前文中我們?cè)?jīng)提到過(guò) return、throw 和 break、continue 的區(qū)別,對(duì)于這條規(guī)則(保留返回值),只適用于 return 和 throw 語(yǔ)句,不適用于 break 和 continue 語(yǔ)句,因?yàn)樗鼈兏揪蜎](méi)有返回值。

    posted @ 2011-11-01 16:56 AK47 閱讀(831) | 評(píng)論 (0)編輯 收藏

    (轉(zhuǎn)貼) jqGrid整理

    原帖地址:
    http://www.cnblogs.com/mycoding/archive/2011/07/07/2099878.html

    一、 jqGrid的加載。

    1.引用相關(guān)頭文件

    引入CSS:

    <link href="Scripts/jquery-ui-1.8.1.custom.css" rel="stylesheet" type="text/css" />

    <link href="Scripts/ui.jqgrid.css" rel="stylesheet" type="text/css" />

    引入JS:

    <script src="Scripts/jquery-1.5.1.js" type="text/javascript"></script>

    <script src="Scripts/jquery-ui.min.js" type="text/javascript"></script>

    <script src="Scripts/grid.locale-en.js" type="text/javascript"></script>

    <script src="Scripts/jquery.jqGrid.min.js" type="text/javascript"></script>

    因?yàn)閖qGrid3.6及以后的版本集成了jQuery UI,所以,此處需要導(dǎo)入U(xiǎn)I相關(guān)js和css。另外grid.locale-en.js這個(gè)語(yǔ)言文件必須在jquery.jqGrid.min.js之前加載,否則會(huì)出問(wèn)題。

    2.將jqgrid加入頁(yè)面中

    根據(jù)jqGrid的文檔,要想生成一個(gè)jqGrid,最直接的方法就是:

    $("#list").jqGrid(options);

    其中l(wèi)ist是頁(yè)面上的一個(gè)table:<table id="list"></table>

    下面是一個(gè)簡(jiǎn)單的例子:

    <script type="text/javascript">
     
    $(document).ready(function () {
     
    jQuery("#list").jqGrid({
     
    url: 'Handler.ashx',
     
    datatype: "json",
     
    mtype: 'GET',
     
    colNames: ['SalesReasonID', 'Name', 'ReasonType', 'ModifiedDate'],
     
    colModel: [
     
    { name: 'SalesReasonID', index: 'SalesReasonID', width: 40, align: "left", editable: true },
     
    { name: 'Name', index: 'Name', width: 100, align: "center" },
     
    { name: 'ReasonType', index: 'ReasonType', width: 100, align: "center" },
     
    { name: 'ModifiedDate', index: 'ModifiedDate', width: 150, align: "center", search: false }
     
    ],
     
    rowList: [10, 20, 30],
     
    sortname: 'SalesReasonID',
     
    viewrecords: true,
     
    sortorder: "desc",
     
    jsonReader: {
     
    root: "griddata",
     
    total: "totalpages",
     
    page: "currpage",
     
    records: "totalrecords",
     
    repeatitems: false
     
    },
     
    pager: jQuery('#pager'),
     
    rowNum: 5,
     
    altclass: 'altRowsColour',
     
    //width: 'auto',
     
    width: '500',
     
    height: 'auto',
     
    caption: "DemoGrid"
     
    }).navGrid('#pager', { add: true, edit: true, del: true,search:false,refresh:false }); ;
     
    })

    二、 jqgrid的重要選項(xiàng)

    具體的options參考,可以訪問(wèn)jqGrid文檔關(guān)于option的章節(jié)(http://www.trirand.com/jqgridwiki/doku.php?id=wiki:options)。其中有幾個(gè)是比較常用的,重點(diǎn)介紹一下:

    • url :jqGrid控件通過(guò)這個(gè)參數(shù)得到需要顯示的數(shù)據(jù),具體的返回值可以使XML也可以是Json。
    • datatype :這個(gè)參數(shù)用于設(shè)定將要得到的數(shù)據(jù)類型。類型包括:json 、xml、xmlstring、local、javascript、function。
    • mtype : 定義使用哪種方法發(fā)起請(qǐng)求,GET或者POST。
    • height :Grid的高度,可以接受數(shù)字、%值、auto,默認(rèn)值為150。
    • width :Grid的寬度,如果未設(shè)置,則寬度應(yīng)為所有列寬的之和;如果設(shè)置了寬度,則每列的寬度將會(huì)根據(jù)shrinkToFit選項(xiàng)的設(shè)置,進(jìn)行設(shè)置。
    • shrinkToFit :此選項(xiàng)用于根據(jù)width計(jì)算每列寬度的算法。默認(rèn)值為true。如果shrinkToFit為true且設(shè)置了width值,則每列寬度會(huì)根據(jù) width成比例縮放;如果shrinkToFit為false且設(shè)置了width值,則每列的寬度不會(huì)成比例縮放,而是保持原有設(shè)置,而Grid將會(huì)有 水平滾動(dòng)條。
    • autowidth :默認(rèn)值為false。如果設(shè)為true,則Grid的寬度會(huì)根據(jù)父容器的寬度自動(dòng)重算。重算僅發(fā)生在Grid初始化的階段;如果當(dāng)父容器尺寸變化了,同時(shí)也需要變化Grid的尺寸的話,則需要在自己的代碼中調(diào)用setGridWidth方法來(lái)完成。
    • pager :定義頁(yè)碼控制條Page Bar,在上面的例子中是用一個(gè)div(<div id=”pager”></div>)來(lái)放置的。
    • sortname :指定默認(rèn)的排序列,可以是列名也可以是數(shù)字。此參數(shù)會(huì)在被傳遞到Server端。
    • viewrecords :設(shè)置是否在Pager Bar顯示所有記錄的總數(shù)。
    • caption :設(shè)置Grid表格的標(biāo)題,如果未設(shè)置,則標(biāo)題區(qū)域不顯示。
    • rowNum :用于設(shè)置Grid中一次顯示的行數(shù),默認(rèn)值為20。正是這個(gè)選項(xiàng)將參數(shù)rows(prmNames中設(shè)置的)通過(guò)url選項(xiàng)設(shè)置的鏈接傳遞到Server。注意如果Server返回的數(shù)據(jù)行數(shù)超過(guò)了rowNum的設(shè)定,則Grid也只顯示rowNum設(shè)定的行數(shù)。
    • rowList :一個(gè)數(shù)組,用于設(shè)置Grid可以接受的rowNum值。例如[10,20,30]。
    • colNames :字符串?dāng)?shù)組,用于指定各列的題頭文本,與列的順序是對(duì)應(yīng)的。
    • colModel :最重要的數(shù)組之一,用于設(shè)定各列的參數(shù)。(稍后詳述)
    • prmNames :這是一個(gè)數(shù)組,用于設(shè)置jqGrid將要向Server傳遞的參數(shù)名稱。(稍后詳述)
    • jsonReader :這又是一個(gè)數(shù)組,用來(lái)設(shè)定如何解析從Server端發(fā)回來(lái)的json數(shù)據(jù)。(稍后詳述)

    2.1 prmNames選項(xiàng)

    prmNames是jqGrid的一個(gè)重要選項(xiàng),用于設(shè)置jqGrid將要向Server傳遞的參數(shù)名稱。其默認(rèn)值為:

    prmNames : {

    page:"page", // 表示請(qǐng)求頁(yè)碼的參數(shù)名稱

    rows:"rows", // 表示請(qǐng)求行數(shù)的參數(shù)名稱

    sort: "sidx", // 表示用于排序的列名的參數(shù)名稱

    order: "sord", // 表示采用的排序方式的參數(shù)名稱

    search:"_search", // 表示是否是搜索請(qǐng)求的參數(shù)名稱

    nd:"nd", // 表示已經(jīng)發(fā)送請(qǐng)求的次數(shù)的參數(shù)名稱

    id:"id", // 表示當(dāng)在編輯數(shù)據(jù)模塊中發(fā)送數(shù)據(jù)時(shí),使用的id的名稱

    oper:"oper", // operation參數(shù)名稱

    editoper:"edit", // 當(dāng)在edit模式中提交數(shù)據(jù)時(shí),操作的名稱

    addoper:"add", // 當(dāng)在add模式中提交數(shù)據(jù)時(shí),操作的名稱

    deloper:"del", // 當(dāng)在delete模式中提交數(shù)據(jù)時(shí),操作的名稱

    subgridid:"id", // 當(dāng)點(diǎn)擊以載入數(shù)據(jù)到子表時(shí),傳遞的數(shù)據(jù)名稱

    npage: null,

    totalrows:"totalrows" // 表示需從Server得到總共多少行數(shù)據(jù)的參數(shù)名稱,參見(jiàn)jqGrid選項(xiàng)中的rowTotal

    }

    2.2 jsonReader選項(xiàng)

    jsonReader是jqGrid的一個(gè)重要選項(xiàng),用于設(shè)置如何解析從Server端發(fā)回來(lái)的json數(shù)據(jù),如果Server返回的是xml數(shù)據(jù),則對(duì)應(yīng)的使用xmlReader來(lái)解析。jsonReader的默認(rèn)值為:

    jsonReader : {

    root: "rows", // json中代表實(shí)際模型數(shù)據(jù)的入口

    page: "page", // json中代表當(dāng)前頁(yè)碼的數(shù)據(jù)

    total: "total", // json中代表頁(yè)碼總數(shù)的數(shù)據(jù)

    records: "records", // json中代表數(shù)據(jù)行總數(shù)的數(shù)據(jù)

    repeatitems: true, // 如果設(shè)為false,則jqGrid在解析json時(shí),會(huì)根據(jù)name來(lái)搜索對(duì)應(yīng)的數(shù)據(jù)元素(即可以json中元素可以不按順序);而所使用的name是來(lái)自于colModel中的name設(shè)定。

    cell: "cell",

    id: "id",

    userdata: "userdata",

    subgrid: {

    root:"rows",

    repeatitems: true,

    cell:"cell"

    }

    }

    假如有下面一個(gè)json字符串:

    {"totalpages":"3","currpage":"1","totalrecords":"11","griddata": [{"SalesReasonID":"1","Name":"Price","ReasonType":"Other","ModifiedDate":"1998 年6月1日"},{"SalesReasonID":"2","Name":"On Promotion","ReasonType":"Promotion","ModifiedDate":"1998年6月1日"}, {"SalesReasonID":"3","Name":"Magazine Advertisement","ReasonType":"Marketing","ModifiedDate":"1998年6月1日"}, {"SalesReasonID":"4","Name":"Television Advertisement","ReasonType":"Marketing","ModifiedDate":"1998年6月1日"}, {"SalesReasonID":"5","Name":"Manufacturer","ReasonType":"Other","ModifiedDate":"1998 年6月1日"}]}

    其對(duì)應(yīng)的jsonReader為:jsonReader: {

    root: "griddata",

    total: "totalpages",

    page: "currpage",

    records: "totalrecords",

    repeatitems: false

    }

    注:cell、id在repeatitems為true時(shí)可以用到,即每一個(gè)記錄是由一對(duì)id和cell組合而成,即可以適用另一種json結(jié)構(gòu)。援引文檔中的例子:

    repeatitems為true時(shí):

    jQuery("#gridid").jqGrid({  

         ...  

         jsonReader : {  

             root:"invdata",  

             page: "currpage",  

             total: "totalpages",  

             records: "totalrecords"

         },  

         ...  

    });  

    json結(jié)構(gòu)為:

    {   

    "totalpages": "xxx",   

    "currpage": "yyy",  

    "totalrecords": "zzz",  

    "invdata" : [  

                      {"id" :"1", "cell" :["cell11", "cell12", "cell13"]},   // cell中不需要各列的name,只要值就OK了,但是需要保持對(duì)應(yīng)

                      {"id" :"2", "cell" :["cell21", "cell22", "cell23"]},  

                      ...  

         ]  

    }  

    repeatitems為false時(shí):

    jQuery("#gridid").jqGrid({  

         ...  

         jsonReader : {  

             root:"invdata",  

             page: "currpage",  

             total: "totalpages",  

             records: "totalrecords",  

             repeatitems: false,  

             id: "0"

         },  

         ...  

    });  

    json結(jié)構(gòu)為:

    {   

    "totalpages" : "xxx",   

    "currpage" : "yyy",  

    "totalrecords" : "zzz",  

    "invdata" : [  

                     {"invid" : "1","invdate":"cell11", "amount" :"cell12", "tax" :"cell13", "total" :"1234", "note" :"somenote"}, // 數(shù)據(jù)中需要各列的name,但是可以不按列的順序

                      {"invid" : "2","invdate":"cell21", "amount" :"cell22", "tax" :"cell23", "total" :"2345", "note" :"some note"},  

                      ...  

         ]  

    }  

    2.3 colModel的重要選項(xiàng)

    colModel也有許多非常重要的選項(xiàng),在使用搜索、排序等方面都會(huì)用到。這里先只說(shuō)說(shuō)最基本的。

    • name :為Grid中的每個(gè)列設(shè)置唯一的名稱,這是一個(gè)必需選項(xiàng),其中保留字包括subgrid、cb、rn。
    • index :設(shè)置排序時(shí)所使用的索引名稱,這個(gè)index名稱會(huì)作為sidx參數(shù)(prmNames中設(shè)置的)傳遞到Server。
    • label :當(dāng)jqGrid的colNames選項(xiàng)數(shù)組為空時(shí),為各列指定題頭。如果colNames和此項(xiàng)都為空時(shí),則name選項(xiàng)值會(huì)成為題頭。
    • width :設(shè)置列的寬度,目前只能接受以px為單位的數(shù)值,默認(rèn)為150。
    • sortable :設(shè)置該列是否可以排序,默認(rèn)為true。
    • search :設(shè)置該列是否可以被列為搜索條件,默認(rèn)為true。
    • resizable :設(shè)置列是否可以變更尺寸,默認(rèn)為true。
    • hidden :設(shè)置此列初始化時(shí)是否為隱藏狀態(tài),默認(rèn)為false。
    • formatter :預(yù)設(shè)類型或用來(lái)格式化該列的自定義函數(shù)名。常用預(yù)設(shè)格式有:integer、date、currency、number等(具體參見(jiàn)文檔 )。

    三、 注意事項(xiàng)

    1. 動(dòng)態(tài)改變Add Form或者Edit Form中的select的內(nèi)容,如:改變下圖中的Comparator下拉中的內(nèi)容。

    clip_image002

    $("#list_d").navGrid('#pager_d',{add:true,edit:true,del:true,search:false,refresh:false},

    {

    checkOnSubmit:false, closeAfterEdit: true,recreateForm:true,

    beforeInitData:function(formid){

    initComparator();

    },

    beforeShowForm: function(formid){

    $("#list_d").jqGrid('setColProp', 'Name', { editrules:{required:false},});

    $('#tr_Name', formid).hide();

    }

    },//edit

    {},//add

    {}//del

    beforeInitData, beforeShowForm在每次點(diǎn)擊編輯的時(shí)候都會(huì)執(zhí)行。initComparator的作用是通過(guò)ajax獲取數(shù)據(jù),然后利 用$("#list_d").jqGrid('setColProp', 'Comparator', { editoptions: { value: valueString} });來(lái)設(shè)置Comparator下拉中的內(nèi)容。其中valueString的格式如下’ equal to: equal to; not equal to: not equal to’。鍵值之間用冒號(hào)隔開(kāi),2項(xiàng)之間用分號(hào)隔開(kāi)。注意:把recreateForm設(shè)為true,否則'setColProp'只在第一次調(diào)用時(shí)有效。

    2. var rowNum = parseInt($(this).getGridParam("records"), 10); 得到數(shù)據(jù)條數(shù)。

    3. jQuery("#list_d").clearGridData();清空數(shù)據(jù)。

    4. jQuery("#list").getCell(ids,"Key");獲取第ids行的key列。

    5. $("#list").jqGrid('setSelection', "1");選中第一行。放在loadComplete:中在gird加載完成的時(shí)候自動(dòng)選中第一行。 loadComplete:function(data){$("#list").jqGrid('setSelection', "1");

    }

    6. 對(duì)于像1中的可編輯的字段,可以設(shè)定rule,參見(jiàn)http://www.trirand.com/jqgridwiki/doku.php?id=wiki:common_rules#editrules

    7. 修改Option,以URL為例

    jQuery("#list_d").jqGrid('setGridParam',{url:"xxx.aspx",page:1}).trigger('reloadGrid');


    復(fù)雜的表格可以參考jquery grid demo網(wǎng)站 :




    posted @ 2011-11-01 14:23 AK47 閱讀(2320) | 評(píng)論 (0)編輯 收藏

    (轉(zhuǎn)載)Spring 注解@Component,@Service,@Controller,@Repository

    Spring 2.5 中除了提供 @Component 注釋外,還定義了幾個(gè)擁有特殊語(yǔ)義的注釋,它們分別是:@Repository、@Service 和 @Controller。在目前的 Spring 版本中,這 3 個(gè)注釋和 @Component 是等效的,但是從注釋類的命名上,很容易看出這 3 個(gè)注釋分別和持久層、業(yè)務(wù)層和控制層(Web 層)相對(duì)應(yīng)。雖然目前這 3 個(gè)注釋和 @Component 相比沒(méi)有什么新意,但 Spring 將在以后的版本中為它們添加特殊的功能。所以,如果 Web 應(yīng)用程序采用了經(jīng)典的三層分層結(jié)構(gòu)的話,最好在持久層、業(yè)務(wù)層和控制層分別采用 @Repository、@Service 和 @Controller 對(duì)分層中的類進(jìn)行注釋,而用 @Component 對(duì)那些比較中立的類進(jìn)行注釋。

    在 一個(gè)稍大的項(xiàng)目中,通常會(huì)有上百個(gè)組件,如果這些組件采用xml的bean定義來(lái)配置,顯然會(huì)增加配置文件的體積,查找以及維護(hù)起來(lái)也不太方便。 Spring2.5為我們引入了組件自動(dòng)掃描機(jī)制,他可以在類路徑底下尋找標(biāo)注了 @Component,@Service,@Controller,@Repository注解的類,并把這些類納入進(jìn)spring容器中管理。它的作用 和在xml文件中使用bean節(jié)點(diǎn)配置組件時(shí)一樣的。要使用自動(dòng)掃描機(jī)制,我們需要打開(kāi)以下配置信息: 
    Java代碼

    1. <?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-2.5.xsd   http://www.springframework.org/schema/context   http://www.springframework.org/schema/context/spring-context-2.5.xsd"  
    2. >  
    3.   
    4. <context:component-scan base-package=”com.eric.spring”>   
    5. </beans>   
       /*其中base-package為需要掃描的包(含所有子包)

         @Service用于標(biāo)注業(yè)務(wù)層組件,

         @Controller用于標(biāo)注控制層組件(如struts中的action),

         @Repository用于標(biāo)注數(shù)據(jù)訪問(wèn)組件,即DAO組件,

         @Component泛指組件,當(dāng)組件不好歸類的時(shí)候,我們可以使用這個(gè)注解進(jìn)行標(biāo)注。

        */   


    6. @Service public class VentorServiceImpl implements iVentorService {   
    7. } @Repository public class VentorDaoImpl implements iVentorDao {  
    8. }

    /*getBean的默認(rèn)名稱是類名(頭字母小 寫(xiě)),如果想自定義,可以@Service(“aaaaa”)這樣來(lái)指定,這種bean默認(rèn)是單例的,如果想改變,可以使用 @Service(“beanName”) @Scope(“prototype”)來(lái)改變。可以使用以下方式指定初始化方法和銷毀方法(方法名任意): @PostConstruct public void init() {  

    */
    9. }  
    10. @PreDestroy public void destory() {  
    11. } 

    注入方式:

    把 DAO實(shí)現(xiàn)類注入到service實(shí)現(xiàn)類中,把service的接口(注意不要是service的實(shí)現(xiàn)類)注入到action中,注入時(shí)不要new 這個(gè)注入的類,因?yàn)閟pring會(huì)自動(dòng)注入,如果手動(dòng)再new的話會(huì)出現(xiàn)錯(cuò)誤,然后屬性加上@Autowired后不需要getter()和 setter()方法,Spring也會(huì)自動(dòng)注入。至于更具體的內(nèi)容,等對(duì)注入的方式更加熟練后會(huì)做個(gè)完整的例子上來(lái)。

    注解:

    在 spring的配置文件里面只需要加上<context:annotation-config/> 和<context:component-scan base-package="需要實(shí)現(xiàn)注入的類所在包"/>,可以使用base-package="*"表示全部的類。   

    <context:component-scan base-package=”com.eric.spring”> 

    其中base-package為需要掃描的包(含所有子包)

    在接口前面標(biāo)上@Autowired和@Qualifier注釋使得接口可以被容器注入,當(dāng)接口存在兩個(gè)實(shí)現(xiàn)類的時(shí)候必須指定其中一個(gè)來(lái)注入,使用實(shí)現(xiàn)類首字母小寫(xiě)的字符串來(lái)注入,如:

    1.     @Autowired     
    2.   
    3.     @Qualifier("chinese")      
    4.   
    5.     private Man man;   

    否則可以省略,只寫(xiě)@Autowired   。 

    @Service服務(wù)層組件,用于標(biāo)注業(yè)務(wù)層組件,表示定義一個(gè)bean,自動(dòng)根據(jù)bean的類名實(shí)例化一個(gè)首寫(xiě)字母為小寫(xiě)的bean,例如Chinese實(shí)例化為chinese,如果需要自己改名字則:@Service("你自己改的bean名")。   

    @Controller用于標(biāo)注控制層組件(如struts中的action)

    @Repository持久層組件,用于標(biāo)注數(shù)據(jù)訪問(wèn)組件,即DAO組件

    @Component泛指組件,當(dāng)組件不好歸類的時(shí)候,我們可以使用這個(gè)注解進(jìn)行標(biāo)注。 


    @Service 
    public class VentorServiceImpl implements iVentorService { 
    }

    @Repository 
    public class VentorDaoImpl implements iVentorDao { 


    getBean 的默認(rèn)名稱是類名(頭字母小寫(xiě)),如果想自定義,可以@Service(“aaaaa”) 這樣來(lái)指定,這種

    bean默認(rèn)是單例的,如果想改變,可以使用@Service(“beanName”) @Scope(“prototype”)來(lái)改變。

    可以使用以下方式指定初始化方法和銷毀方法(方法名任意):

    @PostConstruct

    public void init() { 



    @PreDestroy

    public void destory() { 

    }

    posted @ 2011-10-10 16:46 AK47 閱讀(49714) | 評(píng)論 (3)編輯 收藏

    (轉(zhuǎn)貼)使用 Spring 2.5 注釋驅(qū)動(dòng)的 IoC 功能

    原帖地址
    http://www.ibm.com/developerworks/cn/java/j-lo-spring25-ioc/

    概述

    注釋配置相對(duì)于 XML 配置具有很多的優(yōu)勢(shì):

    • 它可以充分利用 Java 的反射機(jī)制獲取類結(jié)構(gòu)信息,這些信息可以有效減少配置的工作。如使用 JPA 注釋配置 ORM 映射時(shí),我們就不需要指定 PO 的屬性名、類型等信息,如果關(guān)系表字段和 PO 屬性名、類型都一致,您甚至無(wú)需編寫(xiě)任務(wù)屬性映射信息——因?yàn)檫@些信息都可以通過(guò) Java 反射機(jī)制獲取。
    • 注釋和 Java 代碼位于一個(gè)文件中,而 XML 配置采用獨(dú)立的配置文件,大多數(shù)配置信息在程序開(kāi)發(fā)完成后都不會(huì)調(diào)整,如果配置信息和 Java 代碼放在一起,有助于增強(qiáng)程序的內(nèi)聚性。而采用獨(dú)立的 XML 配置文件,程序員在編寫(xiě)一個(gè)功能時(shí),往往需要在程序文件和配置文件中不停切換,這種思維上的不連貫會(huì)降低開(kāi)發(fā)效率。

    因此在很多情況下,注釋配置比 XML 配置更受歡迎,注釋配置有進(jìn)一步流行的趨勢(shì)。Spring 2.5 的一大增強(qiáng)就是引入了很多注釋類,現(xiàn)在您已經(jīng)可以使用注釋配置完成大部分 XML 配置的功能。在這篇文章里,我們將向您講述使用注釋進(jìn)行 Bean 定義和依賴注入的內(nèi)容。

     
    原來(lái)我們是怎么做的      
    在使用注釋配置之前,先來(lái)回顧一下傳統(tǒng)上是如何配置 Bean 并完成 Bean 之間依賴關(guān)系的建立。下面是 3 個(gè)類,它們分別是 Office、Car 和 Boss,這 3 個(gè)類需要在 Spring 容器中配置為 Bean:    
       
    Office 僅有一個(gè)屬性:    
         
    清單 1. Office.java    
                        
    package com.baobaotao;    
    public class Office {    
        private String officeNo =”001”;    
       
        //省略 get/setter    
       
        @Override   
        public String toString() {    
            return "officeNo:" + officeNo;    
        }    
    }    
           
    Car 擁有兩個(gè)屬性:    
         
    清單 2. Car.java 
                         
    package com.baobaotao;    
       
    public class Car {    
        private String brand;    
        private double price;    
       
        // 省略 get/setter    
       
        @Override   
        public String toString() {    
            return "brand:" + brand + "," + "price:" + price;    
        }    
    }    
          
    Boss 擁有 Office 和 Car 類型的兩個(gè)屬性:    
      
    清單 3. Boss.java    
                        
    package com.baobaotao;    
       
    public class Boss {    
        private Car car;    
        private Office office;    
       
        // 省略 get/setter    
       
        @Override   
        public String toString() {    
            return "car:" + car + "\n" + "office:" + office;    
        }    
    }    
        
    我們?cè)?Spring 容器中將 Office 和 Car 聲明為 Bean,并注入到 Boss Bean 中:下面是使用傳統(tǒng) XML 完成這個(gè)工作的配置文件 beans.xml:    
        
    清單 4. beans.xml 將以上三個(gè)類配置成 Bean    
                        
    <?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-2.5.xsd">    
        <bean id="boss" class="com.baobaotao.Boss">    
            <property name="car" ref="car"/>    
            <property name="office" ref="office" />    
        </bean>    
        <bean id="office" class="com.baobaotao.Office">    
            <property name="officeNo" value="002"/>    
        </bean>    
        <bean id="car" class="com.baobaotao.Car" scope="singleton">    
            <property name="brand" value=" 紅旗 CA72"/>    
            <property name="price" value="2000"/>    
        </bean>    
    </beans>    
         
    當(dāng)我們運(yùn)行以下代碼時(shí),控制臺(tái)將正確打出 boss 的信息:    
      
    清單 5. 測(cè)試類:AnnoIoCTest.java    
                        
    import org.springframework.context.ApplicationContext;    
    import org.springframework.context.support.ClassPathXmlApplicationContext;    
    public class AnnoIoCTest {    
       
        public static void main(String[] args) {    
            String[] locations = {"beans.xml"};    
            ApplicationContext ctx =     
                new ClassPathXmlApplicationContext(locations);    
            Boss boss = (Boss) ctx.getBean("boss");    
            System.out.println(boss);    
        }    
    }    
        
    這說(shuō)明 Spring 容器已經(jīng)正確完成了 Bean 創(chuàng)建和裝配的工作。    
         
    使用 @Autowired 注釋    
       
    Spring 2.5 引入了 @Autowired 注釋,它可以對(duì)類成員變量、方法及構(gòu)造函數(shù)進(jìn)行標(biāo)注,完成自動(dòng)裝配的工作。來(lái)看一下使用 @Autowired 進(jìn)行成員變量自動(dòng)注入的代碼:    
      
    清單 6. 使用 @Autowired 注釋的 Boss.java    
                        
    package com.baobaotao;    
    import org.springframework.beans.factory.annotation.Autowired;    
       
    public class Boss {    
       
        @Autowired   
        private Car car;    
       
        @Autowired   
        private Office office;    
       
        …    
    }    
           
    Spring 通過(guò)一個(gè) BeanPostProcessor 對(duì) @Autowired 進(jìn)行解析,所以要讓 @Autowired 起作用必須事先在 Spring 容器中聲明 AutowiredAnnotationBeanPostProcessor Bean。   

    清單 7. 讓 @Autowired 注釋工作起來(lái)    
                        
    <?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-2.5.xsd">    
       
        <!-- 該 BeanPostProcessor 將自動(dòng)起作用,對(duì)標(biāo)注 @Autowired 的 Bean 進(jìn)行自動(dòng)注入 -->    
        <bean class="AutowiredAnnotationBeanPostProcessor  
            org.springframework.beans.factory.annotation.  "/>    
       
        <!-- 移除 boss Bean 的屬性注入配置的信息 -->    
        <bean id="boss" class="com.baobaotao.Boss"/>    
         
        <bean id="office" class="com.baobaotao.Office">    
            <property name="officeNo" value="001"/>    
        </bean>    
        <bean id="car" class="com.baobaotao.Car" scope="singleton">    
            <property name="brand" value=" 紅旗 CA72"/>    
            <property name="price" value="2000"/>    
        </bean>    
    </beans>    
         
        
    這 樣,當(dāng) Spring 容器啟動(dòng)時(shí),AutowiredAnnotationBeanPostProcessor 將掃描 Spring 容器中所有 Bean,當(dāng)發(fā)現(xiàn) Bean 中擁有 @Autowired 注釋時(shí)就找到和其匹配(默認(rèn)按類型匹配)的 Bean,并注入到對(duì)應(yīng)的地方中去。    
       
    按 照上面的配置,Spring 將直接采用 Java 反射機(jī)制對(duì) Boss 中的 car 和 office 這兩個(gè)私有成員變量進(jìn)行自動(dòng)注入。所以對(duì)成員變量使用 @Autowired 后,您大可將它們的 setter 方法(setCar() 和 setOffice())從 Boss 中刪除。    
       
    當(dāng)然,您也可以通過(guò) @Autowired 對(duì)方法或構(gòu)造函數(shù)進(jìn)行標(biāo)注,來(lái)看下面的代碼:    
        
    清單 8. 將 @Autowired 注釋標(biāo)注在 Setter 方法上    
                        
    package com.baobaotao;    
       
    public class Boss {    
        private Car car;    
        private Office office;    
       
         @Autowired   
        public void setCar(Car car) {    
            this.car = car;    
        }    
         
        @Autowired   
        public void setOffice(Office office) {    
            this.office = office;    
        }    
        …    
    }    
         
    這時(shí),@Autowired 將查找被標(biāo)注的方法的入?yún)㈩愋偷?Bean,并調(diào)用方法自動(dòng)注入這些 Bean。而下面的使用方法則對(duì)構(gòu)造函數(shù)進(jìn)行標(biāo)注:    
        
    清單 9. 將 @Autowired 注釋標(biāo)注在構(gòu)造函數(shù)上    
                        
    package com.baobaotao;    
       
    public class Boss {    
        private Car car;    
        private Office office;    
         
        @Autowired   
        public Boss(Car car ,Office office){    
            this.car = car;    
            this.office = office ;    
        }    
         
        …    
    }    
           
    由于 Boss() 構(gòu)造函數(shù)有兩個(gè)入?yún)ⅲ謩e是 car 和 office,@Autowired 將分別尋找和它們類型匹配的 Bean,將它們作為 Boss(Car car ,Office office) 的入?yún)?lái)創(chuàng)建 Boss Bean。    
         
    當(dāng)候選 Bean 數(shù)目不為 1 時(shí)的應(yīng)對(duì)方法    
       
    在 默認(rèn)情況下使用 @Autowired 注釋進(jìn)行自動(dòng)注入時(shí),Spring 容器中匹配的候選 Bean 數(shù)目必須有且僅有一個(gè)。當(dāng)找不到一個(gè)匹配的 Bean 時(shí),Spring 容器將拋出 BeanCreationException 異常,并指出必須至少擁有一個(gè)匹配的 Bean。我們可以來(lái)做一個(gè)實(shí)驗(yàn):    
       
       
    清單 10. 候選 Bean 數(shù)目為 0 時(shí)    
                        
    <?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-2.5.xsd ">    
         
        <bean class="AutowiredAnnotationBeanPostProcessor  
            org.springframework.beans.factory.annotation.  "/>     
       
        <bean id="boss" class="com.baobaotao.Boss"/>    
       
        <!-- 將 office Bean 注釋掉 -->    
        <!-- <bean id="office" class="com.baobaotao.Office">    
        <property name="officeNo" value="001"/>    
        </bean>-->    
       
        <bean id="car" class="com.baobaotao.Car" scope="singleton">    
            <property name="brand" value=" 紅旗 CA72"/>    
            <property name="price" value="2000"/>    
        </bean>    
    </beans>    
         
    由于 office Bean 被注釋掉了,所以 Spring 容器中將沒(méi)有類型為 Office 的 Bean 了,而 Boss 的 office 屬性標(biāo)注了 @Autowired,當(dāng)啟動(dòng) Spring 容器時(shí),異常就產(chǎn)生了。    
       
    當(dāng) 不能確定 Spring 容器中一定擁有某個(gè)類的 Bean 時(shí),可以在需要自動(dòng)注入該類 Bean 的地方可以使用 @Autowired(required = false),這等于告訴 Spring:在找不到匹配 Bean 時(shí)也不報(bào)錯(cuò)。來(lái)看一下具體的例子:    
       
       
    清單 11. 使用 @Autowired(required = false)    
                        
    package com.baobaotao;    
       
    import org.springframework.beans.factory.annotation.Autowired;    
    import org.springframework.beans.factory.annotation.Required;    
       
    public class Boss {    
       
        private Car car;    
        private Office office;    
       
        @Autowired   
        public void setCar(Car car) {    
            this.car = car;    
        }    
        @Autowired(required = false)    
        public void setOffice(Office office) {    
            this.office = office;    
        }    
        …    
    }    
        
    當(dāng) 然,一般情況下,使用 @Autowired 的地方都是需要注入 Bean 的,使用了自動(dòng)注入而又允許不注入的情況一般僅會(huì)在開(kāi)發(fā)期或測(cè)試期碰到(如為了快速啟動(dòng) Spring 容器,僅引入一些模塊的 Spring 配置文件),所以 @Autowired(required = false) 會(huì)很少用到。    
       
    和找不到一個(gè)類型匹配 Bean 相反的一個(gè)錯(cuò)誤是:如果 Spring 容器中擁有多個(gè)候選 Bean,Spring 容器在啟動(dòng)時(shí)也會(huì)拋出 BeanCreationException 異常。來(lái)看下面的例子:    
        
    清單 12. 在 beans.xml 中配置兩個(gè) Office 類型的 Bean    
                        
    …     
    <bean id="office" class="com.baobaotao.Office">    
        <property name="officeNo" value="001"/>    
    </bean>    
    <bean id="office2" class="com.baobaotao.Office">    
        <property name="officeNo" value="001"/>    
    </bean>    
    …    
         
    我們?cè)?Spring 容器中配置了兩個(gè)類型為 Office 類型的 Bean,當(dāng)對(duì) Boss 的 office 成員變量進(jìn)行自動(dòng)注入時(shí),Spring 容器將無(wú)法確定到底要用哪一個(gè) Bean,因此異常發(fā)生了。    
       
    Spring 允許我們通過(guò) @Qualifier 注釋指定注入 Bean 的名稱,這樣歧義就消除了,可以通過(guò)下面的方法解決異常:    
      
    清單 13. 使用 @Qualifier 注釋指定注入 Bean 的名稱    
                        
    @Autowired   
    public void setOffice(@Qualifier("office")Office office) {    
        this.office = office;    
    }    
        
     
    @Qualifier("office") 中的 office 是 Bean 的名稱,所以 @Autowired 和 @Qualifier 結(jié)合使用時(shí),自動(dòng)注入的策略就從 byType 轉(zhuǎn)變成 byName 了。@Autowired 可以對(duì)成員變量、方法以及構(gòu)造函數(shù)進(jìn)行注釋,而 @Qualifier 的標(biāo)注對(duì)象是成員變量、方法入?yún)ⅰ?gòu)造函數(shù)入?yún)ⅰU怯捎谧⑨寣?duì)象的不同,所以 Spring 不將 @Autowired 和 @Qualifier 統(tǒng)一成一個(gè)注釋類。下面是對(duì)成員變量和構(gòu)造函數(shù)入?yún)⑦M(jìn)行注釋的代碼:    
       
    對(duì)成員變量進(jìn)行注釋:    
      
    清單 14. 對(duì)成員變量使用 @Qualifier 注釋    
                        
    public class Boss {    
        @Autowired   
        private Car car;    
         
        @Autowired   
        @Qualifier("office")    
        private Office office;    
        …    
    }    
         
        
    對(duì)構(gòu)造函數(shù)入?yún)⑦M(jìn)行注釋:    
        
    清單 15. 對(duì)構(gòu)造函數(shù)變量使用 @Qualifier 注釋    
                        
    public class Boss {    
        private Car car;    
        private Office office;    
       
        @Autowired   
        public Boss(Car car , @Qualifier("office")Office office){    
            this.car = car;    
            this.office = office ;    
        }    
    }    
         
    @Qualifier 只能和 @Autowired 結(jié)合使用,是對(duì) @Autowired 有益的補(bǔ)充。一般來(lái)講,@Qualifier 對(duì)方法簽名中入?yún)⑦M(jìn)行注釋會(huì)降低代碼的可讀性,而對(duì)成員變量注釋則相對(duì)好一些。    
        
       
    使用 JSR-250 的注釋    
       
    Spring 不但支持自己定義的 @Autowired 的注釋,還支持幾個(gè)由 JSR-250 規(guī)范定義的注釋,它們分別是 @Resource、@PostConstruct 以及 @PreDestroy。    
       
    @Resource   
       
    @Resource 的作用相當(dāng)于 @Autowired,只不過(guò) @Autowired 按 byType 自動(dòng)注入,面 @Resource 默認(rèn)按 byName 自動(dòng)注入罷了。@Resource 有兩個(gè)屬性是比較重要的,分別是 name 和 type,Spring 將 @Resource 注釋的 name 屬性解析為 Bean 的名字,而 type 屬性則解析為 Bean 的類型。所以如果使用 name 屬性,則使用 byName 的自動(dòng)注入策略,而使用 type 屬性時(shí)則使用 byType 自動(dòng)注入策略。如果既不指定 name 也不指定 type 屬性,這時(shí)將通過(guò)反射機(jī)制使用 byName 自動(dòng)注入策略。    
       
    Resource 注釋類位于 Spring 發(fā)布包的 lib/j2ee/common-annotations.jar 類包中,因此在使用之前必須將其加入到項(xiàng)目的類庫(kù)中。來(lái)看一個(gè)使用 @Resource 的例子:    
       
    清單 16. 使用 @Resource 注釋的 Boss.java    
                        
    package com.baobaotao;    
       
    import javax.annotation.Resource;    
       
    public class Boss {    
        // 自動(dòng)注入類型為 Car 的 Bean    
        @Resource   
        private Car car;    
       
        // 自動(dòng)注入 bean 名稱為 office 的 Bean    
        @Resource(name = "office")    
        private Office office;    
    }    
         
    一般情況下,我們無(wú)需使用類似于 @Resource(type=Car.class) 的注釋方式,因?yàn)?Bean 的類型信息可以通過(guò) Java 反射從代碼中獲取。    
       
    要讓 JSR-250 的注釋生效,除了在 Bean 類中標(biāo)注這些注釋外,還需要在 Spring 容器中注冊(cè)一個(gè)負(fù)責(zé)處理這些注釋的 BeanPostProcessor:    
       
    <bean     
      class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor"/>    
         
      
    CommonAnnotationBeanPostProcessor 實(shí)現(xiàn)了 BeanPostProcessor 接口,它負(fù)責(zé)掃描使用了 JSR-250 注釋的 Bean,并對(duì)它們進(jìn)行相應(yīng)的操作。    
       
    @PostConstruct 和 @PreDestroy   
       
    Spring 容器中的 Bean 是有生命周期的,Spring 允許在 Bean 在初始化完成后以及 Bean 銷毀前執(zhí)行特定的操作,您既可以通過(guò)實(shí)現(xiàn) InitializingBean/DisposableBean 接口來(lái)定制初始化之后 / 銷毀之前的操作方法,也可以通過(guò) <bean> 元素的 init-method/destroy-method 屬性指定初始化之后 / 銷毀之前調(diào)用的操作方法。關(guān)于 Spring 的生命周期,筆者在《精通 Spring 2.x—企業(yè)應(yīng)用開(kāi)發(fā)精解》第 3 章進(jìn)行了詳細(xì)的描述,有興趣的讀者可以查閱。    
       
    JSR-250 為初始化之后/銷毀之前方法的指定定義了兩個(gè)注釋類,分別是 @PostConstruct 和 @PreDestroy,這兩個(gè)注釋只能應(yīng)用于方法上。標(biāo)注了 @PostConstruct 注釋的方法將在類實(shí)例化后調(diào)用,而標(biāo)注了 @PreDestroy 的方法將在類銷毀之前調(diào)用。    
      
    清單 17. 使用 @PostConstruct 和 @PreDestroy 注釋的 Boss.java    
                        
    package com.baobaotao;    
       
    import javax.annotation.Resource;    
    import javax.annotation.PostConstruct;    
    import javax.annotation.PreDestroy;    
       
    public class Boss {    
        @Resource   
        private Car car;    
       
        @Resource(name = "office")    
        private Office office;    
       
        @PostConstruct   
        public void postConstruct1(){    
            System.out.println("postConstruct1");    
        }    
       
        @PreDestroy   
        public void preDestroy1(){    
            System.out.println("preDestroy1");     
        }    
        …    
    }    
         
    您只需要在方法前標(biāo)注 @PostConstruct 或 @PreDestroy,這些方法就會(huì)在 Bean 初始化后或銷毀之前被 Spring 容器執(zhí)行了。    
       
    我 們知道,不管是通過(guò)實(shí)現(xiàn) InitializingBean/DisposableBean 接口,還是通過(guò) <bean> 元素的 init-method/destroy-method 屬性進(jìn)行配置,都只能為 Bean 指定一個(gè)初始化 / 銷毀的方法。但是使用 @PostConstruct 和 @PreDestroy 注釋卻可以指定多個(gè)初始化 / 銷毀方法,那些被標(biāo)注 @PostConstruct 或 @PreDestroy 注釋的方法都會(huì)在初始化 / 銷毀時(shí)被執(zhí)行。    
       
    通過(guò)以下的測(cè)試代碼,您將可以看到 Bean 的初始化 / 銷毀方法是如何被執(zhí)行的:    
      
    清單 18. 測(cè)試類代碼    
                        
    package com.baobaotao;    
       
    import org.springframework.context.support.ClassPathXmlApplicationContext;    
       
    public class AnnoIoCTest {    
       
        public static void main(String[] args) {    
            String[] locations = {"beans.xml"};    
            ClassPathXmlApplicationContext ctx =     
                new ClassPathXmlApplicationContext(locations);    
            Boss boss = (Boss) ctx.getBean("boss");    
            System.out.println(boss);    
            ctx.destroy();// 關(guān)閉 Spring 容器,以觸發(fā) Bean 銷毀方法的執(zhí)行    
        }    
    }    
         
       
    這 時(shí),您將看到標(biāo)注了 @PostConstruct 的 postConstruct1() 方法將在 Spring 容器啟動(dòng)時(shí),創(chuàng)建 Boss Bean 的時(shí)候被觸發(fā)執(zhí)行,而標(biāo)注了 @PreDestroy 注釋的 preDestroy1() 方法將在 Spring 容器關(guān)閉前銷毀 Boss Bean 的時(shí)候被觸發(fā)執(zhí)行。    
           
    使用 <context:annotation-config/> 簡(jiǎn)化配置    
       
    Spring 2.1 添加了一個(gè)新的 context 的 Schema 命名空間,該命名空間對(duì)注釋驅(qū)動(dòng)、屬性文件引入、加載期織入等功能提供了便捷的配置。我們知道注釋本身是不會(huì)做任何事情的,它僅提供元數(shù)據(jù)信息。要使元數(shù) 據(jù)信息真正起作用,必須讓負(fù)責(zé)處理這些元數(shù)據(jù)的處理器工作起來(lái)。     
       
    而我們前面所介紹的 AutowiredAnnotationBeanPostProcessor 和 CommonAnnotationBeanPostProcessor 就是處理這些注釋元數(shù)據(jù)的處理器。但是直接在 Spring 配置文件中定義這些 Bean 顯得比較笨拙。Spring 為我們提供了一種方便的注冊(cè)這些 BeanPostProcessor 的方式,這就是 <context:annotation-config/>。請(qǐng)看下面的配置:    
         
    清單 19. 調(diào)整 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-2.5.xsd    
     http://www.springframework.org/schema/context     
     http://www.springframework.org/schema/context/spring-context-2.5.xsd">    
         
        <context:annotation-config/>     
       
        <bean id="boss" class="com.baobaotao.Boss"/>    
        <bean id="office" class="com.baobaotao.Office">    
            <property name="officeNo" value="001"/>    
        </bean>    
        <bean id="car" class="com.baobaotao.Car" scope="singleton">    
            <property name="brand" value=" 紅旗 CA72"/>    
            <property name="price" value="2000"/>    
        </bean>    
    </beans>    
          
    <context:annotationconfig/> 將隱式地向 Spring 容器注冊(cè) AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor、 PersistenceAnnotationBeanPostProcessor 以及 equiredAnnotationBeanPostProcessor 這 4 個(gè) BeanPostProcessor。    
       
    在配置文件中使用 context 命名空間之前,必須在 <beans> 元素中聲明 context 命名空間。    
       
        
    使用 @Component   
       
    雖 然我們可以通過(guò) @Autowired 或 @Resource 在 Bean 類中使用自動(dòng)注入功能,但是 Bean 還是在 XML 文件中通過(guò) <bean> 進(jìn)行定義 —— 也就是說(shuō),在 XML 配置文件中定義 Bean,通過(guò) @Autowired 或 @Resource 為 Bean 的成員變量、方法入?yún)⒒驑?gòu)造函數(shù)入?yún)⑻峁┳詣?dòng)注入的功能。能否也通過(guò)注釋定義 Bean,從 XML 配置文件中完全移除 Bean 定義的配置呢?答案是肯定的,我們通過(guò) Spring 2.5 提供的 @Component 注釋就可以達(dá)到這個(gè)目標(biāo)了。    
       
    下面,我們完全使用注釋定義 Bean 并完成 Bean 之間裝配:    
       
       
    清單 20. 使用 @Component 注釋的 Car.java    
                        
    package com.baobaotao;    
       
    import org.springframework.stereotype.Component;    
       
    @Component   
    public class Car {    
        …    
    }    
         
         
    僅需要在類定義處,使用 @Component 注釋就可以將一個(gè)類定義了 Spring 容器中的 Bean。下面的代碼將 Office 定義為一個(gè) Bean:    
        
    清單 21. 使用 @Component 注釋的 Office.java    
                        
    package com.baobaotao;    
       
    import org.springframework.stereotype.Component;    
       
    @Component   
    public class Office {    
        private String officeNo = "001";    
        …    
    }    
         
    這樣,我們就可以在 Boss 類中通過(guò) @Autowired 注入前面定義的 Car 和 Office Bean 了。    
       
    清單 22. 使用 @Component 注釋的 Boss.java    
                        
    package com.baobaotao;    
       
    import org.springframework.beans.factory.annotation.Autowired;    
    import org.springframework.beans.factory.annotation.Required;    
    import org.springframework.beans.factory.annotation.Qualifier;    
    import org.springframework.stereotype.Component;    
       
    @Component("boss")    
    public class Boss {    
        @Autowired   
        private Car car;    
       
        @Autowired   
        private Office office;    
        …    
    }    
        
    @Component 有一個(gè)可選的入?yún)ⅲ糜谥付?Bean 的名稱,在 Boss 中,我們就將 Bean 名稱定義為“boss”。一般情況下,Bean 都是 singleton 的,需要注入 Bean 的地方僅需要通過(guò) byType 策略就可以自動(dòng)注入了,所以大可不必指定 Bean 的名稱。    
       
    在使用 @Component 注釋后,Spring 容器必須啟用類掃描機(jī)制以啟用注釋驅(qū)動(dòng) Bean 定義和注釋驅(qū)動(dòng) Bean 自動(dòng)注入的策略。Spring 2.5 對(duì) context 命名空間進(jìn)行了擴(kuò)展,提供了這一功能,請(qǐng)看下面的配置:    
        
    清單 23. 簡(jiǎn)化版的 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-2.5.xsd    
     http://www.springframework.org/schema/context     
     http://www.springframework.org/schema/context/spring-context-2.5.xsd">    
        <context:component-scan base-package="com.baobaotao"/>    
    </beans>    
          
    這 里,所有通過(guò) <bean> 元素定義 Bean 的配置內(nèi)容已經(jīng)被移除,僅需要添加一行 <context:component-scan/> 配置就解決所有問(wèn)題了——Spring XML 配置文件得到了極致的簡(jiǎn)化(當(dāng)然配置元數(shù)據(jù)還是需要的,只不過(guò)以注釋形式存在罷了)。<context:component-scan/> 的 base-package 屬性指定了需要掃描的類包,類包及其遞歸子包中所有的類都會(huì)被處理。    
       
    <context:component-scan/> 還允許定義過(guò)濾器將基包下的某些類納入或排除。Spring 支持以下 4 種類型的過(guò)濾方式,通過(guò)下表說(shuō)明:    
       
    表 1. 掃描過(guò)濾方式    
    過(guò)濾器類型 說(shuō)明     
    注釋 假如 com.baobaotao.SomeAnnotation 是一個(gè)注釋類,我們可以將使用該注釋的類過(guò)濾出來(lái)。     
    類名指定 通過(guò)全限定類名進(jìn)行過(guò)濾,如您可以指定將 com.baobaotao.Boss 納入掃描,而將 com.baobaotao.Car 排除在外。     
    正則表達(dá)式 通過(guò)正則表達(dá)式定義過(guò)濾的類,如下所示: com\.baobaotao\.Default.*     
    AspectJ 表達(dá)式 通過(guò) AspectJ 表達(dá)式定義過(guò)濾的類,如下所示: com. baobaotao..*Service+     
       
    下面是一個(gè)簡(jiǎn)單的例子:    
       
    <context:component-scan base-package="com.baobaotao">    
        <context:include-filter type="regex"     
            expression="com\.baobaotao\.service\..*"/>    
        <context:exclude-filter type="aspectj"     
            expression="com.baobaotao.util..*"/>    
    </context:component-scan>    
          
    值 得注意的是 <context:component-scan/> 配置項(xiàng)不但啟用了對(duì)類包進(jìn)行掃描以實(shí)施注釋驅(qū)動(dòng) Bean 定義的功能,同時(shí)還啟用了注釋驅(qū)動(dòng)自動(dòng)注入的功能(即還隱式地在內(nèi)部注冊(cè)了 AutowiredAnnotationBeanPostProcessor 和 CommonAnnotationBeanPostProcessor),因此當(dāng)使用 <context:component-scan/> 后,就可以將 <context:annotation-config/> 移除了。    
       
    默認(rèn)情況下通過(guò) @Component 定義的 Bean 都是 singleton 的,如果需要使用其它作用范圍的 Bean,可以通過(guò) @Scope 注釋來(lái)達(dá)到目標(biāo),如以下代碼所示:    
       
    清單 24. 通過(guò) @Scope 指定 Bean 的作用范圍    
                        
    package com.baobaotao;    
    import org.springframework.context.annotation.Scope;    
    …    
    @Scope("prototype")    
    @Component("boss")    
    public class Boss {    
        …    
    }    
         
    這樣,當(dāng)從 Spring 容器中獲取 boss Bean 時(shí),每次返回的都是新的實(shí)例了。    
          
    采用具有特殊語(yǔ)義的注釋    
       
    Spring 2.5 中除了提供 @Component 注釋外,還定義了幾個(gè)擁有特殊語(yǔ)義的注釋,它們分別是:@Repository、@Service 和 @Controller。在目前的 Spring 版本中,這 3 個(gè)注釋和 @Component 是等效的,但是從注釋類的命名上,很容易看出這 3 個(gè)注釋分別和持久層、業(yè)務(wù)層和控制層(Web 層)相對(duì)應(yīng)。雖然目前這 3 個(gè)注釋和 @Component 相比沒(méi)有什么新意,但 Spring 將在以后的版本中為它們添加特殊的功能。所以,如果 Web 應(yīng)用程序采用了經(jīng)典的三層分層結(jié)構(gòu)的話,最好在持久層、業(yè)務(wù)層和控制層分別采用 @Repository、@Service 和 @Controller 對(duì)分層中的類進(jìn)行注釋,而用 @Component 對(duì)那些比較中立的類進(jìn)行注釋。    
            
    注釋配置和 XML 配置的適用場(chǎng)合    
       
    是否有了這些 IOC 注釋,我們就可以完全摒除原來(lái) XML 配置的方式呢?答案是否定的。有以下幾點(diǎn)原因:    
       
    注 釋配置不一定在先天上優(yōu)于 XML 配置。如果 Bean 的依賴關(guān)系是固定的,(如 Service 使用了哪幾個(gè) DAO 類),這種配置信息不會(huì)在部署時(shí)發(fā)生調(diào)整,那么注釋配置優(yōu)于 XML 配置;反之如果這種依賴關(guān)系會(huì)在部署時(shí)發(fā)生調(diào)整,XML 配置顯然又優(yōu)于注釋配置,因?yàn)樽⑨屖菍?duì) Java 源代碼的調(diào)整,您需要重新改寫(xiě)源代碼并重新編譯才可以實(shí)施調(diào)整。     
    如果 Bean 不是自己編寫(xiě)的類(如 JdbcTemplate、SessionFactoryBean 等),注釋配置將無(wú)法實(shí)施,此時(shí) XML 配置是唯一可用的方式。     
    注釋配置往往是類級(jí)別的,而 XML 配置則可以表現(xiàn)得更加靈活。比如相比于 @Transaction 事務(wù)注釋,使用 aop/tx 命名空間的事務(wù)配置更加靈活和簡(jiǎn)單。     
    所 以在實(shí)現(xiàn)應(yīng)用中,我們往往需要同時(shí)使用注釋配置和 XML 配置,對(duì)于類級(jí)別且不會(huì)發(fā)生變動(dòng)的配置可以優(yōu)先考慮注釋配置;而對(duì)于那些第三方類以及容易發(fā)生調(diào)整的配置則應(yīng)優(yōu)先考慮使用 XML 配置。Spring 會(huì)在具體實(shí)施 Bean 創(chuàng)建和 Bean 注入之前將這兩種配置方式的元信息融合在一起。    
           
    小結(jié)    
       
    Spring 在 2.1 以后對(duì)注釋配置提供了強(qiáng)力的支持,注釋配置功能成為 Spring 2.5 的最大的亮點(diǎn)之一。合理地使用 Spring 2.5 的注釋配置,可以有效減少配置的工作量,提高程序的內(nèi)聚性。但是這并不意味著傳統(tǒng) XML 配置將走向消亡,在第三方類 Bean 的配置,以及那些諸如數(shù)據(jù)源、緩存池、持久層操作模板類、事務(wù)管理等內(nèi)容的配置上,XML 配置依然擁有不可替代的地位。

    posted @ 2011-10-10 15:49 AK47 閱讀(330) | 評(píng)論 (0)編輯 收藏

    (轉(zhuǎn)貼)數(shù)據(jù)庫(kù)三范式經(jīng)典實(shí)例解析

    數(shù)據(jù)庫(kù)的設(shè)計(jì)范式是數(shù)據(jù)庫(kù)設(shè)計(jì)所需要滿足的規(guī)范,滿足這些規(guī)范的數(shù)據(jù)庫(kù)是簡(jiǎn)潔的、結(jié)構(gòu)明晰的,同時(shí),不會(huì)發(fā)生插入(insert)、刪除(delete)和更新(update)操作異常。反之則是亂七八糟,不僅給數(shù)據(jù)庫(kù)的編程人員制造麻煩,而且面目可憎,可能存儲(chǔ)了大量不需要的冗余信息。
         設(shè)計(jì)范式是不是很難懂呢?非也,大學(xué)教材上給我們一堆數(shù)學(xué)公式我們當(dāng)然看不懂,也記不住。所以我們很多人就根本不按照范式來(lái)設(shè)計(jì)數(shù)據(jù)庫(kù)。
         實(shí)質(zhì)上,設(shè)計(jì)范式用很形象、很簡(jiǎn)潔的話語(yǔ)就能說(shuō)清楚,道明白。本文將對(duì)范式進(jìn)行通俗地說(shuō)明,并以筆者曾經(jīng)設(shè)計(jì)的一個(gè)簡(jiǎn)單論壇的數(shù)據(jù)庫(kù)為例來(lái)講解怎樣將這些范式應(yīng)用于實(shí)際工程。

    范式說(shuō)明
         第一范式(1NF):數(shù)據(jù)庫(kù)表中的字段都是單一屬性的,不可再分。這個(gè)單一屬性由基本類型構(gòu)成,包括整型、實(shí)數(shù)、字符型、邏輯型、日期型等。
         例如,如下的數(shù)據(jù)庫(kù)表是符合第一范式:

    字段1 字段2 字段3 字段4
    ? ? ? ?
     而這樣的數(shù)據(jù)庫(kù)表是不符合第一范式的:
    字段1 字段2 字段3 字段4
    ? ? 字段3.1 字段3.2 ?

     

         很顯然,在當(dāng)前的任何關(guān)系數(shù)據(jù)庫(kù)管理系統(tǒng)(DBMS)中,傻瓜也不可能做出不符合第一范式的數(shù)據(jù)庫(kù),因?yàn)檫@些DBMS不允許你把數(shù)據(jù)庫(kù)表的一列再分成二列或多列。因此,你想在現(xiàn)有的DBMS中設(shè)計(jì)出不符合第一范式的數(shù)據(jù)庫(kù)都是不可能的。
         第二范式(2NF):數(shù)據(jù)庫(kù)表中不存在非關(guān)鍵字段對(duì)任一候選關(guān)鍵字段的部分函數(shù)依賴(部分函數(shù)依賴指的是存在組合關(guān)鍵字中的某些字段決定非關(guān)鍵字段的情況),也即所有非關(guān)鍵字段都完全依賴于任意一組候選關(guān)鍵字。
         假定選課關(guān)系表為SelectCourse(學(xué)號(hào), 姓名, 年齡, 課程名稱, 成績(jī), 學(xué)分),關(guān)鍵字為組合關(guān)鍵字(學(xué)號(hào), 課程名稱),因?yàn)榇嬖谌缦聸Q定關(guān)系:
         (學(xué)號(hào), 課程名稱) → (姓名, 年齡, 成績(jī), 學(xué)分)
         這個(gè)數(shù)據(jù)庫(kù)表不滿足第二范式,因?yàn)榇嬖谌缦聸Q定關(guān)系:
         (課程名稱) → (學(xué)分)
         (學(xué)號(hào)) → (姓名, 年齡)
    即存在組合關(guān)鍵字中的字段決定非關(guān)鍵字的情況。
         由于不符合2NF,這個(gè)選課關(guān)系表會(huì)存在如下問(wèn)題:
         (1) 數(shù)據(jù)冗余:
         同一門課程由n個(gè)學(xué)生選修,"學(xué)分"就重復(fù)n-1次;同一個(gè)學(xué)生選修了m門課程,姓名和年齡就重復(fù)了m-1次。
         (2) 更新異常:
         若調(diào)整了某門課程的學(xué)分,數(shù)據(jù)表中所有行的"學(xué)分"值都要更新,否則會(huì)出現(xiàn)同一門課程學(xué)分不同的情況。
         (3) 插入異常:
         假設(shè)要開(kāi)設(shè)一門新的課程,暫時(shí)還沒(méi)有人選修。這樣,由于還沒(méi)有"學(xué)號(hào)"關(guān)鍵字,課程名稱和學(xué)分也無(wú)法記錄入數(shù)據(jù)庫(kù)。
         (4) 刪除異常:
         假設(shè)一批學(xué)生已經(jīng)完成課程的選修,這些選修記錄就應(yīng)該從數(shù)據(jù)庫(kù)表中刪除。但是,與此同時(shí),課程名稱和學(xué)分信息也被刪除了。很顯然,這也會(huì)導(dǎo)致插入異常。

         把選課關(guān)系表SelectCourse改為如下三個(gè)表:
         學(xué)生:Student(學(xué)號(hào), 姓名, 年齡);
         課程:Course(課程名稱, 學(xué)分);
         選課關(guān)系:SelectCourse(學(xué)號(hào), 課程名稱, 成績(jī))。
         這樣的數(shù)據(jù)庫(kù)表是符合第二范式的,消除了數(shù)據(jù)冗余、更新異常、插入異常和刪除異常。
         另外,所有單關(guān)鍵字的數(shù)據(jù)庫(kù)表都符合第二范式,因?yàn)椴豢赡艽嬖诮M合關(guān)鍵字。
         第三范式(3NF):在第二范式的基礎(chǔ)上,數(shù)據(jù)表中如果不存在非關(guān)鍵字段對(duì)任一候選關(guān)鍵字段的傳遞函數(shù)依賴則符合第三范式。所謂傳遞函數(shù)依賴,指的是如果存在"A → B → C"的決定關(guān)系,則C傳遞函數(shù)依賴于A。因此,滿足第三范式的數(shù)據(jù)庫(kù)表應(yīng)該不存在如下依賴關(guān)系:
         關(guān)鍵字段 → 非關(guān)鍵字段x → 非關(guān)鍵字段y
         假定學(xué)生關(guān)系表為Student(學(xué)號(hào), 姓名, 年齡, 所在學(xué)院, 學(xué)院地點(diǎn), 學(xué)院電話),關(guān)鍵字為單一關(guān)鍵字"學(xué)號(hào)",因?yàn)榇嬖谌缦聸Q定關(guān)系:
         (學(xué)號(hào)) → (姓名, 年齡, 所在學(xué)院, 學(xué)院地點(diǎn), 學(xué)院電話)
    這個(gè)數(shù)據(jù)庫(kù)是符合2NF的,但是不符合3NF,因?yàn)榇嬖谌缦聸Q定關(guān)系:
         (學(xué)號(hào)) → (所在學(xué)院) → (學(xué)院地點(diǎn), 學(xué)院電話)
    即存在非關(guān)鍵字段"學(xué)院地點(diǎn)"、"學(xué)院電話"對(duì)關(guān)鍵字段"學(xué)號(hào)"的傳遞函數(shù)依賴。
         它也會(huì)存在數(shù)據(jù)冗余、更新異常、插入異常和刪除異常的情況,讀者可自行分析得知。
         把學(xué)生關(guān)系表分為如下兩個(gè)表:
         學(xué)生:(學(xué)號(hào), 姓名, 年齡, 所在學(xué)院);
         學(xué)院:(學(xué)院, 地點(diǎn), 電話)。
    這樣的數(shù)據(jù)庫(kù)表是符合第三范式的,消除了數(shù)據(jù)冗余、更新異常、插入異常和刪除異常。
         鮑依斯-科得范式(BCNF):在第三范式的基礎(chǔ)上,數(shù)據(jù)庫(kù)表中如果不存在任何字段對(duì)任一候選關(guān)鍵字段的傳遞函數(shù)依賴則符合第三范式。
         假設(shè)倉(cāng)庫(kù)管理關(guān)系表為StorehouseManage(倉(cāng)庫(kù)ID, 存儲(chǔ)物品ID, 管理員ID, 數(shù)量),且有一個(gè)管理員只在一個(gè)倉(cāng)庫(kù)工作;一個(gè)倉(cāng)庫(kù)可以存儲(chǔ)多種物品。這個(gè)數(shù)據(jù)庫(kù)表中存在如下決定關(guān)系:
         (倉(cāng)庫(kù)ID, 存儲(chǔ)物品ID) →(管理員ID, 數(shù)量)
         (管理員ID, 存儲(chǔ)物品ID) → (倉(cāng)庫(kù)ID, 數(shù)量)
         所以,(倉(cāng)庫(kù)ID, 存儲(chǔ)物品ID)和(管理員ID, 存儲(chǔ)物品ID)都是StorehouseManage的候選關(guān)鍵字,表中的唯一非關(guān)鍵字段為數(shù)量,它是符合第三范式的。但是,由于存在如下決定關(guān)系:
         (倉(cāng)庫(kù)ID) → (管理員ID)
         (管理員ID) → (倉(cāng)庫(kù)ID)
    即存在關(guān)鍵字段決定關(guān)鍵字段的情況,所以其不符合 BCNF范式。它會(huì)出現(xiàn)如下異常情況:
         (1) 刪除異常:
         當(dāng)倉(cāng)庫(kù)被清空后,所有"存儲(chǔ)物品ID"和"數(shù)量"信息被刪除的同時(shí),"倉(cāng)庫(kù)ID"和"管理員ID"信息也被刪除了。
         (2) 插入異常:
         當(dāng)倉(cāng)庫(kù)沒(méi)有存儲(chǔ)任何物品時(shí),無(wú)法給倉(cāng)庫(kù)分配管理員。
         (3) 更新異常:
         如果倉(cāng)庫(kù)換了管理員,則表中所有行的管理員ID都要修改。
         把倉(cāng)庫(kù)管理關(guān)系表分解為二個(gè)關(guān)系表:
         倉(cāng)庫(kù)管理:StorehouseManage(倉(cāng)庫(kù)ID, 管理員ID);
         倉(cāng)庫(kù):Storehouse(倉(cāng)庫(kù)ID, 存儲(chǔ)物品ID, 數(shù)量)。
         這樣的數(shù)據(jù)庫(kù)表是符合BCNF范式的,消除了刪除異常、插入異常和更新異常。


    原帖地址: http://www.cublog.cn/u/23975/showart.php?id=391210

    posted @ 2011-02-21 14:45 AK47 閱讀(321) | 評(píng)論 (0)編輯 收藏

    <2011年2月>
    303112345
    6789101112
    13141516171819
    20212223242526
    272812345
    6789101112

    導(dǎo)航

    統(tǒng)計(jì)

    常用鏈接

    留言簿

    隨筆分類

    隨筆檔案

    搜索

    最新評(píng)論

    閱讀排行榜

    評(píng)論排行榜

    主站蜘蛛池模板: 亚洲综合色婷婷在线观看| 在线观看特色大片免费网站| 69精品免费视频| 免费成人av电影| 亚洲乱码一二三四区国产| a级毛片高清免费视频| 午夜爱爱免费视频| 亚洲国产精品不卡在线电影| 一区二区免费国产在线观看| 一个人免费观看www视频在线| 亚洲va久久久噜噜噜久久| 国产成人综合亚洲| 成人啪精品视频免费网站| 亚洲综合色丁香麻豆| 在线观看片免费人成视频播放| 国产又大又粗又硬又长免费| 亚洲一区免费在线观看| 精品一卡2卡三卡4卡免费视频| 亚洲第一永久AV网站久久精品男人的天堂AV | 老司机亚洲精品影院| 狠狠躁狠狠爱免费视频无码| 日本成人在线免费观看| 亚洲区视频在线观看| 久久久免费精品re6| 亚洲AV无码一区二区二三区入口| 九九九国产精品成人免费视频| 日韩精品视频免费观看| 亚洲中文字幕无码爆乳app| 国产a视频精品免费观看| 亚洲人成电影亚洲人成9999网 | 一个人看的www免费视频在线观看| 亚洲第一黄色网址| 免费国产污网站在线观看不要卡| 成人免费视频小说| 国产亚洲玖玖玖在线观看| 成人免费在线看片| 亚洲成电影在线观看青青| 3d成人免费动漫在线观看| 亚洲久本草在线中文字幕| 日本xxxx色视频在线观看免费| 久久精品视频亚洲|