关于支付,一直想参与开发,现在根据项目中已有及参见的微信开发文档,将自己对于微信开发的流程进行简单的总结,以备后用和帮助后来者。

一、相关官方文档

微信支付官方文档:https://pay.weixin.qq.com/wiki/doc/api/index.html

二、参考博文

(待添加,等我找找..)

三、自己参看文档时候的简单文档整理,

ps:只为了方便自己记忆和联想

四、根据官方文档中,标记后台主要做的工作流程

五、参看项目代码时候,整理的demo,来源于网络

(1)MD5Util  ----  生成签名时候使用

package com.weixin.test;

import java.security.MessageDigest;

/**
* 微信测试MD5
* @author Administrator
*
*/
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" }; }

(2)PayTest

package com.weixin.test;

import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap; public class PayTest { // http://mch.weixin.qq.com/wiki/doc/api/index.php?chapter=4_3
private static String Key = "192006250b4c09247ec02edce69f6a2d"; /**
* @param args
*/
public static void main(String[] args) {
System.out.println(">>>模拟微信支付<<<");
System.out.println("==========华丽的分隔符==========");
// 微信api提供的参数
String appid = "wxd930ea5d5a258f4f";
String mch_id = "10000100";
String device_info = "1000";
String body = "test";
String nonce_str = "ibuaiVcKdpRxkhJA"; SortedMap<Object, Object> parameters = new TreeMap<Object, Object>();
parameters.put("appid", appid);
parameters.put("mch_id", mch_id);
parameters.put("device_info", device_info);
parameters.put("body", body);
parameters.put("nonce_str", nonce_str); String characterEncoding = "UTF-8";
String weixinApiSign = "9A0A8659F005D6984697E2CA0A9CF3B7";
System.out.println("微信的签名是:" + weixinApiSign);
String mySign = createSign(characterEncoding, parameters);
System.out.println("我 的签名是:" + mySign); if (weixinApiSign.equals(mySign)) {
System.out.println("恭喜你成功了~");
} else {
System.out.println("不行啊,再接再厉~");
} String userAgent = "Mozilla/5.0(iphone;CPU iphone OS 5_1_1 like Mac OS X) AppleWebKit/534.46(KHTML,like Geocko) Mobile/9B206 MicroMessenger/5.0"; char agent = userAgent.charAt(userAgent.indexOf("MicroMessenger") + 15); System.out.println("微信的版本号:" + new String(new char[] { agent }));
} /**
* 微信支付签名算法sign
* @param characterEncoding
* @param parameters
* @return
*/
@SuppressWarnings("unchecked")
public static String createSign(String characterEncoding, SortedMap<Object, Object> parameters) {
StringBuffer sb = new StringBuffer();
Set es = parameters.entrySet();// 所有参与传参的参数按照accsii排序(升序)
Iterator it = es.iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
String k = (String) entry.getKey();
Object v = entry.getValue();
if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {
sb.append(k + "=" + v + "&");
}
}
sb.append("key=" + Key);
String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase();
return sign;
} }

六、结合项目,微信支付流程解析

主要为微信支付官方文档提供的流程中,对应于 4、5、6、10、11

(1)网页内请求生成支付订单。主要工作就是前端(app)在将商品添加到购物车后下单购买或者立即购买时,在后台系统中所生成的一个未支付订单。

下面只是项目中一个业务处理,可以忽略,仅做参考和方便记忆。

