mirror of
https://gitee.com/devlive-community/datacap.git
synced 2024-12-14 09:20:49 +08:00
Feature upload avatar (#529)
This commit is contained in:
commit
3292a58a3f
1
.gitignore
vendored
1
.gitignore
vendored
@ -52,3 +52,4 @@ shaded/*/dependency-reduced-pom.xml
|
||||
cache/
|
||||
config/
|
||||
docs/site/
|
||||
data/
|
||||
|
@ -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=
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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>
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
10
core/datacap-server/src/main/schema/1.18.0/schema.sql
Normal file
10
core/datacap-server/src/main/schema/1.18.0/schema.sql
Normal 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;
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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"),
|
||||
|
@ -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;
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -167,4 +167,5 @@ export default {
|
||||
releaseNote: 'Release Note',
|
||||
statement: 'Statement',
|
||||
condition: 'Condition',
|
||||
uploadAvatar: 'Upload Avatar'
|
||||
}
|
||||
|
@ -167,4 +167,5 @@ export default {
|
||||
releaseNote: '发行说明',
|
||||
statement: '语句',
|
||||
condition: '条件',
|
||||
uploadAvatar: '上传头像'
|
||||
}
|
||||
|
@ -5,4 +5,5 @@ export interface AuthResponse
|
||||
id: number;
|
||||
username: string;
|
||||
roles: [];
|
||||
avatar: string;
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ export interface User
|
||||
thirdConfigure: ThirdConfigure;
|
||||
createTime?: string;
|
||||
id?: number;
|
||||
avatarConfigure?: Map<string, string>
|
||||
}
|
||||
|
||||
export class UserQuestion
|
||||
|
@ -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>
|
||||
<Avatar v-else
|
||||
size="large"
|
||||
style="background-color: #87d068">
|
||||
{{ username }}
|
||||
</Avatar>
|
||||
</template>
|
||||
@ -110,7 +116,8 @@ export default defineComponent({
|
||||
username,
|
||||
language,
|
||||
version,
|
||||
handlerLogout
|
||||
handlerLogout,
|
||||
authUser
|
||||
}
|
||||
},
|
||||
created()
|
||||
|
@ -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>
|
||||
<Avatar v-else
|
||||
size="large"
|
||||
style="background-color: #87d068">
|
||||
{{ username }}
|
||||
</Avatar>
|
||||
</router-link>
|
||||
@ -44,7 +50,8 @@ export default defineComponent({
|
||||
username = authUser.username;
|
||||
}
|
||||
return {
|
||||
username
|
||||
username,
|
||||
authUser
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -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>
|
||||
<Avatar v-else
|
||||
size="64"
|
||||
style="background-color: #87d068">
|
||||
{{ authUser.username }}
|
||||
</Avatar>
|
||||
<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)
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
5
pom.xml
5
pom.xml
@ -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>
|
||||
|
Loading…
Reference in New Issue
Block a user