Feature upload avatar (#529)

This commit is contained in:
Devlive Community 2023-12-05 17:41:27 +08:00 committed by GitHub
commit 3292a58a3f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 388 additions and 32 deletions

1
.gitignore vendored
View File

@ -52,3 +52,4 @@ shaded/*/dependency-reduced-pom.xml
cache/
config/
docs/site/
data/

View File

@ -1,5 +1,6 @@
################################### Basic configure #################################
server.port=9096
server.address=localhost
# Fixed serialized data missing for 8 hours
spring.jackson.time-zone=GMT+8
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
@ -86,3 +87,14 @@ datacap.pipeline.reset=STOPPED
# This configuration is used to dynamically increase the total number of rows of returned data in SQL during query, and currently only takes effect for user-directed queries
# If the total number of rows returned is included in the SQL, it will not be automatically incremented
datacap.experimental.autoLimit=true
# For data storage and directories, {user.dir} is supported, or the relative path can be specified
datacap.experimental.data={user.dir}/data
# The path to upload the user's avatar
# `{username}` Fixed format, currently not supported to modify, this configuration will automatically get the current user name by default
datacap.experimental.avatarPath={username}/avatar/
# For the file storage type, please refer to datacap-fs-<Type>, which defaults to Local
datacap.experimental.fs.type=Local
datacap.experimental.fs.access=
datacap.experimental.fs.secret=
datacap.experimental.fs.endpoint=
datacap.experimental.fs.bucket=

View File

@ -40,6 +40,11 @@
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>io.edurt.datacap</groupId>
<artifactId>datacap-fs-spi</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
<build>

View File

@ -18,12 +18,14 @@ public class JwtResponse
private Long id;
private String username;
private List<String> roles;
private String avatar;
public JwtResponse(String accessToken, Long id, String username, List<String> roles)
public JwtResponse(String accessToken, Long id, String username, List<String> roles, String avatar)
{
this.token = accessToken;
this.id = id;
this.username = username;
this.roles = roles;
this.avatar = avatar;
}
}

View File

@ -0,0 +1,32 @@
package io.edurt.datacap.common.utils;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.TypeLiteral;
import io.edurt.datacap.fs.Fs;
import java.util.Optional;
import java.util.Set;
public class SpiUtils
{
private SpiUtils()
{
}
/**
* Finds a specific Fs object by name.
*
* @param injector the injector used for dependency injection
* @param name the name of the Fs object to find
* @return an Optional containing the found Fs object, or an empty Optional if not found
*/
public static Optional<Fs> findFs(Injector injector, String name)
{
Optional<Fs> optionalFs = injector.getInstance(Key.get(new TypeLiteral<Set<Fs>>() {}))
.stream()
.filter(item -> item.name().equalsIgnoreCase(name))
.findFirst();
return optionalFs;
}
}

View File

@ -371,6 +371,12 @@
<artifactId>datacap-captcha</artifactId>
<version>${project.version}</version>
</dependency>
<!-- Fs -->
<dependency>
<groupId>io.edurt.datacap</groupId>
<artifactId>datacap-fs-local</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
<build>

View File

@ -2,6 +2,7 @@ package io.edurt.datacap.server.configure;
import com.google.inject.Guice;
import com.google.inject.Injector;
import io.edurt.datacap.fs.FsManager;
import io.edurt.datacap.spi.PluginLoader;
import io.edurt.datacap.spi.executor.ExecutorManager;
import org.springframework.context.annotation.Bean;
@ -14,7 +15,8 @@ public class PluginConfigure
public Injector injector()
{
Injector injector = Guice.createInjector(new PluginLoader(),
new ExecutorManager());
new ExecutorManager(),
new FsManager());
return injector;
}
}

View File

@ -2,6 +2,7 @@ package io.edurt.datacap.server.controller.user;
import com.google.common.collect.Sets;
import io.edurt.datacap.common.response.CommonResponse;
import io.edurt.datacap.fs.FsResponse;
import io.edurt.datacap.service.body.FilterBody;
import io.edurt.datacap.service.body.UserNameBody;
import io.edurt.datacap.service.body.UserPasswordBody;
@ -16,6 +17,8 @@ import io.edurt.datacap.service.record.TreeRecord;
import io.edurt.datacap.service.repository.RoleRepository;
import io.edurt.datacap.service.service.UserLogService;
import io.edurt.datacap.service.service.UserService;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@ -23,12 +26,15 @@ import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
import java.util.Optional;
import java.util.Set;
@Slf4j
@RestController
@RequestMapping(value = "/api/v1/user")
public class UserController
@ -115,4 +121,11 @@ public class UserController
{
return this.userService.changeEditorConfigure(configure);
}
@SneakyThrows
@PostMapping("uploadAvatar")
public CommonResponse<FsResponse> uploadAvatar(@RequestParam("file") MultipartFile file)
{
return this.userService.uploadAvatar(file);
}
}

View File

@ -0,0 +1,10 @@
ALTER TABLE `datacap_user`
ADD COLUMN `avatar_configure` LONGTEXT COMMENT 'avatar configure';
UPDATE `datacap_user`
SET `avatar_configure` = '{}'
WHERE `avatar_configure` IS NULL;
UPDATE `datacap_user`
SET `editor_configure` = '{}'
WHERE `editor_configure` IS NULL;

View File

@ -0,0 +1,29 @@
package io.edurt.datacap.service.converter;
import io.edurt.datacap.common.utils.JsonUtils;
import org.apache.commons.lang3.StringUtils;
import javax.persistence.AttributeConverter;
import java.util.Map;
public class MapConverter
implements AttributeConverter<Map, String>
{
@Override
public String convertToDatabaseColumn(Map map)
{
return JsonUtils.toJSON(map);
}
@Override
public Map convertToEntityAttribute(String s)
{
if (StringUtils.isEmpty(s)) {
return null;
}
else {
return JsonUtils.toObject(s, Map.class);
}
}
}

View File

@ -3,6 +3,7 @@ package io.edurt.datacap.service.entity;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import io.edurt.datacap.service.converter.MapConverter;
import io.edurt.datacap.service.converter.UserEditorConverter;
import io.edurt.datacap.service.entity.itransient.user.UserEditorEntity;
import io.edurt.datacap.service.validation.ValidationGroup;
@ -35,6 +36,7 @@ import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@Entity
@ -88,6 +90,11 @@ public class UserEntity
@Column(name = "create_time", columnDefinition = "datetime(5) default CURRENT_TIMESTAMP()")
private Timestamp createTime;
@Column(name = "avatar_configure")
@Convert(converter = MapConverter.class)
@JsonIgnoreProperties(value = {"fsType", "local"})
private Map<String, String> avatarConfigure;
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(name = "user_roles",
joinColumns = @JoinColumn(name = "user_id"),

View File

@ -0,0 +1,17 @@
package io.edurt.datacap.service.initializer;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Data
@Component
@ConfigurationProperties(prefix = "datacap.experimental.fs")
public class FsConfigure
{
private String type;
private String access;
private String secret;
private String endpoint;
private String bucket;
}

View File

@ -14,6 +14,7 @@ import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.io.File;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
@ -50,6 +51,14 @@ public class InitializerConfigure
@Value(value = "${datacap.experimental.autoLimit}")
private Boolean autoLimit;
@Getter
@Value(value = "${datacap.experimental.data}")
private String dataHome;
@Getter
@Value(value = "${datacap.experimental.avatarPath}")
private String avatarPath;
@Getter
private LoadingCache<Long, ResultEntity> cache;
@ -59,6 +68,14 @@ public class InitializerConfigure
@Getter
private Map<String, ExecutorService> taskExecutors;
@Getter
private final FsConfigure fsConfigure;
public InitializerConfigure(FsConfigure fsConfigure)
{
this.fsConfigure = fsConfigure;
}
/**
* Initializes the function.
*/
@ -104,6 +121,20 @@ public class InitializerConfigure
}
log.info("Datacap experimental auto limit: [ {} ]", this.autoLimit);
if (this.dataHome.toLowerCase().contains("{user.dir}")) {
this.dataHome = this.dataHome.replace("{user.dir}", System.getProperty("user.dir"));
}
this.avatarPath = String.join(File.separator, this.dataHome, this.avatarPath);
log.info("Datacap experimental avatar path: [ {} ]", this.avatarPath);
log.info("=========== Datacap experimental fs configure ===========");
log.info("fs type [ {} ]", fsConfigure.getType());
log.info("fs access [ {} ]", fsConfigure.getAccess());
log.info("fs secret [ {} ]", fsConfigure.getSecret());
log.info("fs endpoint [ {} ]", fsConfigure.getEndpoint());
log.info("fs bucket [ {} ]", fsConfigure.getBucket());
this.taskQueue = new LinkedBlockingQueue<>(this.maxQueue);
this.taskExecutors = Maps.newConcurrentMap();
}

