| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402 |
- package com.ymwk.icvp.signature.service.impl;
- import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
- import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
- import com.ymwk.icvp.component.PageResult;
- import com.ymwk.icvp.component.ResponseDTO;
- import com.ymwk.icvp.pki.entity.CertificateEntity;
- import com.ymwk.icvp.pki.mapper.CertificateMapper;
- import com.ymwk.icvp.signature.entity.Picture;
- import com.ymwk.icvp.signature.entity.Seal;
- import com.ymwk.icvp.signature.mapper.PictureMapper;
- import com.ymwk.icvp.signature.mapper.SealMapper;
- import com.ymwk.icvp.signature.model.*;
- import com.ymwk.icvp.signature.service.SealBuilder;
- import com.ymwk.icvp.signature.service.SealService;
- import com.ymwk.icvp.signature.service.SealVerifyService;
- import com.ymwk.icvp.utils.MinioClientService;
- import lombok.RequiredArgsConstructor;
- import org.springframework.stereotype.Service;
- import org.springframework.transaction.annotation.Transactional;
- import org.springframework.util.StringUtils;
- import java.io.ByteArrayOutputStream;
- import java.io.IOException;
- import java.io.InputStream;
- import java.time.LocalDateTime;
- import java.util.zip.ZipEntry;
- import java.util.zip.ZipOutputStream;
- @Service
- @RequiredArgsConstructor
- public class SealServiceImpl implements SealService {
- private final SealMapper sealMapper;
- private final SealBuilder sealBuilder;
- private final SealVerifyService sealVerifyService;
- private final PictureMapper pictureMapper;
- private final CertificateMapper certificateMapper;
- private final MinioClientService minioClientService;
- @Override
- public ResponseDTO<PageResult<Seal>> pageSeal(SealQueryDTO queryDTO) {
- LambdaQueryWrapper<Seal> wrapper = new LambdaQueryWrapper<>();
- wrapper.like(StringUtils.hasText(queryDTO.getSealAlias()),
- Seal::getSealAlias, queryDTO.getSealAlias())
- .eq(queryDTO.getSealStatus() != null,
- Seal::getSealStatus, queryDTO.getSealStatus())
- .eq(StringUtils.hasText(queryDTO.getAlgorithm()),
- Seal::getAlgorithm, queryDTO.getAlgorithm())
- .ge(queryDTO.getCreateTimeStart() != null,
- Seal::getCreateTime, queryDTO.getCreateTimeStart())
- .le(queryDTO.getCreateTimeEnd() != null,
- Seal::getCreateTime, queryDTO.getCreateTimeEnd())
- .orderByDesc(Seal::getCreateTime);
- Page<Seal> page = sealMapper.selectPage(
- new Page<>(queryDTO.getPageNum(), queryDTO.getPageSize()), wrapper);
- PageResult<Seal> result = new PageResult<>();
- result.setTotal(page.getTotal());
- result.setList(page.getRecords());
- return ResponseDTO.ok(result);
- }
- @Override
- public ResponseDTO<Seal> getSealDetail(Long id) {
- Seal seal = sealMapper.selectById(id);
- /* if (seal == null) {
- return ResponseDTO.error(100001,"印章不存在");
- }*/
- return ResponseDTO.ok(seal);
- }
- @Override
- @Transactional(rollbackFor = Exception.class)
- public ResponseDTO<Long> createSeal(SealCreateDTO createDTO) {
- // 1. 校验印章别名唯一
- Long count = sealMapper.selectCount(new LambdaQueryWrapper<Seal>()
- .eq(Seal::getSealAlias, createDTO.getSealAlias()));
- if (count > 0) {
- return ResponseDTO.error(ResponseDTO.ERROR_CODE, "印章别名已存在:" + createDTO.getSealAlias());
- }
- // 2. 校验算法
- SealAlgorithmEnum algorithm = SealAlgorithmEnum.of(createDTO.getAlgorithm());
- if (algorithm == null) {
- return ResponseDTO.error(ResponseDTO.ERROR_CODE, "不支持的印章算法:" + createDTO.getAlgorithm());
- }
- // 3. 查询印模和证书
- Picture picture = pictureMapper.selectById(createDTO.getImpressionId());
- if (picture == null) {
- return ResponseDTO.error(
- ResponseDTO.ERROR_CODE,
- "印模不存在:" + createDTO.getImpressionId()
- );
- }
- CertificateEntity certificate = certificateMapper.selectById(createDTO.getCertId());
- if (certificate == null) {
- return ResponseDTO.error(
- ResponseDTO.ERROR_CODE,
- "证书不存在:" + createDTO.getCertId()
- );
- }
- // 4. 组装印章基础信息
- Seal seal = new Seal();
- seal.setSealAlias(createDTO.getSealAlias());
- seal.setImpressionId(createDTO.getImpressionId());
- seal.setImpressionAlias(picture.getName());
- seal.setCertId(createDTO.getCertId());
- seal.setCertAlias(certificate.getCertName());
- seal.setAlgorithm(algorithm.getCode());
- seal.setSealStatus(SealStatusEnum.NORMAL.getCode());
- if (certificate.getValidFrom() == null || certificate.getValidTo() == null) {
- return ResponseDTO.error(ResponseDTO.ERROR_CODE, "证书有效期信息不完整");
- }
- seal.setValidStartTime(certificate.getValidFrom());
- seal.setValidEndTime(certificate.getValidTo());
- seal.setRemark(createDTO.getRemark());
- seal.setCreateBy(getCurrentUser());
- seal.setUpdateBy(getCurrentUser());
- LocalDateTime now = LocalDateTime.now();
- seal.setCreateTime(now);
- seal.setUpdateTime(now);
- // 4. 按算法分流构建印章结构体
- if (SealAlgorithmEnum.SM2 == algorithm) {
- seal.setSealFormat(SealFormatEnum.ESL.getCode());
- SealBuildResult buildResult = sealBuilder.buildEsl(seal);
- seal.setSealFileData(buildResult.getFileData());
- seal.setSealFilePath(buildResult.getFilePath());
- } else {
- seal.setSealFormat(SealFormatEnum.CMS.getCode());
- }
- // 5. 计算印章校验值
- seal.setSealCheckValue(sealVerifyService.calcCheckValue(seal));
- // 6. 保存
- sealMapper.insert(seal);
- return ResponseDTO.ok(seal.getId());
- }
- private String getCurrentUser() {
- // TODO 从 SecurityContext / ThreadLocal 获取当前登录用户
- return "system";
- }
- @Override
- @Transactional(rollbackFor = Exception.class)
- public ResponseDTO<Void> freeze(Long id) {
- Seal seal = sealMapper.selectById(id);
- if (seal == null) {
- return ResponseDTO.error(ResponseDTO.ERROR_CODE, "印章不存在");
- }
- // 只有正常状态才允许冻结
- if (!SealStatusEnum.NORMAL.getCode().equals(seal.getSealStatus())) {
- SealStatusEnum current = SealStatusEnum.of(seal.getSealStatus());
- return ResponseDTO.error(ResponseDTO.ERROR_CODE, "当前状态不允许冻结:" + (current != null ? current.getDesc() : "未知"));
- }
- Seal update = new Seal();
- update.setId(id);
- update.setSealStatus(SealStatusEnum.FROZEN.getCode());
- update.setUpdateBy(getCurrentUser());
- sealMapper.updateById(update);
- return ResponseDTO.ok();
- }
- @Override
- @Transactional(rollbackFor = Exception.class)
- public ResponseDTO<Void> unfreeze(Long id) {
- Seal seal = sealMapper.selectById(id);
- if (seal == null) {
- return ResponseDTO.error(ResponseDTO.ERROR_CODE,"印章不存在");
- }
- // 只有冻结状态才允许解冻
- if (!SealStatusEnum.FROZEN.getCode().equals(seal.getSealStatus())) {
- SealStatusEnum current = SealStatusEnum.of(seal.getSealStatus());
- return ResponseDTO.error(ResponseDTO.ERROR_CODE,"当前状态不允许解冻:" + (current != null ? current.getDesc() : "未知"));
- }
- Seal update = new Seal();
- update.setId(id);
- update.setSealStatus(SealStatusEnum.NORMAL.getCode());
- update.setUpdateBy(getCurrentUser());
- sealMapper.updateById(update);
- return ResponseDTO.ok();
- }
- @Override
- @Transactional(rollbackFor = Exception.class)
- public ResponseDTO<Void> destroy(Long id) {
- Seal seal = sealMapper.selectById(id);
- if (seal == null) {
- return ResponseDTO.error(ResponseDTO.ERROR_CODE,"印章不存在");
- }
- // 已销毁的不允许重复销毁
- if (SealStatusEnum.DESTROYED.getCode().equals(seal.getSealStatus())) {
- return ResponseDTO.error(ResponseDTO.ERROR_CODE,"印章已销毁,不可重复操作");
- }
- Seal update = new Seal();
- update.setId(id);
- update.setSealStatus(SealStatusEnum.DESTROYED.getCode());
- update.setUpdateBy(getCurrentUser());
- sealMapper.updateById(update);
- return ResponseDTO.ok();
- }
- @Override
- @Transactional(rollbackFor = Exception.class)
- public ResponseDTO<Void> extend(SealExtendDTO extendDTO) {
- Seal seal = sealMapper.selectById(extendDTO.getSealId());
- if (seal == null) {
- return ResponseDTO.error(ResponseDTO.ERROR_CODE,"印章不存在");
- }
- if (!SealStatusEnum.NORMAL.getCode().equals(seal.getSealStatus())) {
- SealStatusEnum current = SealStatusEnum.of(seal.getSealStatus());
- return ResponseDTO.error(ResponseDTO.ERROR_CODE,"当前状态不允许延期:" + (current != null ? current.getDesc() : "未知"));
- }
- if (seal.getValidEndTime() != null
- && !extendDTO.getNewValidEndTime().isAfter(seal.getValidEndTime())) {
- return ResponseDTO.error(ResponseDTO.ERROR_CODE,"延期时间必须晚于原有效期");
- }
- Seal update = new Seal();
- update.setId(seal.getId());
- update.setValidEndTime(extendDTO.getNewValidEndTime());
- // 用于重算校验值的对象
- Seal checkSeal = new Seal();
- checkSeal.setSealAlias(seal.getSealAlias());
- checkSeal.setCertId(seal.getCertId());
- checkSeal.setImpressionId(seal.getImpressionId());
- checkSeal.setAlgorithm(seal.getAlgorithm());
- checkSeal.setValidEndTime(extendDTO.getNewValidEndTime());
- if (SealAlgorithmEnum.SM2.getCode().equals(seal.getAlgorithm())) {
- // SM2:重新生成 .esl
- seal.setValidEndTime(extendDTO.getNewValidEndTime());
- SealBuildResult buildResult = sealBuilder.rebuildEsl(seal);
- update.setSealFileData(buildResult.getFileData());
- update.setSealFilePath(buildResult.getFilePath());
- checkSeal.setSealFileData(buildResult.getFileData());
- }
- // RSA:无需重建,checkSeal.sealFileData 为 null,走元数据摘要
- update.setSealCheckValue(sealVerifyService.calcCheckValue(checkSeal));
- update.setUpdateBy(getCurrentUser());
- sealMapper.updateById(update);
- return ResponseDTO.ok();
- }
- @Override
- @Transactional(rollbackFor = Exception.class)
- public ResponseDTO<Void> bindCert(SealBindCertDTO bindCertDTO) {
- Seal seal = sealMapper.selectById(bindCertDTO.getSealId());
- if (seal == null) {
- return ResponseDTO.error(ResponseDTO.ERROR_CODE,"印章不存在");
- }
- if (!SealStatusEnum.NORMAL.getCode().equals(seal.getSealStatus())) {
- SealStatusEnum current = SealStatusEnum.of(seal.getSealStatus());
- return ResponseDTO.error(ResponseDTO.ERROR_CODE,"当前状态不允许绑定证书:" + (current != null ? current.getDesc() : "未知"));
- }
- CertificateEntity certificate = certificateMapper.selectById(bindCertDTO.getCertId());
- if (certificate == null) {
- return ResponseDTO.error(ResponseDTO.ERROR_CODE, "证书不存在:" + bindCertDTO.getCertId());
- }
- /* Long boundSealCount = sealMapper.selectCount(new LambdaQueryWrapper<Seal>()
- .eq(Seal::getCertId, bindCertDTO.getCertId())
- .ne(Seal::getId, seal.getId()));
- if (boundSealCount != null && boundSealCount > 0) {
- return ResponseDTO.error(ResponseDTO.ERROR_CODE, "该证书已绑定其他印章");
- }*/
- Seal update = new Seal();
- update.setId(seal.getId());
- update.setCertId(bindCertDTO.getCertId());
- update.setCertAlias(certificate.getCertName());
- if (certificate.getValidFrom() == null || certificate.getValidTo() == null) {
- return ResponseDTO.error(ResponseDTO.ERROR_CODE, "证书有效期信息不完整");
- }
- update.setValidStartTime(certificate.getValidFrom());
- update.setValidEndTime(certificate.getValidTo());
- // 用于重算校验值的对象
- Seal checkSeal = new Seal();
- checkSeal.setSealAlias(seal.getSealAlias());
- checkSeal.setCertId(bindCertDTO.getCertId()); // 新证书
- checkSeal.setImpressionId(seal.getImpressionId());
- checkSeal.setAlgorithm(seal.getAlgorithm());
- checkSeal.setValidEndTime(certificate.getValidTo());
- if (SealAlgorithmEnum.SM2.getCode().equals(seal.getAlgorithm())) {
- // SM2:证书在 .esl 结构体内,必须重新生成
- seal.setCertId(bindCertDTO.getCertId());
- seal.setCertAlias(certificate.getCertName());
- seal.setValidStartTime(certificate.getValidFrom());
- seal.setValidEndTime(certificate.getValidTo());
- SealBuildResult buildResult = sealBuilder.rebuildEsl(seal);
- update.setSealFileData(buildResult.getFileData());
- update.setSealFilePath(buildResult.getFilePath());
- checkSeal.setSealFileData(buildResult.getFileData());
- }
- // RSA:只改 cert_id,无需重建
- update.setSealCheckValue(sealVerifyService.calcCheckValue(checkSeal));
- update.setUpdateBy(getCurrentUser());
- sealMapper.updateById(update);
- return ResponseDTO.ok();
- }
- @Override
- public ResponseDTO<Boolean> verify(Long id) {
- Seal seal = sealMapper.selectById(id);
- if (seal == null) {
- return ResponseDTO.error(ResponseDTO.ERROR_CODE,"印章不存在");
- }
- boolean valid = sealVerifyService.verify(seal);
- return ResponseDTO.ok(valid);
- }
- @Override
- public ResponseDTO<SealDownload> download(Long id) {
- Seal seal = sealMapper.selectById(id);
- if (seal == null) {
- return ResponseDTO.error(ResponseDTO.ERROR_CODE,"印章不存在");
- }
- if (SealStatusEnum.DESTROYED.getCode().equals(seal.getSealStatus())) {
- return ResponseDTO.error(ResponseDTO.ERROR_CODE,"印章已销毁,不可下载");
- }
- // SM2:返回 .esl 字节
- if (SealAlgorithmEnum.SM2.getCode().equals(seal.getAlgorithm())) {
- byte[] data = seal.getSealFileData();
- if (data == null || data.length == 0) {
- return ResponseDTO.error(ResponseDTO.ERROR_CODE,"印章文件不存在");
- }
- return ResponseDTO.ok(new SealDownload(
- data, "seal.esl", "application/octet-stream"));
- }
- if (SealAlgorithmEnum.RSA.getCode().equals(seal.getAlgorithm())) {
- return downloadRsaSeal(seal);
- }
- return ResponseDTO.error(ResponseDTO.ERROR_CODE, "不支持的印章算法:" + seal.getAlgorithm());
- }
- private ResponseDTO<SealDownload> downloadRsaSeal(Seal seal) {
- Picture picture = pictureMapper.selectById(seal.getImpressionId());
- if (picture == null || !StringUtils.hasText(picture.getUrl())) {
- return ResponseDTO.error(ResponseDTO.ERROR_CODE, "印章关联的印模文件不存在");
- }
- CertificateEntity certificate = certificateMapper.selectById(seal.getCertId());
- if (certificate == null || !StringUtils.hasText(certificate.getCertFilePath())) {
- return ResponseDTO.error(ResponseDTO.ERROR_CODE, "印章关联的证书文件不存在");
- }
- String pictureObjectName = extractObjectName(picture.getUrl());
- try (InputStream pictureStream = minioClientService.downloadFile(pictureObjectName);
- InputStream certificateStream = minioClientService.downloadFile(certificate.getCertFilePath());
- ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
- ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream)) {
- addZipEntry(zipOutputStream, "impression.png", pictureStream.readAllBytes());
- addZipEntry(zipOutputStream, "certificate.pem", certificateStream.readAllBytes());
- zipOutputStream.finish();
- return ResponseDTO.ok(new SealDownload(
- outputStream.toByteArray(), "seal_" + seal.getId() + ".zip", "application/zip"));
- } catch (IOException e) {
- throw new RuntimeException("打包RSA印章下载文件失败", e);
- }
- }
- private String extractObjectName(String url) {
- String objectName = url.substring(url.lastIndexOf('/') + 1);
- int queryIndex = objectName.indexOf('?');
- return queryIndex >= 0 ? objectName.substring(0, queryIndex) : objectName;
- }
- private void addZipEntry(ZipOutputStream zipOutputStream, String fileName, byte[] content)
- throws java.io.IOException {
- zipOutputStream.putNextEntry(new ZipEntry(fileName));
- zipOutputStream.write(content);
- zipOutputStream.closeEntry();
- }
- }
|