第一步配置API key:微信支付文档
第二步下载并配置商户证书:微信支付文档
第三步对接微信支付接口:微信支付文档
<!-- 微信支付API -->
<dependency>
<groupId>com.github.wechatpay-apiv3</groupId>
<artifactId>wechatpay-java</artifactId>
<version>0.2.12</version>
</dependency>
<!-- SBSS 用到的HTTP工具包:okhttp 3.13.1 -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.13.1</version>
</dependency>
<!--工具类-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.3.1</version>
</dependency>
weixin:
# AppID(小程序ID)
appId: xxxxxxx
# AppSecret(小程序密钥)
appSecret: xxxxxxx
# 接口链接
url: https://api.weixin.qq.com
# 认证类型
schema: xxxxxxx
# 商户号ID
mchid: xxxxxxx
# 商户证书序号
serialNo: xxxxxxx
# 商户私钥字符串
privateKey: xxxxxxx
#支付接口链接
payUrl: https://api.mch.weixin.qq.com
#回调接口链接
notifyUrl: https://xxx.xxx.com
#支付金额:1元
amount: 100
#apiv3密钥
apiV3Key: xxxxxxx
package com.example.demo.config;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
@Data
@Component
public class WechatConfig {
/**
* AppID(小程序ID)
*/
@Value("${weixin.appId}")
private String appId;
/**
* AppSecret(小程序密钥)
*/
@Value("${weixin.appSecret}")
private String appSecret;
/**
* 微信接口链接
*/
@Value("${weixin.url}")
private String url;
/**
* 商户私钥字符串(下载并配置商户证书中的私钥)
*/
@Value("${weixin.privateKey}")
private String privateKey;
/**
* 商户号
*/
@Value("${weixin.mchid}")
private String mchid;
/**
* 商户证书序号
*/
@Value("${weixin.serialNo}")
private String serialNo;
/**
* 认证类型
*/
@Value("${weixin.schema}")
private String schema;
/**
* 支付接口链接
*/
@Value("${weixin.payUrl}")
private String payUrl;
/**
* 回调路径
*/
@Value("${weixin.notifyUrl}")
private String notifyUrl;
/**
* 支付金额(单位是分)
*/
@Value("${weixin.amount}")
private BigDecimal amount;
/**
* 认证类型
*/
@Value("${weixin.apiV3Key}")
private String apiV3Key;
}
package com.example.demo.util;
import com.example.demo.config.WechatConfig;
import com.wechat.pay.java.core.util.PemUtil;
import okhttp3.HttpUrl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.util.Base64;
@Component
public class WechatCreateToken {
@Autowired
private WechatConfig wechatConfig;
/**
* 获取签名认证信息
* @param method 请求类型
* @param url 请求路径
* @param timestamp 时间戳
* @param nonceStr 随机数
* @param body 请求参数
* @return 结果
*/
public String getAuthorization(String method, HttpUrl url, long timestamp, String nonceStr, String body){
//构造签名串
String message = buildMessage(method, url, timestamp, nonceStr, body);
//Base64编码得到签名值
String signature = sign(message);
return "mchid=\"" + wechatConfig.getMchid() + "\","
+ "serial_no=\"" + wechatConfig.getSerialNo() + "\","
+ "nonce_str=\"" + nonceStr + "\","
+ "timestamp=\"" + timestamp + "\","
+ "signature=\"" + signature + "\"";
}
/**
* 构造签名串
* @param method 请求类型
* @param url 请求路径
* @param timestamp 时间戳
* @param nonceStr 随机数
* @param body 请求参数
* @return 结果
*/
String buildMessage(String method, HttpUrl url, long timestamp, String nonceStr, String body) {
String canonicalUrl = url.encodedPath();
if (url.encodedQuery() != null) {
canonicalUrl += "?" + url.encodedQuery();
}
return method + "\n"
+ canonicalUrl + "\n"
+ timestamp + "\n"
+ nonceStr + "\n"
+ body + "\n";
}
/**
*对签名结果进行Base64编码得到签名值
* @param message 参数
* @return 结果
*/
public String sign(String message){
try {
//加载商户私钥(privateKey:私钥字符串)
Signature sign = Signature.getInstance("SHA256withRSA");
PrivateKey merchantPrivateKey = PemUtil.loadPrivateKeyFromString(wechatConfig.getPrivateKey());
sign.initSign(merchantPrivateKey);
sign.update(message.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(sign.sign());
} catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) {
throw new IllegalArgumentException(e.getMessage());
}
}
/**
*获取支付签名值
* @param timestamp 时间戳
* @param nonceStr 随机数
* @param prepayId 预支付交易会话标识
* @return 结果
*/
public String getPaySignStr(long timestamp, String nonceStr,String prepayId){
//签名
String message = wechatConfig.getAppId() + "\n"
+ timestamp + "\n"
+ nonceStr + "\n"
+ "prepay_id=" + prepayId + "\n";
return sign(message);
}
}
package com.example.demo.util;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.example.demo.config.WechatConfig;
import okhttp3.HttpUrl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
@Component
public class WechatUtil {
@Autowired
private WechatConfig wechatConfig;
@Autowired
private WechatCreateToken wechatCreateToken;
/**
* 获取小程序全局唯一后台接口调用凭据,token有效期为7200s
* @return 结果
*/
public String getAccessToken(){
//请求参数
JSONObject paramMap = new JSONObject();
paramMap.put("grant_type","client_credential");
paramMap.put("appid", wechatConfig.getAppId());
paramMap.put("secret", wechatConfig.getAppSecret());
String body = HttpUtil.createGet(wechatConfig.getUrl() + "/cgi-bin/token")
.form(paramMap)
.execute()
.body();
//返回值
JSONObject result = JSONUtil.parseObj(body);
if (result.get("errcode") != null){
throw new IllegalArgumentException("获取token失败");
}
return result.get("access_token", String.class);
}
/**
* 手机号验证
* @param accessToken 接口调用凭证
* @param code 微信code
* @return 结果
*/
public String getPhoneNumber(String accessToken,String code){
//请求参数
JSONObject paramMap = new JSONObject();
paramMap.put("code", code);
String body = HttpUtil.createPost(wechatConfig.getUrl() + "/wxa/business/getuserphonenumber?access_token=" + accessToken)
.header("Content-Type", "application/json")
.body(paramMap.toString())
.execute()
.body();
//返回值
JSONObject result = JSONUtil.parseObj(body);
if (result.get("errcode").equals(0)){
//用户手机号信息
Map phoneInfo = result.get("phone_info", Map.class);
return String.valueOf(phoneInfo.get("phoneNumber"));
}else {
throw new IllegalArgumentException("code无效");
}
}
/**
* 获取用户openid
* @param code 微信code
* @return 结果
*/
public String getOpenid(String code){
//请求参数
JSONObject paramMap = new JSONObject();
paramMap.put("js_code", code);
paramMap.put("appid", wechatConfig.getAppId());
paramMap.put("secret", wechatConfig.getAppSecret());
paramMap.put("grant_type", "authorization_code");
String body = HttpUtil.createGet(wechatConfig.getUrl() + "/sns/jscode2session")
.form(paramMap)
.execute()
.body();
//返回值
JSONObject result = JSONUtil.parseObj(body);
if (result.get("openid") != null){
return result.get("openid", String.class);
}else {
throw new IllegalArgumentException("微信认证失败");
}
}
/**
*获取微信支付的必要参数
*/
public Map<String,Object> getPaySignParam(String openid) {
//商户订单号(自定义)
String orderNo = "WX" + DateUtil.format(new Date(), "yyyyMMddHHmmss") + RandomUtil.randomNumbers(12);
//预支付交易会话标识
String prepayId = getPrepayId(openid, orderNo);
//时间戳
long timestamp = System.currentTimeMillis() / 1000;
//随机数
String nonceStr = UUID.randomUUID().toString().replace("-", "");
//签名
String paySign = wechatCreateToken.getPaySignStr(timestamp, nonceStr, prepayId);
//返回参数
HashMap<String, Object> resultParam = new HashMap<>();
resultParam.put("orderId", orderNo);
resultParam.put("timeStamp", timestamp + "");
resultParam.put("nonceStr", nonceStr);
resultParam.put("package", "prepay_id=" + prepayId);
resultParam.put("signType", "RSA");
resultParam.put("paySign", paySign);
return resultParam;
}
/**
* 获取预支付交易会话标识(生成订单)
* @param openid 微信id
* @param orderNo 商户订单号
* @return 结果
*/
public String getPrepayId(String openid,String orderNo){
//请求参数
JSONObject param = new JSONObject();
//小程序id
param.put("appid", wechatConfig.getAppId());
//商户号id
param.put("mchid", wechatConfig.getMchid());
//商品描述
param.put("description", "xxx费用");
//商户订单号
param.put("out_trade_no", orderNo);
//支付通知回调接口(需要https路径)
param.put("notify_url", wechatConfig.getNotifyUrl() + "/notifyUrl");
//金额
JSONObject amountParam = new JSONObject();
amountParam.put("total", wechatConfig.getAmount());
amountParam.put("currency", "CNY");
param.put("amount", amountParam);
//支付者信息
JSONObject payerParam = new JSONObject();
payerParam.put("openid", openid);
param.put("payer",payerParam);
//随机数
String nonceStr = UUID.randomUUID().toString().replace("-", "");
//时间戳
long timestamp = System.currentTimeMillis() / 1000;
//下单生成预订单
String body = param.toString();
//生成签名
String authorization = wechatConfig.getSchema() + " " + wechatCreateToken.getAuthorization("POST", Objects.requireNonNull(HttpUrl.parse(wechatConfig.getPayUrl() + "/v3/pay/transactions/jsapi")), timestamp, nonceStr, body);
String result = HttpUtil.createPost(wechatConfig.getPayUrl() + "/v3/pay/transactions/jsapi")
.header("Authorization", authorization)
.header("Content-Type", "application/json")
.header("Accept","application/json")
.body(body)
.execute()
.body();
//返回值
JSONObject data = JSONUtil.parseObj(result);
if (data.get("prepay_id") == null){
throw new IllegalArgumentException("下单失败");
}
return data.get("prepay_id",String.class);
}
/**
*获取订单信息
*/
public Map<String,Object> getOrderInfo(String orderNo){
//请求参数
JSONObject paramMap = new JSONObject();
paramMap.put("mchid", wechatConfig.getMchid());
//随机数
String nonceStr = UUID.randomUUID().toString().replace("-", "");
//时间戳
long timestamp = System.currentTimeMillis() / 1000;
String authorization = wechatConfig.getSchema() + " " + wechatCreateToken.getAuthorization("GET", Objects.requireNonNull(HttpUrl.parse(wechatConfig.getPayUrl() + "/v3/pay/transactions/out-trade-no/" + orderNo + "?mchid=" + wechatConfig.getMchid())), timestamp, nonceStr, "");
String result = HttpUtil.createGet(wechatConfig.getPayUrl() + "/v3/pay/transactions/out-trade-no/" + orderNo)
.header("Authorization",authorization)
.header("Accept","application/json")
.form(paramMap)
.execute()
.body();
JSONObject data = JSONUtil.parseObj(result);
String tradeState = data.get("trade_state",String.class);
if ("SUCCESS".equals(tradeState)) {
//支付成功
Map<String,Object> map = new HashMap<>();
map.put("out_trade_no",data.get("out_trade_no",String.class));
map.put("success_time",data.get("success_time",Date.class));
BigDecimal money = new BigDecimal(data.get("amount", Map.class).get("payer_total").toString());
map.put("amount",money.divide(new BigDecimal(100),2, RoundingMode.HALF_UP));
return map;
} else {
throw new IllegalArgumentException("支付失败");
}
}
}
实体类
package com.example.demo.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import java.io.Serializable;
@Data
public class LoginDTO implements Serializable{
@NotBlank(message = "手机code不能为空")
@ApiModelProperty("手机code")
private String weixinCode;
@NotBlank(message = "登录code不能为空")
@ApiModelProperty("登录code")
private String loginCode;
}
package com.example.demo.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
@Data
public class WechatDTO implements Serializable {
@ApiModelProperty("随机串")
private String nonceStr;
@ApiModelProperty("签名")
private String signature;
@ApiModelProperty("证书序列号")
private String serialNo;
@ApiModelProperty("时间戳")
private String timestamp;
@ApiModelProperty("加密类型")
private String signatureType;
@ApiModelProperty("报文")
private String body;
}
控制层controller
package com.example.demo.controller;
import com.alibaba.fastjson.JSONObject;
import com.example.demo.dto.LoginDTO;
import com.example.demo.dto.WechatDTO;
import com.example.demo.service.WechatService;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Map;
@RestController
public class WechatController {
@Autowired
private WechatService wechatService;
@ApiOperation(value = "授权登录获取手机号")
@RequestMapping(value = "/auth", method = RequestMethod.POST)
public String login(@Valid @RequestBody LoginDTO loginDTO){
return wechatService.login(loginDTO);
}
@ApiOperation(value = "获取支付签名")
@GetMapping("/getPaySign")
public Map<String,Object> getPaySign(){
return wechatService.getPaySign();
}
@ApiOperation(value = "获取订单信息")
@GetMapping("/getOrderInfo")
public Map<String,Object> getOrderInfo(String orderNo){
return wechatService.getOrderInfo(orderNo);
}
@ApiOperation("支付通知(回调)")
@RequestMapping(value = "/notifyUrl",method = RequestMethod.POST)
@ResponseBody
public JSONObject payNotifyUrl(HttpServletRequest request) {
//获取报文
String body = getRequestBody(request);
//随机串
String nonceStr = request.getHeader("Wechatpay-Nonce");
//微信传递过来的签名
String signature = request.getHeader("Wechatpay-Signature");
//证书序列号(微信平台)
String serialNo = request.getHeader("Wechatpay-Serial");
//时间戳
String timestamp = request.getHeader("Wechatpay-Timestamp");
//加密类型
String signatureType = request.getHeader("Wechatpay-Signature-Type");
WechatDTO wechatDTO = new WechatDTO();
wechatDTO.setBody(body);
wechatDTO.setNonceStr(nonceStr);
wechatDTO.setSerialNo(serialNo);
wechatDTO.setTimestamp(timestamp);
wechatDTO.setSignatureType(signatureType);
wechatDTO.setSignature(signature);
wechatService.payNotifyUrl(wechatDTO);
JSONObject jsonObject = new JSONObject();
jsonObject.put("code","SUCCESS");
jsonObject.put("message","成功");
return jsonObject;
}
/**
* 读取请求数据流
*/
private String getRequestBody(HttpServletRequest request) {
StringBuffer sb = new StringBuffer();
try (ServletInputStream inputStream = request.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
) {
String line;
while ((line = reader.readLine()) != null) {
sb.append(line);
}
} catch (IOException e) {
throw new IllegalArgumentException(e);
}
return sb.toString();
}
}
service接口
package com.example.demo.service;
import com.example.demo.dto.LoginDTO;
import com.example.demo.dto.WechatDTO;
import java.util.Map;
public interface WechatService {
String login(LoginDTO loginDTO);
Map<String,Object> getPaySign();
void payNotifyUrl(WechatDTO wechatDTO);
Map<String, Object> getOrderInfo(String orderNo);
}
业务逻辑处理
package com.example.demo.service.impl;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import com.example.demo.config.WechatConfig;
import com.example.demo.dto.LoginDTO;
import com.example.demo.dto.WechatDTO;
import com.example.demo.service.WechatService;
import com.example.demo.util.AesUtil;
import com.example.demo.util.WechatUtil;
import com.wechat.pay.java.service.partnerpayments.jsapi.model.Transaction;
import com.wechat.pay.java.core.notification.NotificationParser;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.util.Map;
@Slf4j
@Service
public class WechatServiceImpl implements WechatService {
@Autowired
private WechatUtil wechatUtil;
@Autowired
private WechatConfig wechatConfig;
@Override
public String login(LoginDTO loginDTO) {
//获取微信用户ID,存储在数据库中
String openid = wechatUtil.getOpenid(loginDTO.getLoginCode());
//获取小程序全局唯一后台接口调用凭据
String accessToken = wechatUtil.getAccessToken();
//微信获取手机号
String phoneNumber = wechatUtil.getPhoneNumber(accessToken, loginDTO.getWeixinCode());
return phoneNumber;
}
@Override
public Map<String,Object> getPaySign() {
//获取数据库存储的微信id
String openid = "xxxx";
return wechatUtil.getPaySignParam(openid);
}
@Override
public Map<String, Object> getOrderInfo(String orderNo) {
return wechatUtil.getOrderInfo(orderNo);
}
@Override
public void payNotifyUrl(WechatDTO wechatDTO) {
//第一种
manualDecryption(wechatDTO);
//第二种
notificationParser(wechatDTO);
}
}
第一种使用AesUtil解密工具类
package com.example.demo.util;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class AesUtil {
static final int KEY_LENGTH_BYTE = 32;
static final int TAG_LENGTH_BIT = 128;
private final byte[] aesKey;
public AesUtil(byte[] key) {
if (key.length != KEY_LENGTH_BYTE) {
throw new IllegalArgumentException("无效的ApiV3Key,长度必须为32个字节");
}
this.aesKey = key;
}
public String decryptToString(byte[] associatedData, byte[] nonce, String ciphertext) throws GeneralSecurityException, IOException {
try {
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
SecretKeySpec key = new SecretKeySpec(aesKey, "AES");
GCMParameterSpec spec = new GCMParameterSpec(TAG_LENGTH_BIT, nonce);
cipher.init(Cipher.DECRYPT_MODE, key, spec);
cipher.updateAAD(associatedData);
return new String(cipher.doFinal(Base64.getDecoder().decode(ciphertext)), StandardCharsets.UTF_8);
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
throw new IllegalStateException(e);
} catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
throw new IllegalArgumentException(e);
}
}
}
业务处理
public void manualDecryption(WechatDTO wechatDTO){
//证书序列号(微信平台)
if (wechatDTO.getSerialNo().equals(wechatConfig.getSerialNo())){
throw new IllegalArgumentException("验签失败");
}
//附加数据
String associatedData = (String) JSONUtil.getByPath(JSONUtil.parse(wechatDTO.getBody()), "resource.associated_data");
//数据密文
String ciphertext = (String) JSONUtil.getByPath(JSONUtil.parse(wechatDTO.getBody()), "resource.ciphertext");
//随机串
String nonce = (String) JSONUtil.getByPath(JSONUtil.parse(wechatDTO.getBody()), "resource.nonce");
//解密
try {
//验签成功
String decryptData = new AesUtil(wechatConfig.getApiV3Key().getBytes(StandardCharsets.UTF_8)).decryptToString(associatedData.getBytes(StandardCharsets.UTF_8), nonce.getBytes(StandardCharsets.UTF_8), ciphertext);
//支付参数
Transaction transaction = JSONObject.parseObject(decryptData, Transaction.class);
log.info("参数-------" + JSONObject.toJSONString(transaction));
//订单编号(本地生成)
String outTradeNo = transaction.getOutTradeNo();
//通过本地订单编号处理业务逻辑(并将付款编号保存到本地)
log.info("订单编码" + outTradeNo);
//业务逻辑处理
if (transaction.getTradeState().equals(Transaction.TradeStateEnum.SUCCESS)) {
}
} catch (GeneralSecurityException | IOException e) {
log.error("解密失败:"+JSONObject.toJSONString(wechatDTO.getBody()));
throw new IllegalArgumentException(e);
}
}
第二种初始化获取证书
package com.example.demo.config;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.notification.NotificationConfig;
import com.wechat.pay.java.core.notification.NotificationParser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PostConstruct;
@Configuration
public class WechatInitConfig {
private Config config;
@Autowired
private WechatConfig wechatConfig;
@PostConstruct
public void init(){
config = new RSAAutoCertificateConfig.Builder()
.merchantId(wechatConfig.getMchid())
.privateKey(wechatConfig.getPrivateKey())
.merchantSerialNumber(wechatConfig.getSerialNo())
.apiV3Key(wechatConfig.getApiV3Key())
.build();
}
@Bean("NotificationParser")
public NotificationParser getNotificationParser(){
return new NotificationParser((NotificationConfig) config);
}
}
业务数据处理
@Autowired
private NotificationParser notificationParser;
public void notificationParser(WechatDTO wechatDTO){
// 获取HTTP请求头中的 Wechatpay-Signature 、 Wechatpay-Nonce 、 Wechatpay-Timestamp 、 Wechatpay-Serial 、 Request-ID 、Wechatpay-Signature-Type 对应的值,构建 RequestParam 。
RequestParam requestParam = new RequestParam.Builder()
.serialNumber(wechatDTO.getSerialNo())
.nonce(wechatDTO.getNonceStr())
.signature(wechatDTO.getSignature())
.timestamp(wechatDTO.getTimestamp())
// 若未设置signType,默认值为 WECHATPAY2-SHA256-RSA2048
.signType(wechatDTO.getSignatureType())
.body(wechatDTO.getBody())
.build();
Transaction transaction = notificationParser.parse(requestParam, Transaction.class);
System.out.println("参数-------"+ JSONObject.toJSONString(transaction));
//处理业务逻辑
Transaction.TradeStateEnum tradeState = transaction.getTradeState();
//订单编号(本地生成)
String outTradeNo = transaction.getOutTradeNo();
System.out.println("订单编号"+outTradeNo);
//付款编号 (微信返回)
String transactionId = transaction.getTransactionId();
//通过本地订单编号处理业务逻辑(并将付款编号保存到本地)
System.out.println("付款编号"+transactionId);
if (tradeState.equals(Transaction.TradeStateEnum.SUCCESS)) {
//业务处理
}
}
文章浏览阅读1w次,点赞2次,收藏27次。来源:机器人小妹 很多时候企业拥有重复,乏味且困难的工作流程,这些流程往往会减慢生产速度并增加运营成本。为了降低生产成本,企业别无选择,只能自动化某些功能以降低生产成本。 通过数字化..._人工智能平台
文章浏览阅读2.2k次。热加载能够在每次保存修改的代码后自动刷新 electron 应用界面,而不必每次去手动操作重新运行,这极大的提升了开发效率。安装 electron 热加载插件热加载虽然很方便,但是不是每个 electron 项目必须的,所以想要舒服的开发 electron 就只能给 electron 项目单独的安装热加载插件[electron-reloader]:// 在项目的根目录下安装 electron-reloader,国内建议使用 cnpm 代替 npmnpm install electron-relo._electron-reloader
文章浏览阅读942次。在11.0 进行定制化开发,会根据需要去掉recovery模式的一些选项 就是在device.cpp去掉一些选项就可以了。_android recovery 删除 部分菜单
文章浏览阅读3.7k次。https://www.yuque.com/mnn/cn/cvrt_linux_mac基础依赖这些依赖是无关编译选项的基础编译依赖• cmake(3.10 以上)• protobuf (3.0 以上)• 指protobuf库以及protobuf编译器。版本号使用 protoc --version 打印出来。• 在某些Linux发行版上这两个包是分开发布的,需要手动安装• Ubuntu需要分别安装 libprotobuf-dev 以及 protobuf-compiler 两个包•..._mnn 编译linux
文章浏览阅读1.8k次。CSS3新增动画属性“@-webkit-keyframes”,从字面就可以看出其含义——关键帧,这与Flash中的含义一致。利用CSS3制作动画效果其原理与Flash一样,我们需要定义关键帧处的状态效果,由CSS3来驱动产生动画效果。下面讲解一下如何利用CSS3制作淡入淡出的动画效果。具体实例可参考刚进入本站时的淡入效果。1. 定义动画,名称为fadeIn@-webkit-keyf_css3入场效果淡入淡出
文章浏览阅读2.8k次。计算机系统应包括硬件和软件两个子系统,硬件和软件又必须依次分别包括中央处理器和系统软件。按人的要求接收和存储信息,自动进行数据处理和计算,并输出结果信息的机器系统。计算机是脑力的延伸和扩充,是近代科学的重大成就之一。计算机系统由硬件(子)系统和软件(子)系统组成。前者是借助电、磁、光、机械等原理构成的各种物理部件的有机组合,是系统赖以工作的实体。后者是各种程序和文件,用于指挥全系统按指定的要求进行..._计算机系统包括硬件系统和软件系统 软件又必须包括
文章浏览阅读7.9k次,点赞3次,收藏22次。一 定义这是最早出现的置换算法。该算法总是淘汰最先进入内存的页面,即选择在内存中驻留时间最久的页面予以淘汰。该算法实现简单,只需把一个进程已调入内存的页面,按先后次序链接成一个队列,并设置一个指针,称为替换指针,使它总是指向最老的页面。但该算法与进程实际运行的规律不相适应,因为在进程中,有些页面经常被访问,比如,含有全局变量、常用函数、例程等的页面,FIFO 算法并不能保证这些页面不被淘汰。这里,我_进程调度fifo算法代码
文章浏览阅读133次。rownum是oracle才有的写法,rownum在oracle中可以用于取第一条数据,或者批量写数据时限定批量写的数量等mysql取第一条数据写法SELECT * FROM t order by id LIMIT 1;oracle取第一条数据写法SELECT * FROM t where rownum =1 order by id;ok,上面是mysql和oracle取第一条数据的写法对比,不过..._mysql 替换@rownum的写法
文章浏览阅读790次,点赞3次,收藏4次。官网下载下载链接:http://www.eclipse.org/downloads/点击Download下载完成后双击运行我选择第2个,看自己需要(我选择企业级应用,如果只是单纯学习java选第一个就行)进入下一步后选择jre和安装路径修改jvm/jre的时候也可以选择本地的(点后面的文件夹进去),但是我们没有11版本的,所以还是用他的吧选择接受安装中安装过程中如果有其他界面弹出就点accept就行..._ecjelm
文章浏览阅读245次。原文链接:https://linux.cn/article-7801-1.htmlifconfigping <IP地址>:发送ICMP echo消息到某个主机traceroute <IP地址>:用于跟踪IP包的路由路由:netstat -r: 打印路由表route add :添加静态路由路径routed:控制动态路由的BSD守护程序。运行RIP路由协议gat..._ifconfig 删除vlan
文章浏览阅读224次。reduxredux里要求把数据都放在公共的存储区域叫store里面,组件中尽量少放数据,假如绿色的组件要给很多灰色的组件传值,绿色的组件只需要改变store里面对应的数据就行了,接着灰色的组件会自动感知到store里的数据发生了改变,store只要有变化,灰色的组件就会自动从store里重新取数据,这样绿色组件的数据就很方便的传到其它灰色组件里了。redux就是把公用的数据放在公共的区域去存..._redux redis
文章浏览阅读2.2k次,点赞3次,收藏6次。unzip版本不支持4G以上的压缩包所以要使用p7zip:Linux一个高压缩率软件wget http://sourceforge.net/projects/p7zip/files/p7zip/9.20.1/p7zip_9.20.1_src_all.tar.bz2tar jxvf p7zip_9.20.1_src_all.tar.bz2cd p7zip_9.20.1make && make install 如果安装失败,看一下报错是不是因为没有下载gcc 和 gcc ++(p7_linux 7za解压中文乱码