diff --git a/backend/pom.xml b/backend/pom.xml index e5eab37f..47300155 100644 --- a/backend/pom.xml +++ b/backend/pom.xml @@ -244,10 +244,6 @@ org.apache.logging.log4j log4j-web - - com.amazonaws - aws-java-sdk-s3 - ${project.parent.artifactId} diff --git a/backend/src/main/java/ervu/client/fileupload/FileUploadWebDavClient.java b/backend/src/main/java/ervu/client/fileupload/FileUploadWebDavClient.java deleted file mode 100644 index a296ee50..00000000 --- a/backend/src/main/java/ervu/client/fileupload/FileUploadWebDavClient.java +++ /dev/null @@ -1,48 +0,0 @@ -package ervu.client.fileupload; - -import java.io.IOException; -import java.net.Authenticator; -import java.net.PasswordAuthentication; -import java.net.URI; -import java.net.http.HttpClient; -import java.net.http.HttpRequest; -import java.net.http.HttpResponse; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.retry.annotation.Backoff; -import org.springframework.retry.annotation.Retryable; -import org.springframework.stereotype.Component; -import org.springframework.web.multipart.MultipartFile; - -/** - * @author Alexandr Shalaginov - */ -@Component -public class FileUploadWebDavClient { - private static final Logger logger = LoggerFactory.getLogger(FileUploadWebDavClient.class); - - @Retryable(value = {IOException.class, InterruptedException.class}, backoff = @Backoff(delay = 500L)) - public boolean webDavUploadFile(String url, String username, String password, MultipartFile multipartFile) { - try { - HttpClient httpClient = HttpClient.newBuilder() - .authenticator(new Authenticator() { - @Override - protected PasswordAuthentication getPasswordAuthentication() { - return new PasswordAuthentication(username, password.toCharArray()); - } - }) - .build(); - - HttpRequest httpRequest = HttpRequest.newBuilder().uri(URI.create(url)) - .PUT(HttpRequest.BodyPublishers.ofByteArray(multipartFile.getBytes())).build(); - - HttpResponse response = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString()); - logger.debug("Response status code: {}", response.statusCode()); - return (response.statusCode() >= 200) && (response.statusCode() <= 202); - } - catch (IOException | InterruptedException e) { - throw new RuntimeException(e); - } - } -} diff --git a/backend/src/main/java/ervu/client/fileupload/WebDavClient.java b/backend/src/main/java/ervu/client/fileupload/WebDavClient.java new file mode 100644 index 00000000..acfa6458 --- /dev/null +++ b/backend/src/main/java/ervu/client/fileupload/WebDavClient.java @@ -0,0 +1,106 @@ +package ervu.client.fileupload; + +import java.io.IOException; +import java.io.InputStream; +import java.net.Authenticator; +import java.net.PasswordAuthentication; +import java.net.URI; +import java.net.URLEncoder; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.charset.StandardCharsets; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.io.InputStreamResource; +import org.springframework.core.io.Resource; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.retry.annotation.Backoff; +import org.springframework.retry.annotation.Retryable; +import org.springframework.stereotype.Component; +import org.springframework.web.multipart.MultipartFile; + +/** + * @author Alexandr Shalaginov + */ +@Component +public class WebDavClient { + private static final Logger logger = LoggerFactory.getLogger(WebDavClient.class); + + @Value("${file.webdav.upload.username}") + private String username; + @Value("${file.webdav.upload.password}") + private String password; + + @Retryable(value = {IOException.class, InterruptedException.class}, backoff = @Backoff(delay = 500L)) + public boolean webDavUploadFile(String url, MultipartFile multipartFile) { + try { + HttpClient httpClient = HttpClient.newBuilder() + .authenticator(new Authenticator() { + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(username, password.toCharArray()); + } + }) + .build(); + + HttpRequest httpRequest = HttpRequest.newBuilder().uri(URI.create(url)) + .PUT(HttpRequest.BodyPublishers.ofByteArray(multipartFile.getBytes())).build(); + + HttpResponse response = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString()); + logger.debug("Response status code: {}", response.statusCode()); + return (response.statusCode() >= 200) && (response.statusCode() <= 202); + } + catch (IOException | InterruptedException e) { + throw new RuntimeException(e); + } + } + + @Retryable(value = {IOException.class, InterruptedException.class}, + backoff = @Backoff(delay = 500L)) + public ResponseEntity webDavDownloadFile(String url) { + try { + HttpClient httpClient = HttpClient.newBuilder() + .authenticator(new Authenticator() { + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(username, password.toCharArray()); + } + }).build(); + + HttpRequest httpRequest = HttpRequest.newBuilder().uri(URI.create(url)) + .GET().build(); + + HttpResponse response = httpClient.send(httpRequest, + HttpResponse.BodyHandlers.ofInputStream() + ); + + if (response.statusCode() == 200) { + InputStreamResource resource = new InputStreamResource(response.body()); + String encodedFilename = URLEncoder.encode(getFilenameFromUrl(url), StandardCharsets.UTF_8); + return ResponseEntity.ok() + .header(HttpHeaders.CONTENT_DISPOSITION, + "attachment; filename*=UTF-8''" + encodedFilename + ) + .contentType(MediaType.APPLICATION_OCTET_STREAM) + .body(resource); + } + else { + logger.error("Failed to download file: HTTP status code {}", response.statusCode()); + return ResponseEntity.status(response.statusCode()).build(); + } + } + catch (IOException | InterruptedException e) { + throw new RuntimeException(e); + } + } + + private String getFilenameFromUrl(String url) { + String path = URI.create(url).getPath(); + return path.substring(path.lastIndexOf('/') + 1); + } +} diff --git a/backend/src/main/java/ervu/service/fileupload/EmployeeInfoFileUploadService.java b/backend/src/main/java/ervu/service/fileupload/EmployeeInfoFileUploadService.java index 93de694c..5405b2a6 100644 --- a/backend/src/main/java/ervu/service/fileupload/EmployeeInfoFileUploadService.java +++ b/backend/src/main/java/ervu/service/fileupload/EmployeeInfoFileUploadService.java @@ -9,7 +9,7 @@ import java.util.UUID; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import ervu.client.fileupload.FileUploadWebDavClient; +import ervu.client.fileupload.WebDavClient; import ervu.model.fileupload.DownloadResponse; import ervu.model.fileupload.EmployeeInfoFileFormType; import ervu.model.fileupload.EmployeeInfoKafkaMessage; @@ -43,7 +43,7 @@ public class EmployeeInfoFileUploadService { private static final Logger logger = LoggerFactory.getLogger(EmployeeInfoFileUploadService.class); private static final String FORMAT = "dd.MM.yyyy HH:mm:ss"; - private final FileUploadWebDavClient fileWebDavUploadClient; + private final WebDavClient fileWebDavUploadClient; private final EmployeeInfoKafkaMessageService employeeInfoKafkaMessageService; private final KafkaTemplate kafkaTemplate; private final InteractionService interactionService; @@ -54,13 +54,9 @@ public class EmployeeInfoFileUploadService { private String kafkaTopicName; @Value("${file.webdav.upload.url:http://localhost:5757}") private String url; - @Value("${file.webdav.upload.username}") - private String username; - @Value("${file.webdav.upload.password}") - private String password; public EmployeeInfoFileUploadService( - FileUploadWebDavClient fileWebDavUploadClient, + WebDavClient fileWebDavUploadClient, EmployeeInfoKafkaMessageService employeeInfoKafkaMessageService, @Qualifier("avTemplate") KafkaTemplate kafkaTemplate, InteractionService interactionService, @@ -77,7 +73,7 @@ public class EmployeeInfoFileUploadService { String fileUploadUrl = this.url + "/" + getNewFilename(multipartFile.getOriginalFilename()); LocalDateTime now = LocalDateTime.now(); - if (this.fileWebDavUploadClient.webDavUploadFile(fileUploadUrl, username, password, multipartFile)) { + if (this.fileWebDavUploadClient.webDavUploadFile(fileUploadUrl, multipartFile)) { FileStatus fileStatus = new FileStatus(); fileStatus.setStatus("Загрузка."); fileStatus.setCode("01"); diff --git a/backend/src/main/java/ru/micord/ervu/kafka/controller/ErvuKafkaController.java b/backend/src/main/java/ru/micord/ervu/kafka/controller/ErvuKafkaController.java index 7ee85074..6fde739e 100644 --- a/backend/src/main/java/ru/micord/ervu/kafka/controller/ErvuKafkaController.java +++ b/backend/src/main/java/ru/micord/ervu/kafka/controller/ErvuKafkaController.java @@ -4,6 +4,7 @@ import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import com.fasterxml.jackson.databind.ObjectMapper; +import ervu.client.fileupload.WebDavClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.io.Resource; @@ -13,7 +14,6 @@ import org.springframework.web.bind.annotation.RestController; import ru.micord.ervu.kafka.model.Data; import ru.micord.ervu.kafka.model.ExcerptResponse; import ru.micord.ervu.kafka.service.ReplyingKafkaService; -import ru.micord.ervu.s3.S3Service; import ru.micord.ervu.security.webbpm.jwt.model.Token; import ru.micord.ervu.security.webbpm.jwt.service.JwtTokenService; @@ -27,7 +27,7 @@ public class ErvuKafkaController { private ReplyingKafkaService replyingKafkaService; @Autowired - private S3Service s3Service; + private WebDavClient webDavClient; @Autowired private JwtTokenService jwtTokenService; @@ -56,12 +56,11 @@ public class ErvuKafkaController { objectMapper.writeValueAsString(data) ); ExcerptResponse excerptResponse = objectMapper.readValue(kafkaResponse, ExcerptResponse.class); - return s3Service.getFile(excerptResponse.getFileUrl()); + return webDavClient.webDavDownloadFile(excerptResponse.getFileUrl()); } catch (Exception e) { throw new RuntimeException(e); } - } private String getAuthToken(HttpServletRequest request) { diff --git a/backend/src/main/java/ru/micord/ervu/s3/S3Connection.java b/backend/src/main/java/ru/micord/ervu/s3/S3Connection.java deleted file mode 100644 index f0134cc5..00000000 --- a/backend/src/main/java/ru/micord/ervu/s3/S3Connection.java +++ /dev/null @@ -1,44 +0,0 @@ -package ru.micord.ervu.s3; - -import com.amazonaws.auth.AWSCredentials; -import com.amazonaws.auth.AWSStaticCredentialsProvider; -import com.amazonaws.auth.BasicAWSCredentials; -import com.amazonaws.client.builder.AwsClientBuilder; -import com.amazonaws.regions.Region; -import com.amazonaws.regions.Regions; -import com.amazonaws.services.s3.AmazonS3; -import com.amazonaws.services.s3.AmazonS3ClientBuilder; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -/** - * @author Eduard Tihomirov - */ -@Configuration -public class S3Connection { - @Value("${s3.endpoint}") - private String endpoint; - @Value("${s3.access_key}") - private String accessKey; - @Value("${s3.secret_key}") - private String secretKey; - @Value("${s3.path.style.access.enabled:true}") - private boolean pathStyleAccessEnabled; - - @Bean("outClient") - public AmazonS3 getS3OutClient() { - return getS3Client(endpoint, accessKey, secretKey, pathStyleAccessEnabled); - } - - private static AmazonS3 getS3Client(String endpoint, String accessKey, String secretKey, Boolean pathStyleAccessEnabled) { - AWSCredentials credentials = new BasicAWSCredentials(accessKey, secretKey); - String region = Region.getRegion(Regions.DEFAULT_REGION).toString(); - - return AmazonS3ClientBuilder.standard() - .withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(endpoint, region)) - .withCredentials(new AWSStaticCredentialsProvider(credentials)) - .withPathStyleAccessEnabled(pathStyleAccessEnabled) - .build(); - } -} diff --git a/backend/src/main/java/ru/micord/ervu/s3/S3Service.java b/backend/src/main/java/ru/micord/ervu/s3/S3Service.java deleted file mode 100644 index 509de3e8..00000000 --- a/backend/src/main/java/ru/micord/ervu/s3/S3Service.java +++ /dev/null @@ -1,48 +0,0 @@ -package ru.micord.ervu.s3; - -import java.net.URLEncoder; -import java.nio.charset.StandardCharsets; - -import com.amazonaws.AmazonServiceException; -import com.amazonaws.services.s3.AmazonS3; -import com.amazonaws.services.s3.AmazonS3URI; -import com.amazonaws.services.s3.model.S3Object; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.core.io.InputStreamResource; -import org.springframework.core.io.Resource; -import org.springframework.http.HttpHeaders; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; -import org.springframework.stereotype.Service; -/** - * @author Eduard Tihomirov - */ -@Service -public class S3Service { - private final AmazonS3 outClient; - - @Autowired - public S3Service(AmazonS3 outClient) { - this.outClient = outClient; - } - - public ResponseEntity getFile(String fileUrl) { - try { - if (fileUrl == null || fileUrl.isEmpty()) { - return ResponseEntity.noContent().build(); - } - AmazonS3URI uri = new AmazonS3URI(fileUrl); - S3Object s3Object = outClient.getObject(uri.getBucket(), uri.getKey()); - InputStreamResource resource = new InputStreamResource(s3Object.getObjectContent()); - String encodedFilename = URLEncoder.encode(uri.getKey(), StandardCharsets.UTF_8); - return ResponseEntity.ok() - .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename*=UTF-8''" + encodedFilename) - .contentLength(s3Object.getObjectMetadata().getContentLength()) - .contentType(MediaType.APPLICATION_OCTET_STREAM) - .body(resource); - } - catch (AmazonServiceException e) { - throw new RuntimeException(e); - } - } -} diff --git a/config.md b/config.md index 64db5212..850d2b34 100644 --- a/config.md +++ b/config.md @@ -813,10 +813,4 @@ JBPM использует 3 корневых категории логирова - `ERVU_KAFKA_JOURNAL_REPLY_TOPIC` - топик для чтения данных по журналу взаимодействия - `ERVU_KAFKA_EXCERPT_REQUEST_TOPIC` - топик для записи запроса для получения выписки по журналу взаимодействия - `ERVU_KAFKA_EXCERPT_REPLY_TOPIC` - топик для чтения выписки по журналу взаимодействия. Содержит ссылку на S3 с файлом выписки -- `DB.JOURNAL.EXCLUDED.STATUSES` - статусы файла, которые необходимо исключить при получении данных по журналу взаимодействия из базы данных приложения - -#### Взаимодействие с S3 - -- `S3_ENDPOINT` - url для подключения к S3 -- `S3_ACCESS_KEY` - публичная часть учетных данных AWS -- `S3_SECRET_KEY` - закрытая часть пары ключей AWS \ No newline at end of file +- `DB.JOURNAL.EXCLUDED.STATUSES` - статусы файла, которые необходимо исключить при получении данных по журналу взаимодействия из базы данных приложения \ No newline at end of file diff --git a/config/micord.env b/config/micord.env index 98c77294..9e25cbb5 100644 --- a/config/micord.env +++ b/config/micord.env @@ -48,9 +48,5 @@ ERVU_FILE_UPLOAD_MAX_FILE_SIZE=5242880 ERVU_FILE_UPLOAD_MAX_REQUEST_SIZE=6291456 ERVU_FILE_UPLOAD_FILE_SIZE_THRESHOLD=0 -S3_ENDPOINT=http://ervu-minio.k8s.micord.ru:31900 -S3_ACCESS_KEY=rlTdTvkmSXu9FsLhfecw -S3_SECRET_KEY=NUmY0wwRIEyAd98GCKd1cOgJWvLQYAcMMul5Ulu0 - ESIA_TOKEN_CLEAR_CRON=0 0 */1 * * * COOKIE_PATH=/ul \ No newline at end of file diff --git a/config/standalone/dev/standalone.xml b/config/standalone/dev/standalone.xml index 0dd43d2e..1e3a794c 100644 --- a/config/standalone/dev/standalone.xml +++ b/config/standalone/dev/standalone.xml @@ -89,9 +89,6 @@ - - - diff --git a/pom.xml b/pom.xml index b6e30171..dd816620 100644 --- a/pom.xml +++ b/pom.xml @@ -387,11 +387,6 @@ log4j-web 2.23.1 - - com.amazonaws - aws-java-sdk-s3 - 1.12.759 -