peter
2026-01-09 1a65e52a171e95296615b178088b599927122a58
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
package com.nq.service.impl;
 
import com.nq.common.ServerResponse;
import com.nq.pojo.User;
import com.nq.service.IUserAgreementService;
import com.nq.utils.PropertiesUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
 
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.Date;
 
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.*;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.parser.PdfTextExtractor;
import com.itextpdf.text.pdf.parser.SimpleTextExtractionStrategy;
 
@Service("iUserAgreementService")
public class UserAgreementServiceImpl implements IUserAgreementService {
    private static final Logger log = LoggerFactory.getLogger(UserAgreementServiceImpl.class);
 
    @Autowired
    private com.nq.service.IUserService iUserService;
 
    @Override
    public ServerResponse generateAgreementPdf(HttpServletRequest request) {
        try {
            User user = iUserService.getCurrentUser(request);
            if (user == null) {
                return ServerResponse.createByErrorMsg("用户未登录");
            }
 
            if (StringUtils.isBlank(user.getRealName()) || StringUtils.isBlank(user.getIdCard()) || StringUtils.isBlank(user.getRegAddress())) {
                return ServerResponse.createByErrorMsg("用户信息不完整,请先完成实名认证");
            }
 
            // 检查是否已生成PDF
            String pdfDir = PropertiesUtil.getProperty("agreement.pdf.dir", System.getProperty("user.dir") + "/agreement_pdf");
            File dir = new File(pdfDir);
            if (!dir.exists()) {
                dir.mkdirs();
            }
 
            String pdfFileName = "agreement_" + user.getId() + ".pdf";
            File pdfFile = new File(dir, pdfFileName);
            if (pdfFile.exists()) {
                return ServerResponse.createBySuccess(pdfFileName);
            }
 
            // 获取模板文件路径
            String templatePath = this.getClass().getResource("/templates").getPath();
            if (templatePath.startsWith("/") && System.getProperty("os.name").toLowerCase().contains("windows")) {
                templatePath = templatePath.substring(1);
            }
            templatePath = templatePath.replaceAll("%20", " ");
            if (templatePath.contains("file:")) {
                templatePath = templatePath.substring(templatePath.indexOf("file:") + 5);
            }
            if (templatePath.contains("!")) {
                templatePath = templatePath.substring(0, templatePath.indexOf("!"));
            }
 
            // 使用PDF模板文件
            File pdfTemplate = new File(templatePath, "中原证券股票分成协议(电子正式版).pdf");
            if (!pdfTemplate.exists()) {
                return ServerResponse.createByErrorMsg("PDF模板文件不存在");
            }
 
            // 从PDF模板生成新的PDF,替换占位符
            generatePdfFromTemplate(pdfTemplate, pdfFile, user);
 
            return ServerResponse.createBySuccess(pdfFileName);
        } catch (Exception e) {
            log.error("生成用户协议PDF失败", e);
            return ServerResponse.createByErrorMsg("生成PDF失败:" + e.getMessage());
        }
    }
 
    public static void main(String[] args) {
        generateAgreementPdf11();
    }
 
    public static void generateAgreementPdf11() {
        try {
 
            // 检查是否已生成PDF
            String pdfDir = PropertiesUtil.getProperty("agreement.pdf.dir", System.getProperty("user.dir") + "/agreement_pdf");
            File dir = new File(pdfDir);
            if (!dir.exists()) {
                dir.mkdirs();
            }
 
            String pdfFileName = "agreement_111.pdf";
            File pdfFile = new File(dir, pdfFileName);
 
            // 获取模板文件路径
            String templatePath = "D:/work/A-stock/src/main/resources/templates";
            if (templatePath.startsWith("/") && System.getProperty("os.name").toLowerCase().contains("windows")) {
                templatePath = templatePath.substring(1);
            }
            templatePath = templatePath.replaceAll("%20", " ");
            if (templatePath.contains("file:")) {
                templatePath = templatePath.substring(templatePath.indexOf("file:") + 5);
            }
            if (templatePath.contains("!")) {
                templatePath = templatePath.substring(0, templatePath.indexOf("!"));
            }
 
            // 使用PDF模板文件
            File pdfTemplate = new File(templatePath, "中原证券股票分成协议(电子正式版).pdf");
            if (!pdfTemplate.exists()) {
                System.out.println("PDF模板文件不存在");
            }
 
            // 从PDF模板生成新的PDF,替换占位符
            generatePdfFromTemplate1(pdfTemplate, pdfFile);
 
 
        } catch (Exception e) {
            log.error("生成用户协议PDF失败", e);
 
        }
    }
    public static void generatePdfFromTemplate1(File templatePdf, File outputPdf) throws Exception {
        PdfReader reader = new PdfReader(new FileInputStream(templatePdf));
        PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(outputPdf));
 
