亚洲AV永久无码精品一福利,亚洲av无码不卡私人影院,亚洲精品乱码久久久久久久久久久久http://m.tkk7.com/fool/category/12815.html堅持就是勝利!zh-cnThu, 14 Jun 2018 07:10:14 GMTThu, 14 Jun 2018 07:10:14 GMT60 Fabric 1.1源代碼分析(3) 系統鏈碼執行過程示例(弟弟篇)http://m.tkk7.com/fool/archive/2018/06/13/433279.html傻 瓜傻 瓜Wed, 13 Jun 2018 06:37:00 GMThttp://m.tkk7.com/fool/archive/2018/06/13/433279.htmlhttp://m.tkk7.com/fool/comments/433279.htmlhttp://m.tkk7.com/fool/archive/2018/06/13/433279.html#Feedback0http://m.tkk7.com/fool/comments/commentRss/433279.htmlhttp://m.tkk7.com/fool/services/trackbacks/433279.html
# Fabric 1.1源代碼分析(3) 系統鏈碼執行過程
## 1、系統鏈碼執行過程
* 以peer channel join -b gensis.block命令為例。該命令結果是peer節點加入通道.
這個命令會單獨啟一個進程.在該進程中會構建一個名稱為cscc的鏈碼消息傳到peer節點.
通過grpc調用最終會進到endorser.go中的ProcessProposal函數進行處理。
參考Fabric 1.1源代碼分析(2)http://m.tkk7.com/fool/archive/2018/06/12/433277.html
系統鏈碼初始化過程,可以找到../shim/handler.go中
的handleTransaction()函數.最終會調用res := handler.cc.Invoke(stub).這里的
cc就是importsysccs.go文件中systemChaincodes數組中的cscc系統鏈碼的.    
Chaincode,其實例是&cscc.PeerConfiger{},實現在cscc/configure.go文件中。每個系統
鏈碼都實現了這個Chaincode接口()
```go
type Chaincode interface {
    // Init is called during Instantiate transaction after the chaincode container
    // has been established for the first time, allowing the chaincode to
    // initialize its internal data
    Init(stub ChaincodeStubInterface) pb.Response

    // Invoke is called to update or query the ledger in a proposal transaction.
    // Updated state variables are not committed to the ledger until the
    // transaction is committed.
    Invoke(stub ChaincodeStubInterface) pb.Response
}
```

* 至此就可以清晰地看到每一個系統鏈碼都會啟動一對協程,通過chan通信。系統鏈碼消息由
shim/handler.go中的函數處理.并且這里最終調用各自的具體實現的Ivoke方法進行業務處理

## 2、peer channel join命令處理流程圖
* peer channel join命令會調用configure.go中的Excute方法。對應cscc系統鏈碼的處理,
原因如下,以下流程圖大致可以了解cscc都做了些什么
![](cscc.png)

## 3、小結

* 上面的流程圖也不是非常地強細,忽略掉了一些方法。但是有了整個流程的理解,就能理解其
它系統鏈碼的調用過程,需要時直接細讀其實現就好了。從上流程圖中可以看到文件末尾添加區
區塊,leveldb中記錄了區塊號,索引位置信息等等。另外因為系統鏈碼跟一般鏈碼雖然經過
的文件基本一樣,但最終處理方式還是不一樣,一個是協程,一個是grpc.可能參考Fabric 1.1
源代碼分析之 Chaincode(鏈碼)初始化 http://m.tkk7.com/fool/archive/2018/06/12/433275.html


傻 瓜 2018-06-13 14:37 發表評論
]]>
Fabric 1.1源代碼分析之 系統鏈碼初始化過程(哥哥篇)http://m.tkk7.com/fool/archive/2018/06/12/433277.html傻 瓜傻 瓜Tue, 12 Jun 2018 07:00:00 GMThttp://m.tkk7.com/fool/archive/2018/06/12/433277.htmlhttp://m.tkk7.com/fool/comments/433277.htmlhttp://m.tkk7.com/fool/archive/2018/06/12/433277.html#Feedback0http://m.tkk7.com/fool/comments/commentRss/433277.htmlhttp://m.tkk7.com/fool/services/trackbacks/433277.html
# Fabric 1.1源代碼分析之 Fabric 1.1源代碼分析 系統鏈碼初始化過程

* 鏈碼這一塊的代碼非常的繞。基本上就是一個大循環。限于水平或者其它原因,差露可能難免,各位看官包涵則個...

## 1、系統鏈碼

* 系統鏈碼跟智能合約鏈碼涉及到的文件差不多,流程也差不多。只是智能合約是grpc,系統鏈碼是chan實現調用.
LSCC Lifecycle system chaincode,處理生命周期請求。我理解的生命周期請求應該指的是一個chaincode的安裝,實例化,升級,
卸載等對其生命周期起關鍵作用的一系列操作請求。
CSCC Configuration system chaincode,處理在peer程序端的channel配置。
QSCC Query system chaincode,提供賬本查詢接口,如獲取塊和交易信息。
ESCC Endorsement system chaincode,通過對交易申請的應答信息進行簽名,來提供背書功能。
VSCC Validation system chaincode,處理交易校驗,包括檢查背書策略和版本在并發時的控制。

## 2、系統鏈碼注冊
* 在/core/chaincode/shim/interfaces_stable.go中實現了下面的接口
```go
type Chaincode interface {
    // Init is called during Instantiate transaction after the chaincode container
    // has been established for the first time, allowing the chaincode to
    // initialize its internal data
    Init(stub ChaincodeStubInterface) pb.Response

    // Invoke is called to update or query the ledger in a proposal transaction.
    // Updated state variables are not committed to the ledger until the
    // transaction is committed.
    Invoke(stub ChaincodeStubInterface) pb.Response
}
```

* 在core/scc/sysccapi.go中定義了SystemChaincode結構體,其中定義了 Chaincode接口變量
```go
type SystemChaincode struct {
    //Unique name of the system chaincode
    Name string

    //Path to the system chaincode; currently not used
    Path string

    //InitArgs initialization arguments to startup the system chaincode
    InitArgs [][]byte

    // Chaincode is the actual chaincode object
    Chaincode shim.Chaincode

    // InvokableExternal keeps track of whether
    // this system chaincode can be invoked
    // through a proposal sent to this peer
    InvokableExternal bool

    // InvokableCC2CC keeps track of whether
    // this system chaincode can be invoked
    // by way of a chaincode-to-chaincode
    // invocation
    InvokableCC2CC bool

    // Enabled a convenient switch to enable/disable system chaincode without
    // having to remove entry from importsysccs.go
    Enabled bool
}
```

* 在 core/scc/importsysccs.go文件中對系統鏈碼進行了初始化,并且每個Chainoce指定了具體實現
```go
//see systemchaincode_test.go for an example using "sample_syscc"
var systemChaincodes = []*SystemChaincode{
    {
        Enabled: true,
        Name: "cscc",
        Path: "github.com/hyperledger/fabric/core/scc/cscc",
        InitArgs: [][]byte{[]byte("")},
        Chaincode: &cscc.PeerConfiger{},
        InvokableExternal: true, // cscc is invoked to join a channel
    },
    {
        Enabled: true,
        Name: "lscc",
        Path: "github.com/hyperledger/fabric/core/scc/lscc",
        InitArgs: [][]byte{[]byte("")},
        Chaincode: lscc.NewLifeCycleSysCC(),
        InvokableExternal: true, // lscc is invoked to deploy new chaincodes
        InvokableCC2CC: true, // lscc can be invoked by other chaincodes
    },
    {
        Enabled: true,
        Name: "escc",
        Path: "github.com/hyperledger/fabric/core/scc/escc",
        InitArgs: [][]byte{[]byte("")},
        Chaincode: &escc.EndorserOneValidSignature{},
    },
    {
        Enabled: true,
        Name: "vscc",
        Path: "github.com/hyperledger/fabric/core/scc/vscc",
        InitArgs: [][]byte{[]byte("")},
        Chaincode: &vscc.ValidatorOneValidSignature{},
    },
    {
        Enabled: true,
        Name: "qscc",
        Path: "github.com/hyperledger/fabric/core/chaincode/qscc",
        InitArgs: [][]byte{[]byte("")},
        Chaincode: &qscc.LedgerQuerier{},
        InvokableExternal: true, // qscc can be invoked to retrieve blocks
        InvokableCC2CC: true, // qscc can be invoked to retrieve blocks also by a cc
    },
}
```
* 注冊流程圖
![](systemcoderegist.png)


## 3、系統鏈碼初始化
* 系統注冊完成后會對鏈碼初始化.跟一般chaincode稍有不同的是chaincode在合約里通過grpc與peer節點交互。
而系統鏈碼則是在協程里通過chan 實現交互.下面代碼創建兩個 peerRcvCCSend := make(chan *pb.ChaincodeMessage)
    ccRcvPeerSend := make(chan *pb.ChaincodeMessage) ,是客戶端和服務端共同的參數
```go

func (ipc *inprocContainer) launchInProc(ctxt context.Context, id string, args []string, env []string, ccSupport ccintf.CCSupport) error {
    peerRcvCCSend := make(chan *pb.ChaincodeMessage)
    ccRcvPeerSend := make(chan *pb.ChaincodeMessage)
    var err error
    ccchan := make(chan struct{}, 1)
    ccsupportchan := make(chan struct{}, 1)
    //啟動客戶端處理
    go func() {
        defer close(ccchan)
        inprocLogger.Debugf("chaincode started for %s", id)
        if args == nil {
            args = ipc.args
        }
        if env == nil {
            env = ipc.env
        }
        err := _shimStartInProc(env, args, ipc.chaincode, ccRcvPeerSend, peerRcvCCSend)
        if err != nil {
            err = fmt.Errorf("chaincode-support ended with err: %s", err)
            _inprocLoggerErrorf("%s", err)
        }
        inprocLogger.Debugf("chaincode ended with for %s with err: %s", id, err)
    }()
//啟動服務端處理
    go func() {
        defer close(ccsupportchan)
        inprocStream := newInProcStream(peerRcvCCSend, ccRcvPeerSend)
        inprocLogger.Debugf("chaincode-support started for %s", id)
        err := ccSupport.HandleChaincodeStream(ctxt, inprocStream)
        if err != nil {
            err = fmt.Errorf("chaincode ended with err: %s", err)
            _inprocLoggerErrorf("%s", err)
        }
        inprocLogger.Debugf("chaincode-support ended with for %s with err: %s", id, err)
    }()

    select {
    case <-ccchan:
        close(peerRcvCCSend)
        inprocLogger.Debugf("chaincode %s quit", id)
    case <-ccsupportchan:
        close(ccRcvPeerSend)
        inprocLogger.Debugf("chaincode support %s quit", id)
    case <-ipc.stopChan:
        close(ccRcvPeerSend)
        close(peerRcvCCSend)
        inprocLogger.Debugf("chaincode %s stopped", id)
    }
    return err
}

```


