Browse Source

资料管理

master
luoweijian 1 month ago
parent
commit
04d650a366
  1. 53
      pom.xml
  2. 1
      src/main/java/com/project/base/domain/dto/BaseDTO.java
  3. 5
      src/main/java/com/project/base/domain/entity/BaseEntity.java
  4. 68
      src/main/java/com/project/ding/auth/DingTalkAuthenticationProvider.java
  5. 25
      src/main/java/com/project/ding/auth/DingTalkAuthenticationToken.java
  6. 61
      src/main/java/com/project/ding/auth/JwtAuthenticationFilter.java
  7. 14
      src/main/java/com/project/ding/config/DingProperties.java
  8. 23
      src/main/java/com/project/ding/config/DtConfig.java
  9. 46
      src/main/java/com/project/ding/config/SecurityConfig.java
  10. 38
      src/main/java/com/project/ding/controller/DepartmentController.java
  11. 27
      src/main/java/com/project/ding/controller/LoginController.java
  12. 2
      src/main/java/com/project/ding/controller/SyncController.java
  13. 2
      src/main/java/com/project/ding/controller/UserController.java
  14. 1
      src/main/java/com/project/ding/domain/dto/DepartmentDTO.java
  15. 14
      src/main/java/com/project/ding/domain/dto/LoginDTO.java
  16. 9
      src/main/java/com/project/ding/domain/dto/UserDTO.java
  17. 40
      src/main/java/com/project/ding/domain/entity/AdminWhiteListEntity.java
  18. 7
      src/main/java/com/project/ding/domain/entity/DepartmentEntity.java
  19. 6
      src/main/java/com/project/ding/domain/entity/SyncLogEntity.java
  20. 5
      src/main/java/com/project/ding/domain/entity/UserEntity.java
  21. 10
      src/main/java/com/project/ding/domain/service/AuthDomainService.java
  22. 60
      src/main/java/com/project/ding/domain/service/impl/AuthDomainServiceImpl.java
  23. 10
      src/main/java/com/project/ding/mapper/AdminWhiteListMapper.java
  24. 21
      src/main/java/com/project/ding/utils/DingUtil.java
  25. 29
      src/main/java/com/project/ding/utils/JwtUtils.java
  26. 14
      src/main/java/com/project/information/application/InformationApplicationService.java
  27. 28
      src/main/java/com/project/information/application/impl/InformationApplicationServiceImpl.java
  28. 2
      src/main/java/com/project/information/controller/BusinessGroupController.java
  29. 27
      src/main/java/com/project/information/controller/InformationController.java
  30. 2
      src/main/java/com/project/information/controller/ProductLineController.java
  31. 2
      src/main/java/com/project/information/domain/dto/BusinessGroupDTO.java
  32. 4
      src/main/java/com/project/information/domain/dto/InformationDTO.java
  33. 2
      src/main/java/com/project/information/domain/dto/ProductLineDTO.java
  34. 10
      src/main/java/com/project/information/domain/entity/BusinessGroupEntity.java
  35. 8
      src/main/java/com/project/information/domain/entity/InformationEntity.java
  36. 11
      src/main/java/com/project/information/domain/entity/ProductLineEntity.java
  37. 15
      src/main/java/com/project/information/domain/enums/InformationParseStatusEnum.java
  38. 11
      src/main/java/com/project/information/domain/param/BatchCheckParam.java
  39. 32
      src/main/java/com/project/information/domain/param/CheckDuplicatesParam.java
  40. 9
      src/main/java/com/project/information/domain/param/FileCheckItem.java
  41. 11
      src/main/java/com/project/information/domain/service/UploadInformationDomainService.java
  42. 28
      src/main/java/com/project/information/domain/service/UploadService.java
  43. 115
      src/main/java/com/project/information/domain/service/impl/UploadInformationDomainServiceImpl.java
  44. 43
      src/main/java/com/project/information/domain/service/impl/UploadServiceImpl.java
  45. 86
      src/main/java/com/project/information/utils/MinIoUtils.java
  46. 17
      src/main/resources/application.yml

53
pom.xml

