亚洲AV无码成人专区片在线观看,国产午夜亚洲精品不卡,亚洲s码欧洲m码吹潮http://www.tkk7.com/fool/堅(jiān)持就是勝利!zh-cnFri, 09 May 2025 22:07:01 GMTFri, 09 May 2025 22:07:01 GMT60DDD小結(jié)http://www.tkk7.com/fool/archive/2019/07/08/434108.html傻 瓜傻 瓜Mon, 08 Jul 2019 08:49:00 GMThttp://www.tkk7.com/fool/archive/2019/07/08/434108.htmlhttp://www.tkk7.com/fool/comments/434108.htmlhttp://www.tkk7.com/fool/archive/2019/07/08/434108.html#Feedback0http://www.tkk7.com/fool/comments/commentRss/434108.htmlhttp://www.tkk7.com/fool/services/trackbacks/434108.html閱讀全文

傻 瓜 2019-07-08 16:49 發(fā)表評(píng)論
]]>
優(yōu)秀代碼賞析http://www.tkk7.com/fool/archive/2019/07/06/434083.html傻 瓜傻 瓜Sat, 06 Jul 2019 04:06:00 GMThttp://www.tkk7.com/fool/archive/2019/07/06/434083.htmlhttp://www.tkk7.com/fool/comments/434083.htmlhttp://www.tkk7.com/fool/archive/2019/07/06/434083.html#Feedback0http://www.tkk7.com/fool/comments/commentRss/434083.htmlhttp://www.tkk7.com/fool/services/trackbacks/434083.html看開源的源代碼,看到一個(gè)有意思的實(shí)現(xiàn) 。
/*
 * Copyright 2019 IBM All Rights Reserved.
 *
 * SPDX-License-Identifier: Apache-2.0
 */
package org.hyperledger.fabric.gateway;
import org.hyperledger.fabric.gateway.impl.AllCommitStrategy;
import org.hyperledger.fabric.gateway.impl.AnyCommitStrategy;
import org.hyperledger.fabric.gateway.impl.CommitHandlerImpl;
import org.hyperledger.fabric.gateway.impl.CommitStrategy;
import org.hyperledger.fabric.gateway.impl.NoOpCommitHandler;
import org.hyperledger.fabric.gateway.spi.CommitHandler;
import org.hyperledger.fabric.gateway.spi.CommitHandlerFactory;
import org.hyperledger.fabric.sdk.Peer;
import org.hyperledger.fabric.sdk.exception.InvalidArgumentException;
import java.util.Collection;
/**
 * Default commit handler implementations. Instances can be referenced directly or looked up by name, for example
 * {@code DefaultCommitHandlers.valueOf("NONE")}.
 */
public enum DefaultCommitHandlers implements CommitHandlerFactory {
    /**
     * Do not wait for any commit events to be received from peers after submitting a transaction.
     */
    NONE((transactionId, network) -> NoOpCommitHandler.INSTANCE),
    /**
     * Wait to receive commit events from all currently responding peers in the user's organization after submitting
     * a transaction.
     */
    MSPID_SCOPE_ALLFORTX((transactionId, network) -> {
        Collection<Peer> peers = getPeersForOrganization(network);
        CommitStrategy strategy = new AllCommitStrategy(peers);
        CommitHandler handler = new CommitHandlerImpl(transactionId, network, strategy);
        return handler;
    }),
    /**
     * Wait to receive commit events from all currently responding peers in the network after submitting a transaction.
     */
    NETWORK_SCOPE_ALLFORTX((transactionId, network) -> {
        Collection<Peer> peers = network.getChannel().getPeers();
        CommitStrategy strategy = new AllCommitStrategy(peers);
        CommitHandler handler = new CommitHandlerImpl(transactionId, network, strategy);
        return handler;
    }),
    /**
     * Wait to receive a commit event from any currently responding peer in the user's organization after submitting
     * a transaction.
     */
    MSPID_SCOPE_ANYFORTX((transactionId, network) -> {
        Collection<Peer> peers = getPeersForOrganization(network);
        CommitStrategy strategy = new AnyCommitStrategy(peers);
        CommitHandler handler = new CommitHandlerImpl(transactionId, network, strategy);
        return handler;
    }),
    /**
     * Wait to receive a commit event from any currently responding peer in the network after submitting a transaction.
     */
    NETWORK_SCOPE_ANYFORTX((transactionId, network) -> {
        Collection<Peer> peers = network.getChannel().getPeers();
        CommitStrategy strategy = new AnyCommitStrategy(peers);
        CommitHandler handler = new CommitHandlerImpl(transactionId, network, strategy);
        return handler;
    });
    private final CommitHandlerFactory factory;
    DefaultCommitHandlers(CommitHandlerFactory factory) {
        this.factory = factory;
    }
    private static Collection<Peer> getPeersForOrganization(Network network) {
        String mspId = network.getGateway().getIdentity().getMspId();
        try {
            return network.getChannel().getPeersForOrganization(mspId);
        } catch (InvalidArgumentException e) {
            // This should never happen as mspId should not be null
            throw new RuntimeException(e);
        }
    }

   //CommitHandlerFactory 接口定義 的方法,這里是其實(shí)現(xiàn) 
    public CommitHandler create(String transactionId, Network network) {
        return factory.create(transactionId, network);
    }
}

先看看enum類的構(gòu)造函數(shù)
    DefaultCommitHandlers(CommitHandlerFactory factory) {
        this.factory = factory;
    }
需要一個(gè) CommitHandlerFactory 是個(gè)接口,同時(shí) enum類本身也實(shí)現(xiàn)了這個(gè)接口。
再來看調(diào)用過程 
CommitHandlerFactory commitHandlerFactory = DefaultCommitHandlers.MSPID_SCOPE_ALLFORTX;
這里會(huì)調(diào)用CommitHandlerFactory 構(gòu)造函數(shù),其傳入?yún)?shù)是
(transactionId, network) -> {
        Collection<Peer> peers = network.getChannel().getPeers();
        CommitStrategy strategy = new AllCommitStrategy(peers);
        CommitHandler handler = new CommitHandlerImpl(transactionId, network, strategy);
        return handler;
    }
它是lamdba寫法,看看構(gòu)造函數(shù)需要一個(gè) CommitHandlerFactory 接口,這個(gè)lamdba 函數(shù)其實(shí)就是CommitHandlerFactory 的實(shí)現(xiàn)。
這樣MSPID_SCOPE_ALLFORTX 枚舉類型就有了一個(gè)  CommitHandlerFactory實(shí)現(xiàn)類的引用。