/**
* 生成订单
*
* @param order
* @param baseUser
* @return
*/
@Override
public Response<String> createRechargeOrder(RechargeOrder order, BaseUser baseUser) {
Response<String> response = new Response<>(); try {
if (baseUser == null) {
throw new BusinessException(ResultCode.ERROR_USER_UNLOGIN.getName());
}
if (order == null) {
throw new ArgumentException(ResultCode.ERROR_ORDER_SAVE_NULL.getName());
}
if (!checkAmount(order.getActuralAmount(), order.getRechargeAmount())) {
throw new ArgumentException("支付金额异常");
} order.setCustomerName(baseUser.getName());
order.setCustomerId(baseUser.getId());
if("customer".equals(baseUser.getType())){
Response<MemberCustomerUser> res = customerService.getCustomerById(baseUser.getId());
if (null != res && res.isSuccess()) {
order.setCustomerPhone(res.getResult().getMobilePhone());
}
}else if("shop".equals(baseUser.getType())){
MemberShopUser user = new MemberShopUser();
user.setId(baseUser.getId());
Response<MemberShopUser> res = terminalShopService.getShopUserById(user);
if (null != res && res.isSuccess()) {
order.setCustomerPhone(res.getResult().getMobilePhone());
}
}
if (StringUtils.isBlank(order.getSource())) {
order.setSource("");
}
//订单状态:01未支付
order.setOrderCode("10");
order.setOrderName("未支付");
//付款状态:待付款
order.setPayStatus("0");
rechargeOrderManager.createRechargeOrder(order);
//记录订单状态日志
if (order.getOrderId() != null && !"".equals(order.getOrderId())) {
ConvenienceOrderLog orderLog = new ConvenienceOrderLog();
orderLog.setOrderId(String.valueOf(order.getOrderId()));
orderLog.setStatusCode(10);
orderLog.setStatusName("未支付");
orderLog.setStatusUserId(baseUser.id);
orderLog.setStatusUser(baseUser.name);
rechargeOrderManager.saveConvenienceOrderLog(orderLog);
}
response.setResult(String.valueOf(order.getOrderId()));
} catch (ArgumentException a) {
//参数异常不写log日志
response.setError(a.getMessage());
} catch (BusinessException b) {
response.setError(b.getMessage());
log.error("保存订单异常!原因:{}", Throwables.getStackTraceAsString(b));
} catch (Exception e) {
response.setError(e.getMessage());
log.error("保存订单异常!原因:{}", Throwables.getStackTraceAsString(e));
}
return response;
}

(2)调用统一下单api,交易请求,获取微信后台返回的交易支付预付单,对返回信息处理后,返回给前端(app)

/**
* 微信支付 交易请求,生成预付单 -====== 公众号
*
* @param orderId
* @param baseUser
* @return
*/
@Override
public Response<Map<String, String>> weChatPayRequest(String orderId, String openId, BaseUser baseUser) {
Response<Map<String, String>> response = new Response<>();
Map<String, String> map = new HashMap<>();
try {
if (Strings.isNullOrEmpty(orderId)) {
throw new ArgumentException("交易编号为空");
}
if (Strings.isNullOrEmpty(openId)) {
throw new ArgumentException("openId为空");
}
if (baseUser == null) {
throw new BusinessException(ResultCode.ERROR_USER_UNLOGIN.getName());
}
Response<String> res = this.getOrderAmount(orderId, "1", baseUser);
int amount = 0;
if (res.isSuccess() && res.getResult() != null) {
amount = new BigDecimal(res.getResult()).multiply(new BigDecimal(100)).intValue();
} else {
throw new BusinessException(res.getError());
}
//生成请求参数XML--公众号
String xml = this.createWeChatPayXml(orderId, openId, amount);
//微信支付统一下单接口
String payRequestURL = "https://api.mch.weixin.qq.com/pay/unifiedorder";
ClientCustomSSL clientCustomSSL = new ClientCustomSSL();
//发起请求
String result = clientCustomSSL.doPayRequest(payRequestURL, xml);
result = result.replaceAll("\n", "").replaceAll("\r", "").replaceAll("\t", "");
log.error(result);
//解析返回结果,重新处理以发给前端(app)
Document doc = DocumentHelper.parseText(result);
Map<String, Object> resultMap = XmlMapHandle.Dom2Map(doc);
if (((String) resultMap.get("return_code")).equalsIgnoreCase("SUCCESS") && ((String) resultMap.get("result_code")).equals("SUCCESS")) {
map.put("appid", (String) resultMap.get("appid"));
map.put("mch_id", (String) resultMap.get("mch_id"));
map.put("prepay_id", (String) resultMap.get("prepay_id"));
map.put("package", "prepay_id=" + resultMap.get("prepay_id"));
Long l = new Date().getTime() / 1000;
Integer timestamp = Integer.parseInt(l.toString());
map.put("timestamp", timestamp.toString());
map.put("nonceStr", "aaronlovem" + timestamp.toString());
// createPaySignStr() ---- 生成支付签名-公众号,注意 :需要跟发起支付时候的,生成签名的参数规则一致。总之,需要跟前端提交时候,微信生成的签名一致。
String paySign = createPaySignStr(map.get("nonceStr").toString(), map.get("package"), map.get("timestamp"));
map.put("paySign", paySign);
map.put("openId", openId);
response.setResult(map);
} else {
response.setSuccess(false);
response.setError((String) resultMap.get("return_msg"));
}
} catch (ArgumentException a) {
response.setError(a.getMessage());
} catch (BusinessException b) {
response.setError(b.getMessage());
log.error("weChatPayRequest 异常!原因:{}", Throwables.getStackTraceAsString(b));
} catch (RuntimeException c) {
response.setError(c.getMessage());
log.error("weChatPayRequest 异常!原因:{}", Throwables.getStackTraceAsString(c));
} catch (Exception e) {
response.setError("微信支付异常!" + Throwables.getStackTraceAsString(e));
log.error("weChatPayRequest 异常!原因:{}", Throwables.getStackTraceAsString(e));
}
//返回给前端,微信支付订单信息
return response;
}

