bankapi/pom.xml
New file @@ -0,0 +1,56 @@ <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>com.ruoyi</groupId> <artifactId>ruoyi</artifactId> <version>3.8.6</version> </parent> <description> 银行接口模块 </description> <groupId>org.taxi591</groupId> <artifactId>bankapi</artifactId> <version>1.0.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>com.ruoyi</groupId> <artifactId>ruoyi-framework</artifactId> </dependency> <dependency> <groupId>com.ruoyi</groupId> <artifactId>ruoyi-common</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>2.5.15</version> <configuration> <fork>true</fork> <!-- 如果没有该配置,devtools不会生效 --> </configuration> <executions> <execution> <goals> <goal>repackage</goal> </goals> </execution> </executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>3.1.0</version> <configuration> <failOnMissingWebXml>false</failOnMissingWebXml> <warName>${project.artifactId}</warName> </configuration> </plugin> </plugins> <finalName>${project.artifactId}</finalName> </build> </project> bankapi/src/main/java/com/taxi591/bankapi/BankConfig.java
New file @@ -0,0 +1,17 @@ package com.taxi591.bankapi; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @Configuration @EnableConfigurationProperties({BankProperties.class}) @ConditionalOnProperty(value = BankProperties.ENBALE_PREFIX, matchIfMissing = true) @ComponentScan("com.taxi591.bankapi.service") public class BankConfig { } bankapi/src/main/java/com/taxi591/bankapi/BankProperties.java
New file @@ -0,0 +1,33 @@ package com.taxi591.bankapi; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import static com.taxi591.bankapi.BankProperties.PREFIX; @Data @ConfigurationProperties(prefix = PREFIX) public class BankProperties { public static final String PREFIX = "com.taxi591.bank"; public static final String ENBALE_PREFIX = PREFIX+".enable"; private Boolean enable = true; /** * 证书路径 */ private String pfxPath; /** * 密码 */ private String keystorePassword; /** * 公钥路径 */ private String cerPath; } bankapi/src/main/java/com/taxi591/bankapi/dto/ChargeBillRequest.java
New file @@ -0,0 +1,175 @@ package com.taxi591.bankapi.dto; import com.alibaba.fastjson2.JSON; import lombok.Data; import java.io.Serializable; /** * 直连商户平台缴费销账输入对象,需要转换成json串发送给第三方系统 * @author DELL * */ @Data public class ChargeBillRequest implements Serializable { private static final long serialVersionUID = 1L; /** 格式 */ private String format; /** 消息 */ private Message message; @Override public String toString() { return "ChargeBillRequest[format=" + format + ",message=" + message.toString() + "]"; } /** * * 账单查询内部消息对象实体message内部类 * */ @Data public class Message implements Serializable { private static final long serialVersionUID = 1L; /** 消息头部 */ private Head head; /** 消息体 */ private Info info; @Override public String toString() { return JSON.toJSONString(this); } /** * message子对象head消息头内部类 */ @Data public class Head implements Serializable { private static final long serialVersionUID = 1L; /** 渠道编码 */ private String channel; /** 交易码 */ private String transCode; /** 交易上行下送标志位 */ private String transFlag; /** 缴费中心交易序列号 */ private String transSeqNum; /** 时间戳 */ private String timeStamp; /** 4为分行iGoal码 */ private String branchCode; @Override public String toString() { return JSON.toJSONString(this); } } /** * message子对象info消息实体内部类 */ @Data public class Info implements Serializable { private static final long serialVersionUID = 1L; /** 缴费项目编号*/ private String epayCode; /** 第三方商户编号*/ private String merchantId; /** 缴费中心流水号*/ private String traceNo; /** 输入要素1*/ private String input1; /** 输入要素2*/ private String input2; /** 输入要素3*/ private String input3; /** 输入要素4*/ private String input4; /** 输入要素5*/ private String input5; /** 农行16位客户号*/ private String userId; /** 缴费金额计算规则*/ private String amtRule; /** 合并支付的子账单数*/ private String payBillCount; /** 合并支付的子账单累加总金额*/ private String payBillAmt; /** 合并支付的子账单*/ private String payBillNo; /** 套餐名称*/ private String optionName; /** 套餐编码*/ private String optionCode; /** 套餐金额*/ private String optionAmt; /** 支付方式交易码*/ private String payType; /** 缴费支付账号*/ private String payAcc; /** 支付系统流水号*/ private String transPaySeq; /** 支付系统日期*/ private String transDate; /** 支付系统时间*/ private String transTime; /** 会计日期*/ private String settleDate; /** 清算模式*/ private String clearType; /** 缓存域信息*/ private String cacheMem; /** 销账报文重发次数,通过此字段识别销账报文是否为重发的,0表示首次、1表示重发一次,2表示重发2次,最多重发3次*/ private String resendTimes; /** 第三方支付平台商户订单号 第三方平台例如微信支付宝的支付订单号 add 2020-01-13*/ private String numOpenMerchantOrder; @Override public String toString() { return JSON.toJSONString(this); } } } } bankapi/src/main/java/com/taxi591/bankapi/dto/ChargeBillResponse.java
New file @@ -0,0 +1,158 @@ package com.taxi591.bankapi.dto; import com.alibaba.fastjson2.JSON; import lombok.Data; import java.io.Serializable; /** * 直连商户平台账单销账返回对象 * @author DELL * */ @Data public class ChargeBillResponse implements Serializable { private static final long serialVersionUID = 1L; /** 格式 */ private String format; /** 消息体 */ private Message message; public ChargeBillResponse(){ } /** * 构造函数,通过输入对象,构造返回对象数据信息 * @param request */ public ChargeBillResponse(ChargeBillRequest request) { this.setFormat(request.getFormat()); this.setMessage(new Message(request.getMessage())); } @Override public String toString() { return JSON.toJSONString(this); } /** * * 账单查询内部消息对象返回实体message内部类 * */ @Data public class Message implements Serializable { private static final long serialVersionUID = 1L; /** 消息头部 */ private Head head; /** 消息实体 */ private Info info; public Message() { this.head = new Head(); this.info = new Info(); } public Message(ChargeBillRequest.Message requestMessage){ this.setHead(new Head(requestMessage.getHead())); this.setInfo(new Info(requestMessage.getInfo())); } @Override public String toString() { return JSON.toJSONString(this); } /** * * 账单销账内部消息对象返回实体Head内部类 * */ @Data public class Head implements Serializable { private static final long serialVersionUID = 1L; /** 渠道 */ private String channel; /** 交易码 */ private String transCode; /** 交易上行下送标志 */ private String transFlag; /** 缴费中心交易序列号 */ private String transSeqNum; /** 时间戳 */ private String timeStamp; /** 查询返回码 */ private String returnCode ; /** 返回提示信息 */ private String returnMessage; public Head() { } public Head(ChargeBillRequest.Message.Head reqMessHead) { this.setChannel(reqMessHead.getChannel()); this.setTransSeqNum(reqMessHead.getTransSeqNum()); this.setTransCode(reqMessHead.getTransCode()); } @Override public String toString() { return JSON.toJSONString(this); } } /** * * 账单查询内部消息对象返回实体Info内部类 * */ @Data public class Info implements Serializable { private static final long serialVersionUID = 1L; /** 缴费项目唯一标识号*/ private String epayCode; /** 缴费中心流水号*/ private String traceNo; /** 退款标志位*/ private String refundFlag; /** 第三方支付平台商户订单号 第三方平台例如微信支付宝的支付订单号 add 2020-01-13*/ private String numOpenMerchantOrder; public Info() { } public Info(ChargeBillRequest.Message.Info reqMessInfo) { this.setEpayCode(reqMessInfo.getEpayCode()); this.setTraceNo(reqMessInfo.getTraceNo()); } @Override public String toString() { return JSON.toJSONString(this); } } } } bankapi/src/main/java/com/taxi591/bankapi/dto/CovertPayBackResult.java
New file @@ -0,0 +1,18 @@ package com.taxi591.bankapi.dto; import lombok.Data; import java.io.Serializable; @Data public class CovertPayBackResult implements Serializable { /** * 解析结果 */ private ChargeBillRequest result; /** * 返回银行应答内容 */ private String back; } bankapi/src/main/java/com/taxi591/bankapi/service/BankService.java
New file @@ -0,0 +1,108 @@ package com.taxi591.bankapi.service; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.TypeReference; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.utils.DateUtils; import com.taxi591.bankapi.dto.ChargeBillRequest; import com.taxi591.bankapi.dto.ChargeBillResponse; import com.taxi591.bankapi.dto.CovertPayBackResult; import com.taxi591.bankapi.utils.Base64; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import javax.servlet.http.HttpServletRequest; import java.io.UnsupportedEncodingException; import java.util.function.Function; import java.util.regex.Matcher; import java.util.regex.Pattern; @Service @Slf4j public class BankService { @Autowired SignatureAndVerification signatureAndVerification; static final String TIMESTAMP_PATTERN = "yyyyMMddHHmmssSSS"; /** * 创建银行应答 * @param request 银行请求对象 * @param dealResult 是否处理成功 * @return */ public String createResponse(ChargeBillRequest request,Boolean dealResult){ ChargeBillResponse response = new ChargeBillResponse(request); response.getMessage().getHead().setReturnCode(dealResult?"0000":"1111"); response.getMessage().getHead().setReturnMessage(dealResult?"处理成功":"处理失败"); response.getMessage().getInfo().setRefundFlag("false"); response.getMessage().getHead().setTimeStamp(DateUtils.dateTimeNow(TIMESTAMP_PATTERN)); if (!dealResult){ if (Integer.parseInt(request.getMessage().getInfo().getResendTimes())==3){ response.getMessage().getInfo().setRefundFlag("true"); }else{ response.getMessage().getInfo().setRefundFlag("false"); } } String respJSON = JSON.toJSONString(response); String sign = signatureAndVerification.signWhithsha1withrsa(respJSON); String respStr = null; try { respStr = sign + "||" + new String(org.apache.commons.codec.binary.Base64.encodeBase64(respJSON.getBytes("utf-8"))); } catch (UnsupportedEncodingException e) { } return respStr; } /** * 处理支付回调数据 * @param httpRequest http请求对象 * @param consumer 处理函数 * @return */ public CovertPayBackResult covertPayCallBack(HttpServletRequest httpRequest, Function<ChargeBillRequest,Boolean> consumer) { CovertPayBackResult result = new CovertPayBackResult(); try { // 接收报文 String requestContent = SignatureAndVerification.getRequestBody(httpRequest).trim(); String sign = requestContent.substring(0, requestContent.indexOf("||"));; String requestBody = requestContent.substring(sign .length() + 2);; Pattern p=Pattern.compile("\""); Matcher m=p.matcher(requestBody); while(m.find()){ requestBody=requestBody.replace(m.group(), ""); } String request = new String(Base64.decodeFast(requestBody)); log.info("-----ChargeBillController------------解析完成后的requestBody-------{}" + request); ChargeBillRequest chargeBillRequest = JSON.parseObject(request, new TypeReference<ChargeBillRequest>() { }); if (chargeBillRequest==null){ log.error("支付回调解析失败:{}",requestContent); throw new ServiceException("支付回调解析失败"); } boolean isok = signatureAndVerification.read_cer_and_verify_sign(requestBody,sign); if (!isok){ throw new ServiceException("支付回调验签失败"); } Boolean dealBack = true; if (consumer!=null){ dealBack = consumer.apply(chargeBillRequest); } result.setResult(chargeBillRequest); result.setBack(createResponse(chargeBillRequest,dealBack)); }catch (Exception e){ log.error("解析报文发生异常",e); } return result; } } bankapi/src/main/java/com/taxi591/bankapi/service/SignatureAndVerification.java
New file @@ -0,0 +1,198 @@ package com.taxi591.bankapi.service; import com.taxi591.bankapi.BankProperties; import lombok.extern.slf4j.Slf4j; import org.apache.commons.codec.binary.Base64; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; import java.io.*; import java.security.KeyStore; import java.security.PrivateKey; import java.security.PublicKey; import java.security.Signature; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; /** * 验签和加签工具类 * @author yzz * */ @Component @Slf4j public class SignatureAndVerification { @Autowired BankProperties bankProperties; public static String getRequestBody(HttpServletRequest request) throws IOException { /** 读取httpbody内容 */ StringBuilder httpBody = new StringBuilder(); BufferedReader br = null; try { br = new BufferedReader(new InputStreamReader( request.getInputStream())); String line = null; while ((line = br.readLine()) != null) { httpBody.append(line); } } catch (IOException ex) { throw ex; } finally { if (br != null) { try { br.close(); } catch (IOException ex) { ex.printStackTrace(); } } } return httpBody.toString(); } /** * 加签名 * @param dataString * @return */ public String signWhithsha1withrsa(String dataString) { String signatureString = null; String filePath=bankProperties.getPfxPath(); try { KeyStore ks = KeyStore.getInstance("PKCS12"); FileInputStream fis = new FileInputStream(filePath); char[] nPassword = null; if ((bankProperties.getKeystorePassword() == null) || bankProperties.getKeystorePassword().trim().equals("")) { nPassword = null; } else { nPassword = bankProperties.getKeystorePassword().toCharArray(); } ks.load(fis, nPassword); fis.close(); Enumeration<String> enums = ks.aliases(); String keyAlias = null; if (enums.hasMoreElements()) { keyAlias = (String) enums.nextElement(); } System.out.println("is key entry=" + ks.isKeyEntry(keyAlias)); PrivateKey prikey = (PrivateKey) ks.getKey(keyAlias, nPassword); java.security.cert.Certificate cert = ks.getCertificate(keyAlias); // SHA1withRSA算法进行签名 Signature sign = Signature.getInstance("SHA1withRSA"); sign.initSign(prikey); byte[] data = dataString.getBytes("utf-8"); byte[] dataBase= Base64.encodeBase64(data); // 更新用于签名的数据 sign.update(dataBase); byte[] signature = sign.sign(); signatureString = new String(Base64.encodeBase64(signature)); System.out.println("加密完成,signature is : " + signatureString); } catch (Exception e) { e.printStackTrace(); } return signatureString; } /** * 读取cer并验证公钥签名 * @return */ public boolean read_cer_and_verify_sign(String requestBody, String signature) { String filePath=bankProperties.getCerPath(); X509Certificate cert = null; boolean flag = false; try { CertificateFactory cf = CertificateFactory.getInstance("X.509"); cert = (X509Certificate) cf .generateCertificate(new FileInputStream(new File( filePath))); PublicKey publicKey = cert.getPublicKey(); String publicKeyString = new String(Base64.encodeBase64(publicKey .getEncoded())); System.out.println("-----------------公钥--------------------"); System.out.println(publicKeyString); System.out.println("-----------------公钥--------------------"); Signature verifySign = Signature.getInstance("SHA1withRSA"); verifySign.initVerify(publicKey); // 用于验签的数据 verifySign.update(requestBody.getBytes("utf-8")); flag = verifySign.verify(Base64 .decodeBase64(signature)); } catch (Exception e) { log.error("验签失败,发生异常:{},{}",requestBody,signature,e); flag = false; } return flag; } /** * 接收报文返回requestBody和使用base64解析后的requestBody以及缴费中心传送的签名 */ public Map<String,String> requestBodyOfBase64(HttpServletRequest request){ Map<String,String> requestMap=new HashMap<String,String>(); // 接收报文 String requestContent=null; try { requestContent = getRequestBody(request) .trim(); } catch (IOException e) { e.printStackTrace(); } String signatureString = null; String requestBody = null; if (requestContent.contains("||")) { signatureString = requestContent.substring(0, requestContent.indexOf("||")); requestBody = requestContent.substring(signatureString .length() + 2); }else { try { requestBody = new String(requestContent.getBytes("GB2312")); log.info("转码后的报文:{}",requestBody); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } log.info("截取报文的requestBody解密前:{}", requestBody); String requestBodyOfDecoded = new String( Base64.decodeBase64(requestBody)); /*if (requestBodyOfDecoded.contains("</Message>")) { requestBody = requestBodyOfDecoded.substring( requestContent.indexOf("</Message>"),requestContent.indexOf("</Message>")+10); signatureString = requestBodyOfDecoded.substring( requestContent.indexOf("<Signature>")+11,requestContent.indexOf("</Signature>")); }*/ log.info("截取报文的signatureString:{}", signatureString); System.out.println("-----解析完成后的requestBody-------" + requestBodyOfDecoded); //使用base64解析完成后的requestBody requestMap.put("requestBodyOfDecoded",requestBodyOfDecoded); //解析前的requestBody requestMap.put("requestBody",requestBody); //获取缴费中心传送过来的签名 requestMap.put("signatureString",signatureString); return requestMap; } } bankapi/src/main/java/com/taxi591/bankapi/utils/Base64.java
New file @@ -0,0 +1,210 @@ package com.taxi591.bankapi.utils; import java.util.Arrays; /** * * @version 2.2 * @author Mikael Grev Date: 2004-aug-02 Time: 11:31:11 */ public class Base64 { public static final char[] CA = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray(); public static final int[] IA = new int[256]; static { Arrays.fill(IA, -1); for (int i = 0, iS = CA.length; i < iS; i++) IA[CA[i]] = i; IA['='] = 0; } /** * Decodes a BASE64 encoded char array that is known to be resonably well formatted. The method is about twice as * fast as #decode(char[]). The preconditions are:<br> * + The array must have a line length of 76 chars OR no line separators at all (one line).<br> * + Line separator must be "\r\n", as specified in RFC 2045 + The array must not contain illegal characters within * the encoded string<br> * + The array CAN have illegal characters at the beginning and end, those will be dealt with appropriately.<br> * * @param chars The source array. Length 0 will return an empty array. <code>null</code> will throw an exception. * @return The decoded array of bytes. May be of length 0. */ public static byte[] decodeFast(char[] chars, int offset, int charsLen) { // Check special case if (charsLen == 0) { return new byte[0]; } int sIx = offset, eIx = offset + charsLen - 1; // Start and end index after trimming. // Trim illegal chars from start while (sIx < eIx && IA[chars[sIx]] < 0) sIx++; // Trim illegal chars from end while (eIx > 0 && IA[chars[eIx]] < 0) eIx--; // get the padding count (=) (0, 1 or 2) int pad = chars[eIx] == '=' ? (chars[eIx - 1] == '=' ? 2 : 1) : 0; // Count '=' at end. int cCnt = eIx - sIx + 1; // Content count including possible separators int sepCnt = charsLen > 76 ? (chars[76] == '\r' ? cCnt / 78 : 0) << 1 : 0; int len = ((cCnt - sepCnt) * 6 >> 3) - pad; // The number of decoded bytes byte[] bytes = new byte[len]; // Preallocate byte[] of exact length // Decode all but the last 0 - 2 bytes. int d = 0; for (int cc = 0, eLen = (len / 3) * 3; d < eLen;) { // Assemble three bytes into an int from four "valid" characters. int i = IA[chars[sIx++]] << 18 | IA[chars[sIx++]] << 12 | IA[chars[sIx++]] << 6 | IA[chars[sIx++]]; // Add the bytes bytes[d++] = (byte) (i >> 16); bytes[d++] = (byte) (i >> 8); bytes[d++] = (byte) i; // If line separator, jump over it. if (sepCnt > 0 && ++cc == 19) { sIx += 2; cc = 0; } } if (d < len) { // Decode last 1-3 bytes (incl '=') into 1-3 bytes int i = 0; for (int j = 0; sIx <= eIx - pad; j++) i |= IA[chars[sIx++]] << (18 - j * 6); for (int r = 16; d < len; r -= 8) bytes[d++] = (byte) (i >> r); } return bytes; } public static byte[] decodeFast(String chars, int offset, int charsLen) { // Check special case if (charsLen == 0) { return new byte[0]; } int sIx = offset, eIx = offset + charsLen - 1; // Start and end index after trimming. // Trim illegal chars from start while (sIx < eIx && IA[chars.charAt(sIx)] < 0) sIx++; // Trim illegal chars from end while (eIx > 0 && IA[chars.charAt(eIx)] < 0) eIx--; // get the padding count (=) (0, 1 or 2) int pad = chars.charAt(eIx) == '=' ? (chars.charAt(eIx - 1) == '=' ? 2 : 1) : 0; // Count '=' at end. int cCnt = eIx - sIx + 1; // Content count including possible separators int sepCnt = charsLen > 76 ? (chars.charAt(76) == '\r' ? cCnt / 78 : 0) << 1 : 0; int len = ((cCnt - sepCnt) * 6 >> 3) - pad; // The number of decoded bytes byte[] bytes = new byte[len]; // Preallocate byte[] of exact length // Decode all but the last 0 - 2 bytes. int d = 0; for (int cc = 0, eLen = (len / 3) * 3; d < eLen;) { // Assemble three bytes into an int from four "valid" characters. int i = IA[chars.charAt(sIx++)] << 18 | IA[chars.charAt(sIx++)] << 12 | IA[chars.charAt(sIx++)] << 6 | IA[chars.charAt(sIx++)]; // Add the bytes bytes[d++] = (byte) (i >> 16); bytes[d++] = (byte) (i >> 8); bytes[d++] = (byte) i; // If line separator, jump over it. if (sepCnt > 0 && ++cc == 19) { sIx += 2; cc = 0; } } if (d < len) { // Decode last 1-3 bytes (incl '=') into 1-3 bytes int i = 0; for (int j = 0; sIx <= eIx - pad; j++) i |= IA[chars.charAt(sIx++)] << (18 - j * 6); for (int r = 16; d < len; r -= 8) bytes[d++] = (byte) (i >> r); } return bytes; } /** * Decodes a BASE64 encoded string that is known to be resonably well formatted. The method is about twice as fast * as decode(String). The preconditions are:<br> * + The array must have a line length of 76 chars OR no line separators at all (one line).<br> * + Line separator must be "\r\n", as specified in RFC 2045 + The array must not contain illegal characters within * the encoded string<br> * + The array CAN have illegal characters at the beginning and end, those will be dealt with appropriately.<br> * * @param s The source string. Length 0 will return an empty array. <code>null</code> will throw an exception. * @return The decoded array of bytes. May be of length 0. */ public static byte[] decodeFast(String s) { // Check special case int sLen = s.length(); if (sLen == 0) { return new byte[0]; } int sIx = 0, eIx = sLen - 1; // Start and end index after trimming. // Trim illegal chars from start while (sIx < eIx && IA[s.charAt(sIx) & 0xff] < 0) sIx++; // Trim illegal chars from end while (eIx > 0 && IA[s.charAt(eIx) & 0xff] < 0) eIx--; // get the padding count (=) (0, 1 or 2) int pad = s.charAt(eIx) == '=' ? (s.charAt(eIx - 1) == '=' ? 2 : 1) : 0; // Count '=' at end. int cCnt = eIx - sIx + 1; // Content count including possible separators int sepCnt = sLen > 76 ? (s.charAt(76) == '\r' ? cCnt / 78 : 0) << 1 : 0; int len = ((cCnt - sepCnt) * 6 >> 3) - pad; // The number of decoded bytes byte[] dArr = new byte[len]; // Preallocate byte[] of exact length // Decode all but the last 0 - 2 bytes. int d = 0; for (int cc = 0, eLen = (len / 3) * 3; d < eLen;) { // Assemble three bytes into an int from four "valid" characters. int i = IA[s.charAt(sIx++)] << 18 | IA[s.charAt(sIx++)] << 12 | IA[s.charAt(sIx++)] << 6 | IA[s.charAt(sIx++)]; // Add the bytes dArr[d++] = (byte) (i >> 16); dArr[d++] = (byte) (i >> 8); dArr[d++] = (byte) i; // If line separator, jump over it. if (sepCnt > 0 && ++cc == 19) { sIx += 2; cc = 0; } } if (d < len) { // Decode last 1-3 bytes (incl '=') into 1-3 bytes int i = 0; for (int j = 0; sIx <= eIx - pad; j++) i |= IA[s.charAt(sIx++)] << (18 - j * 6); for (int r = 16; d < len; r -= 8) dArr[d++] = (byte) (i >> r); } return dArr; } } bankapi/src/main/resources/META-INF/spring.factories
New file @@ -0,0 +1,2 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.taxi591.bankapi.BankConfig pom.xml
@@ -187,6 +187,7 @@ <module>ruoyi-generator</module> <module>ruoyi-common</module> <module>ruoyi-applet</module> <module>bankapi</module> </modules> <packaging>pom</packaging> ruoyi-admin/pom.xml
@@ -16,7 +16,11 @@ </description> <dependencies> <dependency> <groupId>org.taxi591</groupId> <artifactId>bankapi</artifactId> <version>1.0.0-SNAPSHOT</version> </dependency> <dependency> <groupId>com.aliyun.oss</groupId> <artifactId>aliyun-sdk-oss</artifactId> ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/BankOutController.java
New file @@ -0,0 +1,30 @@ package com.ruoyi.web.controller.api; import com.taxi591.bankapi.dto.CovertPayBackResult; import com.taxi591.bankapi.service.BankService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; @RestController @RequestMapping("out/bank") public class BankOutController { @Autowired BankService bankService; @PostMapping(value = "payCallback") public @ResponseBody String payCallback(HttpServletRequest request){ CovertPayBackResult result = bankService.covertPayCallBack(request, (billRequest) -> { return true; }); return result.getBack(); } } ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java
@@ -1,93 +1,10 @@ package com.ruoyi.common.utils.poi; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.math.BigDecimal; import java.text.DecimalFormat; import java.time.LocalDate; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.stream.Collectors; import javax.servlet.http.HttpServletResponse; import com.sun.rowset.internal.Row; import javafx.scene.control.Cell; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.RegExUtils; import org.apache.commons.lang3.reflect.FieldUtils; //import org.apache.poi.hssf.usermodel.HSSFClientAnchor; //import org.apache.poi.hssf.usermodel.HSSFPicture; //import org.apache.poi.hssf.usermodel.HSSFPictureData; //import org.apache.poi.hssf.usermodel.HSSFShape; //import org.apache.poi.hssf.usermodel.HSSFSheet; //import org.apache.poi.hssf.usermodel.HSSFWorkbook; //import org.apache.poi.ooxml.POIXMLDocumentPart; //import org.apache.poi.ss.usermodel.BorderStyle; //import org.apache.poi.ss.usermodel.Cell; //import org.apache.poi.ss.usermodel.CellStyle; //import org.apache.poi.ss.usermodel.CellType; //import org.apache.poi.ss.usermodel.ClientAnchor; //import org.apache.poi.ss.usermodel.DataValidation; //import org.apache.poi.ss.usermodel.DataValidationConstraint; //import org.apache.poi.ss.usermodel.DataValidationHelper; //import org.apache.poi.ss.usermodel.DateUtil; //import org.apache.poi.ss.usermodel.Drawing; //import org.apache.poi.ss.usermodel.FillPatternType; //import org.apache.poi.ss.usermodel.Font; //import org.apache.poi.ss.usermodel.HorizontalAlignment; //import org.apache.poi.ss.usermodel.IndexedColors; //import org.apache.poi.ss.usermodel.Name; //import org.apache.poi.ss.usermodel.PictureData; //import org.apache.poi.ss.usermodel.Row; //import org.apache.poi.ss.usermodel.Sheet; //import org.apache.poi.ss.usermodel.VerticalAlignment; //import org.apache.poi.ss.usermodel.Workbook; //import org.apache.poi.ss.usermodel.WorkbookFactory; //import org.apache.poi.ss.util.CellRangeAddress; //import org.apache.poi.ss.util.CellRangeAddressList; //import org.apache.poi.util.IOUtils; //import org.apache.poi.xssf.streaming.SXSSFWorkbook; //import org.apache.poi.xssf.usermodel.XSSFClientAnchor; //import org.apache.poi.xssf.usermodel.XSSFDataValidation; //import org.apache.poi.xssf.usermodel.XSSFDrawing; //import org.apache.poi.xssf.usermodel.XSSFPicture; //import org.apache.poi.xssf.usermodel.XSSFShape; //import org.apache.poi.xssf.usermodel.XSSFSheet; //import org.apache.poi.xssf.usermodel.XSSFWorkbook; //import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTMarker; import org.slf4j.Logger; import org.slf4j.LoggerFactory; //import com.ruoyi.common.annotation.Excel; //import com.ruoyi.common.annotation.Excel.ColumnType; //import com.ruoyi.common.annotation.Excel.Type; import com.ruoyi.common.annotation.Excels; import com.ruoyi.common.config.RuoYiConfig; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.text.Convert; import com.ruoyi.common.exception.UtilException; import com.ruoyi.common.utils.DateUtils; import com.ruoyi.common.utils.DictUtils; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.file.FileTypeUtils; import com.ruoyi.common.utils.file.FileUtils; import com.ruoyi.common.utils.file.ImageUtils; import com.ruoyi.common.utils.reflect.ReflectUtils; import java.util.HashMap; import java.util.Map; /** * Excel相关处理