From 88c32f02b5eb92a7d86cbf85be0f563c5511f38d Mon Sep 17 00:00:00 2001 From: zhangsan <646228430@qq.com> Date: Thu, 17 Apr 2025 18:55:25 +0800 Subject: [PATCH] =?UTF-8?q?2025.4.17=20=E8=87=AA=E5=B7=B1=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0filebrowser=E4=B8=8A=E4=BC=A0=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E8=BF=94=E5=9B=9Eurl?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sky-common/pom.xml | 5 + .../sky/properties/FileBrowserProperties.java | 14 ++ .../main/java/com/sky/utils/AliOssUtil.java | 118 +++++++---------- .../java/com/sky/utils/FileBrowserUtil.java | 121 ++++++++++++++++++ sky-server/pom.xml | 5 +- .../sky/config/FileBrowserConfiguration.java | 20 +++ .../java/com/sky/config/OssConfiguration.java | 26 ++++ .../com/sky/config/SecurityConfiguration.java | 15 +++ .../com/sky/config/WebSecurityConfig.java | 44 ------- .../controller/admin/CommonController.java | 37 +++++- .../sky/service/impl/EmployeeServiceImpl.java | 11 +- .../src/main/resources/application-dev.yml | 4 + sky-server/src/main/resources/application.yml | 6 + 13 files changed, 299 insertions(+), 127 deletions(-) create mode 100644 sky-common/src/main/java/com/sky/properties/FileBrowserProperties.java create mode 100644 sky-common/src/main/java/com/sky/utils/FileBrowserUtil.java create mode 100644 sky-server/src/main/java/com/sky/config/FileBrowserConfiguration.java create mode 100644 sky-server/src/main/java/com/sky/config/OssConfiguration.java create mode 100644 sky-server/src/main/java/com/sky/config/SecurityConfiguration.java delete mode 100644 sky-server/src/main/java/com/sky/config/WebSecurityConfig.java diff --git a/sky-common/pom.xml b/sky-common/pom.xml index 3a374b4..2c1d2cc 100644 --- a/sky-common/pom.xml +++ b/sky-common/pom.xml @@ -40,6 +40,11 @@ com.aliyun.oss aliyun-sdk-oss + + org.apache.httpcomponents + httpmime + 4.5.13 + javax.xml.bind jaxb-api diff --git a/sky-common/src/main/java/com/sky/properties/FileBrowserProperties.java b/sky-common/src/main/java/com/sky/properties/FileBrowserProperties.java new file mode 100644 index 0000000..2f1955b --- /dev/null +++ b/sky-common/src/main/java/com/sky/properties/FileBrowserProperties.java @@ -0,0 +1,14 @@ +package com.sky.properties; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@Component +@ConfigurationProperties(prefix = "sky.filebrowser") +@Data +public class FileBrowserProperties { + private String domain; + private String username; + private String password; +} diff --git a/sky-common/src/main/java/com/sky/utils/AliOssUtil.java b/sky-common/src/main/java/com/sky/utils/AliOssUtil.java index ac5b027..bd663ba 100644 --- a/sky-common/src/main/java/com/sky/utils/AliOssUtil.java +++ b/sky-common/src/main/java/com/sky/utils/AliOssUtil.java @@ -24,79 +24,57 @@ import java.util.UUID; @Data @AllArgsConstructor @Slf4j -@Component public class AliOssUtil { - @Autowired - private AliOssProperties aliOssProperties; -// private String endpoint; -// private String accessKeyId; -// private String accessKeySecret; -// private String bucketName; -// -// /** -// * 文件上传 -// * -// * @param bytes -// * @param objectName -// * @return -// */ -// public String upload(byte[] bytes, String objectName) { -// -// // 创建OSSClient实例。 -// OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret); -// -// try { -// // 创建PutObject请求。 -// ossClient.putObject(bucketName, objectName, new ByteArrayInputStream(bytes)); -// } catch (OSSException oe) { -// System.out.println("Caught an OSSException, which means your request made it to OSS, " -// + "but was rejected with an error response for some reason."); -// System.out.println("Error Message:" + oe.getErrorMessage()); -// System.out.println("Error Code:" + oe.getErrorCode()); -// System.out.println("Request ID:" + oe.getRequestId()); -// System.out.println("Host ID:" + oe.getHostId()); -// } catch (ClientException ce) { -// System.out.println("Caught an ClientException, which means the client encountered " -// + "a serious internal problem while trying to communicate with OSS, " -// + "such as not being able to access the network."); -// System.out.println("Error Message:" + ce.getMessage()); -// } finally { -// if (ossClient != null) { -// ossClient.shutdown(); -// } -// } -// -// //文件访问路径规则 https://BucketName.Endpoint/ObjectName -// StringBuilder stringBuilder = new StringBuilder("https://"); -// stringBuilder -// .append(bucketName) -// .append(".") -// .append(endpoint) -// .append("/") -// .append(objectName); -// -// log.info("文件上传到:{}", stringBuilder.toString()); -// -// return stringBuilder.toString(); -// } - public String upload(MultipartFile file) throws IOException, com.aliyuncs.exceptions.ClientException { - InputStream inputStream = file.getInputStream(); - // 避免文件覆盖 - String originalFilename = file.getOriginalFilename(); - String extname = originalFilename.substring(originalFilename.lastIndexOf("."));//文件扩展名 - String fileName = UUID.randomUUID().toString() + extname; + private String endpoint; + private String accessKeyId; + private String accessKeySecret; + private String bucketName; - //上传文件到 OSS - EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider(); //从环境变量中获取 - OSS ossClient = new OSSClientBuilder().build(aliOssProperties.getEndpoint(), credentialsProvider); - PutObjectRequest putObjectRequest = new PutObjectRequest(aliOssProperties.getBucketName(), fileName, inputStream); - PutObjectResult result = ossClient.putObject(putObjectRequest); + /** + * 文件上传 + * + * @param bytes + * @param objectName + * @return + */ + public String upload(byte[] bytes, String objectName) { - //文件访问路径 - String url = aliOssProperties.getEndpoint().split("//")[0] + "//" + aliOssProperties.getBucketName() + "." + aliOssProperties.getEndpoint().split("//")[1] + "/" + fileName; - // 关闭ossClient - ossClient.shutdown(); - return url;// 把上传到oss的路径返回 + // 创建OSSClient实例。 + OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret); + + try { + // 创建PutObject请求。 + ossClient.putObject(bucketName, objectName, new ByteArrayInputStream(bytes)); + } catch (OSSException oe) { + System.out.println("Caught an OSSException, which means your request made it to OSS, " + + "but was rejected with an error response for some reason."); + System.out.println("Error Message:" + oe.getErrorMessage()); + System.out.println("Error Code:" + oe.getErrorCode()); + System.out.println("Request ID:" + oe.getRequestId()); + System.out.println("Host ID:" + oe.getHostId()); + } catch (ClientException ce) { + System.out.println("Caught an ClientException, which means the client encountered " + + "a serious internal problem while trying to communicate with OSS, " + + "such as not being able to access the network."); + System.out.println("Error Message:" + ce.getMessage()); + } finally { + if (ossClient != null) { + ossClient.shutdown(); + } + } + + //文件访问路径规则 https://BucketName.Endpoint/ObjectName + StringBuilder stringBuilder = new StringBuilder("https://"); + stringBuilder + .append(bucketName) + .append(".") + .append(endpoint) + .append("/") + .append(objectName); + + log.info("文件上传到:{}", stringBuilder.toString()); + + return stringBuilder.toString(); } } diff --git a/sky-common/src/main/java/com/sky/utils/FileBrowserUtil.java b/sky-common/src/main/java/com/sky/utils/FileBrowserUtil.java new file mode 100644 index 0000000..ab578db --- /dev/null +++ b/sky-common/src/main/java/com/sky/utils/FileBrowserUtil.java @@ -0,0 +1,121 @@ +package com.sky.utils; + +import com.alibaba.fastjson.JSONObject; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.apache.http.HttpEntity; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; +import org.apache.http.entity.mime.HttpMultipartMode; +import org.apache.http.entity.mime.MultipartEntityBuilder; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; +import java.io.IOException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.UUID; + +@Slf4j +@AllArgsConstructor +@Data +public class FileBrowserUtil { + private String domain; + private String username; + private String password; + + /** + * —— 第一步:登录拿 token —— + * 调用 /api/login 接口,返回原始的 JWT token 字符串 + * curl -X POST "https://fshare.bitday.top/api/login" \ + * -H "Content-Type: application/json" \ + * -d '{ + * "username":"admin", + * "password":"asdf14789" + * }' + * 返回值: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9… + */ + + public String login() throws IOException { + String url = domain + "/api/login"; + // 创建 HttpClient 实例 + try (CloseableHttpClient httpClient = HttpClients.createDefault()) { + // 构造 POST 请求 + HttpPost httpPost = new HttpPost(url); + httpPost.setHeader("Content-Type", "application/json"); + + // 构造 JSON body + JSONObject json = new JSONObject(); + json.put("username", username); + json.put("password", password); + + // 设置请求体 + StringEntity requestEntity = new StringEntity(json.toString(), StandardCharsets.UTF_8); + requestEntity.setContentType("application/json"); + httpPost.setEntity(requestEntity); + + // 发送请求并处理响应 + try (CloseableHttpResponse response = httpClient.execute(httpPost)) { + int statusCode = response.getStatusLine().getStatusCode(); + if (statusCode >= 200 && statusCode < 300) { + HttpEntity respEntity = response.getEntity(); + String body = EntityUtils.toString(respEntity, StandardCharsets.UTF_8); + log.info("token:{}",body); + // 返回原始返回值(假设就是 JWT token 字符串) + return body; + } else { + throw new IOException("Login failed, HTTP status code: " + statusCode); + } + } + } + } + + /** + * —— 第二步:上传文件 —— + * curl -v -X POST \ + * "$DOMAIN/api/resources/$REMOTE_PATH?override=true" \ //服务器上相对路径 + * -H "X-Auth: $TOKEN" \ + * -F "data=@/path/to/local/photo.jpg" //photo.jpg 以 multipart/form-data 的格式上传 + */ + public String upload(byte[] fileBytes, String objectName) throws IOException { + // 1.获取唯一文件名 + // 2. 构造远程路径:固定到 userfiles 目录 + String remotePath = "userfiles/" + objectName; + + // 3. 获取登录令牌 + String token = login(); + + // 4. URL 编码(保留斜杠) + String encodedPath = URLEncoder.encode(remotePath, StandardCharsets.UTF_8.toString()) + .replace("%2F", "/"); + String url = domain + "/api/resources/" + encodedPath + "?override=true"; + + // 5. 构建并发送 multipart/form-data 请求 + try (CloseableHttpClient client = HttpClients.createDefault()) { + HttpPost post = new HttpPost(url); + post.setHeader("X-Auth", token); + + HttpEntity multipart = MultipartEntityBuilder.create() + .setMode(HttpMultipartMode.BROWSER_COMPATIBLE) + // name="files",filename 用新生成的 objectName + .addBinaryBody("files", fileBytes, ContentType.APPLICATION_OCTET_STREAM, objectName) + .build(); + + post.setEntity(multipart); + + try (CloseableHttpResponse resp = client.execute(post)) { + int status = resp.getStatusLine().getStatusCode(); + String body = EntityUtils.toString(resp.getEntity(), StandardCharsets.UTF_8); + if (status >= 200 && status < 300) { + log.info("上传成功 → {}", remotePath); + return body; + } else { + throw new IOException("上传失败,HTTP " + status + ",响应:" + body); + } + } + } + } +} diff --git a/sky-server/pom.xml b/sky-server/pom.xml index ff9b983..012b22f 100644 --- a/sky-server/pom.xml +++ b/sky-server/pom.xml @@ -115,8 +115,8 @@ poi-ooxml - org.springframework.boot - spring-boot-starter-security + org.springframework.security + spring-security-crypto com.github.pagehelper @@ -132,6 +132,7 @@ spring-boot-starter-cache 2.7.3 + diff --git a/sky-server/src/main/java/com/sky/config/FileBrowserConfiguration.java b/sky-server/src/main/java/com/sky/config/FileBrowserConfiguration.java new file mode 100644 index 0000000..fedc625 --- /dev/null +++ b/sky-server/src/main/java/com/sky/config/FileBrowserConfiguration.java @@ -0,0 +1,20 @@ +package com.sky.config; +import com.sky.properties.FileBrowserProperties; +import com.sky.utils.FileBrowserUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +@Slf4j +public class FileBrowserConfiguration { + @Bean + @ConditionalOnMissingBean + public FileBrowserUtil fileBrowserUtil(FileBrowserProperties fileBrowserProperties){ + log.info("开始创建filebrowser上传工具类对象:{}",fileBrowserProperties); + return new FileBrowserUtil(fileBrowserProperties.getDomain(), + fileBrowserProperties.getUsername(), + fileBrowserProperties.getPassword()); + } +} diff --git a/sky-server/src/main/java/com/sky/config/OssConfiguration.java b/sky-server/src/main/java/com/sky/config/OssConfiguration.java new file mode 100644 index 0000000..8e75d01 --- /dev/null +++ b/sky-server/src/main/java/com/sky/config/OssConfiguration.java @@ -0,0 +1,26 @@ +package com.sky.config; + +import com.sky.properties.AliOssProperties; +import com.sky.utils.AliOssUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * 配置类,用于创建AliOssUtil对象 + */ +@Configuration +@Slf4j +public class OssConfiguration { + + @Bean + @ConditionalOnMissingBean + public AliOssUtil aliOssUtil(AliOssProperties aliOssProperties){ + log.info("开始创建阿里云文件上传工具类对象:{}",aliOssProperties); + return new AliOssUtil(aliOssProperties.getEndpoint(), + aliOssProperties.getAccessKeyId(), + aliOssProperties.getAccessKeySecret(), + aliOssProperties.getBucketName()); + } +} diff --git a/sky-server/src/main/java/com/sky/config/SecurityConfiguration.java b/sky-server/src/main/java/com/sky/config/SecurityConfiguration.java new file mode 100644 index 0000000..13c5c1d --- /dev/null +++ b/sky-server/src/main/java/com/sky/config/SecurityConfiguration.java @@ -0,0 +1,15 @@ +package com.sky.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; + +@Configuration +public class SecurityConfiguration { + @Bean + public PasswordEncoder passwordEncoder() { + // 参数 strength 为工作因子,默认为 10,这里可以根据需要进行调整 + return new BCryptPasswordEncoder(10); + } +} diff --git a/sky-server/src/main/java/com/sky/config/WebSecurityConfig.java b/sky-server/src/main/java/com/sky/config/WebSecurityConfig.java deleted file mode 100644 index a6aa253..0000000 --- a/sky-server/src/main/java/com/sky/config/WebSecurityConfig.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.sky.config; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; - -@Configuration -@EnableWebSecurity -public class WebSecurityConfig extends WebSecurityConfigurerAdapter { - @Override - protected void configure(HttpSecurity http) throws Exception { - http - .authorizeRequests() - .anyRequest().permitAll() // 允许所有请求 - .and() - .csrf().disable(); // 禁用CSRF保护 - } - @Bean - public BCryptPasswordEncoder encoder(){ - return new BCryptPasswordEncoder(); - } -} -//@Configuration -//@EnableWebSecurity -//public class WebSecurityConfig extends WebSecurityConfigurerAdapter { -// @Override -// protected void configure(HttpSecurity http) throws Exception { -// http -// .authorizeRequests() -// .anyRequest().authenticated() // 需要认证才能访问 -// .and() -// .httpBasic() // 使用基本的HTTP认证 -// .and() -// .csrf().disable(); // 禁用CSRF保护,适用于API服务 -// } -// -// @Bean -// public BCryptPasswordEncoder encoder() { -// return new BCryptPasswordEncoder(); -// } -//} \ No newline at end of file diff --git a/sky-server/src/main/java/com/sky/controller/admin/CommonController.java b/sky-server/src/main/java/com/sky/controller/admin/CommonController.java index 343728e..b10a77b 100644 --- a/sky-server/src/main/java/com/sky/controller/admin/CommonController.java +++ b/sky-server/src/main/java/com/sky/controller/admin/CommonController.java @@ -1,6 +1,6 @@ package com.sky.controller.admin; -import com.aliyuncs.exceptions.ClientException; +import com.sky.constant.MessageConstant; import com.sky.result.Result; import com.sky.utils.AliOssUtil; import io.swagger.annotations.Api; @@ -13,20 +13,45 @@ import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; +import java.util.UUID; +/** + * 通用接口 + */ @RestController @RequestMapping("/admin/common") @Api(tags = "通用接口") @Slf4j - public class CommonController { + @Autowired private AliOssUtil aliOssUtil; + + /** + * 文件上传 + * @param file + * @return + */ @PostMapping("/upload") @ApiOperation("文件上传") - public Result upload(MultipartFile file) throws IOException, ClientException { - log.info("文件上传:{}",file); - String url=aliOssUtil.upload(file); - return Result.success(url); + public Result upload(MultipartFile file){ + log.info("文件上传:{}",file); + + try { + //原始文件名 + String originalFilename = file.getOriginalFilename(); + //截取原始文件名的后缀 dfdfdf.png + String extension = originalFilename.substring(originalFilename.lastIndexOf(".")); + //构造新文件名称 + String objectName = UUID.randomUUID().toString() + extension; + + //文件的访问地址 + String filePath = aliOssUtil.upload(file.getBytes(), objectName); + return Result.success(filePath); + } catch (IOException e) { + log.error("文件上传失败:{}", e); + } + + return Result.error(MessageConstant.UPLOAD_FAILED); } } diff --git a/sky-server/src/main/java/com/sky/service/impl/EmployeeServiceImpl.java b/sky-server/src/main/java/com/sky/service/impl/EmployeeServiceImpl.java index 6f23cac..6d613e3 100644 --- a/sky-server/src/main/java/com/sky/service/impl/EmployeeServiceImpl.java +++ b/sky-server/src/main/java/com/sky/service/impl/EmployeeServiceImpl.java @@ -21,6 +21,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import java.util.List; @@ -32,7 +33,7 @@ public class EmployeeServiceImpl implements EmployeeService { @Autowired private EmployeeMapper employeeMapper; @Autowired - private BCryptPasswordEncoder bCryptPasswordEncoder; + private PasswordEncoder passwordEncoder; /** * 员工登录 @@ -54,7 +55,7 @@ public class EmployeeServiceImpl implements EmployeeService { } //密码比对 - if (!bCryptPasswordEncoder.matches(password,employee.getPassword())) { + if (!passwordEncoder.matches(password,employee.getPassword())) { //密码错误 throw new PasswordErrorException(MessageConstant.PASSWORD_ERROR); } @@ -73,7 +74,7 @@ public class EmployeeServiceImpl implements EmployeeService { Employee employee = new Employee(); //对象属性拷贝 BeanUtils.copyProperties(employeeDTO, employee); - String encodedPassword=bCryptPasswordEncoder.encode(PasswordConstant.DEFAULT_PASSWORD); + String encodedPassword=passwordEncoder.encode(PasswordConstant.DEFAULT_PASSWORD); employee.setPassword(encodedPassword); employee.setStatus(StatusConstant.ENABLE); employeeMapper.save(employee); @@ -113,8 +114,8 @@ public class EmployeeServiceImpl implements EmployeeService { @Override public void changePassword(EmployeeChangePasswordDTO employeeChangePasswordDTO) { Employee employee=employeeMapper.queryById(BaseContext.getCurrentId()); - if(bCryptPasswordEncoder.matches(employeeChangePasswordDTO.getOldPassword(),employee.getPassword())){ - String encodedPassword = bCryptPasswordEncoder.encode(employeeChangePasswordDTO.getNewPassword()); + if(passwordEncoder.matches(employeeChangePasswordDTO.getOldPassword(),employee.getPassword())){ + String encodedPassword = passwordEncoder.encode(employeeChangePasswordDTO.getNewPassword()); employee.setPassword(encodedPassword); employeeMapper.update(employee); }else diff --git a/sky-server/src/main/resources/application-dev.yml b/sky-server/src/main/resources/application-dev.yml index 4a8cc35..11402dc 100644 --- a/sky-server/src/main/resources/application-dev.yml +++ b/sky-server/src/main/resources/application-dev.yml @@ -17,6 +17,10 @@ sky: access-key-secret: AJPJSYc5sdwiZoj8RWzsXtjKR3W8f0 endpoint: https://oss-cn-hangzhou.aliyuncs.com bucket-name: zyjavaweb + filebrowser: + domain: https://fshare.bitday.top + username: admin + password: asdf14789 wechat: appid: wxa3b6f70e4ffb92cd diff --git a/sky-server/src/main/resources/application.yml b/sky-server/src/main/resources/application.yml index 2ba91e8..0486e81 100644 --- a/sky-server/src/main/resources/application.yml +++ b/sky-server/src/main/resources/application.yml @@ -55,6 +55,12 @@ sky: bucket-name: {sky.alioss.bucket-name} access-key-id: {sky.alioss.access-key-id} access-key-secret: {sky.alioss.access-key-secret} + + filebrowser: + domain: {sky.filebrowser.domain} + username: {sky.filebrowser.username} + password: {sky.filebrowser.password} + wechat: appid: ${sky.wechat.appid} secret: ${sky.wechat.secret}