提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言
Apifox
加密算法介绍
常⻅的加密算法
可逆算法:⼀种可以将加密后的密⽂还原为原始明⽂的算法。
◦ 对称算法:对称加密(也叫私钥加密)指加密和解密使⽤相同密钥的加密算法。它要求发送⽅和接收⽅在安全通信之前,商定⼀个密钥。对称算法的安全性依赖于密钥,泄漏密钥就意味着任何⼈都可以对他们发送或接收的消息解密,所以密钥的保密性对通信的安全性⾄关重要
◦ ⾮对称算法:⾮对称加密是指需要两个密钥来进⾏加密和解密,这两个秘钥分别是公钥(public key)和私钥(private key),如果⽤公钥对数据进⾏加密,只有⽤对应的私钥才能解密。
• 不可逆算法:⼀种⽆法将加密后的密⽂还原为原始明⽂的算法。
◦ 单向散列(hash)加密:是指把任意⻓的输⼊串变化成固定⻓的输出串,并且由输出串难以得到输⼊串的加密⽅法。⼴泛应⽤于对敏感数据加密,⽐如⽤⼾密码,请求参数,⽂件加密等。
BCrypt
Bcrypt是⼀种哈希加密算法,被⼴泛应⽤于存储密码和进⾏⾝份验证。并且Bcrypt算法包含⼀个重要的特性即每次⽣成的哈希值都不同,这是由于Bcrypt算法在计算时会先⽣成⼀个随机的盐值与⽤⼾密码⼀起参与计算最终得到⼀个加密后的字符串。由于⽣成的盐值是随机的,所以即使每次使⽤相同的密码得到结果也是不同的。这样可以有效的防⽌攻击者使⽤⼀些⼿段破解⽤⼾密码
这个就是不可逆的
其实应该也是很容易分析出来的,就是加密的时候,先随机生成一个盐,然后把盐和密码一起加密
判断密码是否正确的时候,就要把盐给提取出来,然后用这个盐和密码重新加密,看看和以前加密的是不是一样的
我们在oj-system里面分装一个BCrypt的工具类
/**
* 加密算法⼯具类
*/
public class BCryptUtils {
/**
* ⽣成加密后密⽂
*
* @param password 密码
* @return 加密字符串
*/
public static String encryptPassword(String password) {
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
return passwordEncoder.encode(password);
}
/**
* 判断密码是否相同
*
* @param rawPassword 真实密码
* @param encodedPassword 加密后密⽂
* @return 结果
*/
public static boolean matchesPassword(String rawPassword, String
encodedPassword) {
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
return passwordEncoder.matches(rawPassword, encodedPassword);
}
}
修改数据库
然后就是修改代码了
但是这个生成的密码是60个字符的,但是我们以前设计的密码是20位的,所以还要修改一下
alter table tb_sys_user modify column password char(60)
但是这个ojtest用户没有权限修改字段属性,意思就是没有alter权限,所以还要用root账号登录,然后给这个用户权限
grant alter on ckoj_dev.* to 'ojtest'@'%';
FLUSH PRIVILEGES;
这样ojtest就有alter权限了
然后就可以修改了
update tb_sys_user set password = '$2a$10$Y0flV7ejwwxifZUHooCrSOMl/sB0Z7MVo4o3ZpICKVmNKMFn14vwO' where user_account = 'aaa';
desc tb_sys_user;
这个可以查看表的属性
修改后端
if(!BCryptUtils.matchesPassword(password, sysUser.getPassword())){
r.setCode(ResultCode.FAILED_LOGIN.getCode());
r.setMsg(ResultCode.FAILED_LOGIN.getMsg());
return r;
}
完善
我们给R类增加统一返回的方法
@Data
public class R<T> {
private int code; //定义一些固定的code,前后端商量好的 0 1 请求成功 常量 2 3 枚举
private String msg; //? 通常是code的辅助说明 一个code 对应一个msg
private T data; //请求某个接口返回的数据list SysUser 泛型
public static <T> R<T> ok() {
return assembleResult(null, ResultCode.SUCCESS);
}
public static <T> R<T> ok(T data) {
return assembleResult(data, ResultCode.SUCCESS);
}
public static <T> R<T> fail() {
return assembleResult(null, ResultCode.FAILED);
}
public static <T> R<T> fail(int code, String msg) {
return assembleResult(code, msg, null);
}
/**
* 指定错误码
*
* @param resultCode 指定错误码
* @param <T>
* @return
*/
public static <T> R<T> fail(ResultCode resultCode) {
return assembleResult(null, resultCode);
}
private static <T> R<T> assembleResult(T data, ResultCode resultCode) {
R<T> r = new R<>();
r.setCode(resultCode.getCode());
r.setData(data);
r.setMsg(resultCode.getMsg());
return r;
}
private static <T> R<T> assembleResult(int code, String msg, T data) {
R<T> r = new R<>();
r.setCode(code);
r.setData(data);
r.setMsg(msg);
return r;
}
}
@Override
public R<Void> login(String userAccount, String password) {
LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.select(SysUser::getPassword).eq(SysUser::getUserAccount, userAccount);
SysUser sysUser = sysUserMapper.selectOne(queryWrapper);
if(sysUser == null){
return R.fail(ResultCode.FAILED_USER_NOT_EXISTS);
}
if(!BCryptUtils.matchesPassword(password, sysUser.getPassword())){
return R.fail(ResultCode.FAILED_LOGIN);
}
return R.ok();
}
这样就OK了
全局异常处理
异常分为编译时异常,和运行时异常,如果是编译时异常还好,有红线的提示,我们可以try,catch来捕获
但是呢
如果是运行时异常呢,我们是无法感知的,因为直接就给前端返回500了
所以我们要对异常进行捕获,但不能全部代码都try,catch吧,所以我们使用全局异常处理
在oj-common里面弄一个oj-common-security
/**
* 全局异常处理器
*/
@RestControllerAdvice
//@Slf4j
public class GlobalExceptionHandler
{
/**
* 请求⽅式不⽀持
*/
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
public R<?> handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException e,HttpServletRequest request)
{
String requestURI = request.getRequestURI();
// log.error("请求地址'{}',不⽀持'{}'请求", requestURI, e.getMethod());
return R.fail(ResultCode.ERROR);
}
/**
* 拦截运⾏时异常
*/
@ExceptionHandler(RuntimeException.class)
public R<?> handleRuntimeException(RuntimeException e, HttpServletRequest request) {
String requestURI = request.getRequestURI();
// log.error("请求地址'{}',发⽣异常.", requestURI, e);
return R.fail(ResultCode.ERROR);
}
/**
* 系统异常
*/
@ExceptionHandler(Exception.class)
public R<?> handleException(Exception e, HttpServletRequest request) {
String requestURI = request.getRequestURI();
// log.error("请求地址'{}',发⽣异常.", requestURI, e);
return R.fail(ResultCode.ERROR);
}
}
然后我们还要引入依赖,springweb和oj-common-core
<dependency>
<groupId>com.ck</groupId>
<artifactId>oj-common-core</artifactId>
<version>${oj-common-core.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
我们全局异常的处理就是返回2000,2000就表示出现了异常,不是我们判断出来的错误
因为这还是一个bean,所以还是要配置,这样就可以成为别人的bean了
这样就可以了
测试一下
这样就可以捕获异常了,全局捕获异常后,就给前端返回了2000,其实是什么异常还是不知道,所以我们要用日志框架记录异常,然后由后端人员去处理异常
然后就是这里,左上角的位置,可以直接提交gitee
日志框架引入(slf4j+logback)
简介
重要性:
◦ 故障的排查和问题定位
◦ 系统监控
◦ 数据采集
◦ ⽇志审计
• 注意事项:
◦ 注意⽇志级别
◦ 注意⽇志内容,⽇志格式和可读性
◦ 避免过度⽇志记录
◦ 注意⽇志的滚动和归档
• 为什么选择slf4j+logback
◦ 易于切换
◦ 配置灵活
◦ logback性能更好,集成更⽅便,功能更强⼤
◦ SpringBoot 默认的⽇志框架
所以我们就不用集成,直接就可以使用了
配置
因为配置是要用配置文件的,所以肯定不能用公共的包了,因为从来没有听说过,引入公共的包的配置文件的,而且配置要给web项目使用才行
所以我们就给oj-system弄一个日志的配置文件就可以了logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<!-- 日志存放路径 -->
<property name="log.path" value="logs/oj-system" />
<!-- 日志输出格式 -->
<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
<!-- 控制台输出 -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
</appender>
<!-- 系统日志输出 -->
<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/info.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/info.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 10天 -->
<maxHistory>10</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>INFO</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/error.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/error.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 10天 -->
<maxHistory>10</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>ERROR</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!--日志级别-->
<root level="info">
<appender-ref ref="file_info" />
<appender-ref ref="console" />
<appender-ref ref="file_error" />
</root>
</configuration>
日志存放路径为logs/oj-system,
其中相对路径是以ck-oj为基准的,意思就是实际路径为ck-oj/logs/oj-system
三个appender设置,表示三种日志输出形式,意思就是一个日志,第一必然输出到控制台,第二如果是info,就输出到info文件夹,是error就输出到error文件夹
%d:⽇期和时间,可以使⽤各种格式。在上⾯的例⼦中,它使⽤了 HH:mm:ss.SSS 格式,表⽰⼩
时、分钟、秒和毫秒。
%thread:产⽣⽇志事件的线程名。
%level:⽇志级别(如 INFO, DEBUG, ERROR 等)。
%logger:产⽣⽇志事件的 logger 名,通常⽤于标识发出⽇志请求的类或模块。在上⾯的例⼦
中,%logger{20} 表⽰ logger 名的最⼤⻓度为 20 个字符。
%msg:⽇志消息,即实际记录的⽇志内容。
%method表⽰产⽣⽇志事件的⽅法名
%line表⽰产⽣⽇志事件的⾏号
滚动策略:
◦ TimeBasedRollingPolicy:最常⽤的滚动策略,它根据时间来制定滚动策略。
◦ SizeBasedTriggeringPolicy:基于⽇志⽂件⼤⼩的滚动策略。当⽇志⽂件达到指定的⼤⼩时,它会被滚动(即创建⼀个新的⽇志⽂件)。
◦ FixedWindowRollingPolicy:固定窗⼝滚动策略。它根据⼀个固定的窗⼝⼤⼩(即可以保留的⽇志⽂件数量)来滚动⽇志⽂件。
TimeBasedRollingPolicy每天生成一个日志文件
然后被滚动的日志文件,也就是到了新的一天,日志的文件名后面就会加上日期,然后这个文件可以保留10天
filter是过滤器,表示接收什么样的日志
<root level="info">
这个表示日志级别,表示生成出什么样的日志级别
如果是info,意思就是生成出比info级别大的日志
如果是error,就会生成出比error级别大的日志,就只有error日志了,因为
info级别比erro小
这样就成功了
nacos引入
nacos可以作为服务的注册发现中心,还可以作为配置中心
可以有很多优点,第一就是我们可以在nocos修改配置了,而不是在本地修改配置,然后还要打包才生效,直接在naocs上面修改就生效了
而且不同的人修改本地可能还有冲突
还有就是本地的环境隔离不好,nacos还可以很好的进行环境隔离
nacos官网
docker安装nacos
docker pull nacos/nacos-server:v2.2.3
为nacos外置一个数据库
为什么要外置MySQL数据库
数据持久性:使⽤MySQL作为外置数据库可以确保数据被持久化存储,这对于确保服务的稳定性和数据的可靠性⾄关重要。
⾼可⽤性:Nacos⽀持集群部署,⽽使⽤MySQL作为共享的数据存储可以确保集群中各个节点之间的数据⼀致性。此外,MySQL⾃⾝也⽀持⾼可⽤性和故障转移,如使⽤主从复制或集群解决⽅案,从⽽进⼀步提⾼系统的可⽤性。
性能优化:使⽤nacos内置的数据库虽然能够简化部署,但是性能受到限制,外置的MySQL可以根据需要进⾏优化和扩展,满⾜更⾼的性能要求。
易于管理和维护:⾸先我们系统本⾝采⽤MySQL数据库,nacos外置数据库和我们系统采⽤同样的数据库可以保证技术使⽤的统⼀。简化了数据库的管理和维护⼯作,降低运维成本。
然后就是创建对应的表和数据库了
先用root用户来把nacos的库和表创建起来
/******************************************/
/* 库名称 = bitoj_nacos_local */
/******************************************/
drop database if exists ckoj_nacos_dev;
create database ckoj_nacos_dev;
use ckoj_nacos_dev;
/******************************************/
/* 表名称 = config_info */
/******************************************/
CREATE TABLE `config_info` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
`data_id` varchar(255) NOT NULL COMMENT 'data_id',
`group_id` varchar(128) DEFAULT NULL COMMENT 'group_id',
`content` longtext NOT NULL COMMENT 'content',
`md5` varchar(32) DEFAULT NULL COMMENT 'md5',
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
`src_user` text COMMENT 'source user',
`src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',
`app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
`tenant_id` varchar(128) DEFAULT '' COMMENT '租⼾字段',
`c_desc` varchar(256) DEFAULT NULL COMMENT 'configuration description',
`c_use` varchar(64) DEFAULT NULL COMMENT 'configuration usage',
`effect` varchar(64) DEFAULT NULL COMMENT '配置⽣效的描述',
`type` varchar(64) DEFAULT NULL COMMENT '配置的类型',
`c_schema` text COMMENT '配置的模式',
`encrypted_data_key` text NOT NULL COMMENT '密钥',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_configinfo_datagrouptenant` (`data_id`,`group_id`,`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info';
/******************************************/
/* 表名称 = config_info_aggr */
/******************************************/
CREATE TABLE `config_info_aggr` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
`data_id` varchar(255) NOT NULL COMMENT 'data_id',
`group_id` varchar(128) NOT NULL COMMENT 'group_id',
`datum_id` varchar(255) NOT NULL COMMENT 'datum_id',
`content` longtext NOT NULL COMMENT '内容',
`gmt_modified` datetime NOT NULL COMMENT '修改时间',
`app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
`tenant_id` varchar(128) DEFAULT '' COMMENT '租⼾字段',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_configinfoaggr_datagrouptenantdatum`
(`data_id`,`group_id`,`tenant_id`,`datum_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='增加租⼾字段';
/******************************************/
/* 表名称 = config_info_beta */
/******************************************/
CREATE TABLE `config_info_beta` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
`data_id` varchar(255) NOT NULL COMMENT 'data_id',
`group_id` varchar(128) NOT NULL COMMENT 'group_id',
`app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
`content` longtext NOT NULL COMMENT 'content',
`beta_ips` varchar(1024) DEFAULT NULL COMMENT 'betaIps',
`md5` varchar(32) DEFAULT NULL COMMENT 'md5',
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
`src_user` text COMMENT 'source user',
`src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',
`tenant_id` varchar(128) DEFAULT '' COMMENT '租⼾字段',
`encrypted_data_key` text NOT NULL COMMENT '密钥',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_configinfobeta_datagrouptenant`
(`data_id`,`group_id`,`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin
COMMENT='config_info_beta';
/******************************************/
/* 表名称 = config_info_tag */
/******************************************/
CREATE TABLE `config_info_tag` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
`data_id` varchar(255) NOT NULL COMMENT 'data_id',
`group_id` varchar(128) NOT NULL COMMENT 'group_id',
`tenant_id` varchar(128) DEFAULT '' COMMENT 'tenant_id',
`tag_id` varchar(128) NOT NULL COMMENT 'tag_id',
`app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
`content` longtext NOT NULL COMMENT 'content',
`md5` varchar(32) DEFAULT NULL COMMENT 'md5',
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
`src_user` text COMMENT 'source user',
`src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_configinfotag_datagrouptenanttag`
(`data_id`,`group_id`,`tenant_id`,`tag_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin
COMMENT='config_info_tag';
/******************************************/
/* 表名称 = config_tags_relation */
/******************************************/
CREATE TABLE `config_tags_relation` (
`id` bigint(20) NOT NULL COMMENT 'id',
`tag_name` varchar(128) NOT NULL COMMENT 'tag_name',
`tag_type` varchar(64) DEFAULT NULL COMMENT 'tag_type',
`data_id` varchar(255) NOT NULL COMMENT 'data_id',
`group_id` varchar(128) NOT NULL COMMENT 'group_id',
`tenant_id` varchar(128) DEFAULT '' COMMENT 'tenant_id',
`nid` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'nid, ⾃增⻓标识',
PRIMARY KEY (`nid`),
UNIQUE KEY `uk_configtagrelation_configidtag` (`id`,`tag_name`,`tag_type`),
KEY `idx_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin
COMMENT='config_tag_relation';
/******************************************/
/* 表名称 = group_capacity */
/******************************************/
CREATE TABLE `group_capacity` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`group_id` varchar(128) NOT NULL DEFAULT '' COMMENT 'Group ID,空字符表⽰整个集
群',
`quota` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '配额,0表⽰使⽤默认值',
`usage` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '使⽤量',
`max_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个配置⼤⼩上限,单位
为字节,0表⽰使⽤默认值',
`max_aggr_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '聚合⼦配置最⼤
个数,,0表⽰使⽤默认值',
`max_aggr_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个聚合数据的⼦
配置⼤⼩上限,单位为字节,0表⽰使⽤默认值',
`max_history_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '最⼤变更历史
数量',
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_group_id` (`group_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='集群、各Group容量
信息表';
/******************************************/
/* 表名称 = his_config_info */
/******************************************/
CREATE TABLE `his_config_info` (
`id` bigint(20) unsigned NOT NULL COMMENT 'id',
`nid` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'nid, ⾃增标识',
`data_id` varchar(255) NOT NULL COMMENT 'data_id',
`group_id` varchar(128) NOT NULL COMMENT 'group_id',
`app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
`content` longtext NOT NULL COMMENT 'content',
`md5` varchar(32) DEFAULT NULL COMMENT 'md5',
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
`src_user` text COMMENT 'source user',
`src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',
`op_type` char(10) DEFAULT NULL COMMENT 'operation type',
`tenant_id` varchar(128) DEFAULT '' COMMENT '租⼾字段',
`encrypted_data_key` text NOT NULL COMMENT '密钥',
PRIMARY KEY (`nid`),
KEY `idx_gmt_create` (`gmt_create`),
KEY `idx_gmt_modified` (`gmt_modified`),
KEY `idx_did` (`data_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='多租⼾改造';
/******************************************/
/* 表名称 = tenant_capacity */
/******************************************/
CREATE TABLE `tenant_capacity` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`tenant_id` varchar(128) NOT NULL DEFAULT '' COMMENT 'Tenant ID',
`quota` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '配额,0表⽰使⽤默认值',
`usage` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '使⽤量',
`max_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个配置⼤⼩上限,单位
为字节,0表⽰使⽤默认值',
`max_aggr_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '聚合⼦配置最⼤
个数',
`max_aggr_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个聚合数据的⼦
配置⼤⼩上限,单位为字节,0表⽰使⽤默认值',
`max_history_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '最⼤变更历史
数量',
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='租⼾容量信息表';
CREATE TABLE `tenant_info` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
`kp` varchar(128) NOT NULL COMMENT 'kp',
`tenant_id` varchar(128) default '' COMMENT 'tenant_id',
`tenant_name` varchar(128) default '' COMMENT 'tenant_name',
`tenant_desc` varchar(256) DEFAULT NULL COMMENT 'tenant_desc',
`create_source` varchar(32) DEFAULT NULL COMMENT 'create_source',
`gmt_create` bigint(20) NOT NULL COMMENT '创建时间',
`gmt_modified` bigint(20) NOT NULL COMMENT '修改时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_tenant_info_kptenantid` (`kp`,`tenant_id`),
KEY `idx_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='tenant_info';
CREATE TABLE `users` (
`username` varchar(50) NOT NULL PRIMARY KEY COMMENT 'username',
`password` varchar(500) NOT NULL COMMENT 'password',
`enabled` boolean NOT NULL COMMENT 'enabled'
);
CREATE TABLE `roles` (
`username` varchar(50) NOT NULL COMMENT 'username',
`role` varchar(50) NOT NULL COMMENT 'role',
UNIQUE INDEX `idx_user_role` (`username` ASC, `role` ASC) USING BTREE
);
CREATE TABLE `permissions` (
`role` varchar(50) NOT NULL COMMENT 'role',
`resource` varchar(128) NOT NULL COMMENT 'resource',
`action` varchar(8) NOT NULL COMMENT 'action',
UNIQUE INDEX `uk_role_permission` (`role`,`resource`,`action`) USING BTREE
);
INSERT INTO users (username, password, enabled) VALUES ('nacos',
'$2a$10$EuWPZHzz32dJN7jexM34MOeYirDdFAZm2kuWj7VEOJhhZkDrxfvUu', TRUE);
INSERT INTO roles (username, role) VALUES ('nacos', 'ROLE_ADMIN');
然后就是给ojtest用户赋予权限
grant create,drop,select,insert,update,delete,alter on ckoj_nacos_dev.* to 'ojtest'@'%';
然后就可以外置了
启动nacos容器
docker run -d -p 8848:8848 -p 9848:9848 --name oj-nacos -e MODE=standalone -e JVM_XMS=256m -e JVM_XMX=256m -e SPRING_DATASOURCE_PLATFORM=mysql -e MYSQL_SERVICE_HOST=${mysql_ip} -e MYSQL_SERVICE_PORT=${mysql_port} -e MYSQL_SERVICE_DB_NAME=${nacos_db_name} -e MYSQL_SERVICE_USER=${mysql_user} -e MYSQL_SERVICE_PASSWORD=${mysql_password} nacos/nacos-server:v2.2.3
-e MODE=standalone是以单例的模式启动nacos
-e JVM_XMS=256m -e JVM_XMX=256m这个是占用虚拟机内存大小
SPRING_DATASOURCE_PLATFORM=mysql是数据源平台是mysql
MYSQL_SERVICE_HOST=${mysql_ip} -e MYSQL_SERVICE_PORT=${mysql_port} -e 是数据库ip和端口号
MYSQL_SERVICE_DB_NAME=${nacos_db_name} -e 是数据库名称
MYSQL_SERVICE_USER=${mysql_user} -e 是用户名
MYSQL_SERVICE_PASSWORD=${mysql_password}是密码
但是mysql的ip是多少呢
可以查一下
docker inspect oj-mysql
然后ip地址就是IPAddress,就是172.17.0.2
docker run -d -p 8848:8848 -p 9848:9848 --name oj-nacos -e MODE=standalone -e JVM_XMS=256m -e JVM_XMX=256m -e SPRING_DATASOURCE_PLATFORM=mysql -e MYSQL_SERVICE_HOST=172.17.0.2 -e MYSQL_SERVICE_PORT=3306 -e MYSQL_SERVICE_DB_NAME=ckoj_nacos_dev -e MYSQL_SERVICE_USER=ojtest -e MYSQL_SERVICE_PASSWORD=123456 nacos/nacos-server:v2.2.3
这样就成功了
输入网址http://localhost:8848/nacos
就可以访问管理后台了
这是端口映射的说明
安全问题
但是nacos不用鉴权就登录了,所以很危险
后面再说
结合程序
nacos主要有两个作用,一个是服务注册中心的作用,一个就是配置中心的作用了,我们这里主要讲的就是配置中心的作用
我们创建一个命名空间,专门给oj项目的本地使用
这个创建的命名空间在注册中心和配置中心都是可以用的
然后我们在配置中心的命名空间里面创建配置,创建的一个配置有一个dataId,就是一个配置对应一个程序
在配置中心里面弄的配置,在程序里面引入的话,就可以直接使用了
naocs:
dataId:oj-system-local.yaml
yaml:
server:
port: 9201
spring:
datasource:
url: jdbc:mysql://localhost:3306/ckoj_dev?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=GMT%2B8
username: ojtest
password: 123456
hikari:
minimum-idle: 5 # 最⼩空闲连接数
maximum-pool-size: 20 # 最⼤连接数
idle-timeout: 30000 # 空闲连接存活时间(毫秒)
connection-timeout: 30000 # 连接超时时间(毫秒)
其中dataId就对应了是哪个程序,和oj-system里面的配置是一一对应的
oj-system表示spring:application:name:
local表示环境
yaml表示配置使用的类型
这些东西决定了dataId
所以在程序的配置中就要配置这三个东西,这样才能找到对应的dataId
当然要先配置配置中心的ip地址,然后是命名空间,然后才是这三个属性,来找到对应的dataId,然后加载配置
spring:
application:
name: oj-system
profiles:
active: local
cloud:
nacos:
discovery:
namespace: 6ef31ff7-e5b5-42a7-bc10-2bb286804635
server-addr: http://localhost:8848
config:
namespace: 6ef31ff7-e5b5-42a7-bc10-2bb286804635
server-addr: http://localhost:8848
file-extension: yaml
在本地配置这些东西就可以找到对应的dataId了,然后其余的所有配置都可以在naocs上面配置了,就很方便
注意本地还要引入依赖,就是配置中心和注册中心的依赖
在oj-modules里面引入,因为其他模块也要用
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
然后测试一下,还是可以正常使用,就没有问题了