一个生成签名的方式,还有其他方式,仅做记录,如下:

/**
* 生成支付签名-公众号
*
* @return
*/
public String createPaySignStr(String nonceStr, String packageStr, String timestamp) throws Exception {
String[] arr = new String[5];
arr[0] = "appId=suwxb1d7b09dsaf81c92eb";
arr[1] = "nonceStr=" + nonceStr;
arr[2] = "package=" + packageStr;
arr[3] = "signType=MD5";
arr[4] = "timeStamp=" + timestamp;
Arrays.sort(arr);
String param = "";
for (int i = 0; i < arr.length; i++) {
param += arr[i] + "&";
}
param += "key=我是key呵呵呵呵呵";
log.error("微信支付请求参数:" + param);
return MD5Util.MD5Encode(param, null).toUpperCase();
} /**
* 生成支付签名-B端、C端
*
* @param noncestr
* @param packagestr
* @param prepayid
* @param timestamp
* @return
*/
public String createWeChatGoPayXmlForAPP(String noncestr, String packagestr, String prepayid, String timestamp, String type) {
String appId = "";
String partnerId = "";
String key = "";
if ("B2C".equals(type)) {
appId = "suwxb1d7bf09af81c92eb";
partnerId = "1322218523201";
key = "我是key";
} else if ("B2B".equals(type)) {
appId = "suwxb1d7b09af81c92eb";
partnerId = "1352713d383902";
key = "我是key啊";
}
String[] arr = new String[6];
arr[0] = "appid=" + appId;
arr[1] = "noncestr=" + noncestr;
arr[2] = "package=" + packagestr;
arr[3] = "partnerid=" + partnerId;
arr[4] = "prepayid=" + prepayid;
arr[5] = "timestamp=" + timestamp;
Arrays.sort(arr);
String param = "";
for (int i = 0; i < arr.length; i++) {
param += arr[i] + "&";
}
param += "key=" + key;
log.error("微信支付请求参数:" + param);
return MD5Util.MD5Encode(param, null).toUpperCase();
}

b、c的交易请求,app支付:大体与公众号支付类似,参数不一致

