liujie
2 天以前 3ea64cac3a5fe42c4eba0e54cad64d496093ba82
拉卡拉支付
6个文件已修改
1 文件已重命名
370 ■■■■■ 已修改文件
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/TErpSupplierWarehousingController.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/TSysOrderController.java 300 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/core/config/LakalaConfig.java 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/resources/application-test.yml 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/TErpProcurementService.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TErpProcurementServiceImpl.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/TErpSupplierWarehousingController.java
@@ -8,7 +8,6 @@
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.framework.web.service.TokenService;
import com.ruoyi.system.dto.InventoryDto;
import com.ruoyi.system.dto.InventoryGoodsDto;
import com.ruoyi.system.dto.OutboundGoodsDto;
import com.ruoyi.system.dto.WarehousingGoodsDto;
import com.ruoyi.system.model.TCrmClinic;
@@ -19,10 +18,9 @@
import com.ruoyi.system.service.TErpGoodsService;
import com.ruoyi.system.service.TErpSupplierWarehousingService;
import com.ruoyi.system.vo.*;
import com.ruoyi.web.core.config.LakalaAlipayConfig;
import com.ruoyi.web.core.config.LakalaConfig;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@@ -67,9 +65,9 @@
    @PostMapping(value = "/pageList")
    public R<PageInfo<TErpGoodsVO>> pageList(@RequestBody TErpGoodsQuery query) {
        V3LabsTransPreorderRequest request = new V3LabsTransPreorderRequest();
        request.setLklAppId(LakalaAlipayConfig.appId);
        request.setMerchantNo(LakalaAlipayConfig.MerchantNo);
        request.setTermNo(LakalaAlipayConfig.TermNo);
        request.setLklAppId(LakalaConfig.appId);
        request.setMerchantNo(LakalaConfig.MerchantNo);
        request.setTermNo(LakalaConfig.TermNo);
        SysUser user = tokenService.getLoginUser().getUser();
        Integer roleType = user.getRoleType();
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/TSysOrderController.java
@@ -1,8 +1,44 @@
package com.ruoyi.web.controller.api;
import com.alibaba.fastjson.JSONObject;
import com.lkl.laop.sdk.exception.SDKException;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.framework.web.service.TokenService;
import com.ruoyi.system.query.TErpGoodsWarehouseQuery;
import com.ruoyi.system.service.*;
import com.ruoyi.web.core.config.LakalaConfig;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.SneakyThrows;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.cert.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
/**
 * <p>
@@ -14,7 +50,271 @@
 */
@RestController
@RequestMapping("/t-sys-order")
@Api(tags = "订单管理")
public class TSysOrderController {
    private final TErpProcurementService erpProcurementService;
    private final TokenService tokenService;
    @Autowired
    public TSysOrderController(TErpProcurementService erpProcurementService, TokenService tokenService) {
        this.erpProcurementService = erpProcurementService;
        this.tokenService = tokenService;
    }
    private static final String SYMBOLS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    /**
     * API schema ,固定 LKLAPI-SHA256withRSA
     */
    public final static String SCHEMA = "LKLAPI-SHA256withRSA";
    /**
     * 字符集固定 utf-8
     */
    public static final String ENCODING = "utf-8";
    private static final SecureRandom RANDOM = new SecureRandom();
    @ApiOperation(value = "支付")
    @PostMapping(value = "/payOrder")
    @SneakyThrows
    public R<?> payOrder(@RequestBody @Valid TErpGoodsWarehouseQuery query, HttpServletRequest request) {
        SysUser user = tokenService.getLoginUser().getUser();
        try {
            // 查出采购单 算出价格  下单  算出应该分佣金额 应该分给谁
            String apiPath = "/api/v3/labs/trans/preorder";
            String body = "{\n" +
                    "\t\"req_time\": \"20250915115329\",\n" +
                    "\t\"version\": \"3.0\",\n" +
                    "\t\"req_data\": {\n" +
                    "\t\t\"out_trade_no\": \"c13c493182e1ee84\",\n" +
                    "\t\t\"merchant_no\": \"822290059430BFA\",\n" +
                    "\t\t\"term_no\": \"D9261078\",\n" +
                    "\t\t\"notify_url\": \"http://221.182.45.100:8089/t-sys-order/messageHandle\",\n" +
                    "\t\t\"location_info\": {\n" +
                    "\t\t\t\"request_ip\": \"180.157.249.160\"\n" +
                    "\t\t},\n" +
                    "\t\t\"subject\": \"cc测试\",\n" +
                    "\t\t\"total_amount\": 1,\n" +
                    "\t\t\"account_type\": \"ALIPAY\",\n" +
                    "\t\t\"trans_type\": \"41\"\n" +
                    "\t}\n" +
                    "}";
            String authorization = getAuthorization(body);
            org.apache.http.HttpResponse response = post(LakalaConfig.getServerUrl() + apiPath, body, authorization);
            if (response.getStatusLine().getStatusCode() != 200) {
                return R.fail(500, "请求失败,statusCode  " + response.getStatusLine()
                        + IOUtils.toString(response.getEntity().getContent(), ENCODING));
            }
            String responseStr = IOUtils.toString(response.getEntity().getContent(), ENCODING);
            return R.ok(responseStr);
        } catch (SDKException e) {
            e.printStackTrace();
        }
        return R.fail(500, "调用支付宝支付预下单接口错误");
    }
    @RequestMapping("/messageHandle")
    @ApiOperation(value = "拉卡拉支付信息回调接口")
    public Object messageHandle(HttpServletRequest request) throws Exception {
        String body = this.getBody(request);
        String authorization = request.getHeader("Authorization");
        String timestamp = null;
        String nonce = null;
        String signature = null;
        authorization = authorization.replaceAll("LKLAPI-SHA256withRSA ", "");
        String[] split = authorization.split(",");
        for (String s : split) {
            if (s.startsWith("timestamp")) {
                timestamp = s.split("=")[1].replaceAll("\"", "");
            }
            if (s.startsWith("nonce")) {
                nonce = s.split("=")[1].replaceAll("\"", "");
            }
            if (s.startsWith("signature")) {
                // 取出签名
                signature = s.split("signature=")[1].replaceAll("\"", "");
            }
        }
        X509Certificate lklCertificate = loadCertificate(new FileInputStream(new File(LakalaConfig.getLklNotifyCerStr())));
        String preSignData = timestamp + "\n" + nonce + "\n" + body + "\n";
        boolean verify = verify(lklCertificate, preSignData.getBytes(ENCODING), signature);
        if (verify) {
            // 先处理支付完成  修改状态 后处理分账  后走分账回调
            // 响应success
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("code", "SUCCESS");
            jsonObject.put("message", "执行成功");
            return jsonObject;
        }
        return null;
    }
    public org.apache.http.HttpResponse post(String url, String message, String authorization) throws Exception {
        SSLContext ctx = SSLContext.getInstance("TLS");
        X509TrustManager tm = new X509TrustManager() {
            public X509Certificate[] getAcceptedIssuers() {
                return null;
            }
            public void checkClientTrusted(X509Certificate[] xcs, String str) {
            }
            public void checkServerTrusted(X509Certificate[] xcs, String str) {
            }
        };
        HttpClient http = new DefaultHttpClient();
        ClientConnectionManager ccm = http.getConnectionManager();
        ctx.init(null, new TrustManager[]{tm}, null);
        SSLSocketFactory ssf = new SSLSocketFactory(ctx);
        ssf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
        SchemeRegistry registry = ccm.getSchemeRegistry();
        registry.register(new Scheme("https", ssf, 443));
        HttpPost post = new HttpPost(url);
        StringEntity myEntity = new StringEntity(message, ENCODING);
        post.setEntity(myEntity);
        post.setHeader("Authorization", SCHEMA + " " + authorization);
        post.setHeader("Accept", "application/json");
        post.setHeader("Content-Type", "application/json");
        return http.execute(post);
    }
    public final String getAuthorization(String body) throws IOException {
        String nonceStr = generateNonceStr();
        long timestamp = generateTimestamp();
        String message = LakalaConfig.getAppId() + "\n" + LakalaConfig.getMerchantNo() + "\n" + timestamp + "\n" + nonceStr + "\n" + body + "\n";
        System.out.println("getToken message :  " + message);
        PrivateKey merchantPrivateKey = loadPrivateKey(new FileInputStream(new File(LakalaConfig.getPriKeyStr())));
        String signature = this.sign(message.getBytes(ENCODING), merchantPrivateKey);
        String authorization = "appid=\"" + LakalaConfig.getAppId() + "\"," + "serial_no=\"" + LakalaConfig.getMerchantNo() + "\"," + "timestamp=\""
                + timestamp + "\"," + "nonce_str=\"" + nonceStr + "\"," + "signature=\"" + signature + "\"";
        System.out.println("authorization message :" + authorization);
        return authorization;
    }
    public long generateTimestamp() {
        return System.currentTimeMillis() / 1000;
    }
    public String generateNonceStr() {
        char[] nonceChars = new char[32];
        for (int index = 0; index < nonceChars.length; ++index) {
            nonceChars[index] = SYMBOLS.charAt(RANDOM.nextInt(SYMBOLS.length()));
        }
        return new String(nonceChars);
    }
    public static PrivateKey loadPrivateKey(InputStream inputStream) {
        try {
            ByteArrayOutputStream array = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int length;
            while ((length = inputStream.read(buffer)) != -1) {
                array.write(buffer, 0, length);
            }
            String privateKey = array.toString("utf-8").replace("-----BEGIN PRIVATE KEY-----", "")
                    .replace("-----END PRIVATE KEY-----", "").replaceAll("\\s+", "");
            KeyFactory kf = KeyFactory.getInstance("RSA");
            return kf.generatePrivate(new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey)));
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("当前Java环境不支持RSA", e);
        } catch (InvalidKeySpecException e) {
            throw new RuntimeException("无效的密钥格式");
        } catch (IOException e) {
            throw new RuntimeException("无效的密钥");
        }
    }
    public String sign(byte[] message, PrivateKey privateKey) {
        try {
            Signature sign = Signature.getInstance("SHA256withRSA");
            sign.initSign(privateKey);
            sign.update(message);
            return new String(Base64.encodeBase64(sign.sign()));
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("当前Java环境不支持SHA256withRSA", e);
        } catch (SignatureException e) {
            throw new RuntimeException("签名计算失败", e);
        } catch (InvalidKeyException e) {
            throw new RuntimeException("无效的私钥", e);
        }
    }
    public final String getBody(HttpServletRequest request) {
        InputStreamReader in = null;
        try {
            in = new InputStreamReader(request.getInputStream(), StandardCharsets.UTF_8);
            StringBuffer bf = new StringBuffer();
            int len;
            char[] chs = new char[1024];
            while ((len = in.read(chs)) != -1) {
                bf.append(new String(chs, 0, len));
            }
            return bf.toString();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (null != in) {
                try {
                    in.close();
                } catch (Exception e) {
                }
            }
        }
        return null;
    }
    public static X509Certificate loadCertificate(InputStream inputStream) {
        try {
            CertificateFactory cf = CertificateFactory.getInstance("X509");
            X509Certificate cert = (X509Certificate) cf.generateCertificate(inputStream);
            cert.checkValidity();
            return cert;
        } catch (CertificateExpiredException e) {
            throw new RuntimeException("证书已过期", e);
        } catch (CertificateNotYetValidException e) {
            throw new RuntimeException("证书尚未生效", e);
        } catch (CertificateException e) {
            throw new RuntimeException("无效的证书", e);
        }
    }
    private static boolean verify(X509Certificate certificate, byte[] message, String signature) {
        try {
            Signature sign = Signature.getInstance("SHA256withRSA");
            sign.initVerify(certificate);
            sign.update(message);
            byte[] signatureB = Base64.decodeBase64(signature);
            return sign.verify(signatureB);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("当前Java环境不支持SHA256withRSA", e);
        } catch (SignatureException e) {
            throw new RuntimeException("签名验证过程发生了错误", e);
        } catch (InvalidKeyException e) {
            throw new RuntimeException("无效的证书", e);
        }
    }
}
ruoyi-admin/src/main/java/com/ruoyi/web/core/config/LakalaConfig.java
File was renamed from ruoyi-admin/src/main/java/com/ruoyi/web/core/config/LakalaAlipayConfig.java
@@ -8,7 +8,7 @@
@Component
@ConfigurationProperties(prefix = "lakala")
public class LakalaAlipayConfig {
public class LakalaConfig {
 
