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 extends Payload>[] 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 |
2 |
3 |
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 |
6 |
28 |
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
--------------------------------------------------------------------------------