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

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

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

    2010年12月10日

    (轉貼)數據庫連接(內連接,外連接,交叉連接)

    數據庫連接分為:內連接,外連接(左、右連接,全連接),交叉連接
    文章地址 : http://www.zxbc.cn/html/20080527/51189.html
    轉載 
    內連接:把兩個表中數據對應的數據查出來 
    外連接:以某個表為基礎把對應數據查出來(全連接是以多個表為基礎) 
    student表 
    no name 
    1     a 
    2     b 
    3     c 
    4     d 
    grade表 
    no grade 
    1     90 
    2     98 
    3     95 
    內連接 inner join(查找條件中對應的數據,no4沒有數據不列出來) 
    語法:select * from student inner join grade on student.no = grade.no 
    結果 
    student.no name grade.no grade 
    1             a             1         90 
    2             b             2         98 
    3             c             3         95 
    左連接(左表中所有數據,右表中對應數據) 
    語法:select * from student left join grade on student.no = grade.no 
    結果: 
    student.no name grade.no grade 
    1                 a         1         90 
    2                 b         2         98 
    3                 c         3         95 
    4                 d     
    右連接(右表中所有數據,左表中對應數據) 
    語法:select * from student right join grade on student.no = grade.no 
    結果: 
    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 
    結果: 
    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 將左連接和右連接合并后才可以

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

    行數應該為12行 :
    no name grade 
    1     a     90 
    2     b     98 
    3     c     95 
    4     d  
    1     a     90 
    2     b     98 
    3     c     95 
    4     d 
    1     a     90 
    2     b     98 
    3     c     95 
    4     d 

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

    JAXB向Xml非根節點添加一個或多個屬性

    JAXB 向Xml非根節點添加一個或多個屬性,直接上代碼,關于JAXB的相關注解可查閱JAVA API。

    原創文章,轉載請注明出處。http://www.tkk7.com/kangdy/archive/2011/11/23/364635.html

    code1: colors類  根節點
    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類  子節點
    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 子節點
    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());

        }
    }

    運行結果:
    結果
    <?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)編輯 收藏

    (轉載)關于paramsPrepareParamsStack

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

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

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

    (轉載) Struts 2雜談(1):ValueStack對象的傳送帶機制

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

        name = 超人
        price = 10000

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

    攔截器的源代碼:

    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對象中的相應屬性值
                    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文件復制到WEB-INF/classes目錄,并在該文件中加入name和price屬性。

    測試結果:

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

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

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

    (轉貼)Struts2數據傳輸的背后機制:ValueStack(值棧)

         摘要: (轉)Struts2數據傳輸的背后機制:ValueStack(值棧)原文地址 :http://blog.csdn.net/li_tengfei/article/details/6098134轉載 1.     數據傳輸背后機制:ValueStack(值棧)   在這一切的背后,是因為有了ValueStack(值棧)!   Valu...  閱讀全文

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

    structs2配置UrlRewriteFilter

    轉載每個網頁或請求都是一個url地址,一般,這個地址可能是.do,.page,.action之類的并加上'?'號、'&'號查詢串等構成的一個長長的的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可以很好的改善這個狀況。網站url rewrite應用是非常廣泛的,良好的url設計給用戶帶來的非常好的體驗,同時也能吸引搜索引擎的注意。
    原文地址: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 文件,根據具體需要寫規則
    樣例:
    <?xml version="1.0" encoding="utf-8"?>
    <urlrewrite>
        <rule>
            <from>^/(.*).html$</from>
            <to type="forward">/$1.action</to>
        </rule>
        <rule>
            <from>^/(.*).html?(.*)$</from>
            <to type="forward">/$1.action?$2</to>
        </rule>
    </urlrewrite>

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

    structs2 filter的執行順序

    根據servlet2.3規范filter執行是按照web.xml配置的filter-mapping先后順序進行執行。
    所以自己配置的過濾器放在structs2的過濾器之前。

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

    structs2攔截器

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

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

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

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


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

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

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

    (轉貼)struts2 工作原理圖

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

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

    重新認識Java finally

    關于java finally 網上有2篇文章個人認為相當不錯
    以下是轉貼內容:

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

    finally“微型子例程”不等同于方法函數的調用,finally子句都是在同一個棧內執行的,微型子例程的“返回”操作也不會涉及到方法退棧,僅僅是使程序計數器pc跳轉到同一個方法的一個不同的位置繼續執行。
    一 異常丟失
        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()的輸出結果是“exception in finally”,而不是try塊中拋出的異常,這是JAVA異常機制的一個瑕疵-異常丟失。

    在字節碼中,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) 調用finally微型子程序
    3) 把局部變量中的Exception("exception in try")對象引用push到操作數棧頂,然后拋出異常
      aload_2  // push the reference to the thrown exception from local variable 2

      athrow   // throw the exception

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

    在JDK1.6中,通過字節碼我們可以看到,finally子句作為一種特殊的catch來實現的,下面是exceptionLost()方法的異常表:

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

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

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

    這個方法的返回值是100還是200?結果是100。
    在字節碼中,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) 調用finally微型子程序
    3) 把局部變量(指temp)的值push到操作數棧頂,然后返回到調用方法
         iload_2  // push local varaible 2 - the 100
       ireturn      // return int on top of the stack - the 100: return 100

    由于return語句在返回之前會把返回值保存到一個臨時的局部變量中,所以在finally子句內對value重新賦值不會影響返回值。

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

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

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

    (轉貼) jqGrid整理

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

    一、 jqGrid的加載。

    1.引用相關頭文件

    引入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,所以,此處需要導入UI相關js和css。另外grid.locale-en.js這個語言文件必須在jquery.jqGrid.min.js之前加載,否則會出問題。

    2.將jqgrid加入頁面中

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

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

    其中list是頁面上的一個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文檔關于option的章節(http://www.trirand.com/jqgridwiki/doku.php?id=wiki:options)。其中有幾個是比較常用的,重點介紹一下:

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

    2.1 prmNames選項

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

    prmNames : {

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

    rows:"rows", // 表示請求行數的參數名稱

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

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

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

    nd:"nd", // 表示已經發送請求的次數的參數名稱

    id:"id", // 表示當在編輯數據模塊中發送數據時,使用的id的名稱

    oper:"oper", // operation參數名稱

    editoper:"edit", // 當在edit模式中提交數據時,操作的名稱

    addoper:"add", // 當在add模式中提交數據時,操作的名稱

    deloper:"del", // 當在delete模式中提交數據時,操作的名稱

    subgridid:"id", // 當點擊以載入數據到子表時,傳遞的數據名稱

    npage: null,

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

    }

    2.2 jsonReader選項

    jsonReader是jqGrid的一個重要選項,用于設置如何解析從Server端發回來的json數據,如果Server返回的是xml數據,則對應的使用xmlReader來解析。jsonReader的默認值為:

    jsonReader : {

    root: "rows", // json中代表實際模型數據的入口

    page: "page", // json中代表當前頁碼的數據

    total: "total", // json中代表頁碼總數的數據

    records: "records", // json中代表數據行總數的數據

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

    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日"}]}

    其對應的jsonReader為:jsonReader: {

    root: "griddata",

    total: "totalpages",

    page: "currpage",

    records: "totalrecords",

    repeatitems: false

    }

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

    repeatitems為true時:

    jQuery("#gridid").jqGrid({  

         ...  

         jsonReader : {  

             root:"invdata",  

             page: "currpage",  

             total: "totalpages",  

             records: "totalrecords"

         },  

         ...  

    });  

    json結構為:

    {   

    "totalpages": "xxx",   

    "currpage": "yyy",  

    "totalrecords": "zzz",  

    "invdata" : [  

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

                      {"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結構為:

    {   

    "totalpages" : "xxx",   

    "currpage" : "yyy",  

    "totalrecords" : "zzz",  

    "invdata" : [  

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

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

                      ...  

         ]  

    }  

    2.3 colModel的重要選項

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

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

    三、 注意事項

    1. 動態改變Add Form或者Edit Form中的select的內容,如:改變下圖中的Comparator下拉中的內容。

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

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

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

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

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

    }

    6. 對于像1中的可編輯的字段,可以設定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');


    復雜的表格可以參考jquery grid demo網站 :




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

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

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

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

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

         @Repository用于標注數據訪問組件,即DAO組件,

         @Component泛指組件,當組件不好歸類的時候,我們可以使用這個注解進行標注。

        */   


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

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

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

    注入方式:

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

    注解:

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

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

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

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

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

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

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

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

    @Repository持久層組件,用于標注數據訪問組件,即DAO組件

    @Component泛指組件,當組件不好歸類的時候,我們可以使用這個注解進行標注。 


    @Service 
    public class VentorServiceImpl implements iVentorService { 
    }

    @Repository 
    public class VentorDaoImpl implements iVentorDao { 


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

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

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

    @PostConstruct

    public void init() { 



    @PreDestroy

    public void destory() { 

    }

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

    (轉貼)使用 Spring 2.5 注釋驅動的 IoC 功能

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

    概述

    注釋配置相對于 XML 配置具有很多的優勢:

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

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

     
    原來我們是怎么做的      
    在使用注釋配置之前,先來回顧一下傳統上是如何配置 Bean 并完成 Bean 之間依賴關系的建立。下面是 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 中:下面是使用傳統 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>    
         
    當我們運行以下代碼時,控制臺將正確打出 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 容器已經正確完成了 Bean 創建和裝配的工作。    
         
    使用 @Autowired 注釋    
       
    Spring 2.5 引入了 @Autowired 注釋,它可以對類成員變量、方法及構造函數進行標注,完成自動裝配的工作。來看一下使用 @Autowired 進行成員變量自動注入的代碼:    
      
    清單 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 進行解析,所以要讓 @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 將自動起作用,對標注 @Autowired 的 Bean 進行自動注入 -->    
        <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>    
         
        
    這 樣,當 Spring 容器啟動時,AutowiredAnnotationBeanPostProcessor 將掃描 Spring 容器中所有 Bean,當發現 Bean 中擁有 @Autowired 注釋時就找到和其匹配(默認按類型匹配)的 Bean,并注入到對應的地方中去。    
       
    按 照上面的配置,Spring 將直接采用 Java 反射機制對 Boss 中的 car 和 office 這兩個私有成員變量進行自動注入。所以對成員變量使用 @Autowired 后,您大可將它們的 setter 方法(setCar() 和 setOffice())從 Boss 中刪除。    
       
    當然,您也可以通過 @Autowired 對方法或構造函數進行標注,來看下面的代碼:    
        
    清單 8. 將 @Autowired 注釋標注在 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 將查找被標注的方法的入參類型的 Bean,并調用方法自動注入這些 Bean。而下面的使用方法則對構造函數進行標注:    
        
    清單 9. 將 @Autowired 注釋標注在構造函數上    
                        
    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() 構造函數有兩個入參,分別是 car 和 office,@Autowired 將分別尋找和它們類型匹配的 Bean,將它們作為 Boss(Car car ,Office office) 的入參來創建 Boss Bean。    
         
    當候選 Bean 數目不為 1 時的應對方法    
       
    在 默認情況下使用 @Autowired 注釋進行自動注入時,Spring 容器中匹配的候選 Bean 數目必須有且僅有一個。當找不到一個匹配的 Bean 時,Spring 容器將拋出 BeanCreationException 異常,并指出必須至少擁有一個匹配的 Bean。我們可以來做一個實驗:    
       
       
    清單 10. 候選 Bean 數目為 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 屬性標注了 @Autowired,當啟動 Spring 容器時,異常就產生了。    
       
    當 不能確定 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;    
        }    
        …    
    }    
        
    當 然,一般情況下,使用 @Autowired 的地方都是需要注入 Bean 的,使用了自動注入而又允許不注入的情況一般僅會在開發期或測試期碰到(如為了快速啟動 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,當對 Boss 的 office 成員變量進行自動注入時,Spring 容器將無法確定到底要用哪一個 Bean,因此異常發生了。    
       
    Spring 允許我們通過 @Qualifier 注釋指定注入 Bean 的名稱,這樣歧義就消除了,可以通過下面的方法解決異常:    
      
    清單 13. 使用 @Qualifier 注釋指定注入 Bean 的名稱    
                        
    @Autowired   
    public void setOffice(@Qualifier("office")Office office) {    
        this.office = office;    
    }    
        
     
    @Qualifier("office") 中的 office 是 Bean 的名稱,所以 @Autowired 和 @Qualifier 結合使用時,自動注入的策略就從 byType 轉變成 byName 了。@Autowired 可以對成員變量、方法以及構造函數進行注釋,而 @Qualifier 的標注對象是成員變量、方法入參、構造函數入參。正是由于注釋對象的不同,所以 Spring 不將 @Autowired 和 @Qualifier 統一成一個注釋類。下面是對成員變量和構造函數入參進行注釋的代碼:    
       
    對成員變量進行注釋:    
      
    清單 14. 對成員變量使用 @Qualifier 注釋    
                        
    public class Boss {    
        @Autowired   
        private Car car;    
         
        @Autowired   
        @Qualifier("office")    
        private Office office;    
        …    
    }    
         
        
    對構造函數入參進行注釋:    
        
    清單 15. 對構造函數變量使用 @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 結合使用,是對 @Autowired 有益的補充。一般來講,@Qualifier 對方法簽名中入參進行注釋會降低代碼的可讀性,而對成員變量注釋則相對好一些。    
        
       
    使用 JSR-250 的注釋    
       
    Spring 不但支持自己定義的 @Autowired 的注釋,還支持幾個由 JSR-250 規范定義的注釋,它們分別是 @Resource、@PostConstruct 以及 @PreDestroy。    
       
    @Resource   
       
    @Resource 的作用相當于 @Autowired,只不過 @Autowired 按 byType 自動注入,面 @Resource 默認按 byName 自動注入罷了。@Resource 有兩個屬性是比較重要的,分別是 name 和 type,Spring 將 @Resource 注釋的 name 屬性解析為 Bean 的名字,而 type 屬性則解析為 Bean 的類型。所以如果使用 name 屬性,則使用 byName 的自動注入策略,而使用 type 屬性時則使用 byType 自動注入策略。如果既不指定 name 也不指定 type 屬性,這時將通過反射機制使用 byName 自動注入策略。    
       
    Resource 注釋類位于 Spring 發布包的 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 類中標注這些注釋外,還需要在 Spring 容器中注冊一個負責處理這些注釋的 BeanPostProcessor:    
       
    <bean     
      class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor"/>    
         
      
    CommonAnnotationBeanPostProcessor 實現了 BeanPostProcessor 接口,它負責掃描使用了 JSR-250 注釋的 Bean,并對它們進行相應的操作。    
       
    @PostConstruct 和 @PreDestroy   
       
    Spring 容器中的 Bean 是有生命周期的,Spring 允許在 Bean 在初始化完成后以及 Bean 銷毀前執行特定的操作,您既可以通過實現 InitializingBean/DisposableBean 接口來定制初始化之后 / 銷毀之前的操作方法,也可以通過 <bean> 元素的 init-method/destroy-method 屬性指定初始化之后 / 銷毀之前調用的操作方法。關于 Spring 的生命周期,筆者在《精通 Spring 2.x—企業應用開發精解》第 3 章進行了詳細的描述,有興趣的讀者可以查閱。    
       
    JSR-250 為初始化之后/銷毀之前方法的指定定義了兩個注釋類,分別是 @PostConstruct 和 @PreDestroy,這兩個注釋只能應用于方法上。標注了 @PostConstruct 注釋的方法將在類實例化后調用,而標注了 @PreDestroy 的方法將在類銷毀之前調用。    
      
    清單 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");     
        }    
        …    
    }    
         
    您只需要在方法前標注 @PostConstruct 或 @PreDestroy,這些方法就會在 Bean 初始化后或銷毀之前被 Spring 容器執行了。    
       
    我 們知道,不管是通過實現 InitializingBean/DisposableBean 接口,還是通過 <bean> 元素的 init-method/destroy-method 屬性進行配置,都只能為 Bean 指定一個初始化 / 銷毀的方法。但是使用 @PostConstruct 和 @PreDestroy 注釋卻可以指定多個初始化 / 銷毀方法,那些被標注 @PostConstruct 或 @PreDestroy 注釋的方法都會在初始化 / 銷毀時被執行。    
       
    通過以下的測試代碼,您將可以看到 Bean 的初始化 / 銷毀方法是如何被執行的:    
      
    清單 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();// 關閉 Spring 容器,以觸發 Bean 銷毀方法的執行    
        }    
    }    
         
       
    這 時,您將看到標注了 @PostConstruct 的 postConstruct1() 方法將在 Spring 容器啟動時,創建 Boss Bean 的時候被觸發執行,而標注了 @PreDestroy 注釋的 preDestroy1() 方法將在 Spring 容器關閉前銷毀 Boss Bean 的時候被觸發執行。    
           
    使用 <context:annotation-config/> 簡化配置    
       
    Spring 2.1 添加了一個新的 context 的 Schema 命名空間,該命名空間對注釋驅動、屬性文件引入、加載期織入等功能提供了便捷的配置。我們知道注釋本身是不會做任何事情的,它僅提供元數據信息。要使元數 據信息真正起作用,必須讓負責處理這些元數據的處理器工作起來。     
       
    而我們前面所介紹的 AutowiredAnnotationBeanPostProcessor 和 CommonAnnotationBeanPostProcessor 就是處理這些注釋元數據的處理器。但是直接在 Spring 配置文件中定義這些 Bean 顯得比較笨拙。Spring 為我們提供了一種方便的注冊這些 BeanPostProcessor 的方式,這就是 <context:annotation-config/>。請看下面的配置:    
         
    清單 19. 調整 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> 進行定義 —— 也就是說,在 XML 配置文件中定義 Bean,通過 @Autowired 或 @Resource 為 Bean 的成員變量、方法入參或構造函數入參提供自動注入的功能。能否也通過注釋定義 Bean,從 XML 配置文件中完全移除 Bean 定義的配置呢?答案是肯定的,我們通過 Spring 2.5 提供的 @Component 注釋就可以達到這個目標了。    
       
    下面,我們完全使用注釋定義 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 有一個可選的入參,用于指定 Bean 的名稱,在 Boss 中,我們就將 Bean 名稱定義為“boss”。一般情況下,Bean 都是 singleton 的,需要注入 Bean 的地方僅需要通過 byType 策略就可以自動注入了,所以大可不必指定 Bean 的名稱。    
       
    在使用 @Component 注釋后,Spring 容器必須啟用類掃描機制以啟用注釋驅動 Bean 定義和注釋驅動 Bean 自動注入的策略。Spring 2.5 對 context 命名空間進行了擴展,提供了這一功能,請看下面的配置:    
        
    清單 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 的配置內容已經被移除,僅需要添加一行 <context:component-scan/> 配置就解決所有問題了——Spring XML 配置文件得到了極致的簡化(當然配置元數據還是需要的,只不過以注釋形式存在罷了)。<context:component-scan/> 的 base-package 屬性指定了需要掃描的類包,類包及其遞歸子包中所有的類都會被處理。    
       
    <context:component-scan/> 還允許定義過濾器將基包下的某些類納入或排除。Spring 支持以下 4 種類型的過濾方式,通過下表說明:    
       
    表 1. 掃描過濾方式    
    過濾器類型 說明     
    注釋 假如 com.baobaotao.SomeAnnotation 是一個注釋類,我們可以將使用該注釋的類過濾出來。     
    類名指定 通過全限定類名進行過濾,如您可以指定將 com.baobaotao.Boss 納入掃描,而將 com.baobaotao.Car 排除在外。     
    正則表達式 通過正則表達式定義過濾的類,如下所示: com\.baobaotao\.Default.*     
    AspectJ 表達式 通過 AspectJ 表達式定義過濾的類,如下所示: 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/> 配置項不但啟用了對類包進行掃描以實施注釋驅動 Bean 定義的功能,同時還啟用了注釋驅動自動注入的功能(即還隱式地在內部注冊了 AutowiredAnnotationBeanPostProcessor 和 CommonAnnotationBeanPostProcessor),因此當使用 <context:component-scan/> 后,就可以將 <context:annotation-config/> 移除了。    
       
    默認情況下通過 @Component 定義的 Bean 都是 singleton 的,如果需要使用其它作用范圍的 Bean,可以通過 @Scope 注釋來達到目標,如以下代碼所示:    
       
    清單 24. 通過 @Scope 指定 Bean 的作用范圍    
                        
    package com.baobaotao;    
    import org.springframework.context.annotation.Scope;    
    …    
    @Scope("prototype")    
    @Component("boss")    
    public class Boss {    
        …    
    }    
         
    這樣,當從 Spring 容器中獲取 boss Bean 時,每次返回的都是新的實例了。    
          
    采用具有特殊語義的注釋    
       
    Spring 2.5 中除了提供 @Component 注釋外,還定義了幾個擁有特殊語義的注釋,它們分別是:@Repository、@Service 和 @Controller。在目前的 Spring 版本中,這 3 個注釋和 @Component 是等效的,但是從注釋類的命名上,很容易看出這 3 個注釋分別和持久層、業務層和控制層(Web 層)相對應。雖然目前這 3 個注釋和 @Component 相比沒有什么新意,但 Spring 將在以后的版本中為它們添加特殊的功能。所以,如果 Web 應用程序采用了經典的三層分層結構的話,最好在持久層、業務層和控制層分別采用 @Repository、@Service 和 @Controller 對分層中的類進行注釋,而用 @Component 對那些比較中立的類進行注釋。    
            
    注釋配置和 XML 配置的適用場合    
       
    是否有了這些 IOC 注釋,我們就可以完全摒除原來 XML 配置的方式呢?答案是否定的。有以下幾點原因:    
       
    注 釋配置不一定在先天上優于 XML 配置。如果 Bean 的依賴關系是固定的,(如 Service 使用了哪幾個 DAO 類),這種配置信息不會在部署時發生調整,那么注釋配置優于 XML 配置;反之如果這種依賴關系會在部署時發生調整,XML 配置顯然又優于注釋配置,因為注釋是對 Java 源代碼的調整,您需要重新改寫源代碼并重新編譯才可以實施調整。     
    如果 Bean 不是自己編寫的類(如 JdbcTemplate、SessionFactoryBean 等),注釋配置將無法實施,此時 XML 配置是唯一可用的方式。     
    注釋配置往往是類級別的,而 XML 配置則可以表現得更加靈活。比如相比于 @Transaction 事務注釋,使用 aop/tx 命名空間的事務配置更加靈活和簡單。     
    所 以在實現應用中,我們往往需要同時使用注釋配置和 XML 配置,對于類級別且不會發生變動的配置可以優先考慮注釋配置;而對于那些第三方類以及容易發生調整的配置則應優先考慮使用 XML 配置。Spring 會在具體實施 Bean 創建和 Bean 注入之前將這兩種配置方式的元信息融合在一起。    
           
    小結    
       
    Spring 在 2.1 以后對注釋配置提供了強力的支持,注釋配置功能成為 Spring 2.5 的最大的亮點之一。合理地使用 Spring 2.5 的注釋配置,可以有效減少配置的工作量,提高程序的內聚性。但是這并不意味著傳統 XML 配置將走向消亡,在第三方類 Bean 的配置,以及那些諸如數據源、緩存池、持久層操作模板類、事務管理等內容的配置上,XML 配置依然擁有不可替代的地位。

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

    (轉貼)數據庫三范式經典實例解析

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

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

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

     

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

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


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

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

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

    本帖匯總了網上幾篇關于hibernate的生命周期的帖子。

    轉載:

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

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

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

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

    處于Persistent狀態的實體可以簡單的理解為:如果一個實體對象與session發生了關聯,并且處于session的有效期內,那么這個實體對象就處于Persistent狀態.

    3.游離狀態(Detached)
    處于Persistent狀態的實體對象,其對應的session關閉以后,那么這個實體就處于 Detached狀態.
    我們可以認為session對象就是一個Persistent的宿主,一旦這個宿主失效,那么這個實體就處于 Detached狀態.

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

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

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

    persistence context



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

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

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

    (轉貼)BigInteger 和 BigDecimal

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

    高精度浮點數BigDecimal

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

    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 { 
    //默認除法運算精度,及即保留小數點多少位 
    private static final int DEF_DIV_SCALE = 2; 
    //這個類不能實例化 
    private BigDecimalUtil (){   } 
    /**   
      * * 提供精確的加法運算。   
      * * @param v1 被加數   
      * * @param v2 加數   
      * * @return 兩個參數的和   
      * */ 
    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(); 

    /**

      *提供精確的減法運算。 
      * * @param v1 被減數 
      * * @param v2 減數 
      * * @return 兩個參數的差
      **/ 
    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(); 

    /**   
      * * 提供精確的乘法運算。   
      * * @param v1 被乘數   
      * * @param v2 乘數   
      * * @return 兩個參數的積   
      * */
    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(); 

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

    /**   
      * * 提供(相對)精確的除法運算。當發生除不盡的情況時,由scale參數指   
      * * 定精度,以后的數字四舍五入。   
      * * @param v1 被除數 
      * @param v2 除數   
      * * @param scale 表示表示需要精確到小數點以后幾位。   
      * * @return 兩個參數的商   
      * */ 
    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(); 

    /**   
      * * 提供精確的小數位四舍五入處理。   
      * * @param v 需要四舍五入的數字   
      * * @param scale 小數點后保留幾位   
      * * @return 四舍五入后的結果   
      * */ 
    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); 
    }
    }

    高精度整數BigInteger

    BigInteger支持任意精度的整數,也就是說我們可精確表示任意大小的整數值;同時在運算過程中不會丟失任何信息;
    在BigInteger類中有所有的基本算術運算方法,如加、減、乘、除,以及可能會用到的位運算如或、異或、非、左移、右移等。下面是一些方法的例子:當然,如果要有更多的使用方法,可以查閱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 閱讀(1028) | 評論 (0)編輯 收藏

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

     

    引用:

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

    /**

     * 超大整數相加:

     * 題目要求:如果系統要使用超大整數(超過long的范圍),請你設計一個數據結構來存儲這種

     * 超大型數字以及設計一種算法來實現超大整數的加法運算

     * @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 加數字符串1

         * @param b 加數字符串2

         * @return 結果字符串

         * 分析:

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

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

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

         * 4、從最高位,一個個數的取出來相加,當然首先得轉換為整型

         * 5、設置進位,如果兩個數相加及加上進位大于等于10,并且這不是最左邊一個字符相加,相加結果等于

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

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

         */

        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";

           }

           //把長度調整到相同

           if(maxLen==lenA)

           {

               b=strTmp+b;

           }else

               a=strTmp+a;

           int JW=0;//進位

           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; 也可以實現。

    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 閱讀(926) | 評論 (0)編輯 收藏

    (轉貼)java回調函數

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

    引用:

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

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

    下面舉個通俗的例子:

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

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

     

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

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

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

     

    //另外一個類有方法里面有個參數以是這個接口類型的
    public class FooBar {
        private ICallBack callBack;
        public void setCallBack(ICallBack callBack) {
            this.callBack = callBack;
        }
        public void doSth() {
            callBack.postExec();
        }
    }
    ---------------------------------------
    回調的實現
    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();//調用函數
        }
    }

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

    <2010年12月>
    2829301234
    567891011
    12131415161718
    19202122232425
    2627282930311
    2345678

    導航

    統計

    常用鏈接

    留言簿

    隨筆分類

    隨筆檔案

    搜索

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 久久夜色精品国产嚕嚕亚洲av| a级毛片免费完整视频| 久久精品国产亚洲AV网站| 国产aa免费视频| 影音先锋在线免费观看| 中文字幕成人免费视频| XXX2高清在线观看免费视频| 亚洲精品一卡2卡3卡四卡乱码| 亚洲精品在线免费观看| 亚洲成av人影院| 亚洲国产无套无码av电影| 亚洲女人被黑人巨大进入| 国产乱子伦精品免费无码专区| 最近的免费中文字幕视频 | 国产在线19禁免费观看| 久草在视频免费福利| 久久精品人成免费| 国产一级淫片a免费播放口| 国产精品黄页免费高清在线观看| 亚洲av无一区二区三区| 亚洲AV男人的天堂在线观看| 亚洲一区二区三区精品视频| 亚洲嫩草影院在线观看| 久久亚洲美女精品国产精品| 久久亚洲一区二区| 久久精品国产亚洲AV麻豆王友容| 亚洲成av人在线视| 亚洲第一成年男人的天堂| 亚洲无删减国产精品一区| 久久精品九九亚洲精品| 亚洲麻豆精品果冻传媒| 亚洲小视频在线播放| 亚洲av无码专区在线| 亚洲精品无码久久久久A片苍井空| 伊人久久五月丁香综合中文亚洲| 亚洲一级特黄特黄的大片| 亚洲色偷偷色噜噜狠狠99| 亚洲精品第一国产综合亚AV| 亚洲国产精品美女久久久久| 亚洲AV无码一区二区大桥未久| 337P日本欧洲亚洲大胆精品|