SSL 证书获取

参考

Certbot 免费申请证书

安装Certbot

  1. sudo apt install certbot 安装Certbot
  2. certbot --version 查看版本,验证是否安装成功。

申请证书

  1. certbot certonly -d *.exwckv.top -w /var/www/html --manual --preferred-challenges http 获取域名证书
    • certonly 这个选项告诉Certbot你只需要获取或者更新证书,并不会自动安装它到你的web服务器配置中。
    • -d 指定域名 如*.baidu.com
    • -w 指定了你的网站根目录的位置,Certbot 将在这个目录下创建用于验证的文件。
    • --manual 指定手动模式,手动模式下,Certbot不会自动安装证书到你的web服务器配置中。
    • --preferred-challenges 指定验证方式包括httpdns。注意:对于通配符域名(如 *.example.com),Let’s Encrypt 要求必须使用 DNS 验证而不是 HTTP 验证。
      • http 在这种方式下,Certbot会在你的服务器上创建一个特定的文件,并通过Web服务器使该文件可通过互联网访问。
      • dns 需要在你的域名DNS配置中添加一条TXT记录,包含由Let’s Encrypt提供的特定值。ACME服务器将检查这条TXT记录以验证域名的所有权。
  2. 填写相关选项
    1. 请求你的电子邮件地址,以便用于接收关于证书续订的重要通知和安全警告。
      1
      2
      3
      Saving debug log to /var/log/letsencrypt/letsencrypt.log
      Enter email address (used for urgent renewal and security notices)
      (Enter 'c' to cancel):
    2. 要求你阅读并同意 Let’s Encrypt 的服务条款(Terms of Service)。
      1
      2
      3
      Please read the Terms of Service at
      https://letsencrypt.org/documents/LE-SA-v1.4-April-3-2024.pdf. You must agree in
      order to register with the ACME server. Do you agree?
    3. 询问你是否愿意在首次成功颁发证书后,与电子前哨基金会(Electronic Frontier Foundation, EFF)分享你的电子邮件地址。
      1
      2
      3
      4
      5
      Would you be willing, once your first certificate is successfully issued, to
      share your email address with the Electronic Frontier Foundation, a founding
      partner of the Let's Encrypt project and the non-profit organization that
      develops Certbot? We'd like to send you email about our work encrypting the web,
      EFF news, campaigns, and ways to support digital freedom.
    4. 询问你希望通过哪种方式验证你对域名的控制权。How would you like to authenticate with the ACME CA?
      1. Spin up a temporary webserver (standalone)
        • 临时启动一个独立的 Web 服务器来响应 ACME 挑战。Certbot 会在你的机器上运行一个短期的 Web 服务器,并通过 HTTP 请求来完成挑战。这种方式适合于你的主 Web 服务器暂时不可用或者你不想修改现有 Web 服务器配置的情况。
        • 选择这个选项时,请确保端口 80(HTTP)没有被其他服务占用,因为 Certbot 需要短暂地接管该端口以完成验证过程。
      2. Place files in webroot directory (webroot)
        • 使用这种方法,你需要指定 Web 根目录的位置,Certbot 会在该目录下创建特定的文件,这些文件可通过 HTTP 访问路径进行访问,从而完成验证。这是比较常用的方法,特别是当你已经有一个正在运行的 Web 服务器并且不想中断服务的时候。
        • 你需要使用 -w 参数指定 Web 根目录,例如 -w /var/www/html,并使用 -d 参数指定需要验证的域名。

自己生成证书

自签名证书不被信任,仅限于开发/内部使用,使用时记得手动

  1. openssl version 安装检查OpenSSL
  2. openssl genpkey -algorithm RSA -out private.key -aes256 生成私钥,用于签署证书 -aes256 加密(测试情况建议不加)
  3. openssl req -new -key private.key -out certificate.csr 生成证书请求文件 -config ./openssl.cnf 使用Openssl配置文件
  4. openssl x509 -req -days 365 -in certificate.csr -signkey private.key -out certificate.crt 生成证书文件

Openssl配置文件

openssl.cnf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[ req ]
default_bits = 2048
distinguished_name = req_distinguished_name
req_extensions = req_ext
prompt = no

[ req_distinguished_name ]
C = CN # 国家代码,如中国为CN
ST = Zhejiang # 省/直辖市
L = Wenzhou # 城市
O = Person # 组织名
OU = Person # 组织单位
CN = 114.55.144.224 # 公共名称,这里可以是IP地址或域名

[ req_ext ]
subjectAltName = @alt_names

[ alt_names ]
IP.1 = 114.55.144.224 # 指定IP地址
# 如果你有多个IP地址或域名,可以继续添加
# IP.2 = 192.168.1.1
# DNS.1 = example.com

Hexo 添加ICP备案信息

参考

按照_config.yml文件中使用的主题theme添加ICP备案信息。

landscape主题添加ICP备案信息:Git地址

  1. 找到theme/landscape/layout/_partial/footer.ejs文件。
  2. 直接写入HTML代码,如<a href="http://beian.miit.gov.cn/" target="_blank">粤ICP备12345678号-1</a>

公安联网备案

网站/App已完成ICP备案需要在开通网站/App之日起的30日内提交公安联网备案申请。

RSA加密 过程与原理

参考

RSA加密与解密过程

生成公钥和私钥

  1. 生成两个大质数p和q(注意:p和q不要太接近),p和q的乘积为NN为密钥的长度,N越大越安全,但计算速度越慢。比如:
    1
    2
    3
    p = 3  //随机选择的大质数一
    q = 11 //随机选择的大质数二
    N = p * q = 33 //密钥的长度
  2. 运用欧拉函数计算T
    1
    T = (p - 1) * (q - 1) = 20
  3. 选取公钥E,公钥ET的互质,且小于TE取一个较大的质数,比如:
    1
    2
    规则:E为小于T的质数,且不是T的因子(就是T不能被E整除)
    比如:E = 7 //随机选择符合条件的公钥
  4. 计算私钥D
    1
    2
    规则:(D * E) % T = 1 说明D和E的乘积除以T的余数为1
    D = 3
  5. 成功获得公钥(E,N)即(7,33) 私钥(D,N)(3,33)

加密和解密

  1. 随机生成明文M,明文M小于N,比如:3
  2. 计算明文ME次幂,即3的7次方值 = 2187
  3. 计算幂对N的余数 2187 % 33 = 9
  4. 把最终的余数发送给服务器端
  5. 服务器端收到加密后的密文后,解密过程如下:
  6. 服务器端收到密文后,计算密文CD次幂,即9的3次方值 = 729
  7. 计算幂对N的余数 729 % 33 = 3 3就是明文

二维码

参考

申请流程

实名认证管理员

  1. 前往中国版权保护中心
  2. 注册,登录,实名账号。
    • 企业管理员实名材料
      • 公司营业执照图片
      • 管理员的身份证正反面照片。
      • 授权书

提交软著申请

  1. 前往->登记业务办理->软件著作权相关登记->计算机软件著作权登记申请
  2. 填写相关信息,如:
    • 开发的硬件环境(指运行登记软件的计算机硬件或专用设备。)
      1
      2
      3
      4
      个人计算机
      处理器:i5 10代及以上
      内存:16GB
      硬盘:至少40GB可用空间
    • 开发该软件的操作系统(指运行登记软件的计算机硬件或专用设备。)
      1
      Windows 10 专业版 版本号 22H2 (19045.2965) (64 位)
    • 软件开发环境 / 开发工具
      1
      2
      3
      CocosCreate
      Android Studio
      Visual Studio Code
    • 运行的硬件环境(指运行登记软件的计算机硬件或专用设备。)
      1
      2
      3
      4
      5
      手机
      处理器:1.2 GHz双核
      内存:2GB
      存储空间:至少50MB
      分辨率:1080x1920
    • 源程序量:使用 VS Code Counter 等工具统计
    • 面向领域/行业:数字娱乐,游戏

联系方式

  • 中国版权保护中心:010-83771600 (查号)
  • 软件著作权部:010-61090099

数据库建表规范

参考

命名规范

  • 基础规则:

    • 禁用保留字: 如desc、range、match、delayed等,请参考MySQL官方保留字。
      正例:表达逻辑删除的字段名is_deleted,1表示删除,0表示未删除。
    • 使用小写字母或数字: 禁止出现数字开头,禁止两个下划线中间只
      出现数字。
      正例:aliyun_admin,rdc_config,level3_name
      反例:AliyunAdmin,rdcConfig,level_3_name
    • 是与否概念: ,必须使用is_xxx的方式命名,数据类型是unsigned tinyint
      ( 1表示是,0表示否)。
  • 表名

    • 不使用复数: 表名应该仅仅表示表里面的实体内容,不应该表示实体数量,对应于DO类名也是单数
      形式,符合表达习惯。
    • 命名规范: 表的命名最好是加上“业务名称_表的作用”。正例:alipay_task / force_project / trade_config
  • 字段名

    • 索引: 主键索引名为pk_字段名;唯一索引名为uk_字段名;普通索引名则为idx_字段名。
      说明:pk_ 即primary key;uk_ 即 unique key;idx_ 即index的简称。

表规范

  • 必备字段: 表必备三字段:id, gmt_create, gmt_modified。
    说明:其中id必为主键,类型为unsigned bigint、单表时自增、步长为1。gmt_create, gmt_modified 的类型均为date_time类型,前者现在时表示主动创建,后者过去分词表示被动更新。

Spring Boot JPA连接操作数据库

参考

快速开始

  1. 在Spring Boot中添加相关依赖
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    <!-- Spring Boot JPA依赖 提供对数据库操作的一套标准-->
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>

    <!-- 根据使用的数据库,添加对应的依赖 -->
    <dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <scope>runtime</scope>
    </dependency>
  2. 配置数据库连接
    1
    2
    3
    4
    5
    spring:
    datasource:
    url: jdbc:mysql://xxx.xxx.xxx.xxx:3306/spring
    username: spring
    password: spring

Spring Boot 加载配置文件信息

参考

加载配置文件信息使用场景

  • 游戏物品等策划配置的表格数据,如游戏物品名称,物品描述,物品图标等不会经常变动的数据,可以放在配置文件里,通过配置文件加载到内存中,减少数据库查询次数,提高性能。

配置文件加载方式

  1. 将表格获取其他数据的配置文件放在resources目录下。
  2. 定义数据结构相关的类
  3. 读取配置文件并使用

代码示例

  1. 将文件放在resources目录下,如src/main/resources/Prop.json
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    [
    {
    "tId": 1,
    "name": "珍珠",
    "desc": "购买/解锁。获取说明:通过土地每日固定产出,以及小游戏消耗/获取"
    },
    {
    "tId": 2,
    "name": "铲铲",
    "desc": "解锁沙滩专用。获取说明:官方派发"
    },
    {
    "tId": 3,
    "name": "奇异种子",
    "desc": "用于种植奇异果实。获取说明:通过加工农产品获得奇异种子,加工1000珍珠可以获得1粒种子"
    }
    ]
  2. 定义数据结构相关的类
    1
    2
    3
    4
    5
    package com.chenlvtang.student.pojo.entity;

    //物品基础静态数据类
    public record PropTemplate(Number tId, String name, String desc) {
    }
  3. 读取配置文件并使用
    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
    import com.chenlvtang.student.pojo.entity.PropTemplate;
    import com.chenlvtang.student.service.PropTemplateService;
    import com.fasterxml.jackson.core.type.TypeReference;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import jakarta.annotation.PostConstruct;
    import org.springframework.stereotype.Service;

    import java.io.IOException;
    import java.io.InputStream;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;

    /**
    * Created with IntelliJ IDEA.
    *
    * @author Administrator
    * Date: 2025/1/16
    * Time: 14:42
    * Description:物品静态数据服务实现类
    */
    @Service
    public class PropTemplateServiceImpl implements PropTemplateService {
    private final Map<Number, PropTemplate> itemCache = new HashMap<>();

    private final ObjectMapper objectMapper;

    public PropTemplateServiceImpl(ObjectMapper objectMapper) {
    this.objectMapper = objectMapper;
    }

    @PostConstruct
    public void loadItemsIntoCache() throws IOException {
    InputStream inputStream = getClass().getClassLoader().getResourceAsStream("Prop.json");
    if (inputStream == null) {
    throw new IOException("未发现 Prop.json 文件");
    }

    List<PropTemplate> itemList = objectMapper.readValue(inputStream, new TypeReference<>() {
    });
    for (PropTemplate item : itemList) {
    itemCache.put(item.tId(), item);
    }
    }

    @Override
    public PropTemplate getPropTemplateById(int id) {
    return itemCache.get(id);
    }
    }

进一步完善:使用@Value传值

  1. 在application.properties中添加配置文件路径
    1
    2
    3
    4
    ### 这里都是自定义的
    config:
    file-path:
    prop: Prop.json
  2. 在类中使用@Value注解获取配置文件路径
    1
    2
    @Value("${config.file-path.prop}")
    private String propFilePath;

Spring Boot 参数校验

参考

