微信小程序-统一下单、微信支付(Java后台)
1、首先分享 微信统一下单接口:
https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1
微信接口 签名 对比网址:
https://pay.weixin.qq.com/wiki/tools/signverify/
微信小程序 微信支付 网址:
https://mp.weixin.qq.com/debug/wxadoc/dev/api/api-pay.html#wxrequestpaymentobject
2、微信小程序端 代码示例:
payment:function(event){
var that = this;
console.log('去支付按钮点击事件')
wx.request({
url: 'http://192.168.8.50:8080/matouwang/wechat/wechatAppletGolf/createUnifiedOrder',
method: 'POST', // OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT
// 当method 为POST 时 设置以下 的header
header: { 'content-type': 'application/x-www-form-urlencoded' },
data: {
amount: teamMoney,
openid: openId
},
success: function (res) {
if (res.data.prepayId != ''){
console.log('微信统一下单接口调用成功 数据包:' + res.data.prepayId);
console.log('微信统一下单接口调用成功 订单号:' + res.data.outTradeNo);
console.log('调用微信支付接口之前先生成签名')
//保存订单号信息
var outTradeNo = res.data.outTradeNo;
wx.request({
url: 'http://192.168.8.50:8080/matouwang/wechat/wechatAppletGolf/generateSignature',
method: 'POST', // OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT
// 当method 为POST 时 设置以下 的header
header: { 'content-type': 'application/x-www-form-urlencoded' },
data: {
prepayId: res.data.prepayId
},
success: function (paryResult) {
if (paryResult.data.sign != '') {
console.log('微信支付接口之前先生成签名成功')
console.log('签名:' + paryResult.data.sign)
console.log('随机串:' + paryResult.data.nonceStr)
console.log('时间戳:' + paryResult.data.timeStamp)
//这个applyId一定要大写 而且签名的参数和调用方法的参数值一定要统一
wx.requestPayment({
'appId': '',
'timeStamp': paryResult.data.timeStamp,
'nonceStr': paryResult.data.nonceStr,
'package': paryResult.data.package,
'signType': 'MD5',
'paySign': paryResult.data.sign,
'success': function (paymentRes) {
console.log(paymentRes)
that.setData({
notPay: true,
paySuccess: false,
teamNotPay: true,
button:true,
outTradeNo: outTradeNo,
payDate:new Date()
})
},
'fail': function (error) {
console.log(error)
}
})
} else {
console.log('微信支付接口之前先生成签名失败')
}
}
})
}
}
});
},
3、分享微信 统一下单 后台代码示例:
@Override
public JSONObject createUnifiedOrder(HttpServletRequest request,HttpServletResponse response) {
logger.info("微信 统一下单 接口调用");
//设置最终返回对象
JSONObject resultJson = new JSONObject();
//创建条件
Criteria criteria = new Criteria(); //接受参数(金额)
String amount = request.getParameter("amount");
//接受参数(openid)
String openid = request.getParameter("openid");
//接口调用总金额单位为分换算一下(测试金额改成1,单位为分则是0.01,根据自己业务场景判断是转换成float类型还是int类型)
//String amountFen = Integer.valueOf((Integer.parseInt(amount)*100)).toString();
//String amountFen = Float.valueOf((Float.parseFloat(amount)*100)).toString();
String amountFen = "1";
//创建hashmap(用户获得签名)
SortedMap<String, String> paraMap = new TreeMap<String, String>();
//设置body变量 (支付成功显示在微信支付 商品详情中)
String body = "啦啦啦测试";
//设置随机字符串
String nonceStr = Utils.getUUIDString().replaceAll("-", "");
//设置商户订单号
String outTradeNo = Utils.getUUIDString().replaceAll("-", ""); //设置请求参数(小程序ID)
paraMap.put("appid", APPLYID);
//设置请求参数(商户号)
paraMap.put("mch_id", MCHID);
//设置请求参数(随机字符串)
paraMap.put("nonce_str", nonceStr);
//设置请求参数(商品描述)
paraMap.put("body", body);
//设置请求参数(商户订单号)
paraMap.put("out_trade_no", outTradeNo);
//设置请求参数(总金额)
paraMap.put("total_fee", amountFen);
//设置请求参数(终端IP)
paraMap.put("spbill_create_ip", WebUtils.getIpAddress(request, response));
//设置请求参数(通知地址)
paraMap.put("notify_url", WebUtils.getBasePath()+"wechat/wechatAppletGolf/payCallback");
//设置请求参数(交易类型)
paraMap.put("trade_type", "JSAPI");
//设置请求参数(openid)(在接口文档中 该参数 是否必填项 但是一定要注意 如果交易类型设置成'JSAPI'则必须传入openid)
paraMap.put("openid", openid);
//调用逻辑传入参数按照字段名的 ASCII 码从小到大排序(字典序)
String stringA = formatUrlMap(paraMap, false, false);
//第二步,在stringA最后拼接上key得到stringSignTemp字符串,并对stringSignTemp进行MD5运算,再将得到的字符串所有字符转换为大写,得到sign值signValue。(签名)
String sign = MD5Util.MD5(stringA+"&key="+KEY).toUpperCase();
//将参数 编写XML格式
StringBuffer paramBuffer = new StringBuffer();
paramBuffer.append("<xml>");
paramBuffer.append("<appid>"+APPLYID+"</appid>");
paramBuffer.append("<mch_id>"+MCHID+"</mch_id>");
paramBuffer.append("<nonce_str>"+paraMap.get("nonce_str")+"</nonce_str>");
paramBuffer.append("<sign>"+sign+"</sign>");
paramBuffer.append("<body>"+body+"</body>");
paramBuffer.append("<out_trade_no>"+paraMap.get("out_trade_no")+"</out_trade_no>");
paramBuffer.append("<total_fee>"+paraMap.get("total_fee")+"</total_fee>");
paramBuffer.append("<spbill_create_ip>"+paraMap.get("spbill_create_ip")+"</spbill_create_ip>");
paramBuffer.append("<notify_url>"+paraMap.get("notify_url")+"</notify_url>");
paramBuffer.append("<trade_type>"+paraMap.get("trade_type")+"</trade_type>");
paramBuffer.append("<openid>"+paraMap.get("openid")+"</openid>");
paramBuffer.append("</xml>"); try {
//发送请求(POST)(获得数据包ID)(这有个注意的地方 如果不转码成ISO8859-1则会告诉你body不是UTF8编码 就算你改成UTF8编码也一样不好使 所以修改成ISO8859-1)
Map<String,String> map = doXMLParse(getRemotePortData(URL, new String(paramBuffer.toString().getBytes(), "ISO8859-1")));
//应该创建 支付表数据
if(map!=null){
//清空
criteria.clear();
//设置openId条件
criteria.put("openId", openid);
//获取数据
List<WechatAppletGolfPayInfo> payInfoList = appletGolfPayInfoMapper.selectByExample(criteria);
//如果等于空 则证明是第一次支付
if(CollectionUtils.isEmpty(payInfoList)){
//创建支付信息对象
WechatAppletGolfPayInfo appletGolfPayInfo = new WechatAppletGolfPayInfo();
//设置主键
appletGolfPayInfo.setPayId(outTradeNo);
//设置openid
appletGolfPayInfo.setOpenId(openid);
//设置金额
appletGolfPayInfo.setAmount(Long.valueOf(amount));
//设置支付状态
appletGolfPayInfo.setPayStatus("0");
//插入Dao
int sqlRow = appletGolfPayInfoMapper.insert(appletGolfPayInfo);
//判断
if(sqlRow == 1){
logger.info("微信 统一下单 接口调用成功 并且新增支付信息成功");
resultJson.put("prepayId", map.get("prepay_id"));
resultJson.put("outTradeNo", paraMap.get("out_trade_no"));
return resultJson;
}
}else{
//判断 是否等于一条
if(payInfoList.size() == 1){
//获取 需要更新数据
WechatAppletGolfPayInfo wechatAppletGolfPayInfo = payInfoList.get(0);
//更新 该条的 金额
wechatAppletGolfPayInfo.setAmount(Long.valueOf(amount));
//更新Dao
int sqlRow = appletGolfPayInfoMapper.updateByPrimaryKey(wechatAppletGolfPayInfo);
//判断
if(sqlRow == 1){
logger.info("微信 统一下单 接口调用成功 修改支付信息成功");
resultJson.put("prepayId", map.get("prepay_id"));
resultJson.put("outTradeNo", paraMap.get("out_trade_no"));
return resultJson;
}
}
}
}
//将 数据包ID 返回 System.out.println(map);
} catch (UnsupportedEncodingException e) {
logger.info("微信 统一下单 异常:"+e.getMessage());
e.printStackTrace();
} catch (Exception e) {
logger.info("微信 统一下单 异常:"+e.getMessage());
e.printStackTrace();
}
logger.info("微信 统一下单 失败");
return resultJson;
}
4、生成 微信支付 签名后台 代码示例:
@Override
public JSONObject generateSignature(HttpServletRequest request,
HttpServletResponse response) {
logger.info("微信 支付接口生成签名 方法开始");
//实例化返回对象
JSONObject resultJson = new JSONObject(); //获得参数(微信统一下单接口生成的prepay_id )
String prepayId = request.getParameter("prepayId");
//创建 时间戳
String timeStamp = Long.valueOf(System.currentTimeMillis()).toString();
//创建 随机串
String nonceStr = Utils.getUUIDString().replaceAll("-", "");
//创建 MD5
String signType = "MD5"; //创建hashmap(用户获得签名)
SortedMap<String, String> paraMap = new TreeMap<String, String>();
//设置(小程序ID)(这块一定要是大写)
paraMap.put("appId", APPLYID);
//设置(时间戳)
paraMap.put("timeStamp", timeStamp);
//设置(随机串)
paraMap.put("nonceStr", nonceStr);
//设置(数据包)
paraMap.put("package", "prepay_id="+prepayId);
//设置(签名方式)
paraMap.put("signType", signType); //调用逻辑传入参数按照字段名的 ASCII 码从小到大排序(字典序)
String stringA = formatUrlMap(paraMap, false, false);
//第二步,在stringA最后拼接上key得到stringSignTemp字符串,并对stringSignTemp进行MD5运算,再将得到的字符串所有字符转换为大写,得到sign值signValue。(签名)
String sign = MD5Util.MD5(stringA+"&key="+KEY).toUpperCase(); if(StringUtils.isNotBlank(sign)){
//返回签名信息
resultJson.put("sign", sign);
//返回随机串(这个随机串是新创建的)
resultJson.put("nonceStr", nonceStr);
//返回时间戳
resultJson.put("timeStamp", timeStamp);
//返回数据包
resultJson.put("package", "prepay_id="+prepayId); logger.info("微信 支付接口生成签名 设置返回值");
}
logger.info("微信 支付接口生成签名 方法结束");
return resultJson;
}
5、签名算法 将key Value 字典排序 代码示例:
/**
*
* 方法用途: 对所有传入参数按照字段名的 ASCII 码从小到大排序(字典序),并且生成url参数串<br>
* 实现步骤: <br>
*
* @param paraMap 要排序的Map对象
* @param urlEncode 是否需要URLENCODE
* @param keyToLower 是否需要将Key转换为全小写
* true:key转化成小写,false:不转化
* @return
*/
private static String formatUrlMap(Map<String, String> paraMap, boolean urlEncode, boolean keyToLower){
String buff = "";
Map<String, String> tmpMap = paraMap;
try
{
List<Map.Entry<String, String>> infoIds = new ArrayList<Map.Entry<String, String>>(tmpMap.entrySet());
// 对所有传入参数按照字段名的 ASCII 码从小到大排序(字典序)
Collections.sort(infoIds, new Comparator<Map.Entry<String, String>>()
{
@Override
public int compare(Map.Entry<String, String> o1, Map.Entry<String, String> o2)
{
return (o1.getKey()).toString().compareTo(o2.getKey());
}
});
// 构造URL 键值对的格式
StringBuilder buf = new StringBuilder();
for (Map.Entry<String, String> item : infoIds)
{
if (StringUtils.isNotBlank(item.getKey()))
{
String key = item.getKey();
String val = item.getValue();
if (urlEncode)
{
val = URLEncoder.encode(val, "utf-8");
}
if (keyToLower)
{
buf.append(key.toLowerCase() + "=" + val);
} else
{
buf.append(key + "=" + val);
}
buf.append("&");
} }
buff = buf.toString();
if (buff.isEmpty() == false)
{
buff = buff.substring(0, buff.length() - 1);
}
} catch (Exception e)
{
return null;
}
return buff;
}
6、发送远程请求 获得数据 代码示例:
/**
* 方法名: getRemotePortData
* 描述: 发送远程请求 获得代码示例
* 参数: @param urls 访问路径
* 参数: @param param 访问参数-字符串拼接格式, 例:port_d=10002&port_g=10007&country_a=
* 创建人: Xia ZhengWei
* 创建时间: 2017年3月6日 下午3:20:32
* 版本号: v1.0
* 返回类型: String
*/
private String getRemotePortData(String urls, String param){
logger.info("港距查询抓取数据----开始抓取外网港距数据");
try {
URL url = new URL(urls);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
// 设置连接超时时间
conn.setConnectTimeout(30000);
// 设置读取超时时间
conn.setReadTimeout(30000);
conn.setRequestMethod("POST");
if(StringUtil.isNotBlank(param)) {
conn.setRequestProperty("Origin", "https://sirius.searates.com");// 主要参数
conn.setRequestProperty("Referer", "https://sirius.searates.com/cn/port?A=ChIJP1j2OhRahjURNsllbOuKc3Y&D=567&G=16959&shipment=1&container=20st&weight=1&product=0&request=&weightcargo=1&");
conn.setRequestProperty("X-Requested-With", "XMLHttpRequest");// 主要参数
}
// 需要输出
conn.setDoInput(true);
// 需要输入
conn.setDoOutput(true);
// 设置是否使用缓存
conn.setUseCaches(false);
// 设置请求属性
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
conn.setRequestProperty("Connection", "Keep-Alive");// 维持长连接
conn.setRequestProperty("Charset", "UTF-8");
if(StringUtil.isNotBlank(param)) {
// 建立输入流,向指向的URL传入参数
DataOutputStream dos=new DataOutputStream(conn.getOutputStream());
dos.writeBytes(param);
dos.flush();
dos.close();
}
// 输出返回结果
InputStream input = conn.getInputStream();
int resLen =0;
byte[] res = new byte[1024];
StringBuilder sb=new StringBuilder();
while((resLen=input.read(res))!=-1){
sb.append(new String(res, 0, resLen));
}
return sb.toString();
} catch (MalformedURLException e) {
e.printStackTrace();
logger.info("港距查询抓取数据----抓取外网港距数据发生异常:" + e.getMessage());
} catch (IOException e) {
e.printStackTrace();
logger.info("港距查询抓取数据----抓取外网港距数据发生异常:" + e.getMessage());
}
logger.info("港距查询抓取数据----抓取外网港距数据失败, 返回空字符串");
return "";
}
7、XML 转换成 map 对象 代码示例:
/**
* 解析xml,返回第一级元素键值对。如果第一级元素有子节点,则此节点的值是子节点的xml数据。
* @param strxml
* @return
* @throws JDOMException
* @throws IOException
*/
@SuppressWarnings("rawtypes")
private Map<String,String> doXMLParse(String strxml) throws Exception {
if(null == strxml || "".equals(strxml)) {
return null;
} Map<String,String> m = new HashMap<String,String>();
InputStream in = String2Inputstream(strxml);
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(); return m;
} private InputStream String2Inputstream(String str) {
return new ByteArrayInputStream(str.getBytes());
} /**
* 获取子结点的xml
* @param children
* @return String
*/
@SuppressWarnings("rawtypes")
private 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();
}
8、获取本机IP
/**
* @Title: getIpAddress
* @Description: 获取客户端真实IP地址
* @author yihj
* @param @param request
* @param @param response
* @param @return 参数
* @return String 返回类型
* @throws
*/
public static String getIpAddress(HttpServletRequest request) {
// 避免反向代理不能获取真实地址, 取X-Forwarded-For中第一个非unknown的有效IP字符串
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){
ip = request.getRemoteAddr();
}
return ip;
}
9、通知地址 回调服务器 支付结果(这个回调 如果不返回给微信服务器 是否成功回调标示 则会一直回调8次 一直到返回成功标示位置) 代码示例:
@Override
public void payCallback(HttpServletRequest request,HttpServletResponse response) {
logger.info("微信回调接口方法 start");
logger.info("微信回调接口 操作逻辑 start");
String inputLine = "";
String notityXml = "";
try {
while((inputLine = request.getReader().readLine()) != null){
notityXml += inputLine;
}
//关闭流
request.getReader().close();
logger.info("微信回调内容信息:"+notityXml);
//解析成Map
Map<String,String> map = doXMLParse(notityXml);
//判断 支付是否成功
if("SUCCESS".equals(map.get("result_code"))){
logger.info("微信回调返回是否支付成功:是");
//获得 返回的商户订单号
String outTradeNo = map.get("out_trade_no");
logger.info("微信回调返回商户订单号:"+outTradeNo);
//访问DB
WechatAppletGolfPayInfo payInfo = appletGolfPayInfoMapper.selectByPrimaryKey(outTradeNo);
logger.info("微信回调 根据订单号查询订单状态:"+payInfo.getPayStatus());
if("0".equals(payInfo.getPayStatus())){
//修改支付状态
payInfo.setPayStatus("1");
//更新Bean
int sqlRow = appletGolfPayInfoMapper.updateByPrimaryKey(payInfo);
//判断 是否更新成功
if(sqlRow == 1){
logger.info("微信回调 订单号:"+outTradeNo +",修改状态成功");
//封装 返回值
StringBuffer buffer = new StringBuffer();
buffer.append("<xml>");
buffer.append("<return_code>SUCCESS</return_code>");
buffer.append("<return_msg>OK</return_msg>");
buffer.append("</xml>"); //给微信服务器返回 成功标示 否则会一直询问 咱们服务器 是否回调成功
PrintWriter writer = response.getWriter();
//返回
writer.print(buffer.toString());
}
}
}
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
10、MD5 算法:
/**
* @Title: encodeByMD5
* @Description: 对字符串进行MD5编码
* @author yihj
* @param @param originString
* @param @return 参数
* @return String 返回类型
* @throws
*/
public static String MD5(String originString){
if (originString!=null) {
try {
//创建具有指定算法名称的信息摘要
MessageDigest md5 = MessageDigest.getInstance("MD5");
//使用指定的字节数组对摘要进行最后更新,然后完成摘要计算
byte[] results = md5.digest(originString.getBytes());
//将得到的字节数组变成字符串返回
String result = byteArrayToHexString(results);
return result;
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
11、注意事项:
1)、所有的签名和发送微信服务器的数据必须一致 包括Key的大小写 否则签名失败
2)、微信小程序 前端调用 接口的时候 文档上并没有写appId参数 该参数一定要穿 并且是大写
3)、交易类型 为 JSAPI 的时候 则必须传入openid
4)、body格式问题 写的是UTF-8 实际要的格式则是ISO8859-1 而且单独对body进行设置好像不好使 所以必须全部都改成该格式
5)、生成签名 最后加上key的那块 加的格式是 &key = KEY 这种 而且不是直接 + key 这个地方需要注意一下 我碰了个坑 文档没看仔细
6)、数据包ID 格式 不是 value直接设置成 数据包ID就可以 前面需要加 "prepay_id="
7)、最后一点强调 生成签名的数据和发送服务器的数据 必须保持一致
8)、appid 是公众号的appid
9)、mch_id 这是商户平台的id
10)、key 这是设置的 商户平台支付密钥
11、欢迎大家 发表问题 一起学习 嘿嘿
微信小程序-统一下单、微信支付(Java后台)的更多相关文章
- 微信小程序一:微信小程序UI组件、开发框架、实用库
作者:NiceCui 本文谢绝转载,如需转载需征得作者本人同意,谢谢. 本文链接:http://www.cnblogs.com/NiceCui/p/8079095.html 内容持续更新,维护中 邮箱 ...
- 微信小程序开发01 --- 微信小程序项目结构介绍
一.微信小程序简单介绍: 微信官方介绍微信小程序是一个不需要下载安装就可使用(呵呵,JS代码不用下载吗?展示的UI不用下载吗?)的应用,它实现了应用“触手可及”的梦想,用户扫一扫或搜一下即可打开应用. ...
- [转]微信小程序之购物车 —— 微信小程序实战商城系列(5)
本文转自:http://blog.csdn.net/michael_ouyang/article/details/70755892 续上一篇的文章:微信小程序之商品属性分类 —— 微信小程序实战商城 ...
- 微信小程序唤起其他微信小程序 / 移动应用App唤起小程序
微信小程序唤起其他微信小程序 / 移动应用App唤起小程序 1. 微信小程序唤起微信小程序 小程序唤起其他小程序很简单 先上链接 小程序跳转小程序 Navigator组件 推荐使用 小程序跳转小程序 ...
- 微信小程序POST请求参数传递不到后台, 前台获取不到后端返回的数据, 以及 post 请求返回 404 但后台能收到数据
1 微信小程序POST请求参数传递不到后台 需要在微信请求 wx.request 改变默认 header 配置为如下 wx.request({ url: 'test.php', //仅为示例,并非真实 ...
- 微信小程序中实现微信支付
最近在做微信小程序,今天刚好做到小程序里的微信支付这块,踩过不少坑,特此写个博客记录下,希望能帮到其它人吧. 我总结了一下,小程序中的微信支付和之前其它的公众号里的微信支付有两个区别,第一就是小程序必 ...
- 微信小程序开发之微信支付
微信支付是小程序开发中很重要的一个环节,下面会结合实战进行分析总结 环境准备 https服务器 微信小程序只支持https请求,因此需要配置https的单向认证服务(请参考 另一篇文章https受信证 ...
- 微信小程序篇(微信小程序的支付)
微信小程序的支付和微信公众号的支付是类似的,对比起来还比公众号支付简单了一些,我们只需要调用微信的统一下单接口获取prepay_id之后我们在调用微信的支付即可. 今天我们来封装一般node的支付接口 ...
- h5内嵌微信小程序,调用微信支付功能
在小程序中不能使用之前在浏览器中配置的支付功能,只能调用小程序专属的api进行支付. 因为需要在现在实现的基础上,再添加在小程序中调用微信支付功能,所以我的思路是这样的 1.在点击支付按钮时,判断是不 ...
随机推荐
- 程序压力测试、性能测试AB、Webbench、Tsung
负载生成器是一些生成用于测试的流量的程序.它们可以向你展示服务器在高负载的情况下的性能,以及让你能够找出服务器可能存在的问题.为了得到更加客观和准确的数值,应该从远程访问.局域网访问 ...
- Android 5.0 SEAndroid下如何获得对一个内核节点的访问权限
-9]* u:object_r:tty_device:s0 # We add here /dev/wf_bt u:object_r:wf_bt_device:s0 wf_bt ...
- Obj-C中内存的管理一瞥
注意,ARC仅仅(自动)释放你手工管理的Objective-C类实例的内存, 但是不会释放由C函数或者Core Foundation(Cocoa的底层,C语言的变体)申请的内存.
- Android ORM 框架之 greenDAO
前言 我相信,在平时的开发过程中,大家一定会或多或少地接触到 SQLite.然而在使用它时,我们往往需要做许多额外的工作,像编写 SQL 语句与解析查询结果等.所以,适用于 Android 的ORM ...
- PS图层混合算法之二(线性加深,线性减淡,变亮,变暗)
线性加深模式: 查看每个通道的颜色信息,通过降低"亮度"使底色的颜色变暗来反映绘图色,和白色混合没变化. Linear Burn 线形加深 C=A+B-1 如果上下层的像素值之和小 ...
- Struts2技术内幕 读书笔记一 框架的本质
本读书笔记系列,主要针对陆舟所著<<Struts2技术内幕 深入解析Strtus2架构设计与实现原理>>一书.笔记中所用的图片若无特殊说明,就都取自书中,特此声明. 什么是框架 ...
- 【freeradius3】安装和拓展需求
这次主要来看看 freeradius的安装,以及Python拓展的例子,还有计费字段根据厂家进行拓展. 3.0版本的安装 参考文章 yum install libtalloc-devel wget - ...
- MTU 最大传输单位
MTU 最大传输单位 通过上面 MAC 封装的定义,现在我们知道标准以太网络frame所能传送的数据量最大可以到达 1500 bytes , 这个数值就被我们称为 MTU (Maximum Trans ...
- 【Qt编程】3D迷宫游戏
说起迷宫想必大家都很熟悉,个人感觉迷宫对人的方向感是很大的考验,至少我的方向感是不好的,尤其是在三维空间中.由于这段时间帮导师做项目用到了三维作图,便心血来潮想做个三维迷宫玩玩.要想画出三维的迷宫游戏 ...
- 关于gcc的一点小人性化提示
现在对于大多数平台的C编译器来说都会有很多种选择,而gcc和clang无疑是2个非常优秀的C编译器.当然他们也不只是C编译器.我最近用clang的比较多,原因有很多.不过一些小的细节很让我喜欢,比如O ...