根据P3C优化代码

This commit is contained in:
smallchill 2018-12-27 13:29:11 +08:00
parent 083b42c2fb
commit 912e0dd227
122 changed files with 5538 additions and 5212 deletions

View File

@ -24,52 +24,56 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy; import org.springframework.context.annotation.EnableAspectJAutoProxy;
/**
* 配置类
* @author smallchill
*/
@Slf4j @Slf4j
@Configuration @Configuration
@EnableConfigurationProperties({ @EnableConfigurationProperties({
BladeProperties.class BladeProperties.class
}) })
@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true) @EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)
@AllArgsConstructor @AllArgsConstructor
public class BladeBootAutoConfiguration { public class BladeBootAutoConfiguration {
private BladeProperties bladeProperties; private BladeProperties bladeProperties;
/** /**
* 全局变量定义 * 全局变量定义
*/ */
@Bean @Bean
public SystemConstant fileConst() { public SystemConstant fileConst() {
SystemConstant me = SystemConstant.me(); 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缩小 //设定上传图片缩放选择:true放大;false缩小
me.setCompressFlag(bladeProperties.getBoolean("compress-flag", false)); me.setCompressFlag(bladeProperties.getBoolean("compress-flag", false));
return me; return me;
} }
} }

View File

@ -33,6 +33,7 @@ import java.util.List;
/** /**
* WEB配置 * WEB配置
* @author smallchill
*/ */
@Slf4j @Slf4j
@Configuration @Configuration
@ -40,10 +41,10 @@ import java.util.List;
@Order(Ordered.HIGHEST_PRECEDENCE) @Order(Ordered.HIGHEST_PRECEDENCE)
public class BladeWebMvcConfiguration implements WebMvcConfigurer { public class BladeWebMvcConfiguration implements WebMvcConfigurer {
@Override @Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) { public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(new TokenArgumentResolver()); argumentResolvers.add(new TokenArgumentResolver());
} }
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean

View File

@ -27,6 +27,8 @@ import org.springframework.context.annotation.Profile;
/** /**
* mybatisplus 配置 * mybatisplus 配置
*
* @author smallchill
*/ */
@Configuration @Configuration
@MapperScan("org.springblade.**.mapper.**") @MapperScan("org.springblade.**.mapper.**")
@ -42,14 +44,14 @@ public class MybatisPlusConfiguration {
return new BladeMetaObjectHandler(); return new BladeMetaObjectHandler();
} }
/** /**
* SQL执行效率插件 * SQL执行效率插件
*/ */
@Bean @Bean
@Profile({AppConstant.DEV_CDOE, AppConstant.TEST_CODE}) @Profile({AppConstant.DEV_CDOE, AppConstant.TEST_CODE})
public PerformanceInterceptor performanceInterceptor() { public PerformanceInterceptor performanceInterceptor() {
return new PerformanceInterceptor(); return new PerformanceInterceptor();
} }
} }

View File

@ -35,6 +35,8 @@ import java.time.Duration;
/** /**
* RedisTemplate 配置 * RedisTemplate 配置
*
* @author smallchill
*/ */
@EnableCaching @EnableCaching
@Configuration @Configuration
@ -43,6 +45,7 @@ public class RedisTemplateConfiguration {
/** /**
* value 序列化 * value 序列化
*
* @return RedisSerializer * @return RedisSerializer
*/ */
@Bean @Bean

View File

@ -24,23 +24,25 @@ import org.springframework.retry.interceptor.RetryOperationsInterceptor;
/** /**
* 重试机制 * 重试机制
*
* @author smallchill
*/ */
@Slf4j @Slf4j
@Configuration @Configuration
public class RetryConfiguration { public class RetryConfiguration {
@Bean @Bean
@ConditionalOnMissingBean(name = "configServerRetryInterceptor") @ConditionalOnMissingBean(name = "configServerRetryInterceptor")
public RetryOperationsInterceptor configServerRetryInterceptor() { public RetryOperationsInterceptor configServerRetryInterceptor() {
log.info(String.format( log.info(String.format(
"configServerRetryInterceptor: Changing backOffOptions " + "configServerRetryInterceptor: Changing backOffOptions " +
"to initial: %s, multiplier: %s, maxInterval: %s", "to initial: %s, multiplier: %s, maxInterval: %s",
1000, 1.2, 5000)); 1000, 1.2, 5000));
return RetryInterceptorBuilder return RetryInterceptorBuilder
.stateless() .stateless()
.backOffOptions(1000, 1.2, 5000) .backOffOptions(1000, 1.2, 5000)
.maxAttempts(10) .maxAttempts(10)
.build(); .build();
} }
} }

View File

@ -33,177 +33,179 @@ import java.util.List;
/** /**
* Blade控制器封装类 * Blade控制器封装类
*
* @author smallchill
*/ */
public class BladeController { public class BladeController {
/** /**
* ============================ BINDER ================================================= * ============================ BINDER =================================================
*/ */
@InitBinder @InitBinder
protected void initBinder(ServletRequestDataBinder binder) { protected void initBinder(ServletRequestDataBinder binder) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
dateFormat.setLenient(false); dateFormat.setLenient(false);
binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false)); binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
} }
/** /**
* ============================ REQUEST ================================================= * ============================ REQUEST =================================================
*/ */
@Autowired @Autowired
private HttpServletRequest request; private HttpServletRequest request;
/** /**
* 获取request * 获取request
*/ */
public HttpServletRequest getRequest() { public HttpServletRequest getRequest() {
return this.request; return this.request;
} }
/** /**
* 获取当前用户 * 获取当前用户
* *
* @return * @return
*/ */
public BladeUser getUser() { public BladeUser getUser() {
return SecureUtil.getUser(); return SecureUtil.getUser();
} }
/** ============================ API_RESULT ================================================= */ /** ============================ API_RESULT ================================================= */
/** /**
* 返回ApiResult * 返回ApiResult
* *
* @param data * @param data
* @return R * @return R
*/ */
public <T> R<T> data(T data) { public <T> R<T> data(T data) {
return R.data(data); return R.data(data);
} }
/** /**
* 返回ApiResult * 返回ApiResult
* *
* @param data * @param data
* @param message * @param message
* @return R * @return R
*/ */
public <T> R<T> data(T data, String message) { public <T> R<T> data(T data, String message) {
return R.data(data, message); return R.data(data, message);
} }
/** /**
* 返回ApiResult * 返回ApiResult
* *
* @param data * @param data
* @param message * @param message
* @param code * @param code
* @return R * @return R
*/ */
public <T> R<T> data(T data, String message, int code) { public <T> R<T> data(T data, String message, int code) {
return R.data(code, data, message); return R.data(code, data, message);
} }
/** /**
* 返回ApiResult * 返回ApiResult
* *
* @param message * @param message
* @return R * @return R
*/ */
public R success(String message) { public R success(String message) {
return R.success(message); return R.success(message);
} }
/** /**
* 返回ApiResult * 返回ApiResult
* *
* @param message * @param message
* @return R * @return R
*/ */
public R failure(String message) { public R failure(String message) {
return R.failure(message); return R.failure(message);
} }
/** /**
* 返回ApiResult * 返回ApiResult
* *
* @param flag * @param flag
* @return R * @return R
*/ */
public R status(boolean flag) { public R status(boolean flag) {
return R.status(flag); return R.status(flag);
} }
/**============================ FILE ================================================= */ /**============================ FILE ================================================= */
/** /**
* 获取BladeFile封装类 * 获取BladeFile封装类
* *
* @param file * @param file
* @return * @return
*/ */
public BladeFile getFile(MultipartFile file) { public BladeFile getFile(MultipartFile file) {
return BladeFileUtil.getFile(file); return BladeFileUtil.getFile(file);
} }
/** /**
* 获取BladeFile封装类 * 获取BladeFile封装类
* *
* @param file * @param file
* @param dir * @param dir
* @return * @return
*/ */
public BladeFile getFile(MultipartFile file, String dir) { public BladeFile getFile(MultipartFile file, String dir) {
return BladeFileUtil.getFile(file, dir); return BladeFileUtil.getFile(file, dir);
} }
/** /**
* 获取BladeFile封装类 * 获取BladeFile封装类
* *
* @param file * @param file
* @param dir * @param dir
* @param path * @param path
* @param virtualPath * @param virtualPath
* @return * @return
*/ */
public BladeFile getFile(MultipartFile file, String dir, String path, String virtualPath) { public BladeFile getFile(MultipartFile file, String dir, String path, String virtualPath) {
return BladeFileUtil.getFile(file, dir, path, virtualPath); return BladeFileUtil.getFile(file, dir, path, virtualPath);
} }
/** /**
* 获取BladeFile封装类 * 获取BladeFile封装类
* *
* @param files * @param files
* @return * @return
*/ */
public List<BladeFile> getFiles(List<MultipartFile> files) { public List<BladeFile> getFiles(List<MultipartFile> files) {
return BladeFileUtil.getFiles(files); return BladeFileUtil.getFiles(files);
} }
/** /**
* 获取BladeFile封装类 * 获取BladeFile封装类
* *
* @param files * @param files
* @param dir * @param dir
* @return * @return
*/ */
public List<BladeFile> getFiles(List<MultipartFile> files, String dir) { public List<BladeFile> getFiles(List<MultipartFile> files, String dir) {
return BladeFileUtil.getFiles(files, dir); return BladeFileUtil.getFiles(files, dir);
} }
/** /**
* 获取BladeFile封装类 * 获取BladeFile封装类
* *
* @param files * @param files
* @param path * @param path
* @param virtualPath * @param virtualPath
* @return * @return
*/ */
public List<BladeFile> getFiles(List<MultipartFile> files, String dir, String path, String virtualPath) { public List<BladeFile> getFiles(List<MultipartFile> files, String dir, String path, String virtualPath) {
return BladeFileUtil.getFiles(files, dir, path, virtualPath); return BladeFileUtil.getFiles(files, dir, path, virtualPath);
} }
} }

View File

@ -26,6 +26,8 @@ import java.util.Enumeration;
/** /**
* feign 传递Request header * feign 传递Request header
*
* @author smallchill
*/ */
@Slf4j @Slf4j
public class BladeFeignRequestHeaderInterceptor implements RequestInterceptor { public class BladeFeignRequestHeaderInterceptor implements RequestInterceptor {
@ -40,16 +42,10 @@ public class BladeFeignRequestHeaderInterceptor implements RequestInterceptor {
while (headerNames.hasMoreElements()) { while (headerNames.hasMoreElements()) {
String name = headerNames.nextElement(); String name = headerNames.nextElement();
String value = request.getHeader(name); String value = request.getHeader(name);
/**
* 遍历请求头里面的属性字段将Authorization添加到新的请求头中转发到下游服务
* */
if ("Authorization".equals(name)) { if ("Authorization".equals(name)) {
log.debug("添加自定义请求头key:" + name + ",value:" + value);
requestTemplate.header(name, value); requestTemplate.header(name, value);
} }
} }
} else {
log.warn("FeignHeadConfiguration", "获取请求头失败!");
} }
} }
} }

View File