        // 设置中文字体
        BaseFont baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
        Font font = new Font(baseFont, 12, Font.NORMAL);
//        Font boldFont = new Font(baseFont, 12, Font.BOLD);
//        BaseFont baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
//        Font font = new Font(baseFont, 5, Font.BOLD);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
        String currentDate = sdf.format(new Date());
 
        // 准备替换的数据
        String realName = "陈大雷";
        String idCard = "433123198802456635";
        String address = "广东省清远市三八街道明星之城18栋2单元1506";
 
        // 获取PDF页数
        int pageCount = reader.getNumberOfPages();
 
        // 在每一页上查找并替换占位符
        for (int pageNum = 1; pageNum <= pageCount; pageNum++) {
            PdfContentByte canvas = stamper.getOverContent(pageNum);
            Rectangle pageSize = reader.getPageSize(pageNum);
 
            // 提取PDF文本查找占位符位置
            String pageText = PdfTextExtractor.getTextFromPage(reader, pageNum, new SimpleTextExtractionStrategy());
 
            // 在PDF上查找并替换占位符
            replacePlaceholdersInPdf1(canvas, pageSize, pageText, realName, idCard, address, currentDate, font,pageNum);
            // 添加签名
            if(pageNum == 3){
                // 添加签名
                addHeaderImageToPdf(canvas, templatePdf.getParent(), pageSize);
            }
        }
 
