SpringBoot使用银联支付

目录

前言

一、银联支付java sdk

二、官方DEMO

三、springboot项目使用银联支付

3.1、新建项目

3.2、配置

3.3、封装客户端

写在后面


前言

项目里使用了微信支付,支付宝支付。但是还不满足!我们还需要银联支付!!那就去看看呗。

https://open.unionpay.com/tjweb/api/list?bussId=52,这是银联的开放平台,看了一会,觉得在线网关支付符合要求,虽然看不懂这个名词。先把他的sdk和demo下载下来,下完我就懵逼了。demo竟然是用jsp和servlet写的,这和微信支付和支付宝支付比起来有点差距啊。不过没事,一点一点来就是了。

一、银联支付java sdk

我估计maven中央仓库没有银联支付的sdk,所以就只能自给自足了。新建个项目,先把银联支付的sdk抽出来,可以参考我的码云 https://gitee.com/waynelee/unionpay-java-sdk,然后打入maven本地仓库就可以用了。

mvn install:install-file -Dfile=E:\unionpay-sdk-java-0.0.1.jar -DgroupId=com.unionpay -DartifactId=unionpay-sdk-java -Dversion=0.0.1 -Dpackaging=jar

二、官方DEMO

把银联支付DEMO下载后导入Eclipse,在src/assets/测试环境证书文件夹里是测试环境的证书,把四个证书拷贝至D盘certs文件下,然后确保src/acp_sdk.properties配置文件中配置的四个证书路径是正确的。然后把项目运行在tomcat上,浏览器打开localhost:8081/ACPSample_B2C

银联支付

如上图,点击消费样例->消费,提交,会跳转至银联支付页面

银联

说明整个流程没问题,接下来就是把这些代码放进springboot项目里了。

三、springboot项目使用银联支付

3.1、新建项目

新建springboot项目,pom文件引如自己打好的银联支付的jar包

<dependency><groupId>com.unionpay</groupId><artifactId>unionpay-sdk-java</artifactId><version>0.0.1</version>
</dependency>

拷贝官方DEMO的 src/acp_sdk.properties至新建项目的src/main/resources/acp_sdk.properties

拷贝官方DEMO的 src/com/unionpay/acp/demo/DemoBase.java至新建项目的src/main/java/com/yuyi/lwq/unionpay/DemoBase.java

3.2、配置

通过阅读银联支付的官方DEMO,发现支付是通过src/com/unionpay/acp/demo/consume/Form_6_2_FrontConsume.java这个类实现的。我们发现在servlet的init方法中注释了一段代码

SDKConfig.getConfig().loadPropertiesFromSrc(); //从classpath加载acp_sdk.properties文件

所以,在springboot项目启动的时候,我们也要从classpath下加载拷贝过来的acp_sdk.properties文件,所以项目启动类需要实现CommandLineRunner,在项目启动时加载配置文件。

@SpringBootApplication
public class UnionpayApplication implements CommandLineRunner {public static void main(String[] args) {SpringApplication.run(UnionpayApplication.class, args);}@Overridepublic void run(String... args) throws Exception {SDKConfig.getConfig().loadPropertiesFromSrc();}
}

新建配置类,用于存储一些常量,也可以写在application.properties里,然后在这个类里引用。我就省事写死。

public class UnionpayConfig {/**商户号*/public static final String MER_ID = "777290058110048";/*** 前端异步通知地址*/public static String FRONT_URL = "http://localhost:8080/front.html";/*** 后台异步通知地址*/public static String BACK_URL = "http://yourdomain/union/notifyurl";}

3.3、封装客户端

新建UnionPayClient.java,此类的代码主要是拷贝自官方DEMO里的代码,在此基础上做一些修改,毕竟官方已经实现了,所以我们就不必再写过多的代码了。

