2010年7月6日

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

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

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

          行數(shù)應該為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 閱讀(495) | 評論 (0)編輯 收藏

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

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

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

          code1: colors類  根節(jié)點
          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é)點
          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é)點
          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 閱讀(10143) | 評論 (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之前調用,而業(yè)務中prepare要負責準備model,準備model又需要參數(shù),這就需要在 prepare之前運行params攔截器設置相關參數(shù),這個也就是創(chuàng)建paramsPrepareParamsStack的原因。流程如下:
             1. params攔截器首先給action中的相關參數(shù)賦值,如id  
             2. prepare攔截器執(zhí)行prepare方法,prepare方法中會根據(jù)參數(shù),如id,去調用業(yè)務邏輯,設置model對象
             3. modelDriven攔截器將model對象壓入value stack,這里的model對象就是在prepare中創(chuàng)建的
             4. params攔截器再將參數(shù)賦值給model對象
             5. action的業(yè)務邏輯執(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再為界面準備數(shù)據(jù),因為prepare方法已經(jīng)準備好了model,這些方法很簡單。對于update 方法,prepare首先會從數(shù)據(jù)庫中加載數(shù)據(jù),然后params攔截器會將參數(shù)值付給model,在update直接更新就可以,不會出現(xiàn)數(shù)據(jù)被亂更新 的情況。象Hibernate框架,會判斷哪些字段更新了,然后進行更新,性能也不會損失。
          通過paramsPrepareParamsStack可以讓流程更明確,代碼更簡潔,也更利于大家的交流。

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

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

          Struts 2雜談(1):ValueStack對象的傳送帶機
          作者:nokiaguy  原文地址:http://blog.csdn.net/nokiaguy/article/details/4684750
          轉貼
             眾所周知,Strut 2的Action類通過屬性可以獲得所有相關的值,如請求參數(shù)、Action配置參數(shù)、向其他Action傳遞屬性值(通過chain結果)等等。要獲得 這些參數(shù)值,我們要做的唯一一件事就是在Action類中聲明與參數(shù)同名的屬性,在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攔截器用于將請求參數(shù)值映射到相 應成Action類的屬性值。在params攔截器中在獲得請求參數(shù)值后,會使用setValue方法設置相應的Action類的屬性。
              從這一點可以看出,ValueStack對象就象一個傳送帶,當客戶端請求.action時,Struts 2在創(chuàng)建相應用Action對象后就將Action對象放到了ValueStack傳送帶上,然后ValueStack傳送帶會帶著Action對象經(jīng)過 若干攔截器,在每一攔截器中都可以通過ValueStack對象設置和獲得Action對象中的屬性值。實際上,這些攔截器就相當于流水線作業(yè)。如果要對 Action對象進行某項加工,再加一個攔截器即可,當不需要進行這項工作時,直接將該攔截器去掉即可。
              下面我們使用一個例子來演示這個過程。在這個例子中實現(xiàn)了一個攔截器,該攔截器的功能是將一個屬性文件中的key-value對映射成相應的屬性的值。如下面是一個屬性文件的內容:

              name = 超人
              price = 10000

              我們可以在Action類中定義name和price屬性,在Action中引用這個攔截器后,就會自動為屬性賦值。
              在使用該攔截器有如下規(guī)則:
              1.  攔截器讀取的屬性文件路徑由path參數(shù)指定。
              2.  屬性文件的編碼格式由encoding參數(shù)指定,默認值是UTF-8。
              3.  如果某個key中包含有“.”(該符號不能出現(xiàn)在標識符中),則有如下處理方法:
              (1)將Action類的屬性名定義為去掉“.”的key。例如,key為person.name,而屬性名可定義為personname。
              (2)將Action類的屬性名定義為將“.”替換成其他字符的表示符號。例如,key為person.name,而屬性名可定義為person_name,其中“_”由separator參數(shù)指定。
              4.  如果key太長,也可以直接使用Action參數(shù)進行映射,例如,key為country.person.name,可做如下映射:
                <param name="countrypersonname">name</param>
                要注意的是,name屬性值不能包含“.”,因此,應將key值中的“.”去掉。現(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對象中的相應屬性值
                          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配置參數(shù)或請求參數(shù) 來干預最終究輸出結果了。

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

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

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

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

          structs2配置UrlRewriteFilter

          轉載每個網(wǎng)頁或請求都是一個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可以很好的改善這個狀況。網(wǎng)站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 文件,根據(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 閱讀(1783) | 評論 (0)編輯 收藏

          structs2 filter的執(zhí)行順序

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

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

          structs2攔截器

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

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

          (轉貼)struts2 工作原理圖

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

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

          重新認識Java finally

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

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

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

          在字節(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) 調用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)的異常,并重新拋出捕獲的異常,或者拋出一個自己構造的新異常,這個新異常就會覆蓋try語句塊中的異常。
          二 返回值覆蓋

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

          這個方法的返回值是100還是200?結果是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) 調用finally微型子程序
          3) 把局部變量(指temp)的值push到操作數(shù)棧頂,然后返回到調用方法
               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 節(jié) Compiling finally。那里詳細介紹了 Java 虛擬機是如何編譯 finally 語句塊。實際上,Java 虛擬機會把 finally 語句塊作為 subroutine(對于這個 subroutine 不知該如何翻譯為好,干脆就不翻譯了,免得產(chǎn)生歧義和誤解。)直接插入到 try 語句塊或者 catch 語句塊的控制轉移語句之前。但是,還有另外一個不可忽視的因素,那就是在執(zhí)行 subroutine(也就是 finally 語句塊)之前,try 或者 catch 語句塊會保留其返回值到本地變量表(Local Variable Table)中。待 subroutine 執(zhí)行完畢之后,再恢復保留的返回值到操作數(shù)棧中,然后通過 return 或者 throw 語句將其返回給該方法的調用者(invoker)。請注意,前文中我們曾經(jīng)提到過 return、throw 和 break、continue 的區(qū)別,對于這條規(guī)則(保留返回值),只適用于 return 和 throw 語句,不適用于 break 和 continue 語句,因為它們根本就沒有返回值。

          posted @ 2011-11-01 16:56 AK47 閱讀(837) | 評論 (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加入頁面中

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

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

          2.1 prmNames選項

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

          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", // 表示當在編輯數(shù)據(jù)模塊中發(fā)送數(shù)據(jù)時,使用的id的名稱

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

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

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

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

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

          npage: null,

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

          }

          2.2 jsonReader選項

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

          jsonReader : {

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

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

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

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

          repeatitems: true, // 如果設為false,則jqGrid在解析json時,會根據(jù)name來搜索對應的數(shù)據(jù)元素(即可以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"}, // 數(shù)據(jù)中需要各列的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參數(shù)(prmNames中設置的)傳遞到Server。
          • label :當jqGrid的colNames選項數(shù)組為空時,為各列指定題頭。如果colNames和此項都為空時,則name選項值會成為題頭。
          • width :設置列的寬度,目前只能接受以px為單位的數(shù)值,默認為150。
          • sortable :設置該列是否可以排序,默認為true。
          • search :設置該列是否可以被列為搜索條件,默認為true。
          • resizable :設置列是否可以變更尺寸,默認為true。
          • hidden :設置此列初始化時是否為隱藏狀態(tài),默認為false。
          • formatter :預設類型或用來格式化該列的自定義函數(shù)名。常用預設格式有:integer、date、currency、number等(具體參見文檔 )。

          三、 注意事項

          1. 動態(tài)改變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在每次點擊編輯的時候都會執(zhí)行。initComparator的作用是通過ajax獲取數(shù)據(jù),然后利 用$("#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); 得到數(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中的可編輯的字段,可以設定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網(wǎng)站 :




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

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

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

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

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

               @Repository用于標注數(shù)據(jù)訪問組件,即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實現(xiàn)類注入到service實現(xiàn)類中,把service的接口(注意不要是service的實現(xiàn)類)注入到action中,注入時不要new 這個注入的類,因為spring會自動注入,如果手動再new的話會出現(xiàn)錯誤,然后屬性加上@Autowired后不需要getter()和 setter()方法,Spring也會自動注入。至于更具體的內容,等對注入的方式更加熟練后會做個完整的例子上來。

          注解:

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

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

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

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

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

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

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

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

          @Repository持久層組件,用于標注數(shù)據(jù)訪問組件,即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 閱讀(49719) | 評論 (3)編輯 收藏

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

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

          概述

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

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

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

           
          原來我們是怎么做的      
          在使用注釋配置之前,先來回顧一下傳統(tǒng)上是如何配置 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 中:下面是使用傳統(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>    
               
          當我們運行以下代碼時,控制臺將正確打出 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 注釋,它可以對類成員變量、方法及構造函數(shù)進行標注,完成自動裝配的工作。來看一下使用 @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,當發(fā)現(xiàn) Bean 中擁有 @Autowired 注釋時就找到和其匹配(默認按類型匹配)的 Bean,并注入到對應的地方中去。    
             
          按 照上面的配置,Spring 將直接采用 Java 反射機制對 Boss 中的 car 和 office 這兩個私有成員變量進行自動注入。所以對成員變量使用 @Autowired 后,您大可將它們的 setter 方法(setCar() 和 setOffice())從 Boss 中刪除。    
             
          當然,您也可以通過 @Autowired 對方法或構造函數(shù)進行標注,來看下面的代碼:    
              
          清單 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 將查找被標注的方法的入?yún)㈩愋偷?Bean,并調用方法自動注入這些 Bean。而下面的使用方法則對構造函數(shù)進行標注:    
              
          清單 9. 將 @Autowired 注釋標注在構造函數(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() 構造函數(shù)有兩個入?yún)ⅲ謩e是 car 和 office,@Autowired 將分別尋找和它們類型匹配的 Bean,將它們作為 Boss(Car car ,Office office) 的入?yún)韯?chuàng)建 Boss Bean。    
               
          當候選 Bean 數(shù)目不為 1 時的應對方法    
             
          在 默認情況下使用 @Autowired 注釋進行自動注入時,Spring 容器中匹配的候選 Bean 數(shù)目必須有且僅有一個。當找不到一個匹配的 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 屬性標注了 @Autowired,當啟動 Spring 容器時,異常就產(chǎn)生了。    
             
          當 不能確定 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 的,使用了自動注入而又允許不注入的情況一般僅會在開發(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,當對 Boss 的 office 成員變量進行自動注入時,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 結合使用時,自動注入的策略就從 byType 轉變成 byName 了。@Autowired 可以對成員變量、方法以及構造函數(shù)進行注釋,而 @Qualifier 的標注對象是成員變量、方法入?yún)ⅰ嬙旌瘮?shù)入?yún)ⅰU怯捎谧⑨寣ο蟮牟煌?Spring 不將 @Autowired 和 @Qualifier 統(tǒng)一成一個注釋類。下面是對成員變量和構造函數(shù)入?yún)⑦M行注釋的代碼:    
             
          對成員變量進行注釋:    
            
          清單 14. 對成員變量使用 @Qualifier 注釋    
                              
          public class Boss {    
              @Autowired   
              private Car car;    
               
              @Autowired   
              @Qualifier("office")    
              private Office office;    
              …    
          }    
               
              
          對構造函數(shù)入?yún)⑦M行注釋:    
              
          清單 15. 對構造函數(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 結合使用,是對 @Autowired 有益的補充。一般來講,@Qualifier 對方法簽名中入?yún)⑦M行注釋會降低代碼的可讀性,而對成員變量注釋則相對好一些。    
              
             
          使用 JSR-250 的注釋    
             
          Spring 不但支持自己定義的 @Autowired 的注釋,還支持幾個由 JSR-250 規(guī)范定義的注釋,它們分別是 @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 發(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 類中標注這些注釋外,還需要在 Spring 容器中注冊一個負責處理這些注釋的 BeanPostProcessor:    
             
          <bean     
            class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor"/>    
               
            
          CommonAnnotationBeanPostProcessor 實現(xiàn)了 BeanPostProcessor 接口,它負責掃描使用了 JSR-250 注釋的 Bean,并對它們進行相應的操作。    
             
          @PostConstruct 和 @PreDestroy   
             
          Spring 容器中的 Bean 是有生命周期的,Spring 允許在 Bean 在初始化完成后以及 Bean 銷毀前執(zhí)行特定的操作,您既可以通過實現(xiàn) InitializingBean/DisposableBean 接口來定制初始化之后 / 銷毀之前的操作方法,也可以通過 <bean> 元素的 init-method/destroy-method 屬性指定初始化之后 / 銷毀之前調用的操作方法。關于 Spring 的生命周期,筆者在《精通 Spring 2.x—企業(yè)應用開發(fā)精解》第 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 容器執(zhí)行了。    
             
          我 們知道,不管是通過實現(xiàn) InitializingBean/DisposableBean 接口,還是通過 <bean> 元素的 init-method/destroy-method 屬性進行配置,都只能為 Bean 指定一個初始化 / 銷毀的方法。但是使用 @PostConstruct 和 @PreDestroy 注釋卻可以指定多個初始化 / 銷毀方法,那些被標注 @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();// 關閉 Spring 容器,以觸發(fā) Bean 銷毀方法的執(zhí)行    
              }    
          }    
               
             
          這 時,您將看到標注了 @PostConstruct 的 postConstruct1() 方法將在 Spring 容器啟動時,創(chuàng)建 Boss Bean 的時候被觸發(fā)執(zhí)行,而標注了 @PreDestroy 注釋的 preDestroy1() 方法將在 Spring 容器關閉前銷毀 Boss Bean 的時候被觸發(fā)執(zhí)行。    
                 
          使用 <context:annotation-config/> 簡化配置    
             
          Spring 2.1 添加了一個新的 context 的 Schema 命名空間,該命名空間對注釋驅動、屬性文件引入、加載期織入等功能提供了便捷的配置。我們知道注釋本身是不會做任何事情的,它僅提供元數(shù)據(jù)信息。要使元數(shù) 據(jù)信息真正起作用,必須讓負責處理這些元數(shù)據(jù)的處理器工作起來。     
             
          而我們前面所介紹的 AutowiredAnnotationBeanPostProcessor 和 CommonAnnotationBeanPostProcessor 就是處理這些注釋元數(shù)據(jù)的處理器。但是直接在 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 的成員變量、方法入?yún)⒒驑嬙旌瘮?shù)入?yún)⑻峁┳詣幼⑷氲墓δ堋D芊褚餐ㄟ^注釋定義 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 有一個可選的入?yún)ⅲ糜谥付?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 的配置內容已經(jīng)被移除,僅需要添加一行 <context:component-scan/> 配置就解決所有問題了——Spring XML 配置文件得到了極致的簡化(當然配置元數(shù)據(jù)還是需要的,只不過以注釋形式存在罷了)。<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 個注釋分別和持久層、業(yè)務層和控制層(Web 層)相對應。雖然目前這 3 個注釋和 @Component 相比沒有什么新意,但 Spring 將在以后的版本中為它們添加特殊的功能。所以,如果 Web 應用程序采用了經(jīng)典的三層分層結構的話,最好在持久層、業(yè)務層和控制層分別采用 @Repository、@Service 和 @Controller 對分層中的類進行注釋,而用 @Component 對那些比較中立的類進行注釋。    
                  
          注釋配置和 XML 配置的適用場合    
             
          是否有了這些 IOC 注釋,我們就可以完全摒除原來 XML 配置的方式呢?答案是否定的。有以下幾點原因:    
             
          注 釋配置不一定在先天上優(yōu)于 XML 配置。如果 Bean 的依賴關系是固定的,(如 Service 使用了哪幾個 DAO 類),這種配置信息不會在部署時發(fā)生調整,那么注釋配置優(yōu)于 XML 配置;反之如果這種依賴關系會在部署時發(fā)生調整,XML 配置顯然又優(yōu)于注釋配置,因為注釋是對 Java 源代碼的調整,您需要重新改寫源代碼并重新編譯才可以實施調整。     
          如果 Bean 不是自己編寫的類(如 JdbcTemplate、SessionFactoryBean 等),注釋配置將無法實施,此時 XML 配置是唯一可用的方式。     
          注釋配置往往是類級別的,而 XML 配置則可以表現(xiàn)得更加靈活。比如相比于 @Transaction 事務注釋,使用 aop/tx 命名空間的事務配置更加靈活和簡單。     
          所 以在實現(xiàn)應用中,我們往往需要同時使用注釋配置和 XML 配置,對于類級別且不會發(fā)生變動的配置可以優(yōu)先考慮注釋配置;而對于那些第三方類以及容易發(fā)生調整的配置則應優(yōu)先考慮使用 XML 配置。Spring 會在具體實施 Bean 創(chuàng)建和 Bean 注入之前將這兩種配置方式的元信息融合在一起。    
                 
          小結    
             
          Spring 在 2.1 以后對注釋配置提供了強力的支持,注釋配置功能成為 Spring 2.5 的最大的亮點之一。合理地使用 Spring 2.5 的注釋配置,可以有效減少配置的工作量,提高程序的內聚性。但是這并不意味著傳統(tǒng) XML 配置將走向消亡,在第三方類 Bean 的配置,以及那些諸如數(shù)據(jù)源、緩存池、持久層操作模板類、事務管理等內容的配置上,XML 配置依然擁有不可替代的地位。

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

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

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

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

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

           

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

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

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

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

          轉載:

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

          1. 自由狀態(tài)(Transient)
          所謂的Transient狀態(tài),即實體對象在內存中自由存在,與數(shù)據(jù)庫中的記錄無關,通常是我們的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");
                  
          //在這個事務中我們并沒有顯示的調用save()方法但是由于Persistent狀態(tài)的對象將會自動的固化到
                  
          //數(shù)據(jù)庫中,因此此時正處在Persistent狀態(tài)的test對象的變化也將自動被同步到數(shù)據(jù)庫中
                  tr2.commit();

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

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

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

          既然Transient狀態(tài)的實體與Detached狀態(tài)的實體都與Hibernate的實體管理容器沒有關系,那他們到底存在哪些差異?
          差異就在于處于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的記錄相關聯(lián).
          這就是他們之間所存在的差異, 簡而言之,Transient狀態(tài)的實體缺乏與數(shù)據(jù)庫表記錄之間的聯(lián)系,而Detached狀態(tài)的試題恰恰相反.只不過是脫離了session這個數(shù)據(jù)庫操作平臺而已.
          原帖地址 : http://www.aygfsteel.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:

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

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

          (轉貼)BigInteger 和 BigDecimal

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

          高精度浮點數(shù)BigDecimal

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

          /**

            *提供精確的減法運算。 
            * * @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(); 

          /**   
            * * 提供精確的乘法運算。   
            * * @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(); 

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

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

          高精度整數(shù)BigInteger

          BigInteger支持任意精度的整數(shù),也就是說我們可精確表示任意大小的整數(shù)值;同時在運算過程中不會丟失任何信息;
          在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 閱讀(1031) | 評論 (0)編輯 收藏

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

           

          引用:

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

          /**

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

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

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

           * @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 結果字符串

               * 分析:

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

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

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

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

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

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

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

               */

              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; 也可以實現(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)編輯 收藏

          (轉貼)java回調函數(shù)

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

          引用:

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

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

          下面舉個通俗的例子:

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

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

           

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

          聲明一個接口,另外一個類有方法里面有個參數(shù)以是這個接口類型的,而后在另外類中實現(xiàn)這個接口(java中多用的是匿名內部類),而且以這個匿名的類生成的對象為參數(shù)傳到上面提到類中,而后實現(xiàn)回調.......這種用法可以參考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();
              }
          }
          ---------------------------------------
          回調的實現(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();//調用函數(shù)
              }
          }

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

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

          面向對象設計里有一點大家已基本形成共識,就是面向接口編程,我想大多數(shù)人對這個是沒有什么覺得需要懷疑的。

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

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

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

          一點感想,歡迎大家拍磚。

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

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

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

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

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

          package com.kangdy.test;
          /**
           * 數(shù)字金額轉化成大寫
           * 先將整數(shù)與小數(shù)部分分開,計算小數(shù)部分,角分并保存
           * 整數(shù)部分長度不足12位,前面加0補足。
           * 將整數(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補足
            *
            * @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();
           }

           /**
            * 遞歸拆分數(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)拆分數(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ù)字轉化成字符串
            *
            * @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();
           }

           /**
            * 得到最終結果
            *
            * @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 閱讀(617) | 評論 (0)編輯 收藏

          類和對象的初始化

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


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


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

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


          在Java代碼中,一個正確的初始值是通過類變量初始化語句或者靜態(tài)初始化語句給出的。
           1)一個類變量初始化語句是變量聲明后面的等號和表達式:
           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程序方法是無法
          調用這個<clinit>方法的。這種方法只能被Java虛擬機調用

          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 變量的類變量初始化語句,并且類變量初始化語句是編譯時常量表達式,類不會有<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ī)定,接口中的變量默認自動隱含是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虛擬機在首次主動使用類型時初始化它們。只有6種活動被認為是主動使
          用:
           1)創(chuàng)建類的新實例,
           2)調用類中聲明的靜態(tài)方法,
           3)操作類或者接口中聲明的非常量靜態(tài)字段,
           4)調用JavaAPI中特定的反射方法
           5)初始化一個類的子類;
           6)以及指定一個類作為Java虛擬機啟動時的初始化類。
           
             使用一個非常量的靜態(tài)字段只有當類或者接口的確聲明了這個字段時才是主動使用、比如,
          類中聲明的字段可能會被子類引用;接口中聲明的字段可能會被子接口或者實現(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.");
           }
           
          }
          運行結果:
          example1 is initialized.
          new parement is initialized.
          0
          NewbornBaby 沒有被初始化,也沒有被加載。


          對象的生命周期

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

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

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

          與C++不同的是,在創(chuàng)建新的類實例期間,java編程語言不會為方法分派來指定變更的規(guī)則。如果調用的方法在被
          初始化對象的子類中重寫,那么就是用重寫的方法。甚至新對象被完全初始化前也是如此。編譯和運行下面的例子
          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í)行。而是調用的Test中的printThree()。

           

           
           

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

          Java虛擬機體系結構

          Java虛擬機體系結構


          方法區(qū)
                   在Java虛擬機中,被裝載類型的信息存儲在一個邏輯上被稱為方法區(qū)的內存中。
           當虛擬機裝載某個類型時,它使用類裝載器定位相應的class文件,-->讀入這個class文件(一個線性的二進制流)->將它傳入虛擬機-->
           虛擬機提取類型信息,并將信息存入方法區(qū),類型中的類(靜態(tài))變量也存儲在方法區(qū).
           方法區(qū)特點:
           1)所有線程共享方法區(qū)。它是線程安全的。
           2)方法區(qū)大小不是固定的。虛擬機根據(jù)需要自行調整。
           3)方法區(qū)可以被垃圾回收。
           對于每個被裝載的類型,虛擬機會在方法區(qū)中存儲以下信息。
           
           1)類型的基本信息;
               a)類型的全限定名
               b)類型的直接超類全限定名(除非這個類型是java.lang.Objet,它沒超類)。
               c)類型是類類型還是接口類型(就是說是一個類還是一個接口)。
               d)類型的訪問修飾符(public ,abstract或final的某個子類)
               e)任何直接超接口的全限定名的有序列表。
               
           2)該類型的常量池
             虛擬機必須為每個被裝載的類型維護一個常量池。常量池就是該類型所用常量的一個有序集合,
             包括直接常量(string,integer,floating point常量)和對其他類型、字段和方法的符號引用。
             池中的數(shù)據(jù)項就像數(shù)組一樣是通過索引訪問的。因為常量池存儲了相應類型所用到的所有類型、
             字段和方法的符號引用,所以它在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)
             每個編譯時常量的類型都會復制它所有常量到它自己的常量池中或者它的字節(jié)碼流中(通常情況下編譯時直接替換字節(jié)碼)。

             
           6)一個到類classLoader的引用
             指向ClassLoader類的引用  每個類型被裝載的時候,虛擬機必須跟蹤它是由啟動類裝載器
             還是由用戶自定義類裝載器裝載的。如果是用戶自定義類裝載器裝載的,那么虛擬機必須在類
             型信息中存儲對該裝載器的引用:這是作為方法表中的類型數(shù)據(jù)的一部分保存的。
             虛擬機會在動態(tài)連按期間使用這個信息。當某個類型引用另一個類型的時候,虛擬機會請求裝載
             發(fā)起引用類型的類裝載器來裝載被引用的類型。這個動態(tài)連接的過程,對于虛擬機分離命名空間
             的方式也是至關重要的。為了能夠正確地執(zhí)行動態(tài)連接以及維護多個命名空間,虛擬機需要在方
             法表中得知每個類都是由哪個類裝載器裝載的。
             
           7)一個到Class類的引用
              指向Class類的引用  對于每一個被裝載的類型(不管是類還是接口),虛擬機都會相應地為
              它創(chuàng)建一個java.lang.Class類的實例(Class實例放在內存中的堆區(qū)),
          而且虛擬機還必須以某種方式把這個實例的引用存儲在方法區(qū)
              
                 為了盡可能提高訪問效率,設計者必須仔細設計存儲在方法區(qū)中的類型信息的數(shù)據(jù)結構,因此,
          除了以上時論的原始類型信息,實現(xiàn)中還可能包括其他數(shù)據(jù)結構以加快訪問原始數(shù)據(jù)的速度,比如方法表。
          虛擬機對每個裝載的非抽象類,都生成一個方法表,把它作為類信息的一部分保存在方法區(qū)。方法表是一個數(shù)組,
          它的元素是所有它的實例可能被調用的實例方法的直接引用,包括那些從超類繼承過來的實例方法:(對于抽象類和接口,方法表沒有什么幫
          助,因為程序決不會生成它們的實例。)運行時可以通過方法表快速搜尋在對象中調用的實例方法。
           
          方法區(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)虛擬機在方法區(qū)查找Volcano這個名字,未果,載入volcano.class文件,并提取相應信息
             存入方法區(qū)。
            2)虛擬機開始執(zhí)行Volcano類中main()方法的字節(jié)碼的時候,盡管Lava類還沒被裝載,
            但是和大多數(shù)(也許所有)虛擬機實現(xiàn)一樣,它不會等到把程序中用到的所有類都裝載后才開
            始運行程序。恰好相反,它只在需要時才裝載相應的類。
            3)main()的第一條指令告知虛擬機為列在常量池第一項的類分配足夠的內存。所以虛擬機
            使用指向Volcano常量池的指針找到第一項,發(fā)現(xiàn)它是一個對Lava類的符號引用,然后它就檢查
            方法區(qū),看Lava類是否已經(jīng)被裝載了。
            4)當虛擬機發(fā)現(xiàn)還沒有裝載過名為"Lava"的類時,它就開始查找并裝載文件“Lava.class”,
            并把從讀入的二進制數(shù)據(jù)中提取的類型信息放在方法區(qū)中。
            5)虛擬機以一個直接指向方法區(qū)Lava類數(shù)據(jù)的指針來替換常量池第—項(就是那個
            字符串“Lava”)——以后就可以用這個指針來快速地訪問Lava類了。這個替換過程稱為常量池
            解析,即把常量池中的符號引用替換為直接引用:這是通過在方法區(qū)中搜索被引用的元素實現(xiàn)
            的,在這期間可能又需要裝載其他類。在這里,我們替換掉符號引用的“直接引用”是一個本
            地指針。
            6)虛擬機準備為一個新的Lava對象分配內存。此時,它又需要方法區(qū)中的信息。還記
            得剛剛放到Volcano類常量池第——項的指針嗎?現(xiàn)在虛擬機用它來訪問Lava類型信息(此前剛放
            到方法區(qū)中的),找出其中記錄的這樣一個信息:一個Lava對象需要分配多少堆空間。
            7)虛擬機確定一個Lava對象大小后,就在堆上分配空間,并把這個對象實例變量speed初始化為默認初始值0
            8)當把新生成的Lava對象的引用壓到棧中,main()方法的第一條指令也完成了,指令通過這個引用
            調用Java代碼(該代碼把speed變量初始化為正確初始值5).另外用這個引用調用Lava對象引用的flow()方法。


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

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

          <2010年7月>
          27282930123
          45678910
          11121314151617
          18192021222324
          25262728293031
          1234567

          導航

          統(tǒng)計

          常用鏈接

          留言簿

          隨筆分類

          隨筆檔案

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 五莲县| 扶风县| 公主岭市| 中西区| 西和县| 衡南县| 响水县| 历史| 霍邱县| 杨浦区| 西华县| 横山县| 怀柔区| 丹阳市| 大安市| 东源县| 富民县| 富源县| 西宁市| 阳东县| 江油市| 来凤县| 大埔县| 新密市| 宝清县| 延寿县| 江孜县| 华坪县| 广宁县| 武川县| 弥勒县| 兴安县| 东乡| 玉溪市| 手游| 南昌市| 南川市| 东城区| 肃宁县| 长兴县| 潞西市|