import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.servlet.ServletException;
import org.jdom.JDOMException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import com.alibaba.fastjson.JSON;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.zqdl.base.BaseController;
import com.zqdl.entity.Integral;
import com.zqdl.enums.IntegralTypeEnum;
import com.zqdl.service.UserService;
import com.zqdl.util.CommUtil;
import com.zqdl.util.DateUtil;
import com.zqdl.util.HttpUtil;
import com.zqdl.util.QRCodeUtil;
import com.zqdl.util.Result;
import com.zqdl.util.XMLUtil; @Controller
@RequestMapping(value = "/pay")
public class PayController extends BaseController { final static Logger logger = LoggerFactory.getLogger(PayController.class); // 微信相关
@Value("#{configProperties['mch_id']}")
private String mch_id; @Value("#{configProperties['appid']}")
private String appid; @Value("#{configProperties['notify_url']}")
private String notify_url; @Value("#{configProperties['fee_type']}")
private String fee_type; @Value("#{configProperties['device_info']}")
private String device_info; @Value("#{configProperties['trade_type']}")
private String trade_type; @Value("#{configProperties['sign_type']}")
private String sign_type; @Value("#{configProperties['api_key']}")
private String api_key; @Value("#{configProperties['ufdoder_url']}")
private String ufdoder_url; // 支付宝相关
@Value("#{configProperties['app_id']}")
private String app_id; @Value("#{configProperties['merchant_private_key']}")
private String merchant_private_key; @Value("#{configProperties['alipay_public_key']}")
private String alipay_public_key; @Value("#{configProperties['signType']}")
private String signType; @Value("#{configProperties['charset']}")
private String charset; @Value("#{configProperties['gatewayUrl']}")
private String gatewayUrl; @Value("#{configProperties['notifyUrl']}")
private String notifyUrl; @Value("#{configProperties['returnUrl']}")
private String returnUrl; @Autowired
private UserService userService; /**
* 微信扫码支付
* @author maming
* @param totalFee
*/
@RequestMapping(value = "wechat_pay", method = RequestMethod.GET)
public void wechatPay(@RequestParam Map<String,String> param) {
Map<String, String> params = new HashMap<String, String>();
try {
params.put("mch_id", mch_id);
params.put("appid", appid);
params.put("notify_url", notify_url);
params.put("fee_type", fee_type);
params.put("device_info", device_info);
params.put("trade_type", trade_type);
params.put("sign_type", sign_type);
String tradeNo = param.get("tradeNo");// 获取订单号
params.put("nonce_str", tradeNo);
params.put("out_trade_no", tradeNo);
params.put("spbill_create_ip", CommUtil.getIpAddress(request));
int totalFee = Integer.valueOf(param.get("totalFee"));
params.put("total_fee", String.valueOf(totalFee)); // 将元转换成分
String description = param.get("description");// 消费描述
params.put("body", description);
params.put("product_id", currentUser.getId() + ""); // 商品ID,对应用户ID
params.put("sign", CommUtil.generateSignature(params, api_key, "HMACSHA256"));
String requestXML = XMLUtil.mapToXml(params);
String resultXML = HttpUtil.postData(ufdoder_url, requestXML);
Map<String, String> result = XMLUtil.doXMLParse(resultXML);
String codeURL = result.get("code_url");
// 生成验证码
QRCodeUtil.createQRCode(response, codeURL);
} catch (Exception e) {
logger.error("生成微信支付二维码异常", e);
} } /**
*
* @throws ServletException
* @throws IOException
*/
@RequestMapping(value = "wechat_renotify", method = RequestMethod.GET)
public void wechatPay() throws ServletException, IOException {
InputStream inputStream;
StringBuffer sb = new StringBuffer();
inputStream = request.getInputStream();
String s;
BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
while ((s = in.readLine()) != null) {
sb.append(s);
}
in.close();
inputStream.close(); Map<String, String> params = null;
try {
params = XMLUtil.doXMLParse(sb.toString());
} catch (JDOMException e) {
logger.error(e.getMessage());
} String resXml = ""; // 反馈给微信服务器
// 判断签名是否正确
if (CommUtil.isTenpaySign("UTF-8", params, api_key)) {
// 这里是支付成功
if ("SUCCESS".equals((String) params.get("result_code"))) { // 开始执行自己的业务逻辑 // String mch_id = params.get("mch_id");
// String openid = params.get("openid");
// String is_subscribe = params.get("is_subscribe");
// String out_trade_no = params.get("out_trade_no");
// String total_fee = params.get("total_fee"); // 设置积分记录参数 // 获取消费额度
int total_fee = Integer.parseInt(params.get("total_fee"));
// 获取商品ID,对应用户ID
int userId = Integer.parseInt(params.get("product_id"));
Integral integral = new Integral();
integral.setIntegral(total_fee);
integral.setIntegralType(IntegralTypeEnum.RECHARGE.getCode());
integral.setDescription(String.format("通过微信充值%s积分", total_fee));
integral.setUserId(userId);
// 添加积分记录和修改用户总积分
userService.modifyUserIntegral(integral); // 结束执行自己的业务逻辑 logger.info("支付成功");
// 通知微信.异步确认成功.必写.不然会一直通知后台.八次之后就认为交易失败了.
resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
+ "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> "; } else {
logger.info("支付失败,错误信息:" + params.get("err_code"));
resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
+ "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
} } else {
logger.info("签名验证错误");
resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
+ "<return_msg><![CDATA[签名验证错误]]></return_msg>" + "</xml> ";
} BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
out.write(resXml.getBytes());
out.flush();
out.close();
} /**
* 支付宝支付
*/
@RequestMapping(value = "aliPay/{money}", method = RequestMethod.GET)
@ResponseBody
public String aliPay(@PathVariable("money") String money){
Result rs = new Result();
//获得初始化的AlipayClient
AlipayClient alipayClient =
new DefaultAlipayClient
( gatewayUrl,
app_id,
merchant_private_key,
"json",
charset,
alipay_public_key,
signType
); //设置请求参数
AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
// 页面跳转同步通知页面路径
alipayRequest.setReturnUrl(returnUrl);
// 服务器异步通知页面路径
alipayRequest.setNotifyUrl(notifyUrl);
//请求
String result = ""; try {
//商户订单号,商户网站订单系统中唯一订单号,必填
String out_trade_no = new String(DateUtil.getOrderNum().getBytes("ISO-8859-1"), "UTF-8");
//付款金额,必填
String total_amount = new String("0.01".getBytes("ISO-8859-1"), "UTF-8");
//订单名称,必填
String subject = new String("IphoneX 68G".getBytes("ISO-8859-1"), "UTF-8");
//商品描述,可空
String userId = currentUser.getId() + "";
String body = new String(userId.getBytes("ISO-8859-1"), "UTF-8");
//该笔订单允许的最晚付款时间,逾期将关闭交易。取值范围:1m~15d。m-分钟,h-小时,d-天,1c-当天,可空
String timeout_express = new String("10m".getBytes("ISO-8859-1"), "UTF-8");
//销售产品码,可空
String product_code = new String("FAST_INSTANT_TRADE_PAY".getBytes("ISO-8859-1"), "UTF-8"); Map<String, String> maps = new HashMap<String, String>();
//商户订单号,商户网站订单系统中唯一订单号,必填
maps.put("out_trade_no", out_trade_no);
//付款金额,必填
maps.put("total_amount", total_amount);
//订单名称,必填
maps.put("subject", subject);
//用户id当做商品描述,可空
maps.put("body", body);
//该笔订单允许的最晚付款时间,逾期将关闭交易。取值范围:1m~15d。m-分钟,h-小时,d-天,1c-当天
maps.put("timeout_express", timeout_express);
//销售产品码,可空
maps.put("product_code", product_code);
String bizCon = JSON.toJSONString(maps);
alipayRequest.setBizContent(bizCon); result = alipayClient.pageExecute(alipayRequest).getBody();
//输出
//response.getWriter().write(result);
} catch (Exception e) {
getServerErrorResult(rs);
logger.error("跳转到支付宝支付页面异常", e);
} return result;
} @RequestMapping(value = "ali_renotify", method = RequestMethod.POST)
public void ali_renotify(){
try {
//获取支付宝POST过来反馈信息
Map<String, String> params = new HashMap<String, String>();
Map<String, String[]> requestParams = request.getParameterMap();
for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext();) {
String name = (String) iter.next();
String[] values = (String[]) requestParams.get(name);
String valueStr = "";
for (int i = 0; i < values.length; i++) {
valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
}
//乱码解决,这段代码在出现乱码时使用
valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
params.put(name, valueStr);
}
boolean signVerified = AlipaySignature.rsaCheckV1(params, alipay_public_key, charset, signType); //调用SDK验证签名 if(signVerified) {//验证成功
//订单金额
String total_amount = new String(request.getParameter("total_amount").getBytes("ISO-8859-1"),"UTF-8"); //获取传入的用户id
String body = new String(request.getParameter("body").getBytes("ISO-8859-1"),"UTF-8");
Integer money = Integer.parseInt(total_amount);
Integer userId = Integer.parseInt(body);
Integral integral = new Integral();
integral.setIntegral(money);
integral.setIntegralType(IntegralTypeEnum.RECHARGE.getCode());
integral.setDescription(String.format("通过支付宝充值%s积分", money));
integral.setUserId(userId);
// 添加积分记录和修改用户总积分
userService.modifyUserIntegral(integral); logger.info("支付成功"); response.getWriter().write("success"); }else {//验证失败
response.getWriter().write("fail"); //调试用,写文本函数记录程序运行情况是否正常
//String sWord = AlipaySignature.getSignCheckContentV1(params);
//AlipayConfig.logResult(sWord);
}
} catch (Exception e) { } }
}
工具类
public class CommUtil {
private static Logger logger = LoggerFactory.getLogger(CommUtil.class); public static String generateUUID() {
return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32);
} /**
* 取出一个指定长度大小的随机正整数.
*
* @param length
* int 设定所取出随机数的长度。length小于11
* @return int 返回生成的随机数。
*/
public static int buildRandom(int length) {
int num = 1;
double random = Math.random();
if (random < 0.1) {
random = random + 0.1;
}
for (int i = 0; i < length; i++) {
num = num * 10;
}
return (int) ((random * num));
} /**
* 获取当前时间 yyyyMMddHHmmss
* 生成订单号
* @return String
*/ public synchronized static String getNonce_str() {
Date now = new Date();
SimpleDateFormat outFormat = new SimpleDateFormat("yyyyMMddHHmmss");
String bg = outFormat.format(now);
bg.substring(8, bg.length());
String end = String.valueOf(buildRandom(4));
return bg + end;
} /**
* 生成签名. 注意,若含有sign_type字段,必须和signType参数保持一致。
*
* @param data
* 待签名数据
* @param key
* API密钥
* @param signType
* 签名方式
* @return 签名
*/
public static String generateSignature(final Map<String, String> data, String key,
String signType) throws Exception {
Set<String> keySet = data.keySet();
String[] keyArray = keySet.toArray(new String[keySet.size()]);
Arrays.sort(keyArray);
StringBuilder sb = new StringBuilder();
for (String k : keyArray) {
if (k.equals("sign")) {
continue;
}
if (data.get(k).trim().length() > 0) // 参数值为空,则不参与签名
sb.append(k).append("=").append(data.get(k).trim()).append("&");
}
sb.append("key=").append(key);
if ("MD5".equals(signType)) {
return MD5(sb.toString()).toUpperCase();
} else if ("HMACSHA256".equals(signType)) {
return HMACSHA256(sb.toString(), key);
} else {
throw new RuntimeException(String.format("Invalid sign_type: %s", signType));
}
} /**
* 生成 MD5
*
* @param data
* 待处理数据
* @return MD5结果
* @throws NoSuchAlgorithmException
* @throws UnsupportedEncodingException
*/
public static String MD5(String data) throws NoSuchAlgorithmException, UnsupportedEncodingException {
java.security.MessageDigest md = MessageDigest.getInstance("MD5");
byte[] array = md.digest(data.getBytes("UTF-8"));
StringBuilder sb = new StringBuilder();
for (byte item : array) {
sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
}
return sb.toString().toUpperCase();
} /**
* 生成 HMACSHA256
*
* @param data
* 待处理数据
* @param key
* 密钥
* @return 加密结果
* @throws NoSuchAlgorithmException
* @throws UnsupportedEncodingException
* @throws InvalidKeyException
* @throws Exception
*/
public static String HMACSHA256(String data, String key) throws NoSuchAlgorithmException, UnsupportedEncodingException, InvalidKeyException{
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA256");
sha256_HMAC.init(secret_key);
byte[] array = sha256_HMAC.doFinal(data.getBytes("UTF-8"));
StringBuilder sb = new StringBuilder();
for (byte item : array) {
sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
}
return sb.toString().toUpperCase();
} /**
* 是否签名正确,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。
*
* @return boolean
*/
public static boolean isTenpaySign(String characterEncoding, Map<String, String> params,
String API_KEY) {
StringBuffer sb = new StringBuffer();
Set<Entry<String, String>> es = params.entrySet();
Iterator<Entry<String, String>> it = es.iterator();
while (it.hasNext()) {
Entry<String, String> entry = it.next();
String k = (String) entry.getKey();
String v = (String) entry.getValue();
if (!"sign".equals(k) && null != v && !"".equals(v)) {
sb.append(k + "=" + v + "&");
}
} sb.append("key=" + API_KEY); // 算出摘要
String mysign = Md5Utils.MD5Encode(sb.toString(), characterEncoding).toLowerCase();
String tenpaySign = ((String) params.get("sign")).toLowerCase(); return tenpaySign.equals(mysign);
} /**
* 获取客户端IP
*
* @param request
* @return
*/
public static String getIpAddress(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 || "unknow".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getHeader("WL-Proxy-Client-IP");
}
if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getRemoteAddr(); if (ipAddress.equals(Constants.LOCALHOST1) || ipAddress.equals(Constants.LOCALHOST2)) {
// 根据网卡获取本机配置的IP地址
InetAddress inetAddress = null;
try {
inetAddress = InetAddress.getLocalHost();
} catch (UnknownHostException e) {
logger.error(e.getMessage());
}
if(inetAddress != null){
ipAddress = inetAddress.getHostAddress();
}
}
} // 对于通过多个代理的情况,第一个IP为客户端真实的IP地址,多个IP按照','分割
if (null != ipAddress && ipAddress.length() > 15) {
if (ipAddress.indexOf(",") > 0) {
ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
}
} return ipAddress;
} }
public class XMLUtil { /**
* 解析xml,返回第一级元素键值对。如果第一级元素有子节点,则此节点的值是子节点的xml数据。
*
* @param strxml
* @return
* @throws JDOMException
* @throws IOException
*/
public static Map<String, String> doXMLParse(String strxml) throws JDOMException, IOException {
strxml = strxml.replaceFirst("encoding=\".*\"", "encoding=\"UTF-8\""); if (null == strxml || "".equals(strxml)) {
return null;
} Map<String, String> map = new HashMap<String, String>(); InputStream in = new ByteArrayInputStream(strxml.getBytes("UTF-8"));
SAXBuilder builder = new SAXBuilder();
Document doc = builder.build(in);
Element root = doc.getRootElement();
@SuppressWarnings("unchecked")
List<Element> list = root.getChildren();
Iterator<Element> it = list.iterator();
while (it.hasNext()) {
Element e = it.next();
String k = e.getName();
String v = "";
@SuppressWarnings("unchecked")
List<Element> children = e.getChildren();
if (children.isEmpty()) {
v = e.getTextNormalize();
} else {
v = XMLUtil.getChildrenText(children);
} map.put(k, v);
}
// 关闭流
in.close(); return map;
} /**
* 将Map转换为XML格式的字符串
*
* @param data
* Map类型数据
* @return XML格式的字符串
* @throws ParserConfigurationException
* @throws TransformerException
* @throws Exception
* @throws Exception
*/
public static String mapToXml(Map<String, String> data) throws ParserConfigurationException, TransformerException{
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
org.w3c.dom.Document document = documentBuilder.newDocument();
org.w3c.dom.Element root = document.createElement("xml");
document.appendChild(root);
for (String key : data.keySet()) {
String value = data.get(key);
if (value == null) {
value = "";
}
value = value.trim();
org.w3c.dom.Element filed = document.createElement(key);
filed.appendChild(document.createTextNode(value));
root.appendChild(filed);
}
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
DOMSource source = new DOMSource(document);
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
StringWriter writer = new StringWriter();
StreamResult result = new StreamResult(writer);
transformer.transform(source, result);
String output = writer.getBuffer().toString(); // .replaceAll("\n|\r",
// "");
try {
writer.close();
} catch (Exception ex) {
}
return output;
} /**
* 获取子结点的xml
*
* @param children
* @return String
*/
public static String getChildrenText(List<Element> children) {
StringBuffer sb = new StringBuffer();
if (!children.isEmpty()) {
Iterator<Element> it = children.iterator();
while (it.hasNext()) {
Element e = it.next();
String name = e.getName();
String value = e.getTextNormalize();
@SuppressWarnings("unchecked")
List<Element> list = e.getChildren();
sb.append("<" + name + ">");
if (!list.isEmpty()) {
sb.append(XMLUtil.getChildrenText(list));
}
sb.append(value);
sb.append("</" + name + ">");
}
} return sb.toString();
}
}
public class HttpUtil { private static Logger logger = Logger.getLogger("HttpUtil"); private final static int CONNECT_TIMEOUT = 5000; // in milliseconds
private final static String DEFAULT_ENCODING = "UTF-8";
public static final MediaType MEDIA_TYPE = MediaType.parse("application/json; charset=utf-8");
public static final OkHttpClient client = new OkHttpClient(); public static void httpGet(String urlStr) {
Request request = new Request.Builder().url(urlStr).build();
try {
Response response = client.newCall(request).execute();
if (response.isSuccessful()) {
logger.info(response.body().string());
} else {
logger.info("服务器端错误: " + response);
}
} catch (IOException e) {
logger.error(e.getMessage());
}
} public static void httpPost(String urlStr, String json) {
RequestBody body = RequestBody.create(MEDIA_TYPE, json);
Request request = new Request.Builder().url(urlStr).post(body).build();
try {
Response response = client.newCall(request).execute();
if (response.isSuccessful()) {
logger.info(response.body().string());
} else {
logger.info("服务器端错误: " + response);
}
} catch (IOException e) {
logger.error(e.getMessage());
}
} public static void httpPost(String urlStr, Map<String, String> params) {
FormEncodingBuilder builder = new FormEncodingBuilder();
if (params != null && !params.isEmpty()) {
Set<String> keys = params.keySet();
for (String key : keys) {
builder.add(key, params.get(key));
}
}
RequestBody body = builder.build();
Request request = new Request.Builder().url(urlStr).post(body).build();
try {
Response response = client.newCall(request).execute();
if (response.isSuccessful()) {
logger.info(response.body().string());
} else {
logger.info("服务器端错误: " + response);
}
} catch (IOException e) {
logger.error(e.getMessage());
}
} public static String postData(String urlStr, String data) {
return postData(urlStr, data, null);
} public static String postData(String urlStr, String data, String contentType) {
BufferedReader reader = null;
try {
URL url = new URL(urlStr);
URLConnection conn = url.openConnection();
conn.setDoOutput(true);
conn.setConnectTimeout(CONNECT_TIMEOUT);
conn.setReadTimeout(CONNECT_TIMEOUT);
if (contentType != null)
conn.setRequestProperty("content-type", contentType);
OutputStreamWriter writer = new OutputStreamWriter(conn.getOutputStream(), DEFAULT_ENCODING);
if (data == null)
data = "";
writer.write(data);
writer.flush();
writer.close(); reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), DEFAULT_ENCODING));
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line);
sb.append("\r\n");
}
return sb.toString();
} catch (IOException e) {
} finally {
try {
if (reader != null)
reader.close();
} catch (IOException e) {
}
}
return null;
}
}
二维码相关操作代码
public class QRCodeUtil { final static Logger logger = LoggerFactory.getLogger(QRCodeUtil.class); public static void createQRCode(HttpServletResponse response, String codeURL) { // 生成二维码
Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();
// 指定纠错等级
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L);
// 指定编码格式
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
hints.put(EncodeHintType.MARGIN, 1);
try {
BitMatrix bitMatrix = new MultiFormatWriter().encode(codeURL, BarcodeFormat.QR_CODE, 200, 200, hints);
OutputStream out = response.getOutputStream();
MatrixToImageWriter.writeToStream(bitMatrix, "png", out);// 输出二维码
out.flush();
out.close();
} catch (Exception e) {
logger.error(e.getMessage());
} } }