From c8ca3a7ac084c3816092cf7f63dcddc14ad984f3 Mon Sep 17 00:00:00 2001 From: zyt <1543844906@qq.com> Date: Fri, 13 Oct 2023 11:20:37 +0800 Subject: [PATCH 1/2] =?UTF-8?q?refactor:=E6=8F=90=E4=BA=A4=E6=96=B0?= =?UTF-8?q?=E7=9A=84starter?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .circleci/config.yml | 19 - .gitignore | 80 +-- .mvn/wrapper/maven-wrapper.jar | Bin 0 -> 59925 bytes .mvn/wrapper/maven-wrapper.properties | 18 + .travis.yml | 28 - CONTRIBUTING.md | 65 -- Changelog.md | 8 - LICENSE | 201 +++++++ README.md | 235 +++----- build.gradle | 97 --- doc/CONTRIBUTING_CN.md | 28 - doc/images/WeChatQR.jpeg | Bin 39004 -> 0 bytes gradle/wrapper/gradle-wrapper.jar | Bin 59203 -> 0 bytes gradle/wrapper/gradle-wrapper.properties | 6 - gradlew | 188 ------ gradlew.bat | 100 ---- mvnw | 316 ++++++++++ mvnw.cmd | 188 ++++++ pom.xml | 180 ++++++ release_note.txt | 1 - settings.gradle | 2 - src/main/contracts/HelloWorld.sol | 22 - .../java/org/example/demo/Application.java | 12 - .../org/example/demo/config/BcosConfig.java | 19 - .../example/demo/config/ContractConfig.java | 12 - .../example/demo/config/SdkBeanConfig.java | 97 --- .../org/example/demo/config/SystemConfig.java | 14 - .../demo/constants/ContractConstants.java | 31 - .../demo/controller/HelloController.java | 27 - .../example/demo/model/CommonResponse.java | 25 - .../demo/model/bo/HelloWorldSetInputBO.java | 20 - .../demo/service/HelloWorldService.java | 52 -- src/main/java/zyt/fiscobcos/FManager.java | 54 ++ .../java/zyt/fiscobcos/FiscoBcosInject.java | 44 ++ .../java/zyt/fiscobcos/FiscoBcosRegister.java | 101 ++++ .../zyt/fiscobcos/annotion/EnableDeploy.java | 14 + .../zyt/fiscobcos/annotion/EnableScan.java | 26 + .../zyt/fiscobcos/client/FiscoClient.java | 57 ++ .../zyt/fiscobcos/common/CommonClient.java | 139 +++++ .../config/FiscoBcosConfigProperties.java | 31 + .../zyt/fiscobcos/contract/MyContract.java | 557 ++++++++++++++++++ .../deploy/DeployAnnotationContract.java | 55 ++ .../fiscobcos/deploy/DeployFileContract.java | 48 ++ .../zyt/fiscobcos/entity/ResponseData.java | 67 +++ .../fiscobcos/utils/PackageScannerUtil.java | 88 +++ .../java/zyt/fiscobcos/utils/SpringUtils.java | 121 ++++ src/main/resources/META-INF/spring.factories | 2 + ...ot.autoconfigure.AutoConfiguration.imports | 2 + src/main/resources/abi/HelloWorld.abi | 1 - src/main/resources/application.properties | 15 - src/main/resources/banner.txt | 8 + src/main/resources/bin/HelloWorld.bin | 1 - src/main/resources/bin/HelloWorldSM.bin | 1 - src/main/resources/clog.ini | 9 - src/main/resources/conf/cert.cnf | 29 - src/main/resources/conf/clog.ini | 9 - src/main/resources/contracts/My.sol | 95 +++ src/test/java/org/example/demo/Demos.java | 53 -- ...BcosSpringbootStarterApplicationTests.java | 13 + .../testController/GrxxController.java | 43 ++ 60 files changed, 2582 insertions(+), 1192 deletions(-) delete mode 100644 .circleci/config.yml create mode 100644 .mvn/wrapper/maven-wrapper.jar create mode 100644 .mvn/wrapper/maven-wrapper.properties delete mode 100644 .travis.yml delete mode 100644 CONTRIBUTING.md delete mode 100644 Changelog.md create mode 100644 LICENSE delete mode 100644 build.gradle delete mode 100644 doc/CONTRIBUTING_CN.md delete mode 100644 doc/images/WeChatQR.jpeg delete mode 100644 gradle/wrapper/gradle-wrapper.jar delete mode 100644 gradle/wrapper/gradle-wrapper.properties delete mode 100755 gradlew delete mode 100644 gradlew.bat create mode 100644 mvnw create mode 100644 mvnw.cmd create mode 100644 pom.xml delete mode 100644 release_note.txt delete mode 100644 settings.gradle delete mode 100644 src/main/contracts/HelloWorld.sol delete mode 100644 src/main/java/org/example/demo/Application.java delete mode 100644 src/main/java/org/example/demo/config/BcosConfig.java delete mode 100644 src/main/java/org/example/demo/config/ContractConfig.java delete mode 100644 src/main/java/org/example/demo/config/SdkBeanConfig.java delete mode 100644 src/main/java/org/example/demo/config/SystemConfig.java delete mode 100644 src/main/java/org/example/demo/constants/ContractConstants.java delete mode 100644 src/main/java/org/example/demo/controller/HelloController.java delete mode 100644 src/main/java/org/example/demo/model/CommonResponse.java delete mode 100644 src/main/java/org/example/demo/model/bo/HelloWorldSetInputBO.java delete mode 100644 src/main/java/org/example/demo/service/HelloWorldService.java create mode 100644 src/main/java/zyt/fiscobcos/FManager.java create mode 100644 src/main/java/zyt/fiscobcos/FiscoBcosInject.java create mode 100644 src/main/java/zyt/fiscobcos/FiscoBcosRegister.java create mode 100644 src/main/java/zyt/fiscobcos/annotion/EnableDeploy.java create mode 100644 src/main/java/zyt/fiscobcos/annotion/EnableScan.java create mode 100644 src/main/java/zyt/fiscobcos/client/FiscoClient.java create mode 100644 src/main/java/zyt/fiscobcos/common/CommonClient.java create mode 100644 src/main/java/zyt/fiscobcos/config/FiscoBcosConfigProperties.java create mode 100644 src/main/java/zyt/fiscobcos/contract/MyContract.java create mode 100644 src/main/java/zyt/fiscobcos/deploy/DeployAnnotationContract.java create mode 100644 src/main/java/zyt/fiscobcos/deploy/DeployFileContract.java create mode 100644 src/main/java/zyt/fiscobcos/entity/ResponseData.java create mode 100644 src/main/java/zyt/fiscobcos/utils/PackageScannerUtil.java create mode 100644 src/main/java/zyt/fiscobcos/utils/SpringUtils.java create mode 100644 src/main/resources/META-INF/spring.factories create mode 100644 src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports delete mode 100644 src/main/resources/abi/HelloWorld.abi delete mode 100644 src/main/resources/application.properties create mode 100644 src/main/resources/banner.txt delete mode 100644 src/main/resources/bin/HelloWorld.bin delete mode 100644 src/main/resources/bin/HelloWorldSM.bin delete mode 100644 src/main/resources/clog.ini delete mode 100644 src/main/resources/conf/cert.cnf delete mode 100644 src/main/resources/conf/clog.ini create mode 100644 src/main/resources/contracts/My.sol delete mode 100644 src/test/java/org/example/demo/Demos.java create mode 100644 src/test/java/zyt/fiscobcos/BcosSpringbootStarterApplicationTests.java create mode 100644 src/test/java/zyt/fiscobcos/testController/GrxxController.java diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index 19934df..0000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,19 +0,0 @@ -version: 2.1 -jobs: - build: - working_directory: /spring-boot-starter - docker: - - image: centos:7 - environment: - PATH=$PATH:/usr/bin - steps: - - run: - name: Setup dependencies - command: | - yum install -y epel-release centos-release-scl which python python-devel - yum install -y git openssl-devel openssl java java-devel - - checkout - - run: - name: Compile - command: | - bash gradlew build diff --git a/.gitignore b/.gitignore index 6bc6ed1..549e00a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,53 +1,33 @@ -# Created by .ignore support plugin (hsz.mobi) -### Java template -*.class - -# Mobile Tools for Java (J2ME) -.mtj.tmp/ - -# Package Files # -*.war -*.ear - -# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml -hs_err_pid* -### Gradle template -.gradle -/build -/log -/logs - -*/out/ -out/ -dist/ -gradle.properties - -# Ignore Gradle GUI config -gradle-app.setting - -# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) -!gradle-wrapper.jar - -# Cache of project -.gradletasknamecache - -# Work around https://youtrack.jetbrains.com/issue/IDEA-116898 -# gradle/wrapper/gradle-wrapper.properties - -.idea -*.iml -*.crt -*.key -src/test/resources/solidity/* -src/test/java/org/fisco/bcos/temp/* -# OS X -.DS_Store - -/target - -# eclipse +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated .classpath +.factorypath .project -.settings/ -bin/ +.settings +.springBeans +.sts4-cache +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..bf82ff01c6cdae4a1bb754a6e062954d77ac5c11 GIT binary patch literal 59925 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

