微信APP支付-java后台实现
不说废话,直接上代码
先是工具类(注意签名时要排序):
- import java.io.BufferedReader;
- import java.io.ByteArrayInputStream;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.InputStream;
- import java.io.InputStreamReader;
- import java.io.OutputStream;
- import java.net.ConnectException;
- import java.net.HttpURLConnection;
- import java.net.URL;
- import java.security.KeyStore;
- import java.util.ArrayList;
- import java.util.Collections;
- import java.util.Iterator;
- import java.util.List;
- import java.util.Map;
- import java.util.Random;
- import java.util.Set;
- import java.util.SortedMap;
- import java.util.TreeMap;
- import javax.net.ssl.HttpsURLConnection;
- import javax.net.ssl.SSLContext;
- import org.apache.http.Consts;
- import org.apache.http.HttpEntity;
- import org.apache.http.client.methods.CloseableHttpResponse;
- import org.apache.http.client.methods.HttpPost;
- import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
- import org.apache.http.entity.StringEntity;
- import org.apache.http.impl.client.CloseableHttpClient;
- import org.apache.http.impl.client.HttpClients;
- import org.apache.http.ssl.SSLContexts;
- import org.apache.http.util.EntityUtils;
- import org.jdom.Document;
- import org.jdom.Element;
- import org.jdom.input.SAXBuilder;
- import com.system.property.WXProperty;
- import com.system.util.Tools;
- public class PayCommonUtil {
- /**
- * post请求并得到返回结果
- * @param requestUrl
- * @param requestMethod
- * @param output
- * @return
- */
- public static String httpsRequest21(String requestUrl, String requestMethod, String output) {
- try{
- URL url = new URL(requestUrl);
- HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
- connection.setDoOutput(true);
- connection.setDoInput(true);
- connection.setUseCaches(false);
- connection.setRequestMethod(requestMethod);
- if (null != output) {
- OutputStream outputStream = connection.getOutputStream();
- outputStream.write(output.getBytes("UTF-8"));
- outputStream.close();
- }
- // 从输入流读取返回内容
- InputStream inputStream = connection.getInputStream();
- InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
- BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
- String str = null;
- StringBuffer buffer = new StringBuffer();
- while ((str = bufferedReader.readLine()) != null) {
- buffer.append(str);
- }
- bufferedReader.close();
- inputStreamReader.close();
- inputStream.close();
- inputStream = null;
- connection.disconnect();
- return buffer.toString();
- }catch(Exception ex){
- ex.printStackTrace();
- }
- return "";
- }
- // 随机字符串生成
- public static String getRandomString(int length) { // length表示生成字符串的长度
- String base = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
- Random random = new Random();
- StringBuffer sb = new StringBuffer();
- for (int i = 0; i < length; i++) {
- int number = random.nextInt(base.length());
- sb.append(base.charAt(number));
- }
- return sb.toString();
- }
- // 请求xml组装
- public static String getRequestXml(SortedMap<String, Object> parameters) {
- StringBuffer sb = new StringBuffer();
- sb.append("<xml>");
- Set es = parameters.entrySet();
- Iterator it = es.iterator();
- while (it.hasNext()) {
- Map.Entry entry = (Map.Entry) it.next();
- String key = (String) entry.getKey();
- // String value = (String) entry.getValue();
- Object value = entry.getValue();
- // || "body".equalsIgnoreCase(key) || "sign".equalsIgnoreCase(key)
- if ("attach".equalsIgnoreCase(key) || "body".equalsIgnoreCase(key) || "sign".equalsIgnoreCase(key)) {
- sb.append("<" + key + ">" + "<![CDATA[" + value + "]]></" + key + ">");
- } else {
- sb.append("<" + key + ">" + value + "</" + key + ">");
- }
- }
- sb.append("</xml>");
- return sb.toString();
- }
- // 生成签名
- public static String createSign(String characterEncoding, SortedMap<String, Object> parameterMap) {
- if (parameterMap == null) {
- return null;
- }
- StringBuffer sb = new StringBuffer();
- List<String> keys = new ArrayList<>(parameterMap.keySet());
- Collections.sort(keys);
- for (int i = 0; i < keys.size(); i++) {
- String key = keys.get(i);
- // String value = (String) parameters.get(key);
- Object value = parameterMap.get(key);
- // if (Tools.notEmpty(value)) {
- sb.append((i == 0 ? "" : "&") + key + "=" + value);
- // }
- }
- sb.append("&key=" + WXProperty.get("API_KEY"));
- System.out.println("【生成签名 】" + sb.toString());
- String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase();
- return sign;
- }
- // 微信支付请求
- public static String httpsRequest(String requestUrl, String requestMethod, String outputStr) {
- try {
- URL url = new URL(requestUrl);
- HttpURLConnection conn = (HttpURLConnection) url.openConnection();
- conn.setDoOutput(true);
- conn.setDoInput(true);
- conn.setUseCaches(false);
- // 设置请求方式(GET/POST)
- conn.setRequestMethod(requestMethod);
- conn.setRequestProperty("content-type", "application/x-www-form-urlencoded");
- // 当outputStr不为null时向输出流写数据
- if (null != outputStr) {
- OutputStream outputStream = conn.getOutputStream();
- // 注意编码格式
- outputStream.write(outputStr.getBytes("UTF-8"));
- outputStream.close();
- }
- // 从输入流读取返回内容
- InputStream inputStream = conn.getInputStream();
- InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
- BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
- String str;
- StringBuffer buffer = new StringBuffer();
- while ((str = bufferedReader.readLine()) != null) {
- buffer.append(str);
- }
- // 释放资源
- bufferedReader.close();
- inputStreamReader.close();
- inputStream.close();
- conn.disconnect();
- return buffer.toString();
- } catch (ConnectException ce) {
- System.out.println("连接超时:" + ce);
- } catch (Exception e) {
- System.out.println("https请求异常" + e);
- }
- return null;
- }
- // 退款的请求方法
- public static String httpsRequest2(String requestUrl, String requestMethod, String outputStr) throws Exception {
- KeyStore keyStore = KeyStore.getInstance("PKCS12");
- StringBuilder res = new StringBuilder("");
- FileInputStream instream = new FileInputStream(new File("/home/apiclient_cert.p12"));
- try {
- keyStore.load(instream, "".toCharArray());
- } finally {
- instream.close();
- }
- // Trust own CA and all self-signed certs
- SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, "1313329201".toCharArray()).build();
- // Allow TLSv1 protocol only
- SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1" }, null,
- SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
- CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
- try {
- HttpPost httpost = new HttpPost("https://api.mch.weixin.qq.com/secapi/pay/refund");
- httpost.addHeader("Connection", "keep-alive");
- httpost.addHeader("Accept", "*/*");
- httpost.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
- httpost.addHeader("Host", "api.mch.weixin.qq.com");
- httpost.addHeader("X-Requested-With", "XMLHttpRequest");
- httpost.addHeader("Cache-Control", "max-age=0");
- httpost.addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");
- StringEntity entity2 = new StringEntity(outputStr, Consts.UTF_8);
- httpost.setEntity(entity2);
- System.out.println("executing request" + httpost.getRequestLine());
- CloseableHttpResponse response = httpclient.execute(httpost);
- try {
- HttpEntity entity = response.getEntity();
- System.out.println("----------------------------------------");
- System.out.println(response.getStatusLine());
- if (entity != null) {
- System.out.println("Response content length: " + entity.getContentLength());
- BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent()));
- String text = "";
- res.append(text);
- while ((text = bufferedReader.readLine()) != null) {
- res.append(text);
- System.out.println(text);
- }
- }
- EntityUtils.consume(entity);
- } finally {
- response.close();
- }
- } finally {
- httpclient.close();
- }
- return res.toString();
- }
- // xml解析
- public static SortedMap<String, Object> doXMLParse(String strxml){
- strxml = strxml.replaceFirst("encoding=\".*\"", "encoding=\"UTF-8\"");
- if (null == strxml || "".equals(strxml)) {
- return null;
- }
- SortedMap<String, Object> m = new TreeMap<>();
- InputStream in;
- try {
- in = new ByteArrayInputStream(strxml.getBytes("UTF-8"));
- SAXBuilder builder = new SAXBuilder();
- Document doc = builder.build(in);
- Element root = doc.getRootElement();
- List list = root.getChildren();
- Iterator it = list.iterator();
- while (it.hasNext()) {
- Element e = (Element) it.next();
- String k = e.getName();
- String v = "";
- List children = e.getChildren();
- if (children.isEmpty()) {
- v = e.getTextNormalize();
- } else {
- v = getChildrenText(children);
- }
- m.put(k, v);
- }
- // 关闭流
- in.close();
- } catch (Exception e1) {
- e1.printStackTrace();
- }
- return m;
- }
- public static String getChildrenText(List children) {
- StringBuffer sb = new StringBuffer();
- if (!children.isEmpty()) {
- Iterator it = children.iterator();
- while (it.hasNext()) {
- Element e = (Element) it.next();
- String name = e.getName();
- String value = e.getTextNormalize();
- List list = e.getChildren();
- sb.append("<" + name + ">");
- if (!list.isEmpty()) {
- sb.append(getChildrenText(list));
- }
- sb.append(value);
- sb.append("</" + name + ">");
- }
- }
- return sb.toString();
- }
- /**
- * 验证微信回调签名
- * @Description
- * @Author zhaozhenhua
- * @date 2018年5月10日
- * @param pd
- * @return
- * @throws Exception
- */
- public static boolean checkWXSign(SortedMap<String, Object> receiveMap) {
- String signFromAPIResponse = (String) receiveMap.get("sign");
- if (Tools.isEmpty(signFromAPIResponse)) {
- System.out.println("API返回的数据签名数据不存在,有可能被第三方篡改!!!");
- return false;
- }
- //清掉返回数据对象里面的Sign数据(不能把这个数据也加进去进行签名),然后用签名算法进行签名
- receiveMap.remove("sign");
- String responseSign = createSign("utf-8", receiveMap);
- if (!responseSign.equals(signFromAPIResponse)) {
- //签名验不过,表示这个API返回的数据有可能已经被篡改了
- System.out.println("API返回的数据签名验证不通过,有可能被第三方篡改!!! responseSign生成的签名为" + responseSign);
- return false;
- }
- System.out.println("服务器回包里面的签名是:" + signFromAPIResponse);
- return true;
- }
- }
配置文件信息读取:
- import java.io.FileNotFoundException;
- import java.io.IOException;
- import java.io.InputStream;
- import java.util.Properties;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- public class WXProperty {
- private static final Logger logger = LoggerFactory.getLogger(WXProperty.class);
- private static Properties props;
- static{
- loadProps();
- }
- synchronized static private void loadProps(){
- props = new Properties();
- InputStream in = null;
- try {
- in = WXProperty.class.getClassLoader().getResourceAsStream("wxinfo.properties");
- props.load(in);
- } catch (FileNotFoundException e) {
- logger.error("payment.properties文件未找到");
- } catch (IOException e) {
- logger.error("出现IOException");
- } finally {
- try {
- if(null != in) {
- in.close();
- }
- } catch (IOException e) {
- logger.error("payment.properties文件流关闭出现异常");
- }
- }
- }
- //读取key对应的value
- public static String get(String key){
- if(null == props) {
- loadProps();
- }
- return props.getProperty(key);
- }
- }
配置文件(前三个配置为微信申请APP支付通过后给的,而回调地址是自己定义的,在微信统一下单成功后会随着相应信息返回给前端,前端处理成功后执行这个回调接口):
- #服务号的应用ID
- APP_ID = XXXXXX
- #商户号
- MCH_ID = XXXXXXX
- #API密钥(前三个为微信申请获得)
- API_KEY = XXXXXXX
- #签名加密方式
- SIGN_TYPE = MD5
- #微信支付证书名称
- CERT_PATH = XXXXX
- #微信回调地址(自己定义)
- notify_url = XXXXX/success
MD5加密方法:
- public class MD5Util {
- private static String byteArrayToHexString(byte b[]) {
- StringBuffer resultSb = new StringBuffer();
- for (int i = 0; i < b.length; i++)
- resultSb.append(byteToHexString(b[i]));
- return resultSb.toString();
- }
- private static String byteToHexString(byte b) {
- int n = b;
- if (n < 0)
- n += 256;
- int d1 = n / 16;
- int d2 = n % 16;
- return hexDigits[d1] + hexDigits[d2];
- }
- public static String MD5Encode(String origin, String charsetname) {
- String resultString = null;
- try {
- resultString = new String(origin);
- MessageDigest md = MessageDigest.getInstance("MD5");
- if (charsetname == null || "".equals(charsetname))
- resultString = byteArrayToHexString(md.digest(resultString.getBytes()));
- else
- resultString = byteArrayToHexString(md.digest(resultString.getBytes(charsetname)));
- } catch (Exception exception) {
- }
- return resultString;
- }
- private static final String hexDigits[] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };
- }
微信支付统一下单接口封装的方法:
- public synchronized static SortedMap<String, Object> weixinPrePay (PageData pd) throws JDOMException, IOException{
- Map<String,String> returnMap = new HashMap<>();
- String trade_no = (String) pd.get("ORDERNUMBER");
- //支付金额
- BigDecimal totalAmount = new BigDecimal((String)pd.get("ORDERMONEY"));
- //描述(以商品标题做为描述)
- String description = "XXXX:"+trade_no;
- //预支付
- SortedMap<String, Object> parameterMap = new TreeMap<String, Object>();
- parameterMap.put("appid", WXProperty.get("APP_ID"));
- parameterMap.put("mch_id", WXProperty.get("MCH_ID"));
- parameterMap.put("nonce_str", PayCommonUtil.getRandomString(32));
- parameterMap.put("body", description);
- parameterMap.put("out_trade_no", trade_no);
- parameterMap.put("fee_type", "CNY");
- BigDecimal total = totalAmount.multiply(new BigDecimal(100));
- //parameterMap.put("total_fee", total.intValue()+"");
- parameterMap.put("total_fee", 1+"");
- parameterMap.put("spbill_create_ip", pd.get("spbillCreateIp"));
- parameterMap.put("notify_url", WXProperty.get("notify_url"));
- parameterMap.put("trade_type", "APP");
- parameterMap.put("sign_type", "MD5");
- parameterMap.put("attach", pd.get("ORDERTYPE"));//附加数据
- String sign = PayCommonUtil.createSign("UTF-8", parameterMap) ;
- parameterMap.put("sign", sign);
- String requestXML = PayCommonUtil.getRequestXml(parameterMap);
- System.out.println("【转换为xml格式的参数】 "+requestXML);
- String resultXML = PayCommonUtil.httpsRequest(
- "https://api.mch.weixin.qq.com/pay/unifiedorder","POST", requestXML);
- System.out.println("【返回的XML】 " + resultXML);
- Map mapResult = PayCommonUtil.doXMLParse(resultXML);
- String returnCode = (String) mapResult.get("return_code");
- System.out.println("【返回内容 】 "+returnCode);
- if("SUCCESS".equals(returnCode)){
- String resultCode = (String) mapResult.get("result_code");
- if("SUCCESS".equals(resultCode)){
- String prepay_id = (String) mapResult.get("prepay_id");
- SortedMap<String, Object> finalpackage = new TreeMap<String, Object>();
- finalpackage.put("appid", WXProperty.get("APP_ID"));
- finalpackage.put("partnerid", WXProperty.get("MCH_ID"));
- finalpackage.put("prepayid", prepay_id);
- String noncestr = PayCommonUtil.getRandomString(32);
- finalpackage.put("noncestr", noncestr);
- String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
- finalpackage.put("timestamp", timestamp);
- finalpackage.put("package", "Sign=WXPay");
- sign = PayCommonUtil.createSign("UTF-8", finalpackage) ;
- SortedMap<String, Object> returnmap = new TreeMap<String, Object>();
- returnmap.put("appid", WXProperty.get("APP_ID"));
- returnmap.put("partnerId", WXProperty.get("MCH_ID"));
- returnmap.put("prepayId", prepay_id);
- returnmap.put("nonceStr", noncestr);
- returnmap.put("timeStamp", timestamp);
- returnmap.put("package", "Sign=WXPay");
- returnmap.put("sign", sign);
- return returnmap;
- }else{
- String errCodeDes = (String) mapResult.get("err_code_des");
- returnMap.put("errCodeDes", errCodeDes);
- }
- }else{
- String returnMsg = (String) mapResult.get("return_msg");
- returnMap.put("returnMsg", returnMsg);
- }
- return null;
- }
微信支付回调地址:
- @RequestMapping(value = "/success")
- public String wxpaySucc(HttpServletRequest request){
- logger.info("微信支付回调");
- //商户处理后同步返回给微信参数:
- String xmlResultSuccess = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
- String xmlResultFailure = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
- SortedMap<String, Object> params = null;
- try {
- InputStream inStream = request.getInputStream();
- ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
- byte[] buffer = new byte[1024];
- int len = 0;
- while ((len = inStream.read(buffer)) != -1) {
- outSteam.write(buffer, 0, len);
- }
- String resultxml = new String(outSteam.toByteArray(), "utf-8");
- params = PayCommonUtil.doXMLParse(resultxml);
- logger.info("微信回调的信息:解析XML得到key:value");
- for (Object b : params.keySet()) {
- logger.info("key="+b+":"+"value="+params.get(b));
- }
- outSteam.close();
- inStream.close();
- } catch (Exception e) {
- e.printStackTrace();
- logger.info("回调xml解析失败");
- }
- //验证签名
- boolean signVerified = PayCommonUtil.checkWXSign(params);
- logger.info("验证签名:"+signVerified);
- if (!signVerified) {
- // 支付失败,失败业务逻辑处理
- //将订单状态设置为待支付
- return xmlResultFailure;
- } else {
- String return_code = (String) params.get("return_code");//状态
- String out_trade_no = (String) params.get("out_trade_no");//订单号
- String ORDERTYPE = (String) params.get("attach");//商家数据包
- System.out.println("订单号out_trade_no:"+out_trade_no);
- //防止微信重复通知
- PageData pd = new PageData();
- pd.put("ORDERNUMBER", out_trade_no);
- try {
- PageData payInfo = alipayInService.getPayInfo(pd);
- if(payInfo != null){
- return xmlResultSuccess;
- }
- } catch (Exception e1) {
- e1.printStackTrace();
- }
- if (return_code.equals("SUCCESS")) {
- if (out_trade_no != null) {
- //付款成功业务逻辑处理
- return xmlResultSuccess;
- default:
- break;
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }else{
- logger.info("微信手机支付回调失败订单号:{}"+out_trade_no);
- return xmlResultFailure;
- }
- }
- return null;
- }
微信APP支付-java后台实现的更多相关文章
- 微信app支付java后台流程、原理分析及nei网穿透
一.流程步骤 本实例是基于springmvc框架编写 1.执行流程 当手机端app(就是你公司开发的app)在支付页面时,调起服务端(后台第1个创建订单接口)接口,后台把需要调起微 ...
- 支付宝app支付java后台流程、原理分析(含nei wang chuan tou)
java版支付宝app支付流程及原理分析 本实例是基于springmvc框架编写 一.流程步骤 1.执行流程 当手机端app(就是你公司开发的app)在支付 ...
- 手把手教你完成App支付JAVA后台-支付宝支付JAVA
接着上一篇博客,我们暂时完成了手机端的部分支付代码,接下来,我们继续写后台的代码. 后台基本需要到以下几个参数,我都将他们写在了properties文件中: 支付宝参数 AliPay.payURL = ...
- 微信APP支付Java后端回调处理
package com.gaoxiao.framework.controller.gaojia; import com.gaoxiao.framework.commonfiles.entity.Sta ...
- .Net后台实现微信APP支付
上一节分享了微信小程序支付的后台,这一节来分享一下微信APP支付的后台.微信APP支付和微信小程序差别不大,微信APP支付后台不需要微信登录凭证.后台下单时交易类型(trade_type)不再是&qu ...
- 微信app支付(android端+java后台)
本文讲解使用微信支付接口完成在android开发的原生态app中完成微信支付功能, 文章具体讲解了前端android如何集成微信支付功能以及后台如何组装前端需要支付信息, 话不多话, 具体看文章内容吧 ...
- 微信app支付android客户端以及.net服务端实现
由于公司运营需要,需要在客户端(android/ios)增加微信以及支付宝支付,在调用微信app支付时遇到一些问题,也算是一些踩过的坑,记录下来 ,希望能对.net开发者服务端网站更快的集成微信app ...
- php开发微信APP支付接口
之前在开发APP中用到了微信支付,因为是第一次用,所以中途也遇到了好多问题,通过查看文档和搜集资料,终于完成了该功能的实现.在这里简单分享一下后台php接口的开发实例. 原文地址:代码汇个人博客 ht ...
- H5使用codovar插件实现微信支付(微信APP支付模式,前端)
H5打包的app实现微信支付及支付宝支付,本章主要详解微信支付,支付宝支付请查看另一篇“H5使用codovar插件实现支付宝支付(支付宝APP支付模式,前端)” ps:本文只试用H5开发的,微信 AP ...
随机推荐
- Sed 实记 · laoless's Blog
sed编辑命令 p 打印匹配行 = 打印文件行号 a 在定位行之后追加文本 i 在定位行之前插入文本 d 删除定位行 c 用新文本替换定位文本 s 使用替换模式替换相应模式 r 从另一个文件读取文本 ...
- Android注解支持Support Annotations详解
###注解支持(Support Annotations)Android support library从19.1版本开始引入了一个新的注解库,它包含很多有用的元注解,你能用它们修饰你的代码,帮助你发现 ...
- 人心和隐私怎么防?“防出轨”APP让道德滑落
王尔德曾说过,"一个人应该永远保持一点神秘感".让·保·里克特也表示,:"一个人泄露了秘密,哪怕一丝一毫,就再也得不到安宁了".可见,对于自然人来说,保有自 ...
- 在idea下遇到的问题汇总(间接性更新)
在idea下遇到的问题汇总(间接性更新) tomcat下的jsp代码问题: 在idea的环境下,遇到jsp代码.符号失效,首先需要考虑到jar包没有引入,情况如图: 这种情况是因为jar包没有导入进去 ...
- 前后端分离下的跨域CAS请求
最重要的两点: ajax请求跨域的时候,默认不会携带cookie. 请求分为普通请求(HttpRequest)和Ajax请求(XMLHttpRequest) 先屡一下跨域CAS认证的流程: 前端发起a ...
- [红日安全]Web安全Day9 - 文件下载漏洞实战攻防
本文由红日安全成员: Once 编写,如有不当,还望斧正. 大家好,我们是红日安全-Web安全攻防小组.此项目是关于Web安全的系列文章分享,还包含一个HTB靶场供大家练习,我们给这个项目起了一个名字 ...
- C++ non-const lvalue reference cannot bind to a temporary
1. 问题代码 #include <iostream> #include <vector> //注意begin和end形参都声明为引用 bool find_int(std::v ...
- proteus pro 8.9 安装及汉化教程
最近由于网上上课老师要求我们自己安装proteus这款仿真软件,所以笔者也安装了最新款版的proteus pro 8.9,分享给大家安装心得,也包含汉化过程,希望大家能用软件好好学习. 备注:感谢博主 ...
- R调用C++示例
sourceCpp {Rcpp}:Source C++ Code from a File or String sourceCpp(file = "", code = NULL, e ...
- [android]com.android.support:appcompat-v7:XXX 包导入无法Build
在学习<Android编程权威指南>时,按书中要求添加com.android.support:appcompat的依赖,然后编译不通过,提示如下问题: 大概意思是,Android Pie之 ...