View File

@ -21,14 +21,17 @@ public class UserDetailsService
@JsonIgnore
private String password;
private Collection<? extends GrantedAuthority> authorities;
private String avatar;
public UserDetailsService(Long id, String username, String password,
Collection<? extends GrantedAuthority> authorities)
Collection<? extends GrantedAuthority> authorities,
String avatar)
{
this.id = id;
this.username = username;
this.password = password;
this.authorities = authorities;
this.avatar = avatar;
}
public static UserDetailsService build(UserEntity user)
@ -36,11 +39,16 @@ public class UserDetailsService
List<GrantedAuthority> authorities = user.getRoles().stream()
.map(role -> new SimpleGrantedAuthority(String.valueOf(role.getId())))
.collect(Collectors.toList());
String avatar = null;
if (user.getAvatarConfigure() != null) {
avatar = user.getAvatarConfigure().get("path");
}
return new UserDetailsService(
user.getId(),
user.getUsername(),
user.getPassword(),
authorities);
authorities,
avatar);
}
@Override
@ -90,6 +98,11 @@ public class UserDetailsService
return id;
}
public String getAvatar()
{
return avatar;
}
public static UserEntity getUser()
{
UserEntity userInfo = new UserEntity();

View File

@ -1,6 +1,7 @@
package io.edurt.datacap.service.service;
import io.edurt.datacap.common.response.CommonResponse;
import io.edurt.datacap.fs.FsResponse;
import io.edurt.datacap.service.body.FilterBody;
import io.edurt.datacap.service.body.UserNameBody;
import io.edurt.datacap.service.body.UserPasswordBody;
@ -9,6 +10,7 @@ import io.edurt.datacap.service.entity.UserEntity;
import io.edurt.datacap.service.entity.itransient.user.UserEditorEntity;
import io.edurt.datacap.service.model.AiModel;
import io.edurt.datacap.service.record.TreeRecord;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
@ -33,4 +35,6 @@ public interface UserService
CommonResponse<PageEntity<UserEntity>> getAll(FilterBody filter);
CommonResponse<Long> changeEditorConfigure(UserEditorEntity configure);
CommonResponse<FsResponse> uploadAvatar(MultipartFile file);
}

View File