/**
* 微信支付 交易请求,生成预付单,C端
*
* @param orderId
* @param baseUser
* @return
*/
@Override
public Response<Map<String, String>> weChatPayRequestForC(String orderId, BaseUser baseUser) {
Response<Map<String, String>> response = new Response<Map<String, String>>();
Map<String, String> map = new HashMap<String, String>();
try {
if (Strings.isNullOrEmpty(orderId)) {
throw new ArgumentException("交易编号为空");
}
Response<String> res = this.getOrderAmount(orderId, "1", baseUser);
int amount = 0;
if (res.isSuccess() && res.getResult() != null) {
amount = new BigDecimal(res.getResult()).multiply(new BigDecimal(100)).intValue();
} else {
throw new BusinessException(res.getError());
}
String xml = this.createWeChatPayXmlForAPP(orderId, amount, "B2C");
String payRequestURL = "https://api.mch.weixin.qq.com/pay/unifiedorder";
ClientCustomSSL clientCustomSSL = new ClientCustomSSL();
String result = clientCustomSSL.doPayRequest(payRequestURL, xml);
result = result.replaceAll("\n", "").replaceAll("\r", "").replaceAll("\t", "");
log.error(result);
Document doc = DocumentHelper.parseText(result);
Map<String, Object> resultMap = XmlMapHandle.Dom2Map(doc);
if (((String) resultMap.get("return_code")).equalsIgnoreCase("SUCCESS") && ((String) resultMap.get("result_code")).equals("SUCCESS")) {
Map<String, String> param = new HashMap<String, String>();
param.put("appid", (String) resultMap.get("appid"));
param.put("partnerid", (String) resultMap.get("mch_id"));
param.put("prepayid", (String) resultMap.get("prepay_id"));
param.put("package", "Sign=WXPay");
Long l = new Date().getTime() / 1000;
Integer timestamp = Integer.parseInt(l.toString());
param.put("noncestr", "xxxxxB2Capp" + timestamp.toString());
param.put("timestamp", timestamp.toString());
param.put("sign", this.createWeChatGoPayXmlForAPP(param.get("noncestr").toString(), param.get("package").toString(), param.get("prepayid").toString(), param.get("timestamp").toString(), "B2C"));
response.setResult(param);
} else {
response.setSuccess(false);
response.setError((String) resultMap.get("return_msg"));
}
} catch (ArgumentException a) {
response.setError(a.getMessage());
} catch (BusinessException b) {
response.setError(b.getMessage());
log.error("weChatPayRequest 异常!原因:{}", Throwables.getStackTraceAsString(b));
} catch (RuntimeException c) {
response.setError(c.getMessage());
log.error("weChatPayRequest 异常!原因:{}", Throwables.getStackTraceAsString(c));
} catch (Exception e) {
response.setError("微信支付异常!" + Throwables.getStackTraceAsString(e));
log.error("weChatPayRequest 异常!原因:{}", Throwables.getStackTraceAsString(e));
}
return response;
} @Override
public Response<Map<String, String>> weChatPayRequestForB(String orderId, BaseUser baseUser) {
Response<Map<String, String>> response = new Response<Map<String, String>>();
Map<String, String> map = new HashMap<String, String>();
try {
if (Strings.isNullOrEmpty(orderId)) {
throw new ArgumentException("交易编号为空");
}
Response<String> res = this.getOrderAmount(orderId, "1", baseUser);
int amount = 0;
if (res.isSuccess() && res.getResult() != null) {
amount = new BigDecimal(res.getResult()).multiply(new BigDecimal(100)).intValue();
} else {
throw new BusinessException(res.getError());
}
String xml = this.createWeChatPayXmlForAPP(orderId, amount, "B2B");
String payRequestURL = "https://api.mch.weixin.qq.com/pay/unifiedorder";
ClientCustomSSL clientCustomSSL = new ClientCustomSSL();
String result = clientCustomSSL.doPayRequest(payRequestURL, xml);
result = result.replaceAll("\n", "").replaceAll("\r", "").replaceAll("\t", "");
log.error(result);
Document doc = DocumentHelper.parseText(result);
Map<String, Object> resultMap = XmlMapHandle.Dom2Map(doc);
if (((String) resultMap.get("return_code")).equalsIgnoreCase("SUCCESS") && ((String) resultMap.get("result_code")).equals("SUCCESS")) {
Map<String, String> param = new HashMap<String, String>();
param.put("appid", (String) resultMap.get("appid"));
param.put("partnerid", (String) resultMap.get("mch_id"));
param.put("prepayid", (String) resultMap.get("prepay_id"));
param.put("package", "Sign=WXPay");
Long l = new Date().getTime() / 1000;
Integer timestamp = Integer.parseInt(l.toString());
param.put("noncestr", "xxxxB2Bapp" + timestamp.toString());
param.put("timestamp", timestamp.toString());
param.put("sign", this.createWeChatGoPayXmlForAPP(param.get("noncestr").toString(), param.get("package").toString(), param.get("prepayid").toString(), param.get("timestamp").toString(), "B2B"));
response.setResult(param);
} else {
response.setSuccess(false);
response.setError((String) resultMap.get("return_msg"));
}
} catch (ArgumentException a) {
response.setError(a.getMessage());
} catch (BusinessException b) {
response.setError(b.getMessage());
log.error("weChatPayRequest 异常!原因:{}", Throwables.getStackTraceAsString(b));
} catch (RuntimeException c) {
response.setError(c.getMessage());
log.error("weChatPayRequest 异常!原因:{}", Throwables.getStackTraceAsString(c));
} catch (Exception e) {
response.setError("微信支付异常!" + Throwables.getStackTraceAsString(e));
log.error("weChatPayRequest 异常!原因:{}", Throwables.getStackTraceAsString(e));
}
return response;
}

