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

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

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

    2010年6月10日

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

    數(shù)據(jù)庫連接分為:內(nèi)連接,外連接(左、右連接,全連接),交叉連接
    文章地址 : http://www.zxbc.cn/html/20080527/51189.html
    轉(zhuǎn)載 
    內(nèi)連接:把兩個表中數(shù)據(jù)對應(yīng)的數(shù)據(jù)查出來 
    外連接:以某個表為基礎(chǔ)把對應(yīng)數(shù)據(jù)查出來(全連接是以多個表為基礎(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(查找條件中對應(yīng)的數(shù)據(jù),no4沒有數(shù)據(jù)不列出來) 
    語法: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ù),右表中對應(yīng)數(shù)據(jù)) 
    語法: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ù),左表中對應(yīng)數(shù)據(jù)) 
    語法: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 
    全連接 
    語法: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 將左連接和右連接合并后才可以

    交叉連接
    將兩個表所有行組合,連接后的行數(shù)為兩個表行數(shù)的乘積(笛卡爾積)
    語法,借用上面的例子應(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 閱讀(490) | 評論 (0)編輯 收藏

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

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

    原創(chuàng)文章,轉(zhuǎn)載請注明出處。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) | 評論 (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中是一個很奇妙的interceptor stack,以至于很多人疑問為何不將其設(shè)置為默認(rèn)的interceptor stack。paramsPrepareParamsStack主要解決了ModelDriven和Preparable的配合問題,從字面上理解來說, 這個stack的攔截器調(diào)用的順序為:首先params,然后prepare,接下來modelDriven,最后再params。Struts 2.0的設(shè)計上要求modelDriven在params之前調(diào)用,而業(yè)務(wù)中prepare要負(fù)責(zé)準(zhǔn)備model,準(zhǔn)備model又需要參數(shù),這就需要在 prepare之前運(yùn)行params攔截器設(shè)置相關(guān)參數(shù),這個也就是創(chuàng)建paramsPrepareParamsStack的原因。流程如下:
       1. params攔截器首先給action中的相關(guān)參數(shù)賦值,如id  
       2. prepare攔截器執(zhí)行prepare方法,prepare方法中會根據(jù)參數(shù),如id,去調(diào)用業(yè)務(wù)邏輯,設(shè)置model對象
       3. modelDriven攔截器將model對象壓入value stack,這里的model對象就是在prepare中創(chuàng)建的
       4. params攔截器再將參數(shù)賦值給model對象
       5. action的業(yè)務(wù)邏輯執(zhí)行 依據(jù)此stack,一個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ù),因為prepare方法已經(jīng)準(zhǔn)備好了model,這些方法很簡單。對于update 方法,prepare首先會從數(shù)據(jù)庫中加載數(shù)據(jù),然后params攔截器會將參數(shù)值付給model,在update直接更新就可以,不會出現(xiàn)數(shù)據(jù)被亂更新 的情況。象Hibernate框架,會判斷哪些字段更新了,然后進(jìn)行更新,性能也不會損失。
    通過paramsPrepareParamsStack可以讓流程更明確,代碼更簡潔,也更利于大家的交流。

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

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

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

        name = 超人
        price = 10000

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

    攔截器的源代碼:

    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())
                {
                    
    //  下面會使用setValue方法修改ValueStack對象中的相應(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();
        }
    }

    用于測試的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>

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

    測試結(jié)果:

    name:中國
    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前面(將兩個<interceptor-ref>元素掉換一下),就可以通過同名勝Action配置參數(shù)或請求參數(shù) 來干預(yù)最終究輸出結(jié)果了。

    posted @ 2011-11-11 17:21 AK47 閱讀(373) | 評論 (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(值棧)   在這一切的背后,是因為有了ValueStack(值棧)!   Valu...  閱讀全文

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

    structs2配置UrlRewriteFilter

    轉(zhuǎn)載每個網(wǎng)頁或請求都是一個url地址,一般,這個地址可能是.do,.page,.action之類的并加上'?'號、'&'號查詢串等構(gòu)成的一個長長的的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可以很好的改善這個狀況。網(wǎng)站url rewrite應(yīng)用是非常廣泛的,良好的url設(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過濾器-->
        <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過濾器-->
        <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ù)具體需要寫規(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 閱讀(1777) | 評論 (0)編輯 收藏

    structs2 filter的執(zhí)行順序

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

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

    structs2攔截器

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

    配置攔截器:Struts2中提供了大量的攔截器,多個攔截器可以組成一個攔截器棧,系統(tǒng)配置了一個默認(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


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

    攔截器要保證線程安全。因為structs2中攔截器會在請求間共享

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

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

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

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

    重新認(rèn)識Java finally

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

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

    finally“微型子例程”不等同于方法函數(shù)的調(diào)用,finally子句都是在同一個棧內(nèi)執(zhí)行的,微型子例程的“返回”操作也不會涉及到方法退棧,僅僅是使程序計數(shù)器pc跳轉(zhuǎn)到同一個方法的一個不同的位置繼續(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ī)制的一個瑕疵-異常丟失。

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

      athrow   // throw the exception

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

    在JDK1.6中,通過字節(jié)碼我們可以看到,finally子句作為一種特殊的catch來實現(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òu)造的新異常,這個新異常就會覆蓋try語句塊中的異常。
    二 返回值覆蓋

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

    這個方法的返回值是100還是200?結(jié)果是100。
    在字節(jié)碼中,return語句不是原子性操作,它會把getValue()中的return語句分解為幾步操作:
    1) 把value值存儲到一個局部變量(這里命名為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語句在返回之前會把返回值保存到一個臨時的局部變量中,所以在finally子句內(nèi)對value重新賦值不會影響返回值。

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

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

    posted @ 2011-11-01 16:56 AK47 閱讀(832) | 評論 (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>

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

    2.將jqgrid加入頁面中

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

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

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

    下面是一個簡單的例子:

    <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的重要選項

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

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

    2.1 prmNames選項

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

    prmNames : {

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

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

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

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

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

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

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

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

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

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

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

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

    npage: null,

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

    }

    2.2 jsonReader選項

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

    jsonReader : {

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

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

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

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

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

    cell: "cell",

    id: "id",

    userdata: "userdata",

    subgrid: {

    root:"rows",

    repeatitems: true,

    cell:"cell"

    }

    }

    假如有下面一個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日"}]}

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

    root: "griddata",

    total: "totalpages",

    page: "currpage",

    records: "totalrecords",

    repeatitems: false

    }

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

    repeatitems為true時:

    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了,但是需要保持對應(yīng)

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

                      ...  

         ]  

    }  

    repeatitems為false時:

    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的重要選項

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

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

    三、 注意事項

    1. 動態(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)擊編輯的時候都會執(zhí)行。initComparator的作用是通過ajax獲取數(shù)據(jù),然后利 用$("#list_d").jqGrid('setColProp', 'Comparator', { editoptions: { value: valueString} });來設(shè)置Comparator下拉中的內(nèi)容。其中valueString的格式如下’ equal to: equal to; not equal to: not equal to’。鍵值之間用冒號隔開,2項之間用分號隔開。注意:把recreateForm設(shè)為true,否則'setColProp'只在第一次調(diào)用時有效。

    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加載完成的時候自動選中第一行。 loadComplete:function(data){$("#list").jqGrid('setSelection', "1");

    }

    6. 對于像1中的可編輯的字段,可以設(shè)定rule,參見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 閱讀(2321) | 評論 (0)編輯 收藏

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

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

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

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

        */   


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

    /*getBean的默認(rèn)名稱是類名(頭字母小 寫),如果想自定義,可以@Service(“aaaaa”)這樣來指定,這種bean默認(rèn)是單例的,如果想改變,可以使用 @Service(“beanName”) @Scope(“prototype”)來改變??梢允褂靡韵路绞街付ǔ跏蓟椒ê弯N毀方法(方法名任意): @PostConstruct public void init() {  

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

    注入方式:

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

    注解:

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

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

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

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

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

    否則可以省略,只寫@Autowired   。 

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

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

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

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


    @Service 
    public class VentorServiceImpl implements iVentorService { 
    }

    @Repository 
    public class VentorDaoImpl implements iVentorDao { 


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

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

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

    @PostConstruct

    public void init() { 



    @PreDestroy

    public void destory() { 

    }

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

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

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

    概述

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

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

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

     
    原來我們是怎么做的      
    在使用注釋配置之前,先來回顧一下傳統(tǒng)上是如何配置 Bean 并完成 Bean 之間依賴關(guān)系的建立。下面是 3 個類,它們分別是 Office、Car 和 Boss,這 3 個類需要在 Spring 容器中配置為 Bean:    
       
    Office 僅有一個屬性:    
         
    清單 1. Office.java    
                        
    package com.baobaotao;    
    public class Office {    
        private String officeNo =”001”;    
       
        //省略 get/setter    
       
        @Override   
        public String toString() {    
            return "officeNo:" + officeNo;    
        }    
    }    
           
    Car 擁有兩個屬性:    
         
    清單 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 類型的兩個屬性:    
      
    清單 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;    
        }    
    }    
        
    我們在 Spring 容器中將 Office 和 Car 聲明為 Bean,并注入到 Boss Bean 中:下面是使用傳統(tǒng) XML 完成這個工作的配置文件 beans.xml:    
        
    清單 4. beans.xml 將以上三個類配置成 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)行以下代碼時,控制臺將正確打出 boss 的信息:    
      
    清單 5. 測試類: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);    
        }    
    }    
        
    這說明 Spring 容器已經(jīng)正確完成了 Bean 創(chuàng)建和裝配的工作。    
         
    使用 @Autowired 注釋    
       
    Spring 2.5 引入了 @Autowired 注釋,它可以對類成員變量、方法及構(gòu)造函數(shù)進(jìn)行標(biāo)注,完成自動裝配的工作。來看一下使用 @Autowired 進(jìn)行成員變量自動注入的代碼:    
      
    清單 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 通過一個 BeanPostProcessor 對 @Autowired 進(jìn)行解析,所以要讓 @Autowired 起作用必須事先在 Spring 容器中聲明 AutowiredAnnotationBeanPostProcessor Bean。   

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

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

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

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

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

     

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

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


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

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

    Hibernate 實體對象的生命周期匯總

    本帖匯總了網(wǎng)上幾篇關(guān)于hibernate的生命周期的帖子。

    轉(zhuǎn)載:

    實體對象的生命周期在Hibernate應(yīng)用中是一個很關(guān)鍵的概念,正確的理解實體對象的生命周期將對我們應(yīng)用Hibernate做持久層設(shè)計起到很大的作用.而所謂的實體對象的生命周期就是指實體對象由產(chǎn)生到被GC回收的一段過程.在這過程中我們需要理解的就是實體對象生命周期中的三種狀態(tài).

    1. 自由狀態(tài)(Transient)
    所謂的Transient狀態(tài),即實體對象在內(nèi)存中自由存在,與數(shù)據(jù)庫中的記錄無關(guān),通常是我們的J2EE中 VO,并沒有被納入Hibernate的實體管理容器.

    1    Test test = new Test();
    2        test.setName("energykk");
    3        //此時的test對象處于Transient(自由狀態(tài))并沒有被Hibernate框架所管理
    4        

    2.持久狀態(tài)(Persistent)
    何謂 Persistent? 即實體對象已經(jīng)處于被Hibernate實體管理容器容器所管理的狀態(tài).這種狀態(tài)下這個實體對象的引用將被納入Hibernate實體管理容器容器所管理.
    處于Persistent狀態(tài)的實體對象,對它的變更也將被固化到數(shù)據(jù)庫中.
    在J2EE中通常指的是一個PO.
    Transaction tr = session.beginTransaction();
            session.save(test);
            
    //此時的test對象已經(jīng)處于Persistent(持久狀態(tài))它被Hibernate 納入實體管理容器
            tr.commit();
            Transaction tr2 
    = session.beginTransaction();
            test.setName(
    "xukai");
            
    //在這個事務(wù)中我們并沒有顯示的調(diào)用save()方法但是由于Persistent狀態(tài)的對象將會自動的固化到
            
    //數(shù)據(jù)庫中,因此此時正處在Persistent狀態(tài)的test對象的變化也將自動被同步到數(shù)據(jù)庫中
            tr2.commit();

    處于Persistent狀態(tài)的實體可以簡單的理解為:如果一個實體對象與session發(fā)生了關(guān)聯(lián),并且處于session的有效期內(nèi),那么這個實體對象就處于Persistent狀態(tài).

    3.游離狀態(tài)(Detached)
    處于Persistent狀態(tài)的實體對象,其對應(yīng)的session關(guān)閉以后,那么這個實體就處于 Detached狀態(tài).
    我們可以認(rèn)為session對象就是一個Persistent的宿主,一旦這個宿主失效,那么這個實體就處于 Detached狀態(tài).

    session.close();
            
    //與test對象關(guān)聯(lián)的session被關(guān)閉,因此此時的test對象進(jìn)入 Detached(游離狀態(tài))
            
            session2 
    = HibernateSessionFactory.getSession();
            Transaction tr3 
    = session2.beginTransaction();
            session2.update(test);
            
    //此時正處于Detached狀態(tài)的test對象由于再次借助與session2被納入到Hibernate的實體管理容器所以此時的
            
    //test對象恢復(fù)到Persistent狀態(tài)
            test.setName("jjjj");
            tr3.commit();
            
            session2.close();

    既然Transient狀態(tài)的實體與Detached狀態(tài)的實體都與Hibernate的實體管理容器沒有關(guān)系,那他們到底存在哪些差異?
    差異就在于處于Transient狀態(tài)的只有一個Name的屬性.此時的test對象所包含的數(shù)據(jù)信息僅限于此,他與數(shù)據(jù)庫中的記錄沒有任何瓜葛.
    但是處于Detached狀態(tài)的實體已經(jīng)不止包含Name這個屬性,還被賦予了主鍵也就是通常POJO里的id屬性,由于id是主鍵,他可以確定數(shù)據(jù)庫表中的一條
    唯一的記錄,那么自然的處于Detached狀態(tài)的實體就能與數(shù)據(jù)庫表中擁有相同id的記錄相關(guān)聯(lián).
    這就是他們之間所存在的差異, 簡而言之,Transient狀態(tài)的實體缺乏與數(shù)據(jù)庫表記錄之間的聯(lián)系,而Detached狀態(tài)的試題恰恰相反.只不過是脫離了session這個數(shù)據(jù)庫操作平臺而已.
    原帖地址 : http://www.tkk7.com/energykk/archive/2007/05/08/115927.html

     生命周期圖:
    原圖地址:http://hi.baidu.com/quest2run/blog/item/39e1d08c7dbd45f4503d9222.html
     

    persistence context



    生命周期特征總結(jié) :
    原帖地址 : http://blog.csdn.net/hgd250/archive/2008/08/06/2775943.aspx
    Transient:

        與數(shù)據(jù)庫中的記錄沒有任何關(guān)系,即沒有與其相關(guān)聯(lián)的數(shù)據(jù)庫記錄.
        與session沒有任何關(guān)系.即沒有通過session對象的實例對其進(jìn)行任何持久化的操作
    Persistent:
        每個persistent狀態(tài)的實體對象都與一個session對象的實例相關(guān)聯(lián)
        處于 Persistent狀態(tài)的實體對象是與數(shù)據(jù)庫中的記錄相關(guān)聯(lián)的.
        Hibernate會依據(jù)persistent狀態(tài)的實體對象的屬性變化而改變數(shù)據(jù)庫中相對應(yīng)的記錄
    .
    Detached:
        游離態(tài)是由持久態(tài)實體對象轉(zhuǎn)變而來的.
        游離態(tài)實體不再與session對象相關(guān)聯(lián).
        游離態(tài)實體對象與數(shù)據(jù)庫中的記錄沒有直接聯(lián)系,對其所做的任何修改將不會影響到到數(shù)據(jù)庫中的數(shù)據(jù).
        游離態(tài)實體對象在數(shù)據(jù)庫有相對應(yīng)的數(shù)據(jù)記錄,如果沒有被其他事務(wù)刪除.

    posted @ 2011-02-14 14:26 AK47 閱讀(333) | 評論 (0)編輯 收藏

    (轉(zhuǎn)貼)BigInteger 和 BigDecimal

    高精度數(shù)字
    Java 提供了兩個類專門用于進(jìn)行高精度運(yùn)算BigInteger 和 BigDecimal ,盡管它們可大致劃分到與封裝器相同的類別里,但兩者都沒有對應(yīng)的主類型;這兩個類都有自己的一系列方法,類似于我們針對主類型執(zhí)行的操作,也就是說能用 int 或float 做的事情,用BigInteger和BigDecimal 一樣可以做,只是必須換用方法調(diào)用,而不是使用運(yùn)算符。此外由于牽涉更多,所以運(yùn)算速度會慢一點(diǎn)總之我們犧牲了速度,但換來了精度。

    高精度浮點(diǎn)數(shù)BigDecimal

    一些非整數(shù)值(如幾美元和幾美分這樣的小數(shù))需要很精確。浮點(diǎn)數(shù)不是精確值,所以使用它們會導(dǎo)致舍入誤差。因此,使用浮點(diǎn)數(shù)來試圖表示象貨幣量這樣的精確數(shù)量不是一個好的想法。使用浮點(diǎn)數(shù)來進(jìn)行美元和美分計算會得到災(zāi)難性的后果。浮點(diǎn)數(shù)最好用來表示象測量值這類數(shù)值,這類值從一開始就不怎么精確。
        從 JDK 1.3 起,Java 開發(fā)人員就有了另一種數(shù)值表示法來表示非整數(shù):BigDecimal。BigDecimal 是標(biāo)準(zhǔn)的類,在編譯器中不需要特殊支持,它可以表示任意精度的小數(shù),并對它們進(jìn)行計算。在內(nèi)部,可以用任意精度任何范圍的值和一個換算因子來表示 BigDecimal,換算因子表示左移小數(shù)點(diǎn)多少位,從而得到所期望范圍內(nèi)的值。因此,用 BigDecimal 表示的數(shù)的形式為 unscaledValue*10-scale。
    用于加、減、乘和除的方法給  BigDecimal 值提供了算術(shù)運(yùn)算。由于 BigDecimal 對象是不可變的,這些方法中的每一個都會產(chǎn)生新的 BigDecimal 對象。因此,因為創(chuàng)建對象的開銷,BigDecimal 不適合于大量的數(shù)學(xué)計算,但設(shè)計它的目的是用來精確地表示小數(shù)。如果您正在尋找一種能精確表示如貨幣量這樣的數(shù)值,則 BigDecimal 可以很好地勝任該任務(wù)。
    如浮點(diǎn)類型一樣,BigDecimal 也有一些令人奇怪的行為。尤其在使用 equals() 方法來檢測數(shù)值之間是否相等時要小心。equals() 方法認(rèn)為,兩個表示同一個數(shù)但換算值不同(例如,100.00 和  100.000)的 BigDecimal 值是不相等的。然而,compareTo() 方法會認(rèn)為這兩個數(shù)是相等的,所以在從數(shù)值上比較兩個  BigDecimal 值時,應(yīng)該使用 compareTo() 而不是 equals()。
    另外還有一些情形,任意精度的小數(shù)運(yùn)算仍不能表示精確結(jié)果。例如,1 除以 9 會產(chǎn)生無限循環(huán)的小數(shù) .111111...。出于這個原因,在進(jìn)行除法運(yùn)算時,BigDecimal 可以讓您顯式地控制舍入。movePointLeft() 方法支持 10 的冪次方的精確除法。
    對于 BigDecimal,有幾個可用的構(gòu)造函數(shù)。其中一個構(gòu)造函數(shù)以雙精度浮點(diǎn)數(shù)作為輸入,另一個以整數(shù)和換算因子作為輸入,還有一個以小數(shù)的 String 表示作為輸入。要小心使用  BigDecimal(double) 構(gòu)造函數(shù), 因為如果不了解它,會在計算過程中產(chǎn)生舍入誤差。請使用基于整數(shù)或 String 的構(gòu)造函數(shù)。
    如果使用 BigDecimal(double) 構(gòu)造函數(shù)不恰當(dāng),在傳遞給 JDBC setBigDecimal() 方法時,會造成似乎很奇怪的 JDBC 驅(qū)動程序中的異常。例如,考慮以下 JDBC 代碼,該代碼希望將數(shù)字 0.01 存儲到小數(shù)字段:
      PreparedStatement ps =connection.prepareStatement("INSERT INTO Foo SET name=?, value=?");
      ps.setString(1, "penny");
      ps.setBigDecimal(2, new BigDecimal(0.01));
      ps.executeUpdate();
         在執(zhí)行這段似乎無害的代碼時會拋出一些令人迷惑不解的異常(這取決于具體的 JDBC 驅(qū)動程序),因為 0.01 的雙精度近似值會導(dǎo)致大的換算值,這可能會使 JDBC 驅(qū)動程序或數(shù)據(jù)庫感到迷惑。JDBC 驅(qū)動程序會產(chǎn)生異常,但可能不會說明代碼實際上錯在哪里,除非意識到二進(jìn)制浮點(diǎn)數(shù)的局限性。相反,使用 BigDecimal("0.01") 或 BigDecimal(1, 2) 構(gòu)造 BigDecimal 來避免這類問題, 因為這兩種方法都可以精確地表示小數(shù)。
     

    code :

    import java.math.BigDecimal;
    /** * *
    * <p>Title: 開源,開放</p>
    * * <p>Description: opeansource</p>
    * * <p>Copyright: Copyright (c) 2004</p>
    * * <p>Company: ?海棠</p>
    * * @author HaiTang Ming
    * * @version 1.0 */
    public class BigDecimalUtil { 
    //默認(rèn)除法運(yùn)算精度,及即保留小數(shù)點(diǎn)多少位 
    private static final int DEF_DIV_SCALE = 2; 
    //這個類不能實例化 
    private BigDecimalUtil (){   } 
    /**   
      * * 提供精確的加法運(yùn)算。   
      * * @param v1 被加數(shù)   
      * * @param v2 加數(shù)   
      * * @return 兩個參數(shù)的和   
      * */ 
    public static double add(double v1,double v2){   
      BigDecimal b1 = new BigDecimal(Double.toString(v1));   
      BigDecimal b2 = new BigDecimal(Double.toString(v2));   
      return (b1.add(b2)).doubleValue(); 

    /**

      *提供精確的減法運(yùn)算。 
      * * @param v1 被減數(shù) 
      * * @param v2 減數(shù) 
      * * @return 兩個參數(shù)的差
      **/ 
    public static double sub(double v1,double v2){   
      BigDecimal b1 = new BigDecimal(Double.toString(v1));   
      BigDecimal b2 = new BigDecimal(Double.toString(v2));   
      return (b1.subtract(b2)).doubleValue(); 

    /**   
      * * 提供精確的乘法運(yùn)算。   
      * * @param v1 被乘數(shù)   
      * * @param v2 乘數(shù)   
      * * @return 兩個參數(shù)的積   
      * */
    public static double mul(double v1,double v2){   
      BigDecimal b1 = new BigDecimal(Double.toString(v1));   
      BigDecimal b2 = new BigDecimal(Double.toString(v2));   
      return (b1.multiply(b2)).doubleValue(); 

    /**   
      * * 提供(相對)精確的除法運(yùn)算,當(dāng)發(fā)生除不盡的情況時,精確到   
      * * 小數(shù)點(diǎn)以后多少位,以后的數(shù)字四舍五入。   
      * * @param v1 被除數(shù)   
      * * @param v2 除數(shù)   
      * * @return 兩個參數(shù)的商   
      * */ 
    public static double div(double v1,double v2){   
      return div(v1,v2,DEF_DIV_SCALE); 

    /**   
      * * 提供(相對)精確的除法運(yùn)算。當(dāng)發(fā)生除不盡的情況時,由scale參數(shù)指   
      * * 定精度,以后的數(shù)字四舍五入。   
      * * @param v1 被除數(shù) 
      * @param v2 除數(shù)   
      * * @param scale 表示表示需要精確到小數(shù)點(diǎn)以后幾位。   
      * * @return 兩個參數(shù)的商   
      * */ 
    public static double div(double v1,double v2,int scale){   
      if(scale<0){     
       throw new IllegalArgumentException("The scale must be a positive integer or zero");   
      }   
      BigDecimal b1 = new BigDecimal(Double.toString(v1));   
      BigDecimal b2 = new BigDecimal(Double.toString(v2));   
      return (b1.divide(b2,scale,BigDecimal.ROUND_HALF_UP)).doubleValue(); 

    /**   
      * * 提供精確的小數(shù)位四舍五入處理。   
      * * @param v 需要四舍五入的數(shù)字   
      * * @param scale 小數(shù)點(diǎn)后保留幾位   
      * * @return 四舍五入后的結(jié)果   
      * */ 
    public static double round(double v,int scale){ 
      if(scale<0){     
       throw new IllegalArgumentException("The scale must be a positive integer or zero");
      }   
      BigDecimal b = new BigDecimal(Double.toString(v));   
      BigDecimal one = new BigDecimal("1");   
      return (b.divide(one,scale,BigDecimal.ROUND_HALF_UP)).doubleValue(); 
    }   
    public static void main(String[] args){   
      System.out.println(add(234.44,534.90));
     
      double a = 123.345678;   
      double d = round(a,2);   
      System.out.println("round("+a+",2)--->"+d); 
    }
    }

    高精度整數(shù)BigInteger

    BigInteger支持任意精度的整數(shù),也就是說我們可精確表示任意大小的整數(shù)值;同時在運(yùn)算過程中不會丟失任何信息;
    在BigInteger類中有所有的基本算術(shù)運(yùn)算方法,如加、減、乘、除,以及可能會用到的位運(yùn)算如或、異或、非、左移、右移等。下面是一些方法的例子:當(dāng)然,如果要有更多的使用方法,可以查閱java api 。

    code :public class BigIntegerTest { 
    public BigIntegerTest() {   } 
    /**   
      * * 測試BigInteger
      * */ 
    public static void testBigInteger() {   
      BigInteger bi = new BigInteger("888");   
      //multiply :乘法   
      BigInteger result = bi.multiply(new BigInteger("2"));   
      System.out.println(result);   
      //divide : 除法   
      result = bi.divide(new BigInteger("2"));   
      System.out.println(result);   
      //add : 加法   
      result = bi.add(new BigInteger("232"));   
      System.out.println(result);   
      //subtract :減法   
      result = bi.subtract(new BigInteger("23122"));   
      System.out.println(result);   
      result = bi.shiftRight(2);   
      System.out.println(result); 
    }   
    public static void main(String[] args) {   
      testBigInteger(); 
    }
    }
    原貼地址http://dev.firnow.com/course/3_program/java/javaxl/2008914 /142796_2.html

    posted @ 2010-12-10 14:16 AK47 閱讀(1030) | 評論 (0)編輯 收藏

    (轉(zhuǎn)貼) 超大整數(shù)相加,超過了long的范圍,你要怎么做!

     

    引用:

     這個只能夠用字符串的形式來處理了,因為計算機(jī)能夠處理的最大是long型,本文以字符串的形式來進(jìn)行超大數(shù)據(jù)的相加,理論上只要你的內(nèi)存允許,相加多大的數(shù)都可以。

    /**

     * 超大整數(shù)相加:

     * 題目要求:如果系統(tǒng)要使用超大整數(shù)(超過long的范圍),請你設(shè)計一個數(shù)據(jù)結(jié)構(gòu)來存儲這種

     * 超大型數(shù)字以及設(shè)計一種算法來實現(xiàn)超大整數(shù)的加法運(yùn)算

     * @author Administrator

     *

     */

    public class VeryBigNumAdd {

     

        /**

         * @param args

         */

        public static void main(String[] args) {

           // TODO Auto-generated method stub

           /*

           String a="1223232";

           for(int i=a.length()-1;i>=0;i--)

           {

               System.out.print(a.charAt(i));

           }

           */

           VeryBigNumAdd vbn=new VeryBigNumAdd();

           String a="123453243455535634535252345234677576252241234123523453664563634";

           String b="123453243455535634535252345234677576252241234123523453664563634";

           String result=vbn.doAdd(a,b);

           System.out.println("result:"+result);

        }

        /**

         *

         * @param a 加數(shù)字符串1

         * @param b 加數(shù)字符串2

         * @return 結(jié)果字符串

         * 分析:

         * 1、取得兩個字符串的長度

         * 2、把兩個的長度做比較,并得出較長的長度,及較短的長度

         * 3、把長度較短的加數(shù)字符串,在左面補(bǔ)0,使之與較長的字符串一樣長

         * 4、從最高位,一個個數(shù)的取出來相加,當(dāng)然首先得轉(zhuǎn)換為整型

         * 5、設(shè)置進(jìn)位,如果兩個數(shù)相加及加上進(jìn)位大于等于10,并且這不是最左邊一個字符相加,相加結(jié)果等于

         *    (取出1+取出2+進(jìn)位)-10,并把進(jìn)位設(shè)為1;如果沒有大于10,就把進(jìn)位設(shè)為0,如些循環(huán),把

         *    相加的結(jié)果以字符串的形式結(jié)合起來,就得到最后的結(jié)果

         */

        String doAdd(String a,String b)

        {

           String str="";

           int lenA=a.length();

           int lenB=b.length();

           int maxLen=(lenA>lenB) ? lenA : lenB;

           int minLen=(lenA<lenB) ? lenA : lenB;

           String strTmp="";

           for(int i=maxLen-minLen;i>0;i--)

           {

               strTmp+="0";

           }

           //把長度調(diào)整到相同

           if(maxLen==lenA)

           {

               b=strTmp+b;

           }else

               a=strTmp+a;

           int JW=0;//進(jìn)位

           for(int i=maxLen-1;i>=0;i--)

           {        

               int tempA=Integer.parseInt(String.valueOf(a.charAt(i)));

               int tempB=Integer.parseInt(String.valueOf(b.charAt(i)));

               int temp;

               if(tempA+tempB+JW>=10 && i!=0)

               {

                  temp=tempA+tempB+JW-10;

                  JW=1;

               }

               else

               {

                  temp=tempA+tempB+JW;

                  JW=0;

               }        

               str=String.valueOf(temp)+str;        

           }

           return str;

        }

     

    }

     

    原帖地址: http://blog.csdn.net/fenglibing/archive/2007/08/23/1756773.aspx

        
        其實java 本身也提供了api ,java.math.BigInteger;import java.math.BigDecimal; 也可以實現(xiàn)。

    code :

    package com.kangdy.test;

    import java.math.BigInteger;
    import java.math.BigDecimal;

    public class NumberTest {
     public static void main(String args[]){
      BigInteger b1= new BigInteger("2222222222222222222222222");
      BigInteger b2= new BigInteger("8888888888888888888888888");
      BigDecimal b3 = new BigDecimal("66666666666666666666666666");
      BigDecimal b4 = new BigDecimal("9999999999999999999999999999");
      System.out.println(b1.add(b2).toString());
      System.out.println(b3.add(b4).toString());
     }
    }

    這里只是給出簡單的例子。



    posted @ 2010-12-10 14:06 AK47 閱讀(928) | 評論 (0)編輯 收藏

    (轉(zhuǎn)貼)java回調(diào)函數(shù)

    原帖地址: http://ayzw001.blog.163.com/blog/static/1134114222009420112538726/

    引用:

           所謂回調(diào),就是客戶程序C調(diào)用服務(wù)程序S中的某個方法a,然后S又在某個時候反過來調(diào)用C中的某個方法b,對于C來說,這個b便叫做回調(diào)函數(shù)。

    一般說來,C不會自己調(diào)用b,C提供b的目的就是讓S來調(diào)用它,而且是C不得不提供。由于S并不知道C提供的b叫甚名誰,所以S會約定b的接口規(guī)范(函數(shù)原型),然后由C提前通過S的一個函數(shù)r告訴S自己將要使用b函數(shù),這個過程稱為回調(diào)函數(shù)的注冊,r稱為注冊函數(shù)。

    下面舉個通俗的例子:

    某天,我打電話向你請教問題,當(dāng)然是個難題,:),你一時想不出解決方法,我又不能拿著電話在那里傻等,于是我們約定:等你想出辦法后打手機(jī)通知我,這樣,我就掛掉電話辦其它事情去了。過了XX分鐘,我的手機(jī)響了,你興高采烈的說問題已經(jīng)搞定,應(yīng)該如此這般處理。故事到此結(jié)束。

    這個例子說明了“異步+回調(diào)”的編程模式。其中,你后來打手機(jī)告訴我結(jié)果便是一個“回調(diào)”過程;我的手機(jī)號碼必須在以前告訴你,這便是注冊回調(diào)函數(shù);我的手機(jī)號碼應(yīng)該有效并且手機(jī)能夠接收到你的呼叫,這是回調(diào)函數(shù)必須符合接口規(guī)范。

     

    如果你還不太清楚看看這段描述合和代碼:

    聲明一個接口,另外一個類有方法里面有個參數(shù)以是這個接口類型的,而后在另外類中實現(xiàn)這個接口(java中多用的是匿名內(nèi)部類),而且以這個匿名的類生成的對象為參數(shù)傳到上面提到類中,而后實現(xiàn)回調(diào).......這種用法可以參考java里面常用到的數(shù)據(jù)庫操作所用到的幾個接口.....

    //聲明一個接口
    public interface ICallBack {
        void postExec();
    }

     

    //另外一個類有方法里面有個參數(shù)以是這個接口類型的
    public class FooBar {
        private ICallBack callBack;
        public void setCallBack(ICallBack callBack) {
            this.callBack = callBack;
        }
        public void doSth() {
            callBack.postExec();
        }
    }
    ---------------------------------------
    回調(diào)的實現(xiàn)
    public class Test {
        public static void main(String[] args) {
            FooBar foo = new FooBar();
            foo.setCallBack(new ICallBack() {
                public void postExec() {
                    System.out.println("method executed.");
                }
            });
            foo.doSth();//調(diào)用函數(shù)
        }
    }

    posted @ 2010-12-10 11:22 AK47 閱讀(627) | 評論 (0)編輯 收藏

    (轉(zhuǎn)貼) 真正理解面向接口編程

    面向?qū)ο笤O(shè)計里有一點(diǎn)大家已基本形成共識,就是面向接口編程,我想大多數(shù)人對這個是沒有什么覺得需要懷疑的。

    問題是在實際的項目開發(fā)中我們是怎么體現(xiàn)的呢? 難道就是每一個實現(xiàn)都提供一個接口就了事了?反過來說,你有時候有沒有覺得接口是多余的事? 又或者,你僅僅是覺得現(xiàn)在類似spring這樣的框架已習(xí)慣用接口這種方式而心存當(dāng)然。

    設(shè)計模式解析里提到了面向?qū)ο笤O(shè)計考慮的幾個視角,一個是概念層,一個是規(guī)約層,一個是實現(xiàn)層。我如果沒有猜錯的話,實際上我們大多數(shù)人的眼睛一直是盯著實現(xiàn)層的,而這正是面向?qū)ο笤O(shè)計所極力避免的,即你不要在一開始就關(guān)注這些細(xì)節(jié),你要關(guān)注的是規(guī)約(接口).

    對于實際項目開發(fā)來說,如果我們把實現(xiàn)的過程分為多個階段的話我們不妨這么劃分,第一階段,根據(jù)client端的需要去設(shè)計我們的規(guī)約(interface),在這個階段任何實現(xiàn)都沒有,所有的任務(wù)就是定義接口所需要的職責(zé),以及所需要的一些po,vo;第二階段,實現(xiàn)前面定義的規(guī)約。而以前我是怎么做的呢? 我是交叉作的,即假模假樣的定義一個接口(其實我心里在想這個東西有屁用),然后定義了一個方法,然后就立即去實現(xiàn)這個方法,再然后我又定義一個方法,繼續(xù)去實現(xiàn),我現(xiàn)在終于想通了,這樣好累,效率很低,最重要的是,這不屬于真正的設(shè)計。
    現(xiàn)在我是怎么做的呢?比如一個list.jsp里需要查詢,列表,然后看明細(xì)信息,然后增加信息,我會第一步在接口里定義完(這個過程會有整體設(shè)計的意識),毫不關(guān)心底層實現(xiàn)(數(shù)據(jù)庫、事務(wù)),我的目標(biāo)就是"我想要這個功能,我想要那個功能",至于那個功能怎么實現(xiàn)在第一階段我認(rèn)為那不是我的事情(盡管這個事情最終還是由我來做) .大家看這個過程和前面的過程有什么本質(zhì)的不同呢? 就是分層的概念更加明顯,你的工作更有層次,每次都有先設(shè)計再實現(xiàn)的步驟,而前面那個過程很容易就讓你不知不覺地陷入純實現(xiàn)的陷阱中。

    一點(diǎn)感想,歡迎大家拍磚。

    原帖地址: http://www.tkk7.com/alex/archive/2007/03/12/103185.html

    posted @ 2010-11-05 14:09 AK47 閱讀(318) | 評論 (0)編輯 收藏

    數(shù)字金額的中文大小寫轉(zhuǎn)化

    曾經(jīng)去過一家公司面試。筆試題的最后一題是一個數(shù)字金額大小寫轉(zhuǎn)化的問題。
    當(dāng)時沒想那么多,僅僅想到應(yīng)該把數(shù)拆開然后添加單位的一個大致的設(shè)計思路。
    而那個面試官一個勁兒的問我用啥算法。那個題最后也沒答上,回來后比較郁悶,
    在網(wǎng)上搜了一下。這個答案還真不少。不過覺得有一種設(shè)計還比較靠譜。
    大概是這樣:
     * 先將整數(shù)與小數(shù)部分分開,計算小數(shù)部分,角分并保存
     * 整數(shù)部分長度不足12位,前面加0補(bǔ)足。
     * 將整數(shù)部分分割3部分。高4位代表億,中間的是萬,其余分別代表千,百,十,個
     * 定一個方法拼出每一部分串。
     * 最后整數(shù)與小數(shù)部分合成。

    自己實現(xiàn)了一下,以下是代碼。
    code :

    package com.kangdy.test;
    /**
     * 數(shù)字金額轉(zhuǎn)化成大寫
     * 先將整數(shù)與小數(shù)部分分開,計算小數(shù)部分,角分并保存
     * 整數(shù)部分長度不足12位,前面加0補(bǔ)足。
     * 將整數(shù)部分分割3部分。高4位代表億,中間的是萬,其余分別代表千,百,十,個
     * 定一個方法拼出每一部分串。
     * 最后整數(shù)與小數(shù)部分合成。
     * @author dkang
     *
     */
    public class NumberToString {

     String numberStr;

     public static final String unit[] = { "", "十", "百", "千", "萬", "億" };

     public static final String unit2[] = { "元", "角", "分" };

     public static final String numStr[] = { "零", "壹", "貳", "叁", "肆", "伍", "陸",
       "柒", "捌", "玖" };

     /**
      * 字符串長度不足12位用0補(bǔ)足
      *
      * @param str
      * @return
      */
     private String additionalZero(String str) {
      StringBuffer strb = new StringBuffer();
      if (str.length() < 12) {
       int size = 12 - str.length();
       for (int i = 0; i < size; i++) {
        strb.append("0");
       }
      }
      return strb.append(str).toString();
     }

     /**
      * 遞歸拆分?jǐn)?shù)字成字符串
      *
      * @param value
      * @param strBuffer
      * @return
      */
     private String decomposeNumberToString(int value, StringBuffer strBuffer) {
      int quotient = 0;
      quotient = value / 10;
      if (quotient != 0) {
       decomposeNumberToString(quotient, strBuffer);
      }
      int remaider = value % 10;
      strBuffer.append(remaider + ",");
      return strBuffer.toString().substring(0,
        strBuffer.toString().length() - 1);
     }

     /**
      * 使用循環(huán)拆分?jǐn)?shù)字成字符串
      *
      * @param value
      * @return
      */
     private String decomposeNumberToString2(int value) {
      StringBuilder strBuilder = new StringBuilder();
      int quotient = value;
      int remaider = 0;
      while (quotient != 0) {
       remaider = quotient % 10;
       strBuilder.append(remaider + ",");
       quotient = quotient / 10;
      }
      strBuilder.deleteCharAt(strBuilder.lastIndexOf(","));
      return strBuilder.reverse().toString();
     }

     /**
      * 添加單位
      *
      * @param temp
      * @return
      */
     private String addUnits(String temp) {
      StringBuffer sb = new StringBuffer();
      String str[] = temp.split(",");
      String tempStr = temp.replace(",", "");
      if (tempStr.contains("000")) {
       return sb.append(resplaceNumToStr(str[0]) + unit[3]).toString();
      } else if (tempStr.contains("00")) {
       if (tempStr.charAt(3) == '0') {
        return sb.append(resplaceNumToStr(str[0]) + unit[3]).append(
          resplaceNumToStr(str[1]) + unit[2]).toString();
       } else {
        return sb.append(resplaceNumToStr(str[0]) + unit[3]).append(
          numStr[0]).append(resplaceNumToStr(str[3])).toString();
       }
      } else {
       for (int i = 0; i < str.length; i++) {
        sb.append(resplaceNumToStr(str[i]));
        if (!str[i].equals("0")) {
         sb.append(unit[str.length - (i + 1)]);
        }
       }
      }
      return sb.toString();
     }

     /**
      * 數(shù)字替換
      *
      * @param str
      * @return
      */
     private String resplaceNumToStr(String str) {
      try {
       int num = Integer.parseInt(str);
       return numStr[num];
      } catch (Exception e) {
       e.printStackTrace();
      }
      return "";
     }

     /**
      * 把4位長度的數(shù)字轉(zhuǎn)化成字符串
      *
      * @param number
      * @param i
      * @return
      */
     private String transformNumberToString(String number, int i) {
      StringBuffer strBuffer = new StringBuffer();
      StringBuilder strBuilder = new StringBuilder();
      try {
       int num = Integer.parseInt(number);
       if (num != 0) {
        String s1 = decomposeNumberToString(num, strBuffer);
        strBuilder.append(addUnits(s1));
        if (i == 1) {
         strBuilder.append(unit[5]);
        } else if (i == 2)
         strBuilder.append(unit[4]);
       }
      } catch (Exception e) {
       e.printStackTrace();
      }
      return strBuilder.toString();
     }

     /**
      * 得到最終結(jié)果
      *
      * @param str
      * @return
      */
     public String IntegrationResultString(String str) {
      StringBuffer strBuffer = new StringBuffer();
      String numStr[] = null;
      if (str.indexOf(".") != -1) {
       numStr = str.split("\\.");
      } else {
       return strBuffer.append(createIntegerPartsResult(str)).toString();
      }
      String fractionalStr = createFractionalPartsResult(numStr[1]);
      String integerStr = createIntegerPartsResult(numStr[0]);
      return strBuffer.append(integerStr).append(fractionalStr).toString();
     }

     private String createIntegerPartsResult(String integer) {
      StringBuffer strBuffer = new StringBuffer();
      String temp = additionalZero(integer);
      String str1 = temp.substring(0, 4);
      strBuffer.append(transformNumberToString(str1, 1));
      String str2 = temp.substring(4, 8);
      strBuffer.append(transformNumberToString(str2, 2));
      String str3 = temp.substring(8, temp.length());
      strBuffer.append(transformNumberToString(str3, 3) + unit2[0]);
      return strBuffer.toString();
     }

     private String createFractionalPartsResult(String fractionalStr) {
      StringBuilder strB = new StringBuilder();
      String s1 = fractionalStr.substring(0, 1);
      String s2 = fractionalStr.substring(1, fractionalStr.length());
      if (!s1.equals("0")) {
       strB.append(resplaceNumToStr(s1) + unit2[1]);
      }
      if (!s2.equals("0")) {
       strB.append(resplaceNumToStr(s2) + unit2[2]);
      }
      return strB.toString();
     }

     public static void main(String args[]) {
      NumberToString test = new NumberToString();
      String str = "200123004054.11";
      System.out.println(test.IntegrationResultString(str));
     }
    }



    posted @ 2010-11-02 14:59 AK47 閱讀(611) | 評論 (0)編輯 收藏

    類和對象的初始化

    類的生命周期:分為裝載,鏈接,初始化
    如圖:


    1)裝載:查找并裝載類型的二進(jìn)制數(shù)據(jù)
    2)連接:執(zhí)行驗證,準(zhǔn)備,和解析(可選)
             a) 驗證:確保導(dǎo)入類型正確
             b) 準(zhǔn)備:為類變量分配內(nèi)存,并將其初始化為默認(rèn)值
             c) 解析:把類型中的符號引用轉(zhuǎn)換成直接引用
    3)初始化:把類變量初始化為默認(rèn)初值


          隨著Java虛擬機(jī)裝載了一個類,并執(zhí)行了一些它選擇進(jìn)行的驗證之后,類就可以進(jìn)入準(zhǔn)備階
    段了。在準(zhǔn)備階段,Java虛擬機(jī)為類變量分配內(nèi)存,設(shè)置默認(rèn)初始值:但在到達(dá)初始化階段之前,
    類變量都沒有被初始化為真正的初始值。(在準(zhǔn)備階段是不會執(zhí)行Java代碼的。)在準(zhǔn)備階段,虛
    擬機(jī)把給類變量新分配的內(nèi)存根據(jù)類型設(shè)置為默認(rèn)值。

     為了準(zhǔn)備讓一個類或者接口被"首次主動"使用,最后一個步驟就是初始化,也就是為類變量      
    賦予正確的初始值。這里的”正確”初始值指的是程序員希望這個類變量所具備的起始值。正
    確的初始值是和在準(zhǔn)備階段賦予的默認(rèn)初始值對比而言的。前面說過,根據(jù)類型的不同,類變
    量已經(jīng)被賦予了默認(rèn)初始值。而正確的初始值是根據(jù)程序員制定的主觀計劃面生成的。


    在Java代碼中,一個正確的初始值是通過類變量初始化語句或者靜態(tài)初始化語句給出的。
     1)一個類變量初始化語句是變量聲明后面的等號和表達(dá)式:
     2)靜態(tài)初始化語句是一個以static開頭的程序塊
     example : 
        public class Example1 {
         
         // 類變量初始化語句
         static int value = (int) (Math.random()*6.0);
         
         // 靜態(tài)初始化語句
         static{
          System.out.println("this is example");
         }
        }
    所有的類變量初始化語句和類型的靜態(tài)初始化器都被Java編譯器收集在—起,放到——個特殊
    的方法中。對于類來說,這個方法被稱作類初始化方法;對于接口來說,它被稱為接口初始化
    方法。在類和接口的Javaclass文件中,這個方法被稱為”<clinit>”。通常的Java程序方法是無法
    調(diào)用這個<clinit>方法的。這種方法只能被Java虛擬機(jī)調(diào)用

    clinit>()方法
        前面說過,Java編譯器把類變量初始化語句和靜態(tài)初始化浯句的代碼都放到class文件的
    <clinit>()方法中,順序就按照它們在類或者接門聲明中出現(xiàn)的順序。
     example:
      public class Example1 {
        static int width;
        static int height = (int) (Math.random()*6.0);

        static{
         width = (int) (Math.random()*3.0);
        }
     }
    java 編譯器生成下面<clinit>方法:
    0 invokestatic java.lang.Math.random
    3 ldc2_w 6.0 (double)
    6 dmul
    7 d2i
    8 putstatic Example1.height
    11 invokestatic java.lang.Math.random
    14 ldc2_w 3.0 (double) 17 dmul
    18 d2i
    19 putstatic Example1.width
    22 return

    clinit 方法首先執(zhí)行唯一的類變量初始化語句初始化heght,然后在靜態(tài)初始化語句中
    初始化width(雖然它聲明在height之前,但那僅僅是聲明了類變量而不是類變量初始化語句).

     

    除接口以外,初始化一個類之前必須保證其直接超類已被初始化,并且該初始化過程是由 Jvm 保證線程安全的。
    另外,并非所有的類都會擁有一個 <clinit>() 方法。
    1)如果類沒有聲明任何類變量,也沒有靜態(tài)初始化語句,那么它不會有<clinit>()方法。
    2)如果聲明了類變量但是沒有使用類變量初始化語句或者靜態(tài)初始化語句初始它們,那么類不會有<clinit>()方法。 
       example:
          public class example{
           static int val;
          }
        
    3)如果類僅包含靜態(tài) final 變量的類變量初始化語句,并且類變量初始化語句是編譯時常量表達(dá)式,類不會有<clinit>()方法。
        example:
        public class Example {
         static final String str ="abc";
         static final int value = 100;
        }
    這種情況java編譯器把 str 和 value 被看做是常量,jvm會直接使用該類的常量池或者在字節(jié)碼中直接存放常量值。該類不會被加載。
     
    如果接口不包含在編譯時解析成常量的字段初始化語句,接口中就包含一個<clinit>()方法。
    example:
     interface Example{
      int i =5;
      int hoursOfSleep = (int) (Math.random()*3.0);
      
     }
    字段hoursOfSleep會被放在<clinit>()方法中(比較詭異???它被看作類變量了),而字段i被看作是編譯時常量特殊處理(JAVA語法規(guī)定,接口中的變量默認(rèn)自動隱含是public static final)。
     java 編譯器生成下面<clinit>方法:
    0 invokestatic java.lang.Math.random
    3 ldc2_w 3.0 (double)
    6 dmul
    7 d2i
    8 putstatic Example.hoursOfSleep
    11 return

    主動使用和被動使用
        在前面講過,Java虛擬機(jī)在首次主動使用類型時初始化它們。只有6種活動被認(rèn)為是主動使
    用:
     1)創(chuàng)建類的新實例,
     2)調(diào)用類中聲明的靜態(tài)方法,
     3)操作類或者接口中聲明的非常量靜態(tài)字段,
     4)調(diào)用JavaAPI中特定的反射方法
     5)初始化一個類的子類;
     6)以及指定一個類作為Java虛擬機(jī)啟動時的初始化類。
     
       使用一個非常量的靜態(tài)字段只有當(dāng)類或者接口的確聲明了這個字段時才是主動使用、比如,
    類中聲明的字段可能會被子類引用;接口中聲明的字段可能會被子接口或者實現(xiàn)了這個接口的
    類引用。對于子類、子接口和實現(xiàn)接口的類來說.這就是被動使用(使用它們并不會觸發(fā)
    它們的初始化)。下面的例子說明了這個原理:

    class NewParement{
     static int hoursOfSleep = (int) (Math.random()*3.0);
     
     static{
      System.out.println("new parement is initialized.");
     }
    }

    class NewbornBaby extends NewParement{
     static int hoursOfCry = (int) (Math.random()*2.0);
     
     static{
      System.out.println("new bornBaby is initialized.");
     }
    }


    public class Example1 {
     
     public static void main(String[] args){
      int hours = NewbornBaby.hoursOfSleep;
      System.out.println(hours);
     }
     static{
      System.out.println("example1 is initialized.");
     }
     
    }
    運(yùn)行結(jié)果:
    example1 is initialized.
    new parement is initialized.
    0
    NewbornBaby 沒有被初始化,也沒有被加載。


    對象的生命周期

            當(dāng)java虛擬機(jī)創(chuàng)建一個新的類實例時不管明確的還是隱含的,首先要在堆中為保存對象的實例變量分配內(nèi)存,包含所有在對象類中和它超類中
    聲明的變量(包括隱藏的實例變量)都要分配內(nèi)存。其次賦默認(rèn)初值,最后賦予正確的初始值。

    java編譯器為每個類都至少生成一個實例初始化方法 "<init>()"與構(gòu)造方法相對應(yīng)。

    如果構(gòu)造方法調(diào)用同一個類中的另一個構(gòu)造方法(構(gòu)造方法重載),它對應(yīng)的init<>():
    1)一個同類init<>()調(diào)用。
    2)對應(yīng)構(gòu)造方法體代碼的調(diào)用。
    如果構(gòu)造方法不是通過this()調(diào)用開始,且對象不是Object 它對應(yīng)的init<>():
    1)一個超類init<>()調(diào)用。
    2)任意實例變量初始化代碼調(diào)用。
    3)對應(yīng)構(gòu)造方法體代碼的調(diào)用。
    如果上述對象是Object,則去掉第一條。如果構(gòu)造方法明確使用super()首先調(diào)用對應(yīng)超類init<>()其余不變。
    下面的例子詳細(xì)說明了實例變量初始化(摘自Java Language Specification)
    class Point{
     int x,y;
     Point(){x=1;y=1;}
    }
    class ColoredPoint extends Point{
     int color = OxFF00FF;
    }
    class Test{
     public static void main(String[] args){
      ColoredPoint cp = new ColoredPoint();
      System.out.println(cp.color);
     }
    }
    首先,為新的ColoredPoint實例分配內(nèi)存空間,以存儲實例變量x,y和color;然后將這些變量初始化成默認(rèn)值
    在這個例子中都是0。
    接下來調(diào)用無參數(shù)的ColoredPoint(),由于ColorPoint沒有聲明構(gòu)造方法,java編譯器會自動提供如下的構(gòu)造方
    法:ColoredPoint(){super();}。
    該構(gòu)造方法然后調(diào)用無參數(shù)的Point(),而Point()沒有顯示的超類,編譯器會提供一個對其無參數(shù)的構(gòu)造方法的
    隱式調(diào)用:Point(){super();x=1;y=1}。
    因此將會調(diào)用到Object();Object類沒有超類,至此遞歸調(diào)用會終止。接下來會調(diào)用Object任何實例初始化語句
    及任何實例變量初始化語句。
    接著執(zhí)行Object()由于Object類中未聲明這樣的構(gòu)造方法。因此編譯器會提供默認(rèn)的構(gòu)造方法object(){}。
    但是執(zhí)行該構(gòu)造方法不會產(chǎn)生任何影響,然后返回。
    接下來執(zhí)行Point類實例變量初始化語句。當(dāng)這個過程發(fā)生時,x,y的聲明沒有提供任何初始化表達(dá)式,因此這個
    步驟未采取任何動作(x,y 仍為0);
    接下來執(zhí)行Point構(gòu)造方法體,將x,y賦值為1。
    接下來會執(zhí)行類ColoredPoint的實例變量初始化語句。把color賦值0xFF00FF,最后執(zhí)行ColoredPoint構(gòu)造方法體
    余下的部分(super()調(diào)用之后的部分),碰巧沒有任何語句,因此不需要進(jìn)一步的動作,初始化完成。

    與C++不同的是,在創(chuàng)建新的類實例期間,java編程語言不會為方法分派來指定變更的規(guī)則。如果調(diào)用的方法在被
    初始化對象的子類中重寫,那么就是用重寫的方法。甚至新對象被完全初始化前也是如此。編譯和運(yùn)行下面的例子
    class Super{
     Super(){printThree();}
     void printThree{System.out.println("Three");}
    }
    class Test extends Super{
     int three = (int)Math.PI; // That is 3
     public static void main(String args[]){
      Test t = new Test();
      t.printThree();
     }
     void printThree(){System.out.println(three);}
    }
    輸出:
    0
    3
    這表明Super類中的printThree()沒有被執(zhí)行。而是調(diào)用的Test中的printThree()。

     

     
     

    posted @ 2010-07-14 16:18 AK47 閱讀(895) | 評論 (0)編輯 收藏

    Java虛擬機(jī)體系結(jié)構(gòu)

    Java虛擬機(jī)體系結(jié)構(gòu)


    方法區(qū)
             在Java虛擬機(jī)中,被裝載類型的信息存儲在一個邏輯上被稱為方法區(qū)的內(nèi)存中。
     當(dāng)虛擬機(jī)裝載某個類型時,它使用類裝載器定位相應(yīng)的class文件,-->讀入這個class文件(一個線性的二進(jìn)制流)->將它傳入虛擬機(jī)-->
     虛擬機(jī)提取類型信息,并將信息存入方法區(qū),類型中的類(靜態(tài))變量也存儲在方法區(qū).
     方法區(qū)特點(diǎn):
     1)所有線程共享方法區(qū)。它是線程安全的。
     2)方法區(qū)大小不是固定的。虛擬機(jī)根據(jù)需要自行調(diào)整。
     3)方法區(qū)可以被垃圾回收。
     對于每個被裝載的類型,虛擬機(jī)會在方法區(qū)中存儲以下信息。
     
     1)類型的基本信息;
         a)類型的全限定名
         b)類型的直接超類全限定名(除非這個類型是java.lang.Objet,它沒超類)。
         c)類型是類類型還是接口類型(就是說是一個類還是一個接口)。
         d)類型的訪問修飾符(public ,abstract或final的某個子類)
         e)任何直接超接口的全限定名的有序列表。
         
     2)該類型的常量池
       虛擬機(jī)必須為每個被裝載的類型維護(hù)一個常量池。常量池就是該類型所用常量的一個有序集合,
       包括直接常量(string,integer,floating point常量)和對其他類型、字段和方法的符號引用。
       池中的數(shù)據(jù)項就像數(shù)組一樣是通過索引訪問的。因為常量池存儲了相應(yīng)類型所用到的所有類型、
       字段和方法的符號引用,所以它在Java程序的動態(tài)連接中起著核心的作用。
       
     3)字段信息
       類型中聲明的每一個字段,方法區(qū)中必須保存下面的信息,字段在類或接口中聲明的順序也必須保存。
       字段名,字段類型,字段修飾符(public private protected static final 等)
       
     4)方法信息
       類型中聲明的每一個方法,方法區(qū)中必須保存下面的信息,方法在類或接口中聲明的順序也必須保存。
       方法名,返回值類型,參數(shù)數(shù)量和類型(按聲明順序),方法修飾符(public private protected static final 等)
       如果方法不是抽象的或本地的還必須保存:方法字節(jié)碼,操作數(shù)棧和該方法在棧針中局部變量的大小,異常表。
       
     5)除了常量以外的所有類(靜態(tài))變量
       這里主要說下編譯時常量:就是那些用final聲明以及編譯時已知的值初始化的類變量(例如:static final int val =5)
       每個編譯時常量的類型都會復(fù)制它所有常量到它自己的常量池中或者它的字節(jié)碼流中(通常情況下編譯時直接替換字節(jié)碼)。

       
     6)一個到類classLoader的引用
       指向ClassLoader類的引用  每個類型被裝載的時候,虛擬機(jī)必須跟蹤它是由啟動類裝載器
       還是由用戶自定義類裝載器裝載的。如果是用戶自定義類裝載器裝載的,那么虛擬機(jī)必須在類
       型信息中存儲對該裝載器的引用:這是作為方法表中的類型數(shù)據(jù)的一部分保存的。
       虛擬機(jī)會在動態(tài)連按期間使用這個信息。當(dāng)某個類型引用另一個類型的時候,虛擬機(jī)會請求裝載
       發(fā)起引用類型的類裝載器來裝載被引用的類型。這個動態(tài)連接的過程,對于虛擬機(jī)分離命名空間
       的方式也是至關(guān)重要的。為了能夠正確地執(zhí)行動態(tài)連接以及維護(hù)多個命名空間,虛擬機(jī)需要在方
       法表中得知每個類都是由哪個類裝載器裝載的。
       
     7)一個到Class類的引用
        指向Class類的引用  對于每一個被裝載的類型(不管是類還是接口),虛擬機(jī)都會相應(yīng)地為
        它創(chuàng)建一個java.lang.Class類的實例(Class實例放在內(nèi)存中的堆區(qū)),
    而且虛擬機(jī)還必須以某種方式把這個實例的引用存儲在方法區(qū)
        
           為了盡可能提高訪問效率,設(shè)計者必須仔細(xì)設(shè)計存儲在方法區(qū)中的類型信息的數(shù)據(jù)結(jié)構(gòu),因此,
    除了以上時論的原始類型信息,實現(xiàn)中還可能包括其他數(shù)據(jù)結(jié)構(gòu)以加快訪問原始數(shù)據(jù)的速度,比如方法表。
    虛擬機(jī)對每個裝載的非抽象類,都生成一個方法表,把它作為類信息的一部分保存在方法區(qū)。方法表是一個數(shù)組,
    它的元素是所有它的實例可能被調(diào)用的實例方法的直接引用,包括那些從超類繼承過來的實例方法:(對于抽象類和接口,方法表沒有什么幫
    助,因為程序決不會生成它們的實例。)運(yùn)行時可以通過方法表快速搜尋在對象中調(diào)用的實例方法。
     
    方法區(qū)使用的例子

     class Lava{
      private int speed = 5;
     
      void flow(){
      
      }
     
     }

     public class Volcano {
      
      public static void main(String args[]){
       
       Lava lava = new Lava();
       
       lava.flow();
      }
     }

      1)虛擬機(jī)在方法區(qū)查找Volcano這個名字,未果,載入volcano.class文件,并提取相應(yīng)信息
       存入方法區(qū)。
      2)虛擬機(jī)開始執(zhí)行Volcano類中main()方法的字節(jié)碼的時候,盡管Lava類還沒被裝載,
      但是和大多數(shù)(也許所有)虛擬機(jī)實現(xiàn)一樣,它不會等到把程序中用到的所有類都裝載后才開
      始運(yùn)行程序。恰好相反,它只在需要時才裝載相應(yīng)的類。
      3)main()的第一條指令告知虛擬機(jī)為列在常量池第一項的類分配足夠的內(nèi)存。所以虛擬機(jī)
      使用指向Volcano常量池的指針找到第一項,發(fā)現(xiàn)它是一個對Lava類的符號引用,然后它就檢查
      方法區(qū),看Lava類是否已經(jīng)被裝載了。
      4)當(dāng)虛擬機(jī)發(fā)現(xiàn)還沒有裝載過名為"Lava"的類時,它就開始查找并裝載文件“Lava.class”,
      并把從讀入的二進(jìn)制數(shù)據(jù)中提取的類型信息放在方法區(qū)中。
      5)虛擬機(jī)以一個直接指向方法區(qū)Lava類數(shù)據(jù)的指針來替換常量池第—項(就是那個
      字符串“Lava”)——以后就可以用這個指針來快速地訪問Lava類了。這個替換過程稱為常量池
      解析,即把常量池中的符號引用替換為直接引用:這是通過在方法區(qū)中搜索被引用的元素實現(xiàn)
      的,在這期間可能又需要裝載其他類。在這里,我們替換掉符號引用的“直接引用”是一個本
      地指針。
      6)虛擬機(jī)準(zhǔn)備為一個新的Lava對象分配內(nèi)存。此時,它又需要方法區(qū)中的信息。還記
      得剛剛放到Volcano類常量池第——項的指針嗎?現(xiàn)在虛擬機(jī)用它來訪問Lava類型信息(此前剛放
      到方法區(qū)中的),找出其中記錄的這樣一個信息:一個Lava對象需要分配多少堆空間。
      7)虛擬機(jī)確定一個Lava對象大小后,就在堆上分配空間,并把這個對象實例變量speed初始化為默認(rèn)初始值0
      8)當(dāng)把新生成的Lava對象的引用壓到棧中,main()方法的第一條指令也完成了,指令通過這個引用
      調(diào)用Java代碼(該代碼把speed變量初始化為正確初始值5).另外用這個引用調(diào)用Lava對象引用的flow()方法。


            每個java虛擬機(jī)實例都有一個方法區(qū)以及一個堆,一個java程序獨(dú)占一個java虛擬機(jī)實例,而每個java程序都有自己的堆空間,它們不會彼此干擾,但同一個java程序的多個線程共享一個堆空間。這種情況下要考慮多線程訪問同步問題。
     
    Java棧
            一個新線程被創(chuàng)建時,都會得到自己的PC寄存器和一個java棧,虛擬機(jī)為每個線程開辟內(nèi)存區(qū)。這些內(nèi)存區(qū)是私有的,任何線程不能訪問其他線程的PC寄存器和java棧。java??偸谴鎯υ摼€程中java方法的調(diào)用狀態(tài)。包括它的局部變量,被調(diào)用時傳進(jìn)來的參數(shù),它的返回值,以及運(yùn)算的中間結(jié)果等。java棧是由許多棧幀或者說幀組成,一個棧幀包含一個java方法的調(diào)用狀態(tài),當(dāng)線程調(diào)用java方法時,虛擬機(jī)壓入一個新的棧幀到該線程的java棧中。當(dāng)方法返回時,這個棧幀被從java棧中彈出并拋棄。
    .本地方法棧
             任何本地方法接口都會使用某種本地方法餞。當(dāng)線程調(diào)用Java方法時,虛擬機(jī)會創(chuàng)建一個新的棧幀井壓人Java棧。
    然而當(dāng)它調(diào)用的是本地方法時,虛擬機(jī)會保持Java棧不變,不再在線程的Java棧中壓人新的幀,虛擬機(jī)只是簡單地動態(tài)連接
    并直接調(diào)用指定的本地方法??梢园堰@看做是虛擬機(jī)利用本地方法來動態(tài)擴(kuò)展自己。

    posted @ 2010-07-06 13:47 AK47 閱讀(377) | 評論 (0)編輯 收藏

    Eclipse 內(nèi)置webservice瀏覽器問題

    最近在使用eclipse 內(nèi)置webservice 瀏覽器遇到了些問題,無法點(diǎn)開WSDL Main 如下圖:


    大家遇到過類似的情況沒有,目前我只能先使用外部瀏覽器了。

    posted @ 2010-06-10 14:17 AK47 閱讀(452) | 評論 (0)編輯 收藏

    <2010年6月>
    303112345
    6789101112
    13141516171819
    20212223242526
    27282930123
    45678910

    導(dǎo)航

    統(tǒng)計

    常用鏈接

    留言簿

    隨筆分類

    隨筆檔案

    搜索

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 在线观看亚洲免费| 在人线av无码免费高潮喷水| 亚洲国产成人a精品不卡在线| 国产精品久久久久久亚洲影视| 女性自慰aⅴ片高清免费| 麻豆狠色伊人亚洲综合网站| 美丽的姑娘免费观看在线播放| 亚洲天堂视频在线观看| 日本视频在线观看永久免费| 亚洲高清在线播放| 4虎1515hh永久免费| 亚洲国产精品久久网午夜| 亚洲欧洲免费无码| 亚洲人AV在线无码影院观看| 日韩精品视频免费网址| 综合一区自拍亚洲综合图区| 亚洲成a人片在线观看国产| 亚洲精品黄色视频在线观看免费资源 | 免费国产在线观看| 一级日本高清视频免费观看| 亚洲精品中文字幕乱码三区| 久草免费福利资源站| 亚洲第一页在线播放| 在线观看免费成人| 麻豆一区二区三区蜜桃免费| 亚洲色成人网站WWW永久| 最近中文字幕免费2019| 色偷偷亚洲女人天堂观看欧| 亚洲高清偷拍一区二区三区| 在线免费播放一级毛片| 亚洲色偷偷偷网站色偷一区| 巨胸喷奶水视频www网免费| 免费高清A级毛片在线播放| 亚洲av午夜成人片精品网站| 亚欧色视频在线观看免费| 亚洲av永久无码精品网址| 国产亚洲视频在线播放| 8x8x华人永久免费视频| 亚洲GV天堂GV无码男同| 亚洲中文字幕久久精品无码喷水| 免费在线观看视频网站|