* 初始化流程圖
![](systemcodeinit.png)


## 4、系統鏈碼的執行
...


傻 瓜 2018-06-12 15:00 發表評論
]]>
Fabric 1.1源代碼分析之 Chaincode(鏈碼)初始化http://m.tkk7.com/fool/archive/2018/06/12/433275.html傻 瓜傻 瓜Tue, 12 Jun 2018 06:51:00 GMThttp://m.tkk7.com/fool/archive/2018/06/12/433275.htmlhttp://m.tkk7.com/fool/comments/433275.htmlhttp://m.tkk7.com/fool/archive/2018/06/12/433275.html#Feedback0http://m.tkk7.com/fool/comments/commentRss/433275.htmlhttp://m.tkk7.com/fool/services/trackbacks/433275.html閱讀全文

傻 瓜 2018-06-12 14:51 發表評論
]]>
開源區塊鏈Hyperleger Fabric之通過Composer開發框架快速搭建開發環境http://m.tkk7.com/fool/archive/2018/03/12/433093.html傻 瓜傻 瓜Mon, 12 Mar 2018 08:44:00 GMThttp://m.tkk7.com/fool/archive/2018/03/12/433093.htmlhttp://m.tkk7.com/fool/comments/433093.htmlhttp://m.tkk7.com/fool/archive/2018/03/12/433093.html#Feedback0http://m.tkk7.com/fool/comments/commentRss/433093.htmlhttp://m.tkk7.com/fool/services/trackbacks/433093.html
準備工作:(自行百度)

開發環境必備軟件:

 composer-cli

 generator-hyperledger-composr

composer-rest-server
Yeoman

安裝playground

 

Installing and running Hyperledger Composer Playground locally
docker ps -aq | xargs docker rm -f
docker images -aq | xargs docker rmi -f
curl -sSL https://hyperledger.github.io/composer/install-hlfv1.sh | bash   
執行install-hlfv1.sh 安裝運行fabric1.06版.并運行 playground服務 打開流覽器http://xxxx:8080顯示如下



1,playgroundWeb Browser區域提供了在頁面定義模型、測試模型的能力。并不保存。但可以導出bna文件

2,connection區域提供了在開發環境布署合約,會生成一個智能合約的docker運行環境.
3,可以在上圖中上部分的My Business Networks 工作區點擊虛業部分Deploy a new business network

4,在接下來頁面中選中一個示例。如 marble neetworkd.  選擇 ID and Secret 填入admin 和 adminpw

5,點擊Deploy按鈕后會發布一個合約.并跳到測試頁如下圖:



6,在上圖中 Test Tab頁可以進行測試 ,在Define Tab頁可以導出bna文件.
7,在第一幅圖中點擊下載按鈕,會下載一個 .card文件,描述了連接fabric peer節點等相關連接信息.記得要導 
PeerAdmin@hlfv1的card和你自己測試用的card,及bna文件
8,分別執行  composer card import -f PeerAdmin.card  ,composer card import -f admin.card  .composer card list 可以查看你導入的card的name信息.

       9,composer-rest-server -c admin@empty-business-network -n always -w true  啟動rest服務默認端口3000.

      10,好了,可以體驗一下fabric是個什么玩意了。:) 88!




傻 瓜 2018-03-12 16:44 發表評論
]]>
開源區塊鏈Hyperleger Fabric的SDK-JAVA新手上路指引http://m.tkk7.com/fool/archive/2018/02/01/433032.html傻 瓜傻 瓜Thu, 01 Feb 2018 01:03:00 GMThttp://m.tkk7.com/fool/archive/2018/02/01/433032.htmlhttp://m.tkk7.com/fool/comments/433032.htmlhttp://m.tkk7.com/fool/archive/2018/02/01/433032.html#Feedback0http://m.tkk7.com/fool/comments/commentRss/433032.htmlhttp://m.tkk7.com/fool/services/trackbacks/433032.html區塊鏈工程師。不久抱得美人歸。:)

閱讀本代碼前,先看看fabric的多機布署,參考下面的貼子1:
http://blog.csdn.net/songbin830/article/details/78778806 完成多機布署.

參考貼子2: http://www.cnblogs.com/aberic/p/8206551.html ,把代碼下到本地工程里。新手上路總會遇到
各種細節問題.重點來了:

使用git命令從github.com上拉下SDK-JAVA源碼.
1,源碼文件中有EclipseSetup.md的文件,介紹如何把源碼項目導入eclipse.
2,導入eclipse后發現缺少  org.hyperledger.fabric.protos.*文件。github上的源碼里也沒有。解決辦法:從
其它網站的 SDK-JAVA打包文件中找到源碼包,把org.hyperledger.fabric.protos包中的源碼copy到eclipse。
3,在orderer節點把  crypto-config文件夾中的內容copy到本機.其中包含了用命令工具生成的證書,身份信息
等內容
4,貼子2中代碼如何用,其實跟源碼中的測試用例中的代碼差不多.初始化示例如下:因為貼子2是個demo類代碼,
我作了些改動。有些代碼沒放ChaincodeManager()實例化。看一下這個類的構造方法,構造對應的需要的實例類
也不難

public static ChaincodeManager init() throws Exception{
FabricConfig fabricConfig = new FabricConfig("E:/fabricConfig");  //fabricConfig文件夾中包含
                //crypto-config文件夾
Peers peers = new Peers();   //初始化peer節點
peers.setOrgDomainName("org1.ygsoft.com");
peers.setOrgMSPID("Org1MSP");
peers.setOrgName("Org1MSP");
//peers.addPeer("peer0.org1.ygsoft.com", "peer0.org1.ygsoft.com", "grpcs://10.121.60.2:7051", "grpcs://10.121.60.2:7053", null);
peers.addPeer("peer1.org1.ygsoft.com", "peer1.org1.ygsoft.com", "grpcs://10.121.60.3:7051", "grpcs://10.121.60.3:7053", null);
fabricConfig.setPeers(peers);
//初始化orderer節點
Orderers orders = new Orderers();
orders.setOrdererDomainName("ygsoft.com");
orders.addOrderer("orderer.ygsoft.com", "grpcs://10.121.60.1:7050");
fabricConfig.setOrderers(orders);
fabricConfig.setRegisterEvent(true);
ChaincodeManager chainManager = new ChaincodeManager(fabricConfig);
return chainManager;
}

5,其它參數,比如chaincode相關信息可以在peer節點  peer chaincode list --installed 命令可以查看
可以調用這個ChaincodeManager 的query和invoke方法了.

6,補充內容:需要shim-client.jar包,這個需要拉下fabric的源碼,在文件夾
\src\github.com\hyperledger\fabric\core\chaincode\shim\java 用gradle編譯一個jar包出來

7,如果grpc用了ssl的需要 grpcs://10.121.60.3:7051,grpcs開頭

因為網上有了fabric多機布署教程,和不完善的示例代碼,這里主要介紹一下其中容易遇到的問題,解決起
來也頗為頭痛和費時。
本貼原地址:http://m.tkk7.com/fool .下一篇區塊鏈貼子預告:Fabric的SDK-JAVA動態安裝
Channel













傻 瓜 2018-02-01 09:03 發表評論
]]>
springCloud、boot集成elkhttp://m.tkk7.com/fool/archive/2017/10/08/432851.html傻 瓜傻 瓜Sun, 08 Oct 2017 11:15:00 GMThttp://m.tkk7.com/fool/archive/2017/10/08/432851.htmlhttp://m.tkk7.com/fool/comments/432851.htmlhttp://m.tkk7.com/fool/archive/2017/10/08/432851.html#Feedback0http://m.tkk7.com/fool/comments/commentRss/432851.htmlhttp://m.tkk7.com/fool/services/trackbacks/432851.html1,啟動elashticsearch
2,logstash/config目錄下新建log.conf文件,其內容:
input {
  # For detail config for log4j as input, 
  # See: https://www.elastic.co/guide/en/logstash/current/plugins-inputs-log4j.html
      tcp { 
    mode => "server"
    host => "127.0.0.1"
        port => 4567
        codec => json_lines 
    }  
}
filter {
  #Only matched data are send to output.
}
output {
  # For detail config for elasticsearch as output, 
  # See: https://www.elastic.co/guide/en/logstash/current/plugins-outputs-elasticsearch.html
  elasticsearch {  
    hosts  => ["127.0.0.1:9200"]   #ElasticSearch host, can be array.
    index  => "applog"         #The index to write data to.
  }
}
3,kibana配置.修改kibana/config文件夾中的kibana.yml的配置文件
server.port: 5601
server.host: "localhost"
elasticsearch.url: "http://localhost:9200"
kibana.index: ".kibana"

4,springCload、springBoot中的logback-spring.xml文件配置將日志寫入logstash

    <appender name="logstash2" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
        <remoteHost>127.0.0.1</remoteHost>
        <port>4567</port>
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <!-- Minimum logging level to be presented in the console logs-->
            <level>INFO</level> <!--寫入logstash的日志級別-->
        </filter>
        <encoder charset="UTF-8" class="net.logstash.logback.encoder.LogstashEncoder"/>
    </appender>
    ​
    <root level="INFO">
        <appender-ref ref="console"/>
        <appender-ref ref="logstash"/>
        <appender-ref ref="logstash2"/>
        <!--<appender-ref ref="flatfile"/>-->
    </root>

后記:日志是直接寫入到elashticsearch,可以集成kafka或redis作為緩沖。


傻 瓜 2017-10-08 19:15 發表評論
]]>
springboot、mybatis、mycat分庫實踐http://m.tkk7.com/fool/archive/2017/10/01/432841.html傻 瓜傻 瓜Sun, 01 Oct 2017 09:40:00 GMThttp://m.tkk7.com/fool/archive/2017/10/01/432841.htmlhttp://m.tkk7.com/fool/comments/432841.htmlhttp://m.tkk7.com/fool/archive/2017/10/01/432841.html#Feedback0http://m.tkk7.com/fool/comments/commentRss/432841.htmlhttp://m.tkk7.com/fool/services/trackbacks/432841.html1.pom文件中引入下面引入mybatis逆向工程插件
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.4</version>
<configuration>
<verbose>true</verbose>
<overwrite>true</overwrite>
</configuration>
</plugin>
</plugins>
</build>
   2, src/main/resource 目錄下引入mybatis逆向工程配置文件,這樣就可以自動生成mybatis需要的xml及dao interface