dy!05UMhSKsK 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 VCNKd3JGtOvEm(5t0lFyE{{i--k}m)N literal 0 HcmV?d00001 diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000..ca5ab4b --- /dev/null +++ b/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,18 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.7/apache-maven-3.8.7-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 0bd1f07..0000000 --- a/.travis.yml +++ /dev/null @@ -1,28 +0,0 @@ -# safelist -branches: - only: - - /.*/ - -matrix: - fast_finish: true - include: - - os: linux - dist: xenial - sudo: required - -language: java -jdk: - - openjdk8 - -script: | - - curl -LO https://raw.githubusercontent.com/FISCO-BCOS/FISCO-BCOS/master/tools/build_chain.sh && chmod u+x build_chain.sh - bash <(curl -s https://raw.githubusercontent.com/FISCO-BCOS/FISCO-BCOS/master/tools/ci/download_bin.sh) -b dev - echo "127.0.0.1:4 agency1 1,2,3" > ipconf - ./build_chain.sh -e bin/fisco-bcos -f ipconf -p 30300,20200,8545 - ./nodes/127.0.0.1/start_all.sh - ./nodes/127.0.0.1/fisco-bcos -v - cp nodes/127.0.0.1/sdk/* src/main/resources/ - ./gradlew clean verGJF - ./gradlew clean build - ./gradlew clean test diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index d870dcb..0000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,65 +0,0 @@ -English / [中文](doc/CONTRIBUTING_CN.md) - -# Contributing and Review Guidelines - -All contributions are welcome! - -## Branching - -Our branching method is [git-flow](https://jeffkreeftmeijer.com/git-flow/) - -- **master**: Latest stable branch -- **dev**: Stable branch waiting for release(merge to master) -- **feature-xxxx**: A developing branch of a new feature named xxxx -- **bugfix-xxxx**: A branch to fix the bug named xxxx - -## How to - -### Issue - -Go to [issues page](https://github.com/FISCO-BCOS/spring-boot-starter/issues) - -### Fix bugs - -1. **Fork** this repo -2. **Create** a new branch named **bugfix-xxxx** forked from your repo's **master** branch -3. **Fix** the bug -4. **Test** the fixed code -5. Make **pull request** back to this repo's **dev** branch -6. Wait the community to review the code -7. Merged(**Bug fixed**) - -### Develop a new feature - -1. **Fork** this repo -2. **Create** a new branch named **feature-xxxx** forked from your repo's **dev** branch -3. **Coding** in feature-xxxx -4. **Pull** this repo's dev branch to your feature-xxxx constantly -5. **Test** your code -6. Make **pull request** back to this repo's dev branch -7. Wait the community to review the code -8. Merged !!!! - -## Code formatting - -Execute the task `googleJavaFormat` to format all *.java files in the project -``` -./gradlew goJF -``` -Execute the task `verifyGoogleJavaFormat` to verify that all *.java files are formatted properly -``` -./gradlew verGJF -``` - -## Continous integration - -**Continous integration platform** - -* travis-ci: [![Build Status](https://travis-ci.org/FISCO-BCOS/spring-boot-starter.svg?branch=master)](https://travis-ci.org/FISCO-BCOS/spring-boot-starter) - - -**Code quality** - -* CodeFactor: [![CodeFactor](https://www.codefactor.io/repository/github/fisco-bcos/spring-boot-starter/badge)](https://www.codefactor.io/repository/github/fisco-bcos/spring-boot-starter) - - diff --git a/Changelog.md b/Changelog.md deleted file mode 100644 index babc3e5..0000000 --- a/Changelog.md +++ /dev/null @@ -1,8 +0,0 @@ -### v1.0.0 - -(2021-05-20) - -* Add - -1. 提供java sdk 版本的FISCO BCOS区块链应用开发的基本框架和基本的测试案例 - diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md index e253ea8..57ae432 100644 --- a/README.md +++ b/README.md @@ -1,162 +1,95 @@ -# spring-boot-starter - -本示例项目基于Java SDK + Gradle + SpringBoot方式来调用智能合约。 - -## 前置条件 - -搭建FISCO BCOS 单群组区块链(Air版本),具体步骤[参考这里](https://fisco-bcos-doc.readthedocs.io/zh_CN/latest/docs/tutorial/air/build_chain.html) 。 - -## 下载spring-boot-starter、证书拷贝 - -```shell -git clone https://github.com/FISCO-BCOS/spring-boot-starter.git +# bcos-springboot-starter +本示例项目基于Java SDK + Maven + SpringBoot方式来调用智能合约。 +## 一.项目结构 +annotion:存放注解 +client:fiscobcos客户端,客户端默认提供了crud方法,如果有自定义的方法,继承此类即可,如果想使用此类的方法,在编写智能合约的时候,函数的名称必须为:insert,queryById,updateById,removeById。 +common:提供合约的基础方法 +config:项目相关配置 +contract:生成合约编译后的java程序 +deploy:部署合约方法 +entity:存放实体类 +utils:工具类 +## 二.核心类介绍 +FManager:通过该类可以拿到FiscoClient和BcosSDK实例,通过这两个对象可以对合约进行相关操作。 +## 三.使用方法 +### 1. 下载依赖 ``` - -进入spring-boot-starter项目 - -```shell -cd spring-boot-starter + + com.gitee.zhangyutong + bcos-springboot-starter + 3.0.1-Beta + ``` - -请将证书拷贝到src/main/resources/conf目录下。 - -## 配置连接节点 - -请修改application.properties,该文件包含如下信息: - -```yml -### Java sdk configuration -cryptoMaterial.certPath=conf -network.peers[0]=127.0.0.1:20200 - #network.peers[1]=127.0.0.1:20201 - - ### System configuration -system.groupId=group0 -system.hexPrivateKey= - - ### Springboot configuration -server.port=8080 +### 2. 配置配置文件 +在application.yml文件中加入以下配置: +```yaml +fisco: + peers: + - ip:端口 + enabled: false + basePackages: ``` - -其中: - -- Java SDK configuration配置部分与 [Java SDK](https://fisco-bcos-doc.readthedocs.io/zh_CN/latest/docs/develop/sdk/java_sdk/config.html)一致。就本例而言,用户需要: - - 请将network.peers更换成实际的链节点监听地址。 - - cryptoMaterial.certPath设为conf - -- System configuration配置部分,需要配置: - - system.hexPrivateKey是16进制的私钥明文,可运行Demos.java中的`keyGeneration`生成(文件路径:src/test/java/org/example/demo/Demos.java)。该配置允许为空,此时系统会随机生成一个私钥。 - - system.groupId设为目标群组,默认为group0 - -Demos.java 代码如下:(**以项目最新文件为准**) - +下面对配置字段做下说明: +peers:配置fiscobcos的节点,可配置多个 +enabled:是否部署合约 +basePackages:合约包路径,需要结合enabled字段使用,当enabled为true时,根据包路径进行合约的部署。 +### 3.编写controller代码 +controller主要有核心代码: ```java -package org.example.demo; - -import java.util.Arrays; -import org.example.demo.constants.ContractConstants; -import org.fisco.bcos.sdk.client.Client; -import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair; -import org.fisco.bcos.sdk.crypto.keypair.ECDSAKeyPair; -import org.fisco.bcos.sdk.crypto.keypair.SM2KeyPair; -import org.fisco.bcos.sdk.model.TransactionReceipt; -import org.fisco.bcos.sdk.transaction.manager.AssembleTransactionProcessor; -import org.fisco.bcos.sdk.transaction.manager.TransactionProcessorFactory; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; - -@SpringBootTest -@RunWith(SpringRunner.class) -public class Demos { + FiscoClient fiscoClient = FManager.getFiscoClient(); +``` +首先需要拿到客户端,使用客户端可以对智能合约进行crud操作。下面对fiscoClient四个方法进行说明: +#### (1)queryById +此方法有三个参数:第一个参数为查询的id,第二个参数为合约的名称,项目在自动部署的时候默认使用类名作为合约名称,第三个参数为合约的类。 +### (2)insert +此方法有三个参数:第一个参数为插入的list信息,list的第一个值参数为主键,后面是需要新增的值,其他两个参数同queryById。 +### (3)updateById +此方法共有一个参数,接收list信息,list集合的第一个值为修改的主键,后面为修改的值。 +### (4)removeById +此方法共一个参数,根据id删除数据。 +### (5)下面给出一个案例供参考: +```java +@RestController +public class GrxxController { + + @GetMapping("/query/{id}") + public ResponseData queryById(@PathVariable("id") String id) throws Exception { + FiscoClient fiscoClient = FManager.getFiscoClient(); + TransactionReceipt transactionReceipt = (TransactionReceipt) fiscoClient.queryById(id,"My", My.class); + String output = transactionReceipt.getOutput(); + return ResponseData.success(fiscoClient.decodeMethodAndGetOutputAbiObjectParser(false,output,"selectById")); + } - @Autowired private Client client; + @PostMapping("/insert") + public ResponseData insert(@RequestBody List value) throws Exception { + FiscoClient fiscoClient = FManager.getFiscoClient(); + fiscoClient.insert(value,"My", My.class); + return ResponseData.success("新增成功"); + } - @Test - public void keyGeneration() throws Exception { - // ECDSA key generation - CryptoKeyPair ecdsaKeyPair = new ECDSAKeyPair().generateKeyPair(); - System.out.println("ecdsa private key :" + ecdsaKeyPair.getHexPrivateKey()); - System.out.println("ecdsa public key :" + ecdsaKeyPair.getHexPublicKey()); - System.out.println("ecdsa address :" + ecdsaKeyPair.getAddress()); - // SM2 key generation - CryptoKeyPair sm2KeyPair = new SM2KeyPair().generateKeyPair(); - System.out.println("sm2 private key :" + sm2KeyPair.getHexPrivateKey()); - System.out.println("sm2 public key :" + sm2KeyPair.getHexPublicKey()); - System.out.println("sm2 address :" + sm2KeyPair.getAddress()); - } + @PutMapping("/update") + public ResponseData updateById(@RequestBody List value) throws Exception { + FiscoClient fiscoClient = FManager.getFiscoClient(); + fiscoClient.updateById(value,"My", My.class); + return ResponseData.success("修改成功"); + } - @Test - public void deploy() throws Exception { - AssembleTransactionProcessor txProcessor = - TransactionProcessorFactory.createAssembleTransactionProcessor( - client, client.getCryptoSuite().getCryptoKeyPair()); - String abi = ContractConstants.HelloWorldAbi; - String bin = ContractConstants.HelloWorldBinary; - TransactionReceipt receipt = - txProcessor.deployAndGetResponse(abi, bin, Arrays.asList()).getTransactionReceipt(); - if (receipt.isStatusOK()) { - System.out.println("Contract Address:" + receipt.getContractAddress()); - } else { - System.out.println("Status code:" + receipt.getStatus() + "-" + receipt.getStatusMsg()); + @DeleteMapping("/remove/{id}") + public ResponseData removeById(@PathVariable("id") String id) throws Exception { + FiscoClient fiscoClient = FManager.getFiscoClient(); + fiscoClient.removeById(id,"My", My.class); + return ResponseData.success("删除成功"); } - } } ``` +## 四.补充 +### 1. +项目提供了两种方法实现合约的自动部署 +#### (1)配置配置文件部署 +需要配置enabled和basePackages字段,然后再智能合约的java代码类上加上@EnableDeploy注解,可实现合约的自动部署。 +#### (2)使用注解实现合约的部署 +在springboot的启动类上加上@EnableScan注解,并配置packages,可实现合约的自动部署。 +### 2.所有的合约都是基于内存部署 +### 3.本项目基于fisco-bcos-java-sdk3.4.0开发 +### 4.FiscoClient的方法是基于合约编写,不同的合约FiscoClient的一些基本方法可能不适用,需要自己编写。继承FiscoClient -## 编译和运行 - -您可以在idea内直接运行,也可以编译成可执行jar包后运行。以编译jar包方式为例: - -```shell -cd spring-boot-starter -bash gradlew bootJar -cd dist -``` - -会在dist目录生成spring-boot-starter-exec.jar,可执行此jar包: - -```shell -java -jar spring-boot-starter-exec.jar -``` - -随后,即可访问相关接口。 - -set示例: - -```shell -curl http://127.0.0.1:8080/hello/set?n=hello -``` - -返回示例(表示交易哈希): - -```shell -0x1c8b283daef12b38632e8a6b8fe4d798e053feb5128d9eaf2be77c324645763b -``` - -get示例: - -```shell -curl http://127.0.0.1:8080/hello/get -``` - -返回示例: - -```json -["hello"] -``` - -## 加入我们的社区 - -**FISCO BCOS开源社区**是国内活跃的开源社区,社区长期为机构和个人开发者提供各类支持与帮助。已有来自各行业的数千名技术爱好者在研究和使用FISCO BCOS。如您对FISCO BCOS开源技术及应用感兴趣,欢迎加入社区获得更多支持与帮助。 - -![](https://raw.githubusercontent.com/FISCO-BCOS/LargeFiles/master/images/QR_image.png) - -## 相关链接 - -- FISCO BCOS: [FISCO BCOS文档](https://fisco-bcos-doc.readthedocs.io/zh_CN/latest/docs/introduction.html)。 -- Java Sdk: [JavaSdk文档](https://fisco-bcos-doc.readthedocs.io/zh_CN/latest/docs/develop/sdk/java_sdk/index.html)。 -- SpringBoot文档: [Spring Boot](https://spring.io/guides/gs/spring-boot/)。 -- Maven工程示例:[maven示例](https://github.com/FISCO-BCOS/spring-boot-crud)。 \ No newline at end of file diff --git a/build.gradle b/build.gradle deleted file mode 100644 index 4658ce6..0000000 --- a/build.gradle +++ /dev/null @@ -1,97 +0,0 @@ -plugins { - id 'org.springframework.boot' version '2.6.1' - id 'io.spring.dependency-management' version '1.0.11.RELEASE' - id 'com.github.sherter.google-java-format' version '0.8' -} - -apply plugin: 'java' -apply plugin: 'eclipse' -apply plugin: 'idea' -apply plugin: 'maven' - -sourceCompatibility = 1.8 -targetCompatibility = 1.8 -group = 'org.example' -version = '1.0.0-SNAPSHOT' - - -repositories { - mavenLocal() - mavenCentral() - maven { url "http://maven.aliyun.com/nexus/content/groups/public/"} - maven { url "https://oss.sonatype.org/content/repositories/snapshots" } - maven { url "https://oss.sonatype.org/service/local/staging/deploy/maven2"} -} - -configurations { - compileOnly { - extendsFrom annotationProcessor - } - all { - } -} - -configurations.all { - resolutionStrategy.cacheChangingModulesFor 0, 'seconds' -} - -def log4j_version="2.18.0" -List logger = [ - "org.apache.logging.log4j:log4j-api:$log4j_version", - // "org.apache.logging.log4j:log4j-core:$log4j_version", - // "org.apache.logging.log4j:log4j-slf4j-impl:$log4j_version", - "org.apache.logging.log4j:log4j-to-slf4j:$log4j_version", - // "org.apache.logging.log4j:log4j-web:$log4j_version" -] - -dependencies { - implementation 'junit:junit:4.13.1' - compile logger - compile ('org.fisco-bcos.java-sdk:fisco-bcos-java-sdk:3.0.0') - compile ('org.springframework.boot:spring-boot-starter-web') - compileOnly ('org.projectlombok:lombok') - annotationProcessor ('org.projectlombok:lombok') - - testImplementation('org.springframework.boot:spring-boot-starter-test') { - exclude group: 'org.junit.vintage', module: 'junit-vintage-engine' - } - testImplementation ('org.junit.jupiter:junit-jupiter-api:5.6.1') - testRuntimeOnly ('org.junit.jupiter:junit-jupiter-engine:5.6.1') -} - - -sourceSets { - main { - java { - srcDir 'src/main/java' - } - resources { - srcDir 'src/main/resources' - } - } -} -test { - useJUnitPlatform() -} - -bootJar { - destinationDir file('dist') - archiveName project.name + '-exec.jar' - doLast { - copy { - from file('src/main/resources') - into 'dist' - } - } -} - -googleJavaFormat { - options style: 'AOSP' - source = sourceSets*.allJava - include '**/*.java' -} - -clean { - println "delete ${projectDir}/dist" - delete "${projectDir}/dist" -} diff --git a/doc/CONTRIBUTING_CN.md b/doc/CONTRIBUTING_CN.md deleted file mode 100644 index 32092a4..0000000 --- a/doc/CONTRIBUTING_CN.md +++ /dev/null @@ -1,28 +0,0 @@ -[English](../CONTRIBUTING.md) / 中文 - -# 贡献代码 - -非常感谢能有心为FISCO-BCOS社区贡献代码! - -## 代码格式化 - -执行任务 `googleJavaFormat`格式化java文件。 -``` -./gradlew goJF -``` -执行任务 `verifyGoogleJavaFormat`验证java文件是否格式化完成 -``` -./gradlew verGJF -``` - -## 持续集成(CI) - -持续集成框架 - -* travis-ci: [![Build Status](https://travis-ci.org/FISCO-BCOS/spring-boot-starter.svg?branch=master)](https://travis-ci.org/FISCO-BCOS/spring-boot-starter) - - -代码质量 -* CodeFactor: [![CodeFactor](https://www.codefactor.io/repository/github/fisco-bcos/spring-boot-starter/badge)](https://www.codefactor.io/repository/github/fisco-bcos/spring-boot-starter) - - diff --git a/doc/images/WeChatQR.jpeg b/doc/images/WeChatQR.jpeg deleted file mode 100644 index ad29323ad1c3076c740d106ee65f0d131a29d3c3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 39004 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 ORaMddC%@N|7ymz0JaK3M diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index e708b1c023ec8b20f512888fe07c5bd3ff77bb8f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 59203 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

K7UpUK$>l@ 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 E2O(~oYXATM diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 84dc51e..0000000 --- a/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,6 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -#distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-bin.zip -distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-bin.zip -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew deleted file mode 100755 index 83f2acf..0000000 --- a/gradlew +++ /dev/null @@ -1,188 +0,0 @@ -#!/usr/bin/env sh - -# -# Copyright 2015 the original author or authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -############################################################################## -## -## Gradle start up script for UN*X -## -############################################################################## - -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" - -warn () { - echo "$*" -} - -die () { - echo - echo "$*" - echo - exit 1 -} - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=$((i+1)) - done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac -fi - -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=$(save "$@") - -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" - -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" -fi - -exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat deleted file mode 100644 index 24467a1..0000000 --- a/gradlew.bat +++ /dev/null @@ -1,100 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/mvnw b/mvnw new file mode 100644 index 0000000..8a8fb22 --- /dev/null +++ b/mvnw @@ -0,0 +1,316 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /usr/local/etc/mavenrc ] ; then + . /usr/local/etc/mavenrc + fi + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + export JAVA_HOME="`/usr/libexec/java_home`" + else + export JAVA_HOME="/Library/Java/Home" + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`\\unset -f command; \\command -v java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=`cd "$wdir/.."; pwd` + fi + # end of workaround + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +BASE_DIR=`find_maven_basedir "$(pwd)"` +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found .mvn/wrapper/maven-wrapper.jar" + fi +else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." + fi + if [ -n "$MVNW_REPOURL" ]; then + jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" + else + jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" + fi + while IFS="=" read key value; do + case "$key" in (wrapperUrl) jarUrl="$value"; break ;; + esac + done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Downloading from: $jarUrl" + fi + wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + if $cygwin; then + wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` + fi + + if command -v wget > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found wget ... using wget" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + else + wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found curl ... using curl" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl -o "$wrapperJarPath" "$jarUrl" -f + else + curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f + fi + + else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Falling back to using Java to download" + fi + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaClass=`cygpath --path --windows "$javaClass"` + fi + if [ -e "$javaClass" ]; then + if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Compiling MavenWrapperDownloader.java ..." + fi + # Compiling the Java class + ("$JAVA_HOME/bin/javac" "$javaClass") + fi + if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + # Running the downloader + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Running MavenWrapperDownloader.java ..." + fi + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +if [ "$MVNW_VERBOSE" = true ]; then + echo $MAVEN_PROJECTBASEDIR +fi +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + $MAVEN_DEBUG_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" \ + "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/mvnw.cmd b/mvnw.cmd new file mode 100644 index 0000000..1d8ab01 --- /dev/null +++ b/mvnw.cmd @@ -0,0 +1,188 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM https://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* +if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" + +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %DOWNLOAD_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% ^ + %JVM_CONFIG_MAVEN_PROPS% ^ + %MAVEN_OPTS% ^ + %MAVEN_DEBUG_OPTS% ^ + -classpath %WRAPPER_JAR% ^ + "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ + %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" +if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%"=="on" pause + +if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% + +cmd /C exit /B %ERROR_CODE% diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..bb61540 --- /dev/null +++ b/pom.xml @@ -0,0 +1,180 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.7.15 + + + com.gitee.zhangyutong + bcos-springboot-starter + 3.0.1-Beta + bcos-springboot-starter + 基于fiscobcos java sdk封装的starter + + 1.8 + https://gitee.com/zhangyutong/fiscobcos-springboot-starter.git + ossrh + 5.8.22 + 3.4.0 + 4.8.162 + + + + + + zhangyutong + 1543844906@qq.com + ${projectUrl} + + + + ${projectUrl} + + + The Apache Software License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + repo,manual + + + + ${projectUrl} + ${projectUrl} + ${projectUrl} + + + + ${serverId} + OSS Snapshots Repository + https://s01.oss.sonatype.org/content/repositories/snapshots/ + + + ${serverId} + OSS Staging Repository + https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/ + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + + org.apache.maven.plugins + maven-source-plugin + 2.2.1 + + + attach-sources + + jar-no-fork + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.9.1 + + -Xdoclint:none + true + UTF-8 + UTF-8 + UTF-8 + false + + + + attach-javadocs + + jar + + + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.5 + + + sign-artifacts + verify + + sign + + + + + + org.sonatype.plugins + nexus-staging-maven-plugin + 1.6.7 + true + + ${serverId} + https://s01.oss.sonatype.org/ + true + + + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + io.github.classgraph + classgraph + ${classgraph.version} + + + + org.springframework.boot + spring-boot-devtools + runtime + true + + + org.springframework.boot + spring-boot-configuration-processor + true + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-test + test + + + org.fisco-bcos.java-sdk + fisco-bcos-java-sdk + ${fiscoBcos.sdk.version} + + + cn.hutool + hutool-all + ${hutool.version} + + + + + diff --git a/release_note.txt b/release_note.txt deleted file mode 100644 index 0ec25f7..0000000 --- a/release_note.txt +++ /dev/null @@ -1 +0,0 @@ -v1.0.0 diff --git a/settings.gradle b/settings.gradle deleted file mode 100644 index c369064..0000000 --- a/settings.gradle +++ /dev/null @@ -1,2 +0,0 @@ -rootProject.name = 'spring-boot-starter' - diff --git a/src/main/contracts/HelloWorld.sol b/src/main/contracts/HelloWorld.sol deleted file mode 100644 index 61f0964..0000000 --- a/src/main/contracts/HelloWorld.sol +++ /dev/null @@ -1,22 +0,0 @@ -pragma solidity ^0.4.2; - -contract HelloWorld{ - string name; - - - function set(string n){ - emit test(n); - name = n; - } - - event test(string a); - - function HelloWorld(){ - name = "Hello, World!"; - } - - function get()constant returns(string){ - return name; - } - -} \ No newline at end of file diff --git a/src/main/java/org/example/demo/Application.java b/src/main/java/org/example/demo/Application.java deleted file mode 100644 index 467056b..0000000 --- a/src/main/java/org/example/demo/Application.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.example.demo; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class Application { - - public static void main(String[] args) { - SpringApplication.run(Application.class, args); - } -} diff --git a/src/main/java/org/example/demo/config/BcosConfig.java b/src/main/java/org/example/demo/config/BcosConfig.java deleted file mode 100644 index f3836cd..0000000 --- a/src/main/java/org/example/demo/config/BcosConfig.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.example.demo.config; - -import java.util.List; -import java.util.Map; -import lombok.Data; -import org.fisco.bcos.sdk.v3.config.model.AmopTopic; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.context.annotation.Configuration; - -@Data -@Configuration -@ConfigurationProperties -public class BcosConfig { - private Map cryptoMaterial; - public Map> network; - public List amop; - public Map account; - public Map threadPool; -} diff --git a/src/main/java/org/example/demo/config/ContractConfig.java b/src/main/java/org/example/demo/config/ContractConfig.java deleted file mode 100644 index 2e274d6..0000000 --- a/src/main/java/org/example/demo/config/ContractConfig.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.example.demo.config; - -import lombok.Data; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.context.annotation.Configuration; - -@Data -@Configuration -@ConfigurationProperties(prefix = "contract") -public class ContractConfig { - private String helloWorldAddress; -} diff --git a/src/main/java/org/example/demo/config/SdkBeanConfig.java b/src/main/java/org/example/demo/config/SdkBeanConfig.java deleted file mode 100644 index 5b88534..0000000 --- a/src/main/java/org/example/demo/config/SdkBeanConfig.java +++ /dev/null @@ -1,97 +0,0 @@ -package org.example.demo.config; - -import java.math.BigInteger; -import java.util.Arrays; -import java.util.Map; -import lombok.extern.slf4j.Slf4j; -import org.example.demo.constants.ContractConstants; -import org.fisco.bcos.sdk.v3.BcosSDK; -import org.fisco.bcos.sdk.v3.client.Client; -import org.fisco.bcos.sdk.v3.config.ConfigOption; -import org.fisco.bcos.sdk.v3.config.model.ConfigProperty; -import org.fisco.bcos.sdk.v3.model.CryptoType; -import org.fisco.bcos.sdk.v3.model.TransactionReceipt; -import org.fisco.bcos.sdk.v3.transaction.manager.AssembleTransactionProcessor; -import org.fisco.bcos.sdk.v3.transaction.manager.TransactionProcessorFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -@Configuration -@Slf4j -public class SdkBeanConfig { - - @Autowired private SystemConfig systemConfig; - - @Autowired private BcosConfig bcosConfig; - - @Autowired private ContractConfig contractConfig; - - @Bean - public Client client() throws Exception { - ConfigProperty property = new ConfigProperty(); - configNetwork(property); - configCryptoMaterial(property); - - ConfigOption configOption = new ConfigOption(property); - Client client = new BcosSDK(configOption).getClient(systemConfig.getGroupName()); - - BigInteger blockNumber = client.getBlockNumber().getBlockNumber(); - if (log.isInfoEnabled()) { - log.info("Chain connect successful. Current block number {}", blockNumber); - } - - configCryptoKeyPair(client); - if (log.isInfoEnabled()) { - log.info( - "Your account is Gm:{}, address:{}", - client.getCryptoSuite().cryptoTypeConfig == 1, - client.getCryptoSuite().getCryptoKeyPair().getAddress()); - } - - if (contractConfig.getHelloWorldAddress() == null - || contractConfig.getHelloWorldAddress().isEmpty()) { - contractConfig.setHelloWorldAddress(deploy(client)); - } - return client; - } - - private String deploy(Client client) throws Exception { - AssembleTransactionProcessor txProcessor = - TransactionProcessorFactory.createAssembleTransactionProcessor( - client, client.getCryptoSuite().getCryptoKeyPair()); - String abi = ContractConstants.HelloWorldAbi; - String bin = - (client.getCryptoSuite().getCryptoTypeConfig() == CryptoType.ECDSA_TYPE) - ? ContractConstants.HelloWorldBinary - : ContractConstants.HelloWorldGmBinary; - TransactionReceipt receipt = - txProcessor.deployAndGetResponse(abi, bin, Arrays.asList()).getTransactionReceipt(); - if (receipt.isStatusOK()) { - return receipt.getContractAddress(); - } else { - throw new RuntimeException("Deploy failed"); - } - } - - public void configNetwork(ConfigProperty configProperty) { - Map peers = bcosConfig.getNetwork(); - configProperty.setNetwork(peers); - } - - public void configCryptoMaterial(ConfigProperty configProperty) { - Map cryptoMaterials = bcosConfig.getCryptoMaterial(); - configProperty.setCryptoMaterial(cryptoMaterials); - } - - public void configCryptoKeyPair(Client client) { - if (systemConfig.getHexPrivateKey() == null || systemConfig.getHexPrivateKey().isEmpty()) { - return; - } - if (systemConfig.getHexPrivateKey().startsWith("0x") - || systemConfig.getHexPrivateKey().startsWith("0X")) { - systemConfig.setHexPrivateKey(systemConfig.getHexPrivateKey().substring(2)); - } - client.getCryptoSuite().setCryptoKeyPair(client.getCryptoSuite().getCryptoKeyPair()); - } -} diff --git a/src/main/java/org/example/demo/config/SystemConfig.java b/src/main/java/org/example/demo/config/SystemConfig.java deleted file mode 100644 index 6bf58db..0000000 --- a/src/main/java/org/example/demo/config/SystemConfig.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.example.demo.config; - -import lombok.Data; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.context.annotation.Configuration; - -@Data -@Configuration -@ConfigurationProperties(prefix = "system") -public class SystemConfig { - private String groupName = "group0"; - - private String hexPrivateKey; -} diff --git a/src/main/java/org/example/demo/constants/ContractConstants.java b/src/main/java/org/example/demo/constants/ContractConstants.java deleted file mode 100644 index 5f1c64f..0000000 --- a/src/main/java/org/example/demo/constants/ContractConstants.java +++ /dev/null @@ -1,31 +0,0 @@ -package org.example.demo.constants; - -public class ContractConstants { - public static final String HelloWorldAbi; - - public static final String HelloWorldBinary; - - public static final String HelloWorldGmBinary; - - static { - try { - HelloWorldAbi = - org.apache.commons.io.IOUtils.toString( - Thread.currentThread() - .getContextClassLoader() - .getResource("abi/HelloWorld.abi")); - HelloWorldBinary = - org.apache.commons.io.IOUtils.toString( - Thread.currentThread() - .getContextClassLoader() - .getResource("bin/HelloWorld.bin")); - HelloWorldGmBinary = - org.apache.commons.io.IOUtils.toString( - Thread.currentThread() - .getContextClassLoader() - .getResource("bin/HelloWorldSM.bin")); - } catch (Exception e) { - throw new RuntimeException(e); - } - } -} diff --git a/src/main/java/org/example/demo/controller/HelloController.java b/src/main/java/org/example/demo/controller/HelloController.java deleted file mode 100644 index 9a731f4..0000000 --- a/src/main/java/org/example/demo/controller/HelloController.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.example.demo.controller; - -import org.example.demo.model.bo.HelloWorldSetInputBO; -import org.example.demo.service.HelloWorldService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequestMapping("hello") -public class HelloController { - - @Autowired private HelloWorldService service; - - @GetMapping("set") - public String set(@RequestParam("n") String n) throws Exception { - HelloWorldSetInputBO input = new HelloWorldSetInputBO(n); - return service.set(input).getTransactionReceipt().getTransactionHash(); - } - - @GetMapping("get") - public String get() throws Exception { - return (String) service.get().getResults().get(0).getValue(); - } -} diff --git a/src/main/java/org/example/demo/model/CommonResponse.java b/src/main/java/org/example/demo/model/CommonResponse.java deleted file mode 100644 index 01c5d71..0000000 --- a/src/main/java/org/example/demo/model/CommonResponse.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.example.demo.model; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Data -@NoArgsConstructor -@AllArgsConstructor -public class CommonResponse { - - public static final String OK_CODE = "0"; - - private String code; - private String message; - private Object data; - - public static CommonResponse ok(Object data) { - return new CommonResponse(OK_CODE, "", data); - } - - public static CommonResponse fail(String code, Exception ex) { - return new CommonResponse(code, ex.getMessage(), null); - } -} diff --git a/src/main/java/org/example/demo/model/bo/HelloWorldSetInputBO.java b/src/main/java/org/example/demo/model/bo/HelloWorldSetInputBO.java deleted file mode 100644 index b18129f..0000000 --- a/src/main/java/org/example/demo/model/bo/HelloWorldSetInputBO.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.example.demo.model.bo; - -import java.util.ArrayList; -import java.util.List; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Data -@NoArgsConstructor -@AllArgsConstructor -public class HelloWorldSetInputBO { - private String n; - - public List toArgs() { - List args = new ArrayList(); - args.add(n); - return args; - } -} diff --git a/src/main/java/org/example/demo/service/HelloWorldService.java b/src/main/java/org/example/demo/service/HelloWorldService.java deleted file mode 100644 index 0ff44e1..0000000 --- a/src/main/java/org/example/demo/service/HelloWorldService.java +++ /dev/null @@ -1,52 +0,0 @@ -package org.example.demo.service; - -import java.util.Arrays; -import javax.annotation.PostConstruct; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.example.demo.config.ContractConfig; -import org.example.demo.constants.ContractConstants; -import org.example.demo.model.bo.HelloWorldSetInputBO; -import org.fisco.bcos.sdk.v3.client.Client; -import org.fisco.bcos.sdk.v3.transaction.manager.AssembleTransactionProcessor; -import org.fisco.bcos.sdk.v3.transaction.manager.TransactionProcessorFactory; -import org.fisco.bcos.sdk.v3.transaction.model.dto.CallResponse; -import org.fisco.bcos.sdk.v3.transaction.model.dto.TransactionResponse; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -@Service -@NoArgsConstructor -@Data -public class HelloWorldService { - - private String address; - - @Autowired private Client client; - - @Autowired private ContractConfig contractConfig; - - AssembleTransactionProcessor txProcessor; - - @PostConstruct - public void init() throws Exception { - this.txProcessor = - TransactionProcessorFactory.createAssembleTransactionProcessor( - this.client, this.client.getCryptoSuite().getCryptoKeyPair()); - this.address = contractConfig.getHelloWorldAddress(); - } - - public TransactionResponse set(HelloWorldSetInputBO input) throws Exception { - return this.txProcessor.sendTransactionAndGetResponse( - this.address, ContractConstants.HelloWorldAbi, "set", input.toArgs()); - } - - public CallResponse get() throws Exception { - return this.txProcessor.sendCall( - this.client.getCryptoSuite().getCryptoKeyPair().getAddress(), - this.address, - ContractConstants.HelloWorldAbi, - "get", - Arrays.asList()); - } -} diff --git a/src/main/java/zyt/fiscobcos/FManager.java b/src/main/java/zyt/fiscobcos/FManager.java new file mode 100644 index 0000000..01e5035 --- /dev/null +++ b/src/main/java/zyt/fiscobcos/FManager.java @@ -0,0 +1,54 @@ +package zyt.fiscobcos; + + +import org.fisco.bcos.sdk.v3.BcosSDK; +import org.fisco.bcos.sdk.v3.config.model.ConfigProperty; +import zyt.fiscobcos.client.FiscoClient; +import zyt.fiscobcos.config.FiscoBcosConfigProperties; + + +/** + * @author zyt + * @date 2023/10/09 + * 全局管理类,可以拿到fiscoBcos相关组件 + */ +public class FManager { + + public volatile static FiscoBcosConfigProperties fiscoBcosConfigProperties; + public static void setFiscoBcosConfigConfigProperty(FiscoBcosConfigProperties fiscoBcosConfigProperties) { + FManager.fiscoBcosConfigProperties = fiscoBcosConfigProperties; + } + + public static FiscoBcosConfigProperties getFiscoBcosConfigProperties() { + return fiscoBcosConfigProperties; + } + + public volatile static ConfigProperty configProperty; + public static void setConfigProperty(ConfigProperty configProperty) { + + FManager.configProperty = configProperty; + } + + public static ConfigProperty getConfigProperty() { + return configProperty; + } + + public volatile static FiscoClient fiscoClient; + public static void setFiscoClient(FiscoClient fiscoClient) { + FManager.fiscoClient = fiscoClient; + } + + public static FiscoClient getFiscoClient() { + return fiscoClient; + } + + public volatile static BcosSDK bcosSDK; + public static void setBcosSDK(BcosSDK bcosSDK) { + FManager.bcosSDK = bcosSDK; + } + + public static BcosSDK getBcosSDK() { + return bcosSDK; + } + +} diff --git a/src/main/java/zyt/fiscobcos/FiscoBcosInject.java b/src/main/java/zyt/fiscobcos/FiscoBcosInject.java new file mode 100644 index 0000000..5b6694a --- /dev/null +++ b/src/main/java/zyt/fiscobcos/FiscoBcosInject.java @@ -0,0 +1,44 @@ +package zyt.fiscobcos; + + +import org.fisco.bcos.sdk.v3.BcosSDK; +import org.springframework.beans.factory.annotation.Autowired; +import zyt.fiscobcos.client.FiscoClient; +import zyt.fiscobcos.config.FiscoBcosConfigProperties; + +/** + * @author zyt + * @date 2023/10/09 + * FiscoBcos注入类 + */ +public class FiscoBcosInject { + + /** + * 配置文件 + * @param fiscoBcosConfigProperties + */ + public FiscoBcosInject( + @Autowired(required = false) FiscoBcosConfigProperties fiscoBcosConfigProperties + ) { + FManager.setFiscoBcosConfigConfigProperty(fiscoBcosConfigProperties); + } + + /** + * 客户端注入 + * @param fiscoClient + */ + @Autowired(required = false) + public void setFiscoClient(FiscoClient fiscoClient) { + FManager.setFiscoClient(fiscoClient); + } + + /** + * sdk注入 + * @param bcosSDK + */ + @Autowired(required = false) + public void setBcosSDK(BcosSDK bcosSDK) { + FManager.setBcosSDK(bcosSDK); + } + +} diff --git a/src/main/java/zyt/fiscobcos/FiscoBcosRegister.java b/src/main/java/zyt/fiscobcos/FiscoBcosRegister.java new file mode 100644 index 0000000..17f1d2c --- /dev/null +++ b/src/main/java/zyt/fiscobcos/FiscoBcosRegister.java @@ -0,0 +1,101 @@ +package zyt.fiscobcos; + + +import org.fisco.bcos.sdk.v3.BcosSDK; +import org.fisco.bcos.sdk.v3.codec.ContractCodec; +import org.fisco.bcos.sdk.v3.config.ConfigOption; +import org.fisco.bcos.sdk.v3.config.model.ConfigProperty; +import org.fisco.bcos.sdk.v3.crypto.CryptoSuite; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.DependsOn; +import zyt.fiscobcos.client.FiscoClient; +import zyt.fiscobcos.config.FiscoBcosConfigProperties; +import zyt.fiscobcos.deploy.DeployFileContract; +import zyt.fiscobcos.deploy.DeployAnnotationContract; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author zyt + * @date 2023/10/09 + * FiscoBcos相关对象注册,具体见官网:https://fisco-bcos-documentation.readthedocs.io/zh_CN/latest/docs/sdk/java_sdk/index.html + */ +public class FiscoBcosRegister { + + /** + * 配置文件注册 + * @return + */ + @Bean + @ConfigurationProperties(prefix = "fisco") + public FiscoBcosConfigProperties fiscoBcosConfigProperties() { + return new FiscoBcosConfigProperties(); + } + + /** + * 配置fiscobcos的配置项 + * @return + */ + @Bean + @DependsOn("fiscoBcosConfigProperties") + public ConfigProperty configProperty() { + ConfigProperty configProperty = new ConfigProperty(); + FiscoBcosConfigProperties fiscoBcosConfigProperties = FManager.getFiscoBcosConfigProperties(); + Map map = new HashMap<>(); + map.put("certPath", fiscoBcosConfigProperties.getCertPath()); + configProperty.setCryptoMaterial(map); + + Map netWork = new HashMap<>(); + netWork.put("peers", fiscoBcosConfigProperties.getPeers()); + configProperty.setNetwork(netWork); + + Map Account = new HashMap<>(); + Account.put("keyStoreDir", fiscoBcosConfigProperties.getKeyStoreDir()); + Account.put("accountAddress", fiscoBcosConfigProperties.getAccountAddress()); + Account.put("accountFileFormat", fiscoBcosConfigProperties.getAccountFileFormat()); + Account.put("password", fiscoBcosConfigProperties.getPassword()); + Account.put("accountFilePath", fiscoBcosConfigProperties.getAccountFilePath()); + configProperty.setAccount(Account); + + Map ThreadPool = new HashMap<>(); + ThreadPool.put("channelProcessorThreadSize", fiscoBcosConfigProperties.getChannelProcessorThreadSize()); + ThreadPool.put("receiptProcessorThreadSize", fiscoBcosConfigProperties.getReceiptProcessorThreadSize()); + ThreadPool.put("maxBlockingQueueSize", fiscoBcosConfigProperties.getMaxBlockingQueueSize()); + configProperty.setThreadPool(ThreadPool); + return configProperty; + } + + @Bean + @DependsOn("configProperty") + public ConfigOption configOption(ConfigProperty configProperty) throws Exception { + return new ConfigOption(configProperty); + } + + @Bean + @DependsOn("configOption") + public BcosSDK bcosSDK(ConfigOption configOption) { + return new BcosSDK(configOption); + } + + @Bean + @DependsOn("bcosSDK") + public FiscoClient fiscoClient() { + return new FiscoClient(); + } + + @Bean + @DependsOn("fiscoClient") + public DeployFileContract deployFileContract() { + return new DeployFileContract(); + } + + @Bean + @DependsOn("fiscoClient") + public DeployAnnotationContract packageContractScanner() { + return new DeployAnnotationContract(); + } + + +} diff --git a/src/main/java/zyt/fiscobcos/annotion/EnableDeploy.java b/src/main/java/zyt/fiscobcos/annotion/EnableDeploy.java new file mode 100644 index 0000000..8a6a15a --- /dev/null +++ b/src/main/java/zyt/fiscobcos/annotion/EnableDeploy.java @@ -0,0 +1,14 @@ +package zyt.fiscobcos.annotion; + +import java.lang.annotation.*; + +/** + * 此注解配合配置文件中basePackages使用,在合约类添加此注解,配置文件配置包名,实现扫描 + * @author zyt + * @date 2023/09/28 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +@Documented +public @interface EnableDeploy { +} diff --git a/src/main/java/zyt/fiscobcos/annotion/EnableScan.java b/src/main/java/zyt/fiscobcos/annotion/EnableScan.java new file mode 100644 index 0000000..7756fbf --- /dev/null +++ b/src/main/java/zyt/fiscobcos/annotion/EnableScan.java @@ -0,0 +1,26 @@ +package zyt.fiscobcos.annotion; + +import java.lang.annotation.*; + +/** + * 将此注解放在springboot的启动类上,实现自动部署合约 + * @author zyt + * @date 2023/09/28 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +@Documented +public @interface EnableScan { + + /** + * 默认值,目前不用 + * @return + */ + String value() default ""; + + /** + * 扫描合约所在的包 + * @return + */ + String[] packages() default {}; +} diff --git a/src/main/java/zyt/fiscobcos/client/FiscoClient.java b/src/main/java/zyt/fiscobcos/client/FiscoClient.java new file mode 100644 index 0000000..3555f90 --- /dev/null +++ b/src/main/java/zyt/fiscobcos/client/FiscoClient.java @@ -0,0 +1,57 @@ +package zyt.fiscobcos.client; + +import zyt.fiscobcos.common.CommonClient; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.reflect.Method; +import java.util.List; + +/** + * 这个类封装了一些通用的方法,如果想用这个类的方法,合约名字必须按照如下insert,queryById,updateById,removeById, + * 在solidity中function名称必须是insert,queryById,updateById,removeById + */ +public class FiscoClient extends CommonClient { + + public static final Logger logger = LoggerFactory.getLogger(FiscoClient.class.getName()); + + public void insert(List value,String contractName,Class clazz) throws Exception { + + Object contract = getContractMap().get(contractName); + Method method = clazz.getMethod("insert",List.class); + Object obj = method.invoke(contract,value); + logger.info("调用CRUDClient的insert方法"); + logger.info("结果:{}", obj); + } + + + public Object queryById(String id,String contractName,Class clazz) throws Exception { + + Object contract = getContractMap().get(contractName); + Method method = clazz.getMethod("selectById",String.class); + Object obj = method.invoke(contract,id); + logger.info("调用CRUDClient的query方法"); + logger.info("结果:{}", obj); + return obj; + + } + + public void updateById(List value,String contractName,Class clazz) throws Exception{ + Object contract = getContractMap().get(contractName); + Method method = clazz.getMethod("updateById",List.class); + Object obj = method.invoke(contract,value); + logger.info("调用CRUDClient的edit方法"); + logger.info("结果:{}", obj); + } + + public void removeById(String id,String contractName,Class clazz) throws Exception { + + Object contract = getContractMap().get(contractName); + Method method = clazz.getMethod("removeById",String.class); + Object obj = method.invoke(contract,id); + logger.info("调用CRUDClient的remove方法"); + logger.info("结果:{}", obj); + + } + +} diff --git a/src/main/java/zyt/fiscobcos/common/CommonClient.java b/src/main/java/zyt/fiscobcos/common/CommonClient.java new file mode 100644 index 0000000..3672d6a --- /dev/null +++ b/src/main/java/zyt/fiscobcos/common/CommonClient.java @@ -0,0 +1,139 @@ +package zyt.fiscobcos.common; + + +import org.fisco.bcos.sdk.v3.BcosSDK; +import org.fisco.bcos.sdk.v3.client.Client; +import org.fisco.bcos.sdk.v3.client.protocol.response.*; +import org.fisco.bcos.sdk.v3.codec.ContractCodec; +import org.fisco.bcos.sdk.v3.codec.ContractCodecException; +import org.fisco.bcos.sdk.v3.codec.datatypes.Type; +import org.fisco.bcos.sdk.v3.codec.datatypes.Utf8String; +import org.fisco.bcos.sdk.v3.codec.wrapper.ABIObject; +import org.fisco.bcos.sdk.v3.crypto.CryptoSuite; +import org.fisco.bcos.sdk.v3.crypto.keypair.CryptoKeyPair; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import zyt.fiscobcos.FManager; +import zyt.fiscobcos.contract.MyContract; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * @Author: zyt + * @Description:此类提供一个发布合约的方法,并提供了基本实现方法,可以继承此类实现自己的方法 + * @Date: Created in 16:29 2021/1/20 + */ +public abstract class CommonClient { + + public static final Logger logger = LoggerFactory.getLogger(CommonClient.class.getName()); + + public CommonClient() { + } + + private Map contractMap = new ConcurrentHashMap<>(); + + @SuppressWarnings("unchecked") + public void deploy(String contractName, Class clazz, BcosSDK sdk) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + String groupId = FManager.getFiscoBcosConfigProperties().getGroupId(); + // 为群组初始化client + Client client = sdk.getClient(groupId); + // 向群组部署合约 + CryptoKeyPair cryptoKeyPair = client.getCryptoSuite().getCryptoKeyPair(); + Method method = clazz.getMethod("deploy", Client.class, CryptoKeyPair.class); + T result = (T) method.invoke(null, client, cryptoKeyPair); + logger.info("执行CommonClient的deploy方法"); + logger.info("部署合约 {} 成功:{}", contractName, result); + contractMap.put(contractName, result); + } + + public List decodeMethodAndGetOutputAbiObjectParser(boolean isWasm, String output, String methodName) throws ContractCodecException { + List result = new ArrayList<>(); + CryptoSuite cryptoSuite = getCryptoSuite(); + ContractCodec contractCodec = new ContractCodec(cryptoSuite,isWasm); + ABIObject abiObject = contractCodec.decodeMethodAndGetOutputAbiObject(MyContract.getABI(), methodName,output); + List abiObjects = abiObject.getStructFields(); + abiObjects.forEach(item->{ + if (item!=null) { + item.getListValues().forEach(obj-> result.add(obj.getStringValue())); + } + }); + return result; + } + + // 函数名 + Type格式的返回列表 + @Deprecated + public List decodeMethodParser(boolean isWasm, String output, String methodName) throws ContractCodecException { + CryptoSuite cryptoSuite = getCryptoSuite(); + ContractCodec contractCodec = new ContractCodec(cryptoSuite,isWasm); + List result = contractCodec.decodeMethod(MyContract.getABI(), methodName, output); + return result; + } + + public CryptoSuite getCryptoSuite() { + BcosSDK bcosSDK = FManager.getBcosSDK(); + String groupId = FManager.getFiscoBcosConfigProperties().getGroupId(); + Client client = bcosSDK.getClient(groupId); + CryptoSuite cryptoSuite = client.getCryptoSuite(); + return cryptoSuite; + } + + //获取Client对象对应的群组最新块高 + public BlockNumber getBlockNumber() { + String groupId = FManager.getFiscoBcosConfigProperties().getGroupId(); + Client client = getClient(groupId); + return client.getBlockNumber(); + } + + //获取Client对应群组的交易统计信息,包括上链的交易数、上链失败的交易数目。 + public TotalTransactionCount getTotalTransactionCount() { + String groupId = FManager.getFiscoBcosConfigProperties().getGroupId(); + Client client = getClient(groupId); + TotalTransactionCount totalTransactionCount = client.getTotalTransactionCount(); + return totalTransactionCount; + } + + //根据区块高度获取区块哈希。 + public BlockHash getBlockHashByNumber() { + String groupId = FManager.getFiscoBcosConfigProperties().getGroupId(); + BlockNumber blockNumber = getBlockNumber(); + Client client = getClient(groupId); + BlockHash blockHash = client.getBlockHashByNumber(blockNumber.getBlockNumber()); + return blockHash; + } + + //返回根据交易哈希查询的交易回执信息 + public Object getTransactionReceipt(String hash) { + String groupId = FManager.getFiscoBcosConfigProperties().getGroupId(); + Client client = getClient(groupId); + BcosTransactionReceipt bcosTransactionReceipt = client.getTransactionReceipt(hash,true); + return bcosTransactionReceipt; + } + + private Client getClient(String groupId ) { + BcosSDK sdk = FManager.getBcosSDK(); + Client client = sdk.getClient(String.valueOf(groupId)); + return client; + } + + public Object getContractMap(String contractName) { + if (getContractMap().containsKey(contractName)) { + return getContractMap().get(contractName); + } + return null; + } + + public Map getContractMap() { + return contractMap; + } + + public void setContractMap(Map contractMap) { + this.contractMap = contractMap; + } +} + + diff --git a/src/main/java/zyt/fiscobcos/config/FiscoBcosConfigProperties.java b/src/main/java/zyt/fiscobcos/config/FiscoBcosConfigProperties.java new file mode 100644 index 0000000..a62c263 --- /dev/null +++ b/src/main/java/zyt/fiscobcos/config/FiscoBcosConfigProperties.java @@ -0,0 +1,31 @@ +package zyt.fiscobcos.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +import java.io.Serializable; +import java.util.List; + +/** + * @author zyt + * @date 2023/10/09 + * 配置类,具体可以参见 + * https://fisco-bcos-documentation.readthedocs.io/zh_CN/latest/docs/sdk/java_sdk/configuration.html + */ +@Data +public class FiscoBcosConfigProperties implements Serializable { + private List peers; + private String certPath = "conf"; + private String keyStoreDir = "account"; + private String accountAddress = ""; + private String accountFileFormat = "pem"; + private String password = ""; + private String accountFilePath = ""; + private String channelProcessorThreadSize = "16"; + private String receiptProcessorThreadSize = "16"; + private String maxBlockingQueueSize = "102400"; + private String basePackages; + private boolean enabled = false; + private String groupId ="group0"; +} diff --git a/src/main/java/zyt/fiscobcos/contract/MyContract.java b/src/main/java/zyt/fiscobcos/contract/MyContract.java new file mode 100644 index 0000000..7955dc6 --- /dev/null +++ b/src/main/java/zyt/fiscobcos/contract/MyContract.java @@ -0,0 +1,557 @@ +package zyt.fiscobcos.contract; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import org.fisco.bcos.sdk.v3.client.Client; +import org.fisco.bcos.sdk.v3.codec.datatypes.DynamicArray; +import org.fisco.bcos.sdk.v3.codec.datatypes.Event; +import org.fisco.bcos.sdk.v3.codec.datatypes.Function; +import org.fisco.bcos.sdk.v3.codec.datatypes.Type; +import org.fisco.bcos.sdk.v3.codec.datatypes.TypeReference; +import org.fisco.bcos.sdk.v3.codec.datatypes.Utf8String; +import org.fisco.bcos.sdk.v3.codec.datatypes.generated.Int256; +import org.fisco.bcos.sdk.v3.codec.datatypes.generated.Int32; +import org.fisco.bcos.sdk.v3.codec.datatypes.generated.Uint8; +import org.fisco.bcos.sdk.v3.codec.datatypes.generated.tuples.generated.Tuple1; +import org.fisco.bcos.sdk.v3.codec.datatypes.generated.tuples.generated.Tuple2; +import org.fisco.bcos.sdk.v3.codec.datatypes.generated.tuples.generated.Tuple4; +import org.fisco.bcos.sdk.v3.contract.Contract; +import org.fisco.bcos.sdk.v3.crypto.CryptoSuite; +import org.fisco.bcos.sdk.v3.crypto.keypair.CryptoKeyPair; +import org.fisco.bcos.sdk.v3.model.CryptoType; +import org.fisco.bcos.sdk.v3.model.TransactionReceipt; +import org.fisco.bcos.sdk.v3.model.callback.CallCallback; +import org.fisco.bcos.sdk.v3.model.callback.TransactionCallback; +import org.fisco.bcos.sdk.v3.transaction.model.exception.ContractException; + +@SuppressWarnings("unchecked") +public class MyContract extends Contract { + public static final String[] BINARY_ARRAY = {"608060405260405180606001604052806040518060400160405280600481526020017f6e616d650000000000000000000000000000000000000000000000000000000081525081526020016040518060400160405280600381526020017f616765000000000000000000000000000000000000000000000000000000000081525081526020016040518060400160405280600681526020017f73746174757300000000000000000000000000000000000000000000000000008152508152506001906003620000d0929190620004ff565b506040518060400160405280600281526020017f6964000000000000000000000000000000000000000000000000000000000000815250600290805190602001906200011e92919062000566565b503480156200012c57600080fd5b50600060405180606001604052806000600181111562000151576200015062000684565b5b8152602001600280546200016590620006e2565b80601f01602080910402602001604051908101604052809291908181526020018280546200019390620006e2565b8015620001e45780601f10620001b857610100808354040283529160200191620001e4565b820191906000526020600020905b815481529060010190602001808311620001c657829003601f168201915b505050505081526020016001805480602002602001604051908101604052809291908181526020016000905b82821015620002c65783829060005260206000200180546200023290620006e2565b80601f01602080910402602001604051908101604052809291908181526020018280546200026090620006e2565b8015620002b15780601f106200028557610100808354040283529160200191620002b1565b820191906000526020600020905b8154815290600101906020018083116200029357829003601f168201915b50505050508152602001906001019062000210565b50505050815250905061100273ffffffffffffffffffffffffffffffffffffffff166375b14eea6040518060400160405280600381526020017f7a31310000000000000000000000000000000000000000000000000000000000815250836040518363ffffffff1660e01b8152600401620003439291906200098c565b6020604051808303816000875af115801562000363573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000389919062000a0a565b50600061100273ffffffffffffffffffffffffffffffffffffffff1663f23f63c96040518060400160405280600381526020017f7a313100000000000000000000000000000000000000000000000000000000008152506040518263ffffffff1660e01b8152600401620003fe919062000a3c565b602060405180830381865afa1580156200041c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000442919062000ac5565b9050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415620004b7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401620004ae9062000b21565b60405180910390fd5b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505062000b43565b82805482825590600052602060002090810192821562000553579160200282015b82811115620005525782518290805190602001906200054192919062000566565b509160200191906001019062000520565b5b509050620005629190620005f7565b5090565b8280546200057490620006e2565b90600052602060002090601f016020900481019282620005985760008555620005e4565b82601f10620005b357805160ff1916838001178555620005e4565b82800160010185558215620005e4579182015b82811115620005e3578251825591602001919060010190620005c6565b5b509050620005f391906200061f565b5090565b5b808211156200061b57600081816200061191906200063e565b50600101620005f8565b5090565b5b808211156200063a57600081600090555060010162000620565b5090565b5080546200064c90620006e2565b6000825580601f1062000660575062000681565b601f0160209004906000526020600020908101906200068091906200061f565b5b50565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680620006fb57607f821691505b60208210811415620007125762000711620006b3565b5b50919050565b600081519050919050565b600082825260208201905092915050565b60005b838110156200075457808201518184015260208101905062000737565b8381111562000764576000848401525b50505050565b6000601f19601f8301169050919050565b6000620007888262000718565b62000794818562000723565b9350620007a681856020860162000734565b620007b1816200076a565b840191505092915050565b60028110620007d057620007cf62000684565b5b50565b6000819050620007e382620007bc565b919050565b6000620007f582620007d3565b9050919050565b6200080781620007e8565b82525050565b600082825260208201905092915050565b60006200082b8262000718565b6200083781856200080d565b93506200084981856020860162000734565b62000854816200076a565b840191505092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b60006200089983836200081e565b905092915050565b6000602082019050919050565b6000620008bb826200085f565b620008c781856200086a565b935083602082028501620008db856200087b565b8060005b858110156200091d5784840389528151620008fb85826200088b565b94506200090883620008a1565b925060208a01995050600181019050620008df565b50829750879550505050505092915050565b6000606083016000830151620009496000860182620007fc565b50602083015184820360208601526200096382826200081e565b915050604083015184820360408601526200097f8282620008ae565b9150508091505092915050565b60006040820190508181036000830152620009a881856200077b565b90508181036020830152620009be81846200092f565b90509392505050565b600080fd5b60008160030b9050919050565b620009e481620009cc565b8114620009f057600080fd5b50565b60008151905062000a0481620009d9565b92915050565b60006020828403121562000a235762000a22620009c7565b5b600062000a3384828501620009f3565b91505092915050565b6000602082019050818103600083015262000a5881846200077b565b905092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600062000a8d8262000a60565b9050919050565b62000a9f8162000a80565b811462000aab57600080fd5b50565b60008151905062000abf8162000a94565b92915050565b60006020828403121562000ade5762000add620009c7565b5b600062000aee8482850162000aae565b91505092915050565b50565b600062000b0960008362000723565b915062000b168262000af7565b600082019050919050565b6000602082019050818103600083015262000b3c8162000afa565b9050919050565b611d968062000b536000396000f3fe6080604052600436106100865760003560e01c806355f150f11161005957806355f150f11461015e578063725533361461018a57806375789f01146101c75780638cc77e7e146101f0578063f83315441461022d57610086565b8063223c00891461008b57806326b477fd146100c85780633b41a685146100f85780635246012214610135575b600080fd5b34801561009757600080fd5b506100b260048036038101906100ad91906110da565b61026a565b6040516100bf919061113f565b60405180910390f35b6100e260048036038101906100dd919061115a565b610440565b6040516100ef91906112ed565b60405180910390f35b34801561010457600080fd5b5061011f600480360381019061011a91906110da565b6106e5565b60405161012c919061113f565b60405180910390f35b34801561014157600080fd5b5061015c600480360381019061015791906110da565b61097c565b005b34801561016a57600080fd5b5061017361098d565b604051610181929190611359565b60405180910390f35b34801561019657600080fd5b506101b160048036038101906101ac919061115a565b610a5d565b6040516101be919061113f565b60405180910390f35b3480156101d357600080fd5b506101ee60048036038101906101e9919061115a565b610b3e565b005b3480156101fc57600080fd5b50610217600480360381019061021291906113c9565b610b7d565b604051610224919061149d565b60405180910390f35b34801561023957600080fd5b50610254600480360381019061024f91906114ee565b610cac565b604051610261919061151b565b60405180910390f35b60008060405180604001604052808460008151811061028c5761028b61153d565b5b6020026020010151815260200160018054905067ffffffffffffffff8111156102b8576102b7610ec4565b5b6040519080825280602002602001820160405280156102eb57816020015b60608152602001906001900390816102d65790505b5081525090506000600190505b835181101561035d578381815181106103145761031361153d565b5b6020026020010151826020015160018361032e919061159b565b8151811061033f5761033e61153d565b5b60200260200101819052508080610355906115cf565b9150506102f8565b5060008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16635c6e105f836040518263ffffffff1660e01b81526004016103ba91906116e2565b6020604051808303816000875af11580156103d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103fd9190611730565b90507fc57b01fa77f41df77eaab79a0e2623fab2e7ae3e9530d9b1cab225ad65f2b7ce8160405161042e9190611798565b60405180910390a18092505050919050565b606061051c6003805480602002602001604051908101604052809291908181526020016000905b82821015610513578382906000526020600020018054610486906117e2565b80601f01602080910402602001604051908101604052809291908181526020018280546104b2","906117e2565b80156104ff5780601f106104d4576101008083540402835291602001916104ff565b820191906000526020600020905b8154815290600101906020018083116104e257829003601f168201915b505050505081526020019060010190610467565b5050505061097c565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663fcd7e3c1846040518263ffffffff1660e01b8152600401610578919061151b565b600060405180830381865afa158015610595573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906105be91906119cb565b905060005b81602001515181101561060a576105f7826020015182815181106105ea576105e961153d565b5b6020026020010151610b3e565b8080610602906115cf565b9150506105c3565b506003805480602002602001604051908101604052809291908181526020016000905b828210156106d957838290600052602060002001805461064c906117e2565b80601f0160208091040260200160405190810160405280929190818152602001828054610678906117e2565b80156106c55780601f1061069a576101008083540402835291602001916106c5565b820191906000526020600020905b8154815290600101906020018083116106a857829003601f168201915b50505050508152602001906001019061062d565b50505050915050919050565b60008060018054905067ffffffffffffffff81111561070757610706610ec4565b5b60405190808252806020026020018201604052801561074057816020015b61072d610d58565b8152602001906001900390816107255790505b5090506000600190505b835181101561087c5760405180604001604052806001808461076c919061159b565b8154811061077d5761077c61153d565b5b906000526020600020018054610792906117e2565b80601f01602080910402602001604051908101604052809291908181526020018280546107be906117e2565b801561080b5780601f106107e05761010080835404028352916020019161080b565b820191906000526020600020905b8154815290600101906020018083116107ee57829003601f168201915b5050505050815260200185600184610823919061159b565b815181106108345761083361153d565b5b60200260200101518152508260018361084d919061159b565b8151811061085e5761085d61153d565b5b60200260200101819052508080610874906115cf565b91505061074a565b5060008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166341ffd75f856000815181106108d0576108cf61153d565b5b6020026020010151846040518363ffffffff1660e01b81526004016108f6929190611b1a565b6020604051808303816000875af1158015610915573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109399190611730565b90507f8e5890af40fc24a059396aca2f83d6ce41fcef086876548fa4fb8ec27e9d292a8160405161096a9190611798565b60405180910390a18092505050919050565b6003600061098a9190610d72565b50565b606080600061100273ffffffffffffffffffffffffffffffffffffffff1663b8764d3f6040518060400160405280600381526020017f7a313100000000000000000000000000000000000000000000000000000000008152506040518263ffffffff1660e01b8152600401610a02919061151b565b600060405180830381865afa158015610a1f573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190610a489190611c12565b90508060200151816040015192509250509091565b60008060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166380599e4b846040518263ffffffff1660e01b8152600401610ab9919061151b565b6020604051808303816000875af1158015610ad8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610afc9190611730565b90507f4b930e280fe29620bdff00c88155d46d6d82a39f45dd5c3ea114dc315735811281604051610b2d9190611798565b60405180910390a180915050919050565b600381908060018154018082558091505060019003906000526020600020016000909190919091509080519060200190610b79929190610d93565b5050565b6000808460ff161480610b93575060018460ff16145b610b9c57600080fd5b600060018560ff161415610baf57600190505b60006040518060600160405280836001811115610bcf57610bce611c5b565b5b8152602001868152602001858152509050600061100273ffffffffffffffffffffffffffffffffffffffff166375b14eea89846040518363ffffffff1660e01b8152600401610c1f929190611d29565b6020604051808303816000875af1158015610c3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c629190611730565b90507fb5636cd912a73dcdb5b570dbe331dfa3e6435c93e029e642def2c8e40dacf21081604051610c939190611798565b60405180910390a18060030b9350505050949350505050565b60038181548110610cbc57600080fd5b906000526020600020016000915090508054610cd7906117e2565b80601f0160208091040260200160405190810160405280929190818152602001828054610d03906117e2565b8015610d505780601f10610d2557610100808354040283529160200191610d50565b820191906000526020600020905b815481529060010190602001808311610d3357829003601f168201915b505050505081565b604051806040016040528060608152602001606081525090565b5080546000825590600052602060002090810190610d909190610e19565b50565b828054610d9f906117e2565b90600052602060002090601f016020900481019282610dc15760008555610e08565b82601f10610dda57805160ff1916838001178555610e08565b82800160010185558215610e08579182015b82811115610e07578251825591602001919060010190610dec565b5b509050610e159190610e3d565b5090565b5b80821115610e395760008181610e309190610e5a565b50600101610e1a565b5090565b5b80821115610e56576000816000905550600101610e3e565b5090565b508054610e66906117e2565b6000825580601f10610e785750610e97565b601f016020900490600052602060002090810190610e969190610e3d565b5b50565b6000604051905090565b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b610efc82610eb3565b810181811067ffffffffffffffff82111715610f1b57610f1a610ec4565b5b80604052505050565b6000610f2e610e9a565b9050610f3a8282610ef3565b919050565b600067ffffffffffffffff821115610f5a57610f59610ec4565b5b602082029050602081019050919050565b600080fd5b600080fd5b600067ffffffffffffffff821115610f9057610f8f610ec4565b5b610f9982610eb3565b9050602081019050919050565b82818337600083830152505050565b6000610fc8610fc384610f75565b610f24565b905082815260208101848484011115610fe457610fe3610f70565b5b610fef848285610fa6565b509392505050565b600082601f83011261100c5761100b610eae565b5b813561101c848260208601610fb5565b91505092915050565b600061103861103384610f3f565b610f24565b9050808382526020820190506020840283018581111561105b5761105a610f6b565b5b835b818110156110a257803567ffffffffffffffff8111156110805761107f610eae565b5b80860161108d8982610ff7565b8552602085019450505060208101905061105d565b5050509392505050565b600082601f8301126110c1576110c0610eae565b5b81356110d1848260208601611025565b91505092915050565b6000602082840312156110f0576110ef610ea4565b5b600082013567ffffffffffffffff81111561110e5761110d610ea9565b5b61111a848285016110ac565b91505092915050565b60008160030b9050919050565b61113981611123565b82525050565b60006020820190506111546000830184611130565b92915050565b6000602082840312156111705761116f610ea4565b5b600082013567ffffffffffffffff81111561118e5761118d610ea9565b5b61119a84828501610ff7565b91505092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b600081519050919050565b600082825260208201905092915050565b60005b838110156112095780820151818401526020810190506111ee565b83811115611218576000848401525b50505050565b6000611229826111cf565b61123381856111da565b93506112438185602086016111eb565b61124c81610eb3565b840191505092915050565b6000611263838361121e565b905092915050565b6000602082019050919050565b6000611283826111a3565b61128d81856111ae565b93508360208202850161129f856111bf565b8060005b858110156112db57848403895281516112bc8582611257565b94506112c78361126b565b925060208a019950506001810190506112a3565b50829750879550505050505092915050565b600060208201905081810360008301526113078184611278565b905092915050565b600082825260208201905092915050565b600061132b826111cf565b611335818561130f565b93506113458185602086016111eb565b61134e81610eb3565b840191505092915050565b600060408201905081810360008301526113738185611320565b905081810360208301526113878184611278565b90509392505050565b600060ff82169050919050565b6113a681611390565b81146113b157600080fd5b50565b6000813590506113c38161139d565b92915050565b600080600080608085870312156113e3576113e2610ea4565b5b600085013567ffffffffffffffff81111561140157611400610ea9565b5b61140d87828801610ff7565b945050602061141e878288016113b4565b935050604085013567ffffffffffffffff81111561143f5761143e610ea9565b5b61144b87828801610ff7565b925050606085013567ffffffffffffffff81111561146c5761146b610ea9565b5b611478878288016110ac565b91505092959194509250565b6000819050919050565b61149781611484565b82525050565b60006020820190506114b260008301","8461148e565b92915050565b6000819050919050565b6114cb816114b8565b81146114d657600080fd5b50565b6000813590506114e8816114c2565b92915050565b60006020828403121561150457611503610ea4565b5b6000611512848285016114d9565b91505092915050565b600060208201905081810360008301526115358184611320565b905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006115a6826114b8565b91506115b1836114b8565b9250828210156115c4576115c361156c565b5b828203905092915050565b60006115da826114b8565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82141561160d5761160c61156c565b5b600182019050919050565b600082825260208201905092915050565b6000611634826111a3565b61163e8185611618565b935083602082028501611650856111bf565b8060005b8581101561168c578484038952815161166d8582611257565b94506116788361126b565b925060208a01995050600181019050611654565b50829750879550505050505092915050565b600060408301600083015184820360008601526116bb828261121e565b915050602083015184820360208601526116d58282611629565b9150508091505092915050565b600060208201905081810360008301526116fc818461169e565b905092915050565b61170d81611123565b811461171857600080fd5b50565b60008151905061172a81611704565b92915050565b60006020828403121561174657611745610ea4565b5b60006117548482850161171b565b91505092915050565b6000819050919050565b600061178261177d61177884611123565b61175d565b611484565b9050919050565b61179281611767565b82525050565b60006020820190506117ad6000830184611789565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806117fa57607f821691505b6020821081141561180e5761180d6117b3565b5b50919050565b600080fd5b600080fd5b600061183161182c84610f75565b610f24565b90508281526020810184848401111561184d5761184c610f70565b5b6118588482856111eb565b509392505050565b600082601f83011261187557611874610eae565b5b815161188584826020860161181e565b91505092915050565b60006118a161189c84610f3f565b610f24565b905080838252602082019050602084028301858111156118c4576118c3610f6b565b5b835b8181101561190b57805167ffffffffffffffff8111156118e9576118e8610eae565b5b8086016118f68982611860565b855260208501945050506020810190506118c6565b5050509392505050565b600082601f83011261192a57611929610eae565b5b815161193a84826020860161188e565b91505092915050565b60006040828403121561195957611958611814565b5b6119636040610f24565b9050600082015167ffffffffffffffff81111561198357611982611819565b5b61198f84828501611860565b600083015250602082015167ffffffffffffffff8111156119b3576119b2611819565b5b6119bf84828501611915565b60208301525092915050565b6000602082840312156119e1576119e0610ea4565b5b600082015167ffffffffffffffff8111156119ff576119fe610ea9565b5b611a0b84828501611943565b91505092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b60006040830160008301518482036000860152611a5d828261121e565b91505060208301518482036020860152611a77828261121e565b9150508091505092915050565b6000611a908383611a40565b905092915050565b6000602082019050919050565b6000611ab082611a14565b611aba8185611a1f565b935083602082028501611acc85611a30565b8060005b85811015611b085784840389528151611ae98582611a84565b9450611af483611a98565b925060208a01995050600181019050611ad0565b50829750879550505050505092915050565b60006040820190508181036000830152611b348185611320565b90508181036020830152611b488184611aa5565b90509392505050565b60028110611b5e57600080fd5b50565b600081519050611b7081611b51565b92915050565b600060608284031215611b8c57611b8b611814565b5b611b966060610f24565b90506000611ba684828501611b61565b600083015250602082015167ffffffffffffffff811115611bca57611bc9611819565b5b611bd684828501611860565b602083015250604082015167ffffffffffffffff811115611bfa57611bf9611819565b5b611c0684828501611915565b60408301525092915050565b600060208284031215611c2857611c27610ea4565b5b600082015167ffffffffffffffff811115611c4657611c45610ea9565b5b611c5284828501611b76565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60028110611c9b57611c9a611c5b565b5b50565b6000819050611cac82611c8a565b919050565b6000611cbc82611c9e565b9050919050565b611ccc81611cb1565b82525050565b6000606083016000830151611cea6000860182611cc3565b5060208301518482036020860152611d02828261121e565b91505060408301518482036040860152611d1c8282611629565b9150508091505092915050565b60006040820190508181036000830152611d438185611320565b90508181036020830152611d578184611cd2565b9050939250505056fea26469706673582212201e18ced4308609e2d3c74ec487de854fb288437f1a7d99917932b001ef800b0164736f6c634300080b0033"}; + + public static final String BINARY = org.fisco.bcos.sdk.v3.utils.StringUtils.joinAll("", BINARY_ARRAY); + + public static final String[] SM_BINARY_ARRAY = {}; + + public static final String SM_BINARY = org.fisco.bcos.sdk.v3.utils.StringUtils.joinAll("", SM_BINARY_ARRAY); + + public static final String[] ABI_ARRAY = {"[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"count\",\"type\":\"int256\"}],\"name\":\"CreateResult\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"count\",\"type\":\"int256\"}],\"name\":\"InsertResult\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"count\",\"type\":\"int256\"}],\"name\":\"RemoveResult\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"count\",\"type\":\"int256\"}],\"name\":\"UpdateResult\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"element\",\"type\":\"string\"}],\"name\":\"addElement\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string[]\",\"name\":\"arr\",\"type\":\"string[]\"}],\"name\":\"clearArray\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"tableName\",\"type\":\"string\"},{\"internalType\":\"uint8\",\"name\":\"keyOrder\",\"type\":\"uint8\"},{\"internalType\":\"string\",\"name\":\"key\",\"type\":\"string\"},{\"internalType\":\"string[]\",\"name\":\"fields\",\"type\":\"string[]\"}],\"name\":\"createTable\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"desc\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string[]\",\"name\":\"\",\"type\":\"string[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"dynamicStringArray\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string[]\",\"name\":\"value\",\"type\":\"string[]\"}],\"name\":\"insert\",\"outputs\":[{\"internalType\":\"int32\",\"name\":\"\",\"type\":\"int32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"id\",\"type\":\"string\"}],\"name\":\"removeById\",\"outputs\":[{\"internalType\":\"int32\",\"name\":\"\",\"type\":\"int32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"id\",\"type\":\"string\"}],\"name\":\"selectById\",\"outputs\":[{\"internalType\":\"string[]\",\"name\":\"\",\"type\":\"string[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string[]\",\"name\":\"value\",\"type\":\"string[]\"}],\"name\":\"updateById\",\"outputs\":[{\"internalType\":\"int32\",\"name\":\"\",\"type\":\"int32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]"}; + + public static final String ABI = org.fisco.bcos.sdk.v3.utils.StringUtils.joinAll("", ABI_ARRAY); + + public static final String FUNC_ADDELEMENT = "addElement"; + + public static final String FUNC_CLEARARRAY = "clearArray"; + + public static final String FUNC_CREATETABLE = "createTable"; + + public static final String FUNC_DESC = "desc"; + + public static final String FUNC_DYNAMICSTRINGARRAY = "dynamicStringArray"; + + public static final String FUNC_INSERT = "insert"; + + public static final String FUNC_REMOVEBYID = "removeById"; + + public static final String FUNC_SELECTBYID = "selectById"; + + public static final String FUNC_UPDATEBYID = "updateById"; + + public static final Event CREATERESULT_EVENT = new Event("CreateResult", + Arrays.>asList(new TypeReference() {})); + ; + + public static final Event INSERTRESULT_EVENT = new Event("InsertResult", + Arrays.>asList(new TypeReference() {})); + ; + + public static final Event REMOVERESULT_EVENT = new Event("RemoveResult", + Arrays.>asList(new TypeReference() {})); + ; + + public static final Event UPDATERESULT_EVENT = new Event("UpdateResult", + Arrays.>asList(new TypeReference() {})); + ; + + protected MyContract(String contractAddress, Client client, CryptoKeyPair credential) { + super(getBinary(client.getCryptoSuite()), contractAddress, client, credential); + } + + public static String getBinary(CryptoSuite cryptoSuite) { + return (cryptoSuite.getCryptoTypeConfig() == CryptoType.ECDSA_TYPE ? BINARY : SM_BINARY); + } + + public static String getABI() { + return ABI; + } + + public List getCreateResultEvents( + TransactionReceipt transactionReceipt) { + List valueList = extractEventParametersWithLog(CREATERESULT_EVENT, transactionReceipt); + ArrayList responses = new ArrayList(valueList.size()); + for (EventValuesWithLog eventValues : valueList) { + CreateResultEventResponse typedResponse = new CreateResultEventResponse(); + typedResponse.log = eventValues.getLog(); + typedResponse.count = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); + responses.add(typedResponse); + } + return responses; + } + + public List getInsertResultEvents( + TransactionReceipt transactionReceipt) { + List valueList = extractEventParametersWithLog(INSERTRESULT_EVENT, transactionReceipt); + ArrayList responses = new ArrayList(valueList.size()); + for (EventValuesWithLog eventValues : valueList) { + InsertResultEventResponse typedResponse = new InsertResultEventResponse(); + typedResponse.log = eventValues.getLog(); + typedResponse.count = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); + responses.add(typedResponse); + } + return responses; + } + + public List getRemoveResultEvents( + TransactionReceipt transactionReceipt) { + List valueList = extractEventParametersWithLog(REMOVERESULT_EVENT, transactionReceipt); + ArrayList responses = new ArrayList(valueList.size()); + for (EventValuesWithLog eventValues : valueList) { + RemoveResultEventResponse typedResponse = new RemoveResultEventResponse(); + typedResponse.log = eventValues.getLog(); + typedResponse.count = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); + responses.add(typedResponse); + } + return responses; + } + + public List getUpdateResultEvents( + TransactionReceipt transactionReceipt) { + List valueList = extractEventParametersWithLog(UPDATERESULT_EVENT, transactionReceipt); + ArrayList responses = new ArrayList(valueList.size()); + for (EventValuesWithLog eventValues : valueList) { + UpdateResultEventResponse typedResponse = new UpdateResultEventResponse(); + typedResponse.log = eventValues.getLog(); + typedResponse.count = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue(); + responses.add(typedResponse); + } + return responses; + } + + public TransactionReceipt addElement(String element) { + final Function function = new Function( + FUNC_ADDELEMENT, + Arrays.asList(new Utf8String(element)), + Collections.>emptyList(), 0); + return executeTransaction(function); + } + + public String getSignedTransactionForAddElement(String element) { + final Function function = new Function( + FUNC_ADDELEMENT, + Arrays.asList(new Utf8String(element)), + Collections.>emptyList(), 0); + return createSignedTransaction(function); + } + + public String addElement(String element, TransactionCallback callback) { + final Function function = new Function( + FUNC_ADDELEMENT, + Arrays.asList(new Utf8String(element)), + Collections.>emptyList(), 0); + return asyncExecuteTransaction(function, callback); + } + + public Tuple1 getAddElementInput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getInput().substring(10); + final Function function = new Function(FUNC_ADDELEMENT, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + List results = this.functionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple1( + + (String) results.get(0).getValue() + ); + } + + public TransactionReceipt clearArray(List arr) { + final Function function = new Function( + FUNC_CLEARARRAY, + Arrays.asList(new DynamicArray( + Utf8String.class, + org.fisco.bcos.sdk.v3.codec.Utils.typeMap(arr, Utf8String.class))), + Collections.>emptyList(), 0); + return executeTransaction(function); + } + + public String getSignedTransactionForClearArray(List arr) { + final Function function = new Function( + FUNC_CLEARARRAY, + Arrays.asList(new DynamicArray( + Utf8String.class, + org.fisco.bcos.sdk.v3.codec.Utils.typeMap(arr, Utf8String.class))), + Collections.>emptyList(), 0); + return createSignedTransaction(function); + } + + public String clearArray(List arr, TransactionCallback callback) { + final Function function = new Function( + FUNC_CLEARARRAY, + Arrays.asList(new DynamicArray( + Utf8String.class, + org.fisco.bcos.sdk.v3.codec.Utils.typeMap(arr, Utf8String.class))), + Collections.>emptyList(), 0); + return asyncExecuteTransaction(function, callback); + } + + public Tuple1> getClearArrayInput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getInput().substring(10); + final Function function = new Function(FUNC_CLEARARRAY, + Arrays.asList(), + Arrays.>asList(new TypeReference>() {})); + List results = this.functionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple1>( + + convertToNative((List) results.get(0).getValue()) + ); + } + + public TransactionReceipt createTable(String tableName, BigInteger keyOrder, String key, + List fields) { + final Function function = new Function( + FUNC_CREATETABLE, + Arrays.asList(new Utf8String(tableName), + new Uint8(keyOrder), + new Utf8String(key), + new DynamicArray( + Utf8String.class, + org.fisco.bcos.sdk.v3.codec.Utils.typeMap(fields, Utf8String.class))), + Collections.>emptyList(), 0); + return executeTransaction(function); + } + + public String getSignedTransactionForCreateTable(String tableName, BigInteger keyOrder, + String key, List fields) { + final Function function = new Function( + FUNC_CREATETABLE, + Arrays.asList(new Utf8String(tableName), + new Uint8(keyOrder), + new Utf8String(key), + new DynamicArray( + Utf8String.class, + org.fisco.bcos.sdk.v3.codec.Utils.typeMap(fields, Utf8String.class))), + Collections.>emptyList(), 0); + return createSignedTransaction(function); + } + + public String createTable(String tableName, BigInteger keyOrder, String key, + List fields, TransactionCallback callback) { + final Function function = new Function( + FUNC_CREATETABLE, + Arrays.asList(new Utf8String(tableName), + new Uint8(keyOrder), + new Utf8String(key), + new DynamicArray( + Utf8String.class, + org.fisco.bcos.sdk.v3.codec.Utils.typeMap(fields, Utf8String.class))), + Collections.>emptyList(), 0); + return asyncExecuteTransaction(function, callback); + } + + public Tuple4> getCreateTableInput( + TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getInput().substring(10); + final Function function = new Function(FUNC_CREATETABLE, + Arrays.asList(), + Arrays.>asList(new TypeReference() {}, new TypeReference() {}, new TypeReference() {}, new TypeReference>() {})); + List results = this.functionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple4>( + + (String) results.get(0).getValue(), + (BigInteger) results.get(1).getValue(), + (String) results.get(2).getValue(), + convertToNative((List) results.get(3).getValue()) + ); + } + + public Tuple1 getCreateTableOutput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getOutput(); + final Function function = new Function(FUNC_CREATETABLE, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + List results = this.functionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple1( + + (BigInteger) results.get(0).getValue() + ); + } + + public Tuple2> desc() throws ContractException { + final Function function = new Function(FUNC_DESC, + Arrays.asList(), + Arrays.>asList(new TypeReference() {}, new TypeReference>() {})); + List results = executeCallWithMultipleValueReturn(function); + return new Tuple2>( + (String) results.get(0).getValue(), + convertToNative((List) results.get(1).getValue())); + } + + public void desc(CallCallback callback) throws ContractException { + final Function function = new Function(FUNC_DESC, + Arrays.asList(), + Arrays.>asList(new TypeReference() {}, new TypeReference>() {})); + asyncExecuteCall(function, callback); + } + + public String dynamicStringArray(BigInteger param0) throws ContractException { + final Function function = new Function(FUNC_DYNAMICSTRINGARRAY, + Arrays.asList(new org.fisco.bcos.sdk.v3.codec.datatypes.generated.Uint256(param0)), + Arrays.>asList(new TypeReference() {})); + return executeCallWithSingleValueReturn(function, String.class); + } + + public void dynamicStringArray(BigInteger param0, CallCallback callback) throws + ContractException { + final Function function = new Function(FUNC_DYNAMICSTRINGARRAY, + Arrays.asList(new org.fisco.bcos.sdk.v3.codec.datatypes.generated.Uint256(param0)), + Arrays.>asList(new TypeReference() {})); + asyncExecuteCall(function, callback); + } + + public TransactionReceipt insert(List value) { + final Function function = new Function( + FUNC_INSERT, + Arrays.asList(new DynamicArray( + Utf8String.class, + org.fisco.bcos.sdk.v3.codec.Utils.typeMap(value, Utf8String.class))), + Collections.>emptyList(), 0); + return executeTransaction(function); + } + + public String getSignedTransactionForInsert(List value) { + final Function function = new Function( + FUNC_INSERT, + Arrays.asList(new DynamicArray( + Utf8String.class, + org.fisco.bcos.sdk.v3.codec.Utils.typeMap(value, Utf8String.class))), + Collections.>emptyList(), 0); + return createSignedTransaction(function); + } + + public String insert(List value, TransactionCallback callback) { + final Function function = new Function( + FUNC_INSERT, + Arrays.asList(new DynamicArray( + Utf8String.class, + org.fisco.bcos.sdk.v3.codec.Utils.typeMap(value, Utf8String.class))), + Collections.>emptyList(), 0); + return asyncExecuteTransaction(function, callback); + } + + public Tuple1> getInsertInput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getInput().substring(10); + final Function function = new Function(FUNC_INSERT, + Arrays.asList(), + Arrays.>asList(new TypeReference>() {})); + List results = this.functionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple1>( + + convertToNative((List) results.get(0).getValue()) + ); + } + + public Tuple1 getInsertOutput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getOutput(); + final Function function = new Function(FUNC_INSERT, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + List results = this.functionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple1( + + (BigInteger) results.get(0).getValue() + ); + } + + public TransactionReceipt removeById(String id) { + final Function function = new Function( + FUNC_REMOVEBYID, + Arrays.asList(new Utf8String(id)), + Collections.>emptyList(), 0); + return executeTransaction(function); + } + + public String getSignedTransactionForRemoveById(String id) { + final Function function = new Function( + FUNC_REMOVEBYID, + Arrays.asList(new Utf8String(id)), + Collections.>emptyList(), 0); + return createSignedTransaction(function); + } + + public String removeById(String id, TransactionCallback callback) { + final Function function = new Function( + FUNC_REMOVEBYID, + Arrays.asList(new Utf8String(id)), + Collections.>emptyList(), 0); + return asyncExecuteTransaction(function, callback); + } + + public Tuple1 getRemoveByIdInput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getInput().substring(10); + final Function function = new Function(FUNC_REMOVEBYID, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + List results = this.functionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple1( + + (String) results.get(0).getValue() + ); + } + + public Tuple1 getRemoveByIdOutput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getOutput(); + final Function function = new Function(FUNC_REMOVEBYID, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + List results = this.functionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple1( + + (BigInteger) results.get(0).getValue() + ); + } + + public TransactionReceipt selectById(String id) { + final Function function = new Function( + FUNC_SELECTBYID, + Arrays.asList(new Utf8String(id)), + Collections.>emptyList(), 0); + return executeTransaction(function); + } + + public String getSignedTransactionForSelectById(String id) { + final Function function = new Function( + FUNC_SELECTBYID, + Arrays.asList(new Utf8String(id)), + Collections.>emptyList(), 0); + return createSignedTransaction(function); + } + + public String selectById(String id, TransactionCallback callback) { + final Function function = new Function( + FUNC_SELECTBYID, + Arrays.asList(new Utf8String(id)), + Collections.>emptyList(), 0); + return asyncExecuteTransaction(function, callback); + } + + public Tuple1 getSelectByIdInput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getInput().substring(10); + final Function function = new Function(FUNC_SELECTBYID, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + List results = this.functionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple1( + + (String) results.get(0).getValue() + ); + } + + public Tuple1> getSelectByIdOutput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getOutput(); + final Function function = new Function(FUNC_SELECTBYID, + Arrays.asList(), + Arrays.>asList(new TypeReference>() {})); + List results = this.functionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple1>( + + convertToNative((List) results.get(0).getValue()) + ); + } + + public TransactionReceipt updateById(List value) { + final Function function = new Function( + FUNC_UPDATEBYID, + Arrays.asList(new DynamicArray( + Utf8String.class, + org.fisco.bcos.sdk.v3.codec.Utils.typeMap(value, Utf8String.class))), + Collections.>emptyList(), 0); + return executeTransaction(function); + } + + public String getSignedTransactionForUpdateById(List value) { + final Function function = new Function( + FUNC_UPDATEBYID, + Arrays.asList(new DynamicArray( + Utf8String.class, + org.fisco.bcos.sdk.v3.codec.Utils.typeMap(value, Utf8String.class))), + Collections.>emptyList(), 0); + return createSignedTransaction(function); + } + + public String updateById(List value, TransactionCallback callback) { + final Function function = new Function( + FUNC_UPDATEBYID, + Arrays.asList(new DynamicArray( + Utf8String.class, + org.fisco.bcos.sdk.v3.codec.Utils.typeMap(value, Utf8String.class))), + Collections.>emptyList(), 0); + return asyncExecuteTransaction(function, callback); + } + + public Tuple1> getUpdateByIdInput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getInput().substring(10); + final Function function = new Function(FUNC_UPDATEBYID, + Arrays.asList(), + Arrays.>asList(new TypeReference>() {})); + List results = this.functionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple1>( + + convertToNative((List) results.get(0).getValue()) + ); + } + + public Tuple1 getUpdateByIdOutput(TransactionReceipt transactionReceipt) { + String data = transactionReceipt.getOutput(); + final Function function = new Function(FUNC_UPDATEBYID, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + List results = this.functionReturnDecoder.decode(data, function.getOutputParameters()); + return new Tuple1( + + (BigInteger) results.get(0).getValue() + ); + } + + public static MyContract load(String contractAddress, Client client, CryptoKeyPair credential) { + return new MyContract(contractAddress, client, credential); + } + + public static MyContract deploy(Client client, CryptoKeyPair credential) throws ContractException { + return deploy(MyContract.class, client, credential, getBinary(client.getCryptoSuite()), getABI(), null, null); + } + + public static class CreateResultEventResponse { + public TransactionReceipt.Logs log; + + public BigInteger count; + } + + public static class InsertResultEventResponse { + public TransactionReceipt.Logs log; + + public BigInteger count; + } + + public static class RemoveResultEventResponse { + public TransactionReceipt.Logs log; + + public BigInteger count; + } + + public static class UpdateResultEventResponse { + public TransactionReceipt.Logs log; + + public BigInteger count; + } +} diff --git a/src/main/java/zyt/fiscobcos/deploy/DeployAnnotationContract.java b/src/main/java/zyt/fiscobcos/deploy/DeployAnnotationContract.java new file mode 100644 index 0000000..0465fb2 --- /dev/null +++ b/src/main/java/zyt/fiscobcos/deploy/DeployAnnotationContract.java @@ -0,0 +1,55 @@ +package zyt.fiscobcos.deploy; + +import io.github.classgraph.*; +import lombok.extern.slf4j.Slf4j; +import org.fisco.bcos.sdk.v3.BcosSDK; +import org.fisco.bcos.sdk.v3.contract.Contract; +import org.springframework.boot.CommandLineRunner; +import zyt.fiscobcos.FManager; +import zyt.fiscobcos.annotion.EnableScan; +import zyt.fiscobcos.client.FiscoClient; +import zyt.fiscobcos.utils.PackageScannerUtil; + +import java.util.*; + +/** + * 根据注解部署合约 + * @author zyt + * @date 2023/09/28 + */ +@Slf4j +public class DeployAnnotationContract implements CommandLineRunner { + + @Override + public void run(String... args) throws Exception { + FiscoClient fiscoClient = FManager.getFiscoClient(); + BcosSDK bcosSDK = FManager.getBcosSDK(); + ClassInfoList classInfoList = PackageScannerUtil.scanClassInfoWithAnnotation(EnableScan.class); + if (classInfoList != null && classInfoList.size()>0) { + ClassInfo classInfo = classInfoList.get(0); + AnnotationInfo annotationInfo = classInfo.getAnnotationInfo(EnableScan.class); + AnnotationParameterValueList annotationParameterValueList = annotationInfo.getParameterValues(true); + AnnotationParameterValue annotationParameterValue = annotationParameterValueList.get("packages"); + String[] values = (String[]) annotationParameterValue.getValue(); + if (values != null && values.length>0) { + List packs = Arrays.asList(values); + Set> classes = new HashSet<>(); + packs.forEach(item->{ + log.info("包名为: "+item); + ScanResult clazzes = PackageScannerUtil.scanResultWithPackage(item); + for (ClassInfo info : clazzes.getAllClasses()) { + Class Obj = info.loadClass(); + classes.add(Obj); + } + }); + for (Class clazz : classes) { + if (Contract.class.isAssignableFrom(clazz)) { + fiscoClient.deploy(clazz.getSimpleName(),clazz,bcosSDK); + } + } + + } + } + + } +} diff --git a/src/main/java/zyt/fiscobcos/deploy/DeployFileContract.java b/src/main/java/zyt/fiscobcos/deploy/DeployFileContract.java new file mode 100644 index 0000000..a4f90ef --- /dev/null +++ b/src/main/java/zyt/fiscobcos/deploy/DeployFileContract.java @@ -0,0 +1,48 @@ +package zyt.fiscobcos.deploy; + +import org.fisco.bcos.sdk.v3.BcosSDK; +import org.springframework.boot.CommandLineRunner; +import zyt.fiscobcos.FManager; +import zyt.fiscobcos.annotion.EnableDeploy; +import zyt.fiscobcos.client.FiscoClient; +import zyt.fiscobcos.utils.PackageScannerUtil; +import zyt.fiscobcos.config.FiscoBcosConfigProperties; + +import java.lang.reflect.InvocationTargetException; +import java.util.Arrays; +import java.util.List; +import java.util.Set; + +/** + * 根据配置文件部署合约 + * @author zyt + * @date 2023/09/28 + */ +public class DeployFileContract implements CommandLineRunner { + + @Override + public void run(String... args) { + FiscoClient fiscoClient = FManager.getFiscoClient(); + BcosSDK bcosSDK = FManager.getBcosSDK(); + FiscoBcosConfigProperties properties = FManager.getFiscoBcosConfigProperties(); + if (properties.isEnabled()) { + String basePackage = properties.getBasePackages(); + String[] basePackages = basePackage.split(","); + List basePackageList = Arrays.asList(basePackages); + basePackageList.forEach(pack->{ + Set> classes = PackageScannerUtil.scanWithPackage(pack); + // 处理扫描到的类 + for (Class clazz : classes) { + if (clazz.isAnnotationPresent(EnableDeploy.class)) { + try { + fiscoClient.deploy(clazz.getSimpleName(),clazz,bcosSDK); + } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { + e.printStackTrace(); + } + } + } + }); + } + } + +} diff --git a/src/main/java/zyt/fiscobcos/entity/ResponseData.java b/src/main/java/zyt/fiscobcos/entity/ResponseData.java new file mode 100644 index 0000000..9b145a7 --- /dev/null +++ b/src/main/java/zyt/fiscobcos/entity/ResponseData.java @@ -0,0 +1,67 @@ +package zyt.fiscobcos.entity; + +/** + * @Author: zyt + * @Description:结果集 + * @Date: Created in 13:35 2021/1/8 + */ +@SuppressWarnings("unchecked") +public class ResponseData { + + private int code; + private String msg; + private T data; + + public static ResponseData success(String msg) { + ResponseData responseData = new ResponseData(); + responseData.setCode(200); + responseData.setMsg(msg); + return responseData; + } + + public static ResponseData success(T t) { + ResponseData responseData = new ResponseData(); + responseData.setCode(200); + responseData.setData(t); + return responseData; + } + + public static ResponseData error(String msg) { + ResponseData responseData = new ResponseData(); + responseData.setCode(500); + responseData.setMsg(msg); + return responseData; + } + + public static ResponseData error(T t) { + ResponseData responseData = new ResponseData(); + responseData.setCode(500); + responseData.setData(t); + return responseData; + } + + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + + public T getData() { + return data; + } + + public void setData(T data) { + this.data = data; + } +} diff --git a/src/main/java/zyt/fiscobcos/utils/PackageScannerUtil.java b/src/main/java/zyt/fiscobcos/utils/PackageScannerUtil.java new file mode 100644 index 0000000..32e2149 --- /dev/null +++ b/src/main/java/zyt/fiscobcos/utils/PackageScannerUtil.java @@ -0,0 +1,88 @@ +package zyt.fiscobcos.utils; + +import io.github.classgraph.ClassGraph; +import io.github.classgraph.ClassInfo; +import io.github.classgraph.ClassInfoList; +import io.github.classgraph.ScanResult; +import org.springframework.core.annotation.AnnotationUtils; +import zyt.fiscobcos.annotion.EnableScan; + +import java.io.File; +import java.lang.annotation.Annotation; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * 自定义包扫描工具类 + * @author zyt + * @date 2023/09/28 + */ +public class PackageScannerUtil { + + private PackageScannerUtil() { + } + + /** + * 获取ClassGraph的实例 + */ + public static final ClassGraph classGraphInstance = new ClassGraph(); + + /** + * 根据包名扫描类 + * @param packageName + * @return + */ + public static Set> scanWithPackage(String packageName) { + ScanResult scanResult = classGraphInstance.enableAllInfo().acceptPackages(packageName).scan(); + Set> classes = addClass(scanResult.getAllClasses()); + return classes; + } + + /** + * + * @param packageName + * @return + */ + public static ScanResult scanResultWithPackage(String packageName) { + ScanResult scanResult = classGraphInstance.enableAllInfo().acceptPackages(packageName).scan(); + return scanResult; + } + + /** + * 根据扫描带有注解的类 + * @return + */ + public static Set> scanWithAnnotation(final Class annotation) { + ScanResult scanResult = classGraphInstance.enableAllInfo().scan(); + ClassInfoList classInfoList = scanResult.getClassesWithAnnotation(annotation); + Set> classes = addClass(classInfoList); + return classes; + } + + + public static ClassInfoList scanClassInfoWithAnnotation(final Class annotation) { + ScanResult scanResult = classGraphInstance.enableAllInfo().scan(); + ClassInfoList classInfoList = scanResult.getClassesWithAnnotation(annotation); + return classInfoList; + } + + + /** + * 添加类 + * @param classInfoList + * @return + */ + private static Set> addClass(ClassInfoList classInfoList) { + Set> classes = new HashSet<>(); + for (ClassInfo classInfo : classInfoList) { + Class clazz = classInfo.loadClass(); + classes.add(clazz); + } + return classes; + } + + +} diff --git a/src/main/java/zyt/fiscobcos/utils/SpringUtils.java b/src/main/java/zyt/fiscobcos/utils/SpringUtils.java new file mode 100644 index 0000000..6203679 --- /dev/null +++ b/src/main/java/zyt/fiscobcos/utils/SpringUtils.java @@ -0,0 +1,121 @@ +package zyt.fiscobcos.utils; + +import org.springframework.aop.framework.AopContext; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.beans.factory.config.BeanFactoryPostProcessor; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.stereotype.Component; + +/** + * @Author: zyt + * @Date: Created in 10:09 2021/1/7 + * @Description:spring相关工具类 + */ +@Component +public final class SpringUtils implements BeanFactoryPostProcessor, ApplicationContextAware { + /** + * Spring应用上下文环境 + */ + private static ConfigurableListableBeanFactory beanFactory; + + private static ApplicationContext applicationContext; + + @Override + public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { + SpringUtils.beanFactory = beanFactory; + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + SpringUtils.applicationContext = applicationContext; + } + + /** + * 获取对象 + * + * @param name + * @return Object 一个以所给名字注册的bean的实例 + * @throws BeansException + */ + @SuppressWarnings("unchecked") + public static T getBean(String name) throws BeansException { + return (T) beanFactory.getBean(name); + } + + /** + * 获取类型为requiredType的对象 + * + * @param clz + * @return + * @throws BeansException + */ + public static T getBean(Class clz) throws BeansException { + T result = (T) beanFactory.getBean(clz); + return result; + } + + /** + * 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true + * + * @param name + * @return boolean + */ + public static boolean containsBean(String name) { + return beanFactory.containsBean(name); + } + + /** + * 判断以给定名字注册的bean定义是一个singleton还是一个prototype。 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException) + * + * @param name + * @return boolean + * @throws NoSuchBeanDefinitionException + */ + public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException { + return beanFactory.isSingleton(name); + } + + /** + * @param name + * @return Class 注册对象的类型 + * @throws NoSuchBeanDefinitionException + */ + public static Class getType(String name) throws NoSuchBeanDefinitionException { + return beanFactory.getType(name); + } + + /** + * 如果给定的bean名字在bean定义中有别名,则返回这些别名 + * + * @param name + * @return + * @throws NoSuchBeanDefinitionException + */ + public static String[] getAliases(String name) throws NoSuchBeanDefinitionException { + return beanFactory.getAliases(name); + } + + /** + * 获取aop代理对象 + * + * @param invoker + * @return + */ + @SuppressWarnings("unchecked") + public static T getAopProxy(T invoker) { + return (T) AopContext.currentProxy(); + } + + /** + * 获取当前的环境配置,无配置返回null + * + * @return 当前的环境配置 + */ + public static String[] getActiveProfiles() { + return applicationContext.getEnvironment().getActiveProfiles(); + } + +} diff --git a/src/main/resources/META-INF/spring.factories b/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000..991f558 --- /dev/null +++ b/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +zyt.fiscobcos.FiscoBcosRegister,zyt.fiscobcos.FiscoBcosInject \ No newline at end of file diff --git a/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..6edcd1f --- /dev/null +++ b/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,2 @@ +zyt.fiscobcos.FiscoBcosRegister +zyt.fiscobcos.FiscoBcosInject \ No newline at end of file diff --git a/src/main/resources/abi/HelloWorld.abi b/src/main/resources/abi/HelloWorld.abi deleted file mode 100644 index 2ef8b08..0000000 --- a/src/main/resources/abi/HelloWorld.abi +++ /dev/null @@ -1 +0,0 @@ -[{"constant":false,"inputs":[{"name":"n","type":"string"}],"name":"set","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"name":"a","type":"string"}],"name":"test","type":"event"}] \ No newline at end of file diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties deleted file mode 100644 index bdec3fe..0000000 --- a/src/main/resources/application.properties +++ /dev/null @@ -1,15 +0,0 @@ -### Java sdk configuration, compatible with java sdk config: -cryptoMaterial.certPath=conf -cryptoMaterial.useSMCrypto=false -network.peers[0]=127.0.0.1:20200 - -### System configuration -system.groupName=group0 - -### Springboot configuration -server.port=8080 -server.session.timeout=60 -banner.charset=UTF-8 -spring.jackson.date-format=yyyy-MM-dd HH:mm:ss -spring.jackson.time-zone=GMT+8 - diff --git a/src/main/resources/banner.txt b/src/main/resources/banner.txt new file mode 100644 index 0000000..c48be36 --- /dev/null +++ b/src/main/resources/banner.txt @@ -0,0 +1,8 @@ + __ _ _ _ _ _ _ _ + / _(_) | | (_) | | | | | | | | +| |_ _ ___ ___ ___ | |__ ___ ___ ___ ______ ___ _ __ _ __ _ _ __ __ _| |__ ___ ___ | |_ ______ ___| |_ __ _ _ __| |_ ___ _ __ +| _| / __|/ __/ _ \| '_ \ / __/ _ \/ __|______/ __| '_ \| '__| | '_ \ / _` | '_ \ / _ \ / _ \| __|______/ __| __/ _` | '__| __/ _ \ '__| +| | | \__ \ (_| (_) | |_) | (_| (_) \__ \ \__ \ |_) | | | | | | | (_| | |_) | (_) | (_) | |_ \__ \ || (_| | | | || __/ | +|_| |_|___/\___\___/|_.__/ \___\___/|___/ |___/ .__/|_| |_|_| |_|\__, |_.__/ \___/ \___/ \__| |___/\__\__,_|_| \__\___|_| + | | __/ | + |_| |___/ diff --git a/src/main/resources/bin/HelloWorld.bin b/src/main/resources/bin/HelloWorld.bin deleted file mode 100644 index 3ec543c..0000000 --- a/src/main/resources/bin/HelloWorld.bin +++ /dev/null @@ -1 +0,0 @@ -608060405234801561001057600080fd5b506040805190810160405280600d81526020017f48656c6c6f2c20576f726c6421000000000000000000000000000000000000008152506000908051906020019061005c929190610062565b50610107565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106100a357805160ff19168380011785556100d1565b828001600101855582156100d1579182015b828111156100d05782518255916020019190600101906100b5565b5b5090506100de91906100e2565b5090565b61010491905b808211156101005760008160009055506001016100e8565b5090565b90565b6102d7806101166000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680634ed3885e146100515780636d4ce63c146100ba575b600080fd5b34801561005d57600080fd5b506100b8600480360381019080803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050919291929050505061014a565b005b3480156100c657600080fd5b506100cf610164565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561010f5780820151818401526020810190506100f4565b50505050905090810190601f16801561013c5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b8060009080519060200190610160929190610206565b5050565b606060008054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156101fc5780601f106101d1576101008083540402835291602001916101fc565b820191906000526020600020905b8154815290600101906020018083116101df57829003601f168201915b5050505050905090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061024757805160ff1916838001178555610275565b82800160010185558215610275579182015b82811115610274578251825591602001919060010190610259565b5b5090506102829190610286565b5090565b6102a891905b808211156102a457600081600090555060010161028c565b5090565b905600a165627a7a723058208d205e6922ee3b589e7a309d17cf4242e651ca1b44593d68eae39f57f69751cd0029 \ No newline at end of file diff --git a/src/main/resources/bin/HelloWorldSM.bin b/src/main/resources/bin/HelloWorldSM.bin deleted file mode 100644 index fe1f959..0000000 --- a/src/main/resources/bin/HelloWorldSM.bin +++ /dev/null @@ -1 +0,0 @@ -608060405234801561001057600080fd5b506040805190810160405280600d81526020017f48656c6c6f2c20576f726c6421000000000000000000000000000000000000008152506000908051906020019061005c929190610062565b50610107565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106100a357805160ff19168380011785556100d1565b828001600101855582156100d1579182015b828111156100d05782518255916020019190600101906100b5565b5b5090506100de91906100e2565b5090565b61010491905b808211156101005760008160009055506001016100e8565b5090565b90565b6102d7806101166000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063299f7f9d146100515780633590b49f146100e1575b600080fd5b34801561005d57600080fd5b5061006661014a565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100a657808201518184015260208101905061008b565b50505050905090810190601f1680156100d35780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156100ed57600080fd5b50610148600480360381019080803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843782019150505050505091929192905050506101ec565b005b606060008054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156101e25780601f106101b7576101008083540402835291602001916101e2565b820191906000526020600020905b8154815290600101906020018083116101c557829003601f168201915b5050505050905090565b8060009080519060200190610202929190610206565b5050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061024757805160ff1916838001178555610275565b82800160010185558215610275579182015b82811115610274578251825591602001919060010190610259565b5b5090506102829190610286565b5090565b6102a891905b808211156102a457600081600090555060010161028c565b5090565b905600a165627a7a723058202fc789856b94181b1a9e5bf064bf970b70767f0b5c6b890ad01313e5cbf603870029 \ No newline at end of file diff --git a/src/main/resources/clog.ini b/src/main/resources/clog.ini deleted file mode 100644 index d6647b9..0000000 --- a/src/main/resources/clog.ini +++ /dev/null @@ -1,9 +0,0 @@ -[log] - enable=true - log_path=./log - ; network statistics interval, unit is second, default is 60s - stat_flush_interval=60 - ; info debug trace - level=DEBUG - ; MB - max_log_file_size=200 diff --git a/src/main/resources/conf/cert.cnf b/src/main/resources/conf/cert.cnf deleted file mode 100644 index 552b4cb..0000000 --- a/src/main/resources/conf/cert.cnf +++ /dev/null @@ -1,29 +0,0 @@ -[ca] -default_ca=default_ca -[default_ca] -default_days = 3650 -default_md = sha256 - -[req] -distinguished_name = req_distinguished_name -req_extensions = v3_req -[req_distinguished_name] -countryName = CN -countryName_default = CN -stateOrProvinceName = State or Province Name (full name) -stateOrProvinceName_default =GuangDong -localityName = Locality Name (eg, city) -localityName_default = ShenZhen -organizationalUnitName = Organizational Unit Name (eg, section) -organizationalUnitName_default = FISCO-BCOS -commonName = Organizational commonName (eg, FISCO-BCOS) -commonName_default = FISCO-BCOS -commonName_max = 64 - -[ v3_req ] -basicConstraints = CA:FALSE -keyUsage = nonRepudiation, digitalSignature, keyEncipherment - -[ v4_req ] -basicConstraints = CA:TRUE - diff --git a/src/main/resources/conf/clog.ini b/src/main/resources/conf/clog.ini deleted file mode 100644 index d6647b9..0000000 --- a/src/main/resources/conf/clog.ini +++ /dev/null @@ -1,9 +0,0 @@ -[log] - enable=true - log_path=./log - ; network statistics interval, unit is second, default is 60s - stat_flush_interval=60 - ; info debug trace - level=DEBUG - ; MB - max_log_file_size=200 diff --git a/src/main/resources/contracts/My.sol b/src/main/resources/contracts/My.sol new file mode 100644 index 0000000..dbaeff6 --- /dev/null +++ b/src/main/resources/contracts/My.sol @@ -0,0 +1,95 @@ +pragma solidity >=0.6.10 <0.8.20; +pragma experimental ABIEncoderV2; + +import "./TableV320.sol"; + +contract My { + event CreateResult(int256 count); + event InsertResult(int256 count); + event UpdateResult(int256 count); + event RemoveResult(int256 count); + + Cast constant cast = Cast(address(0x100f)); + TableManager constant tm = TableManager(address(0x1002)); + Table table; + string constant TABLE_NAME = "z11"; + string [] properties = ["name","age","status"]; + string primaryKey = "id"; + string[] public dynamicStringArray; + constructor () public { + // create table + TableInfo memory tf = TableInfo(KeyOrder.Lexicographic ,primaryKey, properties); + + tm.createTable(TABLE_NAME, tf); + address t_address = tm.openTable(TABLE_NAME); + require(t_address!=address(0x0),""); + table = Table(t_address); + } + + function selectById(string memory id) public payable returns (string []memory) + { + + clearArray(dynamicStringArray); + Entry memory entry = table.select(id); + for (uint256 i=0;i value) throws Exception { + FiscoClient fiscoClient = FManager.getFiscoClient(); + fiscoClient.insert(value,"MyContract", MyContract.class); + return ResponseData.success("新增成功"); + } + + @PutMapping("/update") + public ResponseData updateById(@RequestBody List value) throws Exception { + FiscoClient fiscoClient = FManager.getFiscoClient(); + fiscoClient.updateById(value,"MyContract", MyContract.class); + return ResponseData.success("修改成功"); + } + + @DeleteMapping("/remove/{id}") + public ResponseData removeById(@PathVariable("id") String id) throws Exception { + FiscoClient fiscoClient = FManager.getFiscoClient(); + fiscoClient.removeById(id,"MyContract", MyContract.class); + return ResponseData.success("删除成功"); + } +} \ No newline at end of file From d8a1856287951d7620990dcacfafb79f088b23d5 Mon Sep 17 00:00:00 2001 From: zyt <1543844906@qq.com> Date: Wed, 18 Oct 2023 09:14:28 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E5=88=A0=E9=99=A4license?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- LICENSE | 201 -------------------------------------------------------- 1 file changed, 201 deletions(-) delete mode 100644 LICENSE diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 261eeb9..0000000 --- a/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License.