public class UnionPayClient {/***  银联支付* @param orderId 商户订单号* @param txnAmt 金额 (分)* @param goodsName 商品名称* @return*/public static String pay(String orderId,String txnAmt,String goodsName){String txnTime = DateTimeFormatter.ofPattern("yyyyMMddHHmmss").format(LocalDateTime.now());System.out.println(txnTime);Map<String, String> requestData = new HashMap<String, String>();System.out.println("encoding"+DemoBase.encoding);/***银联全渠道系统,产品参数,除了encoding自行选择外其他不需修改***/requestData.put("version", "5.1.0");   			  //版本号,全渠道默认值requestData.put("encoding", DemoBase.encoding); 			  //字符集编码,可以使用UTF-8,GBK两种方式requestData.put("signMethod", SDKConfig.getConfig().getSignMethod()); //签名方法requestData.put("txnType", "01");               			  //交易类型 ,01:消费requestData.put("txnSubType", "01");            			  //交易子类型, 01:自助消费requestData.put("bizType", "000201");           			  //业务类型,B2C网关支付,手机wap支付requestData.put("channelType", "07");           			  //渠道类型,这个字段区分B2C网关支付和手机wap支付;07:PC,平板  08:手机/***商户接入参数***/requestData.put("merId", UnionpayConfig.MER_ID);    	          			  //商户号码,请改成自己申请的正式商户号或者open上注册得来的777测试商户号requestData.put("accessType", "0");             			  //接入类型,0:直连商户 requestData.put("orderId",orderId);             //商户订单号,8-40位数字字母,不能含“-”或“_”,可以自行定制规则		requestData.put("txnTime", txnTime);        //订单发送时间,取系统时间,格式为YYYYMMDDhhmmss,必须取当前时间,否则会报txnTime无效requestData.put("currencyCode", "156");         			  //交易币种(境内商户一般是156 人民币)		requestData.put("txnAmt", txnAmt);             			      //交易金额,单位分,不要带小数点//requestData.put("reqReserved", "透传字段");        		      //请求方保留域,如需使用请启用即可;透传字段(可以实现商户自定义参数的追踪)本交易的后台通知,对本交易的交易状态查询交易、对账文件中均会原样返回,商户可以按需上传,长度为1-1024个字节。出现&={}[]符号时可能导致查询接口应答报文解析失败,建议尽量只传字母数字并使用|分割,或者可以最外层做一次base64编码(base64编码之后出现的等号不会导致解析失败可以不用管)。		requestData.put("riskRateInfo", "{commodityName="+goodsName+"}");//前台通知地址 (需设置为外网能访问 http https均可),支付成功后的页面 点击“返回商户”按钮的时候将异步通知报文post到该地址//如果想要实现过几秒中自动跳转回商户页面权限,需联系银联业务申请开通自动返回商户权限//异步通知参数详见open.unionpay.com帮助中心 下载  产品接口规范  网关支付产品接口规范 消费交易 商户通知requestData.put("frontUrl", UnionpayConfig.FRONT_URL);//后台通知地址(需设置为【外网】能访问 http https均可),支付成功后银联会自动将异步通知报文post到商户上送的该地址,失败的交易银联不会发送后台通知//后台通知参数详见open.unionpay.com帮助中心 下载  产品接口规范  网关支付产品接口规范 消费交易 商户通知//注意:1.需设置为外网能访问,否则收不到通知    2.http https均可  3.收单后台通知后需要10秒内返回http200或302状态码 //    4.如果银联通知服务器发送通知后10秒内未收到返回状态码或者应答码非http200,那么银联会间隔一段时间再次发送。总共发送5次,每次的间隔时间为0,1,2,4分钟。//    5.后台通知地址如果上送了带有?的参数,例如:http://abc/web?a=b&c=d 在后台通知处理程序验证签名之前需要编写逻辑将这些字段去掉再验签,否则将会验签失败requestData.put("backUrl", UnionpayConfig.BACK_URL);// 订单超时时间。// 超过此时间后,除网银交易外,其他交易银联系统会拒绝受理,提示超时。 跳转银行网银交易如果超时后交易成功,会自动退款,大约5个工作日金额返还到持卡人账户。// 此时间建议取支付时的北京时间加15分钟。// 超过超时时间调查询接口应答origRespCode不是A6或者00的就可以判断为失败。requestData.put("payTimeout", new SimpleDateFormat("yyyyMMddHHmmss").format(new Date().getTime() + 15 * 60 * 1000));/**请求参数设置完毕,以下对请求参数进行签名并生成html表单,将表单写入浏览器跳转打开银联页面**/Map<String, String> submitFromData = AcpService.sign(requestData,DemoBase.encoding);  //报文中certId,signature的值是在signData方法中获取并自动赋值的,只要证书配置正确即可。String requestFrontUrl = SDKConfig.getConfig().getFrontRequestUrl();  //获取请求银联的前台地址:对应属性文件acp_sdk.properties文件中的acpsdk.frontTransUrlString html = AcpService.createAutoFormHtml(requestFrontUrl, submitFromData,DemoBase.encoding);   //生成自动跳转的Html表单//LogUtil.writeLog("打印请求HTML,此为请求报文,为联调排查问题的依据:"+html);return html;}/*** 查询订单状态* @param orderId 订单号* @param txnTime 订单发送时间* @return*/public static Map<String, String> query(String orderId,String txnTime){Map<String, String> data = new HashMap<String, String>();/***银联全渠道系统,产品参数,除了encoding自行选择外其他不需修改***/data.put("version", "5.1.0");                 //版本号data.put("encoding", DemoBase.encoding);               //字符集编码 可以使用UTF-8,GBK两种方式data.put("signMethod", SDKConfig.getConfig().getSignMethod()); //签名方法data.put("txnType", "00");                             //交易类型 00-默认data.put("txnSubType", "00");                          //交易子类型  默认00data.put("bizType", "000201");                         //业务类型 B2C网关支付,手机wap支付/***商户接入参数***/data.put("merId", UnionpayConfig.MER_ID);                  //商户号码,请改成自己申请的商户号或者open上注册得来的777商户号测试data.put("accessType", "0");                           //接入类型,商户接入固定填0,不需修改/***要调通交易以下字段必须修改***/data.put("orderId", orderId);                 //****商户订单号,每次发交易测试需修改为被查询的交易的订单号data.put("txnTime", txnTime);                 //****订单发送时间,每次发交易测试需修改为被查询的交易的订单发送时间/**请求参数设置完毕,以下对请求参数进行签名并发送http post请求,接收同步应答报文------------->**/Map<String, String> reqData = AcpService.sign(data,DemoBase.encoding);//报文中certId,signature的值是在signData方法中获取并自动赋值的,只要证书配置正确即可。String url = SDKConfig.getConfig().getSingleQueryUrl();// 交易请求url从配置文件读取对应属性文件acp_sdk.properties中的 acpsdk.singleQueryUrl//这里调用signData之后,调用submitUrl之前不能对submitFromData中的键值对做任何修改,如果修改会导致验签不通过Map<String, String> rspData = AcpService.post(reqData,url,DemoBase.encoding);return rspData;}/*** 订单退款* @param refundOrderId (退款单号)* @param txnAmt 退款金额(分)* @param origQryId 原消费交易返回的的queryId* @return*/public static Map<String, String> refund(String refundOrderId,String txnAmt,String origQryId){String txnTime = DateTimeFormatter.ofPattern("yyyyMMddHHmmss").format(LocalDateTime.now());Map<String, String> data = new HashMap<String, String>();/***银联全渠道系统,产品参数,除了encoding自行选择外其他不需修改***/data.put("version","5.1.0");               //版本号data.put("encoding", DemoBase.encoding);             //字符集编码 可以使用UTF-8,GBK两种方式data.put("signMethod", SDKConfig.getConfig().getSignMethod()); //签名方法data.put("txnType", "04");                           //交易类型 04-退货		data.put("txnSubType", "00");                        //交易子类型  默认00		data.put("bizType", "000201");                       //业务类型 B2C网关支付,手机wap支付	data.put("channelType", "07");                       //渠道类型,07-PC,08-手机		/***商户接入参数***/data.put("merId", UnionpayConfig.MER_ID);                //商户号码,请改成自己申请的商户号或者open上注册得来的777商户号测试data.put("accessType", "0");                         //接入类型,商户接入固定填0,不需修改		data.put("orderId",refundOrderId);          //商户订单号,8-40位数字字母,不能含“-”或“_”,可以自行定制规则,重新产生,不同于原消费		data.put("txnTime", txnTime);      //订单发送时间,格式为YYYYMMDDhhmmss,必须取当前时间,否则会报txnTime无效		data.put("currencyCode", "156");                     //交易币种(境内商户一般是156 人民币)		data.put("txnAmt", txnAmt);                          //****退货金额,单位分,不要带小数点。退货金额小于等于原消费金额,当小于的时候可以多次退货至退货累计金额等于原消费金额		//data.put("reqReserved", "透传信息");                  //请求方保留域,如需使用请启用即可;透传字段(可以实现商户自定义参数的追踪)本交易的后台通知,对本交易的交易状态查询交易、对账文件中均会原样返回,商户可以按需上传,长度为1-1024个字节。出现&={}[]符号时可能导致查询接口应答报文解析失败,建议尽量只传字母数字并使用|分割,或者可以最外层做一次base64编码(base64编码之后出现的等号不会导致解析失败可以不用管)。		data.put("backUrl", UnionpayConfig.BACK_URL);               //后台通知地址,后台通知参数详见open.unionpay.com帮助中心 下载  产品接口规范  网关支付产品接口规范 退货交易 商户通知,其他说明同消费交易的后台通知/***要调通交易以下字段必须修改***/data.put("origQryId", origQryId);      //****原消费交易返回的的queryId,可以从消费交易后台通知接口中或者交易状态查询接口中获取/**请求参数设置完毕,以下对请求参数进行签名并发送http post请求,接收同步应答报文------------->**/Map<String, String> reqData  = AcpService.sign(data,DemoBase.encoding);//报文中certId,signature的值是在signData方法中获取并自动赋值的,只要证书配置正确即可。String url = SDKConfig.getConfig().getBackRequestUrl();//交易请求url从配置文件读取对应属性文件acp_sdk.properties中的 acpsdk.backTransUrlMap<String, String> rspData = AcpService.post(reqData,url,DemoBase.encoding);//这里调用signData之后,调用submitUrl之前不能对submitFromData中的键值对做任何修改,如果修改会导致验签不通过return rspData;}}

我们把验证签名逻辑放在controller层,验证签名成功后再根据返回码判断订单的状态。官方DEMO里的注释已经很详细了,就不做过多的介绍了。

@RestController
@RequestMapping("/union")
public class UnionpayController {/*** 支付* @param orderNumber 商户订单号* @param txnAmt 金额(分)* @return* @throws Exception*/@PostMapping("/orderpay")public ResultBO<Object> pay(@RequestParam String orderNumber,@RequestParam Integer txnAmt,@RequestParam String goodsName) throws Exception{String payhtml = UnionPayClient.pay(orderNumber, txnAmt.toString(),goodsName);//生成自动跳转的form表单,直接返给前端,让前端做页面的跳转return ResultTool.success(payhtml);}/*** 订单状态查询* @param orderNumber* @param txnTime* @return* @throws Exception*/@GetMapping("/orderquery")public ResultBO<Object> query(@RequestParam String orderNumber,@RequestParam String txnTime)throws Exception{//参数限制逻辑Map<String, String> rspData = UnionPayClient.query(orderNumber, txnTime);//返回参数处理if(!rspData.isEmpty()){//验证签名if(AcpService.validate(rspData, DemoBase.encoding)){LogUtil.writeLog("验证签名成功");if("00".equals(rspData.get("respCode"))){//如果查询交易成功//处理被查询交易的应答码逻辑String origRespCode = rspData.get("origRespCode");if("00".equals(origRespCode)){System.out.println("交易成功了!!!!!!!!");//交易成功,更新商户订单状态//数据库修改成功后告诉前端,用户支付成功return ResultTool.success();}else if("03".equals(origRespCode) ||"04".equals(origRespCode) ||"05".equals(origRespCode)){//需再次发起交易状态查询交易 }else{//其他应答码为失败请排查原因}}else{//查询交易本身失败,或者未查到原交易,检查查询交易报文要素}}else{LogUtil.writeErrorLog("验证签名失败");//检查验证签名失败的原因}}else{//未返回正确的http状态LogUtil.writeErrorLog("未获取到返回报文或返回http状态码非200");}return ResultTool.success();}@PostMapping("/orderrefund")public ResultBO<Object> refund(@RequestParam String refundOrderId,@RequestParam String txnAmt,@RequestParam String queryId){Map<String, String> rspData = UnionPayClient.refund(refundOrderId, txnAmt, queryId);/**对应答码的处理,请根据您的业务逻辑来编写程序,以下应答码处理逻辑仅供参考------------->**///应答码规范参考open.unionpay.com帮助中心 下载  产品接口规范  《平台接入接口规范-第5部分-附录》if(!rspData.isEmpty()){if(AcpService.validate(rspData, DemoBase.encoding)){LogUtil.writeLog("验证签名成功");String respCode = rspData.get("respCode");if("00".equals(respCode)){//交易已受理,等待接收后台通知更新订单状态,也可以主动发起 查询交易确定交易状态。return ResultTool.success();}else if("03".equals(respCode)|| "04".equals(respCode)||"05".equals(respCode)){//后续需发起交易状态查询交易确定交易状态}else{//其他应答码为失败请排查原因}}else{LogUtil.writeErrorLog("验证签名失败");}}else{//未返回正确的http状态LogUtil.writeErrorLog("未获取到返回报文或返回http状态码非200");}return ResultTool.success();}}

银联支付的支付方式和支付宝支付差不多,都是返回自动提交的form表单跳转至自己官方页面进行支付。微信支付因为没有官方页面,所以只能扫码了。但是三者的异步通知还是基本一样的。

@RestController
@RequestMapping("/union")
public class NotifyUrlController {/*** 后台异步通知路径* @param req* @return*/@PostMapping("/notifyurl")public ResponseEntity<Object> back(HttpServletRequest req){LogUtil.writeLog("BackRcvResponse接收后台通知开始");String encoding = req.getParameter(SDKConstants.param_encoding);// 获取银联通知服务器发送的后台通知参数Map<String, String> reqParam = getAllRequestParam(req);Map<String, String> valideData = null;if (null != reqParam && !reqParam.isEmpty()) {Iterator<Entry<String, String>> it = reqParam.entrySet().iterator();valideData = new HashMap<String, String>(reqParam.size());while (it.hasNext()) {Entry<String, String> e = it.next();String key = (String) e.getKey();String value = (String) e.getValue();valideData.put(key, value);}}//重要!验证签名前不要修改reqParam中的键值对的内容,否则会验签不过if (!AcpService.validate(valideData, encoding)) {LogUtil.writeLog("验证签名结果[失败].");//验签失败,需解决验签问题} else {LogUtil.writeLog("验证签名结果[成功].");//【注:为了安全验签成功才应该写商户的成功处理逻辑】交易成功,更新商户订单状态String orderId =valideData.get("orderId"); //获取后台通知的数据,其他字段也可用类似方式获取String respCode = valideData.get("respCode");System.out.println(orderId+respCode);}LogUtil.writeLog("BackRcvResponse接收后台通知结束");//返回给银联服务器http 200  状态码return new ResponseEntity<Object>(HttpStatus.OK);}/*** 获取参数集合* @param request* @return*/public static Map<String, String> getAllRequestParam(final HttpServletRequest request) {Map<String, String> res = new HashMap<String, String>();Enumeration<?> temp = request.getParameterNames();if (null != temp) {while (temp.hasMoreElements()) {String en = (String) temp.nextElement();String value = request.getParameter(en);res.put(en, value);// 在报文上送时,如果字段的值为空,则不上送<下面的处理为在获取所有参数数据时,判断若值为空,则删除这个字段>if (res.get(en) == null || "".equals(res.get(en))) {// System.out.println("======为空的字段名===="+en);res.remove(en);}}}return res;}}

以上所有代码,基本都是官方DEMO里的代码,我只是进行了改动和再次封装,使其更适用于springboot前后端分离的开发模式。

写在后面

其实银联支付也不算是太难,和支付宝支付有异曲同工之妙。微信、支付宝、银联,这三个支付,整体流程不会相差太多,多看看官方文档还是能解决问题的。但是有些问题确实是有点棘手,尤其是微信支付。

详细代码:https://gitee.com/waynelee/unionpay

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/39186.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

银联银行卡卡号java_编写Java程序,使用单例模式,创建可以生成银联借记卡号的工具类...

编写Java程序,使用单例模式,创建可以生成银联借记卡号的工具类 编写Java程序,使用单例模式,创建可以生成银联借记卡号的工具类,银联借记卡号是一个 19 位的数字,卡号以“62”开头,如图所示。 使用单例模式,创建可以生成银联借记卡号的工具类,银联借记卡号是一个 19 位…

苹果手机充值显示服务器繁忙,iTunes充值常见错误和解决方法

iTunes充值常见错误和解决方法 小编归纳总结了常见的iTunes充值异常和解决方法&#xff0c;包括充值未到账、语音操作异常、订单状态异常、系统验证信息错误、支付密码异常、账户金额限制、银行卡状态异常及系统异常8大常见iTunes充值错误&#xff0c;以方便果粉顺利充值iTunes…

雅思阅读笔记

一、一个星期七天 1.Monday 2.Tuesday 3.Wednesday 4.Thursday5. Friday 6.Saturday 7.Sunday 二、一年十二个月 1.January 2.February 3.March 4.April 5.May 6.June 7.July 8.August 9.September 10. October 11.November 12.December 三、一年四季 1.spring 2.summer 3.autu…

雅思复习总结

文章目录 1. 考前复习阶段1.1 阅读1.2 听力1.3 写作1.4 口语 2. 考试过程3. 最后成绩 刚刚考完雅思&#xff0c;这是我第一次考雅思&#xff0c;总结一下这次考试的经验。 1. 考前复习阶段 对于中国考生来说&#xff0c;阅读和听力是强项&#xff0c;只需做大量的练习即可。重…

计算雅思成绩C语言,雅思成绩到底如何计算的?

很多烤鸭在漫漫屠鸭路上时常会感到困惑&#xff1a;明明自己发挥不错&#xff0c;为什么成绩却和想象的不同&#xff1f;总分达标了&#xff0c;小分却不够该怎么办&#xff1f; 其实雅思成绩单隐藏了很多的信息&#xff0c;今天我们来分析两份典型的成绩单&#xff0c;帮助烤鸭…

ubc本科计算机雅思要求,英属哥伦比亚大学雅思要求

英属哥伦比亚大学雅思要求是6.5分&#xff1b;托福93分。 英属哥伦比亚大学院系 不列颠哥伦比亚大学共设有25个院系&#xff1a; 应用科学系(Faculty of Applied Science) 建筑与园林建筑学院 (School of Architecture and Landscape Architecture) 文学系 (Faculty of Arts) 听…

【b站雅思笔记】Charlie有好好学习 - 雅思听力

〇、前情提要 最近备考雅思&#xff0c;学习一下前人经验。 参考&#xff1a; 手把手教你做地图题 | 雅思听力地图题 https://www.bilibili.com/video/BV1Pp4y167sM?t1331手把手教你做听力Part4 | 雅思听力填空题 https://www.bilibili.com/video/BV1AK4y1W7dh手把手教你做…

雅思口语P3的逻辑

找最核心的地方 核心-> 玩音乐的好处 然后拉上孩子的关系 然后拉上父母的关系

雅思小作文 柱状图

逻辑不太对&#xff0c;可以找三个女生下降的&#xff0c;两个上升的来写。因为男女比例增长都是相反的。 The bar charts compare the proportion of boy and girl top students in different courses in 1996 and 2000. Girls seemed have the best performance in Languages…

DataV+Echarts

1. 安装 vue3 也就是安装了一下vue3&#xff0c;但是 dataV 和 Echarts 的学习并没有使用vue的脚手架去创建一个项目。 原因有两点&#xff1a; dataV 目前对 vue3 的支持并不是很友好&#xff0c;主要还是基于 vue2 框架的一个组件库。脚手架创建 vue 项目确实会使开发更加的有…

基于Arduino通过并联L298N实现四驱麦克纳姆轮巡迹小车

1 前言 本人也是零基础进行Arduino学习的初学者&#xff0c;做小车期间遇到过很多困难&#xff0c;在此写下整个小车的制作流程以及遇到的问题与解决方案&#xff0c;希望对后来者有所帮助。在制作期间参考了许多文章得到了大佬的指点&#xff0c;以及下面展示成果如建模等是由…

chatgpt赋能python:Python怎么打竖线:学习竖线在Python中的应用

Python怎么打竖线&#xff1a;学习竖线在Python中的应用 1.引言 Python是和其他编程语言一样有许多基本语法&#xff0c;但是新手可能会遇到某些问题&#xff0c;例如&#xff0c;在Python中如何打竖线&#xff1f;在本篇文章中&#xff0c;我们将介绍如何在Python中打竖线以…

双色球彩票生成之一用户彩票号码随机生成

主要流程如下:1. 使用WinningNumber()方法随机生成一组1-33的红球号码和1-16的蓝球号码,作为中奖号码。2. 同样使用WinningNumber()方法随机生成一组作为用户号码。3. 判断用户号码中红球和蓝球的中奖情况: - 红球判断使用contains()方法检查用户号码的红球是否在中奖号码的…

【用java写的】双色球中奖模拟器

双色球&#xff0c;6个红球&#xff0c;1个蓝球&#xff0c;而且红球中的数据不能重复&#xff0c;红球的数字范围为1-33&#xff0c;蓝球的数字范围为1-16。 然后我们作为彩民&#xff0c;自己买号&#xff0c;在模拟器中则自己依次输入每个球对应的号码&#xff0c;最后开奖…

java案例:模拟双色球中奖

1、双色球系统-业务分析、随机生成一组中奖号码 中奖号码由 6 个红球和 1 个篮球组成 ( 注意&#xff1a; 6 个红球要求不能重复 ) 。 可以定义方法用于返回一组中奖号码(7个数据)&#xff0c;返回的形式是一个整型数组 如何去保证随机的6个中奖的红球号码不重复&#xff1f; …

magento email:发送自定义邮件

邮件是几乎所有电商系统都要用到的功能&#xff0c;在magento中实现简单的邮件发送并不复杂&#xff0c;不过要想用特定邮件模板&#xff0c;就需要对magento邮件系统做一些深入了解&#xff0c;本文就分析一下如何发送自定义邮件。之前已经发了一篇介绍magento基本邮件设置的文…

magento email:快速实现发送自定义邮件

之前介绍了一下稍微复杂一点的 magento email:发送自定义邮件 但是呢&#xff0c;当我们对magento email机制有一定的了解之后&#xff0c;便可以在模块中使用自定义邮件模板快速实现发送邮件功能&#xff01; 登入后台system->Transactional Emails,单击右上角Add New T…

postfix自动搭建邮箱黑科技、邮件群发、批量自建邮局系统

大家好今天给大家分享一个 先进的自建邮箱黑科技&#xff0c;零基础3-5分钟快速搭建几百上千个自建邮箱系统。 软件特点&#xff1a;自动搭建&#xff0c;自动解析&#xff0c;多线程操作 自建邮件系统服务器要求 须开通25端口。另要求必须Centos系统&#xff0c;有固定公网I…