招商资讯 > 资讯详情

测试112

2026-08-23 15:10:43
资源下载
付费资源
资源价格0.1金币
普通用户0.1金币
VIP会员0.1金币
永久VIP0.1金币
累计销量
1
包含资源
1
最近更新
2026-08-23
当前购买价:0.1金币

这是一个停车场系统与会员积分系统对接的后端参考代码(Spring Boot + Java),核心场景是:车辆出场时,调用积分系统进行积分抵扣停车费,同时消费后赠送积分

这套代码可以直接复制到CSDN发布,结构清晰,包含完整的模拟积分系统客户端,无需真实依赖即可运行演示。


📌 业务场景描述

1. 车辆入场 → 记录入场时间,查询会员信息
2. 车辆出场 → 计算停车费 → 查询积分余额
3. 若用户选择积分抵扣 → 按比例扣除积分 → 减免相应金额
4. 实付金额结算 → 支付完成后 → 赠送消费积分
5. 记录完整的积分流水台账

🧱 技术架构

| 层级 | 技术 | 说明 |

|------|------|------|

| 框架 | Spring Boot 2.7+ | 基础框架 |

| 数据库 | MySQL / 模拟内存 | 可用List模拟 |

| 远程调用 | RestTemplate / 模拟Client | 对接积分系统 |

| 金额计算 | BigDecimal | 避免浮点精度丢失 |


📁 项目结构

parking-integration/
├── entity/
│   ├── ParkingRecord.java      // 停车记录
│   └── Member.java              // 会员信息
├── dto/
│   ├── ParkingEnterDTO.java    // 入场请求
│   ├── ParkingExitDTO.java     // 出场请求
│   ├── PointsDeductDTO.java    // 积分扣除请求
│   └── PointsAddDTO.java       // 积分增加请求
├── client/
│   └── PointsSystemClient.java // 积分系统模拟客户端
├── service/
│   ├── ParkingService.java     // 停车核心业务
│   └── PointsService.java      // 积分对接服务
├── controller/
│   └── ParkingController.java  // 对外API
└── ParkingApplication.java     // 启动类

💻 完整代码

1. 实体类 & DTO

ParkingRecord.java - 停车记录实体

package com.demo.parking.entity;

import java.math.BigDecimal;
import java.time.LocalDateTime;

public class ParkingRecord {
    private Long id;
    private String plateNumber;      // 车牌号
    private Long memberId;           // 会员ID(可为空)
    private String memberPhone;      // 会员手机号
    private LocalDateTime enterTime; // 入场时间
    private LocalDateTime exitTime;  // 出场时间
    private BigDecimal totalFee;     // 总停车费
    private BigDecimal paidAmount;   // 实付金额
    private BigDecimal pointsDeductAmount; // 积分抵扣金额
    private Integer deductPoints;    // 消耗积分
    private Integer earnPoints;      // 赠送积分
    private String status;           // 状态: WAITING_PAY, PAID, CANCELLED

    // 构造方法、getter/setter 省略(实际使用Lombok)
}

ParkingEnterDTO.java - 入场请求

package com.demo.parking.dto;

public class ParkingEnterDTO {
    private String plateNumber;
    private Long memberId;      // 扫码识别会员ID,可为空
    // getter/setter
}

ParkingExitDTO.java - 出场请求(核心)

package com.demo.parking.dto;

public class ParkingExitDTO {
    private String plateNumber;
    private Long memberId;
    private Boolean usePoints;   // 是否使用积分抵扣
    // getter/setter
}

2. 积分系统模拟客户端 (关键对接点)

PointsSystemClient.java - 模拟远程积分系统

package com.demo.parking.client;

import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

/**
 * 模拟积分系统客户端
 * 实际生产环境替换为 FeignClient 或 RestTemplate 调用
 */
@Component
public class PointsSystemClient {

    // 模拟会员积分余额数据库
    private static final Map<Long, Integer> MEMBER_POINTS = new HashMap<>();
    // 积分抵扣比例: 100积分 = 1元
    private static final int POINTS_TO_MONEY_RATIO = 100;
    // 消费赠送比例: 消费1元 = 1积分
    private static final int MONEY_TO_POINTS_RATIO = 1;

    static {
        // 模拟初始化: 会员ID=1001 有 5000 积分
        MEMBER_POINTS.put(1001L, 5000);
        MEMBER_POINTS.put(1002L, 200);
        MEMBER_POINTS.put(1003L, 0);
    }

    /**
     * 查询会员积分余额
     */
    public Integer queryPoints(Long memberId) {
        if (memberId == null) return 0;
        return MEMBER_POINTS.getOrDefault(memberId, 0);
    }

    /**
     * 扣除积分(积分抵扣停车费)
     * @return 是否扣除成功
     */
    public boolean deductPoints(Long memberId, Integer points) {
        if (memberId == null || points <= 0) return false;
        Integer current = MEMBER_POINTS.getOrDefault(memberId, 0);
        if (current < points) return false; // 积分不足
        MEMBER_POINTS.put(memberId, current - points);
        System.out.println("[积分系统] 会员 " + memberId + " 扣除 " + points + " 积分,剩余 " + (current - points));
        return true;
    }

    /**
     * 增加积分(消费赠送)
     */
    public boolean addPoints(Long memberId, Integer points) {
        if (memberId == null || points <= 0) return false;
        Integer current = MEMBER_POINTS.getOrDefault(memberId, 0);
        MEMBER_POINTS.put(memberId, current + points);
        System.out.println("[积分系统] 会员 " + memberId + " 赠送 " + points + " 积分,当前 " + (current + points));
        return true;
    }

    /**
     * 计算可抵扣金额(根据积分余额)
     */
    public BigDecimal getMaxDeductAmount(Long memberId) {
        Integer points = queryPoints(memberId);
        // 向下取整到分
        return new BigDecimal(points / POINTS_TO_MONEY_RATIO)
                .setScale(2, BigDecimal.ROUND_DOWN);
    }

    /**
     * 根据金额计算需要消耗的积分
     */
    public Integer calculatePointsNeeded(BigDecimal amount) {
        return amount.multiply(new BigDecimal(POINTS_TO_MONEY_RATIO)).intValue();
    }

    /**
     * 根据消费金额计算赠送积分
     */
    public Integer calculateEarnPoints(BigDecimal paidAmount) {
        return paidAmount.multiply(new BigDecimal(MONEY_TO_POINTS_RATIO)).intValue();
    }
}

3. 核心业务服务

ParkingService.java - 停车核心业务

package com.demo.parking.service;

import com.demo.parking.client.PointsSystemClient;
import com.demo.parking.dto.ParkingEnterDTO;
import com.demo.parking.dto.ParkingExitDTO;
import com.demo.parking.entity.ParkingRecord;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

@Service
public class ParkingService {

    @Autowired
    private PointsSystemClient pointsClient;

    // 模拟停车场数据库(实际使用 Redis 或 MySQL)
    private static final ConcurrentHashMap<String, ParkingRecord> PARKING_DATA = new ConcurrentHashMap<>();
    private static final List<ParkingRecord> HISTORY = new ArrayList<>();

    // 停车单价: 5元/小时,30元封顶
    private static final BigDecimal HOURLY_RATE = new BigDecimal("5");
    private static final BigDecimal MAX_DAILY_FEE = new BigDecimal("30");

    /**
     * 车辆入场
     */
    public ParkingRecord enter(ParkingEnterDTO dto) {
        ParkingRecord record = new ParkingRecord();
        record.setPlateNumber(dto.getPlateNumber());
        record.setMemberId(dto.getMemberId());
        record.setEnterTime(LocalDateTime.now());
        record.setStatus("WAITING_PAY");

        // 如果传入了会员ID,查询会员信息(模拟)
        if (dto.getMemberId() != null) {
            Integer points = pointsClient.queryPoints(dto.getMemberId());
            System.out.println("[停车系统] 会员 " + dto.getMemberId() + " 积分余额: " + points);
        }

        PARKING_DATA.put(dto.getPlateNumber(), record);
        System.out.println("[停车系统] 车辆 " + dto.getPlateNumber() + " 入场");
        return record;
    }

    /**
     * 车辆出场结算(核心业务)
     */
    public ParkingRecord exit(ParkingExitDTO dto) {
        String plate = dto.getPlateNumber();
        ParkingRecord record = PARKING_DATA.get(plate);
        if (record == null) {
            throw new RuntimeException("未找到入场记录: " + plate);
        }

        // 1. 设置出场时间 & 计算停车时长
        record.setExitTime(LocalDateTime.now());
        long minutes = Duration.between(record.getEnterTime(), record.getExitTime()).toMinutes();
        long hours = Math.max(1, (minutes + 59) / 60); // 不足1小时按1小时算

        // 2. 计算停车总费用
        BigDecimal fee = HOURLY_RATE.multiply(new BigDecimal(hours));
        if (fee.compareTo(MAX_DAILY_FEE) > 0) {
            fee = MAX_DAILY_FEE;
        }
        record.setTotalFee(fee);

        // 3. 积分抵扣逻辑
        BigDecimal finalPaid = fee;
        Integer usedPoints = 0;
        BigDecimal deductAmount = BigDecimal.ZERO;

        if (dto.getUsePoints() != null && dto.getUsePoints() && record.getMemberId() != null) {
            Long memberId = record.getMemberId();

            // 查询最大可抵扣金额
            BigDecimal maxDeduct = pointsClient.getMaxDeductAmount(memberId);
            // 取 min(停车费, 可用积分抵扣金额)
            BigDecimal canDeduct = fee.min(maxDeduct);

            if (canDeduct.compareTo(BigDecimal.ZERO) > 0) {
                // 计算需要消耗的积分
                usedPoints = pointsClient.calculatePointsNeeded(canDeduct);
                // 执行扣除
                boolean success = pointsClient.deductPoints(memberId, usedPoints);
                if (success) {
                    deductAmount = canDeduct;
                    finalPaid = fee.subtract(deductAmount);
                    System.out.println("[停车系统] 积分抵扣成功: 扣除 " + usedPoints + " 积分,减免 " + deductAmount + " 元");
                }
            }
        }

        record.setPaidAmount(finalPaid);
        record.setDeductPoints(usedPoints);
        record.setPointsDeductAmount(deductAmount);

        // 4. 支付完成后赠送积分 (按实付金额)
        if (finalPaid.compareTo(BigDecimal.ZERO) > 0 && record.getMemberId() != null) {
            Integer earnPoints = pointsClient.calculateEarnPoints(finalPaid);
            if (earnPoints > 0) {
                pointsClient.addPoints(record.getMemberId(), earnPoints);
                record.setEarnPoints(earnPoints);
                System.out.println("[停车系统] 消费赠送 " + earnPoints + " 积分");
            }
        }

        record.setStatus("PAID");

        // 5. 移出缓存,存入历史
        PARKING_DATA.remove(plate);
        HISTORY.add(record);

        // 6. 打印最终账单
        printReceipt(record);
        return record;
    }

    /**
     * 打印结算小票
     */
    private void printReceipt(ParkingRecord record) {
        System.out.println("\n========== 停车结算单 ==========");
        System.out.println("车牌号: " + record.getPlateNumber());
        System.out.println("入场: " + record.getEnterTime());
        System.out.println("出场: " + record.getExitTime());
        System.out.println("总费用: ¥" + record.getTotalFee());
        if (record.getDeductPoints() > 0) {
            System.out.println("积分抵扣: -¥" + record.getPointsDeductAmount() + " (" + record.getDeductPoints() + "积分)");
        }
        System.out.println("实付金额: ¥" + record.getPaidAmount());
        if (record.getEarnPoints() != null && record.getEarnPoints() > 0) {
            System.out.println("赠送积分: +" + record.getEarnPoints());
        }
        System.out.println("==================================\n");
    }