<?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE generatorConfiguration
   PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
   "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
 <generatorConfiguration>
     <!--數據庫驅動-->
     <classPathEntry    location="E:\\worksource\\springboot\\src\\main\\webapp\\WEB-INF\\lib\\mysql-connector-java-5.1.39.jar"/>
     <context id="DB2Tables"    targetRuntime="MyBatis3">
         <commentGenerator>
             <property name="suppressDate" value="true"/>
             <property name="suppressAllComments" value="true"/>
         </commentGenerator>
         <!--數據庫鏈接地址賬號密碼-->
         <jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://localhost:3306/jeeshop" userId="root" password="">
         </jdbcConnection>
         <javaTypeResolver>
             <property name="forceBigDecimals" value="false"/>
         </javaTypeResolver>
         <!--生成Model類存放位置-->
         <javaModelGenerator targetPackage="com.junjun.myblog.domain" targetProject="src/main/java">
             <property name="enableSubPackages" value="true"/>
             <property name="trimStrings" value="true"/>
         </javaModelGenerator>
         <!--生成映射文件存放位置-->
         <sqlMapGenerator targetPackage="src/main/resources/mapper" targetProject=".">
             <property name="enableSubPackages" value="true"/>
         </sqlMapGenerator>
         <!--生成Dao類存放位置-->
         <javaClientGenerator type="XMLMAPPER" targetPackage="com.junjun.myblog.dao" targetProject="src/main/java">
             <property name="enableSubPackages" value="true"/>
         </javaClientGenerator>
         <!--生成對應表及類名 mapperName="AreaDao"  工程右鍵 Debug As -> maven build... -> mybatis-generator:generate
         <table tableName="t_area"   domainObjectName="Area" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table>
    -->
</context>
 </generatorConfiguration>
3,application 中加上注解  @MapperScan("com.junjun") 
4,數據源連接mycat
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:8066/MYSQL?useUnicode=true&characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=123456
二,mycat配置
1,conf/server.xml中配置用戶 和schema
<user name="root">
<property name="password">123456</property>
<property name="schemas">MYSQL</property>
</user>
2,schema.xml配置數據庫和分片表分片規則
<schema name="MYSQL" checkSQLschema="false" sqlMaxLimit="100">
<table name="t_blogger" primaryKey="id" dataNode="dn1" >     </table> 
<!--按需配置分片規則-->
        <table name="t_area" primaryKey="id" dataNode="dn1,dn2,dn3" rule="mod-long1">     </table> 
<table name="t_blog" primaryKey="id" dataNode="dn1" >     </table> 
<table name="t_blogtype" primaryKey="id" dataNode="dn1" >     </table> 
</schema>
<!-- <dataNode name="dn1$0-743" dataHost="localhost1" database="db$0-743"
/> -->
<dataNode name="dn1" dataHost="localhost1" database="jeeshop" />
<dataNode name="dn2" dataHost="localhost2" database="jysystem" />
<dataNode name="dn3" dataHost="localhost3" database="dn3" />
<!--<dataNode name="dn4" dataHost="sequoiadb1" database="SAMPLE" />
<dataNode name="jdbc_dn1" dataHost="jdbchost" database="db1" />
<dataNode name="jdbc_dn2" dataHost="jdbchost" database="db2" />
<dataNode name="jdbc_dn3" dataHost="jdbchost" database="db3" /> -->
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="0"
  writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<!-- can have multi write hosts -->
<writeHost host="hostM1" url="localhost:3306" user="root"
   password="">
<!-- can have multi read hosts 
<readHost host="hostS2" url="192.168.1.200:3306" user="root" password="" /> -->
</writeHost>
<!-- <writeHost host="hostM2" url="localhost:3316" user="root" password="123456"/> -->
</dataHost>
<dataHost name="localhost2" maxCon="1000" minCon="10" balance="0"
  writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<!-- can have multi write hosts -->
<writeHost host="hostM2" url="127.0.0.1:3306" user="root"
   password="">
<!-- can have multi read hosts 
<readHost host="hostS2" url="192.168.1.200:3306" user="root" password="" /> -->
</writeHost>
<!-- <writeHost host="hostM2" url="localhost:3316" user="root" password="123456"/> -->
</dataHost>
<dataHost name="localhost3" maxCon="1000" minCon="10" balance="0"
  writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<!-- can have multi write hosts -->
<writeHost host="hostM2" url="127.0.0.1:3306" user="root"
   password="">
<!-- can have multi read hosts 
<readHost host="hostS2" url="192.168.1.200:3306" user="root" password="" /> -->
</writeHost>
<!-- <writeHost host="hostM2" url="localhost:3316" user="root" password="123456"/> -->
</dataHost>
3,rule.xml配置分片規則
    添加如下規則 按表的name字段進行分片存儲
<tableRule name="mod-long1">
<rule>
<columns>name</columns>
<algorithm>mod-long</algorithm>
</rule>
</tableRule>
備注:內容太多,記一下重點. 分庫后連接查詢不在同一個庫是查不到數據的,真有這需要那就真需要考慮
設計是否合理了.


傻 瓜 2017-10-01 17:40 發表評論
]]>
springboot中action綁定ServletRequest的attirbute的值傳參http://m.tkk7.com/fool/archive/2017/09/29/432838.html傻 瓜傻 瓜Fri, 29 Sep 2017 03:58:00 GMThttp://m.tkk7.com/fool/archive/2017/09/29/432838.htmlhttp://m.tkk7.com/fool/comments/432838.htmlhttp://m.tkk7.com/fool/archive/2017/09/29/432838.html#Feedback0http://m.tkk7.com/fool/comments/commentRss/432838.htmlhttp://m.tkk7.com/fool/services/trackbacks/432838.html根據token查找到對應的用戶信息。比如分布式框架中獲取用戶信息等.springboot中可以自
定義參數解析器來綁定參數,通過它可以拿到ServletRequest中的attirbute中的值進行參數
綁定。

自定義一個annotation,通過這個注解中的 name查找attribute中的key對應的值 

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface AttributeResolve {
String name() default "user";
}

自定義一個解析器類

import javax.servlet.http.HttpServletRequest;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
public class AttributeArgumentResolver implements HandlerMethodArgumentResolver{
@Override
public Object resolveArgument(MethodParameter arg0, ModelAndViewContainer arg1, NativeWebRequest arg2,
WebDataBinderFactory arg3) throws Exception {
// TODO Auto-generated method stub
Object resultObj=null;
 AttributeResolve mp =  arg0.getParameterAnnotation(AttributeResolve.class);
 if(mp!=null) {
String attributeName= mp.name();
HttpServletRequest request = arg2.getNativeRequest(HttpServletRequest.class);
resultObj = request.getAttribute(attributeName);
 }
return resultObj;
}
@Override
public boolean supportsParameter(MethodParameter arg0) {
// TODO Auto-generated method stub
return  arg0.hasParameterAnnotation(AttributeResolve.class);
}

springboot中注冊自定義的參數解析器
@Configuration
public class MyWebMvcConfig extends WebMvcConfigurerAdapter{
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
        argumentResolvers.add(new AttributeArgumentResolver());
    }
}


使用方法.
需要在action調用前向HttpServletRequest中的attribute中注入值 ,可以自定義一個filter,在filter中進行處理
如在filter中處理app傳過來的token驗證后取得對應的用戶信息等.下面例子簡單放入一個對象
@WebFilter(filterName = "axssFilter", urlPatterns = "/*",
initParams = {
@WebInitParam(name = "ignores", value = "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*")// 忽略資源
}
)
public class XssFilter implements javax.servlet.Filter{
private Set<String> prefixIignores = new HashSet<String>();
@Override
public void destroy() {
// TODO Auto-generated method stub
}
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
// TODO Auto-generated method stub
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
            Blogger user = new Blogger();
          user.setUsername("asfdasdf");
         request.setAttribute("user", user);
               chain.doFilter(request, response);  
}
}

action獲取attribute中放入的對象
        @RequestMapping("/index")
public String index(@AttributeResolve(name="user") Bloggerbh, HttpServletRequest request,Model model) 

嗯,還算優雅




傻 瓜 2017-09-29 11:58 發表評論
]]>
springboot文件上傳等雜項http://m.tkk7.com/fool/archive/2017/09/18/432826.html傻 瓜傻 瓜Mon, 18 Sep 2017 03:01:00 GMThttp://m.tkk7.com/fool/archive/2017/09/18/432826.htmlhttp://m.tkk7.com/fool/comments/432826.htmlhttp://m.tkk7.com/fool/archive/2017/09/18/432826.html#Feedback0http://m.tkk7.com/fool/comments/commentRss/432826.htmlhttp://m.tkk7.com/fool/services/trackbacks/432826.htmlspringmvc中配置文件上傳寫法在boot并不支持
@Bean
public MultipartResolver multipartResolver() {
CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
multipartResolver.setMaxUploadSize(100000000);
return multipartResolver;
}
得這樣寫
  @Bean
   public MultipartConfigElement multipartConfigElement() {
       MultipartConfigFactory factory = new MultipartConfigFactory();
       factory.setMaxFileSize("128KB");
       factory.setMaxRequestSize("128KB");
       return factory.createMultipartConfig();
   }

2,攔截器
繼承HandlerInterceptorAdapter確實可以攔截,但是afterCompletion在preHandle方法返回false后并
不執行,那么只能在preHandle中處理了,比如轉向,ajax請求返回內容

3,關于快速跳轉
有時候只是做一個簡單的跳轉,可以集中寫在這里
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/index").setViewName("/index");
       registry.addViewController("/converter").setViewName("/converter");
}