@ -1,11 +1,17 @@
package io.edurt.datacap.service.service.impl;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.inject.Injector;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import io.edurt.datacap.common.enums.ServiceState;
import io.edurt.datacap.common.response.CommonResponse;
import io.edurt.datacap.common.response.JwtResponse;
import io.edurt.datacap.common.utils.JsonUtils;
import io.edurt.datacap.common.utils.SpiUtils;
import io.edurt.datacap.fs.Fs;
import io.edurt.datacap.fs.FsRequest;
import io.edurt.datacap.fs.FsResponse;
import io.edurt.datacap.service.adapter.PageRequestAdapter;
import io.edurt.datacap.service.audit.AuditUserLog;
import io.edurt.datacap.service.body.FilterBody;
@ -17,6 +23,7 @@ import io.edurt.datacap.service.entity.RoleEntity;
import io.edurt.datacap.service.entity.SourceEntity;
import io.edurt.datacap.service.entity.UserEntity;
import io.edurt.datacap.service.entity.itransient.user.UserEditorEntity;
import io.edurt.datacap.service.initializer.InitializerConfigure;
import io.edurt.datacap.service.model.AiModel;
import io.edurt.datacap.service.record.TreeRecord;
import io.edurt.datacap.service.repository.RoleRepository;
@ -27,6 +34,7 @@ import io.edurt.datacap.service.service.JwtService;
import io.edurt.datacap.service.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.core.env.Environment;
import org.springframework.data.domain.Pageable;
import org.springframework.data.redis.core.RedisTemplate;
@ -36,8 +44,13 @@ import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
@ -62,8 +75,11 @@ public class UserServiceImpl
private final JwtService jwtService;
private final RedisTemplate redisTemplate;
private final Environment environment;
private final InitializerConfigure initializerConfigure;
private final Injector injector;
private final ServerProperties serverProperties;
public UserServiceImpl(UserRepository userRepository, RoleRepository roleRepository, SourceRepository sourceRepository, PasswordEncoder encoder, AuthenticationManager authenticationManager, JwtService jwtService, RedisTemplate redisTemplate, Environment environment)
public UserServiceImpl(UserRepository userRepository, RoleRepository roleRepository, SourceRepository sourceRepository, PasswordEncoder encoder, AuthenticationManager authenticationManager, JwtService jwtService, RedisTemplate redisTemplate, Environment environment, InitializerConfigure initializerConfigure, Injector injector, ServerProperties serverProperties)
{
this.userRepository = userRepository;
this.roleRepository = roleRepository;
@ -73,6 +89,9 @@ public class UserServiceImpl
this.jwtService = jwtService;
this.redisTemplate = redisTemplate;
this.environment = environment;
this.initializerConfigure = initializerConfigure;
this.injector = injector;
this.serverProperties = serverProperties;
}
@Override
@ -118,7 +137,7 @@ public class UserServiceImpl
List<String> roles = userDetails.getAuthorities().stream()
.map(item -> item.getAuthority())
.collect(Collectors.toList());
return CommonResponse.success(new JwtResponse(jwt, userDetails.getId(), userDetails.getUsername(), roles));
return CommonResponse.success(new JwtResponse(jwt, userDetails.getId(), userDetails.getUsername(), roles, userDetails.getAvatar()));
}
@Override
@ -257,4 +276,62 @@ public class UserServiceImpl
this.userRepository.save(user);
return CommonResponse.success(user.getId());
}
@Override
public CommonResponse<FsResponse> uploadAvatar(MultipartFile file)
{
Optional<Fs> optionalFs = SpiUtils.findFs(injector, initializerConfigure.getFsConfigure().getType());
if (!optionalFs.isPresent()) {
return CommonResponse.failure(String.format("Not found Fs [ %s ]", initializerConfigure.getFsConfigure().getType()));
}
UserEntity user = UserDetailsService.getUser();
try {
String avatarPath = initializerConfigure.getAvatarPath().replace("{username}", user.getUsername());
log.info("Upload avatar user [ {} ] home [ {} ]", user.getUsername(), avatarPath);
FsRequest fsRequest = FsRequest.builder()
.access(initializerConfigure.getFsConfigure().getAccess())
.secret(initializerConfigure.getFsConfigure().getSecret())
.endpoint(avatarPath)
.bucket(initializerConfigure.getFsConfigure().getBucket())
.stream(file.getInputStream())
.fileName(file.getOriginalFilename())
.build();
FsResponse response = optionalFs.get().writer(fsRequest);
UserEntity entity = userRepository.findById(user.getId()).get();
Map<String, String> avatar = Maps.newConcurrentMap();
avatar.put("fsType", initializerConfigure.getFsConfigure().getType());
avatar.put("local", response.getRemote());
if (initializerConfigure.getFsConfigure().getType().equals("Local")) {
avatar.put("path", encodeImageToBase64(file.getInputStream()));
}
else {
avatar.put("path", response.getRemote());
}
entity.setAvatarConfigure(avatar);
userRepository.save(entity);
return CommonResponse.success(response);
}
catch (IOException e) {
log.warn("File upload exception on user [ {} ]", user.getUsername(), e);
return CommonResponse.failure(e.getMessage());
}
}
private String encodeImageToBase64(InputStream inputStream)
{
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
return String.format("data:image/jpeg;base64,%s", Base64.getEncoder().encodeToString(outputStream.toByteArray()));
}
catch (IOException e) {
log.warn("Encode image to base64 exception", e);
return null;
}
}
}

