This paper introduces contract compilation and how to deploy to blockchain Java SDK Call and access the contract on the blockchain.
This tutorial requires users to be familiar with the Linux operating environment, have the basic skills of Java development, be able to use Gradle tools, and be familiar with Solidity syntax.
If you haven't built a blockchain network or downloaded the console, please complete the tutorial first Build the first blockchain network.
This paper records its own application process, for specific reference Develop the first blockchain application
1. Contract development
The following functions are expected:
- Be able to register assets on the blockchain
- Be able to transfer different accounts
- You can query the asset amount of the account
Firstly, the corresponding smart contract needs to be designed to determine the data to be stored in the contract. On this basis, the external interfaces provided by the smart contract are determined. Finally, the specific implementation of each interface is given.
Step 1: design smart contract
Storage design
Provided by FISCO BCOS Contract CRUD interface In the development mode, you can create tables through contracts and add, delete, modify, and query the created tables. For this application, we need to design a table t to store asset management_ Asset, the table fields are as follows:
- Account: primary key, asset account (string type)
- asset_value: asset amount (uint256 type)
Where account is the primary key, i.e. operation t_ The field that needs to be passed in to the asset table. The blockchain queries the matching records in the table according to the primary key field. t_asset means, for example:
interface design
According to the business design objectives, the functions of asset registration, transfer and query need to be realized. The interfaces of the corresponding functions are as follows:
// Query asset amount function select(string account) public constant returns(int256, uint256) // Asset registration function register(string account, uint256 amount) public returns(int256) // Asset transfer function transfer(string from_asset_account, string to_asset_account, uint256 amount) public returns(int256)
Step 2: develop source code
According to the storage and interface design in the first step, we create an Asset smart contract to realize the functions of registration, transfer and query, and introduce a system contract called Table, which provides CRUD interface.
# Enter the console/contracts directory cd ~/fisco/console/contracts/solidity # Create Asset.sol contract file vi Asset.sol # Write the asset.sol contract content to. # And type wq save to exit.
The content of Asset.sol is as follows:
pragma solidity ^0.4.24; import "./Table.sol"; contract Asset { // event event RegisterEvent(int256 ret, string account, uint256 asset_value); event TransferEvent(int256 ret, string from_account, string to_account, uint256 amount); constructor() public { // Create t in constructor_ Asset table createTable(); } function createTable() private { TableFactory tf = TableFactory(0x1001); // Asset management table, key: account, field: asset_ value // |Asset account (primary key) | asset amount| // |-------------------- |-------------------| // | account | asset_value | // |---------------------|-------------------| // // Create table tf.createTable("t_asset", "account", "asset_value"); } function openTable() private returns(Table) { TableFactory tf = TableFactory(0x1001); Table table = tf.openTable("t_asset"); return table; } /* Description: query asset amount by asset account Parameters: account : Asset account Return value: Parameter 1: 0 is returned successfully, and - 1 is returned if the account does not exist Parameter 2: valid when the first parameter is 0, asset amount */ function select(string account) public constant returns(int256, uint256) { // Open table Table table = openTable(); // query Entries entries = table.select(account, table.newCondition()); uint256 asset_value = 0; if (0 == uint256(entries.size())) { return (-1, asset_value); } else { Entry entry = entries.get(0); return (0, uint256(entry.getInt("asset_value"))); } } /* Description: asset registration Parameters: account : Asset account amount : Asset amount Return value: 0 Asset registration succeeded -1 Asset account already exists -2 Other errors */ function register(string account, uint256 asset_value) public returns(int256){ int256 ret_code = 0; int256 ret= 0; uint256 temp_asset_value = 0; // Query whether the account exists (ret, temp_asset_value) = select(account); if(ret != 0) { Table table = openTable(); Entry entry = table.newEntry(); entry.set("account", account); entry.set("asset_value", int256(asset_value)); // insert int count = table.insert(account, entry); if (count == 1) { // success ret_code = 0; } else { // Failure? No permission or other error ret_code = -2; } } else { // Account already exists ret_code = -1; } emit RegisterEvent(ret_code, account, asset_value); return ret_code; } /* Description: asset transfer Parameters: from_account : Transfer asset account to_account : Receiving asset account amount : Transfer amount Return value: 0 Asset transfer succeeded -1 Transfer asset account does not exist -2 Receiving asset account does not exist -3 Insufficient amount -4 Amount overflow -5 Other errors */ function transfer(string from_account, string to_account, uint256 amount) public returns(int256) { // Query transfer asset account information int ret_code = 0; int256 ret = 0; uint256 from_asset_value = 0; uint256 to_asset_value = 0; // Does the transfer account exist? (ret, from_asset_value) = select(from_account); if(ret != 0) { ret_code = -1; // Transfer account does not exist emit TransferEvent(ret_code, from_account, to_account, amount); return ret_code; } // Does the acceptance account exist? (ret, to_asset_value) = select(to_account); if(ret != 0) { ret_code = -2; // The account receiving the asset does not exist emit TransferEvent(ret_code, from_account, to_account, amount); return ret_code; } if(from_asset_value < amount) { ret_code = -3; // Insufficient account amount of transferred assets emit TransferEvent(ret_code, from_account, to_account, amount); return ret_code; } if (to_asset_value + amount < to_asset_value) { ret_code = -4; // Receiving account amount overflow emit TransferEvent(ret_code, from_account, to_account, amount); return ret_code; } Table table = openTable(); Entry entry0 = table.newEntry(); entry0.set("account", from_account); entry0.set("asset_value", int256(from_asset_value - amount)); // Update transfer account int count = table.update(from_account, entry0, table.newCondition()); if(count != 1) { ret_code = -5; // Failure? No permission or other error? emit TransferEvent(ret_code, from_account, to_account, amount); return ret_code; } Entry entry1 = table.newEntry(); entry1.set("account", to_account); entry1.set("asset_value", int256(to_asset_value + amount)); // Update receiving account table.update(to_account, entry1, table.newCondition()); emit TransferEvent(ret_code, from_account, to_account, amount); return ret_code; } }
The table.sol referenced by Asset.sol is already in ~ / fisco/console/contracts/solidity directory. The interface in the system contract file is implemented by FISCO BCOS bottom layer. When a business contract needs to operate the CRUD interface, it is necessary to import the interface contract file. Table.sol contract detailed interface reference here.
Run the ls command and make sure that Asset.sol and Table.sol are in the directory ~ / FISCO / console / contracts / solid.
Step 3: compile smart contract
The smart contract of. sol needs to be compiled into ABI and BIN files before it can be deployed to the blockchain network. With these two files, you can deploy and call contracts with the Java SDK. However, this calling method is relatively cumbersome, and users need to pass the participation analysis results according to the contract abi. Therefore, the compilation tool provided by the console can not only compile ABI and BIN files, but also automatically generate a contract Java class with the same name as the compiled smart contract. This Java class is generated according to ABI to help users resolve parameters and provide methods with the same name. When an application needs to deploy and call a contract, you can call the corresponding method of the contract class and pass in the specified parameters. Using this contract Java class to develop applications can greatly simplify the user's code.
# Create working directory ~ / fisco mkdir -p ~/fisco # Download console cd ~/fisco && curl -#LO https://github.com/FISCO-BCOS/console/releases/download/v2.7.2/download_console.sh && bash download_console.sh # Switch to the fisco/console / directory cd ~/fisco/console/ # If the console version is greater than or equal to 2.8.0, the contract compilation method is as follows: (you can view the script usage through bash sol2java.sh -h command) bash sol2java.sh -p org.fisco.bcos.asset.contract # If the console version is less than 2.8.0, the compilation contract (specify a Java package name parameter later, and you can specify the package name according to the actual project path) is as follows: ./sol2java.sh org.fisco.bcos.asset.contract
After running successfully, java, abi and bin directories will be generated in the console/contracts/sdk directory, as shown below.
# Other irrelevant documents are omitted |-- abi # The generated abi directory stores the abi files generated by the compilation of the solidity contract | |-- Asset.abi | |-- Table.abi |-- bin # The generated bin directory stores the bin file generated by the compilation of the solidity contract | |-- Asset.bin | |-- Table.bin |-- contracts # Store the source code file of the solidity contract, and copy the contract to be compiled to this directory | |-- Asset.sol # The copied Asset.sol contract depends on Table.sol | |-- Table.sol # Contract interface file for system CRUD operation |-- java # Store the compiled package path and Java contract file | |-- org | |--fisco | |--bcos | |--asset | |--contract | |--Asset.java # Java file generated by Asset.sol contract | |--Table.java # Java file generated by Table.sol contract |-- sol2java.sh
The org/fisco/bcos/asset/contract / package path directory is generated under the Java directory. This directory contains two files: Asset.java and Table.java, in which Asset.java is the file required for Java applications to call the Asset.sol contract.
Main interfaces of Asset.java:
package org.fisco.bcos.asset.contract; public class Asset extends Contract { // Asset.sol contract transfer interface generation public TransactionReceipt transfer(String from_account, String to_account, BigInteger amount); // Asset.sol contract register interface generation public TransactionReceipt register(String account, BigInteger asset_value); // Asset.sol contract is generated by the select interface public Tuple2<BigInteger, BigInteger> select(String account) throws ContractException; // Load the Asset contract address and generate the Asset object public static Asset load(String contractAddress, Client client, CryptoKeyPair credential); // Deploy Asset.sol contract and generate Asset object public static Asset deploy(Client client, CryptoKeyPair credential) throws ContractException; }
The load and deploy functions are used to construct the Asset object, and other interfaces are used to call the interfaces of the corresponding solid contract respectively.
The Java files compiled through the compilation tool provided by the console can be directly brought into the files for use in later programming
2. Run a blockchain project
Required dependencies
- Java
Get source code
$ cd ~/fisco $ curl -#LO https://github.com/FISCO-BCOS/LargeFiles/raw/master/tools/asset-app.tar.gz # Extract the Java project asset app $ tar -zxf asset-app.tar.gz
If you cannot download for a long time due to network problems, try adding 199.232.28.133 raw.githubusercontent.com to / etc/hosts, or try curl -#LO https://osp-1257653870.cos.ap-guangzhou.myqcloud.com/FISCO-BCOS/FISCO-BCOS/tools/asset-app.tar.gz
compile
# Switch to project directory $ cd ~/fisco/asset-app # Compile project $ ./gradlew build
After the compilation is successful, the dist directory will be generated under the project root directory. There is an asset in the dist directory_ Run.sh script to simplify project operation. Now start to verify the requirements set at the beginning of this article one by one.
Deploy Asset.sol contract
Note: in the deployment process, refer to the previous article to start the node first
# Enter dist directory $ cd dist $ bash asset_run.sh deploy Deploy Asset successfully, contract address is 0xd09ad04220e40bb8666e885730c8c460091a4775
Contract call
#Registered assets $ bash asset_run.sh register Alice 100000 Register account successfully => account: Alice, value: 100000 $ bash asset_run.sh register Bob 100000 Register account successfully => account: Bob, value: 100000 #Query assets $ bash asset_run.sh query Alice account Alice, value 100000 $ bash asset_run.sh query Bob account Bob, value 100000 #Asset transfer $ bash asset_run.sh transfer Alice Bob 50000 Transfer successfully => from_account: Alice, to_account: Bob, amount: 50000 $ bash asset_run.sh query Alice account Alice, value 50000 $ bash asset_run.sh query Bob account Bob, value 150000
analysis
After compiling with. / gradlew build, the dist directory will be generated in the root directory of the project. There is an asset in the dist directory_ Run.sh script to simplify project operation. bash asset_run.sh deploy can directly deploy the contract, and the following contract operations are also included in the script, such as bash asset_run.sh register Alice 100000
java source code analysis
Note: this part is actually building the downloaded java file. The main purpose here is to understand its working principle
1. Create gradle project 2.SDK related settingsAdd a reference to the FISCO BCOS Java SDK under dependencies in the build.gradle file.
repositories { mavenCentral() maven { allowInsecureProtocol = true url "http://maven.aliyun.com/nexus/content/groups/public/" } maven { allowInsecureProtocol = true url "https://oss.sonatype.org/content/repositories/snapshots" } }
Import Java SDK jar package
testImplementation group: 'junit', name: 'junit', version: '4.12' implementation ('org.fisco-bcos.java-sdk:fisco-bcos-java-sdk:2.8.0')
Modify the build.gradle file and introduce the Spring framework
def spring_version = "4.3.27.RELEASE" List spring = [ "org.springframework:spring-core:$spring_version", "org.springframework:spring-beans:$spring_version", "org.springframework:spring-context:$spring_version", "org.springframework:spring-tx:$spring_version", ] dependencies { testImplementation group: 'junit', name: 'junit', version: '4.12' implementation ("org.fisco-bcos.java-sdk:fisco-bcos-java-sdk:2.8.0") implementation spring }
Create the configuration file applicationContext.xml in the asset app / test / resources directory and write the configuration content. The contents of each configuration item can be referred to Java SDK configuration description , the configuration description takes the toml configuration file as an example, and the configuration item in this example corresponds to this configuration item.
The contents of applicationContext.xml are as follows:
<?xml version="1.0" encoding="UTF-8" ?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd"> <bean id="defaultConfigProperty"> <property name="cryptoMaterial"> <map> <entry key="certPath" value="conf" /> </map> </property> <property name="network"> <map> <entry key="peers"> <list> <value>127.0.0.1:20200</value> <value>127.0.0.1:20201</value> </list> </entry> </map> </property> <property name="account"> <map> <entry key="keyStoreDir" value="account" /> <entry key="accountAddress" value="" /> <entry key="accountFileFormat" value="pem" /> <entry key="password" value="" /> <entry key="accountFilePath" value="" /> </map> </property> <property name="threadPool"> <map> <entry key="channelProcessorThreadSize" value="16" /> <entry key="receiptProcessorThreadSize" value="16" /> <entry key="maxBlockingQueueSize" value="102400" /> </map> </property> </bean> <bean id="defaultConfigOption"> <constructor-arg name="configProperty"> <ref bean="defaultConfigProperty"/> </constructor-arg> </bean> <bean id="bcosSDK"> <constructor-arg name="configOption"> <ref bean="defaultConfigOption"/> </constructor-arg> </bean> </beans>
In the above configuration file, we specified that the value of the certPath bit stored in the certificate is conf. Next, we need to put the SDK certificate used to connect the node into the specified conf directory.
You need to obtain the certificate from nodes/127.0.0.1/sdk and copy it
# Suppose we put the asset app in the ~ / fisco directory and enter the ~ / fisco directory $ cd ~/fisco # Create a folder to place certificates $ mkdir -p asset-app/src/test/resources/conf # Copy the node certificate to the resource directory of the project $ cp -r nodes/127.0.0.1/sdk/* asset-app/src/test/resources/conf # If you run it directly in the IDE, copy the certificate to the resources path $ mkdir -p asset-app/src/main/resources/conf $ cp -r nodes/127.0.0.1/sdk/* asset-app/src/main/resources/conf3. Introduce Java contract
cd ~/fisco # Introduce the compiled contract Java class into the project. cp console/contracts/sdk/java/org/fisco/bcos/asset/contract/Asset.java asset-app/src/main/java/org/fisco/bcos/asset/contract/Asset.java
Create AssetClient.java class in the directory / src/main/java/org/fisco/bcos/asset/client, and deploy and call the contract by calling Asset.java
package org.fisco.bcos.asset.client; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.math.BigInteger; import java.util.List; import java.util.Properties; import org.fisco.bcos.asset.contract.Asset; import org.fisco.bcos.sdk.BcosSDK; import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated.Tuple2; import org.fisco.bcos.sdk.client.Client; import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair; import org.fisco.bcos.sdk.model.TransactionReceipt; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; public class AssetClient { static Logger logger = LoggerFactory.getLogger(AssetClient.class); private BcosSDK bcosSDK; private Client client; private CryptoKeyPair cryptoKeyPair; public void initialize() throws Exception { @SuppressWarnings("resource") ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); bcosSDK = context.getBean(BcosSDK.class); client = bcosSDK.getClient(1); cryptoKeyPair = client.getCryptoSuite().createKeyPair(); client.getCryptoSuite().setCryptoKeyPair(cryptoKeyPair); logger.debug("create client for group1, account address is " + cryptoKeyPair.getAddress()); } public void deployAssetAndRecordAddr() { try { Asset asset = Asset.deploy(client, cryptoKeyPair); System.out.println( " deploy Asset success, contract address is " + asset.getContractAddress()); recordAssetAddr(asset.getContractAddress()); } catch (Exception e) { // TODO Auto-generated catch block // e.printStackTrace(); System.out.println(" deploy Asset contract failed, error message is " + e.getMessage()); } } public void recordAssetAddr(String address) throws FileNotFoundException, IOException { Properties prop = new Properties(); prop.setProperty("address", address); final Resource contractResource = new ClassPathResource("contract.properties"); FileOutputStream fileOutputStream = new FileOutputStream(contractResource.getFile()); prop.store(fileOutputStream, "contract address"); } public String loadAssetAddr() throws Exception { // load Asset contact address from contract.properties Properties prop = new Properties(); final Resource contractResource = new ClassPathResource("contract.properties"); prop.load(contractResource.getInputStream()); String contractAddress = prop.getProperty("address"); if (contractAddress == null || contractAddress.trim().equals("")) { throw new Exception(" load Asset contract address failed, please deploy it first. "); } logger.info(" load Asset address from contract.properties, address is {}", contractAddress); return contractAddress; } public void queryAssetAmount(String assetAccount) { try { String contractAddress = loadAssetAddr(); Asset asset = Asset.load(contractAddress, client, cryptoKeyPair); Tuple2<BigInteger, BigInteger> result = asset.select(assetAccount); if (result.getValue1().compareTo(new BigInteger("0")) == 0) { System.out.printf(" asset account %s, value %s \n", assetAccount, result.getValue2()); } else { System.out.printf(" %s asset account is not exist \n", assetAccount); } } catch (Exception e) { // TODO Auto-generated catch block // e.printStackTrace(); logger.error(" queryAssetAmount exception, error message is {}", e.getMessage()); System.out.printf(" query asset account failed, error message is %s\n", e.getMessage()); } } public void registerAssetAccount(String assetAccount, BigInteger amount) { try { String contractAddress = loadAssetAddr(); Asset asset = Asset.load(contractAddress, client, cryptoKeyPair); TransactionReceipt receipt = asset.register(assetAccount, amount); List<Asset.RegisterEventEventResponse> response = asset.getRegisterEventEvents(receipt); if (!response.isEmpty()) { if (response.get(0).ret.compareTo(new BigInteger("0")) == 0) { System.out.printf( " register asset account success => asset: %s, value: %s \n", assetAccount, amount); } else { System.out.printf( " register asset account failed, ret code is %s \n", response.get(0).ret.toString()); } } else { System.out.println(" event log not found, maybe transaction not exec. "); } } catch (Exception e) { // TODO Auto-generated catch block // e.printStackTrace(); logger.error(" registerAssetAccount exception, error message is {}", e.getMessage()); System.out.printf(" register asset account failed, error message is %s\n", e.getMessage()); } } public void transferAsset(String fromAssetAccount, String toAssetAccount, BigInteger amount) { try { String contractAddress = loadAssetAddr(); Asset asset = Asset.load(contractAddress, client, cryptoKeyPair); TransactionReceipt receipt = asset.transfer(fromAssetAccount, toAssetAccount, amount); List<Asset.TransferEventEventResponse> response = asset.getTransferEventEvents(receipt); if (!response.isEmpty()) { if (response.get(0).ret.compareTo(new BigInteger("0")) == 0) { System.out.printf( " transfer success => from_asset: %s, to_asset: %s, amount: %s \n", fromAssetAccount, toAssetAccount, amount); } else { System.out.printf( " transfer asset account failed, ret code is %s \n", response.get(0).ret.toString()); } } else { System.out.println(" event log not found, maybe transaction not exec. "); } } catch (Exception e) { // TODO Auto-generated catch block // e.printStackTrace(); logger.error(" registerAssetAccount exception, error message is {}", e.getMessage()); System.out.printf(" register asset account failed, error message is %s\n", e.getMessage()); } } public static void Usage() { System.out.println(" Usage:"); System.out.println( "\t java -cp conf/:lib/*:apps/* org.fisco.bcos.asset.client.AssetClient deploy"); System.out.println( "\t java -cp conf/:lib/*:apps/* org.fisco.bcos.asset.client.AssetClient query account"); System.out.println( "\t java -cp conf/:lib/*:apps/* org.fisco.bcos.asset.client.AssetClient register account value"); System.out.println( "\t java -cp conf/:lib/*:apps/* org.fisco.bcos.asset.client.AssetClient transfer from_account to_account amount"); System.exit(0); } public static void main(String[] args) throws Exception { if (args.length < 1) { Usage(); } AssetClient client = new AssetClient(); client.initialize(); switch (args[0]) { case "deploy": client.deployAssetAndRecordAddr(); break; case "query": if (args.length < 2) { Usage(); } client.queryAssetAmount(args[1]); break; case "register": if (args.length < 3) { Usage(); } client.registerAssetAccount(args[1], new BigInteger(args[2])); break; case "transfer": if (args.length < 4) { Usage(); } client.transferAsset(args[1], args[2], new BigInteger(args[3])); break; default: { Usage(); } } System.exit(0); } }Analyze the call of FISCO BCOS Java SDK
- initialization
The main function of the initialization code is to construct Client and CryptoKeyPair objects, which need to be used when creating corresponding contract class objects (calling the deploy or load function of the contract class).
// Initialize in function initialize // Initialize BcosSDK @SuppressWarnings("resource") ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); bcosSDK = context.getBean(BcosSDK.class); // Initialize the Client that can send transactions to group 1 client = bcosSDK.getClient(1); // Randomly generate public-private key pairs for sending transactions cryptoKeyPair = client.getCryptoSuite().createKeyPair(); client.getCryptoSuite().setCryptoKeyPair(cryptoKeyPair); logger.debug("create client for group1, account address is " + cryptoKeyPair.getAddress());
- Construct contract class object
You can use the deploy or load functions to initialize the contract object. The two use scenarios are different. The former is applicable to the initial deployment of the contract, and the latter is used when the contract has been deployed and the contract address is known.
// Deployment contract Asset asset = Asset.deploy(client, cryptoKeyPair); // Load contract address Asset asset = Asset.load(contractAddress, client, cryptoKeyPair);
- Interface call
Use the contract object to call the corresponding interface and process the returned results.
// select interface call Tuple2<BigInteger, BigInteger> result = asset.select(assetAccount); // register interface call TransactionReceipt receipt = asset.register(assetAccount, amount); // transfer interface TransactionReceipt receipt = asset.transfer(fromAssetAccount, toAssetAccount, amount);
Add a script calling AssetClient in the asset app / tool directory_ run.sh.
4. Create scriptAdd a script calling AssetClient in the asset app / tool directory_ run.sh.
#!/bin/bash function usage() { echo " Usage : " echo " bash asset_run.sh deploy" echo " bash asset_run.sh query asset_account " echo " bash asset_run.sh register asset_account asset_amount " echo " bash asset_run.sh transfer from_asset_account to_asset_account amount " echo " " echo " " echo "examples : " echo " bash asset_run.sh deploy " echo " bash asset_run.sh register Asset0 10000000 " echo " bash asset_run.sh register Asset1 10000000 " echo " bash asset_run.sh transfer Asset0 Asset1 11111 " echo " bash asset_run.sh query Asset0" echo " bash asset_run.sh query Asset1" exit 0 } case $1 in deploy) [ $# -lt 1 ] && { usage; } ;; register) [ $# -lt 3 ] && { usage; } ;; transfer) [ $# -lt 4 ] && { usage; } ;; query) [ $# -lt 2 ] && { usage; } ;; *) usage ;; esac java -Djdk.tls.namedGroups="secp256k1" -cp 'apps/*:conf/:lib/*' org.fisco.bcos.asset.client.AssetClient $@5. Logging
Next, configure the log. Create log4j.properties in the asset app / SRC / test / resources directory
### set log levels ### log4j.rootLogger=DEBUG, file ### output the log information to the file ### log4j.appender.file=org.apache.log4j.DailyRollingFileAppender log4j.appender.file.DatePattern='_'yyyyMMddHH'.log' log4j.appender.file.File=./log/sdk.log log4j.appender.file.Append=true log4j.appender.file.filter.traceFilter=org.apache.log4j.varia.LevelRangeFilter log4j.appender.file.layout=org.apache.log4j.PatternLayout log4j.appender.file.layout.ConversionPattern=[%p] [%-d] %C.%M(%L) | %m%n ###output the log information to the console ### log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.Target=System.out log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=[%p] [%-d] %C.%M(%L) | %m%n
Next, specify the copy and compile tasks by configuring the Jar command in gradle. The log library is introduced, and an empty contract.properties file is created in the asset app / SRC / test / resources directory to store the contract address when the application runs.
dependencies { testCompile group: 'junit', name: 'junit', version: '4.12' compile ("org.fisco-bcos.java-sdk:fisco-bcos-java-sdk:2.7.2") compile spring compile ('org.slf4j:slf4j-log4j12:1.7.25') runtime ('org.slf4j:slf4j-log4j12:1.7.25') } jar { destinationDir file('dist/apps') archiveName project.name + '.jar' exclude '**/*.xml' exclude '**/*.properties' exclude '**/*.crt' exclude '**/*.key' doLast { copy { from configurations.runtime into 'dist/lib' } copy { from file('src/test/resources/') into 'dist/conf' } copy { from file('tool/') into 'dist/' } copy { from file('src/test/resources/contract') into 'dist/contract' } } }
So far, we have completed the development of this application. Finally, the directory structure of assert app is as follows:
|-- build.gradle // gradle profile |-- gradle | |-- wrapper | |-- gradle-wrapper.jar // Code implementation for downloading Gradle | |-- gradle-wrapper.properties // The configuration information used by the wrapper, such as the version of gradle |-- gradlew // Shell script for executing wrapper command under Linux or Unix |-- gradlew.bat // Batch script for executing wrapper command under Windows |-- src | |-- main | | |-- java | | | |-- org | | | |-- fisco | | | |-- bcos | | | |-- asset | | | |-- client // Place client call class | | | |-- AssetClient.java | | | |-- contract // Place Java contract class | | | |-- Asset.java | | |-- resources | | |-- conf | | |-- ca.crt | | |-- node.crt | | |-- node.key | | |-- sdk.crt | | |-- sdk.key | | |-- sdk.publickey | | |-- applicationContext.xml // Project profile | | |-- contract.properties // A file that stores the deployment contract address | | |-- log4j.properties // Log profile | | |-- contract //Storage of solidity files | | |-- Asset.sol | | |-- Table.sol | |-- test | |-- resources // Store code resource files | |-- conf | |-- ca.crt | |-- node.crt | |-- node.key | |-- sdk.crt | |-- sdk.key | |-- sdk.publickey | |-- applicationContext.xml // Project profile | |-- contract.properties // A file that stores the deployment contract address | |-- log4j.properties // Log profile | |-- contract //Storage of solidity files | |-- Asset.sol | |-- Table.sol | |-- tool |-- asset_run.sh // Project run script6. Summary
The Java project here is not built actively, but is started through script compilation. Note several places: the configuration of skd is in applicationContext.xml, and the configuration points the certificate to the conf folder. When the contract is introduced, it is the Java file generated before compiling, and is invoked in AssetClient.java to realize relevant functions.