feat(backend): Implement common module foundation
This commit is contained in:
Generated
+113
@@ -0,0 +1,113 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
|
||||||
|
<data-source source="LOCAL" name="video_comment@5.180.253.115" uuid="ab6de11f-1d47-48db-98f6-db1d34209fad">
|
||||||
|
<driver-ref>mysql.8</driver-ref>
|
||||||
|
<synchronize>true</synchronize>
|
||||||
|
<imported>true</imported>
|
||||||
|
<remarks>$PROJECT_DIR$/video-comment/src/main/resources/application.yml</remarks>
|
||||||
|
<jdbc-driver>com.mysql.cj.jdbc.Driver</jdbc-driver>
|
||||||
|
<jdbc-url>jdbc:mysql://5.180.253.115:3306/video_comment?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai</jdbc-url>
|
||||||
|
<working-dir>$ProjectFileDir$</working-dir>
|
||||||
|
</data-source>
|
||||||
|
<data-source source="LOCAL" name="2@5.180.253.115" uuid="05bbbc25-7313-4531-985f-fe54063c5d9e">
|
||||||
|
<driver-ref>redis</driver-ref>
|
||||||
|
<synchronize>true</synchronize>
|
||||||
|
<imported>true</imported>
|
||||||
|
<remarks>$PROJECT_DIR$/video-content/src/main/resources/application.yml</remarks>
|
||||||
|
<jdbc-driver>jdbc.RedisDriver</jdbc-driver>
|
||||||
|
<jdbc-url>jdbc:redis://5.180.253.115:6379/2</jdbc-url>
|
||||||
|
<working-dir>$ProjectFileDir$</working-dir>
|
||||||
|
</data-source>
|
||||||
|
<data-source source="LOCAL" name="video_admin@5.180.253.115" uuid="a3d423c8-ea1b-4a0d-9bc3-e118ee4c0ceb">
|
||||||
|
<driver-ref>mysql.8</driver-ref>
|
||||||
|
<synchronize>true</synchronize>
|
||||||
|
<imported>true</imported>
|
||||||
|
<remarks>$PROJECT_DIR$/video-admin/src/main/resources/application.yml</remarks>
|
||||||
|
<jdbc-driver>com.mysql.cj.jdbc.Driver</jdbc-driver>
|
||||||
|
<jdbc-url>jdbc:mysql://5.180.253.115:3306/video_admin?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai</jdbc-url>
|
||||||
|
<working-dir>$ProjectFileDir$</working-dir>
|
||||||
|
</data-source>
|
||||||
|
<data-source source="LOCAL" name="video_auth@5.180.253.115" uuid="fe7f3e6f-70a9-4c0c-8779-286de6c5b2d3">
|
||||||
|
<driver-ref>mysql.8</driver-ref>
|
||||||
|
<synchronize>true</synchronize>
|
||||||
|
<imported>true</imported>
|
||||||
|
<remarks>$PROJECT_DIR$/video-auth/src/main/resources/application.yml</remarks>
|
||||||
|
<jdbc-driver>com.mysql.cj.jdbc.Driver</jdbc-driver>
|
||||||
|
<jdbc-url>jdbc:mysql://5.180.253.115:3306/video_auth?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai</jdbc-url>
|
||||||
|
<working-dir>$ProjectFileDir$</working-dir>
|
||||||
|
</data-source>
|
||||||
|
<data-source source="LOCAL" name="1@5.180.253.115" uuid="d45b8713-a138-489e-a0d9-0f333db84a6a">
|
||||||
|
<driver-ref>redis</driver-ref>
|
||||||
|
<synchronize>true</synchronize>
|
||||||
|
<imported>true</imported>
|
||||||
|
<remarks>$PROJECT_DIR$/video-user/src/main/resources/application.yml</remarks>
|
||||||
|
<jdbc-driver>jdbc.RedisDriver</jdbc-driver>
|
||||||
|
<jdbc-url>jdbc:redis://5.180.253.115:6379/1</jdbc-url>
|
||||||
|
<working-dir>$ProjectFileDir$</working-dir>
|
||||||
|
</data-source>
|
||||||
|
<data-source source="LOCAL" name="video_recommend@5.180.253.115" uuid="c2525801-37d0-4e55-9cd2-5881e6af6405">
|
||||||
|
<driver-ref>mysql.8</driver-ref>
|
||||||
|
<synchronize>true</synchronize>
|
||||||
|
<imported>true</imported>
|
||||||
|
<remarks>$PROJECT_DIR$/video-recommend/src/main/resources/application.yml</remarks>
|
||||||
|
<jdbc-driver>com.mysql.cj.jdbc.Driver</jdbc-driver>
|
||||||
|
<jdbc-url>jdbc:mysql://5.180.253.115:3306/video_recommend?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai</jdbc-url>
|
||||||
|
<working-dir>$ProjectFileDir$</working-dir>
|
||||||
|
</data-source>
|
||||||
|
<data-source source="LOCAL" name="4@5.180.253.115" uuid="c4c77b8e-dbd0-4bdd-a7a1-05c3556fef02">
|
||||||
|
<driver-ref>redis</driver-ref>
|
||||||
|
<synchronize>true</synchronize>
|
||||||
|
<imported>true</imported>
|
||||||
|
<remarks>$PROJECT_DIR$/video-recommend/src/main/resources/application.yml</remarks>
|
||||||
|
<jdbc-driver>jdbc.RedisDriver</jdbc-driver>
|
||||||
|
<jdbc-url>jdbc:redis://5.180.253.115:6379/4</jdbc-url>
|
||||||
|
<working-dir>$ProjectFileDir$</working-dir>
|
||||||
|
</data-source>
|
||||||
|
<data-source source="LOCAL" name="3@5.180.253.115" uuid="8cbca513-d6c6-4c77-bc57-ddd56f9c020a">
|
||||||
|
<driver-ref>redis</driver-ref>
|
||||||
|
<synchronize>true</synchronize>
|
||||||
|
<imported>true</imported>
|
||||||
|
<remarks>$PROJECT_DIR$/video-comment/src/main/resources/application.yml</remarks>
|
||||||
|
<jdbc-driver>jdbc.RedisDriver</jdbc-driver>
|
||||||
|
<jdbc-url>jdbc:redis://5.180.253.115:6379/3</jdbc-url>
|
||||||
|
<working-dir>$ProjectFileDir$</working-dir>
|
||||||
|
</data-source>
|
||||||
|
<data-source source="LOCAL" name="0@5.180.253.115" uuid="c17bbdd4-f2b6-479d-a3a4-5716f10b4012">
|
||||||
|
<driver-ref>redis</driver-ref>
|
||||||
|
<synchronize>true</synchronize>
|
||||||
|
<imported>true</imported>
|
||||||
|
<remarks>$PROJECT_DIR$/video-auth/src/main/resources/application.yml</remarks>
|
||||||
|
<jdbc-driver>jdbc.RedisDriver</jdbc-driver>
|
||||||
|
<jdbc-url>jdbc:redis://5.180.253.115:6379/0</jdbc-url>
|
||||||
|
<working-dir>$ProjectFileDir$</working-dir>
|
||||||
|
</data-source>
|
||||||
|
<data-source source="LOCAL" name="video_content@5.180.253.115" uuid="ecb2d324-1d03-46e4-a3f2-57fdef5070c9">
|
||||||
|
<driver-ref>mysql.8</driver-ref>
|
||||||
|
<synchronize>true</synchronize>
|
||||||
|
<imported>true</imported>
|
||||||
|
<remarks>$PROJECT_DIR$/video-content/src/main/resources/application.yml</remarks>
|
||||||
|
<jdbc-driver>com.mysql.cj.jdbc.Driver</jdbc-driver>
|
||||||
|
<jdbc-url>jdbc:mysql://5.180.253.115:3306/video_content?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai</jdbc-url>
|
||||||
|
<working-dir>$ProjectFileDir$</working-dir>
|
||||||
|
</data-source>
|
||||||
|
<data-source source="LOCAL" name="video_user@5.180.253.115" uuid="efd6e1ac-36ec-4873-84f6-c5b93ea834e7">
|
||||||
|
<driver-ref>mysql.8</driver-ref>
|
||||||
|
<synchronize>true</synchronize>
|
||||||
|
<imported>true</imported>
|
||||||
|
<remarks>$PROJECT_DIR$/video-user/src/main/resources/application.yml</remarks>
|
||||||
|
<jdbc-driver>com.mysql.cj.jdbc.Driver</jdbc-driver>
|
||||||
|
<jdbc-url>jdbc:mysql://5.180.253.115:3306/video_user?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai</jdbc-url>
|
||||||
|
<working-dir>$ProjectFileDir$</working-dir>
|
||||||
|
</data-source>
|
||||||
|
<data-source source="LOCAL" name="5@5.180.253.115" uuid="2bbd15fc-3050-4cd1-83b9-16febb136ce9">
|
||||||
|
<driver-ref>redis</driver-ref>
|
||||||
|
<synchronize>true</synchronize>
|
||||||
|
<imported>true</imported>
|
||||||
|
<remarks>$PROJECT_DIR$/video-admin/src/main/resources/application.yml</remarks>
|
||||||
|
<jdbc-driver>jdbc.RedisDriver</jdbc-driver>
|
||||||
|
<jdbc-url>jdbc:redis://5.180.253.115:6379/5</jdbc-url>
|
||||||
|
<working-dir>$ProjectFileDir$</working-dir>
|
||||||
|
</data-source>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
Generated
+6
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="MarkdownSettings">
|
||||||
|
<option name="showProblemsInCodeBlocks" value="false" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -87,18 +87,18 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.jsonwebtoken</groupId>
|
<groupId>io.jsonwebtoken</groupId>
|
||||||
<artifactId>jjwt-api</artifactId>
|
<artifactId>jjwt-api</artifactId>
|
||||||
<version>0.12.3</version>
|
<version>0.12.6</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.jsonwebtoken</groupId>
|
<groupId>io.jsonwebtoken</groupId>
|
||||||
<artifactId>jjwt-impl</artifactId>
|
<artifactId>jjwt-impl</artifactId>
|
||||||
<version>0.12.3</version>
|
<version>0.12.6</version>
|
||||||
<scope>runtime</scope>
|
<scope>runtime</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.jsonwebtoken</groupId>
|
<groupId>io.jsonwebtoken</groupId>
|
||||||
<artifactId>jjwt-jackson</artifactId>
|
<artifactId>jjwt-jackson</artifactId>
|
||||||
<version>0.12.3</version>
|
<version>0.12.6</version>
|
||||||
<scope>runtime</scope>
|
<scope>runtime</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
package com.nuaa.video.common;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hello world!
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class App
|
|
||||||
{
|
|
||||||
public static void main( String[] args )
|
|
||||||
{
|
|
||||||
System.out.println( "Hello World!" );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package com.nuaa.video.common.config;
|
||||||
|
|
||||||
|
import feign.RequestInterceptor;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.web.context.request.RequestContextHolder;
|
||||||
|
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||||
|
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Feign配置类
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class FeignConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public RequestInterceptor requestInterceptor() {
|
||||||
|
return requestTemplate -> {
|
||||||
|
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||||
|
if (attributes != null) {
|
||||||
|
HttpServletRequest request = attributes.getRequest();
|
||||||
|
Enumeration<String> headerNames = request.getHeaderNames();
|
||||||
|
if (headerNames != null) {
|
||||||
|
while (headerNames.hasMoreElements()) {
|
||||||
|
String name = headerNames.nextElement();
|
||||||
|
String value = request.getHeader(name);
|
||||||
|
|
||||||
|
// 传递认证信息
|
||||||
|
if ("Authorization".equalsIgnoreCase(name) ||
|
||||||
|
"Content-Type".equalsIgnoreCase(name)) {
|
||||||
|
requestTemplate.header(name, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
package com.nuaa.video.common.config;
|
||||||
|
|
||||||
|
import io.minio.MinioClient;
|
||||||
|
import lombok.Data;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MinIO配置类
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Configuration
|
||||||
|
@ConfigurationProperties(prefix = "minio")
|
||||||
|
public class MinioConfig {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 服务地址
|
||||||
|
*/
|
||||||
|
private String endpoint;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 访问密钥
|
||||||
|
*/
|
||||||
|
private String accessKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 密钥
|
||||||
|
*/
|
||||||
|
private String secretKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 存储桶名称
|
||||||
|
*/
|
||||||
|
private String bucketName;
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public MinioClient minioClient() {
|
||||||
|
return MinioClient.builder()
|
||||||
|
.endpoint(endpoint)
|
||||||
|
.credentials(accessKey, secretKey)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package com.nuaa.video.common.config;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.DbType;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
|
||||||
|
import org.mybatis.spring.annotation.MapperScan;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MyBatis Plus配置类
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@EnableTransactionManagement
|
||||||
|
@MapperScan("com.nuaa.video.**.mapper")
|
||||||
|
public class MybatisPlusConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public MybatisPlusInterceptor mybatisPlusInterceptor() {
|
||||||
|
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
|
||||||
|
|
||||||
|
// 分页插件
|
||||||
|
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
|
||||||
|
|
||||||
|
// 防止全表更新与删除插件
|
||||||
|
interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());
|
||||||
|
|
||||||
|
// 乐观锁插件
|
||||||
|
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
|
||||||
|
|
||||||
|
return interceptor;
|
||||||
|
}
|
||||||
|
}
|
||||||
+45
@@ -0,0 +1,45 @@
|
|||||||
|
package com.nuaa.video.common.config;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
|
||||||
|
import com.nuaa.video.common.constants.CommonConstants;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.ibatis.reflection.MetaObject;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MyBatis Plus元数据处理器
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class MybatisPlusMetaObjectHandler implements MetaObjectHandler {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void insertFill(MetaObject metaObject) {
|
||||||
|
log.debug("自动填充插入字段");
|
||||||
|
|
||||||
|
// 创建时间
|
||||||
|
this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
|
||||||
|
|
||||||
|
// 更新时间
|
||||||
|
this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
|
||||||
|
|
||||||
|
// 创建人
|
||||||
|
this.strictInsertFill(metaObject, "createdBy", String.class, CommonConstants.SYSTEM_USER);
|
||||||
|
|
||||||
|
// 更新人
|
||||||
|
this.strictInsertFill(metaObject, "updatedBy", String.class, CommonConstants.SYSTEM_USER);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateFill(MetaObject metaObject) {
|
||||||
|
log.debug("自动填充更新字段");
|
||||||
|
|
||||||
|
// 更新时间
|
||||||
|
this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
|
||||||
|
|
||||||
|
// 更新人
|
||||||
|
this.strictUpdateFill(metaObject, "updatedBy", String.class, CommonConstants.SYSTEM_USER);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
package com.nuaa.video.common.config;
|
||||||
|
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
|
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
|
||||||
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
|
import org.springframework.cache.annotation.EnableCaching;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||||
|
import org.springframework.data.redis.core.RedisOperations;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
|
||||||
|
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||||
|
import com.fasterxml.jackson.annotation.PropertyAccessor;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Redis配置类
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@EnableCaching
|
||||||
|
@ConditionalOnClass(RedisOperations.class)
|
||||||
|
@EnableConfigurationProperties(RedisProperties.class)
|
||||||
|
public class RedisConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean(name = "redisTemplate")
|
||||||
|
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
|
||||||
|
RedisTemplate<String, Object> template = new RedisTemplate<>();
|
||||||
|
template.setConnectionFactory(redisConnectionFactory);
|
||||||
|
|
||||||
|
// 创建配置好的ObjectMapper
|
||||||
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
|
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
|
||||||
|
mapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
|
||||||
|
|
||||||
|
// 使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值
|
||||||
|
Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(mapper, Object.class);
|
||||||
|
|
||||||
|
// 使用StringRedisSerializer来序列化和反序列化redis的key值
|
||||||
|
template.setKeySerializer(new StringRedisSerializer());
|
||||||
|
template.setValueSerializer(serializer);
|
||||||
|
|
||||||
|
// Hash的key也采用StringRedisSerializer的序列化方式
|
||||||
|
template.setHashKeySerializer(new StringRedisSerializer());
|
||||||
|
template.setHashValueSerializer(serializer);
|
||||||
|
|
||||||
|
template.afterPropertiesSet();
|
||||||
|
return template;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package com.nuaa.video.common.config;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||||
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Web配置类
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class WebConfig implements WebMvcConfigurer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 配置跨域
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void addCorsMappings(CorsRegistry registry) {
|
||||||
|
registry.addMapping("/**")
|
||||||
|
.allowedOriginPatterns("*")
|
||||||
|
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
|
||||||
|
.allowedHeaders("*")
|
||||||
|
.allowCredentials(true)
|
||||||
|
.maxAge(3600);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
package com.nuaa.video.common.constants;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通用常量
|
||||||
|
*/
|
||||||
|
public interface CommonConstants {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 成功标记
|
||||||
|
*/
|
||||||
|
Integer SUCCESS = 200;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 失败标记
|
||||||
|
*/
|
||||||
|
Integer FAIL = 500;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 已删除
|
||||||
|
*/
|
||||||
|
Integer DELETED = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 未删除
|
||||||
|
*/
|
||||||
|
Integer NOT_DELETED = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 正常状态
|
||||||
|
*/
|
||||||
|
Integer STATUS_NORMAL = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 禁用状态
|
||||||
|
*/
|
||||||
|
Integer STATUS_DISABLED = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 锁定状态
|
||||||
|
*/
|
||||||
|
Integer STATUS_LOCKED = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 系统默认用户
|
||||||
|
*/
|
||||||
|
String SYSTEM_USER = "system";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 匿名用户
|
||||||
|
*/
|
||||||
|
String ANONYMOUS_USER = "anonymous";
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
package com.nuaa.video.common.constants;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 安全相关常量
|
||||||
|
*/
|
||||||
|
public interface SecurityConstants {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 认证请求头
|
||||||
|
*/
|
||||||
|
String AUTHORIZATION_HEADER = "Authorization";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 授权token前缀
|
||||||
|
*/
|
||||||
|
String BEARER_PREFIX = "Bearer ";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Basic认证前缀
|
||||||
|
*/
|
||||||
|
String BASIC_PREFIX = "Basic ";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JWT存储权限前缀
|
||||||
|
*/
|
||||||
|
String AUTHORITY_PREFIX = "ROLE_";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JWT存储权限属性
|
||||||
|
*/
|
||||||
|
String JWT_AUTHORITIES_KEY = "authorities";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 刷新token
|
||||||
|
*/
|
||||||
|
String REFRESH_TOKEN = "refresh_token";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 默认登录URL
|
||||||
|
*/
|
||||||
|
String LOGIN_URL = "/auth/login";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证码缓存前缀
|
||||||
|
*/
|
||||||
|
String CAPTCHA_PREFIX = "captcha:";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证码有效期(秒)
|
||||||
|
*/
|
||||||
|
long CAPTCHA_EXPIRATION = 60;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Token过期时间(秒)
|
||||||
|
*/
|
||||||
|
long TOKEN_EXPIRATION = 86400;
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package com.nuaa.video.common.exception;
|
||||||
|
|
||||||
|
import com.nuaa.video.common.model.enums.ResultCode;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 业务异常类
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
public class BusinessException extends RuntimeException {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 错误码
|
||||||
|
*/
|
||||||
|
private final Integer code;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 错误消息
|
||||||
|
*/
|
||||||
|
private final String message;
|
||||||
|
|
||||||
|
public BusinessException(String message) {
|
||||||
|
this.code = ResultCode.ERROR.getCode();
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BusinessException(Integer code, String message) {
|
||||||
|
this.code = code;
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BusinessException(ResultCode resultCode) {
|
||||||
|
this.code = resultCode.getCode();
|
||||||
|
this.message = resultCode.getMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
public BusinessException(ResultCode resultCode, String message) {
|
||||||
|
this.code = resultCode.getCode();
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
}
|
||||||
+79
@@ -0,0 +1,79 @@
|
|||||||
|
package com.nuaa.video.common.exception;
|
||||||
|
|
||||||
|
import com.nuaa.video.common.model.vo.Result;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.validation.BindException;
|
||||||
|
import org.springframework.validation.FieldError;
|
||||||
|
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||||
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
|
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||||
|
|
||||||
|
import jakarta.validation.ConstraintViolation;
|
||||||
|
import jakarta.validation.ConstraintViolationException;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 全局异常处理器
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@RestControllerAdvice
|
||||||
|
public class GlobalExceptionHandler {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理业务异常
|
||||||
|
*/
|
||||||
|
@ExceptionHandler(BusinessException.class)
|
||||||
|
public Result<Void> handleBusinessException(BusinessException e) {
|
||||||
|
log.error("业务异常:{}", e.getMessage());
|
||||||
|
return Result.error(e.getCode(), e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理参数校验异常 (JSR303)
|
||||||
|
*/
|
||||||
|
@ExceptionHandler(ConstraintViolationException.class)
|
||||||
|
public Result<Void> handleConstraintViolationException(ConstraintViolationException e) {
|
||||||
|
Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
|
||||||
|
String message = violations.stream()
|
||||||
|
.map(ConstraintViolation::getMessage)
|
||||||
|
.collect(Collectors.joining(", "));
|
||||||
|
log.warn("参数校验异常:{}", message);
|
||||||
|
return Result.error(400, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理方法参数校验异常
|
||||||
|
*/
|
||||||
|
@ExceptionHandler(MethodArgumentNotValidException.class)
|
||||||
|
public Result<Void> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
|
||||||
|
List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
|
||||||
|
String message = fieldErrors.stream()
|
||||||
|
.map(FieldError::getDefaultMessage)
|
||||||
|
.collect(Collectors.joining(", "));
|
||||||
|
log.warn("方法参数校验异常:{}", message);
|
||||||
|
return Result.error(400, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理绑定异常
|
||||||
|
*/
|
||||||
|
@ExceptionHandler(BindException.class)
|
||||||
|
public Result<Void> handleBindException(BindException e) {
|
||||||
|
String message = e.getBindingResult().getAllErrors().stream()
|
||||||
|
.map(error -> error.getDefaultMessage())
|
||||||
|
.collect(Collectors.joining(", "));
|
||||||
|
log.warn("参数绑定异常:{}", message);
|
||||||
|
return Result.error(400, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理未知异常
|
||||||
|
*/
|
||||||
|
@ExceptionHandler(Exception.class)
|
||||||
|
public Result<Void> handleException(Exception e) {
|
||||||
|
log.error("系统异常:", e);
|
||||||
|
return Result.error("系统繁忙,请稍后再试");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package com.nuaa.video.common.model.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
import jakarta.validation.constraints.Max;
|
||||||
|
import jakarta.validation.constraints.Min;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页请求DTO
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Accessors(chain = true)
|
||||||
|
public class PageRequestDTO implements Serializable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前页码
|
||||||
|
*/
|
||||||
|
@NotNull(message = "页码不能为空")
|
||||||
|
@Min(value = 1, message = "页码最小值为1")
|
||||||
|
private Integer current = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 每页记录数
|
||||||
|
*/
|
||||||
|
@NotNull(message = "每页记录数不能为空")
|
||||||
|
@Min(value = 1, message = "每页记录数最小值为1")
|
||||||
|
@Max(value = 100, message = "每页记录数最大值为100")
|
||||||
|
private Integer size = 10;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 排序字段
|
||||||
|
*/
|
||||||
|
private String orderField;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 排序方式(asc/desc)
|
||||||
|
*/
|
||||||
|
private String orderType;
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
package com.nuaa.video.common.model.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.FieldFill;
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 基础实体类
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class BaseEntity implements Serializable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主键ID
|
||||||
|
*/
|
||||||
|
@TableId(type = IdType.AUTO)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建人
|
||||||
|
*/
|
||||||
|
@TableField(fill = FieldFill.INSERT)
|
||||||
|
private String createdBy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新人
|
||||||
|
*/
|
||||||
|
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||||
|
private String updatedBy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建时间
|
||||||
|
*/
|
||||||
|
@TableField(fill = FieldFill.INSERT)
|
||||||
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新时间
|
||||||
|
*/
|
||||||
|
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||||
|
private LocalDateTime updateTime;
|
||||||
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
package com.nuaa.video.common.model.enums;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 响应状态码枚举
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
public enum ResultCode {
|
||||||
|
/**
|
||||||
|
* 成功
|
||||||
|
*/
|
||||||
|
SUCCESS(200, "操作成功"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 参数错误
|
||||||
|
*/
|
||||||
|
PARAM_ERROR(400, "参数错误"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 未授权
|
||||||
|
*/
|
||||||
|
UNAUTHORIZED(401, "未授权"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 禁止访问
|
||||||
|
*/
|
||||||
|
FORBIDDEN(403, "禁止访问"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 资源不存在
|
||||||
|
*/
|
||||||
|
NOT_FOUND(404, "资源不存在"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 服务器内部错误
|
||||||
|
*/
|
||||||
|
ERROR(500, "服务器内部错误"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 服务不可用
|
||||||
|
*/
|
||||||
|
SERVICE_UNAVAILABLE(503, "服务不可用"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户不存在
|
||||||
|
*/
|
||||||
|
USER_NOT_FOUND(1001, "用户不存在"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户已存在
|
||||||
|
*/
|
||||||
|
USER_ALREADY_EXISTS(1002, "用户已存在"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 密码错误
|
||||||
|
*/
|
||||||
|
PASSWORD_ERROR(1003, "密码错误"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 视频不存在
|
||||||
|
*/
|
||||||
|
VIDEO_NOT_FOUND(2001, "视频不存在"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 视频上传失败
|
||||||
|
*/
|
||||||
|
VIDEO_UPLOAD_FAILED(2002, "视频上传失败"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 评论不存在
|
||||||
|
*/
|
||||||
|
COMMENT_NOT_FOUND(3001, "评论不存在");
|
||||||
|
|
||||||
|
private final Integer code;
|
||||||
|
private final String message;
|
||||||
|
|
||||||
|
ResultCode(Integer code, String message) {
|
||||||
|
this.code = code;
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
package com.nuaa.video.common.model.vo;
|
||||||
|
|
||||||
|
import com.nuaa.video.common.model.enums.ResultCode;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 统一响应结果类
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class Result<T> implements Serializable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态码
|
||||||
|
*/
|
||||||
|
private Integer code;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回消息
|
||||||
|
*/
|
||||||
|
private String message;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回数据
|
||||||
|
*/
|
||||||
|
private T data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 成功结果
|
||||||
|
*/
|
||||||
|
public static <T> Result<T> success() {
|
||||||
|
return new Result<>(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMessage(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 成功结果(带数据)
|
||||||
|
*/
|
||||||
|
public static <T> Result<T> success(T data) {
|
||||||
|
return new Result<>(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMessage(), data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 成功结果(自定义消息和数据)
|
||||||
|
*/
|
||||||
|
public static <T> Result<T> success(String message, T data) {
|
||||||
|
return new Result<>(ResultCode.SUCCESS.getCode(), message, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 失败结果
|
||||||
|
*/
|
||||||
|
public static <T> Result<T> error() {
|
||||||
|
return new Result<>(ResultCode.ERROR.getCode(), ResultCode.ERROR.getMessage(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 失败结果(自定义消息)
|
||||||
|
*/
|
||||||
|
public static <T> Result<T> error(String message) {
|
||||||
|
return new Result<>(ResultCode.ERROR.getCode(), message, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 失败结果(自定义状态码和消息)
|
||||||
|
*/
|
||||||
|
public static <T> Result<T> error(Integer code, String message) {
|
||||||
|
return new Result<>(code, message, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义结果
|
||||||
|
*/
|
||||||
|
public static <T> Result<T> result(ResultCode resultCode, T data) {
|
||||||
|
return new Result<>(resultCode.getCode(), resultCode.getMessage(), data);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
package com.nuaa.video.common.utils;
|
||||||
|
|
||||||
|
import java.time.*;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日期工具类
|
||||||
|
*/
|
||||||
|
public class DateUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日期格式化
|
||||||
|
*/
|
||||||
|
public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
|
||||||
|
public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
|
||||||
|
public static final String SIMPLE_DATE_FORMAT = "yyyyMMdd";
|
||||||
|
public static final String SIMPLE_DATE_TIME_FORMAT = "yyyyMMddHHmmss";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日期对象格式化
|
||||||
|
*/
|
||||||
|
public static String format(LocalDateTime localDateTime, String pattern) {
|
||||||
|
if (localDateTime == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
|
||||||
|
return formatter.format(localDateTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日期对象格式化(默认格式)
|
||||||
|
*/
|
||||||
|
public static String format(LocalDateTime localDateTime) {
|
||||||
|
return format(localDateTime, DEFAULT_DATE_TIME_FORMAT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字符串转日期
|
||||||
|
*/
|
||||||
|
public static LocalDateTime parse(String dateTimeStr, String pattern) {
|
||||||
|
if (StringUtils.isEmpty(dateTimeStr)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
|
||||||
|
return LocalDateTime.parse(dateTimeStr, formatter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字符串转日期(默认格式)
|
||||||
|
*/
|
||||||
|
public static LocalDateTime parse(String dateTimeStr) {
|
||||||
|
return parse(dateTimeStr, DEFAULT_DATE_TIME_FORMAT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LocalDateTime转Date
|
||||||
|
*/
|
||||||
|
public static Date toDate(LocalDateTime localDateTime) {
|
||||||
|
if (localDateTime == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
ZoneId zoneId = ZoneId.systemDefault();
|
||||||
|
return Date.from(localDateTime.atZone(zoneId).toInstant());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date转LocalDateTime
|
||||||
|
*/
|
||||||
|
public static LocalDateTime toLocalDateTime(Date date) {
|
||||||
|
if (date == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
ZoneId zoneId = ZoneId.systemDefault();
|
||||||
|
return date.toInstant().atZone(zoneId).toLocalDateTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前日期时间
|
||||||
|
*/
|
||||||
|
public static LocalDateTime now() {
|
||||||
|
return LocalDateTime.now();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算两个日期之间的天数
|
||||||
|
*/
|
||||||
|
public static long daysBetween(LocalDateTime start, LocalDateTime end) {
|
||||||
|
if (start == null || end == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return ChronoUnit.DAYS.between(start, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算两个日期之间的小时数
|
||||||
|
*/
|
||||||
|
public static long hoursBetween(LocalDateTime start, LocalDateTime end) {
|
||||||
|
if (start == null || end == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return ChronoUnit.HOURS.between(start, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算两个日期之间的分钟数
|
||||||
|
*/
|
||||||
|
public static long minutesBetween(LocalDateTime start, LocalDateTime end) {
|
||||||
|
if (start == null || end == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return ChronoUnit.MINUTES.between(start, end);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,123 @@
|
|||||||
|
package com.nuaa.video.common.utils;
|
||||||
|
|
||||||
|
import io.jsonwebtoken.Claims;
|
||||||
|
import io.jsonwebtoken.Jwts;
|
||||||
|
import io.jsonwebtoken.security.Keys;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.crypto.SecretKey;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JWT工具类
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class JwtUtils {
|
||||||
|
|
||||||
|
@Value("${jwt.secret:video-platform-secret-key-2024-nuaa}")
|
||||||
|
private String secret;
|
||||||
|
|
||||||
|
@Value("${jwt.expiration:86400}")
|
||||||
|
private long expiration;
|
||||||
|
|
||||||
|
@Value("${jwt.token-header:Authorization}")
|
||||||
|
private String tokenHeader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据用户ID生成JWT
|
||||||
|
*/
|
||||||
|
public String generateToken(Long userId, String username) {
|
||||||
|
Map<String, Object> claims = new HashMap<>();
|
||||||
|
claims.put("userId", userId);
|
||||||
|
claims.put("username", username);
|
||||||
|
return createToken(claims, userId.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从JWT中获取用户ID
|
||||||
|
*/
|
||||||
|
public Long getUserIdFromToken(String token) {
|
||||||
|
return Long.valueOf(getClaimFromToken(token, Claims::getSubject));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断JWT是否过期
|
||||||
|
*/
|
||||||
|
public boolean isTokenExpired(String token) {
|
||||||
|
final Date expiration = getExpirationDateFromToken(token);
|
||||||
|
return expiration.before(new Date());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证JWT
|
||||||
|
*/
|
||||||
|
public boolean validateToken(String token, String username) {
|
||||||
|
try {
|
||||||
|
final String tokenUsername = getUsernameFromToken(token);
|
||||||
|
return (tokenUsername.equals(username) && !isTokenExpired(token));
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("JWT验证失败:", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从JWT中获取用户名
|
||||||
|
*/
|
||||||
|
public String getUsernameFromToken(String token) {
|
||||||
|
return getClaimFromToken(token, claims -> claims.get("username", String.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取JWT过期时间
|
||||||
|
*/
|
||||||
|
public Date getExpirationDateFromToken(String token) {
|
||||||
|
return getClaimFromToken(token, Claims::getExpiration);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从JWT中获取指定声明
|
||||||
|
*/
|
||||||
|
public <T> T getClaimFromToken(String token, Function<Claims, T> claimsResolver) {
|
||||||
|
final Claims claims = getAllClaimsFromToken(token);
|
||||||
|
return claimsResolver.apply(claims);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从JWT中获取所有声明
|
||||||
|
*/
|
||||||
|
private Claims getAllClaimsFromToken(String token) {
|
||||||
|
return Jwts.parser()
|
||||||
|
.verifyWith(getSigningKey())
|
||||||
|
.build()
|
||||||
|
.parseSignedClaims(token)
|
||||||
|
.getPayload();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建JWT
|
||||||
|
*/
|
||||||
|
private String createToken(Map<String, Object> claims, String subject) {
|
||||||
|
return Jwts.builder()
|
||||||
|
.claims(claims)
|
||||||
|
.subject(subject)
|
||||||
|
.issuedAt(new Date(System.currentTimeMillis()))
|
||||||
|
.expiration(new Date(System.currentTimeMillis() + expiration * 1000))
|
||||||
|
.signWith(getSigningKey())
|
||||||
|
.compact();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取签名密钥 - 适配JJWT 0.12.3
|
||||||
|
*/
|
||||||
|
private SecretKey getSigningKey() {
|
||||||
|
byte[] keyBytes = secret.getBytes();
|
||||||
|
return Keys.hmacShaKeyFor(keyBytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,227 @@
|
|||||||
|
// com.nuaa.video.common.utils.MinioUtils.java
|
||||||
|
package com.nuaa.video.common.utils;
|
||||||
|
|
||||||
|
import io.minio.*;
|
||||||
|
import io.minio.http.Method;
|
||||||
|
import io.minio.messages.Bucket;
|
||||||
|
import io.minio.messages.Item;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MinIO工具类
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class MinioUtils {
|
||||||
|
|
||||||
|
private final MinioClient minioClient;
|
||||||
|
|
||||||
|
@Value("${minio.bucketName:video-platform}")
|
||||||
|
private String bucketName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查存储桶是否存在
|
||||||
|
*/
|
||||||
|
public boolean bucketExists(String bucketName) {
|
||||||
|
try {
|
||||||
|
return minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("检查存储桶是否存在失败:", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建存储桶
|
||||||
|
*/
|
||||||
|
public void createBucket(String bucketName) {
|
||||||
|
try {
|
||||||
|
boolean exists = bucketExists(bucketName);
|
||||||
|
if (!exists) {
|
||||||
|
minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("创建存储桶失败:", e);
|
||||||
|
throw new RuntimeException("创建存储桶失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 列出所有存储桶
|
||||||
|
*/
|
||||||
|
public List<Bucket> listBuckets() {
|
||||||
|
try {
|
||||||
|
return minioClient.listBuckets();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("列出所有存储桶失败:", e);
|
||||||
|
throw new RuntimeException("列出所有存储桶失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 列出存储桶中的所有对象
|
||||||
|
*/
|
||||||
|
public Iterable<Result<Item>> listObjects(String bucketName) {
|
||||||
|
return minioClient.listObjects(ListObjectsArgs.builder().bucket(bucketName).recursive(true).build());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上传文件
|
||||||
|
*/
|
||||||
|
public String uploadFile(MultipartFile file, String fileType) {
|
||||||
|
try {
|
||||||
|
// 检查存储桶是否存在
|
||||||
|
createBucket(bucketName);
|
||||||
|
|
||||||
|
// 生成文件名
|
||||||
|
String fileName = System.currentTimeMillis() + "_" + file.getOriginalFilename();
|
||||||
|
String objectName = fileType + "/" + fileName;
|
||||||
|
|
||||||
|
// 上传文件
|
||||||
|
minioClient.putObject(
|
||||||
|
PutObjectArgs.builder()
|
||||||
|
.bucket(bucketName)
|
||||||
|
.object(objectName)
|
||||||
|
.stream(file.getInputStream(), file.getSize(), -1)
|
||||||
|
.contentType(file.getContentType())
|
||||||
|
.build()
|
||||||
|
);
|
||||||
|
|
||||||
|
return objectName;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("上传文件失败:", e);
|
||||||
|
throw new RuntimeException("上传文件失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上传视频文件
|
||||||
|
*/
|
||||||
|
public String uploadVideo(MultipartFile file) {
|
||||||
|
return uploadFile(file, "videos");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上传图片文件
|
||||||
|
*/
|
||||||
|
public String uploadImage(MultipartFile file) {
|
||||||
|
return uploadFile(file, "images");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上传字节数组
|
||||||
|
*/
|
||||||
|
public String uploadBytes(byte[] bytes, String fileName, String contentType, String fileType) {
|
||||||
|
try {
|
||||||
|
// 检查存储桶是否存在
|
||||||
|
createBucket(bucketName);
|
||||||
|
|
||||||
|
// 生成文件名
|
||||||
|
String objectName = fileType + "/" + System.currentTimeMillis() + "_" + fileName;
|
||||||
|
|
||||||
|
// 上传字节数组
|
||||||
|
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
|
||||||
|
minioClient.putObject(
|
||||||
|
PutObjectArgs.builder()
|
||||||
|
.bucket(bucketName)
|
||||||
|
.object(objectName)
|
||||||
|
.stream(bais, bytes.length, -1)
|
||||||
|
.contentType(contentType)
|
||||||
|
.build()
|
||||||
|
);
|
||||||
|
|
||||||
|
return objectName;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("上传字节数组失败:", e);
|
||||||
|
throw new RuntimeException("上传字节数组失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取文件
|
||||||
|
*/
|
||||||
|
public InputStream getObject(String objectName) {
|
||||||
|
try {
|
||||||
|
return minioClient.getObject(
|
||||||
|
GetObjectArgs.builder()
|
||||||
|
.bucket(bucketName)
|
||||||
|
.object(objectName)
|
||||||
|
.build()
|
||||||
|
);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("获取文件失败:", e);
|
||||||
|
throw new RuntimeException("获取文件失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除文件
|
||||||
|
*/
|
||||||
|
public void removeObject(String objectName) {
|
||||||
|
try {
|
||||||
|
minioClient.removeObject(
|
||||||
|
RemoveObjectArgs.builder()
|
||||||
|
.bucket(bucketName)
|
||||||
|
.object(objectName)
|
||||||
|
.build()
|
||||||
|
);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("删除文件失败:", e);
|
||||||
|
throw new RuntimeException("删除文件失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取文件外链
|
||||||
|
*/
|
||||||
|
public String getPreSignedUrl(String objectName, int expiry) {
|
||||||
|
try {
|
||||||
|
return minioClient.getPresignedObjectUrl(
|
||||||
|
GetPresignedObjectUrlArgs.builder()
|
||||||
|
.bucket(bucketName)
|
||||||
|
.object(objectName)
|
||||||
|
.method(Method.GET)
|
||||||
|
.expiry(expiry, TimeUnit.SECONDS)
|
||||||
|
.build()
|
||||||
|
);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("获取文件外链失败:", e);
|
||||||
|
throw new RuntimeException("获取文件外链失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取文件外链(使用默认过期时间7天)
|
||||||
|
*/
|
||||||
|
public String getPreSignedUrl(String objectName) {
|
||||||
|
return getPreSignedUrl(objectName, 7 * 24 * 60 * 60);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取文件基础URL
|
||||||
|
*/
|
||||||
|
public String getBaseUrl(String objectName) {
|
||||||
|
try {
|
||||||
|
return minioClient.getPresignedObjectUrl(
|
||||||
|
GetPresignedObjectUrlArgs.builder()
|
||||||
|
.bucket(bucketName)
|
||||||
|
.object(objectName)
|
||||||
|
.method(Method.GET)
|
||||||
|
.build()
|
||||||
|
).split("\\?")[0];
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("获取文件基础URL失败:", e);
|
||||||
|
throw new RuntimeException("获取文件基础URL失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
package com.nuaa.video.common.utils;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页工具类
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class PageUtils<T> implements Serializable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 总记录数
|
||||||
|
*/
|
||||||
|
private long total;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 每页记录数
|
||||||
|
*/
|
||||||
|
private long size;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前页数
|
||||||
|
*/
|
||||||
|
private long current;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 总页数
|
||||||
|
*/
|
||||||
|
private long pages;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 列表数据
|
||||||
|
*/
|
||||||
|
private List<T> records;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否有前一页
|
||||||
|
*/
|
||||||
|
private boolean hasPrevious;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否有下一页
|
||||||
|
*/
|
||||||
|
private boolean hasNext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造方法
|
||||||
|
*/
|
||||||
|
public PageUtils(IPage<T> page) {
|
||||||
|
this.total = page.getTotal();
|
||||||
|
this.size = page.getSize();
|
||||||
|
this.current = page.getCurrent();
|
||||||
|
this.pages = page.getPages();
|
||||||
|
this.records = page.getRecords();
|
||||||
|
this.hasPrevious = current > 1;
|
||||||
|
this.hasNext = current < pages;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,277 @@
|
|||||||
|
package com.nuaa.video.common.utils;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Redis工具类
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@ConditionalOnBean(RedisTemplate.class)
|
||||||
|
public class RedisUtils {
|
||||||
|
|
||||||
|
private final RedisTemplate<String, Object> redisTemplate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置缓存过期时间
|
||||||
|
*/
|
||||||
|
public boolean expire(String key, long time) {
|
||||||
|
try {
|
||||||
|
if (time > 0) {
|
||||||
|
redisTemplate.expire(key, time, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Redis设置过期时间失败:", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取缓存过期时间
|
||||||
|
*/
|
||||||
|
public long getExpire(String key) {
|
||||||
|
return redisTemplate.getExpire(key, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断key是否存在
|
||||||
|
*/
|
||||||
|
public boolean hasKey(String key) {
|
||||||
|
try {
|
||||||
|
return Boolean.TRUE.equals(redisTemplate.hasKey(key));
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Redis判断key是否存在失败:", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除缓存
|
||||||
|
*/
|
||||||
|
public void del(String... key) {
|
||||||
|
if (key != null && key.length > 0) {
|
||||||
|
if (key.length == 1) {
|
||||||
|
redisTemplate.delete(key[0]);
|
||||||
|
} else {
|
||||||
|
redisTemplate.delete((Collection<String>) List.of(key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取普通缓存
|
||||||
|
*/
|
||||||
|
public Object get(String key) {
|
||||||
|
return key == null ? null : redisTemplate.opsForValue().get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置普通缓存
|
||||||
|
*/
|
||||||
|
public boolean set(String key, Object value) {
|
||||||
|
try {
|
||||||
|
redisTemplate.opsForValue().set(key, value);
|
||||||
|
return true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Redis设置缓存失败:", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置普通缓存并设置过期时间
|
||||||
|
*/
|
||||||
|
public boolean set(String key, Object value, long time) {
|
||||||
|
try {
|
||||||
|
if (time > 0) {
|
||||||
|
redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
|
||||||
|
} else {
|
||||||
|
set(key, value);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Redis设置缓存并设置过期时间失败:", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 递增
|
||||||
|
*/
|
||||||
|
public long incr(String key, long delta) {
|
||||||
|
if (delta < 0) {
|
||||||
|
throw new RuntimeException("递增因子必须大于0");
|
||||||
|
}
|
||||||
|
return redisTemplate.opsForValue().increment(key, delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 递减
|
||||||
|
*/
|
||||||
|
public long decr(String key, long delta) {
|
||||||
|
if (delta < 0) {
|
||||||
|
throw new RuntimeException("递减因子必须大于0");
|
||||||
|
}
|
||||||
|
return redisTemplate.opsForValue().decrement(key, delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取Hash结构数据
|
||||||
|
*/
|
||||||
|
public Object hget(String key, String item) {
|
||||||
|
return redisTemplate.opsForHash().get(key, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取Hash结构中的所有键值
|
||||||
|
*/
|
||||||
|
public Map<Object, Object> hmget(String key) {
|
||||||
|
return redisTemplate.opsForHash().entries(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置Hash结构数据
|
||||||
|
*/
|
||||||
|
public boolean hmset(String key, Map<String, Object> map) {
|
||||||
|
try {
|
||||||
|
redisTemplate.opsForHash().putAll(key, map);
|
||||||
|
return true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Redis设置Hash结构数据失败:", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置Hash结构数据并设置过期时间
|
||||||
|
*/
|
||||||
|
public boolean hmset(String key, Map<String, Object> map, long time) {
|
||||||
|
try {
|
||||||
|
redisTemplate.opsForHash().putAll(key, map);
|
||||||
|
if (time > 0) {
|
||||||
|
expire(key, time);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Redis设置Hash结构数据并设置过期时间失败:", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 向Hash结构中放入一个数据项
|
||||||
|
*/
|
||||||
|
public boolean hset(String key, String item, Object value) {
|
||||||
|
try {
|
||||||
|
redisTemplate.opsForHash().put(key, item, value);
|
||||||
|
return true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Redis向Hash结构中放入一个数据项失败:", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 向Hash结构中放入一个数据项并设置过期时间
|
||||||
|
*/
|
||||||
|
public boolean hset(String key, String item, Object value, long time) {
|
||||||
|
try {
|
||||||
|
redisTemplate.opsForHash().put(key, item, value);
|
||||||
|
if (time > 0) {
|
||||||
|
expire(key, time);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Redis向Hash结构中放入一个数据项并设置过期时间失败:", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除Hash结构中的值
|
||||||
|
*/
|
||||||
|
public void hdel(String key, Object... item) {
|
||||||
|
redisTemplate.opsForHash().delete(key, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断Hash结构中是否有该项的值
|
||||||
|
*/
|
||||||
|
public boolean hHasKey(String key, String item) {
|
||||||
|
return redisTemplate.opsForHash().hasKey(key, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hash结构中递增
|
||||||
|
*/
|
||||||
|
public double hincr(String key, String item, double by) {
|
||||||
|
return redisTemplate.opsForHash().increment(key, item, by);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hash结构中递减
|
||||||
|
*/
|
||||||
|
public double hdecr(String key, String item, double by) {
|
||||||
|
return redisTemplate.opsForHash().increment(key, item, -by);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取Set结构数据
|
||||||
|
*/
|
||||||
|
public Set<Object> sGet(String key) {
|
||||||
|
try {
|
||||||
|
return redisTemplate.opsForSet().members(key);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Redis获取Set结构数据失败:", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 向Set结构中添加值
|
||||||
|
*/
|
||||||
|
public long sSet(String key, Object... values) {
|
||||||
|
try {
|
||||||
|
return redisTemplate.opsForSet().add(key, values);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Redis向Set结构中添加值失败:", e);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取List结构数据
|
||||||
|
*/
|
||||||
|
public List<Object> lGet(String key, long start, long end) {
|
||||||
|
try {
|
||||||
|
return redisTemplate.opsForList().range(key, start, end);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Redis获取List结构数据失败:", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 向List结构中添加值
|
||||||
|
*/
|
||||||
|
public long lSet(String key, Object value) {
|
||||||
|
try {
|
||||||
|
return redisTemplate.opsForList().rightPush(key, value);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Redis向List结构中添加值失败:", e);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
package com.nuaa.video.common.utils;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字符串工具类
|
||||||
|
*/
|
||||||
|
public class StringUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断字符串是否为空
|
||||||
|
*/
|
||||||
|
public static boolean isEmpty(String str) {
|
||||||
|
return str == null || str.trim().length() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断字符串是否不为空
|
||||||
|
*/
|
||||||
|
public static boolean isNotEmpty(String str) {
|
||||||
|
return !isEmpty(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成UUID
|
||||||
|
*/
|
||||||
|
public static String generateUUID() {
|
||||||
|
return UUID.randomUUID().toString().replaceAll("-", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成固定长度的随机字符串
|
||||||
|
*/
|
||||||
|
public static String randomString(int length) {
|
||||||
|
String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
int number = (int) (Math.random() * str.length());
|
||||||
|
sb.append(str.charAt(number));
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 驼峰转下划线
|
||||||
|
*/
|
||||||
|
public static String camelToUnderscore(String str) {
|
||||||
|
if (isEmpty(str)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (int i = 0; i < str.length(); i++) {
|
||||||
|
char c = str.charAt(i);
|
||||||
|
if (Character.isUpperCase(c)) {
|
||||||
|
sb.append("_").append(Character.toLowerCase(c));
|
||||||
|
} else {
|
||||||
|
sb.append(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下划线转驼峰
|
||||||
|
*/
|
||||||
|
public static String underscoreToCamel(String str) {
|
||||||
|
if (isEmpty(str)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
boolean underscoreFlag = false;
|
||||||
|
for (int i = 0; i < str.length(); i++) {
|
||||||
|
char c = str.charAt(i);
|
||||||
|
if (c == '_') {
|
||||||
|
underscoreFlag = true;
|
||||||
|
} else {
|
||||||
|
if (underscoreFlag) {
|
||||||
|
sb.append(Character.toUpperCase(c));
|
||||||
|
underscoreFlag = false;
|
||||||
|
} else {
|
||||||
|
sb.append(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
# src/main/resources/META-INF/spring.factories
|
||||||
|
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||||
|
com.nuaa.video.common.config.RedisConfig,\
|
||||||
|
com.nuaa.video.common.config.MybatisPlusConfig,\
|
||||||
|
com.nuaa.video.common.config.MinioConfig,\
|
||||||
|
com.nuaa.video.common.config.WebConfig,\
|
||||||
|
com.nuaa.video.common.config.FeignConfig,\
|
||||||
|
com.nuaa.video.common.config.MybatisPlusMetaObjectHandler,\
|
||||||
|
com.nuaa.video.common.exception.GlobalExceptionHandler
|
||||||
Reference in New Issue
Block a user