再看create調(diào)用。
CommitHandler commitHandler = commitHandlerFactory.create(transactionId, network);
這里enum類的create方法會(huì)執(zhí)行, return factory.create(transactionId, network);
返回一個(gè) CommitHandler .這里才會(huì)真正執(zhí)行那個(gè) lamdba定義的函數(shù)。
到這里只看到lamdb應(yīng)用。。。
再分析一下create ,枚舉類里的每個(gè)枚舉變量都會(huì)實(shí)現(xiàn)一個(gè)這個(gè)方法。這里可以看到它其實(shí)是一個(gè)工廠類。
它創(chuàng)造的產(chǎn)品是CommitHandler ,其具體實(shí)現(xiàn)是CommitHandlerImpl類。
這里巧妙的使用一個(gè)enum當(dāng)工廠類的實(shí)現(xiàn)。整個(gè)代碼用了工廠模式加策略模式的實(shí)現(xiàn)。
優(yōu)點(diǎn):得宜于lamdb的應(yīng)用,減少了具體工廠類的實(shí)現(xiàn)。
缺點(diǎn):工廠模式可以實(shí)現(xiàn)不改動(dòng)程序創(chuàng)建產(chǎn)品。那么這里如果要增一個(gè)產(chǎn)品,對(duì)這個(gè)enum類需要再添加一個(gè)枚舉變量。
這個(gè)enum類有改動(dòng)。




傻 瓜 2019-07-06 12:06 發(fā)表評(píng)論
]]>
一個(gè)DDD示例代碼http://www.tkk7.com/fool/archive/2019/06/27/433990.html傻 瓜傻 瓜Thu, 27 Jun 2019 09:09:00 GMThttp://www.tkk7.com/fool/archive/2019/06/27/433990.htmlhttp://www.tkk7.com/fool/comments/433990.htmlhttp://www.tkk7.com/fool/archive/2019/06/27/433990.html#Feedback0http://www.tkk7.com/fool/comments/commentRss/433990.htmlhttp://www.tkk7.com/fool/services/trackbacks/433990.htmlgithub上的一個(gè)java版的DDD實(shí)現(xiàn)的示例代碼. 學(xué)習(xí)DDD時(shí)看一下還是不錯(cuò)的。
https://github.com/daoqidelv/community-ddd-demo.git
作者不是俺!

傻 瓜 2019-06-27 17:09 發(fā)表評(píng)論
]]>
Fabric 1.1源代碼分析(4) msp初始化過程http://www.tkk7.com/fool/archive/2018/06/25/433286.html傻 瓜傻 瓜Mon, 25 Jun 2018 01:00:00 GMThttp://www.tkk7.com/fool/archive/2018/06/25/433286.htmlhttp://www.tkk7.com/fool/comments/433286.htmlhttp://www.tkk7.com/fool/archive/2018/06/25/433286.html#Feedback0http://www.tkk7.com/fool/comments/commentRss/433286.htmlhttp://www.tkk7.com/fool/services/trackbacks/433286.html

 (MSP)是一個(gè)提供虛擬成員操作的管理框架的組件。
MSP抽取出簽發(fā)和驗(yàn)證證書以及用戶認(rèn)證背后的所有加密機(jī)制和協(xié)議。 MSP可以定義自己的身份概念,以及這些身份管理的規(guī)則(身份驗(yàn)證)和身份驗(yàn)證(簽名生成和驗(yàn)證)。