(3)告知微信处理通知支付结果。此为,我们在后台发起微信支付请求生成预订单时候,传入的回调函数的方法。微信后台在处理完微信支付结果后,会发起请求,调用我们已经准备好的回调函数地址。

回调函数中,可以具体处理下我们商户系统中的一些业务,比如更新订单状态,提醒消息等等.....处理完成,返回微信后台处理结果。

对应于微信支付下单api接口参数中的,如下:

 /**
* 微信支付回调函数
*
* @param weChatPayReturn
* @return
*/
@Override
public String getWeChatPayReturnForOrder(WeChatPayReturn weChatPayReturn) {
log.error("微信普通订单回调,参数为:" + weChatPayReturn.toString());
System.out.println("微信普通订单回调,参数为:" + weChatPayReturn.toString());
boolean flag = false;
try {
if (null != weChatPayReturn) {
//保存微信回调信息
rechargeOrderManager.saveRechargeOrderWeChatPayInfo(weChatPayReturn);
if (true) {
//判断该笔订单是否在商户网站中已经做过处理
//如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序
//如果有做过处理,不执行商户的业务程序
flag = rechargeOrderManager.getWeChatPayReturnForOrder(weChatPayReturn);
if (flag) {
String successStr = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
return successStr;
} else {
return "fail";
}
}
} else {
throw new ArgumentException("微信回调对象为空!");
}
} catch (ArgumentException a) {
//参数异常不写log日志
log.error("微信回调对象异常!原因:{}", Throwables.getStackTraceAsString(a));
} catch (BusinessException b) {
log.error("微信回调对象异常!原因:{}", Throwables.getStackTraceAsString(b));
} catch (Exception e) {
log.error("微信回调对象异常!原因:{}", Throwables.getStackTraceAsString(e));
}
return "fail";
}

注意:文章中所列出的代码不一定是最好的,只提供流程思路,方便理解和记忆。具体的实现方式,自己把握。比如,在生成支付签名时候,有多种方式来实现。

           