完整示例:
package com.example.demo.config;
import java.util.List;
import javax.servlet.MultipartConfigElement;
import org.springframework.boot.web.servlet.MultipartConfigFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;
//其中默認配置的 /** 映射到 /static (或/public、/resources、/META-INF/resources) 
//其中默認配置的 /webjars/** 映射到 classpath:/META-INF/resources/webjars/ 
/*
spring.mvc.static-path-pattern=
@Configuration
public class MyWebAppConfigurer extends WebMvcConfigurerAdapter {
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/myres/**").addResourceLocations("classpath:/myres/");
//使用外部目錄 registry.addResourceHandler("/api_files/**").addResourceLocations("file:D:/data/api_files");
super.addResourceHandlers(registry);
}
@Bean
public InternalResourceViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
viewResolver.setViewClass(JstlView.class);
return viewResolver;
}
//攔截器
@Override
public void addInterceptors(InterceptorRegistry registry) {// 2
InterceptorRegistration i=registry.addInterceptor(demoInterceptor());
i.addPathPatterns("/jsp/*");//只攔截 /jsp/* 的action
}
@Bean
// 1  配置攔截器
public DemoInterceptor demoInterceptor() {
return new DemoInterceptor();
}
//快速轉向
@Override
public void addViewControllers(ViewControllerRegistry registry) {
// registry.addViewController("/index").setViewName("/index");
registry.addViewController("/toUpload").setViewName("/upload");
registry.addViewController("/converter").setViewName("/converter");
registry.addViewController("/sse").setViewName("/sse");
registry.addViewController("/async").setViewName("/async");
}
   @Bean
   public MultipartConfigElement multipartConfigElement() {
       MultipartConfigFactory factory = new MultipartConfigFactory();
       factory.setMaxFileSize("128KB");
       factory.setMaxRequestSize("128KB");
       return factory.createMultipartConfig();
   }
}
攔截器類
public class DemoInterceptor extends HandlerInterceptorAdapter {// 1
@Override
public boolean preHandle(HttpServletRequest request, // 2
HttpServletResponse response, Object handler) throws Exception {
long startTime = System.currentTimeMillis();
System.out.println("本次始請求處理時間為:" + startTime + "ms");
request.setAttribute("startTime", startTime);
if (request.getHeader("x-requested-with") != null
&& request.getHeader("x-requested-with").equalsIgnoreCase("XMLHttpRequest")) {
response.setHeader("sessionstatus", "timeout"); // 響應頭設置session狀態
} else {
response.sendRedirect("/");
}
return false;
}
@Override
public void postHandle(HttpServletRequest request, // 3
HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
long startTime = (Long) request.getAttribute("startTime");
request.removeAttribute("startTime");
long endTime = System.currentTimeMillis();
System.out.println("本次請求處理時間??:" + new Long(endTime - startTime) + "ms");
request.setAttribute("handlingTime", endTime - startTime);
}
}
文件上傳頁面upload.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>upload page</title>
</head>
<body>
<div class="upload">
<form action="upload" enctype="multipart/form-data" method="post">
<input type="file" name="file"/><br/>
<input type="submit" value="上傳">
</form>
</div>
</body>
</html>

文件上傳控制器類

@Controller
public class UploadController {
@RequestMapping(value = "/upload",method = RequestMethod.POST)
//MultipartFile[] ,涓婁紶澶氫釜鏂囦歡
public @ResponseBody String upload(@RequestParam("file") MultipartFile file) {//1
try {
FileUtils.writeByteArrayToFile(new File("e:/upload/"+file.getOriginalFilename()),
file.getBytes()); //2
return "ok";
} catch (IOException e) {
e.printStackTrace();
return "wrong";
}
}
}


傻 瓜 2017-09-18 11:01 發表評論
]]>
業務規則與自定義規則處理庫http://m.tkk7.com/fool/archive/2017/08/20/432763.html傻 瓜傻 瓜Sun, 20 Aug 2017 06:52:00 GMThttp://m.tkk7.com/fool/archive/2017/08/20/432763.htmlhttp://m.tkk7.com/fool/comments/432763.htmlhttp://m.tkk7.com/fool/archive/2017/08/20/432763.html#Feedback0http://m.tkk7.com/fool/comments/commentRss/432763.htmlhttp://m.tkk7.com/fool/services/trackbacks/432763.html更改或者新增新的業務規則.尤其是在某些場合如促銷,積分商城等場景。正因為規則如此重要,建議使用單獨的文檔
維護,規則名稱編號可以與用例名稱編對一一對應。
業務規則分類:
一,內稟規則:業務實體本身的規則。如訂單中銷售記錄不能為空,數量不能為等。
二,全局規則:一般與所有用例相關而不是某個特定用例相關。例如系統安全方面的sql注入,ddos攻擊等。
三,交互規則:用于用例當中。它們規定了滿足什么條件后業務將如何反應。有些規則需要開發成系統用例。比如人事
管理系統中請假業務只有工作日才計入請假天數,那么這個工作日就需要電腦來維護了,會作為一個系統用例存在,并
且作為請假用例的前置條件。 交互規則又是最容易引起.
交互規則如此靈活多變,需要良好的設計才能保證系統的擴展性和可維護性。如何做:
思路一:
    在 j
avax.swing.border包提供了Border接口和幾個不同的Boder的實現。在swing中每個組件提供了paint方法,每
個組件知道怎么畫自己展示自己的外觀。那么我們可以提供業務規則處理接口,每個具體業務規則自己知道怎么處理業務。
可以用簡單工廠來決定調用哪一個具體業務規則。這個是策略模式的使用,缺點是新增具體業務時工廠類會修改。也可以
用觀察者模式來實現,所有的具體業務類都來觀察這個業務規則,自己判斷是不是自己可以處理的,不是就不理會。
基于策略模式的規則實現類圖:

思路二:
     規則引擎比如drools處理一些問題 。
規則引擎適合于做業務規則頻繁變化的場景.把業務規則抽出來通過規則引擎來
處理。類似工作流系統的概念。

自定義規則處理庫:
     一些動態的語言很適合來做這樣的事情。java支持script.Mvel是一個表達式語言,drools也支持mvel來處理業務規則.
這里自定義規則引擎使用Mvel表達式語言.
      規則文件示例:
     
<rules>
       <!--rule-set 是一個規則集,執行規則 rule1時會迭代規則集里面所有的規則(mvel-rule)-->
<rule-set name="rule1">
<!-- id是規則的標識,也是默認的排序處理順序。exclusive 是排它。如果為true,則當前規則執行后,不再執行后面的規則-->
<mvel-rule id="step1"  exclusive="false">
<block><![CDATA[
if(salary<=3500) {result=0;}
]]></block>
</mvel-rule>
<mvel-rule id="step2" exclusive="false">
<block><![CDATA[if(salary>3500) {result=1};]]></block>
</mvel-rule>
</rule-set>
<rule-set name="rule2">
<mvel-rule id="step1"  exclusive="false">
<block><![CDATA[ 
             import  com.custom.rule.*;
             rs = new RuleSet(); 
             rs.name="asdf";
              rs.print();
         ]]></block>
</mvel-rule>
</rule-set>
</rules>
rule2中可見mvel可以導入未知jar包并進行處理,確實強大,就有了足夠的靈活性. 自定義規則庫源碼及使用示例下載.
本例依賴xstream
1.4.9 ,mvel2.0
自定義規則庫除了可以應用于一般系統業務處理,當然也還可以用于大數據處理。比如hadoop/spark統計用戶積分等
如果再定義一套配置規則的UI。。。好的,業務人員可以自己設置計算規則了。








傻 瓜 2017-08-20 14:52 發表評論
]]>
架構設計過程分析小結http://m.tkk7.com/fool/archive/2017/04/28/432490.html傻 瓜傻 瓜Fri, 28 Apr 2017 06:22:00 GMThttp://m.tkk7.com/fool/archive/2017/04/28/432490.htmlhttp://m.tkk7.com/fool/comments/432490.htmlhttp://m.tkk7.com/fool/archive/2017/04/28/432490.html#Feedback0http://m.tkk7.com/fool/comments/commentRss/432490.htmlhttp://m.tkk7.com/fool/services/trackbacks/432490.html架構設計過程簡單總結:架構設計的驅動力=功能+質量+約束.功能即系統要滿足的業務需求。質量包括運行期質量和開發期質量. 常見的運行期質量屬性包括軟件系統的易用性、性能、可伸縮性、持續可用性、魯棒性、安全性等。開發期質量屬性是開發人員最為關心的,要達到怎樣的目標應根據項目的具體情況而定。約束可能是商業預算,運行環境,使用人員水平,開發團隊水平等。架構設計過程如下:

一,需求收集,分析。

此處省略2000字。。。 見前篇 《需求收集、分析小結http://m.tkk7.com/fool/archive/2017/04/28/432489.html

二,概念架構/概念模型

從需求中找出關健、重大需求,進行概念建模.下面三個圖稱之魯棒圖。其中控制對象理解為mvc模式中的控制器和model。使用魯棒圖可以建立概念模型,約等于初步設計。初步設計并不關心細節。

 

 魯棒圖建立概念模型語法:

概念設計舉例:


上次談到超市小票如何分析實體對象,本次接著舉例如何對收銀進行概念建模



如上圖:具備基本收銀功能的概念模型。概念模型建模可以是增量的。比如商品折扣或其它

促銷活動等。


概念架構的用途:

1) 可以幫助我們找出領域模型中的實體對象。

2) 檢查需求用例是否正確和完善。

3)初步設計,魯棒圖是一種初步設計技術。

4)根據用例和概念設計劃分系統、子系統、模塊或者包。借助魯棒圖,初步識別功能背后的職責,規劃切分系統的方式。

 

三,關注非功能性需求,包括運行期質量和開發期質量。

運用目標場景決策表對非功能性需求作出決策.小舉例:

目標

場景

決策

易用性

銷售員需要輸入條碼檢索商品,繁瑣且速度慢

根據條碼,品名模糊匹配檢索商品,提供輔助錄入。

性能

長時間穩定運行

數據庫集群,服務應用集群                                        

        技術選型                             需要管理錢箱、打印機、響應速    pos系統使用c/s
                                                度快

 

 

 

四,細化架構。RUP 4+1視圖法則將架構需要關注的不同的點使用不同的視圖表示.從不同的維度對系統進行解讀,從而形成統一軟件過程架構描述。

運行架構:

關心進程、線程、同步的相關設計,捕捉并發和同步特征

邏輯架構:

關心邏輯層(layer)的劃分,系統/子系統的劃分,劃分模塊及其接口的定義。功能組劃分也屬于邏輯架構.功能:不僅包括用戶可見的功能,還包括為實現用戶功能而必須提供的"輔助功能模塊";它們可能是邏輯層、功能模塊等。

物理架構:

關心服務器選型,物理層劃分(tier) 描述如何部署機器和網絡來配合軟件系統的可靠性、可伸縮性等要求.layer就運行在tier上。Tier反映系統伸縮能力。

開發架構:

描述了在開發環境中軟件的靜態組織結構。即開發工具下的開發視圖,描述文件編譯及其依賴關系。而使用maven管理開發的項目編譯及依賴關系結構更加分明。

數據架構:

關心數據的存儲、分布和文件的存放及數據的復制,傳遞,同步。數據的存放包括sql,內存數據庫,nosql數據庫等.

 

邏輯架構設計舉例:

還是用收銀系統簡單舉例,收銀系統邏輯架構圖如下:



整個系統劃系統為系統,切為兩個系統,一個收銀員角色處理的業務,收銀系統。

一個后臺管理系統。后臺管理系統包括用戶管理模塊,基礎資料模塊(產品資料等)

銷售模塊(本例對銷售單)。另外,因為收銀系統需要和后臺系統交互,把收銀系統需要使用到的相關的各模塊封裝成一個接口模塊,專門處理和收銀系統交互的模塊。系統、模塊之間的通訊方式應當盡量避免雙向。相互依賴可能會引發很多問題。

 

物理架構設計舉例:

物理架構和邏輯架構可以相互印證。描述軟件系統的物理布署。



如果考慮運行期質量比如長時間運行布署圖可能應用做集群。數據庫做集群等。邏輯層layer運行在物理層tier之上

 

運行架構和數據架構視圖根據實際情況可選設計





傻 瓜 2017-04-28 14:22 發表評論
]]>
需求收集、分析小結http://m.tkk7.com/fool/archive/2017/04/28/432489.html傻 瓜傻 瓜Fri, 28 Apr 2017 06:08:00 GMThttp://m.tkk7.com/fool/archive/2017/04/28/432489.htmlhttp://m.tkk7.com/fool/comments/432489.htmlhttp://m.tkk7.com/fool/archive/2017/04/28/432489.html#Feedback0http://m.tkk7.com/fool/comments/commentRss/432489.htmlhttp://m.tkk7.com/fool/services/trackbacks/432489.html繞不過去的坎---需求分析需求.分析師也好,系統分析師也好,架構師也好乃至PM都有一道繞不過去的坎,那就是需求分析。需求分析也繞不過需求收集。
需求收集的要點:
1,參與人。很重要。廣義上是指各種干系人,如客戶方,自己方的.具體的軟件操作員可以是直接參與人,但也可能是代理參與人,比如聲訊話務員,并不是系統的直接參與者,而是代理人。嗯,可以理解成別人請話員操作軟件。甚至打電話進來的也是一個代理人,他幫別人辦理業務。也有可能有數據權限要求。
2,用例。描述業務場景。通俗一點講即參與人要辦的事情。
3,邊界。邊界有兩種意義。一種是技術實現層面,比如mvc模式中的V。另一種是業務層面的,指本用例需要達到的目標。
以上三點,UML中有業務用例圖表示。但是僅此還不夠。俺給加上第
4,業務規則。即完成業務的約束條件。這個單獨抽出非常重要。有些業務規則最終可能會實現為一個系統用例。比如出國需要辦理出入境業務。如果在電腦上實現預約,當然要考慮辦理中心排班情況,比如除法定節假日以外星期一至星期六都工作。因為每年的法定節假日不是固定的,那我們需要做一個日期是否工作日的排班表出來。這條業務規則即變為一個系統用例,有人機交互界面。在預約出入境時就成了預約的前置條件。還有其它的業務規則比如報表的計算公式等。可見業務規則是如此重要。可以抽出來弄成單獨的文檔。
系統分析員或需求分析師需要根據業務需求做出系統用例。系統用例在人機交互應用中是指人做什么,然后電腦做什么的描述。
pm會跟用戶聊到需求。架構師需要了然關鍵需求及可能存在風險的需求,盡早考慮解決方案。需求分析師也好,架構師也好,基本上應該擅長業務領域模型建模。業務領域模型可能映射成數據架構,即數據的存儲方式,比如數據庫和文件等。如何正確的建立領域模型?
1,不要放過業務場景中的名詞。比如合同,銷售單。
2,不要放過業務場景中的動名詞,比如取款。描述可能一是條取款流水記錄,如某人在某個時間某個地點用某種方式取了多少款。
3, 應當收集業務中用到的一些資料如銷售單,出貨單,甚至是公司章程如請假制度管理等。
參與人和業務規則往往容易被忽視掉,這會帶來需求變更。那么問題來了,這些東西如何映射成程序中的對象?如下圖中的商場的小票聯.應該怎么建數據庫表呢?有沒有方法呢?當然有,那就是找出發票中有哪些對象。根據對象建數據表。
分析過程:
1,問問自己,小票是對象嗎? 當然是.因為它有自己的屬性。比如開票人,銷售的商品。在商場pos系統里這個對象其實就是銷售單對象。
2,銷售時間是一個對象嗎?不是。因為它只是一個時間字符串,本身沒有其它屬性。
3,可樂汽水及商品編號當然是一個對象。這容易理解。
4,金額3.1元也是一個基本屬性,它屬于什么對象?銷售單本身嗎?顯然不是。它跟可樂汽水這個商品合起來才是一個對象,描述的是銷售單什么價格銷售了什么產品,應當單獨建立一個表。如果有多個商品?那很容易擴充,銷售單有一個LIST<銷售明細> 的屬性。
對象本身具有良好的繼承性,換句話講按對象模型建立的數據庫表基本上都是很容易擴展的,在增加新功能的時候不至于大動干戈。架構師則根據此設計數據架構視圖,比如銷售單查詢響應要求,大數據量的水平,垂直分庫,數據庫讀寫分離等。



傻 瓜 2017-04-28 14:08 發表評論
]]>
acegi之Active Directory驗證http://m.tkk7.com/fool/archive/2009/10/30/300395.html傻 瓜傻 瓜Fri, 30 Oct 2009 09:48:00 GMThttp://m.tkk7.com/fool/archive/2009/10/30/300395.htmlhttp://m.tkk7.com/fool/comments/300395.htmlhttp://m.tkk7.com/fool/archive/2009/10/30/300395.html#Feedback0http://m.tkk7.com/fool/comments/commentRss/300395.htmlhttp://m.tkk7.com/fool/services/trackbacks/300395.html客戶要求提供Active Directory登錄驗證.原因是他們公司是在美國的上市公司,要求上市公司的軟件必須提供統一登錄認證.他們想到的解決方案就是Active Directory.呵呵.而我們開發的系統使用的是acegi登錄驗證.嗯,這個,首先想到的就是ldap,沒的想,網上搜吧,資料還不算少.那就配吧,配好了需要測試吧,那就找服務器咧.這公司的域服務器不讓用,那就openldap吧.下好了又一通查資料,openldap總得配是吧.總算給配好了,不容易呀.就拿到客戶環境去試吧,嘿嘿,客戶說了不可能給我們管理員帳號密碼,只有用戶登錄帳號跟密碼,傻了.acegi的ldap驗證就要這個啊.
回來繼續搞咧,咱也沒辦法不是?

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">

<beans>

 <bean id="filterChainProxy"
  class="org.acegisecurity.util.FilterChainProxy">
  <property name="filterInvocationDefinitionSource">
   <value>
    CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
    PATTERN_TYPE_APACHE_ANT
    /**=httpSessionContextIntegrationFilter,logoutFilter,authenticationProcessingFilter,securityContextHolderAwareRequestFilter,rememberMeProcessingFilter,anonymousProcessingFilter,exceptionTranslationFilter,filterInvocationInterceptor
   </value>
  </property>
 </bean>

 <bean id="authenticationManager"
  class="org.acegisecurity.providers.ProviderManager">
  <property name="providers">
   <list>
     <!-- 自己寫一個認證提供者類 我加的-->
       <ref local="activeDirectoryProvider" />
    <ref local="daoAuthenticationProvider" />
    <ref local="anonymousAuthenticationProvider" />
    <ref local="rememberMeAuthenticationProvider" />
   </list>
  </property>
 
 </bean>
 
 <!-- 認證提供者類的配置 我加的-->
 <bean id="activeDirectoryProvider"
  class="net.omw.utility.AcegiTestProvider">
  <property name="url" value="ldap://172.108.4.2"> </property>
  <property name="port" value="389"> </property>
<!--domain取值域服務器的配置-->
  <property name="domain" value="SUNTECH"> </property>
  <!--    <property name="sessionController" ref="concurrentSessionController"></property> -->
 </bean>


 <bean id="jdbcDaoImpl"
  class="org.acegisecurity.userdetails.jdbc.JdbcDaoImpl">
  <property name="dataSource">
   <ref bean="coreDataSource" />
  </property>
  <property name="usersByUsernameQuery">
   <value>
    select C_OPER_ID,C_PASSWORD,1 from Operator where
    C_OPER_ID = ? and C_STATUS='Y'
   </value>
  </property>
  <property name="authoritiesByUsernameQuery">
   <value>
    select C_OPER_ID,C_PASSWORD,1 from Operator where
    C_OPER_ID = ? and C_STATUS='Y'
   </value>
  </property>
 </bean>

 <bean id="passwordEncoder"
  class="org.acegisecurity.providers.encoding.Md5PasswordEncoder">
  <property name="encodeHashAsBase64" value="false"></property>
 </bean>

 <bean id="daoAuthenticationProvider"
  class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">
  <property name="userDetailsService">
   <ref local="jdbcDaoImpl" />
  </property>
  <!-- <property name="userCache">
   <ref local="userCache" />
  </property>-->
  <property name="passwordEncoder">
   <ref local="passwordEncoder" />
  </property>
 </bean>

 <bean id="cacheManager"
  class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" />

 <bean id="userCacheBackend"
  class="org.springframework.cache.ehcache.EhCacheFactoryBean">
  <property name="cacheManager">
   <ref local="cacheManager" />
  </property>
  <property name="cacheName">
   <value>userCache</value>
  </property>
 </bean>

 <bean id="userCache"
  class="org.acegisecurity.providers.dao.cache.EhCacheBasedUserCache">
  <property name="cache">
   <ref local="userCacheBackend" />
  </property>
 </bean>

 <bean id="loggerListener"
  class="org.acegisecurity.event.authentication.LoggerListener" />

 <bean id="anonymousProcessingFilter"
  class="org.acegisecurity.providers.anonymous.AnonymousProcessingFilter">
  <property name="key">
   <value>foobar</value>
  </property>
  <property name="userAttribute">
   <value>anonymousUser,ROLE_ANONYMOUS</value>
  </property>
 </bean>

 <bean id="anonymousAuthenticationProvider"
  class="org.acegisecurity.providers.anonymous.AnonymousAuthenticationProvider">
  <property name="key">
   <value>foobar</value>
  </property>
 </bean>

 <bean id="httpSessionContextIntegrationFilter"
  class="org.acegisecurity.context.HttpSessionContextIntegrationFilter">
 </bean>

 <bean id="rememberMeProcessingFilter"
  class="org.acegisecurity.ui.rememberme.RememberMeProcessingFilter">
  <property name="authenticationManager">
   <ref local="authenticationManager" />
  </property>
  <property name="rememberMeServices">
   <ref local="rememberMeServices" />
  </property>
 </bean>

 <bean id="rememberMeServices"
  class="org.acegisecurity.ui.rememberme.TokenBasedRememberMeServices">
  <property name="userDetailsService">
   <ref local="jdbcDaoImpl" />
  </property>
  <property name="key">
   <value>springRocks</value>
  </property>
 </bean>

 <bean id="rememberMeAuthenticationProvider"
  class="org.acegisecurity.providers.rememberme.RememberMeAuthenticationProvider">
  <property name="key">
   <value>springRocks</value>
  </property>
 </bean>

 <bean id="logoutFilter"
  class="org.acegisecurity.ui.logout.LogoutFilter">
  <constructor-arg value="/login/loginPage.jsp" />
  <constructor-arg>
   <list>
    <ref bean="rememberMeServices" />
    <bean
     class="org.acegisecurity.ui.logout.SecurityContextLogoutHandler" />
   </list>
  </constructor-arg>
 </bean>

 <bean id="securityContextHolderAwareRequestFilter"
  class="org.acegisecurity.wrapper.SecurityContextHolderAwareRequestFilter" />

 <bean id="exceptionTranslationFilter"
  class="org.acegisecurity.ui.ExceptionTranslationFilter">
  <property name="authenticationEntryPoint">
   <ref local="authenticationProcessingFilterEntryPoint" />
  </property>
  <property name="accessDeniedHandler">
   <bean
    class="org.acegisecurity.ui.AccessDeniedHandlerImpl">
    <property name="errorPage"
     value="/common/AccessDenied.jsp" />
   </bean>
  </property>
 </bean>

 <bean id="authenticationProcessingFilter"
  class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter">
  <property name="authenticationManager">
   <ref bean="authenticationManager" />
  </property>
  <property name="authenticationFailureUrl">
   <value>/login/Login.action?login_msg=1</value>
  </property>
  <property name="defaultTargetUrl">
   <value>/login/Login.action?login_msg=0</value>
  </property>
  <property name="filterProcessesUrl">
   <value>/j_acegi_security_check</value>
  </property>
  <property name="rememberMeServices">
   <ref local="rememberMeServices" />
  </property>
 </bean>

 <bean id="authenticationProcessingFilterEntryPoint"
  class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint">
  <property name="loginFormUrl">
   <value>/login/loginPage.jsp</value>
  </property>
  <property name="forceHttps">
   <value>false</value>
  </property>
  <property name="serverSideRedirect" value="false"></property>
 </bean>

 <bean id="httpRequestAccessDecisionManager"
  class="org.acegisecurity.vote.AffirmativeBased">
  <property name="allowIfAllAbstainDecisions">
   <value>false</value>
  </property>
  <property name="decisionVoters">
   <list>
    <ref bean="roleVoter" />
   </list>
  </property>
 </bean>

 <bean id="roleVoter" class="org.acegisecurity.vote.RoleVoter" />

 <bean id="filterInvocationInterceptor"
  class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">
  <property name="validateConfigAttributes" value="true" />
  <property name="authenticationManager">
   <ref bean="authenticationManager" />
  </property>
  <property name="accessDecisionManager">
   <ref local="httpRequestAccessDecisionManager" />
  </property>
  <property name="objectDefinitionSource"
   ref="rdbmsFilterInvocationDefinitionSource" />

 </bean>

 <bean id="rdbmsFilterInvocationDefinitionSource"
  class="net.omw.utility.acegi.interceptor.RdbmsFilterInvocationDefinitionSource">
  <property name="dataSource">
   <ref bean="coreDataSource" />
  </property>
  <property name="webresdbCache" ref="webresCacheBackend" />
 </bean>

 <bean id="webresCacheBackend"
  class="org.springframework.cache.ehcache.EhCacheFactoryBean">
  <property name="cacheManager">
   <ref local="cacheManager" />
  </property>
  <property name="cacheName">
   <value>webresdbCache</value>
  </property>
 </bean>

 <!-- 
  <bean id="switchUserProcessingFilter" class="org.acegisecurity.ui.switchuser.SwitchUserProcessingFilter">
  <property name="userDetailsService" ref="jdbcDaoImpl" />
  <property name="switchUserUrl"><value>/j_acegi_switch_user</value></property>
  <property name="exitUserUrl"><value>/j_acegi_exit_user</value></property>
  <property name="targetUrl"><value>/secure/index.htm</value></property>
  </bean>   
 -->

 <bean id="authenticationLoggerListener"
  class="org.acegisecurity.event.authentication.LoggerListener" />

 <bean id="authorizationLoggerListener"
  class="org.acegisecurity.event.authorization.LoggerListener" />
</beans>

AcegiTestProvider類從AbstractUserDetailsAuthenticationProvider繼承,有兩個方法必須實現
additionalAuthenticationChecks()和retrieveUser()方法.retrieveUser返回UserDetails,UserDetails的實現可以包裝更多的信息.但在本例中幾乎沒什么太大的作用,僅僅是為了返回而重新定義了一個類
真正的驗證邏輯發生在additionalAuthenticationChecks方法里拋出異常就算用戶登錄失敗

package net.omw.utility;

import java.util.Properties;

import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.ldap.InitialLdapContext;

import org.acegisecurity.AuthenticationException;
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.GrantedAuthorityImpl;
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.acegisecurity.providers.dao.AbstractUserDetailsAuthenticationProvider;
import org.acegisecurity.userdetails.UserDetails;
import org.acegisecurity.userdetails.UsernameNotFoundException;

public class AcegiTestProvider extends
  AbstractUserDetailsAuthenticationProvider {
   private String url;
   private String port;
   private String domain;
 
 /*
  * 驗證邏輯
  * @see org.acegisecurity.providers.dao.AbstractUserDetailsAuthenticationProvider#additionalAuthenticationChecks(org.acegisecurity.userdetails.UserDetails, org.acegisecurity.providers.UsernamePasswordAuthenticationToken)
  *
  */
 @Override
 protected void additionalAuthenticationChecks(UserDetails arg0,
   UsernamePasswordAuthenticationToken arg1)
   throws AuthenticationException {
  // TODO Auto-generated method stub

  String URL = url+":"+port;

        String username=domain+"\\"+arg0.getUsername();
  String password = arg0.getPassword();


  Properties env = new Properties();  
  env.put(Context.INITIAL_CONTEXT_FACTORY,
  "com.sun.jndi.ldap.LdapCtxFactory");
  env.put(Context.PROVIDER_URL,"ldap://172.18.0.42:389");
  env.put(Context.SECURITY_AUTHENTICATION,"simple");
  env.put(Context.SECURITY_PRINCIPAL,
  username);
  env.put(Context.SECURITY_CREDENTIALS,password);
  env.put("com.sun.jndi.ldap.connect.pool","true");
  env.put("java.naming.referral","follow"); 
  try{
    new InitialLdapContext(env,null);
  }
  catch(NamingException e){
   // Authentication failed
   throw new UsernameNotFoundException(e.toString());
   
  }


 }

 @Override
 protected UserDetails retrieveUser(String arg0,
   UsernamePasswordAuthenticationToken arg1)
   throws AuthenticationException {
  // TODO Auto-generated method stub
  GrantedAuthority[] authorities = new GrantedAuthority[1];
  authorities[0] = new GrantedAuthorityImpl("ROLE_SUPERVISOR");
  String password = (String) arg1.getCredentials();  
        /*String username = "";
  Object obj = arg1.getPrincipal();
  if (obj instanceof UserDetails) {
   username = ((UserDetails) obj).getUsername();
  } else {
   username = obj.toString();
  }
        */
  UserDetails userDetails = new UserDetailsImpl(authorities, password,
    arg1.getName(), true, true, true, true);
  //if(true)
    //  throw new AuthenticationCredentialsNotFoundException("t");
  
  return userDetails;
 }

 public String getUrl() {
  return url;
 }

 public void setUrl(String url) {
  this.url = url;
 }

 public String getPort() {
  return port;
 }

 public void setPort(String port) {
  this.port = port;
 }

 public String getDomain() {
  return domain;
 }

 public void setDomain(String domain) {
  this.domain = domain;
 }

 
}

