lianshufeng 1 vuosi sitten
commit
47c0e73341

+ 33 - 0
paydemo/.gitignore

@@ -0,0 +1,33 @@
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/

+ 91 - 0
paydemo/pom.xml

@@ -0,0 +1,91 @@
+<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-starter-parent</artifactId>
+        <version>3.3.1</version>
+        <relativePath/> <!-- lookup parent from repository -->
+    </parent>
+    <groupId>com.github.sip.ws</groupId>
+    <artifactId>paydemo</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+    <name>paydemo</name>
+    <description>paydemo</description>
+    <url/>
+    <licenses>
+        <license/>
+    </licenses>
+    <developers>
+        <developer/>
+    </developers>
+    <scm>
+        <connection/>
+        <developerConnection/>
+        <tag/>
+        <url/>
+    </scm>
+    <properties>
+        <java.version>17</java.version>
+    </properties>
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <configuration>
+                    <excludes>
+                        <exclude>
+                            <groupId>org.projectlombok</groupId>
+                            <artifactId>lombok</artifactId>
+                        </exclude>
+                    </excludes>
+                </configuration>
+            </plugin>
+
+            <!-- 配置 Maven 编译插件 -->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>3.8.1</version>
+                <configuration>
+                    <source>1.8</source>
+                    <target>1.8</target>
+                    <!-- 设置编译源文件的编码 -->
+                    <encoding>GBK</encoding>
+                </configuration>
+            </plugin>
+
+            <!-- 配置 Maven 资源插件 -->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-resources-plugin</artifactId>
+                <version>3.2.0</version>
+                <configuration>
+                    <!-- 设置资源文件的编码 -->
+                    <encoding>GBK</encoding>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

+ 16 - 0
paydemo/src/main/java/com/zswl/paymentterminal/demo/PaydemoApplication.java

@@ -0,0 +1,16 @@
+package com.zswl.paymentterminal.demo;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.stereotype.Component;
+
+@ComponentScan("com.zswl.paymentterminal.demo.core")
+@SpringBootApplication
+public class PaydemoApplication {
+
+    public static void main(String[] args) {
+        SpringApplication.run(PaydemoApplication.class, args);
+    }
+
+}

+ 19 - 0
paydemo/src/main/java/com/zswl/paymentterminal/demo/core/config/WebConfig.java

@@ -0,0 +1,19 @@
+//package com.zswl.paymentterminal.demo.core.config;
+//
+//import com.zswl.paymentterminal.demo.core.interceptors.RequestLoggingInterceptor;
+//import org.springframework.beans.factory.annotation.Autowired;
+//import org.springframework.context.annotation.Configuration;
+//import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+//import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+//
+//@Configuration
+//public class WebConfig implements WebMvcConfigurer {
+//
+//    @Autowired
+//    private RequestLoggingInterceptor requestLoggingInterceptor;
+//
+//    @Override
+//    public void addInterceptors(InterceptorRegistry registry) {
+//        registry.addInterceptor(requestLoggingInterceptor);
+//    }
+//}

+ 145 - 0
paydemo/src/main/java/com/zswl/paymentterminal/demo/core/controller/hxz/PayV1Controller.java