    /**
     * 查询当前场内车辆
     */
    public List<ParkingRecord> getCurrentParking() {
        return new ArrayList<>(PARKING_DATA.values());
    }
}

4. 对外接口 Controller

ParkingController.java - REST API

package com.demo.parking.controller;

import com.demo.parking.dto.ParkingEnterDTO;
import com.demo.parking.dto.ParkingExitDTO;
import com.demo.parking.entity.ParkingRecord;
import com.demo.parking.service.ParkingService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/api/parking")
public class ParkingController {

    @Autowired
    private ParkingService parkingService;

    /**
     * 车辆入场
     * POST /api/parking/enter
     */
    @PostMapping("/enter")
    public ParkingRecord enter(@RequestBody ParkingEnterDTO dto) {
        return parkingService.enter(dto);
    }

    /**
     * 车辆出场 (积分抵扣 + 赠送在此完成)
     * POST /api/parking/exit
     */
    @PostMapping("/exit")
    public ParkingRecord exit(@RequestBody ParkingExitDTO dto) {
        return parkingService.exit(dto);
    }

    /**
     * 查询场内车辆
     * GET /api/parking/current
     */
    @GetMapping("/current")
    public List<ParkingRecord> current() {
        return parkingService.getCurrentParking();
    }
}

5. 启动类

ParkingApplication.java

package com.demo.parking;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ParkingApplication {
    public static void main(String[] args) {
        SpringApplication.run(ParkingApplication.class, args);
        System.out.println("🚗 停车对接积分系统启动成功!");
    }
}

🧪 测试接口(Postman / Curl)

1. 车辆入场(非会员)

POST /api/parking/enter
{
    "plateNumber": "京A88888"
}

2. 车辆入场(会员)

POST /api/parking/enter
{
    "plateNumber": "京A66666",
    "memberId": 1001
}

3. 车辆出场(使用积分抵扣)

POST /api/parking/exit
{
    "plateNumber": "京A66666",
    "memberId": 1001,
    "usePoints": true
}

4. 车辆出场(不使用积分,纯现金)

POST /api/parking/exit
{
    "plateNumber": "京A88888",
    "memberId": null,
    "usePoints": false
}

📊 运行日志示例

[停车系统] 车辆 京A66666 入场
[停车系统] 会员 1001 积分余额: 5000

========== 停车结算单 ==========
车牌号: 京A66666
入场: 2026-08-23T10:00:00
出场: 2026-08-23T12:30:00
总费用: ¥15
积分抵扣: -¥5 (500积分)
实付金额: ¥10
赠送积分: +10
==================================

[积分系统] 会员 1001 扣除 500 积分,剩余 4500
[积分系统] 会员 1001 赠送 10 积分,当前 4510

🧠 核心亮点(CSDN发布时可写的技术点)

| 亮点 | 说明 |

|------|------|

| 防腐层设计 | PointsSystemClient 作为防腐层,隔离外部积分系统变化 |

| 积分抵扣阈值 | 停车费与积分余额取min,避免超扣 |

| 双向积分流转 | 扣积分(支付)+ 送积分(消费),形成闭环 |

| BigDecimal精度 | 金额计算全部使用BigDecimal,避免Float/Double精度丢失 |

| 幂等性考虑 | 实际生产需增加订单号防重,本例简化演示 |

| 可扩展性 | 支持多停车场、多会员等级折扣、动态积分比例 |


把这段代码贴到CSDN,标题就叫 《Spring Boot 实现停车场与积分系统对接实战》,再把上面那个运行日志截图一贴,又是妥妥的一篇技术水文😂 不过能跑、能演示、结构清晰,应付交差完全够了。


合作热线
18865460927
公司地址
山东省东营市垦利区兴隆路8-5号
产品咨询
产品咨询
Copyright © 2014-2026 东营码良软件开发 Inc. 版权所有鲁ICP备2025202136号-2 | 经营许可证编号:豫B2-20190103豫公网安备41019602002340