@ -32,6 +32,9 @@
<minio.version>8.0.3</minio.version>
<okhttp3.version>4.8.1</okhttp3.version>
<dynamic-datasource.version>4.3.0</dynamic-datasource.version> <!-- 升级到适配 SB3.2 -->
<jjwt.version>0.11.5</jjwt.version>
<spring.boot.test.version>3.0.13</spring.boot.test.version>
<lombok.version>1.18.30</lombok.version>
@ -120,10 +123,34 @@
<artifactId>hutool-all</artifactId>
<version>5.8.3</version>
</dependency>
<!-- Spring Security (新增) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- JWT 相关 (新增) -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>${jjwt.version}</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>${jjwt.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>${jjwt.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot3-starter</artifactId>
<version>4.2.0</version>
<version>${dynamic-datasource.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
@ -177,4 +204,28 @@
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<!-- 必须确保有这个 execution,它负责把普通 JAR 重新打包成可执行 JAR -->
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>

1
src/main/java/com/project/base/domain/dto/BaseDTO.java

@ -11,7 +11,6 @@ import java.util.function.Supplier;
@Data
public class BaseDTO {
private Long id;
private Long creatorId;

5
src/main/java/com/project/base/domain/entity/BaseEntity.java

@ -17,10 +17,7 @@ import java.util.function.Supplier;
@Data
public class BaseEntity implements Serializable {
@Id
@TableId(value = "id" , type = IdType.ASSIGN_ID)
@Column(name = "id" , columnDefinition="bigint(20)")
private Long id;
@TableField(value = "creator_id" , fill = FieldFill.INSERT)
@Column(name = "creator_id" , columnDefinition="bigint(20) comment '创建用户id'")

68
src/main/java/com/project/ding/auth/DingTalkAuthenticationProvider.java

@ -0,0 +1,68 @@
package com.project.ding.auth;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.project.ding.domain.dto.UserDTO;
import com.project.ding.domain.entity.AdminWhiteListEntity;
import com.project.ding.domain.entity.UserEntity;
import com.project.ding.mapper.AdminWhiteListMapper;
import com.project.ding.mapper.UserMapper;
import com.project.ding.utils.DingUserSyncUtil;
import com.project.ding.utils.DingUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Component;
import java.util.*;
@Component
public class DingTalkAuthenticationProvider implements AuthenticationProvider {
@Autowired
private DingUtil dingUtil; // 封装获取 userId 接口
@Autowired
private UserMapper userMapper;
@Autowired
private AdminWhiteListMapper whitelistMapper;
@Autowired
private DingUserSyncUtil dingUserSyncUtil;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String authCode = (String) authentication.getPrincipal();
// 1. 换取钉钉 UserId
String dingId = dingUtil.getUserIdByCode(authCode);
if (StrUtil.isBlank(dingId)) {
throw new BadCredentialsException("钉钉授权失败");
}
UserEntity user = userMapper.selectById(Long.valueOf(dingId));
if (Objects.isNull(user)) {
// 直接插入这个用户并且触发一次异步的全量用户同步
UserDTO userDTO = dingUtil.getUserById(dingId);
if (Objects.isNull(userDTO)) {
throw new BadCredentialsException("获取用户信息异常,请联系管理员");
}
userMapper.batchUpsert(Collections.singletonList(userDTO.toEntity(UserEntity::new)));
user = userMapper.selectById(Long.valueOf(dingId));
dingUserSyncUtil.triggerSync(false);
}
// 3. 分配角色:默认考生,白名单为管理员
List<SimpleGrantedAuthority> authorities = new ArrayList<>();
authorities.add(new SimpleGrantedAuthority("ROLE_CANDIDATE"));
LambdaQueryWrapper<AdminWhiteListEntity> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(AdminWhiteListEntity::getUserId , user.getId());
AdminWhiteListEntity existOne = whitelistMapper.selectOne(queryWrapper);
if (Objects.nonNull(existOne)) {
authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
}
return new DingTalkAuthenticationToken(user, authorities);
}
@Override public boolean supports(Class<?> a) { return DingTalkAuthenticationToken.class.isAssignableFrom(a); }
}

25
src/main/java/com/project/ding/auth/DingTalkAuthenticationToken.java

@ -0,0 +1,25 @@
package com.project.ding.auth;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import java.util.Collection;
public class DingTalkAuthenticationToken extends AbstractAuthenticationToken {
private final Object principal; // 登录后存 UserEntity,登录前存 authCode
public DingTalkAuthenticationToken(Object principal) {
super(null);
this.principal = principal;
setAuthenticated(false);
}
public DingTalkAuthenticationToken(Object principal, Collection<? extends GrantedAuthority> authorities) {
super(authorities);
this.principal = principal;
setAuthenticated(true);
}
@Override public Object getCredentials() { return null; }
@Override public Object getPrincipal() { return principal; }
}

61
src/main/java/com/project/ding/auth/JwtAuthenticationFilter.java

@ -0,0 +1,61 @@
package com.project.ding.auth;
import com.project.ding.utils.JwtUtils;
import io.jsonwebtoken.Claims;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority; // 确保有这行导入
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
import java.util.List;
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Autowired
private JwtUtils jwtUtils;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
String header = request.getHeader("Authorization");
if (StringUtils.hasText(header) && header.startsWith("Bearer ")) {
String token = header.substring(7);
try {
Claims claims = jwtUtils.parseToken(token);
String userId = claims.getSubject();
// 1. 获取原始的 roles 列表
Object rolesObj = claims.get("roles");
if (userId != null && rolesObj instanceof List<?>) {
// 2. 显式转换并映射,增加 Object::toString 保证类型安全
List<SimpleGrantedAuthority> authorities = ((List<?>) rolesObj).stream()
.map(Object::toString) // 强制转为 String,解决构造器匹配问题
.map(SimpleGrantedAuthority::new) // 现在这里不会报红了
.toList();
// 3. 构建并设置认证信息
UsernamePasswordAuthenticationToken authentication =
new UsernamePasswordAuthenticationToken(userId, null, authorities);
SecurityContextHolder.getContext().setAuthentication(authentication);
}
} catch (Exception e) {
// Token解析失败不处理,后续 Security 拦截器会返回 403
logger.error("JWT authentication failed: " + e.getMessage());
}
}
filterChain.doFilter(request, response);
}
}

14
src/main/java/com/project/ding/config/DingProperties.java

@ -0,0 +1,14 @@
package com.project.ding.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Data
@Component
@ConfigurationProperties(prefix = "ding")
public class DingProperties {
private String appKey;
private String appSecret;
private Long agentId;
}

23
src/main/java/com/project/ding/config/DingConfig.java → src/main/java/com/project/ding/config/DtConfig.java

@ -3,21 +3,30 @@ package com.project.ding.config;
import com.github.tingyugetc520.ali.dingtalk.api.DtService;
import com.github.tingyugetc520.ali.dingtalk.api.impl.DtServiceImpl;
import com.github.tingyugetc520.ali.dingtalk.config.impl.DtDefaultConfigImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class DingConfig {
public class DtConfig {
@Autowired
private DingProperties dingTalkProperties;
@Bean
public DtService dtService() {
DtDefaultConfigImpl config = new DtDefaultConfigImpl();
config.setAppKey("ding4eootvq4jzas96lr");
config.setAppSecret("UI6XcD8GFPE_W_yo2eQkMuoSsTEf1whpZYEXrsDA7CV7bkJp40B3VNcETWS1aGgg");
// 如果是企业内部应用,通常还需要 AgentId ,
// config.setAgentId(4145005949L);
// 直接从属性对象中取值
config.setAppKey(dingTalkProperties.getAppKey());
config.setAppSecret(dingTalkProperties.getAppSecret());
if (dingTalkProperties.getAgentId() != null) {
config.setAgentId(dingTalkProperties.getAgentId());
}
DtService dtService = new DtServiceImpl();
dtService.setDtConfigStorage(config);
return dtService;//
return dtService;
}
}
}

46
src/main/java/com/project/ding/config/SecurityConfig.java

@ -0,0 +1,46 @@
package com.project.ding.config;
import com.project.ding.auth.DingTalkAuthenticationProvider;
import com.project.ding.auth.JwtAuthenticationFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http,
DingTalkAuthenticationProvider provider,
JwtAuthenticationFilter jwtFilter) throws Exception {
return http
.csrf(AbstractHttpConfigurer::disable)
.sessionManagement(s -> s.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(auth -> auth
// 登录放行
.requestMatchers("/api/login/**").permitAll()
// 管理端锁定
.requestMatchers("/api/admin/**").hasRole("ADMIN")
// 其余(考生端)需登录
.anyRequest().authenticated()
)
.authenticationProvider(provider)
.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class)
.build();
}
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {
return config.getAuthenticationManager();
}
}

38
src/main/java/com/project/ding/controller/DepartmentController.java

@ -1,38 +0,0 @@
package com.project.ding.controller;
import com.github.tingyugetc520.ali.dingtalk.api.DtService;
import com.project.ding.domain.dto.DepartmentDTO;
import com.project.ding.domain.dto.DingUserDTO;
import com.project.ding.utils.DingUtil;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
@RestController
@Slf4j
public class DepartmentController {
@Autowired
private DingUtil dingUtil;
@Autowired
private DtService dtService;
@GetMapping("/test")
public void test(HttpServletResponse response) throws Exception {
List<DepartmentDTO> list = dingUtil.getAllDepartment();
List<DingUserDTO> userList = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
List<DingUserDTO> userInDepartment = dingUtil.getUserIdInDepartment(list.get(i).getId());
userList.addAll(userInDepartment);
}
for (int i = 0; i < 10; i++) {
System.out.println(111);
}
}
}

27
src/main/java/com/project/ding/controller/LoginController.java

@ -0,0 +1,27 @@
package com.project.ding.controller;
import com.project.base.domain.result.Result;
import com.project.ding.domain.dto.LoginDTO;
import com.project.ding.domain.service.AuthDomainService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/login")
public class LoginController {
@Autowired
private AuthDomainService authDomainService;
/**
* 钉钉免登
*/
@PostMapping("/ding")
public Result<LoginDTO> login(@RequestParam("authCode") String authCode) {
// 逻辑全部下沉到 Service
return Result.success(authDomainService.loginByDing(authCode));
}
}

2
src/main/java/com/project/ding/controller/SyncController.java

@ -9,7 +9,7 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/ding")
@RequestMapping("/api/ding")
public class SyncController {
@Autowired
private DingUserSyncUtil dingUserSyncUtil;

2
src/main/java/com/project/ding/controller/UserController.java

@ -14,7 +14,7 @@ import org.springframework.web.bind.annotation.RestController;
@RestController
@Slf4j
@RequestMapping("/dingUser")
@RequestMapping("/api/admin/dingUser")
public class UserController {
@Autowired
private UserApplicationService userApplicationService;

1
src/main/java/com/project/ding/domain/dto/DepartmentDTO.java

@ -8,6 +8,7 @@ import java.util.List;
@Data
public class DepartmentDTO extends BaseDTO {
private Long id;
private String name;
private Long parentId;

14
src/main/java/com/project/ding/domain/dto/LoginDTO.java

@ -0,0 +1,14 @@
package com.project.ding.domain.dto;
import lombok.Builder;
import lombok.Data;
import java.util.List;
@Data
@Builder
public class LoginDTO {
private String token; // JWT 令牌
private String name; // 用户姓名
private List<String> roles; // 用户角色列表
}

9
src/main/java/com/project/ding/domain/dto/UserDTO.java

@ -4,15 +4,17 @@ import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.DesensitizedUtil;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.project.base.domain.dto.BaseDTO;
import io.vavr.control.Try;
import lombok.Data;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
@Data
public class UserDTO extends BaseDTO {
private String id;
private String unionId;
@ -57,11 +59,14 @@ public class UserDTO extends BaseDTO {
public static UserDTO fromDingUserDTO(DingUserDTO dto) {
if (Objects.isNull(dto)) {
return null;
}
UserDTO userDTO = new UserDTO();
BeanUtil.copyProperties(dto , userDTO);
userDTO.setId(Try.of(() -> Long.valueOf(dto.getUserId())).getOrElse(-1L));
userDTO.setDeptIdStr(dto.getDeptIdList().stream().map(Object::toString)
.collect(Collectors.joining(",")));
userDTO.setId(dto.getUserId());
return userDTO;
}

40
src/main/java/com/project/ding/domain/entity/AdminWhiteListEntity.java

@ -0,0 +1,40 @@
package com.project.ding.domain.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.project.base.domain.entity.BaseEntity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.hibernate.annotations.Comment;
/**
* 管理员白名单表
*/
@Data
@Entity
@Table(name = "evaluator_admin_white_list")
@TableName("evaluator_admin_white_list")
@EqualsAndHashCode(callSuper = true)
public class AdminWhiteListEntity extends BaseEntity {
@TableId(value = "id" , type = IdType.ASSIGN_ID)
@Id
private Long id;
@Column(name = "user_id", nullable = false)
@Comment("用户ID (关联evaluator_user的id)")
private Long userId;
@Column(name = "user_name", length = 100)
@Comment("用户姓名 (冗余字段,方便管理后台直接查看)")
private String userName;
@Column(name = "admin_type")
@Comment("管理员类型")
private Integer adminType = 0;
}

7
src/main/java/com/project/ding/domain/entity/DepartmentEntity.java

@ -6,10 +6,7 @@ import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import com.project.base.domain.entity.BaseEntity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Index;
import jakarta.persistence.Table;
import jakarta.persistence.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.hibernate.annotations.JdbcTypeCode;
@ -24,7 +21,9 @@ import java.util.List;
@TableName(value = "evaluator_department" , autoResultMap = true)
@EqualsAndHashCode(callSuper = true)
public class DepartmentEntity extends BaseEntity {
@TableId(type = IdType.INPUT)
@Id
private Long id;
@Column(name = "name" , columnDefinition="varchar(255) comment '部门名称'")

6
src/main/java/com/project/ding/domain/entity/SyncLogEntity.java

@ -1,10 +1,13 @@
package com.project.ding.domain.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.project.base.domain.entity.BaseEntity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.Data;
import lombok.EqualsAndHashCode;
@ -19,6 +22,9 @@ import java.util.Date;
@TableName("evaluator_sync_log")
@EqualsAndHashCode(callSuper = true)
public class SyncLogEntity extends BaseEntity {
@TableId(value = "id" , type = IdType.ASSIGN_ID)
@Id
private Long id;
@Comment("同步开始时间")
@Column(name = "start_time")

5
src/main/java/com/project/ding/domain/entity/UserEntity.java

@ -8,6 +8,7 @@ import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import com.project.base.domain.entity.BaseEntity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.Data;
import lombok.EqualsAndHashCode;
@ -26,7 +27,9 @@ import java.util.List;
public class UserEntity extends BaseEntity {
@TableId(type = IdType.INPUT)
private Long id;
@Column(length = 500)
@Id
private String id;
@Column(name = "union_id" , columnDefinition="varchar(255) comment '企业架构内唯一标识'")
@TableField("union_id")

10
src/main/java/com/project/ding/domain/service/AuthDomainService.java

@ -0,0 +1,10 @@
package com.project.ding.domain.service;
import com.project.ding.domain.dto.LoginDTO;
public interface AuthDomainService {
/**
* 钉钉免登逻辑
*/
LoginDTO loginByDing(String authCode);
}

60
src/main/java/com/project/ding/domain/service/impl/AuthDomainServiceImpl.java

@ -0,0 +1,60 @@
package com.project.ding.domain.service.impl;
import com.project.base.domain.exception.BusinessErrorException;
import com.project.ding.auth.DingTalkAuthenticationToken;
import com.project.ding.domain.dto.LoginDTO;
import com.project.ding.domain.entity.UserEntity;
import com.project.ding.domain.service.AuthDomainService;
import com.project.ding.utils.JwtUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.stereotype.Service;
import org.springframework.security.core.GrantedAuthority;
import java.util.List;
@Service
@Slf4j
public class AuthDomainServiceImpl implements AuthDomainService {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private JwtUtils jwtUtils;
@Override
public LoginDTO loginByDing(String authCode) {
// 1. 构建未认证的内部 Token
DingTalkAuthenticationToken authToken = new DingTalkAuthenticationToken(authCode);
// 2. 委托 AuthenticationManager 进行认证
// 这一步会进入你之前写的 DingTalkAuthenticationProvider
Authentication authentication;
try {
authentication = authenticationManager.authenticate(authToken);
} catch (AuthenticationException e) {
log.warn("钉钉认证失败: {}", e.getMessage());
throw new BusinessErrorException("认证失败:" + e.getMessage()); // 抛出自定义业务异常
}
// 3. 认证成功后,从安全上下文中提取用户信息和权限
UserEntity user = (UserEntity) authentication.getPrincipal();
List<String> roles = authentication.getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.toList();
// 4. 生成 JWT
String token = jwtUtils.createToken(user.getId(), roles);
// 5. 组装并返回结果
return LoginDTO.builder()
.token(token)
.name(user.getName())
.roles(roles)
.build();
}
}

10
src/main/java/com/project/ding/mapper/AdminWhiteListMapper.java

@ -0,0 +1,10 @@
package com.project.ding.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.project.ding.domain.entity.AdminWhiteListEntity;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface AdminWhiteListMapper extends BaseMapper<AdminWhiteListEntity> {
}

21
src/main/java/com/project/ding/utils/DingUtil.java

@ -16,9 +16,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
@Component
@ -39,6 +37,12 @@ public class DingUtil {
return res;
}
public String getUserIdByCode(String code) {
return Try.of(() -> dtService.getOauth2Service().getUserInfo(code).getUserId())
.getOrElse("");
}
public List<DingUserDTO> getAllDingUserDTO() throws Exception {
List<DepartmentDTO> list = getAllDepartment();
@ -81,6 +85,19 @@ public class DingUtil {
return u1;
}
public UserDTO getUserById(String id) {
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("userid" , id);
String url = dtService.getDtConfigStorage().getApiUrl("/topapi/v2/user/get");
String responseContent = Try.of(() -> dtService.post(url, jsonObject)).getOrElse("");
DingUserDTO dingUserDTO = Try.of(() -> new ObjectMapper().convertValue(
JsonPath.read(responseContent, "$.result"),
new TypeReference<DingUserDTO>() {
})).getOrNull();
return UserDTO.fromDingUserDTO(dingUserDTO);
}
public List<DingUserDTO> getUserIdInDepartment(Long id) throws Exception {
JsonObject jsonObject = new JsonObject();

29
src/main/java/com/project/ding/utils/JwtUtils.java

@ -0,0 +1,29 @@
package com.project.ding.utils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import org.springframework.stereotype.Component;
import java.security.Key;
import java.util.Date;
import java.util.List;
@Component
public class JwtUtils {
private static final Key KEY = Keys.secretKeyFor(SignatureAlgorithm.HS256);
private static final long EXPIRE = 86400000; // 24小时
public String createToken(String userId, List<String> roles) {
return Jwts.builder()
.setSubject(userId)
.claim("roles", roles)
.setExpiration(new Date(System.currentTimeMillis() + EXPIRE))
.signWith(KEY).compact();
}
public Claims parseToken(String token) {
return Jwts.parserBuilder().setSigningKey(KEY).build().parseClaimsJws(token).getBody();
}
}

14
src/main/java/com/project/information/application/InformationApplicationService.java

@ -0,0 +1,14 @@
package com.project.information.application;
import com.project.base.domain.result.Result;
import com.project.information.domain.param.FileCheckItem;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
public interface InformationApplicationService {
Result<String> checkDuplicates(Long subLineId, List<FileCheckItem> files) throws Exception;
Result<String> batchUploadAndOverwrite(MultipartFile[] files, Long subLineId) throws Exception;
}

28
src/main/java/com/project/information/application/impl/InformationApplicationServiceImpl.java

@ -0,0 +1,28 @@
package com.project.information.application.impl;
import com.project.base.domain.result.Result;
import com.project.information.application.InformationApplicationService;
import com.project.information.domain.param.FileCheckItem;
import com.project.information.domain.service.UploadInformationDomainService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
@Service
public class InformationApplicationServiceImpl implements InformationApplicationService {
@Autowired
private UploadInformationDomainService uploadInformationDomainService;
@Override
public Result<String> checkDuplicates(Long subLineId, List<FileCheckItem> files) throws Exception {
return uploadInformationDomainService.checkDuplicates(subLineId , files);
}
@Override
public Result<String> batchUploadAndOverwrite(MultipartFile[] files, Long subLineId) throws Exception {
return uploadInformationDomainService.batchUploadAndOverwrite(files , subLineId);
}
}

2
src/main/java/com/project/information/controller/BusinessGroupController.java

@ -16,7 +16,7 @@ import java.util.List;
@RestController
@Slf4j
@RequestMapping("/businessGroup")
@RequestMapping("/api/admin/businessGroup")
public class BusinessGroupController {
@Autowired
private BusinessGroupApplicationService businessGroupApplicationService;

27
src/main/java/com/project/information/controller/InformationController.java

@ -1,13 +1,34 @@
package com.project.information.controller;
import com.project.base.domain.result.Result;
import com.project.information.application.InformationApplicationService;
import com.project.information.application.ProductLineApplicationService;
import com.project.information.domain.dto.ProductLineDTO;
import com.project.information.domain.param.CheckDuplicatesParam;
import com.project.information.domain.param.FileCheckItem;
import com.project.information.domain.param.ProductLineParam;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
@RestController
@Slf4j
@RequestMapping("/information")
@RequestMapping("/api/admin/information")
public class InformationController {
@Autowired
private InformationApplicationService informationApplicationService;
@PostMapping("/checkDuplicates")
public Result<String> checkDuplicates(CheckDuplicatesParam param) throws Exception {
return informationApplicationService.checkDuplicates(param.getSubLineId(), param.getFileList());
}
@PostMapping("/batchUploadAndOverwrite")
public Result<String> batchUploadAndOverwrite(MultipartFile[] files, Long subLineId) throws Exception {
return informationApplicationService.batchUploadAndOverwrite(files , subLineId);
}
}

2
src/main/java/com/project/information/controller/ProductLineController.java

@ -17,7 +17,7 @@ import java.util.List;
@RestController
@Slf4j
@RequestMapping("/productLine")
@RequestMapping("/api/admin/productLine")
public class ProductLineController {
@Autowired

2
src/main/java/com/project/information/domain/dto/BusinessGroupDTO.java

@ -5,6 +5,8 @@ import lombok.Data;
@Data
public class BusinessGroupDTO extends BaseDTO {
private Long id;
private String name;
private String sort;
}

4
src/main/java/com/project/information/domain/dto/InformationDTO.java

@ -5,13 +5,13 @@ import lombok.Data;
@Data
public class InformationDTO extends BaseDTO {
private Long id;
private Long subLineId;
private String subLineName;
private String name;
private String filePath;
private Integer parseStatus;
private Integer partCount;
private String uploadId;
}

2
src/main/java/com/project/information/domain/dto/ProductLineDTO.java

@ -8,6 +8,8 @@ import java.util.List;
@Data
public class ProductLineDTO extends BaseDTO {
private Long id;
private String name;
private Integer sort = 0;
private Boolean leaf;

10
src/main/java/com/project/information/domain/entity/BusinessGroupEntity.java

@ -1,12 +1,11 @@
package com.project.information.domain.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.project.base.domain.entity.BaseEntity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Index;
import jakarta.persistence.Table;
import jakarta.persistence.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.hibernate.annotations.Comment;
@ -17,6 +16,9 @@ import org.hibernate.annotations.Comment;
@TableName(value = "evaluator_business_group")
@EqualsAndHashCode(callSuper = true)
public class BusinessGroupEntity extends BaseEntity {
@TableId(value = "id" , type = IdType.ASSIGN_ID)
@Id
private Long id;
@Column(name = "name" , columnDefinition="varchar(255) comment '事业部名称'")
private String name;

8
src/main/java/com/project/information/domain/entity/InformationEntity.java

@ -1,10 +1,13 @@
package com.project.information.domain.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.project.base.domain.entity.BaseEntity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.Data;
import lombok.EqualsAndHashCode;
@ -16,6 +19,9 @@ import org.hibernate.annotations.Comment;
@TableName(value = "evaluator_information")
@EqualsAndHashCode(callSuper = true)
public class InformationEntity extends BaseEntity {
@TableId(value = "id" , type = IdType.ASSIGN_ID)
@Id
private Long id;
@Column(name = "sub_line_id")
@Comment("所属子产品线ID")
@TableField("sub_line_id")
@ -39,6 +45,6 @@ public class InformationEntity extends BaseEntity {
@Column(name = "parse_status")
@TableField("parse_status")
@Comment("排序权重")
@Comment("文件处理状态")
private Integer parseStatus;
}

11
src/main/java/com/project/information/domain/entity/ProductLineEntity.java

@ -1,13 +1,12 @@
package com.project.information.domain.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.project.base.domain.entity.BaseEntity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Index;
import jakarta.persistence.Table;
import jakarta.persistence.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.hibernate.annotations.Comment;
@ -18,6 +17,10 @@ import org.hibernate.annotations.Comment;
@TableName(value = "evaluator_product_line")
@EqualsAndHashCode(callSuper = true)
public class ProductLineEntity extends BaseEntity {
@TableId(value = "id" , type = IdType.ASSIGN_ID)
@Id
private Long id;
@Column(name = "name" , columnDefinition="varchar(550) comment '部门名称'")
private String name;

15
src/main/java/com/project/information/domain/enums/InformationParseStatusEnum.java

@ -0,0 +1,15 @@
package com.project.information.domain.enums;
import com.project.base.domain.enums.HasValueEnum;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
public enum InformationParseStatusEnum implements HasValueEnum<Integer> {
NotStart(0) ,
InProgress(1) ,
Success(2) ,
Fail(-1);
@Getter
private final Integer value;
}

11
src/main/java/com/project/information/domain/param/BatchCheckParam.java

@ -0,0 +1,11 @@
package com.project.information.domain.param;
import lombok.Data;
import java.util.List;
@Data
public class BatchCheckParam {
private Long productLineId;
private List<FileCheckItem> files;
}

32
src/main/java/com/project/information/domain/param/CheckDuplicatesParam.java

@ -0,0 +1,32 @@
package com.project.information.domain.param;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.project.base.domain.exception.BusinessErrorException;
import lombok.Data;
import org.springframework.util.StringUtils;
import java.util.Collections;
import java.util.List;
@Data
public class CheckDuplicatesParam {
private Long subLineId;
private String files; // 先接收为字符串
// 手动解析为List的方法
public List<FileCheckItem> getFileList() {
if (StringUtils.isEmpty(files)) {
return Collections.emptyList();
}
try {
return new ObjectMapper().readValue(
files,
new TypeReference<List<FileCheckItem>>() {});
} catch (JsonProcessingException e) {
// 处理解析异常
throw new BusinessErrorException("Json解析失败");
}
}}

9
src/main/java/com/project/information/domain/param/FileCheckItem.java

@ -0,0 +1,9 @@
package com.project.information.domain.param;
import lombok.Data;
@Data
public class FileCheckItem {
private String name;
private Long size; // 单位:Byte
}

11
src/main/java/com/project/information/domain/service/UploadInformationDomainService.java

@ -1,11 +1,14 @@
package com.project.information.domain.service;
import com.project.base.domain.result.Result;
import com.project.information.domain.dto.FileDTO;
import com.project.information.domain.dto.InformationDTO;
import com.project.information.domain.dto.InitMultipartDTO;
import com.project.information.domain.param.FileCheckItem;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
public interface UploadInformationDomainService {
Result<String> checkDuplicates(Long subLineId, List<FileCheckItem> files) throws Exception;
Result<InitMultipartDTO> initMultiPartUpload(InformationDTO dto) throws Exception;
Result<String> batchUploadAndOverwrite(MultipartFile[] files, Long subLineId) throws Exception;
}

28
src/main/java/com/project/information/domain/service/UploadService.java

@ -1,28 +0,0 @@
package com.project.information.domain.service;
import com.project.information.domain.dto.StreamInfoDTO;
import java.util.Map;
public interface UploadService {
/**
* 分片上传初始化
*
* @param path 路径
* @param filename 文件名
* @param partCount 分片数量
* @param contentType /
* @return /
*/
Map<String, Object> initMultiPartUpload(String path, String filename, Integer partCount, String contentType);
/**
* 完成分片上传
*
* @param objectName 文件名
* @param uploadId 标识
* @return /
*/
StreamInfoDTO mergeMultipartUpload(String objectName, String uploadId);
}

115
src/main/java/com/project/information/domain/service/impl/UploadInformationDomainServiceImpl.java

@ -1,56 +1,117 @@
package com.project.information.domain.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.file.FileNameUtil;
import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.project.base.domain.exception.MissingParameterException;
import com.project.base.domain.exception.BusinessErrorException;
import com.project.base.domain.result.Result;
import com.project.base.domain.result.ResultCodeEnum;
import com.project.information.domain.dto.FileDTO;
import com.project.information.domain.dto.InformationDTO;
import com.project.information.domain.dto.InitMultipartDTO;
import com.project.information.domain.entity.InformationEntity;
import com.project.information.domain.entity.ProductLineEntity;
import com.project.information.domain.enums.InformationParseStatusEnum;
import com.project.information.domain.param.FileCheckItem;
import com.project.information.domain.service.InformationBaseService;
import com.project.information.domain.service.ProductLineBaseService;
import com.project.information.domain.service.UploadInformationDomainService;
import com.project.information.domain.service.UploadService;
import com.project.information.utils.MinIoUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import java.util.Map;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
@Service
public class UploadInformationDomainServiceImpl implements UploadInformationDomainService {
@Autowired
private UploadService uploadService;
@Autowired
private InformationBaseService informationBaseService;
@Autowired
private ProductLineBaseService productLineBaseService;
@Autowired
private MinIoUtils minIoUtils;
private static final long MAX_SIZE = 50 * 1024 * 1024; // 50MB 限制
@Override
public Result<InitMultipartDTO> initMultiPartUpload(InformationDTO dto) throws Exception {
if (StrUtil.isBlank(dto.getName()) || Objects.isNull(dto.getPartCount()) || Objects.isNull(dto.getSubLineId())) {
throw new MissingParameterException(ResultCodeEnum.MISSING_PARAMETER.getMessage());
public Result<String> checkDuplicates(Long subLineId, List<FileCheckItem> files) throws Exception {
if (Objects.isNull(subLineId)) {
throw new BusinessErrorException("所属子产品线id不能为空");
}
if (CollUtil.isEmpty(files)) {
throw new BusinessErrorException("上传文件集合不能为空");
}
ProductLineEntity productLine = productLineBaseService.getById(subLineId);
if (Objects.isNull(productLine) || !productLine.getLeaf()) {
throw new BusinessErrorException("不存在的子产品线");
}
String path = dto.getSubLineId().toString();
List<String> overSizeList = files.stream()
.filter(f -> f.getSize() > MAX_SIZE)
.map(FileCheckItem::getName)
.toList();
LambdaQueryWrapper<InformationEntity> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(InformationEntity::getSubLineId , dto.getSubLineId());
queryWrapper.eq(InformationEntity::getName , dto.getName());
InformationEntity existOne = informationBaseService.getOne(queryWrapper);
if (Objects.nonNull(existOne)) {
if (CollUtil.isNotEmpty(overSizeList)) {
// 发现超大文件,直接中断,不查数据库
throw new BusinessErrorException(String.format(
"以下文件超过50MB限制,禁止上传:【%s】",
String.join("、", overSizeList)));
}
List<String> fileNames = files.stream().map(FileCheckItem::getName).toList();
List<String> duplicatesList = informationBaseService.list(new LambdaQueryWrapper<InformationEntity>()
.select(InformationEntity::getName)
.eq(InformationEntity::getSubLineId, subLineId)
.in(InformationEntity::getName, fileNames))
.stream()
.map(InformationEntity::getName)
.toList();
if (CollUtil.isNotEmpty(duplicatesList)) {
throw new BusinessErrorException(String.format("你上传的文件集合中【%s】已存在,会进行覆盖操作,是否继续?" , String.join("," , duplicatesList)));
}
return Result.success("校验成功");
}
Map<String, Object> stringObjectMap = uploadService.initMultiPartUpload(path, dto.getName() , dto.getPartCount() , "application/octet-stream");
InitMultipartDTO initMultipartDTO = BeanUtil.mapToBean(stringObjectMap, InitMultipartDTO.class, true, CopyOptions.create());
initMultipartDTO.setObjectName(path + "/" + dto.getName());
return Result.success(initMultipartDTO);
@Override
@Transactional(rollbackFor = Exception.class)
public Result<String> batchUploadAndOverwrite(MultipartFile[] files, Long subLineId) throws Exception {
if (Objects.isNull(subLineId)) {
throw new BusinessErrorException("所属子产品线id不能为空");
}
if (Objects.isNull(files) || files.length == 0) {
throw new BusinessErrorException("上传文件集合不能为空");
}
ProductLineEntity productLine = productLineBaseService.getById(subLineId);
if (Objects.isNull(productLine) || !productLine.getLeaf()) {
throw new BusinessErrorException("不存在的子产品线");
}
List<String> successFiles = new ArrayList<>();
for (MultipartFile file : files) {
String fileName = file.getOriginalFilename();
// 删掉原来的
informationBaseService.remove(new LambdaQueryWrapper<InformationEntity>()
.eq(InformationEntity::getSubLineId, subLineId)
.eq(InformationEntity::getName, fileName));
String filePath = String.format("%s/%s/%s.%s",
subLineId,
DateUtil.format(new Date(), "yyyyMMdd"),
IdUtil.fastSimpleUUID(),
FileNameUtil.extName(fileName));
minIoUtils.uploadFile(file.getInputStream() , filePath);
successFiles.add(fileName);
InformationDTO informationDTO = new InformationDTO();
informationDTO.setSubLineId(subLineId);
informationDTO.setSubLineName(productLine.getName());
informationDTO.setName(fileName);
informationDTO.setFilePath(filePath);
informationDTO.setParseStatus(InformationParseStatusEnum.NotStart.getValue());
informationBaseService.save(informationDTO.toEntity(InformationEntity::new));
}
return Result.success(String.format("上传成功:【%s】" , String.join("," , successFiles)));
}
}

43
src/main/java/com/project/information/domain/service/impl/UploadServiceImpl.java

@ -1,43 +0,0 @@
package com.project.information.domain.service.impl;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.project.information.domain.dto.StreamInfoDTO;
import com.project.information.domain.service.UploadService;
import com.project.information.utils.MinIoUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.Map;
@Service
@RequiredArgsConstructor
public class UploadServiceImpl implements UploadService {
private final MinIoUtils minIoUtils;
@Override
public Map<String, Object> initMultiPartUpload(String path, String filename, Integer partCount, String contentType) {
path = path.replaceAll("/+", "/");
if (path.indexOf("/") == 0) {
path = path.substring(1);
}
String filePath = path + "/" + filename;
Map<String, Object> result;
// 单文件,直接上传
if (partCount == 1) {
String uploadObjectUrl = minIoUtils.getUploadObjectUrl(filePath);
result = ImmutableMap.of("uploadUrls", ImmutableList.of(uploadObjectUrl));
} else {//多文件,分片上传
result = minIoUtils.initMultiPartUpload(filePath, partCount, contentType);
}
return result;
}
@Override
public StreamInfoDTO mergeMultipartUpload(String objectName, String uploadId) {
return minIoUtils.mergeMultipartUpload(objectName, uploadId);
}
}

86
src/main/java/com/project/information/utils/MinIoUtils.java

@ -5,18 +5,15 @@ import com.google.common.collect.HashMultimap;
import com.project.information.config.CustomMinioClient;
import com.project.information.config.MinioProperties;
import com.project.information.domain.dto.StreamInfoDTO;
import io.minio.GetObjectArgs;
import io.minio.GetPresignedObjectUrlArgs;
import io.minio.ListPartsResponse;
import io.minio.MinioClient;
import io.minio.*;
import io.minio.http.Method;
import io.minio.messages.Part;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@ -124,4 +121,83 @@ public class MinIoUtils {
return null;
}
}
/**
* 简化的InputStream上传方法自动设置ContentType
*
* @param inputStream 文件输入流
* @param fileName 文件名
* @return
*/
public String uploadFile(InputStream inputStream, String fileName) throws Exception{
String contentType = getContentTypeByFileName(fileName);
uploadInputStream(inputStream, fileName, contentType);
return fileName;
}
/**
* 根据文件扩展名自动设置ContentType
*
* @param fileName 文件名
* @return ContentType
*/
private String getContentTypeByFileName(String fileName) {
if (StrUtil.isBlank(fileName)) {
return "application/octet-stream";
}
String extension = fileName.toLowerCase();
if (extension.endsWith(".xlsx")) {
return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
} else if (extension.endsWith(".xls")) {
return "application/vnd.ms-excel";
} else if (extension.endsWith(".docx")) {
return "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
} else if (extension.endsWith(".doc")) {
return "application/msword";
} else if (extension.endsWith(".pdf")) {
return "application/pdf";
} else if (extension.endsWith(".txt")) {
return "text/plain";
} else if (extension.endsWith(".jpg") || extension.endsWith(".jpeg")) {
return "image/jpeg";
} else if (extension.endsWith(".png")) {
return "image/png";
} else {
return "application/octet-stream";
}
}
public void uploadInputStream(InputStream inputStream, String objectName, String contentType) throws Exception{
if (inputStream == null) {
log.error("文件上传失败,输入流不能为空");
return;
}
if (StrUtil.isBlank(objectName)) {
log.error("文件上传失败,文件名不能为空");
return;
}
// 设置默认内容类型
if (StrUtil.isBlank(contentType)) {
contentType = "application/octet-stream";
}
// 设置请求头
HashMultimap<String, String> headers = HashMultimap.create();
headers.put("Content-Type", contentType);
// 上传文件
customMinioClient.putObject(
PutObjectArgs.builder()
.bucket(minioProperties.getBucket())
.object(objectName)
.stream(inputStream, -1, 10485760) // 10MB part size
.headers(headers)
.build()
);
log.info("文件上传成功,"+objectName);
}
}

17
src/main/resources/application.yml

@ -10,11 +10,14 @@ spring:
driverClassName: com.mysql.cj.jdbc.Driver
password: Itc@123456
url: jdbc:mysql://172.16.204.50:3306/ai_evaluator?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true
# url: jdbc:mysql://8.129.84.155:3306/ai_evaluator?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true
username: root
# Redis
data:
redis:
host: 172.16.204.50
# host: 8.129.84.155
port: 6379
password: 123456
database: 3
@ -47,10 +50,10 @@ spring:
generator:
write-numbers-as-strings: true
minio:
endpoint: ${MINIO_ENDPOINT:http://172.16.124.14:9000}
accessKey: ${MINIO_ASSESSKEY:X42cCp42U4BSJHPAV1Aq}
secretKey: ${MINIO_SECRETKEY:099NCOOSklhJyeJE6C73YxbbUT4Y4dRJK0RafAgv}
bucket: ${MINIO_BUCKET:proposalworkshop}
endpoint: ${MINIO_ENDPOINT:http://172.16.204.50:9000}
accessKey: ${MINIO_ASSESSKEY:DTKYZDZM1i31XOvd24SP}
secretKey: ${MINIO_SECRETKEY:PnfLPcJbvaUboZIwYZAADPB0pDtPZgbi0QiLSs3C}
bucket: ${MINIO_BUCKET:ai-evaluator}
mybatis-plus:
configuration:
map-underscore-to-camel-case: true
@ -59,4 +62,8 @@ mybatis-plus:
milvus:
host: 172.16.204.50
port: 19530
port: 19530
ding:
appKey: ding7ocyghkjyowg38ck
appSecret: x1SWUdGfiLzjeRAoicGQO49J73sI59gwgPXLLkcoI6DY4M0UZDDND4QT2laNtT22
agentId: 4145005949
Loading…
Cancel
Save