@ -38,6 +38,8 @@ import java.util.concurrent.TimeUnit;
/** /**
* 自定义Feign的隔离策略 * 自定义Feign的隔离策略
*
* @author smallchill
*/ */
public class FeignHystrixConcurrencyStrategy extends HystrixConcurrencyStrategy { public class FeignHystrixConcurrencyStrategy extends HystrixConcurrencyStrategy {

View File

@ -23,44 +23,48 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.Date; import java.util.Date;
/**
* 上传文件封装
* @author smallchill
*/
public class BladeFile { public class BladeFile {
/** /**
* 上传文件在附件表中的id * 上传文件在附件表中的id
*/ */
private Object fileId; private Object fileId;
/** /**
* 上传文件 * 上传文件
*/ */
private MultipartFile file; private MultipartFile file;
/** /**
* 上传分类文件夹 * 上传分类文件夹
*/ */
private String dir; private String dir;
/** /**
* 上传物理路径 * 上传物理路径
*/ */
private String uploadPath; private String uploadPath;
/** /**
* 上传虚拟路径 * 上传虚拟路径
*/ */
private String uploadVirtualPath; private String uploadVirtualPath;
/** /**
* 文件名 * 文件名
*/ */
private String fileName; private String fileName;
/** /**
* 真实文件名 * 真实文件名
*/ */
private String originalFileName; private String originalFileName;
public BladeFile() { public BladeFile() {
} }
public BladeFile(MultipartFile file, String dir) { public BladeFile(MultipartFile file, String dir) {
@ -74,55 +78,57 @@ public class BladeFile {
public BladeFile(MultipartFile file, String dir, String uploadPath, String uploadVirtualPath) { public BladeFile(MultipartFile file, String dir, String uploadPath, String uploadVirtualPath) {
this(file, dir); this(file, dir);
if (null != uploadPath){ if (null != uploadPath) {
this.uploadPath = BladeFileUtil.formatUrl(uploadPath); this.uploadPath = BladeFileUtil.formatUrl(uploadPath);
this.uploadVirtualPath = BladeFileUtil.formatUrl(uploadVirtualPath); this.uploadVirtualPath = BladeFileUtil.formatUrl(uploadVirtualPath);
} }
} }
/** /**
* 图片上传 * 图片上传
*/ */
public void transfer() { public void transfer() {
transfer(SystemConstant.me().isCompress()); transfer(SystemConstant.me().isCompress());
} }
/** /**
* 图片上传 * 图片上传
*
* @param compress 是否压缩 * @param compress 是否压缩
*/ */
public void transfer(boolean compress) { public void transfer(boolean compress) {
IFileProxy fileFactory = FileProxyManager.me().getDefaultFileProxyFactory(); IFileProxy fileFactory = FileProxyManager.me().getDefaultFileProxyFactory();
this.transfer(fileFactory, compress); this.transfer(fileFactory, compress);
} }
/** /**
* 图片上传 * 图片上传
*
* @param fileFactory 文件上传工厂类 * @param fileFactory 文件上传工厂类
* @param compress 是否压缩 * @param compress 是否压缩
*/ */
public void transfer(IFileProxy fileFactory, boolean compress) { public void transfer(IFileProxy fileFactory, boolean compress) {
try { try {
File file = new File(uploadPath); File file = new File(uploadPath);
if(null != fileFactory){ if (null != fileFactory) {
String [] path = fileFactory.path(file, dir); String[] path = fileFactory.path(file, dir);
this.uploadPath = path[0]; this.uploadPath = path[0];
this.uploadVirtualPath = path[1]; this.uploadVirtualPath = path[1];
file = fileFactory.rename(file, path[0]); file = fileFactory.rename(file, path[0]);
} }
File pfile = file.getParentFile(); File pfile = file.getParentFile();
if (!pfile.exists()) { if (!pfile.exists()) {
pfile.mkdirs(); pfile.mkdirs();
} }
this.file.transferTo(file); this.file.transferTo(file);
if (compress) { if (compress) {
fileFactory.compress(this.uploadPath); fileFactory.compress(this.uploadPath);
} }
} catch (IllegalStateException | IOException e) { } catch (IllegalStateException | IOException e) {
e.printStackTrace(); e.printStackTrace();
} }

View File

@ -18,12 +18,18 @@ package org.springblade.core.boot.file;
import org.springblade.core.tool.constant.SystemConstant; import org.springblade.core.tool.constant.SystemConstant;
import org.springblade.core.tool.date.DateUtil; import org.springblade.core.tool.date.DateUtil;
import org.springblade.core.tool.utils.ImageUtil; import org.springblade.core.tool.utils.ImageUtil;
import org.springblade.core.tool.utils.StringPool;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.util.Date; import java.util.Date;
/**
* 文件代理类
*
* @author smallchill
*/
public class BladeFileProxyFactory implements IFileProxy { public class BladeFileProxyFactory implements IFileProxy {
@Override @Override
@ -34,55 +40,59 @@ public class BladeFileProxyFactory implements IFileProxy {
} }
@Override @Override
public String [] path(File f, String dir) { public String[] path(File f, String dir) {
//避免网络延迟导致时间不同步 //避免网络延迟导致时间不同步
long time = System.nanoTime(); long time = System.nanoTime();
StringBuilder uploadPath = new StringBuilder() StringBuilder uploadPath = new StringBuilder()
.append(getFileDir(dir, SystemConstant.me().getUploadRealPath())) .append(getFileDir(dir, SystemConstant.me().getUploadRealPath()))
.append(time) .append(time)
.append(getFileExt(f.getName())); .append(getFileExt(f.getName()));
StringBuilder virtualPath = new StringBuilder() StringBuilder virtualPath = new StringBuilder()
.append(getFileDir(dir, SystemConstant.me().getUploadCtxPath())) .append(getFileDir(dir, SystemConstant.me().getUploadCtxPath()))
.append(time) .append(time)
.append(getFileExt(f.getName())); .append(getFileExt(f.getName()));
return new String [] {BladeFileUtil.formatUrl(uploadPath.toString()), BladeFileUtil.formatUrl(virtualPath.toString())}; return new String[]{BladeFileUtil.formatUrl(uploadPath.toString()), BladeFileUtil.formatUrl(virtualPath.toString())};
} }
/** /**
* 获取文件后缀 * 获取文件后缀
*/ */
public static String getFileExt(String fileName) { public static String getFileExt(String fileName) {
if (fileName.indexOf(".") == -1) if (!fileName.contains(StringPool.DOT)) {
return ".jpg"; return ".jpg";
else } else {
return fileName.substring(fileName.lastIndexOf('.'), fileName.length()); return fileName.substring(fileName.lastIndexOf(StringPool.DOT));
}
} }
/** /**
* 获取文件保存地址 * 获取文件保存地址
*
* @param saveDir * @param saveDir
* @return * @return
*/ */
public static String getFileDir(String dir, String saveDir) { public static String getFileDir(String dir, String saveDir) {
StringBuilder newFileDir = new StringBuilder(); StringBuilder newFileDir = new StringBuilder();
newFileDir.append(saveDir) newFileDir.append(saveDir)
.append(File.separator).append(dir).append(File.separator).append(DateUtil.format(new Date(), "yyyyMMdd")) .append(File.separator).append(dir).append(File.separator).append(DateUtil.format(new Date(), "yyyyMMdd"))
.append(File.separator); .append(File.separator);
return newFileDir.toString(); return newFileDir.toString();
} }
/** /**
* 图片压缩 * 图片压缩
*
* @param path 文件地址 * @param path 文件地址
* @return * @return
*/ */
@Override
public void compress(String path) { public void compress(String path) {
try { 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) { } catch (FileNotFoundException e) {
e.printStackTrace(); e.printStackTrace();
} }

View File

@ -20,12 +20,22 @@ import org.springframework.web.multipart.MultipartFile;
import java.util.*; import java.util.*;
/**
* 文件工具类
*
* @author smallchill
*/
public class BladeFileUtil { public class BladeFileUtil {
// 定义允许上传的文件扩展名 /**
* 定义允许上传的文件扩展名
*/
private static HashMap<String, String> extMap = new HashMap<String, String>(); 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 { static {
extMap.put("image", ".gif,.jpg,.jpeg,.png,.bmp,.JPG,.JPEG,.PNG"); 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("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"); 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 设定文件 * @param @return 设定文件
* @return String 返回类型 * @return String 返回类型
*/ */
public static String getFileExt(String fileName) { public static String getFileExt(String fileName) {
return fileName.substring(fileName.lastIndexOf('.'), fileName.length()); return fileName.substring(fileName.lastIndexOf('.'), fileName.length());
} }
/** /**
* 测试文件后缀 只让指定后缀的文件上传像jsp,war,sh等危险的后缀禁止 * 测试文件后缀 只让指定后缀的文件上传像jsp,war,sh等危险的后缀禁止
* *
* @return * @return
*/ */
public static boolean testExt(String dir, String fileName) { public static boolean testExt(String dir, String fileName) {
@ -67,7 +77,12 @@ public class BladeFileUtil {
public enum FileSort { public enum FileSort {
size, type, name; size, type, name;
// 文本排序转换成枚举 /**
* 文本排序转换成枚举
*
* @param sort
* @return
*/
public static FileSort of(String sort) { public static FileSort of(String sort) {
try { try {
return FileSort.valueOf(sort); return FileSort.valueOf(sort);
@ -78,6 +93,7 @@ public class BladeFileUtil {
} }
public static class NameComparator implements Comparator { public static class NameComparator implements Comparator {
@Override
public int compare(Object a, Object b) { public int compare(Object a, Object b) {
Hashtable hashA = (Hashtable) a; Hashtable hashA = (Hashtable) a;
Hashtable hashB = (Hashtable) b; Hashtable hashB = (Hashtable) b;
@ -92,6 +108,7 @@ public class BladeFileUtil {
} }
public static class SizeComparator implements Comparator { public static class SizeComparator implements Comparator {
@Override
public int compare(Object a, Object b) { public int compare(Object a, Object b) {
Hashtable hashA = (Hashtable) a; Hashtable hashA = (Hashtable) a;
Hashtable hashB = (Hashtable) b; Hashtable hashB = (Hashtable) b;
@ -112,6 +129,7 @@ public class BladeFileUtil {
} }
public static class TypeComparator implements Comparator { public static class TypeComparator implements Comparator {
@Override
public int compare(Object a, Object b) { public int compare(Object a, Object b) {
Hashtable hashA = (Hashtable) a; Hashtable hashA = (Hashtable) a;
Hashtable hashB = (Hashtable) b; Hashtable hashB = (Hashtable) b;
@ -128,70 +146,76 @@ public class BladeFileUtil {
public static String formatUrl(String url) { public static String formatUrl(String url) {
return url.replaceAll("\\\\", "/"); return url.replaceAll("\\\\", "/");
} }
/********************************BladeFile封装********************************************************/ /********************************BladeFile封装********************************************************/
/** /**
* 获取BladeFile封装类 * 获取BladeFile封装类
*
* @param file * @param file
* @return * @return
*/ */
public static BladeFile getFile(MultipartFile file){ public static BladeFile getFile(MultipartFile file) {
return getFile(file, "image", null, null); return getFile(file, "image", null, null);
} }
/** /**
* 获取BladeFile封装类 * 获取BladeFile封装类
*
* @param file * @param file
* @param dir * @param dir
* @return * @return
*/ */
public static BladeFile getFile(MultipartFile file, String dir){ public static BladeFile getFile(MultipartFile file, String dir) {
return getFile(file, dir, null, null); return getFile(file, dir, null, null);
} }
/** /**
* 获取BladeFile封装类 * 获取BladeFile封装类
*
* @param file * @param file
* @param dir * @param dir
* @param path * @param path
* @param virtualPath * @param virtualPath
* @return * @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); return new BladeFile(file, dir, path, virtualPath);
} }
/** /**
* 获取BladeFile封装类 * 获取BladeFile封装类
*
* @param files * @param files
* @return * @return
*/ */
public static List<BladeFile> getFiles(List<MultipartFile> files){ public static List<BladeFile> getFiles(List<MultipartFile> files) {
return getFiles(files, "image", null, null); return getFiles(files, "image", null, null);
} }
/** /**
* 获取BladeFile封装类 * 获取BladeFile封装类
*
* @param files * @param files
* @param dir * @param dir
* @return * @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); return getFiles(files, dir, null, null);
} }
/** /**
* 获取BladeFile封装类 * 获取BladeFile封装类
*
* @param files * @param files
* @param path * @param path
* @param virtualPath * @param virtualPath
* @return * @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<>(); List<BladeFile> list = new ArrayList<>();
for (MultipartFile file : files){ for (MultipartFile file : files) {
list.add(new BladeFile(file, dir, path, virtualPath)); list.add(new BladeFile(file, dir, path, virtualPath));
} }
return list; return list;

View File

@ -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");
}
}

View File

@ -17,29 +17,34 @@ package org.springblade.core.boot.file;
import java.io.File; import java.io.File;
/**
* 文件管理类
*
* @author smallchill
*/
public class FileProxyManager { 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() { public static FileProxyManager me() {
return me; return me;
} }
public IFileProxy getDefaultFileProxyFactory() { public IFileProxy getDefaultFileProxyFactory() {
return defaultFileProxyFactory; return defaultFileProxyFactory;
} }
public void setDefaultFileProxyFactory(IFileProxy defaultFileProxyFactory) { public void setDefaultFileProxyFactory(IFileProxy defaultFileProxyFactory) {
this.defaultFileProxyFactory = defaultFileProxyFactory; this.defaultFileProxyFactory = defaultFileProxyFactory;
} }
public String[] path(File file, String dir) { public String[] path(File file, String dir) {
return defaultFileProxyFactory.path(file, dir); return defaultFileProxyFactory.path(file, dir);
} }
public File rename(File file, String path) { public File rename(File file, String path) {
return defaultFileProxyFactory.rename(file, path); return defaultFileProxyFactory.rename(file, path);
} }
} }

View File

@ -17,27 +17,36 @@ package org.springblade.core.boot.file;
import java.io.File; import java.io.File;
/**
* 文件代理接口
*
* @author smallchill
*/
public interface IFileProxy { public interface IFileProxy {
/** /**
* 返回路径[物理路径][虚拟路径] * 返回路径[物理路径][虚拟路径]
*
* @param file * @param file
* @param dir * @param dir
* @return * @return
*/ */
String [] path(File file, String dir); String[] path(File file, String dir);
/** /**
* 文件重命名策略 * 文件重命名策略
*
* @param file * @param file
* @param path * @param path
* @return * @return
*/ */
File rename(File file, String path); File rename(File file, String path);
/** /**
* 图片压缩 * 图片压缩
*/ *
* @param path
*/
void compress(String path); void compress(String path);
} }

View File

@ -40,9 +40,10 @@ public class RequestLogAspect {
/** /**
* AOP 环切 控制器 R 返回值 * AOP 环切 控制器 R 返回值
*
* @param point JoinPoint * @param point JoinPoint
* @throws Throwable 异常
* @return Object * @return Object
* @throws Throwable 异常
*/ */
@Around( @Around(
"execution(!static org.springblade.core.tool.api.R<*> *(..)) && " + "execution(!static org.springblade.core.tool.api.R<*> *(..)) && " +
@ -106,7 +107,7 @@ public class RequestLogAspect {
needRemoveKeys.forEach(paraMap::remove); needRemoveKeys.forEach(paraMap::remove);
// 打印请求 // 打印请求
if (paraMap.isEmpty()) { if (paraMap.isEmpty()) {
log.info("===> {}: {}", requestMethod, requestURI); log.info("===> {}: {}", requestMethod, requestURI);
} else { } else {
log.info("===> {}: {} Parameters: {}", requestMethod, requestURI, JsonUtil.toJson(paraMap)); log.info("===> {}: {} Parameters: {}", requestMethod, requestURI, JsonUtil.toJson(paraMap));
} }
@ -125,7 +126,7 @@ public class RequestLogAspect {
return result; return result;
} finally { } finally {
long tookMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNs); long tookMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNs);
log.info("<=== {}: {} ({} ms)", request.getMethod(), requestURI, tookMs); log.info("<=== {}: {} ({} ms)", request.getMethod(), requestURI, tookMs);
} }
} }

View File

@ -29,7 +29,7 @@ import java.util.Objects;
* 将redis key序列化为字符串 * 将redis key序列化为字符串
* *
* <p> * <p>
* spring cache中的简单基本类型直接使用 StringRedisSerializer 会有问题 * spring cache中的简单基本类型直接使用 StringRedisSerializer 会有问题
* </p> * </p>
* *
* @author L.cm * @author L.cm

View File

@ -26,35 +26,37 @@ import org.springframework.web.method.support.ModelAndViewContainer;
/** /**
* Token转化BladeUser * Token转化BladeUser
*
* @author smallchill
*/ */
@Slf4j @Slf4j
public class TokenArgumentResolver implements HandlerMethodArgumentResolver { public class TokenArgumentResolver implements HandlerMethodArgumentResolver {
/** /**
* 1. 入参筛选 * 1. 入参筛选
* *
* @param methodParameter 参数集合 * @param methodParameter 参数集合
* @return 格式化后的参数 * @return 格式化后的参数
*/ */
@Override @Override
public boolean supportsParameter(MethodParameter methodParameter) { public boolean supportsParameter(MethodParameter methodParameter) {
return methodParameter.getParameterType().equals(BladeUser.class); return methodParameter.getParameterType().equals(BladeUser.class);
} }
/** /**
* @param methodParameter 入参集合 * @param methodParameter 入参集合
* @param modelAndViewContainer model view * @param modelAndViewContainer model view
* @param nativeWebRequest web相关 * @param nativeWebRequest web相关
* @param webDataBinderFactory 入参解析 * @param webDataBinderFactory 入参解析
* @return 包装对象 * @return 包装对象
* @throws Exception exception * @throws Exception exception
*/ */
@Override @Override
public Object resolveArgument(MethodParameter methodParameter, public Object resolveArgument(MethodParameter methodParameter,
ModelAndViewContainer modelAndViewContainer, ModelAndViewContainer modelAndViewContainer,
NativeWebRequest nativeWebRequest, NativeWebRequest nativeWebRequest,
WebDataBinderFactory webDataBinderFactory) { WebDataBinderFactory webDataBinderFactory) {
return SecureUtil.getUser(); return SecureUtil.getUser();
} }
} }

View File

@ -28,6 +28,8 @@ import java.util.function.Function;
/** /**
* 项目启动器搞定环境变量问题 * 项目启动器搞定环境变量问题
*
* @author smallchill
*/ */
public class BladeApplication { public class BladeApplication {
@ -92,7 +94,7 @@ public class BladeApplication {
props.setProperty("blade.service.version", AppConstant.APPLICATION_VERSION); props.setProperty("blade.service.version", AppConstant.APPLICATION_VERSION);
// 加载自定义组件 // 加载自定义组件
ServiceLoader<LauncherService> loader = ServiceLoader.load(LauncherService.class); 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; return builder;
} }

View File

@ -20,13 +20,15 @@ import org.springframework.stereotype.Component;
/** /**
* 系统启动完毕后执行 * 系统启动完毕后执行
*
* @author smallchill
*/ */
@Component @Component
public class BladeLineRunner implements CommandLineRunner { public class BladeLineRunner implements CommandLineRunner {
@Override @Override
public void run(String... args) { public void run(String... args) {
} }
} }

View File

@ -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; package org.springblade.core.launch;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -11,6 +26,8 @@ import org.springframework.util.StringUtils;
/** /**
* 项目启动事件通知 * 项目启动事件通知
*
* @author smallchill
*/ */
@Slf4j @Slf4j
@Configuration @Configuration

View File

@ -31,6 +31,8 @@ import org.springframework.context.annotation.Configuration;
/** /**
* Consul自定义注册规则 * Consul自定义注册规则
*
* @author smallchill
*/ */
@Configuration @Configuration
@ConditionalOnConsulEnabled @ConditionalOnConsulEnabled

View File

@ -26,12 +26,16 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered; import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order; import org.springframework.core.annotation.Order;
/**
* 配置类
*
* @author smallchill
*/
@Configuration @Configuration
@AllArgsConstructor @AllArgsConstructor
@Order(Ordered.HIGHEST_PRECEDENCE) @Order(Ordered.HIGHEST_PRECEDENCE)
@EnableConfigurationProperties({ @EnableConfigurationProperties({
BladeProperties.class BladeProperties.class
}) })
public class BladeLaunchConfiguration { public class BladeLaunchConfiguration {

View File

@ -17,130 +17,132 @@ package org.springblade.core.launch.constant;
/** /**
* 系统常量 * 系统常量
*
* @author smallchill
*/ */
public interface AppConstant { public interface AppConstant {
/** /**
* 应用版本 * 应用版本
*/ */
String APPLICATION_VERSION = "1.0.0"; String APPLICATION_VERSION = "1.0.0";
/** /**
* consul dev 地址 * consul dev 地址
*/ */
String CONSUL_DEV_HOST = "http://localhost"; String CONSUL_DEV_HOST = "http://localhost";
/** /**
* consul prod 地址 * consul prod 地址
*/ */
String CONSUL_PROD_HOST = "http://192.168.186.129"; String CONSUL_PROD_HOST = "http://192.168.186.129";
/** /**
* consul端口 * consul端口
*/ */
String CONSUL_PORT = "8500"; String CONSUL_PORT = "8500";
/** /**
* consul端口 * consul端口
*/ */
String CONSUL_CONFIG_FORMAT = "yaml"; String CONSUL_CONFIG_FORMAT = "yaml";
/** /**
* consul端口 * consul端口
*/ */
String CONSUL_WATCH_DELAY = "1000"; String CONSUL_WATCH_DELAY = "1000";
/** /**
* consul端口 * consul端口
*/ */
String CONSUL_WATCH_ENABLED = "true"; String CONSUL_WATCH_ENABLED = "true";
/** /**
* 基础包 * 基础包
*/ */
String BASE_PACKAGES = "org.springblade"; String BASE_PACKAGES = "org.springblade";
/** /**
* zookeeper id * zookeeper id
*/ */
String ZOOKEEPER_ID = "zk"; String ZOOKEEPER_ID = "zk";
/** /**
* zookeeper connect string * zookeeper connect string
*/ */
String ZOOKEEPER_CONNECT_STRING = "127.0.0.1:2181"; String ZOOKEEPER_CONNECT_STRING = "127.0.0.1:2181";
/** /**
* zookeeper address * zookeeper address
*/ */
String ZOOKEEPER_ADDRESS = "zookeeper://" + ZOOKEEPER_CONNECT_STRING; String ZOOKEEPER_ADDRESS = "zookeeper://" + ZOOKEEPER_CONNECT_STRING;
/** /**
* zookeeper root * zookeeper root
*/ */
String ZOOKEEPER_ROOT = "/blade-services"; String ZOOKEEPER_ROOT = "/blade-services";
/** /**
* 应用名前缀 * 应用名前缀
*/ */
String APPLICATION_NAME_FREFIX = "blade-"; String APPLICATION_NAME_FREFIX = "blade-";
/** /**
* 网关模块名称 * 网关模块名称
*/ */
String APPLICATION_GATEWAY_NAME = APPLICATION_NAME_FREFIX + "gateway"; String APPLICATION_GATEWAY_NAME = APPLICATION_NAME_FREFIX + "gateway";
/** /**
* 授权模块名称 * 授权模块名称
*/ */
String APPLICATION_AUTH_NAME = APPLICATION_NAME_FREFIX + "auth"; String APPLICATION_AUTH_NAME = APPLICATION_NAME_FREFIX + "auth";
/** /**
* 监控模块名称 * 监控模块名称
*/ */
String APPLICATION_ADMIN_NAME = APPLICATION_NAME_FREFIX + "admin"; String APPLICATION_ADMIN_NAME = APPLICATION_NAME_FREFIX + "admin";
/** /**
* 配置中心模块名称 * 配置中心模块名称
*/ */
String APPLICATION_CONFIG_NAME = APPLICATION_NAME_FREFIX + "config-server"; String APPLICATION_CONFIG_NAME = APPLICATION_NAME_FREFIX + "config-server";
/** /**
* TX模块名称 * TX模块名称
*/ */
String APPLICATION_TX_MANAGER = "tx-manager"; String APPLICATION_TX_MANAGER = "tx-manager";
/** /**
* 首页模块名称 * 首页模块名称
*/ */
String APPLICATION_DESK_NAME = APPLICATION_NAME_FREFIX + "desk"; String APPLICATION_DESK_NAME = APPLICATION_NAME_FREFIX + "desk";
/** /**
* 系统模块名称 * 系统模块名称
*/ */
String APPLICATION_SYSTEM_NAME = APPLICATION_NAME_FREFIX + "system"; String APPLICATION_SYSTEM_NAME = APPLICATION_NAME_FREFIX + "system";
/** /**
* 用户模块名称 * 用户模块名称
*/ */
String APPLICATION_USER_NAME = APPLICATION_NAME_FREFIX + "user"; String APPLICATION_USER_NAME = APPLICATION_NAME_FREFIX + "user";
/** /**
* 日志模块名称 * 日志模块名称
*/ */
String APPLICATION_LOG_NAME = APPLICATION_NAME_FREFIX + "log"; String APPLICATION_LOG_NAME = APPLICATION_NAME_FREFIX + "log";
/** /**
* 测试模块名称 * 测试模块名称
*/ */
String APPLICATION_TEST_NAME = APPLICATION_NAME_FREFIX + "test"; String APPLICATION_TEST_NAME = APPLICATION_NAME_FREFIX + "test";
/** /**
* 开发环境 * 开发环境
*/ */
String DEV_CDOE = "dev"; String DEV_CDOE = "dev";
/** /**
* 生产环境 * 生产环境
*/ */
String PROD_CODE = "prod"; String PROD_CODE = "prod";
/** /**
* 测试环境 * 测试环境
*/ */
String TEST_CODE = "test"; String TEST_CODE = "test";
/** /**
* 代码部署于 linux 工作默认为 mac Windows * 代码部署于 linux 工作默认为 mac Windows
*/ */
String OS_NAME_LINUX = "LINUX"; String OS_NAME_LINUX = "LINUX";
} }

View File

@ -25,6 +25,8 @@ import org.springframework.cloud.consul.serviceregistry.ConsulServiceRegistry;
/** /**
* Consul自定义注册规则 * Consul自定义注册规则
*
* @author smallchill
*/ */
public class BladeConsulServiceRegistry extends ConsulServiceRegistry { public class BladeConsulServiceRegistry extends ConsulServiceRegistry {

View File

@ -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; package org.springblade.core.launch.consul;
import org.springblade.core.launch.constant.AppConstant; import org.springblade.core.launch.constant.AppConstant;
@ -8,6 +23,8 @@ import java.util.Properties;
/** /**
* consul启动拓展 * consul启动拓展
*
* @author smallchil
*/ */
public class ConsulLauncherService implements LauncherService { public class ConsulLauncherService implements LauncherService {

View File

@ -25,6 +25,8 @@ import java.util.Map;
/** /**
* 配置文件 * 配置文件
*
* @author smallchill
*/ */
@ConfigurationProperties("blade") @ConfigurationProperties("blade")
public class BladeProperties { public class BladeProperties {
@ -36,19 +38,19 @@ public class BladeProperties {
@Setter @Setter
private String env; private String env;
/** /**
* 服务名 * 服务名
*/ */
@Getter @Getter
@Setter @Setter
private String name; private String name;
/** /**
* 判断是否为 本地开发环境 * 判断是否为 本地开发环境
*/ */
@Getter @Getter
@Setter @Setter
private Boolean isLocal = Boolean.FALSE; private Boolean isLocal = Boolean.FALSE;
/** /**
* 装载自定义配置blade.prop.xxx * 装载自定义配置blade.prop.xxx
@ -170,32 +172,32 @@ public class BladeProperties {
return defaultValue; return defaultValue;
} }
/** /**
* 获取配置 * 获取配置
* *
* @param key key * @param key key
* @return double value * @return double value
*/ */
@Nullable @Nullable
public Double getDouble(String key) { public Double getDouble(String key) {
return getDouble(key, null); return getDouble(key, null);
} }
/** /**
* 获取配置 * 获取配置
* *
* @param key key * @param key key
* @param defaultValue 默认值 * @param defaultValue 默认值
* @return double value * @return double value
*/ */
@Nullable @Nullable
public Double getDouble(String key, @Nullable Double defaultValue) { public Double getDouble(String key, @Nullable Double defaultValue) {
String value = prop.get(key); String value = prop.get(key);
if (value != null) { if (value != null) {
return Double.parseDouble(value.trim()); return Double.parseDouble(value.trim());
} }
return defaultValue; return defaultValue;
} }
/** /**
* 判断是否存在key * 判断是否存在key

View File

@ -20,43 +20,45 @@ import org.springframework.cloud.commons.util.InetUtils;
/** /**
* 服务器信息 * 服务器信息
*
* @author smallchill
*/ */
public class ServerInfo { public class ServerInfo {
private ServerProperties serverProperties; private ServerProperties serverProperties;
private InetUtils inetUtils; private InetUtils inetUtils;
private String hostName; private String hostName;
private String ip; private String ip;
private Integer prot; private Integer prot;
private String ipWithPort; private String ipWithPort;
public ServerInfo(ServerProperties serverProperties, InetUtils inetUtils) { public ServerInfo(ServerProperties serverProperties, InetUtils inetUtils) {
this.serverProperties = serverProperties; this.serverProperties = serverProperties;
this.inetUtils = inetUtils; this.inetUtils = inetUtils;
this.hostName = getHostInfo().getHostname(); this.hostName = getHostInfo().getHostname();
this.ip = getHostInfo().getIpAddress(); this.ip = getHostInfo().getIpAddress();
this.prot = serverProperties.getPort(); this.prot = serverProperties.getPort();
this.ipWithPort = String.format("%s:%d", ip, prot); this.ipWithPort = String.format("%s:%d", ip, prot);
} }
public InetUtils.HostInfo getHostInfo() { public InetUtils.HostInfo getHostInfo() {
return inetUtils.findFirstNonLoopbackHostInfo(); return inetUtils.findFirstNonLoopbackHostInfo();
} }
public String getIP() { public String getIP() {
return this.ip; return this.ip;
} }
public Integer getPort() { public Integer getPort() {
return this.prot; return this.prot;
} }
public String getHostName() { public String getHostName() {
return this.hostName; return this.hostName;
} }
public String getIPWithPort() { public String getIPWithPort() {
return this.ipWithPort; return this.ipWithPort;
} }
} }

View File

@ -19,11 +19,14 @@ import org.springframework.boot.builder.SpringApplicationBuilder;
/** /**
* launcher 扩展 用于一些组件发现 * launcher 扩展 用于一些组件发现
*
* @author smallchill
*/ */
public interface LauncherService { public interface LauncherService {
/** /**
* 启动时 处理 SpringApplicationBuilder * 启动时 处理 SpringApplicationBuilder
*
* @param builder SpringApplicationBuilder * @param builder SpringApplicationBuilder
* @param appName SpringApplicationAppName * @param appName SpringApplicationAppName
* @param profile SpringApplicationProfile * @param profile SpringApplicationProfile

View File

@ -20,6 +20,8 @@ import java.lang.annotation.*;
/** /**
* 操作日志注解 * 操作日志注解
*
* @author smallchill
*/ */
@Target(ElementType.METHOD) @Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)

View File

@ -25,6 +25,8 @@ import org.springblade.core.log.publisher.ApiLogPublisher;
/** /**
* 操作日志使用spring event异步入库 * 操作日志使用spring event异步入库
*
* @author smallchill
*/ */
@Slf4j @Slf4j
@Aspect @Aspect
@ -32,18 +34,18 @@ public class ApiLogAspect {
@Around("@annotation(apiLog)") @Around("@annotation(apiLog)")
public Object around(ProceedingJoinPoint point, ApiLog apiLog) throws Throwable { public Object around(ProceedingJoinPoint point, ApiLog apiLog) throws Throwable {
//获取类名 //获取类名
String className = point.getTarget().getClass().getName(); String className = point.getTarget().getClass().getName();
//获取方法 //获取方法
String methodName = point.getSignature().getName(); String methodName = point.getSignature().getName();
// 发送异步日志事件 // 发送异步日志事件
long beginTime = System.currentTimeMillis(); long beginTime = System.currentTimeMillis();
//执行方法 //执行方法
Object result = point.proceed(); Object result = point.proceed();
//执行时长(毫秒) //执行时长(毫秒)
long time = System.currentTimeMillis() - beginTime; long time = System.currentTimeMillis() - beginTime;
//记录日志 //记录日志
ApiLogPublisher.publishEvent(methodName, className, apiLog, time); ApiLogPublisher.publishEvent(methodName, className, apiLog, time);
return result; return result;
} }

View File

@ -38,26 +38,28 @@ import javax.servlet.Servlet;
/** /**
* 统一异常处理 * 统一异常处理
*
* @author smallchill
*/ */
@Configuration @Configuration
@AllArgsConstructor @AllArgsConstructor
@ConditionalOnWebApplication @ConditionalOnWebApplication
@AutoConfigureBefore(ErrorMvcAutoConfiguration.class) @AutoConfigureBefore(ErrorMvcAutoConfiguration.class)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class }) @ConditionalOnClass({Servlet.class, DispatcherServlet.class})
public class BladeErrorMvcAutoConfiguration { public class BladeErrorMvcAutoConfiguration {
private final ServerProperties serverProperties; private final ServerProperties serverProperties;
@Bean @Bean
@ConditionalOnMissingBean(value = ErrorAttributes.class, search = SearchStrategy.CURRENT) @ConditionalOnMissingBean(value = ErrorAttributes.class, search = SearchStrategy.CURRENT)
public DefaultErrorAttributes errorAttributes() { public DefaultErrorAttributes errorAttributes() {
return new BladeErrorAttributes(); return new BladeErrorAttributes();
} }
@Bean @Bean
@ConditionalOnMissingBean(value = ErrorController.class, search = SearchStrategy.CURRENT) @ConditionalOnMissingBean(value = ErrorController.class, search = SearchStrategy.CURRENT)
public BasicErrorController basicErrorController(ErrorAttributes errorAttributes) { public BasicErrorController basicErrorController(ErrorAttributes errorAttributes) {
return new BladeErrorController(errorAttributes, serverProperties.getError()); return new BladeErrorController(errorAttributes, serverProperties.getError());
} }
} }

View File

@ -31,39 +31,41 @@ import org.springframework.context.annotation.Configuration;
/** /**
* 日志工具自动配置 * 日志工具自动配置
*
* @author smallchill
*/ */
@Configuration @Configuration
@AllArgsConstructor @AllArgsConstructor
@ConditionalOnWebApplication @ConditionalOnWebApplication
public class BladeLogToolAutoConfiguration { public class BladeLogToolAutoConfiguration {
private final ILogClient logService; private final ILogClient logService;
private final ServerInfo serverInfo; private final ServerInfo serverInfo;
private final BladeProperties bladeProperties; private final BladeProperties bladeProperties;
@Bean @Bean
public ApiLogAspect apiLogAspect() { public ApiLogAspect apiLogAspect() {
return new ApiLogAspect(); return new ApiLogAspect();
} }
@Bean @Bean
public BladeLogger bladeLogger() { public BladeLogger bladeLogger() {
return new BladeLogger(); return new BladeLogger();
} }
@Bean @Bean
public ApiLogListener apiLogListener() { public ApiLogListener apiLogListener() {
return new ApiLogListener(logService, serverInfo, bladeProperties); return new ApiLogListener(logService, serverInfo, bladeProperties);
} }
@Bean @Bean
public ErrorLogListener errorEventListener() { public ErrorLogListener errorEventListener() {
return new ErrorLogListener(logService, serverInfo, bladeProperties); return new ErrorLogListener(logService, serverInfo, bladeProperties);
} }
@Bean @Bean
public BladeLogListener bladeEventListener() { public BladeLogListener bladeEventListener() {
return new BladeLogListener(logService, serverInfo, bladeProperties); return new BladeLogListener(logService, serverInfo, bladeProperties);
} }
} }

View File

@ -17,16 +17,18 @@ package org.springblade.core.log.constant;
/** /**
* 事件常量 * 事件常量
*
* @author smallchill
*/ */
public interface EventConstant { public interface EventConstant {
/** /**
* log * log
*/ */
String EVENT_LOG = "log"; String EVENT_LOG = "log";
/** /**
* request * request
*/ */
String EVENT_REQUEST = "request"; String EVENT_REQUEST = "request";
} }

View File

@ -29,31 +29,33 @@ import java.util.Map;
/** /**
* 全局异常处理 * 全局异常处理
*
* @author smallchill
*/ */
@Slf4j @Slf4j
public class BladeErrorAttributes extends DefaultErrorAttributes { public class BladeErrorAttributes extends DefaultErrorAttributes {
@Override @Override
public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) { public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
String requestUri = this.getAttr(webRequest, "javax.servlet.error.request_uri"); String requestUri = this.getAttr(webRequest, "javax.servlet.error.request_uri");
Integer status = this.getAttr(webRequest, "javax.servlet.error.status_code"); Integer status = this.getAttr(webRequest, "javax.servlet.error.status_code");
Throwable error = getError(webRequest); Throwable error = getError(webRequest);
R result; R result;
if (error == null) { if (error == null) {
log.error("URL:{} error status:{}", requestUri, status); log.error("URL:{} error status:{}", requestUri, status);
result = R.failure(ResultCode.FAILURE, "系统未知异常[HttpStatus]:" + status); result = R.failure(ResultCode.FAILURE, "系统未知异常[HttpStatus]:" + status);
} else { } else {
log.error(String.format("URL:%s error status:%d", requestUri, status), error); log.error(String.format("URL:%s error status:%d", requestUri, status), error);
result = R.failure(status, error.getMessage()); result = R.failure(status, error.getMessage());
} }
//发送服务异常事件 //发送服务异常事件
ErrorLogPublisher.publishEvent(error, requestUri); ErrorLogPublisher.publishEvent(error, requestUri);
return BeanUtil.toMap(result); return BeanUtil.toMap(result);
} }
@Nullable @Nullable
private <T> T getAttr(WebRequest webRequest, String name) { private <T> T getAttr(WebRequest webRequest, String name) {
return (T) webRequest.getAttribute(name, RequestAttributes.SCOPE_REQUEST); return (T) webRequest.getAttribute(name, RequestAttributes.SCOPE_REQUEST);
} }
} }

View File

@ -30,22 +30,24 @@ import java.util.Map;
/** /**
* 更改html请求异常为ajax * 更改html请求异常为ajax
*
* @author smallchill
*/ */
public class BladeErrorController extends BasicErrorController { public class BladeErrorController extends BasicErrorController {
public BladeErrorController(ErrorAttributes errorAttributes, ErrorProperties errorProperties) { public BladeErrorController(ErrorAttributes errorAttributes, ErrorProperties errorProperties) {
super(errorAttributes, errorProperties); super(errorAttributes, errorProperties);
} }
@Override @Override
public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) { public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
Map<String, Object> body = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.ALL)); Map<String, Object> body = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.ALL));
HttpStatus status = getStatus(request); HttpStatus status = getStatus(request);
response.setStatus(status.value()); response.setStatus(status.value());
MappingJackson2JsonView view = new MappingJackson2JsonView(); MappingJackson2JsonView view = new MappingJackson2JsonView();
view.setObjectMapper(JsonUtil.getInstance()); view.setObjectMapper(JsonUtil.getInstance());
view.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE); view.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
return new ModelAndView(view, body); return new ModelAndView(view, body);
} }
} }

View File

@ -51,110 +51,112 @@ import java.util.Set;
/** /**
* 全局异常处理处理可预见的异常 * 全局异常处理处理可预见的异常
*
* @author smallchill
*/ */
@Slf4j @Slf4j
@Configuration @Configuration
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class }) @ConditionalOnClass({Servlet.class, DispatcherServlet.class})
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@RestControllerAdvice @RestControllerAdvice
public class BladeRestExceptionTranslator { public class BladeRestExceptionTranslator {
@ExceptionHandler(MissingServletRequestParameterException.class) @ExceptionHandler(MissingServletRequestParameterException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST) @ResponseStatus(HttpStatus.BAD_REQUEST)
public R handleError(MissingServletRequestParameterException e) { public R handleError(MissingServletRequestParameterException e) {
log.warn("缺少请求参数", e.getMessage()); log.warn("缺少请求参数", e.getMessage());
String message = String.format("缺少必要的请求参数: %s", e.getParameterName()); String message = String.format("缺少必要的请求参数: %s", e.getParameterName());
return R.failure(ResultCode.PARAM_MISS, message); return R.failure(ResultCode.PARAM_MISS, message);
} }
@ExceptionHandler(MethodArgumentTypeMismatchException.class) @ExceptionHandler(MethodArgumentTypeMismatchException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST) @ResponseStatus(HttpStatus.BAD_REQUEST)
public R handleError(MethodArgumentTypeMismatchException e) { public R handleError(MethodArgumentTypeMismatchException e) {
log.warn("请求参数格式错误", e.getMessage()); log.warn("请求参数格式错误", e.getMessage());
String message = String.format("请求参数格式错误: %s", e.getName()); String message = String.format("请求参数格式错误: %s", e.getName());
return R.failure(ResultCode.PARAM_TYPE_ERROR, message); return R.failure(ResultCode.PARAM_TYPE_ERROR, message);
} }
@ExceptionHandler(MethodArgumentNotValidException.class) @ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST) @ResponseStatus(HttpStatus.BAD_REQUEST)
public R handleError(MethodArgumentNotValidException e) { public R handleError(MethodArgumentNotValidException e) {
log.warn("参数验证失败", e.getMessage()); log.warn("参数验证失败", e.getMessage());
return handleError(e.getBindingResult()); return handleError(e.getBindingResult());
} }
@ExceptionHandler(BindException.class) @ExceptionHandler(BindException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST) @ResponseStatus(HttpStatus.BAD_REQUEST)
public R handleError(BindException e) { public R handleError(BindException e) {
log.warn("参数绑定失败", e.getMessage()); log.warn("参数绑定失败", e.getMessage());
return handleError(e.getBindingResult()); return handleError(e.getBindingResult());
} }
private R handleError(BindingResult result) { private R handleError(BindingResult result) {
FieldError error = result.getFieldError(); FieldError error = result.getFieldError();
String message = String.format("%s:%s", error.getField(), error.getDefaultMessage()); String message = String.format("%s:%s", error.getField(), error.getDefaultMessage());
return R.failure(ResultCode.PARAM_BIND_ERROR, message); return R.failure(ResultCode.PARAM_BIND_ERROR, message);
} }
@ExceptionHandler(ConstraintViolationException.class) @ExceptionHandler(ConstraintViolationException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST) @ResponseStatus(HttpStatus.BAD_REQUEST)
public R handleError(ConstraintViolationException e) { public R handleError(ConstraintViolationException e) {
log.warn("参数验证失败", e.getMessage()); log.warn("参数验证失败", e.getMessage());
Set<ConstraintViolation<?>> violations = e.getConstraintViolations(); Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
ConstraintViolation<?> violation = violations.iterator().next(); ConstraintViolation<?> violation = violations.iterator().next();
String path = ((PathImpl) violation.getPropertyPath()).getLeafNode().getName(); String path = ((PathImpl) violation.getPropertyPath()).getLeafNode().getName();
String message = String.format("%s:%s", path, violation.getMessage()); String message = String.format("%s:%s", path, violation.getMessage());
return R.failure(ResultCode.PARAM_VALID_ERROR, message); return R.failure(ResultCode.PARAM_VALID_ERROR, message);
} }
@ExceptionHandler(NoHandlerFoundException.class) @ExceptionHandler(NoHandlerFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND) @ResponseStatus(HttpStatus.NOT_FOUND)
public R handleError(NoHandlerFoundException e) { public R handleError(NoHandlerFoundException e) {
log.error("404没找到请求:{}", e.getMessage()); log.error("404没找到请求:{}", e.getMessage());
return R.failure(ResultCode.NOT_FOUND, e.getMessage()); return R.failure(ResultCode.NOT_FOUND, e.getMessage());
} }
@ExceptionHandler(HttpMessageNotReadableException.class) @ExceptionHandler(HttpMessageNotReadableException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST) @ResponseStatus(HttpStatus.BAD_REQUEST)
public R handleError(HttpMessageNotReadableException e) { public R handleError(HttpMessageNotReadableException e) {
log.error("消息不能读取:{}", e.getMessage()); log.error("消息不能读取:{}", e.getMessage());
return R.failure(ResultCode.MSG_NOT_READABLE, e.getMessage()); return R.failure(ResultCode.MSG_NOT_READABLE, e.getMessage());
} }
@ExceptionHandler(HttpRequestMethodNotSupportedException.class) @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
@ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED) @ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
public R handleError(HttpRequestMethodNotSupportedException e) { public R handleError(HttpRequestMethodNotSupportedException e) {
log.error("不支持当前请求方法:{}", e.getMessage()); log.error("不支持当前请求方法:{}", e.getMessage());
return R.failure(ResultCode.METHOD_NOT_SUPPORTED, e.getMessage()); return R.failure(ResultCode.METHOD_NOT_SUPPORTED, e.getMessage());
} }
@ExceptionHandler(HttpMediaTypeNotSupportedException.class) @ExceptionHandler(HttpMediaTypeNotSupportedException.class)
@ResponseStatus(HttpStatus.UNSUPPORTED_MEDIA_TYPE) @ResponseStatus(HttpStatus.UNSUPPORTED_MEDIA_TYPE)
public R handleError(HttpMediaTypeNotSupportedException e) { public R handleError(HttpMediaTypeNotSupportedException e) {
log.error("不支持当前媒体类型:{}", e.getMessage()); log.error("不支持当前媒体类型:{}", e.getMessage());
return R.failure(ResultCode.MEDIA_TYPE_NOT_SUPPORTED, e.getMessage()); return R.failure(ResultCode.MEDIA_TYPE_NOT_SUPPORTED, e.getMessage());
} }
@ExceptionHandler(ServiceException.class) @ExceptionHandler(ServiceException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST) @ResponseStatus(HttpStatus.BAD_REQUEST)
public R handleError(ServiceException e) { public R handleError(ServiceException e) {
log.error("业务异常", e); log.error("业务异常", e);
return R.failure(e.getResultCode(), e.getMessage()); return R.failure(e.getResultCode(), e.getMessage());
} }
@ExceptionHandler(SecureException.class) @ExceptionHandler(SecureException.class)
@ResponseStatus(HttpStatus.UNAUTHORIZED) @ResponseStatus(HttpStatus.UNAUTHORIZED)
public R handleError(SecureException e) { public R handleError(SecureException e) {
log.error("认证异常", e); log.error("认证异常", e);
return R.failure(e.getResultCode(), e.getMessage()); return R.failure(e.getResultCode(), e.getMessage());
} }
@ExceptionHandler(Throwable.class) @ExceptionHandler(Throwable.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public R handleError(Throwable e) { public R handleError(Throwable e) {
log.error("服务器异常", e); log.error("服务器异常", e);
//发送服务异常事件 //发送服务异常事件
ErrorLogPublisher.publishEvent(e, URLUtil.getPath(WebUtil.getRequest().getRequestURI())); 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())); return R.failure(ResultCode.INTERNAL_SERVER_ERROR, (Func.isEmpty(e.getMessage()) ? ResultCode.INTERNAL_SERVER_ERROR.getMessage() : e.getMessage()));
} }
} }

View File

@ -22,11 +22,13 @@ import java.util.Map;
/** /**
* 系统日志事件 * 系统日志事件
*
* @author smallchill
*/ */
public class ApiLogEvent extends ApplicationEvent { public class ApiLogEvent extends ApplicationEvent {
public ApiLogEvent(Map<String, Object> source) { public ApiLogEvent(Map<String, Object> source) {
super(source); super(source);
} }
} }

View File

@ -38,36 +38,38 @@ import java.util.Map;
/** /**
* 异步监听日志事件 * 异步监听日志事件
*
* @author smallchill
*/ */
@Slf4j @Slf4j
@Component @Component
@AllArgsConstructor @AllArgsConstructor
public class ApiLogListener { public class ApiLogListener {
private final ILogClient logService; private final ILogClient logService;
private final ServerInfo serverInfo; private final ServerInfo serverInfo;
private final BladeProperties bladeProperties; private final BladeProperties bladeProperties;
@Async @Async
@Order @Order
@EventListener(ApiLogEvent.class) @EventListener(ApiLogEvent.class)
public void saveApiLog(ApiLogEvent event) { public void saveApiLog(ApiLogEvent event) {
Map<String, Object> source = (Map<String, Object>) event.getSource(); Map<String, Object> source = (Map<String, Object>) event.getSource();
LogApi logApi = (LogApi) source.get(EventConstant.EVENT_LOG); LogApi logApi = (LogApi) source.get(EventConstant.EVENT_LOG);
HttpServletRequest request = (HttpServletRequest) source.get(EventConstant.EVENT_REQUEST); HttpServletRequest request = (HttpServletRequest) source.get(EventConstant.EVENT_REQUEST);
logApi.setServiceId(bladeProperties.getName()); logApi.setServiceId(bladeProperties.getName());
logApi.setServerHost(serverInfo.getHostName()); logApi.setServerHost(serverInfo.getHostName());
logApi.setServerIp(serverInfo.getIPWithPort()); logApi.setServerIp(serverInfo.getIPWithPort());
logApi.setEnv(bladeProperties.getEnv()); logApi.setEnv(bladeProperties.getEnv());
logApi.setRemoteIp(WebUtil.getIP(request)); logApi.setRemoteIp(WebUtil.getIP(request));
logApi.setUserAgent(request.getHeader(WebUtil.USER_AGENT_HEADER)); logApi.setUserAgent(request.getHeader(WebUtil.USER_AGENT_HEADER));
logApi.setRequestUri(URLUtil.getPath(request.getRequestURI())); logApi.setRequestUri(URLUtil.getPath(request.getRequestURI()));
logApi.setMethod(request.getMethod()); logApi.setMethod(request.getMethod());
logApi.setParams(WebUtil.getRequestParamString(request)); logApi.setParams(WebUtil.getRequestParamString(request));
logApi.setCreateBy(SecureUtil.getUserAccount(request)); logApi.setCreateBy(SecureUtil.getUserAccount(request));
logApi.setCreateTime(LocalDateTime.now()); logApi.setCreateTime(LocalDateTime.now());
logService.saveApiLog(logApi); logService.saveApiLog(logApi);
} }
} }

View File

@ -22,11 +22,13 @@ import java.util.Map;
/** /**
* 系统日志事件 * 系统日志事件
*
* @author smallchill
*/ */
public class BladeLogEvent extends ApplicationEvent { public class BladeLogEvent extends ApplicationEvent {
public BladeLogEvent(Map<String, Object> source) { public BladeLogEvent(Map<String, Object> source) {
super(source); super(source);
} }
} }

View File

@ -37,34 +37,36 @@ import java.util.Map;
/** /**
* 异步监听日志事件 * 异步监听日志事件
*
* @author smallchill
*/ */
@Slf4j @Slf4j
@Component @Component
@AllArgsConstructor @AllArgsConstructor
public class BladeLogListener { public class BladeLogListener {
private final ILogClient logService; private final ILogClient logService;
private final ServerInfo serverInfo; private final ServerInfo serverInfo;
private final BladeProperties bladeProperties; private final BladeProperties bladeProperties;
@Async @Async
@Order @Order
@EventListener(BladeLogEvent.class) @EventListener(BladeLogEvent.class)
public void saveBladeLog(BladeLogEvent event) { public void saveBladeLog(BladeLogEvent event) {
Map<String, Object> source = (Map<String, Object>) event.getSource(); Map<String, Object> source = (Map<String, Object>) event.getSource();
LogBlade logBlade = (LogBlade) source.get(EventConstant.EVENT_LOG); LogBlade logBlade = (LogBlade) source.get(EventConstant.EVENT_LOG);
HttpServletRequest request = (HttpServletRequest) source.get(EventConstant.EVENT_REQUEST); HttpServletRequest request = (HttpServletRequest) source.get(EventConstant.EVENT_REQUEST);
logBlade.setRequestUri(URLUtil.getPath(request.getRequestURI())); logBlade.setRequestUri(URLUtil.getPath(request.getRequestURI()));
logBlade.setUserAgent(request.getHeader(WebUtil.USER_AGENT_HEADER)); logBlade.setUserAgent(request.getHeader(WebUtil.USER_AGENT_HEADER));
logBlade.setMethod(request.getMethod()); logBlade.setMethod(request.getMethod());
logBlade.setParams(WebUtil.getRequestParamString(request)); logBlade.setParams(WebUtil.getRequestParamString(request));
logBlade.setServerHost(serverInfo.getHostName()); logBlade.setServerHost(serverInfo.getHostName());
logBlade.setServiceId(bladeProperties.getName()); logBlade.setServiceId(bladeProperties.getName());
logBlade.setEnv(bladeProperties.getEnv()); logBlade.setEnv(bladeProperties.getEnv());
logBlade.setServerIp(serverInfo.getIPWithPort()); logBlade.setServerIp(serverInfo.getIPWithPort());
logBlade.setCreateBy(SecureUtil.getUserAccount(request)); logBlade.setCreateBy(SecureUtil.getUserAccount(request));
logBlade.setCreateTime(LocalDateTime.now()); logBlade.setCreateTime(LocalDateTime.now());
logService.saveBladeLog(logBlade); logService.saveBladeLog(logBlade);
} }
} }

View File

@ -22,11 +22,13 @@ import java.util.Map;
/** /**
* 错误日志事件 * 错误日志事件
*
* @author smallchill
*/ */
public class ErrorLogEvent extends ApplicationEvent { public class ErrorLogEvent extends ApplicationEvent {
public ErrorLogEvent(Map<String, Object> source) { public ErrorLogEvent(Map<String, Object> source) {
super(source); super(source);
} }
} }

View File

@ -36,33 +36,35 @@ import java.util.Map;
/** /**
* 异步监听错误日志事件 * 异步监听错误日志事件
*
* @author smallchill
*/ */
@Slf4j @Slf4j
@Component @Component
@AllArgsConstructor @AllArgsConstructor
public class ErrorLogListener { public class ErrorLogListener {
private final ILogClient logService; private final ILogClient logService;
private final ServerInfo serverInfo; private final ServerInfo serverInfo;
private final BladeProperties bladeProperties; private final BladeProperties bladeProperties;
@Async @Async
@Order @Order
@EventListener(ErrorLogEvent.class) @EventListener(ErrorLogEvent.class)
public void saveErrorLog(ErrorLogEvent event) { public void saveErrorLog(ErrorLogEvent event) {
Map<String, Object> source = (Map<String, Object>) event.getSource(); Map<String, Object> source = (Map<String, Object>) event.getSource();
LogError logError = (LogError) source.get(EventConstant.EVENT_LOG); LogError logError = (LogError) source.get(EventConstant.EVENT_LOG);
HttpServletRequest request = (HttpServletRequest) source.get(EventConstant.EVENT_REQUEST); HttpServletRequest request = (HttpServletRequest) source.get(EventConstant.EVENT_REQUEST);
logError.setUserAgent(request.getHeader(WebUtil.USER_AGENT_HEADER)); logError.setUserAgent(request.getHeader(WebUtil.USER_AGENT_HEADER));
logError.setMethod(request.getMethod()); logError.setMethod(request.getMethod());
logError.setParams(WebUtil.getRequestParamString(request)); logError.setParams(WebUtil.getRequestParamString(request));
logError.setServiceId(bladeProperties.getName()); logError.setServiceId(bladeProperties.getName());
logError.setServerHost(serverInfo.getHostName()); logError.setServerHost(serverInfo.getHostName());
logError.setServerIp(serverInfo.getIPWithPort()); logError.setServerIp(serverInfo.getIPWithPort());
logError.setEnv(bladeProperties.getEnv()); logError.setEnv(bladeProperties.getEnv());
logError.setCreateBy(SecureUtil.getUserAccount(request)); logError.setCreateBy(SecureUtil.getUserAccount(request));
logError.setCreateTime(LocalDateTime.now()); logError.setCreateTime(LocalDateTime.now());
logService.saveErrorLog(logError); logService.saveErrorLog(logError);
} }
} }

View File

@ -22,6 +22,8 @@ import org.springblade.core.tool.api.ResultCode;
/** /**
* 业务异常 * 业务异常
*
* @author smallchill
*/ */
public class ServiceException extends RuntimeException { public class ServiceException extends RuntimeException {
private static final long serialVersionUID = 2359767895161832954L; private static final long serialVersionUID = 2359767895161832954L;
@ -29,23 +31,24 @@ public class ServiceException extends RuntimeException {
@Getter @Getter
private final IResultCode resultCode; private final IResultCode resultCode;
public ServiceException(String message) { public ServiceException(String message) {
super(message); super(message);
this.resultCode = ResultCode.INTERNAL_SERVER_ERROR; this.resultCode = ResultCode.INTERNAL_SERVER_ERROR;
} }
public ServiceException(IResultCode resultCode) { public ServiceException(IResultCode resultCode) {
super(resultCode.getMessage()); super(resultCode.getMessage());
this.resultCode = resultCode; this.resultCode = resultCode;
} }
public ServiceException(IResultCode resultCode, Throwable cause) { public ServiceException(IResultCode resultCode, Throwable cause) {
super(cause); super(cause);
this.resultCode = resultCode; this.resultCode = resultCode;
} }
/** /**
* 提高性能 * 提高性能
*
* @return Throwable * @return Throwable
*/ */
@Override @Override

View File

@ -26,39 +26,41 @@ import org.springframework.web.bind.annotation.RequestBody;
/** /**
* Feign接口类 * Feign接口类
*
* @author smallchill
*/ */
@FeignClient( @FeignClient(
value = AppConstant.APPLICATION_LOG_NAME value = AppConstant.APPLICATION_LOG_NAME
) )
public interface ILogClient { public interface ILogClient {
String API_PREFIX = "/log"; String API_PREFIX = "/log";
/** /**
* 保存错误日志 * 保存错误日志
* *
* @param log * @param log
* @return * @return
*/ */
@PostMapping(API_PREFIX + "/saveBladeLog") @PostMapping(API_PREFIX + "/saveBladeLog")
R<Boolean> saveBladeLog(@RequestBody LogBlade log); R<Boolean> saveBladeLog(@RequestBody LogBlade log);
/** /**
* 保存操作日志 * 保存操作日志
* *
* @param log * @param log
* @return * @return
*/ */
@PostMapping(API_PREFIX + "/saveApiLog") @PostMapping(API_PREFIX + "/saveApiLog")
R<Boolean> saveApiLog(@RequestBody LogApi log); R<Boolean> saveApiLog(@RequestBody LogApi log);
/** /**
* 保存错误日志 * 保存错误日志
* *
* @param log * @param log
* @return * @return
*/ */
@PostMapping(API_PREFIX + "/saveErrorLog") @PostMapping(API_PREFIX + "/saveErrorLog")
R<Boolean> saveErrorLog(@RequestBody LogError log); R<Boolean> saveErrorLog(@RequestBody LogError log);
} }

View File

@ -22,32 +22,34 @@ import org.springframework.beans.factory.annotation.Value;
/** /**
* 日志工具类 * 日志工具类
*
* @author smallchill
*/ */
@Slf4j @Slf4j
public class BladeLogger implements InitializingBean { public class BladeLogger implements InitializingBean {
@Value("${spring.application.name}") @Value("${spring.application.name}")
private String serviceId; private String serviceId;
public void info(String id, String data) { public void info(String id, String data) {
BladeLogPublisher.publishEvent("info", id, data); BladeLogPublisher.publishEvent("info", id, data);
} }
public void debug(String id, String data) { public void debug(String id, String data) {
BladeLogPublisher.publishEvent("debug", id, data); BladeLogPublisher.publishEvent("debug", id, data);
} }
public void warn(String id, String data) { public void warn(String id, String data) {
BladeLogPublisher.publishEvent("warn", id, data); BladeLogPublisher.publishEvent("warn", id, data);
} }
public void error(String id, String data) { public void error(String id, String data) {
BladeLogPublisher.publishEvent("error", id, data); BladeLogPublisher.publishEvent("error", id, data);
} }
@Override @Override
public void afterPropertiesSet() throws Exception { public void afterPropertiesSet() throws Exception {
log.info(serviceId + ": BladeLogger init success!"); log.info(serviceId + ": BladeLogger init success!");
} }
} }

View File

@ -28,94 +28,94 @@ import java.io.Serializable;
import java.time.LocalDateTime; import java.time.LocalDateTime;
/** /**
* 实体类 * 实体类
* *
* @author Blade * @author smallchill
*/ */
@Data @Data
@TableName("blade_log_api") @TableName("blade_log_api")
public class LogApi implements Serializable { public class LogApi implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** /**
* 主键id * 主键id
*/ */
@TableId(value = "id", type = IdType.ID_WORKER) @TableId(value = "id", type = IdType.ID_WORKER)
private Long id; private Long id;
/** /**
* 日志类型 * 日志类型
*/ */
private String type; private String type;
/** /**
* 日志标题 * 日志标题
*/ */
private String title; private String title;
/** /**
* 服务ID * 服务ID
*/ */
private String serviceId; private String serviceId;
/** /**
* 服务器 ip * 服务器 ip
*/ */
private String serverIp; private String serverIp;
/** /**
* 服务器名 * 服务器名
*/ */
private String serverHost; private String serverHost;
/** /**
* 环境 * 环境
*/ */
private String env; private String env;
/** /**
* 操作IP地址 * 操作IP地址
*/ */
private String remoteIp; private String remoteIp;
/** /**
* 用户代理 * 用户代理
*/ */
private String userAgent; private String userAgent;
/** /**
* 请求URI * 请求URI
*/ */
private String requestUri; private String requestUri;
/** /**
* 操作方式 * 操作方式
*/ */
private String method; private String method;
/** /**
* 方法类 * 方法类
*/ */
private String methodClass; private String methodClass;
/** /**
* 方法名 * 方法名
*/ */
private String methodName; private String methodName;
/** /**
* 操作提交的数据 * 操作提交的数据
*/ */
private String params; private String params;
/** /**
* 执行时间 * 执行时间
*/ */
private String time; private String time;
/** /**
* 异常信息 * 异常信息
*/ */
private String exception; private String exception;
/** /**
* 创建人 * 创建人
*/ */
private String createBy; private String createBy;
/** /**
* 创建时间 * 创建时间
*/ */
@DateTimeFormat(pattern = DatePattern.NORM_DATETIME_PATTERN) @DateTimeFormat(pattern = DatePattern.NORM_DATETIME_PATTERN)
@JsonFormat(pattern = DatePattern.NORM_DATETIME_PATTERN) @JsonFormat(pattern = DatePattern.NORM_DATETIME_PATTERN)
private LocalDateTime createTime; private LocalDateTime createTime;
} }

View File

@ -28,76 +28,76 @@ import java.io.Serializable;
import java.time.LocalDateTime; import java.time.LocalDateTime;
/** /**
* 实体类 * 实体类
* *
* @author Blade * @author smallchill
* @since 2018-10-12 * @since 2018-10-12
*/ */
@Data @Data
@TableName("blade_log") @TableName("blade_log")
public class LogBlade implements Serializable { public class LogBlade implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** /**
* 主键id * 主键id
*/ */
@TableId(value = "id", type = IdType.ID_WORKER) @TableId(value = "id", type = IdType.ID_WORKER)
private Long id; private Long id;
/** /**
* 服务ID * 服务ID
*/ */
private String serviceId; private String serviceId;
/** /**
* 服务器名 * 服务器名
*/ */
private String serverHost; private String serverHost;
/** /**
* 服务器IP地址 * 服务器IP地址
*/ */
private String serverIp; private String serverIp;
/** /**
* 系统环境 * 系统环境
*/ */
private String env; private String env;
/** /**
* 日志级别 * 日志级别
*/ */
private String logLevel; private String logLevel;
/** /**
* 日志业务id * 日志业务id
*/ */
private String logId; private String logId;
/** /**
* 日志数据 * 日志数据
*/ */
private String logData; private String logData;
/** /**
* 操作方式 * 操作方式
*/ */
private String method; private String method;
/** /**
* 请求URI * 请求URI
*/ */
private String requestUri; private String requestUri;
/** /**
* 用户代理 * 用户代理
*/ */
private String userAgent; private String userAgent;
/** /**
* 操作提交的数据 * 操作提交的数据
*/ */
private String params; private String params;
/** /**
* 创建者 * 创建者
*/ */
private String createBy; private String createBy;
/** /**
* 创建时间 * 创建时间
*/ */
@DateTimeFormat(pattern = DatePattern.NORM_DATETIME_PATTERN) @DateTimeFormat(pattern = DatePattern.NORM_DATETIME_PATTERN)
@JsonFormat(pattern = DatePattern.NORM_DATETIME_PATTERN) @JsonFormat(pattern = DatePattern.NORM_DATETIME_PATTERN)
private LocalDateTime createTime; private LocalDateTime createTime;
} }

View File

@ -30,89 +30,91 @@ import java.time.LocalDateTime;
/** /**
* 服务 异常 * 服务 异常
*
* @author smallchill
*/ */
@Data @Data
@TableName("blade_log_error") @TableName("blade_log_error")
public class LogError implements Serializable { public class LogError implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** /**
* 主键id * 主键id
*/ */
@TableId(value = "id", type = IdType.ID_WORKER) @TableId(value = "id", type = IdType.ID_WORKER)
private Long id; private Long id;
/** /**
* 应用名 * 应用名
*/ */
private String serviceId; private String serviceId;
/** /**
* 环境 * 环境
*/ */
private String env; private String env;
/** /**
* 服务器 ip * 服务器 ip
*/ */
private String serverIp; private String serverIp;
/** /**
* 服务器名 * 服务器名
*/ */
private String serverHost; private String serverHost;
/** /**
* 用户代理 * 用户代理
*/ */
private String userAgent; private String userAgent;
/** /**
* 请求url * 请求url
*/ */
@Nullable @Nullable
private String requestUri; private String requestUri;
/** /**
* 操作方式 * 操作方式
*/ */
private String method; private String method;
/** /**
* 堆栈信息 * 堆栈信息
*/ */
private String stackTrace; private String stackTrace;
/** /**
* 异常名 * 异常名
*/ */
private String exceptionName; private String exceptionName;
/** /**
* 异常消息 * 异常消息
*/ */
private String message; private String message;
/** /**
* 类名 * 类名
*/ */
private String methodClass; private String methodClass;
/** /**
* 文件名 * 文件名
*/ */
private String fileName; private String fileName;
/** /**
* 方法名 * 方法名
*/ */
private String methodName; private String methodName;
/** /**
* 操作提交的数据 * 操作提交的数据
*/ */
private String params; private String params;
/** /**
* 代码行数 * 代码行数
*/ */
private Integer lineNumber; private Integer lineNumber;
/** /**
* 创建人 * 创建人
*/ */
private String createBy; private String createBy;
/** /**
* 创建时间 * 创建时间
*/ */
@DateTimeFormat(pattern = DatePattern.NORM_DATETIME_PATTERN) @DateTimeFormat(pattern = DatePattern.NORM_DATETIME_PATTERN)
@JsonFormat(pattern = DatePattern.NORM_DATETIME_PATTERN) @JsonFormat(pattern = DatePattern.NORM_DATETIME_PATTERN)
private LocalDateTime createTime; private LocalDateTime createTime;
} }

View File

@ -30,21 +30,23 @@ import java.util.Map;
/** /**
* API日志信息事件发送 * API日志信息事件发送
*
* @author smallchill
*/ */
public class ApiLogPublisher { public class ApiLogPublisher {
public static void publishEvent(String methodName, String methodClass, ApiLog apiLog, long time) { public static void publishEvent(String methodName, String methodClass, ApiLog apiLog, long time) {
HttpServletRequest request = WebUtil.getRequest(); HttpServletRequest request = WebUtil.getRequest();
LogApi logApi = new LogApi(); LogApi logApi = new LogApi();
logApi.setType(BladeConstant.LOG_NORMAL_TYPE); logApi.setType(BladeConstant.LOG_NORMAL_TYPE);
logApi.setTitle(apiLog.value()); logApi.setTitle(apiLog.value());
logApi.setTime(String.valueOf(time)); logApi.setTime(String.valueOf(time));
logApi.setMethodClass(methodClass); logApi.setMethodClass(methodClass);
logApi.setMethodName(methodName); logApi.setMethodName(methodName);
Map<String, Object> event = new HashMap<>(); Map<String, Object> event = new HashMap<>();
event.put(EventConstant.EVENT_LOG, logApi); event.put(EventConstant.EVENT_LOG, logApi);
event.put(EventConstant.EVENT_REQUEST, request); event.put(EventConstant.EVENT_REQUEST, request);
SpringUtil.publishEvent(new ApiLogEvent(event)); SpringUtil.publishEvent(new ApiLogEvent(event));
} }
} }

View File

@ -28,19 +28,21 @@ import java.util.Map;
/** /**
* BLADE日志信息事件发送 * BLADE日志信息事件发送
*
* @author smallchill
*/ */
public class BladeLogPublisher { public class BladeLogPublisher {
public static void publishEvent(String level, String id, String data) { public static void publishEvent(String level, String id, String data) {
HttpServletRequest request = WebUtil.getRequest(); HttpServletRequest request = WebUtil.getRequest();
LogBlade logBlade = new LogBlade(); LogBlade logBlade = new LogBlade();
logBlade.setLogLevel(level); logBlade.setLogLevel(level);
logBlade.setLogId(id); logBlade.setLogId(id);
logBlade.setLogData(data); logBlade.setLogData(data);
Map<String, Object> event = new HashMap<>(); Map<String, Object> event = new HashMap<>();
event.put(EventConstant.EVENT_LOG, logBlade); event.put(EventConstant.EVENT_LOG, logBlade);
event.put(EventConstant.EVENT_REQUEST, request); event.put(EventConstant.EVENT_REQUEST, request);
SpringUtil.publishEvent(new BladeLogEvent(event)); SpringUtil.publishEvent(new BladeLogEvent(event));
} }
} }

View File

@ -27,30 +27,32 @@ import java.util.Map;
/** /**
* 异常信息事件发送 * 异常信息事件发送
*
* @author smallchill
*/ */
public class ErrorLogPublisher { public class ErrorLogPublisher {
public static void publishEvent(Throwable error, String requestUri) { public static void publishEvent(Throwable error, String requestUri) {
HttpServletRequest request = WebUtil.getRequest(); HttpServletRequest request = WebUtil.getRequest();
LogError logError = new LogError(); LogError logError = new LogError();
logError.setRequestUri(requestUri); logError.setRequestUri(requestUri);
if (Func.isNotEmpty(error)) { if (Func.isNotEmpty(error)) {
logError.setStackTrace(Exceptions.getStackTraceAsString(error)); logError.setStackTrace(Exceptions.getStackTraceAsString(error));
logError.setExceptionName(error.getClass().getName()); logError.setExceptionName(error.getClass().getName());
logError.setMessage(error.getMessage()); logError.setMessage(error.getMessage());
StackTraceElement[] elements = error.getStackTrace(); StackTraceElement[] elements = error.getStackTrace();
if (Func.isNotEmpty(elements)) { if (Func.isNotEmpty(elements)) {
StackTraceElement element = elements[0]; StackTraceElement element = elements[0];
logError.setMethodName(element.getMethodName()); logError.setMethodName(element.getMethodName());
logError.setMethodClass(element.getClassName()); logError.setMethodClass(element.getClassName());
logError.setFileName(element.getFileName()); logError.setFileName(element.getFileName());
logError.setLineNumber(element.getLineNumber()); logError.setLineNumber(element.getLineNumber());
} }
} }
Map<String, Object> event = new HashMap<>(); Map<String, Object> event = new HashMap<>(16);
event.put(EventConstant.EVENT_LOG, logError); event.put(EventConstant.EVENT_LOG, logError);
event.put(EventConstant.EVENT_REQUEST, request); event.put(EventConstant.EVENT_REQUEST, request);
SpringUtil.publishEvent(new ErrorLogEvent(event)); SpringUtil.publishEvent(new ErrorLogEvent(event));
} }
} }

View File

@ -21,6 +21,8 @@ import org.apache.ibatis.reflection.MetaObject;
/** /**
* mybatisplus自定义填充 * mybatisplus自定义填充
*
* @author smallchill
*/ */
@Slf4j @Slf4j
public class BladeMetaObjectHandler implements MetaObjectHandler { public class BladeMetaObjectHandler implements MetaObjectHandler {

View File

@ -27,6 +27,11 @@ import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serializable; import java.io.Serializable;
import java.time.LocalDateTime; import java.time.LocalDateTime;
/**
* 基础实体类
*
* @author smallchill
*/
@Data @Data
public class BaseEntity implements Serializable { public class BaseEntity implements Serializable {
/** /**
@ -36,33 +41,33 @@ public class BaseEntity implements Serializable {
@ApiModelProperty(value = "主键id") @ApiModelProperty(value = "主键id")
private Integer id; private Integer id;
/** /**
* 创建人 * 创建人
*/ */
@ApiModelProperty(value = "创建人") @ApiModelProperty(value = "创建人")
private Integer createUser; private Integer createUser;
/** /**
* 创建时间 * 创建时间
*/ */
@DateTimeFormat(pattern = DatePattern.NORM_DATETIME_PATTERN) @DateTimeFormat(pattern = DatePattern.NORM_DATETIME_PATTERN)
@JsonFormat(pattern = DatePattern.NORM_DATETIME_PATTERN) @JsonFormat(pattern = DatePattern.NORM_DATETIME_PATTERN)
@ApiModelProperty(value = "创建时间") @ApiModelProperty(value = "创建时间")
private LocalDateTime createTime; private LocalDateTime createTime;
/** /**
* 更新人 * 更新人
*/ */
@ApiModelProperty(value = "更新人") @ApiModelProperty(value = "更新人")
private Integer updateUser; private Integer updateUser;
/** /**
* 更新时间 * 更新时间
*/ */
@DateTimeFormat(pattern = DatePattern.NORM_DATETIME_PATTERN) @DateTimeFormat(pattern = DatePattern.NORM_DATETIME_PATTERN)
@JsonFormat(pattern = DatePattern.NORM_DATETIME_PATTERN) @JsonFormat(pattern = DatePattern.NORM_DATETIME_PATTERN)
@ApiModelProperty(value = "更新时间") @ApiModelProperty(value = "更新时间")
private LocalDateTime updateTime; private LocalDateTime updateTime;
/** /**
* 状态[1:正常] * 状态[1:正常]
@ -70,9 +75,9 @@ public class BaseEntity implements Serializable {
@ApiModelProperty(value = "业务状态") @ApiModelProperty(value = "业务状态")
private Integer status; private Integer status;
/** /**
* 状态[0:未删除,1:删除] * 状态[0:未删除,1:删除]
*/ */
@ApiModelProperty(value = "是否已删除") @ApiModelProperty(value = "是否已删除")
private Integer isDeleted; private Integer isDeleted;
} }

View File

@ -20,13 +20,20 @@ import com.baomidou.mybatisplus.extension.service.IService;
import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotEmpty;
import java.util.List; import java.util.List;
/**
* 基础业务接口
*
* @param <T>
* @author smallchill
*/
public interface BaseService<T> extends IService<T> { public interface BaseService<T> extends IService<T> {
/** /**
* 逻辑删除 * 逻辑删除
* @param ids id集合(逗号分隔) *
* @return * @param ids id集合(逗号分隔)
*/ * @return
*/
boolean deleteLogic(@NotEmpty List<Integer> ids); boolean deleteLogic(@NotEmpty List<Integer> ids);
} }

View File

@ -35,6 +35,7 @@ import java.util.List;
* *
* @param <M> mapper * @param <M> mapper
* @param <T> model * @param <T> model
* @author smallchill
*/ */
@Validated @Validated
public class BaseServiceImpl<M extends BaseMapper<T>, T extends BaseEntity> extends ServiceImpl<M, T> implements BaseService<T> { public class BaseServiceImpl<M extends BaseMapper<T>, T extends BaseEntity> extends ServiceImpl<M, T> implements BaseService<T> {

View File

@ -23,6 +23,8 @@ import java.util.stream.Collectors;
/** /**
* 视图包装基类 * 视图包装基类
*
* @author smallchill
*/ */
public abstract class BaseEntityWrapper<E, V> { public abstract class BaseEntityWrapper<E, V> {

View File

@ -25,6 +25,8 @@ import java.util.Map;
/** /**
* 分页工具 * 分页工具
*
* @author smallchill
*/ */
public class Condition { public class Condition {

View File

@ -21,33 +21,35 @@ import lombok.Data;
/** /**
* 分页工具 * 分页工具
*
* @author smallchill
*/ */
@Data @Data
@ApiModel(description = "查询条件") @ApiModel(description = "查询条件")
public class Query { public class Query {
/** /**
* 当前页 * 当前页
*/ */
@ApiModelProperty(value = "当前页") @ApiModelProperty(value = "当前页")
private Integer current; private Integer current;
/** /**
* 每页的数量 * 每页的数量
*/ */
@ApiModelProperty(value = "每页的数量") @ApiModelProperty(value = "每页的数量")
private Integer size; private Integer size;
/** /**
* 排序的字段名 * 排序的字段名
*/ */
@ApiModelProperty(value = "升序字段") @ApiModelProperty(value = "升序字段")
private String ascs; private String ascs;
/** /**
* 排序方式 * 排序方式
*/ */
@ApiModelProperty(value = "降序字段") @ApiModelProperty(value = "降序字段")
private String descs; private String descs;
} }

View File

@ -21,6 +21,8 @@ import lombok.Data;
/** /**
* AuthInfo * AuthInfo
*
* @author smallchill
*/ */
@Data @Data
@ApiModel(description = "认证信息") @ApiModel(description = "认证信息")

View File

@ -15,12 +15,15 @@
*/ */
package org.springblade.core.secure; package org.springblade.core.secure;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data; import lombok.Data;
import java.io.Serializable; import java.io.Serializable;
/** /**
* 用户实体 * 用户实体
*
* @author smallchill
*/ */
@Data @Data
public class BladeUser implements Serializable { public class BladeUser implements Serializable {
@ -30,23 +33,27 @@ public class BladeUser implements Serializable {
/** /**
* 主键 * 主键
*/ */
@ApiModelProperty(hidden = true)
private Integer userId; private Integer userId;
/** /**
* 昵称 * 昵称
*/ */
@ApiModelProperty(hidden = true)
private String userName; private String userName;
/** /**
* 账号 * 账号
*/ */
@ApiModelProperty(hidden = true)
private String account; private String account;
/** /**
* 角色id * 角色id
*/ */
@ApiModelProperty(hidden = true)
private String roleId; private String roleId;
/** /**
* 角色名 * 角色名
*/ */
@ApiModelProperty(hidden = true)
private String roleName; private String roleName;
} }

View File

@ -20,6 +20,7 @@ import java.lang.annotation.*;
/** /**
* 权限注解 用于检查权限 规定访问权限 * 权限注解 用于检查权限 规定访问权限
* *
* @author smallchill
* @example @PreAuth("#userVO.id<10") * @example @PreAuth("#userVO.id<10")
* @example @PreAuth("hasRole(#test, #test1)") * @example @PreAuth("hasRole(#test, #test1)")
* @example @PreAuth("hasPermission(#test) and @PreAuth.hasPermission(#test)") * @example @PreAuth("hasPermission(#test) and @PreAuth.hasPermission(#test)")

View File

@ -39,6 +39,8 @@ import java.lang.reflect.Method;
/** /**
* AOP 鉴权 * AOP 鉴权
*
* @author smallchill
*/ */
@Aspect @Aspect
public class AuthAspect implements ApplicationContextAware { public class AuthAspect implements ApplicationContextAware {
@ -50,13 +52,14 @@ public class AuthAspect implements ApplicationContextAware {
/** /**
* 方法 类上的 @PreAuth 注解 * 方法 类上的 @PreAuth 注解
*
* @param point 切点 * @param point 切点
* @return Object * @return Object
* @throws Throwable 没有权限的异常 * @throws Throwable 没有权限的异常
*/ */
@Around( @Around(
"@annotation(org.springblade.core.secure.annotation.PreAuth) || " + "@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 { public Object preAuth(ProceedingJoinPoint point) throws Throwable {
if (handleAuth(point)) { if (handleAuth(point)) {
@ -91,7 +94,7 @@ public class AuthAspect implements ApplicationContextAware {
* 获取方法上的参数 * 获取方法上的参数
* *
* @param method 方法 * @param method 方法
* @param args 变量 * @param args 变量
* @return {SimpleEvaluationContext} * @return {SimpleEvaluationContext}
*/ */
private StandardEvaluationContext getEvaluationContext(Method method, Object[] args) { private StandardEvaluationContext getEvaluationContext(Method method, Object[] args) {

View File

@ -23,6 +23,8 @@ import org.springblade.core.tool.utils.StringUtil;
/** /**
* 权限判断 * 权限判断
*
* @author smallchill
*/ */
public class AuthFun { public class AuthFun {

View File

@ -24,6 +24,8 @@ import org.springframework.context.annotation.Configuration;
/** /**
* secure模块api放行默认配置 * secure模块api放行默认配置
*
* @author smallchill
*/ */
@Configuration @Configuration
@AutoConfigureBefore(SecureConfiguration.class) @AutoConfigureBefore(SecureConfiguration.class)

View File

@ -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.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* 配置类
*
* @author smallchill
*/
@Order @Order
@Configuration @Configuration
@AllArgsConstructor @AllArgsConstructor

View File

@ -21,6 +21,8 @@ import org.springblade.core.tool.api.ResultCode;
/** /**
* Secure异常 * Secure异常
*
* @author smallchill
*/ */
public class SecureException extends RuntimeException { public class SecureException extends RuntimeException {
private static final long serialVersionUID = 2359767895161832954L; private static final long serialVersionUID = 2359767895161832954L;

View File

@ -32,6 +32,8 @@ import java.util.Objects;
/** /**
* jwt拦截器校验 * jwt拦截器校验
*
* @author smallchill
*/ */
@Slf4j @Slf4j
public class SecureInterceptor extends HandlerInterceptorAdapter { public class SecureInterceptor extends HandlerInterceptorAdapter {

View File

@ -23,6 +23,8 @@ import java.util.List;
/** /**
* secure api放行配置 * secure api放行配置
*
* @author smallchill
*/ */
@Data @Data
public class SecureRegistry { public class SecureRegistry {

View File

@ -36,6 +36,8 @@ import java.util.Map;
/** /**
* Secure工具类 * Secure工具类
*
* @author smallchill
*/ */
public class SecureUtil { public class SecureUtil {
public static final String BLADE_USER_REQUEST_ATTR = "_BLADE_USER_REQUEST_ATTR_"; public static final String BLADE_USER_REQUEST_ATTR = "_BLADE_USER_REQUEST_ATTR_";
@ -91,9 +93,9 @@ public class SecureUtil {
} }
/** /**
* 获取用户id * 获取用户id
*
* @return * @return
*/ */
public static Integer getUserId() { public static Integer getUserId() {
@ -102,6 +104,7 @@ public class SecureUtil {
/** /**
* 获取用户id * 获取用户id
*
* @return * @return
*/ */
public static Integer getUserId(HttpServletRequest request) { public static Integer getUserId(HttpServletRequest request) {
@ -110,6 +113,7 @@ public class SecureUtil {
/** /**
* 获取用户账号 * 获取用户账号
*
* @return * @return
*/ */
public static String getUserAccount() { public static String getUserAccount() {
@ -118,6 +122,7 @@ public class SecureUtil {
/** /**
* 获取用户账号 * 获取用户账号
*
* @return * @return
*/ */
public static String getUserAccount(HttpServletRequest request) { public static String getUserAccount(HttpServletRequest request) {

View File

@ -39,6 +39,8 @@ import java.util.List;
/** /**
* swagger配置 * swagger配置
*
* @author smallchill
*/ */
@Configuration @Configuration
@EnableSwagger2 @EnableSwagger2
@ -47,90 +49,90 @@ import java.util.List;
@EnableConfigurationProperties(SwaggerProperties.class) @EnableConfigurationProperties(SwaggerProperties.class)
public class SwaggerAutoConfiguration { public class SwaggerAutoConfiguration {
private static final String DEFAULT_EXCLUDE_PATH = "/error"; private static final String DEFAULT_EXCLUDE_PATH = "/error";
private static final String BASE_PATH = "/**"; private static final String BASE_PATH = "/**";
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public SwaggerProperties swaggerProperties() { public SwaggerProperties swaggerProperties() {
return new SwaggerProperties(); return new SwaggerProperties();
} }
@Bean @Bean
public Docket api(SwaggerProperties swaggerProperties) { public Docket api(SwaggerProperties swaggerProperties) {
// base-path处理 // base-path处理
if (swaggerProperties.getBasePath().size() == 0) { if (swaggerProperties.getBasePath().size() == 0) {
swaggerProperties.getBasePath().add(BASE_PATH); swaggerProperties.getBasePath().add(BASE_PATH);
} }
//noinspection unchecked //noinspection unchecked
List<Predicate<String>> basePath = new ArrayList(); List<Predicate<String>> basePath = new ArrayList();
swaggerProperties.getBasePath().forEach(path -> basePath.add(PathSelectors.ant(path))); swaggerProperties.getBasePath().forEach(path -> basePath.add(PathSelectors.ant(path)));
// exclude-path处理 // exclude-path处理
if (swaggerProperties.getExcludePath().size() == 0) { if (swaggerProperties.getExcludePath().size() == 0) {
swaggerProperties.getExcludePath().add(DEFAULT_EXCLUDE_PATH); swaggerProperties.getExcludePath().add(DEFAULT_EXCLUDE_PATH);
} }
List<Predicate<String>> excludePath = new ArrayList<>(); List<Predicate<String>> excludePath = new ArrayList<>();
swaggerProperties.getExcludePath().forEach(path -> excludePath.add(PathSelectors.ant(path))); swaggerProperties.getExcludePath().forEach(path -> excludePath.add(PathSelectors.ant(path)));
//noinspection Guava //noinspection Guava
return new Docket(DocumentationType.SWAGGER_2) return new Docket(DocumentationType.SWAGGER_2)
.host(swaggerProperties.getHost()) .host(swaggerProperties.getHost())
.apiInfo(apiInfo(swaggerProperties)).select() .apiInfo(apiInfo(swaggerProperties)).select()
.apis(RequestHandlerSelectors.basePackage(swaggerProperties.getBasePackage())) .apis(RequestHandlerSelectors.basePackage(swaggerProperties.getBasePackage()))
.paths(Predicates.and(Predicates.not(Predicates.or(excludePath)), Predicates.or(basePath))) .paths(Predicates.and(Predicates.not(Predicates.or(excludePath)), Predicates.or(basePath)))
.build() .build()
.securitySchemes(Collections.singletonList(securitySchema())) .securitySchemes(Collections.singletonList(securitySchema()))
.securityContexts(Collections.singletonList(securityContext())) .securityContexts(Collections.singletonList(securityContext()))
.pathMapping("/" ); .pathMapping("/");
} }
/** /**
* 配置默认的全局鉴权策略的开关通过正则表达式进行匹配默认匹配所有URL * 配置默认的全局鉴权策略的开关通过正则表达式进行匹配默认匹配所有URL
* *
* @return * @return
*/ */
private SecurityContext securityContext() { private SecurityContext securityContext() {
return SecurityContext.builder() return SecurityContext.builder()
.securityReferences(defaultAuth()) .securityReferences(defaultAuth())
.forPaths(PathSelectors.regex(swaggerProperties().getAuthorization().getAuthRegex())) .forPaths(PathSelectors.regex(swaggerProperties().getAuthorization().getAuthRegex()))
.build(); .build();
} }
/** /**
* 默认的全局鉴权策略 * 默认的全局鉴权策略
* *
* @return * @return
*/ */
private List<SecurityReference> defaultAuth() { private List<SecurityReference> defaultAuth() {
ArrayList<AuthorizationScope> authorizationScopeList = new ArrayList<>(); ArrayList<AuthorizationScope> authorizationScopeList = new ArrayList<>();
swaggerProperties().getAuthorization().getAuthorizationScopeList().forEach(authorizationScope -> authorizationScopeList.add(new AuthorizationScope(authorizationScope.getScope(), authorizationScope.getDescription()))); swaggerProperties().getAuthorization().getAuthorizationScopeList().forEach(authorizationScope -> authorizationScopeList.add(new AuthorizationScope(authorizationScope.getScope(), authorizationScope.getDescription())));
AuthorizationScope[] authorizationScopes = new AuthorizationScope[authorizationScopeList.size()]; AuthorizationScope[] authorizationScopes = new AuthorizationScope[authorizationScopeList.size()];
return Collections.singletonList(SecurityReference.builder() return Collections.singletonList(SecurityReference.builder()
.reference(swaggerProperties().getAuthorization().getName()) .reference(swaggerProperties().getAuthorization().getName())
.scopes(authorizationScopeList.toArray(authorizationScopes)) .scopes(authorizationScopeList.toArray(authorizationScopes))
.build()); .build());
} }
private OAuth securitySchema() { private OAuth securitySchema() {
ArrayList<AuthorizationScope> authorizationScopeList = new ArrayList<>(); ArrayList<AuthorizationScope> authorizationScopeList = new ArrayList<>();
swaggerProperties().getAuthorization().getAuthorizationScopeList().forEach(authorizationScope -> authorizationScopeList.add(new AuthorizationScope(authorizationScope.getScope(), authorizationScope.getDescription()))); swaggerProperties().getAuthorization().getAuthorizationScopeList().forEach(authorizationScope -> authorizationScopeList.add(new AuthorizationScope(authorizationScope.getScope(), authorizationScope.getDescription())));
ArrayList<GrantType> grantTypes = new ArrayList<>(); ArrayList<GrantType> grantTypes = new ArrayList<>();
swaggerProperties().getAuthorization().getTokenUrlList().forEach(tokenUrl -> grantTypes.add(new ResourceOwnerPasswordCredentialsGrant(tokenUrl))); swaggerProperties().getAuthorization().getTokenUrlList().forEach(tokenUrl -> grantTypes.add(new ResourceOwnerPasswordCredentialsGrant(tokenUrl)));
return new OAuth(swaggerProperties().getAuthorization().getName(), authorizationScopeList, grantTypes); return new OAuth(swaggerProperties().getAuthorization().getName(), authorizationScopeList, grantTypes);
} }
private ApiInfo apiInfo(SwaggerProperties swaggerProperties) { private ApiInfo apiInfo(SwaggerProperties swaggerProperties) {
return new ApiInfoBuilder() return new ApiInfoBuilder()
.title(swaggerProperties.getTitle()) .title(swaggerProperties.getTitle())
.description(swaggerProperties.getDescription()) .description(swaggerProperties.getDescription())
.license(swaggerProperties.getLicense()) .license(swaggerProperties.getLicense())
.licenseUrl(swaggerProperties.getLicenseUrl()) .licenseUrl(swaggerProperties.getLicenseUrl())
.termsOfServiceUrl(swaggerProperties.getTermsOfServiceUrl()) .termsOfServiceUrl(swaggerProperties.getTermsOfServiceUrl())
.contact(new Contact(swaggerProperties.getContact().getName(), swaggerProperties.getContact().getUrl(), swaggerProperties.getContact().getEmail())) .contact(new Contact(swaggerProperties.getContact().getName(), swaggerProperties.getContact().getUrl(), swaggerProperties.getContact().getEmail()))
.version(swaggerProperties.getVersion()) .version(swaggerProperties.getVersion())
.build(); .build();
} }
} }

View File

@ -25,6 +25,8 @@ import java.util.List;
/** /**
* SwaggerProperties * SwaggerProperties
*
* @author smallchill
*/ */
@Data @Data
@RefreshScope @RefreshScope

View File

@ -19,11 +19,23 @@ import java.io.Serializable;
/** /**
* 业务代码接口 * 业务代码接口
*
* @author smallchill
*/ */
public interface IResultCode extends Serializable { public interface IResultCode extends Serializable {
String getMessage(); /**
* 消息
*
* @return
*/
String getMessage();
int getCode(); /**
* 状态码
*
* @return
*/
int getCode();
} }

View File

@ -28,6 +28,8 @@ import java.util.Optional;
/** /**
* 统一API响应结果封装 * 统一API响应结果封装
*
* @author smallchill
*/ */
@Getter @Getter
@Setter @Setter
@ -36,32 +38,32 @@ import java.util.Optional;
@NoArgsConstructor(access = AccessLevel.PRIVATE) @NoArgsConstructor(access = AccessLevel.PRIVATE)
public class R<T> implements Serializable { public class R<T> implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "状态码", required = true) @ApiModelProperty(value = "状态码", required = true)
private int code; private int code;
@ApiModelProperty(value = "是否成功", required = true) @ApiModelProperty(value = "是否成功", required = true)
private boolean success; private boolean success;
@ApiModelProperty(value = "承载数据") @ApiModelProperty(value = "承载数据")
private T data; private T data;
@ApiModelProperty(value = "返回消息", required = true) @ApiModelProperty(value = "返回消息", required = true)
private String msg; private String msg;
private R(IResultCode resultCode) { private R(IResultCode resultCode) {
this(resultCode, null, resultCode.getMessage()); this(resultCode, null, resultCode.getMessage());
} }
private R(IResultCode resultCode, String msg) { private R(IResultCode resultCode, String msg) {
this(resultCode, null, msg); this(resultCode, null, msg);
} }
private R(IResultCode resultCode, T data) { private R(IResultCode resultCode, T data) {
this(resultCode, data, resultCode.getMessage()); this(resultCode, data, resultCode.getMessage());
} }
private R(IResultCode resultCode, T data, String msg) { private R(IResultCode resultCode, T data, String msg) {
this(resultCode.getCode(), data, msg); this(resultCode.getCode(), data, msg);
} }
private R(int code, T data, String msg) { private R(int code, T data, String msg) {
this.code = code; this.code = code;
@ -92,97 +94,108 @@ public class R<T> implements Serializable {
return !R.isSuccess(result); return !R.isSuccess(result);
} }
/** /**
* 返回R * 返回R
* @param data 数据 *
*/ * @param data 数据
public static <T> R<T> data(T data) { */
return data(data, BladeConstant.DEFAULT_SUCCESS_MESSAGE); public static <T> R<T> data(T data) {
} return data(data, BladeConstant.DEFAULT_SUCCESS_MESSAGE);
}
/** /**
* 返回R * 返回R
* @param data 数据 *
* @param msg 消息 * @param data 数据
*/ * @param msg 消息
public static <T> R<T> data(T data, String msg) { */
return data(HttpServletResponse.SC_OK, data, msg); public static <T> R<T> data(T data, String msg) {
} return data(HttpServletResponse.SC_OK, data, msg);
}
/** /**
* 返回R * 返回R
* @param code 状态码 *
* @param data 数据 * @param code 状态码
* @param msg 消息 * @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); 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 * 返回R
* @param msg 消息 *
*/ * @param msg 消息
public static <T> R<T> success(String msg) { */
return new R<>(ResultCode.SUCCESS, msg); public static <T> R<T> success(String msg) {
} return new R<>(ResultCode.SUCCESS, msg);
}
/** /**
* 返回R * 返回R
* @param resultCode 业务代码 *
*/ * @param resultCode 业务代码
public static <T> R<T> success(IResultCode resultCode) { */
return new R<>(resultCode); public static <T> R<T> success(IResultCode resultCode) {
} return new R<>(resultCode);
}
/** /**
* 返回R * 返回R
* @param resultCode 业务代码 *
*/ * @param resultCode 业务代码
public static <T> R<T> success(IResultCode resultCode, String msg) { */
return new R<>(resultCode, msg); public static <T> R<T> success(IResultCode resultCode, String msg) {
} return new R<>(resultCode, msg);
}
/** /**
* 返回R * 返回R
* @param msg 消息 *
*/ * @param msg 消息
public static <T> R<T> failure(String msg) { */
return new R<>(ResultCode.FAILURE, msg); public static <T> R<T> failure(String msg) {
} return new R<>(ResultCode.FAILURE, msg);
}
/** /**
* 返回R * 返回R
* @param code 状态码 *
* @param msg 消息 * @param code 状态码
*/ * @param msg 消息
public static <T> R<T> failure(int code, String msg) { */
return new R<>(code, null, msg); public static <T> R<T> failure(int code, String msg) {
} return new R<>(code, null, msg);
}
/** /**
* 返回R * 返回R
* @param resultCode 业务代码 *
*/ * @param resultCode 业务代码
public static <T> R<T> failure(IResultCode resultCode) { */
return new R<>(resultCode); public static <T> R<T> failure(IResultCode resultCode) {
} return new R<>(resultCode);
}
/** /**
* 返回R * 返回R
* @param resultCode 业务代码 *
*/ * @param resultCode 业务代码
public static <T> R<T> failure(IResultCode resultCode, String msg) { */
return new R<>(resultCode, msg); public static <T> R<T> failure(IResultCode resultCode, String msg) {
} return new R<>(resultCode, msg);
}
/** /**
* 返回R * 返回R
* @param flag 成功状态 *
*/ * @param flag 成功状态
public static R status(boolean flag) { */
return flag ? success(BladeConstant.DEFAULT_SUCCESS_MESSAGE) : failure(BladeConstant.DEFAULT_FAILURE_MESSAGE); public static R status(boolean flag) {
} return flag ? success(BladeConstant.DEFAULT_SUCCESS_MESSAGE) : failure(BladeConstant.DEFAULT_FAILURE_MESSAGE);
}
} }

View File

@ -22,84 +22,86 @@ import javax.servlet.http.HttpServletResponse;
/** /**
* 业务代码枚举 * 业务代码枚举
*
* @author smallchill
*/ */
@Getter @Getter
@AllArgsConstructor @AllArgsConstructor
public enum ResultCode implements IResultCode { 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 没找到请求 * 404 没找到请求
*/ */
NOT_FOUND(HttpServletResponse.SC_NOT_FOUND, "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编码 * code编码
*/ */
final int code; final int code;
/** /**
* 中文信息描述 * 中文信息描述
*/ */
final String message; final String message;
} }

View File

@ -34,6 +34,11 @@ import java.time.ZoneId;
import java.util.Locale; import java.util.Locale;
import java.util.TimeZone; import java.util.TimeZone;
/**
* Jackson配置类
*
* @author smallchill
*/
@Configuration @Configuration
@ConditionalOnClass(ObjectMapper.class) @ConditionalOnClass(ObjectMapper.class)
@AutoConfigureBefore(JacksonAutoConfiguration.class) @AutoConfigureBefore(JacksonAutoConfiguration.class)

View File

@ -33,6 +33,11 @@ import javax.servlet.DispatcherType;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.List; import java.util.List;
/**
* 消息配置类
*
* @author smallchill
*/
@Configuration @Configuration
@AllArgsConstructor @AllArgsConstructor
@Order(Ordered.HIGHEST_PRECEDENCE) @Order(Ordered.HIGHEST_PRECEDENCE)

View File

@ -23,17 +23,21 @@ import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order; import org.springframework.core.annotation.Order;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* 工具配置类
*
* @author smallchill
*/
@Configuration @Configuration
@Order(Ordered.HIGHEST_PRECEDENCE) @Order(Ordered.HIGHEST_PRECEDENCE)
public class ToolConfiguration implements WebMvcConfigurer { public class ToolConfiguration implements WebMvcConfigurer {
/** /**
* Spring上下文缓存 * Spring上下文缓存
*/ */
@Bean @Bean
public SpringUtil springUtils() { public SpringUtil springUtils() {
return new SpringUtil(); return new SpringUtil();
} }
} }

View File

@ -17,23 +17,25 @@ package org.springblade.core.tool.constant;
/** /**
* 系统常量 * 系统常量
*
* @author smallchill
*/ */
public interface BladeConstant { public interface BladeConstant {
/** /**
* 编码 * 编码
*/ */
String UTF_8 = "UTF-8"; String UTF_8 = "UTF-8";
/** /**
* JSON 资源 * JSON 资源
*/ */
String CONTENT_TYPE = "application/json; charset=utf-8"; 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"; String IS_DELETED_FIELD = "is_deleted";
/** /**
* 删除状态[0:正常,1:删除] * 删除状态[0:正常,1:删除]
*/ */
int DB_NOT_DELETED = 0; int DB_NOT_DELETED = 0;
int DB_IS_DELETED = 1; int DB_IS_DELETED = 1;
/** /**
* 用户锁定状态 * 用户锁定状态
@ -61,26 +63,26 @@ public interface BladeConstant {
int DB_ADMIN_NON_LOCKED = 0; int DB_ADMIN_NON_LOCKED = 0;
int DB_ADMIN_LOCKED = 1; int DB_ADMIN_LOCKED = 1;
/** /**
* 日志默认状态 * 日志默认状态
*/ */
String LOG_NORMAL_TYPE = "1"; String LOG_NORMAL_TYPE = "1";
/** /**
* 默认为空消息 * 默认为空消息
*/ */
String DEFAULT_NULL_MESSAGE = "暂无承载数据"; String DEFAULT_NULL_MESSAGE = "暂无承载数据";
/** /**
* 默认成功消息 * 默认成功消息
*/ */
String DEFAULT_SUCCESS_MESSAGE = "操作成功"; String DEFAULT_SUCCESS_MESSAGE = "操作成功";
/** /**
* 默认失败消息 * 默认失败消息
*/ */
String DEFAULT_FAILURE_MESSAGE = "操作失败"; String DEFAULT_FAILURE_MESSAGE = "操作失败";
/** /**
* 默认未授权消息 * 默认未授权消息
*/ */
String DEFAULT_UNAUTHORIZED_MESSAGE = "签名认证失败"; String DEFAULT_UNAUTHORIZED_MESSAGE = "签名认证失败";
} }

View File

@ -17,19 +17,21 @@ package org.springblade.core.tool.constant;
/** /**
* 系统默认角色 * 系统默认角色
*
* @author smallchill
*/ */
public class RoleConstant { 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 + "')";
} }

View File

@ -20,6 +20,8 @@ import lombok.Data;
/** /**
* Blade系统配置类 * Blade系统配置类
*
* @author smallchill
*/ */
@Data @Data
public class SystemConstant { public class SystemConstant {
@ -34,10 +36,10 @@ public class SystemConstant {
*/ */
private boolean remoteMode = false; 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 String downloadPath = "/download";
/** /**
* 图片压缩 * 图片压缩
*/ */
private boolean compress = false; private boolean compress = false;
/** /**
* 图片压缩比例 * 图片压缩比例
*/ */
private Double compressScale = 2.00; private Double compressScale = 2.00;
/** /**
* 图片缩放选择:true放大;false缩小 * 图片缩放选择:true放大;false缩小
*/ */
@ -89,12 +91,12 @@ public class SystemConstant {
return me; return me;
} }
public String getUploadRealPath() { public String getUploadRealPath() {
return (remoteMode ? remotePath : realPath) + uploadPath; return (remoteMode ? remotePath : realPath) + uploadPath;
} }
public String getUploadCtxPath() { public String getUploadCtxPath() {
return contextPath + uploadPath; return contextPath + uploadPath;
} }
} }

View File

@ -39,58 +39,58 @@ import java.util.*;
@Slf4j @Slf4j
public class JsonUtil { public class JsonUtil {
/** /**
* 将对象序列化成json字符串 * 将对象序列化成json字符串
* *
* @param value javaBean * @param value javaBean
* @return jsonString json字符串 * @return jsonString json字符串
*/ */
public static <T> String toJson(T value) { public static <T> String toJson(T value) {
try { try {
return getInstance().writeValueAsString(value); return getInstance().writeValueAsString(value);
} catch (Exception e) { } catch (Exception e) {
log.error(e.getMessage(), e); log.error(e.getMessage(), e);
} }
return null; return null;
} }
/** /**
* 将对象序列化成 json byte 数组 * 将对象序列化成 json byte 数组
* *
* @param object javaBean * @param object javaBean
* @return jsonString json字符串 * @return jsonString json字符串
*/ */
public static byte[] toJsonAsBytes(Object object) { public static byte[] toJsonAsBytes(Object object) {
try { try {
return getInstance().writeValueAsBytes(object); return getInstance().writeValueAsBytes(object);
} catch (JsonProcessingException e) { } catch (JsonProcessingException e) {
throw Exceptions.unchecked(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反序列化成对象 * 将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 typeReference 泛型类型
* @param <T> T 泛型标记 * @param <T> T 泛型标记
* @return Bean * @return Bean
*/ */
public static <T> T parse(String content, TypeReference<?> typeReference) { public static <T> T parse(String content, TypeReference<?> typeReference) {
@ -101,29 +101,29 @@ public class JsonUtil {
} }
} }
/** /**
* 将json byte 数组反序列化成对象 * 将json byte 数组反序列化成对象
* *
* @param bytes json bytes * @param bytes json bytes
* @param valueType class * @param valueType class
* @param <T> T 泛型标记 * @param <T> T 泛型标记
* @return Bean * @return Bean
*/ */
public static <T> T parse(byte[] bytes, Class<T> valueType) { public static <T> T parse(byte[] bytes, Class<T> valueType) {
try { try {
return getInstance().readValue(bytes, valueType); return getInstance().readValue(bytes, valueType);
} catch (IOException e) { } catch (IOException e) {
throw Exceptions.unchecked(e); throw Exceptions.unchecked(e);
} }
} }
/** /**
* 将json反序列化成对象 * 将json反序列化成对象
* *
* @param bytes bytes * @param bytes bytes
* @param typeReference 泛型类型 * @param typeReference 泛型类型
* @param <T> T 泛型标记 * @param <T> T 泛型标记
* @return Bean * @return Bean
*/ */
public static <T> T parse(byte[] bytes, TypeReference<?> typeReference) { public static <T> T parse(byte[] bytes, TypeReference<?> typeReference) {
@ -137,9 +137,9 @@ public class JsonUtil {
/** /**
* 将json反序列化成对象 * 将json反序列化成对象
* *
* @param in InputStream * @param in InputStream
* @param valueType class * @param valueType class
* @param <T> T 泛型标记 * @param <T> T 泛型标记
* @return Bean * @return Bean
*/ */
public static <T> T parse(InputStream in, Class<T> valueType) { public static <T> T parse(InputStream in, Class<T> valueType) {
@ -153,9 +153,9 @@ public class JsonUtil {
/** /**
* 将json反序列化成对象 * 将json反序列化成对象
* *
* @param in InputStream * @param in InputStream
* @param typeReference 泛型类型 * @param typeReference 泛型类型
* @param <T> T 泛型标记 * @param <T> T 泛型标记
* @return Bean * @return Bean
*/ */
public static <T> T parse(InputStream in, TypeReference<?> typeReference) { public static <T> T parse(InputStream in, TypeReference<?> typeReference) {
@ -166,74 +166,75 @@ public class JsonUtil {
} }
} }
/** /**
* 将json反序列化成List对象 * 将json反序列化成List对象
* @param content content *
* @param valueTypeRef class * @param content content
* @param <T> T 泛型标记 * @param valueTypeRef class
* @return * @param <T> T 泛型标记
*/ * @return
public static <T> List<T> parseArray(String content, Class<T> valueTypeRef) { */
try { public static <T> List<T> parseArray(String content, Class<T> valueTypeRef) {
try {
if (!StringUtil.startsWithIgnoreCase(content, "[")) { if (!StringUtil.startsWithIgnoreCase(content, "[")) {
content = "[" + content + "]"; content = "[" + content + "]";
} }
List<Map<String, Object>> list = getInstance().readValue(content, new TypeReference<List<T>>() { List<Map<String, Object>> list = getInstance().readValue(content, new TypeReference<List<T>>() {
}); });
List<T> result = new ArrayList<>(); List<T> result = new ArrayList<>();
for (Map<String, Object> map : list) { for (Map<String, Object> map : list) {
result.add(toPojo(map, valueTypeRef)); result.add(toPojo(map, valueTypeRef));
} }
return result; return result;
} catch (IOException e) { } catch (IOException e) {
log.error(e.getMessage(), e); log.error(e.getMessage(), e);
} }
return null; return null;
} }
public static Map<String, Object> toMap(String content) { public static Map<String, Object> toMap(String content) {
try { try {
return getInstance().readValue(content, Map.class); return getInstance().readValue(content, Map.class);
} catch (IOException e) { } catch (IOException e) {
log.error(e.getMessage(), e); log.error(e.getMessage(), e);
} }
return null; return null;
} }
public static <T> Map<String, T> toMap(String content, Class<T> valueTypeRef) { public static <T> Map<String, T> toMap(String content, Class<T> valueTypeRef) {
try { try {
Map<String, Map<String, Object>> map = getInstance().readValue(content, new TypeReference<Map<String, T>>() { Map<String, Map<String, Object>> map = getInstance().readValue(content, new TypeReference<Map<String, T>>() {
}); });
Map<String, T> result = new HashMap<>(); Map<String, T> result = new HashMap<>();
for (Map.Entry<String, Map<String, Object>> entry : map.entrySet()) { for (Map.Entry<String, Map<String, Object>> entry : map.entrySet()) {
result.put(entry.getKey(), toPojo(entry.getValue(), valueTypeRef)); result.put(entry.getKey(), toPojo(entry.getValue(), valueTypeRef));
} }
return result; return result;
} catch (IOException e) { } catch (IOException e) {
log.error(e.getMessage(), e); log.error(e.getMessage(), e);
} }
return null; return null;
} }
public static <T> T toPojo(Map fromValue, Class<T> toValueType) { public static <T> T toPojo(Map fromValue, Class<T> toValueType) {
return getInstance().convertValue(fromValue, toValueType); return getInstance().convertValue(fromValue, toValueType);
} }
/** /**
* 将json字符串转成 JsonNode * 将json字符串转成 JsonNode
* *
* @param jsonString jsonString * @param jsonString jsonString
* @return jsonString json字符串 * @return jsonString json字符串
*/ */
public static JsonNode readTree(String jsonString) { public static JsonNode readTree(String jsonString) {
try { try {
return getInstance().readTree(jsonString); return getInstance().readTree(jsonString);
} catch (IOException e) { } catch (IOException e) {
throw Exceptions.unchecked(e); throw Exceptions.unchecked(e);
} }
} }
/** /**
* 将json字符串转成 JsonNode * 将json字符串转成 JsonNode
@ -277,47 +278,47 @@ public class JsonUtil {
} }
} }
public static ObjectMapper getInstance() { public static ObjectMapper getInstance() {
return JacksonHolder.INSTANCE; return JacksonHolder.INSTANCE;
} }
private static class JacksonHolder { private static class JacksonHolder {
private static ObjectMapper INSTANCE = new JacksonObjectMapper(); private static ObjectMapper INSTANCE = new JacksonObjectMapper();
} }
public static class JacksonObjectMapper extends ObjectMapper { public static class JacksonObjectMapper extends ObjectMapper {
private static final long serialVersionUID = 4288193147502386170L; private static final long serialVersionUID = 4288193147502386170L;
private static final Locale CHINA = Locale.CHINA; private static final Locale CHINA = Locale.CHINA;
public JacksonObjectMapper() { public JacksonObjectMapper() {
super(); super();
//设置地点为中国 //设置地点为中国
super.setLocale(CHINA); super.setLocale(CHINA);
//去掉默认的时间戳格式 //去掉默认的时间戳格式
super.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); super.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
//设置为中国上海时区 //设置为中国上海时区
super.setTimeZone(TimeZone.getTimeZone(ZoneId.systemDefault())); super.setTimeZone(TimeZone.getTimeZone(ZoneId.systemDefault()));
//序列化时日期的统一格式 //序列化时日期的统一格式
super.setDateFormat(new SimpleDateFormat(DatePattern.NORM_DATETIME_PATTERN, Locale.CHINA)); super.setDateFormat(new SimpleDateFormat(DatePattern.NORM_DATETIME_PATTERN, Locale.CHINA));
//序列化处理 //序列化处理
super.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true); super.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
super.configure(JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER, true); super.configure(JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER, true);
super.findAndRegisterModules(); super.findAndRegisterModules();
//失败处理 //失败处理
super.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); super.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
super.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); super.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
//单引号处理 //单引号处理
super.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true); super.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
//反序列化时属性不存在的兼容处理s //反序列化时属性不存在的兼容处理s
super.getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); super.getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
//序列化处理 //序列化处理
super.setSerializerFactory(this.getSerializerFactory().withSerializerModifier(new BladeBeanSerializerModifier())); super.setSerializerFactory(this.getSerializerFactory().withSerializerModifier(new BladeBeanSerializerModifier()));
super.getSerializerProvider().setNullValueSerializer(BladeBeanSerializerModifier.NullJsonSerializers.STRING_JSON_SERIALIZER); super.getSerializerProvider().setNullValueSerializer(BladeBeanSerializerModifier.NullJsonSerializers.STRING_JSON_SERIALIZER);
//日期格式化 //日期格式化
super.registerModule(new BladeJavaTimeModule()); super.registerModule(new BladeJavaTimeModule());
super.findAndRegisterModules(); super.findAndRegisterModules();
} }
@Override @Override
public ObjectMapper copy() { public ObjectMapper copy() {

View File

@ -24,7 +24,7 @@ import java.util.List;
/** /**
* 节点基类 * 节点基类
* *
* @author zhuangqian * @author smallchill
*/ */
@Data @Data
public class BaseNode implements INode { public class BaseNode implements INode {
@ -32,7 +32,7 @@ public class BaseNode implements INode {
/** /**
* 主键ID * 主键ID
*/ */
protected Integer id; protected Integer id;
/** /**
* 父节点ID * 父节点ID
@ -43,6 +43,6 @@ public class BaseNode implements INode {
* 子孙节点 * 子孙节点
*/ */
@JsonInclude(JsonInclude.Include.NON_EMPTY) @JsonInclude(JsonInclude.Include.NON_EMPTY)
protected List<INode> children = new ArrayList<>(); protected List<INode> children = new ArrayList<>();
} }

View File

@ -21,17 +21,22 @@ import lombok.EqualsAndHashCode;
/** /**
* 森林节点类 * 森林节点类
*
* @author smallchill
*/ */
@Data @Data
@EqualsAndHashCode(callSuper = false) @EqualsAndHashCode(callSuper = false)
public class ForestNode extends BaseNode { public class ForestNode extends BaseNode {
private Object content;//节点内容 /**
* 节点内容
*/
private Object content;
public ForestNode(Integer id, Integer parentId, Object content) { public ForestNode(Integer id, Integer parentId, Object content) {
this.id = id; this.id = id;
this.parentId = parentId; this.parentId = parentId;
this.content = content; this.content = content;
} }
} }

View File

@ -21,7 +21,7 @@ import java.util.List;
/** /**
* 森林管理类 * 森林管理类
* *
* @author zhuangqian * @author smallchill
*/ */
public class ForestNodeManager<T extends INode> { public class ForestNodeManager<T extends INode> {

View File

@ -20,7 +20,7 @@ import java.util.List;
/** /**
* 森林节点归并类 * 森林节点归并类
* *
* @author zhuangqian * @author smallchill
*/ */
public class ForestNodeMerger { public class ForestNodeMerger {

View File

@ -20,7 +20,7 @@ import java.util.List;
/** /**
* Created by Blade. * Created by Blade.
* *
* @author zhuangqian * @author smallchill
*/ */
public interface INode { public interface INode {

View File

@ -8,7 +8,7 @@ import java.util.List;
/** /**
* Created by Blade. * Created by Blade.
* *
* @author zhuangqian * @author smallchill
*/ */
public class NodeTest { public class NodeTest {

View File

@ -20,6 +20,8 @@ import lombok.EqualsAndHashCode;
/** /**
* 树型节点类 * 树型节点类
*
* @author smallchill
*/ */
@Data @Data
@EqualsAndHashCode(callSuper = false) @EqualsAndHashCode(callSuper = false)

View File

@ -5,6 +5,8 @@ import lombok.Getter;
/** /**
* Bean属性 * Bean属性
*
* @author smallchill
*/ */
@Getter @Getter
@AllArgsConstructor @AllArgsConstructor

View File

@ -24,172 +24,177 @@ import java.util.HashMap;
/** /**
* 链式map * 链式map
*
* @author smallchill
*/ */
public class CMap extends CaseInsensitiveHashMap<String, Object> { public class CMap extends CaseInsensitiveHashMap<String, Object> {
private CMap(){ private CMap() {
} }
/** /**
* 创建CMap * 创建CMap
* @return CMap *
*/ * @return CMap
public static CMap init() { */
return new CMap(); public static CMap init() {
} return new CMap();
}
public static HashMap newHashMap() { public static HashMap newHashMap() {
return new HashMap(); return new HashMap();
} }
/** /**
* 设置列 * 设置列
* @param attr 属性 *
* @param value * @param attr 属性
* @return 本身 * @param value
*/ * @return 本身
public CMap set(String attr, Object value) { */
this.put(attr, value); public CMap set(String attr, Object value) {
return this; this.put(attr, value);
} return this;
}
/** /**
* 设置列当键或值为null时忽略 * 设置列当键或值为null时忽略
* @param attr 属性 *
* @param value * @param attr 属性
* @return 本身 * @param value
*/ * @return 本身
public CMap setIgnoreNull(String attr, Object value) { */
if(null != attr && null != value) { public CMap setIgnoreNull(String attr, Object value) {
set(attr, value); if (null != attr && null != value) {
} set(attr, value);
return this; }
} return this;
}
public Object getObj(String key) { public Object getObj(String key) {
return super.get(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 字段名 * @param <T> 值类型
* @return 字段值 * @param attr 字段名
*/ * @param defaultValue 默认值
public String getStr(String attr) { * @return 字段值
return Func.toStr(get(attr), null); */
} public <T> T get(String attr, T defaultValue) {
final Object result = get(attr);
return (T) (result != null ? result : defaultValue);
}
/** /**
* 获得特定类型值 * 获得特定类型值
* *
* @param attr 字段名 * @param attr 字段名
* @return 字段值 * @return 字段值
*/ */
public Integer getInt(String attr) { public String getStr(String attr) {
return Func.toInt(get(attr), -1); return Func.toStr(get(attr), null);
} }
/** /**
* 获得特定类型值 * 获得特定类型值
* *
* @param attr 字段名 * @param attr 字段名
* @return 字段值 * @return 字段值
*/ */
public Long getLong(String attr) { public Integer getInt(String attr) {
return Func.toLong(get(attr), -1l); return Func.toInt(get(attr), -1);
} }
/** /**
* 获得特定类型值 * 获得特定类型值
* *
* @param attr 字段名 * @param attr 字段名
* @return 字段值 * @return 字段值
*/ */
public Float getFloat(String attr) { public Long getLong(String attr) {
return Func.toFloat(get(attr), null); return Func.toLong(get(attr), -1l);
} }
public Double getDouble(String attr) { /**
return Func.toDouble(get(attr), null);
}
/**
* 获得特定类型值 * 获得特定类型值
* *
* @param attr 字段名 * @param attr 字段名
* @return 字段值 * @return 字段值
*/ */
public Boolean getBool(String attr) { public Float getFloat(String attr) {
return Func.toBoolean(get(attr), null); return Func.toFloat(get(attr), null);
} }
/** public Double getDouble(String attr) {
return Func.toDouble(get(attr), null);
}
/**
* 获得特定类型值 * 获得特定类型值
* *
* @param attr 字段名 * @param attr 字段名
* @return 字段值 * @return 字段值
*/ */
public byte[] getBytes(String attr) { public Boolean getBool(String attr) {
return get(attr, null); return Func.toBoolean(get(attr), null);
} }
/** /**
* 获得特定类型值 * 获得特定类型值
* *
* @param attr 字段名 * @param attr 字段名
* @return 字段值 * @return 字段值
*/ */
public Date getDate(String attr) { public byte[] getBytes(String attr) {
return get(attr, null); return get(attr, null);
} }
/** /**
* 获得特定类型值 * 获得特定类型值
* *
* @param attr 字段名 * @param attr 字段名
* @return 字段值 * @return 字段值
*/ */
public Time getTime(String attr) { public Date getDate(String attr) {
return get(attr, null); return get(attr, null);
} }
/** /**
* 获得特定类型值 * 获得特定类型值
* *
* @param attr 字段名 * @param attr 字段名
* @return 字段值 * @return 字段值
*/ */
public Timestamp getTimestamp(String attr) { public Time getTime(String attr) {
return get(attr, null); return get(attr, null);
} }
/** /**
* 获得特定类型值 * 获得特定类型值
* *
* @param attr 字段名 * @param attr 字段名
* @return 字段值 * @return 字段值
*/ */
public Number getNumber(String attr) { public Timestamp getTimestamp(String attr) {
return get(attr, null); return get(attr, null);
} }
/**
* 获得特定类型值
*
* @param attr 字段名
* @return 字段值
*/
public Number getNumber(String attr) {
return get(attr, null);
}
@Override @Override
public CMap clone() { public CMap clone() {
return (CMap) super.clone(); return (CMap) super.clone();

View File

@ -17,52 +17,58 @@ package org.springblade.core.tool.support;
import java.util.*; 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 @Override
public boolean containsKey(Object key) { public Object get(Object key) {
Object realKey = lowerCaseMap.get(key.toString().toLowerCase(Locale.ENGLISH)); Object realKey = lowerCaseMap.get(key.toString().toLowerCase(Locale.ENGLISH));
return super.containsKey(realKey); return super.get(realKey);
} }
@Override @Override
public Object get(Object key) { public Set keySet() {
Object realKey = lowerCaseMap.get(key.toString().toLowerCase(Locale.ENGLISH)); return lowerCaseMap.keySet();
return super.get(realKey); }
}
@Override @Override
public Set keySet() { public Object put(String key, Object value) {
return lowerCaseMap.keySet(); Object oldKey = lowerCaseMap.put(key.toLowerCase(Locale.ENGLISH), key);
} Object oldValue = super.remove(oldKey);
super.put(key, value);
return oldValue;
}
@Override @Override
public Object put(String key, Object value) { public void putAll(Map<? extends String, ?> m) {
Object oldKey = lowerCaseMap.put(key.toLowerCase(Locale.ENGLISH), key); for (Map.Entry<? extends String, ?> entry : m.entrySet()) {
Object oldValue = super.remove(oldKey); String key = entry.getKey();
super.put(key, value); Object value = entry.getValue();
return oldValue; this.put(key, value);
} }
}
@Override @Override
public void putAll(Map<? extends String, ?> m) { public Object remove(Object key) {
for (Map.Entry<? extends String, ?> entry : m.entrySet()) { Object realKey = lowerCaseMap.remove(key.toString().toLowerCase(Locale.ENGLISH));
String key = entry.getKey(); return super.remove(realKey);
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);
}
} }

View File

@ -19,6 +19,8 @@ import java.io.OutputStream;
/** /**
* A factory for creating MultiOutputStream objects. * A factory for creating MultiOutputStream objects.
*
* @author smallchill
*/ */
public interface IMultiOutputStream { public interface IMultiOutputStream {
@ -28,6 +30,6 @@ public interface IMultiOutputStream {
* @param params the params * @param params the params
* @return the output stream * @return the output stream
*/ */
OutputStream buildOutputStream(Integer... params) ; OutputStream buildOutputStream(Integer... params);
} }

View File

@ -15,74 +15,99 @@
*/ */
package org.springblade.core.tool.support; package org.springblade.core.tool.support;
/**
* 图片操作类
*
* @author smallchill
*/
public class ImagePosition { public class ImagePosition {
/** 图片顶部. */ /**
* 图片顶部.
*/
public static final int TOP = 32; public static final int TOP = 32;
/** 图片中部. */ /**
* 图片中部.
*/
public static final int MIDDLE = 16; public static final int MIDDLE = 16;
/** 图片底部. */ /**
* 图片底部.
*/
public static final int BOTTOM = 8; public static final int BOTTOM = 8;
/** 图片左侧. */ /**
* 图片左侧.
*/
public static final int LEFT = 4; public static final int LEFT = 4;
/** 图片居中. */ /**
* 图片居中.
*/
public static final int CENTER = 2; public static final int CENTER = 2;
/** 图片右侧. */ /**
* 图片右侧.
*/
public static final int RIGHT = 1; public static final int RIGHT = 1;
/** 横向边距,靠左或靠右时和边界的距离. */ /**
* 横向边距靠左或靠右时和边界的距离.
*/
private static final int PADDING_HORI = 6; private static final int PADDING_HORI = 6;
/** 纵向边距,靠上或靠底时和边界的距离. */ /**
* 纵向边距靠上或靠底时和边界的距离.
*/
private static final int PADDING_VERT = 6; private static final int PADDING_VERT = 6;
/** 图片中盒[左上角]的x坐标. */ /**
private int boxPosX ; * 图片中盒[左上角]的x坐标.
*/
/** 图片中盒[左上角]的y坐标. */ private int boxPosX;
private int boxPosY ;
/**
* 图片中盒[左上角]的y坐标.
*/
private int boxPosY;
/** /**
* Instantiates a new image position. * Instantiates a new image position.
* *
* @param width the width * @param width the width
* @param height the height * @param height the height
* @param boxWidth the box width * @param boxWidth the box width
* @param boxHeight the box height * @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 ) { public ImagePosition(int width, int height, int boxWidth, int boxHeight, int style) {
switch(style & 7) { switch (style & 7) {
case LEFT: case LEFT:
boxPosX = PADDING_HORI; boxPosX = PADDING_HORI;
break; break;
case RIGHT: case RIGHT:
boxPosX = width - boxWidth - PADDING_HORI; boxPosX = width - boxWidth - PADDING_HORI;
break; break;
case CENTER: case CENTER:
default: default:
boxPosX = (width - boxWidth)/2; boxPosX = (width - boxWidth) / 2;
} }
switch(style >> 3 << 3) { switch (style >> 3 << 3) {
case TOP: case TOP:
boxPosY = PADDING_VERT; boxPosY = PADDING_VERT;
break; break;
case MIDDLE: case MIDDLE:
boxPosY = (height - boxHeight)/2; boxPosY = (height - boxHeight) / 2;
break; break;
case BOTTOM: case BOTTOM:
default: default:
boxPosY = height - boxHeight - PADDING_VERT; boxPosY = height - boxHeight - PADDING_VERT;
} }
} }
/** /**
* Gets the x. * Gets the x.
* *
@ -91,7 +116,7 @@ public class ImagePosition {
public int getX() { public int getX() {
return getX(0); return getX(0);
} }
/** /**
* Gets the x. * Gets the x.
* *
@ -101,7 +126,7 @@ public class ImagePosition {
public int getX(int x) { public int getX(int x) {
return this.boxPosX + x; return this.boxPosX + x;
} }
/** /**
* Gets the y. * Gets the y.
* *
@ -110,7 +135,7 @@ public class ImagePosition {
public int getY() { public int getY() {
return getY(0); return getY(0);
} }
/** /**
* Gets the y. * Gets the y.
* *
@ -120,5 +145,5 @@ public class ImagePosition {
public int getY(int y) { public int getY(int y) {
return this.boxPosY + y; return this.boxPosY + y;
} }
} }

View File

@ -3,65 +3,92 @@ package org.springblade.core.tool.support;
import org.springblade.core.tool.utils.Func; import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.StringPool; import org.springblade.core.tool.utils.StringPool;
/**
* 字符串格式化
*
* @author smallchill
*/
public class StrFormatter { public class StrFormatter {
/** /**
* 格式化字符串<br> * 格式化字符串<br>
* 此方法只是简单将占位符 {} 按照顺序替换为参数<br> * 此方法只是简单将占位符 {} 按照顺序替换为参数<br>
* 如果想输出 {} 使用 \\转义 { 即可如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可<br> * 如果想输出 {} 使用 \\转义 { 即可如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可<br>
* <br> * <br>
* 通常使用format("this is {} for {}", "a", "b") = this is a for b<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 \{} for a<br>
* 转义\ format("this is \\\\{} for {}", "a", "b") = this is \a for b<br> * 转义\ format("this is \\\\{} for {}", "a", "b") = this is \a for b<br>
* @param strPattern 字符串模板 *
* @param argArray 参数列表 * @param strPattern 字符串模板
* @return 结果 * @param argArray 参数列表
*/ * @return 结果
public static String format(final String strPattern, final Object... argArray) { */
if (Func.isBlank(strPattern) || Func.isEmpty(argArray)) { public static String format(final String strPattern, final Object... argArray) {
return strPattern; if (Func.isBlank(strPattern) || Func.isEmpty(argArray)) {
} return strPattern;
final int strPatternLength = strPattern.length(); }
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); int handledPosition = 0;
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(); /**
} * 占位符所在位置
*/
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();
}
} }

View File

@ -11,489 +11,494 @@ import java.util.regex.Pattern;
/** /**
* 字符串切分器 * 字符串切分器
* @author Looly
* *
* @author Looly
*/ */
public class StrSpliter { public class StrSpliter {
//---------------------------------------------------------------------------------------------- Split by char //---------------------------------------------------------------------------------------------- Split by char
/**
* 切分字符串路径仅支持Unix分界符/
*
* @param str 被切分的字符串
* @return 切分后的集合
* @since 3.0.8
*/
public static List<String> splitPath(String str){
return splitPath(str, 0);
}
/** /**
* 切分字符串路径仅支持Unix分界符/ * 切分字符串路径仅支持Unix分界符/
* *
* @param str 被切分的字符串 * @param str 被切分的字符串
* @return 切分后的集合 * @return 切分后的集合
* @since 3.0.8 * @since 3.0.8
*/ */
public static String[] splitPathToArray(String str){ public static List<String> splitPath(String str) {
return toArray(splitPath(str)); return splitPath(str, 0);
} }
/** /**
* 切分字符串路径仅支持Unix分界符/ * 切分字符串路径仅支持Unix分界符/
* *
* @param str 被切分的字符串 * @param str 被切分的字符串
* @param limit 限制分片数 * @return 切分后的集合
* @return 切分后的集合 * @since 3.0.8
* @since 3.0.8 */
*/ public static String[] splitPathToArray(String str) {
public static List<String> splitPath(String str, int limit){ return toArray(splitPath(str));
return split(str, StringPool.SLASH, limit, true, true); }
}
/** /**
* 切分字符串路径仅支持Unix分界符/ * 切分字符串路径仅支持Unix分界符/
* *
* @param str 被切分的字符串 * @param str 被切分的字符串
* @param limit 限制分片数 * @param limit 限制分片数
* @return 切分后的集合 * @return 切分后的集合
* @since 3.0.8 * @since 3.0.8
*/ */
public static String[] splitPathToArray(String str, int limit){ public static List<String> splitPath(String str, int limit) {
return toArray(splitPath(str, limit)); return split(str, StringPool.SLASH, limit, true, true);
} }
/** /**
* 切分字符串 * 切分字符串路径仅支持Unix分界符/
* *
* @param str 被切分的字符串 * @param str 被切分的字符串
* @param separator 分隔符字符 * @param limit 限制分片数
* @param ignoreEmpty 是否忽略空串 * @return 切分后的集合
* @return 切分后的集合 * @since 3.0.8
* @since 3.2.1 */
*/ public static String[] splitPathToArray(String str, int limit) {
public static List<String> splitTrim(String str, char separator, boolean ignoreEmpty){ return toArray(splitPath(str, limit));
return split(str, separator, 0, true, ignoreEmpty); }
}
/** /**
* 切分字符串 * 切分字符串
* *
* @param str 被切分的字符串 * @param str 被切分的字符串
* @param separator 分隔符字符 * @param separator 分隔符字符
* @param isTrim 是否去除切分字符串后每个元素两边的空格 * @param ignoreEmpty 是否忽略空串
* @param ignoreEmpty 是否忽略空串 * @return 切分后的集合
* @return 切分后的集合 * @since 3.2.1
* @since 3.0.8 */
*/ public static List<String> splitTrim(String str, char separator, boolean ignoreEmpty) {
public static List<String> split(String str, char separator, boolean isTrim, boolean ignoreEmpty){ return split(str, separator, 0, true, ignoreEmpty);
return split(str, separator, 0, isTrim, ignoreEmpty); }
}
/** /**
* 切分字符串大小写敏感去除每个元素两边空白符 * 切分字符串
* *
* @param str 被切分的字符串 * @param str 被切分的字符串
* @param separator 分隔符字符 * @param separator 分隔符字符
* @param limit 限制分片数-1不限制 * @param isTrim 是否去除切分字符串后每个元素两边的空格
* @param ignoreEmpty 是否忽略空串 * @param ignoreEmpty 是否忽略空串
* @return 切分后的集合 * @return 切分后的集合
* @since 3.0.8 * @since 3.0.8
*/ */
public static List<String> splitTrim(String str, char separator, int limit, boolean ignoreEmpty){ public static List<String> split(String str, char separator, boolean isTrim, boolean ignoreEmpty) {
return split(str, separator, limit, true, ignoreEmpty, false); return split(str, separator, 0, isTrim, ignoreEmpty);
} }
/** /**
* 切分字符串大小写敏感 * 切分字符串大小写敏感去除每个元素两边空白符
* *
* @param str 被切分的字符串 * @param str 被切分的字符串
* @param separator 分隔符字符 * @param separator 分隔符字符
* @param limit 限制分片数-1不限制 * @param limit 限制分片数-1不限制
* @param isTrim 是否去除切分字符串后每个元素两边的空格 * @param ignoreEmpty 是否忽略空串
* @param ignoreEmpty 是否忽略空串 * @return 切分后的集合
* @return 切分后的集合 * @since 3.0.8
* @since 3.0.8 */
*/ public static List<String> splitTrim(String str, char separator, int limit, boolean ignoreEmpty) {
public static List<String> split(String str, char separator, int limit, boolean isTrim, boolean ignoreEmpty){ return split(str, separator, limit, true, ignoreEmpty, false);
return split(str, separator, limit, isTrim, ignoreEmpty, false); }
}
/** /**
* 切分字符串忽略大小写 * 切分字符串大小写敏感
* *
* @param str 被切分的字符串 * @param str 被切分的字符串
* @param separator 分隔符字符 * @param separator 分隔符字符
* @param limit 限制分片数-1不限制 * @param limit 限制分片数-1不限制
* @param isTrim 是否去除切分字符串后每个元素两边的空格 * @param isTrim 是否去除切分字符串后每个元素两边的空格
* @param ignoreEmpty 是否忽略空串 * @param ignoreEmpty 是否忽略空串
* @return 切分后的集合 * @return 切分后的集合
* @since 3.2.1 * @since 3.0.8
*/ */
public static List<String> splitIgnoreCase(String str, char separator, int limit, boolean isTrim, boolean ignoreEmpty){ public static List<String> split(String str, char separator, int limit, boolean isTrim, boolean ignoreEmpty) {
return split(str, separator, limit, isTrim, ignoreEmpty, true); return split(str, separator, limit, isTrim, ignoreEmpty, false);
} }
/** /**
* 切分字符串 * 切分字符串忽略大小写
* *
* @param str 被切分的字符串 * @param str 被切分的字符串
* @param separator 分隔符字符 * @param separator 分隔符字符
* @param limit 限制分片数-1不限制 * @param limit 限制分片数-1不限制
* @param isTrim 是否去除切分字符串后每个元素两边的空格 * @param isTrim 是否去除切分字符串后每个元素两边的空格
* @param ignoreEmpty 是否忽略空串 * @param ignoreEmpty 是否忽略空串
* @param ignoreCase 是否忽略大小写 * @return 切分后的集合
* @return 切分后的集合 * @since 3.2.1
* @since 3.2.1 */
*/ public static List<String> splitIgnoreCase(String str, char separator, int limit, boolean isTrim, boolean ignoreEmpty) {
public static List<String> split(String str, char separator, int limit, boolean isTrim, boolean ignoreEmpty, boolean ignoreCase){ return split(str, separator, limit, isTrim, ignoreEmpty, true);
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<>(limit > 0 ? limit : 16); /**
int len = str.length(); * 切分字符串
int start = 0;//切分后每个部分的起始 *
for(int i = 0; i < len; i++){ * @param str 被切分的字符串
if(Func.equals(separator, str.charAt(i))){ * @param separator 分隔符字符
addToList(list, str.substring(start, i), isTrim, ignoreEmpty); * @param limit 限制分片数-1不限制
start = i+1;//i+1同时将start与i保持一致 * @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个剩下一个留给末尾字符串 final ArrayList<String> list = new ArrayList<>(limit > 0 ? limit : 16);
if(limit > 0 && list.size() > limit-2){ int len = str.length();
break; 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);
return addToList(list, str.substring(start, len), isTrim, ignoreEmpty);//收尾 start = i + 1;//i+1同时将start与i保持一致
}
/** //检查是否超出范围最大允许limit-1个剩下一个留给末尾字符串
* 切分字符串为字符串数组 if (limit > 0 && list.size() > limit - 2) {
* break;
* @param str 被切分的字符串 }
* @param separator 分隔符字符 }
* @param limit 限制分片数 }
* @param isTrim 是否去除切分字符串后每个元素两边的空格 return addToList(list, str.substring(start, len), isTrim, ignoreEmpty);//收尾
* @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));
}
//---------------------------------------------------------------------------------------------- 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));
}
/** //---------------------------------------------------------------------------------------------- Split by String
* 切分字符串不忽略大小写
*
* @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 str 被切分的字符串
* @param separator 分隔符字符串 * @param separator 分隔符字符串
* @param ignoreEmpty 是否忽略空串 * @param isTrim 是否去除切分字符串后每个元素两边的空格
* @return 切分后的集合 * @param ignoreEmpty 是否忽略空串
* @since 3.2.1 * @return 切分后的集合
*/ * @since 3.0.8
public static List<String> splitTrim(String str, String separator, boolean ignoreEmpty){ */
return split(str, separator, true, ignoreEmpty); public static List<String> split(String str, String separator, boolean isTrim, boolean ignoreEmpty) {
} return split(str, separator, -1, isTrim, ignoreEmpty, false);
}
/** /**
* 切分字符串不忽略大小写 * 切分字符串去除每个元素两边空格忽略大小写
* *
* @param str 被切分的字符串 * @param str 被切分的字符串
* @param separator 分隔符字符串 * @param separator 分隔符字符串
* @param limit 限制分片数 * @param ignoreEmpty 是否忽略空串
* @param isTrim 是否去除切分字符串后每个元素两边的空格 * @return 切分后的集合
* @param ignoreEmpty 是否忽略空串 * @since 3.2.1
* @return 切分后的集合 */
* @since 3.0.8 public static List<String> splitTrim(String str, String separator, boolean ignoreEmpty) {
*/ return split(str, separator, true, ignoreEmpty);
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 str 被切分的字符串
* @param separator 分隔符字符串 * @param separator 分隔符字符串
* @param limit 限制分片数 * @param limit 限制分片数
* @param ignoreEmpty 是否忽略空串 * @param isTrim 是否去除切分字符串后每个元素两边的空格
* @return 切分后的集合 * @param ignoreEmpty 是否忽略空串
* @since 3.2.1 * @return 切分后的集合
*/ * @since 3.0.8
public static List<String> splitTrim(String str, String separator, int limit, boolean ignoreEmpty){ */
return split(str, separator, limit, true, ignoreEmpty); 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 str 被切分的字符串
* @param separator 分隔符字符串 * @param separator 分隔符字符串
* @param limit 限制分片数 * @param limit 限制分片数
* @param isTrim 是否去除切分字符串后每个元素两边的空格 * @param ignoreEmpty 是否忽略空串
* @param ignoreEmpty 是否忽略空串 * @return 切分后的集合
* @return 切分后的集合 * @since 3.2.1
* @since 3.2.1 */
*/ public static List<String> splitTrim(String str, String separator, int limit, boolean ignoreEmpty) {
public static List<String> splitIgnoreCase(String str, String separator, int limit, boolean isTrim, boolean ignoreEmpty){ return split(str, separator, limit, true, ignoreEmpty);
return split(str, separator, limit, isTrim, ignoreEmpty, true); }
}
/** /**
* 切分字符串去除每个元素两边空格忽略大小写 * 切分字符串忽略大小写
* *
* @param str 被切分的字符串 * @param str 被切分的字符串
* @param separator 分隔符字符串 * @param separator 分隔符字符串
* @param limit 限制分片数 * @param limit 限制分片数
* @param ignoreEmpty 是否忽略空串 * @param isTrim 是否去除切分字符串后每个元素两边的空格
* @return 切分后的集合 * @param ignoreEmpty 是否忽略空串
* @since 3.2.1 * @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); 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 str 被切分的字符串
* @param separator 分隔符字符串 * @param separator 分隔符字符串
* @param limit 限制分片数 * @param limit 限制分片数
* @param isTrim 是否去除切分字符串后每个元素两边的空格 * @param ignoreEmpty 是否忽略空串
* @param ignoreEmpty 是否忽略空串 * @return 切分后的集合
* @param ignoreCase 是否忽略大小写 * @since 3.2.1
* @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);
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);
}
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<>(); if (StringUtil.isEmpty(separator)) {//分隔符为空时按照空白符切分
int len = str.length(); return split(str, limit);
int separatorLen = separator.length(); } else if (separator.length() == 1) {//分隔符只有一个字符长度时按照单分隔符切分
int start = 0; return split(str, separator.charAt(0), limit, isTrim, ignoreEmpty, ignoreCase);
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;
//检查是否超出范围最大允许limit-1个剩下一个留给末尾字符串 final ArrayList<String> list = new ArrayList<>();
if(limit > 0 && list.size() > limit-2){ int len = str.length();
break; int separatorLen = separator.length();
} int start = 0;
}else{ int i = 0;
break; while (i < len) {
} i = StringUtil.indexOf(str, separator, start, ignoreCase);
} if (i > -1) {
return addToList(list, str.substring(start, len), isTrim, ignoreEmpty); addToList(list, str.substring(start, i), isTrim, ignoreEmpty);
} start = i + separatorLen;
/** //检查是否超出范围最大允许limit-1个剩下一个留给末尾字符串
* 切分字符串为字符串数组 if (limit > 0 && list.size() > limit - 2) {
* break;
* @param str 被切分的字符串 }
* @param separator 分隔符字符 } else {
* @param limit 限制分片数 break;
* @param isTrim 是否去除切分字符串后每个元素两边的空格 }
* @param ignoreEmpty 是否忽略空串 }
* @return 切分后的集合 return addToList(list, str.substring(start, len), isTrim, ignoreEmpty);
* @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));
}
//---------------------------------------------------------------------------------------------- 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));
}
/** //---------------------------------------------------------------------------------------------- Split by Whitespace
* 使用空白符切分字符串<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);
}
final ArrayList<String> list = new ArrayList<>(); /**
int len = str.length(); * 使用空白符切分字符串<br>
int start = 0;//切分后每个部分的起始 * 切分后的字符串两边不包含空白符空串或空白符串并不做为元素之一
for(int i = 0; i < len; i++){ *
if(Func.isEmpty(str.charAt(i))){ * @param str 被切分的字符串
addToList(list, str.substring(start, i), true, true); * @param limit 限制分片数
start = i+1;//i+1同时将start与i保持一致 * @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个剩下一个留给末尾字符串 final ArrayList<String> list = new ArrayList<>();
if(limit > 0 && list.size() > limit-2){ int len = str.length();
break; int start = 0;//切分后每个部分的起始
} for (int i = 0; i < len; i++) {
} if (Func.isEmpty(str.charAt(i))) {
} addToList(list, str.substring(start, i), true, true);
return addToList(list, str.substring(start, len), true, true);//收尾 start = i + 1;//i+1同时将start与i保持一致
}
/** //检查是否超出范围最大允许limit-1个剩下一个留给末尾字符串
* 切分字符串为字符串数组 if (limit > 0 && list.size() > limit - 2) {
* break;
* @param str 被切分的字符串 }
* @param limit 限制分片数 }
* @return 切分后的集合 }
* @since 3.0.8 return addToList(list, str.substring(start, len), true, true);//收尾
*/ }
public static String[] splitToArray(String str, int limit){
return toArray(split(str, limit));
}
//---------------------------------------------------------------------------------------------- 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));
}
/** //---------------------------------------------------------------------------------------------- Split by regex
* 通过正则切分字符串
* @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);
}
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); if (null == separatorPattern) {//分隔符为空时按照空白符切分
final ArrayList<String> list = new ArrayList<>(); return split(str, limit);
int len = str.length(); }
int start = 0;
while(matcher.find()){
addToList(list, str.substring(start, matcher.start()), isTrim, ignoreEmpty);
start = matcher.end();
//检查是否超出范围最大允许limit-1个剩下一个留给末尾字符串 final Matcher matcher = separatorPattern.matcher(str);
if(limit > 0 && list.size() > limit-2){ final ArrayList<String> list = new ArrayList<>();
break; int len = str.length();
} int start = 0;
} while (matcher.find()) {
return addToList(list, str.substring(start, len), isTrim, ignoreEmpty); addToList(list, str.substring(start, matcher.start()), isTrim, ignoreEmpty);
} start = matcher.end();
/** //检查是否超出范围最大允许limit-1个剩下一个留给末尾字符串
* 通过正则切分字符串为字符串数组 if (limit > 0 && list.size() > limit - 2) {
* break;
* @param str 被切分的字符串 }
* @param separatorPattern 分隔符正则{@link Pattern} }
* @param limit 限制分片数 return addToList(list, str.substring(start, len), isTrim, ignoreEmpty);
* @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));
}
//---------------------------------------------------------------------------------------------- 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));
}
/** //---------------------------------------------------------------------------------------------- Split by length
* 根据给定长度将给定字符串截取为多个部分
*
* @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;
}
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); * @param str 字符串
} else { * @param len 每一个小节的长度
strs[i] = str.substring(i * len, i * len + len); * @return 截取后的字符串数组
} */
} public static String[] splitByLength(String str, int len) {
return strs; int partCount = str.length() / len;
} int lastPartCount = str.length() % len;
int fixPart = 0;
if (lastPartCount != 0) {
fixPart = 1;
}
//---------------------------------------------------------------------------------------------------------- Private method start final String[] strs = new String[partCount + fixPart];
/** for (int i = 0; i < partCount + fixPart; i++) {
* 将字符串加入List中 if (i == partCount + fixPart - 1 && lastPartCount != 0) {
* @param list 列表 strs[i] = str.substring(i * len, i * len + lastPartCount);
* @param part 被加入的部分 } else {
* @param isTrim 是否去除两端空白符 strs[i] = str.substring(i * len, i * len + len);
* @param ignoreEmpty 是否略过空字符串空字符串不做为一个元素 }
* @return 列表 }
*/ return strs;
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;
}
/** //---------------------------------------------------------------------------------------------------------- Private method start
* List转Array
* @param list List /**
* @return Array * 将字符串加入List中
*/ *
private static String[] toArray(List<String> list){ * @param list 列表
return list.toArray(new String[list.size()]); * @param part 被加入的部分
} * @param isTrim 是否去除两端空白符
//---------------------------------------------------------------------------------------------------------- Private method end * @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
} }

View File

@ -8,6 +8,8 @@ import java.util.function.Function;
/** /**
* Lambda 遇上受检异常 * Lambda 遇上受检异常
* https://segmentfault.com/a/1190000007832130 * https://segmentfault.com/a/1190000007832130
*
* @author smallchill
*/ */
public class Try { public class Try {

View File

@ -41,514 +41,514 @@ import java.util.regex.Pattern;
*/ */
public final class HTMLFilter { public final class HTMLFilter {
/** /**
* regex flag union representing /si modifiers in php * regex flag union representing /si modifiers in php
**/ **/
private static final int REGEX_FLAGS_SI = Pattern.CASE_INSENSITIVE | Pattern.DOTALL; 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_COMMENTS = Pattern.compile("<!--(.*?)-->", Pattern.DOTALL);
private static final Pattern P_COMMENT = Pattern.compile("^!--(.*)--$", REGEX_FLAGS_SI); 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_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_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_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_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_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_PROTOCOL = Pattern.compile("^([^:]+):", REGEX_FLAGS_SI);
private static final Pattern P_ENTITY = Pattern.compile("&#(\\d+);?"); 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_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_ENCODE = Pattern.compile("%([0-9a-f]{2});?");
private static final Pattern P_VALID_ENTITIES = Pattern.compile("&([^&;]*)(?=(;|&|$))"); 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_VALID_QUOTES = Pattern.compile("(>|^)([^<]+?)(<|$)", Pattern.DOTALL);
private static final Pattern P_END_ARROW = Pattern.compile("^>"); private static final Pattern P_END_ARROW = Pattern.compile("^>");
private static final Pattern P_BODY_TO_END = 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_XML_CONTENT = Pattern.compile("(^|>)([^<]*?)(?=>)");
private static final Pattern P_STRAY_LEFT_ARROW = 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_STRAY_RIGHT_ARROW = Pattern.compile("(^|>)([^<]*?)(?=>)");
private static final Pattern P_AMP = Pattern.compile("&"); private static final Pattern P_AMP = Pattern.compile("&");
private static final Pattern P_QUOTE = Pattern.compile("<"); private static final Pattern P_QUOTE = Pattern.compile("<");
private static final Pattern P_LEFT_ARROW = 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_RIGHT_ARROW = Pattern.compile(">");
private static final Pattern P_BOTH_ARROWS = Pattern.compile("<>"); private static final Pattern P_BOTH_ARROWS = Pattern.compile("<>");
// @xxx could grow large... maybe use sesat's ReferenceMap // @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_PAIR_BLANKS = new ConcurrentHashMap<String, Pattern>();
private static final ConcurrentMap<String, Pattern> P_REMOVE_SELF_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 * set of allowed html elements, along with allowed attributes for each element
**/ **/
private final Map<String, List<String>> vAllowed; private final Map<String, List<String>> vAllowed;
/** /**
* counts of open tags for each (allowable) html element * counts of open tags for each (allowable) html element
**/ **/
private final Map<String, Integer> vTagCounts = new HashMap<String, Integer>(); private final Map<String, Integer> vTagCounts = new HashMap<String, Integer>();
/** /**
* html elements which must always be self-closing (e.g. "<img />") * html elements which must always be self-closing (e.g. "<img />")
**/ **/
private final String[] vSelfClosingTags; private final String[] vSelfClosingTags;
/** /**
* html elements which must always have separate opening and closing tags (e.g. "<b></b>") * html elements which must always have separate opening and closing tags (e.g. "<b></b>")
**/ **/
private final String[] vNeedClosingTags; private final String[] vNeedClosingTags;
/** /**
* set of disallowed html elements * set of disallowed html elements
**/ **/
private final String[] vDisallowed; private final String[] vDisallowed;
/** /**
* attributes which should be checked for valid protocols * attributes which should be checked for valid protocols
**/ **/
private final String[] vProtocolAtts; private final String[] vProtocolAtts;
/** /**
* allowed protocols * allowed protocols
**/ **/
private final String[] vAllowedProtocols; private final String[] vAllowedProtocols;
/** /**
* tags which should be removed if they contain no content (e.g. "<b></b>" or "<b />") * tags which should be removed if they contain no content (e.g. "<b></b>" or "<b />")
**/ **/
private final String[] vRemoveBlanks; private final String[] vRemoveBlanks;
/** /**
* entities allowed within html markup * entities allowed within html markup
**/ **/
private final String[] vAllowedEntities; private final String[] vAllowedEntities;
/** /**
* flag determining whether comments are allowed in input String. * flag determining whether comments are allowed in input String.
*/ */
private final boolean stripComment; private final boolean stripComment;
private final boolean encodeQuotes; private final boolean encodeQuotes;
private boolean vDebug = false; private boolean vDebug = false;
/** /**
* flag determining whether to try to make tags when presented with "unbalanced" * 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, * angle brackets (e.g. "<b text </b>" becomes "<b> text </b>"). If set to false,
* unbalanced angle brackets will be html escaped. * unbalanced angle brackets will be html escaped.
*/ */
private final boolean alwaysMakeTags; private final boolean alwaysMakeTags;
/** /**
* Default constructor. * Default constructor.
*/ */
public HTMLFilter() { public HTMLFilter() {
vAllowed = new HashMap<>(); vAllowed = new HashMap<>();
final ArrayList<String> a_atts = new ArrayList<String>(); final ArrayList<String> a_atts = new ArrayList<String>();
a_atts.add("href"); a_atts.add("href");
a_atts.add("target"); a_atts.add("target");
vAllowed.put("a", a_atts); vAllowed.put("a", a_atts);
final ArrayList<String> img_atts = new ArrayList<String>(); final ArrayList<String> img_atts = new ArrayList<String>();
img_atts.add("src"); img_atts.add("src");
img_atts.add("width"); img_atts.add("width");
img_atts.add("height"); img_atts.add("height");
img_atts.add("alt"); img_atts.add("alt");
vAllowed.put("img", img_atts); vAllowed.put("img", img_atts);
final ArrayList<String> no_atts = new ArrayList<String>(); final ArrayList<String> no_atts = new ArrayList<String>();
vAllowed.put("b", no_atts); vAllowed.put("b", no_atts);
vAllowed.put("strong", no_atts); vAllowed.put("strong", no_atts);
vAllowed.put("i", no_atts); vAllowed.put("i", no_atts);
vAllowed.put("em", no_atts); vAllowed.put("em", no_atts);
vSelfClosingTags = new String[]{"img"}; vSelfClosingTags = new String[]{"img"};
vNeedClosingTags = new String[]{"a", "b", "strong", "i", "em"}; vNeedClosingTags = new String[]{"a", "b", "strong", "i", "em"};
vDisallowed = new String[]{}; vDisallowed = new String[]{};
vAllowedProtocols = new String[]{"http", "mailto", "https"}; // no ftp. vAllowedProtocols = new String[]{"http", "mailto", "https"}; // no ftp.
vProtocolAtts = new String[]{"src", "href"}; vProtocolAtts = new String[]{"src", "href"};
vRemoveBlanks = new String[]{"a", "b", "strong", "i", "em"}; vRemoveBlanks = new String[]{"a", "b", "strong", "i", "em"};
vAllowedEntities = new String[]{"amp", "gt", "lt", "quot"}; vAllowedEntities = new String[]{"amp", "gt", "lt", "quot"};
stripComment = true; stripComment = true;
encodeQuotes = true; encodeQuotes = true;
alwaysMakeTags = true; alwaysMakeTags = true;
} }
/** /**
* Set debug flag to true. Otherwise use default settings. See the default constructor. * Set debug flag to true. Otherwise use default settings. See the default constructor.
* *
* @param debug turn debug on with a true argument * @param debug turn debug on with a true argument
*/ */
public HTMLFilter(final boolean debug) { public HTMLFilter(final boolean debug) {
this(); this();
vDebug = debug; vDebug = debug;
} }
/** /**
* Map-parameter configurable constructor. * Map-parameter configurable constructor.
* *
* @param conf map containing configuration. keys match field names. * @param conf map containing configuration. keys match field names.
*/ */
public HTMLFilter(final Map<String, Object> conf) { public HTMLFilter(final Map<String, Object> conf) {
assert conf.containsKey("vAllowed") : "configuration requires vAllowed"; assert conf.containsKey("vAllowed") : "configuration requires vAllowed";
assert conf.containsKey("vSelfClosingTags") : "configuration requires vSelfClosingTags"; assert conf.containsKey("vSelfClosingTags") : "configuration requires vSelfClosingTags";
assert conf.containsKey("vNeedClosingTags") : "configuration requires vNeedClosingTags"; assert conf.containsKey("vNeedClosingTags") : "configuration requires vNeedClosingTags";
assert conf.containsKey("vDisallowed") : "configuration requires vDisallowed"; assert conf.containsKey("vDisallowed") : "configuration requires vDisallowed";
assert conf.containsKey("vAllowedProtocols") : "configuration requires vAllowedProtocols"; assert conf.containsKey("vAllowedProtocols") : "configuration requires vAllowedProtocols";
assert conf.containsKey("vProtocolAtts") : "configuration requires vProtocolAtts"; assert conf.containsKey("vProtocolAtts") : "configuration requires vProtocolAtts";
assert conf.containsKey("vRemoveBlanks") : "configuration requires vRemoveBlanks"; assert conf.containsKey("vRemoveBlanks") : "configuration requires vRemoveBlanks";
assert conf.containsKey("vAllowedEntities") : "configuration requires vAllowedEntities"; assert conf.containsKey("vAllowedEntities") : "configuration requires vAllowedEntities";
vAllowed = Collections.unmodifiableMap((HashMap<String, List<String>>) conf.get("vAllowed")); vAllowed = Collections.unmodifiableMap((HashMap<String, List<String>>) conf.get("vAllowed"));
vSelfClosingTags = (String[]) conf.get("vSelfClosingTags"); vSelfClosingTags = (String[]) conf.get("vSelfClosingTags");
vNeedClosingTags = (String[]) conf.get("vNeedClosingTags"); vNeedClosingTags = (String[]) conf.get("vNeedClosingTags");
vDisallowed = (String[]) conf.get("vDisallowed"); vDisallowed = (String[]) conf.get("vDisallowed");
vAllowedProtocols = (String[]) conf.get("vAllowedProtocols"); vAllowedProtocols = (String[]) conf.get("vAllowedProtocols");
vProtocolAtts = (String[]) conf.get("vProtocolAtts"); vProtocolAtts = (String[]) conf.get("vProtocolAtts");
vRemoveBlanks = (String[]) conf.get("vRemoveBlanks"); vRemoveBlanks = (String[]) conf.get("vRemoveBlanks");
vAllowedEntities = (String[]) conf.get("vAllowedEntities"); vAllowedEntities = (String[]) conf.get("vAllowedEntities");
stripComment = conf.containsKey("stripComment") ? (Boolean) conf.get("stripComment") : true; stripComment = conf.containsKey("stripComment") ? (Boolean) conf.get("stripComment") : true;
encodeQuotes = conf.containsKey("encodeQuotes") ? (Boolean) conf.get("encodeQuotes") : true; encodeQuotes = conf.containsKey("encodeQuotes") ? (Boolean) conf.get("encodeQuotes") : true;
alwaysMakeTags = conf.containsKey("alwaysMakeTags") ? (Boolean) conf.get("alwaysMakeTags") : true; alwaysMakeTags = conf.containsKey("alwaysMakeTags") ? (Boolean) conf.get("alwaysMakeTags") : true;
} }
private void reset() { private void reset() {
vTagCounts.clear(); vTagCounts.clear();
} }
private void debug(final String msg) { private void debug(final String msg) {
if (vDebug) { if (vDebug) {
Logger.getAnonymousLogger().info(msg); Logger.getAnonymousLogger().info(msg);
} }
} }
//--------------------------------------------------------------- //---------------------------------------------------------------
// my versions of some PHP library functions // my versions of some PHP library functions
public static String chr(final int decimal) { public static String chr(final int decimal) {
return String.valueOf((char) decimal); return String.valueOf((char) decimal);
} }
public static String htmlSpecialChars(final String s) { public static String htmlSpecialChars(final String s) {
String result = s; String result = s;
result = regexReplace(P_AMP, "&amp;", result); result = regexReplace(P_AMP, "&amp;", result);
result = regexReplace(P_QUOTE, "&quot;", result); result = regexReplace(P_QUOTE, "&quot;", result);
result = regexReplace(P_LEFT_ARROW, "&lt;", result); result = regexReplace(P_LEFT_ARROW, "&lt;", result);
result = regexReplace(P_RIGHT_ARROW, "&gt;", result); result = regexReplace(P_RIGHT_ARROW, "&gt;", result);
return result; return result;
} }
//--------------------------------------------------------------- //---------------------------------------------------------------
/** /**
* given a user submitted input String, filter out any invalid or restricted * given a user submitted input String, filter out any invalid or restricted
* html. * html.
* *
* @param input text (i.e. submitted by a user) than may contain 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 * @return "clean" version of input, with only valid, whitelisted html elements allowed
*/ */
public String filter(final String input) { public String filter(final String input) {
reset(); reset();
String s = input; String s = input;
debug("************************************************"); debug("************************************************");
debug(" INPUT: " + input); debug(" INPUT: " + input);
s = escapeComments(s); s = escapeComments(s);
debug(" escapeComments: " + s); debug(" escapeComments: " + s);
s = balanceHTML(s); s = balanceHTML(s);
debug(" balanceHTML: " + s); debug(" balanceHTML: " + s);
s = checkTags(s); s = checkTags(s);
debug(" checkTags: " + s); debug(" checkTags: " + s);
s = processRemoveBlanks(s); s = processRemoveBlanks(s);
debug("processRemoveBlanks: " + s); debug("processRemoveBlanks: " + s);
s = validateEntities(s); s = validateEntities(s);
debug(" validateEntites: " + s); debug(" validateEntites: " + s);
debug("************************************************\n\n"); debug("************************************************\n\n");
return s; return s;
} }
public boolean isAlwaysMakeTags() { public boolean isAlwaysMakeTags() {
return alwaysMakeTags; return alwaysMakeTags;
} }
public boolean isStripComments() { public boolean isStripComments() {
return stripComment; return stripComment;
} }
private String escapeComments(final String s) { private String escapeComments(final String s) {
final Matcher m = P_COMMENTS.matcher(s); final Matcher m = P_COMMENTS.matcher(s);
final StringBuffer buf = new StringBuffer(); final StringBuffer buf = new StringBuffer();
if (m.find()) { if (m.find()) {
final String match = m.group(1); //(.*?) final String match = m.group(1); //(.*?)
m.appendReplacement(buf, Matcher.quoteReplacement("<!--" + htmlSpecialChars(match) + "-->")); m.appendReplacement(buf, Matcher.quoteReplacement("<!--" + htmlSpecialChars(match) + "-->"));
} }
m.appendTail(buf); m.appendTail(buf);
return buf.toString(); return buf.toString();
} }
private String balanceHTML(String s) { private String balanceHTML(String s) {
if (alwaysMakeTags) { if (alwaysMakeTags) {
// //
// try and form html // try and form html
// //
s = regexReplace(P_END_ARROW, "", s); s = regexReplace(P_END_ARROW, "", s);
s = regexReplace(P_BODY_TO_END, "<$1>", s); s = regexReplace(P_BODY_TO_END, "<$1>", s);
s = regexReplace(P_XML_CONTENT, "$1<$2", s); s = regexReplace(P_XML_CONTENT, "$1<$2", s);
} else { } else {
// //
// escape stray brackets // escape stray brackets
// //
s = regexReplace(P_STRAY_LEFT_ARROW, "&lt;$1", s); s = regexReplace(P_STRAY_LEFT_ARROW, "&lt;$1", s);
s = regexReplace(P_STRAY_RIGHT_ARROW, "$1$2&gt;<", s); s = regexReplace(P_STRAY_RIGHT_ARROW, "$1$2&gt;<", s);
// //
// the last regexp causes '<>' entities to appear // the last regexp causes '<>' entities to appear
// (we need to do a lookahead assertion so that the last bracket can // (we need to do a lookahead assertion so that the last bracket can
// be used in the next pass of the regexp) // be used in the next pass of the regexp)
// //
s = regexReplace(P_BOTH_ARROWS, "", s); s = regexReplace(P_BOTH_ARROWS, "", s);
} }
return s; return s;
} }
private String checkTags(String s) { private String checkTags(String s) {
Matcher m = P_TAGS.matcher(s); Matcher m = P_TAGS.matcher(s);
final StringBuffer buf = new StringBuffer(); final StringBuffer buf = new StringBuffer();
while (m.find()) { while (m.find()) {
String replaceStr = m.group(1); String replaceStr = m.group(1);
replaceStr = processTag(replaceStr); replaceStr = processTag(replaceStr);
m.appendReplacement(buf, Matcher.quoteReplacement(replaceStr)); m.appendReplacement(buf, Matcher.quoteReplacement(replaceStr));
} }
m.appendTail(buf); m.appendTail(buf);
s = buf.toString(); s = buf.toString();
// these get tallied in processTag // these get tallied in processTag
// (remember to reset before subsequent calls to filter method) // (remember to reset before subsequent calls to filter method)
for (String key : vTagCounts.keySet()) { for (String key : vTagCounts.keySet()) {
for (int ii = 0; ii < vTagCounts.get(key); ii++) { for (int ii = 0; ii < vTagCounts.get(key); ii++) {
s += "</" + key + ">"; s += "</" + key + ">";
} }
} }
return s; return s;
} }
private String processRemoveBlanks(final String s) { private String processRemoveBlanks(final String s) {
String result = s; String result = s;
for (String tag : vRemoveBlanks) { for (String tag : vRemoveBlanks) {
if (!P_REMOVE_PAIR_BLANKS.containsKey(tag)) { if (!P_REMOVE_PAIR_BLANKS.containsKey(tag)) {
P_REMOVE_PAIR_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?></" + tag + ">")); P_REMOVE_PAIR_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?></" + tag + ">"));
} }
result = regexReplace(P_REMOVE_PAIR_BLANKS.get(tag), "", result); result = regexReplace(P_REMOVE_PAIR_BLANKS.get(tag), "", result);
if (!P_REMOVE_SELF_BLANKS.containsKey(tag)) { if (!P_REMOVE_SELF_BLANKS.containsKey(tag)) {
P_REMOVE_SELF_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?/>")); P_REMOVE_SELF_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?/>"));
} }
result = regexReplace(P_REMOVE_SELF_BLANKS.get(tag), "", result); 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) { private static String regexReplace(final Pattern regex_pattern, final String replacement, final String s) {
Matcher m = regex_pattern.matcher(s); Matcher m = regex_pattern.matcher(s);
return m.replaceAll(replacement); return m.replaceAll(replacement);
} }
private String processTag(final String s) { private String processTag(final String s) {
// ending tags // ending tags
Matcher m = P_END_TAG.matcher(s); Matcher m = P_END_TAG.matcher(s);
if (m.find()) { if (m.find()) {
final String name = m.group(1).toLowerCase(); final String name = m.group(1).toLowerCase();
if (allowed(name)) { if (allowed(name)) {
if (!inArray(name, vSelfClosingTags)) { if (!inArray(name, vSelfClosingTags)) {
if (vTagCounts.containsKey(name)) { if (vTagCounts.containsKey(name)) {
vTagCounts.put(name, vTagCounts.get(name) - 1); vTagCounts.put(name, vTagCounts.get(name) - 1);
return "</" + name + ">"; return "</" + name + ">";
} }
} }
} }
} }
// starting tags // starting tags
m = P_START_TAG.matcher(s); m = P_START_TAG.matcher(s);
if (m.find()) { if (m.find()) {
final String name = m.group(1).toLowerCase(); final String name = m.group(1).toLowerCase();
final String body = m.group(2); final String body = m.group(2);
String ending = m.group(3); String ending = m.group(3);
//debug( "in a starting tag, name='" + name + "'; body='" + body + "'; ending='" + ending + "'" ); //debug( "in a starting tag, name='" + name + "'; body='" + body + "'; ending='" + ending + "'" );
if (allowed(name)) { if (allowed(name)) {
String params = ""; String params = "";
final Matcher m2 = P_QUOTED_ATTRIBUTES.matcher(body); final Matcher m2 = P_QUOTED_ATTRIBUTES.matcher(body);
final Matcher m3 = P_UNQUOTED_ATTRIBUTES.matcher(body); final Matcher m3 = P_UNQUOTED_ATTRIBUTES.matcher(body);
final List<String> paramNames = new ArrayList<String>(); final List<String> paramNames = new ArrayList<String>();
final List<String> paramValues = new ArrayList<String>(); final List<String> paramValues = new ArrayList<String>();
while (m2.find()) { while (m2.find()) {
paramNames.add(m2.group(1)); //([a-z0-9]+) paramNames.add(m2.group(1)); //([a-z0-9]+)
paramValues.add(m2.group(3)); //(.*?) paramValues.add(m2.group(3)); //(.*?)
} }
while (m3.find()) { while (m3.find()) {
paramNames.add(m3.group(1)); //([a-z0-9]+) paramNames.add(m3.group(1)); //([a-z0-9]+)
paramValues.add(m3.group(3)); //([^\"\\s']+) paramValues.add(m3.group(3)); //([^\"\\s']+)
} }
String paramName, paramValue; String paramName, paramValue;
for (int ii = 0; ii < paramNames.size(); ii++) { for (int ii = 0; ii < paramNames.size(); ii++) {
paramName = paramNames.get(ii).toLowerCase(); paramName = paramNames.get(ii).toLowerCase();
paramValue = paramValues.get(ii); paramValue = paramValues.get(ii);
// debug( "paramName='" + paramName + "'" ); // debug( "paramName='" + paramName + "'" );
// debug( "paramValue='" + paramValue + "'" ); // debug( "paramValue='" + paramValue + "'" );
// debug( "allowed? " + vAllowed.get( name ).contains( paramName ) ); // debug( "allowed? " + vAllowed.get( name ).contains( paramName ) );
if (allowedAttribute(name, paramName)) { if (allowedAttribute(name, paramName)) {
if (inArray(paramName, vProtocolAtts)) { if (inArray(paramName, vProtocolAtts)) {
paramValue = processParamProtocol(paramValue); paramValue = processParamProtocol(paramValue);
} }
params += " " + paramName + "=\"" + paramValue + "\""; params += " " + paramName + "=\"" + paramValue + "\"";
} }
} }
if (inArray(name, vSelfClosingTags)) { if (inArray(name, vSelfClosingTags)) {
ending = " /"; ending = " /";
} }
if (inArray(name, vNeedClosingTags)) { if (inArray(name, vNeedClosingTags)) {
ending = ""; ending = "";
} }
if (ending == null || ending.length() < 1) { if (ending == null || ending.length() < 1) {
if (vTagCounts.containsKey(name)) { if (vTagCounts.containsKey(name)) {
vTagCounts.put(name, vTagCounts.get(name) + 1); vTagCounts.put(name, vTagCounts.get(name) + 1);
} else { } else {
vTagCounts.put(name, 1); vTagCounts.put(name, 1);
} }
} else { } else {
ending = " /"; ending = " /";
} }
return "<" + name + params + ending + ">"; return "<" + name + params + ending + ">";
} else { } else {
return ""; return "";
} }
} }
// comments // comments
m = P_COMMENT.matcher(s); m = P_COMMENT.matcher(s);
if (!stripComment && m.find()) { if (!stripComment && m.find()) {
return "<" + m.group() + ">"; return "<" + m.group() + ">";
} }
return ""; return "";
} }
private String processParamProtocol(String s) { private String processParamProtocol(String s) {
s = decodeEntities(s); s = decodeEntities(s);
final Matcher m = P_PROTOCOL.matcher(s); final Matcher m = P_PROTOCOL.matcher(s);
if (m.find()) { if (m.find()) {
final String protocol = m.group(1); final String protocol = m.group(1);
if (!inArray(protocol, vAllowedProtocols)) { if (!inArray(protocol, vAllowedProtocols)) {
// bad protocol, turn into local anchor link instead // bad protocol, turn into local anchor link instead
s = "#" + s.substring(protocol.length() + 1, s.length()); s = "#" + s.substring(protocol.length() + 1, s.length());
if (s.startsWith("#//")) { if (s.startsWith("#//")) {
s = "#" + s.substring(3, s.length()); s = "#" + s.substring(3, s.length());
} }
} }
} }
return s; return s;
} }
private String decodeEntities(String s) { private String decodeEntities(String s) {
StringBuffer buf = new StringBuffer(); StringBuffer buf = new StringBuffer();
Matcher m = P_ENTITY.matcher(s); Matcher m = P_ENTITY.matcher(s);
while (m.find()) { while (m.find()) {
final String match = m.group(1); final String match = m.group(1);
final int decimal = Integer.decode(match).intValue(); final int decimal = Integer.decode(match).intValue();
m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal))); m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
} }
m.appendTail(buf); m.appendTail(buf);
s = buf.toString(); s = buf.toString();
buf = new StringBuffer(); buf = new StringBuffer();
m = P_ENTITY_UNICODE.matcher(s); m = P_ENTITY_UNICODE.matcher(s);
while (m.find()) { while (m.find()) {
final String match = m.group(1); final String match = m.group(1);
final int decimal = Integer.valueOf(match, 16).intValue(); final int decimal = Integer.valueOf(match, 16).intValue();
m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal))); m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
} }
m.appendTail(buf); m.appendTail(buf);
s = buf.toString(); s = buf.toString();
buf = new StringBuffer(); buf = new StringBuffer();
m = P_ENCODE.matcher(s); m = P_ENCODE.matcher(s);
while (m.find()) { while (m.find()) {
final String match = m.group(1); final String match = m.group(1);
final int decimal = Integer.valueOf(match, 16).intValue(); final int decimal = Integer.valueOf(match, 16).intValue();
m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal))); m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
} }
m.appendTail(buf); m.appendTail(buf);
s = buf.toString(); s = buf.toString();
s = validateEntities(s); s = validateEntities(s);
return s; return s;
} }
private String validateEntities(final String s) { private String validateEntities(final String s) {
StringBuffer buf = new StringBuffer(); StringBuffer buf = new StringBuffer();
// validate entities throughout the string // validate entities throughout the string
Matcher m = P_VALID_ENTITIES.matcher(s); Matcher m = P_VALID_ENTITIES.matcher(s);
while (m.find()) { while (m.find()) {
final String one = m.group(1); //([^&;]*) final String one = m.group(1); //([^&;]*)
final String two = m.group(2); //(?=(;|&|$)) final String two = m.group(2); //(?=(;|&|$))
m.appendReplacement(buf, Matcher.quoteReplacement(checkEntity(one, two))); m.appendReplacement(buf, Matcher.quoteReplacement(checkEntity(one, two)));
} }
m.appendTail(buf); m.appendTail(buf);
return encodeQuotes(buf.toString()); return encodeQuotes(buf.toString());
} }
private String encodeQuotes(final String s) { private String encodeQuotes(final String s) {
if (encodeQuotes) { if (encodeQuotes) {
StringBuffer buf = new StringBuffer(); StringBuffer buf = new StringBuffer();
Matcher m = P_VALID_QUOTES.matcher(s); Matcher m = P_VALID_QUOTES.matcher(s);
while (m.find()) { while (m.find()) {
final String one = m.group(1); //(>|^) final String one = m.group(1); //(>|^)
final String two = m.group(2); //([^<]+?) final String two = m.group(2); //([^<]+?)
final String three = m.group(3); //(<|$) final String three = m.group(3); //(<|$)
m.appendReplacement(buf, Matcher.quoteReplacement(one + regexReplace(P_QUOTE, "&quot;", two) + three)); m.appendReplacement(buf, Matcher.quoteReplacement(one + regexReplace(P_QUOTE, "&quot;", two) + three));
} }
m.appendTail(buf); m.appendTail(buf);
return buf.toString(); return buf.toString();
} else { } else {
return s; 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) return ";".equals(term) && isValidEntity(preamble)
? '&' + preamble ? '&' + preamble
: "&amp;" + preamble; : "&amp;" + preamble;
} }
private boolean isValidEntity(final String entity) { private boolean isValidEntity(final String entity) {
return inArray(entity, vAllowedEntities); return inArray(entity, vAllowedEntities);
} }
private static boolean inArray(final String s, final String[] array) { private static boolean inArray(final String s, final String[] array) {
for (String item : array) { for (String item : array) {
if (item != null && item.equals(s)) { if (item != null && item.equals(s)) {
return true; return true;
} }
} }
return false; return false;
} }
private boolean allowed(final String name) { private boolean allowed(final String name) {
return (vAllowed.isEmpty() || vAllowed.containsKey(name)) && !inArray(name, vDisallowed); return (vAllowed.isEmpty() || vAllowed.containsKey(name)) && !inArray(name, vDisallowed);
} }
private boolean allowedAttribute(final String name, final String paramName) { private boolean allowedAttribute(final String name, final String paramName) {
return allowed(name) && (vAllowed.isEmpty() || vAllowed.get(name).contains(paramName)); return allowed(name) && (vAllowed.isEmpty() || vAllowed.get(name).contains(paramName));
} }
} }

View File

@ -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;
}
}

View File

@ -21,29 +21,32 @@ import java.io.IOException;
/** /**
* XSS过滤 * XSS过滤
*
* @author smallchill
*/ */
public class XssFilter implements Filter { public class XssFilter implements Filter {
@Override @Override
public void init(FilterConfig config) throws ServletException { public void init(FilterConfig config) throws ServletException {
} }
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { @Override
ServletRequest requestWrapper = null; public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
if(request instanceof HttpServletRequest) { ServletRequest requestWrapper = null;
requestWrapper = new XssHttpServletRequestWrapper((HttpServletRequest) request); if (request instanceof HttpServletRequest) {
} requestWrapper = new XssHttpServletRequestWrapper((HttpServletRequest) request);
if(requestWrapper == null) { }
chain.doFilter(request, response); if (requestWrapper == null) {
} else { chain.doFilter(request, response);
chain.doFilter(requestWrapper, response); } else {
} chain.doFilter(requestWrapper, response);
} }
}
@Override @Override
public void destroy() { public void destroy() {
} }
} }

View File

@ -34,141 +34,151 @@ import java.util.Map;
/** /**
* XSS过滤处理 * XSS过滤处理
*
* @author smallchill
*/ */
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper { public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
//没被包装过的HttpServletRequest特殊场景,需要自己过滤 /**
HttpServletRequest orgRequest; * 没被包装过的HttpServletRequest特殊场景,需要自己过滤
//html过滤 */
private final static HTMLFilter htmlFilter = new HTMLFilter(); HttpServletRequest orgRequest;
// 缓存报文,支持多次读取流
private final byte[] body;
public XssHttpServletRequestWrapper(HttpServletRequest request) throws IOException { /**
super(request); * html过滤
orgRequest = request; */
body = WebUtil.getRequestBytes(request); 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 XssHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
public ServletInputStream getInputStream() throws IOException { super(request);
orgRequest = request;
body = WebUtil.getRequestBytes(request);
}
//为空直接返回 @Override
if (null == super.getHeader(HttpHeaders.CONTENT_TYPE)) { public BufferedReader getReader() throws IOException {
return super.getInputStream(); return new BufferedReader(new InputStreamReader(getInputStream()));
} }
//非json类型直接返回 @Override
if (!super.getHeader(HttpHeaders.CONTENT_TYPE).equalsIgnoreCase(MediaType.APPLICATION_JSON_VALUE) public ServletInputStream getInputStream() throws IOException {
&& !super.getHeader(HttpHeaders.CONTENT_TYPE).equalsIgnoreCase(MediaType.APPLICATION_JSON_UTF8_VALUE)) {
return super.getInputStream();
}
//为空直接返回 //为空直接返回
String requestStr = WebUtil.getRequestStr(orgRequest, body); if (null == super.getHeader(HttpHeaders.CONTENT_TYPE)) {
if (StringUtil.isBlank(requestStr)) { return super.getInputStream();
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 final ByteArrayInputStream bis = new ByteArrayInputStream(requestStr.getBytes(Charsets.UTF_8));
public boolean isFinished() {
return true;
}
@Override return new ServletInputStream() {
public boolean isReady() {
return true;
}
@Override @Override
public void setReadListener(ReadListener readListener) { public boolean isFinished() {
return true;
}
} @Override
public boolean isReady() {
return true;
}
@Override @Override
public int read() throws IOException { public void setReadListener(ReadListener readListener) {
return bis.read();
}
};
} }
@Override @Override
public String getParameter(String name) { public int read() throws IOException {
String value = super.getParameter(xssEncode(name)); return bis.read();
if (StringUtil.isNotBlank(value)) { }
value = xssEncode(value); };
}
return value;
}
@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++) { @Override
parameters[i] = xssEncode(parameters[i]); public String getParameter(String name) {
} String value = super.getParameter(xssEncode(name));
return parameters; if (StringUtil.isNotBlank(value)) {
} value = xssEncode(value);
}
return value;
}
@Override @Override
public Map<String, String[]> getParameterMap() { public String[] getParameterValues(String name) {
Map<String, String[]> map = new LinkedHashMap<>(); String[] parameters = super.getParameterValues(name);
Map<String, String[]> parameters = super.getParameterMap(); if (parameters == null || parameters.length == 0) {
for (String key : parameters.keySet()) { return null;
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 for (int i = 0; i < parameters.length; i++) {
public String getHeader(String name) { parameters[i] = xssEncode(parameters[i]);
String value = super.getHeader(xssEncode(name)); }
if (StringUtil.isNotBlank(value)) { return parameters;
value = xssEncode(value); }
}
return value;
}
private String xssEncode(String input) { @Override
return htmlFilter.filter(input); 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
* 获取最原始的request public String getHeader(String name) {
*/ String value = super.getHeader(xssEncode(name));
public HttpServletRequest getOrgRequest() { if (StringUtil.isNotBlank(value)) {
return orgRequest; value = xssEncode(value);
} }
return value;
}
/** private String xssEncode(String input) {
* 获取最原始的request return htmlFilter.filter(input);
*/ }
public static HttpServletRequest getOrgRequest(HttpServletRequest request) {
if (request instanceof XssHttpServletRequestWrapper) {
return ((XssHttpServletRequestWrapper) request).getOrgRequest();
}
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