提交 dbedcb47 作者: 方治民

合并分支 '3.x' 到 'dev'

3.x

查看合并请求 !29
......@@ -10,7 +10,7 @@ VOLUME /data
VOLUME /logs
# 复制上下文目录下的 build/libs/app.jar 到容器里
COPY app/build/libs/app-0.0.1-SNAPSHOT.jar app.jar
COPY app/build/libs/app-*-SNAPSHOT.jar app.jar
# bash方式执行,使 app.jar 可访问
# RUN新建立一层,在其上执行这些命令,执行结束后, commit 这一层的修改,构成新的镜像。
......
......@@ -37,11 +37,9 @@ dependencies {
// Optional: Doc
implementation project(":basic-common:doc")
implementation "com.github.xiaoymin:knife4j-openapi3-jakarta-spring-boot-starter:${knife4jOpen3Version}"
// Optional: Auth
implementation project(":basic-auth")
implementation "cn.dev33:sa-token-spring-boot3-starter:${saTokenVersion}"
// Optional: Dict - 数据字典
implementation project(":basic-dict")
......@@ -51,14 +49,13 @@ dependencies {
// Optional: Minio S3
implementation project(":basic-common:minio")
// FIX: minio dep
implementation "io.minio:minio:${minioVersion}"
implementation "com.squareup.okhttp3:okhttp:${okhttpVersion}"
// Optional: 扩展实现在文件上传时对文件进行预处理,依赖 Minio 模块
// https://mvnrepository.com/artifact/org.apache.pdfbox/pdfbox
implementation "org.apache.pdfbox:pdfbox:${pdfboxVersion}"
// https://mvnrepository.com/artifact/net.bramp.ffmpeg/ffmpeg
implementation "net.bramp.ffmpeg:ffmpeg:${ffmpegWrapperVersion}"
// https://mvnrepository.com/artifact/org.apache.pdfbox/pdfbox
implementation("org.apache.pdfbox:pdfbox:${pdfboxVersion}") {
exclude group: 'commons-logging', module: 'commons-logging'
}
// fastjson
implementation "com.alibaba.fastjson2:fastjson2:${fastJsonVersion}"
......@@ -68,5 +65,5 @@ dependencies {
implementation "cn.hutool:hutool-extra:${hutoolVersion}"
// https://github.com/vladmihalcea/hypersistence-utils
implementation "io.hypersistence:hypersistence-utils-hibernate-60:${hibernateTypesVersion}"
implementation "io.hypersistence:hypersistence-utils-hibernate-63:${hibernateTypesVersion}"
}
......@@ -28,6 +28,8 @@ import net.bramp.ffmpeg.FFprobe;
import net.bramp.ffmpeg.builder.FFmpegBuilder;
import net.bramp.ffmpeg.probe.FFmpegFormat;
import net.bramp.ffmpeg.probe.FFmpegProbeResult;
import org.apache.pdfbox.Loader;
import org.apache.pdfbox.io.IOUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.springframework.context.annotation.Primary;
......@@ -86,7 +88,7 @@ public class UploadProcessServiceImpl implements UploadProcessService {
@Cleanup
InputStream is = file.getInputStream();
@Cleanup
PDDocument doc = PDDocument.load(is);
PDDocument doc = Loader.loadPDF(IOUtils.toByteArray(is));
int pages = doc.getNumberOfPages();
// 构建具有 PDF 页数标记的存储地址
......
......@@ -11,6 +11,7 @@ import com.yiring.app.vo.user.UserExtensionVo;
import com.yiring.auth.domain.user.User;
import com.yiring.auth.util.Auths;
import com.yiring.common.annotation.DownloadResponse;
import com.yiring.common.annotation.RateLimiter;
import com.yiring.common.core.I18n;
import com.yiring.common.core.Result;
import com.yiring.common.core.Status;
......@@ -20,6 +21,7 @@ import com.yiring.common.param.PageParam;
import com.yiring.common.service.FileManageService;
import com.yiring.common.util.Commons;
import com.yiring.common.util.FileUtils;
import com.yiring.common.utils.RepositoryUtil;
import com.yiring.common.validation.group.Group;
import com.yiring.common.vo.PageVo;
import io.swagger.v3.oas.annotations.Operation;
......@@ -29,7 +31,6 @@ import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
......@@ -61,6 +62,7 @@ public class ExampleController {
final UserExtensionRepository userExtensionRepository;
final FileManageService fileManageService;
@RateLimiter(count = 1)
@Operation(summary = "Hello World")
@GetMapping
public Result<String> hello() {
......@@ -129,12 +131,8 @@ public class ExampleController {
@GetMapping("findUserExtensionInfo")
public Result<UserExtensionVo> findUserExtensionInfo() {
User user = auths.getLoginUser();
Optional<UserExtension> optional = userExtensionRepository.findOne(Example.of(new UserExtension(user)));
if (optional.isEmpty()) {
throw Status.NOT_FOUND.exception();
}
UserExtension ext = optional.get();
Example<UserExtension> example = Example.of(new UserExtension(user));
UserExtension ext = RepositoryUtil.find(userExtensionRepository, example);
UserExtensionVo vo = Commons.transform(ext, UserExtensionVo.class);
return Result.ok(vo);
}
......
# 环境变量
env:
# host: 192.168.0.156
host: 127.0.0.1
host: 192.168.0.156
# host: 127.0.0.1
prod: false
props:
# username: admin
username: postgres
username: admin
# username: postgres
password: 123456
# ----------------------------------------------
......@@ -15,7 +15,6 @@ spring:
username: ${env.props.username}
password: ${env.props.password}
jpa:
database-platform: org.hibernate.dialect.PostgreSQLDialect
open-in-view: true
hibernate:
ddl-auto: update
......
plugins {
id 'java-library'
}
dependencies {
implementation project(':basic-common:core')
implementation project(':basic-common:util')
......@@ -9,9 +13,9 @@ dependencies {
implementation "com.github.xiaoymin:knife4j-openapi3-jakarta-spring-boot-starter:${knife4jOpen3Version}"
// sa-token
implementation "cn.dev33:sa-token-spring-boot3-starter:${saTokenVersion}"
api "cn.dev33:sa-token-spring-boot3-starter:${saTokenVersion}"
// Sa-Token 整合 Redis (使用 jackson 序列化方式)
implementation "cn.dev33:sa-token-dao-redis-jackson:${saTokenVersion}"
implementation "cn.dev33:sa-token-redis-jackson:${saTokenVersion}"
implementation 'org.apache.commons:commons-pool2'
// fastjson
......@@ -21,8 +25,8 @@ dependencies {
implementation "cn.hutool:hutool-core:${hutoolVersion}"
// https://github.com/vladmihalcea/hypersistence-utils
// hypersistence-utils-hibernate-60
implementation "io.hypersistence:hypersistence-utils-hibernate-60:${hibernateTypesVersion}"
// hypersistence-utils-hibernate-63
implementation "io.hypersistence:hypersistence-utils-hibernate-63:${hibernateTypesVersion}"
// https://mvnrepository.com/artifact/org.jetbrains/annotations
implementation "org.jetbrains:annotations:${jetbrainsAnnotationsVersion}"
......
/* (C) 2023 YiRing, Inc. */
package com.yiring.auth.config;
import cn.dev33.satoken.spring.SaTokenContextForSpringInJakartaServlet;
import cn.dev33.satoken.spring.pathmatch.SaPatternsRequestConditionHolder;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
/**
* 自定义 SaTokenContext 实现类,重写 matchPath 方法,切换为 ant_path_matcher 模式,使之可以支持 `**` 之后再出现内容
* @author Jim
* @version 0.1
* 2023/12/19 11:57
*/
@Primary
@Component
public class SaTokenContextByPatternsRequestCondition extends SaTokenContextForSpringInJakartaServlet {
@Override
public boolean matchPath(String pattern, String path) {
return SaPatternsRequestConditionHolder.match(pattern, path);
}
}
......@@ -6,10 +6,9 @@ import com.yiring.auth.domain.permission.Permission;
import com.yiring.auth.domain.role.Role;
import com.yiring.auth.domain.user.User;
import com.yiring.auth.domain.user.UserRepository;
import com.yiring.common.core.Status;
import com.yiring.common.utils.RepositoryUtil;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
......@@ -58,11 +57,6 @@ public class StpInterfaceImpl implements StpInterface {
*/
public User getUser(Object loginId) {
String id = Objects.toString(loginId);
Optional<User> optional = userRepository.findById(id);
if (optional.isEmpty()) {
throw Status.NOT_FOUND.exception("Code.1000");
}
return optional.get();
return RepositoryUtil.find(userRepository, id, "Code.1000");
}
}
......@@ -17,7 +17,6 @@ import lombok.experimental.FieldNameConstants;
import lombok.experimental.SuperBuilder;
import org.hibernate.annotations.Comment;
import org.hibernate.annotations.SQLDelete;
import org.hibernate.annotations.SQLDeleteAll;
import org.hibernate.annotations.Where;
/**
......@@ -35,7 +34,7 @@ import org.hibernate.annotations.Where;
@FieldNameConstants
@FieldDefaults(level = AccessLevel.PRIVATE)
@SQLDelete(sql = DELETE_SQL + BasicEntity.Where.WHERE_ID)
@SQLDeleteAll(sql = DELETE_SQL)
//@SQLDeleteAll(sql = DELETE_SQL)
@Where(clause = BasicEntity.Where.EXIST)
@Entity
@Table(
......@@ -88,7 +87,7 @@ public class Permission extends BasicEntity implements Serializable {
Boolean hidden;
@Comment("是否禁用")
@Column(columnDefinition = "bool default false")
@Column(columnDefinition = "bool default false", nullable = false)
Boolean disabled;
@Comment("权限父级ID")
......
......@@ -18,7 +18,6 @@ import lombok.experimental.FieldNameConstants;
import lombok.experimental.SuperBuilder;
import org.hibernate.annotations.Comment;
import org.hibernate.annotations.SQLDelete;
import org.hibernate.annotations.SQLDeleteAll;
import org.hibernate.annotations.Where;
/**
......@@ -36,7 +35,7 @@ import org.hibernate.annotations.Where;
@FieldNameConstants
@FieldDefaults(level = AccessLevel.PRIVATE)
@SQLDelete(sql = Permission.DELETE_SQL + BasicEntity.Where.WHERE_ID)
@SQLDeleteAll(sql = Permission.DELETE_SQL)
//@SQLDeleteAll(sql = Permission.DELETE_SQL)
@Where(clause = BasicEntity.Where.EXIST)
@Entity
@Table(
......@@ -62,7 +61,7 @@ public class Role extends BasicEntity implements Serializable {
String name;
@Comment("是否禁用")
@Column(columnDefinition = "bool default false")
@Column(columnDefinition = "bool default false", nullable = false)
Boolean disabled;
@JsonIgnore
......
......@@ -17,7 +17,6 @@ import lombok.experimental.FieldNameConstants;
import lombok.experimental.SuperBuilder;
import org.hibernate.annotations.Comment;
import org.hibernate.annotations.SQLDelete;
import org.hibernate.annotations.SQLDeleteAll;
/**
* 用户
......@@ -34,7 +33,7 @@ import org.hibernate.annotations.SQLDeleteAll;
@FieldNameConstants
@FieldDefaults(level = AccessLevel.PRIVATE)
@SQLDelete(sql = Permission.DELETE_SQL + BasicEntity.Where.WHERE_ID)
@SQLDeleteAll(sql = Permission.DELETE_SQL)
//@SQLDeleteAll(sql = Permission.DELETE_SQL)
@Entity
@Table(
name = User.TABLE_NAME,
......
......@@ -49,7 +49,7 @@ public class Auths {
Object id = StpUtil.getLoginIdByToken(token);
if (id == null) {
StpUtil.logoutByTokenValue(token);
throw NotLoginException.newInstance(StpUtil.TYPE, null);
throw NotLoginException.newInstance(StpUtil.TYPE, null, "Token 无效", token);
}
Optional<User> optional = userRepository.findById(Objects.toString(id));
......@@ -59,7 +59,7 @@ public class Auths {
Boolean.TRUE.equals(optional.get().getDisabled())
) {
StpUtil.logout(id);
throw NotLoginException.newInstance(StpUtil.TYPE, NotLoginException.INVALID_TOKEN);
throw NotLoginException.newInstance(StpUtil.TYPE, NotLoginException.INVALID_TOKEN, "用户被禁用", token);
}
return optional.get();
......@@ -72,7 +72,7 @@ public class Auths {
public User getLoginUser() {
String token = StpUtil.getTokenValue();
if (token == null) {
throw NotLoginException.newInstance(StpUtil.TYPE, null);
throw NotLoginException.newInstance(StpUtil.TYPE, null, "用户未登录", null);
}
return getUserByToken(token);
......
......@@ -81,7 +81,7 @@ public class Permissions {
* @param menus 菜单集合
* @return 排序后的菜单集合
*/
public static List<MenuVo> sortMenuTreeVo(@Nullable List<MenuVo> menus) {
public static List<MenuVo> sortMenuTreeVo(List<MenuVo> menus) {
return menus
.stream()
.sorted(
......
......@@ -12,6 +12,7 @@ import com.yiring.auth.param.auth.RegisterParam;
import com.yiring.auth.param.auth.SafeParam;
import com.yiring.auth.util.Auths;
import com.yiring.auth.vo.auth.LoginVo;
import com.yiring.common.annotation.RateLimiter;
import com.yiring.common.core.Result;
import com.yiring.common.exception.BusinessException;
import com.yiring.common.util.Commons;
......@@ -54,6 +55,7 @@ public class AuthController {
final Auths auths;
final UserRepository userRepository;
@RateLimiter(time = 1, count = 1)
@Operation(summary = "注册")
@PostMapping(value = "register")
public Result<String> register(@ParameterObject @Validated RegisterParam param) {
......@@ -91,6 +93,7 @@ public class AuthController {
return Result.ok();
}
@RateLimiter(count = 3)
@Operation(summary = "登录")
@PostMapping("login")
public Result<LoginVo> login(@ParameterObject @Validated LoginParam param, HttpServletRequest request) {
......@@ -135,6 +138,7 @@ public class AuthController {
return Result.ok(StpUtil.isLogin());
}
@RateLimiter(count = 3)
@Operation(summary = "登出")
@GetMapping("logout")
public Result<String> logout() {
......@@ -149,6 +153,7 @@ public class AuthController {
* @param param 用户密码
* @link { <a href="https://sa-token.dev33.cn/doc.html#/up/safe-auth">...</a> }
*/
@RateLimiter(count = 3)
@SaCheckLogin
@Operation(summary = "安全验证")
@GetMapping("safe")
......
......@@ -8,11 +8,11 @@ import com.yiring.auth.param.permission.PermissionParam;
import com.yiring.auth.util.Permissions;
import com.yiring.auth.vo.permission.PermissionVo;
import com.yiring.common.core.Result;
import com.yiring.common.core.Status;
import com.yiring.common.exception.BusinessException;
import com.yiring.common.param.IdParam;
import com.yiring.common.param.PageParam;
import com.yiring.common.param.PidParam;
import com.yiring.common.utils.RepositoryUtil;
import com.yiring.common.validation.group.Group;
import com.yiring.common.vo.PageVo;
import io.swagger.v3.oas.annotations.Operation;
......@@ -68,12 +68,7 @@ public class PermissionController {
@Operation(summary = "修改")
@PostMapping("modify")
public Result<String> modify(@RequestBody @Validated({ Group.Edit.class }) PermissionParam param) {
Optional<Permission> optional = permissionRepository.findById(param.getId());
if (optional.isEmpty()) {
throw Status.NOT_FOUND.exception();
}
Permission entity = optional.get();
Permission entity = RepositoryUtil.find(permissionRepository, param.getId());
if (!entity.getUid().equals(param.getUid())) {
// 仅当修改了角色标识时才检查重复
if (has(param.getUid())) {
......@@ -88,12 +83,7 @@ public class PermissionController {
@Operation(summary = "删除")
@PostMapping("remove")
public Result<String> remove(@ParameterObject @Validated IdParam param) {
Optional<Permission> optional = permissionRepository.findById(param.getId());
if (optional.isEmpty()) {
throw Status.NOT_FOUND.exception();
}
Permission entity = optional.get();
Permission entity = RepositoryUtil.find(permissionRepository, param.getId());
permissionRepository.delete(entity);
return Result.ok();
}
......@@ -101,14 +91,9 @@ public class PermissionController {
@Operation(summary = "查询")
@GetMapping("find")
public Result<PermissionVo> find(@ParameterObject @Validated IdParam param) {
Optional<Permission> optional = permissionRepository.findById(param.getId());
if (optional.isEmpty()) {
throw Status.NOT_FOUND.exception();
}
Permission permission = optional.get();
Permission permission = RepositoryUtil.find(permissionRepository, param.getId());
PermissionVo vo = new PermissionVo();
BeanUtils.copyProperties(optional.get(), vo, Permission.Fields.meta);
BeanUtils.copyProperties(permission, vo, Permission.Fields.meta);
vo.setMeta(permission.getMetaJson());
return Result.ok(vo);
}
......
......@@ -9,11 +9,11 @@ import com.yiring.auth.param.role.RoleParam;
import com.yiring.auth.util.Permissions;
import com.yiring.auth.vo.role.RoleVo;
import com.yiring.common.core.Result;
import com.yiring.common.core.Status;
import com.yiring.common.exception.BusinessException;
import com.yiring.common.param.IdParam;
import com.yiring.common.param.IdsParam;
import com.yiring.common.param.PageParam;
import com.yiring.common.utils.RepositoryUtil;
import com.yiring.common.validation.group.Group;
import com.yiring.common.vo.PageVo;
import io.swagger.v3.oas.annotations.Operation;
......@@ -73,12 +73,7 @@ public class RoleController {
@Operation(summary = "修改")
@PostMapping("modify")
public Result<String> modify(@ParameterObject @Validated({ Group.Edit.class }) RoleParam param) {
Optional<Role> optional = roleRepository.findById(param.getId());
if (optional.isEmpty()) {
throw Status.NOT_FOUND.exception();
}
Role entity = optional.get();
Role entity = RepositoryUtil.find(roleRepository, param.getId());
if (!entity.getUid().equals(param.getUid())) {
// 仅当修改了角色标识时才检查重复
if (has(param.getUid())) {
......@@ -97,16 +92,11 @@ public class RoleController {
@ParameterObject @Validated IdParam idParam,
@ParameterObject @Validated IdsParam idsParam
) {
Optional<Role> optional = roleRepository.findById(idParam.getId());
if (optional.isEmpty()) {
throw Status.NOT_FOUND.exception();
}
Role entity = RepositoryUtil.find(roleRepository, idParam.getId());
// 查询权限集合
Collection<Serializable> ids = idsParam.toIds();
Set<Permission> permissions = new HashSet<>(permissionRepository.findAllById(ids));
Role entity = optional.get();
entity.setPermissions(permissions);
roleRepository.saveAndFlush(entity);
return Result.ok();
......@@ -123,12 +113,7 @@ public class RoleController {
@Operation(summary = "查询")
@GetMapping("find")
public Result<RoleVo> find(@ParameterObject @Validated IdParam param) {
Optional<Role> optional = roleRepository.findById(param.getId());
if (optional.isEmpty()) {
throw Status.NOT_FOUND.exception();
}
Role entity = optional.get();
Role entity = RepositoryUtil.find(roleRepository, param.getId());
RoleVo vo = new RoleVo();
BeanUtils.copyProperties(entity, vo, Role.Fields.permissions);
vo.setPermissions(Permissions.toPermissionVos(Permissions.toPermissions(Collections.singleton(entity))));
......
......@@ -7,11 +7,11 @@ import com.yiring.auth.domain.user.User;
import com.yiring.auth.domain.user.UserRepository;
import com.yiring.auth.vo.user.UserVo;
import com.yiring.common.core.Result;
import com.yiring.common.core.Status;
import com.yiring.common.param.IdParam;
import com.yiring.common.param.IdsParam;
import com.yiring.common.param.PageParam;
import com.yiring.common.util.Commons;
import com.yiring.common.utils.RepositoryUtil;
import com.yiring.common.utils.Specifications;
import com.yiring.common.vo.PageVo;
import io.swagger.v3.oas.annotations.Operation;
......@@ -60,16 +60,11 @@ public class UserController {
@ParameterObject @Validated IdParam idParam,
@ParameterObject @Validated IdsParam idsParam
) {
Optional<User> optional = userRepository.findById(idParam.getId());
if (optional.isEmpty()) {
throw Status.NOT_FOUND.exception();
}
User entity = RepositoryUtil.find(userRepository, idParam.getId());
// 查询角色集合
Collection<Serializable> ids = idsParam.toIds();
Set<Role> roles = new HashSet<>(roleRepository.findAllById(ids));
User entity = optional.get();
entity.setRoles(roles);
userRepository.saveAndFlush(entity);
return Result.ok();
......
......@@ -5,7 +5,7 @@ sa-token:
# token有效期,单位s 默认30天, -1代表永不过期
timeout: 2592000
# token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒
activity-timeout: -1
active-timeout: -1
# 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)
is-concurrent: true
# 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token)
......
......@@ -6,6 +6,7 @@ Status.FORBIDDEN=Forbidden
Status.NOT_FOUND=Not Found
Status.METHOD_NOT_ALLOWED=Method Not Allowed
Status.EXPECTATION_FAILED=Expectation Failed
Status.TOO_MANY_REQUESTS=Too Many Requests
Status.INTERNAL_SERVER_ERROR=Internal Server Error
Status.UNKNOWN_ERROR=Unknown Error
Status.NOT_IMPLEMENTED=Not Implemented
......
......@@ -6,6 +6,7 @@ Status.FORBIDDEN=\u7981\u6B62\u8BBF\u95EE
Status.NOT_FOUND=\u627E\u4E0D\u5230\u8D44\u6E90
Status.METHOD_NOT_ALLOWED=\u4E0D\u652F\u6301\u7684\u8BF7\u6C42\u7C7B\u578B
Status.EXPECTATION_FAILED=\u65E0\u6548\u53C2\u6570
Status.TOO_MANY_REQUESTS=\u8BF7\u6C42\u8FC7\u4E8E\u9891\u7E41
Status.INTERNAL_SERVER_ERROR=\u670D\u52A1\u5668\u9519\u8BEF
Status.UNKNOWN_ERROR=\u672A\u77E5\u9519\u8BEF
Status.NOT_IMPLEMENTED=API \u672A\u5B9E\u73B0
......
dependencies {
implementation project(":basic-common:util")
implementation project(":basic-common:i18n")
implementation project(":basic-common:redis")
implementation 'org.springframework.boot:spring-boot-starter-aop'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
implementation 'org.springframework.boot:spring-boot-starter-validation'
// swagger(knife4j)
......@@ -20,8 +22,8 @@ dependencies {
implementation "org.locationtech.jts:jts-core:${jtsVersion}"
// https://github.com/vladmihalcea/hypersistence-utils
// hypersistence-utils-hibernate-60
implementation "io.hypersistence:hypersistence-utils-hibernate-60:${hibernateTypesVersion}"
// hypersistence-utils-hibernate-63
implementation "io.hypersistence:hypersistence-utils-hibernate-63:${hibernateTypesVersion}"
// https://mvnrepository.com/artifact/org.n52.jackson/jackson-datatype-jts/1.2.10
implementation("org.n52.jackson:jackson-datatype-jts:1.2.10") {
......
/* (C) 2023 YiRing, Inc. */
package com.yiring.common.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 流控注解
*
* @author Jim
* @version 0.1
* 2023/12/19 15:20
*/
@SuppressWarnings({ "unused" })
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface RateLimiter {
String RATE_LIMIT_KEY = "rate_limit:";
/**
* 限流key
*/
String key() default RATE_LIMIT_KEY;
/**
* 限流时间,单位秒
*/
int time() default 5;
/**
* 限流次数
*/
int count() default 10;
}
/* (C) 2023 YiRing, Inc. */
package com.yiring.common.aspect;
import com.yiring.common.annotation.RateLimiter;
import com.yiring.common.core.Redis;
import com.yiring.common.core.Status;
import com.yiring.common.util.Commons;
import jakarta.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
/**
* 流控切面
*
* @author Jim
* @version 0.1
* 2023/12/19 15:17
*/
@Slf4j
@Aspect
@Component
@RequiredArgsConstructor
public class RateLimiterAspect {
final Redis redis;
/**
* 带有注解的方法之前执行
*/
@Before("@annotation(rateLimiter)")
public void doBefore(JoinPoint point, RateLimiter rateLimiter) {
int time = rateLimiter.time();
int count = rateLimiter.count();
// 将接口方法和用户IP构建Redis的key
String key = getRateLimiterKey(rateLimiter.key(), point);
// 使用 ZSet 的 score 设置成用户访问接口的时间戳
ZSetOperations<String, Object> zSetOperations = redis.getTemplate().opsForZSet();
// 当前时间戳
long currentTime = System.currentTimeMillis();
zSetOperations.add(key, currentTime, currentTime);
// 设置过期时间防止 key 不消失
redis.getTemplate().expire(key, time, TimeUnit.SECONDS);
// 移除 time 秒之前的访问记录,动态时间段
zSetOperations.removeRangeByScore(key, 0, currentTime - time * 1000L);
// 获得当前时间窗口内的访问记录数
Long currentCount = zSetOperations.zCard(key);
// 限流判断
if (Objects.nonNull(currentCount) && currentCount > count) {
log.warn("[Request RateLimit] 接口限流, Key: {}, count: {}, currentCount: {}", key, count, currentCount);
throw Status.TOO_MANY_REQUESTS.exception();
}
}
/**
* 组装 redis 的 key
*/
private String getRateLimiterKey(String prefixKey, JoinPoint point) {
StringBuilder sb = new StringBuilder(prefixKey);
HttpServletRequest request = getRequest();
sb.append(Commons.getClientIpAddress(request));
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod();
Class<?> targetClass = method.getDeclaringClass();
return sb.append("_").append(targetClass.getName()).append("_").append(method.getName()).toString();
}
/**
* 获取 HttpServletRequest
*/
private HttpServletRequest getRequest() {
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
assert requestAttributes != null;
return (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
}
}
......@@ -2,6 +2,7 @@
package com.yiring.common.core;
import com.yiring.common.exception.FailStatusException;
import lombok.Getter;
import org.jetbrains.annotations.PropertyKey;
import org.springframework.lang.Nullable;
......@@ -55,6 +56,11 @@ public enum Status {
EXPECTATION_FAILED(417, "Status.EXPECTATION_FAILED"),
/**
* 请求过于频繁
*/
TOO_MANY_REQUESTS(429, "Status.TOO_MANY_REQUESTS"),
/**
* 服务器错误
*/
INTERNAL_SERVER_ERROR(500, "Status.INTERNAL_SERVER_ERROR"),
......@@ -81,6 +87,11 @@ public enum Status {
private final int value;
/**
* -- GETTER --
* Return the reason phrase of this status code.
*/
@Getter
private final String reasonPhrase;
Status(int value, @PropertyKey(resourceBundle = "i18n.status") String reasonPhrase) {
......@@ -128,13 +139,6 @@ public enum Status {
}
/**
* Return the reason phrase of this status code.
*/
public String getReasonPhrase() {
return this.reasonPhrase;
}
/**
* Return a string representation of this status code.
*/
@Override
......
/* (C) 2022 YiRing, Inc. */
package com.yiring.common.domain;
import com.yiring.common.snowflake.GenerateStringId;
import com.yiring.common.snowflake.SnowflakeId;
import jakarta.persistence.*;
import java.time.LocalDateTime;
......@@ -40,7 +41,7 @@ public class BasicEntity {
@Comment("主键")
@Id
@GeneratedValue(generator = SnowflakeId.GENERATOR)
@GenericGenerator(name = SnowflakeId.GENERATOR, strategy = SnowflakeId.Strategy.STRING)
@GenericGenerator(name = SnowflakeId.GENERATOR, type = GenerateStringId.class)
String id;
@Comment("创建人")
......@@ -61,7 +62,7 @@ public class BasicEntity {
@Builder.Default
@Comment("删除时间")
@Column(columnDefinition = "bool default false")
@Column(columnDefinition = "bool default false", nullable = false)
Boolean deleted = Boolean.FALSE;
public interface Where {
......
/* (C) 2023 YiRing, Inc. */
package com.yiring.common.utils;
import com.yiring.common.core.I18n;
import com.yiring.common.core.Status;
import com.yiring.common.exception.FailStatusException;
import lombok.experimental.UtilityClass;
import org.jetbrains.annotations.PropertyKey;
import org.springframework.data.domain.Example;
import org.springframework.data.jpa.repository.JpaRepository;
/**
* @author Jim
* @version 0.1
* 2023/6/25 17:43
*/
@SuppressWarnings({ "unused" })
@UtilityClass
public class RepositoryUtil {
/**
* 根据 ID 查询数据,如果数据不存在则抛出异常【数据未找到】
* @param repository repository
* @param id id
* @return T
* @param <T> T
* @param <ID> ID
* @exception FailStatusException FailStatusException
*/
public <T, ID> T find(JpaRepository<T, ID> repository, ID id) throws FailStatusException {
return repository.findById(id).orElseThrow(Status.NOT_FOUND::exception);
}
/**
* 根据 ID 查询数据,如果数据不存在则抛出自定义异常【message】
* @param repository repository
* @param id id
* @param message 自定义异常信息
* @return T
* @param <T> T
* @param <ID> ID
* @exception FailStatusException FailStatusException
*/
public <T, ID> T find(
JpaRepository<T, ID> repository,
ID id,
@PropertyKey(resourceBundle = I18n.RESOURCE_BUNDLE) String message
) throws FailStatusException {
return repository.findById(id).orElseThrow(() -> Status.NOT_FOUND.exception(message));
}
/**
* 根据条件查询数据,如果数据不存在则抛出异常【数据未找到】
* @param repository repository
* @param example example
* @return T
* @param <T> T
* @param <ID> ID
* @throws FailStatusException FailStatusException
*/
public <T, ID> T find(JpaRepository<T, ID> repository, Example<T> example) throws FailStatusException {
return repository.findOne(example).orElseThrow(Status.NOT_FOUND::exception);
}
/**
* 根据条件查询数据,如果数据不存在则抛出自定义异常【message】
* @param repository repository
* @param example example
* @param message 自定义异常信息
* @return T
* @param <T> T
* @param <ID> ID
* @throws FailStatusException FailStatusException
*/
public <T, ID> T find(
JpaRepository<T, ID> repository,
Example<T> example,
@PropertyKey(resourceBundle = I18n.RESOURCE_BUNDLE) String message
) throws FailStatusException {
return repository.findOne(example).orElseThrow(() -> Status.NOT_FOUND.exception(message));
}
}
......@@ -6,7 +6,11 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-validation'
// swagger(knife4j)
implementation "com.github.xiaoymin:knife4j-openapi3-jakarta-spring-boot-starter:${knife4jOpen3Version}"
api("com.github.xiaoymin:knife4j-openapi3-jakarta-spring-boot-starter:${knife4jOpen3Version}") {
// FIX: 1.33 CVE
exclude group: 'org.yaml', module: 'snakeyaml'
}
implementation "org.yaml:snakeyaml:${snakeyamlVersion}"
// hutool-core
implementation "cn.hutool:hutool-core:${hutoolVersion}"
......
......@@ -36,7 +36,7 @@ public class I18nConfig {
@Bean
public MessageSource messageSource() {
SmReloadableResourceBundleMessageSource messageSource = new SmReloadableResourceBundleMessageSource();
messageSource.setBasenames("classpath*:i18n/messages", "classpath:i18n/status", "classpath:i18n/validation");
messageSource.setBasenames("classpath*:i18n/messages", "classpath*:i18n/status", "classpath:i18n/validation");
messageSource.setDefaultEncoding("UTF-8");
messageSource.setAlwaysUseMessageFormat(true);
messageSource.setDefaultLocale(DEFAULT_LOCALE);
......
......@@ -6,6 +6,7 @@ Status.FORBIDDEN=Forbidden
Status.NOT_FOUND=Not Found
Status.METHOD_NOT_ALLOWED=Method Not Allowed
Status.EXPECTATION_FAILED=Expectation Failed
Status.TOO_MANY_REQUESTS=Too Many Requests
Status.INTERNAL_SERVER_ERROR=Internal Server Error
Status.UNKNOWN_ERROR=Unknown Error
Status.NOT_IMPLEMENTED=Not Implemented
......
......@@ -6,6 +6,7 @@ Status.FORBIDDEN=\u7981\u6B62\u8BBF\u95EE
Status.NOT_FOUND=\u627E\u4E0D\u5230\u8D44\u6E90
Status.METHOD_NOT_ALLOWED=\u4E0D\u652F\u6301\u7684\u8BF7\u6C42\u7C7B\u578B
Status.EXPECTATION_FAILED=\u65E0\u6548\u53C2\u6570
Status.TOO_MANY_REQUESTS=\u8BF7\u6C42\u8FC7\u4E8E\u9891\u7E41
Status.INTERNAL_SERVER_ERROR=\u670D\u52A1\u5668\u9519\u8BEF
Status.UNKNOWN_ERROR=\u672A\u77E5\u9519\u8BEF
Status.NOT_IMPLEMENTED=API \u672A\u5B9E\u73B0
......
plugins {
id 'java-library'
}
dependencies {
implementation project(":basic-common:core")
implementation project(":basic-common:util")
......@@ -9,7 +13,7 @@ dependencies {
implementation "com.github.xiaoymin:knife4j-openapi3-jakarta-spring-boot-starter:${knife4jOpen3Version}"
// minio
implementation "io.minio:minio:${minioVersion}"
api "io.minio:minio:${minioVersion}"
// hutool
implementation "cn.hutool:hutool-core:${hutoolVersion}"
......
......@@ -127,7 +127,9 @@ public record Minio(MinioConfig config, MinioClient client) {
object = folder + "/" + object;
}
return putObject(file.getInputStream(), file.getContentType(), object);
@Cleanup
InputStream inputStream = file.getInputStream();
return putObject(inputStream, file.getContentType(), object);
}
/**
......
......@@ -481,4 +481,8 @@ public final class Redis {
.info();
return Convert.toStr(info);
}
public RedisTemplate<String, Object> getTemplate() {
return redisTemplate;
}
}
......@@ -48,7 +48,7 @@ public class Commons {
public String getClientIpAddress(HttpServletRequest request) {
for (String header : HEADERS_TO_TRY) {
String ip = request.getHeader(header);
if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {
if (ip != null && !ip.isEmpty() && !"unknown".equalsIgnoreCase(ip)) {
return ip;
}
}
......
......@@ -17,7 +17,6 @@ import lombok.experimental.FieldNameConstants;
import lombok.experimental.SuperBuilder;
import org.hibernate.annotations.Comment;
import org.hibernate.annotations.SQLDelete;
import org.hibernate.annotations.SQLDeleteAll;
/**
* 分类字典
......@@ -35,7 +34,7 @@ import org.hibernate.annotations.SQLDeleteAll;
@FieldNameConstants
@FieldDefaults(level = AccessLevel.PRIVATE)
@SQLDelete(sql = DELETE_SQL + BasicEntity.Where.WHERE_ID)
@SQLDeleteAll(sql = DELETE_SQL)
//@SQLDeleteAll(sql = DELETE_SQL)
@Entity
@Table(
name = TABLE_NAME,
......@@ -70,6 +69,6 @@ public class Category extends BasicEntity implements Serializable {
String pid;
@Comment("是否禁用")
@Column(nullable = false, columnDefinition = "bool default false")
@Column(columnDefinition = "bool default false", nullable = false)
Boolean disabled;
}
......@@ -16,7 +16,6 @@ import lombok.experimental.FieldNameConstants;
import lombok.experimental.SuperBuilder;
import org.hibernate.annotations.Comment;
import org.hibernate.annotations.SQLDelete;
import org.hibernate.annotations.SQLDeleteAll;
/**
* 字典
......@@ -34,7 +33,7 @@ import org.hibernate.annotations.SQLDeleteAll;
@FieldNameConstants
@FieldDefaults(level = AccessLevel.PRIVATE)
@SQLDelete(sql = Category.DELETE_SQL + BasicEntity.Where.WHERE_ID)
@SQLDeleteAll(sql = Category.DELETE_SQL)
//@SQLDeleteAll(sql = Category.DELETE_SQL)
@Entity
@Table(
name = TABLE_NAME,
......@@ -66,7 +65,7 @@ public class Dict extends BasicEntity implements Serializable {
String description;
@Comment("是否禁用")
@Column(columnDefinition = "bool default false")
@Column(columnDefinition = "bool default false", nullable = false)
Boolean disabled;
@JsonIgnore
......
......@@ -14,7 +14,6 @@ import lombok.experimental.FieldNameConstants;
import lombok.experimental.SuperBuilder;
import org.hibernate.annotations.Comment;
import org.hibernate.annotations.SQLDelete;
import org.hibernate.annotations.SQLDeleteAll;
/**
* 字典选项
......@@ -32,7 +31,7 @@ import org.hibernate.annotations.SQLDeleteAll;
@FieldNameConstants
@FieldDefaults(level = AccessLevel.PRIVATE)
@SQLDelete(sql = Category.DELETE_SQL + WHERE_ID)
@SQLDeleteAll(sql = Category.DELETE_SQL)
//@SQLDeleteAll(sql = Category.DELETE_SQL)
@Entity
@Table(
name = TABLE_NAME,
......@@ -71,6 +70,6 @@ public class DictItem extends BasicEntity implements Serializable {
Integer serial;
@Comment("是否禁用")
@Column(columnDefinition = "bool default false")
@Column(columnDefinition = "bool default false", nullable = false)
Boolean disabled;
}
......@@ -2,12 +2,12 @@
package com.yiring.dict.web;
import com.yiring.common.core.Result;
import com.yiring.common.core.Status;
import com.yiring.common.exception.BusinessException;
import com.yiring.common.param.IdParam;
import com.yiring.common.param.IdsParam;
import com.yiring.common.param.PageParam;
import com.yiring.common.util.Commons;
import com.yiring.common.utils.RepositoryUtil;
import com.yiring.common.utils.Specifications;
import com.yiring.common.validation.group.Group;
import com.yiring.common.vo.OptionVo;
......@@ -22,7 +22,6 @@ import io.swagger.v3.oas.annotations.extensions.ExtensionProperty;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
......@@ -74,12 +73,7 @@ public class DictController {
@Operation(summary = "修改")
@PostMapping("modify")
public Result<String> modify(@ParameterObject @Validated({ Group.Edit.class }) DictParam param) {
Optional<Dict> optional = dictRepository.findById(param.getId());
if (optional.isEmpty()) {
throw Status.NOT_FOUND.exception();
}
Dict entity = optional.get();
Dict entity = RepositoryUtil.find(dictRepository, param.getId());
if (!entity.getCode().equals(param.getCode())) {
throw BusinessException.i18n("Code.101002");
}
......@@ -100,12 +94,7 @@ public class DictController {
@Operation(summary = "查询")
@GetMapping("find")
public Result<DictVo> find(@ParameterObject @Validated IdParam param) {
Optional<Dict> optional = dictRepository.findById(param.getId());
if (optional.isEmpty()) {
throw Status.NOT_FOUND.exception();
}
Dict entity = optional.get();
Dict entity = RepositoryUtil.find(dictRepository, param.getId());
DictVo vo = Commons.transform(entity, DictVo.class);
return Result.ok(vo);
}
......
......@@ -3,13 +3,13 @@ package com.yiring.dict.web;
import cn.hutool.core.util.StrUtil;
import com.yiring.common.core.Result;
import com.yiring.common.core.Status;
import com.yiring.common.domain.BasicEntity;
import com.yiring.common.exception.BusinessException;
import com.yiring.common.param.IdParam;
import com.yiring.common.param.IdsParam;
import com.yiring.common.param.PageParam;
import com.yiring.common.util.Commons;
import com.yiring.common.utils.RepositoryUtil;
import com.yiring.common.utils.Specifications;
import com.yiring.common.validation.group.Group;
import com.yiring.common.vo.OptionVo;
......@@ -27,7 +27,6 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
......@@ -76,12 +75,7 @@ public class DictItemController {
@Operation(summary = "修改")
@PostMapping("modify")
public Result<String> modify(@ParameterObject @Validated({ Group.Edit.class }) DictItemParam param) {
Optional<DictItem> optional = dictItemRepository.findById(param.getId());
if (optional.isEmpty()) {
throw Status.NOT_FOUND.exception();
}
DictItem entity = optional.get();
DictItem entity = RepositoryUtil.find(dictItemRepository, param.getId());
BeanUtils.copyProperties(param, entity);
dictItemRepository.saveAndFlush(entity);
return Result.ok();
......@@ -98,12 +92,7 @@ public class DictItemController {
@Operation(summary = "查询")
@GetMapping("find")
public Result<DictItemVo> find(@ParameterObject @Validated IdParam param) {
Optional<DictItem> optional = dictItemRepository.findById(param.getId());
if (optional.isEmpty()) {
throw Status.NOT_FOUND.exception();
}
DictItem entity = optional.get();
DictItem entity = RepositoryUtil.find(dictItemRepository, param.getId());
DictItemVo vo = Commons.transform(entity, DictItemVo.class);
return Result.ok(vo);
}
......
......@@ -32,6 +32,7 @@ public class StompPrincipal implements Principal, Serializable {
Type type;
String user;
String token;
String session;
JSONObject options;
......
/* (C) 2022 YiRing, Inc. */
package com.yiring.websocket.interceptor;
import cn.hutool.core.convert.Convert;
import com.yiring.auth.domain.user.User;
import com.yiring.auth.util.Auths;
import com.yiring.common.core.Redis;
import com.yiring.websocket.constant.RedisKey;
import com.yiring.websocket.domain.StompPrincipal;
import java.util.LinkedList;
import java.util.Collection;
import java.util.Map;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
......@@ -51,10 +52,11 @@ public class ClientInboundChannelInterceptor implements ChannelInterceptor {
principal.setSession(accessor.getSessionId());
Object tokens = ((Map<?, ?>) raw).get("token");
if (tokens instanceof LinkedList) {
String token = ((LinkedList<?>) tokens).getFirst().toString();
if (tokens instanceof Collection<?>) {
String token = Convert.toList(String.class, tokens).get(0);
User user = auths.getUserByToken(token);
principal.setUser(user.getUsername());
principal.setToken(token);
principal.setUser(user.getRealName());
principal.setType(StompPrincipal.Type.LOGIN_USER);
} else {
principal.setUser("Guest." + principal.getSession());
......@@ -65,10 +67,11 @@ public class ClientInboundChannelInterceptor implements ChannelInterceptor {
synchronized (lock) {
redis.hset(RedisKey.STOMP_ONLINE_USERS, principal.getSession(), principal);
log.info(
"STOMP Online Users: {} (incr: +1, session: {}, user: `{}`)",
"STOMP Online Users: {} (incr: +1, user: {}, session: {}, token: {})",
redis.hsize(RedisKey.STOMP_ONLINE_USERS),
principal.getUser(),
principal.getSession(),
principal.getUser()
principal.getToken()
);
}
}
......@@ -78,10 +81,11 @@ public class ClientInboundChannelInterceptor implements ChannelInterceptor {
synchronized (lock) {
redis.hdel(RedisKey.STOMP_ONLINE_USERS, principal.getSession());
log.info(
"STOMP Online Users: {} (incr: -1, session: {}, user: `{}`)",
"STOMP Online Users: {} (incr: -1, user: {}, session: {}, token: {})",
redis.hsize(RedisKey.STOMP_ONLINE_USERS),
principal.getUser(),
principal.getSession(),
principal.getUser()
principal.getToken()
);
}
}
......
plugins {
id 'java'
id 'java-library'
// https://start.spring.io
id 'org.springframework.boot' version '3.0.5'
id 'org.graalvm.buildtools.native' version '0.9.20'
id 'org.springframework.boot' version '3.2.0'
id 'org.graalvm.buildtools.native' version '0.9.28'
// https://plugins.gradle.org/plugin/io.spring.dependency-management
id 'io.spring.dependency-management' version '1.1.0'
id 'io.spring.dependency-management' version '1.1.4'
// https://plugins.gradle.org/plugin/com.diffplug.spotless
id "com.diffplug.spotless" version "6.18.0"
id "com.diffplug.spotless" version "6.23.3"
}
ext {
......@@ -16,49 +17,52 @@ ext {
// Spotless
// https://www.npmjs.com/package/prettier
prettierVersion = '2.8.7'
prettierVersion = '2.8.8'
// https://www.npmjs.com/package/prettier-plugin-java
prettierJavaVersion = '2.1.0'
// SpringCloud
// https://start.spring.io/
springCloudVersion = '2022.0.1'
springCloudVersion = '2023.0.0'
// springBootAdminVersion
// https://central.sonatype.com/artifact/de.codecentric/spring-boot-admin-starter-server
springBootAdminVersion = '3.0.2'
// FIXED: 版本号不兼容,暂时去掉
// springBootAdminVersion = '3.1.0'
// Dependencies
// https://central.sonatype.com/artifact/com.github.xiaoymin/knife4j-openapi3-jakarta-spring-boot-starter
knife4jOpen3Version = '4.1.0'
// https://central.sonatype.com/artifact/io.swagger/swagger-annotations
swaggerAnnotationsVersion = '2.2.8'
knife4jOpen3Version = '4.4.0'
// https://central.sonatype.com/artifact/io.swagger.core.v3/swagger-annotations
swaggerAnnotationsVersion = '2.2.19'
// https://central.sonatype.com/artifact/cn.dev33/sa-token-spring-boot3-starter
saTokenVersion = '1.34.0'
saTokenVersion = '1.37.0'
// https://central.sonatype.com/artifact/cn.hutool/hutool-core
hutoolVersion = '5.8.18'
hutoolVersion = '5.8.23'
// https://central.sonatype.com/artifact/com.alibaba.fastjson2/fastjson2
fastJsonVersion = '2.0.28'
fastJsonVersion = '2.0.43'
// https://central.sonatype.com/artifact/com.xuxueli/xxl-job-core
xxlJobVersion = '2.4.0'
// https://central.sonatype.com/artifact/com.squareup.okhttp3/okhttp
okhttpVersion = '4.9.3'
okhttpVersion = '4.12.0'
// https://central.sonatype.com/artifact/io.minio/minio
minioVersion = '8.5.2'
// https://central.sonatype.com/artifact/io.hypersistence/hypersistence-utils-hibernate-60
hibernateTypesVersion = '3.3.2'
minioVersion = '8.5.7'
// https://central.sonatype.com/artifact/io.hypersistence/hypersistence-utils-hibernate-63
hibernateTypesVersion = '3.7.0'
// https://central.sonatype.com/artifact/org.hibernate.orm/hibernate-spatial
hibernateSpatialVersion = '6.2.1.Final'
hibernateSpatialVersion = '6.4.1.Final'
// https://central.sonatype.com/artifact/org.locationtech.jts/jts-core
jtsVersion = '1.19.0'
// https://central.sonatype.com/artifact/com.github.liaochong/myexcel
myexcelVersion = '4.2.2'
myexcelVersion = '4.4.2'
// https://central.sonatype.com/artifact/org.jetbrains/annotations
jetbrainsAnnotationsVersion = '24.0.1'
jetbrainsAnnotationsVersion = '24.1.0'
// https://central.sonatype.com/artifact/org.apache.pdfbox/pdfbox
pdfboxVersion = '2.0.28'
pdfboxVersion = '3.0.1'
// https://central.sonatype.com/artifact/net.bramp.ffmpeg/ffmpeg
// FIXED: ffmpeg 4.x
ffmpegWrapperVersion = '0.7.0'
ffmpegWrapperVersion = '0.8.0'
// https://central.sonatype.com/artifact/org.yaml/snakeyaml
snakeyamlVersion = '2.2'
}
allprojects {
......@@ -66,8 +70,8 @@ allprojects {
mavenLocal()
// Nexus
// maven { url 'http://10.111.102.83:8081/repository/aliyun-maven/' }
maven { url 'https://mirrors.cloud.tencent.com/nexus/repository/maven-public/' }
maven { url 'https://maven.aliyun.com/repository/public' }
maven { url 'https://mirrors.cloud.tencent.com/nexus/repository/maven-public/' }
mavenCentral()
}
......@@ -76,6 +80,7 @@ allprojects {
subprojects {
apply plugin: 'java'
apply plugin: 'java-library'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
apply plugin: "com.diffplug.spotless"
......@@ -94,12 +99,12 @@ subprojects {
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
}
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
mavenBom "de.codecentric:spring-boot-admin-dependencies:${springBootAdminVersion}"
}
}
// dependencyManagement {
// imports {
// mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
// mavenBom "de.codecentric:spring-boot-admin-dependencies:${springBootAdminVersion}"
// }
// }
[compileJava, compileTestJava, javadoc]*.options*.encoding = 'UTF-8'
......
......@@ -5,13 +5,13 @@
"log": "conventional-changelog -p angular -i CHANGELOG.md -s"
},
"devDependencies": {
"@commitlint/cli": "^17.4.0",
"@commitlint/config-conventional": "^17.4.0",
"commitizen": "^4.2.6",
"@commitlint/cli": "^17.8.1",
"@commitlint/config-conventional": "^17.8.1",
"commitizen": "^4.3.0",
"conventional-changelog-cli": "^2.2.2",
"cz-conventional-changelog": "^3.3.0",
"cz-customizable": "^7.0.0",
"cz-git": "^1.4.1"
"cz-git": "^1.8.0"
},
"config": {
"commitizen": {
......
This source diff could not be displayed because it is too large. You can view the blob instead.
pluginManagement {
repositories {
maven { url "https://maven.aliyun.com/repository/gradle-plugin" }
gradlePluginPortal()
}
}
//pluginManagement {
// repositories {
// maven { url "https://maven.aliyun.com/repository/gradle-plugin" }
// gradlePluginPortal()
// }
//}
rootProject.name = 'basic-api-boot'
include 'app'
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论