View File

@ -167,4 +167,5 @@ export default {
releaseNote: 'Release Note',
statement: 'Statement',
condition: 'Condition',
uploadAvatar: 'Upload Avatar'
}

View File

@ -167,4 +167,5 @@ export default {
releaseNote: '发行说明',
statement: '语句',
condition: '条件',
uploadAvatar: '上传头像'
}

View File

@ -5,4 +5,5 @@ export interface AuthResponse
id: number;
username: string;
roles: [];
avatar: string;
}

View File

@ -4,6 +4,7 @@ export interface User
thirdConfigure: ThirdConfigure;
createTime?: string;
id?: number;
avatarConfigure?: Map<string, string>
}
export class UserQuestion

View File

@ -55,7 +55,13 @@
</Submenu>
<Submenu name="profile">
<template #title>
<Avatar size="large" style="background-color: #87d068">
<Avatar v-if="authUser.avatar"
size="large"
:src="authUser.avatar">
</Avatar>&nbsp;
<Avatar v-else
size="large"
style="background-color: #87d068">
{{ username }}
</Avatar>&nbsp;
</template>
@ -110,7 +116,8 @@ export default defineComponent({
username,
language,
version,
handlerLogout
handlerLogout,
authUser
}
},
created()

View File

@ -4,7 +4,13 @@
<template #title>
<div class="datacap-profile-header">
<router-link to="/profile/index">
<Avatar style="background-color: #87d068">
<Avatar v-if="authUser.avatar"
size="large"
:src="authUser.avatar">
</Avatar>&nbsp;
<Avatar v-else
size="large"
style="background-color: #87d068">
{{ username }}
</Avatar>&nbsp;
</router-link>
@ -44,7 +50,8 @@ export default defineComponent({
username = authUser.username;
}
return {
username
username,
authUser
}
}
});

View File

