回调java 简书_web3j函数回调使用详解
前面solc和web3编译和加载代码的步骤参考其他文章。
web3j中deploy代码
solidity代码
pragma solidity >0.4.18;
contract SimpleVoting {
bytes32[] public candidateList;
mapping (bytes32 => uint8) public votesReceived;
constructor(bytes32[] memory candidateNames) public {
candidateList = candidateNames;
}
function voteForCandidate(bytes32 candidate) public {
require(validCandidate(candidate));
votesReceived[candidate] += 1;
}
function totalVotesFor(bytes32 candidate) view public returns (uint8) {
require(validCandidate(candidate));
return votesReceived[candidate];
}
function validCandidate(bytes32 candidate) view public returns (bool) {
for(uint8 i = 0; i < candidateList.length; i++) {
if(candidateList[i] == candidate)
return true;
}
return false;
}
}
编译后的java代码(有些部分需要手动修改,后文会写道):
package com.gason.blockchain.eth;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import org.web3j.abi.FunctionEncoder;
import org.web3j.abi.TypeReference;
import org.web3j.abi.datatypes.Bool;
import org.web3j.abi.datatypes.Function;
import org.web3j.abi.datatypes.Type;
import org.web3j.abi.datatypes.generated.Bytes32;
import org.web3j.abi.datatypes.generated.Uint8;
import org.web3j.crypto.Credentials;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.core.RemoteCall;
import org.web3j.protocol.core.RemoteFunctionCall;
import org.web3j.protocol.core.methods.response.TransactionReceipt;
import org.web3j.tx.Contract;
import org.web3j.tx.TransactionManager;
import org.web3j.tx.gas.ContractGasProvider;
/**
*
Auto generated code.
*
Do not modify!
*
Please use the web3j command line tools,
* or the org.web3j.codegen.SolidityFunctionWrapperGenerator in the
* codegen module to update.
*
*
Generated with web3j version 4.5.5.
*/
@SuppressWarnings("rawtypes")
public class SimpleVoting extends Contract {
private static final String BINARY = "";
public static final String FUNC_CANDIDATELIST = "candidateList";
public static final String FUNC_TOTALVOTESFOR = "totalVotesFor";
public static final String FUNC_VALIDCANDIDATE = "validCandidate";
public static final String FUNC_VOTEFORCANDIDATE = "voteForCandidate";
public static final String FUNC_VOTESRECEIVED = "votesReceived";
@Deprecated
protected SimpleVoting(String contractAddress, Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) {
super(BINARY, contractAddress, web3j, credentials, gasPrice, gasLimit);
}
protected SimpleVoting(String contractAddress, Web3j web3j, Credentials credentials, ContractGasProvider contractGasProvider) {
super(BINARY, contractAddress, web3j, credentials, contractGasProvider);
}
@Deprecated
protected SimpleVoting(String contractAddress, Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit) {
super(BINARY, contractAddress, web3j, transactionManager, gasPrice, gasLimit);
}
protected SimpleVoting(String contractAddress, Web3j web3j, TransactionManager transactionManager, ContractGasProvider contractGasProvider) {
super(BINARY, contractAddress, web3j, transactionManager, contractGasProvider);
}
public RemoteFunctionCall candidateList(BigInteger param0) {
final Function function = new Function(
FUNC_CANDIDATELIST,
Arrays.asList(new org.web3j.abi.datatypes.generated.Uint256(param0)),
Arrays.>asList(new TypeReference() {
}));
return executeRemoteCallSingleValueReturn(function);
}
public RemoteFunctionCall totalVotesFor(String candidate) {
final Function function = new Function(
FUNC_TOTALVOTESFOR,
Arrays.asList(new org.web3j.abi.datatypes.generated.Bytes32(StrToByte(candidate))),
Arrays.>asList(new TypeReference() {
}));
return executeRemoteCallSingleValueReturn(function);
}
public RemoteFunctionCall validCandidate(String candidate) {
final Function function = new Function(
FUNC_VALIDCANDIDATE,
Arrays.asList(new org.web3j.abi.datatypes.generated.Bytes32(StrToByte(candidate))),
Arrays.>asList(new TypeReference() {
}));
return executeRemoteCallSingleValueReturn(function);
}
public RemoteFunctionCall voteForCandidate(String candidate) {
final Function function = new Function(
FUNC_VOTEFORCANDIDATE,
Arrays.asList(new org.web3j.abi.datatypes.generated.Bytes32(StrToByte(candidate))),
Collections.>emptyList());
return executeRemoteCallTransaction(function);
}
public RemoteFunctionCall votesReceived(byte[] param0) {
final Function function = new Function(
FUNC_VOTESRECEIVED,
Arrays.asList(new org.web3j.abi.datatypes.generated.Bytes32(param0)),
Collections.>emptyList());
return executeRemoteCallTransaction(function);
}
@Deprecated
public static SimpleVoting load(String contractAddress, Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) {
return new SimpleVoting(contractAddress, web3j, credentials, gasPrice, gasLimit);
}
@Deprecated
public static SimpleVoting load(String contractAddress, Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit) {
return new SimpleVoting(contractAddress, web3j, transactionManager, gasPrice, gasLimit);
}
public static SimpleVoting load(String contractAddress, Web3j web3j, Credentials credentials, ContractGasProvider contractGasProvider) {
return new SimpleVoting(contractAddress, web3j, credentials, contractGasProvider);
}
public static SimpleVoting load(String contractAddress, Web3j web3j, TransactionManager transactionManager, ContractGasProvider contractGasProvider) {
return new SimpleVoting(contractAddress, web3j, transactionManager, contractGasProvider);
}
public static RemoteCall deploy(Web3j web3j, Credentials credentials, ContractGasProvider contractGasProvider, List candidateNames) {
String encodedConstructor = FunctionEncoder.encodeConstructor(Arrays.asList(new org.web3j.abi.datatypes.DynamicArray(
org.web3j.abi.datatypes.generated.Bytes32.class,
org.web3j.abi.Utils.typeMap(candidateNames, org.web3j.abi.datatypes.generated.Bytes32.class))));
return deployRemoteCall(SimpleVoting.class, web3j, credentials, contractGasProvider, BINARY, encodedConstructor);
}
public static RemoteCall deploy(Web3j web3j, TransactionManager transactionManager, ContractGasProvider contractGasProvider, List candidateNames) {
String encodedConstructor = FunctionEncoder.encodeConstructor(Arrays.asList(new org.web3j.abi.datatypes.DynamicArray(
org.web3j.abi.datatypes.generated.Bytes32.class,
org.web3j.abi.Utils.typeMap(candidateNames, org.web3j.abi.datatypes.generated.Bytes32.class))));
return deployRemoteCall(SimpleVoting.class, web3j, transactionManager, contractGasProvider, BINARY, encodedConstructor);
}
@Deprecated
public static RemoteCall deploy(Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit, List candidateNames) {
String encodedConstructor = FunctionEncoder.encodeConstructor(Arrays.asList(new org.web3j.abi.datatypes.DynamicArray(
org.web3j.abi.datatypes.generated.Bytes32.class,
org.web3j.abi.Utils.typeMap(candidateNames, org.web3j.abi.datatypes.generated.Bytes32.class))));
return deployRemoteCall(SimpleVoting.class, web3j, credentials, gasPrice, gasLimit, BINARY, encodedConstructor);
}
@Deprecated
public static RemoteCall deploy(Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit, List candidateNames) {
String encodedConstructor = FunctionEncoder.encodeConstructor(Arrays.asList(new org.web3j.abi.datatypes.DynamicArray(
org.web3j.abi.datatypes.generated.Bytes32.class,
org.web3j.abi.Utils.typeMap(candidateNames, org.web3j.abi.datatypes.generated.Bytes32.class))));
return deployRemoteCall(SimpleVoting.class, web3j, transactionManager, gasPrice, gasLimit, BINARY, encodedConstructor);
}
public static RemoteCall deployByString(Web3j web3j, Credentials credentials, ContractGasProvider contractGasProvider, List candidateNames) {
List candidateNamesByte = candidateNames.stream().map(val -> StrToByte(val)).collect(Collectors.toList());
String encodedConstructor = FunctionEncoder.encodeConstructor(Arrays.asList(new org.web3j.abi.datatypes.DynamicArray(
org.web3j.abi.datatypes.generated.Bytes32.class,
org.web3j.abi.Utils.typeMap(candidateNamesByte, org.web3j.abi.datatypes.generated.Bytes32.class))));
return deployRemoteCall(SimpleVoting.class, web3j, credentials, contractGasProvider, BINARY, encodedConstructor);
}
public static byte[] StrToByte(String str) {
byte[] byteValue = str.getBytes();
byte[] byteValueLen32 = new byte[32];
System.arraycopy(byteValue, 0, byteValueLen32, 0, byteValue.length);
return byteValueLen32;
}
}
使用java进行部署:
String pk="";//写你私钥
Web3j web3 = Web3j.build(new HttpService());
ContractGasProvider contractGasProvider = new DefaultGasProvider();
Credentials credentials = Credentials.create(pk);
List candidateNames = Arrays.asList("Bob", "Tom", "Jerry");
SimpleVoting registryContract = SimpleVoting.deployByString(web3, credentials, contractGasProvider, candidateNames).sendAsync().get();
// 合约地址,记得保存
System.out.println(registryContract.getContractAddress());
web3j中的方法调用
注意:solidity中的byte32[]类型与Java中String的转换,String需要转为byte32[]
public static byte[] StrToByte(String str) {
byte[] byteValue = str.getBytes();
byte[] byteValueLen32 = new byte[32];
System.arraycopy(byteValue, 0, byteValueLen32, 0, byteValue.length);
return byteValueLen32;
}
无返回值
solidity代码:
function voteForCandidate(bytes32 candidate) public {
require(validCandidate(candidate));
votesReceived[candidate] += 1;
}
java编译后:
executeRemoteCallTransaction无返回值,Function中第一个参数为函数名,第二个为输入参数集合,第二为返回参数集合,如果无返回参数,就输入 Collections.>emptyList()
public RemoteFunctionCall voteForCandidate(String candidate) {
final Function function = new Function(
"voteForCandidate",
Arrays.asList(new org.web3j.abi.datatypes.generated.Bytes32(StrToByte(candidate))),
Collections.>emptyList());
return executeRemoteCallTransaction(function);
}
调用:
Web3j web3 = Web3j.build(new HttpService()); // defaults to http://localhost:8545/
ContractGasProvider contractGasProvider = new DefaultGasProvider();
//PK为你的私钥
Credentials credentials = Credentials.create(PK);
//address为你之前部署后返回的合约地址
SimpleVoting registryContract = SimpleVoting.load(address, web3, credentials, contractGasProvider);
registryContract.voteForCandidate("Bob").sendAsync().get();
单个参数返回
solidity:
function totalVotesFor(bytes32 candidate) view public returns (uint8) {
require(validCandidate(candidate));
return votesReceived[candidate];
}
java编译后,executeRemoteCallSingleValueReturn为单个参数返回,
public RemoteFunctionCall totalVotesFor(String candidate) {
final Function function = new Function(
"totalVotesFor",
Arrays.asList(new org.web3j.abi.datatypes.generated.Bytes32(StrToByte(candidate))),
Arrays.>asList(new TypeReference() {
}));
return executeRemoteCallSingleValueReturn(function);
}
调用:
Web3j web3 = Web3j.build(new HttpService()); // defaults to http://localhost:8545/
ContractGasProvider contractGasProvider = new DefaultGasProvider();
Credentials credentials = Credentials.create(PK);
SimpleVoting registryContract = SimpleVoting.load(address, web3, credentials, contractGasProvider);
System.out.println(registryContract.totalVotesFor("Bob").sendAsync().get().getValue());
多参数返回
solidity代码:
pragma solidity >0.4.0;
// 官方文档众筹实现
// https://solidity.readthedocs.io/en/develop/types.html#structs
// 独立实现
contract CrowdFunding {
// 众筹项目
struct Fund {
// 众筹地址
address owner;
// 众筹描述
string desc;
// 众筹目标
uint goal;
// 已筹金币
uint coins;
// 是否结束
bool finished;
// 捐赠人数
uint recordCounts;
// 捐赠记录
mapping(uint => Record) records;
// 原本使用 Record[] records 数组定义
// 但是貌似目前版本尚不支持
// 于是将 数组 拆分成 长度 + 映射
// https://solidity.readthedocs.io/en/develop/types.html#mappings
}
// 捐赠记录
struct Record {
// 捐赠成员
address member;
// 捐赠金币
uint coin;
// 捐赠时间
uint time;
}
// 众筹地址列表
Fund[] funds;
// 获取众筹项目数量
function getFundCount() public view returns (uint) {
return funds.length;
}
// 获取众筹项目信息
// 参数:项目编号
// 返回:众筹地址 众筹描述 众筹目标 已筹金币 是否结束
function getFundInfo(uint fundIndex) public view returns (address, string memory, uint, uint, bool) {
Fund storage fund = funds[fundIndex];
return (fund.owner, fund.desc, fund.goal, fund.coins, fund.finished);
}
// 获取众筹捐赠人数
function getRecordCount(uint fundIndex) public view returns (uint) {
return funds[fundIndex].recordCounts;
}
// 获取众筹捐赠记录
// 参数:项目编号 记录编号
// 返回:捐赠成员 捐赠金币 捐赠时间
function getRecordInfo(uint fundIndex, uint recordIndex) public view returns (address, uint, uint) {
Record storage record = funds[fundIndex].records[recordIndex];
return (record.member, record.coin, record.time);
}
// 为自己发起众筹
function raiseFund(string memory info, uint goal) public {
funds.push(Fund(msg.sender, info, goal, 0, false, 0));
}
// 为别人发送金币
// https://solidity.readthedocs.io/en/latest/miscellaneous.html#modifiers
// payable for functions: Allows them to receive Ether together with a call.
function sendCoin(uint fundIndex) public payable {
// 默认属性
// msg.sender 转账账户
// msg.value 转账数目
// 智能合约默认单位 wei
// 1 ether = 10^18 wei
// 引用拷贝
Fund storage fund = funds[fundIndex];
require(!fund.finished);
// 转账 失败自动退出
address(uint256(fund.owner)).transfer(msg.value);
// 更新众筹信息
fund.coins += msg.value;
fund.records[fund.recordCounts++] = Record(msg.sender, msg.value, now);
fund.finished = fund.coins >= fund.goal * 1 ether ? true : false;
}
// 回退函数 防止抛出异常
// https://solidity.readthedocs.io/en/latest/contracts.html#fallback-function
// if you want your contract to receive Ether, you have to implement a fallback function.
// 后面两个函数是最新版本编译器所需要的,可能跟网上一些不一样
fallback () external payable { }
receive() external payable { }
}
java编译后(部分通过手工修改):
package com.gason.blockchain.eth;
import org.web3j.abi.FunctionEncoder;
import org.web3j.abi.TypeReference;
import org.web3j.abi.datatypes.*;
import org.web3j.abi.datatypes.generated.Uint256;
import org.web3j.crypto.Credentials;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.core.RemoteCall;
import org.web3j.protocol.core.methods.response.TransactionReceipt;
import org.web3j.tx.Contract;
import org.web3j.tx.gas.ContractGasProvider;
import org.web3j.utils.Convert;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.List;
public class CrowdFundingContract extends Contract implements CrowdFundingInterface {
private static final String BINARY = "";
/**
* CrowdFunding合约
*
* @param contractAddress 合约地址
* @param web3j RPC请求
* @param credentials 钱包凭证
* @param gasPrice GAS价格
* @param gasLimit GAS上限
*/
private CrowdFundingContract(String contractAddress, Web3j web3j, Credentials credentials, BigInteger gasPrice,
BigInteger gasLimit) {
super(BINARY, contractAddress, web3j, credentials, gasPrice, gasLimit);
}
protected CrowdFundingContract(String contractAddress, Web3j web3j, Credentials credentials, ContractGasProvider contractGasProvider) {
super(BINARY, contractAddress, web3j, credentials, contractGasProvider);
}
/**
* 部署合约
*
* @param web3j RPC请求
* @param credentials 钱包凭证
* @param gasPrice GAS价格
* @param gasLimit GAS上限
* @return
*/
public static RemoteCall deploy(Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) {
// 构造函数传参 NULL
String encodedConstructor = FunctionEncoder.encodeConstructor(Arrays.asList());
return deployRemoteCall(CrowdFundingContract.class, web3j, credentials, gasPrice, gasLimit, BINARY, encodedConstructor);
}
public static RemoteCall deploy(Web3j web3j, Credentials credentials, ContractGasProvider contractGasProvider) {
return deployRemoteCall(CrowdFundingContract.class, web3j, credentials, contractGasProvider, BINARY, "");
}
/**
* 加载合约
*
* @param contractAddress 合约地址
* @param web3j RPC请求
* @param credentials 钱包凭证
* @param gasPrice GAS价格
* @param gasLimit GAS上限
* @return
*/
public static CrowdFundingContract load(String contractAddress, Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) {
return new CrowdFundingContract(contractAddress, web3j, credentials, gasPrice, gasLimit);
}
public static CrowdFundingContract load(String contractAddress, Web3j web3j, Credentials credentials, ContractGasProvider contractGasProvider) {
return new CrowdFundingContract(contractAddress, web3j, credentials, contractGasProvider);
}
//
// crowdfunding.sol //
//
/**
* 获取众筹项目数量
* rinfo.get(0).getValue().toString()
* function getFundCount() public view returns (uint)
*/
@Override
public RemoteCall getFundCount() {
Function function = new Function("getFundCount", Arrays.asList(),
Arrays.>asList(new TypeReference() {
}));
return executeRemoteCallSingleValueReturn(function);
}
/**
* 获取众筹项目信息
* function getFundInfo(uint fundIndex) public view returns (address, string, uint, uint, bool)
*/
@Override
public RemoteCall> getFundInfo(int fundIndex) {
Function function = new Function("getFundInfo", Arrays.asList(new Uint256(fundIndex)),
Arrays.>asList(new TypeReference
() {}, new TypeReference() {
}, new TypeReference() {
}, new TypeReference() {
}, new TypeReference() {
}));
return executeRemoteCallMultipleValueReturn(function);
}
/**
* 获取众筹捐赠人数
* function getRecordCount(uint fundIndex) public view returns (uint)
*/
@Override
public RemoteCall getRecordCount(int fundIndex) {
Function function = new Function("getRecordCount", Arrays.asList(new Uint256(fundIndex)),
Arrays.>asList(new TypeReference() {
}));
return executeRemoteCallSingleValueReturn(function);
}
/**
* 获取众筹捐赠记录
* function getRecordInfo(uint fundIndex, uint recordIndex) public view returns (address, uint, uint)
*/
@Override
public RemoteCall> getRecordInfo(int fundIndex, int recordIndex) {
Function function = new Function("getRecordInfo", Arrays.asList(new Uint256(fundIndex), new Uint256(recordIndex)),
Arrays.>asList(new TypeReference
() {}, new TypeReference() {
}, new TypeReference() {
}));
return executeRemoteCallMultipleValueReturn(function);
}
/**
* 为自己发起众筹
* function raiseFund(string desc, uint goal) public
*/
@Override
public RemoteCall raiseFund(String desc, int goal) {
Function function = new Function("raiseFund", Arrays.asList(new Utf8String(desc), new Uint256(goal)),
Arrays.>asList());
return executeRemoteCallTransaction(function);
}
/**
* 为别人发送金币
* function sendCoin(uint fundIndex) public payable
*/
@Override
public RemoteCall sendCoin(int fundIndex, int coin) {
Function function = new Function("sendCoin", Arrays.asList(new Uint256(fundIndex)),
Arrays.>asList());
return executeRemoteCallTransaction(function, BigInteger.valueOf(coin).multiply(Convert.Unit.ETHER.getWeiFactor().toBigInteger()));
}
}
调用:
Web3j web3 = Web3j.build(new HttpService()); // defaults to http://localhost:8545/
ContractGasProvider contractGasProvider = new DefaultGasProvider();
Credentials credentials = Credentials.create(PK);
CrowdFundingContract registryContract = CrowdFundingContract.load(address, web3, credentials, contractGasProvider);
List outputs = registryContract.getFundInfo(0).sendAsync().get();
System.out.println("address:" + outputs.get(0).toString());
System.out.println("desc:" + outputs.get(1).toString());
System.out.println("goal:" + Integer.parseInt(outputs.get(2).getValue().toString()));
System.out.println("coins:" + new BigInteger(outputs.get(3).getValue().toString()).divide(Convert.Unit.ETHER.getWeiFactor().toBigInteger()).intValue());
System.out.println("finished:" + Boolean.parseBoolean(outputs.get(4).getValue().toString()));
回调java 简书_web3j函数回调使用详解相关推荐
- 回调java 简书_Java接口回调机制详解【转】
一.回调的含义和用途 1. 什么是回调? 一般来说,模块之间都存在一定的调用关系,从调用方式上看,可以分为三类:同步调用.异步调用和回调.同步调用是一种阻塞式调用,即在函数A的函数体里通过书写函数B的 ...
- java asynchronize_Java 中synchronize函数的实例详解
Java 中synchronize函数的实例详解 java中的一个类的成员函数若用synchronized来修饰,则对应同一个对象,多个线程像调用这个对象的这个同步函数时必须等到上一个线程调用完才能由 ...
- java type 简书_Java中的Type详解
ParameterizedType 参数化类型的使用 package com.keytop.att; /** * 实体类 * Created by fengwenhua on 2017/4/25. * ...
- java string()函数_转载java String.split()函数的用法详解
转载java String.split()函数的用法详解 如果您发现本文排版有问题,可以先点击下面的链接切换至老版进行查看!!!在java.lang包中有String.split()方法的原型是: p ...
- php的可变函数,php之可变函数的实例详解
php之可变函数的实例详解 php的可变函数,今天大概的了解下,是看php手册总结的,觉得用处不大: PHP 支持可变函数的概念.这意味着如果一个变量名后有圆括号,PHP 将寻找与变量的值同名的函数, ...
- 好程序员前端教程之JavaScript闭包和匿名函数的关系详解...
好程序员前端教程之JavaScript闭包和匿名函数的关系详解 本文讲的是关于JavaScript闭包和匿名函数两者之间的关系,从匿名函数概念到立即执行函数,最后到闭包.下面一起来看看文章分析,希望你 ...
- Java经典面试题整理及答案详解(三)
简介: 以下是某同学面试时,面试官问到的问题,关于面试题答案可以参考以下内容- 上一篇:Java经典面试题整理及答案详解(二) Java面试真题第三弹接住!相信通过前两节的学习,大家对于Java多少有 ...
- Java多线程编程中Future模式的详解
转载自 https://www.cnblogs.com/winkey4986/p/6203225.html Java多线程编程中,常用的多线程设计模式包括:Future模式.Master-Worker ...
- java throw与throws_基于Java中throw和throws的区别(详解)
系统自动抛出的异常 所有系统定义的编译和运行异常都可以由系统自动抛出,称为标准异常,并且 Java 强烈地要求应用程序进行完整的异常处理,给用户友好的提示,或者修正后使程序继续执行. 语句抛出的异常 ...
最新文章
- win2000堆的调试
- ASP.NET Web API 基本操作(CRUD)
- SQL Cookbook:一、检索记录(1)从表中检索所有行和列
- 【django】路由命名和路由反向解析
- Qt工作笔记-QLineEdit与QTextEdit与QPlainTextEdit区别与联系以及适用范围
- 最流行的自动化测试工具,总有一款适合你
- HTML精仿ios相册,iOS开发-仿微信相册选择Demo
- oracle 学习日志 ----Oracle时间加减
- 使用RMAN恢复目录(catalog)解析
- 开发中常用正则表达式
- excel 第六次人口普查_第六次全国人口普查表短表(标准版)
- 【前端】html页面的字体代码表及字体效果对比
- 低版本浏览器如何兼容html5,解决Vue兼容低版本浏览器的简单方法
- 【OpenCV】图像进行数字化操作:像素确定位置、获取像素BGR值、修改像素BGR值、修改指定区域内像素
- window10系统ie设置代理,保存不了的问题
- 不积跬步无以至千里,不积小流无以成江海
- python pyd 速度提升_pyd打包补充
- springboot+教学工作量管理系统 毕业设计-附源码221541
- vim简单用法-配合pycharm
- Android的Logcat命令详解:翻译Enabling logcat Logging