package net.omw.utility;

import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.userdetails.UserDetails;

public class UserDetailsImpl implements UserDetails {
 GrantedAuthority[] authorities;

 String password;

 String username;
 boolean isAccountNonExpired;

 boolean isAccountNonLocked;

 boolean isCredentialsNonExpired;

 boolean isEnabled;

 UserDetailsImpl(GrantedAuthority[] authorities, String password,
            String username, boolean isAccountNonExpired,
            boolean isCredentialsNonExpired, boolean isEnabled,
            boolean isAccountNonLocked) {
        this.authorities = authorities;
        this.isAccountNonExpired = isAccountNonExpired;
        this.isAccountNonLocked = isAccountNonLocked;
        this.isEnabled = isEnabled;
        this.password = password;
        this.username = username;
        this.isCredentialsNonExpired = isCredentialsNonExpired;

    }

 
 @Override
 public GrantedAuthority[] getAuthorities() {
  // TODO Auto-generated method stub
  return authorities;
 }

 @Override
 public String getPassword() {
  // TODO Auto-generated method stub
  return password;
 }

 @Override
 public String getUsername() {
  // TODO Auto-generated method stub
  return username;
 }

 @Override
 public boolean isAccountNonExpired() {
  // TODO Auto-generated method stub
  return isAccountNonExpired;
 }

