Java实现电子合同案例

wen java案例 2

本文目录导读:

Java实现电子合同案例

  1. 项目结构
  2. Maven配置 (pom.xml)
  3. 实体类
  4. 工具类
  5. 服务类
  6. 控制器
  7. 主应用程序
  8. 测试用例
  9. 配置文��
  10. API示例

我将为您提供一个完整的Java电子合同实现案例,包含合同创建、签名、验证等核心功能。

项目结构

electronic-contract/
├── pom.xml
├── src/main/java/com/example/contract/
│   ├── model/
│   │   ├── Contract.java
│   │   ├── ContractStatus.java
│   │   └── Signature.java
│   ├── service/
│   │   ├── ContractService.java
│   │   ├── SignatureService.java
│   │   └── VerificationService.java
│   ├── util/
│   │   ├── DigitalSignatureUtil.java
│   │   └── EncryptionUtil.java
│   ├── controller/
│   │   └── ContractController.java
│   └── ContractApplication.java

Maven配置 (pom.xml)

<?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>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.0</version>
    </parent>
    <groupId>com.example</groupId>
    <artifactId>electronic-contract</artifactId>
    <version>1.0.0</version>
    <properties>
        <java.version>11</java.version>
    </properties>
    <dependencies>
        <!-- Spring Boot Web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- Spring Data JPA -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <!-- H2 Database (示例用) -->
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </dependency>
        <!-- Lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!-- Bouncy Castle 加密库 -->
        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcpkix-jdk15on</artifactId>
            <version>1.70</version>
        </dependency>
        <!-- PDF处理 -->
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itextpdf</artifactId>
            <version>5.5.13.2</version>
        </dependency>
    </dependencies>
</project>

实体类

Contract.java

package com.example.contract.model;
import lombok.Data;
import javax.persistence.*;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
@Data
@Entity
@Table(name = "contracts")
public class Contract {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @Column(nullable = false, unique = true)
    private String contractNo;
    @Column(nullable = false)
    private String title;
    @Column(length = 2000)
    private String content;
    @Enumerated(EnumType.STRING)
    private ContractStatus status;
    @Column(name = "created_at")
    private LocalDateTime createdAt;
    @Column(name = "updated_at")
    private LocalDateTime updatedAt;
    @Column(name = "created_by")
    private String createdBy;
    @Column(name = "signature_path")
    private String signaturePath;
    @Column(name = "hash_value")
    private String hashValue;
    @OneToMany(mappedBy = "contract", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<Signature> signatures = new ArrayList<>();
    @PrePersist
    protected void onCreate() {
        createdAt = LocalDateTime.now();
        updatedAt = LocalDateTime.now();
    }
    @PreUpdate
    protected void onUpdate() {
        updatedAt = LocalDateTime.now();
    }
}

ContractStatus.java

package com.example.contract.model;
public enum ContractStatus {
    DRAFT("草稿"),
    PENDING_SIGNATURE("待签署"),
    PARTIALLY_SIGNED("部分签署"),
    COMPLETED("已完成"),
    EXPIRED("已过期"),
    CANCELLED("已取消");
    private final String description;
    ContractStatus(String description) {
        this.description = description;
    }
    public String getDescription() {
        return description;
    }
}

Signature.java

package com.example.contract.model;
import lombok.Data;
import javax.persistence.*;
import java.time.LocalDateTime;
@Data
@Entity
@Table(name = "signatures")
public class Signature {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "contract_id", nullable = false)
    private Contract contract;
    @Column(nullable = false)
    private String signerName;
    @Column(nullable = false)
    private String signerId;
    @Column(name = "signature_data", columnDefinition = "TEXT")
    private String signatureData;
    @Column(name = "certificate")
    private String certificate;
    @Column(name = "signed_at")
    private LocalDateTime signedAt;
    @Column(name = "ip_address")
    private String ipAddress;
    @Column(name = "hash_value")
    private String hashValue;
    @PrePersist
    protected void onCreate() {
        signedAt = LocalDateTime.now();
    }
}

工具类

DigitalSignatureUtil.java

package com.example.contract.util;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
@Component
public class DigitalSignatureUtil {
    private static final String ALGORITHM = "RSA";
    private static final String SIGNATURE_ALGORITHM = "SHA256withRSA";
    private static final int KEY_SIZE = 2048;
    @PostConstruct
    public void init() {
        if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
            Security.addProvider(new BouncyCastleProvider());
        }
    }
    /**
     * 生成密钥对
     */
    public KeyPair generateKeyPair() throws Exception {
        KeyPairGenerator keyGen = KeyPairGenerator.getInstance(ALGORITHM);
        keyGen.initialize(KEY_SIZE);
        return keyGen.generateKeyPair();
    }
    /**
     * 签名
     */
    public String sign(String data, PrivateKey privateKey) throws Exception {
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initSign(privateKey);
        signature.update(data.getBytes());
        byte[] signatureBytes = signature.sign();
        return Base64.getEncoder().encodeToString(signatureBytes);
    }
    /**
     * 验证签名
     */
    public boolean verify(String data, String signatureStr, PublicKey publicKey) throws Exception {
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initVerify(publicKey);
        signature.update(data.getBytes());
        byte[] signatureBytes = Base64.getDecoder().decode(signatureStr);
        return signature.verify(signatureBytes);
    }
    /**
     * 私钥转字符串
     */
    public String privateKeyToString(PrivateKey privateKey) {
        return Base64.getEncoder().encodeToString(privateKey.getEncoded());
    }
    /**
     * 公钥转字符串
     */
    public String publicKeyToString(PublicKey publicKey) {
        return Base64.getEncoder().encodeToString(publicKey.getEncoded());
    }
    /**
     * 字符串转私钥
     */
    public PrivateKey stringToPrivateKey(String keyStr) throws Exception {
        byte[] keyBytes = Base64.getDecoder().decode(keyStr);
        PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
        return keyFactory.generatePrivate(spec);
    }
    /**
     * 字符串转公钥
     */
    public PublicKey stringToPublicKey(String keyStr) throws Exception {
        byte[] keyBytes = Base64.getDecoder().decode(keyStr);
        X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
        return keyFactory.generatePublic(spec);
    }
}

EncryptionUtil.java

package com.example.contract.util;
import org.springframework.stereotype.Component;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.security.MessageDigest;
import java.util.Base64;
@Component
public class EncryptionUtil {
    private static final String AES_ALGORITHM = "AES";
    private static final String HASH_ALGORITHM = "SHA-256";
    /**
     * 生成AES密钥
     */
    public SecretKey generateAESKey() throws Exception {
        KeyGenerator keyGen = KeyGenerator.getInstance(AES_ALGORITHM);
        keyGen.init(256);
        return keyGen.generateKey();
    }
    /**
     * AES加密
     */
    public String aesEncrypt(String data, SecretKey key) throws Exception {
        Cipher cipher = Cipher.getInstance(AES_ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, key);
        byte[] encrypted = cipher.doFinal(data.getBytes());
        return Base64.getEncoder().encodeToString(encrypted);
    }
    /**
     * AES解密
     */
    public String aesDecrypt(String encryptedData, SecretKey key) throws Exception {
        Cipher cipher = Cipher.getInstance(AES_ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, key);
        byte[] decrypted = cipher.doFinal(Base64.getDecoder().decode(encryptedData));
        return new String(decrypted);
    }
    /**
     * 计算哈希值
     */
    public String calculateHash(String data) throws Exception {
        MessageDigest digest = MessageDigest.getInstance(HASH_ALGORITHM);
        byte[] hash = digest.digest(data.getBytes());
        return Base64.getEncoder().encodeToString(hash);
    }
}

服务类

ContractService.java

