init
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
<?xml version="1.0"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>BladeX-Tool</artifactId>
|
||||
<groupId>org.springblade</groupId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>blade-core-boot</artifactId>
|
||||
<name>${project.artifactId}</name>
|
||||
<version>${project.parent.version}</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<properties>
|
||||
<module.name>org.springblade.blade.core.boot</module.name>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<!-- Blade -->
|
||||
<dependency>
|
||||
<groupId>org.springblade</groupId>
|
||||
<artifactId>blade-core-context</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springblade</groupId>
|
||||
<artifactId>blade-core-db</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springblade</groupId>
|
||||
<artifactId>blade-core-secure</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springblade</groupId>
|
||||
<artifactId>blade-core-cloud</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springblade</groupId>
|
||||
<artifactId>blade-starter-cache</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springblade</groupId>
|
||||
<artifactId>blade-starter-redis</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springblade</groupId>
|
||||
<artifactId>blade-starter-log</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springblade</groupId>
|
||||
<artifactId>blade-starter-mybatis</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springblade</groupId>
|
||||
<artifactId>blade-starter-xss</artifactId>
|
||||
</dependency>
|
||||
<!-- Auto -->
|
||||
<dependency>
|
||||
<groupId>org.springblade</groupId>
|
||||
<artifactId>blade-core-auto</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.core.boot.config;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springblade.core.launch.props.BladePropertySource;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
||||
|
||||
/**
|
||||
* blade自动配置类
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@Slf4j
|
||||
@AutoConfiguration
|
||||
@AllArgsConstructor
|
||||
@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)
|
||||
@BladePropertySource(value = "classpath:/blade-boot.yml")
|
||||
public class BladeBootAutoConfiguration {
|
||||
|
||||
}
|
||||
+120
@@ -0,0 +1,120 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.core.boot.config;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springblade.core.boot.handler.BladeAsyncUncaughtExceptionHandler;
|
||||
import org.springblade.core.context.BladeContext;
|
||||
import org.springblade.core.context.BladeRunnableWrapper;
|
||||
import org.springblade.core.launch.props.BladeProperties;
|
||||
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.boot.task.ThreadPoolTaskExecutorCustomizer;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.scheduling.annotation.AsyncConfigurer;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
|
||||
/**
|
||||
* 异步处理
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@Slf4j
|
||||
@EnableAsync
|
||||
@EnableScheduling
|
||||
@AllArgsConstructor
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class BladeExecutorConfiguration {
|
||||
|
||||
private static final String ASYNC_TASK_THREAD_NAME_PREFIX = "async-task-";
|
||||
|
||||
private static final String ASYNC_SCHEDULER_THREAD_NAME_PREFIX = "async-scheduler";
|
||||
|
||||
private static final String BOOT_ASYNC_CONFIGURER_BEAN_NAME = "applicationTaskExecutorAsyncConfigurer";
|
||||
|
||||
@Bean
|
||||
public ThreadPoolTaskExecutorCustomizer taskExecutorCustomizer() {
|
||||
return taskExecutor -> {
|
||||
taskExecutor.setThreadNamePrefix(ASYNC_TASK_THREAD_NAME_PREFIX);
|
||||
taskExecutor.setTaskDecorator(BladeRunnableWrapper::new);
|
||||
taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ThreadPoolTaskExecutorCustomizer taskSchedulerCustomizer() {
|
||||
return taskExecutor -> {
|
||||
taskExecutor.setThreadNamePrefix(ASYNC_SCHEDULER_THREAD_NAME_PREFIX);
|
||||
taskExecutor.setTaskDecorator(BladeRunnableWrapper::new);
|
||||
taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
public BladeAsyncUncaughtExceptionHandler bladeAsyncUncaughtExceptionHandler(BladeContext bladeContext,
|
||||
BladeProperties bladeProperties,
|
||||
ApplicationEventPublisher eventPublisher) {
|
||||
return new BladeAsyncUncaughtExceptionHandler(bladeContext, bladeProperties, eventPublisher);
|
||||
}
|
||||
|
||||
/**
|
||||
* 装饰 Spring Boot 自动注册的 applicationTaskExecutorAsyncConfigurer:
|
||||
* getAsyncExecutor() 透传原 Bean 的实现(即 applicationTaskExecutor)
|
||||
* getAsyncUncaughtExceptionHandler() 接入 BladeAsyncUncaughtExceptionHandler 实现统一异步异常处理
|
||||
*/
|
||||
@Bean
|
||||
public static BeanPostProcessor bladeAsyncConfigurerDecorator(ObjectProvider<BladeAsyncUncaughtExceptionHandler> handlerProvider) {
|
||||
return new BeanPostProcessor() {
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(@NonNull Object bean, @NonNull String beanName) {
|
||||
if (!BOOT_ASYNC_CONFIGURER_BEAN_NAME.equals(beanName) || !(bean instanceof AsyncConfigurer original)) {
|
||||
return bean;
|
||||
}
|
||||
return new AsyncConfigurer() {
|
||||
@Override
|
||||
public Executor getAsyncExecutor() {
|
||||
return original.getAsyncExecutor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
|
||||
return handlerProvider.getIfAvailable();
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.core.boot.config;
|
||||
|
||||
import jakarta.servlet.DispatcherType;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.springblade.core.boot.request.BladeRequestFilter;
|
||||
import org.springblade.core.boot.request.RequestProperties;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.core.Ordered;
|
||||
|
||||
/**
|
||||
* 过滤器配置类
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@AutoConfiguration
|
||||
@AllArgsConstructor
|
||||
@EnableConfigurationProperties({RequestProperties.class})
|
||||
public class BladeRequestConfiguration {
|
||||
|
||||
private final RequestProperties requestProperties;
|
||||
|
||||
/**
|
||||
* 全局过滤器
|
||||
*/
|
||||
@Bean
|
||||
public FilterRegistrationBean<BladeRequestFilter> bladeFilterRegistration() {
|
||||
FilterRegistrationBean<BladeRequestFilter> registration = new FilterRegistrationBean<>();
|
||||
registration.setDispatcherTypes(DispatcherType.REQUEST);
|
||||
registration.setFilter(new BladeRequestFilter(requestProperties));
|
||||
registration.addUrlPatterns("/*");
|
||||
registration.setName("bladeRequestFilter");
|
||||
registration.setOrder(Ordered.HIGHEST_PRECEDENCE);
|
||||
return registration;
|
||||
}
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.core.boot.config;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.retry.interceptor.RetryInterceptorBuilder;
|
||||
import org.springframework.retry.interceptor.RetryOperationsInterceptor;
|
||||
|
||||
/**
|
||||
* 重试机制
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@Slf4j
|
||||
@AutoConfiguration
|
||||
public class BladeRetryConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(name = "configServerRetryInterceptor")
|
||||
public RetryOperationsInterceptor configServerRetryInterceptor() {
|
||||
log.info(String.format(
|
||||
"configServerRetryInterceptor: Changing backOffOptions " +
|
||||
"to initial: %s, multiplier: %s, maxInterval: %s",
|
||||
1000, 1.2, 5000));
|
||||
return RetryInterceptorBuilder
|
||||
.stateless()
|
||||
.backOffOptions(1000, 1.2, 5000)
|
||||
.maxAttempts(10)
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.core.boot.config;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springblade.core.boot.props.BladeFileProperties;
|
||||
import org.springblade.core.boot.props.BladeUploadProperties;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
/**
|
||||
* WEB配置
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@Slf4j
|
||||
@AutoConfiguration
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||
@AllArgsConstructor
|
||||
@EnableConfigurationProperties({
|
||||
BladeUploadProperties.class, BladeFileProperties.class
|
||||
})
|
||||
public class BladeWebMvcConfiguration implements WebMvcConfigurer {
|
||||
|
||||
private final BladeUploadProperties bladeUploadProperties;
|
||||
|
||||
@Override
|
||||
public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
||||
String path = bladeUploadProperties.getSavePath();
|
||||
registry.addResourceHandler("/upload/**")
|
||||
.addResourceLocations("file:" + path + "/upload/");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,288 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.core.boot.ctrl;
|
||||
|
||||
import org.springblade.core.boot.file.LocalFile;
|
||||
import org.springblade.core.boot.file.BladeFileUtil;
|
||||
import org.springblade.core.secure.BladeUser;
|
||||
import org.springblade.core.secure.utils.AuthUtil;
|
||||
import org.springblade.core.tool.api.R;
|
||||
import org.springblade.core.tool.utils.Charsets;
|
||||
import org.springblade.core.tool.utils.StringPool;
|
||||
import org.springblade.core.tool.utils.WebUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.io.FileSystemResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.support.ResourceRegion;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import org.springframework.web.util.UriUtils;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Blade控制器封装类
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
public class BladeController {
|
||||
|
||||
/**
|
||||
* ============================ REQUEST =================================================
|
||||
*/
|
||||
|
||||
@Autowired
|
||||
private HttpServletRequest request;
|
||||
|
||||
/**
|
||||
* 获取request
|
||||
*/
|
||||
public HttpServletRequest getRequest() {
|
||||
return this.request;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public BladeUser getUser() {
|
||||
return AuthUtil.getUser();
|
||||
}
|
||||
|
||||
/** ============================ API_RESULT ================================================= */
|
||||
|
||||
/**
|
||||
* 返回ApiResult
|
||||
*
|
||||
* @param data
|
||||
* @return R
|
||||
*/
|
||||
public <T> R<T> data(T data) {
|
||||
return R.data(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回ApiResult
|
||||
*
|
||||
* @param data
|
||||
* @param message
|
||||
* @return R
|
||||
*/
|
||||
public <T> R<T> data(T data, String message) {
|
||||
return R.data(data, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回ApiResult
|
||||
*
|
||||
* @param data
|
||||
* @param message
|
||||
* @param code
|
||||
* @return R
|
||||
*/
|
||||
public <T> R<T> data(T data, String message, int code) {
|
||||
return R.data(code, data, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回ApiResult
|
||||
*
|
||||
* @param message
|
||||
* @return R
|
||||
*/
|
||||
public R success(String message) {
|
||||
return R.success(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回ApiResult
|
||||
*
|
||||
* @param message
|
||||
* @return R
|
||||
*/
|
||||
public R fail(String message) {
|
||||
return R.fail(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回ApiResult
|
||||
*
|
||||
* @param flag
|
||||
* @return R
|
||||
*/
|
||||
public R status(boolean flag) {
|
||||
return R.status(flag);
|
||||
}
|
||||
|
||||
|
||||
/**============================ FILE ================================================= */
|
||||
|
||||
/**
|
||||
* 获取BladeFile封装类
|
||||
*
|
||||
* @param file
|
||||
* @return
|
||||
*/
|
||||
public LocalFile getFile(MultipartFile file) {
|
||||
return BladeFileUtil.getFile(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取BladeFile封装类
|
||||
*
|
||||
* @param file
|
||||
* @param dir
|
||||
* @return
|
||||
*/
|
||||
public LocalFile getFile(MultipartFile file, String dir) {
|
||||
return BladeFileUtil.getFile(file, dir);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取BladeFile封装类
|
||||
*
|
||||
* @param file
|
||||
* @param dir
|
||||
* @param path
|
||||
* @param virtualPath
|
||||
* @return
|
||||
*/
|
||||
public LocalFile getFile(MultipartFile file, String dir, String path, String virtualPath) {
|
||||
return BladeFileUtil.getFile(file, dir, path, virtualPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取BladeFile封装类
|
||||
*
|
||||
* @param files
|
||||
* @return
|
||||
*/
|
||||
public List<LocalFile> getFiles(List<MultipartFile> files) {
|
||||
return BladeFileUtil.getFiles(files);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取BladeFile封装类
|
||||
*
|
||||
* @param files
|
||||
* @param dir
|
||||
* @return
|
||||
*/
|
||||
public List<LocalFile> getFiles(List<MultipartFile> files, String dir) {
|
||||
return BladeFileUtil.getFiles(files, dir);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取BladeFile封装类
|
||||
*
|
||||
* @param files
|
||||
* @param path
|
||||
* @param virtualPath
|
||||
* @return
|
||||
*/
|
||||
public List<LocalFile> getFiles(List<MultipartFile> files, String dir, String path, String virtualPath) {
|
||||
return BladeFileUtil.getFiles(files, dir, path, virtualPath);
|
||||
}
|
||||
/**
|
||||
* 下载文件
|
||||
*
|
||||
* @param file 文件
|
||||
* @return {ResponseEntity}
|
||||
* @throws IOException io异常
|
||||
*/
|
||||
protected ResponseEntity<ResourceRegion> download(File file) throws IOException {
|
||||
String fileName = file.getName();
|
||||
return download(file, fileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载
|
||||
*
|
||||
* @param file 文件
|
||||
* @param fileName 生成的文件名
|
||||
* @return {ResponseEntity}
|
||||
* @throws IOException io异常
|
||||
*/
|
||||
protected ResponseEntity<ResourceRegion> download(File file, String fileName) throws IOException {
|
||||
Resource resource = new FileSystemResource(file);
|
||||
return download(resource, fileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载
|
||||
*
|
||||
* @param resource 资源
|
||||
* @param fileName 生成的文件名
|
||||
* @return {ResponseEntity}
|
||||
* @throws IOException io异常
|
||||
*/
|
||||
protected ResponseEntity<ResourceRegion> download(Resource resource, String fileName) throws IOException {
|
||||
HttpServletRequest request = WebUtil.getRequest();
|
||||
String header = request.getHeader(HttpHeaders.USER_AGENT);
|
||||
// 避免空指针
|
||||
header = header == null ? StringPool.EMPTY : header.toUpperCase();
|
||||
HttpStatus status;
|
||||
String msie= "MSIE";
|
||||
String trident= "TRIDENT";
|
||||
String edge= "EDGE";
|
||||
if (header.contains(msie) || header.contains(trident) || header.contains(edge)) {
|
||||
status = HttpStatus.OK;
|
||||
} else {
|
||||
status = HttpStatus.CREATED;
|
||||
}
|
||||
// 断点续传
|
||||
long position = 0;
|
||||
long count = resource.contentLength();
|
||||
String range = request.getHeader(HttpHeaders.RANGE);
|
||||
if (null != range) {
|
||||
status = HttpStatus.PARTIAL_CONTENT;
|
||||
String[] rangeRange = range.replace("bytes=", StringPool.EMPTY).split(StringPool.DASH);
|
||||
position = Long.parseLong(rangeRange[0]);
|
||||
if (rangeRange.length > 1) {
|
||||
long end = Long.parseLong(rangeRange[1]);
|
||||
count = end - position + 1;
|
||||
}
|
||||
}
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
|
||||
String encodeFileName = UriUtils.encode(fileName, Charsets.UTF_8);
|
||||
// 兼容各种浏览器下载:
|
||||
// https://blog.robotshell.org/2012/deal-with-http-header-encoding-for-file-download/
|
||||
String disposition = "attachment;" +
|
||||
"filename=\"" + encodeFileName + "\";" +
|
||||
"filename*=utf-8''" + encodeFileName;
|
||||
headers.set(HttpHeaders.CONTENT_DISPOSITION, disposition);
|
||||
return new ResponseEntity<>(new ResourceRegion(resource, position, count), headers, status);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: DreamLu (596392912@qq.com)
|
||||
*/
|
||||
package org.springblade.core.boot.error;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonValue;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* 异常类型
|
||||
*
|
||||
* @author L.cm
|
||||
*/
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public enum ErrorType {
|
||||
/**
|
||||
* 异常类型
|
||||
*/
|
||||
REQUEST("request"),
|
||||
ASYNC("async"),
|
||||
SCHEDULER("scheduler"),
|
||||
WEB_SOCKET("websocket"),
|
||||
OTHER("other");
|
||||
|
||||
@JsonValue
|
||||
private final String type;
|
||||
|
||||
@Nullable
|
||||
@JsonCreator
|
||||
public static ErrorType of(String type) {
|
||||
ErrorType[] values = ErrorType.values();
|
||||
for (ErrorType errorType : values) {
|
||||
if (errorType.type.equals(type)) {
|
||||
return errorType;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: DreamLu (596392912@qq.com)
|
||||
*/
|
||||
package org.springblade.core.boot.error;
|
||||
|
||||
import org.springblade.core.log.model.LogError;
|
||||
import org.springblade.core.tool.utils.DateUtil;
|
||||
import org.springblade.core.tool.utils.Exceptions;
|
||||
import org.springblade.core.tool.utils.ObjectUtil;
|
||||
|
||||
/**
|
||||
* 异常工具类
|
||||
*
|
||||
* @author L.cm
|
||||
*/
|
||||
public class ErrorUtil {
|
||||
|
||||
/**
|
||||
* 初始化异常信息
|
||||
*
|
||||
* @param error 异常
|
||||
* @param event 异常事件封装
|
||||
*/
|
||||
public static void initErrorInfo(Throwable error, LogError event) {
|
||||
// 堆栈信息
|
||||
event.setStackTrace(Exceptions.getStackTraceAsString(error));
|
||||
event.setExceptionName(error.getClass().getName());
|
||||
event.setMessage(error.getMessage());
|
||||
event.setCreateTime(DateUtil.now());
|
||||
StackTraceElement[] elements = error.getStackTrace();
|
||||
if (ObjectUtil.isNotEmpty(elements)) {
|
||||
// 报错的类信息
|
||||
StackTraceElement element = elements[0];
|
||||
event.setMethodClass(element.getClassName());
|
||||
event.setFileName(element.getFileName());
|
||||
event.setMethodName(element.getMethodName());
|
||||
event.setLineNumber(element.getLineNumber());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,249 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.core.boot.file;
|
||||
|
||||
import org.springblade.core.tool.utils.StringPool;
|
||||
import org.springblade.core.tool.utils.StringUtil;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 文件工具类
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
public class BladeFileUtil {
|
||||
|
||||
/**
|
||||
* 定义允许上传的文件扩展名
|
||||
*/
|
||||
private static final HashMap<String, String> EXT_MAP = new HashMap<>();
|
||||
private static final String IS_DIR = "is_dir";
|
||||
private static final String FILE_NAME = "filename";
|
||||
private static final String FILE_SIZE = "filesize";
|
||||
|
||||
/**
|
||||
* 图片扩展名
|
||||
*/
|
||||
private static final String[] FILE_TYPES = new String[]{"gif", "jpg", "jpeg", "png", "bmp"};
|
||||
|
||||
static {
|
||||
EXT_MAP.put("image", ".gif,.jpg,.jpeg,.png,.bmp,.JPG,.JPEG,.PNG");
|
||||
EXT_MAP.put("flash", ".swf,.flv");
|
||||
EXT_MAP.put("media", ".swf,.flv,.mp3,.mp4,.wav,.wma,.wmv,.mid,.avi,.mpg,.asf,.rm,.rmvb");
|
||||
EXT_MAP.put("file", ".doc,.docx,.xls,.xlsx,.ppt,.htm,.html,.txt,.zip,.rar,.gz,.bz2");
|
||||
EXT_MAP.put("allfile", ".gif,.jpg,.jpeg,.png,.bmp,.swf,.flv,.mp3,.mp4,.wav,.wma,.wmv,.mid,.avi,.mpg,.asf,.rm,.rmvb,.doc,.docx,.xls,.xlsx,.ppt,.htm,.html,.txt,.zip,.rar,.gz,.bz2");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件后缀
|
||||
*
|
||||
* @param fileName 文件名
|
||||
* @return String 返回后缀
|
||||
*/
|
||||
public static String getFileExt(String fileName) {
|
||||
return fileName.substring(fileName.lastIndexOf(StringPool.DOT));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试文件后缀 只让指定后缀的文件上传,像jsp,war,sh等危险的后缀禁止
|
||||
*
|
||||
* @param dir 目录
|
||||
* @param fileName 文件名
|
||||
* @return 返回成功与否
|
||||
*/
|
||||
public static boolean testExt(String dir, String fileName) {
|
||||
String fileExt = getFileExt(fileName);
|
||||
String ext = EXT_MAP.get(dir);
|
||||
return StringUtil.isNotBlank(ext) && (ext.contains(fileExt.toLowerCase()) || ext.contains(fileExt.toUpperCase()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件管理排序
|
||||
*/
|
||||
public enum FileSort {
|
||||
|
||||
/**
|
||||
* 大小
|
||||
*/
|
||||
size,
|
||||
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
type,
|
||||
|
||||
/**
|
||||
* 名称
|
||||
*/
|
||||
name;
|
||||
|
||||
/**
|
||||
* 文本排序转换成枚举
|
||||
*
|
||||
* @param sort
|
||||
* @return
|
||||
*/
|
||||
public static FileSort of(String sort) {
|
||||
try {
|
||||
return FileSort.valueOf(sort);
|
||||
} catch (Exception e) {
|
||||
return FileSort.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class NameComparator implements Comparator {
|
||||
@Override
|
||||
public int compare(Object a, Object b) {
|
||||
Hashtable hashA = (Hashtable) a;
|
||||
Hashtable hashB = (Hashtable) b;
|
||||
if (((Boolean) hashA.get(IS_DIR)) && !((Boolean) hashB.get(IS_DIR))) {
|
||||
return -1;
|
||||
} else if (!((Boolean) hashA.get(IS_DIR)) && ((Boolean) hashB.get(IS_DIR))) {
|
||||
return 1;
|
||||
} else {
|
||||
return ((String) hashA.get(FILE_NAME)).compareTo((String) hashB.get(FILE_NAME));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class SizeComparator implements Comparator {
|
||||
@Override
|
||||
public int compare(Object a, Object b) {
|
||||
Hashtable hashA = (Hashtable) a;
|
||||
Hashtable hashB = (Hashtable) b;
|
||||
if (((Boolean) hashA.get(IS_DIR)) && !((Boolean) hashB.get(IS_DIR))) {
|
||||
return -1;
|
||||
} else if (!((Boolean) hashA.get(IS_DIR)) && ((Boolean) hashB.get(IS_DIR))) {
|
||||
return 1;
|
||||
} else {
|
||||
if (((Long) hashA.get(FILE_SIZE)) > ((Long) hashB.get(FILE_SIZE))) {
|
||||
return 1;
|
||||
} else if (((Long) hashA.get(FILE_SIZE)) < ((Long) hashB.get(FILE_SIZE))) {
|
||||
return -1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class TypeComparator implements Comparator {
|
||||
@Override
|
||||
public int compare(Object a, Object b) {
|
||||
Hashtable hashA = (Hashtable) a;
|
||||
Hashtable hashB = (Hashtable) b;
|
||||
if (((Boolean) hashA.get(IS_DIR)) && !((Boolean) hashB.get(IS_DIR))) {
|
||||
return -1;
|
||||
} else if (!((Boolean) hashA.get(IS_DIR)) && ((Boolean) hashB.get(IS_DIR))) {
|
||||
return 1;
|
||||
} else {
|
||||
return ((String) hashA.get("filetype")).compareTo((String) hashB.get("filetype"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static String formatUrl(String url) {
|
||||
return url.replaceAll("\\\\", "/");
|
||||
}
|
||||
|
||||
|
||||
/********************************BladeFile封装********************************************************/
|
||||
|
||||
/**
|
||||
* 获取BladeFile封装类
|
||||
*
|
||||
* @param file 文件
|
||||
* @return BladeFile
|
||||
*/
|
||||
public static LocalFile getFile(MultipartFile file) {
|
||||
return getFile(file, "image", null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取BladeFile封装类
|
||||
*
|
||||
* @param file 文件
|
||||
* @param dir 目录
|
||||
* @return BladeFile
|
||||
*/
|
||||
public static LocalFile getFile(MultipartFile file, String dir) {
|
||||
return getFile(file, dir, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取BladeFile封装类
|
||||
*
|
||||
* @param file 文件
|
||||
* @param dir 目录
|
||||
* @param path 路径
|
||||
* @param virtualPath 虚拟路径
|
||||
* @return BladeFile
|
||||
*/
|
||||
public static LocalFile getFile(MultipartFile file, String dir, String path, String virtualPath) {
|
||||
return new LocalFile(file, dir, path, virtualPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取BladeFile封装类
|
||||
*
|
||||
* @param files 文件集合
|
||||
* @return BladeFile
|
||||
*/
|
||||
public static List<LocalFile> getFiles(List<MultipartFile> files) {
|
||||
return getFiles(files, "image", null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取BladeFile封装类
|
||||
*
|
||||
* @param files 文件集合
|
||||
* @param dir 目录
|
||||
* @return BladeFile
|
||||
*/
|
||||
public static List<LocalFile> getFiles(List<MultipartFile> files, String dir) {
|
||||
return getFiles(files, dir, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取BladeFile封装类
|
||||
*
|
||||
* @param files 文件集合
|
||||
* @param path 路径
|
||||
* @param virtualPath 虚拟路径
|
||||
* @return BladeFile
|
||||
*/
|
||||
public static List<LocalFile> getFiles(List<MultipartFile> files, String dir, String path, String virtualPath) {
|
||||
List<LocalFile> list = new ArrayList<>();
|
||||
for (MultipartFile file : files) {
|
||||
list.add(new LocalFile(file, dir, path, virtualPath));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.core.boot.file;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* 文件管理类
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
public class FileProxyManager {
|
||||
private IFileProxy defaultFileProxyFactory = new LocalFileProxyFactory();
|
||||
|
||||
private static final FileProxyManager ME = new FileProxyManager();
|
||||
|
||||
public static FileProxyManager me() {
|
||||
return ME;
|
||||
}
|
||||
|
||||
public IFileProxy getDefaultFileProxyFactory() {
|
||||
return defaultFileProxyFactory;
|
||||
}
|
||||
|
||||
public void setDefaultFileProxyFactory(IFileProxy defaultFileProxyFactory) {
|
||||
this.defaultFileProxyFactory = defaultFileProxyFactory;
|
||||
}
|
||||
|
||||
public String[] path(File file, String dir) {
|
||||
return defaultFileProxyFactory.path(file, dir);
|
||||
}
|
||||
|
||||
public File rename(File file, String path) {
|
||||
return defaultFileProxyFactory.rename(file, path);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.core.boot.file;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* 文件代理接口
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
public interface IFileProxy {
|
||||
|
||||
/**
|
||||
* 返回路径[物理路径][虚拟路径]
|
||||
*
|
||||
* @param file 文件
|
||||
* @param dir 目录
|
||||
* @return
|
||||
*/
|
||||
String[] path(File file, String dir);
|
||||
|
||||
/**
|
||||
* 文件重命名策略
|
||||
*
|
||||
* @param file 文件
|
||||
* @param path 路径
|
||||
* @return
|
||||
*/
|
||||
File rename(File file, String path);
|
||||
|
||||
/**
|
||||
* 图片压缩
|
||||
*
|
||||
* @param path 路径
|
||||
*/
|
||||
void compress(String path);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.core.boot.file;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import lombok.Data;
|
||||
import org.springblade.core.boot.props.BladeFileProperties;
|
||||
import org.springblade.core.tool.utils.DateUtil;
|
||||
import org.springblade.core.tool.utils.SpringUtil;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* 上传文件封装
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@Data
|
||||
public class LocalFile {
|
||||
/**
|
||||
* 上传文件在附件表中的id
|
||||
*/
|
||||
private Object fileId;
|
||||
|
||||
/**
|
||||
* 上传文件
|
||||
*/
|
||||
@JsonIgnore
|
||||
private MultipartFile file;
|
||||
|
||||
/**
|
||||
* 文件外网地址
|
||||
*/
|
||||
private String domain;
|
||||
|
||||
/**
|
||||
* 上传分类文件夹
|
||||
*/
|
||||
private String dir;
|
||||
|
||||
/**
|
||||
* 上传物理路径
|
||||
*/
|
||||
private String uploadPath;
|
||||
|
||||
/**
|
||||
* 上传虚拟路径
|
||||
*/
|
||||
private String uploadVirtualPath;
|
||||
|
||||
/**
|
||||
* 文件名
|
||||
*/
|
||||
private String fileName;
|
||||
|
||||
/**
|
||||
* 真实文件名
|
||||
*/
|
||||
private String originalFileName;
|
||||
|
||||
/**
|
||||
* 文件配置
|
||||
*/
|
||||
private static BladeFileProperties fileProperties;
|
||||
|
||||
private static BladeFileProperties getBladeFileProperties() {
|
||||
if (fileProperties == null) {
|
||||
fileProperties = SpringUtil.getBean(BladeFileProperties.class);
|
||||
}
|
||||
return fileProperties;
|
||||
}
|
||||
|
||||
public LocalFile(MultipartFile file, String dir) {
|
||||
this.dir = dir;
|
||||
this.file = file;
|
||||
this.fileName = file.getName();
|
||||
this.originalFileName = file.getOriginalFilename();
|
||||
this.domain = getBladeFileProperties().getUploadDomain();
|
||||
this.uploadPath = BladeFileUtil.formatUrl(File.separator + getBladeFileProperties().getUploadRealPath() + File.separator + dir + File.separator + DateUtil.format(DateUtil.now(), "yyyyMMdd") + File.separator + this.originalFileName);
|
||||
this.uploadVirtualPath = BladeFileUtil.formatUrl(getBladeFileProperties().getUploadCtxPath().replace(getBladeFileProperties().getContextPath(), "") + File.separator + dir + File.separator + DateUtil.format(DateUtil.now(), "yyyyMMdd") + File.separator + this.originalFileName);
|
||||
}
|
||||
|
||||
public LocalFile(MultipartFile file, String dir, String uploadPath, String uploadVirtualPath) {
|
||||
this(file, dir);
|
||||
if (null != uploadPath) {
|
||||
this.uploadPath = BladeFileUtil.formatUrl(uploadPath);
|
||||
this.uploadVirtualPath = BladeFileUtil.formatUrl(uploadVirtualPath);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 图片上传
|
||||
*/
|
||||
public void transfer() {
|
||||
transfer(getBladeFileProperties().getCompress());
|
||||
}
|
||||
|
||||
/**
|
||||
* 图片上传
|
||||
*
|
||||
* @param compress 是否压缩
|
||||
*/
|
||||
public void transfer(boolean compress) {
|
||||
IFileProxy fileFactory = FileProxyManager.me().getDefaultFileProxyFactory();
|
||||
this.transfer(fileFactory, compress);
|
||||
}
|
||||
|
||||
/**
|
||||
* 图片上传
|
||||
*
|
||||
* @param fileFactory 文件上传工厂类
|
||||
* @param compress 是否压缩
|
||||
*/
|
||||
public void transfer(IFileProxy fileFactory, boolean compress) {
|
||||
try {
|
||||
File file = new File(uploadPath);
|
||||
|
||||
if (null != fileFactory) {
|
||||
String[] path = fileFactory.path(file, dir);
|
||||
this.uploadPath = path[0];
|
||||
this.uploadVirtualPath = path[1];
|
||||
file = fileFactory.rename(file, path[0]);
|
||||
}
|
||||
|
||||
File pfile = file.getParentFile();
|
||||
if (!pfile.exists()) {
|
||||
pfile.mkdirs();
|
||||
}
|
||||
|
||||
this.file.transferTo(file);
|
||||
|
||||
if (compress) {
|
||||
fileFactory.compress(this.uploadPath);
|
||||
}
|
||||
|
||||
} catch (IllegalStateException | IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+126
@@ -0,0 +1,126 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.core.boot.file;
|
||||
|
||||
import org.springblade.core.boot.props.BladeFileProperties;
|
||||
import org.springblade.core.tool.utils.DateUtil;
|
||||
import org.springblade.core.tool.utils.ImageUtil;
|
||||
import org.springblade.core.tool.utils.SpringUtil;
|
||||
import org.springblade.core.tool.utils.StringPool;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
|
||||
/**
|
||||
* 文件代理类
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
public class LocalFileProxyFactory implements IFileProxy {
|
||||
|
||||
/**
|
||||
* 文件配置
|
||||
*/
|
||||
private static BladeFileProperties fileProperties;
|
||||
|
||||
private static BladeFileProperties getBladeFileProperties() {
|
||||
if (fileProperties == null) {
|
||||
fileProperties = SpringUtil.getBean(BladeFileProperties.class);
|
||||
}
|
||||
return fileProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public File rename(File f, String path) {
|
||||
File dest = new File(path);
|
||||
f.renameTo(dest);
|
||||
return dest;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] path(File f, String dir) {
|
||||
//避免网络延迟导致时间不同步
|
||||
long time = System.nanoTime();
|
||||
|
||||
StringBuilder uploadPath = new StringBuilder()
|
||||
.append(getFileDir(dir, getBladeFileProperties().getUploadRealPath()))
|
||||
.append(time)
|
||||
.append(getFileExt(f.getName()));
|
||||
|
||||
StringBuilder virtualPath = new StringBuilder()
|
||||
.append(getFileDir(dir, getBladeFileProperties().getUploadCtxPath()))
|
||||
.append(time)
|
||||
.append(getFileExt(f.getName()));
|
||||
|
||||
return new String[]{BladeFileUtil.formatUrl(uploadPath.toString()), BladeFileUtil.formatUrl(virtualPath.toString())};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件后缀
|
||||
*
|
||||
* @param fileName 文件名
|
||||
* @return 文件后缀
|
||||
*/
|
||||
public static String getFileExt(String fileName) {
|
||||
if (!fileName.contains(StringPool.DOT)) {
|
||||
return ".jpg";
|
||||
} else {
|
||||
return fileName.substring(fileName.lastIndexOf(StringPool.DOT));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件保存地址
|
||||
*
|
||||
* @param dir 目录
|
||||
* @param saveDir 保存目录
|
||||
* @return 地址
|
||||
*/
|
||||
public static String getFileDir(String dir, String saveDir) {
|
||||
StringBuilder newFileDir = new StringBuilder();
|
||||
newFileDir.append(saveDir)
|
||||
.append(File.separator).append(dir).append(File.separator).append(DateUtil.format(DateUtil.now(), "yyyyMMdd"))
|
||||
.append(File.separator);
|
||||
return newFileDir.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 图片压缩
|
||||
*
|
||||
* @param path 文件地址
|
||||
*/
|
||||
@Override
|
||||
public void compress(String path) {
|
||||
try {
|
||||
ImageUtil.zoomScale(ImageUtil.readImage(path), new FileOutputStream(new File(path)), null, getBladeFileProperties().getCompressScale(), getBladeFileProperties().getCompressFlag());
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.core.boot.handler;
|
||||
|
||||
|
||||
import jakarta.annotation.Nonnull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springblade.core.boot.error.ErrorType;
|
||||
import org.springblade.core.boot.error.ErrorUtil;
|
||||
import org.springblade.core.context.BladeContext;
|
||||
import org.springblade.core.launch.props.BladeProperties;
|
||||
import org.springblade.core.log.constant.EventConstant;
|
||||
import org.springblade.core.log.event.ErrorLogEvent;
|
||||
import org.springblade.core.log.model.LogError;
|
||||
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 异步任务异常处理器
|
||||
*
|
||||
* @author BladeX
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class BladeAsyncUncaughtExceptionHandler implements AsyncUncaughtExceptionHandler {
|
||||
private final BladeContext bladeContext;
|
||||
private final BladeProperties bladeProperties;
|
||||
private final ApplicationEventPublisher eventPublisher;
|
||||
|
||||
@Override
|
||||
public void handleUncaughtException(@Nonnull Throwable error, @Nonnull Method method, @Nonnull Object... params) {
|
||||
log.error("Unexpected exception occurred invoking async method: {}", method, error);
|
||||
LogError logError = new LogError();
|
||||
// 服务信息、环境、异常类型
|
||||
logError.setParams(ErrorType.ASYNC.getType());
|
||||
logError.setEnv(bladeProperties.getEnv());
|
||||
logError.setServiceId(bladeProperties.getName());
|
||||
logError.setRequestUri(bladeContext.getRequestId());
|
||||
// 堆栈信息
|
||||
ErrorUtil.initErrorInfo(error, logError);
|
||||
Map<String, Object> event = new HashMap<>(16);
|
||||
event.put(EventConstant.EVENT_LOG, logError);
|
||||
eventPublisher.publishEvent(new ErrorLogEvent(event));
|
||||
}
|
||||
}
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.core.boot.props;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* BladeFileProperties
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@ConfigurationProperties("blade.file")
|
||||
public class BladeFileProperties {
|
||||
|
||||
/**
|
||||
* 远程上传模式
|
||||
*/
|
||||
private boolean remoteMode = false;
|
||||
|
||||
/**
|
||||
* 外网地址
|
||||
*/
|
||||
private String uploadDomain = "http://127.0.0.1:8999";
|
||||
|
||||
/**
|
||||
* 上传下载路径(物理路径)
|
||||
*/
|
||||
private String remotePath = System.getProperty("user.dir") + "/target/blade";
|
||||
|
||||
/**
|
||||
* 上传路径(相对路径)
|
||||
*/
|
||||
private String uploadPath = "/upload";
|
||||
|
||||
/**
|
||||
* 下载路径
|
||||
*/
|
||||
private String downloadPath = "/download";
|
||||
|
||||
/**
|
||||
* 图片压缩
|
||||
*/
|
||||
private Boolean compress = false;
|
||||
|
||||
/**
|
||||
* 图片压缩比例
|
||||
*/
|
||||
private Double compressScale = 2.00;
|
||||
|
||||
/**
|
||||
* 图片缩放选择:true放大;false缩小
|
||||
*/
|
||||
private Boolean compressFlag = false;
|
||||
|
||||
/**
|
||||
* 项目物理路径
|
||||
*/
|
||||
private String realPath = System.getProperty("user.dir");
|
||||
|
||||
/**
|
||||
* 项目相对路径
|
||||
*/
|
||||
private String contextPath = "/";
|
||||
|
||||
|
||||
public String getUploadRealPath() {
|
||||
return (remoteMode ? remotePath : realPath) + uploadPath;
|
||||
}
|
||||
|
||||
public String getUploadCtxPath() {
|
||||
return contextPath + uploadPath;
|
||||
}
|
||||
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.core.boot.props;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springblade.core.tool.utils.PathUtil;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.cloud.context.config.annotation.RefreshScope;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
|
||||
/**
|
||||
* 文件上传配置
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@RefreshScope
|
||||
@ConfigurationProperties("blade.upload")
|
||||
public class BladeUploadProperties {
|
||||
|
||||
/**
|
||||
* 文件保存目录,默认:jar 包同级目录
|
||||
*/
|
||||
@Nullable
|
||||
private String savePath = PathUtil.getJarPath();
|
||||
}
|
||||
+125
@@ -0,0 +1,125 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.core.boot.request;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.springblade.core.tool.utils.WebUtil;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
|
||||
import jakarta.servlet.ReadListener;
|
||||
import jakarta.servlet.ServletInputStream;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletRequestWrapper;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
|
||||
/**
|
||||
* 全局Request包装
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
public class BladeHttpServletRequestWrapper extends HttpServletRequestWrapper {
|
||||
|
||||
/**
|
||||
* 没被包装过的HttpServletRequest(特殊场景,需要自己过滤)
|
||||
* 获取初始request
|
||||
*/
|
||||
@Getter
|
||||
private final HttpServletRequest orgRequest;
|
||||
|
||||
/**
|
||||
* 缓存报文,支持多次读取流
|
||||
*/
|
||||
private byte[] body;
|
||||
|
||||
|
||||
public BladeHttpServletRequestWrapper(HttpServletRequest request) {
|
||||
super(request);
|
||||
orgRequest = request;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BufferedReader getReader() throws IOException {
|
||||
return new BufferedReader(new InputStreamReader(getInputStream()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServletInputStream getInputStream() throws IOException {
|
||||
if (super.getHeader(HttpHeaders.CONTENT_TYPE) == null) {
|
||||
return super.getInputStream();
|
||||
}
|
||||
|
||||
if (super.getHeader(HttpHeaders.CONTENT_TYPE).startsWith(MediaType.MULTIPART_FORM_DATA_VALUE)) {
|
||||
return super.getInputStream();
|
||||
}
|
||||
|
||||
if (body == null) {
|
||||
body = WebUtil.getRequestBody(super.getInputStream()).getBytes();
|
||||
}
|
||||
|
||||
final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body);
|
||||
|
||||
return new ServletInputStream() {
|
||||
|
||||
@Override
|
||||
public int read() {
|
||||
return byteArrayInputStream.read();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFinished() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReady() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setReadListener(ReadListener readListener) {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取初始request
|
||||
*
|
||||
* @param request request
|
||||
* @return HttpServletRequest
|
||||
*/
|
||||
public static HttpServletRequest getOrgRequest(HttpServletRequest request) {
|
||||
if (request instanceof BladeHttpServletRequestWrapper) {
|
||||
return ((BladeHttpServletRequestWrapper) request).getOrgRequest();
|
||||
}
|
||||
return request;
|
||||
}
|
||||
|
||||
}
|
||||
+216
@@ -0,0 +1,216 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.core.boot.request;
|
||||
|
||||
import jakarta.servlet.*;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.springblade.core.tool.utils.WebUtil;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
import org.springframework.util.PatternMatchUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Request全局过滤
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
public class BladeRequestFilter implements Filter {
|
||||
|
||||
/**
|
||||
* 请求配置
|
||||
*/
|
||||
private final RequestProperties requestProperties;
|
||||
/**
|
||||
* 路径匹配
|
||||
*/
|
||||
private final AntPathMatcher antPathMatcher = new AntPathMatcher();
|
||||
|
||||
/**
|
||||
* 默认拦截路径
|
||||
*/
|
||||
private final List<String> defaultBlockUrl = List.of("/**/actuator/**", "/health/**");
|
||||
/**
|
||||
* 默认白名单
|
||||
*/
|
||||
private final List<String> defaultWhiteList = List.of("127.0.0.1", "172.30.*.*", "192.168.*.*", "10.*.*.*", "0:0:0:0:0:0:0:1");
|
||||
/**
|
||||
* 默认提示信息
|
||||
*/
|
||||
private static final String DEFAULT_MESSAGE = "当前请求被拒绝,请联系管理员!";
|
||||
/**
|
||||
* 方法不允许提示信息
|
||||
*/
|
||||
private static final String METHOD_NOT_ALLOWED_MESSAGE = "当前请求方法不被允许,请联系管理员!";
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig config) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
|
||||
// 获取请求
|
||||
HttpServletRequest httpRequest = (HttpServletRequest) request;
|
||||
// 判断 拦截请求 与 白名单
|
||||
if (requestProperties.getEnabled()) {
|
||||
// 获取请求路径
|
||||
String path = httpRequest.getServletPath();
|
||||
// 获取请求IP
|
||||
String ip = WebUtil.getIP(httpRequest);
|
||||
// 获取请求方法
|
||||
String method = httpRequest.getMethod();
|
||||
// 判断是否拦截请求
|
||||
if (isRequestBlock(path, ip)) {
|
||||
throw new ServletException(DEFAULT_MESSAGE);
|
||||
}
|
||||
// 判断请求方法是否允许
|
||||
if (!isMethodAllowed(path, method)) {
|
||||
throw new ServletException(METHOD_NOT_ALLOWED_MESSAGE);
|
||||
}
|
||||
// 判断是否跳过Request包装
|
||||
if (isRequestSkip(path)) {
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
// 采用Request包装
|
||||
else {
|
||||
BladeHttpServletRequestWrapper bladeRequest = new BladeHttpServletRequestWrapper(httpRequest);
|
||||
chain.doFilter(bladeRequest, response);
|
||||
}
|
||||
}
|
||||
// 采用原版Request请求
|
||||
else {
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否白名单
|
||||
*
|
||||
* @param ip ip地址
|
||||
* @return boolean
|
||||
*/
|
||||
private boolean isWhiteList(String ip) {
|
||||
List<String> whiteList = requestProperties.getWhiteList();
|
||||
String[] defaultWhiteIps = defaultWhiteList.toArray(new String[0]);
|
||||
String[] whiteIps = whiteList.toArray(new String[0]);
|
||||
return PatternMatchUtils.simpleMatch(defaultWhiteIps, ip) || PatternMatchUtils.simpleMatch(whiteIps, ip);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否黑名单
|
||||
*
|
||||
* @param ip ip地址
|
||||
* @return boolean
|
||||
*/
|
||||
private boolean isBlackList(String ip) {
|
||||
List<String> blackList = requestProperties.getBlackList();
|
||||
String[] blackIps = blackList.toArray(new String[0]);
|
||||
return PatternMatchUtils.simpleMatch(blackIps, ip);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否禁用请求访问
|
||||
*
|
||||
* @param path 请求路径
|
||||
* @return boolean
|
||||
*/
|
||||
private boolean isRequestBlock(String path) {
|
||||
List<String> blockUrl = requestProperties.getBlockUrl();
|
||||
return defaultBlockUrl.stream().anyMatch(pattern -> antPathMatcher.match(pattern, path)) ||
|
||||
blockUrl.stream().anyMatch(pattern -> antPathMatcher.match(pattern, path));
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否拦截请求
|
||||
*
|
||||
* @param path 请求路径
|
||||
* @param ip ip地址
|
||||
* @return boolean
|
||||
*/
|
||||
private boolean isRequestBlock(String path, String ip) {
|
||||
return (isRequestBlock(path) && !isWhiteList(ip)) || isBlackList(ip);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否跳过请求包装
|
||||
*
|
||||
* @param path 请求路径
|
||||
* @return boolean
|
||||
*/
|
||||
private boolean isRequestSkip(String path) {
|
||||
return requestProperties.getSkipUrl().stream().anyMatch(pattern -> antPathMatcher.match(pattern, path));
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断请求方法是否允许
|
||||
*
|
||||
* @param path 请求路径
|
||||
* @param method 请求方法
|
||||
* @return boolean
|
||||
*/
|
||||
private boolean isMethodAllowed(String path, String method) {
|
||||
// 优先匹配路径级别规则
|
||||
List<HttpMethod> allowMethods = findAllowMethodsByPath(path);
|
||||
// 如果没有匹配的路径规则,使用全局配置
|
||||
if (allowMethods == null) {
|
||||
allowMethods = requestProperties.getAllowMethods();
|
||||
}
|
||||
// 如果配置为空,允许所有方法
|
||||
if (allowMethods == null || allowMethods.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
// 检查请求方法是否在允许列表中
|
||||
return allowMethods.stream().anyMatch(httpMethod -> httpMethod.matches(method));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据路径查找匹配的方法规则
|
||||
*
|
||||
* @param path 请求路径
|
||||
* @return 允许的方法列表,未匹配返回null
|
||||
*/
|
||||
private List<HttpMethod> findAllowMethodsByPath(String path) {
|
||||
List<MethodRule> methodRules = requestProperties.getMethodRules();
|
||||
if (methodRules == null || methodRules.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return methodRules.stream()
|
||||
.filter(rule -> rule.getPattern() != null && antPathMatcher.match(rule.getPattern(), path))
|
||||
.findFirst()
|
||||
.map(MethodRule::getAllowMethods)
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.core.boot.request;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
/**
|
||||
* HTTP请求方法枚举
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public enum HttpMethod {
|
||||
|
||||
/**
|
||||
* GET请求
|
||||
*/
|
||||
GET("GET"),
|
||||
|
||||
/**
|
||||
* POST请求
|
||||
*/
|
||||
POST("POST"),
|
||||
|
||||
/**
|
||||
* PUT请求
|
||||
*/
|
||||
PUT("PUT"),
|
||||
|
||||
/**
|
||||
* DELETE请求
|
||||
*/
|
||||
DELETE("DELETE"),
|
||||
|
||||
/**
|
||||
* PATCH请求
|
||||
*/
|
||||
PATCH("PATCH"),
|
||||
|
||||
/**
|
||||
* HEAD请求
|
||||
*/
|
||||
HEAD("HEAD"),
|
||||
|
||||
/**
|
||||
* OPTIONS请求
|
||||
*/
|
||||
OPTIONS("OPTIONS"),
|
||||
|
||||
/**
|
||||
* TRACE请求
|
||||
*/
|
||||
TRACE("TRACE");
|
||||
|
||||
/**
|
||||
* 方法名称
|
||||
*/
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* 根据方法名称解析枚举
|
||||
*
|
||||
* @param method 方法名称
|
||||
* @return HttpMethod
|
||||
*/
|
||||
public static HttpMethod resolve(String method) {
|
||||
if (method == null) {
|
||||
return null;
|
||||
}
|
||||
for (HttpMethod httpMethod : values()) {
|
||||
if (httpMethod.name.equalsIgnoreCase(method)) {
|
||||
return httpMethod;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否匹配
|
||||
*
|
||||
* @param method 方法名称
|
||||
* @return boolean
|
||||
*/
|
||||
public boolean matches(String method) {
|
||||
return this.name.equalsIgnoreCase(method);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.core.boot.request;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 请求方法规则配置
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@Data
|
||||
public class MethodRule {
|
||||
|
||||
/**
|
||||
* 匹配路径模式,支持Ant风格,例如:/api/**, /admin/*
|
||||
*/
|
||||
private String pattern;
|
||||
|
||||
/**
|
||||
* 允许的请求方法列表
|
||||
*/
|
||||
private List<HttpMethod> allowMethods = new ArrayList<>();
|
||||
|
||||
}
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.core.boot.request;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Request配置类
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@Data
|
||||
@ConfigurationProperties("blade.request")
|
||||
public class RequestProperties {
|
||||
|
||||
/**
|
||||
* 开启自定义request
|
||||
*/
|
||||
private Boolean enabled = true;
|
||||
|
||||
/**
|
||||
* 放行url
|
||||
*/
|
||||
private List<String> skipUrl = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* 禁用url
|
||||
*/
|
||||
private List<String> blockUrl = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* 白名单,支持通配符,例如:10.20.0.8*、10.20.0.*
|
||||
*/
|
||||
private List<String> whiteList = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* 黑名单,支持通配符,例如:10.20.0.8*、10.20.0.*
|
||||
*/
|
||||
private List<String> blackList = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* 全局允许的请求方法列表,为空则允许所有方法
|
||||
*/
|
||||
private List<HttpMethod> allowMethods = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* 路径级别的请求方法规则,优先级高于全局配置
|
||||
*/
|
||||
private List<MethodRule> methodRules = new ArrayList<>();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
${AnsiColor.BLUE} ______ _ _ ___ ___
|
||||
${AnsiColor.BLUE} | ___ \| | | | \ \ / /
|
||||
${AnsiColor.BLUE} | |_/ /| | __ _ __| | ___ \ V /
|
||||
${AnsiColor.BLUE} | ___ \| | / _` | / _` | / _ \ > <
|
||||
${AnsiColor.BLUE} | |_/ /| || (_| || (_| || __/ / . \
|
||||
${AnsiColor.BLUE} \____/ |_| \__,_| \__,_| \___|/__/ \__\
|
||||
|
||||
${AnsiColor.BLUE}:: BladeX ${blade.service.version} :: ${spring.application.name}:${AnsiColor.RED}${blade.env}${AnsiColor.BLUE} :: Running SpringBoot ${spring-boot.version} :: ${AnsiColor.BRIGHT_BLACK}
|
||||
@@ -0,0 +1,63 @@
|
||||
#服务器配置
|
||||
server:
|
||||
undertow:
|
||||
# 线程配置
|
||||
threads:
|
||||
# 设置IO线程数, 它主要执行非阻塞的任务,它们会负责多个连接, 默认设置每个CPU核心一个线程
|
||||
io: 16
|
||||
# 阻塞任务线程池, 当执行类似servlet请求阻塞操作, undertow会从这个线程池中取得线程,它的值设置取决于系统的负载
|
||||
worker: 400
|
||||
# 以下的配置会影响buffer,这些buffer会用于服务器连接的IO操作,有点类似netty的池化内存管理
|
||||
buffer-size: 1024
|
||||
# 是否分配的直接内存
|
||||
direct-buffers: true
|
||||
servlet:
|
||||
# 编码配置
|
||||
encoding:
|
||||
charset: UTF-8
|
||||
force: true
|
||||
|
||||
#spring配置
|
||||
spring:
|
||||
task:
|
||||
execution:
|
||||
# 线程名前缀
|
||||
thread-name-prefix: BladeAsync-
|
||||
# 线程池配置
|
||||
pool:
|
||||
# 核心线程数
|
||||
core-size: 5
|
||||
# 最大线程数
|
||||
max-size: 10
|
||||
# 队列容量
|
||||
queue-capacity: 25
|
||||
# 允许核心线程超时
|
||||
allow-core-thread-timeout: true
|
||||
# 线程保持存活时间
|
||||
keep-alive: 60s
|
||||
servlet:
|
||||
multipart:
|
||||
enabled: true
|
||||
max-file-size: 1024MB
|
||||
max-request-size: 1024MB
|
||||
mvc:
|
||||
throw-exception-if-no-handler-found: true
|
||||
web:
|
||||
resources:
|
||||
add-mappings: false
|
||||
devtools:
|
||||
restart:
|
||||
log-condition-evaluation-delta: false
|
||||
|
||||
blade:
|
||||
request:
|
||||
enabled: true
|
||||
# 全局允许的请求方法
|
||||
allow-methods:
|
||||
- GET
|
||||
- POST
|
||||
- PUT
|
||||
- DELETE
|
||||
- PATCH
|
||||
- HEAD
|
||||
- OPTIONS
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 66 KiB |
Reference in New Issue
Block a user