 @Override
 public boolean isAccountNonLocked() {
  // TODO Auto-generated method stub
  return isAccountNonLocked;
 }

 @Override
 public boolean isCredentialsNonExpired() {
  // TODO Auto-generated method stub
  return isCredentialsNonExpired;
 }

 @Override
 public boolean isEnabled() {
  // TODO Auto-generated method stub
  return isEnabled;
 }

}





 



傻 瓜 2009-10-30 17:48 發表評論
]]>
oracle 嵌套游標以及java,oracle的時間處理http://m.tkk7.com/fool/archive/2009/03/09/258559.html傻 瓜傻 瓜Mon, 09 Mar 2009 02:50:00 GMThttp://m.tkk7.com/fool/archive/2009/03/09/258559.htmlhttp://m.tkk7.com/fool/comments/258559.htmlhttp://m.tkk7.com/fool/archive/2009/03/09/258559.html#Feedback0http://m.tkk7.com/fool/comments/commentRss/258559.htmlhttp://m.tkk7.com/fool/services/trackbacks/258559.html 

create or replace procedure test is
 
       ids VOD_CMS_OPERATION_REGION.id%type; //變量ids與VOD_CMS_OPERATION_REGION表的id字段的類型一致
       cursor cur_region is    select id from VOD_CMS_OPERATION_REGION; //定義游標
       phoneId VOD_CMS_OPERATION_REGION2PHONE.id%type;
       cursor cur_phone is select id from   VOD_CMS_OPERATION_REGION2PHONE  //第二個游標
               where VOD_CMS_OPERATION_REGION2PHONE.REGION_ID=ids ;
        
begin
       open cur_region;  //打開游標
       loop    //循環
         fetch cur_region  into ids;    //逐行處理游標把值放入變量 ids
         exit when cur_region%notfound; //沒找到游標退出循環
        
         open cur_phone;
         
         loop                           
           fetch cur_phone into phoneId; 
           exit when cur_phone%notfound;
           update VOD_CMS_OPERATION_REGION2PHONE set creater=1 where VOD_CMS_OPERATION_REGION2PHONE.id=phoneId;
         end loop;
         close cur_phone;
        
       end loop;
       close cur_region; 關閉游標
       commit;