@ -1,14 +1,18 @@
<template>
<div>
<Card style="width:100%; minHeight: 150px;">
<Card style="width:100%; minHeight: 150px;"
dis-hover>
<template #title>
{{ $t('setting.profile') }}
</template>
<Spin fix v-if="loading"/>
<Spin fix
v-if="loading">
</Spin>
<div v-else>
<Layout>
<Layout>
<Content class="content" style="padding: 0 0 0 40px;">
<Content class="content"
style="padding: 0 0 0 40px;">
<Form :label-width="80">
<FormItem :label="$t('common.username')">
<span>{{ formState.username }}</span>
@ -18,8 +22,25 @@
</FormItem>
</Form>
</Content>
<Sider class="content" hide-trigger>
<Avatar style="background-color: #87d068" size="64" icon="ios-person"/>
<Sider class="content"
style="text-align: center;"
hide-trigger>
<Avatar v-if="authUser.avatar"
size="64"
:src="formState.avatarConfigure['path']">
</Avatar>&nbsp;
<Avatar v-else
size="64"
style="background-color: #87d068">
{{ authUser.username }}
</Avatar>&nbsp;
<Upload style="margin-top: 10px;"
:headers="{'Authorization': auth.type + ' ' + auth.token}"
:format="['jpg', 'png', 'jpeg']"
:on-success="handlerUploadSuccess"
action="/api/v1/user/uploadAvatar">
<Button>{{ $t('common.uploadAvatar') }}</Button>
</Upload>
</Sider>
</Layout>
</Layout>
@ -31,13 +52,24 @@
import {defineComponent} from 'vue';
import {User} from "@/model/User";
import UserService from "@/services/UserService";
import Common from "@/common/Common";
import {ResponseModel} from "@/model/ResponseModel";
import {AuthResponse} from "@/model/AuthResponse";
export default defineComponent({
setup()
{
const authUser = JSON.parse(localStorage.getItem(Common.token) || '{}') as AuthResponse;
return {
authUser
}
},
data()
{
return {
loading: false,
formState: {} as User
formState: {} as User,
auth: null
}
},
created()
@ -47,6 +79,7 @@ export default defineComponent({
methods: {
handlerInitialize()
{
this.auth = JSON.parse(localStorage.getItem(Common.token) || '{}');
this.loading = true;
UserService.getInfo()
.then(response => {
@ -57,6 +90,13 @@ export default defineComponent({
.finally(() => {
this.loading = false;
});
},
handlerUploadSuccess(response: ResponseModel)
{
if (response.status) {
const configure = this.applyPlugin.configures.filter(configure => configure.field === 'file')
configure[0].value.push(response.data)
}
}
}
});

View File

@ -1,10 +1,11 @@
package io.edurt.datacap.fs;
import java.io.Reader;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.nio.file.StandardOpenOption;
public class IOUtils
{
@ -37,15 +38,39 @@ public class IOUtils
}
/**
* Returns a Reader object for the specified source.
* Copies the contents of the input stream to the specified target file path.
*
* @param source the path of the file to be read
* @return a Reader object for reading the file contents
* @param stream the input stream containing the contents to be copied
* @param target the path of the target file where the contents will be copied to
* @param createdDir indicates whether the parent directory of the target file has been created
* @return true if the contents were successfully copied, false otherwise
*/
public static Reader reader(String source)
public static boolean copy(InputStream stream, String target, boolean createdDir)
{
try {
return Files.newBufferedReader(Paths.get(source));
Path targetPath = Paths.get(target);
if (createdDir) {
Files.createDirectories(targetPath.getParent());
}
Files.copy(stream, targetPath, StandardCopyOption.REPLACE_EXISTING);
return true;
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* This function takes a source file path and returns an InputStream object that can be used to read the contents of the file.
*
* @param source the path of the source file to read
* @return an InputStream object representing the source file
*/
public static InputStream reader(String source)
{
try {
return Files.newInputStream(Paths.get(source), StandardOpenOption.READ);
}
catch (Exception e) {
throw new RuntimeException(e);

View File

@ -20,7 +20,12 @@ public class LocalFs
.build();
log.info("LocalFs writer target path [ {} ]", targetPath);
try {
IOUtils.copy(request.getLocalPath(), targetPath, true);
if (request.getLocalPath() == null || request.getLocalPath().isEmpty()) {
IOUtils.copy(request.getStream(), targetPath, true);
}
else {
IOUtils.copy(request.getLocalPath(), targetPath, true);
}
log.info("LocalFs writer [ {} ] successfully", targetPath);
}
catch (Exception e) {

View File

@ -12,6 +12,8 @@ import org.junit.Test;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Optional;
import java.util.Set;
@ -66,7 +68,7 @@ public class LocalFsTest
Assert.assertEquals(true, response.isSuccessful());
log.info("====== [ {} ] ======", response.getRemote());
try (BufferedReader reader = new BufferedReader(response.getContext())) {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(response.getContext(), StandardCharsets.UTF_8))) {
String line;
while ((line = reader.readLine()) != null) {
log.info(line);

View File

@ -22,12 +22,8 @@
<version>${guice.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -6,6 +6,8 @@ import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import java.io.InputStream;
@Data
@Builder
@ToString
@ -17,6 +19,8 @@ public class FsRequest
private String secret;
private String endpoint;
private String bucket;
@Deprecated
private String localPath;
private InputStream stream;
private String fileName;
}

View File

@ -6,7 +6,7 @@ import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import java.io.Reader;
import java.io.InputStream;
@Data
@Builder
@ -18,6 +18,6 @@ public class FsResponse
private String origin;
private String remote;
private String message;
private Reader context;
private InputStream context;
private boolean successful;
}

View File

@ -245,6 +245,11 @@
<artifactId>logback-core</artifactId>
<version>${logback.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>