    public static  String MerchantNo;
 
@@ -78,7 +78,7 @@
    }
 
    public  void setAppId(String appId) {
        LakalaAlipayConfig.appId = appId;
        LakalaConfig.appId = appId;
    }
 
    public static String getSubAppId() {
@@ -86,14 +86,14 @@
    }
 
    public void setSubAppId(String subAppId) {
        LakalaAlipayConfig.subAppId = subAppId;
        LakalaConfig.subAppId = subAppId;
    }
    public static String getSerialNo() {
        return serialNo;
    }
 
    public  void setSerialNo(String serialNo) {
        LakalaAlipayConfig.serialNo = serialNo;
        LakalaConfig.serialNo = serialNo;
    }
 
    public static String getPriKeyStr() {
@@ -101,7 +101,7 @@
    }
 
    public  void setPriKeyStr(String priKeyStr) {
        LakalaAlipayConfig.priKeyStr = priKeyStr;
        LakalaConfig.priKeyStr = priKeyStr;
    }
 
    public static String getLklCerStr() {
@@ -109,7 +109,7 @@
    }
 
    public  void setLklCerStr(String lklCerStr) {
        LakalaAlipayConfig.lklCerStr = lklCerStr;
        LakalaConfig.lklCerStr = lklCerStr;
    }
 
