├── .gitignore ├── .idea ├── .gitignore ├── compiler.xml ├── encodings.xml ├── jarRepositories.xml ├── misc.xml └── vcs.xml ├── LICENSE ├── README.md ├── docs ├── images │ ├── 1705906252616-c7176b84-502b-4fa1-a795-71abb78a4978.png │ ├── 1705908549370-57691237-9ed9-4b74-83c1-38ce82ded646.png │ ├── pdf-cert.png │ ├── product.png │ ├── seal-template.png │ ├── seal-ym.png │ ├── signature.png │ └── verify.png └── kaifangqian-doc.pdf ├── kaifangqian-api ├── README.md ├── pom.xml └── src │ └── main │ ├── java │ └── org │ │ └── resrun │ │ └── api │ │ ├── OpenSignApiApplication.java │ │ ├── aop │ │ ├── AopLog.java │ │ └── CheckParamAspect.java │ │ ├── config │ │ ├── ApiClientConfig.java │ │ └── SpringBeanManage.java │ │ ├── controller │ │ └── APIController.java │ │ ├── enums │ │ ├── APIResultEnum.java │ │ ├── BusinessErrorEnum.java │ │ ├── ParamFormatErrorEnum.java │ │ └── SignTypeEnum.java │ │ ├── exception │ │ ├── APIExceptionHandler.java │ │ ├── BusinessException.java │ │ ├── ParamFormatException.java │ │ └── ResultException.java │ │ ├── pdfbox │ │ ├── AssinaturaPDF.java │ │ ├── CMSProcessableInputStream.java │ │ ├── CreatedPDFForm.java │ │ ├── SigUtils.java │ │ ├── SignatureBase.java │ │ ├── TSAClient.java │ │ ├── ValidationTimeStamp.java │ │ └── vo │ │ │ ├── AssinaturaModel.java │ │ │ ├── AssinaturaPosition.java │ │ │ ├── CertificateInfo.java │ │ │ └── FormField.java │ │ ├── service │ │ ├── CalculatePositionService.java │ │ ├── CertHttpService.java │ │ ├── EntSealGenerateService.java │ │ └── pojo │ │ │ ├── ApplyCert.java │ │ │ ├── ApplyCertData.java │ │ │ ├── BaseCertificateInfo.java │ │ │ ├── CertGenerateProperty.java │ │ │ ├── CertSubjectProperty.java │ │ │ ├── CertificateProperty.java │ │ │ ├── CertificationInfo.java │ │ │ ├── PdfOperateProperty.java │ │ │ ├── PositionProperty.java │ │ │ ├── PositionSignPage.java │ │ │ ├── RealPositionProperty.java │ │ │ ├── SelectKeywords.java │ │ │ ├── SignPanelInfo.java │ │ │ └── SourcePositionProperty.java │ │ ├── utils │ │ ├── Base64.java │ │ ├── BusinessUtils.java │ │ ├── CallBack.java │ │ ├── CertificateSort.java │ │ ├── ConvertImage.java │ │ ├── HttpUtils.java │ │ ├── IOUtils.java │ │ ├── IPUtil.java │ │ ├── MyStringUtils.java │ │ ├── SpringContextHolder.java │ │ └── SystemCertIuss.java │ │ ├── validation │ │ ├── SignTypeValid.java │ │ ├── SignTypeValidator.java │ │ └── ValidationSorts.java │ │ └── vo │ │ ├── base │ │ ├── APIRequest.java │ │ ├── Result.java │ │ └── SignLocation.java │ │ ├── request │ │ ├── CertEventRequest.java │ │ ├── DocumentSignRequest.java │ │ └── SignatureMakeRequest.java │ │ └── response │ │ ├── CertEventResponse.java │ │ ├── DocumentSignResponse.java │ │ └── SignatureMakeResponse.java │ └── resources │ ├── application-prod.yml │ ├── application.yml │ ├── ip2region │ └── ip2region.xdb │ ├── logback-spring.xml │ └── root │ └── root.jks ├── kaifangqian-demo-api ├── README.md ├── pom.xml └── src │ ├── main │ ├── java │ │ └── org │ │ │ └── resrun │ │ │ ├── OpenSignDemoApplication.java │ │ │ ├── aop │ │ │ └── AopLog.java │ │ │ ├── config │ │ │ └── SpringBeanManage.java │ │ │ ├── controller │ │ │ ├── OpenSignController.java │ │ │ └── vo │ │ │ │ ├── base │ │ │ │ └── Result.java │ │ │ │ ├── request │ │ │ │ ├── ClipSealRequest.java │ │ │ │ ├── GenerateSealRequest.java │ │ │ │ ├── PositionRequest.java │ │ │ │ ├── SignRequest.java │ │ │ │ └── VerifyRequest.java │ │ │ │ └── response │ │ │ │ ├── SealResponse.java │ │ │ │ ├── SignResponse.java │ │ │ │ └── VerifyResponse.java │ │ │ ├── enums │ │ │ ├── SealColorEnum.java │ │ │ ├── SealShapeStyleEnum.java │ │ │ ├── SignStatus.java │ │ │ └── SignTypeEnum.java │ │ │ ├── service │ │ │ ├── cert │ │ │ │ └── CertService.java │ │ │ ├── image │ │ │ │ ├── EntSealClipService.java │ │ │ │ ├── PdfConvertImageService.java │ │ │ │ └── PersonalSealService.java │ │ │ ├── pojo │ │ │ │ ├── BaseCertificateInfo.java │ │ │ │ ├── CertificateProperty.java │ │ │ │ ├── ConvertImage.java │ │ │ │ ├── GenerateCertificateInfo.java │ │ │ │ ├── RealPositionProperty.java │ │ │ │ ├── SelectKeywords.java │ │ │ │ ├── SignPdfInfoVo.java │ │ │ │ ├── SignatureDetail.java │ │ │ │ └── SourcePositionProperty.java │ │ │ └── verify │ │ │ │ ├── ExtImageRenderListener.java │ │ │ │ ├── SignVerifyService.java │ │ │ │ └── VerifySign.java │ │ │ └── utils │ │ │ ├── Base64.java │ │ │ ├── CallBack.java │ │ │ ├── IOUtils.java │ │ │ ├── IPUtil.java │ │ │ ├── MyStringUtils.java │ │ │ └── SpringContextHolder.java │ └── resources │ │ ├── application-prod.yml │ │ ├── application.yml │ │ ├── ip2region │ │ └── ip2region.xdb │ │ ├── logback-spring.xml │ │ └── 开源工具版说明.pdf │ └── test │ ├── java │ └── org │ │ └── resrun │ │ ├── ApplyCertTest.java │ │ ├── ChopStampSignTest.java │ │ ├── PositionSignTest.java │ │ ├── PsersonSealTest.java │ │ └── UpdateCertPassword.java │ └── resources │ ├── example.pdf │ └── seal.png ├── kaifangqian-demo-vue ├── .gitignore ├── LICENSE ├── README.md ├── index.html ├── jsconfig.json ├── package.json ├── public │ └── favicon.ico ├── src │ ├── App.vue │ ├── assets │ │ ├── images │ │ │ ├── doc_1.png │ │ │ ├── doc_2.png │ │ │ ├── kaifangqian-logo.png │ │ │ ├── pdf-cert.png │ │ │ ├── product.png │ │ │ ├── seal-template.png │ │ │ ├── seal-ym.png │ │ │ ├── signature-bg.png │ │ │ ├── signature.png │ │ │ └── verify.png │ │ ├── main.css │ │ └── style │ │ │ └── main.less │ ├── components │ │ ├── control │ │ │ ├── ControlItem.vue │ │ │ └── data │ │ │ │ ├── ControlData.ts │ │ │ │ └── ControlerMoveRange.ts │ │ └── scrollbar │ │ │ ├── index.ts │ │ │ ├── scrollbarDirective.ts │ │ │ ├── src │ │ │ ├── Bar.vue │ │ │ ├── Index.vue │ │ │ ├── index.d.ts │ │ │ ├── resize-event.ts │ │ │ └── utils.ts │ │ │ └── usePerfectScrollbar.ts │ ├── layouts │ │ └── header │ │ │ └── index.vue │ ├── main.js │ ├── router │ │ └── index.js │ ├── utils │ │ ├── axios │ │ │ └── index.ts │ │ ├── flexible.js │ │ ├── index.js │ │ └── request.ts │ └── views │ │ ├── SealModal.vue │ │ ├── SignatureModal.vue │ │ ├── data │ │ └── image.ts │ │ └── main.vue └── vite.config.js ├── kaifangqian-sdk ├── README.md ├── pom.xml └── src │ └── main │ ├── java │ └── org │ │ └── resrun │ │ └── sdk │ │ ├── config │ │ └── SDKClientConfig.java │ │ ├── enums │ │ ├── APIResultEnum.java │ │ ├── BusinessErrorEnum.java │ │ ├── ControlPropertyTypePageConfigEnum.java │ │ ├── ParamFormatErrorEnum.java │ │ └── SDKSignTypeEnum.java │ │ ├── exception │ │ ├── BusinessException.java │ │ ├── ParamFormatException.java │ │ └── ResultException.java │ │ ├── pdfbox │ │ ├── AssinaturaPDF.java │ │ ├── CMSProcessableInputStream.java │ │ ├── CreatedPDFForm.java │ │ ├── SigUtils.java │ │ ├── SignatureBase.java │ │ ├── TSAClient.java │ │ └── vo │ │ │ ├── AssinaturaModel.java │ │ │ ├── AssinaturaPosition.java │ │ │ ├── CertificateInfo.java │ │ │ └── FormField.java │ │ ├── service │ │ ├── CalculatePositionService.java │ │ ├── CertHttpService.java │ │ ├── EntSealGenerateService.java │ │ ├── SDKService.java │ │ └── pojo │ │ │ ├── ApplyCert.java │ │ │ ├── ApplyCertData.java │ │ │ ├── BaseCertificateInfo.java │ │ │ ├── CertGenerateProperty.java │ │ │ ├── CertSubjectProperty.java │ │ │ ├── CertificateProperty.java │ │ │ ├── CertificationInfo.java │ │ │ ├── PdfOperateProperty.java │ │ │ ├── PositionProperty.java │ │ │ ├── PositionSignPage.java │ │ │ ├── RealPositionProperty.java │ │ │ ├── SelectKeywords.java │ │ │ ├── SignPanelInfo.java │ │ │ └── SourcePositionProperty.java │ │ ├── utils │ │ ├── Base64.java │ │ ├── CertificateSort.java │ │ ├── ConvertImage.java │ │ ├── CutImage.java │ │ ├── HttpUtils.java │ │ ├── IOUtils.java │ │ └── SystemCertIuss.java │ │ └── vo │ │ ├── base │ │ ├── APIRequest.java │ │ ├── Result.java │ │ └── SignLocation.java │ │ ├── request │ │ ├── CertEventRequest.java │ │ └── DocumentSignRequest.java │ │ └── response │ │ ├── CertEventResponse.java │ │ └── DocumentSignResponse.java │ └── resources │ └── root │ └── root.jks └── pom.xml /.gitignore: -------------------------------------------------------------------------------- 1 | ### IntelliJ IDEA ### 2 | .idea/modules.xml 3 | .idea/jarRepositories.xml 4 | .idea/compiler.xml 5 | .idea/libraries/ 6 | *.iws 7 | *.iml 8 | *.ipr 9 | 10 | 11 | 12 | ### Mac OS ### 13 | .DS_Store 14 | 15 | ### log file ### 16 | logs/ 17 | *.log 18 | 19 | /.idea/uiDesigner.xml 20 | /kaifangqian-demo-api/src/main/resources/application-apply.yml 21 | /kaifangqian-demo-api/src/test/java/org/resrun/ApplyLocalCertTest.java 22 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | # Datasource local storage ignored files 7 | /dataSources/ 8 | /dataSources.local.xml 9 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 kaifangqian 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /docs/images/1705906252616-c7176b84-502b-4fa1-a795-71abb78a4978.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaifangqian/kaifangqian-base/9157ecd23e1e59d3d8849efadd83efe2bd28e00a/docs/images/1705906252616-c7176b84-502b-4fa1-a795-71abb78a4978.png -------------------------------------------------------------------------------- /docs/images/1705908549370-57691237-9ed9-4b74-83c1-38ce82ded646.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaifangqian/kaifangqian-base/9157ecd23e1e59d3d8849efadd83efe2bd28e00a/docs/images/1705908549370-57691237-9ed9-4b74-83c1-38ce82ded646.png -------------------------------------------------------------------------------- /docs/images/pdf-cert.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaifangqian/kaifangqian-base/9157ecd23e1e59d3d8849efadd83efe2bd28e00a/docs/images/pdf-cert.png -------------------------------------------------------------------------------- /docs/images/product.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaifangqian/kaifangqian-base/9157ecd23e1e59d3d8849efadd83efe2bd28e00a/docs/images/product.png -------------------------------------------------------------------------------- /docs/images/seal-template.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaifangqian/kaifangqian-base/9157ecd23e1e59d3d8849efadd83efe2bd28e00a/docs/images/seal-template.png -------------------------------------------------------------------------------- /docs/images/seal-ym.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaifangqian/kaifangqian-base/9157ecd23e1e59d3d8849efadd83efe2bd28e00a/docs/images/seal-ym.png -------------------------------------------------------------------------------- /docs/images/signature.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaifangqian/kaifangqian-base/9157ecd23e1e59d3d8849efadd83efe2bd28e00a/docs/images/signature.png -------------------------------------------------------------------------------- /docs/images/verify.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaifangqian/kaifangqian-base/9157ecd23e1e59d3d8849efadd83efe2bd28e00a/docs/images/verify.png -------------------------------------------------------------------------------- /docs/kaifangqian-doc.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaifangqian/kaifangqian-base/9157ecd23e1e59d3d8849efadd83efe2bd28e00a/docs/kaifangqian-doc.pdf -------------------------------------------------------------------------------- /kaifangqian-api/README.md: -------------------------------------------------------------------------------- 1 | # 开放签--接口API 2 | 3 | ## 1、配置application-prod.yml 4 | ``` 5 | kaifangqian: 6 | #证书服务地址 7 | cert-apply-url: https://localhost/service/cert/event 8 | #授权token 9 | token: 123456 10 | # 默认 false 签发本地测试证书 true 签发 CA 证书 11 | prod: false 12 | ``` 13 | ## 2、启动项目 14 | ``` 15 | #需要提前准备好jdk1.8+,maven3.0+的环境 16 | 17 | #进入项目目录 18 | cd kaifangqian-api 19 | 20 | #打包 21 | mvn clean package 22 | 23 | #启动项目 默认端口为8891 24 | java -jar ./target/kaifangqian-api.jar 25 | ``` 26 | 27 | ## 3、api接口 28 | 请阅读[开放签API接口文档](../docs/kaifangqian-doc.pdf) 29 | 30 | 31 | -------------------------------------------------------------------------------- /kaifangqian-api/src/main/java/org/resrun/api/OpenSignApiApplication.java: -------------------------------------------------------------------------------- 1 | package org.resrun.api; 2 | 3 | import io.swagger.annotations.ApiOperation; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import org.springframework.boot.SpringApplication; 7 | import org.springframework.boot.autoconfigure.SpringBootApplication; 8 | import org.springframework.context.ConfigurableApplicationContext; 9 | import org.springframework.core.env.Environment; 10 | import org.springframework.web.bind.annotation.GetMapping; 11 | import org.springframework.web.bind.annotation.RestController; 12 | 13 | 14 | @SpringBootApplication 15 | @RestController 16 | public class OpenSignApiApplication { 17 | 18 | private static Logger log = LoggerFactory.getLogger(OpenSignApiApplication.class); 19 | 20 | public static void main(String[] args) { 21 | 22 | ConfigurableApplicationContext application = SpringApplication.run(OpenSignApiApplication.class, args); 23 | Environment env = application.getEnvironment(); 24 | String ip = "127.0.0.1"; 25 | String port = env.getProperty("server.port"); 26 | String path = env.getProperty("server.servlet.context-path"); 27 | log.info("\n----------------------------------------------------------\n\t" + 28 | "Application kaifangqian-api is running! Access URLs:\n\t" + 29 | "External: \thttp://" + ip + ":" + port + path + "\n" + 30 | "----------------------------------------------------------"); 31 | } 32 | 33 | @GetMapping("/") 34 | @ApiOperation(value = "项目根目录") 35 | public String index(){ 36 | return "kaifangqian-api run success"; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /kaifangqian-api/src/main/java/org/resrun/api/config/ApiClientConfig.java: -------------------------------------------------------------------------------- 1 | package org.resrun.api.config; 2 | 3 | public class ApiClientConfig { 4 | 5 | /** 6 | * 是否生产环境 默认为否 7 | */ 8 | private Boolean prod = false; 9 | 10 | /** 11 | * 授权token 12 | */ 13 | private String token; 14 | 15 | /** 16 | * 证书申请路径 17 | */ 18 | private String certApplyUrl; 19 | 20 | 21 | public Boolean getProd() { 22 | return prod; 23 | } 24 | 25 | public void setProd(Boolean prod) { 26 | this.prod = prod; 27 | } 28 | 29 | public String getToken() { 30 | return token; 31 | } 32 | 33 | public void setToken(String token) { 34 | this.token = token; 35 | } 36 | 37 | public String getCertApplyUrl() { 38 | return certApplyUrl; 39 | } 40 | 41 | public void setCertApplyUrl(String certApplyUrl) { 42 | this.certApplyUrl = certApplyUrl; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /kaifangqian-api/src/main/java/org/resrun/api/config/SpringBeanManage.java: -------------------------------------------------------------------------------- 1 | package org.resrun.api.config; 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | 7 | @Configuration 8 | public class SpringBeanManage { 9 | 10 | @Bean 11 | @ConfigurationProperties(prefix = "kaifangqian") 12 | public ApiClientConfig clientConfig(){ 13 | return new ApiClientConfig(); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /kaifangqian-api/src/main/java/org/resrun/api/enums/APIResultEnum.java: -------------------------------------------------------------------------------- 1 | package org.resrun.api.enums; 2 | 3 | /** 4 | * @Description: APIResultEnum 5 | * @Package: org.resrun.enums 6 | * @ClassName: APIResultEnum 7 | * @author: FengLai_Gong 8 | */ 9 | public enum APIResultEnum { 10 | 11 | 12 | SUCCESS(10000,"处理成功","处理成功"), 13 | 14 | VERIFY_FAIL(20000,"sign verify fail","sign verify fail"), 15 | 16 | PARAM_MISSING(21000,"{0}参数缺失","param_missing"), 17 | PARAM_BLANK(22000,"{0}参数不能为空","param_blank"), 18 | PARAM_FORMAT(23000,"{0}参数格式不正确,{1}","param_format"), 19 | 20 | 21 | BUSINESS_ERROR(31000,"业务处理失败,{0}","business_error"), 22 | 23 | 24 | TOKEN_INVALID(41000,"token无效","token_invalid"), 25 | TOKEN_NO_AUTH(42000,"token中未授权该接口调用权限","token_no_auth"), 26 | 27 | SERVICE_CONNECT_ERROR(43000,"调用发证服务超时,请检查","service_connect_error"), 28 | 29 | 30 | SQL_INJECTION_ERROR(51000,"请勿SQL攻击","sql_injection_error"), 31 | CROSS_SITE_ERROR(52000,"请勿跨站点攻击","cross_site_error"), 32 | UNKNOWN(91000, "系统未知错误","unknown"), 33 | 34 | ; 35 | 36 | private Integer code; 37 | 38 | private String template; 39 | 40 | private String message; 41 | 42 | APIResultEnum(Integer code, String message) { 43 | this.code = code; 44 | this.message = message; 45 | } 46 | APIResultEnum(Integer code,String template, String message) { 47 | this.code = code; 48 | this.message = message; 49 | this.template = template; 50 | } 51 | 52 | public Integer getCode(){ 53 | return code ; 54 | } 55 | 56 | public String getTemplate() { 57 | return template; 58 | } 59 | 60 | public void setMessage(String message) { 61 | this.message = message; 62 | } 63 | 64 | public static APIResultEnum statOf(Integer code) { 65 | for (APIResultEnum state : values()) { 66 | if (state.code.equals(code)) { 67 | return state; 68 | } 69 | } 70 | return null; 71 | } 72 | 73 | 74 | public static APIResultEnum getByMessage(String message){ 75 | if(message != null && message.length() > 0){ 76 | for(APIResultEnum state : APIResultEnum.values()){ 77 | // System.out.println(state.message); 78 | if(state.message.equals(message)){ 79 | return state; 80 | } 81 | } 82 | } 83 | return null ; 84 | } 85 | 86 | } -------------------------------------------------------------------------------- /kaifangqian-api/src/main/java/org/resrun/api/enums/BusinessErrorEnum.java: -------------------------------------------------------------------------------- 1 | package org.resrun.api.enums; 2 | 3 | /** 4 | * @Description: 业务异常枚举 5 | * @Package: org.resrun.enums 6 | * @ClassName: BusinessErrorEnum 7 | * @author: FengLai_Gong 8 | */ 9 | public enum BusinessErrorEnum { 10 | 11 | 12 | CERT_INVALID_ERROR(1,"证书已失效,无法签署"), 13 | 14 | SIGN_FAILED_ERROR(2,"文件签署失败"), 15 | KEYWORDS_NO_EXISTS_ERROR(3,"签署关键字在文件中不存在,无法签署"), 16 | DOWNLOAD_FILE_ERROR(4,"文件网络地址下载失败"), 17 | FILE_PARSE_BASE64_ERROR(5,"文件格式不正确或文件解析失败"), 18 | FILE_READ_ERROR(5,"文件读取失败"), 19 | PAGE_NUMBER_ERROR(6,"page页码不合规,规范:0 handlePaasException(ResultException e, HttpServletRequest request,HttpServletResponse response) { 26 | Result result = Result.error(e.code,e.message,e.uniqueCode); 27 | printExceptionLog(request,response,result); 28 | return result; 29 | } 30 | 31 | @ExceptionHandler(BusinessException.class) 32 | public Result handlePaasException(BusinessException e, HttpServletRequest request,HttpServletResponse response) { 33 | 34 | Result result = Result.error(e.resultEnum,e.businessErrorEnum); 35 | printExceptionLog(request,response,result); 36 | return result; 37 | 38 | } 39 | 40 | @ExceptionHandler(ParamFormatException.class) 41 | public Result handlePaasException(ParamFormatException e, HttpServletRequest request,HttpServletResponse response) { 42 | Result result = Result.error(e.resultEnum,e.paramFormatErrorEnum); 43 | printExceptionLog(request,response,result); 44 | return result; 45 | } 46 | 47 | public void printExceptionLog(HttpServletRequest request, HttpServletResponse response, Result result) { 48 | // 请求Url 49 | String requestUrl = request.getRequestURI().toString(); 50 | //请求方法名称 51 | String method = request.getMethod(); 52 | // 异常信息: 53 | log.info("统一异常处理:requestUrl = {}, method = {}, result= {}", requestUrl, method, JSONObject.toJSON(result)); 54 | } 55 | 56 | 57 | 58 | 59 | } -------------------------------------------------------------------------------- /kaifangqian-api/src/main/java/org/resrun/api/exception/BusinessException.java: -------------------------------------------------------------------------------- 1 | package org.resrun.api.exception; 2 | 3 | import org.resrun.api.enums.APIResultEnum; 4 | import org.resrun.api.enums.BusinessErrorEnum; 5 | 6 | /** 7 | * @Description: PaasException 8 | * @Package: org.resrun.exception 9 | * @ClassName: PaasException 10 | * @author: FengLai_Gong 11 | */ 12 | public class BusinessException extends RuntimeException{ 13 | 14 | // private static final long serialVersionUID = 1L; 15 | 16 | protected final transient APIResultEnum resultEnum ; 17 | 18 | protected final transient BusinessErrorEnum businessErrorEnum ; 19 | 20 | 21 | public BusinessException(APIResultEnum resultEnum, BusinessErrorEnum businessErrorEnum){ 22 | this.resultEnum = resultEnum ; 23 | this.businessErrorEnum = businessErrorEnum; 24 | } 25 | 26 | 27 | 28 | 29 | 30 | } -------------------------------------------------------------------------------- /kaifangqian-api/src/main/java/org/resrun/api/exception/ParamFormatException.java: -------------------------------------------------------------------------------- 1 | package org.resrun.api.exception; 2 | 3 | import org.resrun.api.enums.APIResultEnum; 4 | import org.resrun.api.enums.ParamFormatErrorEnum; 5 | 6 | /** 7 | * @Description: PaasException 8 | * @Package: org.resrun.exception 9 | * @ClassName: PaasException 10 | * @author: FengLai_Gong 11 | */ 12 | public class ParamFormatException extends RuntimeException{ 13 | 14 | // private static final long serialVersionUID = 1L; 15 | 16 | protected final transient APIResultEnum resultEnum ; 17 | 18 | protected final transient ParamFormatErrorEnum paramFormatErrorEnum ; 19 | 20 | 21 | public ParamFormatException(APIResultEnum resultEnum, ParamFormatErrorEnum paramFormatErrorEnum){ 22 | this.resultEnum = resultEnum ; 23 | this.paramFormatErrorEnum = paramFormatErrorEnum; 24 | } 25 | 26 | 27 | 28 | 29 | 30 | } -------------------------------------------------------------------------------- /kaifangqian-api/src/main/java/org/resrun/api/exception/ResultException.java: -------------------------------------------------------------------------------- 1 | package org.resrun.api.exception; 2 | 3 | /** 4 | * @Description: PaasException 5 | * @Package: org.resrun.exception 6 | * @ClassName: PaasException 7 | * @author: FengLai_Gong 8 | */ 9 | public class ResultException extends RuntimeException{ 10 | 11 | 12 | protected final transient Integer code ; 13 | 14 | protected final transient String message ; 15 | 16 | protected final transient String uniqueCode ; 17 | 18 | 19 | 20 | 21 | public ResultException(Integer code,String message,String uniqueCode){ 22 | this.code = code ; 23 | this.message = message ; 24 | this.uniqueCode = uniqueCode ; 25 | } 26 | 27 | 28 | 29 | 30 | 31 | } -------------------------------------------------------------------------------- /kaifangqian-api/src/main/java/org/resrun/api/pdfbox/CMSProcessableInputStream.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.resrun.api.pdfbox; 18 | 19 | import org.apache.pdfbox.io.IOUtils; 20 | import org.bouncycastle.asn1.ASN1ObjectIdentifier; 21 | import org.bouncycastle.asn1.cms.CMSObjectIdentifiers; 22 | import org.bouncycastle.cms.CMSException; 23 | import org.bouncycastle.cms.CMSTypedData; 24 | 25 | import java.io.IOException; 26 | import java.io.InputStream; 27 | import java.io.OutputStream; 28 | 29 | /** 30 | * Wraps a InputStream into a CMSProcessable object for bouncy castle. It's a memory saving 31 | * alternative to the {@link org.bouncycastle.cms.CMSProcessableByteArray CMSProcessableByteArray} 32 | * class. 33 | * 34 | * @author Thomas Chojecki 35 | */ 36 | class CMSProcessableInputStream implements CMSTypedData 37 | { 38 | private final InputStream in; 39 | private final ASN1ObjectIdentifier contentType; 40 | 41 | CMSProcessableInputStream(InputStream is) 42 | { 43 | this(new ASN1ObjectIdentifier(CMSObjectIdentifiers.data.getId()), is); 44 | } 45 | 46 | CMSProcessableInputStream(ASN1ObjectIdentifier type, InputStream is) 47 | { 48 | contentType = type; 49 | in = is; 50 | } 51 | 52 | @Override 53 | public Object getContent() 54 | { 55 | return in; 56 | } 57 | 58 | @Override 59 | public void write(OutputStream out) throws IOException, CMSException 60 | { 61 | // read the content only one time 62 | IOUtils.copy(in, out); 63 | in.close(); 64 | } 65 | 66 | @Override 67 | public ASN1ObjectIdentifier getContentType() 68 | { 69 | return contentType; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /kaifangqian-api/src/main/java/org/resrun/api/pdfbox/vo/AssinaturaModel.java: -------------------------------------------------------------------------------- 1 | package org.resrun.api.pdfbox.vo; 2 | 3 | public class AssinaturaModel { 4 | 5 | /** 6 | * 证书对象 7 | */ 8 | private CertificateInfo certInfo; 9 | 10 | /** 11 | * 待签名PDF文件 12 | */ 13 | private byte [] pdf; 14 | 15 | /** 16 | * 签名图片 17 | */ 18 | private byte [] signatureImage; 19 | 20 | 21 | /** 22 | * 签署位置信息 23 | */ 24 | private AssinaturaPosition position; 25 | 26 | /** 27 | * 签名域key 控件的interface_name 28 | */ 29 | private String signatureKey; 30 | 31 | /** 32 | * 签名时间戳 33 | */ 34 | private String tsa; 35 | 36 | /** 37 | * 签名人 38 | */ 39 | private String name; 40 | private String reason; 41 | private String location; 42 | 43 | 44 | public String getName() { 45 | return name; 46 | } 47 | 48 | public void setName(String name) { 49 | this.name = name; 50 | } 51 | 52 | public String getReason() { 53 | return reason; 54 | } 55 | 56 | public void setReason(String reason) { 57 | this.reason = reason; 58 | } 59 | 60 | public String getLocation() { 61 | return location; 62 | } 63 | 64 | public void setLocation(String location) { 65 | this.location = location; 66 | } 67 | 68 | public String getSignatureKey() { 69 | return signatureKey; 70 | } 71 | 72 | public void setSignatureKey(String signatureKey) { 73 | this.signatureKey = signatureKey; 74 | } 75 | 76 | public String getTsa() { 77 | return tsa; 78 | } 79 | 80 | public void setTsa(String tsa) { 81 | this.tsa = tsa; 82 | } 83 | 84 | public CertificateInfo getCertInfo() { 85 | return certInfo; 86 | } 87 | 88 | public void setCertInfo(CertificateInfo certInfo) { 89 | this.certInfo = certInfo; 90 | } 91 | 92 | public byte[] getPdf() { 93 | return pdf; 94 | } 95 | 96 | public void setPdf(byte[] pdf) { 97 | this.pdf = pdf; 98 | } 99 | 100 | public byte[] getSignatureImage() { 101 | return signatureImage; 102 | } 103 | 104 | public void setSignatureImage(byte[] signatureImage) { 105 | this.signatureImage = signatureImage; 106 | } 107 | 108 | public AssinaturaPosition getPosition() { 109 | return position; 110 | } 111 | 112 | public void setPosition(AssinaturaPosition position) { 113 | this.position = position; 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /kaifangqian-api/src/main/java/org/resrun/api/pdfbox/vo/AssinaturaPosition.java: -------------------------------------------------------------------------------- 1 | package org.resrun.api.pdfbox.vo; 2 | 3 | public class AssinaturaPosition { 4 | 5 | /** 6 | * 签名的页码 7 | */ 8 | private Integer page; 9 | 10 | /** 11 | * 距离左侧的距离 12 | */ 13 | private String offsetX; 14 | /** 15 | * 距离顶部的距离 16 | */ 17 | private String offsetY; 18 | 19 | /** 20 | * 前端页面显示的宽度 21 | */ 22 | private String pageWidth; 23 | /** 24 | * 前端页面显示的高度 25 | */ 26 | private String pageHeight; 27 | /** 28 | * 签章图片宽度 29 | */ 30 | private String signWidth; 31 | /** 32 | * 签章图片高度 33 | */ 34 | private String signHeight; 35 | 36 | public Integer getPage() { 37 | return page; 38 | } 39 | 40 | public void setPage(Integer page) { 41 | this.page = page; 42 | } 43 | 44 | public String getOffsetX() { 45 | return offsetX; 46 | } 47 | public Float getParseX() { 48 | return Float.parseFloat(offsetX); 49 | } 50 | public Float getParseY() { 51 | return Float.parseFloat(offsetY); 52 | } 53 | 54 | public void setOffsetX(String offsetX) { 55 | this.offsetX = offsetX; 56 | } 57 | 58 | public String getOffsetY() { 59 | return offsetY; 60 | } 61 | 62 | public void setOffsetY(String offsetY) { 63 | this.offsetY = offsetY; 64 | } 65 | 66 | public String getPageWidth() { 67 | return pageWidth; 68 | } 69 | 70 | public void setPageWidth(String pageWidth) { 71 | this.pageWidth = pageWidth; 72 | } 73 | 74 | public String getPageHeight() { 75 | return pageHeight; 76 | } 77 | 78 | public void setPageHeight(String pageHeight) { 79 | this.pageHeight = pageHeight; 80 | } 81 | 82 | public String getSignWidth() { 83 | return signWidth; 84 | } 85 | 86 | public void setSignWidth(String signWidth) { 87 | this.signWidth = signWidth; 88 | } 89 | 90 | public String getSignHeight() { 91 | return signHeight; 92 | } 93 | public Float getSignHeightFloat() { 94 | return Float.parseFloat(signHeight); 95 | } 96 | public Float getSignWidthFloat() { 97 | return Float.parseFloat(signWidth); 98 | } 99 | 100 | public void setSignHeight(String signHeight) { 101 | this.signHeight = signHeight; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /kaifangqian-api/src/main/java/org/resrun/api/pdfbox/vo/CertificateInfo.java: -------------------------------------------------------------------------------- 1 | package org.resrun.api.pdfbox.vo; 2 | 3 | public class CertificateInfo { 4 | 5 | 6 | /** 7 | * 证书密码 8 | */ 9 | private String password; 10 | 11 | /** 12 | * 证书文集 PFX格式 13 | */ 14 | private byte [] cert; 15 | 16 | 17 | /** 18 | * 证书类型 PFX格式为PKCS12 19 | */ 20 | private CertTypeEnum certType; 21 | 22 | public CertTypeEnum getCertType() { 23 | return certType; 24 | } 25 | 26 | public void setCertType(CertTypeEnum certType) { 27 | this.certType = certType; 28 | } 29 | 30 | public String getPassword() { 31 | return password; 32 | } 33 | 34 | public void setPassword(String password) { 35 | this.password = password; 36 | } 37 | 38 | public byte[] getCert() { 39 | return cert; 40 | } 41 | 42 | public void setCert(byte[] cert) { 43 | this.cert = cert; 44 | } 45 | public enum CertTypeEnum { 46 | 47 | PKCS12,JKS 48 | 49 | } 50 | 51 | } 52 | 53 | -------------------------------------------------------------------------------- /kaifangqian-api/src/main/java/org/resrun/api/service/pojo/ApplyCert.java: -------------------------------------------------------------------------------- 1 | package org.resrun.api.service.pojo; 2 | 3 | 4 | import java.io.Serializable; 5 | 6 | /** 7 | * @Description: 申请证书-返回对象 8 | * @Package: org.resrun.modules.cert.pojo 9 | * @ClassName: ApplyCert 10 | * @author: FengLai_Gong 11 | */ 12 | public class ApplyCert implements Serializable { 13 | 14 | private static final long serialVersionUID = -2734385624897679135L; 15 | 16 | private Integer code ; 17 | 18 | private String message ; 19 | 20 | private String uniqueCode ; 21 | 22 | private ApplyCertData data ; 23 | 24 | public Integer getCode() { 25 | return code; 26 | } 27 | 28 | public void setCode(Integer code) { 29 | this.code = code; 30 | } 31 | 32 | public String getMessage() { 33 | return message; 34 | } 35 | 36 | public void setMessage(String message) { 37 | this.message = message; 38 | } 39 | 40 | public String getUniqueCode() { 41 | return uniqueCode; 42 | } 43 | 44 | public void setUniqueCode(String uniqueCode) { 45 | this.uniqueCode = uniqueCode; 46 | } 47 | 48 | public ApplyCertData getData() { 49 | return data; 50 | } 51 | 52 | public void setData(ApplyCertData data) { 53 | this.data = data; 54 | } 55 | } -------------------------------------------------------------------------------- /kaifangqian-api/src/main/java/org/resrun/api/service/pojo/ApplyCertData.java: -------------------------------------------------------------------------------- 1 | package org.resrun.api.service.pojo; 2 | 3 | 4 | import java.io.Serializable; 5 | 6 | /** 7 | * @Description: ApplyCertData 8 | * @Package: org.resrun.modules.cert.pojo 9 | * @ClassName: ApplyCertData 10 | * @author: FengLai_Gong 11 | */ 12 | public class ApplyCertData implements Serializable { 13 | 14 | private static final long serialVersionUID = 3447485591197821614L; 15 | 16 | private String p7b ; 17 | 18 | private String certSN ; 19 | 20 | private String certNO ; 21 | 22 | private String certSubject ; 23 | 24 | //时间格式 20231229102348 25 | private String certValidityNotBefore ; 26 | 27 | //时间格式 20231230102348 28 | private String certValidityNotAfter ; 29 | 30 | private Integer certValidity ; 31 | 32 | public String getP7b() { 33 | return p7b; 34 | } 35 | 36 | public void setP7b(String p7b) { 37 | this.p7b = p7b; 38 | } 39 | 40 | public String getCertSN() { 41 | return certSN; 42 | } 43 | 44 | public void setCertSN(String certSN) { 45 | this.certSN = certSN; 46 | } 47 | 48 | public String getCertNO() { 49 | return certNO; 50 | } 51 | 52 | public void setCertNO(String certNO) { 53 | this.certNO = certNO; 54 | } 55 | 56 | public String getCertSubject() { 57 | return certSubject; 58 | } 59 | 60 | public void setCertSubject(String certSubject) { 61 | this.certSubject = certSubject; 62 | } 63 | 64 | public String getCertValidityNotBefore() { 65 | return certValidityNotBefore; 66 | } 67 | 68 | public void setCertValidityNotBefore(String certValidityNotBefore) { 69 | this.certValidityNotBefore = certValidityNotBefore; 70 | } 71 | 72 | public String getCertValidityNotAfter() { 73 | return certValidityNotAfter; 74 | } 75 | 76 | public void setCertValidityNotAfter(String certValidityNotAfter) { 77 | this.certValidityNotAfter = certValidityNotAfter; 78 | } 79 | 80 | public Integer getCertValidity() { 81 | return certValidity; 82 | } 83 | 84 | public void setCertValidity(Integer certValidity) { 85 | this.certValidity = certValidity; 86 | } 87 | } -------------------------------------------------------------------------------- /kaifangqian-api/src/main/java/org/resrun/api/service/pojo/BaseCertificateInfo.java: -------------------------------------------------------------------------------- 1 | package org.resrun.api.service.pojo; 2 | 3 | import java.security.KeyStore; 4 | 5 | public class BaseCertificateInfo { 6 | 7 | /** 8 | * 根证书 9 | */ 10 | private KeyStore cert; 11 | 12 | /** 13 | * 证书别名 14 | */ 15 | private String alias; 16 | 17 | /** 18 | * 证书密码 19 | */ 20 | private String password; 21 | 22 | public KeyStore getCert() { 23 | return cert; 24 | } 25 | 26 | public void setCert(KeyStore cert) { 27 | this.cert = cert; 28 | } 29 | 30 | public String getAlias() { 31 | return alias; 32 | } 33 | 34 | public void setAlias(String alias) { 35 | this.alias = alias; 36 | } 37 | 38 | public String getPassword() { 39 | return password; 40 | } 41 | 42 | public void setPassword(String password) { 43 | this.password = password; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /kaifangqian-api/src/main/java/org/resrun/api/service/pojo/CertSubjectProperty.java: -------------------------------------------------------------------------------- 1 | package org.resrun.api.service.pojo; 2 | 3 | 4 | import java.io.Serializable; 5 | 6 | /** 7 | * @Description: CertSubjectProperty 8 | * @Package: org.resrun.modules.opensign.service.tool.pojo 9 | * @ClassName: CertSubjectProperty 10 | * @author: FengLai_Gong 11 | */ 12 | public class CertSubjectProperty implements Serializable { 13 | 14 | 15 | 16 | // C Country Name (国家代号),eg: CN 17 | private String c ; 18 | 19 | // ST State or Province Name (洲或者省份),eg: Beijing 20 | private String st ; 21 | // CN Common Name (服务器ip或者域名),eg: 192.168.30.71 or www.baidu.com 22 | //1)个人:【姓名】@【身份证号码】@【手机号】 23 | //2)企业:【企业名称】@【统一社会信用代码】 24 | private String cn ; 25 | 26 | // L Locality Name (城市名),eg: Beijing 27 | private String l ; 28 | 29 | // O Organization Name (可以是公司名称),eg: 北京资源律动科技有限公司 30 | private String o ; 31 | // OU Organizational Unit Name (可以是单位部门名称) 32 | private String ou ; 33 | 34 | // STREET streetAddress 35 | private String street ; 36 | // DC domainComponent 37 | private String dc ; 38 | // UID userid 39 | private String uid ; 40 | 41 | 42 | // 1为个人,2为企业 43 | private Integer certType ; 44 | 45 | 46 | public String getC() { 47 | return c; 48 | } 49 | 50 | public void setC(String c) { 51 | this.c = c; 52 | } 53 | 54 | public String getSt() { 55 | return st; 56 | } 57 | 58 | public void setSt(String st) { 59 | this.st = st; 60 | } 61 | 62 | public String getCn() { 63 | return cn; 64 | } 65 | 66 | public void setCn(String cn) { 67 | this.cn = cn; 68 | } 69 | 70 | public String getL() { 71 | return l; 72 | } 73 | 74 | public void setL(String l) { 75 | this.l = l; 76 | } 77 | 78 | public String getO() { 79 | return o; 80 | } 81 | 82 | public void setO(String o) { 83 | this.o = o; 84 | } 85 | 86 | public String getOu() { 87 | return ou; 88 | } 89 | 90 | public void setOu(String ou) { 91 | this.ou = ou; 92 | } 93 | 94 | public String getStreet() { 95 | return street; 96 | } 97 | 98 | public void setStreet(String street) { 99 | this.street = street; 100 | } 101 | 102 | public String getDc() { 103 | return dc; 104 | } 105 | 106 | public void setDc(String dc) { 107 | this.dc = dc; 108 | } 109 | 110 | public String getUid() { 111 | return uid; 112 | } 113 | 114 | public void setUid(String uid) { 115 | this.uid = uid; 116 | } 117 | 118 | public Integer getCertType() { 119 | return certType; 120 | } 121 | 122 | public void setCertType(Integer certType) { 123 | this.certType = certType; 124 | } 125 | } -------------------------------------------------------------------------------- /kaifangqian-api/src/main/java/org/resrun/api/service/pojo/CertificateProperty.java: -------------------------------------------------------------------------------- 1 | package org.resrun.api.service.pojo; 2 | 3 | 4 | import java.io.Serializable; 5 | 6 | /** 7 | * @Description: 证书文件属性类 8 | * @Package: org.resrun.modules.sign.pojo 9 | * @ClassName: CertificateProperty 10 | * @author: FengLai_Gong 11 | */ 12 | public class CertificateProperty implements Serializable { 13 | 14 | private static final long serialVersionUID = -2073805779543816269L; 15 | 16 | 17 | private byte[] certFile; 18 | /** 证书的类型 比如:PKCS12和jks*/ 19 | private String certType; 20 | /** 证书密码 */ 21 | private String password; 22 | 23 | public byte[] getCertFile() { 24 | return certFile; 25 | } 26 | 27 | public void setCertFile(byte[] certFile) { 28 | this.certFile = certFile; 29 | } 30 | 31 | public String getCertType() { 32 | return certType; 33 | } 34 | 35 | public void setCertType(String certType) { 36 | this.certType = certType; 37 | } 38 | 39 | public String getPassword() { 40 | return password; 41 | } 42 | 43 | public void setPassword(String password) { 44 | this.password = password; 45 | } 46 | } -------------------------------------------------------------------------------- /kaifangqian-api/src/main/java/org/resrun/api/service/pojo/CertificationInfo.java: -------------------------------------------------------------------------------- 1 | package org.resrun.api.service.pojo; 2 | 3 | 4 | import java.io.Serializable; 5 | 6 | /** 7 | * @Description: CertificateInfo 8 | * @Package: org.resrun.modules.cert.pojo 9 | * @ClassName: CertificateInfo 10 | * @author: FengLai_Gong 11 | */ 12 | public class CertificationInfo implements Serializable { 13 | 14 | 15 | private static final long serialVersionUID = -9222852413621841079L; 16 | 17 | //证书头信息 18 | private String certDn ; 19 | 20 | //证书keyName 21 | private String keyName ; 22 | 23 | //证书密码 24 | private String password ; 25 | 26 | //p10文件 27 | private byte[] p10; 28 | //生成的p7b文件 29 | private byte[] p7bFile ; 30 | //生成的jks文件 31 | private byte[] jksFile ; 32 | //p7b之后jks文件 33 | private byte[] certFile ; 34 | //将原始证书认证后最终生成的pfx文件 35 | private byte[] pfxFile ; 36 | 37 | 38 | public String getCertDn() { 39 | return certDn; 40 | } 41 | 42 | public void setCertDn(String certDn) { 43 | this.certDn = certDn; 44 | } 45 | 46 | public String getKeyName() { 47 | return keyName; 48 | } 49 | 50 | public void setKeyName(String keyName) { 51 | this.keyName = keyName; 52 | } 53 | 54 | public String getPassword() { 55 | return password; 56 | } 57 | 58 | public void setPassword(String password) { 59 | this.password = password; 60 | } 61 | 62 | public byte[] getP10() { 63 | return p10; 64 | } 65 | 66 | public void setP10(byte[] p10) { 67 | this.p10 = p10; 68 | } 69 | 70 | public byte[] getP7bFile() { 71 | return p7bFile; 72 | } 73 | 74 | public void setP7bFile(byte[] p7bFile) { 75 | this.p7bFile = p7bFile; 76 | } 77 | 78 | public byte[] getJksFile() { 79 | return jksFile; 80 | } 81 | 82 | public void setJksFile(byte[] jksFile) { 83 | this.jksFile = jksFile; 84 | } 85 | 86 | public byte[] getCertFile() { 87 | return certFile; 88 | } 89 | 90 | public void setCertFile(byte[] certFile) { 91 | this.certFile = certFile; 92 | } 93 | 94 | public byte[] getPfxFile() { 95 | return pfxFile; 96 | } 97 | 98 | public void setPfxFile(byte[] pfxFile) { 99 | this.pfxFile = pfxFile; 100 | } 101 | } -------------------------------------------------------------------------------- /kaifangqian-api/src/main/java/org/resrun/api/service/pojo/PdfOperateProperty.java: -------------------------------------------------------------------------------- 1 | package org.resrun.api.service.pojo; 2 | 3 | 4 | import java.io.Serializable; 5 | 6 | /** 7 | * @Description: pdf文件操作属性对象 8 | * @Package: org.resrun.modules.sign.service.tool.pojo 9 | * @ClassName: PdfOperateProperty 10 | * @author: FengLai_Gong 11 | */ 12 | public class PdfOperateProperty implements Serializable { 13 | 14 | private static final long serialVersionUID = 136217989504135671L; 15 | 16 | //pdf文件数据 17 | private byte[] pdfFile ; 18 | //图片数据 19 | private byte[] imageFile ; 20 | //文本数据 21 | private String value ; 22 | //横坐标偏移量 23 | private Float offsetX ; 24 | //纵坐标偏移量 25 | private Float offsetY ; 26 | //页码 27 | private Integer pageNum ; 28 | 29 | 30 | public byte[] getPdfFile() { 31 | return pdfFile; 32 | } 33 | 34 | public void setPdfFile(byte[] pdfFile) { 35 | this.pdfFile = pdfFile; 36 | } 37 | 38 | public byte[] getImageFile() { 39 | return imageFile; 40 | } 41 | 42 | public void setImageFile(byte[] imageFile) { 43 | this.imageFile = imageFile; 44 | } 45 | 46 | public String getValue() { 47 | return value; 48 | } 49 | 50 | public void setValue(String value) { 51 | this.value = value; 52 | } 53 | 54 | public Float getOffsetX() { 55 | return offsetX; 56 | } 57 | 58 | public void setOffsetX(Float offsetX) { 59 | this.offsetX = offsetX; 60 | } 61 | 62 | public Float getOffsetY() { 63 | return offsetY; 64 | } 65 | 66 | public void setOffsetY(Float offsetY) { 67 | this.offsetY = offsetY; 68 | } 69 | 70 | public Integer getPageNum() { 71 | return pageNum; 72 | } 73 | 74 | public void setPageNum(Integer pageNum) { 75 | this.pageNum = pageNum; 76 | } 77 | } -------------------------------------------------------------------------------- /kaifangqian-api/src/main/java/org/resrun/api/service/pojo/PositionProperty.java: -------------------------------------------------------------------------------- 1 | package org.resrun.api.service.pojo; 2 | 3 | 4 | import java.io.Serializable; 5 | 6 | /** 7 | * @Description: 文件签署属性类 8 | * @Package: org.resrun.modules.sign.pojo 9 | * @ClassName: PositionProperty 10 | * @author: FengLai_Gong 11 | */ 12 | public class PositionProperty implements Serializable { 13 | 14 | 15 | private static final long serialVersionUID = 8586984409612483553L; 16 | 17 | /** 签章左下角x坐标 */ 18 | private float startx; 19 | 20 | /** 签章左下角y坐标*/ 21 | private float starty; 22 | 23 | /** 签章右上角x坐标*/ 24 | private float endx; 25 | 26 | /** 签章右上角x坐标*/ 27 | private float endy; 28 | 29 | private int pageNum; 30 | 31 | public float getStartx() { 32 | return startx; 33 | } 34 | 35 | public void setStartx(float startx) { 36 | this.startx = startx; 37 | } 38 | 39 | public float getStarty() { 40 | return starty; 41 | } 42 | 43 | public void setStarty(float starty) { 44 | this.starty = starty; 45 | } 46 | 47 | public float getEndx() { 48 | return endx; 49 | } 50 | 51 | public void setEndx(float endx) { 52 | this.endx = endx; 53 | } 54 | 55 | public float getEndy() { 56 | return endy; 57 | } 58 | 59 | public void setEndy(float endy) { 60 | this.endy = endy; 61 | } 62 | 63 | public int getPageNum() { 64 | return pageNum; 65 | } 66 | 67 | public void setPageNum(int pageNum) { 68 | this.pageNum = pageNum; 69 | } 70 | } -------------------------------------------------------------------------------- /kaifangqian-api/src/main/java/org/resrun/api/service/pojo/PositionSignPage.java: -------------------------------------------------------------------------------- 1 | package org.resrun.api.service.pojo; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * @Description: PositionSignPage 7 | * @Package: org.resrun.modules.sign.pojo 8 | * @ClassName: PositionSignPage 9 | * @author: FengLai_Gong 10 | */ 11 | public class PositionSignPage implements Serializable { 12 | 13 | //签署点坐在页码 14 | private int pageNum; 15 | //签署点相对于该页的x坐标 16 | private String xScale; 17 | //签署点相对于该页的y坐标 18 | private String yScale; 19 | 20 | 21 | 22 | public int getPageNum() { 23 | return pageNum; 24 | } 25 | public void setPageNum(int pageNum) { 26 | this.pageNum = pageNum; 27 | } 28 | public String getxScale() { 29 | return xScale; 30 | } 31 | public void setxScale(String xScale) { 32 | this.xScale = xScale; 33 | } 34 | public String getyScale() { 35 | return yScale; 36 | } 37 | public void setyScale(String yScale) { 38 | this.yScale = yScale; 39 | } 40 | } -------------------------------------------------------------------------------- /kaifangqian-api/src/main/java/org/resrun/api/service/pojo/SignPanelInfo.java: -------------------------------------------------------------------------------- 1 | package org.resrun.api.service.pojo; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * @Description: SignPanelInfo 7 | * @Package: org.resrun.modules.sign.pojo 8 | * @ClassName: SignPanelInfo 9 | * @author: FengLai_Gong 10 | */ 11 | public class SignPanelInfo implements Serializable { 12 | 13 | /** 签署方指定签名位置距离页面合同图片左边的距离 */ 14 | private String leftzb; 15 | /** 签署方指定签名位置距离页面合同图片顶部的距离 */ 16 | private String topzb; 17 | /** 页码 */ 18 | private String pageNum; 19 | /** 签名弹框的宽度 */ 20 | private String signW; 21 | /** 签名弹框的高度 */ 22 | private String signH; 23 | /** 获取手机屏幕宽、高 */ 24 | private String phoneWidth; 25 | /** 获取手机屏幕宽、高 */ 26 | private String phoneHeight; 27 | 28 | 29 | public String getLeftzb() { 30 | return leftzb; 31 | } 32 | public void setLeftzb(String leftzb) { 33 | this.leftzb = leftzb; 34 | } 35 | public String getTopzb() { 36 | return topzb; 37 | } 38 | public void setTopzb(String topzb) { 39 | this.topzb = topzb; 40 | } 41 | public String getPageNum() { 42 | return pageNum; 43 | } 44 | public void setPageNum(String pageNum) { 45 | this.pageNum = pageNum; 46 | } 47 | public String getSignW() { 48 | return signW; 49 | } 50 | public void setSignW(String signW) { 51 | this.signW = signW; 52 | } 53 | public String getSignH() { 54 | return signH; 55 | } 56 | public void setSignH(String signH) { 57 | this.signH = signH; 58 | } 59 | public String getPhoneWidth() { 60 | return phoneWidth; 61 | } 62 | public void setPhoneWidth(String phoneWidth) { 63 | this.phoneWidth = phoneWidth; 64 | } 65 | public String getPhoneHeight() { 66 | return phoneHeight; 67 | } 68 | public void setPhoneHeight(String phoneHeight) { 69 | this.phoneHeight = phoneHeight; 70 | } 71 | 72 | 73 | 74 | } -------------------------------------------------------------------------------- /kaifangqian-api/src/main/java/org/resrun/api/utils/CallBack.java: -------------------------------------------------------------------------------- 1 | package org.resrun.api.utils; 2 | 3 | /** 4 | * @author: zhh 5 | * @see {@link SpringContextHolder} 6 | * 针对某些初始化方法,在SpringContextHolder 初始化前时,
7 | * 可提交一个 提交回调任务。
8 | * 在SpringContextHolder 初始化后,进行回调使用 9 | */ 10 | 11 | public interface CallBack { 12 | /** 13 | * 回调执行方法 14 | */ 15 | void executor(); 16 | 17 | /** 18 | * 本回调任务名称 19 | * @return / 20 | */ 21 | default String getCallBackName() { 22 | return Thread.currentThread().getId() + ":" + this.getClass().getName(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /kaifangqian-api/src/main/java/org/resrun/api/utils/CertificateSort.java: -------------------------------------------------------------------------------- 1 | package org.resrun.api.utils; 2 | 3 | import java.security.cert.X509Certificate; 4 | import java.util.ArrayList; 5 | import java.util.Collections; 6 | import java.util.List; 7 | 8 | public class CertificateSort { 9 | 10 | /** 11 | * 根据顺序将证书链重新排序 12 | * @param chains 13 | * @return 14 | */ 15 | public static List sort(List chains){ 16 | 17 | 18 | List sortChains = new ArrayList<>(chains.size()); 19 | 20 | X509Certificate rootCert = chains.stream().filter(c->c.getIssuerDN().getName().equals(c.getSubjectDN().getName())).findFirst().get(); 21 | 22 | String issuer = rootCert.getSubjectDN().getName(); 23 | 24 | sortChains.add(rootCert); 25 | 26 | for (int i=0;i convertImage(byte[] signFileByte){ 30 | if(signFileByte == null){ 31 | return null ; 32 | } 33 | List responseList = new ArrayList<>(); 34 | PDDocument doc = null; 35 | try { 36 | //加载pdf文件 37 | doc = Loader.loadPDF(signFileByte); 38 | PDFRenderer renderer = new PDFRenderer(doc); 39 | int pageCount = doc.getNumberOfPages(); 40 | if(pageCount == 0){ 41 | return responseList; 42 | } 43 | 44 | for (int i = 0; i < pageCount; ++i) { 45 | int page = i ; 46 | BufferedImage image = renderer.renderImageWithDPI(page, resolution); 47 | ByteArrayOutputStream stream = new ByteArrayOutputStream(); 48 | ImageIO.write(image, IMG_PNG, stream); 49 | byte[] bytes = stream.toByteArray(); 50 | if(bytes != null){ 51 | 52 | responseList.add(bytes); 53 | 54 | } 55 | } 56 | }catch (Exception e) { 57 | e.printStackTrace(); 58 | } 59 | if(responseList.size() == 0){ 60 | throw new RuntimeException("图片转换失败"); 61 | } 62 | 63 | 64 | return responseList ; 65 | } 66 | 67 | public static void main(String[] args) throws IOException { 68 | byte [] pdf = FileUtils.readFileToByteArray(new File("22222.pdf")); 69 | List images = new ConvertImage().convertImage(pdf); 70 | System.out.println("图片:"+images.size()); 71 | } 72 | 73 | } -------------------------------------------------------------------------------- /kaifangqian-api/src/main/java/org/resrun/api/utils/MyStringUtils.java: -------------------------------------------------------------------------------- 1 | package org.resrun.api.utils; 2 | 3 | /** 4 | * @author zhh 5 | * 字符串工具类, 继承org.apache.commons.lang3.StringUtils类 6 | */ 7 | public class MyStringUtils extends org.apache.commons.lang3.StringUtils { 8 | 9 | private static final char SEPARATOR = '_'; 10 | 11 | /** 12 | * 驼峰命名法工具 13 | * 14 | * @return toCamelCase(" hello_world ") == "helloWorld" 15 | */ 16 | public static String toCamelCase(String s) { 17 | if (s == null) { 18 | return null; 19 | } 20 | 21 | s = s.toLowerCase(); 22 | 23 | StringBuilder sb = new StringBuilder(s.length()); 24 | boolean upperCase = false; 25 | for (int i = 0; i < s.length(); i++) { 26 | char c = s.charAt(i); 27 | 28 | if (c == SEPARATOR) { 29 | upperCase = true; 30 | } else if (upperCase) { 31 | sb.append(Character.toUpperCase(c)); 32 | upperCase = false; 33 | } else { 34 | sb.append(c); 35 | } 36 | } 37 | 38 | return sb.toString(); 39 | } 40 | 41 | /** 42 | * 驼峰命名法工具 43 | *

44 | * toCapitalizeCamelCase("hello_world") == "HelloWorld" 45 | */ 46 | public static String toCapitalizeCamelCase(String s) { 47 | if (s == null) { 48 | return null; 49 | } 50 | s = toCamelCase(s); 51 | return s.substring(0, 1).toUpperCase() + s.substring(1); 52 | } 53 | 54 | /** 55 | * 驼峰命名法工具 56 | * toUnderScoreCase("helloWorld") = "hello_world" 57 | */ 58 | public static String toUnderScoreCase(String s) { 59 | if (s == null) { 60 | return null; 61 | } 62 | 63 | StringBuilder sb = new StringBuilder(); 64 | boolean upperCase = false; 65 | for (int i = 0; i < s.length(); i++) { 66 | char c = s.charAt(i); 67 | 68 | boolean nextUpperCase = true; 69 | 70 | if (i < (s.length() - 1)) { 71 | nextUpperCase = Character.isUpperCase(s.charAt(i + 1)); 72 | } 73 | 74 | if ((i > 0) && Character.isUpperCase(c)) { 75 | if (!upperCase || !nextUpperCase) { 76 | sb.append(SEPARATOR); 77 | } 78 | upperCase = true; 79 | } else { 80 | upperCase = false; 81 | } 82 | 83 | sb.append(Character.toLowerCase(c)); 84 | } 85 | 86 | return sb.toString(); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /kaifangqian-api/src/main/java/org/resrun/api/validation/SignTypeValid.java: -------------------------------------------------------------------------------- 1 | package org.resrun.api.validation; 2 | 3 | import javax.validation.Constraint; 4 | import javax.validation.Payload; 5 | import java.lang.annotation.ElementType; 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.RetentionPolicy; 8 | import java.lang.annotation.Target; 9 | 10 | /** 11 | * @Description: SignType 12 | * @Package: org.resrun.validation 13 | * @ClassName: SignType 14 | * @author: FengLai_Gong 15 | */ 16 | @Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE, 17 | ElementType.TYPE_USE}) 18 | @Retention(RetentionPolicy.RUNTIME) 19 | @Constraint(validatedBy = {SignTypeValidator.class}) 20 | public @interface SignTypeValid { 21 | 22 | String message() ; 23 | 24 | Class[] groups() default {}; 25 | 26 | Class[] payload() default { }; 27 | 28 | 29 | } 30 | -------------------------------------------------------------------------------- /kaifangqian-api/src/main/java/org/resrun/api/validation/SignTypeValidator.java: -------------------------------------------------------------------------------- 1 | package org.resrun.api.validation; 2 | 3 | import org.resrun.api.enums.SignTypeEnum; 4 | 5 | import javax.validation.ConstraintValidator; 6 | import javax.validation.ConstraintValidatorContext; 7 | 8 | /** 9 | * @Description: SignTypeValidator 10 | * @Package: org.resrun.validation 11 | * @ClassName: SignTypeValidator 12 | * @author: FengLai_Gong 13 | */ 14 | public class SignTypeValidator implements ConstraintValidator { 15 | 16 | @Override 17 | public boolean isValid(Integer signType, ConstraintValidatorContext context) { 18 | // if(value == SignTypeEnum.KEYWORDS.getCode() || value == SignTypeEnum.POSITION.getCode()){ 19 | // return true ; 20 | // } 21 | if(signType.equals(SignTypeEnum.KEYWORDS.getCode()) || signType.equals(SignTypeEnum.POSITION.getCode())){ 22 | return true ; 23 | } 24 | // System.out.println(signType); 25 | // System.out.println(map.get("keywords")); 26 | // System.out.println(map.get("signLocationList")); 27 | return false; 28 | } 29 | 30 | } -------------------------------------------------------------------------------- /kaifangqian-api/src/main/java/org/resrun/api/vo/base/APIRequest.java: -------------------------------------------------------------------------------- 1 | package org.resrun.api.vo.base; 2 | 3 | import org.resrun.api.validation.ValidationSorts; 4 | 5 | import javax.validation.constraints.NotBlank; 6 | import javax.validation.constraints.NotNull; 7 | import javax.validation.constraints.Pattern; 8 | import javax.validation.constraints.Size; 9 | import java.io.Serializable; 10 | import java.util.Map; 11 | 12 | /** 13 | * @Description: 接口统一请求参数父类 14 | * @Package: org.resrun.vo 15 | * @ClassName: APIRequest 16 | * @author: FengLai_Gong 17 | */ 18 | public abstract class APIRequest implements Serializable { 19 | 20 | private static final long serialVersionUID = -2266306977154288057L; 21 | 22 | //流水号 23 | @NotNull(message = "param_missing",groups = ValidationSorts.SortA1.class) 24 | @NotBlank(message = "param_blank",groups = ValidationSorts.SortA2.class) 25 | @Size(message = "param_format",max = 36,groups = ValidationSorts.SortA3.class) 26 | @Pattern(message = "param_format",regexp = "^[^ ]+$",groups = ValidationSorts.SortA4.class) 27 | private String uniqueCode ; 28 | 29 | 30 | public abstract Map paramNameMap(); 31 | 32 | public String getUniqueCode() { 33 | return uniqueCode; 34 | } 35 | 36 | public void setUniqueCode(String uniqueCode) { 37 | this.uniqueCode = uniqueCode; 38 | } 39 | } -------------------------------------------------------------------------------- /kaifangqian-api/src/main/java/org/resrun/api/vo/base/SignLocation.java: -------------------------------------------------------------------------------- 1 | package org.resrun.api.vo.base; 2 | 3 | 4 | import java.io.Serializable; 5 | 6 | /** 7 | * @Description: 签署位置数据 8 | * @Package: org.resrun.vo.base 9 | * @ClassName: SignLocation 10 | * @author: FengLai_Gong 11 | */ 12 | public class SignLocation implements Serializable { 13 | 14 | private static final long serialVersionUID = -3441618832286287804L; 15 | 16 | 17 | //文件宽度 18 | private Number pageWidth ; 19 | 20 | //文件高度 21 | private Number pageHeight ; 22 | 23 | //页码 24 | private Integer page; 25 | 26 | //偏移量-X坐标 27 | private Number offsetX ; 28 | 29 | //偏移量-Y坐标 30 | private Number offsetY ; 31 | 32 | //签章宽度 33 | private Number signWidth ; 34 | 35 | //签章高度 36 | private Number signHeight ; 37 | 38 | public Number getPageWidth() { 39 | return pageWidth; 40 | } 41 | 42 | public void setPageWidth(Number pageWidth) { 43 | this.pageWidth = pageWidth; 44 | } 45 | 46 | public Number getPageHeight() { 47 | return pageHeight; 48 | } 49 | 50 | public void setPageHeight(Number pageHeight) { 51 | this.pageHeight = pageHeight; 52 | } 53 | 54 | public Integer getPage() { 55 | return page; 56 | } 57 | 58 | public void setPage(Integer page) { 59 | this.page = page; 60 | } 61 | 62 | public Number getOffsetX() { 63 | return offsetX; 64 | } 65 | 66 | public void setOffsetX(Number offsetX) { 67 | this.offsetX = offsetX; 68 | } 69 | 70 | public Number getOffsetY() { 71 | return offsetY; 72 | } 73 | 74 | public void setOffsetY(Number offsetY) { 75 | this.offsetY = offsetY; 76 | } 77 | 78 | public Number getSignWidth() { 79 | return signWidth; 80 | } 81 | 82 | public void setSignWidth(Number signWidth) { 83 | this.signWidth = signWidth; 84 | } 85 | 86 | public Number getSignHeight() { 87 | return signHeight; 88 | } 89 | 90 | public void setSignHeight(Number signHeight) { 91 | this.signHeight = signHeight; 92 | } 93 | } -------------------------------------------------------------------------------- /kaifangqian-api/src/main/java/org/resrun/api/vo/request/CertEventRequest.java: -------------------------------------------------------------------------------- 1 | package org.resrun.api.vo.request; 2 | 3 | import org.resrun.api.validation.ValidationSorts; 4 | import org.resrun.api.vo.base.APIRequest; 5 | 6 | import javax.validation.constraints.NotBlank; 7 | import javax.validation.constraints.NotNull; 8 | import javax.validation.constraints.Pattern; 9 | import javax.validation.constraints.Size; 10 | import java.io.Serializable; 11 | import java.util.HashMap; 12 | import java.util.Map; 13 | 14 | /** 15 | * @Description: 签名证书(事件证书)签发-请求对象 16 | * @Package: org.resrun.vo 17 | * @ClassName: CertEventRequest 18 | * @author: FengLai_Gong 19 | */ 20 | public class CertEventRequest extends APIRequest implements Serializable { 21 | 22 | private static final long serialVersionUID = -5135668270081357110L; 23 | 24 | 25 | //证书主题 长度100 26 | @NotNull(message = "param_missing",groups = ValidationSorts.SortB1.class) 27 | @NotBlank(message = "param_blank",groups = ValidationSorts.SortB2.class) 28 | @Size(message = "param_format",max = 100, groups = ValidationSorts.SortB3.class) 29 | @Pattern(message = "param_format",regexp = "^[^ ]+$",groups = ValidationSorts.SortB4.class) 30 | private String certSubject ; 31 | 32 | //证书密码 长度32 33 | @NotNull(message = "param_missing",groups = ValidationSorts.SortC1.class) 34 | @NotBlank(message = "param_blank",groups = ValidationSorts.SortC2.class) 35 | @Size(message = "param_format",max = 32,groups = ValidationSorts.SortC3.class) 36 | @Pattern(message = "param_format",regexp = "^[^ ]+$",groups = ValidationSorts.SortC4.class) 37 | private String certPassword ; 38 | 39 | 40 | @Override 41 | public Map paramNameMap() { 42 | Map map = new HashMap<>(); 43 | map.put("uniqueCode","uniqueCode"); 44 | map.put("certSubject","certSubject"); 45 | map.put("certPassword","certPassword"); 46 | return map; 47 | } 48 | 49 | public String getCertSubject() { 50 | return certSubject; 51 | } 52 | 53 | public void setCertSubject(String certSubject) { 54 | this.certSubject = certSubject; 55 | } 56 | 57 | public String getCertPassword() { 58 | return certPassword; 59 | } 60 | 61 | public void setCertPassword(String certPassword) { 62 | this.certPassword = certPassword; 63 | } 64 | } -------------------------------------------------------------------------------- /kaifangqian-api/src/main/java/org/resrun/api/vo/request/SignatureMakeRequest.java: -------------------------------------------------------------------------------- 1 | package org.resrun.api.vo.request; 2 | 3 | import org.resrun.api.validation.ValidationSorts; 4 | import org.resrun.api.vo.base.APIRequest; 5 | 6 | import javax.validation.constraints.NotBlank; 7 | import javax.validation.constraints.NotNull; 8 | import javax.validation.constraints.Size; 9 | import java.io.Serializable; 10 | import java.util.HashMap; 11 | import java.util.Map; 12 | 13 | public class SignatureMakeRequest extends APIRequest implements Serializable { 14 | 15 | //环绕文字 6~20长度,建议传递真实章的环绕文字 16 | @NotNull(message = "param_missing",groups = ValidationSorts.SortC1.class) 17 | @NotBlank(message = "param_blank",groups = ValidationSorts.SortC2.class) 18 | @Size(message = "param_format",max = 20, min = 6,groups = ValidationSorts.SortC3.class) 19 | 20 | 21 | private String topText; 22 | //横排文字 2~10长度,如:合同专用章 23 | @Size(message = "param_format",max = 10, min = 2,groups = ValidationSorts.SortD1.class) 24 | private String middleText; 25 | 26 | @Override 27 | public Map paramNameMap() { 28 | Map map = new HashMap<>(); 29 | map.put("uniqueCode","uniqueCode"); 30 | map.put("middleText","middleText"); 31 | map.put("topText","topText"); 32 | return map; 33 | } 34 | 35 | public String getTopText() { 36 | return topText; 37 | } 38 | 39 | public void setTopText(String topText) { 40 | this.topText = topText; 41 | } 42 | 43 | public String getMiddleText() { 44 | return middleText; 45 | } 46 | 47 | public void setMiddleText(String middleText) { 48 | this.middleText = middleText; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /kaifangqian-api/src/main/java/org/resrun/api/vo/response/CertEventResponse.java: -------------------------------------------------------------------------------- 1 | package org.resrun.api.vo.response; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * @Description: CertEventResponse 7 | * @Package: org.resrun.vo.response 8 | * @ClassName: CertEventResponse 9 | * @author: FengLai_Gong 10 | */ 11 | public class CertEventResponse implements Serializable { 12 | 13 | 14 | private static final long serialVersionUID = -2670652937955458956L; 15 | 16 | //证书主题 长度100 17 | private String certSubject ; 18 | 19 | //证书序列号 长度50 20 | private String certSN ; 21 | 22 | //签名证书文件 23 | private String pfx ; 24 | 25 | //证书密码 26 | private String certPassword ; 27 | 28 | //证书有效期起始时间 14 证书有效期起始时间(格式:yyyyMMddHHmmss) 29 | private String certValidityNotBefore ; 30 | 31 | //证书有效期截止时间 14 证书有效期截止时间(格式:yyyyMMddHHmmss) 32 | private String certValidityNotAfter ; 33 | 34 | //有效期天数 35 | private Integer certValidity ; 36 | 37 | public String getCertSubject() { 38 | return certSubject; 39 | } 40 | 41 | public void setCertSubject(String certSubject) { 42 | this.certSubject = certSubject; 43 | } 44 | 45 | public String getCertSN() { 46 | return certSN; 47 | } 48 | 49 | public void setCertSN(String certSN) { 50 | this.certSN = certSN; 51 | } 52 | 53 | public String getPfx() { 54 | return pfx; 55 | } 56 | 57 | public void setPfx(String pfx) { 58 | this.pfx = pfx; 59 | } 60 | 61 | public String getCertPassword() { 62 | return certPassword; 63 | } 64 | 65 | public void setCertPassword(String certPassword) { 66 | this.certPassword = certPassword; 67 | } 68 | 69 | public String getCertValidityNotBefore() { 70 | return certValidityNotBefore; 71 | } 72 | 73 | public void setCertValidityNotBefore(String certValidityNotBefore) { 74 | this.certValidityNotBefore = certValidityNotBefore; 75 | } 76 | 77 | public String getCertValidityNotAfter() { 78 | return certValidityNotAfter; 79 | } 80 | 81 | public void setCertValidityNotAfter(String certValidityNotAfter) { 82 | this.certValidityNotAfter = certValidityNotAfter; 83 | } 84 | 85 | public Integer getCertValidity() { 86 | return certValidity; 87 | } 88 | 89 | public void setCertValidity(Integer certValidity) { 90 | this.certValidity = certValidity; 91 | } 92 | } -------------------------------------------------------------------------------- /kaifangqian-api/src/main/java/org/resrun/api/vo/response/DocumentSignResponse.java: -------------------------------------------------------------------------------- 1 | package org.resrun.api.vo.response; 2 | 3 | 4 | import java.io.Serializable; 5 | 6 | /** 7 | * @Description: DocumentSignResponse 8 | * @Package: org.resrun.vo.response 9 | * @ClassName: DocumentSignResponse 10 | * @author: FengLai_Gong 11 | */ 12 | public class DocumentSignResponse implements Serializable { 13 | 14 | private static final long serialVersionUID = 620669287901843970L; 15 | 16 | //签署后的文件 17 | private String documentFile ; 18 | 19 | public String getDocumentFile() { 20 | return documentFile; 21 | } 22 | 23 | public void setDocumentFile(String documentFile) { 24 | this.documentFile = documentFile; 25 | } 26 | } -------------------------------------------------------------------------------- /kaifangqian-api/src/main/java/org/resrun/api/vo/response/SignatureMakeResponse.java: -------------------------------------------------------------------------------- 1 | package org.resrun.api.vo.response; 2 | 3 | public class SignatureMakeResponse { 4 | 5 | private String entSeal; 6 | 7 | public String getEntSeal() { 8 | return entSeal; 9 | } 10 | 11 | public void setEntSeal(String entSeal) { 12 | this.entSeal = entSeal; 13 | } 14 | 15 | public SignatureMakeResponse(String entSeal) { 16 | this.entSeal = entSeal; 17 | } 18 | 19 | public SignatureMakeResponse() { 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /kaifangqian-api/src/main/resources/application-prod.yml: -------------------------------------------------------------------------------- 1 | server: 2 | # 项目启动端口号 3 | port: 8891 4 | tomcat: 5 | # 上传文件限制 -1 无限制 6 | max-swallow-size: -1 7 | error: 8 | #true:开启自定义异常处理 9 | include-exception: true 10 | # 是否包含异常的堆栈信息,默认是NEVER,其他ALWAYS,ON_TRACE_PARAM等。 11 | include-stacktrace: ALWAYS 12 | # 是否包含异常的返回信息,默认是NEVER,其他ALWAYS,ON_TRACE_PARAM等。 13 | include-message: ALWAYS 14 | servlet: 15 | #路径前缀 16 | context-path: / 17 | 18 | 19 | spring: 20 | servlet: 21 | multipart: 22 | #请求文件大小限制 23 | max-file-size: 20MB 24 | #请求体大小限制 25 | max-request-size: 20MB 26 | #json时间戳统一转换 27 | jackson: 28 | date-format: yyyy-MM-dd HH:mm:ss 29 | time-zone: GMT+8 30 | aop: 31 | #代理方式(手动创建时生效) 默认为false,表示使用JDK动态代理织入增强;当值为true时,表示使用CGLib动态代理织入增强。 32 | proxy-target-class: true 33 | mvc: 34 | static-path-pattern: /** 35 | # IP 本地解析 36 | ip: 37 | local-parsing: true 38 | 39 | 40 | kaifangqian: 41 | #证书服务地址 42 | cert-apply-url: https://localhost/service/cert/event 43 | #授权token 44 | token: 123456 45 | # 默认 false 签发本地测试证书 true 签发 CA 证书 46 | prod: false -------------------------------------------------------------------------------- /kaifangqian-api/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: kaifangqian-api 4 | profiles: 5 | active: prod -------------------------------------------------------------------------------- /kaifangqian-api/src/main/resources/ip2region/ip2region.xdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaifangqian/kaifangqian-base/9157ecd23e1e59d3d8849efadd83efe2bd28e00a/kaifangqian-api/src/main/resources/ip2region/ip2region.xdb -------------------------------------------------------------------------------- /kaifangqian-api/src/main/resources/logback-spring.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | kaifangqian-api 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | INFO 13 | 14 | 15 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger\(%line\)- %msg%n 16 | 17 | 18 | 19 | 20 | 22 | 24 | ${logback.logdir}/${logback.appname}.log 25 | 26 | 28 | 29 | ${logback.logdir}/${logback.appname}.%d{yyyy-MM-dd}.log 30 | 32 | 33 | 90 34 | 35 | 300GB 36 | true 37 | 38 | 39 | 40 | UTF-8 41 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger\(%line\)- %msg%n 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /kaifangqian-api/src/main/resources/root/root.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaifangqian/kaifangqian-base/9157ecd23e1e59d3d8849efadd83efe2bd28e00a/kaifangqian-api/src/main/resources/root/root.jks -------------------------------------------------------------------------------- /kaifangqian-demo-api/README.md: -------------------------------------------------------------------------------- 1 | # 开放签--demo后端api 2 | 3 | ## 1、启动项目 4 | ``` 5 | #需要提前准备好jdk1.8+,maven3.0+的环境 6 | 7 | #进入项目目录 8 | cd kaifangqian-demo-api 9 | 10 | #打包 11 | mvn clean package 12 | 13 | #启动项目 默认端口为8666 14 | java -jar ./target/kaifangqian-demo-api.jar 15 | ``` 16 | 17 | 18 | -------------------------------------------------------------------------------- /kaifangqian-demo-api/src/main/java/org/resrun/OpenSignDemoApplication.java: -------------------------------------------------------------------------------- 1 | package org.resrun; 2 | 3 | import io.swagger.annotations.ApiOperation; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import org.springframework.boot.SpringApplication; 7 | import org.springframework.boot.autoconfigure.SpringBootApplication; 8 | import org.springframework.context.ConfigurableApplicationContext; 9 | import org.springframework.core.env.Environment; 10 | import org.springframework.web.bind.annotation.GetMapping; 11 | import org.springframework.web.bind.annotation.RestController; 12 | 13 | import java.net.InetAddress; 14 | 15 | @RestController 16 | @SpringBootApplication 17 | public class OpenSignDemoApplication { 18 | 19 | private static Logger log = LoggerFactory.getLogger(OpenSignDemoApplication.class); 20 | 21 | public static void main(String[] args) { 22 | 23 | 24 | ConfigurableApplicationContext application = SpringApplication.run(OpenSignDemoApplication.class, args); 25 | Environment env = application.getEnvironment(); 26 | String ip = "127.0.0.1"; 27 | String port = env.getProperty("server.port"); 28 | String path = env.getProperty("server.servlet.context-path"); 29 | log.info("\n----------------------------------------------------------\n\t" + 30 | "Application kaifangqian-demo is running! Access URLs:\n\t" + 31 | "External: \thttp://" + ip + ":" + port + path + "/\n" + 32 | "----------------------------------------------------------"); 33 | 34 | } 35 | 36 | @GetMapping("/") 37 | @ApiOperation(value = "项目根目录") 38 | public String index(){ 39 | return "kaifangqian-demo run success"; 40 | } 41 | 42 | } -------------------------------------------------------------------------------- /kaifangqian-demo-api/src/main/java/org/resrun/config/SpringBeanManage.java: -------------------------------------------------------------------------------- 1 | package org.resrun.config; 2 | 3 | import org.resrun.sdk.config.SDKClientConfig; 4 | import org.springframework.boot.context.properties.ConfigurationProperties; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | 8 | @Configuration 9 | public class SpringBeanManage { 10 | @Bean 11 | @ConfigurationProperties(prefix = "kaifangqian") 12 | public SDKClientConfig clientConfig(){ 13 | return new SDKClientConfig(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /kaifangqian-demo-api/src/main/java/org/resrun/controller/vo/base/Result.java: -------------------------------------------------------------------------------- 1 | package org.resrun.controller.vo.base; 2 | 3 | import io.swagger.annotations.ApiModel; 4 | import io.swagger.annotations.ApiModelProperty; 5 | 6 | import java.io.Serializable; 7 | 8 | /** 9 | * @Description: Result 10 | * @Package: org.resrun.controller.vo 11 | * @ClassName: Result 12 | * @copyright 北京资源律动科技有限公司 13 | */ 14 | 15 | @ApiModel("统一返回对象") 16 | public class Result implements Serializable { 17 | 18 | private static final long serialVersionUID = 4186430915088458662L; 19 | 20 | @ApiModelProperty("成功标志") 21 | private boolean success = true; 22 | @ApiModelProperty("返回处理消息") 23 | private String message = ""; 24 | @ApiModelProperty("返回代码") 25 | private Integer code = 200; 26 | @ApiModelProperty("返回数据对象") 27 | private T result; 28 | @ApiModelProperty("时间戳") 29 | private long timestamp = System.currentTimeMillis(); 30 | 31 | 32 | public static Result OK(T data) { 33 | Result r = new Result(); 34 | r.setSuccess(true); 35 | r.setCode(200); 36 | r.setResult(data); 37 | return r; 38 | } 39 | 40 | 41 | 42 | public static Result error(String msg, T data) { 43 | Result r = new Result(); 44 | r.setSuccess(false); 45 | r.setCode(500); 46 | r.setMessage(msg); 47 | r.setResult(data); 48 | return r; 49 | } 50 | 51 | public Result(boolean success, String message, Integer code, T result, long timestamp) { 52 | this.success = success; 53 | this.message = message; 54 | this.code = code; 55 | this.result = result; 56 | this.timestamp = timestamp; 57 | } 58 | 59 | public Result() { 60 | } 61 | 62 | public boolean isSuccess() { 63 | return success; 64 | } 65 | 66 | public void setSuccess(boolean success) { 67 | this.success = success; 68 | } 69 | 70 | public String getMessage() { 71 | return message; 72 | } 73 | 74 | public void setMessage(String message) { 75 | this.message = message; 76 | } 77 | 78 | public Integer getCode() { 79 | return code; 80 | } 81 | 82 | public void setCode(Integer code) { 83 | this.code = code; 84 | } 85 | 86 | public T getResult() { 87 | return result; 88 | } 89 | 90 | public void setResult(T result) { 91 | this.result = result; 92 | } 93 | 94 | public long getTimestamp() { 95 | return timestamp; 96 | } 97 | 98 | public void setTimestamp(long timestamp) { 99 | this.timestamp = timestamp; 100 | } 101 | } -------------------------------------------------------------------------------- /kaifangqian-demo-api/src/main/java/org/resrun/controller/vo/request/ClipSealRequest.java: -------------------------------------------------------------------------------- 1 | package org.resrun.controller.vo.request; 2 | 3 | import io.swagger.annotations.ApiModel; 4 | import io.swagger.annotations.ApiModelProperty; 5 | 6 | import java.io.Serializable; 7 | 8 | /** 9 | * @Description: ClipSealRequest 10 | * @Package: org.resrun.controller.vo.request 11 | * @ClassName: ClipSealRequest 12 | * @copyright 北京资源律动科技有限公司 13 | */ 14 | @ApiModel("企业印章上传生成-请求对象") 15 | public class ClipSealRequest implements Serializable { 16 | 17 | private static final long serialVersionUID = 7532064967450524188L; 18 | 19 | @ApiModelProperty("图片base64") 20 | private String image ; 21 | 22 | @ApiModelProperty("色差范围0~255") 23 | private Integer colorRange ; 24 | 25 | public String getImage() { 26 | return image; 27 | } 28 | 29 | public void setImage(String image) { 30 | this.image = image; 31 | } 32 | 33 | public Integer getColorRange() { 34 | return colorRange; 35 | } 36 | 37 | public void setColorRange(Integer colorRange) { 38 | this.colorRange = colorRange; 39 | } 40 | 41 | public ClipSealRequest(String image, Integer colorRange) { 42 | this.image = image; 43 | this.colorRange = colorRange; 44 | } 45 | 46 | public ClipSealRequest() { 47 | } 48 | } -------------------------------------------------------------------------------- /kaifangqian-demo-api/src/main/java/org/resrun/controller/vo/request/GenerateSealRequest.java: -------------------------------------------------------------------------------- 1 | package org.resrun.controller.vo.request; 2 | 3 | import io.swagger.annotations.ApiModel; 4 | import io.swagger.annotations.ApiModelProperty; 5 | 6 | import java.io.Serializable; 7 | 8 | /** 9 | * @Description: SealRequest 10 | * @Package: org.resrun.controller.vo.request 11 | * @ClassName: SealRequest 12 | * @copyright 北京资源律动科技有限公司 13 | */ 14 | @ApiModel("企业印章参数生成-请求对象") 15 | public class GenerateSealRequest implements Serializable { 16 | 17 | private static final long serialVersionUID = -7107056549410243340L; 18 | 19 | @ApiModelProperty("企业名称") 20 | private String topText; 21 | @ApiModelProperty("横排文字") 22 | private String middleText ; 23 | 24 | public GenerateSealRequest() { 25 | } 26 | 27 | public GenerateSealRequest(String topText, String middleText) { 28 | this.topText = topText; 29 | this.middleText = middleText; 30 | } 31 | 32 | public String getTopText() { 33 | return topText; 34 | } 35 | 36 | public void setTopText(String topText) { 37 | this.topText = topText; 38 | } 39 | 40 | public String getMiddleText() { 41 | return middleText; 42 | } 43 | 44 | public void setMiddleText(String middleText) { 45 | this.middleText = middleText; 46 | } 47 | } -------------------------------------------------------------------------------- /kaifangqian-demo-api/src/main/java/org/resrun/controller/vo/request/PositionRequest.java: -------------------------------------------------------------------------------- 1 | package org.resrun.controller.vo.request; 2 | 3 | import io.swagger.annotations.ApiModel; 4 | import io.swagger.annotations.ApiModelProperty; 5 | 6 | import java.io.Serializable; 7 | 8 | /** 9 | * @Description: PositionRequest 10 | * @Package: org.resrun.controller.vo.request 11 | * @ClassName: PositionRequest 12 | * @copyright 北京资源律动科技有限公司 13 | */ 14 | @ApiModel("签署位置-请求对象") 15 | public class PositionRequest implements Serializable { 16 | 17 | private static final long serialVersionUID = 1407897694551031954L; 18 | 19 | @ApiModelProperty("控件X坐标(左上角)") 20 | private String offsetX ; 21 | 22 | @ApiModelProperty("控件Y坐标(左上角)") 23 | private String offsetY ; 24 | 25 | @ApiModelProperty("控件宽度") 26 | private String width ; 27 | 28 | @ApiModelProperty("控件高度") 29 | private String height ; 30 | 31 | @ApiModelProperty("控件所属页码") 32 | private Integer page ; 33 | 34 | @ApiModelProperty("当前文件页面宽度") 35 | private String pageWidth ; 36 | 37 | @ApiModelProperty("当前文件页面高度") 38 | private String pageHeight ; 39 | 40 | 41 | public String getOffsetX() { 42 | return offsetX; 43 | } 44 | 45 | public void setOffsetX(String offsetX) { 46 | this.offsetX = offsetX; 47 | } 48 | 49 | public String getOffsetY() { 50 | return offsetY; 51 | } 52 | 53 | public void setOffsetY(String offsetY) { 54 | this.offsetY = offsetY; 55 | } 56 | 57 | public String getWidth() { 58 | return width; 59 | } 60 | 61 | public void setWidth(String width) { 62 | this.width = width; 63 | } 64 | 65 | public String getHeight() { 66 | return height; 67 | } 68 | 69 | public void setHeight(String height) { 70 | this.height = height; 71 | } 72 | 73 | public Integer getPage() { 74 | return page; 75 | } 76 | 77 | public void setPage(Integer page) { 78 | this.page = page; 79 | } 80 | 81 | public String getPageWidth() { 82 | return pageWidth; 83 | } 84 | 85 | public void setPageWidth(String pageWidth) { 86 | this.pageWidth = pageWidth; 87 | } 88 | 89 | public String getPageHeight() { 90 | return pageHeight; 91 | } 92 | 93 | public void setPageHeight(String pageHeight) { 94 | this.pageHeight = pageHeight; 95 | } 96 | } -------------------------------------------------------------------------------- /kaifangqian-demo-api/src/main/java/org/resrun/controller/vo/request/SignRequest.java: -------------------------------------------------------------------------------- 1 | package org.resrun.controller.vo.request; 2 | 3 | import io.swagger.annotations.ApiModel; 4 | import io.swagger.annotations.ApiModelProperty; 5 | 6 | import java.io.Serializable; 7 | import java.util.List; 8 | 9 | /** 10 | * @Description: SignRequest 11 | * @Package: org.resrun.controller.vo.request 12 | * @ClassName: SignRequest 13 | * @copyright 北京资源律动科技有限公司 14 | */ 15 | 16 | @ApiModel("签署-请求对象") 17 | public class SignRequest implements Serializable { 18 | 19 | @ApiModelProperty("签署类型,1位置签署,2关键字签署") 20 | private Integer signType ; 21 | 22 | @ApiModelProperty("企业签章base64") 23 | private String entSeal ; 24 | 25 | @ApiModelProperty("企业名称") 26 | private String entName ; 27 | 28 | @ApiModelProperty("个人签章base64") 29 | private String personalSeal ; 30 | 31 | @ApiModelProperty("个人名称") 32 | private String personalName ; 33 | 34 | @ApiModelProperty("企业签署位置") 35 | private List entPositionList ; 36 | 37 | @ApiModelProperty("个人签章位置") 38 | private List personalPositionList ; 39 | 40 | @ApiModelProperty("企业签章关键字") 41 | private String entKeyword ; 42 | 43 | @ApiModelProperty("个人签章关键字") 44 | private String personalKeyword ; 45 | 46 | 47 | public Integer getSignType() { 48 | return signType; 49 | } 50 | 51 | public void setSignType(Integer signType) { 52 | this.signType = signType; 53 | } 54 | 55 | public String getEntSeal() { 56 | return entSeal; 57 | } 58 | 59 | public void setEntSeal(String entSeal) { 60 | this.entSeal = entSeal; 61 | } 62 | 63 | public String getEntName() { 64 | return entName; 65 | } 66 | 67 | public void setEntName(String entName) { 68 | this.entName = entName; 69 | } 70 | 71 | public String getPersonalSeal() { 72 | return personalSeal; 73 | } 74 | 75 | public void setPersonalSeal(String personalSeal) { 76 | this.personalSeal = personalSeal; 77 | } 78 | 79 | public String getPersonalName() { 80 | return personalName; 81 | } 82 | 83 | public void setPersonalName(String personalName) { 84 | this.personalName = personalName; 85 | } 86 | 87 | public List getEntPositionList() { 88 | return entPositionList; 89 | } 90 | 91 | public void setEntPositionList(List entPositionList) { 92 | this.entPositionList = entPositionList; 93 | } 94 | 95 | public List getPersonalPositionList() { 96 | return personalPositionList; 97 | } 98 | 99 | public void setPersonalPositionList(List personalPositionList) { 100 | this.personalPositionList = personalPositionList; 101 | } 102 | 103 | public String getEntKeyword() { 104 | return entKeyword; 105 | } 106 | 107 | public void setEntKeyword(String entKeyword) { 108 | this.entKeyword = entKeyword; 109 | } 110 | 111 | public String getPersonalKeyword() { 112 | return personalKeyword; 113 | } 114 | 115 | public void setPersonalKeyword(String personalKeyword) { 116 | this.personalKeyword = personalKeyword; 117 | } 118 | } -------------------------------------------------------------------------------- /kaifangqian-demo-api/src/main/java/org/resrun/controller/vo/request/VerifyRequest.java: -------------------------------------------------------------------------------- 1 | package org.resrun.controller.vo.request; 2 | 3 | import io.swagger.annotations.ApiModel; 4 | import io.swagger.annotations.ApiModelProperty; 5 | 6 | import java.io.Serializable; 7 | 8 | /** 9 | * @Description: VerifyRequest 10 | * @Package: org.resrun.controller.vo.request 11 | * @ClassName: VerifyRequest 12 | * @copyright 北京资源律动科技有限公司 13 | */ 14 | @ApiModel("文件验签-请求对象") 15 | public class VerifyRequest implements Serializable { 16 | 17 | private static final long serialVersionUID = -5412004997017887483L; 18 | 19 | @ApiModelProperty("验签文件base64") 20 | private String verifyFile ; 21 | 22 | @ApiModelProperty("验签文件名称") 23 | private String fileName ; 24 | 25 | 26 | public VerifyRequest(String verifyFile, String fileName) { 27 | this.verifyFile = verifyFile; 28 | this.fileName = fileName; 29 | } 30 | 31 | public VerifyRequest() { 32 | } 33 | 34 | public String getVerifyFile() { 35 | return verifyFile; 36 | } 37 | 38 | public void setVerifyFile(String verifyFile) { 39 | this.verifyFile = verifyFile; 40 | } 41 | 42 | public String getFileName() { 43 | return fileName; 44 | } 45 | 46 | public void setFileName(String fileName) { 47 | this.fileName = fileName; 48 | } 49 | } -------------------------------------------------------------------------------- /kaifangqian-demo-api/src/main/java/org/resrun/controller/vo/response/SealResponse.java: -------------------------------------------------------------------------------- 1 | package org.resrun.controller.vo.response; 2 | 3 | import io.swagger.annotations.ApiModel; 4 | import io.swagger.annotations.ApiModelProperty; 5 | 6 | import java.io.Serializable; 7 | 8 | /** 9 | * @Description: SealResponse 10 | * @Package: org.resrun.controller.vo.response 11 | * @ClassName: SealResponse 12 | * @copyright 北京资源律动科技有限公司 13 | */ 14 | @ApiModel("企业印章生成-返回对象") 15 | public class SealResponse implements Serializable { 16 | 17 | private static final long serialVersionUID = 3376686508340918420L; 18 | 19 | @ApiModelProperty("企业签章base64") 20 | private String entSeal ; 21 | 22 | 23 | 24 | public String getEntSeal() { 25 | return entSeal; 26 | } 27 | 28 | public void setEntSeal(String entSeal) { 29 | this.entSeal = entSeal; 30 | } 31 | } -------------------------------------------------------------------------------- /kaifangqian-demo-api/src/main/java/org/resrun/controller/vo/response/SignResponse.java: -------------------------------------------------------------------------------- 1 | package org.resrun.controller.vo.response; 2 | 3 | import io.swagger.annotations.ApiModel; 4 | import io.swagger.annotations.ApiModelProperty; 5 | 6 | import java.io.Serializable; 7 | 8 | /** 9 | * @Description: SignResponse 10 | * @Package: org.resrun.controller.vo.response 11 | * @ClassName: SignResponse 12 | * @copyright 北京资源律动科技有限公司 13 | */ 14 | 15 | @ApiModel("文件签署-返回对象") 16 | public class SignResponse implements Serializable { 17 | 18 | private static final long serialVersionUID = 7191345743000212815L; 19 | 20 | @ApiModelProperty("签署后文件") 21 | private String signFile ; 22 | 23 | public String getSignFile() { 24 | return signFile; 25 | } 26 | 27 | public void setSignFile(String signFile) { 28 | this.signFile = signFile; 29 | } 30 | } -------------------------------------------------------------------------------- /kaifangqian-demo-api/src/main/java/org/resrun/controller/vo/response/VerifyResponse.java: -------------------------------------------------------------------------------- 1 | package org.resrun.controller.vo.response; 2 | 3 | import org.resrun.service.pojo.SignPdfInfoVo; 4 | import io.swagger.annotations.ApiModel; 5 | import io.swagger.annotations.ApiModelProperty; 6 | 7 | import java.io.Serializable; 8 | 9 | /** 10 | * @Description: VerifyRequest 11 | * @Package: org.resrun.controller.vo.response 12 | * @ClassName: VerifyRequest 13 | * @copyright 北京资源律动科技有限公司 14 | */ 15 | 16 | @ApiModel("文件验签-返回对象") 17 | public class VerifyResponse implements Serializable { 18 | 19 | private static final long serialVersionUID = -1498109564641142303L; 20 | 21 | @ApiModelProperty("返回信息") 22 | private String msg ; 23 | 24 | @ApiModelProperty("详细数据") 25 | private SignPdfInfoVo vo ; 26 | 27 | public VerifyResponse(String msg, SignPdfInfoVo vo) { 28 | this.msg = msg; 29 | this.vo = vo; 30 | } 31 | 32 | public VerifyResponse() { 33 | } 34 | 35 | public String getMsg() { 36 | return msg; 37 | } 38 | 39 | public void setMsg(String msg) { 40 | this.msg = msg; 41 | } 42 | 43 | public SignPdfInfoVo getVo() { 44 | return vo; 45 | } 46 | 47 | public void setVo(SignPdfInfoVo vo) { 48 | this.vo = vo; 49 | } 50 | } -------------------------------------------------------------------------------- /kaifangqian-demo-api/src/main/java/org/resrun/enums/SealColorEnum.java: -------------------------------------------------------------------------------- 1 | package org.resrun.enums; 2 | 3 | /** 4 | * @Description: 签章颜色枚举类 5 | * @Package: org.resrun.enums 6 | * @ClassName: SealColorEnum 7 | * @copyright 北京资源律动科技有限公司 8 | */ 9 | public enum SealColorEnum { 10 | 11 | RED(1,"红色"), 12 | BLUE(2,"蓝色"), 13 | BLACK(3,"黑色"), 14 | 15 | ; 16 | 17 | private Integer code ; 18 | private String name ; 19 | 20 | SealColorEnum(Integer code, String name){ 21 | this.code = code ; 22 | this.name = name ; 23 | } 24 | 25 | public String getName(){ 26 | return this.name ; 27 | } 28 | 29 | public Integer getCode(){ 30 | return this.code ; 31 | } 32 | 33 | 34 | 35 | 36 | } -------------------------------------------------------------------------------- /kaifangqian-demo-api/src/main/java/org/resrun/enums/SealShapeStyleEnum.java: -------------------------------------------------------------------------------- 1 | package org.resrun.enums; 2 | 3 | /** 4 | * @Description: 个人签章形状样式 5 | * @Package: com.resrun.modules.sign.enums 6 | * @ClassName: SealBorderEnum 7 | * @author: FengLai_Gong 8 | */ 9 | public enum SealShapeStyleEnum { 10 | 11 | RECTANGLE_NO_FRAME(1,"长方形无框"), 12 | RECTANGLE_FRAME(2,"长方形有框"), 13 | SQUARE_NO_FRAME(3,"正方形无框"), 14 | SQUARE_FRAME(4,"正方形有框"), 15 | 16 | ; 17 | 18 | private Integer code ; 19 | private String name ; 20 | 21 | SealShapeStyleEnum(Integer code, String name){ 22 | this.code = code ; 23 | this.name = name ; 24 | } 25 | 26 | public String getName(){ 27 | return this.name ; 28 | } 29 | 30 | public Integer getCode(){ 31 | return this.code ; 32 | } 33 | } -------------------------------------------------------------------------------- /kaifangqian-demo-api/src/main/java/org/resrun/enums/SignStatus.java: -------------------------------------------------------------------------------- 1 | package org.resrun.enums; 2 | 3 | 4 | /** 5 | * @Description: 签名文件状态枚举 6 | * @Package: org.resrun.enums 7 | * @ClassName: SignStatus 8 | * @copyright 北京资源律动科技有限公司 9 | */ 10 | 11 | public enum SignStatus { 12 | SIGN_STATUS_NOSIGNATURE("PDF文件未发现任何数字签名信息",1), 13 | SIGN_STATUS_ERROR("PDF签名验证时发生错误,签名包含不正确的、无法识别的、已损坏的或可疑的数据",2), 14 | SIGN_STATUS_FIDDLE("PDF中存在数字证书,但文档被篡改,进入下一步,展示验证结果",3), 15 | SIGN_STATUS_RIGHT("PDF中存在数字证书,文档未被篡改,进入下一步,展示验证结果",4), 16 | 17 | ; 18 | 19 | private String msg; 20 | private Integer code; 21 | SignStatus(String msg,Integer code){ 22 | this.msg = msg; 23 | this.code = code; 24 | } 25 | 26 | public Integer getCode(){ 27 | return code; 28 | } 29 | public String getMsg(){ 30 | return msg; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /kaifangqian-demo-api/src/main/java/org/resrun/enums/SignTypeEnum.java: -------------------------------------------------------------------------------- 1 | package org.resrun.enums; 2 | 3 | /** 4 | * @Description: 签署类型 1:关键字签署;2:指定位置签署 5 | * @Package: org.resrun.enums 6 | * @ClassName: SignTypeEnum 7 | * @author: FengLai_Gong 8 | */ 9 | public enum SignTypeEnum { 10 | 11 | 12 | POSITION(1,"指定位置签署"), 13 | KEYWORDS(2,"关键字签署"), 14 | 15 | 16 | 17 | ; 18 | 19 | private Integer code ; 20 | 21 | private String name ; 22 | 23 | SignTypeEnum(Integer code, String name){ 24 | this.code = code ; 25 | this.name = name; 26 | } 27 | 28 | 29 | public Integer getCode(){ 30 | return this.code; 31 | } 32 | 33 | public String getName(){ 34 | return this.name ; 35 | } 36 | 37 | 38 | } -------------------------------------------------------------------------------- /kaifangqian-demo-api/src/main/java/org/resrun/service/image/EntSealClipService.java: -------------------------------------------------------------------------------- 1 | package org.resrun.service.image; 2 | 3 | import org.springframework.stereotype.Service; 4 | 5 | import javax.imageio.ImageIO; 6 | import javax.swing.*; 7 | import java.awt.*; 8 | import java.awt.image.BufferedImage; 9 | import java.io.ByteArrayInputStream; 10 | import java.io.ByteArrayOutputStream; 11 | import java.io.IOException; 12 | 13 | /** 14 | * @Description: 企业签章业务 15 | * @Package: org.resrun.service.image 16 | * @ClassName: EntSealClipService 17 | * @copyright 北京资源律动科技有限公司 18 | */ 19 | @Service 20 | public class EntSealClipService { 21 | 22 | public byte[] clip(byte[] originByte, Integer colorRange){ 23 | ByteArrayInputStream inputStream = new ByteArrayInputStream(originByte); 24 | BufferedImage image = null; 25 | try { 26 | image = ImageIO.read(inputStream); 27 | } catch (Exception e) { 28 | e.printStackTrace(); 29 | } 30 | // 高度和宽度 31 | int height = image.getHeight(); 32 | int width = image.getWidth(); 33 | 34 | // 生产背景透明和内容透明的图片 35 | ImageIcon imageIcon = new ImageIcon(image); 36 | BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR); 37 | Graphics2D g2D = (Graphics2D) bufferedImage.getGraphics(); // 获取画笔 38 | g2D.drawImage(imageIcon.getImage(), 0, 0, null); // 绘制Image的图片,使用了imageIcon.getImage(),目的就是得到image,直接使用image就可以的 39 | 40 | int alpha = 0; // 图片透明度 41 | // 外层遍历是Y轴的像素 42 | for (int y = bufferedImage.getMinY(); y < bufferedImage.getHeight(); y++) { 43 | // 内层遍历是X轴的像素 44 | for (int x = bufferedImage.getMinX(); x < bufferedImage.getWidth(); x++) { 45 | int rgb = bufferedImage.getRGB(x, y); 46 | // 对当前颜色判断是否在指定区间内 47 | if (colorInRange(rgb,colorRange)){ 48 | // #AARRGGBB 最前两位为透明度 49 | rgb = (alpha << 24) | (rgb & 0x00ffffff); 50 | bufferedImage.setRGB(x, y, rgb); 51 | alpha = 0; 52 | }else{ 53 | // 设置为不透明 54 | alpha = 255; 55 | // #AARRGGBB 最前两位为透明度 56 | rgb = (alpha << 24) | (0xff0000); 57 | bufferedImage.setRGB(x, y, rgb); 58 | } 59 | 60 | } 61 | } 62 | // 绘制设置了RGB的新图片,这一步感觉不用也可以只是透明地方的深浅有变化而已,就像蒙了两层的感觉 63 | g2D.drawImage(bufferedImage, 0, 0, null); 64 | 65 | // 生成图片为PNG 66 | ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 67 | try { 68 | ImageIO.write(bufferedImage, "png", outputStream); 69 | } catch (IOException e) { 70 | e.printStackTrace(); 71 | } 72 | return outputStream.toByteArray(); 73 | } 74 | 75 | // 判断是背景还是内容 76 | public boolean colorInRange(int color , Integer colorRange) { 77 | int red = (color & 0xff0000) >> 16;// 获取color(RGB)中R位 78 | int green = (color & 0x00ff00) >> 8;// 获取color(RGB)中G位 79 | int blue = (color & 0x0000ff);// 获取color(RGB)中B位 80 | // 通过RGB三分量来判断当前颜色是否在指定的颜色区间内 81 | if (red >= colorRange && green >= colorRange && blue >= colorRange){ 82 | return true; 83 | } 84 | return false; 85 | } 86 | } -------------------------------------------------------------------------------- /kaifangqian-demo-api/src/main/java/org/resrun/service/image/PdfConvertImageService.java: -------------------------------------------------------------------------------- 1 | package org.resrun.service.image; 2 | 3 | import org.apache.pdfbox.Loader; 4 | import org.resrun.service.pojo.ConvertImage; 5 | import org.apache.pdfbox.pdmodel.PDDocument; 6 | import org.apache.pdfbox.rendering.PDFRenderer; 7 | import org.springframework.stereotype.Service; 8 | 9 | import javax.imageio.ImageIO; 10 | import java.awt.image.BufferedImage; 11 | import java.io.ByteArrayOutputStream; 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | 15 | /** 16 | * @Description: pdf文件转图片业务 17 | * @Package: org.resrun.service.image 18 | * @ClassName: Pdf2ImageService 19 | * @copyright 北京资源律动科技有限公司 20 | */ 21 | @Service 22 | public class PdfConvertImageService { 23 | 24 | private Float resolution = 90f ; 25 | /**图片格式为jpg类型**/ 26 | public static final String IMG_JPE = "jpg"; 27 | /**图片格式为png类型**/ 28 | public static final String IMG_PNG = "png"; 29 | 30 | public List convertImage(byte[] signFileByte){ 31 | if(signFileByte == null){ 32 | return null ; 33 | } 34 | List responseList = new ArrayList<>(); 35 | PDDocument doc = null; 36 | try { 37 | //加载pdf文件 38 | doc = Loader.loadPDF(signFileByte); 39 | PDFRenderer renderer = new PDFRenderer(doc); 40 | int pageCount = doc.getNumberOfPages(); 41 | if(pageCount == 0){ 42 | return responseList; 43 | } 44 | 45 | for (int i = 0; i < pageCount; ++i) { 46 | int page = i ; 47 | BufferedImage image = renderer.renderImageWithDPI(page, resolution); 48 | ByteArrayOutputStream stream = new ByteArrayOutputStream(); 49 | ImageIO.write(image, IMG_PNG, stream); 50 | byte[] bytes = stream.toByteArray(); 51 | if(bytes != null){ 52 | ConvertImage response = new ConvertImage(); 53 | response.setImageByte(bytes); 54 | response.setPage(page); 55 | responseList.add(response); 56 | 57 | } 58 | } 59 | }catch (Exception e) { 60 | e.printStackTrace(); 61 | } 62 | 63 | return responseList ; 64 | } 65 | 66 | 67 | } -------------------------------------------------------------------------------- /kaifangqian-demo-api/src/main/java/org/resrun/service/pojo/BaseCertificateInfo.java: -------------------------------------------------------------------------------- 1 | package org.resrun.service.pojo; 2 | 3 | import java.security.KeyStore; 4 | 5 | /** 6 | * @Description: 证书文件属性类 7 | * @Package: org.resrun.service.pojo 8 | * @ClassName: CertificateProperty 9 | * @copyright 北京资源律动科技有限公司 10 | */ 11 | public class BaseCertificateInfo { 12 | 13 | /** 14 | * 根证书 15 | */ 16 | private KeyStore cert; 17 | 18 | /** 19 | * 证书别名 20 | */ 21 | private String alias; 22 | 23 | /** 24 | * 证书密码 25 | */ 26 | private String password; 27 | 28 | public KeyStore getCert() { 29 | return cert; 30 | } 31 | 32 | public void setCert(KeyStore cert) { 33 | this.cert = cert; 34 | } 35 | 36 | public String getAlias() { 37 | return alias; 38 | } 39 | 40 | public void setAlias(String alias) { 41 | this.alias = alias; 42 | } 43 | 44 | public String getPassword() { 45 | return password; 46 | } 47 | 48 | public void setPassword(String password) { 49 | this.password = password; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /kaifangqian-demo-api/src/main/java/org/resrun/service/pojo/CertificateProperty.java: -------------------------------------------------------------------------------- 1 | package org.resrun.service.pojo; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * @Description: 证书文件属性类 7 | * @Package: org.resrun.service.pojo 8 | * @ClassName: CertificateProperty 9 | * @copyright 北京资源律动科技有限公司 10 | */ 11 | public class CertificateProperty implements Serializable { 12 | 13 | private static final long serialVersionUID = -2073805779543816269L; 14 | 15 | 16 | private byte[] certFile; 17 | /** 证书的类型 比如:PKCS12和jks*/ 18 | private String certType; 19 | /** 证书密码 */ 20 | private String password; 21 | 22 | public CertificateProperty(byte[] certFile, String certType, String password) { 23 | this.certFile = certFile; 24 | this.certType = certType; 25 | this.password = password; 26 | } 27 | 28 | public CertificateProperty() { 29 | } 30 | 31 | public byte[] getCertFile() { 32 | return certFile; 33 | } 34 | 35 | public void setCertFile(byte[] certFile) { 36 | this.certFile = certFile; 37 | } 38 | 39 | public String getCertType() { 40 | return certType; 41 | } 42 | 43 | public void setCertType(String certType) { 44 | this.certType = certType; 45 | } 46 | 47 | public String getPassword() { 48 | return password; 49 | } 50 | 51 | public void setPassword(String password) { 52 | this.password = password; 53 | } 54 | } -------------------------------------------------------------------------------- /kaifangqian-demo-api/src/main/java/org/resrun/service/pojo/ConvertImage.java: -------------------------------------------------------------------------------- 1 | package org.resrun.service.pojo; 2 | 3 | import io.swagger.annotations.ApiModelProperty; 4 | 5 | 6 | import java.io.Serializable; 7 | 8 | /** 9 | * @Description: 图片转换对象 10 | * @Package: org.resrun.service.pojo 11 | * @ClassName: ConvertImage 12 | * @copyright 北京资源律动科技有限公司 13 | */ 14 | public class ConvertImage implements Serializable { 15 | 16 | 17 | private static final long serialVersionUID = -7285616018724242137L; 18 | 19 | @ApiModelProperty("页码") 20 | private Integer page ; 21 | 22 | @ApiModelProperty("图片数据") 23 | private byte[] imageByte ; 24 | 25 | public Integer getPage() { 26 | return page; 27 | } 28 | 29 | public void setPage(Integer page) { 30 | this.page = page; 31 | } 32 | 33 | public byte[] getImageByte() { 34 | return imageByte; 35 | } 36 | 37 | public void setImageByte(byte[] imageByte) { 38 | this.imageByte = imageByte; 39 | } 40 | } -------------------------------------------------------------------------------- /kaifangqian-demo-api/src/main/java/org/resrun/service/pojo/GenerateCertificateInfo.java: -------------------------------------------------------------------------------- 1 | package org.resrun.service.pojo; 2 | 3 | import java.util.Date; 4 | 5 | 6 | /** 7 | * @Description: 证书生成对象 8 | * @Package: org.resrun.service.pojo 9 | * @ClassName: GenerateCertificateInfo 10 | * @copyright 北京资源律动科技有限公司 11 | */ 12 | 13 | public class GenerateCertificateInfo { 14 | 15 | /** 16 | * 证书密码 17 | */ 18 | private String password; 19 | 20 | /** 21 | * 证书类型 JKS PFX 22 | */ 23 | private String certFileType; 24 | 25 | /** 26 | * 证书库 27 | */ 28 | private byte [] jks; 29 | 30 | 31 | /** 32 | * 签名证书 33 | */ 34 | private byte [] pfx; 35 | 36 | /** 37 | * 证书序列号 38 | */ 39 | private String serial; 40 | /** 41 | * 证书签名算法 SHA1withRSA SHA256withRSA 42 | */ 43 | private String algorithmSignature; 44 | 45 | /** 46 | * 证书算法类型: RSA、SM2 47 | */ 48 | private String algorithm; 49 | 50 | /** 51 | * 证书有效期起始时间 52 | */ 53 | private Date termOfValidityStartTime; 54 | 55 | /** 56 | * 证书有效期结束时间 57 | */ 58 | private Date termOfValidityEndTime; 59 | 60 | 61 | public String getPassword() { 62 | return password; 63 | } 64 | 65 | public void setPassword(String password) { 66 | this.password = password; 67 | } 68 | 69 | public String getCertFileType() { 70 | return certFileType; 71 | } 72 | 73 | public void setCertFileType(String certFileType) { 74 | this.certFileType = certFileType; 75 | } 76 | 77 | public byte[] getJks() { 78 | return jks; 79 | } 80 | 81 | public void setJks(byte[] jks) { 82 | this.jks = jks; 83 | } 84 | 85 | public byte[] getPfx() { 86 | return pfx; 87 | } 88 | 89 | public void setPfx(byte[] pfx) { 90 | this.pfx = pfx; 91 | } 92 | 93 | public String getSerial() { 94 | return serial; 95 | } 96 | 97 | public void setSerial(String serial) { 98 | this.serial = serial; 99 | } 100 | 101 | public String getAlgorithmSignature() { 102 | return algorithmSignature; 103 | } 104 | 105 | public void setAlgorithmSignature(String algorithmSignature) { 106 | this.algorithmSignature = algorithmSignature; 107 | } 108 | 109 | public String getAlgorithm() { 110 | return algorithm; 111 | } 112 | 113 | public void setAlgorithm(String algorithm) { 114 | this.algorithm = algorithm; 115 | } 116 | 117 | public Date getTermOfValidityStartTime() { 118 | return termOfValidityStartTime; 119 | } 120 | 121 | public void setTermOfValidityStartTime(Date termOfValidityStartTime) { 122 | this.termOfValidityStartTime = termOfValidityStartTime; 123 | } 124 | 125 | public Date getTermOfValidityEndTime() { 126 | return termOfValidityEndTime; 127 | } 128 | 129 | public void setTermOfValidityEndTime(Date termOfValidityEndTime) { 130 | this.termOfValidityEndTime = termOfValidityEndTime; 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /kaifangqian-demo-api/src/main/java/org/resrun/service/pojo/RealPositionProperty.java: -------------------------------------------------------------------------------- 1 | package org.resrun.service.pojo; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * @Description: 经过计算后的文件签署位置属性类 7 | * @Package: org.resrun.service.pojo 8 | * @ClassName: PositionProperty 9 | * @copyright 北京资源律动科技有限公司 10 | */ 11 | 12 | public class RealPositionProperty implements Serializable { 13 | 14 | 15 | private static final long serialVersionUID = 8586984409612483553L; 16 | 17 | /** 签章左下角x坐标 */ 18 | private float startx; 19 | 20 | /** 签章左下角y坐标*/ 21 | private float starty; 22 | 23 | /** 签章右上角x坐标*/ 24 | private float endx; 25 | 26 | /** 签章右上角x坐标*/ 27 | private float endy; 28 | 29 | private int pageNum; 30 | 31 | // 填写值,填写专用 32 | private String value ; 33 | //对齐方式 34 | private String align ; 35 | //字体 36 | private String fontFamily ; 37 | //文字大小 38 | private Integer fontSize ; 39 | 40 | public float getStartx() { 41 | return startx; 42 | } 43 | 44 | public void setStartx(float startx) { 45 | this.startx = startx; 46 | } 47 | 48 | public float getStarty() { 49 | return starty; 50 | } 51 | 52 | public void setStarty(float starty) { 53 | this.starty = starty; 54 | } 55 | 56 | public float getEndx() { 57 | return endx; 58 | } 59 | 60 | public void setEndx(float endx) { 61 | this.endx = endx; 62 | } 63 | 64 | public float getEndy() { 65 | return endy; 66 | } 67 | 68 | public void setEndy(float endy) { 69 | this.endy = endy; 70 | } 71 | 72 | public int getPageNum() { 73 | return pageNum; 74 | } 75 | 76 | public void setPageNum(int pageNum) { 77 | this.pageNum = pageNum; 78 | } 79 | 80 | public String getValue() { 81 | return value; 82 | } 83 | 84 | public void setValue(String value) { 85 | this.value = value; 86 | } 87 | 88 | public String getAlign() { 89 | return align; 90 | } 91 | 92 | public void setAlign(String align) { 93 | this.align = align; 94 | } 95 | 96 | public String getFontFamily() { 97 | return fontFamily; 98 | } 99 | 100 | public void setFontFamily(String fontFamily) { 101 | this.fontFamily = fontFamily; 102 | } 103 | 104 | public Integer getFontSize() { 105 | return fontSize; 106 | } 107 | 108 | public void setFontSize(Integer fontSize) { 109 | this.fontSize = fontSize; 110 | } 111 | } -------------------------------------------------------------------------------- /kaifangqian-demo-api/src/main/java/org/resrun/service/pojo/SignPdfInfoVo.java: -------------------------------------------------------------------------------- 1 | package org.resrun.service.pojo; 2 | 3 | import io.swagger.annotations.ApiModel; 4 | import io.swagger.annotations.ApiModelProperty; 5 | 6 | import java.util.ArrayList; 7 | import java.util.Date; 8 | import java.util.List; 9 | 10 | /** 11 | * @Description: 数字签名信息 12 | * @Package: org.resrun.service.pojo 13 | * @ClassName: SignPdfInfoVo 14 | * @copyright 北京资源律动科技有限公司 15 | */ 16 | 17 | @ApiModel("数字签名信息返回对象") 18 | public class SignPdfInfoVo { 19 | /** 20 | * PDF名称 21 | */ 22 | @ApiModelProperty(value = "PDF名称") 23 | private String pdfName; 24 | /** 25 | * PDF大小 26 | */ 27 | @ApiModelProperty(value = "PDF大小") 28 | private String pdfSize; 29 | 30 | /** 31 | * 文件签名结果 32 | */ 33 | @ApiModelProperty(value = "文件签名结果") 34 | private Integer pdfSingResult; 35 | 36 | @ApiModelProperty(value = "数字签名详细集合") 37 | private List signatureDetails = new ArrayList<>(); 38 | 39 | public String getPdfName() { 40 | return pdfName; 41 | } 42 | 43 | public void setPdfName(String pdfName) { 44 | this.pdfName = pdfName; 45 | } 46 | 47 | public String getPdfSize() { 48 | return pdfSize; 49 | } 50 | 51 | public void setPdfSize(String pdfSize) { 52 | this.pdfSize = pdfSize; 53 | } 54 | 55 | public Integer getPdfSingResult() { 56 | return pdfSingResult; 57 | } 58 | 59 | public void setPdfSingResult(Integer pdfSingResult) { 60 | this.pdfSingResult = pdfSingResult; 61 | } 62 | 63 | public List getSignatureDetails() { 64 | return signatureDetails; 65 | } 66 | 67 | public void setSignatureDetails(List signatureDetails) { 68 | this.signatureDetails = signatureDetails; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /kaifangqian-demo-api/src/main/java/org/resrun/service/pojo/SourcePositionProperty.java: -------------------------------------------------------------------------------- 1 | package org.resrun.service.pojo; 2 | 3 | import io.swagger.annotations.ApiModelProperty; 4 | 5 | 6 | import java.io.Serializable; 7 | 8 | /** 9 | * @Description: 原始文件签署位置属性 10 | * @Package: org.resrun.service.pojo 11 | * @ClassName: SourcePositionProperty 12 | * @copyright 北京资源律动科技有限公司 13 | */ 14 | 15 | public class SourcePositionProperty implements Serializable { 16 | 17 | private static final long serialVersionUID = 725976764583634367L; 18 | 19 | @ApiModelProperty("控件X坐标(左上角)") 20 | private Float offsetX ; 21 | @ApiModelProperty("控件Y坐标(左上角)") 22 | private Float offsetY ; 23 | @ApiModelProperty("控件宽度") 24 | private Float width ; 25 | @ApiModelProperty("控件高度") 26 | private Float height ; 27 | @ApiModelProperty("当前文件页面宽度") 28 | private Float pageWidth ; 29 | @ApiModelProperty("当前文件页面高度") 30 | private Float pageHeight ; 31 | @ApiModelProperty("控件所属页码") 32 | private Integer page ; 33 | 34 | @ApiModelProperty("当前文件页面宽度") 35 | private Float realWidth ; 36 | @ApiModelProperty("当前文件页面高度") 37 | private Float realHeight ; 38 | 39 | public Float getOffsetX() { 40 | return offsetX; 41 | } 42 | 43 | public void setOffsetX(Float offsetX) { 44 | this.offsetX = offsetX; 45 | } 46 | 47 | public Float getOffsetY() { 48 | return offsetY; 49 | } 50 | 51 | public void setOffsetY(Float offsetY) { 52 | this.offsetY = offsetY; 53 | } 54 | 55 | public Float getWidth() { 56 | return width; 57 | } 58 | 59 | public void setWidth(Float width) { 60 | this.width = width; 61 | } 62 | 63 | public Float getHeight() { 64 | return height; 65 | } 66 | 67 | public void setHeight(Float height) { 68 | this.height = height; 69 | } 70 | 71 | public Float getPageWidth() { 72 | return pageWidth; 73 | } 74 | 75 | public void setPageWidth(Float pageWidth) { 76 | this.pageWidth = pageWidth; 77 | } 78 | 79 | public Float getPageHeight() { 80 | return pageHeight; 81 | } 82 | 83 | public void setPageHeight(Float pageHeight) { 84 | this.pageHeight = pageHeight; 85 | } 86 | 87 | public Integer getPage() { 88 | return page; 89 | } 90 | 91 | public void setPage(Integer page) { 92 | this.page = page; 93 | } 94 | 95 | public Float getRealWidth() { 96 | return realWidth; 97 | } 98 | 99 | public void setRealWidth(Float realWidth) { 100 | this.realWidth = realWidth; 101 | } 102 | 103 | public Float getRealHeight() { 104 | return realHeight; 105 | } 106 | 107 | public void setRealHeight(Float realHeight) { 108 | this.realHeight = realHeight; 109 | } 110 | } -------------------------------------------------------------------------------- /kaifangqian-demo-api/src/main/java/org/resrun/service/verify/ExtImageRenderListener.java: -------------------------------------------------------------------------------- 1 | //package org.resrun.service.verify; 2 | // 3 | //import com.itextpdf.text.pdf.PdfDictionary; 4 | //import com.itextpdf.text.pdf.parser.ImageRenderInfo; 5 | //import com.itextpdf.text.pdf.parser.PdfImageObject; 6 | //import com.itextpdf.text.pdf.parser.RenderListener; 7 | //import com.itextpdf.text.pdf.parser.TextRenderInfo; 8 | //import lombok.Data; 9 | //import lombok.SneakyThrows; 10 | //import lombok.extern.slf4j.Slf4j; 11 | // 12 | //import java.util.ArrayList; 13 | //import java.util.List; 14 | // 15 | ///** 16 | // * @Description: 图像监听类 17 | // * @Package: org.resrun.service.verify 18 | // * @ClassName: ExtImageRenderListener 19 | // * @copyright 北京资源律动科技有限公司 20 | // */ 21 | //@Slf4j 22 | //@Data 23 | //public class ExtImageRenderListener implements RenderListener { 24 | // private int i; 25 | // private String basePath; 26 | // 27 | // private byte [] seal; 28 | // @Override 29 | // public void beginTextBlock() { 30 | // 31 | // } 32 | // 33 | // public void setBasePath(String basePath) { 34 | // if (basePath.endsWith("/")) { 35 | // this.basePath = basePath; 36 | // } else { 37 | // this.basePath = basePath + "/"; 38 | // } 39 | // } 40 | // 41 | // @Override 42 | // public void renderText(TextRenderInfo renderInfo) { 43 | // } 44 | // 45 | // @Override 46 | // public void endTextBlock() { 47 | // } 48 | // PdfDictionary resources; 49 | // 50 | // List> numbers = new ArrayList<>(); 51 | // 52 | // 53 | // @SneakyThrows 54 | // @Override 55 | // public void renderImage(ImageRenderInfo renderInfo) { 56 | // PdfImageObject image = renderInfo.getImage(); 57 | // if (image == null) { 58 | // log.debug("Image {} could not be read", renderInfo.getRef().getNumber()); 59 | // return; 60 | // } 61 | // seal = image.getImageAsBytes(); 62 | // } 63 | //} 64 | // 65 | -------------------------------------------------------------------------------- /kaifangqian-demo-api/src/main/java/org/resrun/service/verify/SignVerifyService.java: -------------------------------------------------------------------------------- 1 | package org.resrun.service.verify; 2 | 3 | 4 | import org.resrun.controller.vo.response.VerifyResponse; 5 | import org.resrun.service.pojo.SignPdfInfoVo; 6 | import org.springframework.stereotype.Service; 7 | 8 | import java.io.File; 9 | import java.io.IOException; 10 | 11 | 12 | /** 13 | * @Description: 在线签名验签服务实现类 14 | * @Package: org.resrun.service.verify 15 | * @ClassName: SignVerifyServiceImpl 16 | * @copyright 北京资源律动科技有限公司 17 | */ 18 | @Service 19 | public class SignVerifyService{ 20 | 21 | /** 22 | * 获取pdf签名图片信息 23 | * @return 提取结果 24 | */ 25 | public VerifyResponse verify(byte[] bytes, String fileName) { 26 | SignPdfInfoVo signPdfInfo = new SignPdfInfoVo(); 27 | 28 | try { 29 | signPdfInfo = VerifySign.getSignFromPdf(bytes); 30 | signPdfInfo.setPdfName(fileName); 31 | signPdfInfo.setPdfSize(String.format("%.2f",bytes.length/1024.0)); 32 | switch (signPdfInfo.getPdfSingResult()) { 33 | case 1: 34 | return new VerifyResponse(org.resrun.enums.SignStatus.SIGN_STATUS_NOSIGNATURE.getMsg(),signPdfInfo); 35 | case 2: 36 | return new VerifyResponse(org.resrun.enums.SignStatus.SIGN_STATUS_ERROR.getMsg(), signPdfInfo); 37 | case 3: 38 | return new VerifyResponse(org.resrun.enums.SignStatus.SIGN_STATUS_FIDDLE.getMsg(), signPdfInfo); 39 | default: 40 | return new VerifyResponse(org.resrun.enums.SignStatus.SIGN_STATUS_RIGHT.getMsg(), signPdfInfo); 41 | } 42 | }catch (Exception e){ 43 | signPdfInfo.setPdfName(fileName); 44 | signPdfInfo.setPdfSize(String.valueOf(bytes.length/1024)); 45 | 46 | signPdfInfo.setPdfSingResult(org.resrun.enums.SignStatus.SIGN_STATUS_NOSIGNATURE.getCode()); 47 | return new VerifyResponse(org.resrun.enums.SignStatus.SIGN_STATUS_NOSIGNATURE.getMsg(),signPdfInfo); 48 | } 49 | 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /kaifangqian-demo-api/src/main/java/org/resrun/utils/CallBack.java: -------------------------------------------------------------------------------- 1 | package org.resrun.utils; 2 | 3 | /** 4 | * @author: zhh 5 | * @see {@link SpringContextHolder} 6 | * 针对某些初始化方法,在SpringContextHolder 初始化前时,
7 | * 可提交一个 提交回调任务。
8 | * 在SpringContextHolder 初始化后,进行回调使用 9 | */ 10 | 11 | public interface CallBack { 12 | /** 13 | * 回调执行方法 14 | */ 15 | void executor(); 16 | 17 | /** 18 | * 本回调任务名称 19 | * @return / 20 | */ 21 | default String getCallBackName() { 22 | return Thread.currentThread().getId() + ":" + this.getClass().getName(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /kaifangqian-demo-api/src/main/java/org/resrun/utils/MyStringUtils.java: -------------------------------------------------------------------------------- 1 | package org.resrun.utils; 2 | 3 | /** 4 | * @author zhh 5 | * 字符串工具类, 继承org.apache.commons.lang3.StringUtils类 6 | */ 7 | public class MyStringUtils extends org.apache.commons.lang3.StringUtils { 8 | 9 | private static final char SEPARATOR = '_'; 10 | 11 | /** 12 | * 驼峰命名法工具 13 | * 14 | * @return toCamelCase(" hello_world ") == "helloWorld" 15 | */ 16 | public static String toCamelCase(String s) { 17 | if (s == null) { 18 | return null; 19 | } 20 | 21 | s = s.toLowerCase(); 22 | 23 | StringBuilder sb = new StringBuilder(s.length()); 24 | boolean upperCase = false; 25 | for (int i = 0; i < s.length(); i++) { 26 | char c = s.charAt(i); 27 | 28 | if (c == SEPARATOR) { 29 | upperCase = true; 30 | } else if (upperCase) { 31 | sb.append(Character.toUpperCase(c)); 32 | upperCase = false; 33 | } else { 34 | sb.append(c); 35 | } 36 | } 37 | 38 | return sb.toString(); 39 | } 40 | 41 | /** 42 | * 驼峰命名法工具 43 | *

44 | * toCapitalizeCamelCase("hello_world") == "HelloWorld" 45 | */ 46 | public static String toCapitalizeCamelCase(String s) { 47 | if (s == null) { 48 | return null; 49 | } 50 | s = toCamelCase(s); 51 | return s.substring(0, 1).toUpperCase() + s.substring(1); 52 | } 53 | 54 | /** 55 | * 驼峰命名法工具 56 | * toUnderScoreCase("helloWorld") = "hello_world" 57 | */ 58 | public static String toUnderScoreCase(String s) { 59 | if (s == null) { 60 | return null; 61 | } 62 | 63 | StringBuilder sb = new StringBuilder(); 64 | boolean upperCase = false; 65 | for (int i = 0; i < s.length(); i++) { 66 | char c = s.charAt(i); 67 | 68 | boolean nextUpperCase = true; 69 | 70 | if (i < (s.length() - 1)) { 71 | nextUpperCase = Character.isUpperCase(s.charAt(i + 1)); 72 | } 73 | 74 | if ((i > 0) && Character.isUpperCase(c)) { 75 | if (!upperCase || !nextUpperCase) { 76 | sb.append(SEPARATOR); 77 | } 78 | upperCase = true; 79 | } else { 80 | upperCase = false; 81 | } 82 | 83 | sb.append(Character.toLowerCase(c)); 84 | } 85 | 86 | return sb.toString(); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /kaifangqian-demo-api/src/main/resources/application-prod.yml: -------------------------------------------------------------------------------- 1 | server: 2 | # 项目启动端口号 3 | port: 8666 4 | tomcat: 5 | # 上传文件限制 -1 无限制 6 | max-swallow-size: -1 7 | servlet: 8 | #路径前缀 9 | context-path: /openSign 10 | 11 | kaifangqian: 12 | #证书服务地址 13 | cert-apply-url: https://service.kaifangqian.com/service/cert/event 14 | #授权token 15 | token: 123456 16 | # 默认 false 签发本地测试证书 true 签发 CA 证书 17 | prod: false -------------------------------------------------------------------------------- /kaifangqian-demo-api/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | profiles: 3 | active: prod -------------------------------------------------------------------------------- /kaifangqian-demo-api/src/main/resources/ip2region/ip2region.xdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaifangqian/kaifangqian-base/9157ecd23e1e59d3d8849efadd83efe2bd28e00a/kaifangqian-demo-api/src/main/resources/ip2region/ip2region.xdb -------------------------------------------------------------------------------- /kaifangqian-demo-api/src/main/resources/logback-spring.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | kaifangqian-demo 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | INFO 13 | 14 | 15 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger\(%line\)- %msg%n 16 | 17 | 18 | 19 | 20 | 22 | 24 | ${logback.logdir}/${logback.appname}.log 25 | 26 | 28 | 29 | ${logback.logdir}/${logback.appname}.%d{yyyy-MM-dd}.log 30 | 32 | 33 | 90 34 | 35 | 300GB 36 | true 37 | 38 | 39 | 40 | UTF-8 41 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger\(%line\)- %msg%n 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /kaifangqian-demo-api/src/main/resources/开源工具版说明.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaifangqian/kaifangqian-base/9157ecd23e1e59d3d8849efadd83efe2bd28e00a/kaifangqian-demo-api/src/main/resources/开源工具版说明.pdf -------------------------------------------------------------------------------- /kaifangqian-demo-api/src/test/java/org/resrun/ApplyCertTest.java: -------------------------------------------------------------------------------- 1 | package org.resrun; 2 | 3 | import com.alibaba.fastjson.JSONObject; 4 | import org.apache.commons.io.FileUtils; 5 | import org.junit.Test; 6 | import org.junit.runner.RunWith; 7 | import org.resrun.sdk.service.SDKService; 8 | import org.resrun.sdk.vo.base.Result; 9 | import org.resrun.sdk.vo.request.CertEventRequest; 10 | import org.resrun.sdk.vo.response.CertEventResponse; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.boot.test.context.SpringBootTest; 13 | import org.springframework.test.context.junit4.SpringRunner; 14 | 15 | import java.io.File; 16 | import java.io.IOException; 17 | import java.util.Base64; 18 | import java.util.UUID; 19 | 20 | @RunWith(SpringRunner.class) 21 | @SpringBootTest(classes = {OpenSignDemoApplication.class}, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 22 | public class ApplyCertTest { 23 | 24 | @Autowired 25 | private SDKService service; 26 | 27 | @Test 28 | public void apply() throws IOException { 29 | 30 | CertEventRequest certEventRequest = new CertEventRequest(); 31 | certEventRequest.setCertPassword("123456"); 32 | certEventRequest.setCertSubject("张三@123456789987654321"); 33 | certEventRequest.setUniqueCode(UUID.randomUUID().toString()); 34 | Result result = service.certEvent(certEventRequest); 35 | System.out.println(result.getData().getPfx()); 36 | System.out.println(JSONObject.toJSONString(result.getData())); 37 | 38 | FileUtils.writeByteArrayToFile(new File("E:\\work\\tem\\cert\\123456789987654321.pfx"), Base64.getDecoder().decode(result.getData().getPfx())); 39 | 40 | 41 | 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /kaifangqian-demo-api/src/test/java/org/resrun/PsersonSealTest.java: -------------------------------------------------------------------------------- 1 | package org.resrun; 2 | 3 | import com.alibaba.fastjson.JSONObject; 4 | import org.apache.commons.io.FileUtils; 5 | import org.junit.Test; 6 | import org.junit.runner.RunWith; 7 | import org.resrun.enums.SealShapeStyleEnum; 8 | import org.resrun.sdk.service.SDKService; 9 | import org.resrun.sdk.vo.base.Result; 10 | import org.resrun.sdk.vo.request.CertEventRequest; 11 | import org.resrun.sdk.vo.response.CertEventResponse; 12 | import org.resrun.service.image.PersonalSealService; 13 | import org.springframework.beans.factory.annotation.Autowired; 14 | import org.springframework.boot.test.context.SpringBootTest; 15 | import org.springframework.test.context.junit4.SpringRunner; 16 | 17 | import javax.imageio.ImageIO; 18 | import java.awt.image.BufferedImage; 19 | import java.io.ByteArrayOutputStream; 20 | import java.io.File; 21 | import java.io.IOException; 22 | import java.util.UUID; 23 | 24 | @RunWith(SpringRunner.class) 25 | @SpringBootTest(classes = {OpenSignDemoApplication.class}, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 26 | public class PsersonSealTest { 27 | 28 | 29 | 30 | @Test 31 | public void seal() throws IOException { 32 | 33 | //生成个人印章的名字 34 | String name = "张三"; 35 | byte [] sealByte = null; 36 | BufferedImage bufferedImage = null ; 37 | ByteArrayOutputStream output = new ByteArrayOutputStream(); 38 | 39 | //生成的印章类型 详情请看SealShapeStyleEnum枚举中的定义 40 | Integer shapeStyle = SealShapeStyleEnum.RECTANGLE_FRAME.getCode(); 41 | 42 | //1红色,2蓝色,3黑色 43 | Integer sealColor = 1; 44 | try { 45 | if (SealShapeStyleEnum.RECTANGLE_NO_FRAME.getCode().equals(shapeStyle)) { 46 | bufferedImage = PersonalSealService.drawRectangleNoFrame(name, sealColor); 47 | } else if (SealShapeStyleEnum.RECTANGLE_FRAME.getCode().equals(shapeStyle)) { 48 | 49 | bufferedImage = PersonalSealService.drawRectangleFrame(name, sealColor); 50 | } else if (SealShapeStyleEnum.SQUARE_NO_FRAME.getCode().equals(shapeStyle)) { 51 | 52 | bufferedImage = PersonalSealService.drawSquareNoFrame(name, sealColor); 53 | } else if (SealShapeStyleEnum.SQUARE_FRAME.getCode().equals(shapeStyle)) { 54 | bufferedImage = PersonalSealService.drawSquareFrame(name, sealColor); 55 | } 56 | ImageIO.write(bufferedImage, "png", output); 57 | sealByte = output.toByteArray(); 58 | 59 | FileUtils.writeByteArrayToFile(new File("target/pserson_seal.png"),sealByte); 60 | 61 | }catch(Exception e){ 62 | e.printStackTrace(); 63 | } 64 | } 65 | } 66 | 67 | -------------------------------------------------------------------------------- /kaifangqian-demo-api/src/test/java/org/resrun/UpdateCertPassword.java: -------------------------------------------------------------------------------- 1 | package org.resrun; 2 | 3 | import org.apache.commons.io.FileUtils; 4 | 5 | import java.io.ByteArrayInputStream; 6 | import java.io.ByteArrayOutputStream; 7 | import java.io.File; 8 | import java.security.KeyStore; 9 | import java.security.Security; 10 | 11 | public class UpdateCertPassword { 12 | 13 | public static void main(String[] args) throws Exception { 14 | 15 | byte [] pfx = FileUtils.readFileToByteArray(new File("C://example.pfx")); 16 | 17 | String oldPwd = "oldPwd"; 18 | String newPwd = "newPwd"; 19 | Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); 20 | 21 | //加载证书 22 | ByteArrayInputStream inputStream = new ByteArrayInputStream(pfx); 23 | KeyStore outputKeyStore = KeyStore.getInstance("PKCS12","BC"); 24 | outputKeyStore.load(inputStream,oldPwd.toCharArray()); 25 | 26 | //另存为证书 27 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 28 | outputKeyStore.store(out, newPwd.toCharArray()); 29 | 30 | byte [] newPfx = out.toByteArray(); 31 | FileUtils.writeByteArrayToFile(new File("C://new.pfx"),newPfx); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /kaifangqian-demo-api/src/test/resources/example.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaifangqian/kaifangqian-base/9157ecd23e1e59d3d8849efadd83efe2bd28e00a/kaifangqian-demo-api/src/test/resources/example.pdf -------------------------------------------------------------------------------- /kaifangqian-demo-api/src/test/resources/seal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaifangqian/kaifangqian-base/9157ecd23e1e59d3d8849efadd83efe2bd28e00a/kaifangqian-demo-api/src/test/resources/seal.png -------------------------------------------------------------------------------- /kaifangqian-demo-vue/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | .DS_Store 12 | dist 13 | dist-ssr 14 | coverage 15 | *.local 16 | 17 | /cypress/videos/ 18 | /cypress/screenshots/ 19 | package-lock.json 20 | # Editor directories and files 21 | .vscode/* 22 | !.vscode/extensions.json 23 | .idea 24 | *.suo 25 | *.ntvs* 26 | *.njsproj 27 | *.sln 28 | *.sw? 29 | 30 | *.tsbuildinfo 31 | -------------------------------------------------------------------------------- /kaifangqian-demo-vue/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 kaifangqian 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /kaifangqian-demo-vue/README.md: -------------------------------------------------------------------------------- 1 | # 开放签电子签章系统-demo 2 | 3 | 4 | ## 安装步骤 5 | ``` 6 | #需要提前准备node环境,最低版本 v14.20 7 | #进入项目目录 8 | cd kaifangqian-demo-vue 9 | 10 | # 安装依赖 11 | npm install -registry=https://registry.npmmirror.com/ 12 | 13 | # 启动前需要将后端服务启动,并修改vite.config.js中的代理地址,否则无法体验签署功能 14 | # 启动后浏览器访问 http://128.0.0.1:8080 15 | npm run dev 16 | 17 | # 构建生产环境 18 | npm run build 19 | ``` 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /kaifangqian-demo-vue/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 开放签 8 | 9 | 10 |

11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /kaifangqian-demo-vue/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "paths": { 4 | "@/*": ["./src/*"] 5 | } 6 | }, 7 | "exclude": ["node_modules", "dist"] 8 | } 9 | -------------------------------------------------------------------------------- /kaifangqian-demo-vue/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "kaifangqian-demo-vue", 3 | "version": "0.0.0", 4 | "private": true, 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "vite build", 9 | "preview": "vite preview" 10 | }, 11 | "dependencies": { 12 | "ant-design-vue": "^3.2.20", 13 | "axios": "^1.6.2", 14 | "cropperjs": "^1.6.1", 15 | "less": "^4.2.0", 16 | "less-loader": "^11.1.3", 17 | "perfect-scrollbar": "^1.5.5", 18 | "vue": "^3.3.10", 19 | "vue-router": "^4.2.5", 20 | "vue-signature-pad": "^3.0.2", 21 | "vuedraggable": "^4.1.0" 22 | }, 23 | "devDependencies": { 24 | "@vitejs/plugin-vue": "^2.3.1", 25 | "vite": "^2.9.5" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /kaifangqian-demo-vue/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaifangqian/kaifangqian-base/9157ecd23e1e59d3d8849efadd83efe2bd28e00a/kaifangqian-demo-vue/public/favicon.ico -------------------------------------------------------------------------------- /kaifangqian-demo-vue/src/App.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 8 | -------------------------------------------------------------------------------- /kaifangqian-demo-vue/src/assets/images/doc_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaifangqian/kaifangqian-base/9157ecd23e1e59d3d8849efadd83efe2bd28e00a/kaifangqian-demo-vue/src/assets/images/doc_1.png -------------------------------------------------------------------------------- /kaifangqian-demo-vue/src/assets/images/doc_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaifangqian/kaifangqian-base/9157ecd23e1e59d3d8849efadd83efe2bd28e00a/kaifangqian-demo-vue/src/assets/images/doc_2.png -------------------------------------------------------------------------------- /kaifangqian-demo-vue/src/assets/images/kaifangqian-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaifangqian/kaifangqian-base/9157ecd23e1e59d3d8849efadd83efe2bd28e00a/kaifangqian-demo-vue/src/assets/images/kaifangqian-logo.png -------------------------------------------------------------------------------- /kaifangqian-demo-vue/src/assets/images/pdf-cert.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaifangqian/kaifangqian-base/9157ecd23e1e59d3d8849efadd83efe2bd28e00a/kaifangqian-demo-vue/src/assets/images/pdf-cert.png -------------------------------------------------------------------------------- /kaifangqian-demo-vue/src/assets/images/product.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaifangqian/kaifangqian-base/9157ecd23e1e59d3d8849efadd83efe2bd28e00a/kaifangqian-demo-vue/src/assets/images/product.png -------------------------------------------------------------------------------- /kaifangqian-demo-vue/src/assets/images/seal-template.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaifangqian/kaifangqian-base/9157ecd23e1e59d3d8849efadd83efe2bd28e00a/kaifangqian-demo-vue/src/assets/images/seal-template.png -------------------------------------------------------------------------------- /kaifangqian-demo-vue/src/assets/images/seal-ym.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaifangqian/kaifangqian-base/9157ecd23e1e59d3d8849efadd83efe2bd28e00a/kaifangqian-demo-vue/src/assets/images/seal-ym.png -------------------------------------------------------------------------------- /kaifangqian-demo-vue/src/assets/images/signature-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaifangqian/kaifangqian-base/9157ecd23e1e59d3d8849efadd83efe2bd28e00a/kaifangqian-demo-vue/src/assets/images/signature-bg.png -------------------------------------------------------------------------------- /kaifangqian-demo-vue/src/assets/images/signature.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaifangqian/kaifangqian-base/9157ecd23e1e59d3d8849efadd83efe2bd28e00a/kaifangqian-demo-vue/src/assets/images/signature.png -------------------------------------------------------------------------------- /kaifangqian-demo-vue/src/assets/images/verify.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaifangqian/kaifangqian-base/9157ecd23e1e59d3d8849efadd83efe2bd28e00a/kaifangqian-demo-vue/src/assets/images/verify.png -------------------------------------------------------------------------------- /kaifangqian-demo-vue/src/assets/main.css: -------------------------------------------------------------------------------- 1 | #app,body,ul{ 2 | margin: 0; 3 | padding: 0; 4 | } 5 | 6 | .font-red{ 7 | color: red; 8 | } 9 | 10 | ul li{ 11 | list-style: none; 12 | } 13 | 14 | -------------------------------------------------------------------------------- /kaifangqian-demo-vue/src/components/control/data/ControlData.ts: -------------------------------------------------------------------------------- 1 | export enum ControlType { 2 | Signature = "signature", 3 | Seal = "seal", 4 | // LineText = "line-text", 5 | // MultilineText = "multiline-text", 6 | // Date="date", 7 | // SignDate="sign-date", 8 | // Number = "number", 9 | } 10 | 11 | 12 | export enum ControlOperationType { 13 | template = "template", 14 | create = "create", 15 | sign = "sign", 16 | } 17 | 18 | export interface ControlSize{ 19 | [key: string]: any; 20 | //控件宽度 21 | width:number; 22 | //控件高度 23 | height:number; 24 | //控件最小宽度 25 | minWidth:number; 26 | //控件最小高度 27 | minHeight:number; 28 | } 29 | export interface ControlPosition{ 30 | [key: string]: any; 31 | //控件x坐标 32 | left: number; 33 | //控件y坐标 34 | right: number; 35 | } 36 | 37 | 38 | export interface ControlOptins{ 39 | [key: string]: any; 40 | //控件类型 41 | type:String; 42 | //控件名称 43 | name:String; 44 | //控件iocn 45 | icon: String; 46 | //控件大小 47 | size?:ControlSize; 48 | //控件位置 49 | position?:ControlPosition; 50 | //控件提示内容 51 | placeholder?: String; 52 | //控件绑定的value值 53 | value:String 54 | //是否点一点击 active 55 | controlClick:Boolean, 56 | //是否可缩放 57 | zoom:Boolean, 58 | //是否可移动 59 | move:Boolean, 60 | 61 | } 62 | export const CanvasZoom = { 63 | space:16, 64 | width:800, 65 | height: 1131, 66 | zoom:100 67 | } 68 | 69 | export const controlList = [ 70 | { 71 | icon:"seal", 72 | name:"电子印章", 73 | title:"企业签章", 74 | type:ControlType.Seal, 75 | placeholder:"", 76 | value:"", 77 | zoom:false, 78 | move:true, 79 | size:{ 80 | width:160, 81 | height:160, 82 | minWidth:160, 83 | minHeight:160, 84 | }, 85 | position:{ 86 | left: 0, 87 | top: 0, 88 | page:-1, 89 | }, 90 | user:{ 91 | index:-1, 92 | userName:"", 93 | } 94 | }, 95 | { 96 | icon:"signature", 97 | name:"手写签名", 98 | title:"个人签名", 99 | type:ControlType.Signature, 100 | placeholder:"", 101 | value:"", 102 | zoom:false, 103 | move:true, 104 | size:{ 105 | width:150, 106 | height:70, 107 | minWidth:150, 108 | minHeight:70, 109 | }, 110 | position:{ 111 | left: 0, 112 | top: 0, 113 | page:-1, 114 | }, 115 | user:{ 116 | index:-1, 117 | userName:"", 118 | } 119 | } 120 | ] -------------------------------------------------------------------------------- /kaifangqian-demo-vue/src/components/control/data/ControlerMoveRange.ts: -------------------------------------------------------------------------------- 1 | 2 | import {CanvasZoom} from "./ControlData"; 3 | 4 | 5 | export function moveRange(opt:any){ 6 | //CanvasZoom 7 | const allHeight = (CanvasZoom.height + CanvasZoom.space) * opt.pageSize; 8 | if(opt.x < 0){ 9 | opt.x = 0; 10 | } 11 | else if(opt.x>CanvasZoom.width - opt.size.width){ 12 | opt.x = CanvasZoom.width - opt.size.width; 13 | } 14 | if(opt.yallHeight){ 17 | opt.y = allHeight; 18 | } 19 | currentPage(opt); 20 | isControlPage(opt,allHeight); 21 | } 22 | //计算控件所在每页的位置 23 | export function currentPosition(top:number,pageSize:number){ 24 | return top - (pageSize + 1) * CanvasZoom.space - pageSize * CanvasZoom.height; 25 | } 26 | //将每页的位置转换成为一大页的位置 27 | export function currentPositionReverse (top:number,pageSize:number){ 28 | return top + (pageSize + 1) * CanvasZoom.space + pageSize * CanvasZoom.height; 29 | } 30 | 31 | //计算控件所在的页面 32 | function currentPage(opt:any){ 33 | 34 | for(var i =0;istart && opt.y< end){ 40 | opt.currentPage = i; 41 | } 42 | } 43 | // console.log(opt); 44 | } 45 | 46 | //判断控件是否再边界上 47 | function isControlPage(opt:any,allHeight:number){ 48 | //var temHeight = 0; 49 | var start = (opt.currentPage+1) * CanvasZoom.space + opt.currentPage * CanvasZoom.height; 50 | var end =(opt.currentPage+1) * CanvasZoom.space + (opt.currentPage+1) * CanvasZoom.height; 51 | var top = opt.y + opt.size.height; 52 | // console.log("scope:",start,end,opt.y + opt.size.height); 53 | 54 | if(top>start && top< end){ 55 | return; 56 | } 57 | if(top>allHeight){ 58 | opt.y = allHeight - opt.size.height ; 59 | return; 60 | } 61 | 62 | var outSize = top - end; 63 | 64 | if(outSize>opt.size.height/2){ 65 | opt.currentPage += 1; 66 | opt.y = end + CanvasZoom.space; 67 | }else{ 68 | opt.y = end - opt.size.height; 69 | } 70 | console.log("超出:",outSize); 71 | } -------------------------------------------------------------------------------- /kaifangqian-demo-vue/src/components/scrollbar/index.ts: -------------------------------------------------------------------------------- 1 | import { App } from 'vue'; 2 | import CScrollbar from './src/Index.vue'; 3 | 4 | export default { 5 | install(app: App) { 6 | app.component(CScrollbar.name, CScrollbar); 7 | return app; 8 | }, 9 | CScrollbar 10 | }; 11 | -------------------------------------------------------------------------------- /kaifangqian-demo-vue/src/components/scrollbar/scrollbarDirective.ts: -------------------------------------------------------------------------------- 1 | import { App } from 'vue' 2 | import usePerfectScrollbar from './usePerfectScrollbar' 3 | 4 | export default { 5 | install(app: App) { 6 | const { install, uninstall } = usePerfectScrollbar() 7 | app.directive('scrollbar', { 8 | mounted(el) { 9 | install(el) 10 | }, 11 | beforeUnmount() { 12 | uninstall() 13 | } 14 | }) 15 | } 16 | } -------------------------------------------------------------------------------- /kaifangqian-demo-vue/src/components/scrollbar/src/index.d.ts: -------------------------------------------------------------------------------- 1 | export interface ElementObj extends Node { 2 | [key: string]: any; 3 | resizeListners: Function[]; 4 | observer: MutationObserver; 5 | } 6 | 7 | export interface BarMapItem { 8 | key: string; 9 | size: string; // 长度 10 | axis: string; 11 | client: string; 12 | scrollSize: string; 13 | scroll: string; 14 | offset: string; 15 | direction: string; 16 | wide: string; // 宽度 17 | } 18 | 19 | export interface BarMap { 20 | [key: string]: BarMapItem; 21 | } 22 | -------------------------------------------------------------------------------- /kaifangqian-demo-vue/src/components/scrollbar/src/resize-event.ts: -------------------------------------------------------------------------------- 1 | import { ElementObj } from './index.d'; 2 | 3 | const isServer = typeof window === 'undefined'; 4 | 5 | export const resizeHandler = (mutationsList: MutationRecord[], observer: any, element: ElementObj) => { 6 | const listeners = element.resizeListners || []; 7 | if (listeners.length) { 8 | listeners.forEach((fn: Function) => fn()); 9 | } 10 | }; 11 | 12 | export const addResizeListener = (element: ElementObj, fn: any) => { 13 | if (isServer) return; 14 | if (!element.resizeListners) { 15 | element.resizeListners = []; 16 | window.addEventListener('resize', fn); 17 | const mutationObserverSupported = typeof MutationObserver !== 'undefined'; 18 | if (mutationObserverSupported) { 19 | element.observer = new MutationObserver((mutationsList, observer) => resizeHandler(mutationsList, observer, element)); 20 | const config = { 21 | attributes: true, 22 | childList: true, 23 | subtree: true, 24 | characterData: true, 25 | }; 26 | 27 | element.observer.observe(element as Node, config); 28 | } 29 | } 30 | element.resizeListners.push(fn); 31 | }; 32 | 33 | export const removeResizeListener = (element: ElementObj, fn: Function) => { 34 | if (!element || !element.resizeListners) return; 35 | element.resizeListners.splice(element.resizeListners.indexOf(fn), 1); 36 | if (!element.resizeListners.length) { 37 | element.observer.disconnect(); 38 | } 39 | }; 40 | -------------------------------------------------------------------------------- /kaifangqian-demo-vue/src/components/scrollbar/src/utils.ts: -------------------------------------------------------------------------------- 1 | interface BarMapItem { 2 | key: string; 3 | size: string; 4 | axis: string; 5 | client: string; 6 | scroll: string; 7 | scrollSize: string; 8 | offset: string; 9 | direction: string; 10 | wide: string; 11 | } 12 | 13 | interface BarMap { 14 | [key: string]: BarMapItem; 15 | } 16 | 17 | export const BAR_MAP: BarMap = { 18 | vertical: { 19 | offset: 'offsetHeight', 20 | key: 'vertical', 21 | size: 'height', 22 | wide: 'width', 23 | axis: 'Y', 24 | client: 'clientY', 25 | scroll: 'scrollTop', 26 | scrollSize: 'scrollHeight', 27 | direction: 'top', 28 | }, 29 | horizontal: { 30 | offset: 'offsetWidth', 31 | key: 'horizontal', 32 | size: 'width', 33 | wide: 'height', 34 | axis: 'X', 35 | client: 'clientX', 36 | scroll: 'scrollLeft', 37 | scrollSize: 'scrollWidth', 38 | direction: 'left', 39 | }, 40 | }; 41 | -------------------------------------------------------------------------------- /kaifangqian-demo-vue/src/components/scrollbar/usePerfectScrollbar.ts: -------------------------------------------------------------------------------- 1 | import PerfectScrollbar from 'perfect-scrollbar' 2 | import 'perfect-scrollbar/css/perfect-scrollbar.css' 3 | 4 | export default function usePerfectScrollbar() { 5 | let ps: null | PerfectScrollbar 6 | const resize = () => { 7 | ps && ps.update() 8 | } 9 | return { 10 | 11 | install(el: Element | string) { 12 | if(el){ 13 | ps = new PerfectScrollbar(el, { 14 | wheelSpeed: 1, 15 | wheelPropagation: false 16 | }) 17 | window.addEventListener('resize', resize, false) 18 | return ps 19 | } 20 | }, 21 | uninstall() { 22 | console.log("uninstall"); 23 | window.removeEventListener('resize', resize, false) 24 | ps && ps.destroy() 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /kaifangqian-demo-vue/src/layouts/header/index.vue: -------------------------------------------------------------------------------- 1 | 5 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /kaifangqian-demo-vue/src/main.js: -------------------------------------------------------------------------------- 1 | 2 | import 'ant-design-vue/dist/antd.css' 3 | import './assets/main.css' 4 | import { createApp } from 'vue' 5 | import App from './App.vue' 6 | import router from './router' 7 | 8 | import CScrollbar from '@/components/scrollbar' 9 | 10 | const app = createApp(App) 11 | 12 | app.use(router) 13 | app.use(CScrollbar); 14 | 15 | app.mount('#app') 16 | -------------------------------------------------------------------------------- /kaifangqian-demo-vue/src/router/index.js: -------------------------------------------------------------------------------- 1 | import { createRouter, createWebHistory } from 'vue-router' 2 | import main from '../views/main.vue' 3 | 4 | const router = createRouter({ 5 | history: createWebHistory(import.meta.env.BASE_URL), 6 | routes: [ 7 | { 8 | path: '/', 9 | name: 'home', 10 | component: main 11 | } 12 | ] 13 | }) 14 | 15 | export default router 16 | -------------------------------------------------------------------------------- /kaifangqian-demo-vue/src/utils/axios/index.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | // import jsonBig from 'json-bigint'; 3 | import {message} from 'ant-design-vue'; 4 | 5 | const service = axios.create({ 6 | baseURL:"/openSign", //开发环境api 生产环境配置服务域名 7 | timeout: 30000, 8 | // transformResponse:function(data){ 9 | // try { 10 | // const json = jsonBig({ 11 | // storeAsString: true 12 | // }) 13 | // return json.parse(data); 14 | // } catch (err) { 15 | // console.log("jsonBig error",err,data); 16 | // return data; 17 | // } 18 | // }, 19 | }); 20 | 21 | service.interceptors.request.use( 22 | (config:any) => { 23 | console.log(config); 24 | return config; 25 | }, 26 | (error:any) => { 27 | return Promise.reject(); 28 | } 29 | ); 30 | 31 | service.interceptors.response.use( 32 | (response:any) => { 33 | if (response.status === 200) { 34 | return response.data; 35 | } else { 36 | return Promise.reject('请求失败'); 37 | } 38 | }, 39 | (error:any) => { 40 | if (error && error.response) { 41 | if(error.response.status == 401){ 42 | message.warning("系统检测到未登录,请登录PaaS平台进行跳转"); 43 | console.error(error); 44 | } 45 | switch (error.response.status) { 46 | case 400: 47 | error.message = '错误请求' 48 | break; 49 | case 401: 50 | //error.message = '未授权,请重新登录' 51 | break; 52 | case 403: 53 | error.message = '拒绝访问' 54 | break; 55 | case 404: 56 | error.message = '请求错误,未找到该资源' 57 | break; 58 | case 405: 59 | error.message = '请求方法未允许' 60 | break; 61 | case 408: 62 | error.message = '请求超时' 63 | break; 64 | case 431: 65 | error.message = '请求错误,未找到该资源' 66 | break; 67 | case 500: 68 | error.message = '服务器端出错' 69 | break; 70 | case 501: 71 | error.message = '网络未实现' 72 | break; 73 | case 502: 74 | error.message = '网络错误' 75 | break; 76 | case 503: 77 | error.message = '服务不可用' 78 | break; 79 | case 504: 80 | error.message = '网络超时' 81 | break; 82 | case 505: 83 | error.message = 'http版本不支持该请求' 84 | break; 85 | default: 86 | error.message = `连接错误${error.response.status}` 87 | } 88 | } else { 89 | error.message = "连接到服务器失败" 90 | } 91 | return Promise.reject(error); 92 | } 93 | ); 94 | 95 | export default service 96 | -------------------------------------------------------------------------------- /kaifangqian-demo-vue/src/utils/flexible.js: -------------------------------------------------------------------------------- 1 | 2 | //设置基础字号 3 | const baseSize = 100 4 | //设置基本缩放比 5 | let scaleRate = 1; 6 | 7 | let fontSize = 0; 8 | // 设置 rem 函数 9 | function setRem() { 10 | // 当前页面宽度相对于 1920 宽的缩放比例,可根据自己需要修改。 11 | let clientWidth = document.documentElement.clientWidth; 12 | if(clientWidth < 1366){ 13 | clientWidth = 1366; 14 | } 15 | const scale = clientWidth / 1920 16 | console.log("setRem",clientWidth,scale); 17 | 18 | scaleRate = scale 19 | // if (scaleRate > 1.5) { 20 | // store.commit("newScreen/setScaleRate", 1.5) 21 | // } else if (scaleRate < 0.5) { 22 | 23 | // store.commit("newScreen/setScaleRate", 0.5) 24 | // } else { 25 | // store.commit("newScreen/setScaleRate", scaleRate) 26 | // } 27 | // 设置页面根节点字体大小 28 | if (clientWidth > 2880) { 29 | document.documentElement.style.fontSize = 14 + 'px' 30 | } else { 31 | document.documentElement.style.fontSize = (baseSize * scale) + 'px' 32 | } 33 | } 34 | // 初始化 35 | setRem() 36 | // 改变窗口大小时重新设置 rem 37 | // window.onresize = function () { 38 | // setRem() 39 | // } 40 | window.addEventListener('resize',function(){ 41 | setRem() 42 | }) 43 | export default scaleRate; -------------------------------------------------------------------------------- /kaifangqian-demo-vue/src/utils/index.js: -------------------------------------------------------------------------------- 1 | export function getWindowHeight() { 2 | var h = document.documentElement.clientHeight || document.body.clientHeight; 3 | window.sessionStorage.setItem("clientHeight", h); 4 | return h; 5 | } 6 | 7 | 8 | export function saveBlob(data, filename) { 9 | const url = URL.createObjectURL(new Blob([data])); 10 | const link = document.createElement("a"); 11 | link.href = url; 12 | link.setAttribute("download", filename); 13 | link.download = filename; 14 | link.hidden = true; 15 | document.body.appendChild(link); 16 | link.click(); 17 | setTimeout(() => { 18 | document.body.removeChild(link); 19 | window.URL.revokeObjectURL(url); 20 | }, 0); 21 | } 22 | 23 | // base64 转 Blob 24 | export function base64ToBlob(base64) { 25 | let binary = atob(base64); 26 | let array = []; 27 | for (let i = 0; i < binary.length; i++) { 28 | array.push(binary.charCodeAt(i)); 29 | } 30 | return new Blob([new Uint8Array(array)], { type: "image/png" }); 31 | } -------------------------------------------------------------------------------- /kaifangqian-demo-vue/src/utils/request.ts: -------------------------------------------------------------------------------- 1 | import axios from "./axios" 2 | 3 | export const requestHeader =()=>{ 4 | return{ 5 | "x-access-token": "", 6 | } 7 | }; 8 | export function baseUrl(){ 9 | return process.env.VUE_APP_BASE_URI; 10 | } 11 | export function doGet(url, params) { 12 | return axios({ 13 | url: url, 14 | method: "get", 15 | params: params, 16 | headers: requestHeader() 17 | }) 18 | }; 19 | export function doPost(url, params) { 20 | return axios({ 21 | url: url, 22 | method: "post", 23 | data: params, 24 | headers: requestHeader() 25 | }) 26 | } 27 | export function doDelete(url, params) { 28 | return axios({ 29 | url: url, 30 | method: "delete", 31 | params: params, 32 | headers: requestHeader() 33 | }) 34 | } 35 | export function doPut(url: string, params: any) { 36 | return axios({ 37 | url: url, 38 | method: "put", 39 | data: params, 40 | headers: requestHeader() 41 | }) 42 | } 43 | 44 | 45 | export function doPostDowload(url, params) { 46 | return axios({ 47 | url: url, 48 | method: "post", 49 | responseType: "blob", 50 | data: params, 51 | headers: requestHeader() 52 | }) 53 | } -------------------------------------------------------------------------------- /kaifangqian-demo-vue/vite.config.js: -------------------------------------------------------------------------------- 1 | import { 2 | fileURLToPath, 3 | URL 4 | } from 'node:url' 5 | 6 | import { 7 | defineConfig 8 | } from 'vite' 9 | import vue from '@vitejs/plugin-vue' 10 | 11 | export default defineConfig({ 12 | outputDir: "dist/esign", 13 | transpileDependencies: true, 14 | server: { 15 | host: '0.0.0.0', 16 | port: 8080, 17 | open: false, // vue项目启动时自动打开浏览器 18 | proxy: { 19 | "/openSign": { 20 | target: "http://127.0.0.1:8666", 21 | changeOrigin: true, 22 | } 23 | }, 24 | }, 25 | plugins: [ 26 | vue(), 27 | ], 28 | resolve: { 29 | alias: { 30 | '@': fileURLToPath(new URL('./src', import.meta.url)) 31 | } 32 | }, 33 | build:{ 34 | target: 'es2020', 35 | cssTarget: 'chrome80', 36 | outDir: "dist/esign" 37 | } 38 | }) -------------------------------------------------------------------------------- /kaifangqian-sdk/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.resrun 8 | kaifangqian-base 9 | 1.1 10 | 11 | 12 | 13 | org.springframework.boot 14 | spring-boot-autoconfigure 15 | 16 | 17 | 18 | 19 | org.apache.pdfbox 20 | pdfbox-tools 21 | 22 | 23 | 24 | 25 | org.bouncycastle 26 | bcpkix-jdk15on 27 | 28 | 29 | org.bouncycastle 30 | bcprov-ext-jdk15on 31 | 32 | 33 | 34 | org.apache.httpcomponents 35 | httpclient 36 | 37 | 38 | org.apache.httpcomponents 39 | httpcore 40 | 41 | 42 | 43 | 44 | com.alibaba 45 | fastjson 46 | 47 | 48 | org.apache.commons 49 | commons-lang3 50 | 51 | 52 | 53 | 54 | kaifangqian-sdk 55 | 56 | 57 | UTF-8 58 | 1.9.4 59 | 60 | 61 | kaifangqian-sdk 62 | 63 | 64 | 65 | org.springframework.boot 66 | spring-boot-maven-plugin 67 | 68 | 69 | false 70 | 71 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /kaifangqian-sdk/src/main/java/org/resrun/sdk/config/SDKClientConfig.java: -------------------------------------------------------------------------------- 1 | package org.resrun.sdk.config; 2 | 3 | public class SDKClientConfig { 4 | 5 | /** 6 | * 是否生产环境 默认为否 7 | */ 8 | private Boolean prod = false; 9 | 10 | /** 11 | * 授权token 12 | */ 13 | private String token; 14 | 15 | /** 16 | * 证书申请路径 17 | */ 18 | private String certApplyUrl; 19 | 20 | 21 | public Boolean getProd() { 22 | return prod; 23 | } 24 | 25 | public void setProd(Boolean prod) { 26 | this.prod = prod; 27 | } 28 | 29 | public String getToken() { 30 | return token; 31 | } 32 | 33 | public void setToken(String token) { 34 | this.token = token; 35 | } 36 | 37 | public String getCertApplyUrl() { 38 | return certApplyUrl; 39 | } 40 | 41 | public void setCertApplyUrl(String certApplyUrl) { 42 | this.certApplyUrl = certApplyUrl; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /kaifangqian-sdk/src/main/java/org/resrun/sdk/enums/APIResultEnum.java: -------------------------------------------------------------------------------- 1 | package org.resrun.sdk.enums; 2 | 3 | /** 4 | * @Description: APIResultEnum 5 | * @Package: org.resrun.enums 6 | * @ClassName: APIResultEnum 7 | * @author: FengLai_Gong 8 | */ 9 | public enum APIResultEnum { 10 | 11 | 12 | SUCCESS(10000,"处理成功","处理成功"), 13 | 14 | VERIFY_FAIL(20000,"sign verify fail","sign verify fail"), 15 | 16 | PARAM_MISSING(21000,"{0}参数缺失","param_missing"), 17 | PARAM_BLANK(22000,"{0}参数不能为空","param_blank"), 18 | PARAM_FORMAT(23000,"{0}参数格式不正确,{1}","param_format"), 19 | 20 | 21 | BUSINESS_ERROR(31000,"业务处理失败,{0}","business_error"), 22 | 23 | 24 | TOKEN_INVALID(41000,"token无效","token_invalid"), 25 | TOKEN_NO_AUTH(42000,"token中未授权该接口调用权限","token_no_auth"), 26 | 27 | SERVICE_CONNECT_ERROR(43000,"调用证书签发服务超时","service_connect_error"), 28 | 29 | 30 | SQL_INJECTION_ERROR(51000,"请勿SQL攻击","sql_injection_error"), 31 | CROSS_SITE_ERROR(52000,"请勿跨站点攻击","cross_site_error"), 32 | UNKNOWN(91000, "系统未知错误","unknown"), 33 | 34 | ; 35 | 36 | private Integer code; 37 | 38 | private String template; 39 | 40 | private String message; 41 | 42 | APIResultEnum(Integer code, String message) { 43 | this.code = code; 44 | this.message = message; 45 | } 46 | APIResultEnum(Integer code,String template, String message) { 47 | this.code = code; 48 | this.message = message; 49 | this.template = template; 50 | } 51 | 52 | public Integer getCode(){ 53 | return code ; 54 | } 55 | 56 | public String getTemplate() { 57 | return template; 58 | } 59 | 60 | public void setMessage(String message) { 61 | this.message = message; 62 | } 63 | 64 | public static APIResultEnum statOf(Integer code) { 65 | for (APIResultEnum state : values()) { 66 | if (state.code.equals(code)) { 67 | return state; 68 | } 69 | } 70 | return null; 71 | } 72 | 73 | 74 | public static APIResultEnum getByMessage(String message){ 75 | if(message != null && message.length() > 0){ 76 | for(APIResultEnum state : APIResultEnum.values()){ 77 | if(state.message.equals(message)){ 78 | return state; 79 | } 80 | } 81 | } 82 | return null ; 83 | } 84 | 85 | } -------------------------------------------------------------------------------- /kaifangqian-sdk/src/main/java/org/resrun/sdk/enums/BusinessErrorEnum.java: -------------------------------------------------------------------------------- 1 | package org.resrun.sdk.enums; 2 | 3 | /** 4 | * @Description: 业务异常枚举 5 | * @Package: org.resrun.enums 6 | * @ClassName: BusinessErrorEnum 7 | * @author: FengLai_Gong 8 | */ 9 | public enum BusinessErrorEnum { 10 | 11 | 12 | CERT_INVALID_ERROR(1,"证书已失效,无法签署"), 13 | 14 | SIGN_FAILED_ERROR(2,"文件签署失败"), 15 | KEYWORDS_NO_EXISTS_ERROR(3,"签署关键字在文件中不存在,无法签署"), 16 | DOWNLOAD_FILE_ERROR(4,"文件网络地址下载失败"), 17 | FILE_PARSE_BASE64_ERROR(5,"文件格式不正确或文件解析失败"), 18 | FILE_READ_ERROR(5,"文件读取失败"), 19 | PAGE_NUMBER_ERROR(6,"page页码不合规,规范:0 sort(List chains){ 16 | if(chains.size() == 1){ 17 | return chains; 18 | } 19 | 20 | List sortChains = new ArrayList<>(chains.size()); 21 | 22 | X509Certificate rootCert = chains.stream().filter(c->c.getIssuerDN().getName().equals(c.getSubjectDN().getName())).findFirst().get(); 23 | 24 | String issuer = rootCert.getSubjectDN().getName(); 25 | 26 | sortChains.add(rootCert); 27 | 28 | for (int i=0;i convertImage(byte[] signFileByte){ 29 | if(signFileByte == null){ 30 | return null ; 31 | } 32 | List responseList = new ArrayList<>(); 33 | PDDocument doc = null; 34 | try { 35 | //加载pdf文件 36 | doc = Loader.loadPDF(signFileByte); 37 | PDFRenderer renderer = new PDFRenderer(doc); 38 | int pageCount = doc.getNumberOfPages(); 39 | if(pageCount == 0){ 40 | return responseList; 41 | } 42 | 43 | for (int i = 0; i < pageCount; ++i) { 44 | int page = i ; 45 | BufferedImage image = renderer.renderImageWithDPI(page, resolution); 46 | ByteArrayOutputStream stream = new ByteArrayOutputStream(); 47 | ImageIO.write(image, IMG_PNG, stream); 48 | byte[] bytes = stream.toByteArray(); 49 | if(bytes != null){ 50 | 51 | responseList.add(bytes); 52 | 53 | } 54 | } 55 | }catch (Exception e) { 56 | e.printStackTrace(); 57 | } 58 | if(responseList.size() == 0){ 59 | throw new RuntimeException("图片转换失败"); 60 | } 61 | 62 | 63 | return responseList ; 64 | } 65 | 66 | public static void main(String[] args) throws IOException { 67 | byte [] pdf = FileUtils.readFileToByteArray(new File("22222.pdf")); 68 | List images = new ConvertImage().convertImage(pdf); 69 | System.out.println("图片:"+images.size()); 70 | } 71 | 72 | } -------------------------------------------------------------------------------- /kaifangqian-sdk/src/main/java/org/resrun/sdk/utils/CutImage.java: -------------------------------------------------------------------------------- 1 | package org.resrun.sdk.utils; 2 | 3 | import javax.imageio.ImageIO; 4 | import java.awt.image.BufferedImage; 5 | import java.io.ByteArrayInputStream; 6 | import java.io.ByteArrayOutputStream; 7 | import java.io.IOException; 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | /** 12 | * @Description: CutImageService 13 | * @Package: com.resrun.modules.opensign.service.tool 14 | * @ClassName: CutImageService 15 | * @author: FengLai_Gong 16 | */ 17 | public class CutImage { 18 | 19 | public List cutImage(byte[] originImage,int number){ 20 | List imageList = new ArrayList<>(); 21 | 22 | // 加载图像 23 | BufferedImage originalImage = null; 24 | int cols = number ; 25 | int rows = 1 ; 26 | try { 27 | originalImage = ImageIO.read(new ByteArrayInputStream(originImage)); 28 | int tileSizeX = originalImage.getWidth() / cols; 29 | int tileSizeY = originalImage.getHeight() / rows; 30 | 31 | BufferedImage[] slicedImages = new BufferedImage[rows * cols]; 32 | 33 | for (int i = 0; i < rows; i++) { 34 | for (int j = 0; j < cols; j++) { 35 | slicedImages[i * cols + j] = originalImage.getSubimage(j * tileSizeX, i * tileSizeY, tileSizeX, tileSizeY); 36 | } 37 | } 38 | for(int i = 0 ; i < slicedImages.length ; i++){ 39 | ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 40 | ImageIO.write(slicedImages[i], "png", outputStream); 41 | imageList.add(outputStream.toByteArray()); 42 | } 43 | } catch (IOException e) { 44 | e.printStackTrace(); 45 | } 46 | 47 | 48 | 49 | return imageList ; 50 | } 51 | } -------------------------------------------------------------------------------- /kaifangqian-sdk/src/main/java/org/resrun/sdk/vo/base/APIRequest.java: -------------------------------------------------------------------------------- 1 | package org.resrun.sdk.vo.base; 2 | 3 | import java.io.Serializable; 4 | import java.util.Map; 5 | 6 | /** 7 | * @Description: 接口统一请求参数父类 8 | * @Package: org.resrun.vo 9 | * @ClassName: APIRequest 10 | * @author: FengLai_Gong 11 | */ 12 | public abstract class APIRequest implements Serializable { 13 | 14 | private static final long serialVersionUID = -2266306977154288057L; 15 | 16 | //流水号 17 | private String uniqueCode; 18 | 19 | public abstract Map paramNameMap(); 20 | 21 | public String getUniqueCode() { 22 | return uniqueCode; 23 | } 24 | 25 | public void setUniqueCode(String uniqueCode) { 26 | this.uniqueCode = uniqueCode; 27 | } 28 | } -------------------------------------------------------------------------------- /kaifangqian-sdk/src/main/java/org/resrun/sdk/vo/base/SignLocation.java: -------------------------------------------------------------------------------- 1 | package org.resrun.sdk.vo.base; 2 | 3 | 4 | import java.io.Serializable; 5 | 6 | /** 7 | * @Description: 签署位置数据 8 | * @Package: org.resrun.vo.base 9 | * @ClassName: SignLocation 10 | * @author: FengLai_Gong 11 | */ 12 | public class SignLocation implements Serializable { 13 | 14 | private static final long serialVersionUID = -3441618832286287804L; 15 | 16 | 17 | //文件宽度 18 | private Number pageWidth ; 19 | 20 | //文件高度 21 | private Number pageHeight ; 22 | 23 | //页码 24 | private Integer page; 25 | 26 | //偏移量-X坐标 27 | private Number offsetX ; 28 | 29 | //偏移量-Y坐标 30 | private Number offsetY ; 31 | 32 | //签章宽度 33 | private Number signWidth ; 34 | 35 | //签章高度 36 | private Number signHeight ; 37 | 38 | 39 | public Number getPageWidth() { 40 | return pageWidth; 41 | } 42 | 43 | public void setPageWidth(Number pageWidth) { 44 | this.pageWidth = pageWidth; 45 | } 46 | 47 | public Number getPageHeight() { 48 | return pageHeight; 49 | } 50 | 51 | public void setPageHeight(Number pageHeight) { 52 | this.pageHeight = pageHeight; 53 | } 54 | 55 | public Integer getPage() { 56 | return page; 57 | } 58 | 59 | public void setPage(Integer page) { 60 | this.page = page; 61 | } 62 | 63 | public Number getOffsetX() { 64 | return offsetX; 65 | } 66 | 67 | public void setOffsetX(Number offsetX) { 68 | this.offsetX = offsetX; 69 | } 70 | 71 | public Number getOffsetY() { 72 | return offsetY; 73 | } 74 | 75 | public void setOffsetY(Number offsetY) { 76 | this.offsetY = offsetY; 77 | } 78 | 79 | public Number getSignWidth() { 80 | return signWidth; 81 | } 82 | 83 | public void setSignWidth(Number signWidth) { 84 | this.signWidth = signWidth; 85 | } 86 | 87 | public Number getSignHeight() { 88 | return signHeight; 89 | } 90 | 91 | public void setSignHeight(Number signHeight) { 92 | this.signHeight = signHeight; 93 | } 94 | } -------------------------------------------------------------------------------- /kaifangqian-sdk/src/main/java/org/resrun/sdk/vo/request/CertEventRequest.java: -------------------------------------------------------------------------------- 1 | package org.resrun.sdk.vo.request; 2 | 3 | import org.resrun.sdk.vo.base.APIRequest; 4 | 5 | import java.io.Serializable; 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | 9 | /** 10 | * @Description: 签名证书(事件证书)签发-请求对象 11 | * @Package: org.resrun.vo 12 | * @ClassName: CertEventRequest 13 | * @author: FengLai_Gong 14 | */ 15 | public class CertEventRequest extends APIRequest implements Serializable { 16 | 17 | private static final long serialVersionUID = -5135668270081357110L; 18 | 19 | 20 | //证书主题 长度100 21 | // @NotNull(message = "param_missing",groups = ValidationSorts.SortB1.class) 22 | // @NotBlank(message = "param_blank",groups = ValidationSorts.SortB2.class) 23 | // @Size(message = "param_format",max = 100, groups = ValidationSorts.SortB3.class) 24 | // @Pattern(message = "param_format",regexp = "^[^ ]+$",groups = ValidationSorts.SortB4.class) 25 | private String certSubject ; 26 | 27 | //证书密码 长度32 28 | // @NotNull(message = "param_missing",groups = ValidationSorts.SortC1.class) 29 | // @NotBlank(message = "param_blank",groups = ValidationSorts.SortC2.class) 30 | // @Size(message = "param_format",max = 32,groups = ValidationSorts.SortC3.class) 31 | // @Pattern(message = "param_format",regexp = "^[^ ]+$",groups = ValidationSorts.SortC4.class) 32 | private String certPassword ; 33 | 34 | 35 | @Override 36 | public Map paramNameMap() { 37 | Map map = new HashMap<>(); 38 | map.put("uniqueCode","uniqueCode"); 39 | map.put("certSubject","certSubject"); 40 | map.put("certPassword","certPassword"); 41 | return map; 42 | } 43 | 44 | public String getCertSubject() { 45 | return certSubject; 46 | } 47 | 48 | public void setCertSubject(String certSubject) { 49 | this.certSubject = certSubject; 50 | } 51 | 52 | public String getCertPassword() { 53 | return certPassword; 54 | } 55 | 56 | public void setCertPassword(String certPassword) { 57 | this.certPassword = certPassword; 58 | } 59 | } -------------------------------------------------------------------------------- /kaifangqian-sdk/src/main/java/org/resrun/sdk/vo/response/CertEventResponse.java: -------------------------------------------------------------------------------- 1 | package org.resrun.sdk.vo.response; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * @Description: CertEventResponse 7 | * @Package: org.resrun.vo.response 8 | * @ClassName: CertEventResponse 9 | * @author: FengLai_Gong 10 | */ 11 | public class CertEventResponse implements Serializable { 12 | 13 | 14 | private static final long serialVersionUID = -2670652937955458956L; 15 | 16 | //证书主题 长度100 17 | private String certSubject ; 18 | 19 | //证书序列号 长度50 20 | private String certSN ; 21 | 22 | //签名证书文件 23 | private String pfx ; 24 | 25 | //证书密码 26 | private String certPassword ; 27 | 28 | //证书有效期起始时间 14 证书有效期起始时间(格式:yyyyMMddHHmmss) 29 | private String certValidityNotBefore ; 30 | 31 | //证书有效期截止时间 14 证书有效期截止时间(格式:yyyyMMddHHmmss) 32 | private String certValidityNotAfter ; 33 | 34 | //有效期天数 35 | private Integer certValidity ; 36 | 37 | 38 | public String getCertSubject() { 39 | return certSubject; 40 | } 41 | 42 | public void setCertSubject(String certSubject) { 43 | this.certSubject = certSubject; 44 | } 45 | 46 | public String getCertSN() { 47 | return certSN; 48 | } 49 | 50 | public void setCertSN(String certSN) { 51 | this.certSN = certSN; 52 | } 53 | 54 | public String getPfx() { 55 | return pfx; 56 | } 57 | 58 | public void setPfx(String pfx) { 59 | this.pfx = pfx; 60 | } 61 | 62 | public String getCertPassword() { 63 | return certPassword; 64 | } 65 | 66 | public void setCertPassword(String certPassword) { 67 | this.certPassword = certPassword; 68 | } 69 | 70 | public String getCertValidityNotBefore() { 71 | return certValidityNotBefore; 72 | } 73 | 74 | public void setCertValidityNotBefore(String certValidityNotBefore) { 75 | this.certValidityNotBefore = certValidityNotBefore; 76 | } 77 | 78 | public String getCertValidityNotAfter() { 79 | return certValidityNotAfter; 80 | } 81 | 82 | public void setCertValidityNotAfter(String certValidityNotAfter) { 83 | this.certValidityNotAfter = certValidityNotAfter; 84 | } 85 | 86 | public Integer getCertValidity() { 87 | return certValidity; 88 | } 89 | 90 | public void setCertValidity(Integer certValidity) { 91 | this.certValidity = certValidity; 92 | } 93 | } -------------------------------------------------------------------------------- /kaifangqian-sdk/src/main/java/org/resrun/sdk/vo/response/DocumentSignResponse.java: -------------------------------------------------------------------------------- 1 | package org.resrun.sdk.vo.response; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * @Description: DocumentSignResponse 7 | * @Package: org.resrun.vo.response 8 | * @ClassName: DocumentSignResponse 9 | * @author: FengLai_Gong 10 | */ 11 | public class DocumentSignResponse implements Serializable { 12 | 13 | private static final long serialVersionUID = 620669287901843970L; 14 | 15 | //签署后的文件 16 | private byte [] documentFile ; 17 | 18 | public byte [] getDocumentFile() { 19 | return documentFile; 20 | } 21 | 22 | public void setDocumentFile(byte [] documentFile) { 23 | this.documentFile = documentFile; 24 | } 25 | } -------------------------------------------------------------------------------- /kaifangqian-sdk/src/main/resources/root/root.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaifangqian/kaifangqian-base/9157ecd23e1e59d3d8849efadd83efe2bd28e00a/kaifangqian-sdk/src/main/resources/root/root.jks --------------------------------------------------------------------------------