mirror of
				https://github.com/suyiiyii/SIMS.git
				synced 2025-11-04 15:54:52 +08:00 
			
		
		
		
	
						commit
						94bf792cd2
					
				
							
								
								
									
										20
									
								
								pom.xml
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								pom.xml
									
									
									
									
									
								
							@ -95,16 +95,34 @@
 | 
			
		||||
            <artifactId>spring-restdocs-mockmvc</artifactId>
 | 
			
		||||
            <scope>test</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
        <!-- https://mvnrepository.com/artifact/org.springdoc/springdoc-openapi-starter-webmvc-ui -->
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>org.springdoc</groupId>
 | 
			
		||||
            <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
 | 
			
		||||
            <version>2.3.0</version>
 | 
			
		||||
            <version>2.6.0</version>
 | 
			
		||||
        </dependency>
 | 
			
		||||
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>org.xerial</groupId>
 | 
			
		||||
            <artifactId>sqlite-jdbc</artifactId>
 | 
			
		||||
            <scope>test</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>com.amazonaws</groupId>
 | 
			
		||||
            <artifactId>aws-java-sdk-s3</artifactId>
 | 
			
		||||
            <version>1.12.706</version>
 | 
			
		||||
        </dependency>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>commons-io</groupId>
 | 
			
		||||
            <artifactId>commons-io</artifactId>
 | 
			
		||||
            <version>2.11.0</version>
 | 
			
		||||
        </dependency>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>org.mockito</groupId>
 | 
			
		||||
            <artifactId>mockito-core</artifactId>
 | 
			
		||||
            <version>4.0.0</version>
 | 
			
		||||
            <scope>test</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
    </dependencies>
 | 
			
		||||
 | 
			
		||||
    <build>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										17
									
								
								src/main/java/top/suyiiyii/sims/common/S3Config.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								src/main/java/top/suyiiyii/sims/common/S3Config.java
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,17 @@
 | 
			
		||||
package top.suyiiyii.sims.common;
 | 
			
		||||
 | 
			
		||||
import org.springframework.beans.factory.annotation.Value;
 | 
			
		||||
import org.springframework.context.annotation.Bean;
 | 
			
		||||
import org.springframework.context.annotation.Configuration;
 | 
			
		||||
import top.suyiiyii.sims.utils.S3Client;
 | 
			
		||||
 | 
			
		||||
@Configuration
 | 
			
		||||
public class S3Config {
 | 
			
		||||
    @Bean
 | 
			
		||||
    public static S3Client Config(@Value("${S3.ENDPOINT}") String endpoint,
 | 
			
		||||
                                  @Value("${S3.ACCESS_KEY}") String accessKey,
 | 
			
		||||
                                  @Value("${S3.SECRET_KEY}") String secretKey,
 | 
			
		||||
                                  @Value("${S3.BUCKET}") String bucket) {
 | 
			
		||||
        return new S3Client(endpoint, accessKey, secretKey, bucket);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,40 @@
 | 
			
		||||
package top.suyiiyii.sims.controller;
 | 
			
		||||
 | 
			
		||||
import io.swagger.v3.oas.annotations.Operation;
 | 
			
		||||
import io.swagger.v3.oas.annotations.Parameter;
 | 
			
		||||
import io.swagger.v3.oas.annotations.media.Content;
 | 
			
		||||
import io.swagger.v3.oas.annotations.media.Schema;
 | 
			
		||||
import io.swagger.v3.oas.annotations.parameters.RequestBody;
 | 
			
		||||
import lombok.extern.slf4j.Slf4j;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.web.bind.annotation.PostMapping;
 | 
			
		||||
import org.springframework.web.bind.annotation.RestController;
 | 
			
		||||
import org.springframework.web.multipart.MultipartFile;
 | 
			
		||||
import top.suyiiyii.sims.common.AuthAccess;
 | 
			
		||||
import top.suyiiyii.sims.service.FileService;
 | 
			
		||||
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.io.InputStream;
 | 
			
		||||
 | 
			
		||||
@Slf4j
 | 
			
		||||
@RestController
 | 
			
		||||
public class FileController {
 | 
			
		||||
    @Autowired
 | 
			
		||||
    FileService fileService;
 | 
			
		||||
 | 
			
		||||
    @AuthAccess(allowRoles = {"user"})
 | 
			
		||||
    @Operation(summary = "上传文件", description = "使用form-data格式\nfile:文件\nfilename: 文件名\n返回可访问的路径")
 | 
			
		||||
    @PostMapping("/upload")
 | 
			
		||||
    public String uploadFile(
 | 
			
		||||
            @Parameter String filename,
 | 
			
		||||
            @RequestBody(content = @Content(mediaType = "multipart/form-data",
 | 
			
		||||
                    schema = @Schema(type = "string", format = "binary"))) MultipartFile file) {
 | 
			
		||||
        try (InputStream in = file.getInputStream()) {
 | 
			
		||||
            log.info("文件上传,文件名:{},描述:{}", file.getOriginalFilename(), filename);
 | 
			
		||||
            return fileService.uploadFile(in, filename);
 | 
			
		||||
        } catch (IOException e) {
 | 
			
		||||
            log.warn("文件上传失败", e);
 | 
			
		||||
            throw new RuntimeException(e);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										18
									
								
								src/main/java/top/suyiiyii/sims/service/FileService.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/main/java/top/suyiiyii/sims/service/FileService.java
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,18 @@
 | 
			
		||||
package top.suyiiyii.sims.service;
 | 
			
		||||
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.stereotype.Service;
 | 
			
		||||
import top.suyiiyii.sims.utils.S3Client;
 | 
			
		||||
 | 
			
		||||
import java.io.InputStream;
 | 
			
		||||
 | 
			
		||||
@Service
 | 
			
		||||
public class FileService {
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private S3Client s3Client;
 | 
			
		||||
 | 
			
		||||
    public String uploadFile(InputStream input,String fileName) {
 | 
			
		||||
        String extension = fileName.substring(fileName.lastIndexOf("."));
 | 
			
		||||
        return s3Client.uploadFile(input, extension);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										123
									
								
								src/main/java/top/suyiiyii/sims/utils/S3Client.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										123
									
								
								src/main/java/top/suyiiyii/sims/utils/S3Client.java
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,123 @@
 | 
			
		||||
package top.suyiiyii.sims.utils;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
import com.amazonaws.ClientConfiguration;
 | 
			
		||||
import com.amazonaws.Protocol;
 | 
			
		||||
import com.amazonaws.auth.AWSCredentials;
 | 
			
		||||
import com.amazonaws.auth.BasicAWSCredentials;
 | 
			
		||||
import com.amazonaws.services.s3.AmazonS3;
 | 
			
		||||
import com.amazonaws.services.s3.AmazonS3Client;
 | 
			
		||||
import com.amazonaws.services.s3.S3ClientOptions;
 | 
			
		||||
import com.amazonaws.services.s3.model.ObjectMetadata;
 | 
			
		||||
import com.amazonaws.services.s3.model.S3Object;
 | 
			
		||||
import org.apache.commons.io.IOUtils;
 | 
			
		||||
 | 
			
		||||
import java.io.InputStream;
 | 
			
		||||
import java.io.OutputStream;
 | 
			
		||||
import java.net.MalformedURLException;
 | 
			
		||||
import java.net.URL;
 | 
			
		||||
import java.util.UUID;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
public class S3Client {
 | 
			
		||||
    private final String endpoint;
 | 
			
		||||
    private final String bucket;
 | 
			
		||||
    private final AmazonS3 s3client;
 | 
			
		||||
 | 
			
		||||
    public S3Client(String endpoint, String accessKey, String secretKey, String bucket) {
 | 
			
		||||
        this.endpoint = endpoint;
 | 
			
		||||
        this.bucket = bucket;
 | 
			
		||||
        URL endpointUrl;
 | 
			
		||||
        try {
 | 
			
		||||
            endpointUrl = new URL(endpoint);
 | 
			
		||||
        } catch (MalformedURLException e) {
 | 
			
		||||
            throw new RuntimeException(e);
 | 
			
		||||
        }
 | 
			
		||||
        String protocol = endpointUrl.getProtocol();
 | 
			
		||||
        int port = endpointUrl.getPort() == -1 ? endpointUrl.getDefaultPort() : endpointUrl.getPort();
 | 
			
		||||
        ClientConfiguration clientConfig = new ClientConfiguration();
 | 
			
		||||
        clientConfig.setSignerOverride("S3SignerType");
 | 
			
		||||
        clientConfig.setProtocol(Protocol.valueOf(protocol.toUpperCase()));
 | 
			
		||||
        // 禁用证书检查,避免https自签证书校验失败
 | 
			
		||||
        System.setProperty("com.amazonaws.sdk.disableCertChecking", "true");
 | 
			
		||||
        // 屏蔽 AWS 的 MD5 校验,避免校验导致的下载抛出异常问题
 | 
			
		||||
        System.setProperty("com.amazonaws.services.s3.disableGetObjectMD5Validation", "true");
 | 
			
		||||
        AWSCredentials awsCredentials = new BasicAWSCredentials(accessKey, secretKey);
 | 
			
		||||
        // 创建 S3Client 实例
 | 
			
		||||
        AmazonS3 s3client = new AmazonS3Client(awsCredentials, clientConfig);
 | 
			
		||||
        s3client.setEndpoint(endpointUrl.getHost() + ":" + port);
 | 
			
		||||
        s3client.setS3ClientOptions(S3ClientOptions.builder().setPathStyleAccess(true).build());
 | 
			
		||||
        this.s3client = s3client;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public boolean bucketExists(String bucket) {
 | 
			
		||||
        try {
 | 
			
		||||
            return s3client.doesBucketExist(bucket);
 | 
			
		||||
        } catch (Exception e) {
 | 
			
		||||
            e.printStackTrace();
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public boolean existObject(String bucket, String objectId) {
 | 
			
		||||
        try {
 | 
			
		||||
            return s3client.doesObjectExist(bucket, objectId);
 | 
			
		||||
        } catch (Exception e) {
 | 
			
		||||
            e.printStackTrace();
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public InputStream download(String bucket, String objectId) {
 | 
			
		||||
        try {
 | 
			
		||||
            S3Object o = s3client.getObject(bucket, objectId);
 | 
			
		||||
            return o.getObjectContent();
 | 
			
		||||
        } catch (Exception e) {
 | 
			
		||||
            e.printStackTrace();
 | 
			
		||||
        }
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void download(String bucket, String objectId, OutputStream out) {
 | 
			
		||||
        S3Object o = s3client.getObject(bucket, objectId);
 | 
			
		||||
        try (InputStream in = o.getObjectContent()) {
 | 
			
		||||
            IOUtils.copyLarge(in, out);
 | 
			
		||||
        } catch (Exception e) {
 | 
			
		||||
            e.printStackTrace();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void upload(String bucket, String objectId, InputStream input) {
 | 
			
		||||
        try {
 | 
			
		||||
            // 创建文件上传的元数据
 | 
			
		||||
            ObjectMetadata meta = new ObjectMetadata();
 | 
			
		||||
            // 设置文件上传长度
 | 
			
		||||
            meta.setContentLength(input.available());
 | 
			
		||||
            // 上传
 | 
			
		||||
            s3client.putObject(bucket, objectId, input, meta);
 | 
			
		||||
        } catch (Exception e) {
 | 
			
		||||
            e.printStackTrace();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String uploadFile(InputStream input) {
 | 
			
		||||
        String objectID = UUID.randomUUID().toString();
 | 
			
		||||
        upload(bucket, objectID, input);
 | 
			
		||||
        return endpoint + "/" + bucket + "/" + objectID;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 接收文件流,自动使用随机uuid命名并保留扩展名
 | 
			
		||||
     * 返回公网上可以直接访问的URL
 | 
			
		||||
     *
 | 
			
		||||
     * @param input         文件流
 | 
			
		||||
     * @param extensionName 扩展名
 | 
			
		||||
     * @return 文件的URL
 | 
			
		||||
     */
 | 
			
		||||
    public String uploadFile(InputStream input, String extensionName) {
 | 
			
		||||
        String objectID = UUID.randomUUID() + extensionName;
 | 
			
		||||
        upload(bucket, objectID, input);
 | 
			
		||||
        return endpoint + "/" + bucket + "/" + objectID;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -2,6 +2,10 @@
 | 
			
		||||
spring:
 | 
			
		||||
  profiles:
 | 
			
		||||
    active: prod
 | 
			
		||||
  servlet:
 | 
			
		||||
    multipart:
 | 
			
		||||
      max-file-size: 100MB
 | 
			
		||||
      max-request-size: 100MB
 | 
			
		||||
  datasource:
 | 
			
		||||
    url: ${DATASOURCE_URL}
 | 
			
		||||
    username: ${DATASOURCE_USERNAME}
 | 
			
		||||
@ -15,3 +19,9 @@ auto-table:
 | 
			
		||||
 | 
			
		||||
jwt:
 | 
			
		||||
  secret: ${JWT_SECRET}
 | 
			
		||||
 | 
			
		||||
S3:
 | 
			
		||||
  ENDPOINT: ${S3_ENDPOINT}
 | 
			
		||||
  BUCKET: ${S3_BUCKET}
 | 
			
		||||
  ACCESS_KEY: ${S3_ACCESS_KEY}
 | 
			
		||||
  SECRET_KEY: ${S3_SECRET_KEY}
 | 
			
		||||
 | 
			
		||||
@ -1,10 +1,14 @@
 | 
			
		||||
package top.suyiiyii.sims.service;
 | 
			
		||||
 | 
			
		||||
import org.junit.jupiter.api.Test;
 | 
			
		||||
import org.junit.jupiter.api.extension.ExtendWith;
 | 
			
		||||
import org.mockito.junit.jupiter.MockitoExtension;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.boot.test.context.SpringBootTest;
 | 
			
		||||
import org.springframework.boot.test.mock.mockito.MockBean;
 | 
			
		||||
import org.springframework.test.context.ActiveProfiles;
 | 
			
		||||
import top.suyiiyii.sims.entity.Role;
 | 
			
		||||
import top.suyiiyii.sims.utils.S3Client;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
@ -12,11 +16,15 @@ import static org.junit.jupiter.api.Assertions.*;
 | 
			
		||||
 | 
			
		||||
@SpringBootTest
 | 
			
		||||
@ActiveProfiles("test")
 | 
			
		||||
@ExtendWith(MockitoExtension.class)
 | 
			
		||||
class RbacServiceTest {
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private RbacService rbacService;
 | 
			
		||||
 | 
			
		||||
    @MockBean
 | 
			
		||||
    private S3Client s3Client;
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    void addRoleWithUserId() {
 | 
			
		||||
        int userId = 1; // mock userId
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user