package com.example.contract.service;
import com.example.contract.model.Contract;
import com.example.contract.model.ContractStatus;
import com.example.contract.model.Signature;
import com.example.contract.repository.ContractRepository;
import com.example.contract.util.DigitalSignatureUtil;
import com.example.contract.util.EncryptionUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.UUID;
@Service
@RequiredArgsConstructor
public class ContractService {
    private final ContractRepository contractRepository;
    private final DigitalSignatureUtil digitalSignatureUtil;
    private final EncryptionUtil encryptionUtil;
    /**
     * 创建合同
     */
    @Transactional
    public Contract createContract(String title, String content, String userId) {
        Contract contract = new Contract();
        contract.setContractNo(generateContractNo());
        contract.setTitle(title);
        contract.setContent(content);
        contract.setStatus(ContractStatus.DRAFT);
        contract.setCreatedBy(userId);
        // 计算合同内容哈希值
        try {
            String hash = encryptionUtil.calculateHash(content);
            contract.setHashValue(hash);
        } catch (Exception e) {
            throw new RuntimeException("计算合同哈希值失败", e);
        }
        return contractRepository.save(contract);
    }
    /**
     * 获取合同
     */
    public Contract getContract(Long id) {
        return contractRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("合同不存在: " + id));
    }
    /**
     * 获取合同列表
     */
    public List<Contract> getAllContracts() {
        return contractRepository.findAll();
    }
    /**
     * 更新合同内容
     */
    @Transactional
    public Contract updateContract(Long id, String title, String content) {
        Contract contract = getContract(id);
        // 检查合同状态
        if (contract.getStatus() != ContractStatus.DRAFT) {
            throw new RuntimeException("只有草稿状态的合同才能修改");
        }
        contract.setTitle(title);
        contract.setContent(content);
        // 更新哈希值
        try {
            contract.setHashValue(encryptionUtil.calculateHash(content));
        } catch (Exception e) {
            throw new RuntimeException("更新哈希值失败", e);
        }
        return contractRepository.save(contract);
    }
    /**
     * 发布合同(进入待签署状态)
     */
    @Transactional
    public Contract publishContract(Long id) {
        Contract contract = getContract(id);
        if (contract.getStatus() != ContractStatus.DRAFT) {
            throw new RuntimeException("只有草稿状态的合同才能发布");
        }
        contract.setStatus(ContractStatus.PENDING_SIGNATURE);
        return contractRepository.save(contract);
    }
    /**
     * 签署合同
     */
    @Transactional
    public Contract signContract(Long contractId, String signerName, 
                                String signerId, String signatureData) {
        Contract contract = getContract(contractId);
        // 验证合同状态
        if (contract.getStatus() != ContractStatus.PENDING_SIGNATURE &&
            contract.getStatus() != ContractStatus.PARTIALLY_SIGNED) {
            throw new RuntimeException("合同当前状态不允许签署");
        }
        // 创建签名记录
        Signature signature = new Signature();
        signature.setContract(contract);
        signature.setSignerName(signerName);
        signature.setSignerId(signerId);
        signature.setSignatureData(signatureData);
        signature.setSignedAt(LocalDateTime.now());
        // 验证签名数据(示例中简单验证非空)
        if (signatureData == null || signatureData.trim().isEmpty()) {
            throw new RuntimeException("签名数据无效");
        }
        contract.getSignatures().add(signature);
        // 更新合同状态
        // 这里假设需要双方签署完成,实际业务根据需求调整
        if (contract.getSignatures().size() >= 2) {
            contract.setStatus(ContractStatus.COMPLETED);
        } else {
            contract.setStatus(ContractStatus.PARTIALLY_SIGNED);
        }
        return contractRepository.save(contract);
    }
    /**
     * 取消合同
     */
    @Transactional
    public Contract cancelContract(Long id) {
        Contract contract = getContract(id);
        if (contract.getStatus() == ContractStatus.COMPLETED) {
            throw new RuntimeException("已完成的合同不能取消");
        }
        contract.setStatus(ContractStatus.CANCELLED);
        return contractRepository.save(contract);
    }
    /**
     * 生成合同编号
     */
    private String generateContractNo() {
        String dateStr = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        String uuid = UUID.randomUUID().toString().substring(0, 8).toUpperCase();
        return "CT-" + dateStr + "-" + uuid;
    }
}

SignatureService.java

package com.example.contract.service;
import com.example.contract.model.Contract;
import com.example.contract.model.Signature;
import com.example.contract.repository.SignatureRepository;
import com.example.contract.util.DigitalSignatureUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.security.KeyPair;
import java.util.List;
@Service
@RequiredArgsConstructor
public class SignatureService {
    private final SignatureRepository signatureRepository;
    private final DigitalSignatureUtil digitalSignatureUtil;
    /**
     * 获取合同的所有签名
     */
    public List<Signature> getSignaturesByContract(Long contractId) {
        return signatureRepository.findByContractIdOrderBySignedAtAsc(contractId);
    }
    /**
     * 创建数字签名
     */
    @Transactional
    public Signature createDigitalSignature(Contract contract, String signerName, 
                                           String signerId, String ipAddress) {
        try {
            // 生成密钥对
            KeyPair keyPair = digitalSignatureUtil.generateKeyPair();
            // 创建签名记录
            Signature signature = new Signature();
            signature.setContract(contract);
            signature.setSignerName(signerName);
            signature.setSignerId(signerId);
            signature.setIpAddress(ipAddress);
            // 计算合同数据的签名
            String dataToSign = buildDataToSign(contract, signerName, signerId);
            String signatureStr = digitalSignatureUtil.sign(
                dataToSign, keyPair.getPrivate());
            signature.setSignatureData(signatureStr);
            signature.setCertificate(digitalSignatureUtil.publicKeyToString(keyPair.getPublic()));
            // 计算签名哈希
            signature.setHashValue(calculateSignatureHash(signatureStr));
            return signatureRepository.save(signature);
        } catch (Exception e) {
            throw new RuntimeException("创建数字签名失败", e);
        }
    }
    /**
     * 验证签名
     */
    public boolean verifySignature(Signature signature, Contract contract) {
        try {
            // 重建签名的数据
            String dataToVerify = buildDataToSign(contract, 
                signature.getSignerName(), signature.getSignerId());
            // 获取公钥
            var publicKey = digitalSignatureUtil.stringToPublicKey(
                signature.getCertificate());
            // 验证签名
            return digitalSignatureUtil.verify(
                dataToVerify, signature.getSignatureData(), publicKey);
        } catch (Exception e) {
            throw new RuntimeException("验证签名失败", e);
        }
    }
    /**
     * 构建待签名数据
     */
    private String buildDataToSign(Contract contract, String signerName, String signerId) {
        return String.format("%s|%s|%s|%s", 
            contract.getContractNo(),
            contract.getContent(),
            signerName,
            signerId);
    }
    /**
     * 计算签名哈希值
     */
    private String calculateSignatureHash(String signature) {
        try {
            java.security.MessageDigest digest = 
                java.security.MessageDigest.getInstance("SHA-256");
            byte[] hash = digest.digest(signature.getBytes());
            return java.util.Base64.getEncoder().encodeToString(hash);
        } catch (Exception e) {
            throw new RuntimeException("计算哈希失败", e);
        }
    }
}

VerificationService.java

package com.example.contract.service;
import com.example.contract.model.Contract;
import com.example.contract.model.Signature;
import com.example.contract.util.EncryptionUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
@RequiredArgsConstructor
public class VerificationService {
    private final ContractService contractService;
    private final SignatureService signatureService;
    private final EncryptionUtil encryptionUtil;
    /**
     * 验证合同完整性
     */
    public boolean verifyContractIntegrity(Long contractId) {
        Contract contract = contractService.getContract(contractId);
        try {
            // 重新计算合同内容哈希值
            String currentHash = encryptionUtil.calculateHash(contract.getContent());
            // 与保存的哈希值比较
            return currentHash.equals(contract.getHashValue());
        } catch (Exception e) {
            throw new RuntimeException("验证合同完整性失败", e);
        }
    }
    /**
     * 验证所有签名
     */
    public boolean verifyAllSignatures(Long contractId) {
        Contract contract = contractService.getContract(contractId);
        List<Signature> signatures = signatureService.getSignaturesByContract(contractId);
        if (signatures.isEmpty()) {
            return false;
        }
        // 验证所有签名
        for (Signature signature : signatures) {
            boolean isValid = signatureService.verifySignature(signature, contract);
            if (!isValid) {
                return false;
            }
        }
        return true;
    }
    /**
     * 获取合同验证报告
     */
    public String generateVerificationReport(Long contractId) {
        Contract contract = contractService.getContract(contractId);
        StringBuilder report = new StringBuilder();
        report.append("===== 合同验证报告 =====\n");
        report.append("合同编号: ").append(contract.getContractNo()).append("\n");
        report.append("合同标题: ").append(contract.getTitle()).append("\n");
        report.append("合同状态: ").append(contract.getStatus().getDescription()).append("\n");
        report.append("创建时间: ").append(contract.getCreatedAt()).append("\n\n");
        // 验证完整性
        boolean integrity = verifyContractIntegrity(contractId);
        report.append("内容完整性: ").append(integrity ? "通过" : "未通过").append("\n");
        // 验证签名
        List<Signature> signatures = signatureService.getSignaturesByContract(contractId);
        report.append("签名数量: ").append(signatures.size()).append("\n");
        for (int i = 0; i < signatures.size(); i++) {
            Signature sig = signatures.get(i);
            boolean valid = signatureService.verifySignature(sig, contract);
            report.append("签名").append(i + 1).append(": ")
                   .append(sig.getSignerName())
                   .append(" - ").append(valid ? "有效" : "无效")
                   .append("\n");
        }
        return report.toString();
    }
}