end test;


程序處理oracle時間

  Calendar ca = Calendar.getInstance(Locale.CHINA);
  ca.setTime(new Date());
  ca.set(Calendar.HOUR_OF_DAY, 0);
  ca.set(Calendar.MINUTE,0);
  ca.set(Calendar.SECOND, 0);
  SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  StringBuffer buffer = new StringBuffer();
  buffer.append("select cmsAssetObject.regionIds from CmsAssetObject cmsAssetObject where cmsAssetObject.validdate >= " );
  buffer.append("to_date('"+sdf.format(ca.getTime())+ "','yyyy-MM-dd hh24:mi:ss') ");
  ca.set(Calendar.HOUR_OF_DAY, 23);
  ca.set(Calendar.MINUTE,59);
  ca.set(Calendar.SECOND,59);
  buffer.append(" and cmsAssetObject.expiredate <= ");
  buffer.append("to_date('"+sdf.format(ca.getTime())+ "','yyyy-MM-dd hh24:mi:ss') ");
  buffer.append(" and cmsAssetObject.isWeather = 1");


傻 瓜 2009-03-09 10:50 發表評論
]]>
訪問者模式實戰:構建通用的數據庫插入操作http://m.tkk7.com/fool/archive/2006/08/14/63474.html傻 瓜傻 瓜Mon, 14 Aug 2006 06:39:00 GMThttp://m.tkk7.com/fool/archive/2006/08/14/63474.htmlhttp://m.tkk7.com/fool/comments/63474.htmlhttp://m.tkk7.com/fool/archive/2006/08/14/63474.html#Feedback2http://m.tkk7.com/fool/comments/commentRss/63474.htmlhttp://m.tkk7.com/fool/services/trackbacks/63474.html
在做一些簡單的JDBC的API應用時,就老想只用一個方法向數據庫不同的表做插入操作,省得
用一大堆的insert語句。訪問者模式可以實現對未知的類進行操作,于是就用了這個簡化了的模
式的實現方案。請高手指正。 在使用訪問者模式之前先敘述一點概念性的東西。
靜態類型的概念:變量被申明時的類型。實際類型:變量的實際類型。
比如 Object object=new String(); object靜態類型是Object,實際類型是String.
觀察者模式是一個比較難理解的模式,在理解觀察者模式之前當然應該先理解雙重分派的概念。
java語言支持靜態的多分派跟動態的單分派。java通重載支持靜態的多分派。書上的例子:
public class Mozi {
???
??? public void ride(Horse h){
??????? System.out.println("ridding a horse");
??? }
??? public void ride(WhiteHorse w){
??????? System.out.println("ridding a white horse");
??? }
??? public void ride(BlackHorse b){
??????? System.out.println("rdding a black horse");
??? }

??? public static void main(String[] args){
????? Mozi mozi=new Mozi();
????? Horse w=new WhiteHorse();
????? Horse b=new BlackHorse();
????? mozi.ride(w);
????? mozi.ride(b);
??? }
}?
程序打印輸出:
ridding a horse
ridding a horse
原因就是對兩次ride方法的調用傳入的參量不同,但是它們的靜態類型是一樣的,都是 Horse;
這個過程在編譯時期就完成了。
java通過方法置換支持動態分派。比如 String s1="ab"; Object o=s1+"c"; String s="abc";
o.equals(s) 打印true? o.equals()方法執行的是String類的equals()方法.java調用對象的
真實類型的方法,這就是動態分派。
雙重分派:
public abstract class Vistor{

protected void processStrig(Object e){
?if(e instanceof String){
???? String tmp=(String) e;
???? String need="'"+e+"'";
???? System.out.println(nedd);
?? }else if(e instanceof Integer){
?????? String need=e.toString();
?????? System.out.println(need);
??? }else if(e instanceof Date){
???????????? Date tmp=(Date) e;
???????????? String need="'"+tmp.toString()+"'";
??????? }
????? ....
??? }

}

public class ConcreteVisitor extends Visitor{

protected void processString(Object e){
???? super.processString(e);
?? }??
}
方法的調用Visitor v=new ConcreteVisitor(); v.processString(new String("tt"));
v.processString()方法在調用的時候會檢察v的真實類型,調用真實類型的方法,這個時候就
發生了一動態的單分派過程.當子類調用超類的方法的時候明顯的根據instanceof判斷的真實類
型去執行不同的方法,又發生了一次動態分派的過程.這個就是雙重分派的實現。這種方法實現的
程序比較冗長和容易出錯.
“返傳球”方案:
public abstract class Vistor{

?? public abstract String processStrig(Object e);

}

public class ConcreteVisitor extends Visitor{

? public String processString(WrapperString e){
??? String tmp= t.toString();
??? System.out.println(tmp);
?? }??

? public String processInteger(WrapperInteger e){
??? String tmp=e.toString();
??? System.out.println(tmp);

?? }

}

public class abstract Wrapper{
? public abstract String processString(Vistor v);
}

public class WrapperString extends Wrapper{

? public String processString(Vistor v){
??? v.processString(this);
?? }
? public String toString(){
?? ...
?? }
}

public class WrapperInteger extends Wrapper{
??? public String processInteger(Visitor v){
???? v.processString(this);
??? }
??? public String toString(){
???? ...
??? }
?}
方法的調用:
Visitor v = new ConcreteVisitor();
Wrapper wrapper= new WrapperString();
wrapper.processString(v);
當wrapper.processString()方法執行的時候會檢察wrapper的真實類型,這個就產生了一次
動態單分派,processString()里面的語句v.processString()在執行的時候也會檢察v的真
實類型,動態雙重分派就發生了。
訪問者模式的核心就是“返傳球“方案的雙重分派。其示意性類圖:(注:虛線箭頭劃錯了)



visitor.jpg

在一個方法內實現向不同的表插入不同數據的具體實現方案(簡化了的):因為整個方案里只需
要一個訪問者對象,因此使用簡化了的訪問者模式。因為java基本類型及對應的類是不變模式的
實現:因此包裝一下這些基本類型和類并實現訪問者模式需要的方法。
public abstract class Wrapper {
??? public Wrapper() {
??? }
??? public abstract String action(Visitor visitor);

}

包裝Date類:
import java.util.Date;
public class WrapperDate extends Wrapper {
??? private Date date;
??? public WrapperDate(Date date) {
??????? this.date=date;
??? }
??? public String action(Visitor visitor){
???????? return( visitor.visit(this));
??? }

??? public String toString(){
??????? if (date==null){
??????????? return "null";
??????? }
??????? return "'"+date.toString()+"'";
??? }

}


包裝Integer類:
public class WrapperInteger extends Wrapper {
??? private Integer value;

??? public WrapperInteger(Integer value) {
??????? this.value=value;

??? }
??? public WrapperInteger(int value){

??????? this.value=new Integer(value);
??? }
??? public WrapperInteger(String value){

????? this.value=new Integer(value);
??? }

??? public String action(Visitor visitor){
?????? return( visitor.visit(this));
??? }
??? public String toString(){
??????? if(value==null){
??????????? return "null";
??????? }
??????? return value.toString();
??? }
}

包裝String類:
public class WrapperString extends Wrapper {
??? private String wrapper;
??? public WrapperString( String wrapper) {

??????? this.wrapper = wrapper;
??? }

??? public WrapperString( char[] wrap) {
??????? wrapper = new String(wrap);
??? }

??? public String action(Visitor visitor) {
??????? return (visitor.vistit(this));
??? }

??? public String toString() {
??????? if(wrapper==null){
??????????? return "null";
??????? }
??????? return "'" + wrapper + "'";
??? }


}

具體訪問者的實現:
public class Visitor {
??? public Visitor() {
??? }


??? public String vistit(WrapperString wrap){
?????? return wrap.toString();
??? }
??? public String visit(WrapperInteger value){
??????? return value.toString();
??? }
??? public String visit(WrapperDate date){
??????? return date.toString();
??? }
}

具體應用類的實現:

import java.util.*;

public class Test {


??? private Visitor visitor = new Visitor();

??? public Test() {
??? }

??? public Visitor getVisitor() {
??????? return visitor;
??? }

??


??? public int insertData(String tablename, List columNameCollection,
????????????????????????? List values) {

??????? StringBuffer query = new StringBuffer("insert into " + tablename + " (");

??????? int count = 0;

??????? for (Iterator it = columNameCollection.iterator(); it.hasNext(); ) {
??????????? String columName = (String) it.next();
??????????? query.append(columName);
??????????? query.append(",");
??????? }
??????? query.deleteCharAt(query.length() - 1);
??????? query.append(") values(");
??????? for (Iterator it = values.iterator(); it.hasNext(); ) {
??????????? Wrapper wrapper = (Wrapper) it.next();
??????????? String tmp = wrapper.action(getVisitor());
??????????? query.append(tmp);
??????????? query.append(",");
??????? }
??????? query.deleteCharAt(query.length() - 1);
??????? query.append(")");

??????? System.out.println(query.toString());
??????? return count;
??? }


??? public static void main(String[] args) {
??????? Test test = new Test();
??????? String tableName = "cutomer";
??????? List columNameCollection = new ArrayList();
??????? String columName = "name";
??????? String columAge = "age";
??????? String columFunctionTime="fuctiontime";
??????? columNameCollection.add(columName);
??????? columNameCollection.add(columAge);
??????? columNameCollection.add(columFunctionTime);
??????? List values = new ArrayList();
??????? String name=null;
??????? Wrapper wrapper1 = new WrapperString(name);
??????? Wrapper wrapper2 = new WrapperInteger(1);
??????? Wrapper wrapper3= new WrapperDate(new java.util.Date());
??????? values.add(wrapper1);
??????? values.add(wrapper2);
??????? values.add(wrapper3);
??????? test.insertData(tableName,columNameCollection,values);
???????


??? }
}

程序打印結果:

insert into cutomer (name,age,fuctiontime) values(null,1,'Sat Aug 12 13:46:58 CST 2006')

這個輸出是滿足MSSQL執行插入的語法要求的.雖然這樣就實現了想要的結果,
但是insertData(String tablename, List columNameCollection, List values) 方法在每次調
用的時候需要輸入表名跟該表的列的集合,還是很麻煩,不盡人意,而且不同的數
據庫的表名是不一樣的,因此最好用配置文件來解決這一個問題.

歡迎加入QQ群:30406099?

?


?



傻 瓜 2006-08-14 14:39 發表評論
]]>
在java中改變菜單的外觀http://m.tkk7.com/fool/archive/2006/07/06/56921.html傻 瓜傻 瓜Thu, 06 Jul 2006 03:24:00 GMThttp://m.tkk7.com/fool/archive/2006/07/06/56921.htmlhttp://m.tkk7.com/fool/comments/56921.htmlhttp://m.tkk7.com/fool/archive/2006/07/06/56921.html#Feedback3http://m.tkk7.com/fool/comments/commentRss/56921.htmlhttp://m.tkk7.com/fool/services/trackbacks/56921.html在java中改變菜單的外觀,想必只有傻瓜才會這么干吧,哈哈哈~~~你不許笑,只許我笑.因為隨便笑人家是傻瓜不是一個禮貌的孩子:) 好了,說實現思路吧 .javax.swing包中的組件都是繼承JComponent組件 JComponent組件中有一個方法setBorder(Border border) 用來設置組件的邊框 Boder是一個接口,在avax.swing.border包中
那么改變菜單的外觀就可以首先從這個來著手了.因此我們需要一個實現這個接口的類.好了,來看看這個接口的方法吧 :
void paintBorder(Component c,
???????????????? Graphics g,
???????????????? int x,
???????????????? int y,
???????????????? int width,
???????????????? int height)按指定的位置和尺寸繪制指定組件的邊框。

參數:
c - 要為其繪制邊框的組件
g - 繪制的圖形
x - 所繪制邊框的 x 坐標位置
y - 所繪制邊框的 y 坐標位置
width - 所繪制邊框的寬度
height - 所繪制邊框的高度

//附注:邊框就是在這個方法中給畫出來的
--------------------------------------------------------------------------------


Insets getBorderInsets(Component c)返回該邊框的 insets。

//附注一下:該類是容器邊界的表示形式。它指定容器必須在其各個邊緣留出的空間。這個空間可以是邊
//界、空白空間或標題。
參數:
c - 要應用此邊框 insets 值的組件

--------------------------------------------------------------------------------

isBorderOpaque
boolean isBorderOpaque()返回此邊框是否透明。如果邊框為不透明,則在繪制它時將用自身的背景來填充。



首先來看看效果圖: 請注意右上角是橢圓的噢,這個就暗示了我們可以把菜單弄成任意形狀,只要你愿意!
按照這種思路,同樣的,你也可以改變右鍵彈出菜單的外觀

menu.gif


接口的實現類? 至于畫圖用到的方法,詳見JAVA API.
import java.awt.*;
import java.awt.geom.*;

import javax.swing.*;
import javax.swing.border.*;

public class MyBorder implements Border
{
?//設置邊框四周留出的空間
? protected int m_w=6;??
? protected int m_h=6;
? protected int m_left=16;
//設置邊框的前景色跟背景色
? protected Color m_topColor = Color.white;
? protected Color m_bottomColor = Color.gray;

? public MyBorder() {
??? m_w=6;
??? m_h=6;
??? m_left=16;
? }

? public MyBorder(int w, int h) {
??? m_w=w;
??? m_h=h;
? }

? public MyBorder(int w, int h, Color topColor,
?? Color bottomColor) {
??? m_w=w;
??? m_h=h;
??? m_topColor = topColor;
??? m_bottomColor = bottomColor;
? }

? public Insets getBorderInsets(Component c) {
??? return new Insets(m_h, m_left, m_h, m_w);
? }

? public boolean isBorderOpaque() { return true; }

? public void paintBorder(Component c, Graphics gd,
?? int x, int y, int w, int h) {
??? Graphics2D g = (Graphics2D) gd;
??? w--;
??? h--;
??? g.setColor(m_topColor);
??? g.drawLine(x, y+h, x, y+m_h);
??? g.drawArc(x, y, 2*m_w, 2*m_h, 180, -90);
??? g.drawLine(x, y, x+w-m_w, y);
??? g.drawArc(x+w-2*m_w, y, 2*m_w, 2*m_h, 90, -90);
??? int stringHeitht = y+h-5;

??? Point2D.Float? p1 = new Point2D.Float(x,y+h);
??? Point2D.Float p2 = new Point2D.Float(x,y);
??? GradientPaint gradient = new GradientPaint(p1,Color.blue,p2,Color.gray,false);
??? //g.setColor(Color.YELLOW);
??? //g.drawRect();
??? g.setPaint(gradient);
??? g.fillRect(x,y,x+m_left,y+h);

??? g.setColor(Color.GRAY);
??? g.drawString("瓜",((x+m_left)-g.getFontMetrics().charWidth('傻'))/2,stringHeitht);
??? int simpleFontHeitht = g.getFontMetrics().getHeight();
??? stringHeitht-=simpleFontHeitht;
??? g.drawString("傻",((x+m_left)-g.getFontMetrics().charWidth('傻'))/2,stringHeitht);

??? g.setColor(m_bottomColor);
??? g.drawLine(x+w, y+m_h, x+w, y+h);
?? // g.drawArc(x+w-2*m_w, y+h-2*m_h, 2*m_w, 2*m_h, 0, -90);
?? g.drawLine(x, y+h, x+w, y+h);
??? //g.drawArc(x, y+h-2*m_h, 2*m_w, 2*m_h, -90, -90);
? }

}


剩下的就是把這個邊框給它裝上去了.在JMenu中有一個方法getPopupMenu()得到彈出菜單對象JPopupMenu;
然后調用這個JPopupMenu對象的setBorder方法就行了.下面是完整的測試程序

import java.awt.Toolkit;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import java.awt.Dimension;

public class Application1 {
? boolean packFrame = false;

? /**
?? * Construct and show the application.
?? */
? public Application1() {
??? MenuFaces frame = new MenuFaces();
??? // Validate frames that have preset sizes
??? // Pack frames that have useful preferred size info, e.g. from their layout
??? if (packFrame) {
????? frame.pack();
??? }
??? else {
????? frame.validate();
??? }

??? // Center the window
??? Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
??? Dimension frameSize = frame.getSize();
??? if (frameSize.height > screenSize.height) {
????? frameSize.height = screenSize.height;
??? }
??? if (frameSize.width > screenSize.width) {
????? frameSize.width = screenSize.width;
??? }
??? frame.setLocation( (screenSize.width - frameSize.width) / 2,
????????????????????? (screenSize.height - frameSize.height) / 2);
??? frame.setVisible(true);
? }

? /**
?? * Application entry point.
?? *
?? * @param args String[]
?? */
? public static void main(String[] args) {
??? SwingUtilities.invokeLater(new Runnable() {
????? public void run() {
??????? try {
????????? UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
??????? }
??????? catch (Exception exception) {
????????? exception.printStackTrace();
??????? }

??????? new Application1();
????? }
??? });
? }
}


import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class MenuFaces
??? extends JFrame {
? JPanel contentPane;
? BorderLayout borderLayout1 = new BorderLayout();
? JMenuBar jMenuBar1 = new JMenuBar();
? JMenu jMenuFile = new JMenu();
? JMenuItem jMenuFileExit = new JMenuItem();
? JMenuItem jMenuItem1 = new JMenuItem();
? JMenuItem jMenuItem2 = new JMenuItem();
? JMenuItem jMenuItem3 = new JMenuItem();
? JMenu jMenu1 = new JMenu();
? JMenuItem jMenuItem4 = new JMenuItem();

? public MenuFaces() {
??? try {
????? setDefaultCloseOperation(EXIT_ON_CLOSE);
????? jbInit();
??? }
??? catch (Exception exception) {
????? exception.printStackTrace();
??? }
? }

? /**
?? * Component initialization.
?? *
?? * @throws java.lang.Exception
?? */
? private void jbInit() throws Exception {
??? contentPane = (JPanel) getContentPane();
??? contentPane.setLayout(borderLayout1);
??? setSize(new Dimension(400, 300));
??? setTitle("Frame Title");
??? jMenuFile.setText("File");
??? jMenuFileExit.setText("Exit");
??? jMenuFileExit.addActionListener(new MenuFaces_jMenuFileExit_ActionAdapter(this));
??? jMenuItem1.setText("open");
??? jMenuItem2.setText("save");
??? jMenuItem3.setText("save as");
??? jMenu1.setText("other");
??? jMenuItem4.setText("tt");
??? jMenuBar1.add(jMenuFile);
??? jMenuBar1.add(jMenu1);
??? jMenuFile.add(jMenuItem3);
??? jMenuFile.add(jMenuItem2);
??? jMenuFile.add(jMenuItem1);
??? jMenuFile.add(jMenuFileExit);
??? jMenu1.add(jMenuItem4);
??? JPopupMenu tt = jMenuFile.getPopupMenu();
??? MyBorder myBorder = new MyBorder();
??? tt.setBorder(myBorder);

??? setJMenuBar(jMenuBar1);
? }

? /**
?? * File | Exit action performed.
?? *
?? * @param actionEvent ActionEvent
?? */
? void jMenuFileExit_actionPerformed(ActionEvent actionEvent) {
??? System.exit(0);
? }
}

class MenuFaces_jMenuFileExit_ActionAdapter
??? implements ActionListener {
? MenuFaces adaptee;

? MenuFaces_jMenuFileExit_ActionAdapter(MenuFaces adaptee) {
??? this.adaptee = adaptee;
? }

? public void actionPerformed(ActionEvent actionEvent) {
??? adaptee.jMenuFileExit_actionPerformed(actionEvent);
? }
}


歡迎加入QQ群:30406099?




?



傻 瓜 2006-07-06 11:24 發表評論
]]>
主站蜘蛛池模板: 亚洲专区一路线二| 日本免费网址大全在线观看| 亚洲综合色丁香婷婷六月图片| 亚洲人色婷婷成人网站在线观看| 国产成人精品高清免费| 100部毛片免费全部播放完整| 水蜜桃视频在线观看免费播放高清| 亚洲精品欧美综合四区| 亚洲精品伊人久久久久| 亚洲黄色网址大全| 亚洲AV无码国产精品麻豆天美| 日韩亚洲国产二区| 国产人成免费视频| 四虎影院免费在线播放| 午夜国产精品免费观看| 最近中文字幕国语免费完整 | 麻豆视频免费播放| 日韩免费无码一区二区三区| 十八禁在线观看视频播放免费| 欧洲乱码伦视频免费国产| 国产亚洲欧美日韩亚洲中文色| 亚洲午夜无码毛片av久久京东热| 亚洲精品韩国美女在线| 亚洲成人在线网站| 亚洲成人免费在线| 亚洲a在线视频视频| 亚洲gv白嫩小受在线观看| 亚洲午夜福利AV一区二区无码| 久久亚洲精品无码观看不卡| 亚洲精品美女久久久久99小说| 亚洲免费日韩无码系列| 国产精品亚洲mnbav网站 | 苍井空亚洲精品AA片在线播放 | 狼友av永久网站免费观看| 成年人在线免费看视频| 岛国大片免费在线观看| 白白国产永久免费视频| 成人伊人亚洲人综合网站222| 亚洲а∨天堂久久精品| 亚洲综合网站色欲色欲| 久久亚洲国产视频|