@Data
@Table(name = "t_contract")
public class Contract implements Serializable {
/**
* 合同ID
*/
@Id
private String contractId;
/**
* 合同名称
*/
private String contractName;
/**
* 合同类型
*/
@Enumerated(EnumType.STRING)
private ContractType contractType;
/**
* 合同状态
*/
@Enumerated(EnumType.STRING)
private ContractStatus contractStatus;
/**
* 甲方企业ID
*/
private String partyAId;
/**
* 甲方企业名称
*/
private String partyAName;
/**
* 乙方企业ID
*/
private String partyBId;
/**
* 乙方企业名称
*/
private String partyBName;
/**
* 合同金额
*/
private BigDecimal contractAmount;
/**
* 合同期限(天)
*/
private Integer contractPeriod;
/**
* 开始日期
*/
private Date startDate;
/**
* 结束日期
*/
private Date endDate;
/**
* 合同描述
*/
private String description;
/**
* 合同文件ID
*/
private String contractFileId;
/**
* 已签署合同文件ID
*/
private String signedContractFileId;
/**
* 创建用户
*/
private String createUser;
/**
* 创建时间
*/
private Date createTime;
/**
* 更新用户
*/
private String updateUser;
/**
* 更新时间
*/
private Date updateTime;
}
@Data
@Table(name = "t_contract_sign_task")
public class ContractSignTask implements Serializable {
/**
* 任务ID
*/
@Id
private String taskId;
/**
* 合同ID
*/
private String contractId;
/**
* 企业ID
*/
private String enterpriseId;
/**
* 企业名称
*/
private String enterpriseName;
/**
* 签署状态
*/
@Enumerated(EnumType.STRING)
private SignStatus signStatus;
/**
* 签署人姓名
*/
private String signerName;
/**
* 签署人职位
*/
private String signerPosition;
/**
* 签署方法
*/
@Enumerated(EnumType.STRING)
private SignMethod signMethod;
/**
* 数字签名
*/
private String signature;
/**
* 签署时间
*/
private Date signTime;
/**
* 创建时间
*/
private Date createTime;
/**
* 更新时间
*/
private Date updateTime;
}
@Data
@Table(name = "t_contract_log")
public class ContractLog implements Serializable {
/**
* 日志ID
*/
@Id
private String logId;
/**
* 合同ID
*/
private String contractId;
/**
* 操作类型
*/
@Enumerated(EnumType.STRING)
private ContractOperationType operationType;
/**
* 操作描述
*/
private String operationDesc;
/**
* 操作用户
*/
private String operationUser;
/**
* 操作时间
*/
private Date operationTime;
/**
* IP地址
*/
private String ip;
}
/**
* 合同状态枚举
*/
public enum ContractStatus {
/**
* 草稿
*/
DRAFT,
/**
* 待签署
*/
PENDING_SIGNING,
/**
* 已签署
*/
SIGNED,
/**
* 已完成
*/
COMPLETED,
/**
* 已取消
*/
CANCELED,
/**
* 已过期
*/
EXPIRED
}
/**
* 合同类型枚举
*/
public enum ContractType {
/**
* 采购合同
*/
PURCHASE,
/**
* 销售合同
*/
SALES,
/**
* 融资合同
*/
FINANCING,
/**
* 一般合同
*/
GENERAL
}
/**
* 签署状态枚举
*/
public enum SignStatus {
/**
* 待签署
*/
PENDING,
/**
* 已签署
*/
SIGNED,
/**
* 已拒绝
*/
REJECTED
}
/**
* 签署方法枚举
*/
public enum SignMethod {
/**
* 数字签名
*/
DIGITAL_SIGNATURE,
/**
* 电子签章
*/
ELECTRONIC_SEAL,
/**
* 手写签名
*/
HANDWRITTEN
}
/**
* 合同操作类型枚举
*/
public enum ContractOperationType {
/**
* 创建
*/
CREATE,
/**
* 提交签署
*/
SUBMIT,
/**
* 签署
*/
SIGN,
/**
* 拒绝签署
*/
REJECT,
/**
* 取消
*/
CANCEL,
/**
* 完成
*/
COMPLETE,
/**
* 下载
*/
DOWNLOAD,
/**
* 查看
*/
VIEW
}
public class ContractBusinessException extends BusinessException {
/**
* 合同不存在
*/
public static final int CONTRACT_NOT_FOUND = 4001;
/**
* 合同状态错误
*/
public static final int CONTRACT_STATUS_ERROR = 4002;
/**
* 无权操作
*/
public static final int NO_PERMISSION = 4003;
/**
* 签署信息错误
*/
public static final int SIGN_INFO_ERROR = 4004;
/**
* 签署任务不存在
*/
public static final int SIGN_TASK_NOT_FOUND = 4005;
/**
* 构造函数
*
* @param code 错误码
* @param message 错误信息
*/
public ContractBusinessException(int code, String message) {
super(code, message);
}
}
@RestControllerAdvice
@Slf4j
public class ContractExceptionHandler {
/**
* 处理合同业务异常
*/
@ExceptionHandler(ContractBusinessException.class)
public ApiResult<String> handleContractBusinessException(ContractBusinessException ex) {
log.warn("合同业务异常: {}", ex.getMessage());
return ApiResult.failed(ex.getCode(), ex.getMessage());
}
/**
* 处理合同文件异常
*/
@ExceptionHandler(ContractFileException.class)
public ApiResult<String> handleContractFileException(ContractFileException ex) {
log.error("合同文件处理异常", ex);
return ApiResult.failed(ex.getCode(), ex.getMessage());
}
}
@Service
@RequiredArgsConstructor
@Slf4j
public class ContractCacheServiceImpl implements ContractCacheService {
private final RedisTemplate<String, Object> redisTemplate;
private static final String CONTRACT_CACHE_KEY_PREFIX = "contract:detail:";
private static final long CONTRACT_CACHE_EXPIRE_TIME = 3600L; // 一小时
@Override
public void cacheContract(Contract contract) {
if (contract == null) {
return;
}
String key = CONTRACT_CACHE_KEY_PREFIX + contract.getContractId();
redisTemplate.opsForValue().set(key, contract, CONTRACT_CACHE_EXPIRE_TIME, TimeUnit.SECONDS);
log.debug("缓存合同信息, ID: {}", contract.getContractId());
}
@Override
public Contract getContractFromCache(String contractId) {
String key = CONTRACT_CACHE_KEY_PREFIX + contractId;
Object cachedContract = redisTemplate.opsForValue().get(key);
if (cachedContract instanceof Contract) {
log.debug("从缓存获取合同信息, ID: {}", contractId);
return (Contract) cachedContract;
}
return null;
}
@Override
public void removeContractCache(String contractId) {
String key = CONTRACT_CACHE_KEY_PREFIX + contractId;
redisTemplate.delete(key);
log.debug("移除合同缓存, ID: {}", contractId);
}
}
┌──────────┐ ┌───────────────┐ ┌─────────────┐ ┌──────────┐ ┌───────────┐ ┌─────────┐
│ 客户端 │ │ 控制器层 │ │ 服务层 │ │ 数据访问层│ │ 文件服务 │ │ 缓存层 │
└────┬─────┘ └───────┬───────┘ └──────┬──────┘ └────┬─────┘ └─────┬─────┘ └────┬────┘
│ │ │ │ │ │
│ 1.创建合同请求 │ │ │ │ │
│──────────────────>│ │ │ │ │
│ │ │ │ │ │
│ │ 2.调用创建合同服务 │ │ │ │
│ │────────────────────>│ │ │ │
│ │ │ │ │ │
│ │ │ 3.校验企业信息 │ │ │
│ │ │────────────────>│ │ │
│ │ │ │ │ │
│ │ │ 4.返回校验结果 │ │ │
│ │ │<────────────────│ │ │
│ │ │ │ │ │
│ │ │ 5.保存合同基本信息 │ │
│ │ │────────────────>│ │ │
│ │ │ │ │ │
│ │ │ 6.生成合同文件 │ │ │
│ │ │──────────────────────────────────>│ │
│ │ │ │ │ │
│ │ │ 7.返回文件ID │ │ │
│ │ │<──────────────────────────────────│ │
│ │ │ │ │ │
│ │ │ 8.更新合同文件ID│ │ │
│ │ │────────────────>│ │ │
│ │ │ │ │ │
│ │ │ 9.缓存合同信息 │ │ │
│ │ │──────────────────────────────────────────────────>│
│ │ │ │ │ │
│ │ 10.返回创建结果 │ │ │ │
│ │<────────────────────│ │ │ │
│ │ │ │ │ │
│ 11.返回合同ID和下载链接 │ │ │ │
│<──────────────────│ │ │ │ │
│ │ │ │ │ │
│ 12.提交合同签署请求 │ │ │ │
│──────────────────>│ │ │ │ │
│ │ │ │ │ │
│ │ 13.调用提交签署服务 │ │ │ │
│ │────────────────────>│ │ │ │
│ │ │ │ │ │
│ │ │ 14.查询合同信息 │ │ │
│ │ │────────────────>│ │ │
│ │ │ │ │ │
│ │ │ 15.更新合同状态 │ │ │
│ │ │────────────────>│ │ │
│ │ │ │ │ │
│ │ │ 16.创建签署任务 │ │ │
│ │ │────────────────>│ │ │
│ │ │ │ │ │
│ │ 17.返回提交结果 │ │ │ │
│ │<────────────────────│ │ │ │
│ │ │ │ │ │
│ 18.返回签署链接 │ │ │ │ │
│<──────────────────│ │ │ │ │
│ │ │ │ │ │
│ 19.甲方签署请求 │ │ │ │ │
│──────────────────>│ │ │ │ │
│ │ │ │ │ │
│ │ 20.调用签署服务 │ │ │ │
│ │────────────────────>│ │ │ │
│ │ │ │ │ │
│ │ │ 21.验证签署权限 │ │ │
│ │ │────────────────>│ │ │
│ │ │ │ │ │
│ │ │ 22.创建数字签名 │ │ │
│ │ │──────────────────────────────────>│ │
│ │ │ │ │ │
│ │ │ 23.更新签署状态 │ │ │
│ │ │────────────────>│ │ │
│ │ │ │ │ │
│ │ 24.返回签署结果 │ │ │ │
│ │<────────────────────│ │ │ │
│ │ │ │ │ │
│ 25.返回甲方签署成功 │ │ │ │
│<──────────────────│ │ │ │ │
│ │ │ │ │ │
│ 26.乙方签署请求 │ │ │ │ │
│──────────────────>│ │ │ │ │
│ │ │ │ │ │
│ │ 27.调用签署服务 │ │ │ │
│ │────────────────────>│ │ │ │
│ │ │ │ │ │
│ │ │ 28.验证签署权限 │ │ │
│ │ │────────────────>│ │ │
│ │ │ │ │ │
│ │ │ 29.创建数字签名 │ │ │
│ │ │──────────────────────────────────>│ │
│ │ │ │ │ │
│ │ │ 30.更新签署状态 │ │ │
│ │ │────────────────>│ │ │
│ │ │ │ │ │
│ │ │ 31.检查是否全部签署 │ │
│ │ │────────────────>│ │ │
│ │ │ │ │ │
│ │ │ 32.更新合同为已签署 │ │
│ │ │────────────────>│ │ │
│ │ │ │ │ │
│ │ │ 33.生成签署版合同 │ │
│ │ │──────────────────────────────────>│ │
│ │ │ │ │ │
│ │ 34.返回签署结果 │ │ │ │
│ │<────────────────────│ │ │ │
│ │ │ │ │ │
│ 35.返回合同签署完成 │ │ │ │
│<──────────────────│ │ │ │ │
│ │ │ │ │ │
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
@RequiredArgsConstructor
public class ContractSecurityConfig {
/**
* 配置合同相关接口的安全规则
*/
@Bean
public SecurityFilterChain contractFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authorize -> authorize
// 创建合同接口,企业用户可访问
.requestMatchers(HttpMethod.POST, "/api/v1/contract/create").hasRole("ENTERPRISE")
// 提交签署接口,企业用户可访问
.requestMatchers(HttpMethod.POST, "/api/v1/contract/*/submit").hasRole("ENTERPRISE")
// 签署合同接口,企业用户可访问
.requestMatchers(HttpMethod.POST, "/api/v1/contract/*/sign").hasRole("ENTERPRISE")
// 查询合同详情,企业用户和银行用户可访问
.requestMatchers(HttpMethod.GET, "/api/v1/contract/*").hasAnyRole("ENTERPRISE", "BANK")
// 查询合同列表,企业用户和银行用户可访问
.requestMatchers(HttpMethod.GET, "/api/v1/contract/list").hasAnyRole("ENTERPRISE", "BANK")
// 下载合同文件,企业用户和银行用户可访问
.requestMatchers(HttpMethod.GET, "/api/v1/contract/download/**").hasAnyRole("ENTERPRISE", "BANK")
);
return http.build();
}
}
电子合同签署功能是供应链金融平台中的核心功能之一,为供应链参与方提供了便捷、高效、合法的合同签署方式。本文档详细描述了从合同创建到最终签署的完整生命周期,包括:
整个签约流程基于数字签名技术,确保了合同的法律效力和防篡改性。同时,系统通过完善的日志记录和状态追踪,保证了合同处理过程的透明性和可追溯性。