控制器

ContractController.java

package com.example.contract.controller;
import com.example.contract.model.Contract;
import com.example.contract.model.Signature;
import com.example.contract.service.ContractService;
import com.example.contract.service.SignatureService;
import com.example.contract.service.VerificationService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/api/contracts")
@RequiredArgsConstructor
public class ContractController {
    private final ContractService contractService;
    private final SignatureService signatureService;
    private final VerificationService verificationService;
    /**
     * 创建合同
     */
    @PostMapping
    public ResponseEntity<?> createContract(@RequestBody Map<String, String> request) {
        try {
            Contract contract = contractService.createContract(
                request.get("title"),
                request.get("content"),
                request.get("userId")
            );
            return ResponseEntity.ok(contract);
        } catch (Exception e) {
            return ResponseEntity.badRequest().body(e.getMessage());
        }
    }
    /**
     * 获取所有合同
     */
    @GetMapping
    public ResponseEntity<List<Contract>> getAllContracts() {
        return ResponseEntity.ok(contractService.getAllContracts());
    }
    /**
     * 获取合同详情
     */
    @GetMapping("/{id}")
    public ResponseEntity<?> getContract(@PathVariable Long id) {
        try {
            Contract contract = contractService.getContract(id);
            return ResponseEntity.ok(contract);
        } catch (Exception e) {
            return ResponseEntity.badRequest().body(e.getMessage());
        }
    }
    /**
     * 更新合同
     */
    @PutMapping("/{id}")
    public ResponseEntity<?> updateContract(@PathVariable Long id, 
                                           @RequestBody Map<String, String> request) {
        try {
            Contract contract = contractService.updateContract(
                id, request.get("title"), request.get("content"));
            return ResponseEntity.ok(contract);
        } catch (Exception e) {
            return ResponseEntity.badRequest().body(e.getMessage());
        }
    }
    /**
     * 发布合同
     */
    @PostMapping("/{id}/publish")
    public ResponseEntity<?> publishContract(@PathVariable Long id) {
        try {
            Contract contract = contractService.publishContract(id);
            return ResponseEntity.ok(contract);
        } catch (Exception e) {
            return ResponseEntity.badRequest().body(e.getMessage());
        }
    }
    /**
     * 签署合同
     */
    @PostMapping("/{id}/sign")
    public ResponseEntity<?> signContract(@PathVariable Long id,
                                         @RequestBody Map<String, String> request) {
        try {
            Contract contract = contractService.signContract(
                id,
                request.get("signerName"),
                request.get("signerId"),
                request.get("signatureData")
            );
            return ResponseEntity.ok(contract);
        } catch (Exception e) {
            return ResponseEntity.badRequest().body(e.getMessage());
        }
    }
    /**
     * 创建数字签名(带证书)
     */
    @PostMapping("/{id}/digital-signature")
    public ResponseEntity<?> createDigitalSignature(@PathVariable Long id,
                                                   @RequestBody Map<String, String> request) {
        try {
            Contract contract = contractService.getContract(id);
            Signature signature = signatureService.createDigitalSignature(
                contract,
                request.get("signerName"),
                request.get("signerId"),
                request.get("ipAddress")
            );
            return ResponseEntity.ok(signature);
        } catch (Exception e) {
            return ResponseEntity.badRequest().body(e.getMessage());
        }
    }
    /**
     * 获取合同签名列表
     */
    @GetMapping("/{id}/signatures")
    public ResponseEntity<List<Signature>> getSignatures(@PathVariable Long id) {
        return ResponseEntity.ok(signatureService.getSignaturesByContract(id));
    }
    /**
     * 验证合同
     */
    @GetMapping("/{id}/verify")
    public ResponseEntity<?> verifyContract(@PathVariable Long id) {
        try {
            Map<String, Object> result = new HashMap<>();
            result.put("integrity", verificationService.verifyContractIntegrity(id));
            result.put("signaturesValid", verificationService.verifyAllSignatures(id));
            result.put("report", verificationService.generateVerificationReport(id));
            return ResponseEntity.ok(result);
        } catch (Exception e) {
            return ResponseEntity.badRequest().body(e.getMessage());
        }
    }
    /**
     * 取消合同
     */
    @PostMapping("/{id}/cancel")
    public ResponseEntity<?> cancelContract(@PathVariable Long id) {
        try {
            Contract contract = contractService.cancelContract(id);
            return ResponseEntity.ok(contract);
        } catch (Exception e) {
            return ResponseEntity.badRequest().body(e.getMessage());
        }
    }
}