@@ -0,0 +1,145 @@
+package com.zswl.paymentterminal.demo.core.controller.hxz;
+
+import ch.qos.logback.core.testUtil.RandomUtil;
+import com.zswl.paymentterminal.demo.core.model.ConsumTransactionsModel;
+import com.zswl.paymentterminal.demo.core.model.OrderQuery;
+import com.zswl.paymentterminal.demo.core.model.ServerTimeModel;
+import com.zswl.paymentterminal.demo.core.util.BytesUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.MediaType;
+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 java.text.SimpleDateFormat;
+import java.time.DayOfWeek;
+import java.time.LocalDate;
+import java.util.Date;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Random;
+
+@Slf4j
+@RestController
+@RequestMapping("hxz/v1")
+public class PayV1Controller {
+
+
+    /**
+     * 同步时间服务
+     */
+    @PostMapping(value = "ServerTime", consumes = MediaType.APPLICATION_JSON_VALUE)
+    public Object serverTime(@RequestBody ServerTimeModel serverTimeModel) {
+        var nowTime = new Date(System.currentTimeMillis());
+        LocalDate date = LocalDate.now();
+        int week = Map.of(DayOfWeek.MONDAY, 1, DayOfWeek.TUESDAY, 2, DayOfWeek.WEDNESDAY, 3, DayOfWeek.THURSDAY, 4, DayOfWeek.FRIDAY, 5, DayOfWeek.SATURDAY, 6, DayOfWeek.SUNDAY, 0).get(date.getDayOfWeek());
+        var ret = new LinkedHashMap() {{
+            put("Status", 1);
+            put("Msg", "");
+            put("Time", new SimpleDateFormat("yyyyMMddHHmmss").format(nowTime) + "" + week);
+            put("WLUptate", 0);
+            put("WLPage", 0);
+        }};
+        log.info("ServerTime : {} - {}", serverTimeModel, ret);
+        return ret;
+    }
+
+    /**
+     * 用户刷卡综合接口
+     */
+    @PostMapping(value = "ConsumTransactions", consumes = MediaType.APPLICATION_JSON_VALUE)
+    public Object consumTransactions(@RequestBody ConsumTransactionsModel consumTransactionsModel) {
+        //十进制转16进制
+        final String cardNumber = toCardNumber(Long.parseLong(String.valueOf(consumTransactionsModel.getCardNo())));
+        final String amount = consumTransactionsModel.getAmount();
+
+        //查询卡(钱包)
+        if (consumTransactionsModel.getMode() == 2) {
+            return new LinkedHashMap() {{
+                put("Status", 1);
+                put("Msg", 1);
+                put("Name", "测试用户");
+                put("CardNo", consumTransactionsModel.getCardNo());
+                put("Money", "0"); // 现金金额
+                put("Subsidy", "0.0"); // 补贴金额
+                put("Times", "");
+                put("Integral", "");
+                put("InTime", "");
+                put("OutTime", "");
+                put("CumulativeTime", "");
+                put("Amount", amount);
+                put("VoiceID", "");
+                put("Text", "");
+            }};
+        }
+
+        //刷卡消费
+        log.info("consumTransactions : {} - {} - {}", consumTransactionsModel.getOrder(), cardNumber, amount);
+        var ret = new LinkedHashMap() {{
+            put("Status", 1);
+            put("Msg", 1);
+            put("Name", "测试用户");
+            put("CardNo", consumTransactionsModel.getCardNo());
+            put("Money", amount); // 现金金额
+            put("Subsidy", "0.0"); // 补贴金额
+            put("Times", "");
+
+            put("Integral", "");
+            put("InTime", "");
+            put("OutTime", "");
+            put("CumulativeTime", "");
+            put("Amount", amount);
+            put("VoiceID", "");
+            put("Text", "");
+        }};
+        log.info("ConsumTransactions : {} - {}", consumTransactionsModel, ret);
+        return ret;
+    }
+
+
+    /**
+     * 补偿查询
+     */
+    @PostMapping(value = "orderQuery", consumes = MediaType.APPLICATION_JSON_VALUE)
+    public Object orderQuery(@RequestBody OrderQuery orderQuery) {
+        //十进制转16进制
+        final String cardNumber = toCardNumber(Long.parseLong(String.valueOf(orderQuery.getCardNo())));
+        //刷卡消费
+        log.info("orderQuery {} - {}:", orderQuery.getOrder(), cardNumber);
+        var amount = "99.99";
+        var ret = new LinkedHashMap() {{
+            put("Status", 1);
+            put("Msg", 1);
+            put("Name", "测试用户");
+            put("CardNo", orderQuery.getCardMode());
+            put("Money", amount); // 现金金额
+            put("Subsidy", "0.0"); // 补贴金额
+            put("Times", "");
+
+            put("Integral", "");
+            put("InTime", "");
+            put("OutTime", "");
+            put("CumulativeTime", "");
+            put("Amount", amount);
+            put("VoiceID", "");
+            put("Text", "");
+        }};
+        return ret;
+    }
+
+
+    /**
+     * 转换为卡号
+     *
+     * @param cardNo
+     * @return
+     */
+    private static String toCardNumber(long cardNo) {
+        byte[] bins = BytesUtil.longToBin(cardNo, 4);
+        var ret = BytesUtil.reverse(bins);
+        return BytesUtil.binToHex(ret);
+    }
+
+
+}

