一、微信小程序支付
1.前端小程序支付页面
基本安全检测服务具体包含以下20项服务
注:基本安全检测服务,不包含问题部件的更换、维修及车辆保养。
1.发动机怠速运转;
2.空调及暖风系统;
3.倒车雷达、影像;
4.全车灯光、喇叭、反光镜、雨刷;
5.发动机运转是否有杂音或有异响;
6.机油油位及清洁程度;
7.防冻液液位及冰点;
8.蓄电池启动电压;
9.备胎、三角牌、灭火器;
10.四轮轮胎状态、气压;
11.检查四轮刹车盘;
12.检查四轮刹车片;
13.检查车身外观/轮毂;
14.检查故障灯;
15.鼓风机运转;
16.轮胎花纹深度;
17.轮胎胎侧;
18.油液渗漏检查;
19.转向拉杆球头、上下支臂球头;
20.内外球笼及防尘套,共20项。
2、微信小程序支付控制层
/** * 安全检测 * * @param platenumber * @param phonenumber * @param appointment * @param carType * @param request * @param response */ @RequestMapping("safetyMonitoring") public void safetyMonitoring(@RequestParam(required = false) String userId, @RequestParam(required = false) String platenumber, @RequestParam(required = false) String phonenumber, @RequestParam(required = false) String appointment, @RequestParam(required = false) String carType, @RequestParam(required = false) String startPlace, @RequestParam(required = false) String formId, @RequestParam(required = false) String city,HttpServletRequest request, HttpServletResponse response) { ReturnInfo info = new ReturnInfo(); try { InsureRealOrder order = new InsureRealOrder(); User user = userService.get(userId); order.setName(user.getUserName()); order.setUserId(userId); order.setFromId(formId); order.setStartTime(new Date()); order.setIsApi("1"); order.setState("0"); if (StringUtils.isNotBlank(platenumber)) { platenumber = new String(platenumber.getBytes("iso8859-1"), "utf-8"); order.setLicensePlate(platenumber); } if (StringUtils.isNotBlank(startPlace)) { startPlace = new String(startPlace.getBytes("iso8859-1"), "utf-8"); order.setStartPlace(startPlace); } if (StringUtils.isNotBlank(phonenumber)) { order.setTel(phonenumber); } if (StringUtils.isNotBlank(appointment)) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm"); Date parse = sdf.parse(appointment); order.setAppointment(parse); } if (StringUtils.isNotBlank(carType)) { carType = new String(carType.getBytes("iso8859-1"), "utf-8"); order.setCarType(carType); } if (StringUtils.isNotBlank(city)) { city = new String(city.getBytes("iso8859-1"), "utf-8"); order.setCity(city); } String serviceType = "安全检测"; InsureService insureService = insureServiceService.getInsurePayMoney(serviceType); order.setServiceType(serviceType); String json = ChinaCoalUtil.queryTimes(platenumber, "12"); JSONObject object = JSONObject.parseObject(json); log.info(object); Integer customerAttr = object.getInteger("customerAttr"); Integer lastTimes = object.getInteger("lastTimes"); //是中煤保险客户剩余次数大于零,继续提供免费服务 if (customerAttr.equals(0)&& lastTimes>0){ log.info("-----------------中煤保险公司用户---------------"); order.setType("1"); order.setPayTime(new Date()); order.setPayMoney(0.00); order.setSubsidyMoney(insureService.getPrice()); order.setPayState("1"); order = insureRealOrderService.save(order); //再调更新次数接口 ChinaCoalUtil.updateTimes(platenumber,"12","success"); NcscMerchant ncscMerchant = ncscMerchantService.getByProperty("city",city); if (ncscMerchant!=null){ //该市代理授权过的服务 String agentServices=ncscMerchant.getAgentService(); String[] str=agentServices.split(","); ListasList = Arrays.asList(str); String st = serviceType.substring(0,4); //判断该订单的服务是否在商家市代理授权服务中 if (asList.contains(st)){ String city2=order.getCity(); if (StringUtils.isNotBlank(city2)){ String tel2=ncscMerchant.getTel(); String licensePlate2=order.getLicensePlate(); String serviceType2=order.getServiceType(); JuheMsgUtil.smsSend(tel2, "195559", "#code#=" + "用户位置-"+city2 + "-服务类型-"+serviceType2 + "-车牌号-"+licensePlate2 + "-联系方式-"+tel2); info.setResult(true); info.setMsg("下单成功"); this.writeJson(response, info); return; } } } }else if (customerAttr.equals(0)&& lastTimes==0){ //是中煤保险客户但剩余次数为0,需支付金额,不在提供免费服务 order.setType("1"); order.setPayMoney(insureService.getPrice()); order.setPayState("0"); order.setSubsidyMoney(0.00); }else { InsureUser insureUser = insureUserService.getByProperty("licensePlate", platenumber); if (insureUser != null) { order.setType(insureUser.getType()); order.setPayMoney(0.00); order.setSubsidyMoney(insureService.getPrice()); order.setPayState("1"); order.setType(insureUser.getType()); String state = order.getState(); if (StringUtils.isNotBlank(state)) { state = "待处理"; } String payState = order.getPayState(); if (StringUtils.isNotBlank(payState)) { payState = "已支付"; } if (StringUtils.isNotBlank(user.getMiniappOpenId())) { String template_id = Constants.API_MOVECARInsure_TEMPLATE_ID; String data = Constants.API_MOVECAR_TEMPLATE_DATA2; Date date = new Date(); data = String.format(data, order.getId(), order.getServiceType(), state, payState, "保险公司vip用户无需支付", date, date); String sysUserMsgId = ConfigUtil.getValue("chl_program_sys_user_msg_id"); TemplateMessageUtil.sendApiMsg(formId, user.getMiniappOpenId(), template_id, data, sysUserMsgId, "pages/index/main"); } } else { order.setPayMoney(insureService.getPrice()); order.setSubsidyMoney(0.00); order.setType("0"); order.setPayState("0"); } } insureRealOrderService.saveOrUpdate(order); if (order.getPayMoney() != 0) { //这里先获取用户要支付的公众号配置 String appid = ConfigUtil.getValue("chl_program_app_id"); String mch_id = ConfigUtil.getValue("chl_program_mch_id"); String key = ConfigUtil.getValue("chl_program_pay_key"); //微信支付部分 String ip = IPUtil.getIpAddr(request); Map paramsMap = new HashMap } catch (Exception e) { e.printStackTrace(); info.setResult(false); info.setObj(e); } finally { this.writeJson(response, info); } } 3.微信支付回调 /** * 安全监测支付异步回调 * * @param response * @param request */ @RequestMapping("safetyMonitoringNotify") public void safetyMonitoringNotify(HttpServletResponse response, HttpServletRequest request) { String result = "(); //拼接参数开始 paramsMap.put("appid", appid); //公众账号ID paramsMap.put("mch_id", mch_id); //商户号 paramsMap.put("nonce_str", ConfigUtil.getValue("randomStr")); //随机字符串,不长于32位 paramsMap.put("body", "微信支付!"); //商品描述 paramsMap.put("out_trade_no", order.getId()); //商户订单号 DecimalFormat decimalFormat = new DecimalFormat("#"); paramsMap.put("spbill_create_ip", ip); //终端IP String path = request.getContextPath(); String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/"; //接收微信支付异步通知回调地址,通知url必须为直接可访问的url,不能携带参数 paramsMap.put("notify_url", basePath + "/xxx/xxx.html"); paramsMap.put("trade_type", "JSAPI"); paramsMap.put("total_fee", decimalFormat.format(order.getPayMoney() * 100)); //总金额 paramsMap.put("openid", user.getMiniappOpenId()); //用户标识 paramsMap.put("sign", AdvancedWeiXinPaySignUtils.buildRequestMysign(paramsMap, key));//签名 //把参数转换成xml字符串 String xmlParam = WeiXinPayUtil.getRequestXml(paramsMap); log.info("----------------------给微信发送---------------------------"); log.info(xmlParam); //返回微信服务器响应的信息 String returnResult = WeiXinPayUtil.httpsRequest(xmlParam); log.info("----------------------微信返回---------------------------"); log.info(returnResult); if (!StringUtils.isBlank(returnResult)) { Map resMap = new HashMap (); resMap = WeiXinPayUtil.doXMLParse(returnResult); String return_code = resMap.get("return_code"); String result_code = resMap.get("result_code"); String return_msg = resMap.get("return_msg"); if ("SUCCESS".equalsIgnoreCase(return_code) && "SUCCESS".equalsIgnoreCase(result_code)) { String prepay_id = resMap.get("prepay_id"); //预支付交易会话标识 Map wxPayParams = new HashMap<>(); long timeStamp = new Date().getTime(); wxPayParams.put("timestamp", String.valueOf(timeStamp)); wxPayParams.put("nonceStr", ConfigUtil.getValue("randomStr")); wxPayParams.put("package", "prepay_id=" + prepay_id); wxPayParams.put("paySign", WeChatUtils.sha2Str(String.valueOf(timeStamp), "prepay_id=" + prepay_id, appid, key)); wxPayParams.put("appId", appid); wxPayParams.put("insureRealOrderId", order.getId()); info.setObj(wxPayParams); info.setResult(true); info.setMsg(return_msg); } else { info.setResult(false); info.setMsg(return_msg); } } } else { info.setResult(true); info.setMsg("保险公司用户无需支付"); } "; Map returnMap; try { returnMap = WeiXinPayUtil.parseXml(request); if (returnMap.size() > 0) { Object out_trade_no = returnMap.get("out_trade_no"); if (out_trade_no != null) { InsureRealOrder insureRealOrder = insureRealOrderService.get((String) out_trade_no); if (insureRealOrder != null) { //这里先获取用户要支付的公众号配置 insureRealOrder.setPayTime(new Date()); insureRealOrder.setPayState("1"); insureRealOrderService.update(insureRealOrder); String state = insureRealOrder.getState(); if (StringUtils.isNotBlank(state)) { state = "待处理"; } String payState = insureRealOrder.getPayState(); if (StringUtils.isNotBlank(payState)) { payState = "已支付"; } User user = userService.get(insureRealOrder.getUserId()); if (StringUtils.isNotBlank(user.getMiniappOpenId())) { String template_id = Constants.API_MOVECARInsure_TEMPLATE_ID; String data = Constants.API_MOVECAR_TEMPLATE_DATA2; Date date = new Date(); data = String.format(data, insureRealOrder.getId(), insureRealOrder.getServiceType(), state, payState, insureRealOrder.getPayMoney(), date, date); String sysUserMsgId = ConfigUtil.getValue("chl_program_sys_user_msg_id"); TemplateMessageUtil.sendApiMsg(insureRealOrder.getFromId(), user.getMiniappOpenId(), template_id, data, sysUserMsgId, "pages/index/main"); } //这个是微信支付回调必须要的,不然会多次回调 result = " "; } } } response.getWriter().write(result); response.getWriter().flush(); response.getWriter().close(); } catch (Exception e) { e.printStackTrace(); } } 二、微信退款 1. /** * 改变订单状态(微信小程序或者微信公众号申请退款需要的证书可以是同一个,每次下载都会不同,使用最新下载证书) * * @param * @return */ @RequestMapping("safeChangeStateById") public void safeChangeStateById(@RequestParam(required = false) String id, @RequestParam(required = false) String state, HttpServletResponse response, HttpServletRequest request) { ReturnInfo info = new ReturnInfo(); try { InsureRealOrder insureRealOrder = insureRealOrderService.get(id); User user = userService.get(insureRealOrder.getUserId()); if (user == null) { throw new Exception("用户为空"); } String tel = insureRealOrder.getTel(); String openId = user.getMiniappOpenId(); String sys_user_msg_id = ConfigUtil.getValue("sys_user_msg_id"); //这里先获取退款用户的公众号配置 String appid = ConfigUtil.getValue("appID"); String mch_id = ConfigUtil.getValue("shop_mchid"); String key = ConfigUtil.getValue("weixin.key"); if (StringUtils.isNotBlank(sysUserMsgId)) { SysUserMsg sysUserMsg = sysUserMsgService.get(sysUserMsgId); if (sysUserMsg != null) { appid = sysUserMsg.getAppId(); mch_id = sysUserMsg.getShopMchId(); key = sysUserMsg.getPayKey(); } } if ("1".equals(insureRealOrder.getIsApi())) { appid = ConfigUtil.getValue("chl_program_app_id"); mch_id = ConfigUtil.getValue("chl_program_mch_id"); key = ConfigUtil.getValue("chl_program_pay_key"); } Date date = new Date(); if ("1".equals(state)) { state = "2"; } else if ("1".equals(state)) { state = "2"; info.setResult(true); } else if ("-1".equals(state)) { //只有在支付后才能退金额AND抵扣余额(订单存在且存在支付金额,支付时间) if (insureRealOrder != null) { String state1 = insureRealOrder.getState(); //有已支付订单,-->有无付款 if (insureRealOrder.getPayTime() != null) { //付款 if (insureRealOrder.getPayMoney() > 0) { //处理中,支付成功的违章才能处理失败 if (state1.equals("2") || state1.equals("1")||state1.equals("0")) { HashMapparamsMap = new HashMap<>(); DecimalFormat decimalFormat = new DecimalFormat("#"); paramsMap.put("appid", appid); //公众号id paramsMap.put("mch_id", mch_id); //商户号 paramsMap.put("nonce_str", ConfigUtil.getValue("randomStr")); //随机字符串 paramsMap.put("out_trade_no", insureRealOrder.getId()); //订单号 paramsMap.put("out_refund_no", insureRealOrder.getId()); //退款订单号 paramsMap.put("fee_type", "CNY"); paramsMap.put("total_fee", decimalFormat.format(insureRealOrder.getPayMoney() * 100)); //订单金额 paramsMap.put("refund_fee", decimalFormat.format(insureRealOrder.getPayMoney() * 100)); //退款金额 paramsMap.put("sign", AdvancedWeiXinPaySignUtils.buildRequestMysign(paramsMap, key)); //签名 //把参数转换成xml字符串 //这个在下面工具类里 String reuqestXml = WeiXinPayUtil.getRequestXml(paramsMap); log.info("----------------------给微信发送-----退款----------------------"); log.info(reuqestXml); log.info("----------------------微信返回-----退款----------------------"); //这个也在下面工具类里 String returnResult = WeiXinPayUtil.httpsRequestForReturn(reuqestXml, mch_id.toCharArray(), insureRealOrder.getIsApi()); log.info(returnResult); if (!StringUtils.isBlank(returnResult)) { MapresMap = new HashMap if (info.isResult()) { insureRealOrder.setState(state); insureRealOrder.setUpdateTime(date); insureRealOrderService.saveOrUpdate(insureRealOrder); info.setObj(insureRealOrder); info.setResult(true); } else { info.setObj(insureRealOrder); this.writeJson(response, info); } } catch (Exception e) { e.printStackTrace(); info.setMsg("系统异常"); info.setResult(false); } this.writeJson(response, info); }(); resMap = WeiXinPayUtil.doXMLParse(returnResult); log.info(resMap); String return_code = resMap.get("return_code"); String result_code = resMap.get("result_code"); String return_msg = resMap.get("return_msg"); if ("SUCCESS".equalsIgnoreCase(return_code) && "SUCCESS".equalsIgnoreCase(result_code)) { info.setResult(true); log.info("return_msg----------" + return_msg); } else { info.setResult(false); } } //-------------------支付金额退还结束--------------------- } } } } } else if (state.equals("0")) { state = "1"; } 2.工具类util(微信支付工具)
package com.zc.project.utils.pay; import java.io.*; import java.security.KeyStore; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Map.Entry; import javax.net.ssl.SSLContext; import javax.servlet.http.HttpServletRequest; import javax.xml.XMLConstants; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpPost; 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.DefaultHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.ssl.SSLContexts; import org.apache.http.util.EntityUtils; import org.dom4j.io.SAXReader; import org.jdom.Document; import org.jdom.Element; import org.jdom.JDOMException; import org.jdom.input.SAXBuilder; import com.zc.project.utils.ConfigUtil; /** * 微信支付工具 * * @author zhangxiao * @author 2016年11月25日下午4:15:51 * @Description */ public class WeiXinPayUtil { public static final String WEIXIN_APP_CS_APPID = ConfigUtil.getValue("weixinappcs.appid"); public static final String WEIXIN_APP_SHOP_APPID = ConfigUtil.getValue("appID"); public static final String WEIXIN_APP_CS_MCHID = ConfigUtil.getValue("weixinappcs.mch_id"); public static final String WEIXIN_APP_SHOP_MCHID = ConfigUtil.getValue("shop_mchid"); public static final String NOTIFY_URL = ConfigUtil.getValue("weixin.notify_url"); /** * 把参数转换成xml字符串 * * @param parameters * @return */ public static String getRequestXml(Mapparameters) { StringBuffer sb = new StringBuffer(); sb.append(" /** * 微信提供给商户的服务接入网关URL */ private static final String WEIXINPAY_GATEWAY = "https://api.mch.weixin.qq.com/pay/unifiedorder"; /** * 发送https请求 * * @param xmlParam 提交的数据 * @return 返回微信服务器响应的信息 */ public static String httpsRequest(String xmlParam) { String result = ""; //创建httpclient工具对象 DefaultHttpClient client = new DefaultHttpClient(); //创建post请求方法 HttpPost method = new HttpPost(WEIXINPAY_GATEWAY); StringEntity entity = new StringEntity(xmlParam, "UTF-8"); entity.setContentType("text/xml"); method.setEntity(entity); try { HttpResponse response = client.execute(method); result = EntityUtils.toString(response.getEntity(), "UTF-8"); } catch (ClientProtocolException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return result; } /** * 微信退款发送https请求 * * @param xmlParam 提交的数据 * @return 返回微信服务器响应的信息 */ public static String httpsRequestForReturn(String xmlParam, char[] chars, String isApi) throws IOException { CloseableHttpClient httpclient = null; StringBuilder sb = new StringBuilder(); try { KeyStore keyStore = KeyStore.getInstance("PKCS12"); File file = null; //证书路径(证书路径)线上 // if("1".equals(isApi)){ // file = new File("/usr/apiclient_cert_api.p12"); // }else{ // file = new File("/usr/apiclient_cert.p12"); // } //测试路径 if("1".equals(isApi)){ // file = new File("D:/微信商户平台支付证书/apiclient_cert_api.p12"); file = new File("D:/微信商户平台支付证书/apiclient_cert.p12"); }else{ file = new File("D:/微信商户平台支付证书/apiclient_cert.p12"); } FileInputStream instream = new FileInputStream(file);//放退款证书的路径 try { keyStore.load(instream, chars); } finally { instream.close(); } SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, chars).build(); SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[]{"TLSv1"}, null, SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER); httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build(); HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/secapi/pay/refund");//退款接口 System.out.println("executing request" + httpPost.getRequestLine()); StringEntity reqEntity = new StringEntity(xmlParam); // 设置类型 reqEntity.setContentType("application/x-www-form-urlencoded"); httpPost.setEntity(reqEntity); CloseableHttpResponse cresponse = httpclient.execute(httpPost); HttpEntity entity = cresponse.getEntity(); System.out.println("----------------------------------------"); System.out.println(cresponse.getStatusLine()); if (entity != null) { System.out.println("Response content length: " + entity.getContentLength()); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent(), "UTF-8")); String text; while ((text = bufferedReader.readLine()) != null) { sb.append(text); } } EntityUtils.consume(entity); } catch (Exception e) { e.printStackTrace(); } finally { httpclient.close(); } return sb.toString(); } /** * 解析xml,返回第一级元素键值对。如果第一级元素有子节点,则此节点的值是子节点的xml数据。 * * @param strxml * @return * @throws JDOMException * @throws IOException */ public static Map"); Set "); return sb.toString(); }> es = parameters.entrySet(); Iterator > it = es.iterator(); while (it.hasNext()) { Entry entry = it.next(); String k = entry.getKey(); Object v = entry.getValue(); if ("attach".equalsIgnoreCase(k) || "body".equalsIgnoreCase(k) || "sign".equalsIgnoreCase(k)) { sb.append("<" + k + ">" + "" + k + ">"); } else { sb.append("<" + k + ">" + v + "" + k + ">"); } } sb.append(" doXMLParse(String strxml) throws JDOMException, IOException { strxml = strxml.replaceFirst("encoding=\".*\"", "encoding=\"UTF-8\""); if (null == strxml || "".equals(strxml)) { return null; } Map m = new HashMap (); InputStream in = new ByteArrayInputStream(strxml.getBytes("UTF-8")); SAXBuilder builder = new SAXBuilder(); // 这是优先选择. 如果不允许DTDs (doctypes) ,几乎可以阻止所有的XML实体攻击 builder.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); builder.setFeature("http://xml.org/sax/features/external-general-entities", false); builder.setFeature("http://xml.org/sax/features/external-parameter-entities", false); builder.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); builder.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); Document doc = builder.build(in); Element root = doc.getRootElement(); List list = root.getChildren(); Iterator it = list.iterator(); while (it.hasNext()) { Element e = (Element) it.next(); String k = e.getName(); String v = ""; List children = e.getChildren(); if (children.isEmpty()) { v = e.getTextNormalize(); } else { v = getChildrenText(children); } m.put(k, v); } //关闭流 in.close(); return m; } /** * 获取子结点的xml * * @param children * @return String */ public static String getChildrenText(List children) { StringBuffer sb = new StringBuffer(); if (!children.isEmpty()) { Iterator it = children.iterator(); while (it.hasNext()) { Element e = (Element) it.next(); String name = e.getName(); String value = e.getTextNormalize(); List list = e.getChildren(); sb.append("<" + name + ">"); if (!list.isEmpty()) { sb.append(getChildrenText(list)); } sb.append(value); sb.append("" + name + ">"); } } return sb.toString(); } /** * * 解析微信发来的请求(XML) * * @param request * * @return * * @throws Exception **/ public static Map parseXml(HttpServletRequest request) throws Exception { // 将解析结果存储在HashMap中 Map map = new HashMap (); // 从request中取得输入流 InputStream inputStream = request.getInputStream(); // 读取输入流 SAXReader reader = new SAXReader(); // 这是优先选择. 如果不允许DTDs (doctypes) ,几乎可以阻止所有的XML实体攻击 reader.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); reader.setFeature("http://xml.org/sax/features/external-general-entities", false); reader.setFeature("http://xml.org/sax/features/external-parameter-entities", false); reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); reader.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); org.dom4j.Document document = reader.read(inputStream); // 得到xml根元素 org.dom4j.Element root = document.getRootElement(); // 得到根元素的所有子节点 List elementList = root.elements(); // 遍历所有子节点 for (org.dom4j.Element e : elementList) map.put(e.getName(), e.getText()); // 释放资源 inputStream.close(); inputStream = null; return map; } } 这只是自己的简单笔记!