1、MSP接口定義
// MSP is the minimal Membership Service Provider Interface to be implemented
// to accommodate peer functionality
//最基本成員服務(wù)接口 其實(shí)現(xiàn)在mspimp.go文件中
type MSP interface {
// IdentityDeserializer interface needs to be implemented by MSP
IdentityDeserializer
// Setup the MSP instance according to configuration information
Setup(config *msp.MSPConfig) error
// GetVersion returns the version of this MSP
GetVersion() MSPVersion
// GetType returns the provider type
GetType() ProviderType
// GetIdentifier returns the provider identifier
GetIdentifier() (string, error)
// GetSigningIdentity returns a signing identity corresponding to the provided identifier
GetSigningIdentity(identifier *IdentityIdentifier) (SigningIdentity, error)
// GetDefaultSigningIdentity returns the default signing identity
GetDefaultSigningIdentity() (SigningIdentity, error)
// GetTLSRootCerts returns the TLS root certificates for this MSP
GetTLSRootCerts() [][]byte
// GetTLSIntermediateCerts returns the TLS intermediate root certificates for this MSP
GetTLSIntermediateCerts() [][]byte
// Validate checks whether the supplied identity is valid
Validate(id Identity) error
// SatisfiesPrincipal checks whether the identity matches
// the description supplied in MSPPrincipal. The check may
// involve a byte-by-byte comparison (if the principal is
// a serialized identity) or may require MSP validation
SatisfiesPrincipal(id Identity, principal *msp.MSPPrincipal) error
}
2、 BCCSP接口定義 BCCSP是加、解密及簽名服務(wù)。 bccp.go文件中默認(rèn)實(shí)現(xiàn)是sw/impl.go .
支持ecdsa、rsa以及aes算法 BCCSP的實(shí)現(xiàn)包括:
1,[sw]目錄為the software-based implementation of the BCCSP,即基于軟件的BCCSP實(shí)現(xiàn),通過調(diào)用go原生支持的密碼算法實(shí)現(xiàn),并提供keystore來保存密鑰
2,[pkcs11]目錄,為bccsp的pkcs11實(shí)現(xiàn),通過調(diào)用pkcs11接口實(shí)現(xiàn)相關(guān)加密操作,,密碼保存在pkcs11通過pin口令保護(hù)的數(shù)據(jù)庫(kù)或者硬件設(shè)備中。
type BCCSP interface {
    KeyGen(opts KeyGenOpts) (k Key, err error) //生成Key
    KeyDeriv(k Key, opts KeyDerivOpts) (dk Key, err error) //派生Key
    KeyImport(raw interface{}, opts KeyImportOpts) (k Key, err error) //導(dǎo)入Key
    GetKey(ski []byte) (k Key, err error) //獲取Key
    Hash(msg []byte, opts HashOpts) (hash []byte, err error) //哈希msg
    GetHash(opts HashOpts) (h hash.Hash, err error) //獲取哈希實(shí)例
    Sign(k Key, digest []byte, opts SignerOpts) (signature []byte, err error) //簽名
    Verify(k Key, signature, digest []byte, opts SignerOpts) (valid bool, err error) //校驗(yàn)簽名
    Encrypt(k Key, plaintext []byte, opts EncrypterOpts) (ciphertext []byte, err error) //加密
    Decrypt(k Key, ciphertext []byte, opts DecrypterOpts) (plaintext []byte, err error) //解密
}
//代碼在bccsp/bccsp.go
3、KeyStore接口(密鑰存儲(chǔ))定義如下: 其實(shí)現(xiàn)是bccsp/sw/fileks.go
type KeyStore interface {
    ReadOnly() bool //密鑰庫(kù)是否只讀,只讀時(shí)StoreKey將失敗
    GetKey(ski []byte) (k Key, err error) //如果SKI通過,返回Key.從相關(guān)文件中加載 
  StoreKey(k Key) (err error) //將Key存儲(chǔ)到密鑰庫(kù)中 sw實(shí)現(xiàn)是寫入相關(guān)文件
}
//代碼在bccsp/keystore.go
bccsp/sw/fileks.go中 StoreKey的實(shí)現(xiàn) 可見相關(guān)key寫入文件
func (ks *fileBasedKeyStore) StoreKey(k bccsp.Key) (err error) {
if ks.readOnly {
return errors.New("Read only KeyStore.")
}
if k == nil {
return errors.New("Invalid key. It must be different from nil.")
}
switch k.(type) {
case *ecdsaPrivateKey:
kk := k.(*ecdsaPrivateKey)
err = ks.storePrivateKey(hex.EncodeToString(k.SKI()), kk.privKey)
if err != nil {
return fmt.Errorf("Failed storing ECDSA private key [%s]", err)
}
case *ecdsaPublicKey:
kk := k.(*ecdsaPublicKey)
err = ks.storePublicKey(hex.EncodeToString(k.SKI()), kk.pubKey)
if err != nil {
return fmt.Errorf("Failed storing ECDSA public key [%s]", err)
}
case *rsaPrivateKey:
kk := k.(*rsaPrivateKey)
err = ks.storePrivateKey(hex.EncodeToString(k.SKI()), kk.privKey)
if err != nil {
return fmt.Errorf("Failed storing RSA private key [%s]", err)
}
case *rsaPublicKey:
kk := k.(*rsaPublicKey)
err = ks.storePublicKey(hex.EncodeToString(k.SKI()), kk.pubKey)
if err != nil {
return fmt.Errorf("Failed storing RSA public key [%s]", err)
}
case *aesPrivateKey:
kk := k.(*aesPrivateKey)
err = ks.storeKey(hex.EncodeToString(k.SKI()), kk.privKey)
if err != nil {
return fmt.Errorf("Failed storing AES key [%s]", err)
}
4、mspconfig的初始化流程圖
其中g(shù)etMspConfig方法比較重要.也一目了然,加載相關(guān)證書存入byte[].最終串行化成json
func getMspConfig(dir string, ID string, sigid *msp.SigningIdentityInfo) (*msp.MSPConfig, error) {
///data/config/hyperledger/fabric/crypto-config/peerOrganizations/org1.ygsoft.com/peers/peer0.org1.ygsoft.com/msp/cacerts
cacertDir := filepath.Join(dir, cacerts)
///data/config/hyperledger/fabric/crypto-config/peerOrganizations/org1.ygsoft.com/peers/peer0.org1.ygsoft.com/msp/admincerts
admincertDir := filepath.Join(dir, admincerts)
// //data/config/hyperledger/fabric/crypto-config/peerOrganizations/org1.ygsoft.com/peers/peer0.org1.ygsoft.com/msp/ntermediatecerts
intermediatecertsDir := filepath.Join(dir, intermediatecerts)
///data/config/hyperledger/fabric/crypto-config/peerOrganizations/org1.ygsoft.com/peers/peer0.org1.ygsoft.com/msp/crls
crlsDir := filepath.Join(dir, crlsfolder)
configFile := filepath.Join(dir, configfilename)
///data/config/hyperledger/fabric/crypto-config/peerOrganizations/org1.ygsoft.com/peers/peer0.org1.ygsoft.com/msp/tlscacerts
tlscacertDir := filepath.Join(dir, tlscacerts)
tlsintermediatecertsDir := filepath.Join(dir, tlsintermediatecerts)
cacerts, err := getPemMaterialFromDir(cacertDir)
if err != nil || len(cacerts) == 0 {
return nil, errors.WithMessage(err, fmt.Sprintf("could not load a valid ca certificate from directory %s", cacertDir))
}
admincert, err := getPemMaterialFromDir(admincertDir)
if err != nil || len(admincert) == 0 {
return nil, errors.WithMessage(err, fmt.Sprintf("could not load a valid admin certificate from directory %s", admincertDir))
}
intermediatecerts, err := getPemMaterialFromDir(intermediatecertsDir)
if os.IsNotExist(err) {
mspLogger.Debugf("Intermediate certs folder not found at [%s]. Skipping. [%s]", intermediatecertsDir, err)
} else if err != nil {
return nil, errors.WithMessage(err, fmt.Sprintf("failed loading intermediate ca certs at [%s]", intermediatecertsDir))
}
tlsCACerts, err := getPemMaterialFromDir(tlscacertDir)
tlsIntermediateCerts := [][]byte{}
if os.IsNotExist(err) {
mspLogger.Debugf("TLS CA certs folder not found at [%s]. Skipping and ignoring TLS intermediate CA folder. [%s]", tlsintermediatecertsDir, err)
} else if err != nil {
return nil, errors.WithMessage(err, fmt.Sprintf("failed loading TLS ca certs at [%s]", tlsintermediatecertsDir))
} else if len(tlsCACerts) != 0 {
tlsIntermediateCerts, err = getPemMaterialFromDir(tlsintermediatecertsDir)
if os.IsNotExist(err) {
mspLogger.Debugf("TLS intermediate certs folder not found at [%s]. Skipping. [%s]", tlsintermediatecertsDir, err)
} else if err != nil {
return nil, errors.WithMessage(err, fmt.Sprintf("failed loading TLS intermediate ca certs at [%s]", tlsintermediatecertsDir))
}
} else {
mspLogger.Debugf("TLS CA certs folder at [%s] is empty. Skipping.", tlsintermediatecertsDir)
}
crls, err := getPemMaterialFromDir(crlsDir)
if os.IsNotExist(err) {
mspLogger.Debugf("crls folder not found at [%s]. Skipping. [%s]", crlsDir, err)
} else if err != nil {
return nil, errors.WithMessage(err, fmt.Sprintf("failed loading crls at [%s]", crlsDir))
}
// Load configuration file
// if the configuration file is there then load it
// otherwise skip it
//加載配置文件  ../msp/config.yaml 存在就加載,不存在就跳過
var ouis []*msp.FabricOUIdentifier
var nodeOUs *msp.FabricNodeOUs
_, err = os.Stat(configFile)
if err == nil {
// load the file, if there is a failure in loading it then
// return an error
raw, err := ioutil.ReadFile(configFile)
if err != nil {
return nil, errors.Wrapf(err, "failed loading configuration file at [%s]", configFile)
}
configuration := Configuration{}
err = yaml.Unmarshal(raw, &configuration)
if err != nil {
return nil, errors.Wrapf(err, "failed unmarshalling configuration file at [%s]", configFile)
}
// Prepare OrganizationalUnitIdentifiers
if len(configuration.OrganizationalUnitIdentifiers) > 0 {
for _, ouID := range configuration.OrganizationalUnitIdentifiers {
f := filepath.Join(dir, ouID.Certificate)
raw, err = readFile(f)
if err != nil {
return nil, errors.Wrapf(err, "failed loading OrganizationalUnit certificate at [%s]", f)
}
oui := &msp.FabricOUIdentifier{
Certificate:                  raw,
OrganizationalUnitIdentifier: ouID.OrganizationalUnitIdentifier,
}
ouis = append(ouis, oui)
}
}
// Prepare NodeOUs
if configuration.NodeOUs != nil && configuration.NodeOUs.Enable {
mspLogger.Info("Loading NodeOUs")
if configuration.NodeOUs.ClientOUIdentifier == nil || len(configuration.NodeOUs.ClientOUIdentifier.OrganizationalUnitIdentifier) == 0 {
return nil, errors.New("Failed loading NodeOUs. ClientOU must be different from nil.")
}
if configuration.NodeOUs.PeerOUIdentifier == nil || len(configuration.NodeOUs.PeerOUIdentifier.OrganizationalUnitIdentifier) == 0 {
return nil, errors.New("Failed loading NodeOUs. PeerOU must be different from nil.")
}
nodeOUs = &msp.FabricNodeOUs{
Enable:             configuration.NodeOUs.Enable,
ClientOUIdentifier: &msp.FabricOUIdentifier{OrganizationalUnitIdentifier: configuration.NodeOUs.ClientOUIdentifier.OrganizationalUnitIdentifier},
PeerOUIdentifier:   &msp.FabricOUIdentifier{OrganizationalUnitIdentifier: configuration.NodeOUs.PeerOUIdentifier.OrganizationalUnitIdentifier},
}
// Read certificates, if defined
// ClientOU
f := filepath.Join(dir, configuration.NodeOUs.ClientOUIdentifier.Certificate)
raw, err = readFile(f)
if err != nil {
mspLogger.Infof("Failed loading ClientOU certificate at [%s]: [%s]", f, err)
} else {
nodeOUs.ClientOUIdentifier.Certificate = raw
}
// PeerOU
f = filepath.Join(dir, configuration.NodeOUs.PeerOUIdentifier.Certificate)
raw, err = readFile(f)
if err != nil {
mspLogger.Debugf("Failed loading PeerOU certificate at [%s]: [%s]", f, err)
} else {
nodeOUs.PeerOUIdentifier.Certificate = raw
}
}
} else {
mspLogger.Debugf("MSP configuration file not found at [%s]: [%s]", configFile, err)
}
// Set FabricCryptoConfig
cryptoConfig := &msp.FabricCryptoConfig{
SignatureHashFamily:            bccsp.SHA2,
IdentityIdentifierHashFunction: bccsp.SHA256,
}
// Compose FabricMSPConfig
fmspconf := &msp.FabricMSPConfig{
Admins:            admincert,
RootCerts:         cacerts,
IntermediateCerts: intermediatecerts,
SigningIdentity:   sigid,
Name:              ID,
OrganizationalUnitIdentifiers: ouis,
RevocationList:                crls,
CryptoConfig:                  cryptoConfig,
TlsRootCerts:                  tlsCACerts,
TlsIntermediateCerts:          tlsIntermediateCerts,
FabricNodeOUs:                 nodeOUs,
}
    //串行化成json格式的byte[] 
fmpsjs, _ := proto.Marshal(fmspconf)
 
//MSPConfig的msp_config.pb.go文件中定義 
    //type MSPConfig struct {
//Type int32 `protobuf:"varint,1,opt,name=type" json:"type,omitempty"`
//Config []byte `protobuf:"bytes,2,opt,name=config,proto3" json:"config,omitempty"`
    //}
mspconf := &msp.MSPConfig{Config: fmpsjs, Type: int32(FABRIC)}
return mspconf, nil
msp/mspimplsetup.go文件中根據(jù)上面生成的mspconf對(duì)證書進(jìn)行了相關(guān)設(shè)置,結(jié)果保存
在/mspimpl.go中的結(jié)體bccspmsp中
func (msp *bccspmsp) preSetupV1(conf *m.FabricMSPConfig) error {
// setup crypto config
if err := msp.setupCrypto(conf); err != nil {
return err
}
// Setup CAs  //設(shè)置ca證書,中間證書等,涉及到x509包。并構(gòu)建相關(guān)identity類。
//根據(jù)證書內(nèi)容加hash后生成identity類
if err := msp.setupCAs(conf); err != nil {
return err
}
// Setup Admins
if err := msp.setupAdmins(conf); err != nil {
return err
}
// Setup CRLs
if err := msp.setupCRLs(conf); err != nil {
return err
}
// Finalize setup of the CAs
if err := msp.finalizeSetupCAs(conf); err != nil {
return err
}
// setup the signer (if present)
if err := msp.setupSigningIdentity(conf); err != nil {
return err
}
// setup TLS CAs
if err := msp.setupTLSCAs(conf); err != nil {
return err
}
// setup the OUs
if err := msp.setupOUs(conf); err != nil {
return err
}
return nil
}


傻 瓜 2018-06-25 09:00 發(fā)表評(píng)論
]]>
Fabric 1.1源代碼分析(3) 系統(tǒng)鏈碼執(zhí)行過程示例(弟弟篇)http://www.tkk7.com/fool/archive/2018/06/13/433279.html傻 瓜傻 瓜Wed, 13 Jun 2018 06:37:00 GMThttp://www.tkk7.com/fool/archive/2018/06/13/433279.htmlhttp://www.tkk7.com/fool/comments/433279.htmlhttp://www.tkk7.com/fool/archive/2018/06/13/433279.html#Feedback0http://www.tkk7.com/fool/comments/commentRss/433279.htmlhttp://www.tkk7.com/fool/services/trackbacks/433279.html
# Fabric 1.1源代碼分析(3) 系統(tǒng)鏈碼執(zhí)行過程
## 1、系統(tǒng)鏈碼執(zhí)行過程
* 以peer channel join -b gensis.block命令為例。該命令結(jié)果是peer節(jié)點(diǎn)加入通道.
這個(gè)命令會(huì)單獨(dú)啟一個(gè)進(jìn)程.在該進(jìn)程中會(huì)構(gòu)建一個(gè)名稱為cscc的鏈碼消息傳到peer節(jié)點(diǎn).
通過grpc調(diào)用最終會(huì)進(jìn)到endorser.go中的ProcessProposal函數(shù)進(jìn)行處理。
參考Fabric 1.1源代碼分析(2)http://www.tkk7.com/fool/archive/2018/06/12/433277.html
系統(tǒng)鏈碼初始化過程,可以找到../shim/handler.go中
的handleTransaction()函數(shù).最終會(huì)調(diào)用res := handler.cc.Invoke(stub).這里的
cc就是importsysccs.go文件中systemChaincodes數(shù)組中的cscc系統(tǒng)鏈碼的.    
Chaincode,其實(shí)例是&cscc.PeerConfiger{},實(shí)現(xiàn)在cscc/configure.go文件中。每個(gè)系統(tǒng)
鏈碼都實(shí)現(xiàn)了這個(gè)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
}
```

* 至此就可以清晰地看到每一個(gè)系統(tǒng)鏈碼都會(huì)啟動(dòng)一對(duì)協(xié)程,通過chan通信。系統(tǒng)鏈碼消息由
shim/handler.go中的函數(shù)處理.并且這里最終調(diào)用各自的具體實(shí)現(xiàn)的Ivoke方法進(jìn)行業(yè)務(wù)處理

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

## 3、小結(jié)

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


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

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

## 1、系統(tǒng)鏈碼

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

## 2、系統(tǒng)鏈碼注冊(cè)
* 在/core/chaincode/shim/interfaces_stable.go中實(shí)現(xiàn)了下面的接口
```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結(jié)構(gòu)體,其中定義了 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文件中對(duì)系統(tǒng)鏈碼進(jìn)行了初始化,并且每個(gè)Chainoce指定了具體實(shí)現(xiàn)
```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
    },
}
```
* 注冊(cè)流程圖
![](systemcoderegist.png)


## 3、系統(tǒng)鏈碼初始化
* 系統(tǒng)注冊(cè)完成后會(huì)對(duì)鏈碼初始化.跟一般chaincode稍有不同的是chaincode在合約里通過grpc與peer節(jié)點(diǎn)交互。
而系統(tǒng)鏈碼則是在協(xié)程里通過chan 實(shí)現(xiàn)交互.下面代碼創(chuàng)建兩個(gè) peerRcvCCSend := make(chan *pb.ChaincodeMessage)
    ccRcvPeerSend := make(chan *pb.ChaincodeMessage) ,是客戶端和服務(wù)端共同的參數(shù)
```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)
    //啟動(dòng)客戶端處理
    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)
    }()
//啟動(dòng)服務(wù)端處理
    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、系統(tǒng)鏈碼的執(zhí)行
...


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

傻 瓜 2018-06-12 14:51 發(fā)表評(píng)論
]]>
開源區(qū)塊鏈Hyperleger Fabric之鏈碼開發(fā)調(diào)試模式在IDE里debug鏈碼http://www.tkk7.com/fool/archive/2018/05/23/433231.html傻 瓜傻 瓜Wed, 23 May 2018 06:17:00 GMThttp://www.tkk7.com/fool/archive/2018/05/23/433231.htmlhttp://www.tkk7.com/fool/comments/433231.htmlhttp://www.tkk7.com/fool/archive/2018/05/23/433231.html#Feedback0http://www.tkk7.com/fool/comments/commentRss/433231.htmlhttp://www.tkk7.com/fool/services/trackbacks/433231.html1,啟動(dòng)order
    orderer start
2, 使用開發(fā)模式啟動(dòng)peer節(jié)點(diǎn)
   peer node start --peer-chaincodedev=true
3,創(chuàng)建通道
4,啟動(dòng)鏈碼程序
這一步可以在IDE里啟動(dòng)鏈碼,這樣就可以debug了
cd examples/chaincode/go/chaincode_example02
go build
CORE_CHAINCODE_LOGLEVEL=debug CORE_PEER_ADDRESS=127.0.0.1:7052 CORE_CHAINCODE_ID_NAME=mycc:0 ./chaincode_example02
5,安裝鏈碼
peer chaincode install -n mycc -v 0 -p github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02
6,初始化鏈碼
peer chaincode instantiate -n mycc -v 0 -c '{"Args":["init","a","100","b","200"]}' -o 127.0.0.1:7050 -C ch1
7,鏈碼調(diào)用和測(cè)試


傻 瓜 2018-05-23 14:17 發(fā)表評(píng)論
]]>
開源區(qū)塊鏈Hyperleger Fabric之通過Composer開發(fā)框架快速搭建開發(fā)環(huán)境http://www.tkk7.com/fool/archive/2018/03/12/433093.html傻 瓜傻 瓜Mon, 12 Mar 2018 08:44:00 GMThttp://www.tkk7.com/fool/archive/2018/03/12/433093.htmlhttp://www.tkk7.com/fool/comments/433093.htmlhttp://www.tkk7.com/fool/archive/2018/03/12/433093.html#Feedback0http://www.tkk7.com/fool/comments/commentRss/433093.htmlhttp://www.tkk7.com/fool/services/trackbacks/433093.html
準(zhǔn)備工作:(自行百度)

開發(fā)環(huán)境必備軟件:

 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   
執(zhí)行install-hlfv1.sh 安裝運(yùn)行fabric1.06版.并運(yùn)行 playground服務(wù) 打開流覽器http://xxxx:8080顯示如下



1,playgroundWeb Browser區(qū)域提供了在頁(yè)面定義模型、測(cè)試模型的能力。并不保存。但可以導(dǎo)出bna文件

2,connection區(qū)域提供了在開發(fā)環(huán)境布署合約,會(huì)生成一個(gè)智能合約的docker運(yùn)行環(huán)境.
3,可以在上圖中上部分的My Business Networks 工作區(qū)點(diǎn)擊虛業(yè)部分Deploy a new business network

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

5,點(diǎn)擊Deploy按鈕后會(huì)發(fā)布一個(gè)合約.并跳到測(cè)試頁(yè)如下圖:



6,在上圖中 Test Tab頁(yè)可以進(jìn)行測(cè)試 ,在Define Tab頁(yè)可以導(dǎo)出bna文件.
7,在第一幅圖中點(diǎn)擊下載按鈕,會(huì)下載一個(gè) .card文件,描述了連接fabric peer節(jié)點(diǎn)等相關(guān)連接信息.記得要導(dǎo) 
PeerAdmin@hlfv1的card和你自己測(cè)試用的card,及bna文件
8,分別執(zhí)行  composer card import -f PeerAdmin.card  ,composer card import -f admin.card  .composer card list 可以查看你導(dǎo)入的card的name信息.

       9,composer-rest-server -c admin@empty-business-network -n always -w true  啟動(dòng)rest服務(wù)默認(rèn)端口3000.

      10,好了,可以體驗(yàn)一下fabric是個(gè)什么玩意了。:) 88!




傻 瓜 2018-03-12 16:44 發(fā)表評(píng)論
]]>
開源區(qū)塊鏈Hyperleger Fabric通過SDK-JAVA動(dòng)態(tài)添加通道http://www.tkk7.com/fool/archive/2018/03/12/433090.html傻 瓜傻 瓜Mon, 12 Mar 2018 03:55:00 GMThttp://www.tkk7.com/fool/archive/2018/03/12/433090.htmlhttp://www.tkk7.com/fool/comments/433090.htmlhttp://www.tkk7.com/fool/archive/2018/03/12/433090.html#Feedback0http://www.tkk7.com/fool/comments/commentRss/433090.htmlhttp://www.tkk7.com/fool/services/trackbacks/433090.html
在閱讀本篇之前需要理解
configtxgen工具使用原理.基本上能跑通
開源區(qū)塊鏈Hyperleger Fabric的SDK-JAVA新手上路指引
中的內(nèi)容。可以參考http://www.tkk7.com/fool/archive/2018/02/01/433032.html.
如果知道通過命令行工具進(jìn)行智能合約的安裝測(cè)試就更好了。fabric中的channel可以理解為泳道。在這個(gè)泳道中可以布署
多個(gè)智能合約。當(dāng)然也可以安裝多個(gè)channel. 順便多一嘴,在智能合約可以調(diào)用另一個(gè)channel中的智能合約中的查詢方法.
通過sdk動(dòng)態(tài)安裝通道的步驟:
1,通過configtxgen命令生成交易通道初始文件.
configtxgen --profile TestSoft --outputCreateChannelTx testsoft.tx --channelID testsoft
2,下載testsoft.tx到本機(jī).
3,sdk安裝通道代碼及解釋
@Override
public boolean installChannel(String channelName) throws IOException, InvalidArgumentException, TransactionException, ProposalException {
// TODO Auto-generated method stub
 String configPath = this.config.getConfigPath();
                         //初始化 ChannelConfiguration 對(duì)象.參數(shù)是通道初始化文件路徑
 ChannelConfiguration channelConfiguration = new ChannelConfiguration(new File(configPath + "/"+channelName + ".tx"));
  //構(gòu)造orderder節(jié)點(diǎn)信息
   String ordererName = orderers.get().get(0).getOrdererName();
Properties ordererProperties = loadOrderProperty(ordererName);
Orderer anOrderer = client.newOrderer(
ordererName,
orderers.get().get(0).getOrdererLocation(), ordererProperties);
       //Create channel that has only one signer that is this orgs peer admin. If channel creation policy needed more signature they would need to be added too.
       Channel channel = client.newChannel(channelName, anOrderer, channelConfiguration, client.getChannelConfigurationSignature(channelConfiguration, fabricOrg.getPeerAdmin()));
                       //構(gòu)造peer節(jié)點(diǎn)信息,并且將peer節(jié)點(diǎn)加入到通道中。peer節(jié)點(diǎn)加入通道后,才能通過該peer節(jié)點(diǎn)中訪問通道中的智能合約
       for (com.ygsoft.fabric.bean.Peers.Peer p : config.getInstallPeers().get()) {
Properties peerProperties = this.loadPeerProperties(p.getPeerName());
Peer peer = client.newPeer(p.getPeerName(),p.getPeerLocation(),peerProperties);
channel.joinPeer(peer);
}
for (int i = 0; i < orderers.get().size(); i++) {
Properties ordererProperties2 = loadOrderProperty(ordererName);
channel.addOrderer(client.newOrderer(
orderers.get().get(i).getOrdererName(),
orderers.get().get(i)
.getOrdererLocation(), ordererProperties2));
}
log.debug("channel.isInitialized() = " + channel.isInitialized());
  channel.initialize();
 return true;
}

知道了手工命令行安裝合約的過程,上面的理解還是比較簡(jiǎn)單的。安裝通道后就可以調(diào)用sdk安裝合約了。













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

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

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

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

public static ChaincodeManager init() throws Exception{
FabricConfig fabricConfig = new FabricConfig("E:/fabricConfig");  //fabricConfig文件夾中包含
                //crypto-config文件夾
Peers peers = new Peers();   //初始化peer節(jié)點(diǎn)
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節(jié)點(diǎn)
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,其它參數(shù),比如chaincode相關(guān)信息可以在peer節(jié)點(diǎn)  peer chaincode list --installed 命令可以查看
可以調(diào)用這個(gè)ChaincodeManager 的query和invoke方法了.

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

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

因?yàn)榫W(wǎng)上有了fabric多機(jī)布署教程,和不完善的示例代碼,這里主要介紹一下其中容易遇到的問題,解決起
來也頗為頭痛和費(fèi)時(shí)。
本貼原地址:http://www.tkk7.com/fool .下一篇區(qū)塊鏈貼子預(yù)告:Fabric的SDK-JAVA動(dòng)態(tài)安裝
Channel













傻 瓜 2018-02-01 09:03 發(fā)表評(píng)論
]]>
springCloud、boot集成elkhttp://www.tkk7.com/fool/archive/2017/10/08/432851.html傻 瓜傻 瓜Sun, 08 Oct 2017 11:15:00 GMThttp://www.tkk7.com/fool/archive/2017/10/08/432851.htmlhttp://www.tkk7.com/fool/comments/432851.htmlhttp://www.tkk7.com/fool/archive/2017/10/08/432851.html#Feedback0http://www.tkk7.com/fool/comments/commentRss/432851.htmlhttp://www.tkk7.com/fool/services/trackbacks/432851.html1,啟動(dòng)elashticsearch
2,logstash/config目錄下新建log.conf文件,其內(nèi)容:
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的日志級(jí)別-->
        </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 發(fā)表評(píng)論
]]>
springboot、mybatis、mycat分庫(kù)實(shí)踐http://www.tkk7.com/fool/archive/2017/10/01/432841.html傻 瓜傻 瓜Sun, 01 Oct 2017 09:40:00 GMThttp://www.tkk7.com/fool/archive/2017/10/01/432841.htmlhttp://www.tkk7.com/fool/comments/432841.htmlhttp://www.tkk7.com/fool/archive/2017/10/01/432841.html#Feedback0http://www.tkk7.com/fool/comments/commentRss/432841.htmlhttp://www.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逆向工程配置文件,這樣就可以自動(dòng)生成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>
     <!--數(shù)據(jù)庫(kù)驅(qū)動(dòng)-->
     <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>
         <!--數(shù)據(jù)庫(kù)鏈接地址賬號(hào)密碼-->
         <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>
         <!--生成對(duì)應(yīng)表及類名 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,數(shù)據(jù)源連接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配置數(shù)據(jù)庫(kù)和分片表分片規(guī)則
<schema name="MYSQL" checkSQLschema="false" sqlMaxLimit="100">
<table name="t_blogger" primaryKey="id" dataNode="dn1" >     </table> 
<!--按需配置分片規(guī)則-->
        <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配置分片規(guī)則
    添加如下規(guī)則 按表的name字段進(jìn)行分片存儲(chǔ)
<tableRule name="mod-long1">
<rule>
<columns>name</columns>
<algorithm>mod-long</algorithm>
</rule>
</tableRule>
備注:內(nèi)容太多,記一下重點(diǎn). 分庫(kù)后連接查詢不在同一個(gè)庫(kù)是查不到數(shù)據(jù)的,真有這需要那就真需要考慮
設(shè)計(jì)是否合理了.


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

自定義一個(gè)annotation,通過這個(gè)注解中的 name查找attribute中的key對(duì)應(yīng)的值 

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

自定義一個(gè)解析器類

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中注冊(cè)自定義的參數(shù)解析器
@Configuration
public class MyWebMvcConfig extends WebMvcConfigurerAdapter{
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
        argumentResolvers.add(new AttributeArgumentResolver());
    }
}


使用方法.
需要在action調(diào)用前向HttpServletRequest中的attribute中注入值 ,可以自定義一個(gè)filter,在filter中進(jìn)行處理
如在filter中處理app傳過來的token驗(yàn)證后取得對(duì)應(yīng)的用戶信息等.下面例子簡(jiǎn)單放入一個(gè)對(duì)象
@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中放入的對(duì)象
        @RequestMapping("/index")
public String index(@AttributeResolve(name="user") Bloggerbh, HttpServletRequest request,Model model) 

嗯,還算優(yōu)雅




傻 瓜 2017-09-29 11:58 發(fā)表評(píng)論
]]>
sbringboot異步執(zhí)行http://www.tkk7.com/fool/archive/2017/09/26/432832.html傻 瓜傻 瓜Tue, 26 Sep 2017 04:26:00 GMThttp://www.tkk7.com/fool/archive/2017/09/26/432832.htmlhttp://www.tkk7.com/fool/comments/432832.htmlhttp://www.tkk7.com/fool/archive/2017/09/26/432832.html#Feedback0http://www.tkk7.com/fool/comments/commentRss/432832.htmlhttp://www.tkk7.com/fool/services/trackbacks/432832.html
import java.util.concurrent.Executor;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
@Configuration
@EnableAsync   //開啟異步任務(wù)支持
public class TaskExcutorConfig implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
// TODO Auto-generated method stub
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setMaxPoolSize(10);
taskExecutor.setQueueCapacity(20);
taskExecutor.setCorePoolSize(5);
taskExecutor.initialize();
return taskExecutor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
// TODO Auto-generated method stub
return null;
}

任務(wù)類或方法

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
//@Async 寫在這里則整個(gè)類的方法都 是異步執(zhí)行
@Service
public class AsynTestService {
@Async   //需要異步執(zhí)行的方法
public void asyncTest() {
for(int i = 0; i < 10;i++) {
System.out.println(i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}


傻 瓜 2017-09-26 12:26 發(fā)表評(píng)論
]]>
springboot文件上傳等雜項(xiàng)http://www.tkk7.com/fool/archive/2017/09/18/432826.html傻 瓜傻 瓜Mon, 18 Sep 2017 03:01:00 GMThttp://www.tkk7.com/fool/archive/2017/09/18/432826.htmlhttp://www.tkk7.com/fool/comments/432826.htmlhttp://www.tkk7.com/fool/archive/2017/09/18/432826.html#Feedback0http://www.tkk7.com/fool/comments/commentRss/432826.htmlhttp://www.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確實(shí)可以攔截,但是afterCompletion在preHandle方法返回false后并
不執(zhí)行,那么只能在preHandle中處理了,比如轉(zhuǎn)向,ajax請(qǐng)求返回內(nèi)容

3,關(guān)于快速跳轉(zhuǎn)
有時(shí)候只是做一個(gè)簡(jiǎn)單的跳轉(zhuǎn),可以集中寫在這里
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;
//其中默認(rèn)配置的 /** 映射到 /static (或/public、/resources、/META-INF/resources) 
//其中默認(rèn)配置的 /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();
}
//快速轉(zhuǎn)向
@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("本次始請(qǐng)求處理時(shí)間為:" + startTime + "ms");
request.setAttribute("startTime", startTime);
if (request.getHeader("x-requested-with") != null
&& request.getHeader("x-requested-with").equalsIgnoreCase("XMLHttpRequest")) {
response.setHeader("sessionstatus", "timeout"); // 響應(yīng)頭設(shè)置session狀態(tài)
} 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("本次請(qǐng)求處理時(shí)間??:" + new Long(endTime - startTime) + "ms");
request.setAttribute("handlingTime", endTime - startTime);
}
}
文件上傳頁(yè)面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 發(fā)表評(píng)論
]]>
springboot中的jsp支持http://www.tkk7.com/fool/archive/2017/09/18/432823.html傻 瓜傻 瓜Mon, 18 Sep 2017 01:22:00 GMThttp://www.tkk7.com/fool/archive/2017/09/18/432823.htmlhttp://www.tkk7.com/fool/comments/432823.htmlhttp://www.tkk7.com/fool/archive/2017/09/18/432823.html#Feedback0http://www.tkk7.com/fool/comments/commentRss/432823.htmlhttp://www.tkk7.com/fool/services/trackbacks/432823.html
       <dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
      </dependency>
   <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>

寫配置類配置jsp支持
@Configuration
public class MyWebAppConfigurer extends WebMvcConfigurerAdapter {

@Bean
public InternalResourceViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
viewResolver.setViewClass(JstlView.class);
return viewResolver;
}

}

所謂零配置。。。 一言難盡


傻 瓜 2017-09-18 09:22 發(fā)表評(píng)論
]]>
js外部調(diào)用更新angularjs的ng-repeat視圖問題 http://www.tkk7.com/fool/archive/2017/09/11/432808.html傻 瓜傻 瓜Mon, 11 Sep 2017 13:37:00 GMThttp://www.tkk7.com/fool/archive/2017/09/11/432808.htmlhttp://www.tkk7.com/fool/comments/432808.htmlhttp://www.tkk7.com/fool/archive/2017/09/11/432808.html#Feedback0http://www.tkk7.com/fool/comments/commentRss/432808.htmlhttp://www.tkk7.com/fool/services/trackbacks/432808.html新table中數(shù)據(jù)就有些麻煩。所以用angularjs重構(gòu)一下。
頁(yè)面中angularjs展示數(shù)據(jù)  
<body   ng-controller="multi"> 
  <table id="baseTable" class="table table-striped table-bordered table-hover" >
<thead>
<tr><th style="width:10%" class="center">標(biāo)題</th>
</tr>
</thead>
               <body   ng-controller="multi">   
                <tbody>  
                         <tr ng-repeat="item in defaultData " >
                             <td class='center hidden-480'>{{item.title}}</td>    
               </tr> 
  </tbody>
            </body>
  </table>
</body>
外部jquery的ajax調(diào)用更新數(shù)據(jù) 
                    var controllerScope = $('body[ng-controller="multi"]').scope();
            controllerScope.defaultData=results;
            controllerScope.$apply();
          
注意:外部js不要?jiǎng)h除了下面這段代碼塊。
                        <tr ng-repeat="item in defaultData " >
                             <td class='center hidden-480'>{{item.title}}</td>    
                 </tr> 


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

思路二:
     規(guī)則引擎比如drools處理一些問題 。
規(guī)則引擎適合于做業(yè)務(wù)規(guī)則頻繁變化的場(chǎng)景.把業(yè)務(wù)規(guī)則抽出來通過規(guī)則引擎來
處理。類似工作流系統(tǒng)的概念。

自定義規(guī)則處理庫(kù):
     一些動(dòng)態(tài)的語(yǔ)言很適合來做這樣的事情。java支持script.Mvel是一個(gè)表達(dá)式語(yǔ)言,drools也支持mvel來處理業(yè)務(wù)規(guī)則.
這里自定義規(guī)則引擎使用Mvel表達(dá)式語(yǔ)言.
      規(guī)則文件示例:
     
<rules>
       <!--rule-set 是一個(gè)規(guī)則集,執(zhí)行規(guī)則 rule1時(shí)會(huì)迭代規(guī)則集里面所有的規(guī)則(mvel-rule)-->
<rule-set name="rule1">
<!-- id是規(guī)則的標(biāo)識(shí),也是默認(rèn)的排序處理順序。exclusive 是排它。如果為true,則當(dāng)前規(guī)則執(zhí)行后,不再執(zhí)行后面的規(guī)則-->
<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可以導(dǎo)入未知jar包并進(jìn)行處理,確實(shí)強(qiáng)大,就有了足夠的靈活性. 自定義規(guī)則庫(kù)源碼及使用示例下載.
本例依賴xstream
1.4.9 ,mvel2.0
自定義規(guī)則庫(kù)除了可以應(yīng)用于一般系統(tǒng)業(yè)務(wù)處理,當(dāng)然也還可以用于大數(shù)據(jù)處理。比如hadoop/spark統(tǒng)計(jì)用戶積分等
如果再定義一套配置規(guī)則的UI。。。好的,業(yè)務(wù)人員可以自己設(shè)置計(jì)算規(guī)則了。








傻 瓜 2017-08-20 14:52 發(fā)表評(píng)論
]]>
架構(gòu)設(shè)計(jì)過程分析小結(jié)http://www.tkk7.com/fool/archive/2017/04/28/432490.html傻 瓜傻 瓜Fri, 28 Apr 2017 06:22:00 GMThttp://www.tkk7.com/fool/archive/2017/04/28/432490.htmlhttp://www.tkk7.com/fool/comments/432490.htmlhttp://www.tkk7.com/fool/archive/2017/04/28/432490.html#Feedback0http://www.tkk7.com/fool/comments/commentRss/432490.htmlhttp://www.tkk7.com/fool/services/trackbacks/432490.html架構(gòu)設(shè)計(jì)過程簡(jiǎn)單總結(jié):架構(gòu)設(shè)計(jì)的驅(qū)動(dòng)力=功能+質(zhì)量+約束.功能即系統(tǒng)要滿足的業(yè)務(wù)需求。質(zhì)量包括運(yùn)行期質(zhì)量和開發(fā)期質(zhì)量. 常見的運(yùn)行期質(zhì)量屬性包括軟件系統(tǒng)的易用性、性能、可伸縮性、持續(xù)可用性、魯棒性、安全性等。開發(fā)期質(zhì)量屬性是開發(fā)人員最為關(guān)心的,要達(dá)到怎樣的目標(biāo)應(yīng)根據(jù)項(xiàng)目的具體情況而定。約束可能是商業(yè)預(yù)算,運(yùn)行環(huán)境,使用人員水平,開發(fā)團(tuán)隊(duì)水平等。架構(gòu)設(shè)計(jì)過程如下:

一,需求收集,分析。

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

二,概念架構(gòu)/概念模型

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

 

 魯棒圖建立概念模型語(yǔ)法:

概念設(shè)計(jì)舉例:


上次談到超市小票如何分析實(shí)體對(duì)象,本次接著舉例如何對(duì)收銀進(jìn)行概念建模



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

促銷活動(dòng)等。


概念架構(gòu)的用途:

1) 可以幫助我們找出領(lǐng)域模型中的實(shí)體對(duì)象。

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

3)初步設(shè)計(jì),魯棒圖是一種初步設(shè)計(jì)技術(shù)。

4)根據(jù)用例和概念設(shè)計(jì)劃分系統(tǒng)、子系統(tǒng)、模塊或者包。借助魯棒圖,初步識(shí)別功能背后的職責(zé),規(guī)劃切分系統(tǒng)的方式。

 

三,關(guān)注非功能性需求,包括運(yùn)行期質(zhì)量和開發(fā)期質(zhì)量。

運(yùn)用目標(biāo)場(chǎng)景決策表對(duì)非功能性需求作出決策.小舉例:

目標(biāo)

場(chǎng)景

決策

易用性

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

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

性能

長(zhǎng)時(shí)間穩(wěn)定運(yùn)行

數(shù)據(jù)庫(kù)集群,服務(wù)應(yīng)用集群                                        

        技術(shù)選型                             需要管理錢箱、打印機(jī)、響應(yīng)速    pos系統(tǒng)使用c/s
                                                度快

 

 

 

四,細(xì)化架構(gòu)。RUP 4+1視圖法則將架構(gòu)需要關(guān)注的不同的點(diǎn)使用不同的視圖表示.從不同的維度對(duì)系統(tǒng)進(jìn)行解讀,從而形成統(tǒng)一軟件過程架構(gòu)描述。

運(yùn)行架構(gòu):

關(guān)心進(jìn)程、線程、同步的相關(guān)設(shè)計(jì),捕捉并發(fā)和同步特征

邏輯架構(gòu):

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

物理架構(gòu):

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

開發(fā)架構(gòu):

描述了在開發(fā)環(huán)境中軟件的靜態(tài)組織結(jié)構(gòu)。即開發(fā)工具下的開發(fā)視圖,描述文件編譯及其依賴關(guān)系。而使用maven管理開發(fā)的項(xiàng)目編譯及依賴關(guān)系結(jié)構(gòu)更加分明。

數(shù)據(jù)架構(gòu):

關(guān)心數(shù)據(jù)的存儲(chǔ)、分布和文件的存放及數(shù)據(jù)的復(fù)制,傳遞,同步。數(shù)據(jù)的存放包括sql,內(nèi)存數(shù)據(jù)庫(kù),nosql數(shù)據(jù)庫(kù)等.

 

邏輯架構(gòu)設(shè)計(jì)舉例:

還是用收銀系統(tǒng)簡(jiǎn)單舉例,收銀系統(tǒng)邏輯架構(gòu)圖如下:



整個(gè)系統(tǒng)劃系統(tǒng)為系統(tǒng),切為兩個(gè)系統(tǒng),一個(gè)收銀員角色處理的業(yè)務(wù),收銀系統(tǒng)。

一個(gè)后臺(tái)管理系統(tǒng)。后臺(tái)管理系統(tǒng)包括用戶管理模塊,基礎(chǔ)資料模塊(產(chǎn)品資料等)

銷售模塊(本例對(duì)銷售單)。另外,因?yàn)槭浙y系統(tǒng)需要和后臺(tái)系統(tǒng)交互,把收銀系統(tǒng)需要使用到的相關(guān)的各模塊封裝成一個(gè)接口模塊,專門處理和收銀系統(tǒng)交互的模塊。系統(tǒng)、模塊之間的通訊方式應(yīng)當(dāng)盡量避免雙向。相互依賴可能會(huì)引發(fā)很多問題。

 

物理架構(gòu)設(shè)計(jì)舉例:

物理架構(gòu)和邏輯架構(gòu)可以相互印證。描述軟件系統(tǒng)的物理布署。



如果考慮運(yùn)行期質(zhì)量比如長(zhǎng)時(shí)間運(yùn)行布署圖可能應(yīng)用做集群。數(shù)據(jù)庫(kù)做集群等。邏輯層layer運(yùn)行在物理層tier之上

 

運(yùn)行架構(gòu)和數(shù)據(jù)架構(gòu)視圖根據(jù)實(shí)際情況可選設(shè)計(jì)





傻 瓜 2017-04-28 14:22 發(fā)表評(píng)論
]]>
主站蜘蛛池模板: 亚洲avav天堂av在线网爱情| 国产精品成人免费观看| 国产精品白浆在线观看免费 | 18禁止看的免费污网站| 亚洲人午夜射精精品日韩| 亚洲中文字幕精品久久| **实干一级毛片aa免费| 亚洲日韩精品一区二区三区无码 | 欧美男同gv免费网站观看| 亚洲av永久无码精品网站| 黄色大片免费网站| 最近最新的免费中文字幕| 久久久久久亚洲精品成人| a色毛片免费视频| 亚洲成av人片在线观看天堂无码| 亚洲色精品VR一区区三区| 亚洲一级毛片免费在线观看| 亚洲爆乳精品无码一区二区三区 | 最近更新免费中文字幕大全| 亚洲av高清在线观看一区二区| 最新亚洲卡一卡二卡三新区| 精品国产污污免费网站aⅴ| 久久久久久亚洲精品| 成人无码精品1区2区3区免费看 | 亚洲国产另类久久久精品黑人 | 国产免费无遮挡精品视频| 亚洲砖码砖专无区2023 | 亚洲在成人网在线看| 久久综合给合久久国产免费| 国产亚洲人成网站观看| 国产精品美女免费视频观看| 亚洲第一网站男人都懂| 黄色片网站在线免费观看| 国产传媒在线观看视频免费观看 | 国产偷国产偷亚洲高清日韩| 精品一区二区三区免费毛片| 日本特黄特色aa大片免费| 亚洲午夜无码久久| 成人男女网18免费视频| 在线精品亚洲一区二区| 18禁超污无遮挡无码免费网站国产|