+ 22 - 0
paydemo/src/main/java/com/zswl/paymentterminal/demo/core/interceptors/RequestLoggingInterceptor.java

@@ -0,0 +1,22 @@
+//package com.zswl.paymentterminal.demo.core.interceptors;
+//
+//
+//import jakarta.servlet.http.HttpServletRequest;
+//import jakarta.servlet.http.HttpServletResponse;
+//import lombok.extern.slf4j.Slf4j;
+//import org.springframework.stereotype.Component;
+//import org.springframework.web.servlet.HandlerInterceptor;
+//
+//@Slf4j
+//@Component
+//public class RequestLoggingInterceptor implements HandlerInterceptor {
+//    @Override
+//    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
+////        log.info("parameterMap {}", request.getParameterMap());
+//        // 打印请求参数
+//        request.getParameterMap().forEach((key, value) -> {
+//            System.out.println("Parameter: " + key + ", Value: " + value);
+//        });
+//        return true;
+//    }
+//}

+ 42 - 0
paydemo/src/main/java/com/zswl/paymentterminal/demo/core/model/ConsumTransactionsModel.java

@@ -0,0 +1,42 @@
+package com.zswl.paymentterminal.demo.core.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class ConsumTransactionsModel {
+
+    @JsonProperty("Order")
+    private String order;
+
+    @JsonProperty("CardNo")
+    private String cardNo;
+
+    @JsonProperty("CardMode")
+    private Integer cardMode;
+
+    @JsonProperty("Mode")
+    private Integer mode;
+
+    @JsonProperty("PayType")
+    private Integer payType;
+
+    @JsonProperty("Amount")
+    private String amount;
+
+    @JsonProperty("Menus")
+    private Menus[] menus;
+
+    public static class Menus {
+        @JsonProperty("MenuID")
+        private String menuID;
+
+        @JsonProperty("Count")
+        private String count;
+    }
+}
+

+ 21 - 0
paydemo/src/main/java/com/zswl/paymentterminal/demo/core/model/OrderQuery.java

@@ -0,0 +1,21 @@
+package com.zswl.paymentterminal.demo.core.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class OrderQuery {
+
+    @JsonProperty("Order")
+    private String order;
+
+    @JsonProperty("CardNo")
+    private String cardNo;
+
+    @JsonProperty("CardMode")
+    private Integer cardMode;
+}

+ 20 - 0
paydemo/src/main/java/com/zswl/paymentterminal/demo/core/model/ServerTimeModel.java

@@ -0,0 +1,20 @@
+package com.zswl.paymentterminal.demo.core.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class ServerTimeModel {
+
+    //设备中的总白名单数
+    @JsonProperty("WLSum")
+    private Integer wLSum;
+
+    //机号
+    @JsonProperty("DeviceID")
+    private Integer deviceID;
+}

+ 349 - 0
paydemo/src/main/java/com/zswl/paymentterminal/demo/core/util/BytesUtil.java

@@ -0,0 +1,349 @@
+package com.zswl.paymentterminal.demo.core.util;
+
+import lombok.SneakyThrows;
+
+import java.io.*;
+import java.util.ArrayList;
+import java.util.Collections;
+
+/**
+ * @功能:字节集工具类
+ * @作者:练书锋
+ * @创建日期 : 2013-8-29
+ */
+public class BytesUtil {
+
+    /**
+     * 填充算法,将字节集填充到8的整数倍
+     *
+     * @param bin
+     * @return
+     * @throws IOException
+     */
+    public static byte[] fillCode(byte[] bin) throws IOException {
+        ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream();
+        int n = (bin.length + 10) % 8;
+        if (n != 0) {
+            n = 8 - n;
+        }
+        // 将随即码改为数据完整度的校验
+        int r = 0;
+        for (int i = 0; i < bin.length; i++) {
+            r = (r + (bin[i] & 0xFF)) % 256;
+        }
+        int first = (r & 248) | n;
+        arrayOutputStream.write(first);
+        arrayOutputStream.write(r);
+        arrayOutputStream.write(bin);
+        for (int i = 0; i < n; i++) {
+            arrayOutputStream.write(r);
+        }
+        byte[] result = arrayOutputStream.toByteArray();
+        arrayOutputStream.close();
+        return result;
+    }
+
+    /**
+     * 将填充算法的数据还原
+     *
+     * @param bin
+     * @return
+     * @throws IOException
+     */
+    public static byte[] unFillCode(byte[] bin) throws IOException {
+        ByteArrayInputStream arrayInputStream = new ByteArrayInputStream(bin);
+        int first = arrayInputStream.read();// 第一位
+        // 校验码
+        int r = arrayInputStream.read();// 第二位
+        int n = (r & 248) ^ first;
+        if (n < 0 || n > 14 || arrayInputStream.available() < n) {
+            return null;// 长度不正确,解密失败
+        }
+        byte[] result = new byte[arrayInputStream.available() - n];
+        arrayInputStream.read(result);
+        arrayInputStream.close();
+        int d = 0;
+        for (int i = 0; i < result.length; i++) {
+            d = (d + (result[i] & 0xFF)) % 256;
+        }
+        return d == r ? result : null;
+    }
+
+    /**
+     * 倒找字节集
+     *
+     * @param bin
+     * @param queryBin
+     * @return
+     */
+    public static int findLast(byte[] bin, byte[] queryBin) {
+        int total = bin.length - queryBin.length + 1;
+        for (int i = 0; i < total; i++) {
+            int lastIndex = total - i - 1;
+            byte[] target = subBytes(bin, lastIndex, queryBin.length + lastIndex);
+            if (isEquery(target, queryBin)) {
+                return lastIndex;
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * 从一个字节中查询出现的字节
+     *
+     * @param bin
+     * @param queryBin
+     * @return
+     */
+    public static int find(byte[] bin, byte[] queryBin) {
+        for (int i = 0; i < bin.length - queryBin.length + 1; i++) {
+            byte[] target = subBytes(bin, i, queryBin.length + i);
+            if (isEquery(target, queryBin)) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * 两个字节集数组是否相等
+     *
+     * @param bin1
+     * @param bin2
+     * @return
+     */
+    public static boolean isEquery(byte[] bin1, byte[] bin2) {
+        for (int i = 0; i < bin1.length; i++) {
+            if (bin1[i] != bin2[i]) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * 取字节集中间
+     *
+     * @param bin
+     * @param start
+     * @param end
+     * @return
+     */
+    public static byte[] subBytes(final byte[] bin, final int start, final int end) {
+        if (start == 0 && end == bin.length) {
+            return bin;
+        }
+        byte[] result = new byte[end - start];
+        System.arraycopy(bin, start, result, 0, result.length);
+        return result;
+    }
+
+    /**
+     * 将字节集转换为long类
+     *
+     * @param b
+     * @return
+     */
+    public static long binToLong(byte[] b) {
+        long l = 0;
+        for (int i = 0; i < b.length; i++) {
+            long j_tmp = 1;
+            for (int j = 0; j < b.length - i - 1; j++) {
+                j_tmp <<= 8;
+            }
+            l += j_tmp * (b[i] & 0xFF);
+        }
+        return l;
+    }
+
+    /**
+     * 将字节集转换为int类型
+     *
+     * @param b
+     * @return
+     */
+    public static int binToInt(byte[] b) {
+        return (int) binToLong(b);
+    }
+
+    /**
+     * 将字节集转换为short类型
+     *
+     * @param b
+     * @return
+     */
+    public static short binToShort(byte[] b) {
+        return (short) binToLong(b);
+    }
+
+    /**
+     * 将long类转字节集
+     *
+     * @param l
+     * @param size 保证长度
+     * @return
+     * @throws IOException
+     */
+    @SneakyThrows
+    public static byte[] longToBin(long l, int size) {
+        byte[] result = new byte[size];
+        for (int i = 0; i < size; i++) {
+            result[i] = (byte) ((l >> ((size - 1 - i) << 3)) & 0xFF);
+        }
+        return result;
+    }
+
+    /**
+     * 将int类转字节集
+     *
+     * @param
+     * @return
+     * @throws IOException
+     * @throws NumberFormatException
+     */
+    public static byte[] intToBin(int i, int size) throws IOException {
+        return longToBin(i, size);
+    }
+
+    /**
+     * 将short类型转换为字节集
+     *
+     * @param i
+     * @param size
+     * @return
+     * @throws IOException
+     */
+    public static byte[] shortToBin(short i, int size) throws IOException {
+        return longToBin(i, size);
+    }
+
+    /**
+     * 将字节集转换为16进制
+     *
+     * @param bin
+     * @return
+     */
+    public static String binToHex(byte[] bin) {
+        return binToHex(bin, false);
+    }
+
+    /**
+     * 将字节集转换16进制
+     *
+     * @param bin
+     * @param format 格式化显示
+     * @return
+     */
+    public static String binToHex(byte[] bin, boolean format) {
+        StringBuffer stringBuffer = new StringBuffer();
+        for (byte b : bin) {
+            int i = (int) b;
+            if (i < 0) {
+                i = i + 256;
+            }
+            String hex = Integer.toHexString(i);
+            while (hex.length() < 2) {
+                hex = "0" + hex;
+            }
+            stringBuffer.append(hex);
+            if (format) {
+                stringBuffer.append(" ");
+            }
+        }
+        return stringBuffer.toString();
+    }
+
+    /**
+     * 十六进制转换为字节集
+     *
+     * @param
+     * @return
+     * @throws IOException
+     */
+    public static byte[] hexToBin(String str) throws IOException {
+        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+        String hex = str;
+        if (hex.length() % 2 != 0)
+            hex = "0" + hex;
+        for (int i = 0; i < hex.length() / 2; i++) {
+            int point = i * 2;
+            byteArrayOutputStream.write(Integer.parseInt(hex.substring(point, point + 2), 16));
+        }
+        byteArrayOutputStream.flush();
+        byte[] bin = byteArrayOutputStream.toByteArray();
+        byteArrayOutputStream.close();
+        return bin;
+    }
+
+
+    public static byte[] reverse(byte[] bin) {
+        var items = new ArrayList<Byte>();
+        for (var b : bin) {
+            items.add(b);
+        }
+        Collections.reverse(items);
+        byte[] ret = new byte[items.size()];
+        for (int i = 0; i < items.size(); i++) {
+            ret[i] = items.get(i);
+        }
+        return ret;
+    }
+
+
+    /**
+     * 合并两个字节集
+     *
+     * @param bin1
+     * @param
+     * @return
+     * @throws IOException
+     */
+    public static byte[] merge(byte[] bin1, byte[]... bins) throws IOException {
+        ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream();
+        arrayOutputStream.write(bin1);
+        for (byte[] bin : bins) {
+            arrayOutputStream.write(bin);
+        }
+        arrayOutputStream.flush();
+        byte[] bin = arrayOutputStream.toByteArray();
+        arrayOutputStream.close();
+        return bin;
+    }
+
+    /**
+     * 对象到字节集
+     *
+     * @param
+     * @return
+     * @throws IOException
+     */
+    public static byte[] objectToBytes(Object object) throws IOException {
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        ObjectOutputStream oos = new ObjectOutputStream(out);
+        oos.writeObject(object);
+        oos.flush();
+        byte[] bin = out.toByteArray();
+        oos.close();
+        out.close();
+        return bin;
+    }
+
+    /**
+     * 字节集到对象
+     *
+     * @param buffer
+     * @return
+     * @throws IOException
+     * @throws ClassNotFoundException
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T bytesToObject(byte[] buffer) throws IOException, ClassNotFoundException {
+        ByteArrayInputStream in = new ByteArrayInputStream(buffer);
+        ObjectInputStream inputStream = new ObjectInputStream(in);
+        Object o = inputStream.readObject();
+        inputStream.close();
+        in.close();
+        return (T) o;
+    }
+
+}

+ 10 - 0
paydemo/src/main/resources/application.yml

@@ -0,0 +1,10 @@
+spring:
+  application:
+    name: paydemo
+
+server:
+  port: 9090
+
+logging:
+  level:
+    org.springframework.web.servlet.DispatcherServlet: DEBUG