主应用程序

ContractApplication.java

package com.example.contract;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ContractApplication {
    public static void main(String[] args) {
        SpringApplication.run(ContractApplication.class, args);
    }
}

测试用例

ContractServiceTest.java

package com.example.contract;
import com.example.contract.model.Contract;
import com.example.contract.model.ContractStatus;
import com.example.contract.service.ContractService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import static org.junit.jupiter.api.Assertions.*;
@SpringBootTest
public class ContractServiceTest {
    @Autowired
    private ContractService contractService;
    @Test
    public void testCreateAndPublishContract() {
        // 创建合同
        Contract contract = contractService.createContract(
            "测试合同", "合同内容", "user001");
        assertNotNull(contract);
        assertNotNull(contract.getContractNo());
        assertEquals(ContractStatus.DRAFT, contract.getStatus());
        // 发布合同
        Contract published = contractService.publishContract(contract.getId());
        assertEquals(ContractStatus.PENDING_SIGNATURE, published.getStatus());
    }
    @Test
    public void testSignContract() {
        // 创建并发布合同
        Contract contract = contractService.createContract(
            "签署测试", "合同内容", "user001");
        contractService.publishContract(contract.getId());
        // 第一次签署
        Contract signed1 = contractService.signContract(
            contract.getId(), "张三", "1001", "signature1");
        assertEquals(ContractStatus.PARTIALLY_SIGNED, signed1.getStatus());
        // 第二次签署
        Contract signed2 = contractService.signContract(
            contract.getId(), "李四", "1002", "signature2");
        assertEquals(ContractStatus.COMPLETED, signed2.getStatus());
    }
    @Test
    public void testVerifyContractIntegrity() {
        // 创建合同
        Contract contract = contractService.createContract(
            "完整性测试", "原始内容", "user001");
        // 这里假设有注入VerificationService
        // 验证通过
        assertNotNull(contract);
    }
}

配置文��

application.yml

server:
  port: 8080
spring:
  application:
    name: electronic-contract
  datasource:
    url: jdbc:h2:mem:contractdb
    driver-class-name: org.h2.Driver
    username: sa
    password: 
  jpa:
    database-platform: org.hibernate.dialect.H2Dialect
    hibernate:
      ddl-auto: create-drop
    show-sql: true
  h2:
    console:
      enabled: true
      path: /h2-console
management:
  endpoints:
    web:
      exposure:
        include: health,info

API示例

# 创建合同
curl -X POST http://localhost:8080/api/contracts \
  -H "Content-Type: application/json" \
  -d '{: "劳动合同",
    "content": "甲乙双方经平等协商,达成如下协议...",
    "userId": "user001"
  }'
# 发布合同
curl -X POST http://localhost:8080/api/contracts/1/publish
# 签署合同
curl -X POST http://localhost:8080/api/contracts/1/sign \
  -H "Content-Type: application/json" \
  -d '{
    "signerName": "张三",
    "signerId": "1001",
    "signatureData": "base64签名数据"
  }'
# 验证合同
curl http://localhost:8080/api/contracts/1/verify

这个电子合同系统实现了:

  1. 合同管理:创建、修改、发布、取消
  2. 数字签名:支持电子签名和数字证书签名
  3. 完整性验证:通过哈希值验证合同内容未被篡改
  4. 签名验证:验证签名的真实性和有效性
  5. 状态管理:合同全生命周期状态追踪

可以根据实际业务需求扩展更多功能,如PDF生成、合同模板、审批流程等。

抱歉,评论功能暂时关闭!