mirror of
https://github.com/chillzhuang/blade-tool
synced 2025-01-13 08:25:47 +08:00
⚡ 根据P3C优化代码
This commit is contained in:
parent
083b42c2fb
commit
912e0dd227
@ -24,52 +24,56 @@ import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
||||
|
||||
/**
|
||||
* 配置类
|
||||
* @author smallchill
|
||||
*/
|
||||
@Slf4j
|
||||
@Configuration
|
||||
@EnableConfigurationProperties({
|
||||
BladeProperties.class
|
||||
BladeProperties.class
|
||||
})
|
||||
@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)
|
||||
@AllArgsConstructor
|
||||
public class BladeBootAutoConfiguration {
|
||||
|
||||
private BladeProperties bladeProperties;
|
||||
private BladeProperties bladeProperties;
|
||||
|
||||
/**
|
||||
* 全局变量定义
|
||||
*/
|
||||
@Bean
|
||||
public SystemConstant fileConst() {
|
||||
SystemConstant me = SystemConstant.me();
|
||||
/**
|
||||
* 全局变量定义
|
||||
*/
|
||||
@Bean
|
||||
public SystemConstant fileConst() {
|
||||
SystemConstant me = SystemConstant.me();
|
||||
|
||||
//设定开发模式
|
||||
me.setDevMode((bladeProperties.getEnv().equals("dev") ? true : false));
|
||||
//设定开发模式
|
||||
me.setDevMode((bladeProperties.getEnv().equals("dev") ? true : false));
|
||||
|
||||
//设定文件上传远程地址
|
||||
me.setDomain(bladeProperties.get("upload-domain", "http://localhost:8888"));
|
||||
//设定文件上传远程地址
|
||||
me.setDomain(bladeProperties.get("upload-domain", "http://localhost:8888"));
|
||||
|
||||
//设定文件上传是否为远程模式
|
||||
me.setRemoteMode(bladeProperties.getBoolean("remote-mode", true));
|
||||
//设定文件上传是否为远程模式
|
||||
me.setRemoteMode(bladeProperties.getBoolean("remote-mode", true));
|
||||
|
||||
//远程上传地址
|
||||
me.setRemotePath(bladeProperties.get("remote-path", System.getProperty("user.dir") + "/work/blade"));
|
||||
//远程上传地址
|
||||
me.setRemotePath(bladeProperties.get("remote-path", System.getProperty("user.dir") + "/work/blade"));
|
||||
|
||||
//设定文件上传头文件夹
|
||||
me.setUploadPath(bladeProperties.get("upload-path", "/upload"));
|
||||
//设定文件上传头文件夹
|
||||
me.setUploadPath(bladeProperties.get("upload-path", "/upload"));
|
||||
|
||||
//设定文件下载头文件夹
|
||||
me.setDownloadPath(bladeProperties.get("download-path", "/download"));
|
||||
//设定文件下载头文件夹
|
||||
me.setDownloadPath(bladeProperties.get("download-path", "/download"));
|
||||
|
||||
//设定上传图片是否压缩
|
||||
me.setCompress(bladeProperties.getBoolean("compress", false));
|
||||
//设定上传图片是否压缩
|
||||
me.setCompress(bladeProperties.getBoolean("compress", false));
|
||||
|
||||
//设定上传图片压缩比例
|
||||
me.setCompressScale(bladeProperties.getDouble("compress-scale", 2.00));
|
||||
//设定上传图片压缩比例
|
||||
me.setCompressScale(bladeProperties.getDouble("compress-scale", 2.00));
|
||||
|
||||
//设定上传图片缩放选择:true放大;false缩小
|
||||
me.setCompressFlag(bladeProperties.getBoolean("compress-flag", false));
|
||||
//设定上传图片缩放选择:true放大;false缩小
|
||||
me.setCompressFlag(bladeProperties.getBoolean("compress-flag", false));
|
||||
|
||||
return me;
|
||||
}
|
||||
return me;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -33,6 +33,7 @@ import java.util.List;
|
||||
|
||||
/**
|
||||
* WEB配置
|
||||
* @author smallchill
|
||||
*/
|
||||
@Slf4j
|
||||
@Configuration
|
||||
@ -40,10 +41,10 @@ import java.util.List;
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||
public class BladeWebMvcConfiguration implements WebMvcConfigurer {
|
||||
|
||||
@Override
|
||||
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
|
||||
argumentResolvers.add(new TokenArgumentResolver());
|
||||
}
|
||||
@Override
|
||||
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
|
||||
argumentResolvers.add(new TokenArgumentResolver());
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
|
@ -27,6 +27,8 @@ import org.springframework.context.annotation.Profile;
|
||||
|
||||
/**
|
||||
* mybatisplus 配置
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
@Configuration
|
||||
@MapperScan("org.springblade.**.mapper.**")
|
||||
@ -42,14 +44,14 @@ public class MybatisPlusConfiguration {
|
||||
return new BladeMetaObjectHandler();
|
||||
}
|
||||
|
||||
/**
|
||||
* SQL执行效率插件
|
||||
*/
|
||||
@Bean
|
||||
@Profile({AppConstant.DEV_CDOE, AppConstant.TEST_CODE})
|
||||
public PerformanceInterceptor performanceInterceptor() {
|
||||
return new PerformanceInterceptor();
|
||||
}
|
||||
/**
|
||||
* SQL执行效率插件
|
||||
*/
|
||||
@Bean
|
||||
@Profile({AppConstant.DEV_CDOE, AppConstant.TEST_CODE})
|
||||
public PerformanceInterceptor performanceInterceptor() {
|
||||
return new PerformanceInterceptor();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -35,6 +35,8 @@ import java.time.Duration;
|
||||
|
||||
/**
|
||||
* RedisTemplate 配置
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
@EnableCaching
|
||||
@Configuration
|
||||
@ -43,6 +45,7 @@ public class RedisTemplateConfiguration {
|
||||
|
||||
/**
|
||||
* value 值 序列化
|
||||
*
|
||||
* @return RedisSerializer
|
||||
*/
|
||||
@Bean
|
||||
|
@ -24,23 +24,25 @@ import org.springframework.retry.interceptor.RetryOperationsInterceptor;
|
||||
|
||||
/**
|
||||
* 重试机制
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
@Slf4j
|
||||
@Configuration
|
||||
public class RetryConfiguration {
|
||||
|
||||
@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();
|
||||
}
|
||||
@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();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -33,177 +33,179 @@ import java.util.List;
|
||||
|
||||
/**
|
||||
* Blade控制器封装类
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
public class BladeController {
|
||||
|
||||
/**
|
||||
* ============================ BINDER =================================================
|
||||
*/
|
||||
/**
|
||||
* ============================ BINDER =================================================
|
||||
*/
|
||||
|
||||
@InitBinder
|
||||
protected void initBinder(ServletRequestDataBinder binder) {
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
dateFormat.setLenient(false);
|
||||
binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
|
||||
}
|
||||
@InitBinder
|
||||
protected void initBinder(ServletRequestDataBinder binder) {
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
dateFormat.setLenient(false);
|
||||
binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
|
||||
}
|
||||
|
||||
/**
|
||||
* ============================ REQUEST =================================================
|
||||
*/
|
||||
/**
|
||||
* ============================ REQUEST =================================================
|
||||
*/
|
||||
|
||||
@Autowired
|
||||
private HttpServletRequest request;
|
||||
@Autowired
|
||||
private HttpServletRequest request;
|
||||
|
||||
/**
|
||||
* 获取request
|
||||
*/
|
||||
public HttpServletRequest getRequest() {
|
||||
return this.request;
|
||||
}
|
||||
/**
|
||||
* 获取request
|
||||
*/
|
||||
public HttpServletRequest getRequest() {
|
||||
return this.request;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public BladeUser getUser() {
|
||||
return SecureUtil.getUser();
|
||||
}
|
||||
/**
|
||||
* 获取当前用户
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public BladeUser getUser() {
|
||||
return SecureUtil.getUser();
|
||||
}
|
||||
|
||||
/** ============================ API_RESULT ================================================= */
|
||||
/** ============================ API_RESULT ================================================= */
|
||||
|
||||
/**
|
||||
* 返回ApiResult
|
||||
*
|
||||
* @param data
|
||||
* @return R
|
||||
*/
|
||||
public <T> R<T> data(T data) {
|
||||
return R.data(data);
|
||||
}
|
||||
/**
|
||||
* 返回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
|
||||
* @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 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 success(String message) {
|
||||
return R.success(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回ApiResult
|
||||
*
|
||||
* @param message
|
||||
* @return R
|
||||
*/
|
||||
public R failure(String message) {
|
||||
return R.failure(message);
|
||||
}
|
||||
/**
|
||||
* 返回ApiResult
|
||||
*
|
||||
* @param message
|
||||
* @return R
|
||||
*/
|
||||
public R failure(String message) {
|
||||
return R.failure(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回ApiResult
|
||||
*
|
||||
* @param flag
|
||||
* @return R
|
||||
*/
|
||||
public R status(boolean flag) {
|
||||
return R.status(flag);
|
||||
}
|
||||
/**
|
||||
* 返回ApiResult
|
||||
*
|
||||
* @param flag
|
||||
* @return R
|
||||
*/
|
||||
public R status(boolean flag) {
|
||||
return R.status(flag);
|
||||
}
|
||||
|
||||
|
||||
/**============================ FILE ================================================= */
|
||||
/**============================ FILE ================================================= */
|
||||
|
||||
/**
|
||||
* 获取BladeFile封装类
|
||||
*
|
||||
* @param file
|
||||
* @return
|
||||
*/
|
||||
public BladeFile getFile(MultipartFile file) {
|
||||
return BladeFileUtil.getFile(file);
|
||||
}
|
||||
/**
|
||||
* 获取BladeFile封装类
|
||||
*
|
||||
* @param file
|
||||
* @return
|
||||
*/
|
||||
public BladeFile getFile(MultipartFile file) {
|
||||
return BladeFileUtil.getFile(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取BladeFile封装类
|
||||
*
|
||||
* @param file
|
||||
* @param dir
|
||||
* @return
|
||||
*/
|
||||
public BladeFile getFile(MultipartFile file, String dir) {
|
||||
return BladeFileUtil.getFile(file, dir);
|
||||
}
|
||||
/**
|
||||
* 获取BladeFile封装类
|
||||
*
|
||||
* @param file
|
||||
* @param dir
|
||||
* @return
|
||||
*/
|
||||
public BladeFile getFile(MultipartFile file, String dir) {
|
||||
return BladeFileUtil.getFile(file, dir);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取BladeFile封装类
|
||||
*
|
||||
* @param file
|
||||
* @param dir
|
||||
* @param path
|
||||
* @param virtualPath
|
||||
* @return
|
||||
*/
|
||||
public BladeFile getFile(MultipartFile file, String dir, String path, String virtualPath) {
|
||||
return BladeFileUtil.getFile(file, dir, path, virtualPath);
|
||||
}
|
||||
/**
|
||||
* 获取BladeFile封装类
|
||||
*
|
||||
* @param file
|
||||
* @param dir
|
||||
* @param path
|
||||
* @param virtualPath
|
||||
* @return
|
||||
*/
|
||||
public BladeFile getFile(MultipartFile file, String dir, String path, String virtualPath) {
|
||||
return BladeFileUtil.getFile(file, dir, path, virtualPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取BladeFile封装类
|
||||
*
|
||||
* @param files
|
||||
* @return
|
||||
*/
|
||||
public List<BladeFile> getFiles(List<MultipartFile> files) {
|
||||
return BladeFileUtil.getFiles(files);
|
||||
}
|
||||
/**
|
||||
* 获取BladeFile封装类
|
||||
*
|
||||
* @param files
|
||||
* @return
|
||||
*/
|
||||
public List<BladeFile> getFiles(List<MultipartFile> files) {
|
||||
return BladeFileUtil.getFiles(files);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取BladeFile封装类
|
||||
*
|
||||
* @param files
|
||||
* @param dir
|
||||
* @return
|
||||
*/
|
||||
public List<BladeFile> getFiles(List<MultipartFile> files, String dir) {
|
||||
return BladeFileUtil.getFiles(files, dir);
|
||||
}
|
||||
/**
|
||||
* 获取BladeFile封装类
|
||||
*
|
||||
* @param files
|
||||
* @param dir
|
||||
* @return
|
||||
*/
|
||||
public List<BladeFile> getFiles(List<MultipartFile> files, String dir) {
|
||||
return BladeFileUtil.getFiles(files, dir);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取BladeFile封装类
|
||||
*
|
||||
* @param files
|
||||
* @param path
|
||||
* @param virtualPath
|
||||
* @return
|
||||
*/
|
||||
public List<BladeFile> getFiles(List<MultipartFile> files, String dir, String path, String virtualPath) {
|
||||
return BladeFileUtil.getFiles(files, dir, path, virtualPath);
|
||||
}
|
||||
/**
|
||||
* 获取BladeFile封装类
|
||||
*
|
||||
* @param files
|
||||
* @param path
|
||||
* @param virtualPath
|
||||
* @return
|
||||
*/
|
||||
public List<BladeFile> getFiles(List<MultipartFile> files, String dir, String path, String virtualPath) {
|
||||
return BladeFileUtil.getFiles(files, dir, path, virtualPath);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -26,6 +26,8 @@ import java.util.Enumeration;
|
||||
|
||||
/**
|
||||
* feign 传递Request header
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
@Slf4j
|
||||
public class BladeFeignRequestHeaderInterceptor implements RequestInterceptor {
|
||||
@ -40,16 +42,10 @@ public class BladeFeignRequestHeaderInterceptor implements RequestInterceptor {
|
||||
while (headerNames.hasMoreElements()) {
|
||||
String name = headerNames.nextElement();
|
||||
String value = request.getHeader(name);
|
||||
/**
|
||||
* 遍历请求头里面的属性字段,将Authorization添加到新的请求头中转发到下游服务
|
||||
* */
|
||||
if ("Authorization".equals(name)) {
|
||||
log.debug("添加自定义请求头key:" + name + ",value:" + value);
|
||||
requestTemplate.header(name, value);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.warn("FeignHeadConfiguration", "获取请求头失败!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -38,6 +38,8 @@ import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* 自定义Feign的隔离策略
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
public class FeignHystrixConcurrencyStrategy extends HystrixConcurrencyStrategy {
|
||||
|
||||
|
@ -23,44 +23,48 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 上传文件封装
|
||||
* @author smallchill
|
||||
*/
|
||||
public class BladeFile {
|
||||
/**
|
||||
* 上传文件在附件表中的id
|
||||
*/
|
||||
private Object fileId;
|
||||
|
||||
|
||||
/**
|
||||
* 上传文件
|
||||
*/
|
||||
private MultipartFile file;
|
||||
|
||||
|
||||
/**
|
||||
* 上传分类文件夹
|
||||
*/
|
||||
private String dir;
|
||||
|
||||
|
||||
/**
|
||||
* 上传物理路径
|
||||
*/
|
||||
private String uploadPath;
|
||||
|
||||
|
||||
/**
|
||||
* 上传虚拟路径
|
||||
*/
|
||||
private String uploadVirtualPath;
|
||||
|
||||
|
||||
/**
|
||||
* 文件名
|
||||
*/
|
||||
private String fileName;
|
||||
|
||||
|
||||
/**
|
||||
* 真实文件名
|
||||
*/
|
||||
private String originalFileName;
|
||||
|
||||
public BladeFile() {
|
||||
|
||||
|
||||
}
|
||||
|
||||
public BladeFile(MultipartFile file, String dir) {
|
||||
@ -74,55 +78,57 @@ public class BladeFile {
|
||||
|
||||
public BladeFile(MultipartFile file, String dir, String uploadPath, String uploadVirtualPath) {
|
||||
this(file, dir);
|
||||
if (null != uploadPath){
|
||||
if (null != uploadPath) {
|
||||
this.uploadPath = BladeFileUtil.formatUrl(uploadPath);
|
||||
this.uploadVirtualPath = BladeFileUtil.formatUrl(uploadVirtualPath);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* 图片上传
|
||||
*/
|
||||
*/
|
||||
public void transfer() {
|
||||
transfer(SystemConstant.me().isCompress());
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* 图片上传
|
||||
*
|
||||
* @param compress 是否压缩
|
||||
*/
|
||||
*/
|
||||
public void transfer(boolean compress) {
|
||||
IFileProxy fileFactory = FileProxyManager.me().getDefaultFileProxyFactory();
|
||||
this.transfer(fileFactory, compress);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
/**
|
||||
* 图片上传
|
||||
*
|
||||
* @param fileFactory 文件上传工厂类
|
||||
* @param compress 是否压缩
|
||||
*/
|
||||
* @param compress 是否压缩
|
||||
*/
|
||||
public void transfer(IFileProxy fileFactory, boolean compress) {
|
||||
try {
|
||||
File file = new File(uploadPath);
|
||||
|
||||
if(null != fileFactory){
|
||||
String [] path = fileFactory.path(file, dir);
|
||||
|
||||
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);
|
||||
fileFactory.compress(this.uploadPath);
|
||||
}
|
||||
|
||||
|
||||
} catch (IllegalStateException | IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
@ -18,12 +18,18 @@ package org.springblade.core.boot.file;
|
||||
import org.springblade.core.tool.constant.SystemConstant;
|
||||
import org.springblade.core.tool.date.DateUtil;
|
||||
import org.springblade.core.tool.utils.ImageUtil;
|
||||
import org.springblade.core.tool.utils.StringPool;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 文件代理类
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
public class BladeFileProxyFactory implements IFileProxy {
|
||||
|
||||
@Override
|
||||
@ -34,55 +40,59 @@ public class BladeFileProxyFactory implements IFileProxy {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String [] path(File f, String dir) {
|
||||
public String[] path(File f, String dir) {
|
||||
//避免网络延迟导致时间不同步
|
||||
long time = System.nanoTime();
|
||||
|
||||
|
||||
StringBuilder uploadPath = new StringBuilder()
|
||||
.append(getFileDir(dir, SystemConstant.me().getUploadRealPath()))
|
||||
.append(time)
|
||||
.append(getFileExt(f.getName()));
|
||||
|
||||
.append(getFileDir(dir, SystemConstant.me().getUploadRealPath()))
|
||||
.append(time)
|
||||
.append(getFileExt(f.getName()));
|
||||
|
||||
StringBuilder virtualPath = new StringBuilder()
|
||||
.append(getFileDir(dir, SystemConstant.me().getUploadCtxPath()))
|
||||
.append(time)
|
||||
.append(getFileExt(f.getName()));
|
||||
|
||||
return new String [] {BladeFileUtil.formatUrl(uploadPath.toString()), BladeFileUtil.formatUrl(virtualPath.toString())};
|
||||
.append(getFileDir(dir, SystemConstant.me().getUploadCtxPath()))
|
||||
.append(time)
|
||||
.append(getFileExt(f.getName()));
|
||||
|
||||
return new String[]{BladeFileUtil.formatUrl(uploadPath.toString()), BladeFileUtil.formatUrl(virtualPath.toString())};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取文件后缀
|
||||
*/
|
||||
public static String getFileExt(String fileName) {
|
||||
if (fileName.indexOf(".") == -1)
|
||||
if (!fileName.contains(StringPool.DOT)) {
|
||||
return ".jpg";
|
||||
else
|
||||
return fileName.substring(fileName.lastIndexOf('.'), fileName.length());
|
||||
} else {
|
||||
return fileName.substring(fileName.lastIndexOf(StringPool.DOT));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件保存地址
|
||||
*
|
||||
* @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(new Date(), "yyyyMMdd"))
|
||||
.append(File.separator);
|
||||
.append(File.separator).append(dir).append(File.separator).append(DateUtil.format(new Date(), "yyyyMMdd"))
|
||||
.append(File.separator);
|
||||
return newFileDir.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 图片压缩
|
||||
*
|
||||
* @param path 文件地址
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public void compress(String path) {
|
||||
try {
|
||||
ImageUtil.zoomScale(ImageUtil.readImage(path), new FileOutputStream(new File(path)), null, SystemConstant.me().getCompressScale(), SystemConstant.me().isCompressFlag());
|
||||
ImageUtil.zoomScale(ImageUtil.readImage(path), new FileOutputStream(new File(path)), null, SystemConstant.me().getCompressScale(), SystemConstant.me().isCompressFlag());
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
@ -20,12 +20,22 @@ import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 文件工具类
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
public class BladeFileUtil {
|
||||
|
||||
// 定义允许上传的文件扩展名
|
||||
/**
|
||||
* 定义允许上传的文件扩展名
|
||||
*/
|
||||
private static HashMap<String, String> extMap = new HashMap<String, String>();
|
||||
// 图片扩展名
|
||||
private static String[] fileTypes = new String[] { "gif", "jpg", "jpeg", "png", "bmp" };
|
||||
|
||||
/**
|
||||
* 图片扩展名
|
||||
*/
|
||||
private static String[] fileTypes = new String[]{"gif", "jpg", "jpeg", "png", "bmp"};
|
||||
|
||||
static {
|
||||
extMap.put("image", ".gif,.jpg,.jpeg,.png,.bmp,.JPG,.JPEG,.PNG");
|
||||
@ -34,21 +44,21 @@ public class BladeFileUtil {
|
||||
extMap.put("file", ".doc,.docx,.xls,.xlsx,.ppt,.htm,.html,.txt,.zip,.rar,.gz,.bz2");
|
||||
extMap.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 @param fileName
|
||||
*
|
||||
* @param @param fileName
|
||||
* @param @return 设定文件
|
||||
* @return String 返回类型
|
||||
*/
|
||||
public static String getFileExt(String fileName) {
|
||||
return fileName.substring(fileName.lastIndexOf('.'), fileName.length());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 测试文件后缀 只让指定后缀的文件上传,像jsp,war,sh等危险的后缀禁止
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static boolean testExt(String dir, String fileName) {
|
||||
@ -67,7 +77,12 @@ public class BladeFileUtil {
|
||||
public enum FileSort {
|
||||
size, type, name;
|
||||
|
||||
// 文本排序转换成枚举
|
||||
/**
|
||||
* 文本排序转换成枚举
|
||||
*
|
||||
* @param sort
|
||||
* @return
|
||||
*/
|
||||
public static FileSort of(String sort) {
|
||||
try {
|
||||
return FileSort.valueOf(sort);
|
||||
@ -78,6 +93,7 @@ public class BladeFileUtil {
|
||||
}
|
||||
|
||||
public static class NameComparator implements Comparator {
|
||||
@Override
|
||||
public int compare(Object a, Object b) {
|
||||
Hashtable hashA = (Hashtable) a;
|
||||
Hashtable hashB = (Hashtable) b;
|
||||
@ -92,6 +108,7 @@ public class BladeFileUtil {
|
||||
}
|
||||
|
||||
public static class SizeComparator implements Comparator {
|
||||
@Override
|
||||
public int compare(Object a, Object b) {
|
||||
Hashtable hashA = (Hashtable) a;
|
||||
Hashtable hashB = (Hashtable) b;
|
||||
@ -112,6 +129,7 @@ public class BladeFileUtil {
|
||||
}
|
||||
|
||||
public static class TypeComparator implements Comparator {
|
||||
@Override
|
||||
public int compare(Object a, Object b) {
|
||||
Hashtable hashA = (Hashtable) a;
|
||||
Hashtable hashB = (Hashtable) b;
|
||||
@ -128,70 +146,76 @@ public class BladeFileUtil {
|
||||
public static String formatUrl(String url) {
|
||||
return url.replaceAll("\\\\", "/");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/********************************BladeFile封装********************************************************/
|
||||
|
||||
|
||||
/**
|
||||
* 获取BladeFile封装类
|
||||
*
|
||||
* @param file
|
||||
* @return
|
||||
*/
|
||||
public static BladeFile getFile(MultipartFile file){
|
||||
public static BladeFile getFile(MultipartFile file) {
|
||||
return getFile(file, "image", null, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取BladeFile封装类
|
||||
*
|
||||
* @param file
|
||||
* @param dir
|
||||
* @return
|
||||
*/
|
||||
public static BladeFile getFile(MultipartFile file, String dir){
|
||||
public static BladeFile getFile(MultipartFile file, String dir) {
|
||||
return getFile(file, dir, null, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取BladeFile封装类
|
||||
*
|
||||
* @param file
|
||||
* @param dir
|
||||
* @param path
|
||||
* @param virtualPath
|
||||
* @return
|
||||
*/
|
||||
public static BladeFile getFile(MultipartFile file, String dir, String path, String virtualPath){
|
||||
public static BladeFile getFile(MultipartFile file, String dir, String path, String virtualPath) {
|
||||
return new BladeFile(file, dir, path, virtualPath);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取BladeFile封装类
|
||||
*
|
||||
* @param files
|
||||
* @return
|
||||
*/
|
||||
public static List<BladeFile> getFiles(List<MultipartFile> files){
|
||||
public static List<BladeFile> getFiles(List<MultipartFile> files) {
|
||||
return getFiles(files, "image", null, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取BladeFile封装类
|
||||
*
|
||||
* @param files
|
||||
* @param dir
|
||||
* @return
|
||||
*/
|
||||
public static List<BladeFile> getFiles(List<MultipartFile> files, String dir){
|
||||
public static List<BladeFile> getFiles(List<MultipartFile> files, String dir) {
|
||||
return getFiles(files, dir, null, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取BladeFile封装类
|
||||
*
|
||||
* @param files
|
||||
* @param path
|
||||
* @param virtualPath
|
||||
* @return
|
||||
*/
|
||||
public static List<BladeFile> getFiles(List<MultipartFile> files, String dir, String path, String virtualPath){
|
||||
public static List<BladeFile> getFiles(List<MultipartFile> files, String dir, String path, String virtualPath) {
|
||||
List<BladeFile> list = new ArrayList<>();
|
||||
for (MultipartFile file : files){
|
||||
for (MultipartFile file : files) {
|
||||
list.add(new BladeFile(file, dir, path, virtualPath));
|
||||
}
|
||||
return list;
|
||||
|
@ -1,209 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springblade.core.boot.file;
|
||||
|
||||
|
||||
import org.springblade.core.tool.utils.StringUtil;
|
||||
import org.springblade.core.tool.utils.StringPool;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.*;
|
||||
|
||||
public class FileMaker {
|
||||
private static final String DEFAULT_CONTENT_TYPE = "application/octet-stream";
|
||||
|
||||
private File file;
|
||||
|
||||
private String fileName;
|
||||
|
||||
private HttpServletRequest request;
|
||||
|
||||
private HttpServletResponse response;
|
||||
|
||||
public static FileMaker init(HttpServletRequest request, HttpServletResponse response, File file) {
|
||||
return new FileMaker(request, response, file);
|
||||
}
|
||||
|
||||
public static FileMaker init(HttpServletRequest request, HttpServletResponse response, File file, String fileName) {
|
||||
return new FileMaker(request, response, file, fileName);
|
||||
}
|
||||
|
||||
private FileMaker(HttpServletRequest request, HttpServletResponse response, File file) {
|
||||
if (file == null) {
|
||||
throw new IllegalArgumentException("file can not be null.");
|
||||
}
|
||||
this.file = file;
|
||||
this.request = request;
|
||||
this.response = response;
|
||||
this.fileName = file.getName();
|
||||
}
|
||||
|
||||
private FileMaker(HttpServletRequest request, HttpServletResponse response, File file, String fileName) {
|
||||
if (file == null) {
|
||||
throw new IllegalArgumentException("file can not be null.");
|
||||
}
|
||||
this.file = file;
|
||||
this.request = request;
|
||||
this.response = response;
|
||||
this.fileName = fileName;
|
||||
}
|
||||
|
||||
public void start() {
|
||||
if (file == null || !file.isFile()) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
// ---------
|
||||
response.setHeader("Accept-Ranges", "bytes");
|
||||
response.setHeader("Content-disposition", "attachment; filename=" + encodeFileName(fileName));
|
||||
response.setContentType(DEFAULT_CONTENT_TYPE);
|
||||
|
||||
// ---------
|
||||
if (StringUtil.isBlank(request.getHeader("Range")))
|
||||
normalStart();
|
||||
else
|
||||
rangeStart();
|
||||
}
|
||||
|
||||
private String encodeFileName(String fileName) {
|
||||
try {
|
||||
return new String(fileName.getBytes(StringPool.GBK), StringPool.ISO_8859_1);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
return fileName;
|
||||
}
|
||||
}
|
||||
|
||||
private void normalStart() {
|
||||
response.setHeader("Content-Length", String.valueOf(file.length()));
|
||||
InputStream inputStream = null;
|
||||
OutputStream outputStream = null;
|
||||
try {
|
||||
inputStream = new BufferedInputStream(new FileInputStream(file));
|
||||
outputStream = response.getOutputStream();
|
||||
byte[] buffer = new byte[1024];
|
||||
for (int len = -1; (len = inputStream.read(buffer)) != -1;) {
|
||||
outputStream.write(buffer, 0, len);
|
||||
}
|
||||
outputStream.flush();
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
finally {
|
||||
if (inputStream != null)
|
||||
try {inputStream.close();} catch (IOException e) {}
|
||||
if (outputStream != null)
|
||||
try {outputStream.close();} catch (IOException e) {}
|
||||
}
|
||||
}
|
||||
|
||||
private void rangeStart() {
|
||||
Long[] range = {null, null};
|
||||
processRange(range);
|
||||
|
||||
String contentLength = String.valueOf(range[1].longValue() - range[0].longValue() + 1);
|
||||
response.setHeader("Content-Length", contentLength);
|
||||
response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); // status = 206
|
||||
|
||||
// Content-Range: bytes 0-499/10000
|
||||
StringBuilder contentRange = new StringBuilder("bytes ").append(String.valueOf(range[0])).append("-").append(String.valueOf(range[1])).append("/").append(String.valueOf(file.length()));
|
||||
response.setHeader("Content-Range", contentRange.toString());
|
||||
|
||||
InputStream inputStream = null;
|
||||
OutputStream outputStream = null;
|
||||
try {
|
||||
long start = range[0];
|
||||
long end = range[1];
|
||||
inputStream = new BufferedInputStream(new FileInputStream(file));
|
||||
if (inputStream.skip(start) != start)
|
||||
throw new RuntimeException("File skip error");
|
||||
outputStream = response.getOutputStream();
|
||||
byte[] buffer = new byte[1024];
|
||||
long position = start;
|
||||
for (int len; position <= end && (len = inputStream.read(buffer)) != -1;) {
|
||||
if (position + len <= end) {
|
||||
outputStream.write(buffer, 0, len);
|
||||
position += len;
|
||||
}
|
||||
else {
|
||||
for (int i=0; i<len && position <= end; i++) {
|
||||
outputStream.write(buffer[i]);
|
||||
position++;
|
||||
}
|
||||
}
|
||||
}
|
||||
outputStream.flush();
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
finally {
|
||||
if (inputStream != null)
|
||||
try {inputStream.close();} catch (IOException e) {}
|
||||
if (outputStream != null)
|
||||
try {outputStream.close();} catch (IOException e) {}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Examples of byte-ranges-specifier values (assuming an entity-body of length 10000):
|
||||
* The first 500 bytes (byte offsets 0-499, inclusive): bytes=0-499
|
||||
* The second 500 bytes (byte offsets 500-999, inclusive): bytes=500-999
|
||||
* The final 500 bytes (byte offsets 9500-9999, inclusive): bytes=-500
|
||||
* Or bytes=9500-
|
||||
*/
|
||||
private void processRange(Long[] range) {
|
||||
String rangeStr = request.getHeader("Range");
|
||||
int index = rangeStr.indexOf(',');
|
||||
if (index != -1)
|
||||
rangeStr = rangeStr.substring(0, index);
|
||||
rangeStr = rangeStr.replace("bytes=", "");
|
||||
|
||||
String[] arr = rangeStr.split("-", 2);
|
||||
if (arr.length < 2)
|
||||
throw new RuntimeException("Range error");
|
||||
|
||||
long fileLength = file.length();
|
||||
for (int i=0; i<range.length; i++) {
|
||||
if (StringUtil.isNotBlank(arr[i])) {
|
||||
range[i] = Long.parseLong(arr[i].trim());
|
||||
if (range[i] >= fileLength)
|
||||
range[i] = fileLength - 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Range format like: 9500-
|
||||
if (range[0] != null && range[1] == null) {
|
||||
range[1] = fileLength - 1;
|
||||
}
|
||||
// Range format like: -500
|
||||
else if (range[0] == null && range[1] != null) {
|
||||
range[0] = fileLength - range[1];
|
||||
range[1] = fileLength - 1;
|
||||
}
|
||||
|
||||
// check final range
|
||||
if (range[0] == null || range[1] == null || range[0].longValue() > range[1].longValue())
|
||||
throw new RuntimeException("Range error");
|
||||
}
|
||||
}
|
@ -17,29 +17,34 @@ package org.springblade.core.boot.file;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* 文件管理类
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
public class FileProxyManager {
|
||||
private IFileProxy defaultFileProxyFactory = new BladeFileProxyFactory();
|
||||
private IFileProxy defaultFileProxyFactory = new BladeFileProxyFactory();
|
||||
|
||||
private static FileProxyManager me = new FileProxyManager();
|
||||
private static FileProxyManager me = new FileProxyManager();
|
||||
|
||||
public static FileProxyManager me() {
|
||||
return me;
|
||||
}
|
||||
public static FileProxyManager me() {
|
||||
return me;
|
||||
}
|
||||
|
||||
public IFileProxy getDefaultFileProxyFactory() {
|
||||
return defaultFileProxyFactory;
|
||||
}
|
||||
public IFileProxy getDefaultFileProxyFactory() {
|
||||
return defaultFileProxyFactory;
|
||||
}
|
||||
|
||||
public void setDefaultFileProxyFactory(IFileProxy defaultFileProxyFactory) {
|
||||
this.defaultFileProxyFactory = defaultFileProxyFactory;
|
||||
}
|
||||
public void setDefaultFileProxyFactory(IFileProxy defaultFileProxyFactory) {
|
||||
this.defaultFileProxyFactory = defaultFileProxyFactory;
|
||||
}
|
||||
|
||||
public String[] path(File file, String dir) {
|
||||
return defaultFileProxyFactory.path(file, dir);
|
||||
}
|
||||
public String[] path(File file, String dir) {
|
||||
return defaultFileProxyFactory.path(file, dir);
|
||||
}
|
||||
|
||||
public File rename(File file, String path) {
|
||||
return defaultFileProxyFactory.rename(file, path);
|
||||
}
|
||||
public File rename(File file, String path) {
|
||||
return defaultFileProxyFactory.rename(file, path);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -17,27 +17,36 @@ package org.springblade.core.boot.file;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* 文件代理接口
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
public interface IFileProxy {
|
||||
|
||||
|
||||
/**
|
||||
* 返回路径[物理路径][虚拟路径]
|
||||
*
|
||||
* @param file
|
||||
* @param dir
|
||||
* @return
|
||||
*/
|
||||
String [] path(File file, String dir);
|
||||
String[] path(File file, String dir);
|
||||
|
||||
/**
|
||||
* 文件重命名策略
|
||||
*
|
||||
* @param file
|
||||
* @param path
|
||||
* @return
|
||||
*/
|
||||
File rename(File file, String path);
|
||||
|
||||
/**
|
||||
|
||||
/**
|
||||
* 图片压缩
|
||||
*/
|
||||
*
|
||||
* @param path
|
||||
*/
|
||||
void compress(String path);
|
||||
|
||||
|
||||
}
|
||||
|
@ -40,9 +40,10 @@ public class RequestLogAspect {
|
||||
|
||||
/**
|
||||
* AOP 环切 控制器 R 返回值
|
||||
*
|
||||
* @param point JoinPoint
|
||||
* @throws Throwable 异常
|
||||
* @return Object
|
||||
* @throws Throwable 异常
|
||||
*/
|
||||
@Around(
|
||||
"execution(!static org.springblade.core.tool.api.R<*> *(..)) && " +
|
||||
@ -106,7 +107,7 @@ public class RequestLogAspect {
|
||||
needRemoveKeys.forEach(paraMap::remove);
|
||||
// 打印请求
|
||||
if (paraMap.isEmpty()) {
|
||||
log.info("===> {}: {}", requestMethod, requestURI);
|
||||
log.info("===> {}: {}", requestMethod, requestURI);
|
||||
} else {
|
||||
log.info("===> {}: {} Parameters: {}", requestMethod, requestURI, JsonUtil.toJson(paraMap));
|
||||
}
|
||||
@ -125,7 +126,7 @@ public class RequestLogAspect {
|
||||
return result;
|
||||
} finally {
|
||||
long tookMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNs);
|
||||
log.info("<=== {}: {} ({} ms)", request.getMethod(), requestURI, tookMs);
|
||||
log.info("<=== {}: {} ({} ms)", request.getMethod(), requestURI, tookMs);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,7 @@ import java.util.Objects;
|
||||
* 将redis key序列化为字符串
|
||||
*
|
||||
* <p>
|
||||
* spring cache中的简单基本类型直接使用 StringRedisSerializer 会有问题
|
||||
* spring cache中的简单基本类型直接使用 StringRedisSerializer 会有问题
|
||||
* </p>
|
||||
*
|
||||
* @author L.cm
|
||||
|
@ -26,35 +26,37 @@ import org.springframework.web.method.support.ModelAndViewContainer;
|
||||
|
||||
/**
|
||||
* Token转化BladeUser
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
@Slf4j
|
||||
public class TokenArgumentResolver implements HandlerMethodArgumentResolver {
|
||||
|
||||
/**
|
||||
* 1. 入参筛选
|
||||
*
|
||||
* @param methodParameter 参数集合
|
||||
* @return 格式化后的参数
|
||||
*/
|
||||
@Override
|
||||
public boolean supportsParameter(MethodParameter methodParameter) {
|
||||
return methodParameter.getParameterType().equals(BladeUser.class);
|
||||
}
|
||||
/**
|
||||
* 1. 入参筛选
|
||||
*
|
||||
* @param methodParameter 参数集合
|
||||
* @return 格式化后的参数
|
||||
*/
|
||||
@Override
|
||||
public boolean supportsParameter(MethodParameter methodParameter) {
|
||||
return methodParameter.getParameterType().equals(BladeUser.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param methodParameter 入参集合
|
||||
* @param modelAndViewContainer model 和 view
|
||||
* @param nativeWebRequest web相关
|
||||
* @param webDataBinderFactory 入参解析
|
||||
* @return 包装对象
|
||||
* @throws Exception exception
|
||||
*/
|
||||
@Override
|
||||
public Object resolveArgument(MethodParameter methodParameter,
|
||||
ModelAndViewContainer modelAndViewContainer,
|
||||
NativeWebRequest nativeWebRequest,
|
||||
WebDataBinderFactory webDataBinderFactory) {
|
||||
return SecureUtil.getUser();
|
||||
}
|
||||
/**
|
||||
* @param methodParameter 入参集合
|
||||
* @param modelAndViewContainer model 和 view
|
||||
* @param nativeWebRequest web相关
|
||||
* @param webDataBinderFactory 入参解析
|
||||
* @return 包装对象
|
||||
* @throws Exception exception
|
||||
*/
|
||||
@Override
|
||||
public Object resolveArgument(MethodParameter methodParameter,
|
||||
ModelAndViewContainer modelAndViewContainer,
|
||||
NativeWebRequest nativeWebRequest,
|
||||
WebDataBinderFactory webDataBinderFactory) {
|
||||
return SecureUtil.getUser();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -28,6 +28,8 @@ import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* 项目启动器,搞定环境变量问题
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
public class BladeApplication {
|
||||
|
||||
@ -92,7 +94,7 @@ public class BladeApplication {
|
||||
props.setProperty("blade.service.version", AppConstant.APPLICATION_VERSION);
|
||||
// 加载自定义组件
|
||||
ServiceLoader<LauncherService> loader = ServiceLoader.load(LauncherService.class);
|
||||
loader.forEach(launcherService -> launcherService.launcher(builder, appName, profile));
|
||||
loader.forEach(launcherService -> launcherService.launcher(builder, appName, profile));
|
||||
return builder;
|
||||
}
|
||||
|
||||
|
@ -20,13 +20,15 @@ import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 系统启动完毕后执行
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
@Component
|
||||
public class BladeLineRunner implements CommandLineRunner {
|
||||
|
||||
@Override
|
||||
public void run(String... args) {
|
||||
@Override
|
||||
public void run(String... args) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,3 +1,18 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springblade.core.launch;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -11,6 +26,8 @@ import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* 项目启动事件通知
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
@Slf4j
|
||||
@Configuration
|
||||
|
@ -31,6 +31,8 @@ import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* Consul自定义注册规则
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnConsulEnabled
|
||||
|
@ -26,12 +26,16 @@ import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
|
||||
|
||||
/**
|
||||
* 配置类
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
@Configuration
|
||||
@AllArgsConstructor
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||
@EnableConfigurationProperties({
|
||||
BladeProperties.class
|
||||
BladeProperties.class
|
||||
})
|
||||
public class BladeLaunchConfiguration {
|
||||
|
||||
|
@ -17,130 +17,132 @@ package org.springblade.core.launch.constant;
|
||||
|
||||
/**
|
||||
* 系统常量
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
public interface AppConstant {
|
||||
|
||||
/**
|
||||
* 应用版本
|
||||
*/
|
||||
String APPLICATION_VERSION = "1.0.0";
|
||||
/**
|
||||
* 应用版本
|
||||
*/
|
||||
String APPLICATION_VERSION = "1.0.0";
|
||||
|
||||
/**
|
||||
* consul dev 地址
|
||||
*/
|
||||
String CONSUL_DEV_HOST = "http://localhost";
|
||||
/**
|
||||
* consul dev 地址
|
||||
*/
|
||||
String CONSUL_DEV_HOST = "http://localhost";
|
||||
|
||||
/**
|
||||
* consul prod 地址
|
||||
*/
|
||||
String CONSUL_PROD_HOST = "http://192.168.186.129";
|
||||
|
||||
/**
|
||||
* consul端口
|
||||
*/
|
||||
String CONSUL_PORT = "8500";
|
||||
/**
|
||||
* consul端口
|
||||
*/
|
||||
String CONSUL_PORT = "8500";
|
||||
|
||||
/**
|
||||
* consul端口
|
||||
*/
|
||||
String CONSUL_CONFIG_FORMAT = "yaml";
|
||||
/**
|
||||
* consul端口
|
||||
*/
|
||||
String CONSUL_CONFIG_FORMAT = "yaml";
|
||||
|
||||
/**
|
||||
* consul端口
|
||||
*/
|
||||
String CONSUL_WATCH_DELAY = "1000";
|
||||
/**
|
||||
* consul端口
|
||||
*/
|
||||
String CONSUL_WATCH_DELAY = "1000";
|
||||
|
||||
/**
|
||||
* consul端口
|
||||
*/
|
||||
String CONSUL_WATCH_ENABLED = "true";
|
||||
/**
|
||||
* consul端口
|
||||
*/
|
||||
String CONSUL_WATCH_ENABLED = "true";
|
||||
|
||||
/**
|
||||
* 基础包
|
||||
*/
|
||||
String BASE_PACKAGES = "org.springblade";
|
||||
/**
|
||||
* 基础包
|
||||
*/
|
||||
String BASE_PACKAGES = "org.springblade";
|
||||
|
||||
/**
|
||||
* zookeeper id
|
||||
*/
|
||||
String ZOOKEEPER_ID = "zk";
|
||||
/**
|
||||
* zookeeper id
|
||||
*/
|
||||
String ZOOKEEPER_ID = "zk";
|
||||
|
||||
/**
|
||||
* zookeeper connect string
|
||||
*/
|
||||
String ZOOKEEPER_CONNECT_STRING = "127.0.0.1:2181";
|
||||
/**
|
||||
* zookeeper connect string
|
||||
*/
|
||||
String ZOOKEEPER_CONNECT_STRING = "127.0.0.1:2181";
|
||||
|
||||
/**
|
||||
* zookeeper address
|
||||
*/
|
||||
String ZOOKEEPER_ADDRESS = "zookeeper://" + ZOOKEEPER_CONNECT_STRING;
|
||||
/**
|
||||
* zookeeper address
|
||||
*/
|
||||
String ZOOKEEPER_ADDRESS = "zookeeper://" + ZOOKEEPER_CONNECT_STRING;
|
||||
|
||||
/**
|
||||
* zookeeper root
|
||||
*/
|
||||
String ZOOKEEPER_ROOT = "/blade-services";
|
||||
/**
|
||||
* zookeeper root
|
||||
*/
|
||||
String ZOOKEEPER_ROOT = "/blade-services";
|
||||
|
||||
/**
|
||||
* 应用名前缀
|
||||
*/
|
||||
String APPLICATION_NAME_FREFIX = "blade-";
|
||||
/**
|
||||
* 网关模块名称
|
||||
*/
|
||||
String APPLICATION_GATEWAY_NAME = APPLICATION_NAME_FREFIX + "gateway";
|
||||
/**
|
||||
* 授权模块名称
|
||||
*/
|
||||
String APPLICATION_AUTH_NAME = APPLICATION_NAME_FREFIX + "auth";
|
||||
/**
|
||||
* 监控模块名称
|
||||
*/
|
||||
String APPLICATION_ADMIN_NAME = APPLICATION_NAME_FREFIX + "admin";
|
||||
/**
|
||||
* 配置中心模块名称
|
||||
*/
|
||||
String APPLICATION_CONFIG_NAME = APPLICATION_NAME_FREFIX + "config-server";
|
||||
/**
|
||||
* TX模块名称
|
||||
*/
|
||||
String APPLICATION_TX_MANAGER = "tx-manager";
|
||||
/**
|
||||
* 首页模块名称
|
||||
*/
|
||||
String APPLICATION_DESK_NAME = APPLICATION_NAME_FREFIX + "desk";
|
||||
/**
|
||||
* 系统模块名称
|
||||
*/
|
||||
String APPLICATION_SYSTEM_NAME = APPLICATION_NAME_FREFIX + "system";
|
||||
/**
|
||||
* 用户模块名称
|
||||
*/
|
||||
String APPLICATION_USER_NAME = APPLICATION_NAME_FREFIX + "user";
|
||||
/**
|
||||
* 日志模块名称
|
||||
*/
|
||||
String APPLICATION_LOG_NAME = APPLICATION_NAME_FREFIX + "log";
|
||||
/**
|
||||
* 测试模块名称
|
||||
*/
|
||||
String APPLICATION_TEST_NAME = APPLICATION_NAME_FREFIX + "test";
|
||||
/**
|
||||
* 应用名前缀
|
||||
*/
|
||||
String APPLICATION_NAME_FREFIX = "blade-";
|
||||
/**
|
||||
* 网关模块名称
|
||||
*/
|
||||
String APPLICATION_GATEWAY_NAME = APPLICATION_NAME_FREFIX + "gateway";
|
||||
/**
|
||||
* 授权模块名称
|
||||
*/
|
||||
String APPLICATION_AUTH_NAME = APPLICATION_NAME_FREFIX + "auth";
|
||||
/**
|
||||
* 监控模块名称
|
||||
*/
|
||||
String APPLICATION_ADMIN_NAME = APPLICATION_NAME_FREFIX + "admin";
|
||||
/**
|
||||
* 配置中心模块名称
|
||||
*/
|
||||
String APPLICATION_CONFIG_NAME = APPLICATION_NAME_FREFIX + "config-server";
|
||||
/**
|
||||
* TX模块名称
|
||||
*/
|
||||
String APPLICATION_TX_MANAGER = "tx-manager";
|
||||
/**
|
||||
* 首页模块名称
|
||||
*/
|
||||
String APPLICATION_DESK_NAME = APPLICATION_NAME_FREFIX + "desk";
|
||||
/**
|
||||
* 系统模块名称
|
||||
*/
|
||||
String APPLICATION_SYSTEM_NAME = APPLICATION_NAME_FREFIX + "system";
|
||||
/**
|
||||
* 用户模块名称
|
||||
*/
|
||||
String APPLICATION_USER_NAME = APPLICATION_NAME_FREFIX + "user";
|
||||
/**
|
||||
* 日志模块名称
|
||||
*/
|
||||
String APPLICATION_LOG_NAME = APPLICATION_NAME_FREFIX + "log";
|
||||
/**
|
||||
* 测试模块名称
|
||||
*/
|
||||
String APPLICATION_TEST_NAME = APPLICATION_NAME_FREFIX + "test";
|
||||
|
||||
/**
|
||||
* 开发环境
|
||||
*/
|
||||
String DEV_CDOE = "dev";
|
||||
/**
|
||||
* 生产环境
|
||||
*/
|
||||
String PROD_CODE = "prod";
|
||||
/**
|
||||
* 测试环境
|
||||
*/
|
||||
String TEST_CODE = "test";
|
||||
/**
|
||||
* 开发环境
|
||||
*/
|
||||
String DEV_CDOE = "dev";
|
||||
/**
|
||||
* 生产环境
|
||||
*/
|
||||
String PROD_CODE = "prod";
|
||||
/**
|
||||
* 测试环境
|
||||
*/
|
||||
String TEST_CODE = "test";
|
||||
|
||||
/**
|
||||
* 代码部署于 linux 上,工作默认为 mac 和 Windows
|
||||
*/
|
||||
String OS_NAME_LINUX = "LINUX";
|
||||
/**
|
||||
* 代码部署于 linux 上,工作默认为 mac 和 Windows
|
||||
*/
|
||||
String OS_NAME_LINUX = "LINUX";
|
||||
|
||||
}
|
||||
|
@ -25,6 +25,8 @@ import org.springframework.cloud.consul.serviceregistry.ConsulServiceRegistry;
|
||||
|
||||
/**
|
||||
* Consul自定义注册规则
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
public class BladeConsulServiceRegistry extends ConsulServiceRegistry {
|
||||
|
||||
|
@ -1,3 +1,18 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springblade.core.launch.consul;
|
||||
|
||||
import org.springblade.core.launch.constant.AppConstant;
|
||||
@ -8,6 +23,8 @@ import java.util.Properties;
|
||||
|
||||
/**
|
||||
* consul启动拓展
|
||||
*
|
||||
* @author smallchil
|
||||
*/
|
||||
public class ConsulLauncherService implements LauncherService {
|
||||
|
||||
|
@ -25,6 +25,8 @@ import java.util.Map;
|
||||
|
||||
/**
|
||||
* 配置文件
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
@ConfigurationProperties("blade")
|
||||
public class BladeProperties {
|
||||
@ -36,19 +38,19 @@ public class BladeProperties {
|
||||
@Setter
|
||||
private String env;
|
||||
|
||||
/**
|
||||
* 服务名
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
private String name;
|
||||
/**
|
||||
* 服务名
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 判断是否为 本地开发环境
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
private Boolean isLocal = Boolean.FALSE;
|
||||
/**
|
||||
* 判断是否为 本地开发环境
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
private Boolean isLocal = Boolean.FALSE;
|
||||
|
||||
/**
|
||||
* 装载自定义配置blade.prop.xxx
|
||||
@ -170,32 +172,32 @@ public class BladeProperties {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取配置
|
||||
*
|
||||
* @param key key
|
||||
* @return double value
|
||||
*/
|
||||
/**
|
||||
* 获取配置
|
||||
*
|
||||
* @param key key
|
||||
* @return double value
|
||||
*/
|
||||
@Nullable
|
||||
public Double getDouble(String key) {
|
||||
return getDouble(key, null);
|
||||
}
|
||||
public Double getDouble(String key) {
|
||||
return getDouble(key, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取配置
|
||||
*
|
||||
* @param key key
|
||||
* @param defaultValue 默认值
|
||||
* @return double value
|
||||
*/
|
||||
/**
|
||||
* 获取配置
|
||||
*
|
||||
* @param key key
|
||||
* @param defaultValue 默认值
|
||||
* @return double value
|
||||
*/
|
||||
@Nullable
|
||||
public Double getDouble(String key, @Nullable Double defaultValue) {
|
||||
String value = prop.get(key);
|
||||
if (value != null) {
|
||||
return Double.parseDouble(value.trim());
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
public Double getDouble(String key, @Nullable Double defaultValue) {
|
||||
String value = prop.get(key);
|
||||
if (value != null) {
|
||||
return Double.parseDouble(value.trim());
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否存在key
|
||||
|
@ -20,43 +20,45 @@ import org.springframework.cloud.commons.util.InetUtils;
|
||||
|
||||
/**
|
||||
* 服务器信息
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
public class ServerInfo {
|
||||
|
||||
private ServerProperties serverProperties;
|
||||
private InetUtils inetUtils;
|
||||
private String hostName;
|
||||
private String ip;
|
||||
private Integer prot;
|
||||
private String ipWithPort;
|
||||
private ServerProperties serverProperties;
|
||||
private InetUtils inetUtils;
|
||||
private String hostName;
|
||||
private String ip;
|
||||
private Integer prot;
|
||||
private String ipWithPort;
|
||||
|
||||
public ServerInfo(ServerProperties serverProperties, InetUtils inetUtils) {
|
||||
this.serverProperties = serverProperties;
|
||||
this.inetUtils = inetUtils;
|
||||
this.hostName = getHostInfo().getHostname();
|
||||
this.ip = getHostInfo().getIpAddress();
|
||||
this.prot = serverProperties.getPort();
|
||||
this.ipWithPort = String.format("%s:%d", ip, prot);
|
||||
}
|
||||
public ServerInfo(ServerProperties serverProperties, InetUtils inetUtils) {
|
||||
this.serverProperties = serverProperties;
|
||||
this.inetUtils = inetUtils;
|
||||
this.hostName = getHostInfo().getHostname();
|
||||
this.ip = getHostInfo().getIpAddress();
|
||||
this.prot = serverProperties.getPort();
|
||||
this.ipWithPort = String.format("%s:%d", ip, prot);
|
||||
}
|
||||
|
||||
public InetUtils.HostInfo getHostInfo() {
|
||||
return inetUtils.findFirstNonLoopbackHostInfo();
|
||||
}
|
||||
public InetUtils.HostInfo getHostInfo() {
|
||||
return inetUtils.findFirstNonLoopbackHostInfo();
|
||||
}
|
||||
|
||||
public String getIP() {
|
||||
return this.ip;
|
||||
}
|
||||
public String getIP() {
|
||||
return this.ip;
|
||||
}
|
||||
|
||||
public Integer getPort() {
|
||||
return this.prot;
|
||||
}
|
||||
public Integer getPort() {
|
||||
return this.prot;
|
||||
}
|
||||
|
||||
public String getHostName() {
|
||||
return this.hostName;
|
||||
}
|
||||
public String getHostName() {
|
||||
return this.hostName;
|
||||
}
|
||||
|
||||
public String getIPWithPort() {
|
||||
return this.ipWithPort;
|
||||
}
|
||||
public String getIPWithPort() {
|
||||
return this.ipWithPort;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -19,11 +19,14 @@ import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
|
||||
/**
|
||||
* launcher 扩展 用于一些组件发现
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
public interface LauncherService {
|
||||
|
||||
/**
|
||||
* 启动时 处理 SpringApplicationBuilder
|
||||
*
|
||||
* @param builder SpringApplicationBuilder
|
||||
* @param appName SpringApplicationAppName
|
||||
* @param profile SpringApplicationProfile
|
||||
|
@ -20,6 +20,8 @@ import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 操作日志注解
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
|
@ -25,6 +25,8 @@ import org.springblade.core.log.publisher.ApiLogPublisher;
|
||||
|
||||
/**
|
||||
* 操作日志使用spring event异步入库
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
@Slf4j
|
||||
@Aspect
|
||||
@ -32,18 +34,18 @@ public class ApiLogAspect {
|
||||
|
||||
@Around("@annotation(apiLog)")
|
||||
public Object around(ProceedingJoinPoint point, ApiLog apiLog) throws Throwable {
|
||||
//获取类名
|
||||
//获取类名
|
||||
String className = point.getTarget().getClass().getName();
|
||||
//获取方法
|
||||
String methodName = point.getSignature().getName();
|
||||
// 发送异步日志事件
|
||||
long beginTime = System.currentTimeMillis();
|
||||
//执行方法
|
||||
Object result = point.proceed();
|
||||
//执行时长(毫秒)
|
||||
long time = System.currentTimeMillis() - beginTime;
|
||||
//记录日志
|
||||
ApiLogPublisher.publishEvent(methodName, className, apiLog, time);
|
||||
long beginTime = System.currentTimeMillis();
|
||||
//执行方法
|
||||
Object result = point.proceed();
|
||||
//执行时长(毫秒)
|
||||
long time = System.currentTimeMillis() - beginTime;
|
||||
//记录日志
|
||||
ApiLogPublisher.publishEvent(methodName, className, apiLog, time);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -38,26 +38,28 @@ import javax.servlet.Servlet;
|
||||
|
||||
/**
|
||||
* 统一异常处理
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
@Configuration
|
||||
@AllArgsConstructor
|
||||
@ConditionalOnWebApplication
|
||||
@AutoConfigureBefore(ErrorMvcAutoConfiguration.class)
|
||||
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class })
|
||||
@ConditionalOnClass({Servlet.class, DispatcherServlet.class})
|
||||
public class BladeErrorMvcAutoConfiguration {
|
||||
|
||||
private final ServerProperties serverProperties;
|
||||
private final ServerProperties serverProperties;
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(value = ErrorAttributes.class, search = SearchStrategy.CURRENT)
|
||||
public DefaultErrorAttributes errorAttributes() {
|
||||
return new BladeErrorAttributes();
|
||||
}
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(value = ErrorAttributes.class, search = SearchStrategy.CURRENT)
|
||||
public DefaultErrorAttributes errorAttributes() {
|
||||
return new BladeErrorAttributes();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(value = ErrorController.class, search = SearchStrategy.CURRENT)
|
||||
public BasicErrorController basicErrorController(ErrorAttributes errorAttributes) {
|
||||
return new BladeErrorController(errorAttributes, serverProperties.getError());
|
||||
}
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(value = ErrorController.class, search = SearchStrategy.CURRENT)
|
||||
public BasicErrorController basicErrorController(ErrorAttributes errorAttributes) {
|
||||
return new BladeErrorController(errorAttributes, serverProperties.getError());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -31,39 +31,41 @@ import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* 日志工具自动配置
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
@Configuration
|
||||
@AllArgsConstructor
|
||||
@ConditionalOnWebApplication
|
||||
public class BladeLogToolAutoConfiguration {
|
||||
|
||||
private final ILogClient logService;
|
||||
private final ServerInfo serverInfo;
|
||||
private final BladeProperties bladeProperties;
|
||||
private final ILogClient logService;
|
||||
private final ServerInfo serverInfo;
|
||||
private final BladeProperties bladeProperties;
|
||||
|
||||
@Bean
|
||||
public ApiLogAspect apiLogAspect() {
|
||||
return new ApiLogAspect();
|
||||
}
|
||||
@Bean
|
||||
public ApiLogAspect apiLogAspect() {
|
||||
return new ApiLogAspect();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public BladeLogger bladeLogger() {
|
||||
return new BladeLogger();
|
||||
}
|
||||
@Bean
|
||||
public BladeLogger bladeLogger() {
|
||||
return new BladeLogger();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ApiLogListener apiLogListener() {
|
||||
return new ApiLogListener(logService, serverInfo, bladeProperties);
|
||||
}
|
||||
@Bean
|
||||
public ApiLogListener apiLogListener() {
|
||||
return new ApiLogListener(logService, serverInfo, bladeProperties);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ErrorLogListener errorEventListener() {
|
||||
return new ErrorLogListener(logService, serverInfo, bladeProperties);
|
||||
}
|
||||
@Bean
|
||||
public ErrorLogListener errorEventListener() {
|
||||
return new ErrorLogListener(logService, serverInfo, bladeProperties);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public BladeLogListener bladeEventListener() {
|
||||
return new BladeLogListener(logService, serverInfo, bladeProperties);
|
||||
}
|
||||
@Bean
|
||||
public BladeLogListener bladeEventListener() {
|
||||
return new BladeLogListener(logService, serverInfo, bladeProperties);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -17,16 +17,18 @@ package org.springblade.core.log.constant;
|
||||
|
||||
/**
|
||||
* 事件常量
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
public interface EventConstant {
|
||||
|
||||
/**
|
||||
* log
|
||||
*/
|
||||
String EVENT_LOG = "log";
|
||||
/**
|
||||
* request
|
||||
*/
|
||||
String EVENT_REQUEST = "request";
|
||||
/**
|
||||
* log
|
||||
*/
|
||||
String EVENT_LOG = "log";
|
||||
/**
|
||||
* request
|
||||
*/
|
||||
String EVENT_REQUEST = "request";
|
||||
|
||||
}
|
||||
|
@ -29,31 +29,33 @@ import java.util.Map;
|
||||
|
||||
/**
|
||||
* 全局异常处理
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
@Slf4j
|
||||
public class BladeErrorAttributes extends DefaultErrorAttributes {
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
|
||||
String requestUri = this.getAttr(webRequest, "javax.servlet.error.request_uri");
|
||||
Integer status = this.getAttr(webRequest, "javax.servlet.error.status_code");
|
||||
Throwable error = getError(webRequest);
|
||||
R result;
|
||||
if (error == null) {
|
||||
log.error("URL:{} error status:{}", requestUri, status);
|
||||
result = R.failure(ResultCode.FAILURE, "系统未知异常[HttpStatus]:" + status);
|
||||
} else {
|
||||
log.error(String.format("URL:%s error status:%d", requestUri, status), error);
|
||||
result = R.failure(status, error.getMessage());
|
||||
}
|
||||
//发送服务异常事件
|
||||
ErrorLogPublisher.publishEvent(error, requestUri);
|
||||
return BeanUtil.toMap(result);
|
||||
}
|
||||
@Override
|
||||
public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
|
||||
String requestUri = this.getAttr(webRequest, "javax.servlet.error.request_uri");
|
||||
Integer status = this.getAttr(webRequest, "javax.servlet.error.status_code");
|
||||
Throwable error = getError(webRequest);
|
||||
R result;
|
||||
if (error == null) {
|
||||
log.error("URL:{} error status:{}", requestUri, status);
|
||||
result = R.failure(ResultCode.FAILURE, "系统未知异常[HttpStatus]:" + status);
|
||||
} else {
|
||||
log.error(String.format("URL:%s error status:%d", requestUri, status), error);
|
||||
result = R.failure(status, error.getMessage());
|
||||
}
|
||||
//发送服务异常事件
|
||||
ErrorLogPublisher.publishEvent(error, requestUri);
|
||||
return BeanUtil.toMap(result);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private <T> T getAttr(WebRequest webRequest, String name) {
|
||||
return (T) webRequest.getAttribute(name, RequestAttributes.SCOPE_REQUEST);
|
||||
}
|
||||
@Nullable
|
||||
private <T> T getAttr(WebRequest webRequest, String name) {
|
||||
return (T) webRequest.getAttribute(name, RequestAttributes.SCOPE_REQUEST);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -30,22 +30,24 @@ import java.util.Map;
|
||||
|
||||
/**
|
||||
* 更改html请求异常为ajax
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
public class BladeErrorController extends BasicErrorController {
|
||||
|
||||
public BladeErrorController(ErrorAttributes errorAttributes, ErrorProperties errorProperties) {
|
||||
super(errorAttributes, errorProperties);
|
||||
}
|
||||
public BladeErrorController(ErrorAttributes errorAttributes, ErrorProperties errorProperties) {
|
||||
super(errorAttributes, errorProperties);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
|
||||
Map<String, Object> body = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.ALL));
|
||||
HttpStatus status = getStatus(request);
|
||||
response.setStatus(status.value());
|
||||
MappingJackson2JsonView view = new MappingJackson2JsonView();
|
||||
view.setObjectMapper(JsonUtil.getInstance());
|
||||
view.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
|
||||
return new ModelAndView(view, body);
|
||||
}
|
||||
@Override
|
||||
public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
|
||||
Map<String, Object> body = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.ALL));
|
||||
HttpStatus status = getStatus(request);
|
||||
response.setStatus(status.value());
|
||||
MappingJackson2JsonView view = new MappingJackson2JsonView();
|
||||
view.setObjectMapper(JsonUtil.getInstance());
|
||||
view.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
|
||||
return new ModelAndView(view, body);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -51,110 +51,112 @@ import java.util.Set;
|
||||
|
||||
/**
|
||||
* 全局异常处理,处理可预见的异常
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
@Slf4j
|
||||
@Configuration
|
||||
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class })
|
||||
@ConditionalOnClass({Servlet.class, DispatcherServlet.class})
|
||||
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
|
||||
@RestControllerAdvice
|
||||
public class BladeRestExceptionTranslator {
|
||||
|
||||
@ExceptionHandler(MissingServletRequestParameterException.class)
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
public R handleError(MissingServletRequestParameterException e) {
|
||||
log.warn("缺少请求参数", e.getMessage());
|
||||
String message = String.format("缺少必要的请求参数: %s", e.getParameterName());
|
||||
return R.failure(ResultCode.PARAM_MISS, message);
|
||||
}
|
||||
@ExceptionHandler(MissingServletRequestParameterException.class)
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
public R handleError(MissingServletRequestParameterException e) {
|
||||
log.warn("缺少请求参数", e.getMessage());
|
||||
String message = String.format("缺少必要的请求参数: %s", e.getParameterName());
|
||||
return R.failure(ResultCode.PARAM_MISS, message);
|
||||
}
|
||||
|
||||
@ExceptionHandler(MethodArgumentTypeMismatchException.class)
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
public R handleError(MethodArgumentTypeMismatchException e) {
|
||||
log.warn("请求参数格式错误", e.getMessage());
|
||||
String message = String.format("请求参数格式错误: %s", e.getName());
|
||||
return R.failure(ResultCode.PARAM_TYPE_ERROR, message);
|
||||
}
|
||||
@ExceptionHandler(MethodArgumentTypeMismatchException.class)
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
public R handleError(MethodArgumentTypeMismatchException e) {
|
||||
log.warn("请求参数格式错误", e.getMessage());
|
||||
String message = String.format("请求参数格式错误: %s", e.getName());
|
||||
return R.failure(ResultCode.PARAM_TYPE_ERROR, message);
|
||||
}
|
||||
|
||||
@ExceptionHandler(MethodArgumentNotValidException.class)
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
public R handleError(MethodArgumentNotValidException e) {
|
||||
log.warn("参数验证失败", e.getMessage());
|
||||
return handleError(e.getBindingResult());
|
||||
}
|
||||
@ExceptionHandler(MethodArgumentNotValidException.class)
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
public R handleError(MethodArgumentNotValidException e) {
|
||||
log.warn("参数验证失败", e.getMessage());
|
||||
return handleError(e.getBindingResult());
|
||||
}
|
||||
|
||||
@ExceptionHandler(BindException.class)
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
public R handleError(BindException e) {
|
||||
log.warn("参数绑定失败", e.getMessage());
|
||||
return handleError(e.getBindingResult());
|
||||
}
|
||||
@ExceptionHandler(BindException.class)
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
public R handleError(BindException e) {
|
||||
log.warn("参数绑定失败", e.getMessage());
|
||||
return handleError(e.getBindingResult());
|
||||
}
|
||||
|
||||
private R handleError(BindingResult result) {
|
||||
FieldError error = result.getFieldError();
|
||||
String message = String.format("%s:%s", error.getField(), error.getDefaultMessage());
|
||||
return R.failure(ResultCode.PARAM_BIND_ERROR, message);
|
||||
}
|
||||
private R handleError(BindingResult result) {
|
||||
FieldError error = result.getFieldError();
|
||||
String message = String.format("%s:%s", error.getField(), error.getDefaultMessage());
|
||||
return R.failure(ResultCode.PARAM_BIND_ERROR, message);
|
||||
}
|
||||
|
||||
@ExceptionHandler(ConstraintViolationException.class)
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
public R handleError(ConstraintViolationException e) {
|
||||
log.warn("参数验证失败", e.getMessage());
|
||||
Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
|
||||
ConstraintViolation<?> violation = violations.iterator().next();
|
||||
String path = ((PathImpl) violation.getPropertyPath()).getLeafNode().getName();
|
||||
String message = String.format("%s:%s", path, violation.getMessage());
|
||||
return R.failure(ResultCode.PARAM_VALID_ERROR, message);
|
||||
}
|
||||
@ExceptionHandler(ConstraintViolationException.class)
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
public R handleError(ConstraintViolationException e) {
|
||||
log.warn("参数验证失败", e.getMessage());
|
||||
Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
|
||||
ConstraintViolation<?> violation = violations.iterator().next();
|
||||
String path = ((PathImpl) violation.getPropertyPath()).getLeafNode().getName();
|
||||
String message = String.format("%s:%s", path, violation.getMessage());
|
||||
return R.failure(ResultCode.PARAM_VALID_ERROR, message);
|
||||
}
|
||||
|
||||
@ExceptionHandler(NoHandlerFoundException.class)
|
||||
@ResponseStatus(HttpStatus.NOT_FOUND)
|
||||
public R handleError(NoHandlerFoundException e) {
|
||||
log.error("404没找到请求:{}", e.getMessage());
|
||||
return R.failure(ResultCode.NOT_FOUND, e.getMessage());
|
||||
}
|
||||
@ExceptionHandler(NoHandlerFoundException.class)
|
||||
@ResponseStatus(HttpStatus.NOT_FOUND)
|
||||
public R handleError(NoHandlerFoundException e) {
|
||||
log.error("404没找到请求:{}", e.getMessage());
|
||||
return R.failure(ResultCode.NOT_FOUND, e.getMessage());
|
||||
}
|
||||
|
||||
@ExceptionHandler(HttpMessageNotReadableException.class)
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
public R handleError(HttpMessageNotReadableException e) {
|
||||
log.error("消息不能读取:{}", e.getMessage());
|
||||
return R.failure(ResultCode.MSG_NOT_READABLE, e.getMessage());
|
||||
}
|
||||
@ExceptionHandler(HttpMessageNotReadableException.class)
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
public R handleError(HttpMessageNotReadableException e) {
|
||||
log.error("消息不能读取:{}", e.getMessage());
|
||||
return R.failure(ResultCode.MSG_NOT_READABLE, e.getMessage());
|
||||
}
|
||||
|
||||
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
|
||||
@ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
|
||||
public R handleError(HttpRequestMethodNotSupportedException e) {
|
||||
log.error("不支持当前请求方法:{}", e.getMessage());
|
||||
return R.failure(ResultCode.METHOD_NOT_SUPPORTED, e.getMessage());
|
||||
}
|
||||
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
|
||||
@ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
|
||||
public R handleError(HttpRequestMethodNotSupportedException e) {
|
||||
log.error("不支持当前请求方法:{}", e.getMessage());
|
||||
return R.failure(ResultCode.METHOD_NOT_SUPPORTED, e.getMessage());
|
||||
}
|
||||
|
||||
@ExceptionHandler(HttpMediaTypeNotSupportedException.class)
|
||||
@ResponseStatus(HttpStatus.UNSUPPORTED_MEDIA_TYPE)
|
||||
public R handleError(HttpMediaTypeNotSupportedException e) {
|
||||
log.error("不支持当前媒体类型:{}", e.getMessage());
|
||||
return R.failure(ResultCode.MEDIA_TYPE_NOT_SUPPORTED, e.getMessage());
|
||||
}
|
||||
@ExceptionHandler(HttpMediaTypeNotSupportedException.class)
|
||||
@ResponseStatus(HttpStatus.UNSUPPORTED_MEDIA_TYPE)
|
||||
public R handleError(HttpMediaTypeNotSupportedException e) {
|
||||
log.error("不支持当前媒体类型:{}", e.getMessage());
|
||||
return R.failure(ResultCode.MEDIA_TYPE_NOT_SUPPORTED, e.getMessage());
|
||||
}
|
||||
|
||||
@ExceptionHandler(ServiceException.class)
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
public R handleError(ServiceException e) {
|
||||
log.error("业务异常", e);
|
||||
return R.failure(e.getResultCode(), e.getMessage());
|
||||
}
|
||||
@ExceptionHandler(ServiceException.class)
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
public R handleError(ServiceException e) {
|
||||
log.error("业务异常", e);
|
||||
return R.failure(e.getResultCode(), e.getMessage());
|
||||
}
|
||||
|
||||
@ExceptionHandler(SecureException.class)
|
||||
@ResponseStatus(HttpStatus.UNAUTHORIZED)
|
||||
public R handleError(SecureException e) {
|
||||
log.error("认证异常", e);
|
||||
return R.failure(e.getResultCode(), e.getMessage());
|
||||
}
|
||||
@ExceptionHandler(SecureException.class)
|
||||
@ResponseStatus(HttpStatus.UNAUTHORIZED)
|
||||
public R handleError(SecureException e) {
|
||||
log.error("认证异常", e);
|
||||
return R.failure(e.getResultCode(), e.getMessage());
|
||||
}
|
||||
|
||||
@ExceptionHandler(Throwable.class)
|
||||
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
public R handleError(Throwable e) {
|
||||
log.error("服务器异常", e);
|
||||
//发送服务异常事件
|
||||
ErrorLogPublisher.publishEvent(e, URLUtil.getPath(WebUtil.getRequest().getRequestURI()));
|
||||
return R.failure(ResultCode.INTERNAL_SERVER_ERROR, (Func.isEmpty(e.getMessage()) ? ResultCode.INTERNAL_SERVER_ERROR.getMessage() : e.getMessage()));
|
||||
}
|
||||
@ExceptionHandler(Throwable.class)
|
||||
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
public R handleError(Throwable e) {
|
||||
log.error("服务器异常", e);
|
||||
//发送服务异常事件
|
||||
ErrorLogPublisher.publishEvent(e, URLUtil.getPath(WebUtil.getRequest().getRequestURI()));
|
||||
return R.failure(ResultCode.INTERNAL_SERVER_ERROR, (Func.isEmpty(e.getMessage()) ? ResultCode.INTERNAL_SERVER_ERROR.getMessage() : e.getMessage()));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -22,11 +22,13 @@ import java.util.Map;
|
||||
|
||||
/**
|
||||
* 系统日志事件
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
public class ApiLogEvent extends ApplicationEvent {
|
||||
|
||||
public ApiLogEvent(Map<String, Object> source) {
|
||||
super(source);
|
||||
}
|
||||
public ApiLogEvent(Map<String, Object> source) {
|
||||
super(source);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -38,36 +38,38 @@ import java.util.Map;
|
||||
|
||||
/**
|
||||
* 异步监听日志事件
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@AllArgsConstructor
|
||||
public class ApiLogListener {
|
||||
|
||||
private final ILogClient logService;
|
||||
private final ServerInfo serverInfo;
|
||||
private final BladeProperties bladeProperties;
|
||||
private final ILogClient logService;
|
||||
private final ServerInfo serverInfo;
|
||||
private final BladeProperties bladeProperties;
|
||||
|
||||
|
||||
@Async
|
||||
@Order
|
||||
@EventListener(ApiLogEvent.class)
|
||||
public void saveApiLog(ApiLogEvent event) {
|
||||
Map<String, Object> source = (Map<String, Object>) event.getSource();
|
||||
LogApi logApi = (LogApi) source.get(EventConstant.EVENT_LOG);
|
||||
HttpServletRequest request = (HttpServletRequest) source.get(EventConstant.EVENT_REQUEST);
|
||||
logApi.setServiceId(bladeProperties.getName());
|
||||
logApi.setServerHost(serverInfo.getHostName());
|
||||
logApi.setServerIp(serverInfo.getIPWithPort());
|
||||
logApi.setEnv(bladeProperties.getEnv());
|
||||
logApi.setRemoteIp(WebUtil.getIP(request));
|
||||
logApi.setUserAgent(request.getHeader(WebUtil.USER_AGENT_HEADER));
|
||||
logApi.setRequestUri(URLUtil.getPath(request.getRequestURI()));
|
||||
logApi.setMethod(request.getMethod());
|
||||
logApi.setParams(WebUtil.getRequestParamString(request));
|
||||
logApi.setCreateBy(SecureUtil.getUserAccount(request));
|
||||
logApi.setCreateTime(LocalDateTime.now());
|
||||
logService.saveApiLog(logApi);
|
||||
Map<String, Object> source = (Map<String, Object>) event.getSource();
|
||||
LogApi logApi = (LogApi) source.get(EventConstant.EVENT_LOG);
|
||||
HttpServletRequest request = (HttpServletRequest) source.get(EventConstant.EVENT_REQUEST);
|
||||
logApi.setServiceId(bladeProperties.getName());
|
||||
logApi.setServerHost(serverInfo.getHostName());
|
||||
logApi.setServerIp(serverInfo.getIPWithPort());
|
||||
logApi.setEnv(bladeProperties.getEnv());
|
||||
logApi.setRemoteIp(WebUtil.getIP(request));
|
||||
logApi.setUserAgent(request.getHeader(WebUtil.USER_AGENT_HEADER));
|
||||
logApi.setRequestUri(URLUtil.getPath(request.getRequestURI()));
|
||||
logApi.setMethod(request.getMethod());
|
||||
logApi.setParams(WebUtil.getRequestParamString(request));
|
||||
logApi.setCreateBy(SecureUtil.getUserAccount(request));
|
||||
logApi.setCreateTime(LocalDateTime.now());
|
||||
logService.saveApiLog(logApi);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -22,11 +22,13 @@ import java.util.Map;
|
||||
|
||||
/**
|
||||
* 系统日志事件
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
public class BladeLogEvent extends ApplicationEvent {
|
||||
|
||||
public BladeLogEvent(Map<String, Object> source) {
|
||||
super(source);
|
||||
}
|
||||
public BladeLogEvent(Map<String, Object> source) {
|
||||
super(source);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -37,34 +37,36 @@ import java.util.Map;
|
||||
|
||||
/**
|
||||
* 异步监听日志事件
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@AllArgsConstructor
|
||||
public class BladeLogListener {
|
||||
|
||||
private final ILogClient logService;
|
||||
private final ServerInfo serverInfo;
|
||||
private final BladeProperties bladeProperties;
|
||||
private final ILogClient logService;
|
||||
private final ServerInfo serverInfo;
|
||||
private final BladeProperties bladeProperties;
|
||||
|
||||
@Async
|
||||
@Order
|
||||
@EventListener(BladeLogEvent.class)
|
||||
public void saveBladeLog(BladeLogEvent event) {
|
||||
Map<String, Object> source = (Map<String, Object>) event.getSource();
|
||||
LogBlade logBlade = (LogBlade) source.get(EventConstant.EVENT_LOG);
|
||||
HttpServletRequest request = (HttpServletRequest) source.get(EventConstant.EVENT_REQUEST);
|
||||
logBlade.setRequestUri(URLUtil.getPath(request.getRequestURI()));
|
||||
logBlade.setUserAgent(request.getHeader(WebUtil.USER_AGENT_HEADER));
|
||||
logBlade.setMethod(request.getMethod());
|
||||
logBlade.setParams(WebUtil.getRequestParamString(request));
|
||||
logBlade.setServerHost(serverInfo.getHostName());
|
||||
logBlade.setServiceId(bladeProperties.getName());
|
||||
logBlade.setEnv(bladeProperties.getEnv());
|
||||
logBlade.setServerIp(serverInfo.getIPWithPort());
|
||||
logBlade.setCreateBy(SecureUtil.getUserAccount(request));
|
||||
logBlade.setCreateTime(LocalDateTime.now());
|
||||
logService.saveBladeLog(logBlade);
|
||||
}
|
||||
@Async
|
||||
@Order
|
||||
@EventListener(BladeLogEvent.class)
|
||||
public void saveBladeLog(BladeLogEvent event) {
|
||||
Map<String, Object> source = (Map<String, Object>) event.getSource();
|
||||
LogBlade logBlade = (LogBlade) source.get(EventConstant.EVENT_LOG);
|
||||
HttpServletRequest request = (HttpServletRequest) source.get(EventConstant.EVENT_REQUEST);
|
||||
logBlade.setRequestUri(URLUtil.getPath(request.getRequestURI()));
|
||||
logBlade.setUserAgent(request.getHeader(WebUtil.USER_AGENT_HEADER));
|
||||
logBlade.setMethod(request.getMethod());
|
||||
logBlade.setParams(WebUtil.getRequestParamString(request));
|
||||
logBlade.setServerHost(serverInfo.getHostName());
|
||||
logBlade.setServiceId(bladeProperties.getName());
|
||||
logBlade.setEnv(bladeProperties.getEnv());
|
||||
logBlade.setServerIp(serverInfo.getIPWithPort());
|
||||
logBlade.setCreateBy(SecureUtil.getUserAccount(request));
|
||||
logBlade.setCreateTime(LocalDateTime.now());
|
||||
logService.saveBladeLog(logBlade);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -22,11 +22,13 @@ import java.util.Map;
|
||||
|
||||
/**
|
||||
* 错误日志事件
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
public class ErrorLogEvent extends ApplicationEvent {
|
||||
|
||||
public ErrorLogEvent(Map<String, Object> source) {
|
||||
super(source);
|
||||
}
|
||||
public ErrorLogEvent(Map<String, Object> source) {
|
||||
super(source);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -36,33 +36,35 @@ import java.util.Map;
|
||||
|
||||
/**
|
||||
* 异步监听错误日志事件
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@AllArgsConstructor
|
||||
public class ErrorLogListener {
|
||||
|
||||
private final ILogClient logService;
|
||||
private final ServerInfo serverInfo;
|
||||
private final BladeProperties bladeProperties;
|
||||
private final ILogClient logService;
|
||||
private final ServerInfo serverInfo;
|
||||
private final BladeProperties bladeProperties;
|
||||
|
||||
@Async
|
||||
@Order
|
||||
@EventListener(ErrorLogEvent.class)
|
||||
public void saveErrorLog(ErrorLogEvent event) {
|
||||
Map<String, Object> source = (Map<String, Object>) event.getSource();
|
||||
LogError logError = (LogError) source.get(EventConstant.EVENT_LOG);
|
||||
HttpServletRequest request = (HttpServletRequest) source.get(EventConstant.EVENT_REQUEST);
|
||||
logError.setUserAgent(request.getHeader(WebUtil.USER_AGENT_HEADER));
|
||||
logError.setMethod(request.getMethod());
|
||||
logError.setParams(WebUtil.getRequestParamString(request));
|
||||
logError.setServiceId(bladeProperties.getName());
|
||||
logError.setServerHost(serverInfo.getHostName());
|
||||
logError.setServerIp(serverInfo.getIPWithPort());
|
||||
logError.setEnv(bladeProperties.getEnv());
|
||||
logError.setCreateBy(SecureUtil.getUserAccount(request));
|
||||
logError.setCreateTime(LocalDateTime.now());
|
||||
logService.saveErrorLog(logError);
|
||||
}
|
||||
@Async
|
||||
@Order
|
||||
@EventListener(ErrorLogEvent.class)
|
||||
public void saveErrorLog(ErrorLogEvent event) {
|
||||
Map<String, Object> source = (Map<String, Object>) event.getSource();
|
||||
LogError logError = (LogError) source.get(EventConstant.EVENT_LOG);
|
||||
HttpServletRequest request = (HttpServletRequest) source.get(EventConstant.EVENT_REQUEST);
|
||||
logError.setUserAgent(request.getHeader(WebUtil.USER_AGENT_HEADER));
|
||||
logError.setMethod(request.getMethod());
|
||||
logError.setParams(WebUtil.getRequestParamString(request));
|
||||
logError.setServiceId(bladeProperties.getName());
|
||||
logError.setServerHost(serverInfo.getHostName());
|
||||
logError.setServerIp(serverInfo.getIPWithPort());
|
||||
logError.setEnv(bladeProperties.getEnv());
|
||||
logError.setCreateBy(SecureUtil.getUserAccount(request));
|
||||
logError.setCreateTime(LocalDateTime.now());
|
||||
logService.saveErrorLog(logError);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -22,6 +22,8 @@ import org.springblade.core.tool.api.ResultCode;
|
||||
|
||||
/**
|
||||
* 业务异常
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
public class ServiceException extends RuntimeException {
|
||||
private static final long serialVersionUID = 2359767895161832954L;
|
||||
@ -29,23 +31,24 @@ public class ServiceException extends RuntimeException {
|
||||
@Getter
|
||||
private final IResultCode resultCode;
|
||||
|
||||
public ServiceException(String message) {
|
||||
super(message);
|
||||
this.resultCode = ResultCode.INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
public ServiceException(String message) {
|
||||
super(message);
|
||||
this.resultCode = ResultCode.INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
public ServiceException(IResultCode resultCode) {
|
||||
super(resultCode.getMessage());
|
||||
this.resultCode = resultCode;
|
||||
}
|
||||
public ServiceException(IResultCode resultCode) {
|
||||
super(resultCode.getMessage());
|
||||
this.resultCode = resultCode;
|
||||
}
|
||||
|
||||
public ServiceException(IResultCode resultCode, Throwable cause) {
|
||||
super(cause);
|
||||
this.resultCode = resultCode;
|
||||
this.resultCode = resultCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* 提高性能
|
||||
*
|
||||
* @return Throwable
|
||||
*/
|
||||
@Override
|
||||
|
@ -26,39 +26,41 @@ import org.springframework.web.bind.annotation.RequestBody;
|
||||
|
||||
/**
|
||||
* Feign接口类
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
@FeignClient(
|
||||
value = AppConstant.APPLICATION_LOG_NAME
|
||||
value = AppConstant.APPLICATION_LOG_NAME
|
||||
)
|
||||
public interface ILogClient {
|
||||
|
||||
String API_PREFIX = "/log";
|
||||
String API_PREFIX = "/log";
|
||||
|
||||
/**
|
||||
* 保存错误日志
|
||||
*
|
||||
* @param log
|
||||
* @return
|
||||
*/
|
||||
@PostMapping(API_PREFIX + "/saveBladeLog")
|
||||
/**
|
||||
* 保存错误日志
|
||||
*
|
||||
* @param log
|
||||
* @return
|
||||
*/
|
||||
@PostMapping(API_PREFIX + "/saveBladeLog")
|
||||
R<Boolean> saveBladeLog(@RequestBody LogBlade log);
|
||||
|
||||
/**
|
||||
* 保存操作日志
|
||||
*
|
||||
* @param log
|
||||
* @return
|
||||
*/
|
||||
@PostMapping(API_PREFIX + "/saveApiLog")
|
||||
/**
|
||||
* 保存操作日志
|
||||
*
|
||||
* @param log
|
||||
* @return
|
||||
*/
|
||||
@PostMapping(API_PREFIX + "/saveApiLog")
|
||||
R<Boolean> saveApiLog(@RequestBody LogApi log);
|
||||
|
||||
/**
|
||||
* 保存错误日志
|
||||
*
|
||||
* @param log
|
||||
* @return
|
||||
*/
|
||||
@PostMapping(API_PREFIX + "/saveErrorLog")
|
||||
/**
|
||||
* 保存错误日志
|
||||
*
|
||||
* @param log
|
||||
* @return
|
||||
*/
|
||||
@PostMapping(API_PREFIX + "/saveErrorLog")
|
||||
R<Boolean> saveErrorLog(@RequestBody LogError log);
|
||||
|
||||
}
|
||||
|
@ -22,32 +22,34 @@ import org.springframework.beans.factory.annotation.Value;
|
||||
|
||||
/**
|
||||
* 日志工具类
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
@Slf4j
|
||||
public class BladeLogger implements InitializingBean {
|
||||
|
||||
@Value("${spring.application.name}")
|
||||
private String serviceId;
|
||||
@Value("${spring.application.name}")
|
||||
private String serviceId;
|
||||
|
||||
public void info(String id, String data) {
|
||||
BladeLogPublisher.publishEvent("info", id, data);
|
||||
}
|
||||
public void info(String id, String data) {
|
||||
BladeLogPublisher.publishEvent("info", id, data);
|
||||
}
|
||||
|
||||
public void debug(String id, String data) {
|
||||
BladeLogPublisher.publishEvent("debug", id, data);
|
||||
}
|
||||
public void debug(String id, String data) {
|
||||
BladeLogPublisher.publishEvent("debug", id, data);
|
||||
}
|
||||
|
||||
public void warn(String id, String data) {
|
||||
BladeLogPublisher.publishEvent("warn", id, data);
|
||||
}
|
||||
public void warn(String id, String data) {
|
||||
BladeLogPublisher.publishEvent("warn", id, data);
|
||||
}
|
||||
|
||||
public void error(String id, String data) {
|
||||
BladeLogPublisher.publishEvent("error", id, data);
|
||||
}
|
||||
public void error(String id, String data) {
|
||||
BladeLogPublisher.publishEvent("error", id, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
log.info(serviceId + ": BladeLogger init success!");
|
||||
}
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
log.info(serviceId + ": BladeLogger init success!");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -28,94 +28,94 @@ import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 实体类
|
||||
* 实体类
|
||||
*
|
||||
* @author Blade
|
||||
* @author smallchill
|
||||
*/
|
||||
@Data
|
||||
@TableName("blade_log_api")
|
||||
public class LogApi implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键id
|
||||
*/
|
||||
@TableId(value = "id", type = IdType.ID_WORKER)
|
||||
private Long id;
|
||||
/**
|
||||
* 主键id
|
||||
*/
|
||||
@TableId(value = "id", type = IdType.ID_WORKER)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 日志类型
|
||||
*/
|
||||
private String type;
|
||||
/**
|
||||
* 日志标题
|
||||
*/
|
||||
private String title;
|
||||
/**
|
||||
* 服务ID
|
||||
*/
|
||||
private String serviceId;
|
||||
/**
|
||||
* 服务器 ip
|
||||
*/
|
||||
private String serverIp;
|
||||
/**
|
||||
* 服务器名
|
||||
*/
|
||||
private String serverHost;
|
||||
/**
|
||||
* 环境
|
||||
*/
|
||||
private String env;
|
||||
/**
|
||||
* 操作IP地址
|
||||
*/
|
||||
private String remoteIp;
|
||||
/**
|
||||
* 用户代理
|
||||
*/
|
||||
private String userAgent;
|
||||
/**
|
||||
* 请求URI
|
||||
*/
|
||||
private String requestUri;
|
||||
/**
|
||||
* 操作方式
|
||||
*/
|
||||
private String method;
|
||||
/**
|
||||
* 方法类
|
||||
*/
|
||||
private String methodClass;
|
||||
/**
|
||||
* 方法名
|
||||
*/
|
||||
private String methodName;
|
||||
/**
|
||||
* 操作提交的数据
|
||||
*/
|
||||
private String params;
|
||||
/**
|
||||
* 执行时间
|
||||
*/
|
||||
private String time;
|
||||
/**
|
||||
* 异常信息
|
||||
*/
|
||||
private String exception;
|
||||
/**
|
||||
* 日志类型
|
||||
*/
|
||||
private String type;
|
||||
/**
|
||||
* 日志标题
|
||||
*/
|
||||
private String title;
|
||||
/**
|
||||
* 服务ID
|
||||
*/
|
||||
private String serviceId;
|
||||
/**
|
||||
* 服务器 ip
|
||||
*/
|
||||
private String serverIp;
|
||||
/**
|
||||
* 服务器名
|
||||
*/
|
||||
private String serverHost;
|
||||
/**
|
||||
* 环境
|
||||
*/
|
||||
private String env;
|
||||
/**
|
||||
* 操作IP地址
|
||||
*/
|
||||
private String remoteIp;
|
||||
/**
|
||||
* 用户代理
|
||||
*/
|
||||
private String userAgent;
|
||||
/**
|
||||
* 请求URI
|
||||
*/
|
||||
private String requestUri;
|
||||
/**
|
||||
* 操作方式
|
||||
*/
|
||||
private String method;
|
||||
/**
|
||||
* 方法类
|
||||
*/
|
||||
private String methodClass;
|
||||
/**
|
||||
* 方法名
|
||||
*/
|
||||
private String methodName;
|
||||
/**
|
||||
* 操作提交的数据
|
||||
*/
|
||||
private String params;
|
||||
/**
|
||||
* 执行时间
|
||||
*/
|
||||
private String time;
|
||||
/**
|
||||
* 异常信息
|
||||
*/
|
||||
private String exception;
|
||||
|
||||
/**
|
||||
* 创建人
|
||||
*/
|
||||
private String createBy;
|
||||
/**
|
||||
* 创建人
|
||||
*/
|
||||
private String createBy;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@DateTimeFormat(pattern = DatePattern.NORM_DATETIME_PATTERN)
|
||||
@JsonFormat(pattern = DatePattern.NORM_DATETIME_PATTERN)
|
||||
private LocalDateTime createTime;
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@DateTimeFormat(pattern = DatePattern.NORM_DATETIME_PATTERN)
|
||||
@JsonFormat(pattern = DatePattern.NORM_DATETIME_PATTERN)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
|
||||
}
|
||||
|
@ -28,76 +28,76 @@ import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 实体类
|
||||
* 实体类
|
||||
*
|
||||
* @author Blade
|
||||
* @author smallchill
|
||||
* @since 2018-10-12
|
||||
*/
|
||||
@Data
|
||||
@TableName("blade_log")
|
||||
public class LogBlade implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键id
|
||||
*/
|
||||
@TableId(value = "id", type = IdType.ID_WORKER)
|
||||
private Long id;
|
||||
/**
|
||||
* 服务ID
|
||||
*/
|
||||
private String serviceId;
|
||||
/**
|
||||
* 服务器名
|
||||
*/
|
||||
private String serverHost;
|
||||
/**
|
||||
* 服务器IP地址
|
||||
*/
|
||||
private String serverIp;
|
||||
/**
|
||||
* 系统环境
|
||||
*/
|
||||
private String env;
|
||||
/**
|
||||
* 日志级别
|
||||
*/
|
||||
private String logLevel;
|
||||
/**
|
||||
* 日志业务id
|
||||
*/
|
||||
private String logId;
|
||||
/**
|
||||
* 日志数据
|
||||
*/
|
||||
private String logData;
|
||||
/**
|
||||
* 操作方式
|
||||
*/
|
||||
private String method;
|
||||
/**
|
||||
* 请求URI
|
||||
*/
|
||||
private String requestUri;
|
||||
/**
|
||||
* 用户代理
|
||||
*/
|
||||
private String userAgent;
|
||||
/**
|
||||
* 操作提交的数据
|
||||
*/
|
||||
private String params;
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
private String createBy;
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@DateTimeFormat(pattern = DatePattern.NORM_DATETIME_PATTERN)
|
||||
@JsonFormat(pattern = DatePattern.NORM_DATETIME_PATTERN)
|
||||
private LocalDateTime createTime;
|
||||
/**
|
||||
* 主键id
|
||||
*/
|
||||
@TableId(value = "id", type = IdType.ID_WORKER)
|
||||
private Long id;
|
||||
/**
|
||||
* 服务ID
|
||||
*/
|
||||
private String serviceId;
|
||||
/**
|
||||
* 服务器名
|
||||
*/
|
||||
private String serverHost;
|
||||
/**
|
||||
* 服务器IP地址
|
||||
*/
|
||||
private String serverIp;
|
||||
/**
|
||||
* 系统环境
|
||||
*/
|
||||
private String env;
|
||||
/**
|
||||
* 日志级别
|
||||
*/
|
||||
private String logLevel;
|
||||
/**
|
||||
* 日志业务id
|
||||
*/
|
||||
private String logId;
|
||||
/**
|
||||
* 日志数据
|
||||
*/
|
||||
private String logData;
|
||||
/**
|
||||
* 操作方式
|
||||
*/
|
||||
private String method;
|
||||
/**
|
||||
* 请求URI
|
||||
*/
|
||||
private String requestUri;
|
||||
/**
|
||||
* 用户代理
|
||||
*/
|
||||
private String userAgent;
|
||||
/**
|
||||
* 操作提交的数据
|
||||
*/
|
||||
private String params;
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
private String createBy;
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@DateTimeFormat(pattern = DatePattern.NORM_DATETIME_PATTERN)
|
||||
@JsonFormat(pattern = DatePattern.NORM_DATETIME_PATTERN)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
|
||||
}
|
||||
|
@ -30,89 +30,91 @@ import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 服务 异常
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
@Data
|
||||
@TableName("blade_log_error")
|
||||
public class LogError implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键id
|
||||
*/
|
||||
@TableId(value = "id", type = IdType.ID_WORKER)
|
||||
private Long id;
|
||||
/**
|
||||
* 应用名
|
||||
*/
|
||||
private String serviceId;
|
||||
/**
|
||||
* 环境
|
||||
*/
|
||||
private String env;
|
||||
/**
|
||||
* 服务器 ip
|
||||
*/
|
||||
private String serverIp;
|
||||
/**
|
||||
* 服务器名
|
||||
*/
|
||||
private String serverHost;
|
||||
/**
|
||||
* 用户代理
|
||||
*/
|
||||
private String userAgent;
|
||||
/**
|
||||
* 请求url
|
||||
*/
|
||||
@Nullable
|
||||
private String requestUri;
|
||||
/**
|
||||
* 操作方式
|
||||
*/
|
||||
private String method;
|
||||
/**
|
||||
* 堆栈信息
|
||||
*/
|
||||
private String stackTrace;
|
||||
/**
|
||||
* 异常名
|
||||
*/
|
||||
private String exceptionName;
|
||||
/**
|
||||
* 异常消息
|
||||
*/
|
||||
private String message;
|
||||
/**
|
||||
* 类名
|
||||
*/
|
||||
private String methodClass;
|
||||
/**
|
||||
* 文件名
|
||||
*/
|
||||
private String fileName;
|
||||
/**
|
||||
* 方法名
|
||||
*/
|
||||
private String methodName;
|
||||
/**
|
||||
* 操作提交的数据
|
||||
*/
|
||||
private String params;
|
||||
/**
|
||||
* 代码行数
|
||||
*/
|
||||
private Integer lineNumber;
|
||||
/**
|
||||
* 主键id
|
||||
*/
|
||||
@TableId(value = "id", type = IdType.ID_WORKER)
|
||||
private Long id;
|
||||
/**
|
||||
* 应用名
|
||||
*/
|
||||
private String serviceId;
|
||||
/**
|
||||
* 环境
|
||||
*/
|
||||
private String env;
|
||||
/**
|
||||
* 服务器 ip
|
||||
*/
|
||||
private String serverIp;
|
||||
/**
|
||||
* 服务器名
|
||||
*/
|
||||
private String serverHost;
|
||||
/**
|
||||
* 用户代理
|
||||
*/
|
||||
private String userAgent;
|
||||
/**
|
||||
* 请求url
|
||||
*/
|
||||
@Nullable
|
||||
private String requestUri;
|
||||
/**
|
||||
* 操作方式
|
||||
*/
|
||||
private String method;
|
||||
/**
|
||||
* 堆栈信息
|
||||
*/
|
||||
private String stackTrace;
|
||||
/**
|
||||
* 异常名
|
||||
*/
|
||||
private String exceptionName;
|
||||
/**
|
||||
* 异常消息
|
||||
*/
|
||||
private String message;
|
||||
/**
|
||||
* 类名
|
||||
*/
|
||||
private String methodClass;
|
||||
/**
|
||||
* 文件名
|
||||
*/
|
||||
private String fileName;
|
||||
/**
|
||||
* 方法名
|
||||
*/
|
||||
private String methodName;
|
||||
/**
|
||||
* 操作提交的数据
|
||||
*/
|
||||
private String params;
|
||||
/**
|
||||
* 代码行数
|
||||
*/
|
||||
private Integer lineNumber;
|
||||
|
||||
/**
|
||||
* 创建人
|
||||
*/
|
||||
private String createBy;
|
||||
/**
|
||||
* 创建人
|
||||
*/
|
||||
private String createBy;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@DateTimeFormat(pattern = DatePattern.NORM_DATETIME_PATTERN)
|
||||
@JsonFormat(pattern = DatePattern.NORM_DATETIME_PATTERN)
|
||||
private LocalDateTime createTime;
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@DateTimeFormat(pattern = DatePattern.NORM_DATETIME_PATTERN)
|
||||
@JsonFormat(pattern = DatePattern.NORM_DATETIME_PATTERN)
|
||||
private LocalDateTime createTime;
|
||||
}
|
||||
|
@ -30,21 +30,23 @@ import java.util.Map;
|
||||
|
||||
/**
|
||||
* API日志信息事件发送
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
public class ApiLogPublisher {
|
||||
|
||||
public static void publishEvent(String methodName, String methodClass, ApiLog apiLog, long time) {
|
||||
HttpServletRequest request = WebUtil.getRequest();
|
||||
LogApi logApi = new LogApi();
|
||||
logApi.setType(BladeConstant.LOG_NORMAL_TYPE);
|
||||
logApi.setTitle(apiLog.value());
|
||||
logApi.setTime(String.valueOf(time));
|
||||
logApi.setMethodClass(methodClass);
|
||||
logApi.setMethodName(methodName);
|
||||
Map<String, Object> event = new HashMap<>();
|
||||
event.put(EventConstant.EVENT_LOG, logApi);
|
||||
event.put(EventConstant.EVENT_REQUEST, request);
|
||||
SpringUtil.publishEvent(new ApiLogEvent(event));
|
||||
}
|
||||
public static void publishEvent(String methodName, String methodClass, ApiLog apiLog, long time) {
|
||||
HttpServletRequest request = WebUtil.getRequest();
|
||||
LogApi logApi = new LogApi();
|
||||
logApi.setType(BladeConstant.LOG_NORMAL_TYPE);
|
||||
logApi.setTitle(apiLog.value());
|
||||
logApi.setTime(String.valueOf(time));
|
||||
logApi.setMethodClass(methodClass);
|
||||
logApi.setMethodName(methodName);
|
||||
Map<String, Object> event = new HashMap<>();
|
||||
event.put(EventConstant.EVENT_LOG, logApi);
|
||||
event.put(EventConstant.EVENT_REQUEST, request);
|
||||
SpringUtil.publishEvent(new ApiLogEvent(event));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -28,19 +28,21 @@ import java.util.Map;
|
||||
|
||||
/**
|
||||
* BLADE日志信息事件发送
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
public class BladeLogPublisher {
|
||||
|
||||
public static void publishEvent(String level, String id, String data) {
|
||||
HttpServletRequest request = WebUtil.getRequest();
|
||||
LogBlade logBlade = new LogBlade();
|
||||
logBlade.setLogLevel(level);
|
||||
logBlade.setLogId(id);
|
||||
logBlade.setLogData(data);
|
||||
Map<String, Object> event = new HashMap<>();
|
||||
event.put(EventConstant.EVENT_LOG, logBlade);
|
||||
event.put(EventConstant.EVENT_REQUEST, request);
|
||||
SpringUtil.publishEvent(new BladeLogEvent(event));
|
||||
}
|
||||
public static void publishEvent(String level, String id, String data) {
|
||||
HttpServletRequest request = WebUtil.getRequest();
|
||||
LogBlade logBlade = new LogBlade();
|
||||
logBlade.setLogLevel(level);
|
||||
logBlade.setLogId(id);
|
||||
logBlade.setLogData(data);
|
||||
Map<String, Object> event = new HashMap<>();
|
||||
event.put(EventConstant.EVENT_LOG, logBlade);
|
||||
event.put(EventConstant.EVENT_REQUEST, request);
|
||||
SpringUtil.publishEvent(new BladeLogEvent(event));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -27,30 +27,32 @@ import java.util.Map;
|
||||
|
||||
/**
|
||||
* 异常信息事件发送
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
public class ErrorLogPublisher {
|
||||
|
||||
public static void publishEvent(Throwable error, String requestUri) {
|
||||
HttpServletRequest request = WebUtil.getRequest();
|
||||
LogError logError = new LogError();
|
||||
logError.setRequestUri(requestUri);
|
||||
if (Func.isNotEmpty(error)) {
|
||||
logError.setStackTrace(Exceptions.getStackTraceAsString(error));
|
||||
logError.setExceptionName(error.getClass().getName());
|
||||
logError.setMessage(error.getMessage());
|
||||
StackTraceElement[] elements = error.getStackTrace();
|
||||
if (Func.isNotEmpty(elements)) {
|
||||
StackTraceElement element = elements[0];
|
||||
logError.setMethodName(element.getMethodName());
|
||||
logError.setMethodClass(element.getClassName());
|
||||
logError.setFileName(element.getFileName());
|
||||
logError.setLineNumber(element.getLineNumber());
|
||||
}
|
||||
}
|
||||
Map<String, Object> event = new HashMap<>();
|
||||
event.put(EventConstant.EVENT_LOG, logError);
|
||||
event.put(EventConstant.EVENT_REQUEST, request);
|
||||
SpringUtil.publishEvent(new ErrorLogEvent(event));
|
||||
}
|
||||
public static void publishEvent(Throwable error, String requestUri) {
|
||||
HttpServletRequest request = WebUtil.getRequest();
|
||||
LogError logError = new LogError();
|
||||
logError.setRequestUri(requestUri);
|
||||
if (Func.isNotEmpty(error)) {
|
||||
logError.setStackTrace(Exceptions.getStackTraceAsString(error));
|
||||
logError.setExceptionName(error.getClass().getName());
|
||||
logError.setMessage(error.getMessage());
|
||||
StackTraceElement[] elements = error.getStackTrace();
|
||||
if (Func.isNotEmpty(elements)) {
|
||||
StackTraceElement element = elements[0];
|
||||
logError.setMethodName(element.getMethodName());
|
||||
logError.setMethodClass(element.getClassName());
|
||||
logError.setFileName(element.getFileName());
|
||||
logError.setLineNumber(element.getLineNumber());
|
||||
}
|
||||
}
|
||||
Map<String, Object> event = new HashMap<>(16);
|
||||
event.put(EventConstant.EVENT_LOG, logError);
|
||||
event.put(EventConstant.EVENT_REQUEST, request);
|
||||
SpringUtil.publishEvent(new ErrorLogEvent(event));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -21,6 +21,8 @@ import org.apache.ibatis.reflection.MetaObject;
|
||||
|
||||
/**
|
||||
* mybatisplus自定义填充
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
@Slf4j
|
||||
public class BladeMetaObjectHandler implements MetaObjectHandler {
|
||||
|
@ -27,6 +27,11 @@ import org.springframework.format.annotation.DateTimeFormat;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 基础实体类
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
@Data
|
||||
public class BaseEntity implements Serializable {
|
||||
/**
|
||||
@ -36,33 +41,33 @@ public class BaseEntity implements Serializable {
|
||||
@ApiModelProperty(value = "主键id")
|
||||
private Integer id;
|
||||
|
||||
/**
|
||||
* 创建人
|
||||
*/
|
||||
/**
|
||||
* 创建人
|
||||
*/
|
||||
@ApiModelProperty(value = "创建人")
|
||||
private Integer createUser;
|
||||
private Integer createUser;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@DateTimeFormat(pattern = DatePattern.NORM_DATETIME_PATTERN)
|
||||
@JsonFormat(pattern = DatePattern.NORM_DATETIME_PATTERN)
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@DateTimeFormat(pattern = DatePattern.NORM_DATETIME_PATTERN)
|
||||
@JsonFormat(pattern = DatePattern.NORM_DATETIME_PATTERN)
|
||||
@ApiModelProperty(value = "创建时间")
|
||||
private LocalDateTime createTime;
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 更新人
|
||||
*/
|
||||
/**
|
||||
* 更新人
|
||||
*/
|
||||
@ApiModelProperty(value = "更新人")
|
||||
private Integer updateUser;
|
||||
private Integer updateUser;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@DateTimeFormat(pattern = DatePattern.NORM_DATETIME_PATTERN)
|
||||
@JsonFormat(pattern = DatePattern.NORM_DATETIME_PATTERN)
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@DateTimeFormat(pattern = DatePattern.NORM_DATETIME_PATTERN)
|
||||
@JsonFormat(pattern = DatePattern.NORM_DATETIME_PATTERN)
|
||||
@ApiModelProperty(value = "更新时间")
|
||||
private LocalDateTime updateTime;
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
/**
|
||||
* 状态[1:正常]
|
||||
@ -70,9 +75,9 @@ public class BaseEntity implements Serializable {
|
||||
@ApiModelProperty(value = "业务状态")
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 状态[0:未删除,1:删除]
|
||||
*/
|
||||
/**
|
||||
* 状态[0:未删除,1:删除]
|
||||
*/
|
||||
@ApiModelProperty(value = "是否已删除")
|
||||
private Integer isDeleted;
|
||||
private Integer isDeleted;
|
||||
}
|
||||
|
@ -20,13 +20,20 @@ import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 基础业务接口
|
||||
*
|
||||
* @param <T>
|
||||
* @author smallchill
|
||||
*/
|
||||
public interface BaseService<T> extends IService<T> {
|
||||
|
||||
/**
|
||||
* 逻辑删除
|
||||
* @param ids id集合(逗号分隔)
|
||||
* @return
|
||||
*/
|
||||
/**
|
||||
* 逻辑删除
|
||||
*
|
||||
* @param ids id集合(逗号分隔)
|
||||
* @return
|
||||
*/
|
||||
boolean deleteLogic(@NotEmpty List<Integer> ids);
|
||||
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ import java.util.List;
|
||||
*
|
||||
* @param <M> mapper
|
||||
* @param <T> model
|
||||
* @author smallchill
|
||||
*/
|
||||
@Validated
|
||||
public class BaseServiceImpl<M extends BaseMapper<T>, T extends BaseEntity> extends ServiceImpl<M, T> implements BaseService<T> {
|
||||
|
@ -23,6 +23,8 @@ import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 视图包装基类
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
public abstract class BaseEntityWrapper<E, V> {
|
||||
|
||||
|
@ -25,6 +25,8 @@ import java.util.Map;
|
||||
|
||||
/**
|
||||
* 分页工具
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
public class Condition {
|
||||
|
||||
|
@ -21,33 +21,35 @@ import lombok.Data;
|
||||
|
||||
/**
|
||||
* 分页工具
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
@Data
|
||||
@ApiModel(description = "查询条件")
|
||||
public class Query {
|
||||
|
||||
/**
|
||||
* 当前页
|
||||
*/
|
||||
@ApiModelProperty(value = "当前页")
|
||||
private Integer current;
|
||||
/**
|
||||
* 当前页
|
||||
*/
|
||||
@ApiModelProperty(value = "当前页")
|
||||
private Integer current;
|
||||
|
||||
/**
|
||||
* 每页的数量
|
||||
*/
|
||||
@ApiModelProperty(value = "每页的数量")
|
||||
private Integer size;
|
||||
/**
|
||||
* 每页的数量
|
||||
*/
|
||||
@ApiModelProperty(value = "每页的数量")
|
||||
private Integer size;
|
||||
|
||||
/**
|
||||
* 排序的字段名
|
||||
*/
|
||||
@ApiModelProperty(value = "升序字段")
|
||||
private String ascs;
|
||||
/**
|
||||
* 排序的字段名
|
||||
*/
|
||||
@ApiModelProperty(value = "升序字段")
|
||||
private String ascs;
|
||||
|
||||
/**
|
||||
* 排序方式
|
||||
*/
|
||||
@ApiModelProperty(value = "降序字段")
|
||||
private String descs;
|
||||
/**
|
||||
* 排序方式
|
||||
*/
|
||||
@ApiModelProperty(value = "降序字段")
|
||||
private String descs;
|
||||
|
||||
}
|
||||
|
@ -21,6 +21,8 @@ import lombok.Data;
|
||||
|
||||
/**
|
||||
* AuthInfo
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
@Data
|
||||
@ApiModel(description = "认证信息")
|
||||
|
@ -15,12 +15,15 @@
|
||||
*/
|
||||
package org.springblade.core.secure;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 用户实体
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
@Data
|
||||
public class BladeUser implements Serializable {
|
||||
@ -30,23 +33,27 @@ public class BladeUser implements Serializable {
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
@ApiModelProperty(hidden = true)
|
||||
private Integer userId;
|
||||
/**
|
||||
* 昵称
|
||||
*/
|
||||
@ApiModelProperty(hidden = true)
|
||||
private String userName;
|
||||
/**
|
||||
* 账号
|
||||
*/
|
||||
@ApiModelProperty(hidden = true)
|
||||
private String account;
|
||||
/**
|
||||
* 角色id
|
||||
*/
|
||||
@ApiModelProperty(hidden = true)
|
||||
private String roleId;
|
||||
/**
|
||||
* 角色名
|
||||
*/
|
||||
@ApiModelProperty(hidden = true)
|
||||
private String roleName;
|
||||
|
||||
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ import java.lang.annotation.*;
|
||||
/**
|
||||
* 权限注解 用于检查权限 规定访问权限
|
||||
*
|
||||
* @author smallchill
|
||||
* @example @PreAuth("#userVO.id<10")
|
||||
* @example @PreAuth("hasRole(#test, #test1)")
|
||||
* @example @PreAuth("hasPermission(#test) and @PreAuth.hasPermission(#test)")
|
||||
|
@ -39,6 +39,8 @@ import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* AOP 鉴权
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
@Aspect
|
||||
public class AuthAspect implements ApplicationContextAware {
|
||||
@ -50,13 +52,14 @@ public class AuthAspect implements ApplicationContextAware {
|
||||
|
||||
/**
|
||||
* 切 方法 和 类上的 @PreAuth 注解
|
||||
*
|
||||
* @param point 切点
|
||||
* @return Object
|
||||
* @throws Throwable 没有权限的异常
|
||||
*/
|
||||
@Around(
|
||||
"@annotation(org.springblade.core.secure.annotation.PreAuth) || " +
|
||||
"@within(org.springblade.core.secure.annotation.PreAuth)"
|
||||
"@within(org.springblade.core.secure.annotation.PreAuth)"
|
||||
)
|
||||
public Object preAuth(ProceedingJoinPoint point) throws Throwable {
|
||||
if (handleAuth(point)) {
|
||||
@ -91,7 +94,7 @@ public class AuthAspect implements ApplicationContextAware {
|
||||
* 获取方法上的参数
|
||||
*
|
||||
* @param method 方法
|
||||
* @param args 变量
|
||||
* @param args 变量
|
||||
* @return {SimpleEvaluationContext}
|
||||
*/
|
||||
private StandardEvaluationContext getEvaluationContext(Method method, Object[] args) {
|
||||
|
@ -23,6 +23,8 @@ import org.springblade.core.tool.utils.StringUtil;
|
||||
|
||||
/**
|
||||
* 权限判断
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
public class AuthFun {
|
||||
|
||||
|
@ -24,6 +24,8 @@ import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* secure模块api放行默认配置
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
@Configuration
|
||||
@AutoConfigureBefore(SecureConfiguration.class)
|
||||
|
@ -26,6 +26,11 @@ import org.springframework.core.annotation.Order;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
/**
|
||||
* 配置类
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
@Order
|
||||
@Configuration
|
||||
@AllArgsConstructor
|
||||
|
@ -21,6 +21,8 @@ import org.springblade.core.tool.api.ResultCode;
|
||||
|
||||
/**
|
||||
* Secure异常
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
public class SecureException extends RuntimeException {
|
||||
private static final long serialVersionUID = 2359767895161832954L;
|
||||
|
@ -32,6 +32,8 @@ import java.util.Objects;
|
||||
|
||||
/**
|
||||
* jwt拦截器校验
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
@Slf4j
|
||||
public class SecureInterceptor extends HandlerInterceptorAdapter {
|
||||
|
@ -23,6 +23,8 @@ import java.util.List;
|
||||
|
||||
/**
|
||||
* secure api放行配置
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
@Data
|
||||
public class SecureRegistry {
|
||||
|
@ -36,6 +36,8 @@ import java.util.Map;
|
||||
|
||||
/**
|
||||
* Secure工具类
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
public class SecureUtil {
|
||||
public static final String BLADE_USER_REQUEST_ATTR = "_BLADE_USER_REQUEST_ATTR_";
|
||||
@ -91,9 +93,9 @@ public class SecureUtil {
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 获取用户id
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static Integer getUserId() {
|
||||
@ -102,6 +104,7 @@ public class SecureUtil {
|
||||
|
||||
/**
|
||||
* 获取用户id
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static Integer getUserId(HttpServletRequest request) {
|
||||
@ -110,6 +113,7 @@ public class SecureUtil {
|
||||
|
||||
/**
|
||||
* 获取用户账号
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static String getUserAccount() {
|
||||
@ -118,6 +122,7 @@ public class SecureUtil {
|
||||
|
||||
/**
|
||||
* 获取用户账号
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static String getUserAccount(HttpServletRequest request) {
|
||||
|
@ -39,6 +39,8 @@ import java.util.List;
|
||||
|
||||
/**
|
||||
* swagger配置
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
@Configuration
|
||||
@EnableSwagger2
|
||||
@ -47,90 +49,90 @@ import java.util.List;
|
||||
@EnableConfigurationProperties(SwaggerProperties.class)
|
||||
public class SwaggerAutoConfiguration {
|
||||
|
||||
private static final String DEFAULT_EXCLUDE_PATH = "/error";
|
||||
private static final String BASE_PATH = "/**";
|
||||
private static final String DEFAULT_EXCLUDE_PATH = "/error";
|
||||
private static final String BASE_PATH = "/**";
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public SwaggerProperties swaggerProperties() {
|
||||
return new SwaggerProperties();
|
||||
}
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public SwaggerProperties swaggerProperties() {
|
||||
return new SwaggerProperties();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Docket api(SwaggerProperties swaggerProperties) {
|
||||
// base-path处理
|
||||
if (swaggerProperties.getBasePath().size() == 0) {
|
||||
swaggerProperties.getBasePath().add(BASE_PATH);
|
||||
}
|
||||
//noinspection unchecked
|
||||
List<Predicate<String>> basePath = new ArrayList();
|
||||
swaggerProperties.getBasePath().forEach(path -> basePath.add(PathSelectors.ant(path)));
|
||||
@Bean
|
||||
public Docket api(SwaggerProperties swaggerProperties) {
|
||||
// base-path处理
|
||||
if (swaggerProperties.getBasePath().size() == 0) {
|
||||
swaggerProperties.getBasePath().add(BASE_PATH);
|
||||
}
|
||||
//noinspection unchecked
|
||||
List<Predicate<String>> basePath = new ArrayList();
|
||||
swaggerProperties.getBasePath().forEach(path -> basePath.add(PathSelectors.ant(path)));
|
||||
|
||||
// exclude-path处理
|
||||
if (swaggerProperties.getExcludePath().size() == 0) {
|
||||
swaggerProperties.getExcludePath().add(DEFAULT_EXCLUDE_PATH);
|
||||
}
|
||||
List<Predicate<String>> excludePath = new ArrayList<>();
|
||||
swaggerProperties.getExcludePath().forEach(path -> excludePath.add(PathSelectors.ant(path)));
|
||||
// exclude-path处理
|
||||
if (swaggerProperties.getExcludePath().size() == 0) {
|
||||
swaggerProperties.getExcludePath().add(DEFAULT_EXCLUDE_PATH);
|
||||
}
|
||||
List<Predicate<String>> excludePath = new ArrayList<>();
|
||||
swaggerProperties.getExcludePath().forEach(path -> excludePath.add(PathSelectors.ant(path)));
|
||||
|
||||
//noinspection Guava
|
||||
return new Docket(DocumentationType.SWAGGER_2)
|
||||
.host(swaggerProperties.getHost())
|
||||
.apiInfo(apiInfo(swaggerProperties)).select()
|
||||
.apis(RequestHandlerSelectors.basePackage(swaggerProperties.getBasePackage()))
|
||||
.paths(Predicates.and(Predicates.not(Predicates.or(excludePath)), Predicates.or(basePath)))
|
||||
.build()
|
||||
.securitySchemes(Collections.singletonList(securitySchema()))
|
||||
.securityContexts(Collections.singletonList(securityContext()))
|
||||
.pathMapping("/" );
|
||||
}
|
||||
//noinspection Guava
|
||||
return new Docket(DocumentationType.SWAGGER_2)
|
||||
.host(swaggerProperties.getHost())
|
||||
.apiInfo(apiInfo(swaggerProperties)).select()
|
||||
.apis(RequestHandlerSelectors.basePackage(swaggerProperties.getBasePackage()))
|
||||
.paths(Predicates.and(Predicates.not(Predicates.or(excludePath)), Predicates.or(basePath)))
|
||||
.build()
|
||||
.securitySchemes(Collections.singletonList(securitySchema()))
|
||||
.securityContexts(Collections.singletonList(securityContext()))
|
||||
.pathMapping("/");
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置默认的全局鉴权策略的开关,通过正则表达式进行匹配;默认匹配所有URL
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private SecurityContext securityContext() {
|
||||
return SecurityContext.builder()
|
||||
.securityReferences(defaultAuth())
|
||||
.forPaths(PathSelectors.regex(swaggerProperties().getAuthorization().getAuthRegex()))
|
||||
.build();
|
||||
}
|
||||
/**
|
||||
* 配置默认的全局鉴权策略的开关,通过正则表达式进行匹配;默认匹配所有URL
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private SecurityContext securityContext() {
|
||||
return SecurityContext.builder()
|
||||
.securityReferences(defaultAuth())
|
||||
.forPaths(PathSelectors.regex(swaggerProperties().getAuthorization().getAuthRegex()))
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 默认的全局鉴权策略
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private List<SecurityReference> defaultAuth() {
|
||||
ArrayList<AuthorizationScope> authorizationScopeList = new ArrayList<>();
|
||||
swaggerProperties().getAuthorization().getAuthorizationScopeList().forEach(authorizationScope -> authorizationScopeList.add(new AuthorizationScope(authorizationScope.getScope(), authorizationScope.getDescription())));
|
||||
AuthorizationScope[] authorizationScopes = new AuthorizationScope[authorizationScopeList.size()];
|
||||
return Collections.singletonList(SecurityReference.builder()
|
||||
.reference(swaggerProperties().getAuthorization().getName())
|
||||
.scopes(authorizationScopeList.toArray(authorizationScopes))
|
||||
.build());
|
||||
}
|
||||
/**
|
||||
* 默认的全局鉴权策略
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private List<SecurityReference> defaultAuth() {
|
||||
ArrayList<AuthorizationScope> authorizationScopeList = new ArrayList<>();
|
||||
swaggerProperties().getAuthorization().getAuthorizationScopeList().forEach(authorizationScope -> authorizationScopeList.add(new AuthorizationScope(authorizationScope.getScope(), authorizationScope.getDescription())));
|
||||
AuthorizationScope[] authorizationScopes = new AuthorizationScope[authorizationScopeList.size()];
|
||||
return Collections.singletonList(SecurityReference.builder()
|
||||
.reference(swaggerProperties().getAuthorization().getName())
|
||||
.scopes(authorizationScopeList.toArray(authorizationScopes))
|
||||
.build());
|
||||
}
|
||||
|
||||
|
||||
private OAuth securitySchema() {
|
||||
ArrayList<AuthorizationScope> authorizationScopeList = new ArrayList<>();
|
||||
swaggerProperties().getAuthorization().getAuthorizationScopeList().forEach(authorizationScope -> authorizationScopeList.add(new AuthorizationScope(authorizationScope.getScope(), authorizationScope.getDescription())));
|
||||
ArrayList<GrantType> grantTypes = new ArrayList<>();
|
||||
swaggerProperties().getAuthorization().getTokenUrlList().forEach(tokenUrl -> grantTypes.add(new ResourceOwnerPasswordCredentialsGrant(tokenUrl)));
|
||||
return new OAuth(swaggerProperties().getAuthorization().getName(), authorizationScopeList, grantTypes);
|
||||
}
|
||||
private OAuth securitySchema() {
|
||||
ArrayList<AuthorizationScope> authorizationScopeList = new ArrayList<>();
|
||||
swaggerProperties().getAuthorization().getAuthorizationScopeList().forEach(authorizationScope -> authorizationScopeList.add(new AuthorizationScope(authorizationScope.getScope(), authorizationScope.getDescription())));
|
||||
ArrayList<GrantType> grantTypes = new ArrayList<>();
|
||||
swaggerProperties().getAuthorization().getTokenUrlList().forEach(tokenUrl -> grantTypes.add(new ResourceOwnerPasswordCredentialsGrant(tokenUrl)));
|
||||
return new OAuth(swaggerProperties().getAuthorization().getName(), authorizationScopeList, grantTypes);
|
||||
}
|
||||
|
||||
private ApiInfo apiInfo(SwaggerProperties swaggerProperties) {
|
||||
return new ApiInfoBuilder()
|
||||
.title(swaggerProperties.getTitle())
|
||||
.description(swaggerProperties.getDescription())
|
||||
.license(swaggerProperties.getLicense())
|
||||
.licenseUrl(swaggerProperties.getLicenseUrl())
|
||||
.termsOfServiceUrl(swaggerProperties.getTermsOfServiceUrl())
|
||||
.contact(new Contact(swaggerProperties.getContact().getName(), swaggerProperties.getContact().getUrl(), swaggerProperties.getContact().getEmail()))
|
||||
.version(swaggerProperties.getVersion())
|
||||
.build();
|
||||
}
|
||||
private ApiInfo apiInfo(SwaggerProperties swaggerProperties) {
|
||||
return new ApiInfoBuilder()
|
||||
.title(swaggerProperties.getTitle())
|
||||
.description(swaggerProperties.getDescription())
|
||||
.license(swaggerProperties.getLicense())
|
||||
.licenseUrl(swaggerProperties.getLicenseUrl())
|
||||
.termsOfServiceUrl(swaggerProperties.getTermsOfServiceUrl())
|
||||
.contact(new Contact(swaggerProperties.getContact().getName(), swaggerProperties.getContact().getUrl(), swaggerProperties.getContact().getEmail()))
|
||||
.version(swaggerProperties.getVersion())
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -25,6 +25,8 @@ import java.util.List;
|
||||
|
||||
/**
|
||||
* SwaggerProperties
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
@Data
|
||||
@RefreshScope
|
||||
|
@ -19,11 +19,23 @@ import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 业务代码接口
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
public interface IResultCode extends Serializable {
|
||||
|
||||
String getMessage();
|
||||
/**
|
||||
* 消息
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String getMessage();
|
||||
|
||||
int getCode();
|
||||
/**
|
||||
* 状态码
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
int getCode();
|
||||
|
||||
}
|
||||
|
@ -28,6 +28,8 @@ import java.util.Optional;
|
||||
|
||||
/**
|
||||
* 统一API响应结果封装
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@ -36,32 +38,32 @@ import java.util.Optional;
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class R<T> implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ApiModelProperty(value = "状态码", required = true)
|
||||
private int code;
|
||||
@ApiModelProperty(value = "状态码", required = true)
|
||||
private int code;
|
||||
@ApiModelProperty(value = "是否成功", required = true)
|
||||
private boolean success;
|
||||
@ApiModelProperty(value = "承载数据")
|
||||
private T data;
|
||||
@ApiModelProperty(value = "返回消息", required = true)
|
||||
private String msg;
|
||||
@ApiModelProperty(value = "承载数据")
|
||||
private T data;
|
||||
@ApiModelProperty(value = "返回消息", required = true)
|
||||
private String msg;
|
||||
|
||||
private R(IResultCode resultCode) {
|
||||
this(resultCode, null, resultCode.getMessage());
|
||||
}
|
||||
private R(IResultCode resultCode) {
|
||||
this(resultCode, null, resultCode.getMessage());
|
||||
}
|
||||
|
||||
private R(IResultCode resultCode, String msg) {
|
||||
this(resultCode, null, msg);
|
||||
}
|
||||
private R(IResultCode resultCode, String msg) {
|
||||
this(resultCode, null, msg);
|
||||
}
|
||||
|
||||
private R(IResultCode resultCode, T data) {
|
||||
this(resultCode, data, resultCode.getMessage());
|
||||
}
|
||||
private R(IResultCode resultCode, T data) {
|
||||
this(resultCode, data, resultCode.getMessage());
|
||||
}
|
||||
|
||||
private R(IResultCode resultCode, T data, String msg) {
|
||||
this(resultCode.getCode(), data, msg);
|
||||
}
|
||||
private R(IResultCode resultCode, T data, String msg) {
|
||||
this(resultCode.getCode(), data, msg);
|
||||
}
|
||||
|
||||
private R(int code, T data, String msg) {
|
||||
this.code = code;
|
||||
@ -92,97 +94,108 @@ public class R<T> implements Serializable {
|
||||
return !R.isSuccess(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回R
|
||||
* @param data 数据
|
||||
*/
|
||||
public static <T> R<T> data(T data) {
|
||||
return data(data, BladeConstant.DEFAULT_SUCCESS_MESSAGE);
|
||||
}
|
||||
/**
|
||||
* 返回R
|
||||
*
|
||||
* @param data 数据
|
||||
*/
|
||||
public static <T> R<T> data(T data) {
|
||||
return data(data, BladeConstant.DEFAULT_SUCCESS_MESSAGE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回R
|
||||
* @param data 数据
|
||||
* @param msg 消息
|
||||
*/
|
||||
public static <T> R<T> data(T data, String msg) {
|
||||
return data(HttpServletResponse.SC_OK, data, msg);
|
||||
}
|
||||
/**
|
||||
* 返回R
|
||||
*
|
||||
* @param data 数据
|
||||
* @param msg 消息
|
||||
*/
|
||||
public static <T> R<T> data(T data, String msg) {
|
||||
return data(HttpServletResponse.SC_OK, data, msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回R
|
||||
* @param code 状态码
|
||||
* @param data 数据
|
||||
* @param msg 消息
|
||||
*/
|
||||
public static <T> R<T> data(int code, T data, String msg) {
|
||||
return new R<>(code, data, data == null ? BladeConstant.DEFAULT_NULL_MESSAGE : msg);
|
||||
}
|
||||
/**
|
||||
* 返回R
|
||||
*
|
||||
* @param code 状态码
|
||||
* @param data 数据
|
||||
* @param msg 消息
|
||||
*/
|
||||
public static <T> R<T> data(int code, T data, String msg) {
|
||||
return new R<>(code, data, data == null ? BladeConstant.DEFAULT_NULL_MESSAGE : msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回R
|
||||
* @param msg 消息
|
||||
*/
|
||||
public static <T> R<T> success(String msg) {
|
||||
return new R<>(ResultCode.SUCCESS, msg);
|
||||
}
|
||||
/**
|
||||
* 返回R
|
||||
*
|
||||
* @param msg 消息
|
||||
*/
|
||||
public static <T> R<T> success(String msg) {
|
||||
return new R<>(ResultCode.SUCCESS, msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回R
|
||||
* @param resultCode 业务代码
|
||||
*/
|
||||
public static <T> R<T> success(IResultCode resultCode) {
|
||||
return new R<>(resultCode);
|
||||
}
|
||||
/**
|
||||
* 返回R
|
||||
*
|
||||
* @param resultCode 业务代码
|
||||
*/
|
||||
public static <T> R<T> success(IResultCode resultCode) {
|
||||
return new R<>(resultCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回R
|
||||
* @param resultCode 业务代码
|
||||
*/
|
||||
public static <T> R<T> success(IResultCode resultCode, String msg) {
|
||||
return new R<>(resultCode, msg);
|
||||
}
|
||||
/**
|
||||
* 返回R
|
||||
*
|
||||
* @param resultCode 业务代码
|
||||
*/
|
||||
public static <T> R<T> success(IResultCode resultCode, String msg) {
|
||||
return new R<>(resultCode, msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回R
|
||||
* @param msg 消息
|
||||
*/
|
||||
public static <T> R<T> failure(String msg) {
|
||||
return new R<>(ResultCode.FAILURE, msg);
|
||||
}
|
||||
/**
|
||||
* 返回R
|
||||
*
|
||||
* @param msg 消息
|
||||
*/
|
||||
public static <T> R<T> failure(String msg) {
|
||||
return new R<>(ResultCode.FAILURE, msg);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 返回R
|
||||
* @param code 状态码
|
||||
* @param msg 消息
|
||||
*/
|
||||
public static <T> R<T> failure(int code, String msg) {
|
||||
return new R<>(code, null, msg);
|
||||
}
|
||||
/**
|
||||
* 返回R
|
||||
*
|
||||
* @param code 状态码
|
||||
* @param msg 消息
|
||||
*/
|
||||
public static <T> R<T> failure(int code, String msg) {
|
||||
return new R<>(code, null, msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回R
|
||||
* @param resultCode 业务代码
|
||||
*/
|
||||
public static <T> R<T> failure(IResultCode resultCode) {
|
||||
return new R<>(resultCode);
|
||||
}
|
||||
/**
|
||||
* 返回R
|
||||
*
|
||||
* @param resultCode 业务代码
|
||||
*/
|
||||
public static <T> R<T> failure(IResultCode resultCode) {
|
||||
return new R<>(resultCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回R
|
||||
* @param resultCode 业务代码
|
||||
*/
|
||||
public static <T> R<T> failure(IResultCode resultCode, String msg) {
|
||||
return new R<>(resultCode, msg);
|
||||
}
|
||||
/**
|
||||
* 返回R
|
||||
*
|
||||
* @param resultCode 业务代码
|
||||
*/
|
||||
public static <T> R<T> failure(IResultCode resultCode, String msg) {
|
||||
return new R<>(resultCode, msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回R
|
||||
* @param flag 成功状态
|
||||
*/
|
||||
public static R status(boolean flag) {
|
||||
return flag ? success(BladeConstant.DEFAULT_SUCCESS_MESSAGE) : failure(BladeConstant.DEFAULT_FAILURE_MESSAGE);
|
||||
}
|
||||
/**
|
||||
* 返回R
|
||||
*
|
||||
* @param flag 成功状态
|
||||
*/
|
||||
public static R status(boolean flag) {
|
||||
return flag ? success(BladeConstant.DEFAULT_SUCCESS_MESSAGE) : failure(BladeConstant.DEFAULT_FAILURE_MESSAGE);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -22,84 +22,86 @@ import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* 业务代码枚举
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum ResultCode implements IResultCode {
|
||||
|
||||
/**
|
||||
* 操作成功
|
||||
*/
|
||||
SUCCESS(HttpServletResponse.SC_OK, "操作成功"),
|
||||
/**
|
||||
* 操作成功
|
||||
*/
|
||||
SUCCESS(HttpServletResponse.SC_OK, "操作成功"),
|
||||
|
||||
/**
|
||||
* 业务异常
|
||||
*/
|
||||
FAILURE(HttpServletResponse.SC_BAD_REQUEST, "业务异常"),
|
||||
/**
|
||||
* 业务异常
|
||||
*/
|
||||
FAILURE(HttpServletResponse.SC_BAD_REQUEST, "业务异常"),
|
||||
|
||||
/**
|
||||
* 请求未授权
|
||||
*/
|
||||
UN_AUTHORIZED(HttpServletResponse.SC_UNAUTHORIZED, "请求未授权"),
|
||||
/**
|
||||
* 请求未授权
|
||||
*/
|
||||
UN_AUTHORIZED(HttpServletResponse.SC_UNAUTHORIZED, "请求未授权"),
|
||||
|
||||
/**
|
||||
* 404 没找到请求
|
||||
*/
|
||||
NOT_FOUND(HttpServletResponse.SC_NOT_FOUND, "404 没找到请求"),
|
||||
/**
|
||||
* 404 没找到请求
|
||||
*/
|
||||
NOT_FOUND(HttpServletResponse.SC_NOT_FOUND, "404 没找到请求"),
|
||||
|
||||
/**
|
||||
* 消息不能读取
|
||||
*/
|
||||
MSG_NOT_READABLE(HttpServletResponse.SC_BAD_REQUEST, "消息不能读取"),
|
||||
/**
|
||||
* 消息不能读取
|
||||
*/
|
||||
MSG_NOT_READABLE(HttpServletResponse.SC_BAD_REQUEST, "消息不能读取"),
|
||||
|
||||
/**
|
||||
* 不支持当前请求方法
|
||||
*/
|
||||
METHOD_NOT_SUPPORTED(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "不支持当前请求方法"),
|
||||
/**
|
||||
* 不支持当前请求方法
|
||||
*/
|
||||
METHOD_NOT_SUPPORTED(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "不支持当前请求方法"),
|
||||
|
||||
/**
|
||||
* 不支持当前媒体类型
|
||||
*/
|
||||
MEDIA_TYPE_NOT_SUPPORTED(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE, "不支持当前媒体类型"),
|
||||
/**
|
||||
* 不支持当前媒体类型
|
||||
*/
|
||||
MEDIA_TYPE_NOT_SUPPORTED(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE, "不支持当前媒体类型"),
|
||||
|
||||
/**
|
||||
* 请求被拒绝
|
||||
*/
|
||||
REQ_REJECT(HttpServletResponse.SC_FORBIDDEN, "请求被拒绝"),
|
||||
/**
|
||||
* 请求被拒绝
|
||||
*/
|
||||
REQ_REJECT(HttpServletResponse.SC_FORBIDDEN, "请求被拒绝"),
|
||||
|
||||
/**
|
||||
* 服务器异常
|
||||
*/
|
||||
INTERNAL_SERVER_ERROR(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "服务器异常"),
|
||||
/**
|
||||
* 服务器异常
|
||||
*/
|
||||
INTERNAL_SERVER_ERROR(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "服务器异常"),
|
||||
|
||||
/**
|
||||
* 缺少必要的请求参数
|
||||
*/
|
||||
PARAM_MISS(HttpServletResponse.SC_BAD_REQUEST, "缺少必要的请求参数"),
|
||||
/**
|
||||
* 缺少必要的请求参数
|
||||
*/
|
||||
PARAM_MISS(HttpServletResponse.SC_BAD_REQUEST, "缺少必要的请求参数"),
|
||||
|
||||
/**
|
||||
* 请求参数类型错误
|
||||
*/
|
||||
PARAM_TYPE_ERROR(HttpServletResponse.SC_BAD_REQUEST, "请求参数类型错误"),
|
||||
/**
|
||||
* 请求参数类型错误
|
||||
*/
|
||||
PARAM_TYPE_ERROR(HttpServletResponse.SC_BAD_REQUEST, "请求参数类型错误"),
|
||||
|
||||
/**
|
||||
* 请求参数绑定错误
|
||||
*/
|
||||
PARAM_BIND_ERROR(HttpServletResponse.SC_BAD_REQUEST, "请求参数绑定错误"),
|
||||
/**
|
||||
* 请求参数绑定错误
|
||||
*/
|
||||
PARAM_BIND_ERROR(HttpServletResponse.SC_BAD_REQUEST, "请求参数绑定错误"),
|
||||
|
||||
/**
|
||||
* 参数校验失败
|
||||
*/
|
||||
PARAM_VALID_ERROR(HttpServletResponse.SC_BAD_REQUEST, "参数校验失败"),
|
||||
;
|
||||
/**
|
||||
* 参数校验失败
|
||||
*/
|
||||
PARAM_VALID_ERROR(HttpServletResponse.SC_BAD_REQUEST, "参数校验失败"),
|
||||
;
|
||||
|
||||
/**
|
||||
* code编码
|
||||
*/
|
||||
final int code;
|
||||
/**
|
||||
* 中文信息描述
|
||||
*/
|
||||
final String message;
|
||||
/**
|
||||
* code编码
|
||||
*/
|
||||
final int code;
|
||||
/**
|
||||
* 中文信息描述
|
||||
*/
|
||||
final String message;
|
||||
|
||||
}
|
||||
|
@ -34,6 +34,11 @@ import java.time.ZoneId;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
/**
|
||||
* Jackson配置类
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass(ObjectMapper.class)
|
||||
@AutoConfigureBefore(JacksonAutoConfiguration.class)
|
||||
|
@ -33,6 +33,11 @@ import javax.servlet.DispatcherType;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 消息配置类
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
@Configuration
|
||||
@AllArgsConstructor
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||
|
@ -23,17 +23,21 @@ import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
|
||||
/**
|
||||
* 工具配置类
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
@Configuration
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||
public class ToolConfiguration implements WebMvcConfigurer {
|
||||
|
||||
/**
|
||||
* Spring上下文缓存
|
||||
*/
|
||||
@Bean
|
||||
public SpringUtil springUtils() {
|
||||
return new SpringUtil();
|
||||
}
|
||||
/**
|
||||
* Spring上下文缓存
|
||||
*/
|
||||
@Bean
|
||||
public SpringUtil springUtils() {
|
||||
return new SpringUtil();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -17,23 +17,25 @@ package org.springblade.core.tool.constant;
|
||||
|
||||
/**
|
||||
* 系统常量
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
public interface BladeConstant {
|
||||
|
||||
/**
|
||||
* 编码
|
||||
*/
|
||||
String UTF_8 = "UTF-8";
|
||||
/**
|
||||
* 编码
|
||||
*/
|
||||
String UTF_8 = "UTF-8";
|
||||
|
||||
/**
|
||||
* JSON 资源
|
||||
*/
|
||||
String CONTENT_TYPE = "application/json; charset=utf-8";
|
||||
/**
|
||||
* JSON 资源
|
||||
*/
|
||||
String CONTENT_TYPE = "application/json; charset=utf-8";
|
||||
|
||||
/**
|
||||
* 角色前缀
|
||||
*/
|
||||
String SECURITY_ROLE_PREFIX = "ROLE_";
|
||||
/**
|
||||
* 角色前缀
|
||||
*/
|
||||
String SECURITY_ROLE_PREFIX = "ROLE_";
|
||||
|
||||
/**
|
||||
* 主键字段名
|
||||
@ -49,11 +51,11 @@ public interface BladeConstant {
|
||||
* 是否删除字段名
|
||||
*/
|
||||
String IS_DELETED_FIELD = "is_deleted";
|
||||
/**
|
||||
* 删除状态[0:正常,1:删除]
|
||||
*/
|
||||
int DB_NOT_DELETED = 0;
|
||||
int DB_IS_DELETED = 1;
|
||||
/**
|
||||
* 删除状态[0:正常,1:删除]
|
||||
*/
|
||||
int DB_NOT_DELETED = 0;
|
||||
int DB_IS_DELETED = 1;
|
||||
|
||||
/**
|
||||
* 用户锁定状态
|
||||
@ -61,26 +63,26 @@ public interface BladeConstant {
|
||||
int DB_ADMIN_NON_LOCKED = 0;
|
||||
int DB_ADMIN_LOCKED = 1;
|
||||
|
||||
/**
|
||||
* 日志默认状态
|
||||
*/
|
||||
String LOG_NORMAL_TYPE = "1";
|
||||
/**
|
||||
* 日志默认状态
|
||||
*/
|
||||
String LOG_NORMAL_TYPE = "1";
|
||||
|
||||
/**
|
||||
* 默认为空消息
|
||||
*/
|
||||
String DEFAULT_NULL_MESSAGE = "暂无承载数据";
|
||||
/**
|
||||
* 默认成功消息
|
||||
*/
|
||||
String DEFAULT_SUCCESS_MESSAGE = "操作成功";
|
||||
/**
|
||||
* 默认失败消息
|
||||
*/
|
||||
String DEFAULT_FAILURE_MESSAGE = "操作失败";
|
||||
/**
|
||||
* 默认未授权消息
|
||||
*/
|
||||
String DEFAULT_UNAUTHORIZED_MESSAGE = "签名认证失败";
|
||||
/**
|
||||
* 默认为空消息
|
||||
*/
|
||||
String DEFAULT_NULL_MESSAGE = "暂无承载数据";
|
||||
/**
|
||||
* 默认成功消息
|
||||
*/
|
||||
String DEFAULT_SUCCESS_MESSAGE = "操作成功";
|
||||
/**
|
||||
* 默认失败消息
|
||||
*/
|
||||
String DEFAULT_FAILURE_MESSAGE = "操作失败";
|
||||
/**
|
||||
* 默认未授权消息
|
||||
*/
|
||||
String DEFAULT_UNAUTHORIZED_MESSAGE = "签名认证失败";
|
||||
|
||||
}
|
||||
|
@ -17,19 +17,21 @@ package org.springblade.core.tool.constant;
|
||||
|
||||
/**
|
||||
* 系统默认角色
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
public class RoleConstant {
|
||||
|
||||
public static final String ADMIN = "admin";
|
||||
public static final String ADMIN = "admin";
|
||||
|
||||
public static final String HAS_ROLE_ADMIN = "hasRole('" + ADMIN + "')";
|
||||
public static final String HAS_ROLE_ADMIN = "hasRole('" + ADMIN + "')";
|
||||
|
||||
public static final String USER = "user";
|
||||
public static final String USER = "user";
|
||||
|
||||
public static final String HAS_ROLE_USER = "hasRole('" + USER + "')";
|
||||
public static final String HAS_ROLE_USER = "hasRole('" + USER + "')";
|
||||
|
||||
public static final String TEST = "test";
|
||||
public static final String TEST = "test";
|
||||
|
||||
public static final String HAS_ROLE_TEST = "hasRole('" + TEST + "')";
|
||||
public static final String HAS_ROLE_TEST = "hasRole('" + TEST + "')";
|
||||
|
||||
}
|
||||
|
@ -20,6 +20,8 @@ import lombok.Data;
|
||||
|
||||
/**
|
||||
* Blade系统配置类
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
@Data
|
||||
public class SystemConstant {
|
||||
@ -34,10 +36,10 @@ public class SystemConstant {
|
||||
*/
|
||||
private boolean remoteMode = false;
|
||||
|
||||
/**
|
||||
* 外网地址
|
||||
*/
|
||||
private String domain = "http://localhost:8888";
|
||||
/**
|
||||
* 外网地址
|
||||
*/
|
||||
private String domain = "http://localhost:8888";
|
||||
|
||||
/**
|
||||
* 上传下载路径(物理路径)
|
||||
@ -53,17 +55,17 @@ public class SystemConstant {
|
||||
* 下载路径
|
||||
*/
|
||||
private String downloadPath = "/download";
|
||||
|
||||
|
||||
/**
|
||||
* 图片压缩
|
||||
*/
|
||||
private boolean compress = false;
|
||||
|
||||
|
||||
/**
|
||||
* 图片压缩比例
|
||||
*/
|
||||
private Double compressScale = 2.00;
|
||||
|
||||
|
||||
/**
|
||||
* 图片缩放选择:true放大;false缩小
|
||||
*/
|
||||
@ -89,12 +91,12 @@ public class SystemConstant {
|
||||
return me;
|
||||
}
|
||||
|
||||
public String getUploadRealPath() {
|
||||
return (remoteMode ? remotePath : realPath) + uploadPath;
|
||||
}
|
||||
public String getUploadRealPath() {
|
||||
return (remoteMode ? remotePath : realPath) + uploadPath;
|
||||
}
|
||||
|
||||
public String getUploadCtxPath() {
|
||||
return contextPath + uploadPath;
|
||||
}
|
||||
public String getUploadCtxPath() {
|
||||
return contextPath + uploadPath;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -39,58 +39,58 @@ import java.util.*;
|
||||
@Slf4j
|
||||
public class JsonUtil {
|
||||
|
||||
/**
|
||||
* 将对象序列化成json字符串
|
||||
*
|
||||
* @param value javaBean
|
||||
* @return jsonString json字符串
|
||||
*/
|
||||
public static <T> String toJson(T value) {
|
||||
try {
|
||||
return getInstance().writeValueAsString(value);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* 将对象序列化成json字符串
|
||||
*
|
||||
* @param value javaBean
|
||||
* @return jsonString json字符串
|
||||
*/
|
||||
public static <T> String toJson(T value) {
|
||||
try {
|
||||
return getInstance().writeValueAsString(value);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将对象序列化成 json byte 数组
|
||||
*
|
||||
* @param object javaBean
|
||||
* @return jsonString json字符串
|
||||
*/
|
||||
public static byte[] toJsonAsBytes(Object object) {
|
||||
try {
|
||||
return getInstance().writeValueAsBytes(object);
|
||||
} catch (JsonProcessingException e) {
|
||||
throw Exceptions.unchecked(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将json反序列化成对象
|
||||
*
|
||||
* @param content content
|
||||
* @param valueType class
|
||||
* @param <T> T 泛型标记
|
||||
* @return Bean
|
||||
*/
|
||||
public static <T> T parse(String content, Class<T> valueType) {
|
||||
try {
|
||||
return getInstance().readValue(content, valueType);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* 将对象序列化成 json byte 数组
|
||||
*
|
||||
* @param object javaBean
|
||||
* @return jsonString json字符串
|
||||
*/
|
||||
public static byte[] toJsonAsBytes(Object object) {
|
||||
try {
|
||||
return getInstance().writeValueAsBytes(object);
|
||||
} catch (JsonProcessingException e) {
|
||||
throw Exceptions.unchecked(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将json反序列化成对象
|
||||
*
|
||||
* @param content content
|
||||
* @param content content
|
||||
* @param valueType class
|
||||
* @param <T> T 泛型标记
|
||||
* @return Bean
|
||||
*/
|
||||
public static <T> T parse(String content, Class<T> valueType) {
|
||||
try {
|
||||
return getInstance().readValue(content, valueType);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将json反序列化成对象
|
||||
*
|
||||
* @param content content
|
||||
* @param typeReference 泛型类型
|
||||
* @param <T> T 泛型标记
|
||||
* @param <T> T 泛型标记
|
||||
* @return Bean
|
||||
*/
|
||||
public static <T> T parse(String content, TypeReference<?> typeReference) {
|
||||
@ -101,29 +101,29 @@ public class JsonUtil {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将json byte 数组反序列化成对象
|
||||
*
|
||||
* @param bytes json bytes
|
||||
* @param valueType class
|
||||
* @param <T> T 泛型标记
|
||||
* @return Bean
|
||||
*/
|
||||
public static <T> T parse(byte[] bytes, Class<T> valueType) {
|
||||
try {
|
||||
return getInstance().readValue(bytes, valueType);
|
||||
} catch (IOException e) {
|
||||
throw Exceptions.unchecked(e);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 将json byte 数组反序列化成对象
|
||||
*
|
||||
* @param bytes json bytes
|
||||
* @param valueType class
|
||||
* @param <T> T 泛型标记
|
||||
* @return Bean
|
||||
*/
|
||||
public static <T> T parse(byte[] bytes, Class<T> valueType) {
|
||||
try {
|
||||
return getInstance().readValue(bytes, valueType);
|
||||
} catch (IOException e) {
|
||||
throw Exceptions.unchecked(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 将json反序列化成对象
|
||||
*
|
||||
* @param bytes bytes
|
||||
* @param bytes bytes
|
||||
* @param typeReference 泛型类型
|
||||
* @param <T> T 泛型标记
|
||||
* @param <T> T 泛型标记
|
||||
* @return Bean
|
||||
*/
|
||||
public static <T> T parse(byte[] bytes, TypeReference<?> typeReference) {
|
||||
@ -137,9 +137,9 @@ public class JsonUtil {
|
||||
/**
|
||||
* 将json反序列化成对象
|
||||
*
|
||||
* @param in InputStream
|
||||
* @param valueType class
|
||||
* @param <T> T 泛型标记
|
||||
* @param in InputStream
|
||||
* @param valueType class
|
||||
* @param <T> T 泛型标记
|
||||
* @return Bean
|
||||
*/
|
||||
public static <T> T parse(InputStream in, Class<T> valueType) {
|
||||
@ -153,9 +153,9 @@ public class JsonUtil {
|
||||
/**
|
||||
* 将json反序列化成对象
|
||||
*
|
||||
* @param in InputStream
|
||||
* @param in InputStream
|
||||
* @param typeReference 泛型类型
|
||||
* @param <T> T 泛型标记
|
||||
* @param <T> T 泛型标记
|
||||
* @return Bean
|
||||
*/
|
||||
public static <T> T parse(InputStream in, TypeReference<?> typeReference) {
|
||||
@ -166,74 +166,75 @@ public class JsonUtil {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将json反序列化成List对象
|
||||
* @param content content
|
||||
* @param valueTypeRef class
|
||||
* @param <T> T 泛型标记
|
||||
* @return
|
||||
*/
|
||||
public static <T> List<T> parseArray(String content, Class<T> valueTypeRef) {
|
||||
try {
|
||||
/**
|
||||
* 将json反序列化成List对象
|
||||
*
|
||||
* @param content content
|
||||
* @param valueTypeRef class
|
||||
* @param <T> T 泛型标记
|
||||
* @return
|
||||
*/
|
||||
public static <T> List<T> parseArray(String content, Class<T> valueTypeRef) {
|
||||
try {
|
||||
|
||||
if (!StringUtil.startsWithIgnoreCase(content, "[")) {
|
||||
content = "[" + content + "]";
|
||||
}
|
||||
if (!StringUtil.startsWithIgnoreCase(content, "[")) {
|
||||
content = "[" + content + "]";
|
||||
}
|
||||
|
||||
List<Map<String, Object>> list = getInstance().readValue(content, new TypeReference<List<T>>() {
|
||||
});
|
||||
List<T> result = new ArrayList<>();
|
||||
for (Map<String, Object> map : list) {
|
||||
result.add(toPojo(map, valueTypeRef));
|
||||
}
|
||||
return result;
|
||||
} catch (IOException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
List<Map<String, Object>> list = getInstance().readValue(content, new TypeReference<List<T>>() {
|
||||
});
|
||||
List<T> result = new ArrayList<>();
|
||||
for (Map<String, Object> map : list) {
|
||||
result.add(toPojo(map, valueTypeRef));
|
||||
}
|
||||
return result;
|
||||
} catch (IOException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Map<String, Object> toMap(String content) {
|
||||
try {
|
||||
return getInstance().readValue(content, Map.class);
|
||||
} catch (IOException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public static Map<String, Object> toMap(String content) {
|
||||
try {
|
||||
return getInstance().readValue(content, Map.class);
|
||||
} catch (IOException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static <T> Map<String, T> toMap(String content, Class<T> valueTypeRef) {
|
||||
try {
|
||||
Map<String, Map<String, Object>> map = getInstance().readValue(content, new TypeReference<Map<String, T>>() {
|
||||
});
|
||||
Map<String, T> result = new HashMap<>();
|
||||
for (Map.Entry<String, Map<String, Object>> entry : map.entrySet()) {
|
||||
result.put(entry.getKey(), toPojo(entry.getValue(), valueTypeRef));
|
||||
}
|
||||
return result;
|
||||
} catch (IOException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public static <T> Map<String, T> toMap(String content, Class<T> valueTypeRef) {
|
||||
try {
|
||||
Map<String, Map<String, Object>> map = getInstance().readValue(content, new TypeReference<Map<String, T>>() {
|
||||
});
|
||||
Map<String, T> result = new HashMap<>();
|
||||
for (Map.Entry<String, Map<String, Object>> entry : map.entrySet()) {
|
||||
result.put(entry.getKey(), toPojo(entry.getValue(), valueTypeRef));
|
||||
}
|
||||
return result;
|
||||
} catch (IOException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static <T> T toPojo(Map fromValue, Class<T> toValueType) {
|
||||
return getInstance().convertValue(fromValue, toValueType);
|
||||
}
|
||||
public static <T> T toPojo(Map fromValue, Class<T> toValueType) {
|
||||
return getInstance().convertValue(fromValue, toValueType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将json字符串转成 JsonNode
|
||||
*
|
||||
* @param jsonString jsonString
|
||||
* @return jsonString json字符串
|
||||
*/
|
||||
public static JsonNode readTree(String jsonString) {
|
||||
try {
|
||||
return getInstance().readTree(jsonString);
|
||||
} catch (IOException e) {
|
||||
throw Exceptions.unchecked(e);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 将json字符串转成 JsonNode
|
||||
*
|
||||
* @param jsonString jsonString
|
||||
* @return jsonString json字符串
|
||||
*/
|
||||
public static JsonNode readTree(String jsonString) {
|
||||
try {
|
||||
return getInstance().readTree(jsonString);
|
||||
} catch (IOException e) {
|
||||
throw Exceptions.unchecked(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将json字符串转成 JsonNode
|
||||
@ -277,47 +278,47 @@ public class JsonUtil {
|
||||
}
|
||||
}
|
||||
|
||||
public static ObjectMapper getInstance() {
|
||||
return JacksonHolder.INSTANCE;
|
||||
}
|
||||
public static ObjectMapper getInstance() {
|
||||
return JacksonHolder.INSTANCE;
|
||||
}
|
||||
|
||||
private static class JacksonHolder {
|
||||
private static ObjectMapper INSTANCE = new JacksonObjectMapper();
|
||||
}
|
||||
private static class JacksonHolder {
|
||||
private static ObjectMapper INSTANCE = new JacksonObjectMapper();
|
||||
}
|
||||
|
||||
public static class JacksonObjectMapper extends ObjectMapper {
|
||||
private static final long serialVersionUID = 4288193147502386170L;
|
||||
public static class JacksonObjectMapper extends ObjectMapper {
|
||||
private static final long serialVersionUID = 4288193147502386170L;
|
||||
|
||||
private static final Locale CHINA = Locale.CHINA;
|
||||
private static final Locale CHINA = Locale.CHINA;
|
||||
|
||||
public JacksonObjectMapper() {
|
||||
super();
|
||||
//设置地点为中国
|
||||
super.setLocale(CHINA);
|
||||
//去掉默认的时间戳格式
|
||||
super.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
|
||||
public JacksonObjectMapper() {
|
||||
super();
|
||||
//设置地点为中国
|
||||
super.setLocale(CHINA);
|
||||
//去掉默认的时间戳格式
|
||||
super.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
|
||||
//设置为中国上海时区
|
||||
super.setTimeZone(TimeZone.getTimeZone(ZoneId.systemDefault()));
|
||||
//序列化时,日期的统一格式
|
||||
super.setDateFormat(new SimpleDateFormat(DatePattern.NORM_DATETIME_PATTERN, Locale.CHINA));
|
||||
//序列化处理
|
||||
super.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
|
||||
super.configure(JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER, true);
|
||||
super.findAndRegisterModules();
|
||||
//失败处理
|
||||
super.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
|
||||
super.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
//单引号处理
|
||||
super.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
|
||||
//反序列化时,属性不存在的兼容处理s
|
||||
super.getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
|
||||
//序列化处理
|
||||
super.setSerializerFactory(this.getSerializerFactory().withSerializerModifier(new BladeBeanSerializerModifier()));
|
||||
super.getSerializerProvider().setNullValueSerializer(BladeBeanSerializerModifier.NullJsonSerializers.STRING_JSON_SERIALIZER);
|
||||
//日期格式化
|
||||
//序列化处理
|
||||
super.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
|
||||
super.configure(JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER, true);
|
||||
super.findAndRegisterModules();
|
||||
//失败处理
|
||||
super.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
|
||||
super.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
//单引号处理
|
||||
super.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
|
||||
//反序列化时,属性不存在的兼容处理s
|
||||
super.getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
|
||||
//序列化处理
|
||||
super.setSerializerFactory(this.getSerializerFactory().withSerializerModifier(new BladeBeanSerializerModifier()));
|
||||
super.getSerializerProvider().setNullValueSerializer(BladeBeanSerializerModifier.NullJsonSerializers.STRING_JSON_SERIALIZER);
|
||||
//日期格式化
|
||||
super.registerModule(new BladeJavaTimeModule());
|
||||
super.findAndRegisterModules();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectMapper copy() {
|
||||
|
@ -24,7 +24,7 @@ import java.util.List;
|
||||
/**
|
||||
* 节点基类
|
||||
*
|
||||
* @author zhuangqian
|
||||
* @author smallchill
|
||||
*/
|
||||
@Data
|
||||
public class BaseNode implements INode {
|
||||
@ -32,7 +32,7 @@ public class BaseNode implements INode {
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
protected Integer id;
|
||||
protected Integer id;
|
||||
|
||||
/**
|
||||
* 父节点ID
|
||||
@ -43,6 +43,6 @@ public class BaseNode implements INode {
|
||||
* 子孙节点
|
||||
*/
|
||||
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||
protected List<INode> children = new ArrayList<>();
|
||||
protected List<INode> children = new ArrayList<>();
|
||||
|
||||
}
|
||||
|
@ -21,17 +21,22 @@ import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 森林节点类
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class ForestNode extends BaseNode {
|
||||
|
||||
private Object content;//节点内容
|
||||
/**
|
||||
* 节点内容
|
||||
*/
|
||||
private Object content;
|
||||
|
||||
public ForestNode(Integer id, Integer parentId, Object content) {
|
||||
this.id = id;
|
||||
this.parentId = parentId;
|
||||
this.content = content;
|
||||
}
|
||||
public ForestNode(Integer id, Integer parentId, Object content) {
|
||||
this.id = id;
|
||||
this.parentId = parentId;
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ import java.util.List;
|
||||
/**
|
||||
* 森林管理类
|
||||
*
|
||||
* @author zhuangqian
|
||||
* @author smallchill
|
||||
*/
|
||||
public class ForestNodeManager<T extends INode> {
|
||||
|
||||
|
@ -20,7 +20,7 @@ import java.util.List;
|
||||
/**
|
||||
* 森林节点归并类
|
||||
*
|
||||
* @author zhuangqian
|
||||
* @author smallchill
|
||||
*/
|
||||
public class ForestNodeMerger {
|
||||
|
||||
|
@ -20,7 +20,7 @@ import java.util.List;
|
||||
/**
|
||||
* Created by Blade.
|
||||
*
|
||||
* @author zhuangqian
|
||||
* @author smallchill
|
||||
*/
|
||||
public interface INode {
|
||||
|
||||
|
@ -8,7 +8,7 @@ import java.util.List;
|
||||
/**
|
||||
* Created by Blade.
|
||||
*
|
||||
* @author zhuangqian
|
||||
* @author smallchill
|
||||
*/
|
||||
public class NodeTest {
|
||||
|
||||
|
@ -20,6 +20,8 @@ import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 树型节点类
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
|
@ -5,6 +5,8 @@ import lombok.Getter;
|
||||
|
||||
/**
|
||||
* Bean属性
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
|
@ -24,172 +24,177 @@ import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* 链式map
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
public class CMap extends CaseInsensitiveHashMap<String, Object> {
|
||||
|
||||
|
||||
private CMap(){
|
||||
|
||||
private CMap() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建CMap
|
||||
* @return CMap
|
||||
*/
|
||||
public static CMap init() {
|
||||
return new CMap();
|
||||
}
|
||||
/**
|
||||
* 创建CMap
|
||||
*
|
||||
* @return CMap
|
||||
*/
|
||||
public static CMap init() {
|
||||
return new CMap();
|
||||
}
|
||||
|
||||
public static HashMap newHashMap() {
|
||||
return new HashMap();
|
||||
}
|
||||
public static HashMap newHashMap() {
|
||||
return new HashMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置列
|
||||
* @param attr 属性
|
||||
* @param value 值
|
||||
* @return 本身
|
||||
*/
|
||||
public CMap set(String attr, Object value) {
|
||||
this.put(attr, value);
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* 设置列
|
||||
*
|
||||
* @param attr 属性
|
||||
* @param value 值
|
||||
* @return 本身
|
||||
*/
|
||||
public CMap set(String attr, Object value) {
|
||||
this.put(attr, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置列,当键或值为null时忽略
|
||||
* @param attr 属性
|
||||
* @param value 值
|
||||
* @return 本身
|
||||
*/
|
||||
public CMap setIgnoreNull(String attr, Object value) {
|
||||
if(null != attr && null != value) {
|
||||
set(attr, value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* 设置列,当键或值为null时忽略
|
||||
*
|
||||
* @param attr 属性
|
||||
* @param value 值
|
||||
* @return 本身
|
||||
*/
|
||||
public CMap setIgnoreNull(String attr, Object value) {
|
||||
if (null != attr && null != value) {
|
||||
set(attr, value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Object getObj(String key) {
|
||||
return super.get(key);
|
||||
}
|
||||
public Object getObj(String key) {
|
||||
return super.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得特定类型值
|
||||
*
|
||||
* @param <T> 值类型
|
||||
* @param attr 字段名
|
||||
* @param defaultValue 默认值
|
||||
* @return 字段值
|
||||
*/
|
||||
public <T> T get(String attr, T defaultValue) {
|
||||
final Object result = get(attr);
|
||||
return (T)(result != null ? result : defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* 获得特定类型值
|
||||
*
|
||||
* @param attr 字段名
|
||||
* @return 字段值
|
||||
*/
|
||||
public String getStr(String attr) {
|
||||
return Func.toStr(get(attr), null);
|
||||
}
|
||||
* @param <T> 值类型
|
||||
* @param attr 字段名
|
||||
* @param defaultValue 默认值
|
||||
* @return 字段值
|
||||
*/
|
||||
public <T> T get(String attr, T defaultValue) {
|
||||
final Object result = get(attr);
|
||||
return (T) (result != null ? result : defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* 获得特定类型值
|
||||
*
|
||||
* @param attr 字段名
|
||||
* @return 字段值
|
||||
*/
|
||||
public Integer getInt(String attr) {
|
||||
return Func.toInt(get(attr), -1);
|
||||
}
|
||||
* @return 字段值
|
||||
*/
|
||||
public String getStr(String attr) {
|
||||
return Func.toStr(get(attr), null);
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* 获得特定类型值
|
||||
*
|
||||
* @param attr 字段名
|
||||
* @return 字段值
|
||||
*/
|
||||
public Long getLong(String attr) {
|
||||
return Func.toLong(get(attr), -1l);
|
||||
}
|
||||
* @return 字段值
|
||||
*/
|
||||
public Integer getInt(String attr) {
|
||||
return Func.toInt(get(attr), -1);
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* 获得特定类型值
|
||||
*
|
||||
* @param attr 字段名
|
||||
* @return 字段值
|
||||
*/
|
||||
public Float getFloat(String attr) {
|
||||
return Func.toFloat(get(attr), null);
|
||||
}
|
||||
* @return 字段值
|
||||
*/
|
||||
public Long getLong(String attr) {
|
||||
return Func.toLong(get(attr), -1l);
|
||||
}
|
||||
|
||||
public Double getDouble(String attr) {
|
||||
return Func.toDouble(get(attr), null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
/**
|
||||
* 获得特定类型值
|
||||
*
|
||||
* @param attr 字段名
|
||||
* @return 字段值
|
||||
*/
|
||||
public Boolean getBool(String attr) {
|
||||
return Func.toBoolean(get(attr), null);
|
||||
}
|
||||
* @return 字段值
|
||||
*/
|
||||
public Float getFloat(String attr) {
|
||||
return Func.toFloat(get(attr), null);
|
||||
}
|
||||
|
||||
/**
|
||||
public Double getDouble(String attr) {
|
||||
return Func.toDouble(get(attr), null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获得特定类型值
|
||||
*
|
||||
* @param attr 字段名
|
||||
* @return 字段值
|
||||
*/
|
||||
public byte[] getBytes(String attr) {
|
||||
return get(attr, null);
|
||||
}
|
||||
* @return 字段值
|
||||
*/
|
||||
public Boolean getBool(String attr) {
|
||||
return Func.toBoolean(get(attr), null);
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* 获得特定类型值
|
||||
*
|
||||
* @param attr 字段名
|
||||
* @return 字段值
|
||||
*/
|
||||
public Date getDate(String attr) {
|
||||
return get(attr, null);
|
||||
}
|
||||
* @return 字段值
|
||||
*/
|
||||
public byte[] getBytes(String attr) {
|
||||
return get(attr, null);
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* 获得特定类型值
|
||||
*
|
||||
* @param attr 字段名
|
||||
* @return 字段值
|
||||
*/
|
||||
public Time getTime(String attr) {
|
||||
return get(attr, null);
|
||||
}
|
||||
* @return 字段值
|
||||
*/
|
||||
public Date getDate(String attr) {
|
||||
return get(attr, null);
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* 获得特定类型值
|
||||
*
|
||||
* @param attr 字段名
|
||||
* @return 字段值
|
||||
*/
|
||||
public Timestamp getTimestamp(String attr) {
|
||||
return get(attr, null);
|
||||
}
|
||||
* @return 字段值
|
||||
*/
|
||||
public Time getTime(String attr) {
|
||||
return get(attr, null);
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* 获得特定类型值
|
||||
*
|
||||
* @param attr 字段名
|
||||
* @return 字段值
|
||||
*/
|
||||
public Number getNumber(String attr) {
|
||||
return get(attr, null);
|
||||
}
|
||||
|
||||
* @return 字段值
|
||||
*/
|
||||
public Timestamp getTimestamp(String attr) {
|
||||
return get(attr, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得特定类型值
|
||||
*
|
||||
* @param attr 字段名
|
||||
* @return 字段值
|
||||
*/
|
||||
public Number getNumber(String attr) {
|
||||
return get(attr, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CMap clone() {
|
||||
return (CMap) super.clone();
|
||||
|
@ -17,52 +17,58 @@ package org.springblade.core.tool.support;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 大小写忽略Map拓展
|
||||
*
|
||||
* @param <K>
|
||||
* @param <V>
|
||||
* @author smallchill
|
||||
*/
|
||||
public class CaseInsensitiveHashMap<K, V> extends LinkedHashMap<String, Object> {
|
||||
|
||||
public class CaseInsensitiveHashMap<K,V> extends LinkedHashMap<String, Object> {
|
||||
private static final long serialVersionUID = 9178606903603606031L;
|
||||
|
||||
private static final long serialVersionUID = 9178606903603606031L;
|
||||
private final Map<String, String> lowerCaseMap = new HashMap<String, String>();
|
||||
|
||||
private final Map<String, String> lowerCaseMap = new HashMap<String, String>();
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
Object realKey = lowerCaseMap.get(key.toString().toLowerCase(Locale.ENGLISH));
|
||||
return super.containsKey(realKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
Object realKey = lowerCaseMap.get(key.toString().toLowerCase(Locale.ENGLISH));
|
||||
return super.containsKey(realKey);
|
||||
}
|
||||
@Override
|
||||
public Object get(Object key) {
|
||||
Object realKey = lowerCaseMap.get(key.toString().toLowerCase(Locale.ENGLISH));
|
||||
return super.get(realKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(Object key) {
|
||||
Object realKey = lowerCaseMap.get(key.toString().toLowerCase(Locale.ENGLISH));
|
||||
return super.get(realKey);
|
||||
}
|
||||
@Override
|
||||
public Set keySet() {
|
||||
return lowerCaseMap.keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set keySet() {
|
||||
return lowerCaseMap.keySet();
|
||||
}
|
||||
@Override
|
||||
public Object put(String key, Object value) {
|
||||
Object oldKey = lowerCaseMap.put(key.toLowerCase(Locale.ENGLISH), key);
|
||||
Object oldValue = super.remove(oldKey);
|
||||
super.put(key, value);
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object put(String key, Object value) {
|
||||
Object oldKey = lowerCaseMap.put(key.toLowerCase(Locale.ENGLISH), key);
|
||||
Object oldValue = super.remove(oldKey);
|
||||
super.put(key, value);
|
||||
return oldValue;
|
||||
}
|
||||
@Override
|
||||
public void putAll(Map<? extends String, ?> m) {
|
||||
for (Map.Entry<? extends String, ?> entry : m.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
Object value = entry.getValue();
|
||||
this.put(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Map<? extends String, ?> m) {
|
||||
for (Map.Entry<? extends String, ?> entry : m.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
Object value = entry.getValue();
|
||||
this.put(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object remove(Object key) {
|
||||
Object realKey = lowerCaseMap.remove(key.toString().toLowerCase(Locale.ENGLISH));
|
||||
return super.remove(realKey);
|
||||
}
|
||||
@Override
|
||||
public Object remove(Object key) {
|
||||
Object realKey = lowerCaseMap.remove(key.toString().toLowerCase(Locale.ENGLISH));
|
||||
return super.remove(realKey);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -19,6 +19,8 @@ import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* A factory for creating MultiOutputStream objects.
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
public interface IMultiOutputStream {
|
||||
|
||||
@ -28,6 +30,6 @@ public interface IMultiOutputStream {
|
||||
* @param params the params
|
||||
* @return the output stream
|
||||
*/
|
||||
OutputStream buildOutputStream(Integer... params) ;
|
||||
|
||||
OutputStream buildOutputStream(Integer... params);
|
||||
|
||||
}
|
||||
|
@ -15,74 +15,99 @@
|
||||
*/
|
||||
package org.springblade.core.tool.support;
|
||||
|
||||
/**
|
||||
* 图片操作类
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
public class ImagePosition {
|
||||
|
||||
/** 图片顶部. */
|
||||
/**
|
||||
* 图片顶部.
|
||||
*/
|
||||
public static final int TOP = 32;
|
||||
|
||||
/** 图片中部. */
|
||||
|
||||
/**
|
||||
* 图片中部.
|
||||
*/
|
||||
public static final int MIDDLE = 16;
|
||||
|
||||
/** 图片底部. */
|
||||
|
||||
/**
|
||||
* 图片底部.
|
||||
*/
|
||||
public static final int BOTTOM = 8;
|
||||
|
||||
/** 图片左侧. */
|
||||
|
||||
/**
|
||||
* 图片左侧.
|
||||
*/
|
||||
public static final int LEFT = 4;
|
||||
|
||||
/** 图片居中. */
|
||||
|
||||
/**
|
||||
* 图片居中.
|
||||
*/
|
||||
public static final int CENTER = 2;
|
||||
|
||||
/** 图片右侧. */
|
||||
|
||||
/**
|
||||
* 图片右侧.
|
||||
*/
|
||||
public static final int RIGHT = 1;
|
||||
|
||||
/** 横向边距,靠左或靠右时和边界的距离. */
|
||||
|
||||
/**
|
||||
* 横向边距,靠左或靠右时和边界的距离.
|
||||
*/
|
||||
private static final int PADDING_HORI = 6;
|
||||
|
||||
/** 纵向边距,靠上或靠底时和边界的距离. */
|
||||
|
||||
/**
|
||||
* 纵向边距,靠上或靠底时和边界的距离.
|
||||
*/
|
||||
private static final int PADDING_VERT = 6;
|
||||
|
||||
|
||||
/** 图片中盒[左上角]的x坐标. */
|
||||
private int boxPosX ;
|
||||
|
||||
/** 图片中盒[左上角]的y坐标. */
|
||||
private int boxPosY ;
|
||||
|
||||
|
||||
/**
|
||||
* 图片中盒[左上角]的x坐标.
|
||||
*/
|
||||
private int boxPosX;
|
||||
|
||||
/**
|
||||
* 图片中盒[左上角]的y坐标.
|
||||
*/
|
||||
private int boxPosY;
|
||||
|
||||
/**
|
||||
* Instantiates a new image position.
|
||||
*
|
||||
* @param width the width
|
||||
* @param height the height
|
||||
* @param boxWidth the box width
|
||||
* @param width the width
|
||||
* @param height the height
|
||||
* @param boxWidth the box width
|
||||
* @param boxHeight the box height
|
||||
* @param style the style
|
||||
* @param style the style
|
||||
*/
|
||||
public ImagePosition(int width , int height , int boxWidth , int boxHeight, int style ) {
|
||||
switch(style & 7) {
|
||||
public ImagePosition(int width, int height, int boxWidth, int boxHeight, int style) {
|
||||
switch (style & 7) {
|
||||
case LEFT:
|
||||
boxPosX = PADDING_HORI;
|
||||
boxPosX = PADDING_HORI;
|
||||
break;
|
||||
case RIGHT:
|
||||
boxPosX = width - boxWidth - PADDING_HORI;
|
||||
boxPosX = width - boxWidth - PADDING_HORI;
|
||||
break;
|
||||
case CENTER:
|
||||
default:
|
||||
boxPosX = (width - boxWidth)/2;
|
||||
boxPosX = (width - boxWidth) / 2;
|
||||
}
|
||||
switch(style >> 3 << 3) {
|
||||
switch (style >> 3 << 3) {
|
||||
case TOP:
|
||||
boxPosY = PADDING_VERT;
|
||||
break;
|
||||
case MIDDLE:
|
||||
boxPosY = (height - boxHeight)/2;
|
||||
boxPosY = (height - boxHeight) / 2;
|
||||
break;
|
||||
case BOTTOM:
|
||||
default:
|
||||
boxPosY = height - boxHeight - PADDING_VERT;
|
||||
boxPosY = height - boxHeight - PADDING_VERT;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Gets the x.
|
||||
*
|
||||
@ -91,7 +116,7 @@ public class ImagePosition {
|
||||
public int getX() {
|
||||
return getX(0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the x.
|
||||
*
|
||||
@ -101,7 +126,7 @@ public class ImagePosition {
|
||||
public int getX(int x) {
|
||||
return this.boxPosX + x;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the y.
|
||||
*
|
||||
@ -110,7 +135,7 @@ public class ImagePosition {
|
||||
public int getY() {
|
||||
return getY(0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the y.
|
||||
*
|
||||
@ -120,5 +145,5 @@ public class ImagePosition {
|
||||
public int getY(int y) {
|
||||
return this.boxPosY + y;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -3,65 +3,92 @@ package org.springblade.core.tool.support;
|
||||
import org.springblade.core.tool.utils.Func;
|
||||
import org.springblade.core.tool.utils.StringPool;
|
||||
|
||||
/**
|
||||
* 字符串格式化
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
public class StrFormatter {
|
||||
|
||||
/**
|
||||
* 格式化字符串<br>
|
||||
* 此方法只是简单将占位符 {} 按照顺序替换为参数<br>
|
||||
* 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可<br>
|
||||
* 例:<br>
|
||||
* 通常使用:format("this is {} for {}", "a", "b") =》 this is a for b<br>
|
||||
* 转义{}: format("this is \\{} for {}", "a", "b") =》 this is \{} for a<br>
|
||||
* 转义\: format("this is \\\\{} for {}", "a", "b") =》 this is \a for b<br>
|
||||
* @param strPattern 字符串模板
|
||||
* @param argArray 参数列表
|
||||
* @return 结果
|
||||
*/
|
||||
public static String format(final String strPattern, final Object... argArray) {
|
||||
if (Func.isBlank(strPattern) || Func.isEmpty(argArray)) {
|
||||
return strPattern;
|
||||
}
|
||||
final int strPatternLength = strPattern.length();
|
||||
/**
|
||||
* 格式化字符串<br>
|
||||
* 此方法只是简单将占位符 {} 按照顺序替换为参数<br>
|
||||
* 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可<br>
|
||||
* 例:<br>
|
||||
* 通常使用:format("this is {} for {}", "a", "b") =》 this is a for b<br>
|
||||
* 转义{}: format("this is \\{} for {}", "a", "b") =》 this is \{} for a<br>
|
||||
* 转义\: format("this is \\\\{} for {}", "a", "b") =》 this is \a for b<br>
|
||||
*
|
||||
* @param strPattern 字符串模板
|
||||
* @param argArray 参数列表
|
||||
* @return 结果
|
||||
*/
|
||||
public static String format(final String strPattern, final Object... argArray) {
|
||||
if (Func.isBlank(strPattern) || Func.isEmpty(argArray)) {
|
||||
return strPattern;
|
||||
}
|
||||
final int strPatternLength = strPattern.length();
|
||||
|
||||
//初始化定义好的长度以获得更好的性能
|
||||
StringBuilder sbuf = new StringBuilder(strPatternLength + 50);
|
||||
/**
|
||||
* 初始化定义好的长度以获得更好的性能
|
||||
*/
|
||||
StringBuilder sbuf = new StringBuilder(strPatternLength + 50);
|
||||
|
||||
int handledPosition = 0;//记录已经处理到的位置
|
||||
int delimIndex;//占位符所在位置
|
||||
for (int argIndex = 0; argIndex < argArray.length; argIndex++) {
|
||||
delimIndex = strPattern.indexOf(StringPool.EMPTY_JSON, handledPosition);
|
||||
if (delimIndex == -1) {//剩余部分无占位符
|
||||
if (handledPosition == 0) { //不带占位符的模板直接返回
|
||||
return strPattern;
|
||||
} else { //字符串模板剩余部分不再包含占位符,加入剩余部分后返回结果
|
||||
sbuf.append(strPattern, handledPosition, strPatternLength);
|
||||
return sbuf.toString();
|
||||
}
|
||||
} else {
|
||||
if (delimIndex > 0 && strPattern.charAt(delimIndex - 1) == StringPool.BACK_SLASH) {//转义符
|
||||
if (delimIndex > 1 && strPattern.charAt(delimIndex - 2) == StringPool.BACK_SLASH) {//双转义符
|
||||
//转义符之前还有一个转义符,占位符依旧有效
|
||||
sbuf.append(strPattern, handledPosition, delimIndex - 1);
|
||||
sbuf.append(Func.toStr(argArray[argIndex]));
|
||||
handledPosition = delimIndex + 2;
|
||||
} else {
|
||||
//占位符被转义
|
||||
argIndex--;
|
||||
sbuf.append(strPattern, handledPosition, delimIndex - 1);
|
||||
sbuf.append(StringPool.LEFT_BRACE);
|
||||
handledPosition = delimIndex + 1;
|
||||
}
|
||||
} else {//正常占位符
|
||||
sbuf.append(strPattern, handledPosition, delimIndex);
|
||||
sbuf.append(Func.toStr(argArray[argIndex]));
|
||||
handledPosition = delimIndex + 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
// append the characters following the last {} pair.
|
||||
//加入最后一个占位符后所有的字符
|
||||
sbuf.append(strPattern, handledPosition, strPattern.length());
|
||||
/**
|
||||
* 记录已经处理到的位置
|
||||
*/
|
||||
int handledPosition = 0;
|
||||
|
||||
return sbuf.toString();
|
||||
}
|
||||
/**
|
||||
* 占位符所在位置
|
||||
*/
|
||||
int delimIndex;
|
||||
for (int argIndex = 0; argIndex < argArray.length; argIndex++) {
|
||||
delimIndex = strPattern.indexOf(StringPool.EMPTY_JSON, handledPosition);
|
||||
/**
|
||||
* 剩余部分无占位符
|
||||
*/
|
||||
if (delimIndex == -1) {
|
||||
/**
|
||||
* 不带占位符的模板直接返回
|
||||
*/
|
||||
if (handledPosition == 0) {
|
||||
return strPattern;
|
||||
} else {
|
||||
sbuf.append(strPattern, handledPosition, strPatternLength);
|
||||
return sbuf.toString();
|
||||
}
|
||||
} else {
|
||||
/**
|
||||
* 转义符
|
||||
*/
|
||||
if (delimIndex > 0 && strPattern.charAt(delimIndex - 1) == StringPool.BACK_SLASH) {
|
||||
/**
|
||||
* 双转义符
|
||||
*/
|
||||
if (delimIndex > 1 && strPattern.charAt(delimIndex - 2) == StringPool.BACK_SLASH) {
|
||||
//转义符之前还有一个转义符,占位符依旧有效
|
||||
sbuf.append(strPattern, handledPosition, delimIndex - 1);
|
||||
sbuf.append(Func.toStr(argArray[argIndex]));
|
||||
handledPosition = delimIndex + 2;
|
||||
} else {
|
||||
//占位符被转义
|
||||
argIndex--;
|
||||
sbuf.append(strPattern, handledPosition, delimIndex - 1);
|
||||
sbuf.append(StringPool.LEFT_BRACE);
|
||||
handledPosition = delimIndex + 1;
|
||||
}
|
||||
} else {//正常占位符
|
||||
sbuf.append(strPattern, handledPosition, delimIndex);
|
||||
sbuf.append(Func.toStr(argArray[argIndex]));
|
||||
handledPosition = delimIndex + 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
// append the characters following the last {} pair.
|
||||
//加入最后一个占位符后所有的字符
|
||||
sbuf.append(strPattern, handledPosition, strPattern.length());
|
||||
|
||||
return sbuf.toString();
|
||||
}
|
||||
}
|
||||
|
@ -11,489 +11,494 @@ import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* 字符串切分器
|
||||
* @author Looly
|
||||
*
|
||||
* @author Looly
|
||||
*/
|
||||
public class StrSpliter {
|
||||
|
||||
//---------------------------------------------------------------------------------------------- Split by char
|
||||
/**
|
||||
* 切分字符串路径,仅支持Unix分界符:/
|
||||
*
|
||||
* @param str 被切分的字符串
|
||||
* @return 切分后的集合
|
||||
* @since 3.0.8
|
||||
*/
|
||||
public static List<String> splitPath(String str){
|
||||
return splitPath(str, 0);
|
||||
}
|
||||
//---------------------------------------------------------------------------------------------- Split by char
|
||||
|
||||
/**
|
||||
* 切分字符串路径,仅支持Unix分界符:/
|
||||
*
|
||||
* @param str 被切分的字符串
|
||||
* @return 切分后的集合
|
||||
* @since 3.0.8
|
||||
*/
|
||||
public static String[] splitPathToArray(String str){
|
||||
return toArray(splitPath(str));
|
||||
}
|
||||
/**
|
||||
* 切分字符串路径,仅支持Unix分界符:/
|
||||
*
|
||||
* @param str 被切分的字符串
|
||||
* @return 切分后的集合
|
||||
* @since 3.0.8
|
||||
*/
|
||||
public static List<String> splitPath(String str) {
|
||||
return splitPath(str, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 切分字符串路径,仅支持Unix分界符:/
|
||||
*
|
||||
* @param str 被切分的字符串
|
||||
* @param limit 限制分片数
|
||||
* @return 切分后的集合
|
||||
* @since 3.0.8
|
||||
*/
|
||||
public static List<String> splitPath(String str, int limit){
|
||||
return split(str, StringPool.SLASH, limit, true, true);
|
||||
}
|
||||
/**
|
||||
* 切分字符串路径,仅支持Unix分界符:/
|
||||
*
|
||||
* @param str 被切分的字符串
|
||||
* @return 切分后的集合
|
||||
* @since 3.0.8
|
||||
*/
|
||||
public static String[] splitPathToArray(String str) {
|
||||
return toArray(splitPath(str));
|
||||
}
|
||||
|
||||
/**
|
||||
* 切分字符串路径,仅支持Unix分界符:/
|
||||
*
|
||||
* @param str 被切分的字符串
|
||||
* @param limit 限制分片数
|
||||
* @return 切分后的集合
|
||||
* @since 3.0.8
|
||||
*/
|
||||
public static String[] splitPathToArray(String str, int limit){
|
||||
return toArray(splitPath(str, limit));
|
||||
}
|
||||
/**
|
||||
* 切分字符串路径,仅支持Unix分界符:/
|
||||
*
|
||||
* @param str 被切分的字符串
|
||||
* @param limit 限制分片数
|
||||
* @return 切分后的集合
|
||||
* @since 3.0.8
|
||||
*/
|
||||
public static List<String> splitPath(String str, int limit) {
|
||||
return split(str, StringPool.SLASH, limit, true, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 切分字符串
|
||||
*
|
||||
* @param str 被切分的字符串
|
||||
* @param separator 分隔符字符
|
||||
* @param ignoreEmpty 是否忽略空串
|
||||
* @return 切分后的集合
|
||||
* @since 3.2.1
|
||||
*/
|
||||
public static List<String> splitTrim(String str, char separator, boolean ignoreEmpty){
|
||||
return split(str, separator, 0, true, ignoreEmpty);
|
||||
}
|
||||
/**
|
||||
* 切分字符串路径,仅支持Unix分界符:/
|
||||
*
|
||||
* @param str 被切分的字符串
|
||||
* @param limit 限制分片数
|
||||
* @return 切分后的集合
|
||||
* @since 3.0.8
|
||||
*/
|
||||
public static String[] splitPathToArray(String str, int limit) {
|
||||
return toArray(splitPath(str, limit));
|
||||
}
|
||||
|
||||
/**
|
||||
* 切分字符串
|
||||
*
|
||||
* @param str 被切分的字符串
|
||||
* @param separator 分隔符字符
|
||||
* @param isTrim 是否去除切分字符串后每个元素两边的空格
|
||||
* @param ignoreEmpty 是否忽略空串
|
||||
* @return 切分后的集合
|
||||
* @since 3.0.8
|
||||
*/
|
||||
public static List<String> split(String str, char separator, boolean isTrim, boolean ignoreEmpty){
|
||||
return split(str, separator, 0, isTrim, ignoreEmpty);
|
||||
}
|
||||
/**
|
||||
* 切分字符串
|
||||
*
|
||||
* @param str 被切分的字符串
|
||||
* @param separator 分隔符字符
|
||||
* @param ignoreEmpty 是否忽略空串
|
||||
* @return 切分后的集合
|
||||
* @since 3.2.1
|
||||
*/
|
||||
public static List<String> splitTrim(String str, char separator, boolean ignoreEmpty) {
|
||||
return split(str, separator, 0, true, ignoreEmpty);
|
||||
}
|
||||
|
||||
/**
|
||||
* 切分字符串,大小写敏感,去除每个元素两边空白符
|
||||
*
|
||||
* @param str 被切分的字符串
|
||||
* @param separator 分隔符字符
|
||||
* @param limit 限制分片数,-1不限制
|
||||
* @param ignoreEmpty 是否忽略空串
|
||||
* @return 切分后的集合
|
||||
* @since 3.0.8
|
||||
*/
|
||||
public static List<String> splitTrim(String str, char separator, int limit, boolean ignoreEmpty){
|
||||
return split(str, separator, limit, true, ignoreEmpty, false);
|
||||
}
|
||||
/**
|
||||
* 切分字符串
|
||||
*
|
||||
* @param str 被切分的字符串
|
||||
* @param separator 分隔符字符
|
||||
* @param isTrim 是否去除切分字符串后每个元素两边的空格
|
||||
* @param ignoreEmpty 是否忽略空串
|
||||
* @return 切分后的集合
|
||||
* @since 3.0.8
|
||||
*/
|
||||
public static List<String> split(String str, char separator, boolean isTrim, boolean ignoreEmpty) {
|
||||
return split(str, separator, 0, isTrim, ignoreEmpty);
|
||||
}
|
||||
|
||||
/**
|
||||
* 切分字符串,大小写敏感
|
||||
*
|
||||
* @param str 被切分的字符串
|
||||
* @param separator 分隔符字符
|
||||
* @param limit 限制分片数,-1不限制
|
||||
* @param isTrim 是否去除切分字符串后每个元素两边的空格
|
||||
* @param ignoreEmpty 是否忽略空串
|
||||
* @return 切分后的集合
|
||||
* @since 3.0.8
|
||||
*/
|
||||
public static List<String> split(String str, char separator, int limit, boolean isTrim, boolean ignoreEmpty){
|
||||
return split(str, separator, limit, isTrim, ignoreEmpty, false);
|
||||
}
|
||||
/**
|
||||
* 切分字符串,大小写敏感,去除每个元素两边空白符
|
||||
*
|
||||
* @param str 被切分的字符串
|
||||
* @param separator 分隔符字符
|
||||
* @param limit 限制分片数,-1不限制
|
||||
* @param ignoreEmpty 是否忽略空串
|
||||
* @return 切分后的集合
|
||||
* @since 3.0.8
|
||||
*/
|
||||
public static List<String> splitTrim(String str, char separator, int limit, boolean ignoreEmpty) {
|
||||
return split(str, separator, limit, true, ignoreEmpty, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 切分字符串,忽略大小写
|
||||
*
|
||||
* @param str 被切分的字符串
|
||||
* @param separator 分隔符字符
|
||||
* @param limit 限制分片数,-1不限制
|
||||
* @param isTrim 是否去除切分字符串后每个元素两边的空格
|
||||
* @param ignoreEmpty 是否忽略空串
|
||||
* @return 切分后的集合
|
||||
* @since 3.2.1
|
||||
*/
|
||||
public static List<String> splitIgnoreCase(String str, char separator, int limit, boolean isTrim, boolean ignoreEmpty){
|
||||
return split(str, separator, limit, isTrim, ignoreEmpty, true);
|
||||
}
|
||||
/**
|
||||
* 切分字符串,大小写敏感
|
||||
*
|
||||
* @param str 被切分的字符串
|
||||
* @param separator 分隔符字符
|
||||
* @param limit 限制分片数,-1不限制
|
||||
* @param isTrim 是否去除切分字符串后每个元素两边的空格
|
||||
* @param ignoreEmpty 是否忽略空串
|
||||
* @return 切分后的集合
|
||||
* @since 3.0.8
|
||||
*/
|
||||
public static List<String> split(String str, char separator, int limit, boolean isTrim, boolean ignoreEmpty) {
|
||||
return split(str, separator, limit, isTrim, ignoreEmpty, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 切分字符串
|
||||
*
|
||||
* @param str 被切分的字符串
|
||||
* @param separator 分隔符字符
|
||||
* @param limit 限制分片数,-1不限制
|
||||
* @param isTrim 是否去除切分字符串后每个元素两边的空格
|
||||
* @param ignoreEmpty 是否忽略空串
|
||||
* @param ignoreCase 是否忽略大小写
|
||||
* @return 切分后的集合
|
||||
* @since 3.2.1
|
||||
*/
|
||||
public static List<String> split(String str, char separator, int limit, boolean isTrim, boolean ignoreEmpty, boolean ignoreCase){
|
||||
if(StringUtil.isEmpty(str)){
|
||||
return new ArrayList<String>(0);
|
||||
}
|
||||
if(limit == 1){
|
||||
return addToList(new ArrayList<String>(1), str, isTrim, ignoreEmpty);
|
||||
}
|
||||
/**
|
||||
* 切分字符串,忽略大小写
|
||||
*
|
||||
* @param str 被切分的字符串
|
||||
* @param separator 分隔符字符
|
||||
* @param limit 限制分片数,-1不限制
|
||||
* @param isTrim 是否去除切分字符串后每个元素两边的空格
|
||||
* @param ignoreEmpty 是否忽略空串
|
||||
* @return 切分后的集合
|
||||
* @since 3.2.1
|
||||
*/
|
||||
public static List<String> splitIgnoreCase(String str, char separator, int limit, boolean isTrim, boolean ignoreEmpty) {
|
||||
return split(str, separator, limit, isTrim, ignoreEmpty, true);
|
||||
}
|
||||
|
||||
final ArrayList<String> list = new ArrayList<>(limit > 0 ? limit : 16);
|
||||
int len = str.length();
|
||||
int start = 0;//切分后每个部分的起始
|
||||
for(int i = 0; i < len; i++){
|
||||
if(Func.equals(separator, str.charAt(i))){
|
||||
addToList(list, str.substring(start, i), isTrim, ignoreEmpty);
|
||||
start = i+1;//i+1同时将start与i保持一致
|
||||
/**
|
||||
* 切分字符串
|
||||
*
|
||||
* @param str 被切分的字符串
|
||||
* @param separator 分隔符字符
|
||||
* @param limit 限制分片数,-1不限制
|
||||
* @param isTrim 是否去除切分字符串后每个元素两边的空格
|
||||
* @param ignoreEmpty 是否忽略空串
|
||||
* @param ignoreCase 是否忽略大小写
|
||||
* @return 切分后的集合
|
||||
* @since 3.2.1
|
||||
*/
|
||||
public static List<String> split(String str, char separator, int limit, boolean isTrim, boolean ignoreEmpty, boolean ignoreCase) {
|
||||
if (StringUtil.isEmpty(str)) {
|
||||
return new ArrayList<String>(0);
|
||||
}
|
||||
if (limit == 1) {
|
||||
return addToList(new ArrayList<String>(1), str, isTrim, ignoreEmpty);
|
||||
}
|
||||
|
||||
//检查是否超出范围(最大允许limit-1个,剩下一个留给末尾字符串)
|
||||
if(limit > 0 && list.size() > limit-2){
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return addToList(list, str.substring(start, len), isTrim, ignoreEmpty);//收尾
|
||||
}
|
||||
final ArrayList<String> list = new ArrayList<>(limit > 0 ? limit : 16);
|
||||
int len = str.length();
|
||||
int start = 0;//切分后每个部分的起始
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (Func.equals(separator, str.charAt(i))) {
|
||||
addToList(list, str.substring(start, i), isTrim, ignoreEmpty);
|
||||
start = i + 1;//i+1同时将start与i保持一致
|
||||
|
||||
/**
|
||||
* 切分字符串为字符串数组
|
||||
*
|
||||
* @param str 被切分的字符串
|
||||
* @param separator 分隔符字符
|
||||
* @param limit 限制分片数
|
||||
* @param isTrim 是否去除切分字符串后每个元素两边的空格
|
||||
* @param ignoreEmpty 是否忽略空串
|
||||
* @return 切分后的集合
|
||||
* @since 3.0.8
|
||||
*/
|
||||
public static String[] splitToArray(String str, char separator, int limit, boolean isTrim, boolean ignoreEmpty){
|
||||
return toArray(split(str, separator, limit, isTrim, ignoreEmpty));
|
||||
}
|
||||
//检查是否超出范围(最大允许limit-1个,剩下一个留给末尾字符串)
|
||||
if (limit > 0 && list.size() > limit - 2) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return addToList(list, str.substring(start, len), isTrim, ignoreEmpty);//收尾
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------- Split by String
|
||||
/**
|
||||
* 切分字符串为字符串数组
|
||||
*
|
||||
* @param str 被切分的字符串
|
||||
* @param separator 分隔符字符
|
||||
* @param limit 限制分片数
|
||||
* @param isTrim 是否去除切分字符串后每个元素两边的空格
|
||||
* @param ignoreEmpty 是否忽略空串
|
||||
* @return 切分后的集合
|
||||
* @since 3.0.8
|
||||
*/
|
||||
public static String[] splitToArray(String str, char separator, int limit, boolean isTrim, boolean ignoreEmpty) {
|
||||
return toArray(split(str, separator, limit, isTrim, ignoreEmpty));
|
||||
}
|
||||
|
||||
/**
|
||||
* 切分字符串,不忽略大小写
|
||||
*
|
||||
* @param str 被切分的字符串
|
||||
* @param separator 分隔符字符串
|
||||
* @param isTrim 是否去除切分字符串后每个元素两边的空格
|
||||
* @param ignoreEmpty 是否忽略空串
|
||||
* @return 切分后的集合
|
||||
* @since 3.0.8
|
||||
*/
|
||||
public static List<String> split(String str, String separator, boolean isTrim, boolean ignoreEmpty){
|
||||
return split(str, separator, -1, isTrim, ignoreEmpty, false);
|
||||
}
|
||||
//---------------------------------------------------------------------------------------------- Split by String
|
||||
|
||||
/**
|
||||
* 切分字符串,去除每个元素两边空格,忽略大小写
|
||||
*
|
||||
* @param str 被切分的字符串
|
||||
* @param separator 分隔符字符串
|
||||
* @param ignoreEmpty 是否忽略空串
|
||||
* @return 切分后的集合
|
||||
* @since 3.2.1
|
||||
*/
|
||||
public static List<String> splitTrim(String str, String separator, boolean ignoreEmpty){
|
||||
return split(str, separator, true, ignoreEmpty);
|
||||
}
|
||||
/**
|
||||
* 切分字符串,不忽略大小写
|
||||
*
|
||||
* @param str 被切分的字符串
|
||||
* @param separator 分隔符字符串
|
||||
* @param isTrim 是否去除切分字符串后每个元素两边的空格
|
||||
* @param ignoreEmpty 是否忽略空串
|
||||
* @return 切分后的集合
|
||||
* @since 3.0.8
|
||||
*/
|
||||
public static List<String> split(String str, String separator, boolean isTrim, boolean ignoreEmpty) {
|
||||
return split(str, separator, -1, isTrim, ignoreEmpty, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 切分字符串,不忽略大小写
|
||||
*
|
||||
* @param str 被切分的字符串
|
||||
* @param separator 分隔符字符串
|
||||
* @param limit 限制分片数
|
||||
* @param isTrim 是否去除切分字符串后每个元素两边的空格
|
||||
* @param ignoreEmpty 是否忽略空串
|
||||
* @return 切分后的集合
|
||||
* @since 3.0.8
|
||||
*/
|
||||
public static List<String> split(String str, String separator, int limit, boolean isTrim, boolean ignoreEmpty){
|
||||
return split(str, separator, limit, isTrim, ignoreEmpty, false);
|
||||
}
|
||||
/**
|
||||
* 切分字符串,去除每个元素两边空格,忽略大小写
|
||||
*
|
||||
* @param str 被切分的字符串
|
||||
* @param separator 分隔符字符串
|
||||
* @param ignoreEmpty 是否忽略空串
|
||||
* @return 切分后的集合
|
||||
* @since 3.2.1
|
||||
*/
|
||||
public static List<String> splitTrim(String str, String separator, boolean ignoreEmpty) {
|
||||
return split(str, separator, true, ignoreEmpty);
|
||||
}
|
||||
|
||||
/**
|
||||
* 切分字符串,去除每个元素两边空格,忽略大小写
|
||||
*
|
||||
* @param str 被切分的字符串
|
||||
* @param separator 分隔符字符串
|
||||
* @param limit 限制分片数
|
||||
* @param ignoreEmpty 是否忽略空串
|
||||
* @return 切分后的集合
|
||||
* @since 3.2.1
|
||||
*/
|
||||
public static List<String> splitTrim(String str, String separator, int limit, boolean ignoreEmpty){
|
||||
return split(str, separator, limit, true, ignoreEmpty);
|
||||
}
|
||||
/**
|
||||
* 切分字符串,不忽略大小写
|
||||
*
|
||||
* @param str 被切分的字符串
|
||||
* @param separator 分隔符字符串
|
||||
* @param limit 限制分片数
|
||||
* @param isTrim 是否去除切分字符串后每个元素两边的空格
|
||||
* @param ignoreEmpty 是否忽略空串
|
||||
* @return 切分后的集合
|
||||
* @since 3.0.8
|
||||
*/
|
||||
public static List<String> split(String str, String separator, int limit, boolean isTrim, boolean ignoreEmpty) {
|
||||
return split(str, separator, limit, isTrim, ignoreEmpty, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 切分字符串,忽略大小写
|
||||
*
|
||||
* @param str 被切分的字符串
|
||||
* @param separator 分隔符字符串
|
||||
* @param limit 限制分片数
|
||||
* @param isTrim 是否去除切分字符串后每个元素两边的空格
|
||||
* @param ignoreEmpty 是否忽略空串
|
||||
* @return 切分后的集合
|
||||
* @since 3.2.1
|
||||
*/
|
||||
public static List<String> splitIgnoreCase(String str, String separator, int limit, boolean isTrim, boolean ignoreEmpty){
|
||||
return split(str, separator, limit, isTrim, ignoreEmpty, true);
|
||||
}
|
||||
/**
|
||||
* 切分字符串,去除每个元素两边空格,忽略大小写
|
||||
*
|
||||
* @param str 被切分的字符串
|
||||
* @param separator 分隔符字符串
|
||||
* @param limit 限制分片数
|
||||
* @param ignoreEmpty 是否忽略空串
|
||||
* @return 切分后的集合
|
||||
* @since 3.2.1
|
||||
*/
|
||||
public static List<String> splitTrim(String str, String separator, int limit, boolean ignoreEmpty) {
|
||||
return split(str, separator, limit, true, ignoreEmpty);
|
||||
}
|
||||
|
||||
/**
|
||||
* 切分字符串,去除每个元素两边空格,忽略大小写
|
||||
*
|
||||
* @param str 被切分的字符串
|
||||
* @param separator 分隔符字符串
|
||||
* @param limit 限制分片数
|
||||
* @param ignoreEmpty 是否忽略空串
|
||||
* @return 切分后的集合
|
||||
* @since 3.2.1
|
||||
*/
|
||||
public static List<String> splitTrimIgnoreCase(String str, String separator, int limit, boolean ignoreEmpty){
|
||||
return split(str, separator, limit, true, ignoreEmpty, true);
|
||||
}
|
||||
/**
|
||||
* 切分字符串,忽略大小写
|
||||
*
|
||||
* @param str 被切分的字符串
|
||||
* @param separator 分隔符字符串
|
||||
* @param limit 限制分片数
|
||||
* @param isTrim 是否去除切分字符串后每个元素两边的空格
|
||||
* @param ignoreEmpty 是否忽略空串
|
||||
* @return 切分后的集合
|
||||
* @since 3.2.1
|
||||
*/
|
||||
public static List<String> splitIgnoreCase(String str, String separator, int limit, boolean isTrim, boolean ignoreEmpty) {
|
||||
return split(str, separator, limit, isTrim, ignoreEmpty, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 切分字符串
|
||||
*
|
||||
* @param str 被切分的字符串
|
||||
* @param separator 分隔符字符串
|
||||
* @param limit 限制分片数
|
||||
* @param isTrim 是否去除切分字符串后每个元素两边的空格
|
||||
* @param ignoreEmpty 是否忽略空串
|
||||
* @param ignoreCase 是否忽略大小写
|
||||
* @return 切分后的集合
|
||||
* @since 3.2.1
|
||||
*/
|
||||
public static List<String> split(String str, String separator, int limit, boolean isTrim, boolean ignoreEmpty, boolean ignoreCase){
|
||||
if(StringUtil.isEmpty(str)){
|
||||
return new ArrayList<String>(0);
|
||||
}
|
||||
if(limit == 1){
|
||||
return addToList(new ArrayList<String>(1), str, isTrim, ignoreEmpty);
|
||||
}
|
||||
/**
|
||||
* 切分字符串,去除每个元素两边空格,忽略大小写
|
||||
*
|
||||
* @param str 被切分的字符串
|
||||
* @param separator 分隔符字符串
|
||||
* @param limit 限制分片数
|
||||
* @param ignoreEmpty 是否忽略空串
|
||||
* @return 切分后的集合
|
||||
* @since 3.2.1
|
||||
*/
|
||||
public static List<String> splitTrimIgnoreCase(String str, String separator, int limit, boolean ignoreEmpty) {
|
||||
return split(str, separator, limit, true, ignoreEmpty, true);
|
||||
}
|
||||
|
||||
if(StringUtil.isEmpty(separator)){//分隔符为空时按照空白符切分
|
||||
return split(str, limit);
|
||||
}else if(separator.length() == 1){//分隔符只有一个字符长度时按照单分隔符切分
|
||||
return split(str, separator.charAt(0), limit, isTrim, ignoreEmpty, ignoreCase);
|
||||
}
|
||||
/**
|
||||
* 切分字符串
|
||||
*
|
||||
* @param str 被切分的字符串
|
||||
* @param separator 分隔符字符串
|
||||
* @param limit 限制分片数
|
||||
* @param isTrim 是否去除切分字符串后每个元素两边的空格
|
||||
* @param ignoreEmpty 是否忽略空串
|
||||
* @param ignoreCase 是否忽略大小写
|
||||
* @return 切分后的集合
|
||||
* @since 3.2.1
|
||||
*/
|
||||
public static List<String> split(String str, String separator, int limit, boolean isTrim, boolean ignoreEmpty, boolean ignoreCase) {
|
||||
if (StringUtil.isEmpty(str)) {
|
||||
return new ArrayList<String>(0);
|
||||
}
|
||||
if (limit == 1) {
|
||||
return addToList(new ArrayList<String>(1), str, isTrim, ignoreEmpty);
|
||||
}
|
||||
|
||||
final ArrayList<String> list = new ArrayList<>();
|
||||
int len = str.length();
|
||||
int separatorLen = separator.length();
|
||||
int start = 0;
|
||||
int i = 0;
|
||||
while(i < len){
|
||||
i = StringUtil.indexOf(str, separator, start, ignoreCase);
|
||||
if(i > -1){
|
||||
addToList(list, str.substring(start, i), isTrim, ignoreEmpty);
|
||||
start = i + separatorLen;
|
||||
if (StringUtil.isEmpty(separator)) {//分隔符为空时按照空白符切分
|
||||
return split(str, limit);
|
||||
} else if (separator.length() == 1) {//分隔符只有一个字符长度时按照单分隔符切分
|
||||
return split(str, separator.charAt(0), limit, isTrim, ignoreEmpty, ignoreCase);
|
||||
}
|
||||
|
||||
//检查是否超出范围(最大允许limit-1个,剩下一个留给末尾字符串)
|
||||
if(limit > 0 && list.size() > limit-2){
|
||||
break;
|
||||
}
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return addToList(list, str.substring(start, len), isTrim, ignoreEmpty);
|
||||
}
|
||||
final ArrayList<String> list = new ArrayList<>();
|
||||
int len = str.length();
|
||||
int separatorLen = separator.length();
|
||||
int start = 0;
|
||||
int i = 0;
|
||||
while (i < len) {
|
||||
i = StringUtil.indexOf(str, separator, start, ignoreCase);
|
||||
if (i > -1) {
|
||||
addToList(list, str.substring(start, i), isTrim, ignoreEmpty);
|
||||
start = i + separatorLen;
|
||||
|
||||
/**
|
||||
* 切分字符串为字符串数组
|
||||
*
|
||||
* @param str 被切分的字符串
|
||||
* @param separator 分隔符字符
|
||||
* @param limit 限制分片数
|
||||
* @param isTrim 是否去除切分字符串后每个元素两边的空格
|
||||
* @param ignoreEmpty 是否忽略空串
|
||||
* @return 切分后的集合
|
||||
* @since 3.0.8
|
||||
*/
|
||||
public static String[] splitToArray(String str, String separator, int limit, boolean isTrim, boolean ignoreEmpty){
|
||||
return toArray(split(str, separator, limit, isTrim, ignoreEmpty));
|
||||
}
|
||||
//检查是否超出范围(最大允许limit-1个,剩下一个留给末尾字符串)
|
||||
if (limit > 0 && list.size() > limit - 2) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return addToList(list, str.substring(start, len), isTrim, ignoreEmpty);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------- Split by Whitespace
|
||||
/**
|
||||
* 切分字符串为字符串数组
|
||||
*
|
||||
* @param str 被切分的字符串
|
||||
* @param separator 分隔符字符
|
||||
* @param limit 限制分片数
|
||||
* @param isTrim 是否去除切分字符串后每个元素两边的空格
|
||||
* @param ignoreEmpty 是否忽略空串
|
||||
* @return 切分后的集合
|
||||
* @since 3.0.8
|
||||
*/
|
||||
public static String[] splitToArray(String str, String separator, int limit, boolean isTrim, boolean ignoreEmpty) {
|
||||
return toArray(split(str, separator, limit, isTrim, ignoreEmpty));
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用空白符切分字符串<br>
|
||||
* 切分后的字符串两边不包含空白符,空串或空白符串并不做为元素之一
|
||||
*
|
||||
* @param str 被切分的字符串
|
||||
* @param limit 限制分片数
|
||||
* @return 切分后的集合
|
||||
* @since 3.0.8
|
||||
*/
|
||||
public static List<String> split(String str, int limit){
|
||||
if(StringUtil.isEmpty(str)){
|
||||
return new ArrayList<String>(0);
|
||||
}
|
||||
if(limit == 1){
|
||||
return addToList(new ArrayList<String>(1), str, true, true);
|
||||
}
|
||||
//---------------------------------------------------------------------------------------------- Split by Whitespace
|
||||
|
||||
final ArrayList<String> list = new ArrayList<>();
|
||||
int len = str.length();
|
||||
int start = 0;//切分后每个部分的起始
|
||||
for(int i = 0; i < len; i++){
|
||||
if(Func.isEmpty(str.charAt(i))){
|
||||
addToList(list, str.substring(start, i), true, true);
|
||||
start = i+1;//i+1同时将start与i保持一致
|
||||
/**
|
||||
* 使用空白符切分字符串<br>
|
||||
* 切分后的字符串两边不包含空白符,空串或空白符串并不做为元素之一
|
||||
*
|
||||
* @param str 被切分的字符串
|
||||
* @param limit 限制分片数
|
||||
* @return 切分后的集合
|
||||
* @since 3.0.8
|
||||
*/
|
||||
public static List<String> split(String str, int limit) {
|
||||
if (StringUtil.isEmpty(str)) {
|
||||
return new ArrayList<String>(0);
|
||||
}
|
||||
if (limit == 1) {
|
||||
return addToList(new ArrayList<String>(1), str, true, true);
|
||||
}
|
||||
|
||||
//检查是否超出范围(最大允许limit-1个,剩下一个留给末尾字符串)
|
||||
if(limit > 0 && list.size() > limit-2){
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return addToList(list, str.substring(start, len), true, true);//收尾
|
||||
}
|
||||
final ArrayList<String> list = new ArrayList<>();
|
||||
int len = str.length();
|
||||
int start = 0;//切分后每个部分的起始
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (Func.isEmpty(str.charAt(i))) {
|
||||
addToList(list, str.substring(start, i), true, true);
|
||||
start = i + 1;//i+1同时将start与i保持一致
|
||||
|
||||
/**
|
||||
* 切分字符串为字符串数组
|
||||
*
|
||||
* @param str 被切分的字符串
|
||||
* @param limit 限制分片数
|
||||
* @return 切分后的集合
|
||||
* @since 3.0.8
|
||||
*/
|
||||
public static String[] splitToArray(String str, int limit){
|
||||
return toArray(split(str, limit));
|
||||
}
|
||||
//检查是否超出范围(最大允许limit-1个,剩下一个留给末尾字符串)
|
||||
if (limit > 0 && list.size() > limit - 2) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return addToList(list, str.substring(start, len), true, true);//收尾
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------- Split by regex
|
||||
/**
|
||||
* 切分字符串为字符串数组
|
||||
*
|
||||
* @param str 被切分的字符串
|
||||
* @param limit 限制分片数
|
||||
* @return 切分后的集合
|
||||
* @since 3.0.8
|
||||
*/
|
||||
public static String[] splitToArray(String str, int limit) {
|
||||
return toArray(split(str, limit));
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过正则切分字符串
|
||||
* @param str 字符串
|
||||
* @param separatorPattern 分隔符正则{@link Pattern}
|
||||
* @param limit 限制分片数
|
||||
* @param isTrim 是否去除切分字符串后每个元素两边的空格
|
||||
* @param ignoreEmpty 是否忽略空串
|
||||
* @return 切分后的集合
|
||||
* @since 3.0.8
|
||||
*/
|
||||
public static List<String> split(String str, Pattern separatorPattern, int limit, boolean isTrim, boolean ignoreEmpty){
|
||||
if(StringUtil.isEmpty(str)){
|
||||
return new ArrayList<String>(0);
|
||||
}
|
||||
if(limit == 1){
|
||||
return addToList(new ArrayList<String>(1), str, isTrim, ignoreEmpty);
|
||||
}
|
||||
//---------------------------------------------------------------------------------------------- Split by regex
|
||||
|
||||
if(null == separatorPattern){//分隔符为空时按照空白符切分
|
||||
return split(str, limit);
|
||||
}
|
||||
/**
|
||||
* 通过正则切分字符串
|
||||
*
|
||||
* @param str 字符串
|
||||
* @param separatorPattern 分隔符正则{@link Pattern}
|
||||
* @param limit 限制分片数
|
||||
* @param isTrim 是否去除切分字符串后每个元素两边的空格
|
||||
* @param ignoreEmpty 是否忽略空串
|
||||
* @return 切分后的集合
|
||||
* @since 3.0.8
|
||||
*/
|
||||
public static List<String> split(String str, Pattern separatorPattern, int limit, boolean isTrim, boolean ignoreEmpty) {
|
||||
if (StringUtil.isEmpty(str)) {
|
||||
return new ArrayList<String>(0);
|
||||
}
|
||||
if (limit == 1) {
|
||||
return addToList(new ArrayList<String>(1), str, isTrim, ignoreEmpty);
|
||||
}
|
||||
|
||||
final Matcher matcher = separatorPattern.matcher(str);
|
||||
final ArrayList<String> list = new ArrayList<>();
|
||||
int len = str.length();
|
||||
int start = 0;
|
||||
while(matcher.find()){
|
||||
addToList(list, str.substring(start, matcher.start()), isTrim, ignoreEmpty);
|
||||
start = matcher.end();
|
||||
if (null == separatorPattern) {//分隔符为空时按照空白符切分
|
||||
return split(str, limit);
|
||||
}
|
||||
|
||||
//检查是否超出范围(最大允许limit-1个,剩下一个留给末尾字符串)
|
||||
if(limit > 0 && list.size() > limit-2){
|
||||
break;
|
||||
}
|
||||
}
|
||||
return addToList(list, str.substring(start, len), isTrim, ignoreEmpty);
|
||||
}
|
||||
final Matcher matcher = separatorPattern.matcher(str);
|
||||
final ArrayList<String> list = new ArrayList<>();
|
||||
int len = str.length();
|
||||
int start = 0;
|
||||
while (matcher.find()) {
|
||||
addToList(list, str.substring(start, matcher.start()), isTrim, ignoreEmpty);
|
||||
start = matcher.end();
|
||||
|
||||
/**
|
||||
* 通过正则切分字符串为字符串数组
|
||||
*
|
||||
* @param str 被切分的字符串
|
||||
* @param separatorPattern 分隔符正则{@link Pattern}
|
||||
* @param limit 限制分片数
|
||||
* @param isTrim 是否去除切分字符串后每个元素两边的空格
|
||||
* @param ignoreEmpty 是否忽略空串
|
||||
* @return 切分后的集合
|
||||
* @since 3.0.8
|
||||
*/
|
||||
public static String[] splitToArray(String str, Pattern separatorPattern, int limit, boolean isTrim, boolean ignoreEmpty){
|
||||
return toArray(split(str, separatorPattern, limit, isTrim, ignoreEmpty));
|
||||
}
|
||||
//检查是否超出范围(最大允许limit-1个,剩下一个留给末尾字符串)
|
||||
if (limit > 0 && list.size() > limit - 2) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return addToList(list, str.substring(start, len), isTrim, ignoreEmpty);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------- Split by length
|
||||
/**
|
||||
* 通过正则切分字符串为字符串数组
|
||||
*
|
||||
* @param str 被切分的字符串
|
||||
* @param separatorPattern 分隔符正则{@link Pattern}
|
||||
* @param limit 限制分片数
|
||||
* @param isTrim 是否去除切分字符串后每个元素两边的空格
|
||||
* @param ignoreEmpty 是否忽略空串
|
||||
* @return 切分后的集合
|
||||
* @since 3.0.8
|
||||
*/
|
||||
public static String[] splitToArray(String str, Pattern separatorPattern, int limit, boolean isTrim, boolean ignoreEmpty) {
|
||||
return toArray(split(str, separatorPattern, limit, isTrim, ignoreEmpty));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据给定长度,将给定字符串截取为多个部分
|
||||
*
|
||||
* @param str 字符串
|
||||
* @param len 每一个小节的长度
|
||||
* @return 截取后的字符串数组
|
||||
*/
|
||||
public static String[] splitByLength(String str, int len) {
|
||||
int partCount = str.length() / len;
|
||||
int lastPartCount = str.length() % len;
|
||||
int fixPart = 0;
|
||||
if (lastPartCount != 0) {
|
||||
fixPart = 1;
|
||||
}
|
||||
//---------------------------------------------------------------------------------------------- Split by length
|
||||
|
||||
final String[] strs = new String[partCount + fixPart];
|
||||
for (int i = 0; i < partCount + fixPart; i++) {
|
||||
if (i == partCount + fixPart - 1 && lastPartCount != 0) {
|
||||
strs[i] = str.substring(i * len, i * len + lastPartCount);
|
||||
} else {
|
||||
strs[i] = str.substring(i * len, i * len + len);
|
||||
}
|
||||
}
|
||||
return strs;
|
||||
}
|
||||
/**
|
||||
* 根据给定长度,将给定字符串截取为多个部分
|
||||
*
|
||||
* @param str 字符串
|
||||
* @param len 每一个小节的长度
|
||||
* @return 截取后的字符串数组
|
||||
*/
|
||||
public static String[] splitByLength(String str, int len) {
|
||||
int partCount = str.length() / len;
|
||||
int lastPartCount = str.length() % len;
|
||||
int fixPart = 0;
|
||||
if (lastPartCount != 0) {
|
||||
fixPart = 1;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------- Private method start
|
||||
/**
|
||||
* 将字符串加入List中
|
||||
* @param list 列表
|
||||
* @param part 被加入的部分
|
||||
* @param isTrim 是否去除两端空白符
|
||||
* @param ignoreEmpty 是否略过空字符串(空字符串不做为一个元素)
|
||||
* @return 列表
|
||||
*/
|
||||
private static List<String> addToList(List<String> list, String part, boolean isTrim, boolean ignoreEmpty){
|
||||
part = part.toString();
|
||||
if(isTrim){
|
||||
part = part.trim();
|
||||
}
|
||||
if(false == ignoreEmpty || false == part.isEmpty()){
|
||||
list.add(part);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
final String[] strs = new String[partCount + fixPart];
|
||||
for (int i = 0; i < partCount + fixPart; i++) {
|
||||
if (i == partCount + fixPart - 1 && lastPartCount != 0) {
|
||||
strs[i] = str.substring(i * len, i * len + lastPartCount);
|
||||
} else {
|
||||
strs[i] = str.substring(i * len, i * len + len);
|
||||
}
|
||||
}
|
||||
return strs;
|
||||
}
|
||||
|
||||
/**
|
||||
* List转Array
|
||||
* @param list List
|
||||
* @return Array
|
||||
*/
|
||||
private static String[] toArray(List<String> list){
|
||||
return list.toArray(new String[list.size()]);
|
||||
}
|
||||
//---------------------------------------------------------------------------------------------------------- Private method end
|
||||
//---------------------------------------------------------------------------------------------------------- Private method start
|
||||
|
||||
/**
|
||||
* 将字符串加入List中
|
||||
*
|
||||
* @param list 列表
|
||||
* @param part 被加入的部分
|
||||
* @param isTrim 是否去除两端空白符
|
||||
* @param ignoreEmpty 是否略过空字符串(空字符串不做为一个元素)
|
||||
* @return 列表
|
||||
*/
|
||||
private static List<String> addToList(List<String> list, String part, boolean isTrim, boolean ignoreEmpty) {
|
||||
part = part.toString();
|
||||
if (isTrim) {
|
||||
part = part.trim();
|
||||
}
|
||||
if (false == ignoreEmpty || false == part.isEmpty()) {
|
||||
list.add(part);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* List转Array
|
||||
*
|
||||
* @param list List
|
||||
* @return Array
|
||||
*/
|
||||
private static String[] toArray(List<String> list) {
|
||||
return list.toArray(new String[list.size()]);
|
||||
}
|
||||
//---------------------------------------------------------------------------------------------------------- Private method end
|
||||
}
|
||||
|
@ -8,6 +8,8 @@ import java.util.function.Function;
|
||||
/**
|
||||
* 当 Lambda 遇上受检异常
|
||||
* https://segmentfault.com/a/1190000007832130
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
public class Try {
|
||||
|
||||
|
@ -41,514 +41,514 @@ import java.util.regex.Pattern;
|
||||
*/
|
||||
public final class HTMLFilter {
|
||||
|
||||
/**
|
||||
* regex flag union representing /si modifiers in php
|
||||
**/
|
||||
private static final int REGEX_FLAGS_SI = Pattern.CASE_INSENSITIVE | Pattern.DOTALL;
|
||||
private static final Pattern P_COMMENTS = Pattern.compile("<!--(.*?)-->", Pattern.DOTALL);
|
||||
private static final Pattern P_COMMENT = Pattern.compile("^!--(.*)--$", REGEX_FLAGS_SI);
|
||||
private static final Pattern P_TAGS = Pattern.compile("<(.*?)>", Pattern.DOTALL);
|
||||
private static final Pattern P_END_TAG = Pattern.compile("^/([a-z0-9]+)", REGEX_FLAGS_SI);
|
||||
private static final Pattern P_START_TAG = Pattern.compile("^([a-z0-9]+)(.*?)(/?)$", REGEX_FLAGS_SI);
|
||||
private static final Pattern P_QUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)=([\"'])(.*?)\\2", REGEX_FLAGS_SI);
|
||||
private static final Pattern P_UNQUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)(=)([^\"\\s']+)", REGEX_FLAGS_SI);
|
||||
private static final Pattern P_PROTOCOL = Pattern.compile("^([^:]+):", REGEX_FLAGS_SI);
|
||||
private static final Pattern P_ENTITY = Pattern.compile("&#(\\d+);?");
|
||||
private static final Pattern P_ENTITY_UNICODE = Pattern.compile("&#x([0-9a-f]+);?");
|
||||
private static final Pattern P_ENCODE = Pattern.compile("%([0-9a-f]{2});?");
|
||||
private static final Pattern P_VALID_ENTITIES = Pattern.compile("&([^&;]*)(?=(;|&|$))");
|
||||
private static final Pattern P_VALID_QUOTES = Pattern.compile("(>|^)([^<]+?)(<|$)", Pattern.DOTALL);
|
||||
private static final Pattern P_END_ARROW = Pattern.compile("^>");
|
||||
private static final Pattern P_BODY_TO_END = Pattern.compile("<([^>]*?)(?=<|$)");
|
||||
private static final Pattern P_XML_CONTENT = Pattern.compile("(^|>)([^<]*?)(?=>)");
|
||||
private static final Pattern P_STRAY_LEFT_ARROW = Pattern.compile("<([^>]*?)(?=<|$)");
|
||||
private static final Pattern P_STRAY_RIGHT_ARROW = Pattern.compile("(^|>)([^<]*?)(?=>)");
|
||||
private static final Pattern P_AMP = Pattern.compile("&");
|
||||
private static final Pattern P_QUOTE = Pattern.compile("<");
|
||||
private static final Pattern P_LEFT_ARROW = Pattern.compile("<");
|
||||
private static final Pattern P_RIGHT_ARROW = Pattern.compile(">");
|
||||
private static final Pattern P_BOTH_ARROWS = Pattern.compile("<>");
|
||||
/**
|
||||
* regex flag union representing /si modifiers in php
|
||||
**/
|
||||
private static final int REGEX_FLAGS_SI = Pattern.CASE_INSENSITIVE | Pattern.DOTALL;
|
||||
private static final Pattern P_COMMENTS = Pattern.compile("<!--(.*?)-->", Pattern.DOTALL);
|
||||
private static final Pattern P_COMMENT = Pattern.compile("^!--(.*)--$", REGEX_FLAGS_SI);
|
||||
private static final Pattern P_TAGS = Pattern.compile("<(.*?)>", Pattern.DOTALL);
|
||||
private static final Pattern P_END_TAG = Pattern.compile("^/([a-z0-9]+)", REGEX_FLAGS_SI);
|
||||
private static final Pattern P_START_TAG = Pattern.compile("^([a-z0-9]+)(.*?)(/?)$", REGEX_FLAGS_SI);
|
||||
private static final Pattern P_QUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)=([\"'])(.*?)\\2", REGEX_FLAGS_SI);
|
||||
private static final Pattern P_UNQUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)(=)([^\"\\s']+)", REGEX_FLAGS_SI);
|
||||
private static final Pattern P_PROTOCOL = Pattern.compile("^([^:]+):", REGEX_FLAGS_SI);
|
||||
private static final Pattern P_ENTITY = Pattern.compile("&#(\\d+);?");
|
||||
private static final Pattern P_ENTITY_UNICODE = Pattern.compile("&#x([0-9a-f]+);?");
|
||||
private static final Pattern P_ENCODE = Pattern.compile("%([0-9a-f]{2});?");
|
||||
private static final Pattern P_VALID_ENTITIES = Pattern.compile("&([^&;]*)(?=(;|&|$))");
|
||||
private static final Pattern P_VALID_QUOTES = Pattern.compile("(>|^)([^<]+?)(<|$)", Pattern.DOTALL);
|
||||
private static final Pattern P_END_ARROW = Pattern.compile("^>");
|
||||
private static final Pattern P_BODY_TO_END = Pattern.compile("<([^>]*?)(?=<|$)");
|
||||
private static final Pattern P_XML_CONTENT = Pattern.compile("(^|>)([^<]*?)(?=>)");
|
||||
private static final Pattern P_STRAY_LEFT_ARROW = Pattern.compile("<([^>]*?)(?=<|$)");
|
||||
private static final Pattern P_STRAY_RIGHT_ARROW = Pattern.compile("(^|>)([^<]*?)(?=>)");
|
||||
private static final Pattern P_AMP = Pattern.compile("&");
|
||||
private static final Pattern P_QUOTE = Pattern.compile("<");
|
||||
private static final Pattern P_LEFT_ARROW = Pattern.compile("<");
|
||||
private static final Pattern P_RIGHT_ARROW = Pattern.compile(">");
|
||||
private static final Pattern P_BOTH_ARROWS = Pattern.compile("<>");
|
||||
|
||||
// @xxx could grow large... maybe use sesat's ReferenceMap
|
||||
private static final ConcurrentMap<String, Pattern> P_REMOVE_PAIR_BLANKS = new ConcurrentHashMap<String, Pattern>();
|
||||
private static final ConcurrentMap<String, Pattern> P_REMOVE_SELF_BLANKS = new ConcurrentHashMap<String, Pattern>();
|
||||
// @xxx could grow large... maybe use sesat's ReferenceMap
|
||||
private static final ConcurrentMap<String, Pattern> P_REMOVE_PAIR_BLANKS = new ConcurrentHashMap<String, Pattern>();
|
||||
private static final ConcurrentMap<String, Pattern> P_REMOVE_SELF_BLANKS = new ConcurrentHashMap<String, Pattern>();
|
||||
|
||||
/**
|
||||
* set of allowed html elements, along with allowed attributes for each element
|
||||
**/
|
||||
private final Map<String, List<String>> vAllowed;
|
||||
/**
|
||||
* counts of open tags for each (allowable) html element
|
||||
**/
|
||||
private final Map<String, Integer> vTagCounts = new HashMap<String, Integer>();
|
||||
/**
|
||||
* set of allowed html elements, along with allowed attributes for each element
|
||||
**/
|
||||
private final Map<String, List<String>> vAllowed;
|
||||
/**
|
||||
* counts of open tags for each (allowable) html element
|
||||
**/
|
||||
private final Map<String, Integer> vTagCounts = new HashMap<String, Integer>();
|
||||
|
||||
/**
|
||||
* html elements which must always be self-closing (e.g. "<img />")
|
||||
**/
|
||||
private final String[] vSelfClosingTags;
|
||||
/**
|
||||
* html elements which must always have separate opening and closing tags (e.g. "<b></b>")
|
||||
**/
|
||||
private final String[] vNeedClosingTags;
|
||||
/**
|
||||
* set of disallowed html elements
|
||||
**/
|
||||
private final String[] vDisallowed;
|
||||
/**
|
||||
* attributes which should be checked for valid protocols
|
||||
**/
|
||||
private final String[] vProtocolAtts;
|
||||
/**
|
||||
* allowed protocols
|
||||
**/
|
||||
private final String[] vAllowedProtocols;
|
||||
/**
|
||||
* tags which should be removed if they contain no content (e.g. "<b></b>" or "<b />")
|
||||
**/
|
||||
private final String[] vRemoveBlanks;
|
||||
/**
|
||||
* entities allowed within html markup
|
||||
**/
|
||||
private final String[] vAllowedEntities;
|
||||
/**
|
||||
* flag determining whether comments are allowed in input String.
|
||||
*/
|
||||
private final boolean stripComment;
|
||||
private final boolean encodeQuotes;
|
||||
private boolean vDebug = false;
|
||||
/**
|
||||
* flag determining whether to try to make tags when presented with "unbalanced"
|
||||
* angle brackets (e.g. "<b text </b>" becomes "<b> text </b>"). If set to false,
|
||||
* unbalanced angle brackets will be html escaped.
|
||||
*/
|
||||
private final boolean alwaysMakeTags;
|
||||
/**
|
||||
* html elements which must always be self-closing (e.g. "<img />")
|
||||
**/
|
||||
private final String[] vSelfClosingTags;
|
||||
/**
|
||||
* html elements which must always have separate opening and closing tags (e.g. "<b></b>")
|
||||
**/
|
||||
private final String[] vNeedClosingTags;
|
||||
/**
|
||||
* set of disallowed html elements
|
||||
**/
|
||||
private final String[] vDisallowed;
|
||||
/**
|
||||
* attributes which should be checked for valid protocols
|
||||
**/
|
||||
private final String[] vProtocolAtts;
|
||||
/**
|
||||
* allowed protocols
|
||||
**/
|
||||
private final String[] vAllowedProtocols;
|
||||
/**
|
||||
* tags which should be removed if they contain no content (e.g. "<b></b>" or "<b />")
|
||||
**/
|
||||
private final String[] vRemoveBlanks;
|
||||
/**
|
||||
* entities allowed within html markup
|
||||
**/
|
||||
private final String[] vAllowedEntities;
|
||||
/**
|
||||
* flag determining whether comments are allowed in input String.
|
||||
*/
|
||||
private final boolean stripComment;
|
||||
private final boolean encodeQuotes;
|
||||
private boolean vDebug = false;
|
||||
/**
|
||||
* flag determining whether to try to make tags when presented with "unbalanced"
|
||||
* angle brackets (e.g. "<b text </b>" becomes "<b> text </b>"). If set to false,
|
||||
* unbalanced angle brackets will be html escaped.
|
||||
*/
|
||||
private final boolean alwaysMakeTags;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public HTMLFilter() {
|
||||
vAllowed = new HashMap<>();
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public HTMLFilter() {
|
||||
vAllowed = new HashMap<>();
|
||||
|
||||
final ArrayList<String> a_atts = new ArrayList<String>();
|
||||
a_atts.add("href");
|
||||
a_atts.add("target");
|
||||
vAllowed.put("a", a_atts);
|
||||
final ArrayList<String> a_atts = new ArrayList<String>();
|
||||
a_atts.add("href");
|
||||
a_atts.add("target");
|
||||
vAllowed.put("a", a_atts);
|
||||
|
||||
final ArrayList<String> img_atts = new ArrayList<String>();
|
||||
img_atts.add("src");
|
||||
img_atts.add("width");
|
||||
img_atts.add("height");
|
||||
img_atts.add("alt");
|
||||
vAllowed.put("img", img_atts);
|
||||
final ArrayList<String> img_atts = new ArrayList<String>();
|
||||
img_atts.add("src");
|
||||
img_atts.add("width");
|
||||
img_atts.add("height");
|
||||
img_atts.add("alt");
|
||||
vAllowed.put("img", img_atts);
|
||||
|
||||
final ArrayList<String> no_atts = new ArrayList<String>();
|
||||
vAllowed.put("b", no_atts);
|
||||
vAllowed.put("strong", no_atts);
|
||||
vAllowed.put("i", no_atts);
|
||||
vAllowed.put("em", no_atts);
|
||||
final ArrayList<String> no_atts = new ArrayList<String>();
|
||||
vAllowed.put("b", no_atts);
|
||||
vAllowed.put("strong", no_atts);
|
||||
vAllowed.put("i", no_atts);
|
||||
vAllowed.put("em", no_atts);
|
||||
|
||||
vSelfClosingTags = new String[]{"img"};
|
||||
vNeedClosingTags = new String[]{"a", "b", "strong", "i", "em"};
|
||||
vDisallowed = new String[]{};
|
||||
vAllowedProtocols = new String[]{"http", "mailto", "https"}; // no ftp.
|
||||
vProtocolAtts = new String[]{"src", "href"};
|
||||
vRemoveBlanks = new String[]{"a", "b", "strong", "i", "em"};
|
||||
vAllowedEntities = new String[]{"amp", "gt", "lt", "quot"};
|
||||
stripComment = true;
|
||||
encodeQuotes = true;
|
||||
alwaysMakeTags = true;
|
||||
}
|
||||
vSelfClosingTags = new String[]{"img"};
|
||||
vNeedClosingTags = new String[]{"a", "b", "strong", "i", "em"};
|
||||
vDisallowed = new String[]{};
|
||||
vAllowedProtocols = new String[]{"http", "mailto", "https"}; // no ftp.
|
||||
vProtocolAtts = new String[]{"src", "href"};
|
||||
vRemoveBlanks = new String[]{"a", "b", "strong", "i", "em"};
|
||||
vAllowedEntities = new String[]{"amp", "gt", "lt", "quot"};
|
||||
stripComment = true;
|
||||
encodeQuotes = true;
|
||||
alwaysMakeTags = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set debug flag to true. Otherwise use default settings. See the default constructor.
|
||||
*
|
||||
* @param debug turn debug on with a true argument
|
||||
*/
|
||||
public HTMLFilter(final boolean debug) {
|
||||
this();
|
||||
vDebug = debug;
|
||||
/**
|
||||
* Set debug flag to true. Otherwise use default settings. See the default constructor.
|
||||
*
|
||||
* @param debug turn debug on with a true argument
|
||||
*/
|
||||
public HTMLFilter(final boolean debug) {
|
||||
this();
|
||||
vDebug = debug;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Map-parameter configurable constructor.
|
||||
*
|
||||
* @param conf map containing configuration. keys match field names.
|
||||
*/
|
||||
public HTMLFilter(final Map<String, Object> conf) {
|
||||
/**
|
||||
* Map-parameter configurable constructor.
|
||||
*
|
||||
* @param conf map containing configuration. keys match field names.
|
||||
*/
|
||||
public HTMLFilter(final Map<String, Object> conf) {
|
||||
|
||||
assert conf.containsKey("vAllowed") : "configuration requires vAllowed";
|
||||
assert conf.containsKey("vSelfClosingTags") : "configuration requires vSelfClosingTags";
|
||||
assert conf.containsKey("vNeedClosingTags") : "configuration requires vNeedClosingTags";
|
||||
assert conf.containsKey("vDisallowed") : "configuration requires vDisallowed";
|
||||
assert conf.containsKey("vAllowedProtocols") : "configuration requires vAllowedProtocols";
|
||||
assert conf.containsKey("vProtocolAtts") : "configuration requires vProtocolAtts";
|
||||
assert conf.containsKey("vRemoveBlanks") : "configuration requires vRemoveBlanks";
|
||||
assert conf.containsKey("vAllowedEntities") : "configuration requires vAllowedEntities";
|
||||
assert conf.containsKey("vAllowed") : "configuration requires vAllowed";
|
||||
assert conf.containsKey("vSelfClosingTags") : "configuration requires vSelfClosingTags";
|
||||
assert conf.containsKey("vNeedClosingTags") : "configuration requires vNeedClosingTags";
|
||||
assert conf.containsKey("vDisallowed") : "configuration requires vDisallowed";
|
||||
assert conf.containsKey("vAllowedProtocols") : "configuration requires vAllowedProtocols";
|
||||
assert conf.containsKey("vProtocolAtts") : "configuration requires vProtocolAtts";
|
||||
assert conf.containsKey("vRemoveBlanks") : "configuration requires vRemoveBlanks";
|
||||
assert conf.containsKey("vAllowedEntities") : "configuration requires vAllowedEntities";
|
||||
|
||||
vAllowed = Collections.unmodifiableMap((HashMap<String, List<String>>) conf.get("vAllowed"));
|
||||
vSelfClosingTags = (String[]) conf.get("vSelfClosingTags");
|
||||
vNeedClosingTags = (String[]) conf.get("vNeedClosingTags");
|
||||
vDisallowed = (String[]) conf.get("vDisallowed");
|
||||
vAllowedProtocols = (String[]) conf.get("vAllowedProtocols");
|
||||
vProtocolAtts = (String[]) conf.get("vProtocolAtts");
|
||||
vRemoveBlanks = (String[]) conf.get("vRemoveBlanks");
|
||||
vAllowedEntities = (String[]) conf.get("vAllowedEntities");
|
||||
stripComment = conf.containsKey("stripComment") ? (Boolean) conf.get("stripComment") : true;
|
||||
encodeQuotes = conf.containsKey("encodeQuotes") ? (Boolean) conf.get("encodeQuotes") : true;
|
||||
alwaysMakeTags = conf.containsKey("alwaysMakeTags") ? (Boolean) conf.get("alwaysMakeTags") : true;
|
||||
}
|
||||
vAllowed = Collections.unmodifiableMap((HashMap<String, List<String>>) conf.get("vAllowed"));
|
||||
vSelfClosingTags = (String[]) conf.get("vSelfClosingTags");
|
||||
vNeedClosingTags = (String[]) conf.get("vNeedClosingTags");
|
||||
vDisallowed = (String[]) conf.get("vDisallowed");
|
||||
vAllowedProtocols = (String[]) conf.get("vAllowedProtocols");
|
||||
vProtocolAtts = (String[]) conf.get("vProtocolAtts");
|
||||
vRemoveBlanks = (String[]) conf.get("vRemoveBlanks");
|
||||
vAllowedEntities = (String[]) conf.get("vAllowedEntities");
|
||||
stripComment = conf.containsKey("stripComment") ? (Boolean) conf.get("stripComment") : true;
|
||||
encodeQuotes = conf.containsKey("encodeQuotes") ? (Boolean) conf.get("encodeQuotes") : true;
|
||||
alwaysMakeTags = conf.containsKey("alwaysMakeTags") ? (Boolean) conf.get("alwaysMakeTags") : true;
|
||||
}
|
||||
|
||||
private void reset() {
|
||||
vTagCounts.clear();
|
||||
}
|
||||
private void reset() {
|
||||
vTagCounts.clear();
|
||||
}
|
||||
|
||||
private void debug(final String msg) {
|
||||
if (vDebug) {
|
||||
Logger.getAnonymousLogger().info(msg);
|
||||
}
|
||||
}
|
||||
private void debug(final String msg) {
|
||||
if (vDebug) {
|
||||
Logger.getAnonymousLogger().info(msg);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// my versions of some PHP library functions
|
||||
public static String chr(final int decimal) {
|
||||
return String.valueOf((char) decimal);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
// my versions of some PHP library functions
|
||||
public static String chr(final int decimal) {
|
||||
return String.valueOf((char) decimal);
|
||||
}
|
||||
|
||||
public static String htmlSpecialChars(final String s) {
|
||||
String result = s;
|
||||
result = regexReplace(P_AMP, "&", result);
|
||||
result = regexReplace(P_QUOTE, """, result);
|
||||
result = regexReplace(P_LEFT_ARROW, "<", result);
|
||||
result = regexReplace(P_RIGHT_ARROW, ">", result);
|
||||
return result;
|
||||
}
|
||||
public static String htmlSpecialChars(final String s) {
|
||||
String result = s;
|
||||
result = regexReplace(P_AMP, "&", result);
|
||||
result = regexReplace(P_QUOTE, """, result);
|
||||
result = regexReplace(P_LEFT_ARROW, "<", result);
|
||||
result = regexReplace(P_RIGHT_ARROW, ">", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
//---------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* given a user submitted input String, filter out any invalid or restricted
|
||||
* html.
|
||||
*
|
||||
* @param input text (i.e. submitted by a user) than may contain html
|
||||
* @return "clean" version of input, with only valid, whitelisted html elements allowed
|
||||
*/
|
||||
public String filter(final String input) {
|
||||
reset();
|
||||
String s = input;
|
||||
/**
|
||||
* given a user submitted input String, filter out any invalid or restricted
|
||||
* html.
|
||||
*
|
||||
* @param input text (i.e. submitted by a user) than may contain html
|
||||
* @return "clean" version of input, with only valid, whitelisted html elements allowed
|
||||
*/
|
||||
public String filter(final String input) {
|
||||
reset();
|
||||
String s = input;
|
||||
|
||||
debug("************************************************");
|
||||
debug(" INPUT: " + input);
|
||||
debug("************************************************");
|
||||
debug(" INPUT: " + input);
|
||||
|
||||
s = escapeComments(s);
|
||||
debug(" escapeComments: " + s);
|
||||
s = escapeComments(s);
|
||||
debug(" escapeComments: " + s);
|
||||
|
||||
s = balanceHTML(s);
|
||||
debug(" balanceHTML: " + s);
|
||||
s = balanceHTML(s);
|
||||
debug(" balanceHTML: " + s);
|
||||
|
||||
s = checkTags(s);
|
||||
debug(" checkTags: " + s);
|
||||
s = checkTags(s);
|
||||
debug(" checkTags: " + s);
|
||||
|
||||
s = processRemoveBlanks(s);
|
||||
debug("processRemoveBlanks: " + s);
|
||||
s = processRemoveBlanks(s);
|
||||
debug("processRemoveBlanks: " + s);
|
||||
|
||||
s = validateEntities(s);
|
||||
debug(" validateEntites: " + s);
|
||||
s = validateEntities(s);
|
||||
debug(" validateEntites: " + s);
|
||||
|
||||
debug("************************************************\n\n");
|
||||
return s;
|
||||
}
|
||||
debug("************************************************\n\n");
|
||||
return s;
|
||||
}
|
||||
|
||||
public boolean isAlwaysMakeTags() {
|
||||
return alwaysMakeTags;
|
||||
}
|
||||
public boolean isAlwaysMakeTags() {
|
||||
return alwaysMakeTags;
|
||||
}
|
||||
|
||||
public boolean isStripComments() {
|
||||
return stripComment;
|
||||
}
|
||||
public boolean isStripComments() {
|
||||
return stripComment;
|
||||
}
|
||||
|
||||
private String escapeComments(final String s) {
|
||||
final Matcher m = P_COMMENTS.matcher(s);
|
||||
final StringBuffer buf = new StringBuffer();
|
||||
if (m.find()) {
|
||||
final String match = m.group(1); //(.*?)
|
||||
m.appendReplacement(buf, Matcher.quoteReplacement("<!--" + htmlSpecialChars(match) + "-->"));
|
||||
}
|
||||
m.appendTail(buf);
|
||||
private String escapeComments(final String s) {
|
||||
final Matcher m = P_COMMENTS.matcher(s);
|
||||
final StringBuffer buf = new StringBuffer();
|
||||
if (m.find()) {
|
||||
final String match = m.group(1); //(.*?)
|
||||
m.appendReplacement(buf, Matcher.quoteReplacement("<!--" + htmlSpecialChars(match) + "-->"));
|
||||
}
|
||||
m.appendTail(buf);
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private String balanceHTML(String s) {
|
||||
if (alwaysMakeTags) {
|
||||
//
|
||||
// try and form html
|
||||
//
|
||||
s = regexReplace(P_END_ARROW, "", s);
|
||||
s = regexReplace(P_BODY_TO_END, "<$1>", s);
|
||||
s = regexReplace(P_XML_CONTENT, "$1<$2", s);
|
||||
private String balanceHTML(String s) {
|
||||
if (alwaysMakeTags) {
|
||||
//
|
||||
// try and form html
|
||||
//
|
||||
s = regexReplace(P_END_ARROW, "", s);
|
||||
s = regexReplace(P_BODY_TO_END, "<$1>", s);
|
||||
s = regexReplace(P_XML_CONTENT, "$1<$2", s);
|
||||
|
||||
} else {
|
||||
//
|
||||
// escape stray brackets
|
||||
//
|
||||
s = regexReplace(P_STRAY_LEFT_ARROW, "<$1", s);
|
||||
s = regexReplace(P_STRAY_RIGHT_ARROW, "$1$2><", s);
|
||||
} else {
|
||||
//
|
||||
// escape stray brackets
|
||||
//
|
||||
s = regexReplace(P_STRAY_LEFT_ARROW, "<$1", s);
|
||||
s = regexReplace(P_STRAY_RIGHT_ARROW, "$1$2><", s);
|
||||
|
||||
//
|
||||
// the last regexp causes '<>' entities to appear
|
||||
// (we need to do a lookahead assertion so that the last bracket can
|
||||
// be used in the next pass of the regexp)
|
||||
//
|
||||
s = regexReplace(P_BOTH_ARROWS, "", s);
|
||||
}
|
||||
//
|
||||
// the last regexp causes '<>' entities to appear
|
||||
// (we need to do a lookahead assertion so that the last bracket can
|
||||
// be used in the next pass of the regexp)
|
||||
//
|
||||
s = regexReplace(P_BOTH_ARROWS, "", s);
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
private String checkTags(String s) {
|
||||
Matcher m = P_TAGS.matcher(s);
|
||||
private String checkTags(String s) {
|
||||
Matcher m = P_TAGS.matcher(s);
|
||||
|
||||
final StringBuffer buf = new StringBuffer();
|
||||
while (m.find()) {
|
||||
String replaceStr = m.group(1);
|
||||
replaceStr = processTag(replaceStr);
|
||||
m.appendReplacement(buf, Matcher.quoteReplacement(replaceStr));
|
||||
}
|
||||
m.appendTail(buf);
|
||||
final StringBuffer buf = new StringBuffer();
|
||||
while (m.find()) {
|
||||
String replaceStr = m.group(1);
|
||||
replaceStr = processTag(replaceStr);
|
||||
m.appendReplacement(buf, Matcher.quoteReplacement(replaceStr));
|
||||
}
|
||||
m.appendTail(buf);
|
||||
|
||||
s = buf.toString();
|
||||
s = buf.toString();
|
||||
|
||||
// these get tallied in processTag
|
||||
// (remember to reset before subsequent calls to filter method)
|
||||
for (String key : vTagCounts.keySet()) {
|
||||
for (int ii = 0; ii < vTagCounts.get(key); ii++) {
|
||||
s += "</" + key + ">";
|
||||
}
|
||||
}
|
||||
// these get tallied in processTag
|
||||
// (remember to reset before subsequent calls to filter method)
|
||||
for (String key : vTagCounts.keySet()) {
|
||||
for (int ii = 0; ii < vTagCounts.get(key); ii++) {
|
||||
s += "</" + key + ">";
|
||||
}
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
private String processRemoveBlanks(final String s) {
|
||||
String result = s;
|
||||
for (String tag : vRemoveBlanks) {
|
||||
if (!P_REMOVE_PAIR_BLANKS.containsKey(tag)) {
|
||||
P_REMOVE_PAIR_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?></" + tag + ">"));
|
||||
}
|
||||
result = regexReplace(P_REMOVE_PAIR_BLANKS.get(tag), "", result);
|
||||
if (!P_REMOVE_SELF_BLANKS.containsKey(tag)) {
|
||||
P_REMOVE_SELF_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?/>"));
|
||||
}
|
||||
result = regexReplace(P_REMOVE_SELF_BLANKS.get(tag), "", result);
|
||||
}
|
||||
private String processRemoveBlanks(final String s) {
|
||||
String result = s;
|
||||
for (String tag : vRemoveBlanks) {
|
||||
if (!P_REMOVE_PAIR_BLANKS.containsKey(tag)) {
|
||||
P_REMOVE_PAIR_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?></" + tag + ">"));
|
||||
}
|
||||
result = regexReplace(P_REMOVE_PAIR_BLANKS.get(tag), "", result);
|
||||
if (!P_REMOVE_SELF_BLANKS.containsKey(tag)) {
|
||||
P_REMOVE_SELF_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?/>"));
|
||||
}
|
||||
result = regexReplace(P_REMOVE_SELF_BLANKS.get(tag), "", result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static String regexReplace(final Pattern regex_pattern, final String replacement, final String s) {
|
||||
Matcher m = regex_pattern.matcher(s);
|
||||
return m.replaceAll(replacement);
|
||||
}
|
||||
private static String regexReplace(final Pattern regex_pattern, final String replacement, final String s) {
|
||||
Matcher m = regex_pattern.matcher(s);
|
||||
return m.replaceAll(replacement);
|
||||
}
|
||||
|
||||
private String processTag(final String s) {
|
||||
// ending tags
|
||||
Matcher m = P_END_TAG.matcher(s);
|
||||
if (m.find()) {
|
||||
final String name = m.group(1).toLowerCase();
|
||||
if (allowed(name)) {
|
||||
if (!inArray(name, vSelfClosingTags)) {
|
||||
if (vTagCounts.containsKey(name)) {
|
||||
vTagCounts.put(name, vTagCounts.get(name) - 1);
|
||||
return "</" + name + ">";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private String processTag(final String s) {
|
||||
// ending tags
|
||||
Matcher m = P_END_TAG.matcher(s);
|
||||
if (m.find()) {
|
||||
final String name = m.group(1).toLowerCase();
|
||||
if (allowed(name)) {
|
||||
if (!inArray(name, vSelfClosingTags)) {
|
||||
if (vTagCounts.containsKey(name)) {
|
||||
vTagCounts.put(name, vTagCounts.get(name) - 1);
|
||||
return "</" + name + ">";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// starting tags
|
||||
m = P_START_TAG.matcher(s);
|
||||
if (m.find()) {
|
||||
final String name = m.group(1).toLowerCase();
|
||||
final String body = m.group(2);
|
||||
String ending = m.group(3);
|
||||
// starting tags
|
||||
m = P_START_TAG.matcher(s);
|
||||
if (m.find()) {
|
||||
final String name = m.group(1).toLowerCase();
|
||||
final String body = m.group(2);
|
||||
String ending = m.group(3);
|
||||
|
||||
//debug( "in a starting tag, name='" + name + "'; body='" + body + "'; ending='" + ending + "'" );
|
||||
if (allowed(name)) {
|
||||
String params = "";
|
||||
//debug( "in a starting tag, name='" + name + "'; body='" + body + "'; ending='" + ending + "'" );
|
||||
if (allowed(name)) {
|
||||
String params = "";
|
||||
|
||||
final Matcher m2 = P_QUOTED_ATTRIBUTES.matcher(body);
|
||||
final Matcher m3 = P_UNQUOTED_ATTRIBUTES.matcher(body);
|
||||
final List<String> paramNames = new ArrayList<String>();
|
||||
final List<String> paramValues = new ArrayList<String>();
|
||||
while (m2.find()) {
|
||||
paramNames.add(m2.group(1)); //([a-z0-9]+)
|
||||
paramValues.add(m2.group(3)); //(.*?)
|
||||
}
|
||||
while (m3.find()) {
|
||||
paramNames.add(m3.group(1)); //([a-z0-9]+)
|
||||
paramValues.add(m3.group(3)); //([^\"\\s']+)
|
||||
}
|
||||
final Matcher m2 = P_QUOTED_ATTRIBUTES.matcher(body);
|
||||
final Matcher m3 = P_UNQUOTED_ATTRIBUTES.matcher(body);
|
||||
final List<String> paramNames = new ArrayList<String>();
|
||||
final List<String> paramValues = new ArrayList<String>();
|
||||
while (m2.find()) {
|
||||
paramNames.add(m2.group(1)); //([a-z0-9]+)
|
||||
paramValues.add(m2.group(3)); //(.*?)
|
||||
}
|
||||
while (m3.find()) {
|
||||
paramNames.add(m3.group(1)); //([a-z0-9]+)
|
||||
paramValues.add(m3.group(3)); //([^\"\\s']+)
|
||||
}
|
||||
|
||||
String paramName, paramValue;
|
||||
for (int ii = 0; ii < paramNames.size(); ii++) {
|
||||
paramName = paramNames.get(ii).toLowerCase();
|
||||
paramValue = paramValues.get(ii);
|
||||
String paramName, paramValue;
|
||||
for (int ii = 0; ii < paramNames.size(); ii++) {
|
||||
paramName = paramNames.get(ii).toLowerCase();
|
||||
paramValue = paramValues.get(ii);
|
||||
|
||||
// debug( "paramName='" + paramName + "'" );
|
||||
// debug( "paramValue='" + paramValue + "'" );
|
||||
// debug( "allowed? " + vAllowed.get( name ).contains( paramName ) );
|
||||
|
||||
if (allowedAttribute(name, paramName)) {
|
||||
if (inArray(paramName, vProtocolAtts)) {
|
||||
paramValue = processParamProtocol(paramValue);
|
||||
}
|
||||
params += " " + paramName + "=\"" + paramValue + "\"";
|
||||
}
|
||||
}
|
||||
if (allowedAttribute(name, paramName)) {
|
||||
if (inArray(paramName, vProtocolAtts)) {
|
||||
paramValue = processParamProtocol(paramValue);
|
||||
}
|
||||
params += " " + paramName + "=\"" + paramValue + "\"";
|
||||
}
|
||||
}
|
||||
|
||||
if (inArray(name, vSelfClosingTags)) {
|
||||
ending = " /";
|
||||
}
|
||||
if (inArray(name, vSelfClosingTags)) {
|
||||
ending = " /";
|
||||
}
|
||||
|
||||
if (inArray(name, vNeedClosingTags)) {
|
||||
ending = "";
|
||||
}
|
||||
if (inArray(name, vNeedClosingTags)) {
|
||||
ending = "";
|
||||
}
|
||||
|
||||
if (ending == null || ending.length() < 1) {
|
||||
if (vTagCounts.containsKey(name)) {
|
||||
vTagCounts.put(name, vTagCounts.get(name) + 1);
|
||||
} else {
|
||||
vTagCounts.put(name, 1);
|
||||
}
|
||||
} else {
|
||||
ending = " /";
|
||||
}
|
||||
return "<" + name + params + ending + ">";
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
if (ending == null || ending.length() < 1) {
|
||||
if (vTagCounts.containsKey(name)) {
|
||||
vTagCounts.put(name, vTagCounts.get(name) + 1);
|
||||
} else {
|
||||
vTagCounts.put(name, 1);
|
||||
}
|
||||
} else {
|
||||
ending = " /";
|
||||
}
|
||||
return "<" + name + params + ending + ">";
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
// comments
|
||||
m = P_COMMENT.matcher(s);
|
||||
if (!stripComment && m.find()) {
|
||||
return "<" + m.group() + ">";
|
||||
}
|
||||
// comments
|
||||
m = P_COMMENT.matcher(s);
|
||||
if (!stripComment && m.find()) {
|
||||
return "<" + m.group() + ">";
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
private String processParamProtocol(String s) {
|
||||
s = decodeEntities(s);
|
||||
final Matcher m = P_PROTOCOL.matcher(s);
|
||||
if (m.find()) {
|
||||
final String protocol = m.group(1);
|
||||
if (!inArray(protocol, vAllowedProtocols)) {
|
||||
// bad protocol, turn into local anchor link instead
|
||||
s = "#" + s.substring(protocol.length() + 1, s.length());
|
||||
if (s.startsWith("#//")) {
|
||||
s = "#" + s.substring(3, s.length());
|
||||
}
|
||||
}
|
||||
}
|
||||
private String processParamProtocol(String s) {
|
||||
s = decodeEntities(s);
|
||||
final Matcher m = P_PROTOCOL.matcher(s);
|
||||
if (m.find()) {
|
||||
final String protocol = m.group(1);
|
||||
if (!inArray(protocol, vAllowedProtocols)) {
|
||||
// bad protocol, turn into local anchor link instead
|
||||
s = "#" + s.substring(protocol.length() + 1, s.length());
|
||||
if (s.startsWith("#//")) {
|
||||
s = "#" + s.substring(3, s.length());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
private String decodeEntities(String s) {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
private String decodeEntities(String s) {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
|
||||
Matcher m = P_ENTITY.matcher(s);
|
||||
while (m.find()) {
|
||||
final String match = m.group(1);
|
||||
final int decimal = Integer.decode(match).intValue();
|
||||
m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
|
||||
}
|
||||
m.appendTail(buf);
|
||||
s = buf.toString();
|
||||
Matcher m = P_ENTITY.matcher(s);
|
||||
while (m.find()) {
|
||||
final String match = m.group(1);
|
||||
final int decimal = Integer.decode(match).intValue();
|
||||
m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
|
||||
}
|
||||
m.appendTail(buf);
|
||||
s = buf.toString();
|
||||
|
||||
buf = new StringBuffer();
|
||||
m = P_ENTITY_UNICODE.matcher(s);
|
||||
while (m.find()) {
|
||||
final String match = m.group(1);
|
||||
final int decimal = Integer.valueOf(match, 16).intValue();
|
||||
m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
|
||||
}
|
||||
m.appendTail(buf);
|
||||
s = buf.toString();
|
||||
buf = new StringBuffer();
|
||||
m = P_ENTITY_UNICODE.matcher(s);
|
||||
while (m.find()) {
|
||||
final String match = m.group(1);
|
||||
final int decimal = Integer.valueOf(match, 16).intValue();
|
||||
m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
|
||||
}
|
||||
m.appendTail(buf);
|
||||
s = buf.toString();
|
||||
|
||||
buf = new StringBuffer();
|
||||
m = P_ENCODE.matcher(s);
|
||||
while (m.find()) {
|
||||
final String match = m.group(1);
|
||||
final int decimal = Integer.valueOf(match, 16).intValue();
|
||||
m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
|
||||
}
|
||||
m.appendTail(buf);
|
||||
s = buf.toString();
|
||||
buf = new StringBuffer();
|
||||
m = P_ENCODE.matcher(s);
|
||||
while (m.find()) {
|
||||
final String match = m.group(1);
|
||||
final int decimal = Integer.valueOf(match, 16).intValue();
|
||||
m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
|
||||
}
|
||||
m.appendTail(buf);
|
||||
s = buf.toString();
|
||||
|
||||
s = validateEntities(s);
|
||||
return s;
|
||||
}
|
||||
s = validateEntities(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
private String validateEntities(final String s) {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
private String validateEntities(final String s) {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
|
||||
// validate entities throughout the string
|
||||
Matcher m = P_VALID_ENTITIES.matcher(s);
|
||||
while (m.find()) {
|
||||
final String one = m.group(1); //([^&;]*)
|
||||
final String two = m.group(2); //(?=(;|&|$))
|
||||
m.appendReplacement(buf, Matcher.quoteReplacement(checkEntity(one, two)));
|
||||
}
|
||||
m.appendTail(buf);
|
||||
// validate entities throughout the string
|
||||
Matcher m = P_VALID_ENTITIES.matcher(s);
|
||||
while (m.find()) {
|
||||
final String one = m.group(1); //([^&;]*)
|
||||
final String two = m.group(2); //(?=(;|&|$))
|
||||
m.appendReplacement(buf, Matcher.quoteReplacement(checkEntity(one, two)));
|
||||
}
|
||||
m.appendTail(buf);
|
||||
|
||||
return encodeQuotes(buf.toString());
|
||||
}
|
||||
return encodeQuotes(buf.toString());
|
||||
}
|
||||
|
||||
private String encodeQuotes(final String s) {
|
||||
if (encodeQuotes) {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
Matcher m = P_VALID_QUOTES.matcher(s);
|
||||
while (m.find()) {
|
||||
final String one = m.group(1); //(>|^)
|
||||
final String two = m.group(2); //([^<]+?)
|
||||
final String three = m.group(3); //(<|$)
|
||||
m.appendReplacement(buf, Matcher.quoteReplacement(one + regexReplace(P_QUOTE, """, two) + three));
|
||||
}
|
||||
m.appendTail(buf);
|
||||
return buf.toString();
|
||||
} else {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
private String encodeQuotes(final String s) {
|
||||
if (encodeQuotes) {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
Matcher m = P_VALID_QUOTES.matcher(s);
|
||||
while (m.find()) {
|
||||
final String one = m.group(1); //(>|^)
|
||||
final String two = m.group(2); //([^<]+?)
|
||||
final String three = m.group(3); //(<|$)
|
||||
m.appendReplacement(buf, Matcher.quoteReplacement(one + regexReplace(P_QUOTE, """, two) + three));
|
||||
}
|
||||
m.appendTail(buf);
|
||||
return buf.toString();
|
||||
} else {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
private String checkEntity(final String preamble, final String term) {
|
||||
private String checkEntity(final String preamble, final String term) {
|
||||
|
||||
return ";".equals(term) && isValidEntity(preamble)
|
||||
? '&' + preamble
|
||||
: "&" + preamble;
|
||||
}
|
||||
return ";".equals(term) && isValidEntity(preamble)
|
||||
? '&' + preamble
|
||||
: "&" + preamble;
|
||||
}
|
||||
|
||||
private boolean isValidEntity(final String entity) {
|
||||
return inArray(entity, vAllowedEntities);
|
||||
}
|
||||
private boolean isValidEntity(final String entity) {
|
||||
return inArray(entity, vAllowedEntities);
|
||||
}
|
||||
|
||||
private static boolean inArray(final String s, final String[] array) {
|
||||
for (String item : array) {
|
||||
if (item != null && item.equals(s)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private static boolean inArray(final String s, final String[] array) {
|
||||
for (String item : array) {
|
||||
if (item != null && item.equals(s)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean allowed(final String name) {
|
||||
return (vAllowed.isEmpty() || vAllowed.containsKey(name)) && !inArray(name, vDisallowed);
|
||||
}
|
||||
private boolean allowed(final String name) {
|
||||
return (vAllowed.isEmpty() || vAllowed.containsKey(name)) && !inArray(name, vDisallowed);
|
||||
}
|
||||
|
||||
private boolean allowedAttribute(final String name, final String paramName) {
|
||||
return allowed(name) && (vAllowed.isEmpty() || vAllowed.get(name).contains(paramName));
|
||||
}
|
||||
}
|
||||
private boolean allowedAttribute(final String name, final String paramName) {
|
||||
return allowed(name) && (vAllowed.isEmpty() || vAllowed.get(name).contains(paramName));
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,58 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springblade.core.tool.support.xss;
|
||||
|
||||
|
||||
import org.springblade.core.tool.utils.StringUtil;
|
||||
|
||||
/**
|
||||
* SQL过滤
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
public class SqlFilter {
|
||||
|
||||
/**
|
||||
* SQL注入过滤
|
||||
*
|
||||
* @param str 待验证的字符串
|
||||
*/
|
||||
public static String sqlInject(String str) {
|
||||
if (StringUtil.isBlank(str)) {
|
||||
return null;
|
||||
}
|
||||
//去掉'|"|;|\字符
|
||||
str = str.replace("'", "");
|
||||
str = str.replace("\"", "");
|
||||
str = str.replace(";", "");
|
||||
str = str.replace("\\", "");
|
||||
|
||||
//转换成小写
|
||||
str = str.toLowerCase();
|
||||
|
||||
//非法字符
|
||||
String[] keywords = {"master", "truncate", "insert", "select", "delete", "update", "declare", "alert", "drop"};
|
||||
|
||||
//判断是否包含非法字符
|
||||
for (String keyword : keywords) {
|
||||
if (str.indexOf(keyword) != -1) {
|
||||
throw new RuntimeException("包含非法字符");
|
||||
}
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
}
|
@ -21,29 +21,32 @@ import java.io.IOException;
|
||||
|
||||
/**
|
||||
* XSS过滤
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
public class XssFilter implements Filter {
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig config) throws ServletException {
|
||||
@Override
|
||||
public void init(FilterConfig config) throws ServletException {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
|
||||
ServletRequest requestWrapper = null;
|
||||
if(request instanceof HttpServletRequest) {
|
||||
requestWrapper = new XssHttpServletRequestWrapper((HttpServletRequest) request);
|
||||
}
|
||||
if(requestWrapper == null) {
|
||||
chain.doFilter(request, response);
|
||||
} else {
|
||||
chain.doFilter(requestWrapper, response);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
|
||||
ServletRequest requestWrapper = null;
|
||||
if (request instanceof HttpServletRequest) {
|
||||
requestWrapper = new XssHttpServletRequestWrapper((HttpServletRequest) request);
|
||||
}
|
||||
if (requestWrapper == null) {
|
||||
chain.doFilter(request, response);
|
||||
} else {
|
||||
chain.doFilter(requestWrapper, response);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
@Override
|
||||
public void destroy() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -34,141 +34,151 @@ import java.util.Map;
|
||||
|
||||
/**
|
||||
* XSS过滤处理
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
|
||||
|
||||
//没被包装过的HttpServletRequest(特殊场景,需要自己过滤)
|
||||
HttpServletRequest orgRequest;
|
||||
//html过滤
|
||||
private final static HTMLFilter htmlFilter = new HTMLFilter();
|
||||
// 缓存报文,支持多次读取流
|
||||
private final byte[] body;
|
||||
/**
|
||||
* 没被包装过的HttpServletRequest(特殊场景,需要自己过滤)
|
||||
*/
|
||||
HttpServletRequest orgRequest;
|
||||
|
||||
public XssHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
|
||||
super(request);
|
||||
orgRequest = request;
|
||||
body = WebUtil.getRequestBytes(request);
|
||||
}
|
||||
/**
|
||||
* html过滤
|
||||
*/
|
||||
private final static HTMLFilter htmlFilter = new HTMLFilter();
|
||||
|
||||
@Override
|
||||
public BufferedReader getReader() throws IOException {
|
||||
return new BufferedReader(new InputStreamReader(getInputStream()));
|
||||
}
|
||||
/**
|
||||
* 缓存报文,支持多次读取流
|
||||
*/
|
||||
private final byte[] body;
|
||||
|
||||
@Override
|
||||
public ServletInputStream getInputStream() throws IOException {
|
||||
public XssHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
|
||||
super(request);
|
||||
orgRequest = request;
|
||||
body = WebUtil.getRequestBytes(request);
|
||||
}
|
||||
|
||||
//为空,直接返回
|
||||
if (null == super.getHeader(HttpHeaders.CONTENT_TYPE)) {
|
||||
return super.getInputStream();
|
||||
}
|
||||
@Override
|
||||
public BufferedReader getReader() throws IOException {
|
||||
return new BufferedReader(new InputStreamReader(getInputStream()));
|
||||
}
|
||||
|
||||
//非json类型,直接返回
|
||||
if (!super.getHeader(HttpHeaders.CONTENT_TYPE).equalsIgnoreCase(MediaType.APPLICATION_JSON_VALUE)
|
||||
&& !super.getHeader(HttpHeaders.CONTENT_TYPE).equalsIgnoreCase(MediaType.APPLICATION_JSON_UTF8_VALUE)) {
|
||||
return super.getInputStream();
|
||||
}
|
||||
@Override
|
||||
public ServletInputStream getInputStream() throws IOException {
|
||||
|
||||
//为空,直接返回
|
||||
String requestStr = WebUtil.getRequestStr(orgRequest, body);
|
||||
if (StringUtil.isBlank(requestStr)) {
|
||||
return super.getInputStream();
|
||||
}
|
||||
//为空,直接返回
|
||||
if (null == super.getHeader(HttpHeaders.CONTENT_TYPE)) {
|
||||
return super.getInputStream();
|
||||
}
|
||||
|
||||
requestStr = xssEncode(requestStr);
|
||||
//非json类型,直接返回
|
||||
if (!super.getHeader(HttpHeaders.CONTENT_TYPE).equalsIgnoreCase(MediaType.APPLICATION_JSON_VALUE)
|
||||
&& !super.getHeader(HttpHeaders.CONTENT_TYPE).equalsIgnoreCase(MediaType.APPLICATION_JSON_UTF8_VALUE)) {
|
||||
return super.getInputStream();
|
||||
}
|
||||
|
||||
final ByteArrayInputStream bis = new ByteArrayInputStream(requestStr.getBytes(Charsets.UTF_8));
|
||||
//为空,直接返回
|
||||
String requestStr = WebUtil.getRequestStr(orgRequest, body);
|
||||
if (StringUtil.isBlank(requestStr)) {
|
||||
return super.getInputStream();
|
||||
}
|
||||
|
||||
return new ServletInputStream() {
|
||||
requestStr = xssEncode(requestStr);
|
||||
|
||||
@Override
|
||||
public boolean isFinished() {
|
||||
return true;
|
||||
}
|
||||
final ByteArrayInputStream bis = new ByteArrayInputStream(requestStr.getBytes(Charsets.UTF_8));
|
||||
|
||||
@Override
|
||||
public boolean isReady() {
|
||||
return true;
|
||||
}
|
||||
return new ServletInputStream() {
|
||||
|
||||
@Override
|
||||
public void setReadListener(ReadListener readListener) {
|
||||
@Override
|
||||
public boolean isFinished() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@Override
|
||||
public boolean isReady() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
return bis.read();
|
||||
}
|
||||
};
|
||||
@Override
|
||||
public void setReadListener(ReadListener readListener) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getParameter(String name) {
|
||||
String value = super.getParameter(xssEncode(name));
|
||||
if (StringUtil.isNotBlank(value)) {
|
||||
value = xssEncode(value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
return bis.read();
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public String[] getParameterValues(String name) {
|
||||
String[] parameters = super.getParameterValues(name);
|
||||
if (parameters == null || parameters.length == 0) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < parameters.length; i++) {
|
||||
parameters[i] = xssEncode(parameters[i]);
|
||||
}
|
||||
return parameters;
|
||||
}
|
||||
@Override
|
||||
public String getParameter(String name) {
|
||||
String value = super.getParameter(xssEncode(name));
|
||||
if (StringUtil.isNotBlank(value)) {
|
||||
value = xssEncode(value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String[]> getParameterMap() {
|
||||
Map<String, String[]> map = new LinkedHashMap<>();
|
||||
Map<String, String[]> parameters = super.getParameterMap();
|
||||
for (String key : parameters.keySet()) {
|
||||
String[] values = parameters.get(key);
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
values[i] = xssEncode(values[i]);
|
||||
}
|
||||
map.put(key, values);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
@Override
|
||||
public String[] getParameterValues(String name) {
|
||||
String[] parameters = super.getParameterValues(name);
|
||||
if (parameters == null || parameters.length == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHeader(String name) {
|
||||
String value = super.getHeader(xssEncode(name));
|
||||
if (StringUtil.isNotBlank(value)) {
|
||||
value = xssEncode(value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
for (int i = 0; i < parameters.length; i++) {
|
||||
parameters[i] = xssEncode(parameters[i]);
|
||||
}
|
||||
return parameters;
|
||||
}
|
||||
|
||||
private String xssEncode(String input) {
|
||||
return htmlFilter.filter(input);
|
||||
}
|
||||
@Override
|
||||
public Map<String, String[]> getParameterMap() {
|
||||
Map<String, String[]> map = new LinkedHashMap<>();
|
||||
Map<String, String[]> parameters = super.getParameterMap();
|
||||
for (String key : parameters.keySet()) {
|
||||
String[] values = parameters.get(key);
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
values[i] = xssEncode(values[i]);
|
||||
}
|
||||
map.put(key, values);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取最原始的request
|
||||
*/
|
||||
public HttpServletRequest getOrgRequest() {
|
||||
return orgRequest;
|
||||
}
|
||||
@Override
|
||||
public String getHeader(String name) {
|
||||
String value = super.getHeader(xssEncode(name));
|
||||
if (StringUtil.isNotBlank(value)) {
|
||||
value = xssEncode(value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取最原始的request
|
||||
*/
|
||||
public static HttpServletRequest getOrgRequest(HttpServletRequest request) {
|
||||
if (request instanceof XssHttpServletRequestWrapper) {
|
||||
return ((XssHttpServletRequestWrapper) request).getOrgRequest();
|
||||
}
|
||||
private String xssEncode(String input) {
|
||||
return htmlFilter.filter(input);
|
||||
}
|
||||
|
||||
return request;
|
||||
}
|
||||
/**
|
||||
* 获取最原始的request
|
||||
*/
|
||||
public HttpServletRequest getOrgRequest() {
|
||||
return orgRequest;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取最原始的request
|
||||
*/
|
||||
public static HttpServletRequest getOrgRequest(HttpServletRequest request) {
|
||||
if (request instanceof XssHttpServletRequestWrapper) {
|
||||
return ((XssHttpServletRequestWrapper) request).getOrgRequest();
|
||||
}
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user