2010年6月10日

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

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

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

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

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

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

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

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

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

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

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

              public Red getRed() {
                  return red;
              }

              public Blue getBlue() {
                  return blue;
              }

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

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

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

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

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

              public String getAtt() {
                  return att;
              }

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


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

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

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

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

              public String getValue() {
                  return value;
              }

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

              public String getAtt2() {
                  return att2;
              }

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

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

          import java.io.StringWriter;

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

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

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

              }
          }

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

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

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

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

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

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

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

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

              public Object getModel() {
                  return user;
              }

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

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

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

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

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

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

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

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

              name = 超人
              price = 10000

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

          攔截器的源代碼:

          package interceptors;

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

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

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

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

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

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

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

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

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

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

          用于測試的Action類的源代碼:

          package actions;

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

              
          public String getName()
              {
                  
          return name;
              }

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

              
          public Integer getPrice()
              {
                  
          return price;
              }

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

              
          public String getLog4jappenderstdout()
              {
                  
          return log4jappenderstdout;
              }

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

              
          public String getLog4j_rootLogger()
              {
                  
          return log4j_rootLogger;
              }

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

              
          public String getConversionPattern()
              {
                  
          return conversionPattern;
              }

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

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

          Action類的配置代碼如:

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

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

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

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

          測試結(jié)果:

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

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

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

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

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

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

          structs2配置UrlRewriteFilter

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

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

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

          使用url rewrite可以很好的改善這個(gè)狀況。網(wǎng)站url rewrite應(yīng)用是非常廣泛的,良好的url設(shè)計(jì)給用戶帶來的非常好的體驗(yàn),同時(shí)也能吸引搜索引擎的注意。
          原文地址:http://www.iteye.com/topic/53834
          使用方式:
          1 配置web.xml文件
          樣例:
              <listener>
                  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
              </listener>
              <filter>
                  <filter-name>encodingFilter</filter-name>
                  <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
                  <init-param>
                      <param-name>encoding</param-name>
                      <param-value>UTF-8</param-value>
                  </init-param>
              </filter>
              <filter-mapping>
                  <filter-name>encodingFilter</filter-name>
                  <url-pattern>/*</url-pattern>
              </filter-mapping>
              <filter>
                  <filter-name>osivFilter</filter-name>
                  <filter-class>
                      org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
              </filter>
              <listener>
                  <listener-class>
                      org.springframework.web.context.request.RequestContextListener</listener-class>
              </listener>
              <filter-mapping>
                  <filter-name>osivFilter</filter-name>
                  <url-pattern>/*</url-pattern>
              </filter-mapping>
              <!--配置UrlRewriteFilter過濾器-->
              <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 閱讀(1782) | 評論 (0)編輯 收藏

          structs2 filter的執(zhí)行順序

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

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

          structs2攔截器

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

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

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

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

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

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

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


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

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

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

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

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

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

          重新認(rèn)識Java finally

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

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

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

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

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

            athrow   // throw the exception

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

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

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

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

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

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

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

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

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

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

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

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

          一、 jqGrid的加載。

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

          引入CSS:

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

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

          引入JS:

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

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

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

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

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

          2.將jqgrid加入頁面中

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

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

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

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

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

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

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

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

          2.1 prmNames選項(xiàng)

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

          prmNames : {

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

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

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

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

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

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

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

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

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

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

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

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

          npage: null,

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

          }

          2.2 jsonReader選項(xiàng)

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

          jsonReader : {

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

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

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

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

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

          cell: "cell",

          id: "id",

          userdata: "userdata",

          subgrid: {

          root:"rows",

          repeatitems: true,

          cell:"cell"

          }

          }

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

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

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

          root: "griddata",

          total: "totalpages",

          page: "currpage",

          records: "totalrecords",

          repeatitems: false

          }

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

          repeatitems為true時(shí):

          jQuery("#gridid").jqGrid({  

               ...  

               jsonReader : {  

                   root:"invdata",  

                   page: "currpage",  

                   total: "totalpages",  

                   records: "totalrecords"

               },  

               ...  

          });  

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

          {   

          "totalpages": "xxx",   

          "currpage": "yyy",  

          "totalrecords": "zzz",  

          "invdata" : [  

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

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

                            ...  

               ]  

          }  

          repeatitems為false時(shí):

          jQuery("#gridid").jqGrid({  

               ...  

               jsonReader : {  

                   root:"invdata",  

                   page: "currpage",  

                   total: "totalpages",  

                   records: "totalrecords",  

                   repeatitems: false,  

                   id: "0"

               },  

               ...  

          });  

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

          {   

          "totalpages" : "xxx",   

          "currpage" : "yyy",  

          "totalrecords" : "zzz",  

          "invdata" : [  

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

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

                            ...  

               ]  

          }  

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

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

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

          三、 注意事項(xiàng)

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

          clip_image002

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

          {

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

          beforeInitData:function(formid){

          initComparator();

          },

          beforeShowForm: function(formid){

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

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

          }

          },//edit

          {},//add

          {}//del

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

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

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

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

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

          }

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

          7. 修改Option,以URL為例

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


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




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

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

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

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

          1. <?xml version="1.0" encoding="UTF-8" ?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans   http://www.springframework.org/schema/beans/spring-beans-2.5.xsd   http://www.springframework.org/schema/context   http://www.springframework.org/schema/context/spring-context-2.5.xsd"  
          2. >  
          3.   
          4. <context:component-scan base-package=”com.eric.spring”>   
          5. </beans>   
             /*其中base-package為需要掃描的包(含所有子包)

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

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

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

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

              */   


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

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

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

          注入方式:

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

          注解:

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

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

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

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

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

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

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

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

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

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


          @Service 
          public class VentorServiceImpl implements iVentorService { 
          }

          @Repository 
          public class VentorDaoImpl implements iVentorDao { 


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

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

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

          @PostConstruct

          public void init() { 



          @PreDestroy

          public void destory() { 

          }

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

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

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

          概述

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

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

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

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

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

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

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

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

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

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

           

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

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


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

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

          Hibernate 實(shí)體對象的生命周期匯總

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

          轉(zhuǎn)載:

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

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

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

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

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

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

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

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

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

          persistence context



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

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

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

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

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

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

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

          code :

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

          /**

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

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

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

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

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

          高精度整數(shù)BigInteger

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

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

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

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

           

          引用:

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

          /**

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

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

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

           * @author Administrator

           *

           */

          public class VeryBigNumAdd {

           

              /**

               * @param args

               */

              public static void main(String[] args) {

                 // TODO Auto-generated method stub

                 /*

                 String a="1223232";

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

                 {

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

                 }

                 */

                 VeryBigNumAdd vbn=new VeryBigNumAdd();

                 String a="123453243455535634535252345234677576252241234123523453664563634";

                 String b="123453243455535634535252345234677576252241234123523453664563634";

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

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

              }

              /**

               *

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

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

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

               * 分析:

               * 1、取得兩個(gè)字符串的長度

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

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

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

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

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

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

               */

              String doAdd(String a,String b)

              {

                 String str="";

                 int lenA=a.length();

                 int lenB=b.length();

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

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

                 String strTmp="";

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

                 {

                     strTmp+="0";

                 }

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

                 if(maxLen==lenA)

                 {

                     b=strTmp+b;

                 }else

                     a=strTmp+a;

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

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

                 {        

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

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

                     int temp;

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

                     {

                        temp=tempA+tempB+JW-10;

                        JW=1;

                     }

                     else

                     {

                        temp=tempA+tempB+JW;

                        JW=0;

                     }        

                     str=String.valueOf(temp)+str;        

                 }

                 return str;

              }

           

          }

           

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

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

          code :

          package com.kangdy.test;

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

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

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



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

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

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

          引用:

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

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

          下面舉個(gè)通俗的例子:

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

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

           

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

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

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

           

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

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

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

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

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

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

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

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

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

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

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

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

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

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

           String numberStr;

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

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

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

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

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

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

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

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

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

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

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

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

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



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

          類和對象的初始化

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


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


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

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


          在Java代碼中,一個(gè)正確的初始值是通過類變量初始化語句或者靜態(tài)初始化語句給出的。
           1)一個(gè)類變量初始化語句是變量聲明后面的等號和表達(dá)式:
           2)靜態(tài)初始化語句是一個(gè)以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編譯器收集在—起,放到——個(gè)特殊
          的方法中。對于類來說,這個(gè)方法被稱作類初始化方法;對于接口來說,它被稱為接口初始化
          方法。在類和接口的Javaclass文件中,這個(gè)方法被稱為”<clinit>”。通常的Java程序方法是無法
          調(diào)用這個(gè)<clinit>方法的。這種方法只能被Java虛擬機(jī)調(diào)用

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

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

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

           

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

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

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

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


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


          對象的生命周期

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

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

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

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

           

           
           

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

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

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


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

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


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

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

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

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


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

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

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

          導(dǎo)航

          統(tǒng)計(jì)

          常用鏈接

          留言簿

          隨筆分類

          隨筆檔案

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 鹰潭市| 贵定县| 无锡市| 青田县| 金华市| 贞丰县| 行唐县| 镇康县| 孙吴县| 峨眉山市| 土默特左旗| 大名县| 洛阳市| 三亚市| 观塘区| 吉木乃县| 城市| 太原市| 清河县| 迁西县| 卫辉市| 阳江市| 湘乡市| 依安县| 乌拉特后旗| 锡林郭勒盟| 遵化市| 曲麻莱县| 宜川县| 祁东县| 页游| 旌德县| 勐海县| 西盟| 靖安县| 通江县| 皮山县| 集贤县| 定兴县| 乐平市| 芜湖县|