    public static String getLklNotifyCerStr() {
@@ -117,7 +117,7 @@
    }
 
    public  void setLklNotifyCerStr(String lklNotifyCerStr) {
        LakalaAlipayConfig.lklNotifyCerStr = lklNotifyCerStr;
        LakalaConfig.lklNotifyCerStr = lklNotifyCerStr;
    }
 
    public static String getSm4Key() {
@@ -125,7 +125,7 @@
    }
 
    public  void setSm4Key(String sm4Key) {
        LakalaAlipayConfig.sm4Key = sm4Key;
        LakalaConfig.sm4Key = sm4Key;
    }
 
    public static String getServerUrl() {
@@ -133,7 +133,7 @@
    }
 
    public  void setServerUrl(String serverUrl) {
        LakalaAlipayConfig.serverUrl = serverUrl;
        LakalaConfig.serverUrl = serverUrl;
    }
 
    private static volatile boolean init = false;
ruoyi-admin/src/main/resources/application-test.yml
@@ -205,14 +205,13 @@
    accessKeySecret: wAGHKUEBrrTgDcbfjnBKTEt5858Ru5
    signName: "海诊通"
lakala:
  MerchantNo: 1
  TermNo: 1
  MerchantNo: 822290059430BFA
  TermNo: D9261078
  NotifyUrl: 1
  subAppId: 1
  appId: 1
  serialNo: 1
  priKeyStr: 1
  lklCerStr: 1
  lklNotifyCerStr: 1
  sm4Key: 1
  serverUrl: 1
  appId: OP00000003
  serialNo: 00dfba8194c41b84cf
  priKeyStr: C:\Users\Admin\Desktop\test\OP00000003_private_key.pem
  lklNotifyCerStr: C:\Users\Admin\Desktop\test\lkl-apigw-v2.cer
  sm4Key: LHo55AjrT4aDhAIBZhb5KQ==
  serverUrl: https://test.wsmsd.cn/
ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java
@@ -124,6 +124,7 @@
                // 静态资源,可匿名访问
                .antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll()
                .antMatchers("/swagger-ui.html","/doc.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll()
                .antMatchers("/t-sys-order/**").permitAll()
                // 除上面外的所有请求全部需要鉴权认证
                .anyRequest().authenticated()
                .and()
ruoyi-system/src/main/java/com/ruoyi/system/service/TErpProcurementService.java
@@ -24,4 +24,6 @@
    TErpProcurementDetailVo detail(String id, SysUser user, String goodsName);
}
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TErpProcurementServiceImpl.java
@@ -14,10 +14,29 @@
import com.ruoyi.system.vo.TErpProcurementDetailVo;
import com.ruoyi.system.vo.TErpProcurementVo;
import com.ruoyi.system.vo.ValidityPeriodWarningVo;
import lombok.SneakyThrows;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@@ -47,6 +66,8 @@
    @Resource
    private SysUserMapper sysUserMapper;
    @Override
    public PageInfo<TErpProcurementVo> pageList(TErpProcurementQuery query, SysUser user) {
@@ -184,4 +205,5 @@
        tErpProcurementVo.setList(tErpProcurementDetailNextVos);
        return tErpProcurementVo;
    }
}