一、生成预支付订单并返回给前端
@ApiOperation("订单支付")
@PostMapping("/payOrder")
public Result<?> payOrder(@RequestParam("orderId")String orderId,
@RequestParam("memberId")String memberId,
HttpServletRequest request){
try{
Map<Object, Object> resultObj = new TreeMap();
OnlineLessonsApply onlineLessonsApply = onlineLessonsApplyService.getById(orderId);
CdpMember member = cdpMemberService.getById(memberId);
//获取支付参数
SysConfig sysConfig = sysConfigService.getOne(new QueryWrapper<SysConfig>().eq("type",2));
if(sysConfig == null){
return Result.error("支付参数未配置");
}
JSONObject object = JSONObject.parseObject(sysConfig.getJsonConfig());
String mchid = object.getString("mchid");
String key = object.getString("key");
String appid = object.getString("appid");
String notifyUrl = object.getString("notifyUrl");
Map<Object, Object> parame = new TreeMap<Object, Object>();
parame.put("appid", appid);
// 商家账号。
parame.put("mch_id", mchid);
String randomStr = CharUtil.getRandomNum(18).toUpperCase();
// 随机字符串
parame.put("nonce_str", randomStr);
// 商户订单编号
parame.put("out_trade_no", onlineLessonsApply.getId());
parame.put("body", "小程序支付");
//支付金额
parame.put("total_fee", new BigDecimal(onlineLessonsApply.getLessonsPrice()).multiply(new BigDecimal(100)).intValue());
// 回调地址
parame.put("notify_url", notifyUrl);
// 交易类型APP
parame.put("trade_type", "JSAPI");
parame.put("spbill_create_ip", IpAddressUtil.getIpAddr(request));
parame.put("openid", member.getOpenid());
String sign = WechatUtil.arraySign(parame, key);
// 数字签证
parame.put("sign", sign);
String xml = MapUtils.convertMap2Xml(parame);
log.info("xml:" + xml);
Map<String, Object> resultUn = XmlUtil.xmlStrToMap(WechatUtil.requestOnce(uniformorder, xml));
String prepay_id = MapUtils.getString("prepay_id", resultUn);
// 响应报文
String return_code = MapUtils.getString("return_code", resultUn);
String return_msg = MapUtils.getString("return_msg", resultUn);
if(return_code.equalsIgnoreCase("FAIL")) {
return Result.error("支付失败," + return_msg);
} else if(return_code.equalsIgnoreCase("SUCCESS")) {
// 返回数据
String result_code = MapUtils.getString("result_code", resultUn);
String err_code_des = MapUtils.getString("err_code_des", resultUn);
if(result_code.equalsIgnoreCase("FAIL")) {
return Result.error("支付失败," + err_code_des);
} else if(result_code.equalsIgnoreCase("SUCCESS")) {
String nonceStr = CharUtil.getRandomString(32);
// 先生成paySign 参考https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_7&index=5
resultObj.put("appId", appid);
resultObj.put("timeStamp", DateUtils.timeToStr(System.currentTimeMillis() / 1000, DateUtils.DATE_TIME_PATTERN));
resultObj.put("nonceStr", nonceStr);
resultObj.put("package", "prepay_id=" + prepay_id);
resultObj.put("signType", "MD5");
String paySign = WechatUtil.arraySign(resultObj, key);
resultObj.put("paySign", paySign);
onlineLessonsApply.setPrepayId(prepay_id);
onlineLessonsApplyService.updateById(onlineLessonsApply);
return Result.ok(resultObj);
}
}
return Result.error("支付失败");
}catch (Exception e){
e.printStackTrace();
return Result.error("订单支付失败");
}
}
2.订单回调
@ApiOperation(value = "微信订单回调接口")
@RequestMapping(value = "/notify", method = RequestMethod.POST, produces = "text/html;charset=UTF-8")
public void notify(HttpServletRequest request, HttpServletResponse response) {
System.out.println("微信订单回调接口");
try {
log.info("微信订单回调接口");
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
response.setHeader("Access-Control-Allow-Origin", "*");
InputStream in = request.getInputStream();
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = 0;
while ((len = in.read(buffer)) != -1) {
out.write(buffer, 0, len);
}
out.close();
in.close();
//xml数据
String reponseXml = new String(out.toByteArray(), "utf-8");
log.info("xml:"+reponseXml);
WechatRefundApiResult result = (WechatRefundApiResult) XmlUtil.xmlStrToBean(reponseXml, WechatRefundApiResult.class);
String result_code = result.getResult_code();
//订单编号
String out_trade_no = result.getOut_trade_no();
// 业务处理
OnlineLessonsApply param = new OnlineLessonsApply();
param.setId(out_trade_no);
OnlineLessonsApply orderInfo = onlineLessonsApplyService.getById(param);
if(result_code.equalsIgnoreCase("FAIL")) {
//订单编号
log.error("订单" + out_trade_no + "支付失败");
response.getWriter().write(setXml("SUCCESS", "OK"));
} else if(result_code.equalsIgnoreCase("SUCCESS")) {
log.error("订单" + out_trade_no + "支付成功");
orderInfo.setTransactionId(result.getTransaction_id());
orderInfo.setStatus("2");
orderInfo.setPayTime(new Date());
onlineLessonsApplyService.updateById(orderInfo);
response.getWriter().write(setXml("SUCCESS", "OK"));
}
} catch (Exception e) {
log.error("notify 错误:{}", e.getStackTrace());
return;
}
}
//返回微信服务
public static String setXml(String return_code, String return_msg) {
return "<xml><return_code><![CDATA[" + return_code + "]]></return_code><return_msg><![CDATA[" + return_msg + "]]></return_msg></xml>";
}
3.工具类
import java.util.Random;
public class CharUtil {
/**
* 获取随机字符串
*
* @param num
* @return
*/
public static String getRandomString(Integer num) {
String base = "abcdefghijklmnopqrstuvwxyz0123456789";
Random random = new Random();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < num; i++) {
int number = random.nextInt(base.length());
sb.append(base.charAt(number));
}
return sb.toString();
}
/**
* 获取随机字符串
*
* @param num
* @return
*/
public static String getRandomNum(Integer num) {
String base = "0123456789";
Random random = new Random();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < num; i++) {
int number = random.nextInt(base.length());
sb.append(base.charAt(number));
}
return sb.toString();
}
/**
* 右补位,左对齐
*
* @param oriStr 原字符串
* @param len 目标字符串长度
* @param fillChar 补位字符
* @return 目标字符串
*/
public static String padRight(String oriStr, int len, char fillChar) {
String str = "";
int strlen = oriStr.length();
if (strlen < len) {
for (int i = 0; i < len - strlen; i++) {
str = str + fillChar;
}
}
str = str + oriStr;
return str;
}
/**
* 左补位,右对齐
*
* @param oriStr 原字符串
* @param len 目标字符串长度
* @param fillChar 补位字符
* @return 目标字符串
*/
public static String padLeft(String oriStr, int len, char fillChar) {
int strlen = oriStr.length();
String str = "";
if (strlen < len) {
for (int i = 0; i < len - strlen; i++) {
str = str + fillChar;
}
}
str = oriStr + str;
return str;
}
}
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
/**
* 日期处理
*
* @author zscat
* @email 939961241@qq.com
* @date 2016年12月21日 下午12:53:33
*/
public class DateUtils {
/**
* 时间格式(yyyy-MM-dd)
*/
public final static String DATE_PATTERN = "yyyy-MM-dd";
/**
* 时间格式(yyyy-MM-dd HH:mm:ss)
*/
public final static String DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
/**
* 无分隔符日期格式 "yyyyMMddHHmmssSSS"
*/
public static String DATE_TIME_PATTERN_YYYY_MM_DD_HH_MM_SS_SSS = "yyyyMMddHHmmssSSS";
// 日期转换格式数组
public static String[][] regularExp = new String[][]{
// 默认格式
{"\\d{4}-((([0][1,3-9]|[1][0-2]|[1-9])-([0-2]\\d|[3][0,1]|[1-9]))|((02|2)-(([1-9])|[0-2]\\d)))\\s+([0,1]\\d|[2][0-3]|\\d):([0-5]\\d|\\d):([0-5]\\d|\\d)",
DATE_TIME_PATTERN},
// 仅日期格式 年月日
{"\\d{4}-((([0][1,3-9]|[1][0-2]|[1-9])-([0-2]\\d|[3][0,1]|[1-9]))|((02|2)-(([1-9])|[0-2]\\d)))",
DATE_PATTERN},
// 带毫秒格式
{"\\d{4}((([0][1,3-9]|[1][0-2]|[1-9])([0-2]\\d|[3][0,1]|[1-9]))|((02|2)(([1-9])|[0-2]\\d)))([0,1]\\d|[2][0-3])([0-5]\\d|\\d)([0-5]\\d|\\d)\\d{1,3}",
DATE_TIME_PATTERN_YYYY_MM_DD_HH_MM_SS_SSS}
};
// 日志
private static org.slf4j.Logger logger = LoggerFactory.getLogger(DateUtils.class);
public static String format(Date date) {
return format(date, DATE_PATTERN);
}
public static String format(Date date, String pattern) {
if (date != null) {
SimpleDateFormat df = new SimpleDateFormat(pattern);
return df.format(date);
}
return null;
}
public static String timeToStr(Long time, String pattern) {
SimpleDateFormat dateFormat = new SimpleDateFormat(pattern);
if (time.toString().length() < 13) {
time = time * 1000L;
}
Date date = new Date(time);
String value = dateFormat.format(date);
return value;
}
public static long strToTime(String timeStr) {
Date time = strToDate(timeStr);
return time.getTime() / 1000;
}
/**
* 转换为时间类型格式
*
* @param strDate 日期
* @return
*/
public static Date strToDate(String strDate) {
try {
String strType = getDateFormat(strDate);
SimpleDateFormat sf = new SimpleDateFormat(strType);
return new Date((sf.parse(strDate).getTime()));
} catch (Exception e) {
return null;
}
}
/**
* 根据传入的日期格式字符串,获取日期的格式
*
* @return 秒
*/
public static String getDateFormat(String date_str) {
String style = null;
if (StringUtils.isEmpty(date_str)) {
return null;
}
boolean b = false;
for (int i = 0; i < regularExp.length; i++) {
b = date_str.matches(regularExp[i][0]);
if (b) {
style = regularExp[i][1];
}
}
if (StringUtils.isEmpty(style)) {
logger.info("date_str:" + date_str);
logger.info("日期格式获取出错,未识别的日期格式");
}
return style;
}
/**
* 将字符串类型的转换成Date类型
*
* @param dateStr 字符串类型的日期 yyyy-MM-dd
* @return Date类型的日期
* @throws ParseException
*/
public static Date convertStringToDate(String dateStr) {
// 返回的日期
Date resultDate = null;
try {
// 日期格式转换
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
resultDate = sdf.parse(dateStr);
} catch (ParseException e) {
e.printStackTrace();
}
return resultDate;
}
/**
* 将字符串类型的转换成Date类型
*
* @param dateStr 字符串类型的日期 yyyy-MM-dd
* @return Date类型的日期
* @throws ParseException
*/
public static Date convertStringToDate(String dateStr, String formate) {
// 返回的日期
Date resultDate = null;
try {
// 日期格式转换
SimpleDateFormat sdf = new SimpleDateFormat(formate);
resultDate = sdf.parse(dateStr);
} catch (ParseException e) {
e.printStackTrace();
}
return resultDate;
}
/**
* 添加小时
*
* @param date
* @param hour
* @return
*/
public static String addHours(Date date, int hour) {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Calendar cal = Calendar.getInstance();
cal.setTime(date);
cal.add(Calendar.HOUR, hour);// 24小时制
date = cal.getTime();
cal = null;
return format.format(date);
}
public static void main(String[] args) {
Date date = new Date();
String str = "20170818223629599";
System.out.println(DateUtils.getDateFormat(str));
}
}
public interface DealMapValueHelper {
void dealValue(String key, Map<String, Object> map);
}
import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* IP地址工具类定义
* @author yang.liu
*/
public class IpAddressUtil {
public static String getIpAddr(HttpServletRequest request){
String ipAddress = request.getHeader("x-forwarded-for");
if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getHeader("Proxy-Client-IP");
}
if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getHeader("WL-Proxy-Client-IP");
}
if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getRemoteAddr();
if(ipAddress.equals("127.0.0.1") || ipAddress.equals("0:0:0:0:0:0:0:1")){
//根据网卡取本机配置的IP
InetAddress inet=null;
try {
inet = InetAddress.getLocalHost();
} catch (UnknownHostException e) {
e.printStackTrace();
}
ipAddress= inet.getHostAddress();
}
}
//对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
if(ipAddress!=null && ipAddress.length()>15){ //"***.***.***.***".length() = 15
if(ipAddress.indexOf(",")>0){
ipAddress = ipAddress.substring(0,ipAddress.indexOf(","));
}
if(ipAddress.indexOf(":")>0){
ipAddress = ipAddress.substring(0,ipAddress.indexOf(":"));
}
}
return ipAddress;
}
}
import org.apache.commons.beanutils.PropertyUtilsBean;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.Assert;
import java.beans.PropertyDescriptor;
import java.math.BigDecimal;
import java.sql.Date;
import java.sql.Timestamp;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/**
* 获取map中值的工具类,自动进行类型转换
*
* @author DT_panda
*/
public class MapUtils {
public static String getString(String key, Map<String, Object> map) {
if (map == null || key == null)
throw new IllegalArgumentException();
if (!map.containsKey(key))
return null;
Object value = map.get(key);
if (value == null)
return null;
return value.toString();
}
public static Integer getInteger(String key, Map<String, Object> map) {
if (map == null || key == null)
throw new IllegalArgumentException();
if (!map.containsKey(key))
return null;
Object value = map.get(key);
if (value == null)
return null;
if (value instanceof Integer)
return (Integer) value;
if (value instanceof String)
return Integer.valueOf((String) value);
//Date 不支持变成为date类型
if (value instanceof Date)
throw new ClassCastException();
if (value instanceof Number)
return ((Number) value).intValue();
throw new ClassCastException();
}
public static Long getLong(String key, Map<String, Object> map) {
if (map == null || key == null)
throw new IllegalArgumentException();
if (!map.containsKey(key))
return null;
Object value = map.get(key);
if (value == null)
return null;
if (value instanceof Long)
return (Long) value;
if (value instanceof Number)
return ((Number) value).longValue();
if (value instanceof String)
return Long.valueOf((String) value);
if (value instanceof Date) {
return (((Date) value).getTime());
}
if (value instanceof java.sql.Time) {
return ((java.sql.Time) value).getTime();
}
if (value instanceof Timestamp) {
return ((Timestamp) value).getTime();
}
throw new ClassCastException();
}
public static Double getDouble(String key, Map<String, Object> map) {
if (map == null || key == null)
throw new IllegalArgumentException();
if (!map.containsKey(key))
return null;
Object value = map.get(key);
if (value == null)
return null;
if (value instanceof Double)
return (Double) value;
if (value instanceof Number)
return ((Number) value).doubleValue();
if (value instanceof String)
return Double.valueOf((String) value);
throw new ClassCastException();
}
public static BigDecimal getBigDecimal(String key, Map<String, Object> map) {
if (map == null || key == null)
throw new IllegalArgumentException();
if (!map.containsKey(key))
return null;
Object value = map.get(key);
if (value == null)
return null;
if (value instanceof BigDecimal)
return (BigDecimal) value;
if (value instanceof Integer)
return new BigDecimal((Integer) value);
if (value instanceof Short)
return new BigDecimal((Short) value);
if (value instanceof Byte)
return new BigDecimal((Byte) value);
if (value instanceof Long)
return new BigDecimal((Long) value);
if (value instanceof Float)
return new BigDecimal((Float) value);
if (value instanceof Double)
return new BigDecimal((Double) value);
if (value instanceof Date) {
return new BigDecimal(((Date) value).getTime());
}
if (value instanceof java.sql.Time) {
return new BigDecimal(((java.sql.Time) value).getTime());
}
if (value instanceof Timestamp) {
return new BigDecimal(((Timestamp) value).getTime());
}
if (value instanceof String) {
if (!StringUtils.isEmpty((String) value))
return new BigDecimal((String) value);
else
return null;
}
throw new ClassCastException();
}
/**
* 将bean转化为map
*
* @param bean
* @return
*/
public static Map<String, Object> getMap(Object bean) {
return beanToMap(bean);
}
/**
* 将map中key为likeKey的value前后加上字符'%',用于like查询
*
* @param map
* @param likeKey
*/
public static void toLikeValue(Map<String, Object> map, String... likeKey) {
if (ArrayUtils.isEmpty(likeKey))
return;
for (String key : likeKey) {
if (map.containsKey(key))
map.put(key, "%" + map.get(key) + "%");
}
}
/**
* 获取日期
*
* @param key
* @param map
* @return
*/
public static Date getDate(String key, Map<String, Object> map) {
if (map == null || key == null)
throw new IllegalArgumentException();
if (!map.containsKey(key))
return null;
Object value = map.get(key);
if (value == null)
return null;
else {
if (value instanceof Date) {
return (Date) value;
} else if (value instanceof Timestamp) {
return new Date(((Timestamp) value).getTime());
}
}
return null;
}
/**
* 获取日期
*
* @param key
* @param map
* @return
*/
public static java.util.Date getTimestamp(String key, Map<String, Object> map) {
if (map == null || key == null)
throw new IllegalArgumentException();
if (!map.containsKey(key))
return null;
Object value = map.get(key);
if (value == null)
return null;
else {
if (value instanceof Date) {
return (Date) value;
} else if (value instanceof Timestamp) {
Timestamp ts = (Timestamp) value;
return ts;
}
}
return null;
}
/**
* 如果value不为空 ,则放到map中
*
* @param map
* @param key
* @param value
*/
public static void putIfValueNotNull(Map<String, Object> map, String key, Object value) {
Assert.notNull(map);
Assert.hasText(key);
if (value != null)
map.put(key, value);
}
/**
* 如果value不为空 ,则放到map中
*
* @param map
* @param key
* @param value
*/
public static void putIfValueNotEmpty(Map<String, Object> map, String key, String value) {
Assert.notNull(map);
Assert.hasText(key);
if (!StringUtils.isEmpty(value))
map.put(key, value);
}
/**
* 将map中指定的key的value值进行处理
*
* @param key
* @param map
* @param helper
*/
public static void convertMapValuePattern(String key, Map<String, Object> map, DealMapValueHelper helper) {
Assert.hasText(key);
Assert.notNull(map);
Assert.notNull(helper);
helper.dealValue(key, map);
}
/**
* 将javabean实体类转为map类型,然后返回一个map类型的值
*
* @return
*/
public static Map<String, Object> beanToMap(Object beanObj) {
Map<String, Object> params = new HashMap<String, Object>(0);
try {
PropertyUtilsBean propertyUtilsBean = new PropertyUtilsBean();
PropertyDescriptor[] descriptors = propertyUtilsBean.getPropertyDescriptors(beanObj);
for (int i = 0; i < descriptors.length; i++) {
String name = descriptors[i].getName();
if (!"class".equals(name)) {
params.put(name, propertyUtilsBean.getNestedProperty(beanObj, name));
}
}
} catch (Exception e) {
e.printStackTrace();
}
return params;
}
public static String convertMap2Xml(Map<Object, Object> paraMap) {
StringBuffer xmlStr = new StringBuffer();
if (paraMap != null) {
xmlStr.append("<xml>");
Set<Object> keySet = paraMap.keySet();
Iterator<Object> keyIte = keySet.iterator();
while (keyIte.hasNext()) {
String key = (String) keyIte.next();
String val = String.valueOf(paraMap.get(key));
xmlStr.append("<");
xmlStr.append(key);
xmlStr.append(">");
xmlStr.append(val);
xmlStr.append("</");
xmlStr.append(key);
xmlStr.append(">");
}
xmlStr.append("</xml>");
}
return xmlStr.toString();
}
}
import java.security.MessageDigest;
public class MD5 {
private MD5() {
}
/* * 生成 MD5
*
* @param data 待处理数据
* @return MD5结果
*/
public static String getMessageDigest(String data) {
StringBuilder sb = new StringBuilder();
try {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] array = md.digest(data.getBytes("UTF-8"));
for (byte item : array) {
sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
}
} catch (Exception e) {
return null;
}
return sb.toString().toUpperCase();
}
}
@SuppressWarnings("deprecation")
public class WechatConfig {
private static SSLConnectionSocketFactory sslcsf;
public static SSLConnectionSocketFactory getSslcsf() {
if (null == sslcsf) {
setSsslcsf();
}
return sslcsf;
}
private static void setSsslcsf() {
try {
KeyStore keyStore = KeyStore.getInstance("PKCS12");
Thread.currentThread().getContextClassLoader();
InputStream instream = new WechatRefundApiResult().getClass().getResourceAsStream("certName");
try {
keyStore.load(instream, "mchId".toCharArray());
} finally {
instream.close();
}
SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, "mchId".toCharArray()).build();
sslcsf = new SSLConnectionSocketFactory(sslcontext, new String[]{"TLSv1"}, null, SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class WechatRefundApiResult {
private String return_code;
private String return_msg;
private String result_code;
private String err_code;
private String err_code_des;
private String appid;
private String mch_id;
private String device_info;
private String nonce_str;
private String sign;
private String transaction_id;
private String out_trade_no;
private String out_refund_no;
private String refund_id;
private String refund_channel;
private String refund_fee;
private String settlement_refund_fee;
private String total_fee;
private String settlement_total_fee;
private String fee_type;
private String cash_fee;
private String cash_refund_fee;
private String refund_status;
public String getRefund_status() {
return refund_status;
}
public void setRefund_status(String refund_status) {
this.refund_status = refund_status;
}
public String getReturn_code() {
return return_code;
}
public void setReturn_code(String return_code) {
this.return_code = return_code;
}
public String getReturn_msg() {
return return_msg;
}
public void setReturn_msg(String return_msg) {
this.return_msg = return_msg;
}
public String getResult_code() {
return result_code;
}
public void setResult_code(String result_code) {
this.result_code = result_code;
}
public String getErr_code() {
return err_code;
}
public void setErr_code(String err_code) {
this.err_code = err_code;
}
public String getErr_code_des() {
return err_code_des;
}
public void setErr_code_des(String err_code_des) {
this.err_code_des = err_code_des;
}
public String getAppid() {
return appid;
}
public void setAppid(String appid) {
this.appid = appid;
}
public String getMch_id() {
return mch_id;
}
public void setMch_id(String mch_id) {
this.mch_id = mch_id;
}
public String getDevice_info() {
return device_info;
}
public void setDevice_info(String device_info) {
this.device_info = device_info;
}
public String getNonce_str() {
return nonce_str;
}
public void setNonce_str(String nonce_str) {
this.nonce_str = nonce_str;
}
public String getSign() {
return sign;
}
public void setSign(String sign) {
this.sign = sign;
}
public String getTransaction_id() {
return transaction_id;
}
public void setTransaction_id(String transaction_id) {
this.transaction_id = transaction_id;
}
public String getOut_trade_no() {
return out_trade_no;
}
public void setOut_trade_no(String out_trade_no) {
this.out_trade_no = out_trade_no;
}
public String getOut_refund_no() {
return out_refund_no;
}
public void setOut_refund_no(String out_refund_no) {
this.out_refund_no = out_refund_no;
}
public String getRefund_id() {
return refund_id;
}
public void setRefund_id(String refund_id) {
this.refund_id = refund_id;
}
public String getRefund_channel() {
return refund_channel;
}
public void setRefund_channel(String refund_channel) {
this.refund_channel = refund_channel;
}
public String getRefund_fee() {
return refund_fee;
}
public void setRefund_fee(String refund_fee) {
this.refund_fee = refund_fee;
}
public String getSettlement_refund_fee() {
return settlement_refund_fee;
}
public void setSettlement_refund_fee(String settlement_refund_fee) {
this.settlement_refund_fee = settlement_refund_fee;
}
public String getTotal_fee() {
return total_fee;
}
public void setTotal_fee(String total_fee) {
this.total_fee = total_fee;
}
public String getSettlement_total_fee() {
return settlement_total_fee;
}
public void setSettlement_total_fee(String settlement_total_fee) {
this.settlement_total_fee = settlement_total_fee;
}
public String getFee_type() {
return fee_type;
}
public void setFee_type(String fee_type) {
this.fee_type = fee_type;
}
public String getCash_fee() {
return cash_fee;
}
public void setCash_fee(String cash_fee) {
this.cash_fee = cash_fee;
}
public String getCash_refund_fee() {
return cash_refund_fee;
}
public void setCash_refund_fee(String cash_refund_fee) {
this.cash_refund_fee = cash_refund_fee;
}
}
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
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.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.BasicHttpClientConnectionManager;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.*;
/**
* <p>Title: 微信退款工具类</p>
* <p>Description: 微信退款工具类,通过充值客户端的不同初始化不同的工具类,得到相应微信退款相关的appid和muchid</p>
*
* @author xubo
* @date 2017年6月6日 下午5:05:03
*/
public class WechatUtil {
/**
* 充值客户端类型--微信公众号
*/
public static Integer CLIENTTYPE_WX = 2;
/**
* 充值客户端类型--app
*/
public static Integer CLIENTTYPE_APP = 1;
private static Logger logger = LoggerFactory.getLogger(WechatUtil.class);
/**
* 方法描述:微信退款逻辑
* 创建时间:2017年4月12日 上午11:04:25
* 作者: xubo
*
* @param
* @return
*/
/* public static WechatRefundApiResult wxRefund(String out_trade_no, Double orderMoney, Double refundMoney) {
//初始化请求微信服务器的配置信息包括appid密钥等
//转换金钱格式
BigDecimal bdOrderMoney = new BigDecimal(orderMoney, MathContext.DECIMAL32);
BigDecimal bdRefundMoney = new BigDecimal(refundMoney, MathContext.DECIMAL32);
//构建请求参数
Map<Object, Object> params = buildRequsetMapParam(out_trade_no, bdOrderMoney, bdRefundMoney);
String mapToXml = MapUtils.convertMap2Xml(params);
//请求微信
String reponseXml = sendSSLPostToWx(mapToXml, WechatConfig.getSslcsf());
WechatRefundApiResult result = (WechatRefundApiResult) XmlUtil.xmlStrToBean(reponseXml, WechatRefundApiResult.class);
return result;
}*/
/**
* 方法描述:得到请求微信退款请求的参数
* 创建时间:2017年6月8日 上午11:27:02
* 作者: xubo
*
* @param
* @return
*/
/* private static Map<Object, Object> buildRequsetMapParam(String out_trade_no, BigDecimal bdOrderMoney, BigDecimal bdRefundMoney) {
Map<Object, Object> params = new HashMap<Object, Object>();
//微信分配的公众账号ID(企业号corpid即为此appId)
params.put("appid", ResourceUtil.getConfigByName("wx.appId"));
//微信支付分配的商户号
params.put("mch_id", ResourceUtil.getConfigByName("wx.mchId"));
//随机字符串,不长于32位。推荐随机数生成算法
params.put("nonce_str", CharUtil.getRandomString(16));
//商户侧传给微信的订单号
params.put("out_trade_no", out_trade_no);
//商户系统内部的退款单号,商户系统内部唯一,同一退款单号多次请求只退一笔
params.put("out_refund_no", getBundleId());
//订单总金额,单位为分,只能为整数
params.put("total_fee", bdOrderMoney.multiply(new BigDecimal(100)).intValue());
//退款总金额,订单总金额,单位为分,只能为整数
params.put("refund_fee", bdRefundMoney.multiply(new BigDecimal(100)).intValue());
//操作员帐号, 默认为商户号
params.put("op_user_id", ResourceUtil.getConfigByName("wx.mchId"));
//签名前必须要参数全部写在前面
params.put("sign", arraySign(params, ResourceUtil.getConfigByName("wx.paySignKey")));
return params;
}*/
/**
* ResourceUtil.getConfigByName("wx.refundUrl")
* 请求微信https
**/
public static String sendSSLPostToWx(String mapToXml, SSLConnectionSocketFactory sslcsf, String refundUrl) {
logger.info("*******退款(WX Request:" + mapToXml);
HttpPost httPost = new HttpPost(refundUrl);
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) ");
httPost.setEntity(new StringEntity(mapToXml, "UTF-8"));
CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslcsf).build();
CloseableHttpResponse response = null;
try {
response = httpClient.execute(httPost);
HttpEntity entity = response.getEntity();
String xmlStr = EntityUtils.toString(entity, "UTF-8");
logger.info("*******退款(WX Response:" + xmlStr);
return xmlStr;
} catch (Exception e) {
logger.error(e.getMessage(), e);
return null;
} finally {
try {
if (response != null) {
response.close();
}
} catch (IOException e) {
logger.error(e.getMessage(), e);
}
}
}
/**
* 支付交易ID
*/
public static String getBundleId() {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmssSSS");
String tradeno = dateFormat.format(new Date());
String str = "000000" + (int) (Math.random() * 1000000);
tradeno = tradeno + str.substring(str.length() - 6);
return tradeno;
}
/**
* 方法描述:根据签名加密请求参数
* 创建时间:2017年6月8日 上午11:28:52
* 作者: xubo
*
* @param
* @return
*/
public static String arraySign(Map<Object, Object> params, String paySignKey) {
boolean encode = false;
Set<Object> keysSet = params.keySet();
Object[] keys = keysSet.toArray();
Arrays.sort(keys);
StringBuffer temp = new StringBuffer();
boolean first = true;
for (Object key : keys) {
if (first) {
first = false;
} else {
temp.append("&");
}
temp.append(key).append("=");
Object value = params.get(key);
String valueString = "";
if (null != value) {
valueString = value.toString();
}
if (encode) {
try {
temp.append(URLEncoder.encode(valueString, "UTF-8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
} else {
temp.append(valueString);
}
}
temp.append("&key=");
temp.append(paySignKey);
String packageSign = MD5.getMessageDigest(temp.toString());
return packageSign;
}
/**
* 请求,只请求一次,不做重试
*
* @param url
* @param data
* @return
* @throws Exception
*/
public static String requestOnce(final String url, String data) throws Exception {
BasicHttpClientConnectionManager connManager;
connManager = new BasicHttpClientConnectionManager(
RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.register("https", SSLConnectionSocketFactory.getSocketFactory())
.build(),
null,
null,
null
);
HttpClient httpClient = HttpClientBuilder.create()
.setConnectionManager(connManager)
.build();
HttpPost httpPost = new HttpPost(url);
RequestConfig requestConfig = RequestConfig.custom()
.setSocketTimeout(5000)
.setConnectTimeout(5000)
.setConnectionRequestTimeout(10000).build();
httpPost.setConfig(requestConfig);
StringEntity postEntity = new StringEntity(data, "UTF-8");
httpPost.addHeader("Content-Type", "text/xml");
httpPost.addHeader("User-Agent", "wxpay sdk java v1.0 " + "mchId");
httpPost.setEntity(postEntity);
HttpResponse httpResponse = httpClient.execute(httpPost);
HttpEntity httpEntity = httpResponse.getEntity();
String reusltObj = EntityUtils.toString(httpEntity, "UTF-8");
logger.info("请求结果:" + reusltObj);
return reusltObj;
}
/**
* 方法描述:微信查询退款逻辑
* 创建时间:2017年4月12日 上午11:04:25
* 作者: xubo
*
* @param
* @return
*/
public Map<String, Object> wxRefundquery(String out_trade_no, String out_refund_no) {
Map<Object, Object> params = new HashMap<Object, Object>();
//微信分配的公众账号ID(企业号corpid即为此appId)
params.put("appid", "xx");
//微信支付分配的商户号
params.put("mch_id", "xx");
//随机字符串,不长于32位。推荐随机数生成算法
params.put("nonce_str", CharUtil.getRandomString(16));
//商户侧传给微信的订单号
params.put("out_trade_no", out_trade_no);
//签名前必须要参数全部写在前面
//签名
params.put("sign", arraySign(params, "wx.paySignKey"));
String mapToXml = MapUtils.convertMap2Xml(params);
HttpPost httPost = new HttpPost("refundqueryUrl");
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) ");
httPost.setEntity(new StringEntity(mapToXml, "UTF-8"));
CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(WechatConfig.getSslcsf()).build();
CloseableHttpResponse response = null;
try {
response = httpClient.execute(httPost);
HttpEntity entity = response.getEntity();
String xmlStr = EntityUtils.toString(entity, "UTF-8");
System.out.println(xmlStr);
Map<String, Object> result = XmlUtil.xmlStrToMap(xmlStr);//.xmlStrToBean(xmlStr, WechatRefundApiResult.class);
return result;
//将信息保存到数据库
} catch (Exception e) {
logger.error(e.getMessage(), e);
return null;
} finally {
try {
if (response != null) {
response.close();
}
} catch (IOException e) {
logger.error(e.getMessage(), e);
}
}
}
}
import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* xml相关的工具类
*
* @author yang.y
*/
@SuppressWarnings("unchecked")
public class XmlUtil {
/**
* xml字符串转换成bean对象
*
* @param xmlStr xml字符串
* @param clazz 待转换的class
* @return 转换后的对象
*/
public static Object xmlStrToBean(String xmlStr, Class clazz) {
Object obj = null;
try {
// 将xml格式的数据转换成Map对象
Map<String, Object> map = xmlStrToMap(xmlStr);
// 将map对象的数据转换成Bean对象
obj = mapToBean(map, clazz);
} catch (Exception e) {
e.printStackTrace();
}
return obj;
}
/**
* 将xml格式的字符串转换成Map对象
*
* @param xmlStr xml格式的字符串
* @return Map对象
* @throws Exception 异常
*/
public static Map<String, Object> xmlStrToMap(String xmlStr) throws Exception {
if (StringUtils.isEmpty(xmlStr)) {
return null;
}
Map<String, Object> map = new HashMap<String, Object>();
// 将xml格式的字符串转换成Document对象
Document doc = DocumentHelper.parseText(xmlStr);
// 获取根节点
Element root = doc.getRootElement();
// 获取根节点下的所有元素
List children = root.elements();
// 循环所有子元素
if (children != null && children.size() > 0) {
for (int i = 0; i < children.size(); i++) {
Element child = (Element) children.get(i);
map.put(child.getName(), child.getTextTrim());
}
}
return map;
}
/**
* 将xml格式字符串转换成Bean对象
* 多级子节点递归遍历
*
* @param xmlStr
* @param clazz
* @return
* @throws Exception
*/
public static Object xmlStrToJavaBean(String xmlStr, Class clazz) {
if (StringUtils.isEmpty(xmlStr)) {
return null;
}
Object obj = null;
Map<String, Object> map = new HashMap<String, Object>();
// 将xml格式的字符串转换成Document对象
Document doc;
try {
doc = DocumentHelper.parseText(xmlStr);
// 获取根节点
Element root = doc.getRootElement();
map = elementToMap(root, map);
// 将map对象的数据转换成Bean对象
obj = mapToBean(map, clazz);
} catch (Exception e) {
e.printStackTrace();
}
return obj;
}
/**
* 递归遍历xml子节点,转换Map
*
* @param element
* @param map
* @return
*/
public static Map<String, Object> elementToMap(Element element, Map<String, Object> map) {
if (element == null || map == null)
return null;
List children = element.elements();
if (children != null && children.size() > 0) {
for (int i = 0; i < children.size(); i++) {
Element child = (Element) children.get(i);
if (child.elements() != null && child.elements().size() > 0)
elementToMap(child, map);
else
map.put(child.getName(), child.getTextTrim());
}
}
return map;
}
/**
* 将Map对象通过反射机制转换成Bean对象
*
* @param map 存放数据的map对象
* @param clazz 待转换的class
* @return 转换后的Bean对象
* @throws Exception 异常
*/
public static Object mapToBean(Map<String, Object> map, Class clazz) throws Exception {
Object obj = clazz.newInstance();
if (map != null && map.size() > 0) {
for (Map.Entry<String, Object> entry : map.entrySet()) {
String propertyName = entry.getKey();
Object value = entry.getValue();
String setMethodName = "set" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1);
Field field = getClassField(clazz, propertyName);
if (field != null) {
Class fieldTypeClass = field.getType();
value = convertValType(value, fieldTypeClass);
clazz.getMethod(setMethodName, field.getType()).invoke(obj, value);
}
}
}
return obj;
}
/**
* 将Object类型的值,转换成bean对象属性里对应的类型值
*
* @param value Object对象值
* @param fieldTypeClass 属性的类型
* @return 转换后的值
*/
private static Object convertValType(Object value, Class fieldTypeClass) {
Object retVal = null;
if (Long.class.getName().equals(fieldTypeClass.getName())
|| long.class.getName().equals(fieldTypeClass.getName())) {
retVal = Long.parseLong(value.toString());
} else if (Integer.class.getName().equals(fieldTypeClass.getName())
|| int.class.getName().equals(fieldTypeClass.getName())) {
retVal = Integer.parseInt(value.toString());
} else if (Float.class.getName().equals(fieldTypeClass.getName())
|| float.class.getName().equals(fieldTypeClass.getName())) {
retVal = Float.parseFloat(value.toString());
} else if (Double.class.getName().equals(fieldTypeClass.getName())
|| double.class.getName().equals(fieldTypeClass.getName())) {
retVal = Double.parseDouble(value.toString());
} else {
retVal = value;
}
return retVal;
}
/**
* 获取指定字段名称查找在class中的对应的Field对象(包括查找父类)
*
* @param clazz 指定的class
* @param fieldName 字段名称
* @return Field对象
*/
private static Field getClassField(Class clazz, String fieldName) {
if (Object.class.getName().equals(clazz.getName())) {
return null;
}
Field[] declaredFields = clazz.getDeclaredFields();
for (Field field : declaredFields) {
if (field.getName().equals(fieldName)) {
return field;
}
}
Class superClass = clazz.getSuperclass();
if (superClass != null) {// 简单的递归一下
return getClassField(superClass, fieldName);
}
return null;
}
}