简单实现参数校验

  1. 添加依赖参数校验所需依赖
    1
    2
    3
    4
    5
    <!-- 参数校验  -->
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
    </dependency>
  2. 添加参数校验注解:在要校验的类中添加参数校验注解如age
    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
    public class TestJson {

    private String name;

    @Min(value = 1, message = "年龄必须大于等于1")
    @Max(value = 160, message = "年龄必须小于等于160")
    private int age;

    public TestJson(String name, int age) {
    this.name = name;
    this.age = age;
    }

    public String getName() {
    return name;
    }

    public void setName(String name) {
    this.name = name;
    }

    public int getAge() {
    return age;
    }

    public void setAge(int age) {
    this.age = age;
    }
    }
  3. 添加参数校验接口:在传入的参数中添加@Validated注解
    1
    2
    3
    4
    @PostMapping("/json")
    public TestJson json(@Validated @RequestBody TestJson json) {
    return json;
    }

Spring Boot 异常处理

参考

一、全局异常处理

代码示例

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
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

/**
* Created with IntelliJ IDEA.
*
* @author Administrator
* Date: 2025/1/14
* Time: 12:37
* Description:全局异常处理类
*/
@RestControllerAdvice
public class GlobalRestExceptionHandler {

/**
* 处理异常
*
* @param ex 捕获异常类型
* @return 返回
*/
@ExceptionHandler(Exception.class)
public ResponseEntity<String> handleException(Exception ex) {
return new ResponseEntity<>("网络服务错误", HttpStatus.INTERNAL_SERVER_ERROR);
}

/**
* 处理算数运算异常:如除零错误
*
* @param ex 捕获异常类型
* @return 返回
*/
@ExceptionHandler(ArithmeticException.class)
public ResponseEntity<String> arithmeticException(ArithmeticException ex) {
return new ResponseEntity<>("算数运行异常", HttpStatus.INTERNAL_SERVER_ERROR);
}

}

@RestControllerAdvice 相关设置

优先级设置:存在多个处理器时,使用@Order注解,设置处理器类优先级,例如@Order(Ordered.HIGHEST_PRECEDENCE)

范围设置: 存在多个处理器,例如全局处理器和多个局部处理器时,应当妥善设置范围,避免出现多个处理器同时处理同一个请求。

  • 指定包范围: basePackages: 指定一个或多个包,这些包及其子包下的所有 Controller 都被管理。
    • @RestControllerAdvice(“com.example.controller") // 只管理 com.example.controller 包及其子包下的所有 Controller
    • @RestControllerAdvice(basePackages={"com.example.controller","com.example.controller2"}) // 只管理 com.example.controller 包及其子包下的所有 Controller 和 com.example.controller2 包及其子包下的所有 Controller
    • 指定@RestControllerAdvice(basePackageClasses={Controller1.class,Controller2.class}) 是 basePackages 的一种变形,指定一个或多个 Controller 类,这些类所属的包及其子包下的所有 Controller 都被管理
  • 指定类: assignableTypes 指定一个或多个 Controller 类,这些类被管理
  • 指定注解: annotations 指定一个或多个注解,被这些注解所标记的 Controller 会被管理

处理404错误

即使我们配置了全局异常处理,当出现404 not found等4xx错误时,依然会出现意外情况:

1
2
3
4
5
6
7
8
9
10
11
{
"code": 200,
"msg": "ok",
"data": {
"timestamp": "2023-08-23T17:01:15.102+00:00",
"status": 404,
"error": "Not Found",
"path": "/test/nullapi"
},
"timestamp": 1692810075116
}

解决方法:
application.yml配置文件增加以下配置项:

1
2
3
4
5
6
7
8
9
# 当HTTP状态码为4xx时直接抛出异常
spring:
mvc:
# 高版本这个已经弃用
throw-exception-if-no-handler-found: true
# 关闭默认的静态资源路径映射
web:
resources:
add-mappings: false

现在当我们再次请求一个不存在的接口时,404的话控制台会报NoHandlerFoundException异常,然后被全局异常处理捕获到并统一返回。

Spring Boot 有趣的配置

自定义Banner

  1. 创建一个banner.txt文件,放在resources目录下
  2. 在banner.txt中写上想要显示的Ascii画
  3. 还可以使用 Environment 中的任何key,以及一些占位符如${spring-boot.version}
  4. 重新启动应用,就发现默认的图案已经banner.txt中的内容了

Banner图案生成推荐

Spring Boot 热部署