mirror of https://github.com/halo-dev/halo
commit
de89b65837
|
@ -1,5 +1,12 @@
|
|||
# CHANGELOG
|
||||
|
||||
# 1.3.1
|
||||
|
||||
# Fixed
|
||||
|
||||
- 修复自定义页面设置中的地址预览出现 undefined 的问题。
|
||||
- 升级 fastjson 版本为 `1.2.67`。
|
||||
|
||||
# 1.3.0
|
||||
|
||||
## Feature
|
||||
|
|
|
@ -2,14 +2,48 @@
|
|||
|
||||
### 开发步骤
|
||||
|
||||
1. `Fork` 本仓库到你自己的 Github。
|
||||
2. `Clone` 你刚刚 Fork 的仓库到本地。
|
||||
3. 执行 `git checkout dev` 切换到 `dev` 分支并进行开发。
|
||||
4. 提交代码到自己的仓库。
|
||||
5. 回到自己的仓库页面,选择 `New pull request` 按钮,创建 `Pull request` 到原仓库的 `dev` 分支。
|
||||
6. 等待合并。
|
||||
#### 1. Fork 此仓库
|
||||
|
||||
点击右上角的 `fork` 按钮即可。
|
||||
|
||||
#### 2. Clone 仓库到本地
|
||||
|
||||
```bash
|
||||
git clone https://github.com/{YOUR_USERNAME}/halo
|
||||
|
||||
git submodule init
|
||||
|
||||
git submodule update
|
||||
```
|
||||
|
||||
#### 3. 创建新的开发分支
|
||||
|
||||
```bash
|
||||
git checkout -b {BRANCH_NAME}
|
||||
```
|
||||
|
||||
#### 4. 提交代码
|
||||
|
||||
```bash
|
||||
git push origin {BRANCH_NAME}
|
||||
```
|
||||
|
||||
#### 5. 提交 pull request
|
||||
|
||||
回到自己的仓库页面,选择 `New pull request` 按钮,创建 `Pull request` 到原仓库的 `master` 分支。
|
||||
|
||||
然后等待我们 Review 即可,如有 `Change Request`,再本地修改之后再次提交即可。
|
||||
|
||||
#### 6. 更新主仓库代码到自己的仓库
|
||||
|
||||
```bash
|
||||
git remote add upstream git@github.com:halo-dev/halo.git
|
||||
|
||||
git pull upstream master
|
||||
|
||||
git push
|
||||
```
|
||||
|
||||
### 开发规范
|
||||
|
||||
1. 在提交前请使用 IDE 格式化代码。
|
||||
2. 不接受创建 `Pull request` 到 `master` 分支。
|
||||
请参考 [https://halo.run/archives/code-style](https://halo.run/archives/code-style),请确保所有代码格式化之后再提交。
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
另外,写给想自己拉代码编译运行的同学:
|
||||
|
||||
> 目前我们的开发分支即 master,肯定会有很多小问题,不要运行不起来就跑过来吐槽什么代码开源不完整之类的,多找找自己的原因。同时建议下载最新 release 版本的代码,或者在 master 分支执行 `git checkout v1.3.0`。
|
||||
> 目前我们的开发分支即 master,肯定会有很多小问题,不要运行不起来就跑过来吐槽什么代码开源不完整之类的,多找找自己的原因。同时建议下载最新 release 版本的代码,或者在 master 分支执行 `git checkout v1.3.1`。
|
||||
|
||||
PS:实在不想写这个声明(影响 README 的美观),但是就目前来看,写在 README 上是有必要的,因为大部分遇到问题的人都不会去仔细阅读文档。
|
||||
|
||||
|
@ -35,13 +35,13 @@ PS:实在不想写这个声明(影响 README 的美观),但是就目前
|
|||
### 下载最新的 Halo 安装包
|
||||
|
||||
```bash
|
||||
curl -L https://github.com/halo-dev/halo/releases/download/v1.3.0/halo-1.3.0.jar --output halo-latest.jar
|
||||
curl -L https://github.com/halo-dev/halo/releases/download/v1.3.1/halo-1.3.1.jar --output halo-latest.jar
|
||||
```
|
||||
|
||||
或者
|
||||
|
||||
```bash
|
||||
wget https://github.com/halo-dev/halo/releases/download/v1.3.0/halo-1.3.0.jar -O halo-latest.jar
|
||||
wget https://github.com/halo-dev/halo/releases/download/v1.3.1/halo-1.3.1.jar -O halo-latest.jar
|
||||
```
|
||||
|
||||
### 启动 Halo
|
||||
|
|
173
build.gradle
173
build.gradle
|
@ -1,22 +1,22 @@
|
|||
plugins {
|
||||
id 'org.springframework.boot' version '2.2.5.RELEASE'
|
||||
id 'io.spring.dependency-management' version '1.0.9.RELEASE'
|
||||
id 'checkstyle'
|
||||
id 'java'
|
||||
id "org.springframework.boot" version "2.2.5.RELEASE"
|
||||
id "io.spring.dependency-management" version "1.0.9.RELEASE"
|
||||
id "checkstyle"
|
||||
id "java"
|
||||
}
|
||||
|
||||
group = 'run.halo.app'
|
||||
version = '1.3.0'
|
||||
description = 'Halo, An excellent open source blog publishing application.'
|
||||
group = "run.halo.app"
|
||||
version = "1.3.1"
|
||||
description = "Halo, An excellent open source blog publishing application."
|
||||
|
||||
java {
|
||||
archivesBaseName = 'halo'
|
||||
archivesBaseName = "halo"
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
repositories {
|
||||
maven {
|
||||
url 'https://maven.aliyun.com/nexus/content/groups/public'
|
||||
url "https://maven.aliyun.com/nexus/content/groups/public"
|
||||
}
|
||||
mavenCentral()
|
||||
jcenter()
|
||||
|
@ -24,8 +24,8 @@ repositories {
|
|||
|
||||
configurations {
|
||||
implementation {
|
||||
exclude module: 'spring-boot-starter-tomcat'
|
||||
exclude module: 'slf4j-log4j12'
|
||||
exclude module: "spring-boot-starter-tomcat"
|
||||
exclude module: "slf4j-log4j12"
|
||||
}
|
||||
|
||||
developmentOnly
|
||||
|
@ -39,95 +39,100 @@ configurations {
|
|||
}
|
||||
}
|
||||
|
||||
bootJar {
|
||||
manifest {
|
||||
attributes('Implementation-Title': 'Halo Application',
|
||||
'Implementation-Version': archiveVersion)
|
||||
|
||||
springBoot {
|
||||
buildInfo()
|
||||
}
|
||||
|
||||
// gradle 的 Property Expansion 的占位符 ${..} 与 springboot 的占位符 冲突, springboot 的需要转义 \${..}
|
||||
processResources {
|
||||
filesMatching("application.yaml") {
|
||||
expand(project.properties)
|
||||
}
|
||||
}
|
||||
|
||||
ext {
|
||||
set('hutoolVersion', "5.2.3")
|
||||
set('upyunSdkVersion', "4.2.0")
|
||||
set('qiniuSdkVersion', "7.2.28")
|
||||
set('aliyunSdkVersion', "3.8.1")
|
||||
set('baiduSdkVersion', "0.10.36")
|
||||
set('qcloudSdkVersion', "5.6.18")
|
||||
set('swaggerVersion', "2.9.2")
|
||||
set('commonsLangVersion', "3.9")
|
||||
set('httpclientVersion', "4.5.12")
|
||||
set('dataformatYamlVersion', "2.10.3")
|
||||
set('jgitVersion', "5.7.0.202003110725-r")
|
||||
set('flexmarkVersion', "0.60.2")
|
||||
set('thumbnailatorVersion', "0.4.11")
|
||||
set('image4jVersion', "0.7zensight1")
|
||||
set('flywayVersion', "6.3.1")
|
||||
set('h2Version', "1.4.196")
|
||||
set('levelDbVersion', "0.12")
|
||||
set('jsonVersion', "20190722")
|
||||
set('fastJsonVersion', "1.2.66")
|
||||
set('annotationsVersion',"3.0.1")
|
||||
hutoolVersion = "5.2.3"
|
||||
upyunSdkVersion = "4.2.0"
|
||||
qiniuSdkVersion = "7.2.28"
|
||||
aliyunSdkVersion = "3.8.1"
|
||||
baiduSdkVersion = "0.10.36"
|
||||
qcloudSdkVersion = "5.6.18"
|
||||
swaggerVersion = "2.9.2"
|
||||
commonsLangVersion = "3.9"
|
||||
httpclientVersion = "4.5.12"
|
||||
dataformatYamlVersion = "2.10.3"
|
||||
jgitVersion = "5.7.0.202003110725-r"
|
||||
flexmarkVersion = "0.60.2"
|
||||
thumbnailatorVersion = "0.4.11"
|
||||
image4jVersion = "0.7zensight1"
|
||||
flywayVersion = "6.3.1"
|
||||
h2Version = "1.4.196"
|
||||
levelDbVersion = "0.12"
|
||||
jsonVersion = "20190722"
|
||||
fastJsonVersion = "1.2.67"
|
||||
annotationsVersion = "3.0.1"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'org.springframework.boot:spring-boot-starter-actuator'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-web'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-undertow'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-freemarker'
|
||||
implementation "org.springframework.boot:spring-boot-starter-actuator"
|
||||
implementation "org.springframework.boot:spring-boot-starter-data-jpa"
|
||||
implementation "org.springframework.boot:spring-boot-starter-web"
|
||||
implementation "org.springframework.boot:spring-boot-starter-undertow"
|
||||
implementation "org.springframework.boot:spring-boot-starter-freemarker"
|
||||
implementation "com.sun.mail:jakarta.mail"
|
||||
|
||||
implementation "cn.hutool:hutool-core:${hutoolVersion}"
|
||||
implementation "cn.hutool:hutool-crypto:${hutoolVersion}"
|
||||
implementation "cn.hutool:hutool-extra:${hutoolVersion}"
|
||||
implementation "com.upyun:java-sdk:${upyunSdkVersion}"
|
||||
implementation "com.qiniu:qiniu-java-sdk:${qiniuSdkVersion}"
|
||||
implementation "com.aliyun.oss:aliyun-sdk-oss:${aliyunSdkVersion}"
|
||||
implementation "com.baidubce:bce-java-sdk:${baiduSdkVersion}"
|
||||
implementation "com.qcloud:cos_api:${qcloudSdkVersion}"
|
||||
implementation "io.springfox:springfox-swagger2:${swaggerVersion}"
|
||||
implementation "io.springfox:springfox-swagger-ui:${swaggerVersion}"
|
||||
implementation "org.apache.commons:commons-lang3:${commonsLangVersion}"
|
||||
implementation "org.apache.httpcomponents:httpclient:${httpclientVersion}"
|
||||
implementation "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:${dataformatYamlVersion}"
|
||||
implementation "org.eclipse.jgit:org.eclipse.jgit:${jgitVersion}"
|
||||
implementation "com.google.code.findbugs:annotations:${annotationsVersion}"
|
||||
implementation "cn.hutool:hutool-core:$hutoolVersion"
|
||||
implementation "cn.hutool:hutool-crypto:$hutoolVersion"
|
||||
implementation "cn.hutool:hutool-extra:$hutoolVersion"
|
||||
implementation "com.upyun:java-sdk:$upyunSdkVersion"
|
||||
implementation "com.qiniu:qiniu-java-sdk:$qiniuSdkVersion"
|
||||
implementation "com.aliyun.oss:aliyun-sdk-oss:$aliyunSdkVersion"
|
||||
implementation "com.baidubce:bce-java-sdk:$baiduSdkVersion"
|
||||
implementation "com.qcloud:cos_api:$qcloudSdkVersion"
|
||||
implementation "io.springfox:springfox-swagger2:$swaggerVersion"
|
||||
implementation "io.springfox:springfox-swagger-ui:$swaggerVersion"
|
||||
implementation "org.apache.commons:commons-lang3:$commonsLangVersion"
|
||||
implementation "org.apache.httpcomponents:httpclient:$httpclientVersion"
|
||||
implementation "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:$dataformatYamlVersion"
|
||||
implementation "org.eclipse.jgit:org.eclipse.jgit:$jgitVersion"
|
||||
implementation "com.google.code.findbugs:annotations:$annotationsVersion"
|
||||
|
||||
implementation "com.vladsch.flexmark:flexmark:${flexmarkVersion}"
|
||||
implementation "com.vladsch.flexmark:flexmark-ext-attributes:${flexmarkVersion}"
|
||||
implementation "com.vladsch.flexmark:flexmark-ext-autolink:${flexmarkVersion}"
|
||||
implementation "com.vladsch.flexmark:flexmark-ext-emoji:${flexmarkVersion}"
|
||||
implementation "com.vladsch.flexmark:flexmark-ext-escaped-character:${flexmarkVersion}"
|
||||
implementation "com.vladsch.flexmark:flexmark-ext-gfm-strikethrough:${flexmarkVersion}"
|
||||
implementation "com.vladsch.flexmark:flexmark-ext-gfm-tasklist:${flexmarkVersion}"
|
||||
implementation "com.vladsch.flexmark:flexmark-ext-ins:${flexmarkVersion}"
|
||||
implementation "com.vladsch.flexmark:flexmark-ext-media-tags:${flexmarkVersion}"
|
||||
implementation "com.vladsch.flexmark:flexmark-ext-tables:${flexmarkVersion}"
|
||||
implementation "com.vladsch.flexmark:flexmark-ext-toc:${flexmarkVersion}"
|
||||
implementation "com.vladsch.flexmark:flexmark-ext-superscript:${flexmarkVersion}"
|
||||
implementation "com.vladsch.flexmark:flexmark-ext-yaml-front-matter:${flexmarkVersion}"
|
||||
implementation "com.vladsch.flexmark:flexmark-ext-gitlab:${flexmarkVersion}"
|
||||
// implementation "com.vladsch.flexmark:flexmark-html-parser:${flexmarkVersion}"
|
||||
implementation "com.vladsch.flexmark:flexmark:$flexmarkVersion"
|
||||
implementation "com.vladsch.flexmark:flexmark-ext-attributes:$flexmarkVersion"
|
||||
implementation "com.vladsch.flexmark:flexmark-ext-autolink:$flexmarkVersion"
|
||||
implementation "com.vladsch.flexmark:flexmark-ext-emoji:$flexmarkVersion"
|
||||
implementation "com.vladsch.flexmark:flexmark-ext-escaped-character:$flexmarkVersion"
|
||||
implementation "com.vladsch.flexmark:flexmark-ext-gfm-strikethrough:$flexmarkVersion"
|
||||
implementation "com.vladsch.flexmark:flexmark-ext-gfm-tasklist:$flexmarkVersion"
|
||||
implementation "com.vladsch.flexmark:flexmark-ext-ins:$flexmarkVersion"
|
||||
implementation "com.vladsch.flexmark:flexmark-ext-media-tags:$flexmarkVersion"
|
||||
implementation "com.vladsch.flexmark:flexmark-ext-tables:$flexmarkVersion"
|
||||
implementation "com.vladsch.flexmark:flexmark-ext-toc:$flexmarkVersion"
|
||||
implementation "com.vladsch.flexmark:flexmark-ext-superscript:$flexmarkVersion"
|
||||
implementation "com.vladsch.flexmark:flexmark-ext-yaml-front-matter:$flexmarkVersion"
|
||||
implementation "com.vladsch.flexmark:flexmark-ext-gitlab:$flexmarkVersion"
|
||||
// implementation "com.vladsch.flexmark:flexmark-html-parser:$flexmarkVersion"
|
||||
|
||||
implementation "net.coobird:thumbnailator:${thumbnailatorVersion}"
|
||||
implementation "net.sf.image4j:image4j:${image4jVersion}"
|
||||
implementation "org.flywaydb:flyway-core:${flywayVersion}"
|
||||
implementation "net.coobird:thumbnailator:$thumbnailatorVersion"
|
||||
implementation "net.sf.image4j:image4j:$image4jVersion"
|
||||
implementation "org.flywaydb:flyway-core:$flywayVersion"
|
||||
|
||||
implementation "org.json:json:${jsonVersion}"
|
||||
implementation "com.alibaba:fastjson:${fastJsonVersion}"
|
||||
implementation "org.json:json:$jsonVersion"
|
||||
implementation "com.alibaba:fastjson:$fastJsonVersion"
|
||||
|
||||
implementation "org.iq80.leveldb:leveldb:${levelDbVersion}"
|
||||
runtimeOnly "com.h2database:h2:${h2Version}"
|
||||
runtimeOnly 'mysql:mysql-connector-java'
|
||||
implementation "org.iq80.leveldb:leveldb:$levelDbVersion"
|
||||
runtimeOnly "com.h2database:h2:$h2Version"
|
||||
runtimeOnly "mysql:mysql-connector-java"
|
||||
|
||||
|
||||
compileOnly 'org.projectlombok:lombok'
|
||||
annotationProcessor 'org.projectlombok:lombok'
|
||||
compileOnly "org.projectlombok:lombok"
|
||||
annotationProcessor "org.projectlombok:lombok"
|
||||
|
||||
testCompileOnly 'org.projectlombok:lombok'
|
||||
testAnnotationProcessor 'org.projectlombok:lombok'
|
||||
testCompileOnly "org.projectlombok:lombok"
|
||||
testAnnotationProcessor "org.projectlombok:lombok"
|
||||
|
||||
testImplementation 'org.springframework.boot:spring-boot-starter-test'
|
||||
testImplementation "org.springframework.boot:spring-boot-starter-test"
|
||||
|
||||
developmentOnly 'org.springframework.boot:spring-boot-devtools'
|
||||
developmentOnly "org.springframework.boot:spring-boot-devtools"
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.2.2-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-all.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
|
|
@ -5,6 +5,7 @@ import lombok.extern.slf4j.Slf4j;
|
|||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.info.BuildProperties;
|
||||
import org.springframework.boot.web.client.RestTemplateBuilder;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
@ -15,8 +16,10 @@ import run.halo.app.cache.AbstractStringCacheStore;
|
|||
import run.halo.app.cache.InMemoryCacheStore;
|
||||
import run.halo.app.cache.LevelCacheStore;
|
||||
import run.halo.app.config.properties.HaloProperties;
|
||||
import run.halo.app.model.support.HaloConst;
|
||||
import run.halo.app.utils.HttpClientUtils;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
@ -34,6 +37,9 @@ public class HaloConfiguration {
|
|||
@Autowired
|
||||
HaloProperties haloProperties;
|
||||
|
||||
@Autowired
|
||||
BuildProperties buildProperties;
|
||||
|
||||
@Bean
|
||||
public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) {
|
||||
builder.failOnEmptyBeans(false);
|
||||
|
@ -70,4 +76,8 @@ public class HaloConfiguration {
|
|||
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
HaloConst.HALO_VERSION = buildProperties.getVersion();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -113,8 +113,8 @@ public class YamlThemeConfigResolverImpl implements ThemeConfigResolver {
|
|||
item.setName(itemMap.get("name").toString());
|
||||
item.setLabel(itemMap.getOrDefault("label", item.getName()).toString());
|
||||
Object dataType = itemMap.getOrDefault("data-type", itemMap.get("dataType"));
|
||||
item.setDataType(DataType.typeOf(dataType));
|
||||
item.setType(InputType.typeOf(itemMap.get("type")));
|
||||
item.setDataType(item.getType().equals(InputType.SWITCH) ? DataType.BOOL : DataType.typeOf(dataType));
|
||||
item.setDefaultValue(itemMap.get("default"));
|
||||
item.setPlaceholder(itemMap.getOrDefault("placeholder", "").toString());
|
||||
item.setDescription(itemMap.getOrDefault("description", "").toString());
|
||||
|
@ -140,8 +140,8 @@ public class YamlThemeConfigResolverImpl implements ThemeConfigResolver {
|
|||
item.setName(key.toString());
|
||||
item.setLabel(itemMap.getOrDefault("label", item.getName()).toString());
|
||||
Object dataType = itemMap.getOrDefault("data-type", itemMap.get("dataType"));
|
||||
item.setDataType(DataType.typeOf(dataType));
|
||||
item.setType(InputType.typeOf(itemMap.get("type")));
|
||||
item.setDataType(item.getType().equals(InputType.SWITCH) ? DataType.BOOL : DataType.typeOf(dataType));
|
||||
item.setDefaultValue(itemMap.get("default"));
|
||||
item.setPlaceholder(itemMap.getOrDefault("placeholder", "").toString());
|
||||
item.setDescription(itemMap.getOrDefault("description", "").toString());
|
||||
|
|
|
@ -17,7 +17,9 @@ import javax.persistence.*;
|
|||
*/
|
||||
@Data
|
||||
@Entity
|
||||
@Table(name = "attachments")
|
||||
@Table(name = "attachments",
|
||||
indexes = {@Index(name = "attachments_media_type", columnList = "media_type"),
|
||||
@Index(name = "attachments_create_time", columnList = "create_time")})
|
||||
@ToString
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class Attachment extends BaseEntity {
|
||||
|
|
|
@ -16,7 +16,9 @@ import javax.persistence.*;
|
|||
*/
|
||||
@Data
|
||||
@Entity
|
||||
@Table(name = "menus", indexes = {@Index(name = "menus_parent_id", columnList = "parent_id")})
|
||||
@Table(name = "menus",
|
||||
indexes = {@Index(name = "menus_parent_id", columnList = "parent_id"),
|
||||
@Index(name = "menus_name", columnList = "name")})
|
||||
@ToString
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class Menu extends BaseEntity {
|
||||
|
|
|
@ -16,7 +16,9 @@ import java.util.Date;
|
|||
*/
|
||||
@Data
|
||||
@Entity
|
||||
@Table(name = "photos", indexes = {@Index(name = "photos_team", columnList = "team")})
|
||||
@Table(name = "photos",
|
||||
indexes = {@Index(name = "photos_team", columnList = "team"),
|
||||
@Index(name = "photos_create_time", columnList = "create_time")})
|
||||
@ToString
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class Photo extends BaseEntity {
|
||||
|
|
|
@ -44,7 +44,12 @@ public enum InputType {
|
|||
/**
|
||||
* Attachment picker input type
|
||||
*/
|
||||
ATTACHMENT;
|
||||
ATTACHMENT,
|
||||
|
||||
/**
|
||||
* Switch input type, only true or false
|
||||
*/
|
||||
SWITCH;
|
||||
|
||||
/**
|
||||
* Convert type to input type.
|
||||
|
|
|
@ -50,10 +50,6 @@ public class HaloConst {
|
|||
*/
|
||||
public final static String DEFAULT_THEME_ID = "caicai_anatole";
|
||||
|
||||
/**
|
||||
* Version constant. (Available in production environment)
|
||||
*/
|
||||
public static final String HALO_VERSION;
|
||||
/**
|
||||
* Path separator.
|
||||
*/
|
||||
|
@ -143,8 +139,9 @@ public class HaloConst {
|
|||
*/
|
||||
public static String USER_SESSION_KEY = "user_session";
|
||||
|
||||
static {
|
||||
// Set version
|
||||
HALO_VERSION = HaloConst.class.getPackage().getImplementationVersion();
|
||||
}
|
||||
/**
|
||||
* Version constant.
|
||||
*/
|
||||
public static String HALO_VERSION = null;
|
||||
|
||||
}
|
||||
|
|
|
@ -10,9 +10,9 @@ import run.halo.app.repository.PostCommentRepository;
|
|||
import run.halo.app.service.CommentBlackListService;
|
||||
import run.halo.app.service.OptionService;
|
||||
import run.halo.app.service.base.AbstractCrudService;
|
||||
import run.halo.app.utils.DateTimeUtils;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.util.Date;
|
||||
import java.util.Optional;
|
||||
|
||||
|
@ -26,7 +26,6 @@ import java.util.Optional;
|
|||
@Service
|
||||
@Slf4j
|
||||
public class CommentBlackListServiceImpl extends AbstractCrudService<CommentBlackList, Long> implements CommentBlackListService {
|
||||
private static final ZoneId ZONE_ID = ZoneId.of("Asia/Shanghai");
|
||||
private final CommentBlackListRepository commentBlackListRepository;
|
||||
private final PostCommentRepository postCommentRepository;
|
||||
private final OptionService optionService;
|
||||
|
@ -50,10 +49,9 @@ public class CommentBlackListServiceImpl extends AbstractCrudService<CommentBlac
|
|||
*/
|
||||
Optional<CommentBlackList> blackList = commentBlackListRepository.findByIpAddress(ipAddress);
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
Date endTime = new Date(now.atZone(ZONE_ID).toInstant().toEpochMilli());
|
||||
Date endTime = new Date(DateTimeUtils.toEpochMilli(now));
|
||||
Integer banTime = optionService.getByPropertyOrDefault(CommentProperties.COMMENT_BAN_TIME, Integer.class, 10);
|
||||
Date startTime = new Date(now.minusMinutes(banTime)
|
||||
.atZone(ZONE_ID).toInstant().toEpochMilli());
|
||||
Date startTime = new Date(DateTimeUtils.toEpochMilli(now.minusMinutes(banTime)));
|
||||
Integer range = optionService.getByPropertyOrDefault(CommentProperties.COMMENT_RANGE, Integer.class, 30);
|
||||
boolean isPresent = postCommentRepository.countByIpAndTime(ipAddress, startTime, endTime) >= range;
|
||||
if (isPresent && blackList.isPresent()) {
|
||||
|
@ -61,10 +59,10 @@ public class CommentBlackListServiceImpl extends AbstractCrudService<CommentBlac
|
|||
return CommentViolationTypeEnum.FREQUENTLY;
|
||||
} else if (isPresent) {
|
||||
CommentBlackList commentBlackList = CommentBlackList
|
||||
.builder()
|
||||
.banTime(getBanTime(now, banTime))
|
||||
.ipAddress(ipAddress)
|
||||
.build();
|
||||
.builder()
|
||||
.banTime(getBanTime(now, banTime))
|
||||
.ipAddress(ipAddress)
|
||||
.build();
|
||||
super.create(commentBlackList);
|
||||
return CommentViolationTypeEnum.FREQUENTLY;
|
||||
}
|
||||
|
@ -75,10 +73,10 @@ public class CommentBlackListServiceImpl extends AbstractCrudService<CommentBlac
|
|||
blackList.setBanTime(getBanTime(localDateTime, banTime));
|
||||
int updateResult = commentBlackListRepository.updateByIpAddress(blackList);
|
||||
Optional.of(updateResult)
|
||||
.filter(result -> result <= 0).ifPresent(result -> log.error("更新评论封禁时间失败"));
|
||||
.filter(result -> result <= 0).ifPresent(result -> log.error("更新评论封禁时间失败"));
|
||||
}
|
||||
|
||||
private Date getBanTime(LocalDateTime localDateTime, Integer banTime) {
|
||||
return new Date(localDateTime.plusMinutes(banTime).atZone(ZONE_ID).toInstant().toEpochMilli());
|
||||
return new Date(DateTimeUtils.toEpochMilli(localDateTime.plusMinutes(banTime)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,543 @@
|
|||
package run.halo.app.utils;
|
||||
|
||||
import java.time.*;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeFormatterBuilder;
|
||||
import java.time.temporal.ChronoField;
|
||||
import java.time.temporal.Temporal;
|
||||
|
||||
import static cn.hutool.core.date.DatePattern.*;
|
||||
|
||||
/**
|
||||
* 日期工具
|
||||
*
|
||||
* @author LeiXinXin
|
||||
* @date 2019/12/10
|
||||
*/
|
||||
public class DateTimeUtils {
|
||||
/**
|
||||
* 标准日期格式 {@link DateTimeFormatter}:yyyyMMddHHmmssSSS
|
||||
*/
|
||||
public static final DateTimeFormatter PURE_DATETIME_MS_FORMATTER = new DateTimeFormatterBuilder()
|
||||
.appendPattern(PURE_DATETIME_PATTERN)
|
||||
.appendValue(ChronoField.MILLI_OF_SECOND, 3)
|
||||
.toFormatter();
|
||||
/**
|
||||
* 标准日期格式 {@link DateTimeFormatter}:yyyyMMdd
|
||||
*/
|
||||
public static final DateTimeFormatter PURE_DATE_FORMATTER = DateTimeFormatter.ofPattern(PURE_DATE_PATTERN);
|
||||
/**
|
||||
* 标准日期格式 {@link DateTimeFormatter}:yyyy-MM-dd
|
||||
*/
|
||||
public static final DateTimeFormatter NORM_DATE_FORMATTER = DateTimeFormatter.ofPattern(NORM_DATE_PATTERN);
|
||||
/**
|
||||
* 标准日期格式:HHmm
|
||||
*/
|
||||
public final static String TIME_PATTERN = "HHmm";
|
||||
/**
|
||||
* 标准日期格式 {@link DateTimeFormatter} HHmm
|
||||
*/
|
||||
public static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern(TIME_PATTERN);
|
||||
/**
|
||||
* 标准日期格式:HH:mm
|
||||
*/
|
||||
public final static String NORM_TIME_PATTERN = "HH:mm";
|
||||
/**
|
||||
* 标准日期格式 {@link DateTimeFormatter} HH:mm
|
||||
*/
|
||||
public static final DateTimeFormatter NORM_TIME_FORMATTER = DateTimeFormatter.ofPattern(NORM_TIME_PATTERN);
|
||||
/**
|
||||
* 标准日期时间格式,精确到秒 {@link DateTimeFormatter}:yyyy-MM-dd HH:mm:ss
|
||||
*/
|
||||
public static final DateTimeFormatter NORM_DATETIME_FORMATTER = DateTimeFormatter.ofPattern(NORM_DATETIME_PATTERN);
|
||||
/**
|
||||
* 上海时区格式
|
||||
*/
|
||||
public static final String CTT = ZoneId.SHORT_IDS.get("CTT");
|
||||
/**
|
||||
* 上海时区
|
||||
*/
|
||||
public static final ZoneId CTT_ZONE_ID = ZoneId.of(CTT);
|
||||
|
||||
|
||||
private DateTimeUtils() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前时间,默认为上海时区
|
||||
*
|
||||
* @return Now LocalDateTime
|
||||
*/
|
||||
public static LocalDateTime now() {
|
||||
return now(CTT_ZONE_ID);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据时区获取当前时间
|
||||
*
|
||||
* @param zoneId 时区
|
||||
* @return Now LocalDateTime
|
||||
*/
|
||||
public static LocalDateTime now(ZoneId zoneId) {
|
||||
return LocalDateTime.now(zoneId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按 yyyyMMdd 格式化
|
||||
*
|
||||
* @param localDateTime 日期时间
|
||||
* @return Result
|
||||
*/
|
||||
public static String formatDate(LocalDateTime localDateTime) {
|
||||
return format(localDateTime, PURE_DATE_FORMATTER);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按 yyyyMMdd 格式化
|
||||
*
|
||||
* @param localDate 日期
|
||||
* @return Result
|
||||
*/
|
||||
public static String formatDate(LocalDate localDate) {
|
||||
return format(localDate, PURE_DATE_FORMATTER);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按 HHmm 格式化
|
||||
*
|
||||
* @param localDateTime 时间
|
||||
* @return Result
|
||||
*/
|
||||
public static String formatTime(LocalDateTime localDateTime) {
|
||||
return format(localDateTime, TIME_FORMATTER);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按 HHmm 格式化
|
||||
*
|
||||
* @param localTime 时间
|
||||
* @return Result
|
||||
*/
|
||||
public static String formatTime(LocalTime localTime) {
|
||||
return format(localTime, TIME_FORMATTER);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按 yyyy-MM-dd HH:mm:ss 格式格式化
|
||||
*
|
||||
* @param localDateTime 时间
|
||||
* @return Result
|
||||
*/
|
||||
public static String formatDateTime(LocalDateTime localDateTime) {
|
||||
return format(localDateTime, NORM_DATETIME_FORMATTER);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据日期格式化时间
|
||||
*
|
||||
* @param localDateTime 时间
|
||||
* @param formatter 时间格式
|
||||
* @return Result
|
||||
*/
|
||||
public static String format(LocalDateTime localDateTime, DateTimeFormatter formatter) {
|
||||
return localDateTime.format(formatter);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据时间格式,格式化时间
|
||||
*
|
||||
* @param localTime 时间
|
||||
* @param formatter 时间格式
|
||||
* @return Result
|
||||
*/
|
||||
public static String format(LocalTime localTime, DateTimeFormatter formatter) {
|
||||
return localTime.format(formatter);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据日期格式,格式化日期
|
||||
*
|
||||
* @param localDate 日期
|
||||
* @param formatter 日期格式
|
||||
* @return Result
|
||||
*/
|
||||
public static String format(LocalDate localDate, DateTimeFormatter formatter) {
|
||||
return localDate.format(formatter);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按照上海时区,解析香港格式的时间
|
||||
* <p>
|
||||
* 时间格式 yyyyMMddHHmmssSSS
|
||||
*
|
||||
* @param time 时间
|
||||
* @return LocalDateTime
|
||||
*/
|
||||
public static LocalDateTime parseCttDateTime(String time) {
|
||||
return parse(time, PURE_DATETIME_MS_FORMATTER);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据日期格式解析时间
|
||||
*
|
||||
* @param formatter 时间格式
|
||||
* @param time 时间
|
||||
* @return LocalDateTime
|
||||
*/
|
||||
public static LocalDateTime parse(String time, DateTimeFormatter formatter) {
|
||||
return LocalDateTime.parse(time, formatter);
|
||||
}
|
||||
|
||||
/**
|
||||
* to instant by default zoneId(Shanghai)
|
||||
*
|
||||
* @param localDateTime 时间
|
||||
* @return Instant
|
||||
*/
|
||||
public static Instant toInstant(LocalDateTime localDateTime) {
|
||||
return toInstant(localDateTime, CTT_ZONE_ID);
|
||||
}
|
||||
|
||||
/**
|
||||
* To instant by zoneId
|
||||
*
|
||||
* @param localDateTime 时间
|
||||
* @return Instant
|
||||
*/
|
||||
public static Instant toInstant(LocalDateTime localDateTime, ZoneId zoneId) {
|
||||
return localDateTime.atZone(zoneId).toInstant();
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 localDateTime 转为秒
|
||||
*
|
||||
* @param localDateTime 时间
|
||||
* @return 秒
|
||||
*/
|
||||
public static long getEpochSecond(LocalDateTime localDateTime) {
|
||||
return toInstant(localDateTime).getEpochSecond();
|
||||
}
|
||||
|
||||
/**
|
||||
* 将localDateTime 转为时间戳
|
||||
*
|
||||
* @param localDateTime 时间
|
||||
* @return 时间戳
|
||||
*/
|
||||
public static long toEpochMilli(LocalDateTime localDateTime) {
|
||||
return toInstant(localDateTime).toEpochMilli();
|
||||
}
|
||||
|
||||
/**
|
||||
* 将秒和毫秒设为0
|
||||
*
|
||||
* @param localDateTime 需要被设置的时间
|
||||
* @return 返回被设置的LocalDateTime
|
||||
*/
|
||||
public static LocalDateTime secondAndNanoSetZero(LocalDateTime localDateTime) {
|
||||
return localDateTime.withSecond(0).withNano(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加一天时间
|
||||
*
|
||||
* @param localDateTime 日期时间
|
||||
* @return 新增一天后的 LocalDateTime
|
||||
*/
|
||||
public static LocalDateTime plusOneDayToDateTime(LocalDateTime localDateTime) {
|
||||
return plusDays(localDateTime, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加一天时间
|
||||
*
|
||||
* @param localDateTime 日期时间
|
||||
* @param localTime 时间
|
||||
* @return 新增一天后的 LocalDateTime
|
||||
*/
|
||||
public static LocalDateTime plusOneDay(LocalDateTime localDateTime, LocalTime localTime) {
|
||||
return plusOneDay(localDateTime.toLocalDate(), localTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加一天时间
|
||||
*
|
||||
* @param localDate 日期
|
||||
* @param localTime 时间
|
||||
* @return 新增一天后的 LocalDateTime
|
||||
*/
|
||||
public static LocalDateTime plusOneDay(LocalDate localDate, LocalTime localTime) {
|
||||
final LocalDateTime localDateTime = LocalDateTime.of(localDate, localTime);
|
||||
return plusDays(localDateTime, 1);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 增加一天时间
|
||||
*
|
||||
* @param localDateTime 日期时间
|
||||
* @return 新增一天后的 LocalDate
|
||||
*/
|
||||
public static LocalDate plusOneDayToDate(LocalDateTime localDateTime) {
|
||||
return plusDays(localDateTime, 1).toLocalDate();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据days新增天数
|
||||
*
|
||||
* @param localDateTime 日期时间
|
||||
* @param days 天数
|
||||
* @return 新增 days 后的 LocalDateTime
|
||||
*/
|
||||
public static LocalDateTime plusDays(LocalDateTime localDateTime, long days) {
|
||||
return localDateTime.plusDays(days);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增一天
|
||||
*
|
||||
* @param localDate 日期
|
||||
* @return 新增一天后的 LocalDate
|
||||
*/
|
||||
public static LocalDate plusOneDayToDate(LocalDate localDate) {
|
||||
return plusDays(localDate, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据days新增天数
|
||||
*
|
||||
* @param localDate 日期
|
||||
* @param days 新增的天数
|
||||
* @return 新增 days 后的 LocalDate
|
||||
*/
|
||||
public static LocalDate plusDays(LocalDate localDate, long days) {
|
||||
return localDate.plusDays(days);
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加1分钟
|
||||
*
|
||||
* @param localDateTime 日期时间
|
||||
* @return 返回新增的 LocalDateTime
|
||||
*/
|
||||
public static LocalDateTime plusOneMinute(LocalDateTime localDateTime, LocalTime localTime) {
|
||||
return plusOneMinute(localDateTime.toLocalDate(), localTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加1分钟
|
||||
*
|
||||
* @param localDate 日期
|
||||
* @param localTime 时间
|
||||
* @return 返回新增的 LocalDateTime
|
||||
*/
|
||||
public static LocalDateTime plusOneMinute(LocalDate localDate, LocalTime localTime) {
|
||||
final LocalDateTime localDateTime = LocalDateTime.of(localDate, localTime);
|
||||
return plusMinutes(localDateTime, 1);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 增加1分钟
|
||||
*
|
||||
* @param localDateTime 日期时间
|
||||
* @return 返回新增的 LocalDateTime
|
||||
*/
|
||||
public static LocalDateTime plusOneMinute(LocalDateTime localDateTime) {
|
||||
return plusMinutes(localDateTime, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加30分钟
|
||||
*
|
||||
* @param localDateTime 日期时间
|
||||
* @return 返回新增的 LocalDateTime
|
||||
*/
|
||||
public static LocalDateTime plusThirtyMinute(LocalDateTime localDateTime) {
|
||||
return plusMinutes(localDateTime, 30);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增1分钟
|
||||
*
|
||||
* @param localDateTime 日期时间
|
||||
* @return 返回新增的 LocalTime
|
||||
*/
|
||||
public static LocalTime plusOneMinuteToTime(LocalDateTime localDateTime) {
|
||||
return plusMinutes(localDateTime, 1).toLocalTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增1分钟
|
||||
*
|
||||
* @param localTime 日期时间
|
||||
* @return 返回新增的 LocalTime
|
||||
*/
|
||||
public static LocalTime plusOneMinute(LocalTime localTime) {
|
||||
return plusMinutes(localTime, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加30分钟
|
||||
*
|
||||
* @param localTime 日期时间
|
||||
* @return 返回新增的 LocalTime
|
||||
*/
|
||||
public static LocalTime plusThirtyMinute(LocalTime localTime) {
|
||||
return plusMinutes(localTime, 30);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 minutes 新增分钟
|
||||
*
|
||||
* @param localDateTime 日期时间
|
||||
* @param minutes 分钟数
|
||||
* @return 返回新增的 LocalDateTime
|
||||
*/
|
||||
public static LocalDateTime plusMinutes(LocalDateTime localDateTime, long minutes) {
|
||||
return localDateTime.plusMinutes(minutes);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 minutes 新增分钟
|
||||
*
|
||||
* @param localTime 时间
|
||||
* @param minutes 分钟数
|
||||
* @return 返回新增的 LocalTime
|
||||
*/
|
||||
public static LocalTime plusMinutes(LocalTime localTime, long minutes) {
|
||||
return localTime.plusMinutes(minutes);
|
||||
}
|
||||
|
||||
/**
|
||||
* 减少 1 分钟
|
||||
*
|
||||
* @param localDateTime 日期时间
|
||||
* @param localTime 时间
|
||||
* @return 返回新增的 LocalTime
|
||||
*/
|
||||
public static LocalDateTime minusOneMinutes(LocalDateTime localDateTime, LocalTime localTime) {
|
||||
return minusOneMinutes(localDateTime.toLocalDate(), localTime);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 减少 1 分钟
|
||||
*
|
||||
* @param localDate 日期
|
||||
* @param localTime 时间
|
||||
* @return 返回新增的 LocalTime
|
||||
*/
|
||||
public static LocalDateTime minusOneMinutes(LocalDate localDate, LocalTime localTime) {
|
||||
final LocalDateTime localDateTime = LocalDateTime.of(localDate, localTime);
|
||||
return minusMinutes(localDateTime, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 减少 1 分钟
|
||||
*
|
||||
* @param localDateTime 日期时间
|
||||
* @return 返回新增的 LocalTime
|
||||
*/
|
||||
public static LocalDateTime minusOneMinutes(LocalDateTime localDateTime) {
|
||||
return minusMinutes(localDateTime, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 minutes 减少分钟
|
||||
*
|
||||
* @param localDateTime 日期时间
|
||||
* @param minutes 分钟数
|
||||
* @return 返回新增的 LocalTime
|
||||
*/
|
||||
public static LocalDateTime minusMinutes(LocalDateTime localDateTime, long minutes) {
|
||||
return localDateTime.minusMinutes(minutes);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 minutes 减少分钟
|
||||
*
|
||||
* @param localTime 时间
|
||||
* @param minutes 分钟数
|
||||
* @return 返回新增的 LocalTime
|
||||
*/
|
||||
public static LocalTime minusMinutes(LocalTime localTime, long minutes) {
|
||||
return localTime.minusMinutes(minutes);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否是中午
|
||||
*
|
||||
* @param startInclusive Start
|
||||
* @return boolean
|
||||
*/
|
||||
public static boolean isNoon(LocalDateTime startInclusive) {
|
||||
LocalDateTime noonDateTime = LocalDateTime.of(startInclusive.toLocalDate(), LocalTime.NOON);
|
||||
return Duration.between(startInclusive, noonDateTime).isZero();
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否是中午
|
||||
*
|
||||
* @param startInclusive Start
|
||||
* @return boolean
|
||||
*/
|
||||
public static boolean isNoon(LocalTime startInclusive) {
|
||||
return Duration.between(startInclusive, LocalTime.NOON).isZero();
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是负数,startInclusive 大于 endInclusive 就是负数
|
||||
*
|
||||
* @param startInclusive Start
|
||||
* @param endInclusive end
|
||||
* @return boolean
|
||||
*/
|
||||
public static boolean isNegative(Temporal startInclusive, Temporal endInclusive) {
|
||||
return Duration.between(startInclusive, endInclusive).isNegative();
|
||||
}
|
||||
|
||||
/**
|
||||
* 相比是否是0,两个时间一致就是0
|
||||
*
|
||||
* @param startInclusive Start
|
||||
* @param endInclusive end
|
||||
* @return boolean
|
||||
*/
|
||||
public static boolean isZero(Temporal startInclusive, Temporal endInclusive) {
|
||||
return Duration.between(startInclusive, endInclusive).isZero();
|
||||
}
|
||||
|
||||
/**
|
||||
* endInclusive 大于或等于 startInclusive
|
||||
*
|
||||
* @param startInclusive Start
|
||||
* @param endInclusive end
|
||||
* @return boolean
|
||||
*/
|
||||
public static boolean isGreaterOrEqual(Temporal startInclusive, Temporal endInclusive) {
|
||||
return Duration.between(startInclusive, endInclusive).toNanos() >= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* endInclusive 大于 startInclusive
|
||||
*
|
||||
* @param startInclusive Start
|
||||
* @param endInclusive end
|
||||
* @return boolean
|
||||
*/
|
||||
public static boolean isGreater(Temporal startInclusive, Temporal endInclusive) {
|
||||
return Duration.between(startInclusive, endInclusive).toNanos() > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* endInclusive 小或等于 startInclusive
|
||||
*
|
||||
* @param startInclusive Start
|
||||
* @param endInclusive end
|
||||
* @return boolean
|
||||
*/
|
||||
public static boolean isLessThanOrEqual(Temporal startInclusive, Temporal endInclusive) {
|
||||
return Duration.between(startInclusive, endInclusive).toNanos() <= 0;
|
||||
}
|
||||
}
|
File diff suppressed because one or more lines are too long
|
@ -37,7 +37,7 @@ spring:
|
|||
multipart:
|
||||
max-file-size: 10240MB
|
||||
max-request-size: 10240MB
|
||||
location: ${java.io.tmpdir}
|
||||
location: \${java.io.tmpdir}
|
||||
management:
|
||||
endpoints:
|
||||
web:
|
||||
|
@ -48,7 +48,10 @@ logging:
|
|||
level:
|
||||
run.halo.app: INFO
|
||||
file:
|
||||
path: ${user.home}/.halo/logs
|
||||
path: \${user.home}/.halo/logs
|
||||
|
||||
halo:
|
||||
download-timeout: 5m
|
||||
download-timeout: 5m
|
||||
|
||||
application:
|
||||
version: ${version}
|
||||
|
|
|
@ -0,0 +1,156 @@
|
|||
package run.halo.app.utils;
|
||||
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import java.time.*;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
/**
|
||||
* DateTimeUtils 测试用例
|
||||
*
|
||||
* @author LeiXinXin
|
||||
* @date 2020/1/9
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
public class DateTimeUtilsTest {
|
||||
/**
|
||||
* 获取上海时区的当前时间
|
||||
*/
|
||||
@Test
|
||||
public void nowTest() {
|
||||
final LocalDateTime now = DateTimeUtils.now().withNano(0);
|
||||
Assert.assertNotNull(now);
|
||||
final LocalDateTime ctt = DateTimeUtils.now(ZoneId.of(ZoneId.SHORT_IDS.get("CTT"))).withNano(0);
|
||||
Assert.assertNotNull(ctt);
|
||||
|
||||
Assert.assertEquals(Duration.between(now, ctt).toMinutes(), 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化日期时间
|
||||
*/
|
||||
@Test
|
||||
public void formatTest() {
|
||||
final LocalDateTime now = LocalDateTime.of(2020, 1, 9, 20, 20, 20);
|
||||
final String formatDate = DateTimeUtils.formatDate(now);
|
||||
Assert.assertEquals(formatDate, "20200109");
|
||||
|
||||
final LocalDate localDate = LocalDate.of(2020, 1, 9);
|
||||
final String localFormatDate = DateTimeUtils.formatDate(localDate);
|
||||
Assert.assertEquals(localFormatDate, "20200109");
|
||||
|
||||
final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd");
|
||||
final String formatDateTime1 = DateTimeUtils.format(now, dateTimeFormatter);
|
||||
Assert.assertEquals(formatDateTime1, "2020/01/09");
|
||||
|
||||
final LocalTime time1 = LocalTime.of(10, 20);
|
||||
final String formatTime = DateTimeUtils.formatTime(time1);
|
||||
Assert.assertEquals(formatTime, "1020");
|
||||
|
||||
final String formatTime1 = DateTimeUtils.format(time1, DateTimeFormatter.ofPattern("HH:mm"));
|
||||
Assert.assertEquals(formatTime1, "10:20");
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加时间
|
||||
*/
|
||||
@Test
|
||||
public void plusTest() {
|
||||
final LocalDateTime now = LocalDateTime.of(2020, 1, 9, 10, 20);
|
||||
final LocalDateTime localDateTime = DateTimeUtils.plusOneMinute(now);
|
||||
Assert.assertEquals(localDateTime.toString(), "2020-01-09T10:21");
|
||||
|
||||
LocalTime localTime = LocalTime.of(7, 30);
|
||||
final LocalDateTime localDateTime1 = DateTimeUtils.plusOneMinute(now, localTime);
|
||||
Assert.assertEquals(localDateTime1.toString(), "2020-01-09T07:31");
|
||||
|
||||
final LocalDate date = LocalDate.of(2020, 1, 3);
|
||||
final LocalDateTime localDateTime2 = DateTimeUtils.plusOneMinute(date, localTime);
|
||||
Assert.assertEquals(localDateTime2.toString(), "2020-01-03T07:31");
|
||||
|
||||
final LocalTime localTime1 = DateTimeUtils.plusOneMinute(localTime);
|
||||
Assert.assertEquals(localTime1.toString(), "07:31");
|
||||
|
||||
final LocalDateTime localDateTime3 = DateTimeUtils.plusDays(now, 10);
|
||||
Assert.assertEquals(localDateTime3.toString(), "2020-01-19T10:20");
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析时间格式为LocalDateTime
|
||||
*/
|
||||
@Test
|
||||
public void parseTest() {
|
||||
String time = "20200109135500000";
|
||||
final LocalDateTime localDateTime = DateTimeUtils.parseCttDateTime(time);
|
||||
Assert.assertEquals(localDateTime.toString(), "2020-01-09T13:55");
|
||||
|
||||
String time2 = "2020/1/9 13:56";
|
||||
final LocalDateTime dateTime = DateTimeUtils.parse(time2, DateTimeFormatter.ofPattern("yyyy/M/d HH:mm"));
|
||||
Assert.assertEquals(dateTime.toString(), "2020-01-09T13:56");
|
||||
}
|
||||
|
||||
/**
|
||||
* 减少日期时间
|
||||
*/
|
||||
@Test
|
||||
public void minusTest() {
|
||||
final LocalDateTime now = LocalDateTime.of(2020, 1, 3, 14, 20);
|
||||
final LocalDateTime localDateTime = DateTimeUtils.minusOneMinutes(now);
|
||||
Assert.assertEquals(localDateTime.toString(), "2020-01-03T14:19");
|
||||
}
|
||||
|
||||
/**
|
||||
* 转为Instant
|
||||
*/
|
||||
@Test
|
||||
public void toInstantTest() {
|
||||
final LocalDateTime now = LocalDateTime.of(2020, 1, 3, 14, 20);
|
||||
|
||||
final Instant instant = DateTimeUtils.toInstant(now);
|
||||
Assert.assertEquals(instant.toString(), "2020-01-03T06:20:00Z");
|
||||
|
||||
final Instant jst = DateTimeUtils.toInstant(now, ZoneId.of(ZoneId.SHORT_IDS.get("JST")));
|
||||
Assert.assertEquals(jst.toString(), "2020-01-03T05:20:00Z");
|
||||
}
|
||||
|
||||
/**
|
||||
* 一些其他的使用方法
|
||||
*/
|
||||
@Test
|
||||
public void other() {
|
||||
LocalDateTime startInclusive = LocalDateTime.of(2020, 1, 3, 10, 10, 30);
|
||||
LocalDateTime endInclusive = LocalDateTime.of(2020, 1, 4, 10, 10, 30);
|
||||
// End 大于等于 Start
|
||||
final boolean greaterOrEqual = DateTimeUtils.isGreaterOrEqual(startInclusive, endInclusive);
|
||||
Assert.assertTrue(greaterOrEqual);
|
||||
|
||||
/*
|
||||
* 小于等于
|
||||
*/
|
||||
final boolean lessThanOrEqual = DateTimeUtils.isLessThanOrEqual(startInclusive, endInclusive);
|
||||
Assert.assertFalse(lessThanOrEqual);
|
||||
|
||||
/*
|
||||
* 两个时间的比较是否为0
|
||||
*/
|
||||
final boolean zero = DateTimeUtils.isZero(startInclusive, endInclusive);
|
||||
Assert.assertFalse(zero);
|
||||
|
||||
// 是否是负数,startInclusive 大于 endInclusive 就是负数
|
||||
final boolean negative = DateTimeUtils.isNegative(startInclusive, endInclusive);
|
||||
Assert.assertFalse(negative);
|
||||
|
||||
// 是否是中午
|
||||
final boolean noon = DateTimeUtils.isNoon(LocalTime.of(12, 0));
|
||||
Assert.assertTrue(noon);
|
||||
|
||||
// 把纳秒和秒设置为0
|
||||
final LocalDateTime localDateTime = LocalDateTime.of(2020, 1, 5, 6, 40, 30, 999);
|
||||
final LocalDateTime time = DateTimeUtils.secondAndNanoSetZero(localDateTime);
|
||||
Assert.assertEquals(time.toString(), "2020-01-05T06:40");
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue