温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

java如何实现微信jsApi支付

发布时间:2021-10-19 17:09:44 来源:亿速云 阅读:116 作者:柒染 栏目:大数据

java如何实现微信jsApi支付,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。

标注:1、必须在微信内置浏览器进行支付;2、open id必须获取;3、获取code必须请求后台服务器,将code获取到返回前端,再请求获取openid,将openid存在自己服务器的session中

一、账户准备

1、在微信公众平台开通服务号并付费300元认证(只有企业才能开通)获取appid,在微信支付商户平台注册超级管理员并付费300认证,获取mch_id(商户id)。

2、在微信公众平台获取 appid,appsecret。在商户平台获取mch_id,api安全中获取API密钥(paternerKey)

二、平台配置

1、商户平台:产品中心开发配置,属于支付页面

2、公众平台:账户详情功能设置,配置网页授权域名,(将txt文件放在一级域名以及目录中,可通过域名/txt(文件全称)访问,测试是否可以获取txt内容。如果不行,则进行nginx配置域名访问目录)

3、公众平台:开发,基本设置,配置服务器地址(需要写接口并返回echostr,验证服务器),令牌随便写,消息密钥(随机生成),加密模式:兼容模式。

三、开发(下载javasdk。将微信中的工具类导入https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1)

1、支付前获取基本参数

  /**
     * 微信中请求打开页面
     */
    @RequestMapping(value = "/toJob")
    public String  toJob(HttpServletResponse response){
        String appId = WxConstants.APPID;
        String tologin =redirectURL;
        return "redirect:https://open.weixin.qq.com/connect/oauth3/authorize?appid="+appId+"&redirect_uri="+tologin+"&response_type=code&scope=snsapi_base#wechat_redirect";
    }

    /**
     * 微信请求打开页面重定向到该接口,获取code
     * 然后重定向到自己页面
     */
    @RequestMapping(value = "/tologin")
    public String  tologin(String code ,HttpServletResponse response){
        return "redirect:"+loginUrl+code;
    }

    /**
     * 获取open id
     */
    @RequestMapping("/getOpenId")
    @ResponseBody
    public String getOpenId( @RequestParam("code") String code,HttpServletRequest request){
        logger.info("code  code:" + code);
        Map<String, String> result = new HashMap<>();
        //页面获取openId接口
        String getopenid_url = "https://api.weixin.qq.com/sns/oauth3/access_token";
        Map<String, String> param = new HashMap<>();
        param.put("appid", WxConstants.APPID);
        param.put("secret", WxConstants.SECRET);
        param.put("code", code);
        param.put("grant_type", "authorization_code");
        //向微信服务器发送get请求获取openIdStr
        String openIdStr = HttpClientUtil.doGet(getopenid_url, param);
        JSONObject jsonObject = JSON.parseObject(openIdStr);
        logger.info("opendID  JSON:" + openIdStr);
        String openid =  jsonObject.getString("openid");
        //将open id存入session。
        //如果直接重定向到该接口,openid存不到session中,只会存在腾讯的session中
        //微信中打开页面只能请求后台接口,后台获取到code拼接到前台页面后面
        //前台获取到code,然后请求获取open id的接口,可以将open id存到我们自己服务器中
        request.getSession().setAttribute("openid", openid);
        //返回登录页
        return openid;
    }

    /**
     * 微信测试接口
     * @param request
     * @return
     */
    @RequestMapping("/Token")
    @ResponseBody
    public String Token(HttpServletRequest request){
        logger.info(JSON.toJSONString(request.getParameterMap()));
        return request.getParameter("echostr");
    }

2、支付、回调

