网站搭建步骤

日期:2020-12-30 类型:行业动态 

关键词:学生个人网页制作代码,如何做网页或网站,网页游戏制作,dw网页设计作业,动态网页

网站搭建步骤:微信小程序支付+Java后台实现(完整版)

在开发微信小程序支付的功能前 我们先熟悉下微信小程序支付的业务流程图

不熟悉流程的建议还是仔细阅读微信官方的开发者文档。

一 准备工作

事先需要申请企业版小程序 并开通“微信支付” 即商户功能 。并获取一下参数

appid ******** //小程序appid
mchid ******** //小程序绑定商户id
key ***************** //商户后台设置的key

并在商户后天设置开发者选项 主要是设置回调域名。

二 Java后台代码编写

Controller层代码

 RestController
 RequestMapping(value /payment/ )
public class PaymentController {
 private static Logger logger LoggerFactory.getLogger(PaymentController.class);
 Value( ${hcc.wx.domain} )
 private String orderDomain;
 Autowired
 private PaymentService paymentService;
 * p 统一下单入口 /p 
 * param request
 * param response
 * throws Exception
 ResponseBody
 RequestMapping(value toPay , method RequestMethod.POST, 
produces { application/json;charset UTF-8 })
 public JSONObject toPay(HttpServletRequest request) throws Exception {
 String requestStr RequestStr.getRequestStr(request);
 if (StringUtils.isEmpty(requestStr)) {
 throw new ParamException();
 JSONObject jsonObj JSONObject.parseObject(requestStr);
 if(StringUtils.isEmpty(jsonObj.getString( orderNo )) || StringUtils.isEmpty(jsonObj.getString( openId ))){
 throw new ParamException();
 OrderInfo orderInfo .....//此处写获取订单信息方法
 if(orderInfo null){
 return AjaxUtil.renderFailMsg( 订单不存在 
 }else if(orderInfo.getPayAmount() null || orderInfo.getPayAmount() 0){
 return AjaxUtil.renderFailMsg( 订单有误 请确认 
 }else if(orderInfo.getOrderStatus() ! 1){//1待付款
 String msg orderInfo.getOrderStatus() 1 ? 此订单已支付 : 订单未提交 请确认 
 return AjaxUtil.renderFailMsg(msg);
 }else{
 logger.info( 【小程序支付服务】请求订单编号:[ orderInfo.getOrderNo() ] 
 Map String, String resMap paymentService.xcxPayment( orderInfo.getOrderNo(),orderInfo.getPayAmount(),jsonObj.getString( openId 
 if( SUCCESS .equals(resMap.get( returnCode )) OK .equals(resMap.get( returnMsg ))){
 //统一下单成功
 resMap.remove( returnCode 
 resMap.remove( returnMsg 
 logger.info( 【小程序支付服务】支付下单成功 
 return AjaxUtil.renderSuccessMsg(resMap);
 }else{
 logger.info( 【小程序支付服务】支付下单失败 原因: resMap.get( returnMsg 
 return AjaxUtil.renderFailMsg(resMap.get( returnMsg 
 * p 回调Api /p 
 * param request
 * param response
 * throws Exception
 RequestMapping(value xcxNotify )
 public void xcxNotify(HttpServletRequest request,HttpServletResponse response) throws Exception {
 InputStream inputStream request.getInputStream();
 //获取请求输入流
 ByteArrayOutputStream outputStream new ByteArrayOutputStream();
 byte[] buffer new byte[1024];
 int len 
 while ((len inputStream.read(buffer))! -1){
 outputStream.write(buffer,0,len);
 outputStream.close();
 inputStream.close();
 Map String,Object map BeanToMap.getMapFromXML(new String(outputStream.toByteArray(), utf-8 
 logger.info( 【小程序支付回调】 回调数据 \n map);
 String resXml 
 String returnCode (String) map.get( return_code 
 if ( SUCCESS .equalsIgnoreCase(returnCode)) {
 String returnmsg (String) map.get( result_code 
 if( SUCCESS .equals(returnmsg)){
 //更新数据
 int result paymentService.xcxNotify(map);
 if(result 0){
 //支付成功
 resXml xml return_code ![CDATA[SUCCESS]] /return_code 
 return_msg ![CDATA[OK]] /return_msg /xml 
 }else{
 resXml xml return_code ![CDATA[FAIL]] /return_code 
 return_msg ![CDATA[报文为空] /return_msg /xml 
 logger.info( 支付失败: resXml);
 }else{
 resXml xml return_code ![CDATA[FAIL]] /return_code 
 return_msg ![CDATA[报文为空] /return_msg /xml 
 logger.info( 【订单支付失败】 
 logger.info( 【小程序支付回调响应】 响应内容 \n resXml);
 response.getWriter().print(resXml);
}

Service接口层代码 部分代码

/**
* p 支付接口层 /p 
* author att 
* date 2018年5月27日
* since jdk1.8
* version 1.0
public interface PaymentService {
 Map String,String xcxPayment(String orderNo, double money,String openId) throws Exception;
 int xcxNotify(Map String,Object map) throws Exception;
}

Service接口实现 部分代码

 Service(value paymentService )
public class PaymentServiceImpl implements PaymentService{
 private static Logger LOGGER LoggerFactory.getLogger(PaymentServiceImpl.class);
 Value( ${spring.profiles.active} )
 private String PROJECT_ENV;
 Value( ${hcc.wx.domain} )
 private String orderDomain;
 Autowired
 private PaymentRecordMapper paymentRecordMapper;
 Autowired
 private PaymentNotifyMapper paymentNotifyMapper;
 Override
 public Map String, String xcxPayment(String orderNum, double money,String openId) throws Exception {
 LOGGER.info( 【小程序支付】 统一下单开始, 订单编号 orderNum);
 SortedMap String, String resultMap new TreeMap String, String 
 //生成支付金额 开发环境处理支付金额数到0.01、0.02、0.03元
 double payAmount PayUtil.getPayAmountByEnv(PROJECT_ENV, money);
 //添加或更新支付记录(参数跟进自己业务需求添加)
 int flag this.addOrUpdatePaymentRecord(orderNum, payAmount,.....);
 if(flag 0){
 resultMap.put( returnCode , FAIL 
 resultMap.put( returnMsg , 此订单已支付 
 LOGGER.info( 【小程序支付】 此订单已支付 
 }else if(flag 0){
 resultMap.put( returnCode , FAIL 
 resultMap.put( returnMsg , 支付记录生成或更新失败 
 LOGGER.info( 【小程序支付】 支付记录生成或更新失败 
 }else{
 Map String,String resMap this.xcxUnifieldOrder(orderNum, PayConfig.TRADE_TYPE_JSAPI, payAmount,openId);
 if(PayConstant.SUCCESS.equals(resMap.get( return_code )) PayConstant.SUCCESS.equals(resMap.get( result_code ))){
 resultMap.put( appId , PayConfig.XCX_APP_ID);
 resultMap.put( timeStamp , PayUtil.getCurrentTimeStamp());
 resultMap.put( nonceStr , PayUtil.makeUUID(32));
 resultMap.put( package , prepay_id resMap.get( prepay_id 
 resultMap.put( signType , MD5 
 resultMap.put( sign , PayUtil.createSign(resultMap,PayConfig.XCX_KEY));
 resultMap.put( returnCode , SUCCESS 
 resultMap.put( returnMsg , OK 
 LOGGER.info( 【小程序支付】统一下单成功 返回参数: resultMap);
 }else{
 resultMap.put( returnCode , resMap.get( return_code 
 resultMap.put( returnMsg , resMap.get( return_msg 
 LOGGER.info( 【小程序支付】统一下单失败 失败原因: resMap.get( return_msg 
 return resultMap;
 * 小程序支付统一下单
 private Map String,String xcxUnifieldOrder(String orderNum,String tradeType, double payAmount,String openid) throws Exception{
 //封装参数
 SortedMap String,String paramMap new TreeMap String,String 
 paramMap.put( appid , PayConfig.XCX_APP_ID);
 paramMap.put( mch_id , PayConfig.XCX_MCH_ID);
 paramMap.put( nonce_str , PayUtil.makeUUID(32));
 paramMap.put( body , BaseConstants.PLATFORM_COMPANY_NAME);
 paramMap.put( out_trade_no , orderNum);
 paramMap.put( total_fee , PayUtil.moneyToIntegerStr(payAmount));
 paramMap.put( spbill_create_ip , PayUtil.getLocalIp());
 paramMap.put( notify_url , this.getNotifyUrl());
 paramMap.put( trade_type , tradeType);
 paramMap.put( openid ,openid);
 paramMap.put( sign , PayUtil.createSign(paramMap,PayConfig.XCX_KEY));
 //转换为xml
 String xmlData PayUtil.mapToXml(paramMap);
 //请求微信后台 获取预支付ID
 String resXml HttpUtils.postData(PayConfig.WX_PAY_UNIFIED_ORDER, xmlData);
 LOGGER.info( 【小程序支付】 统一下单响应 \n resXml);
 return PayUtil.xmlStrToMap(resXml);
 private String getNotifyUrl(){
 //服务域名
 return PayConfig.PRO_SERVER_DOMAIN /wxapp/payment/xcxNotify 
 * 添加或更新支付记录
 Override
 public int addOrUpdatePaymentRecord(String orderNo, double payAmount,......) throws Exception{
 //写自己的添加或更新支付记录的业务代码
 return 0;
 Override
 Transactional(readOnly false,rollbackFor {Exception.class})
 public int xcxNotify(Map String,Object map) throws Exception{
 int flag 
 //支付订单编号
 String orderNo (String)map.get( out_trade_no 
 //检验是否需要再次回调刷新数据
 //TODO 微信后台回调 刷新订单支付状态等相关业务
 return flag;
 }

PayUtil工具类

/**
 * Function: 支付工具类 br/ 
 * date:  br/ 
 * author att
 * version 1.0
 * since JDK1.8
 * see
public class PayUtil {
 static Logger log LogManager.getLogger(PayUtil.class.getName());
 * 获取当前机器的ip
 * return String
 public static String getLocalIp(){
 InetAddress ia null;
 String localip null;
 try {
 ia ia.getLocalHost();
 localip ia.getHostAddress();
 } catch (Exception e) {
 e.printStackTrace();
 return localip;
 * Map转换为 Xml
 * param data
 * return Xml
 * throws Exception
 public static String mapToXml(SortedMap String, String map) throws Exception {
 DocumentBuilderFactory documentBuilderFactory DocumentBuilderFactory.newInstance();
 //防止XXE攻击
 documentBuilderFactory.setXIncludeAware(false);
 documentBuilderFactory.setExpandEntityReferences(false);
 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: map.keySet()) {
 String value map.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();
 try {
 writer.close();
 catch (Exception ex) {
 return output;

public static String createSign(SortedMap String,String parameters,String key){ StringBuffer sb new StringBuffer(); Set es parameters.entrySet(); Iterator ? it es.iterator(); while(it.hasNext()) { Map.Entry entry (Map.Entry)it.next(); String k (String)entry.getKey(); if(entry.getValue() ! null || ! .equals(entry.getValue())) { String v String.valueOf(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(), UTF-8 ).toUpperCase(); return sign;
public static Map String, Object getMapFromXML(String strXML) throws Exception { try { Map String, Object data new HashMap String, Object DocumentBuilderFactory documentBuilderFactory DocumentBuilderFactory.newInstance(); //防止XXE攻击 documentBuilderFactory.setXIncludeAware(false); documentBuilderFactory.setExpandEntityReferences(false); DocumentBuilder documentBuilder documentBuilderFactory.newDocumentBuilder(); InputStream stream new ByteArrayInputStream(strXML.getBytes( UTF-8 org.w3c.dom.Document doc documentBuilder.parse(stream); doc.getDocumentElement().normalize(); NodeList nodeList doc.getDocumentElement().getChildNodes(); for (int idx idx nodeList.getLength(); idx) { Node node nodeList.item(idx); if (node.getNodeType() Node.ELEMENT_NODE) { org.w3c.dom.Element element (org.w3c.dom.Element) node; data.put(element.getNodeName(), element.getTextContent()); try { stream.close(); } catch (Exception ex) { ex.printStackTrace(); return data; } catch (Exception ex) { throw ex; * 生成随机数 * return public static String makeUUID(int len) { return UUID.randomUUID().toString().replaceAll( - , ).substring(0, len); * 获取当前的Timestamp * return public static String getCurrentTimeStamp() { return Long.toString(System.currentTimeMillis()/1000); * 获取当前的时间 * return public static long getCurrentTimestampMs() { return System.currentTimeMillis(); * 生成订单号 * return public static String generateOrderNo() { SimpleDateFormat sdf new SimpleDateFormat( yyMMdd return sdf.format(new Date()) makeUUID(16); * 获取当前工程url * param request * return public static String getCurrentUrl(HttpServletRequest request){ return request.getScheme() :// request.getServerName() : request.getServerPort() request.getContextPath(); * Xml字符串转换为Map * param xmlStr * return public static Map String,String xmlStrToMap(String xmlStr){ Map String,String map new HashMap String,String Document doc; try { doc DocumentHelper.parseText(xmlStr); Element root doc.getRootElement(); List children root.elements(); if(children ! null children.size() 0) { for(int i i children.size(); i ) { Element child (Element)children.get(i); map.put(child.getName(), child.getTextTrim()); } catch (DocumentException e) { e.printStackTrace(); return map; public static String getSceneInfo(String wapUrl,String name){ Map String,Map String,String map new HashMap String, Map String,String (); if(!StringUtils.isEmpty(wapUrl) !StringUtils.isEmpty(name)){ /*{ h5_info : { type : Wap , wap_url : https://pay.qq.com , wap_name : 腾讯充值 }}*/ Map String,String childmap new TreeMap String, String childmap.put( type , Wap childmap.put( wap_url ,wapUrl); childmap.put( wap_name , name); map.put( h5_info , childmap); return JSON.toJSONString(map); return null;
public static String moneyToIntegerStr(Double money){ BigDecimal decimal new BigDecimal(money); int amount decimal.multiply(new BigDecimal(100)) .setScale(0, BigDecimal.ROUND_HALF_UP).intValue(); return String.valueOf(amount); /** * 除去数组中的空值和签名参数 * param sArray 签名参数组 * return 去掉空值与签名参数后的新签名参数组 public static Map String, String paraFilter(Map String, String sArray) { Map String, String result new HashMap String, String if (sArray null || sArray.size() 0) { return result; for (String key : sArray.keySet()) { String value sArray.get(key); if (value null || value.equals( ) || key.equalsIgnoreCase( sign ) || key.equalsIgnoreCase( sign_type )) { continue; result.put(key, value); return result; /** * 把数组所有元素排序 并按照“参数 参数值”的模式用“ ”字符拼接成字符串 * param params 需要排序并参与字符拼接的参数组 * return 拼接后字符串 public static String createLinkString(Map String, String params) { List String keys new ArrayList String (params.keySet()); Collections.sort(keys); String prestr for (int i i keys.size(); i ) { String key keys.get(i); String value params.get(key); if (i keys.size() - 1) {//拼接时 不包括最后一个 字符 prestr prestr key value; } else { prestr prestr key value return prestr; * 根据不同环境生成支付金额 * param env * param money * param payType * return public static double getPayAmountByEnv(String env,Double money){ double pay_money 0.01; //测试环境 if(BaseConstants.PLATFORM_ENV_DEV.equals(env)){ if(money 10000){ pay_money 0.03; }else if(money 1000){ pay_money 0.02; }else{ pay_money 0.01; return pay_money; }else{ //生成环境 return money; }

支付配置类

/**
 * Function: 支付配置 br/ 
 * date:  br/ 
 * author att
 * version 1.0
 * since JDK1.8
public class PayConfig {
 //微信支付类型
 //NATIVE--原生支付
 //JSAPI--公众号支付-小程序支付
 //MWEB--H5支付
 //APP -- app支付
 public static final String TRADE_TYPE_NATIVE NATIVE 
 public static final String TRADE_TYPE_JSAPI JSAPI 
 public static final String TRADE_TYPE_MWEB MWEB 
 public static final String TRADE_TYPE_APP APP 
 //小程序支付参数
 public static String XCX_APP_ID;
 public static String XCX_MCH_ID;
 public static String XCX_KEY;
 //微信支付API
 public static final String WX_PAY_UNIFIED_ORDER https://api.mch.weixin.qq.com/pay/unifiedorder 
 //参数
 static{
 Properties properties new Properties();
 try {
 properties.load(PayConstant.class.getClassLoader().getResourceAsStream( payment_config.properties 
 //xcx
 XCX_APP_ID (String) properties.get( xcx.pay.appid 
 XCX_MCH_ID (String) properties.get( xcx.pay.mchid 
 XCX_KEY (String) properties.get( xcx.pay.key 
 } catch (Exception e) {
 e.printStackTrace();
}

Properties配置

##config
xcx.pay.appid wx**********
xcx.pay.mchid *****
xcx.pay.key **********

三 小程序端 获取统一下单返回参数发起支付

在小程序端 发起支付请求到 Java后台的统一下单接口返回prepay_id等参数 然后封装调起微信的js方法 wx.requestPayment(OBJECT) 具体参考文档

测试一把

本代码仅仅为项目中抽取的内容来写技术文章 如果想获取更完整内容或支持 请关注以下公众号 然后进入 关于我 联系我  联系本人。