iTextPdf

使用 itextpdfPDF 文件加水印, https://github.com/itext/itextpdf

Maven

1
2
3
4
5
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.13</version>
</dependency>

Gradle

1
compile group: 'com.itextpdf', name: 'itextpdf', version: '5.5.13'

Java

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
import com.itextpdf.text.BaseColor;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;

import java.io.FileOutputStream;
import java.io.IOException;

/**
* @author hdvsyu
*/
public class PdfStampService {

String stampPdf(String fileName, String newFileName) {
try {
PdfReader pdfReader = new PdfReader(fileName);
try {
PdfStamper pdfStamper = new PdfStamper(pdfReader, new FileOutputStream(newFileName));
int totalPage = pdfReader.getNumberOfPages();
for (int i = 1; i <= totalPage; i++) {
PdfContentByte pdfContentByte = pdfStamper.getOverContent(i);
pdfContentByte.beginText();
pdfContentByte.setColorFill(BaseColor.BLACK);
pdfContentByte.setFontAndSize(BaseFont.createFont(), 9);
pdfContentByte.setTextMatrix(66, 20);
pdfContentByte.showText("some text");
pdfContentByte.endText();
}
pdfStamper.close();
} catch (DocumentException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}

return newFileName;
}
}

pdfContentByte.setTextMatrix(x, y); 坐标是以左下角为原点的坐标系中的坐标

配置SSL证书

由于 Spring Boot 内置了 Tomcat , 故将 Tomcat 服务器的配置写在项目的配置文件 application.yml 中。

在阿里云里可以申请到赛门铁克免费型DV SSL证书, 审核通过后下载的证书有两个文件, 分别是 ***.pfx***.txt

txt文件里面存储的是证书的密码, pfx文件就是证书。

1
2
3
4
5
6
7
server:
port: 8443
ssl:
enabled: true
key-store: # 证书路径
key-store-password: # 证书密码
key-store-type: PKCS12 # 证书类型

使用阿里云企业邮箱发送邮件

阿里云邮箱服务器地址列表:

协议 服务器地址 服务器端口号(常规) 服务器端口号(加密)
POP3 pop.qiye.aliyun.com 110 995
IMAP imap.qiye.aliyun.com 143 993
SMTP smtp.qiye.aliyun.com 25 465

阿里云邮箱服务器列表(旧地址):

协议 服务器地址 服务器端口号(常规) 服务器端口号(加密)
POP3 pop3.mxhichina.com 110 995
IMAP imap.mxhichina.com 143 993
SMTP smtp.mxhichina.com 25 465

阿里云服务器ECS封禁了25端口, 且阿里云企业邮箱 SMTP 不支持 Starttls

Tomcat 在启动的时候耗时

如果在打印的日志中看到 Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [x,xxx] milliseconds. 这个警告, 则可以使用下面的方法

JDK 中找到 java.security 文件, 将 securerandom.source=file:/dev/urandom 修改为 securerandom.source=file:/dev/./urandom

使用 mvn -v 查看 maven 的安装目录

Maven 目录中的 conf/settings.xml 中的 mirrors 结点中添加

1
2
3
4
5
6
<mirror>
<id>nexus-aliyun</id>
<mirrorOf>*</mirrorOf>
<name>Nexus aliyun</name>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>

安装OpenJDK

1
yum install java-11-openjdk

下载Maven

1
wget https://mirrors.tuna.tsinghua.edu.cn/apache/maven/maven-3/3.6.2/binaries/apache-maven-3.6.2-bin.tar.gz

你也可以从官网复制你要的 Maven 的其他版本的连接 https://maven.apache.org/download.cgi

配置Maven

/etc/profile 文件的最下面添加下面的命令并使用 source /etc/profile 命令重新加载

1
export PATH=/[PATH]/apache-maven-3.6.2/bin:$PATH

使用 mvn -v 测试是否安装成功

下载MySQL yum包

https://dev.mysql.com/downloads/repo/yum/

1
wget http://repo.mysql.com/mysql80-community-release-el7-1.noarch.rpm

安装软件源

1
rpm -Uvh mysql80-community-release-el7-1.noarch.rpm

安装MySQL服务器

1
yum install mysql-community-server

MySQL服务相关命令

1
2
3
4
systemctl start mysqld
systemctl stop mysqld
systemctl restart mysqld
systemctl enable mysqld # 开机自启

修改root密码

刚安装的 MySQL root 密码可以在 /var/log/mysqld.log 中找到, 使用找到的密码登录数据库

1
mysql -uroot -p

然后输入刚才找到的密码即可进入数据库, 使用下面的数据库语句修改 root 用户的密码

1
ALTER USER 'root'@'localhost' IDENTIFIED BY 'A-COMPLEX-PASSWORD';

添加用户

1
CREATE USER 'hdvsyu'@'localhost' IDENTIFIED BY 'A-COMPLEX-PASSWORD';

创建数据库

1
CREATE DATABASE hdvsyu CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

将某个数据库的权限赋予某个用户

1
GRANT ALL PRIVILEGES ON hdvsyu.* TO 'hdvsyu'@'localhost';

刷新权限

1
FLUSH PRIVILEGES;

从数据库文件中恢复数据

1
source backup.sql

使用命令行生成SSH密钥:

1
2
cd ~/.ssh
ssh-keygen -t rsa -b 4096 -C "www.hdvsyu.com"

-t 密钥类型有 dsaecdsaed25519rsa 等可选

-b 指定密钥长度

-C 备注

1
2
3
4
Generating public/private rsa key pair.
Enter file in which to save the key (/Users/hdvsyu/.ssh/id_rsa): # 指定密钥的文件名, 默认使用id_rsa
Enter passphrase (empty for no passphrase): # 密钥的密码, 一般情况下不加密, 直接输回车
Enter same passphrase again: # 输入密码或者继续回车

在服务器创建 authorized_keys 文件并授600权限

1
2
touch authorized_keys
chmod 600 authorized_keys

将生成的公钥放入 authorized_keys 文件中

这样就可以通过密钥登陆服务器啦~

A registration card number of PAT consists of 4 parts:

  • the 1st letter represents the test level, namely, T for the top level, A for advance and B for basic;
  • the 2nd - 4th digits are the test site number, ranged from 101 to 999;
  • the 5th - 10th digits give the test date, in the form of yymmdd;
  • finally the 11th - 13th digits are the testee’s number, ranged from 000 to 999.

Now given a set of registration card numbers and the scores of the card owners, you are supposed to output the various statistics according to the given queries.

Input Specification:

Each input file contains one test case. For each case, the first line gives two positive integers N (≤104) and M (≤100), the numbers of cards and the queries, respectively.

Then N lines follow, each gives a card number and the owner’s score (integer in [0,100]), separated by a space.

After the info of testees, there are M lines, each gives a query in the format Type Term, where

  • Type being 1 means to output all the testees on a given level, in non-increasing order of their scores. The corresponding Term will be the letter which specifies the level;
  • Type being 2 means to output the total number of testees together with their total scores in a given site. The corresponding Term will then be the site number;
  • Type being 3 means to output the total number of testees of every site for a given test date. The corresponding Term will then be the date, given in the same format as in the registration card.

Output Specification:

For each query, first print in a line Case #: input, where # is the index of the query case, starting from 1; and input is a copy of the corresponding input query. Then output as requested:

  • for a type 1 query, the output format is the same as in input, that is, CardNumber Score. If there is a tie of the scores, output in increasing alphabetical order of their card numbers (uniqueness of the card numbers is guaranteed);
  • for a type 2 query, output in the format Nt Ns where Nt is the total number of testees and Ns is their total score;
  • for a type 3 query, output in the format Site Nt where Site is the site number and Nt is the total number of testees at Site. The output must be in non-increasing order of Nt‘s, or in increasing order of site numbers if there is a tie of Nt.

If the result of a query is empty, simply print NA.

Sample Input:

8 4
B123180908127 99
B102180908003 86
A112180318002 98
T107150310127 62
A107180908108 100
T123180908010 78
B112160918035 88
A107180908021 98
1 A
2 107
3 180908
2 999

Sample Output:

Case 1: 1 A
A107180908108 100
A107180908021 98
A112180318002 98
Case 2: 2 107
3 260
Case 3: 3 180908
107 2
123 2
102 1
Case 4: 2 999
NA

大意及分析:

Code:

1

2004 年 7 月,谷歌在硅谷的 101 号公路边竖立了一块巨大的广告牌(如下图)用于招聘。内容超级简单,就是一个以 .com 结尾的网址,而前面的网址是一个 10 位素数,这个素数是自然常数 e 中最早出现的 10 位连续数字。能找出这个素数的人,就可以通过访问谷歌的这个网站进入招聘流程的下一步。

自然常数 e 是一个著名的超越数,前面若干位写出来是这样的:e = 2.718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178525166427427466391932003059921… 其中粗体标出的 10 位数就是答案。

本题要求你编程解决一个更通用的问题:从任一给定的长度为 L 的数字中,找出最早出现的 K 位连续数字所组成的素数。

输入格式:

输入在第一行给出 2 个正整数,分别是 L(不超过 1000 的正整数,为数字长度)和 K(小于 10 的正整数)。接下来一行给出一个长度为 L 的正整数 N。

输出格式:

在一行中输出 N 中最早出现的 K 位连续数字所组成的素数。如果这样的素数不存在,则输出 404。注意,原始数字中的前导零也计算在位数之内。例如在 200236 中找 4 位素数,0023 算是解;但第一位 2 不能被当成 0002 输出,因为在原始数字中不存在这个 2 的前导零。

输入样例 1:

20 5
23654987725541023819

输出样例 1:

49877

输入样例 1:

10 3
2468024680

输出样例 1:

404

大意及分析:

给出一个最大长度为1000位的字符串,找到其中第一个K(<10)位长度的素数,如果没有找到则输出404

使用substr对字符串进行截取,使用stoi转为数字,使用is_prime函数进行判断是否为素数

Code:

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
#include <iostream>
#include <cstdio>
#include <cmath>

using namespace std;

bool is_prime(int num) {
for (int i = 2; i <= sqrt(num); i++)
if (num % i == 0)
return false;
return true;
}

int main() {
int l = 0, k = 0;
scanf("%d %d", &l, &k);
char s[1010];
scanf("%s", s);
string str = s;
for (int i = 0; i <= l - k; i++) {
string tmp = str.substr(i, k);
if (is_prime(stoi(tmp))) {
printf("%s", tmp.c_str());
return 0;
}
}
printf("404");
return 0;
}

In July 2004, Google posted on a giant billboard along Highway 101 in Silicon Valley (shown in the picture below) for recruitment. The content is super-simple, a URL consisting of the first 10-digit prime found in consecutive digits of the natural constant e. The person who could find this prime number could go to the next step in Google’s hiring process by visiting this website.

The natural constant e is a well known transcendental number(超越数). The first several digits are: e = 2.718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178525166427427466391932003059921… where the 10 digits in bold are the answer to Google’s question.

Now you are asked to solve a more general problem: find the first K-digit prime in consecutive digits of any given L-digit number.

Input Specification:

Each input file contains one test case. Each case first gives in a line two positive integers: L (≤ 1,000) and K (< 10), which are the numbers of digits of the given number and the prime to be found, respectively. Then the L-digit number N is given in the next line.

Output Specification:

For each test case, print in a line the first K-digit prime in consecutive digits of N. If such a number does not exist, output 404 instead. Note: the leading zeroes must also be counted as part of the K digits. For example, to find the 4-digit prime in 200236, 0023 is a solution. However the first digit 2 must not be treated as a solution 0002 since the leading zeroes are not in the original number.

Sample Iutput 1:

20 5
23654987725541023819

Sample Output 1:

49877

Sample Input 2:

10 3
2468024680

Sample Output 2:

404

大意及分析:

给出一个最大长度为1000位的字符串,找到其中第一个K(<10)位长度的素数,如果没有找到则输出404

使用substr对字符串进行截取,使用stoi转为数字,使用is_prime函数进行判断是否为素数

Code:

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
#include <iostream>
#include <cstdio>
#include <cmath>

using namespace std;

bool is_prime(int num) {
for (int i = 2; i <= sqrt(num); i++)
if (num % i == 0)
return false;
return true;
}

int main() {
int l = 0, k = 0;
scanf("%d %d", &l, &k);
char s[1010];
scanf("%s", s);
string str = s;
for (int i = 0; i <= l - k; i++) {
string tmp = str.substr(i, k);
if (is_prime(stoi(tmp))) {
printf("%s", tmp.c_str());
return 0;
}
}
printf("404");
return 0;
}

The “Hamilton cycle problem” is to find a simple cycle that contains every vertex in a graph. Such a cycle is called a “Hamiltonian cycle”. In this problem, you are supposed to tell if a given cycle is a Hamiltonian cycle.

Input Specification:

Each input file contains one test case. For each case, the first line contains 2 positive integers N (2< N <= 200), the number of vertices, and M, the number of edges in an undirected graph. Then M lines follow, each describes an edge in the format “Vertex1 Vertex2”, where the vertices are numbered from 1 to N. The next line gives a positive integer K which is the number of queries, followed by K lines of queries, each in the format: n V1 V2 … Vn where n is the number of vertices in the list, and Vi’s are the vertices on a path.

Output Specification:

For each query, print in a line “YES” if the path does form a Hamiltonian cycle, or “NO” if not.

Sample Input:

6 10
6 2
3 4
1 5
2 5
3 1
4 1
1 6
6 3
1 2
4 5
6
7 5 1 4 3 6 2 5
6 5 1 4 3 6 2
9 6 2 1 6 3 4 5 2 6
4 1 2 5 1
7 6 1 3 4 5 2 6
7 6 1 2 5 4 3 1

Sample Output:

YES
NO
NO
NO
YES
NO

闭合的哈密顿路径称作哈密顿回路(Hamiltonian cycle),含有图中所有顶点的路径称作哈密顿路径。 明白了什么是哈密顿回路,这个题目是不难了,首先给出的路径必须比题目给出的结点数大1,因为哈密顿路径经过图中所有顶点,而哈密顿回路则是在哈密顿路径的基础上回到起点,所以哈密顿回路的顶点数应该比给出的图的顶点大1。然后这个给出的哈密顿回路应该是在图中表现为连通的。最后,这个给出的哈密顿回路必须经过除起点外的其余结点一次,经过起点两次。 下面给出的代码用graph题目给出的图 isConnected方法测试给出的哈密顿回路在图中的连通性,pre表示前一个结点,v[i]表示当前结点,如果v[i]到pre在图中有路径则是连通的,否则就不连通的 isHamilt方法测试给出的哈密顿回路是不是哈密顿回路,第一个结点比如和最后一个结点相同才能满足闭合这个条件,times数组用来表示哈密顿回路中各结点出现的次数。如果除起始结点外,其余结点的出现次数不为1,则不是哈密顿回路,如果起始节点出现的次数不为2,则不是哈密顿回路

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
#include <cstdio>

int **graph;

int isConnected(int *v, int n) {
int pre = v[0];
for (int i = 1; i < n; i++) {
if (graph[pre][v[i]] != 1) {
return 0;
}
pre = v[i];
}
return 1;
}

int isHamilt(int *v, int n) {
if (v[0] != v[n - 1]) return 0;
int *times = new int[n];
for (int i = 0; i < n; i++) {
times[i] = 0;
}
for (int i = 0; i < n; i++) {
times[v[i]]++;
}

for (int i = 1; i < n; i++) {
if (i == v[0]) {
if (times[i] != 2) {
return 0;
}
} else {
if (times[i] != 1) {
return 0;
}
}
}
return 1;
}

int main() {
int n = 0, m = 0;
scanf("%d %d", &n, &m);
graph = new int *[n + 1];
for (int i = 0; i <= n; i++) {
graph[i] = new int[n + 1];
}
for (int i = 0; i <= n; i++) {
for (int j = 0; j <= n; j++) {
graph[i][j] = 0;
}
}
for (int i = 0; i < m; i++) {
int a = 0, b = 0;
scanf("%d %d", &a, &b);
graph[a][b] = graph[b][a] = 1;
}
int k = 0;
scanf("%d", &k);
for (int i = 0; i < k; i++) {
int kn = 0;
scanf("%d", &kn);
int *v = new int[kn];
for (int j = 0; j < kn; j++) {
scanf("%d", &v[j]);
}
if (kn == n + 1 && isConnected(v, kn) && isHamilt(v, kn)) {
printf("YES\n");
} else {
printf("NO\n");
}
}
return 0;
}
0%