<正则吃饺子> :关于微信支付的简单总结说明(一)的更多相关文章

  1. <正则吃饺子>:关于集合的简单整理总结

    项目中用到的集合不可谓不多,对于自己的一次面试,要求说下自己用过的集合,自己开始说的并不系统也不完整,一直耿耿于怀,特整理一下,以备后期之用和帮助后来者. package com.love.malin ...

  2. <正则吃饺子>:关于java中垃圾回收技术的简单学习总结

    知识介绍来自网络,后面会根据继续学习进行补充和适当的修改,谢谢!原文地址:http://www.importnew.com/26821.html#comment-578355 java中的垃圾回收机制 ...

  3. <正则吃饺子> :关于微信支付的简单总结说明(二)

    关于微信退款 一.官方文档 申请退款:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_4&index=6 二.退款流程 ...

  4. <正则吃饺子>:关于java中对内存部分的简单总结整理

    在项目和一些群讨论中,经常看到对内存的处理,但是,自己确是一知半解的,基于此,就把这部分的知识简单的整理了下,知识点来源于网络博文,也一一标明出处,谢谢. package com.love.malin ...

  5. <正则吃饺子> :关于 Matcher 的 replaceAll 的简单使用

    在线文档地址:http://tool.oschina.net/apidocs/apidoc?api=jdk-zh replaceAll public String replaceAll(String  ...

  6. <正则吃饺子> :关于oracle 中 with的简单使用

    oracle中 with的简单使用介绍,具体可以参见其他的博文介绍,在这里只是简单的介绍: with 构建了一个临时表,类似于存储过程中的游标,我是这么理解的. 一.数据准备: select * fr ...

  7. <正则吃饺子> :关于oracle 中 exists 、not exists 的简单使用

    话不多说,简单的总结而已.网络上很多很详细介绍. 例如,博文:http://blog.csdn.net/zhiweianran/article/details/7868894  当然这篇也是转载的,原 ...

  8. <正则吃饺子> :关于Guava中 Joiner 和 Splitter 的简单使用

    在现在项目中经常看到 这两个类的使用,开始时候不明白具体是做的什么事情,就单独拿出来学习下了,参照了网上的博文,这里主要是简单的讲讲用法. 具体对这两个类,不做过多介绍,有个在线文档,需要的可以自己去 ...

  9. <正则吃饺子> :关于Collections中 比较器的简单使用

    在线文档地址: http://tool.oschina.net/apidocs/apidoc?api=jdk-zh sort public static <T extends Comparabl ...

随机推荐

  1. 【BZOJ3451】Tyvj1953 Normal 点分治+FFT+期望

    [BZOJ3451]Tyvj1953 Normal Description 某天WJMZBMR学习了一个神奇的算法:树的点分治!这个算法的核心是这样的:消耗时间=0Solve(树 a) 消耗时间 += ...

  2. rtmp直播拉流客户端EasyRTMPClient设计过程中时间戳问题汇总

    EasyRTMPClient 简介 EasyRTMPClient是EasyDarwin流媒体团队开发.提供的一套非常稳定.易用.支持重连接的RTMPClient工具,以SDK形式提供,接口调用非常简单 ...

  3. 一种微信直播H5直播与存储回放的HLS摄像机方案

    接上篇 在上一篇博客<一种流量成本节省60%以上的手机直播微信直播H5直播幼儿园直播方案>中,我们一共介绍了两种省钱的HLS直播途径: 方案一:编码器或者内网推流直接对接云存储的场景 如果 ...

  4. Angular入门(二) 服务

    目的:为了不再把相同的代码复制一遍又一遍,我们要创建一个单一的可复用的数据服务,并且把它注入到需要它的那些组件中. ※  文件命名约定:服务名称的小写形式(基本名),加上.service后缀,如果服务 ...

  5. 洛谷 3275 [SCOI2011]糖果

    题目戳这里 N句话题意 有N个人,k个限制,有五种限制 如果X=1, 表示第A个小朋友的糖果必须和第B个小朋友的糖果一样多: 如果X=2, 表示第A个小朋友的糖果必须少于第B个小朋友的糖果: 如果X= ...

  6. POJ - 1321 棋盘问题 【DFS】

    题目链接 http://poj.org/problem?id=1321 思路 和N皇后问题类似 但是有一点不同的是 这个是只需要摆放K个棋子就可以了 所以 我们要做好 两个出口 并且要持续往下一层找 ...

  7. Spring Boot2.0之web开发

    1.关于静态资源的访问 在我们开发Web应用的时候,需要引用大量的js.css.图片等静态资源. Spring Boot默认提供静态资源目录位置需置于classpath下,目录名需符合如下规则: /s ...

  8. ansible playbook学习

    摘自: http://www.ywnds.com/?p=6064 https://github.com/ansible/ansible-examples

  9. C语言实现队列(纯C)

    1. [代码][C/C++]代码 #include <stdio.h>#include <stdlib.h>#define ElemType int #define Statu ...

  10. Java 吃货联盟

    import java.util.Scanner; public class Shao {  private static final int[] dishNames = null;  private ...