diff --git a/pom.xml b/pom.xml index 58ebe62a..574bf741 100644 --- a/pom.xml +++ b/pom.xml @@ -71,6 +71,12 @@ 1.8.2 + + com.microsoft.playwright + playwright + 1.40.0 + + com.aliyun.oss aliyun-sdk-oss diff --git a/src/main/java/cn/lihongjie/coal/file/service/FileService.java b/src/main/java/cn/lihongjie/coal/file/service/FileService.java index a0eb25a2..15a6422e 100644 --- a/src/main/java/cn/lihongjie/coal/file/service/FileService.java +++ b/src/main/java/cn/lihongjie/coal/file/service/FileService.java @@ -130,25 +130,65 @@ public class FileService extends BaseService { } String objectKey = fileEntity.getDirectory() + "/" + fileEntity.getObjectId(); - String objectUrl = ""; - // PutObjectResult putObjectResult = - // obsClient.putObject( - // hwCloudProperty.getObs().getBucketName(), - // objectKey, - // file.getInputStream()); - // - // if (putObjectResult.getStatusCode() != 200) { - // throw new BizException("上传文件失败 %s".formatted(putObjectResult.toString())); - // } - // objectUrl = putObjectResult.getObjectUrl(); + fileEntity.setPublicUrl(uploadToOSS(objectKey, file.getInputStream())); + + this.save(fileEntity); + + return getById(fileEntity.getId()); + } + + @SneakyThrows + public FileDto upload( + InputStream file, + String name, + String dir, + String sortKey, + String code, + String remarks) { + FileEntity fileEntity = new FileEntity(); + fileEntity.setFileName(name); + fileEntity.setFileSize(Long.valueOf(file.available())); + fileEntity.setCode(code); + fileEntity.setRemarks(remarks); + try { + + fileEntity.setSortKey(Integer.parseInt(sortKey)); + } catch (Exception e) { + + fileEntity.setSortKey(1); + } + fileEntity.setDirectory( + "%s/%s/%s" + .formatted( + activateProfile, + Ctx.currentUser().getOrganizationId(), + StringUtils.defaultIfBlank(dir, "public"))); + InputStream inputStream = file; + fileEntity.setObjectId( + UUID.randomUUID() + "." + FilenameUtils.getExtension(name.replace(":", "_"))); + try (inputStream) { + fileEntity.setMimeType(tika.detect(inputStream)); + } + + String objectKey = fileEntity.getDirectory() + "/" + fileEntity.getObjectId(); + + fileEntity.setPublicUrl(uploadToOSS(objectKey, file)); + + this.save(fileEntity); + + return getById(fileEntity.getId()); + } + + private String uploadToOSS(String objectKey, InputStream inputStream) { + String objectUrl; try { com.aliyun.oss.model.PutObjectResult objectResult = ossClient.putObject( aliyunProperty.getOSS().getBucketName(), objectKey, - file.getInputStream()); + inputStream); } catch (Exception e) { log.warn("上传文件失败", e); @@ -171,11 +211,6 @@ public class FileService extends BaseService { aliyunProperty.getOSS().getBucketName(), ossRegion.getEndpoint(), objectKey); - - fileEntity.setPublicUrl(objectUrl); - - this.save(fileEntity); - - return getById(fileEntity.getId()); + return objectUrl; } } diff --git a/src/main/java/cn/lihongjie/coal/pdfGenerator/controller/PdfGeneratorController.java b/src/main/java/cn/lihongjie/coal/pdfGenerator/controller/PdfGeneratorController.java new file mode 100644 index 00000000..20e1fc29 --- /dev/null +++ b/src/main/java/cn/lihongjie/coal/pdfGenerator/controller/PdfGeneratorController.java @@ -0,0 +1,61 @@ +package cn.lihongjie.coal.pdfGenerator.controller; + +import cn.lihongjie.coal.annotation.OrgScope; +import cn.lihongjie.coal.annotation.SysLog; +import cn.lihongjie.coal.base.dto.CommonQuery; +import cn.lihongjie.coal.base.dto.IdRequest; +import cn.lihongjie.coal.pdfGenerator.dto.CreatePdfGeneratorDto; +import cn.lihongjie.coal.pdfGenerator.dto.GeneratePdfDto; +import cn.lihongjie.coal.pdfGenerator.dto.PdfGeneratorDto; +import cn.lihongjie.coal.pdfGenerator.dto.UpdatePdfGeneratorDto; +import cn.lihongjie.coal.pdfGenerator.service.PdfGeneratorService; + +import lombok.extern.slf4j.Slf4j; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +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; + +@RestController +@RequestMapping("/pdfGenerator") +@SysLog(module = "Pdf生成器") +@Slf4j +@OrgScope +public class PdfGeneratorController { + @Autowired private PdfGeneratorService service; + + @PostMapping("/create") + public PdfGeneratorDto create(@RequestBody CreatePdfGeneratorDto request) { + return this.service.create(request); + } + + @PostMapping("/update") + public PdfGeneratorDto update(@RequestBody UpdatePdfGeneratorDto request) { + return this.service.update(request); + } + + @PostMapping("/delete") + public Object delete(@RequestBody IdRequest request) { + this.service.delete(request); + return true; + } + + @PostMapping("/getById") + public PdfGeneratorDto getById(@RequestBody IdRequest request) { + return this.service.getById(request.getId()); + } + + + @PostMapping("/generate") + public PdfGeneratorDto generate(@RequestBody GeneratePdfDto request) { + return this.service.generate(request); + } + + @PostMapping("/list") + public Page list(@RequestBody CommonQuery request) { + return this.service.list(request); + } +} diff --git a/src/main/java/cn/lihongjie/coal/pdfGenerator/dto/CreatePdfGeneratorDto.java b/src/main/java/cn/lihongjie/coal/pdfGenerator/dto/CreatePdfGeneratorDto.java new file mode 100644 index 00000000..c3ab8529 --- /dev/null +++ b/src/main/java/cn/lihongjie/coal/pdfGenerator/dto/CreatePdfGeneratorDto.java @@ -0,0 +1,13 @@ +package cn.lihongjie.coal.pdfGenerator.dto; + +import cn.lihongjie.coal.base.dto.OrgCommonDto; + +import lombok.Data; + +@Data +public class CreatePdfGeneratorDto extends OrgCommonDto { + + + + +} diff --git a/src/main/java/cn/lihongjie/coal/pdfGenerator/dto/GeneratePdfDto.java b/src/main/java/cn/lihongjie/coal/pdfGenerator/dto/GeneratePdfDto.java new file mode 100644 index 00000000..5bc118e4 --- /dev/null +++ b/src/main/java/cn/lihongjie/coal/pdfGenerator/dto/GeneratePdfDto.java @@ -0,0 +1,15 @@ +package cn.lihongjie.coal.pdfGenerator.dto; + +import cn.lihongjie.coal.base.dto.OrgCommonDto; + +import com.fasterxml.jackson.databind.node.ObjectNode; + +import lombok.Data; + +@Data +public class GeneratePdfDto extends OrgCommonDto { + private String htmlUrl; + private String htmlText; + + private ObjectNode options; +} diff --git a/src/main/java/cn/lihongjie/coal/pdfGenerator/dto/PdfGeneratorDto.java b/src/main/java/cn/lihongjie/coal/pdfGenerator/dto/PdfGeneratorDto.java new file mode 100644 index 00000000..692c71c3 --- /dev/null +++ b/src/main/java/cn/lihongjie/coal/pdfGenerator/dto/PdfGeneratorDto.java @@ -0,0 +1,28 @@ +package cn.lihongjie.coal.pdfGenerator.dto; + +import cn.lihongjie.coal.base.dto.OrgCommonDto; + +import lombok.Data; + +import java.time.LocalDateTime; + +@Data +public class PdfGeneratorDto extends OrgCommonDto { + + + private String htmlUrl; + private String htmlText; + + + private String pdfUrl; + + + private LocalDateTime startTime; + private LocalDateTime endTime; + + private Long duration; + + + private String options; + +} diff --git a/src/main/java/cn/lihongjie/coal/pdfGenerator/dto/UpdatePdfGeneratorDto.java b/src/main/java/cn/lihongjie/coal/pdfGenerator/dto/UpdatePdfGeneratorDto.java new file mode 100644 index 00000000..a2cc6d21 --- /dev/null +++ b/src/main/java/cn/lihongjie/coal/pdfGenerator/dto/UpdatePdfGeneratorDto.java @@ -0,0 +1,8 @@ +package cn.lihongjie.coal.pdfGenerator.dto; + +import cn.lihongjie.coal.base.dto.OrgCommonDto; + +import lombok.Data; + +@Data +public class UpdatePdfGeneratorDto extends OrgCommonDto {} diff --git a/src/main/java/cn/lihongjie/coal/pdfGenerator/entity/PdfGeneratorEntity.java b/src/main/java/cn/lihongjie/coal/pdfGenerator/entity/PdfGeneratorEntity.java new file mode 100644 index 00000000..521903b7 --- /dev/null +++ b/src/main/java/cn/lihongjie/coal/pdfGenerator/entity/PdfGeneratorEntity.java @@ -0,0 +1,46 @@ +package cn.lihongjie.coal.pdfGenerator.entity; + +import cn.lihongjie.coal.base.entity.OrgCommonEntity; + +import jakarta.persistence.Entity; + +import lombok.Data; + +import org.hibernate.annotations.Comment; +import org.hibernate.annotations.Formula; + +import java.time.LocalDateTime; + +@Data +@Entity +public class PdfGeneratorEntity extends OrgCommonEntity { + + + + private String htmlUrl; + private String htmlText; + + + private String pdfUrl; + + + private LocalDateTime startTime; + private LocalDateTime endTime; + + private Long duration; + + + private String options; + + @Comment("生成状态") + private String execStatus; + + @Formula( + "(select i.name\n" + + "from t_dictionary d,\n" + + " t_dictionary_item i\n" + + "where d.id = i.dictionary_id\n" + + " and d.code = 'common.execStatus'\n" + + " and i.code = exec_status)") + private String execStatusName; +} diff --git a/src/main/java/cn/lihongjie/coal/pdfGenerator/mapper/PdfGeneratorMapper.java b/src/main/java/cn/lihongjie/coal/pdfGenerator/mapper/PdfGeneratorMapper.java new file mode 100644 index 00000000..e85d1c1e --- /dev/null +++ b/src/main/java/cn/lihongjie/coal/pdfGenerator/mapper/PdfGeneratorMapper.java @@ -0,0 +1,25 @@ +package cn.lihongjie.coal.pdfGenerator.mapper; + +import cn.lihongjie.coal.base.mapper.BaseMapper; +import cn.lihongjie.coal.base.mapper.CommonMapper; +import cn.lihongjie.coal.pdfGenerator.dto.CreatePdfGeneratorDto; +import cn.lihongjie.coal.pdfGenerator.dto.GeneratePdfDto; +import cn.lihongjie.coal.pdfGenerator.dto.PdfGeneratorDto; +import cn.lihongjie.coal.pdfGenerator.dto.UpdatePdfGeneratorDto; +import cn.lihongjie.coal.pdfGenerator.entity.PdfGeneratorEntity; + +import org.mapstruct.Mapper; +import org.mapstruct.control.DeepClone; + +@Mapper( + componentModel = org.mapstruct.MappingConstants.ComponentModel.SPRING, + uses = {CommonMapper.class}, + mappingControl = DeepClone.class) +public interface PdfGeneratorMapper + extends BaseMapper< + PdfGeneratorEntity, + PdfGeneratorDto, + CreatePdfGeneratorDto, + UpdatePdfGeneratorDto> { + PdfGeneratorEntity toEntity(GeneratePdfDto request); +} diff --git a/src/main/java/cn/lihongjie/coal/pdfGenerator/repository/PdfGeneratorRepository.java b/src/main/java/cn/lihongjie/coal/pdfGenerator/repository/PdfGeneratorRepository.java new file mode 100644 index 00000000..d0ec3ced --- /dev/null +++ b/src/main/java/cn/lihongjie/coal/pdfGenerator/repository/PdfGeneratorRepository.java @@ -0,0 +1,9 @@ +package cn.lihongjie.coal.pdfGenerator.repository; + +import cn.lihongjie.coal.base.dao.BaseRepository; +import cn.lihongjie.coal.pdfGenerator.entity.PdfGeneratorEntity; + +import org.springframework.stereotype.Repository; + +@Repository +public interface PdfGeneratorRepository extends BaseRepository {} diff --git a/src/main/java/cn/lihongjie/coal/pdfGenerator/service/PdfGeneratorService.java b/src/main/java/cn/lihongjie/coal/pdfGenerator/service/PdfGeneratorService.java new file mode 100644 index 00000000..ea2714ac --- /dev/null +++ b/src/main/java/cn/lihongjie/coal/pdfGenerator/service/PdfGeneratorService.java @@ -0,0 +1,188 @@ +package cn.lihongjie.coal.pdfGenerator.service; + +import cn.lihongjie.coal.base.dto.CommonQuery; +import cn.lihongjie.coal.base.dto.IdRequest; +import cn.lihongjie.coal.base.service.BaseService; +import cn.lihongjie.coal.file.dto.FileDto; +import cn.lihongjie.coal.file.service.FileService; +import cn.lihongjie.coal.pdfGenerator.dto.CreatePdfGeneratorDto; +import cn.lihongjie.coal.pdfGenerator.dto.GeneratePdfDto; +import cn.lihongjie.coal.pdfGenerator.dto.PdfGeneratorDto; +import cn.lihongjie.coal.pdfGenerator.dto.UpdatePdfGeneratorDto; +import cn.lihongjie.coal.pdfGenerator.entity.PdfGeneratorEntity; +import cn.lihongjie.coal.pdfGenerator.mapper.PdfGeneratorMapper; +import cn.lihongjie.coal.pdfGenerator.repository.PdfGeneratorRepository; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.microsoft.playwright.Browser; +import com.microsoft.playwright.Playwright; +import com.microsoft.playwright.Response; + +import jakarta.annotation.PreDestroy; + +import lombok.Cleanup; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.convert.ConversionService; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Sort; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.io.ByteArrayInputStream; +import java.time.Duration; +import java.time.LocalDateTime; + +@Service +@Slf4j +@Transactional +public class PdfGeneratorService extends BaseService { + @Autowired FileService fileService; + @Autowired ObjectMapper objectMapper; + @Autowired private PdfGeneratorRepository repository; + @Autowired private PdfGeneratorMapper mapper; + @Autowired private ConversionService conversionService; + private Boolean chromeInit = false; + private Playwright playwright; + private Browser browser; + + @PreDestroy + public void destroy() { + log.info("销毁chrome"); + if (browser != null) { + + browser.close(); + } + + if (playwright != null) { + + playwright.close(); + } + } + + @SneakyThrows + public PdfGeneratorDto generate(GeneratePdfDto request) { + + synchronized (this) { + LocalDateTime startTime = LocalDateTime.now(); + if (!chromeInit) { + log.info("初始化chrome"); + + playwright = Playwright.create(); + browser = playwright.chromium().launch(); + chromeInit = true; + } + + @Cleanup com.microsoft.playwright.Page page = browser.newPage(); + + if (StringUtils.isNotEmpty(request.getHtmlText())) { + page.setContent(request.getHtmlText()); + } else if (StringUtils.isNotEmpty(request.getHtmlUrl())) { + Response response = page.navigate(request.getHtmlUrl()); + + log.info("访问{}返回{}", request.getHtmlUrl(), response.status()); + } else { + throw new IllegalArgumentException("htmlText和htmlUrl不能同时为空"); + } + + com.microsoft.playwright.Page.PdfOptions pdfOptions = null; + if (request.getOptions() != null) { + pdfOptions = + objectMapper.treeToValue( + request.getOptions(), + com.microsoft.playwright.Page.PdfOptions.class); + } + PdfGeneratorEntity entity = mapper.toEntity(request); + boolean error = false; + String stackTrace = null; + byte[] pdf = null; + try { + + pdf = page.pdf(pdfOptions); + } catch (Exception e) { + + log.error("生成pdf失败", e); + stackTrace = ExceptionUtils.getStackTrace(e); + error = true; + } + + if (pdf != null) { + + FileDto generatePdf = null; + try { + + generatePdf = + fileService.upload( + new ByteArrayInputStream(pdf), + request.getName(), + "generatePdf", + null, + null, + ""); + } catch (Exception e) { + log.error("上传pdf失败", e); + error = true; + stackTrace = ExceptionUtils.getStackTrace(e); + } + + if (!error) { + + entity.setPdfUrl(generatePdf.getPublicUrl()); + } + } + + entity.setEndTime(LocalDateTime.now()); + + entity.setDuration(Duration.between(startTime, entity.getEndTime()).toMillis()); + + entity.setRemarks(stackTrace); + entity.setExecStatus(error ? "1" : "0"); + + this.save(entity); + return this.mapper.toDto(entity); + } + } + + public PdfGeneratorDto create(CreatePdfGeneratorDto request) { + PdfGeneratorEntity entity = mapper.toEntity(request); + + this.repository.save(entity); + return getById(entity.getId()); + } + + public PdfGeneratorDto update(UpdatePdfGeneratorDto request) { + PdfGeneratorEntity entity = this.repository.get(request.getId()); + this.mapper.updateEntity(entity, request); + + this.repository.save(entity); + + return getById(entity.getId()); + } + + public void delete(IdRequest request) { + this.repository.deleteAllById(request.getIds()); + } + + public PdfGeneratorDto getById(String id) { + PdfGeneratorEntity entity = repository.get(id); + + return mapper.toDto(entity); + } + + public Page list(CommonQuery query) { + Page page = + repository.findAll( + query.specification(conversionService), + PageRequest.of( + query.getPageNo(), + query.getPageSize(), + Sort.by(query.getOrders()))); + + return page.map(this.mapper::toDto); + } +} diff --git a/src/main/resources/config/dictionary.json b/src/main/resources/config/dictionary.json index 37d69669..4eb8d5e3 100644 --- a/src/main/resources/config/dictionary.json +++ b/src/main/resources/config/dictionary.json @@ -1703,6 +1703,20 @@ } ] }, + { + "code": "common.execStatus", + "name": "通用状态", + "item": [ + { + "code": "0", + "name": "成功" + }, + { + "code": "1", + "name": "失败" + } + ] + }, { "code": "loginUserHis.loginStatus", "name": "登录状态",