        stamper.close();
        reader.close();
    }
 
    /**
     * 在PDF上替换占位符(使用文本覆盖方式)
     */
    public static void replacePlaceholdersInPdf1(PdfContentByte canvas, Rectangle pageSize, String pageText,
                                          String realName, String idCard, String address,
                                          String currentDate, Font font,int pageNum) throws Exception {
        // 查找占位符在文本中的位置,然后估算在PDF中的坐标
        // 由于PDF坐标系统复杂,这里使用固定位置替换
        // 实际使用时需要根据PDF模板的具体布局调整坐标
 
        float margin = 50;
        float lineHeight = 14;
        float startY = pageSize.getHeight() - 194;
 
        if(pageNum == 1){
            replacePlaceholder1(canvas, "", realName, margin + 75, startY, 0, font);
            startY -= lineHeight;
 
            replacePlaceholder1(canvas, "", address, margin + 75, startY-2, 0, font);
            startY -= lineHeight;
 
            replacePlaceholder1(canvas, "", idCard, margin + 95, startY-2, 0, font);
        }
        if(pageNum == 3){
            replacePlaceholder1(canvas, "", currentDate, margin + 60, startY+32, 0, font);
            replacePlaceholder1(canvas, "", currentDate, margin + 60, startY, 0, font);
        }
 
//        if (pageText.contains("${jcurrentDate}")) {
//            replacePlaceholder1(canvas, "${jcurrentDate}", currentDate, margin + 100, startY, 150, font);
//            startY -= lineHeight;
//        }
//
//        if (pageText.contains("${ucurrentDate}")) {
//            replacePlaceholder1(canvas, "${ucurrentDate}", currentDate, margin + 100, startY, 300, font);
//        }
    }
 
    /**
     * 在PDF左上角添加图片
     */
    public static void addHeaderImageToPdf(PdfContentByte canvas, String templatePath, Rectangle pageSize) throws Exception {
        // 获取图片路径
        String imagePath = templatePath + File.separator + "zczq.png";
        File imageFile = new File(imagePath);
        // 如果使用相对路径找不到,尝试从resources获取
        if (!imageFile.exists()) {
            String resourcePath = "D:/work/A-stock/src/main/resources/templates";
            if (resourcePath.startsWith("/") && System.getProperty("os.name").toLowerCase().contains("windows")) {
                resourcePath = resourcePath.substring(1);
            }
            resourcePath = resourcePath.replaceAll("%20", " ");
            if (resourcePath.contains("file:")) {
                resourcePath = resourcePath.substring(resourcePath.indexOf("file:") + 5);
            }
            if (resourcePath.contains("!")) {
                resourcePath = resourcePath.substring(0, resourcePath.indexOf("!"));
            }
            imageFile = new File(resourcePath);
        }
 
        if (imageFile.exists()) {
            Image image = Image.getInstance(imageFile.getAbsolutePath());
            // 设置图片大小
            image.scaleToFit(100, 100);
            // 设置图片位置(左上角)
            image.setAbsolutePosition(370, pageSize.getHeight() - 194);
            canvas.addImage(image);
        } else {
            log.warn("未找到图片文件: {}", imagePath);
        }
    }
    /**
     * 替换单个占位符
     */
    public static void replacePlaceholder1(PdfContentByte canvas, String placeholder, String value,
                                    float x, float y, float width, Font font) {
        // 添加白色背景覆盖占位符区域
        canvas.saveState();
        canvas.setColorFill(BaseColor.WHITE);
        canvas.rectangle(x - 5, y - 15, width, 20);
        canvas.fill();
        canvas.restoreState();
 
        // 添加新文本
        ColumnText.showTextAligned(canvas, Element.ALIGN_LEFT,
                new Phrase(value, font), x, y, 0);
    }
 
 
    /**
     * 从PDF模板生成新的PDF,替换占位符
     */
    private void generatePdfFromTemplate(File templatePdf, File outputPdf, User user) throws Exception {
        PdfReader reader = new PdfReader(new FileInputStream(templatePdf));
        PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(outputPdf));
 
        // 设置中文字体
        BaseFont baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
        Font font = new Font(baseFont, 12, Font.NORMAL);
        Font boldFont = new Font(baseFont, 12, Font.BOLD);
 
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
        String currentDate = sdf.format(new Date());
 
        // 准备替换的数据
        String realName = user.getRealName() != null ? user.getRealName() : "";
        String idCard = user.getIdCard() != null ? user.getIdCard() : "";
        String address = user.getRegAddress() != null ? user.getRegAddress() : "";
 
        // 获取PDF页数
        int pageCount = reader.getNumberOfPages();
 
        // 在每一页上查找并替换占位符
        for (int pageNum = 1; pageNum <= pageCount; pageNum++) {
            PdfContentByte canvas = stamper.getOverContent(pageNum);
            Rectangle pageSize = reader.getPageSize(pageNum);
 
            // 提取PDF文本查找占位符位置
            String pageText = PdfTextExtractor.getTextFromPage(reader, pageNum, new SimpleTextExtractionStrategy());
 
            // 在PDF上查找并替换占位符
            replacePlaceholdersInPdf(canvas, pageSize, pageText, realName, idCard, address, currentDate, font,pageNum);
        }
 
        stamper.close();
        reader.close();
    }
 
    /**
     * 在PDF上替换占位符(使用文本覆盖方式)
     */
    private void replacePlaceholdersInPdf(PdfContentByte canvas, Rectangle pageSize, String pageText,
                                         String realName, String idCard, String address, 
                                         String currentDate, Font font,int pageNum) throws Exception {
        // 查找占位符在文本中的位置,然后估算在PDF中的坐标
        // 由于PDF坐标系统复杂,这里使用固定位置替换
        // 实际使用时需要根据PDF模板的具体布局调整坐标
        float margin = 50;
        float lineHeight = 14;
        float startY = pageSize.getHeight() - 194;
 
        if(pageNum == 1){
            replacePlaceholder(canvas, "", realName, margin + 75, startY, 0, font);
            startY -= lineHeight;
 
            replacePlaceholder(canvas, "", address, margin + 75, startY-2, 0, font);
            startY -= lineHeight;
 
            replacePlaceholder(canvas, "", idCard, margin + 95, startY-2, 0, font);
        }
        if(pageNum == 3){
            replacePlaceholder(canvas, "", currentDate, margin + 60, startY+32, 0, font);
            replacePlaceholder(canvas, "", currentDate, margin + 60, startY, 0, font);
        }
 
    }
 
    /**
     * 替换单个占位符
     */
    private void replacePlaceholder(PdfContentByte canvas, String placeholder, String value,
                                   float x, float y, float width, Font font) {
        // 添加白色背景覆盖占位符区域
        canvas.saveState();
        canvas.setColorFill(BaseColor.WHITE);
        canvas.rectangle(x - 5, y - 15, width, 20);
        canvas.fill();
        canvas.restoreState();
 
        // 添加新文本
        ColumnText.showTextAligned(canvas, Element.ALIGN_LEFT,
                new Phrase(value, font), x, y, 0);
    }
 
    @Override
    public void viewAgreementPdf(HttpServletRequest request, HttpServletResponse response) {
        try {
            User user = iUserService.getCurrentUser(request);
            if (user == null) {
                response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "用户未登录");
                return;
            }
 
            String pdfDir = PropertiesUtil.getProperty("agreement.pdf.dir", System.getProperty("user.dir") + "/agreement_pdf");
            String pdfFileName = "agreement_" + user.getId() + ".pdf";
            File pdfFile = new File(pdfDir, pdfFileName);
 
            if (!pdfFile.exists()) {
                response.sendError(HttpServletResponse.SC_NOT_FOUND, "协议文件不存在,请先生成协议");
                return;
            }
 
            response.setContentType("application/pdf");
            response.setHeader("Content-Disposition", "inline; filename=" + pdfFileName);
 
            FileInputStream fis = new FileInputStream(pdfFile);
            OutputStream os = response.getOutputStream();
 
            byte[] buffer = new byte[4096];
            int bytesRead;
            while ((bytesRead = fis.read(buffer)) != -1) {
                os.write(buffer, 0, bytesRead);
            }
 
            fis.close();
            os.flush();
            os.close();
        } catch (Exception e) {
            log.error("查看用户协议PDF失败", e);
            try {
                response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "查看PDF失败");
            } catch (IOException ex) {
                log.error("发送错误响应失败", ex);
            }
        }
    }
}