/**
     * 简历微信支付
     * @param request
     * @param isUpdate 是否是认证订单
     */
    @RequestMapping(value = "/wxPayJob")
    @ResponseBody
    public Map<String,String> wxpay(HttpServletRequest request,
                                    @RequestParam("isUpdate") Integer isUpdate,
                                     @RequestParam("jobUserId") Long jobUserId,
                                     @RequestParam("totalAmount") String totalAmount) {
        String openId = (String) request.getSession().getAttribute("openid");
        logger.info("opendID  pay:" + openId);
        //获取openId
        String ip = WxUtils.getIpAddress(request);
        //将元转化为分
        String totalFee =  AmountUtils.changeY2F(totalAmount);
        Map<String, String> result = wxService.orderPayment(openId, ip, totalFee, jobUserId, isUpdate);
        return result;
    }

    /**
     * 微信支付回调
     * @param request
     * @param response
     * @return
     */
    @RequestMapping(value = "/wxPayJobNotify")
    @ResponseBody
    public  String wxPayJobNotify(HttpServletRequest request, HttpServletResponse response) {
        InputStream is = null;
        try {
            is = request.getInputStream();//获取请求的流信息(这里是微信发的xml格式所有只能使用流来读)
            String xml =  IOUtils.toString(is, "utf-8");
            Map<String, String> notifyMap = WXPayUtil.xmlToMap(xml);//将微信发的xml转map

            if(notifyMap.get("return_code").equals("SUCCESS")){
                if(notifyMap.get("result_code").equals("SUCCESS")){
                    String orderNum = notifyMap.get("out_trade_no");//商户订单号
                    String amountpaid = notifyMap.get("total_fee");//实际支付的订单金额:单位 分
                    String  amount =  AmountUtils.changeF2Y(amountpaid);
                    //String openid = notifyMap.get("openid");  //如果有需要可以获取
                    //String trade_type = notifyMap.get("trade_type");
                    //修改认证状态,订单状态
                    jobOrderDtoService.updateState(orderNum);
                    }
                }
            //告诉微信服务器收到信息了,不要在调用回调action了========这里很重要回复微信服务器信息用流发送一个xml即可
            response.getWriter().write("<xml><return_code><![CDATA[SUCCESS]]></return_code></xml>");
            is.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

3、支付统一下单主体

 //微信支付----异步回调(接口:payForOrder)
    @Value(value = "${WxConfig.wxJObNotifyUrl}")
    private String wxJObNotifyUrl;


    /**
     *  调用微信支付
     */
    @Override
    public Map<String, String> orderPayment(String openId, String ip, String totalAmount, Long jobUserId, Integer isUpdate) {
        Map<String, String> payMap = new HashMap<String, String>();
        try{
            String OrderNum = OrderNumUtil.outtradeno("JOB");
            String body = "认证";
            Map<String, String>  mapBody =  setSortedMap(openId,OrderNum,body,totalAmount,ip);
            String xml = WXPayUtil.mapToXml(mapBody);//将所有参数(map)转xml格式
            // 统一下单
            String unifiedorder_url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
            //发送post请求"统一下单接口"返回预支付id:prepay_id
            Map<String, String> xmlMap = new HashMap<>();
            xmlMap.put("xml",xml);
            String xmlStr = HttpClientUtil.doPostJson(unifiedorder_url, xml);
            //返回前端页面的json数据
            payMap = resultMap(xmlStr);
           
            //插入简历订单
            
        } catch (Exception e) {
            e.printStackTrace();
        }
            return payMap;
     }

    /**
     * 下单主体信息
     */
    public Map<String, String> setSortedMap(String openId,String OrderNum,String body,String totalFee,String ip) throws  Exception{
        //拼接统一下单地址参数
        Map<String, String> paraMap = new HashMap<String, String>();
        paraMap.put("appid", WxConstants.APPID);
        paraMap.put("body", body);
        paraMap.put("mch_id", WxConstants.MCHID);
        paraMap.put("nonce_str", WXPayUtil.generateNonceStr());//生成uuID
        paraMap.put("openid", openId);
        paraMap.put("out_trade_no", OrderNum);//订单号
        paraMap.put("spbill_create_ip", ip);
        paraMap.put("total_fee",totalFee);//金额 单位 分
        paraMap.put("trade_type", WxConstants.WX_TRADE_JSAPI);
        paraMap.put("notify_url",wxJObNotifyUrl);// 此路径是微信服务器调用支付结果通知路径随意写
        String sign = WXPayUtil.generateSignature(paraMap, WxConstants.KEY);
        paraMap.put("sign", sign);
        return paraMap;
    }

    /**
     * 返回前端页面的json数据
     */
    public  Map<String, String> resultMap(String xmlStr)throws  Exception{

        Map<String, String> json = WXPayUtil.xmlToMap(xmlStr);
        //JSONObject json = JSONObject.parseObject(xmlStr);//转成Json格式
        LOGGER.info("prepay_id  JSON:" + json);
        //获取prepay_id
        String prepay_id = json.get("prepay_id");//预支付id
        if (xmlStr.indexOf("SUCCESS") != -1) {
            Map<String, String> map = WXPayUtil.xmlToMap(xmlStr);
            prepay_id = (String) map.get("prepay_id");
        }
        Map<String, String> payMap = new HashMap<String, String>();
        payMap.put("appId", WxConstants.APPID);
        payMap.put("timeStamp", WXPayUtil.getCurrentTimestamp()+"");
        payMap.put("nonceStr", WXPayUtil.generateNonceStr());
        payMap.put("signType", "MD5");
        payMap.put("package", "prepay_id=" + prepay_id);
        String paySign = WXPayUtil.generateSignature(payMap, WxConstants.KEY);
        payMap.put("paySign", paySign);
        return payMap;
    }

4、工具类:

元转分,分转元

public class AmountUtils {
    /**金额为分的格式 */
    public static final String CURRENCY_FEN_REGEX = "\\-?[0-9]+";

    /**
     * 将分为单位的转换为元并返回金额格式的字符串 (除100)
     *
     * @param amount
     * @return
     * @throws Exception
     */
    public static String changeF2Y(Long amount) throws Exception{
        if(!amount.toString().matches(CURRENCY_FEN_REGEX)) {
            throw new Exception("金额格式有误");
        }

        int flag = 0;
        String amString = amount.toString();
        if(amString.charAt(0)=='-'){
            flag = 1;
            amString = amString.substring(1);
        }
        StringBuffer result = new StringBuffer();
        if(amString.length()==1){
            result.append("0.0").append(amString);
        }else if(amString.length() == 2){
            result.append("0.").append(amString);
        }else{
            String intString = amString.substring(0,amString.length()-2);
            for(int i=1; i<=intString.length();i++){
                if( (i-1)%3 == 0 && i !=1){
                    result.append(",");
                }
                result.append(intString.substring(intString.length()-i,intString.length()-i+1));
            }
            result.reverse().append(".").append(amString.substring(amString.length()-2));
        }
        if(flag == 1){
            return "-"+result.toString();
        }else{
            return result.toString();
        }
    }

    /**
     * 将分为单位的转换为元 (除100)
     *
     * @param amount
     * @return
     * @throws Exception
     */
    public static String changeF2Y(String amount) throws Exception{
        if(!amount.matches(CURRENCY_FEN_REGEX)) {
            throw new Exception("金额格式有误");
        }
        return BigDecimal.valueOf(Long.valueOf(amount)).divide(new BigDecimal(100)).toString();
    }

    /**
     * 将元为单位的转换为分 (乘100)
     *
     * @param amount
     * @return
     */
    public static String changeY2F(Long amount){
        return BigDecimal.valueOf(amount).multiply(new BigDecimal(100)).toString();
    }

    /**
     * 将元为单位的转换为分 替换小数点,支持以逗号区分的金额
     *
     * @param amount
     * @return
     */
    public static String changeY2F(String amount){
        String currency =  amount.replaceAll("\\$|\\¥|\\,", "");  //处理包含, ¥ 或者$的金额
        int index = currency.indexOf(".");
        int length = currency.length();
        Long amLong = 0l;
        if(index == -1){
            amLong = Long.valueOf(currency+"00");
        }else if(length - index >= 3){
            amLong = Long.valueOf((currency.substring(0, index+3)).replace(".", ""));
        }else if(length - index == 2){
            amLong = Long.valueOf((currency.substring(0, index+2)).replace(".", "")+0);
        }else{
            amLong = Long.valueOf((currency.substring(0, index+1)).replace(".", "")+"00");
        }
        return amLong.toString();
    }

    public static void main(String[] args) {
//        try {
//            System.out.println("结果:"+changeF2Y("-000a00"));
//        } catch(Exception e){
//            System.out.println("----------->>>"+e.getMessage());
////          return e.getErrorCode();
//        }
//      System.out.println("结果:"+changeY2F("1.00000000001E10"));

        System.out.println(AmountUtils.changeY2F("1.33"));
        try {
            System.out.println(AmountUtils.changeF2Y("1322"));
        } catch (Exception e) {
            e.printStackTrace();
        }
//        System.out.println(Long.parseLong(AmountUtils.changeY2F("1000000000000000")));
//        System.out.println(Integer.parseInt(AmountUtils.changeY2F("10000000")));
//        System.out.println(Integer.MIN_VALUE);
//        long a = 0;
//        System.out.println(a);

    }

}

http doPost doGet 请求

import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class HttpClientUtil {

	public static String doGet(String url, Map<String, String> param) {

		// 创建Httpclient对象
		CloseableHttpClient httpclient = HttpClients.createDefault();
		String resultString = "";
		CloseableHttpResponse response = null;
		try {

			StringBuilder sb = new StringBuilder(url+"?");
			for (String key : param.keySet()) {
				sb.append(key+"="+param.get(key)+"&");
			}
			sb.deleteCharAt(sb.length()-1);
			URI uri = new URI(sb.toString());
			// 创建http GET请求
			HttpGet httpGet = new HttpGet(uri);

			// 执行请求
			response = httpclient.execute(httpGet);
			// 判断返回状态是否为200
			if (response.getStatusLine().getStatusCode() == 200) {
				resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (response != null) {
					response.close();
				}
				httpclient.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return resultString;
	}

	public static String doGet(String url) {
		return doGet(url, null);
	}

	public static String doPost(String url, Map<String, String> param) {
		// 创建Httpclient对象
		CloseableHttpClient httpClient = HttpClients.createDefault();
		CloseableHttpResponse response = null;
		String resultString = "";
		try {
			// 创建Http Post请求
			HttpPost httpPost = new HttpPost(url);
			// 创建参数列表
			if (param != null) {
				List<NameValuePair> paramList = new ArrayList<>();
				for (String key : param.keySet()) {
					paramList.add(new BasicNameValuePair(key, param.get(key)));
				}
				// 模拟表单
				UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList);
				httpPost.setEntity(entity);
			}
			// 执行http请求
			response = httpClient.execute(httpPost);
			resultString = EntityUtils.toString(response.getEntity(), "utf-8");
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				response.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		return resultString;
	}

	public static String doPost(String url) {
		return doPost(url, null);
	}
	
	public static String doPostJson(String url, String json) {
		// 创建Httpclient对象
		CloseableHttpClient httpClient = HttpClients.createDefault();
		CloseableHttpResponse response = null;
		String resultString = "";
		try {
			// 创建Http Post请求
			HttpPost httpPost = new HttpPost(url);
			// 创建请求内容
			StringEntity entity = new StringEntity(json, ContentType.APPLICATION_JSON);
			httpPost.setEntity(entity);
			// 执行http请求
			response = httpClient.execute(httpPost);
			resultString = EntityUtils.toString(response.getEntity(), "utf-8");
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				response.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		return resultString;
	}
}

微信工具类

import com.alibaba.fastjson.JSON;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

import javax.servlet.http.HttpServletRequest;
import java.util.*;

public class WxUtils {


    //请求xml组装
    public static String getRequestXml(Map<String,String> parameters){
        StringBuffer sb = new StringBuffer();
        sb.append("<xml>");
        Set es = parameters.entrySet();
        Iterator it = es.iterator();
        while(it.hasNext()) {
            Map.Entry<String,String> entry = (Map.Entry)it.next();
            sb.append("<"+entry.getKey()+">"+entry.getValue()+"</"+entry.getKey()+">");
        }
        sb.append("</xml>");
        return sb.toString();
    }

    /**
     * 随机字符串生成
     */
    public static String getRandomString(int length) { //length表示生成字符串的长度
        String base = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < length; i++) {
            int number = random.nextInt(base.length());
            sb.append(base.charAt(number));
        }
        return sb.toString();
    }
    /**
     * 将xml格式的字符串转换成Map对象
     *
     * @param xmlStr xml格式的字符串
     * @return Map对象
     * @throws Exception 异常
     */
    public static Map<String, String> xmlStrToMap(String xmlStr) throws Exception {
        if(StringUtils.isEmpty(xmlStr)) {
            return null;
        }
        Map<String, String> map = new HashMap<>();
        //将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;
    }

    public static <T> T  xmlStrToBean(String xmlStr, Class<T> clazz) throws InstantiationException, IllegalAccessException {
        T obj = clazz.newInstance();
        try {
            // 将xml格式的数据转换成Map对象
            Map<String, String> map = xmlStrToMap(xmlStr);
            //将map对象的数据转换成Bean对象
            obj = JSON.parseObject(JSON.toJSONString(map),clazz);

        } catch(Exception e) {
            e.printStackTrace();
        }
        return obj;
    }
    public static String getIpAddress(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }



}

微信常量类

public class WxConstants {

    //微信统一下单请求xml参数
    public static final String APPID="wx1111111"; //appid是微信公众账号或开放平台APP的唯一标识
    public static final String MCHID="111111";//商户申请微信支付后,由微信支付分配的商户收款账号
    public static final String SECRET="aaaaaaaa";//AppSecret是APPID对应的接口密码
    public static final String KEY="1111111111";//交易过程生成签名的密钥 同API密钥
    public static final String NONCE_STR="nonce_str";
    public static final String SIGN="sign";//生成签名
    public static final String ATTACH="attach";
    public static final String TIMESTAMP = "timeStamp";
    public static final String NONCESTR = "noncestr";
    public static final String PREPAYID = "prepayid";
    public static final String PARTNERID = "111111";//API密钥
    public static final String PACKAGE = "package";
    public static final String OPENID ="OPENID";//用户唯一标识
    public static final int getHttpConnectTimeoutMs = 8000;//连接时间
    public static final int getHttpReadTimeoutMs = 10000; //超时时间


    /**
     * 微信 JSAPI支付(或小程序支付)微信中调用网页支付
     */
    public static final String WX_TRADE_JSAPI = "JSAPI";
    /**
     * 微信 Native支付
     */
    public static final String WX_TRADE_NATIVE = "NATIVE";
    /**
     * 微信 H5支付
     */
    public static final String WX_TRADE_MWEB = "MWEB";
    /**
     * 微信 app支付
     */
    public static final String WX_TRADE_APP = "APP";
    
}

看完上述内容,你们掌握java如何实现微信jsApi支付的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注亿速云行业资讯频道,感谢各位的阅读!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI