Merge branch 'feature/SUPPORT-8381_file_upload_back' into feature/SUPPORT-8381_file_upload
This commit is contained in:
commit
1f6e79466e
11 changed files with 310 additions and 46 deletions
|
|
@ -99,6 +99,10 @@
|
|||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-config</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.kafka</groupId>
|
||||
<artifactId>spring-kafka</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ru.cg.webbpm.modules</groupId>
|
||||
<artifactId>inject</artifactId>
|
||||
|
|
|
|||
45
backend/src/main/java/ervu/KafkaProducerConfig.java
Normal file
45
backend/src/main/java/ervu/KafkaProducerConfig.java
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
package ervu;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.kafka.clients.producer.ProducerConfig;
|
||||
import org.apache.kafka.common.serialization.StringSerializer;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.kafka.core.DefaultKafkaProducerFactory;
|
||||
import org.springframework.kafka.core.KafkaTemplate;
|
||||
import org.springframework.kafka.core.ProducerFactory;
|
||||
|
||||
/**
|
||||
* @author Alexandr Shalaginov
|
||||
*/
|
||||
@Configuration
|
||||
public class KafkaProducerConfig {
|
||||
@Value("${kafka.send.url:#{null}}")
|
||||
private String kafkaUrl;
|
||||
|
||||
@Bean
|
||||
public ProducerFactory<String, String> producerFactory() {
|
||||
return new DefaultKafkaProducerFactory<>(producerConfigs());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Map<String, Object> producerConfigs() {
|
||||
if (this.kafkaUrl == null) {
|
||||
throw new RuntimeException("Property kafka.send.url is null");
|
||||
}
|
||||
Map<String, Object> props = new HashMap<>();
|
||||
props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, this.kafkaUrl);
|
||||
props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
|
||||
props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
|
||||
return props;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public KafkaTemplate<String, String> kafkaTemplate() {
|
||||
return new KafkaTemplate<>(producerFactory());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
package ervu.client.fileupload;
|
||||
|
||||
import java.io.IOException;
|
||||
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.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
/**
|
||||
* @author Alexandr Shalaginov
|
||||
*/
|
||||
@Component
|
||||
public class EmployeeInfoWebDavClient {
|
||||
private static final Logger logger = LoggerFactory.getLogger(EmployeeInfoWebDavClient.class);
|
||||
|
||||
@Value("${file.webdav.upload.url:http://localhost:5757}")
|
||||
private String url;
|
||||
|
||||
public boolean webDavUploadFile(String filename, MultipartFile multipartFile) {
|
||||
try {
|
||||
HttpClient httpClient = HttpClient.newBuilder().build();
|
||||
HttpRequest httpRequest = HttpRequest.newBuilder().uri(URI.create(this.url + "/" + filename))
|
||||
.PUT(HttpRequest.BodyPublishers.ofByteArray(multipartFile.getBytes())).build();
|
||||
HttpResponse<String> response = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());
|
||||
return (response.statusCode() >= 200) && (response.statusCode() <= 202);
|
||||
}
|
||||
catch (IOException | InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
package ervu.controller;
|
||||
|
||||
import ervu.service.fileupload.EmployeeInfoFileUploadService;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
/**
|
||||
* @author Alexandr Shalaginov
|
||||
*/
|
||||
@RestController
|
||||
public class EmployeeInfoFileUploadController {
|
||||
private final EmployeeInfoFileUploadService fileUploadService;
|
||||
|
||||
public EmployeeInfoFileUploadController(EmployeeInfoFileUploadService fileUploadService) {
|
||||
this.fileUploadService = fileUploadService;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/employee/document", method = RequestMethod.POST)
|
||||
public ResponseEntity<?> saveEmployeeInformationFile(@RequestParam("file") MultipartFile multipartFile) {
|
||||
if (this.fileUploadService.saveEmployeeInformationFile(multipartFile)) {
|
||||
return ResponseEntity.ok("File successfully uploaded.");
|
||||
}
|
||||
else {
|
||||
return ResponseEntity.internalServerError().body("An error occurred while uploading file.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
package ervu.controller;
|
||||
|
||||
import ervu.service.fileupload.FileUploadV2Service;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import ru.cg.webbpm.modules.standard_annotations.validation.NotNull;
|
||||
import ru.cg.webbpm.modules.webkit.beans.Behavior;
|
||||
|
||||
/**
|
||||
* @author Alexandr Shalaginov
|
||||
*/
|
||||
@RestController
|
||||
public class FileUploadV2Controller extends Behavior {
|
||||
@NotNull
|
||||
public final FileUploadV2Service fileUploadV2Service;
|
||||
|
||||
public FileUploadV2Controller(FileUploadV2Service fileUploadV2Service) {
|
||||
this.fileUploadV2Service = fileUploadV2Service;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/file/upload", method = RequestMethod.POST)
|
||||
public ResponseEntity<?> saveFile(@RequestParam("file") MultipartFile multipartFile) {
|
||||
if (this.fileUploadV2Service.saveFile(multipartFile)) {
|
||||
return ResponseEntity.ok("File successfully uploaded.");
|
||||
}
|
||||
else {
|
||||
return ResponseEntity.internalServerError().body("An error occurred while uploading file.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
package ervu.service.fileupload;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import ervu.client.fileupload.EmployeeInfoWebDavClient;
|
||||
import org.apache.kafka.clients.producer.ProducerRecord;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.kafka.core.KafkaTemplate;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import ru.cg.webbpm.modules.security.api.runtime.SecurityContext;
|
||||
|
||||
/**
|
||||
* @author Alexandr Shalaginov
|
||||
*/
|
||||
@Service
|
||||
public class EmployeeInfoFileUploadService {
|
||||
private static final Logger logger = LoggerFactory.getLogger(EmployeeInfoFileUploadService.class);
|
||||
|
||||
private final EmployeeInfoWebDavClient fileWebDavUploadClient;
|
||||
private final KafkaTemplate<String, String> kafkaTemplate;
|
||||
|
||||
@Value("${kafka.send.message.topic.name:employee-files}")
|
||||
private String kafkaTopicName;
|
||||
|
||||
public EmployeeInfoFileUploadService(
|
||||
EmployeeInfoWebDavClient fileWebDavUploadClient,
|
||||
KafkaTemplate<String, String> kafkaTemplate) {
|
||||
this.fileWebDavUploadClient = fileWebDavUploadClient;
|
||||
this.kafkaTemplate = kafkaTemplate;
|
||||
}
|
||||
|
||||
public boolean saveEmployeeInformationFile(MultipartFile multipartFile) {
|
||||
String newFilename = getNewFilename(multipartFile.getOriginalFilename());
|
||||
|
||||
if (this.fileWebDavUploadClient.webDavUploadFile(newFilename, multipartFile)) {
|
||||
String jsonMessage = getJsonKafkaMessage(
|
||||
new KafkaMessage(
|
||||
getCurrentUsername(),
|
||||
newFilename,
|
||||
multipartFile.getOriginalFilename()
|
||||
)
|
||||
);
|
||||
return sendMessage(jsonMessage);
|
||||
}
|
||||
else {
|
||||
logger.error("Fail upload file: {}", multipartFile.getOriginalFilename());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean sendMessage(String message) {
|
||||
ProducerRecord<String, String> record = new ProducerRecord<>(this.kafkaTopicName, message);
|
||||
try {
|
||||
this.kafkaTemplate.send(record).get();
|
||||
logger.debug("Success send record: {}", record);
|
||||
return true;
|
||||
}
|
||||
catch (Exception exception) {
|
||||
logger.error("Fail send message.", exception);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private String getNewFilename(String oldFilename) {
|
||||
return UUID.randomUUID() + getFileExtension(oldFilename);
|
||||
}
|
||||
|
||||
private String getFileExtension(String filename) {
|
||||
int lastIndexOf = filename.lastIndexOf(".");
|
||||
if (lastIndexOf == -1) {
|
||||
return "";
|
||||
}
|
||||
return filename.substring(lastIndexOf);
|
||||
}
|
||||
|
||||
private String getJsonKafkaMessage(KafkaMessage kafkaMessage) {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
try {
|
||||
return mapper.writeValueAsString(kafkaMessage);
|
||||
}
|
||||
catch (JsonProcessingException e) {
|
||||
throw new RuntimeException(String.format("Fail get json from: %s", kafkaMessage), e);
|
||||
}
|
||||
}
|
||||
|
||||
private String getCurrentUsername() {
|
||||
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||
if (auth != null && auth.isAuthenticated()) {
|
||||
return auth.getName();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
package ervu.service.fileupload;
|
||||
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
/**
|
||||
* @author Alexandr Shalaginov
|
||||
*/
|
||||
public interface FileUploadV2Service {
|
||||
boolean saveFile(MultipartFile multipartFile);
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
package ervu.service.fileupload;
|
||||
|
||||
/**
|
||||
* @author Alexandr Shalaginov
|
||||
*/
|
||||
class KafkaMessage {
|
||||
private final String username;
|
||||
private final String filename;
|
||||
private final String originalFilename;
|
||||
|
||||
public KafkaMessage(String username, String filename, String originalFilename) {
|
||||
this.username = username;
|
||||
this.filename = filename;
|
||||
this.originalFilename = originalFilename;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public String getFilename() {
|
||||
return filename;
|
||||
}
|
||||
|
||||
public String getOriginalFilename() {
|
||||
return originalFilename;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "KafkaMessage{" +
|
||||
"username='" + username + '\'' +
|
||||
", filename='" + filename + '\'' +
|
||||
", originalFilename='" + originalFilename + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
|
@ -49,7 +49,7 @@ export class FileUploadV2 extends InputControl {
|
|||
protected isProgressBarVisible: boolean = false;
|
||||
|
||||
private fileInputEl: any;
|
||||
private url: string = '/backend/file/upload';
|
||||
private url: string = '/backend/employee/document';
|
||||
private messagesService: MessagesService;
|
||||
|
||||
constructor(el: ElementRef, cd: ChangeDetectorRef) {
|
||||
|
|
|
|||
6
pom.xml
6
pom.xml
|
|
@ -23,6 +23,7 @@
|
|||
<webbpm-platform.version>3.174.1</webbpm-platform.version>
|
||||
<wbp.overall-timeout>72000</wbp.overall-timeout>
|
||||
<jasperreports.version>6.15.0</jasperreports.version>
|
||||
<spring-kafka.version>2.6.13</spring-kafka.version>
|
||||
</properties>
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
|
|
@ -293,6 +294,11 @@
|
|||
<artifactId>spring-security-kerberos-web</artifactId>
|
||||
<version>${spring-security-kerberos.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.kafka</groupId>
|
||||
<artifactId>spring-kafka</artifactId>
|
||||
<version>${spring-kafka.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpcore</artifactId>
|
||||
|
|
|
|||
48
resources/src/main/resources/FileUploadV2.component
Normal file
48
resources/src/main/resources/FileUploadV2.component
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<xmlComponent>
|
||||
<id>f6d7a9d9-acfe-4414-a835-e9625fa06fb3</id>
|
||||
<name>FileUploadV2</name>
|
||||
<internal>false</internal>
|
||||
<versions>
|
||||
<studioVersion>3.175.0-SNAPSHOT</studioVersion>
|
||||
<packageVersions>
|
||||
<entry>
|
||||
<key>ru.cg.webbpm.packages.base.resources</key>
|
||||
<value>3.174.1</value>
|
||||
</entry>
|
||||
</packageVersions>
|
||||
</versions>
|
||||
<rootObject id="5694e7c5-bbb5-4d23-be6c-7ad71b8ad38c">
|
||||
<name>FileUploadV2</name>
|
||||
<container>false</container>
|
||||
<childrenReordered>false</childrenReordered>
|
||||
<scripts id="36fe7f3d-d9d5-472b-ad12-956ef734ee76">
|
||||
<classRef type="TS">
|
||||
<className>FileUploadV2</className>
|
||||
<packageName>ervu.component.fileupload</packageName>
|
||||
</classRef>
|
||||
<enabled>true</enabled>
|
||||
<expanded>true</expanded>
|
||||
<properties>
|
||||
<entry>
|
||||
<key>displayFileSize</key>
|
||||
<value>
|
||||
<simple>true</simple>
|
||||
</value>
|
||||
</entry>
|
||||
<entry>
|
||||
<key>displayProgressBar</key>
|
||||
<value>
|
||||
<simple>true</simple>
|
||||
</value>
|
||||
</entry>
|
||||
<entry>
|
||||
<key>visible</key>
|
||||
<value>
|
||||
<simple>true</simple>
|
||||
</value>
|
||||
</entry>
|
||||
</properties>
|
||||
</scripts>
|
||||
</rootObject>
|
||||
</xmlComponent>
|
||||
Loading…
Add table
Add a link
Reference in a new issue