commit
e48923f301
|
@ -3,6 +3,7 @@
|
|||
*.iml
|
||||
application.properties
|
||||
application-*.properties
|
||||
.DS_Store
|
||||
|
||||
# Ignore Gradle build output directory
|
||||
build/
|
||||
|
|
|
@ -27,7 +27,7 @@ diboot 2.0版本,实现: diboot-core全新内核 + diboot-devtools代码生成
|
|||
|
||||
|
||||
|
||||
## 二、 diboot-devtools 代码生成工具 [(我要试试)](https://www.diboot.com/guide/diboot-devtools/%E4%BB%8B%E7%BB%8D.html)
|
||||
## 二、 diboot-devtools 自动化开发助理 [(我要试试)](https://www.diboot.com/guide/diboot-devtools/%E4%BB%8B%E7%BB%8D.html)
|
||||
|
||||
##### 1. 支持多数据库(MySQL、MariaDB、ORACLE、SQLServer、PostgreSQL)
|
||||
##### 2. 使用很简单(引入依赖jar,配置参数后,即可随SpringBoot启动运行)
|
||||
|
@ -37,7 +37,7 @@ diboot 2.0版本,实现: diboot-core全新内核 + diboot-devtools代码生成
|
|||
|
||||
|
||||
## 三、技术交流群
|
||||
如果Diboot对您有用,欢迎您为Diboot的发展提供捐助。我们不喝咖啡,所有捐助费用都将用于Diboot服务器支出。
|
||||
如果Diboot对您有用,欢迎您为Diboot的发展提供捐助。
|
||||
<p align="center">
|
||||
<img src="https://www.diboot.com/donate.jpg" width = "500" alt="支持Diboot发展">
|
||||
</p>
|
||||
|
@ -45,4 +45,4 @@ diboot 2.0版本,实现: diboot-core全新内核 + diboot-devtools代码生成
|
|||
|
||||
> QQ群: [731690096]()
|
||||
|
||||
> 微信群加: [wx20201024]()
|
||||
> 微信群(备注diboot)加: [wx20201024]()
|
||||
|
|
15
build.gradle
15
build.gradle
|
@ -1,10 +1,9 @@
|
|||
buildscript {
|
||||
ext {
|
||||
springBootVersion = '2.1.8.RELEASE'
|
||||
springBootVersion = '2.2.1.RELEASE'
|
||||
}
|
||||
repositories {
|
||||
mavenLocal() //优先查找本地maven库,性能最好
|
||||
maven{ url 'http://maven.diboot.com/repository/diboot'}
|
||||
maven{ url 'http://maven.aliyun.com/nexus/content/groups/public/'}
|
||||
}
|
||||
dependencies {
|
||||
|
@ -31,17 +30,15 @@ subprojects {
|
|||
[compileJava,compileTestJava,javadoc]*.options*.encoding = 'UTF-8'
|
||||
repositories {
|
||||
mavenLocal() //优先查找本地maven库,性能最好
|
||||
maven{ url 'http://maven.diboot.com/repository/diboot'}
|
||||
maven{ url 'http://maven.aliyun.com/nexus/content/groups/public/'}
|
||||
}
|
||||
ext {//依赖版本
|
||||
springBootVersion = "2.1.8.RELEASE"
|
||||
springBootVersion = "2.2.1.RELEASE"
|
||||
mysqlConnectorVersion = "8.0.16"
|
||||
mybatisStarterVersion = "2.1.0"
|
||||
mybatisPlusVersion = "3.2.0"
|
||||
fastjsonVersion = "1.2.60"
|
||||
lombokVersion = "1.18.8"
|
||||
validatorVersion = "6.0.17.Final"
|
||||
lombokVersion = "1.18.10"
|
||||
validatorVersion = "6.0.18.Final"
|
||||
}
|
||||
dependencies {
|
||||
// Gradle 5.0及以上版本,使用如下方式
|
||||
|
@ -51,8 +48,6 @@ subprojects {
|
|||
|
||||
compile("javax.servlet:javax.servlet-api:4.0.1")
|
||||
compile("org.springframework.boot:spring-boot-starter-web:$springBootVersion")
|
||||
// Mybatis
|
||||
compile("org.mybatis.spring.boot:mybatis-spring-boot-starter:$mybatisStarterVersion")
|
||||
// Mybatis-Plus
|
||||
compile("com.baomidou:mybatis-plus-boot-starter:$mybatisPlusVersion")
|
||||
// Log4j2
|
||||
|
@ -65,7 +60,7 @@ subprojects {
|
|||
compile("org.hibernate.validator:hibernate-validator:$validatorVersion")
|
||||
// Apache Commons
|
||||
compile("org.apache.commons:commons-lang3:3.8.1",
|
||||
"commons-fileupload:commons-fileupload:1.3.3",
|
||||
// "commons-fileupload:commons-fileupload:1.3.3",
|
||||
"commons-io:commons-io:2.6")
|
||||
|
||||
// 单元测试
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
|
||||
dependencies {
|
||||
compile project(":diboot-core")
|
||||
compile project(":diboot-component-file")
|
||||
|
||||
def poiversion = "3.17"
|
||||
// office文件相关依赖
|
||||
compile("org.apache.poi:poi:$poiversion",
|
||||
"org.apache.poi:poi-ooxml:$poiversion")
|
||||
//easyexcel
|
||||
compile("com.alibaba:easyexcel:2.0.5")
|
||||
|
||||
testCompile group: 'junit', name: 'junit', version: '4.12'
|
||||
}
|
|
@ -1,273 +0,0 @@
|
|||
package com.diboot.component.excel.controller;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.diboot.component.excel.entity.BaseExcelDataEntity;
|
||||
import com.diboot.component.excel.entity.ExcelColumn;
|
||||
import com.diboot.component.excel.listener.BaseExcelDataListener;
|
||||
import com.diboot.component.excel.service.ExcelColumnService;
|
||||
import com.diboot.component.excel.service.ExcelImportRecordService;
|
||||
import com.diboot.component.excel.utils.EasyExcelHelper;
|
||||
import com.diboot.component.file.entity.BaseFile;
|
||||
import com.diboot.component.file.file.FileHelper;
|
||||
import com.diboot.component.file.service.BaseFileService;
|
||||
import com.diboot.core.entity.BaseEntity;
|
||||
import com.diboot.core.service.BaseService;
|
||||
import com.diboot.core.util.S;
|
||||
import com.diboot.core.util.V;
|
||||
import com.diboot.core.vo.JsonResult;
|
||||
import com.diboot.core.vo.Pagination;
|
||||
import com.diboot.core.vo.Status;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Excel导入基类
|
||||
* @author Mazc
|
||||
* @version 2017/9/18
|
||||
* Copyright @ www.com.ltd
|
||||
*/
|
||||
public abstract class BaseExcelImportController <T extends BaseExcelDataEntity> {
|
||||
private static final Logger logger = LoggerFactory.getLogger(BaseExcelImportController.class);
|
||||
|
||||
@Autowired
|
||||
protected BaseFileService baseFileService;
|
||||
@Autowired
|
||||
protected ExcelColumnService excelColumnService;
|
||||
@Autowired
|
||||
protected ExcelImportRecordService excelImportRecordService;
|
||||
|
||||
protected static final String PARAM_IMPORT_UUID = "importUid";
|
||||
|
||||
/**
|
||||
* 获取Excel列的定义
|
||||
*/
|
||||
private static Map<String, List<ExcelColumn>> excelColumnMap = null;
|
||||
|
||||
/***
|
||||
* 获取Model类
|
||||
* @return
|
||||
*/
|
||||
protected abstract Class<?> getModelClass();
|
||||
|
||||
/***
|
||||
* 获取ExcelData模板类
|
||||
* @return
|
||||
*/
|
||||
protected abstract Class<T> getExcelDataClass();
|
||||
|
||||
/***
|
||||
* 获取业务的service
|
||||
* @return
|
||||
*/
|
||||
protected abstract BaseService getBusinessService();
|
||||
|
||||
/***
|
||||
* 获取对应的ExcelDataListener
|
||||
* @return
|
||||
*/
|
||||
protected abstract BaseExcelDataListener getExcelDataListener();
|
||||
|
||||
protected BaseService getService() {
|
||||
return baseFileService;
|
||||
}
|
||||
|
||||
/***
|
||||
* 列表页处理
|
||||
* @param request
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public JsonResult listPaging(LambdaQueryWrapper<? extends BaseFile> queryWrapper, Pagination pagination, HttpServletRequest request) throws Exception{
|
||||
queryWrapper.eq(BaseFile::getRelObjType, getModelClass().getSimpleName());
|
||||
// 查询当前页的数据
|
||||
List entityList = getService().getEntityList(queryWrapper, pagination);
|
||||
// 返回结果
|
||||
return new JsonResult(Status.OK, entityList).bindPagination(pagination);
|
||||
}
|
||||
|
||||
/***
|
||||
* 预览处理
|
||||
* @param request
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public JsonResult preview(HttpServletRequest request) throws Exception {
|
||||
Map dataMap = new HashMap();
|
||||
try{
|
||||
BaseEntity model = (BaseEntity) getModelClass().newInstance();
|
||||
List<T> modelList = saveExcelFile(request, model, true);
|
||||
//获取预览时的表头
|
||||
List<Map> header = getPreviewDataHeader();
|
||||
dataMap.put("header", header);
|
||||
//最多返回前端十条数据
|
||||
dataMap.put("modelList", modelList.size()>10?modelList.subList(0,10):modelList.subList(0,modelList.size()));
|
||||
// 上传文件的id
|
||||
dataMap.put(PARAM_IMPORT_UUID, request.getAttribute(PARAM_IMPORT_UUID));
|
||||
return new JsonResult(Status.OK, dataMap);
|
||||
}
|
||||
catch(Exception e){
|
||||
logger.warn("预览数据失败 -->" + e);
|
||||
return new JsonResult(Status.FAIL_OPERATION, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* 预览保存
|
||||
* @param request
|
||||
* @param
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public JsonResult previewSave(HttpServletRequest request) throws Exception {
|
||||
String importUid = request.getParameter(PARAM_IMPORT_UUID);
|
||||
if(V.isEmpty(importUid)){
|
||||
return new JsonResult(Status.FAIL_OPERATION, "预览保存失败,无法获取上传文件编号 importUid!");
|
||||
}
|
||||
try{
|
||||
LambdaQueryWrapper<BaseFile> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(BaseFile::getUuid, importUid);
|
||||
BaseFile importFile = baseFileService.getModel(wrapper);
|
||||
boolean success = false;
|
||||
success = EasyExcelHelper.simpleReadAndSave(FileHelper.getFileStorageDirectory() + importFile.getPath(),getExcelDataClass(),getExcelDataListener());
|
||||
if(success){
|
||||
// 更新上传文件信息
|
||||
importFile.setDeleted(false);
|
||||
importFile.setDataCount(getExcelDataListener().getEntityList().size());
|
||||
baseFileService.updateModel(importFile);
|
||||
// 批量保存导入记录明细
|
||||
success = excelImportRecordService.batchCreateRecords(importUid, getExcelDataListener().getEntityList());
|
||||
if(!success){
|
||||
logger.warn("数据导入成功,但保存导入历史记录信息失败!fileUuid="+importUid);
|
||||
}
|
||||
}else{
|
||||
logger.error("数据上传失败:"+ S.join(getExcelDataListener().getErrorMsgs(), "<br/>"));
|
||||
return new JsonResult(Status.FAIL_OPERATION, S.join(getExcelDataListener().getErrorMsgs(), "<br/>"));
|
||||
}
|
||||
}
|
||||
catch(Exception e){
|
||||
logger.error("上传数据错误: "+ e.getMessage(), e);
|
||||
}
|
||||
return new JsonResult(Status.OK,"上传成功");
|
||||
}
|
||||
|
||||
/***
|
||||
* 直接上传
|
||||
* @param request
|
||||
* @param
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public JsonResult upload(HttpServletRequest request) throws Exception {
|
||||
try{
|
||||
BaseEntity model = (BaseEntity) getModelClass().newInstance();
|
||||
saveExcelFile(request, model, false);
|
||||
String importUid = (String) request.getAttribute(PARAM_IMPORT_UUID);
|
||||
// 批量保存导入记录明细
|
||||
if(importUid != null){
|
||||
boolean success = excelImportRecordService.batchCreateRecords(importUid, getExcelDataListener().getEntityList());
|
||||
if(!success){
|
||||
logger.warn("数据导入成功,但保存导入历史记录信息失败!fileUuid="+importUid);
|
||||
}
|
||||
}
|
||||
else{
|
||||
logger.warn("数据导入成功,但无法导入历史记录信息: importUuid不存在!");
|
||||
}
|
||||
}
|
||||
catch(Exception e){
|
||||
logger.error("上传数据错误: "+ e.getMessage(), e);
|
||||
return new JsonResult(Status.FAIL_OPERATION, e.getMessage());
|
||||
}
|
||||
return new JsonResult(Status.OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存上传文件
|
||||
* @param request
|
||||
* @param model
|
||||
* @param fileInputName
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
protected List<T> saveExcelFile(HttpServletRequest request, BaseEntity model, boolean isPreview, String... fileInputName) throws Exception{
|
||||
MultipartFile file = FileHelper.getFileFromRequest(request, fileInputName);
|
||||
if(V.isEmpty(file)) {
|
||||
throw new Exception("未获取待处理的excel文件!");
|
||||
}
|
||||
List<T> dataList = null;
|
||||
String fileName = file.getOriginalFilename();
|
||||
if (V.isEmpty(fileName) || !FileHelper.isExcel(fileName)) {
|
||||
logger.info("非Excel类型: " + fileName);
|
||||
throw new Exception("上传的文件为非Excel文件类型!");
|
||||
}
|
||||
// 文件后缀
|
||||
String ext = fileName.substring(fileName.lastIndexOf(".") + 1);
|
||||
// 先保存文件
|
||||
String uuid = S.newUuid();
|
||||
String newFileName = uuid + "." + ext;
|
||||
String path = FileHelper.saveFile(file, newFileName);
|
||||
if(V.isEmpty(path)){
|
||||
logger.info("文件保存失败");
|
||||
throw new Exception("文件保存失败");
|
||||
}
|
||||
BaseFile fileObj = new BaseFile();
|
||||
// fileObj.setUuid(uuid);
|
||||
fileObj.setName(fileName);
|
||||
fileObj.setRelObjType(model.getClass().getSimpleName());
|
||||
fileObj.setRelObjId(model.getId());
|
||||
fileObj.setFileType(ext);
|
||||
fileObj.setName(fileName);
|
||||
fileObj.setPath(path);
|
||||
fileObj.setLink("/file/download/" + uuid);
|
||||
fileObj.setSize(file.getSize());
|
||||
fileObj.setComment(request.getParameter("comment"));
|
||||
try {
|
||||
dataList = EasyExcelHelper.simpleRead(FileHelper.getFileStorageDirectory() + path, getExcelDataClass(), getExcelDataListener(), isPreview);
|
||||
} catch (Exception e) {
|
||||
throw new Exception("解析excel文件失败");
|
||||
}
|
||||
if(V.notEmpty(getExcelDataListener().getErrorMsgs())){
|
||||
throw new Exception(S.join(getExcelDataListener().getErrorMsgs(), "<br/>"));
|
||||
}
|
||||
// 初始设置为0,批量保存数据后更新
|
||||
if(isPreview){
|
||||
fileObj.setDeleted(true);
|
||||
fileObj.setDataCount(0);
|
||||
}else{
|
||||
fileObj.setDeleted(false);
|
||||
fileObj.setDataCount(getExcelDataListener().getEntityList().size());
|
||||
}
|
||||
baseFileService.createEntity(fileObj);
|
||||
// 绑定属性到model
|
||||
request.setAttribute(PARAM_IMPORT_UUID, uuid);
|
||||
logger.info("成功保存附件: uid=" + uuid + ", name=" + fileName);
|
||||
// 返回结果
|
||||
return dataList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取预览数据时显示在页面上的数据表头
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
private List<Map> getPreviewDataHeader() throws Exception{
|
||||
List<Map> list = new ArrayList<>();
|
||||
List<ExcelColumn> excelColumns = getExcelDataListener().getExcelColumnList(getModelClass().getSimpleName());
|
||||
if(V.notEmpty(excelColumns)){
|
||||
for(ExcelColumn excelColumn : excelColumns){
|
||||
Map map = new HashMap();
|
||||
map.put("title",excelColumn.getColName());
|
||||
map.put("dataIndex", excelColumn.getModelField());
|
||||
list.add(map);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
package com.diboot.component.excel.converter;
|
||||
|
||||
import com.alibaba.excel.converters.Converter;
|
||||
import com.alibaba.excel.enums.CellDataTypeEnum;
|
||||
import com.alibaba.excel.metadata.CellData;
|
||||
import com.alibaba.excel.metadata.GlobalConfiguration;
|
||||
import com.alibaba.excel.metadata.property.ExcelContentProperty;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
public class BigDecimalConverter implements Converter<BigDecimal> {
|
||||
@Override
|
||||
public Class supportJavaTypeKey() {
|
||||
return BigDecimal.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CellDataTypeEnum supportExcelTypeKey() {
|
||||
return CellDataTypeEnum.NUMBER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
|
||||
BigDecimal value = null;
|
||||
String colName = contentProperty.getHead().getHeadNameList().get(0);//当前列
|
||||
try {
|
||||
value = cellData.getNumberValue();
|
||||
} catch (Exception e) {
|
||||
throw new Exception("["+colName+"]列数据格式有误,请填写正确的浮点型数据");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CellData convertToExcelData(BigDecimal value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
|
||||
return new CellData(value);
|
||||
}
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
package com.diboot.component.excel.converter;
|
||||
|
||||
import com.alibaba.excel.converters.Converter;
|
||||
import com.alibaba.excel.enums.CellDataTypeEnum;
|
||||
import com.alibaba.excel.metadata.CellData;
|
||||
import com.alibaba.excel.metadata.GlobalConfiguration;
|
||||
import com.alibaba.excel.metadata.property.ExcelContentProperty;
|
||||
|
||||
public class BooleanConverter implements Converter<Boolean> {
|
||||
@Override
|
||||
public Class supportJavaTypeKey() {
|
||||
return Boolean.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CellDataTypeEnum supportExcelTypeKey() {
|
||||
return CellDataTypeEnum.BOOLEAN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
|
||||
Boolean value = null;
|
||||
String colName = contentProperty.getHead().getHeadNameList().get(0);//当前列
|
||||
if(!CellDataTypeEnum.BOOLEAN.equals(cellData.getType())){
|
||||
throw new Exception("["+colName+"]列数据格式有误,请填写正确的逻辑类型数据");
|
||||
}
|
||||
try {
|
||||
value = cellData.getBooleanValue();
|
||||
} catch (Exception e) {
|
||||
throw new Exception("["+colName+"]列数据格式有误,请填写正确的逻辑类型数据");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CellData convertToExcelData(Boolean value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
|
||||
return new CellData(value);
|
||||
}
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
package com.diboot.component.excel.converter;
|
||||
|
||||
import com.alibaba.excel.converters.Converter;
|
||||
import com.alibaba.excel.enums.CellDataTypeEnum;
|
||||
import com.alibaba.excel.metadata.CellData;
|
||||
import com.alibaba.excel.metadata.GlobalConfiguration;
|
||||
import com.alibaba.excel.metadata.property.ExcelContentProperty;
|
||||
import com.alibaba.excel.util.DateUtils;
|
||||
import org.apache.poi.ss.usermodel.DateUtil;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public class DateConverter implements Converter<Date> {
|
||||
@Override
|
||||
public Class supportJavaTypeKey() {
|
||||
return Date.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CellDataTypeEnum supportExcelTypeKey() {
|
||||
return CellDataTypeEnum.NUMBER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
|
||||
Date value = null;
|
||||
String colName = contentProperty.getHead().getHeadNameList().get(0);//当前列
|
||||
try {
|
||||
value = DateUtil.getJavaDate(cellData.getNumberValue().doubleValue(),
|
||||
globalConfiguration.getUse1904windowing(), null);
|
||||
} catch (Exception e) {
|
||||
throw new Exception("["+colName+"]列数据格式有误,请填写正确的时间类型数据");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CellData convertToExcelData(Date value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
|
||||
if (contentProperty == null || contentProperty.getDateTimeFormatProperty() == null) {
|
||||
return new CellData(DateUtils.format(value, null));
|
||||
} else {
|
||||
return new CellData(DateUtils.format(value, contentProperty.getDateTimeFormatProperty().getFormat()));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
package com.diboot.component.excel.converter;
|
||||
|
||||
import com.alibaba.excel.converters.Converter;
|
||||
import com.alibaba.excel.enums.CellDataTypeEnum;
|
||||
import com.alibaba.excel.metadata.CellData;
|
||||
import com.alibaba.excel.metadata.GlobalConfiguration;
|
||||
import com.alibaba.excel.metadata.property.ExcelContentProperty;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
public class DoubleConverter implements Converter<Double> {
|
||||
@Override
|
||||
public Class supportJavaTypeKey() {
|
||||
return Double.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CellDataTypeEnum supportExcelTypeKey() {
|
||||
return CellDataTypeEnum.NUMBER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
|
||||
Double value = null;
|
||||
String colName = contentProperty.getHead().getHeadNameList().get(0);//当前列
|
||||
try {
|
||||
value = cellData.getNumberValue().doubleValue();
|
||||
} catch (Exception e) {
|
||||
throw new Exception("["+colName+"]列数据格式有误,请填写正确的浮点型数据");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CellData convertToExcelData(Double value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
|
||||
return new CellData(BigDecimal.valueOf(value));
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
package com.diboot.component.excel.converter;
|
||||
|
||||
import com.alibaba.excel.converters.Converter;
|
||||
import com.alibaba.excel.enums.CellDataTypeEnum;
|
||||
import com.alibaba.excel.metadata.CellData;
|
||||
import com.alibaba.excel.metadata.GlobalConfiguration;
|
||||
import com.alibaba.excel.metadata.property.ExcelContentProperty;
|
||||
|
||||
public class IntegerConverter implements Converter<Integer> {
|
||||
@Override
|
||||
public Class supportJavaTypeKey() {
|
||||
return Integer.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CellDataTypeEnum supportExcelTypeKey() {
|
||||
return CellDataTypeEnum.NUMBER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
|
||||
Integer value = null;
|
||||
String colName = contentProperty.getHead().getHeadNameList().get(0);//当前列
|
||||
try {
|
||||
value = cellData.getNumberValue().intValue();
|
||||
} catch (Exception e) {
|
||||
throw new Exception("["+colName+"]列数据格式有误,请填写正确的整型数据");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CellData convertToExcelData(Integer value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
|
||||
return new CellData(value.toString());
|
||||
}
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
package com.diboot.component.excel.converter;
|
||||
|
||||
import com.alibaba.excel.converters.Converter;
|
||||
import com.alibaba.excel.enums.CellDataTypeEnum;
|
||||
import com.alibaba.excel.metadata.CellData;
|
||||
import com.alibaba.excel.metadata.GlobalConfiguration;
|
||||
import com.alibaba.excel.metadata.property.ExcelContentProperty;
|
||||
|
||||
public class StringConverter implements Converter<String> {
|
||||
@Override
|
||||
public Class supportJavaTypeKey() {
|
||||
return String.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CellDataTypeEnum supportExcelTypeKey() {
|
||||
return CellDataTypeEnum.STRING;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
|
||||
return cellData.getStringValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CellData convertToExcelData(String value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
|
||||
return new CellData(value);
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
package com.diboot.component.excel.entity;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/***
|
||||
* excel数据导入导出实体基类
|
||||
* @auther wangyl
|
||||
* @date 2019-10-9
|
||||
*/
|
||||
@Data
|
||||
public class BaseExcelDataEntity {
|
||||
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
package com.diboot.component.excel.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.diboot.core.entity.BaseEntity;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* Excel列定义
|
||||
* @author Mazc
|
||||
* @version 2017-09-18
|
||||
* Copyright @ www.com.ltd
|
||||
*/
|
||||
@Data
|
||||
public class ExcelColumn extends BaseEntity {
|
||||
private static final long serialVersionUID = -1539079350889067812L;
|
||||
|
||||
@TableField
|
||||
private String modelClass; // Java对象类
|
||||
|
||||
@TableField
|
||||
private String modelField; // Java对象属性
|
||||
|
||||
@TableField
|
||||
private String colName; // 列标题
|
||||
|
||||
@TableField
|
||||
private Integer colIndex; // 列索引
|
||||
|
||||
@TableField
|
||||
private String dataType; // 数据类型
|
||||
|
||||
@TableField
|
||||
private String validation; // 校验
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
package com.diboot.component.excel.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.diboot.core.entity.BaseEntity;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* Excel导入记录
|
||||
* @author Mazc
|
||||
* @version 2017-09-18
|
||||
* Copyright @ www.com.ltd
|
||||
*/
|
||||
@Data
|
||||
public class ExcelImportRecord extends BaseEntity {
|
||||
private static final long serialVersionUID = 7628990901469833759L;
|
||||
|
||||
@TableField
|
||||
private String fileUuid; // 文件ID
|
||||
|
||||
@TableField
|
||||
private String relObjType; // 关联类型
|
||||
|
||||
@TableField
|
||||
private Long relObjId; // 关联ID
|
||||
|
||||
@TableField
|
||||
private String relObjUid; // 关联UUID
|
||||
|
||||
}
|
|
@ -1,246 +0,0 @@
|
|||
package com.diboot.component.excel.listener;
|
||||
|
||||
import com.alibaba.excel.context.AnalysisContext;
|
||||
import com.alibaba.excel.event.AnalysisEventListener;
|
||||
import com.alibaba.excel.exception.ExcelDataConvertException;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.diboot.component.excel.entity.BaseExcelDataEntity;
|
||||
import com.diboot.component.excel.entity.ExcelColumn;
|
||||
import com.diboot.component.excel.service.ExcelColumnService;
|
||||
import com.diboot.core.entity.BaseEntity;
|
||||
import com.diboot.core.service.BaseService;
|
||||
import com.diboot.core.util.BeanUtils;
|
||||
import com.diboot.core.util.JSON;
|
||||
import com.diboot.core.util.V;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/***
|
||||
* excel数据导入导出listener基类
|
||||
* @auther wangyl
|
||||
* @date 2019-10-9
|
||||
*/
|
||||
@Component
|
||||
public abstract class BaseExcelDataListener <T extends BaseExcelDataEntity, E extends BaseEntity> extends AnalysisEventListener<T> {
|
||||
private static final Logger logger = LoggerFactory.getLogger(BaseExcelDataListener.class);
|
||||
|
||||
@Autowired
|
||||
protected ExcelColumnService excelColumnService;
|
||||
|
||||
private Map<Integer, String> headMap;//解析出的excel表头
|
||||
private List<T> dataList = new ArrayList<>();//解析后的数据实体list
|
||||
private List<E> entityList = new ArrayList<>();//可存入数据库的数据实体list
|
||||
private List<String> errorMsgs = new ArrayList<>();//错误日志
|
||||
private boolean isPreview = false;//是否预览模式,默认否
|
||||
private static Map<String, List<ExcelColumn>> excelColumnMap = null;//Excel列定义缓存
|
||||
|
||||
/*
|
||||
* 当前一行数据解析成功后的操作
|
||||
* */
|
||||
@Override
|
||||
public void invoke(T data, AnalysisContext context) {
|
||||
dataList.add(data);
|
||||
}
|
||||
|
||||
/*
|
||||
* 所有数据解析成功后的操作
|
||||
* */
|
||||
@Override
|
||||
public void doAfterAllAnalysed(AnalysisContext context) {
|
||||
if(isPreview){
|
||||
return;
|
||||
}
|
||||
checkHeader(headMap);//表头校验
|
||||
checkDataList(dataList);//数据校验
|
||||
List<String> errors = customVerify(dataList);//自定义数据校验
|
||||
if(V.notEmpty(errors)){
|
||||
errorMsgs.addAll(errors);
|
||||
}
|
||||
try {
|
||||
convertToEntityList(dataList);
|
||||
} catch (Exception e) {
|
||||
logger.error("excel数据转化失败",e);
|
||||
errorMsgs.add("excel数据解析失败");
|
||||
}
|
||||
if(V.notEmpty(errorMsgs)){
|
||||
return;
|
||||
}
|
||||
try {
|
||||
saveData();
|
||||
} catch (Exception e) {
|
||||
logger.error("保存excel数据失败", e);
|
||||
errorMsgs.add("保存excel数据失败");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 在转换异常、获取其他异常下会调用本接口。
|
||||
* 抛出异常则停止读取。如果这里不抛出异常则 继续读取下一行。
|
||||
* */
|
||||
@Override
|
||||
public void onException(Exception exception, AnalysisContext context) throws Exception {
|
||||
int currentRowNum = context.readRowHolder().getRowIndex();
|
||||
//数据类型转化异常
|
||||
if (exception instanceof ExcelDataConvertException) {
|
||||
logger.error("数据转化异常", exception);
|
||||
errorMsgs.add("第"+currentRowNum+"行"+exception.getCause().getMessage());
|
||||
}else{//其他异常
|
||||
logger.error("出现暂未处理的异常:",exception);
|
||||
errorMsgs.add(exception.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* excel表头数据
|
||||
* */
|
||||
@Override
|
||||
public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
|
||||
logger.error("解析到一条表头数据:",JSON.toJSONString(headMap));
|
||||
this.headMap = headMap;
|
||||
}
|
||||
|
||||
/*
|
||||
* 校验表头
|
||||
* */
|
||||
private void checkHeader(Map<Integer, String> headMap) {
|
||||
List<ExcelColumn> excelColumnList = null;
|
||||
try {
|
||||
excelColumnList = getExcelColumnList(getModelClass().getSimpleName());
|
||||
} catch (Exception e) {
|
||||
logger.error("获取表格列定义失败");
|
||||
errorMsgs.add("获取表格列定义失败");
|
||||
return;
|
||||
}
|
||||
if(V.isEmpty(headMap) || V.isEmpty(excelColumnList)){
|
||||
logger.error("请设置excel表头");
|
||||
errorMsgs.add("请设置excel表头");
|
||||
return;
|
||||
}
|
||||
if(headMap.size() != excelColumnList.size()){
|
||||
logger.error("Excel文件中的标题列数与期望不符");
|
||||
errorMsgs.add("Excel文件中的标题列数与预期不符,期望为"+excelColumnList.size()+"列");
|
||||
return;
|
||||
}
|
||||
for(ExcelColumn excelColumn : excelColumnList){
|
||||
if(V.notEquals(excelColumn.getColName(), headMap.get(excelColumn.getColIndex()-1))){
|
||||
errorMsgs.add("标题名:["+headMap.get(excelColumn.getColIndex()-1)+"]与预期不符,请改为["+excelColumn.getColName()+"]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 校验数据实体list
|
||||
* */
|
||||
private void checkDataList(List<T> dataList) {
|
||||
List<ExcelColumn> excelColumnList = null;
|
||||
try {
|
||||
excelColumnList = getExcelColumnList(getModelClass().getSimpleName());
|
||||
} catch (Exception e) {
|
||||
logger.error("获取表格列定义失败", e);
|
||||
errorMsgs.add("获取表格列定义失败");
|
||||
return;
|
||||
}
|
||||
if(V.isEmpty(excelColumnList)){
|
||||
logger.error("获取表格列定义为空");
|
||||
errorMsgs.add("获取表格列定义为空");
|
||||
return;
|
||||
}
|
||||
if(V.notEmpty(dataList)){
|
||||
for(int i=0;i<dataList.size();i++){
|
||||
checkData(dataList.get(i), i+1,excelColumnList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 校验数据实体
|
||||
* */
|
||||
private void checkData(T data, Integer currentRowNum, List<ExcelColumn> excelColumnList) {
|
||||
if(V.notEmpty(excelColumnList)){
|
||||
for(ExcelColumn excelColumn : excelColumnList){
|
||||
String value = BeanUtils.getStringProperty(data,excelColumn.getModelField());
|
||||
String error = V.validate(value, excelColumn.getValidation());
|
||||
if(V.notEmpty(error)){
|
||||
errorMsgs.add("第"+currentRowNum+"行["+excelColumn.getColName()+"]"+error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 将解析后的数据实体list转化为可存入数据库的实体list
|
||||
* */
|
||||
private void convertToEntityList(List<T> dataList) throws Exception{
|
||||
entityList = BeanUtils.convertList(dataList, getModelClass());
|
||||
}
|
||||
|
||||
/*
|
||||
* 自定义数据检验方式,例:数据重复性校验等,返回校验日志信息
|
||||
* */
|
||||
protected abstract List<String> customVerify(List<T> dataList) ;
|
||||
|
||||
/*
|
||||
* 保存解析的数据到数据库
|
||||
* */
|
||||
private boolean saveData() throws Exception{
|
||||
return getBusinessService().createEntities(entityList);
|
||||
}
|
||||
|
||||
/***
|
||||
* 获取业务的service
|
||||
* @return
|
||||
*/
|
||||
protected abstract BaseService getBusinessService();
|
||||
|
||||
/***
|
||||
* 获取Model类
|
||||
* @return
|
||||
*/
|
||||
protected abstract Class<E> getModelClass();
|
||||
|
||||
/**
|
||||
* 加载表格列定义
|
||||
*/
|
||||
public List<ExcelColumn> getExcelColumnList(String modelClass) throws Exception{
|
||||
if(excelColumnMap == null){
|
||||
excelColumnMap = new ConcurrentHashMap<>();
|
||||
}
|
||||
List<ExcelColumn> list = excelColumnMap.get(modelClass);
|
||||
if(list == null){
|
||||
// 构建查询时的排序定义,根据列序号进行升序排列
|
||||
LambdaQueryWrapper<ExcelColumn> wrapper = new LambdaQueryWrapper();
|
||||
wrapper.eq(ExcelColumn::getModelClass, modelClass)
|
||||
.orderByAsc(ExcelColumn::getColIndex);
|
||||
list = excelColumnService.getEntityList(wrapper);
|
||||
excelColumnMap.put(modelClass, list);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public List<T> getDataList(){
|
||||
return dataList;
|
||||
}
|
||||
|
||||
public List<E> getEntityList(){
|
||||
return entityList;
|
||||
}
|
||||
|
||||
public List<String> getErrorMsgs(){
|
||||
return errorMsgs;
|
||||
}
|
||||
|
||||
public boolean isPreview() {
|
||||
return isPreview;
|
||||
}
|
||||
|
||||
public void setPreview(boolean preview) {
|
||||
isPreview = preview;
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
package com.diboot.component.excel.mapper;
|
||||
|
||||
import com.diboot.component.excel.entity.ExcelColumn;
|
||||
import com.diboot.core.mapper.BaseCrudMapper;
|
||||
|
||||
/**
|
||||
* @author Lishuaifei
|
||||
* @description
|
||||
* @creatime 2019-07-11 17:03
|
||||
*/
|
||||
public interface ExcelColumnMapper extends BaseCrudMapper<ExcelColumn> {
|
||||
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"./mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.diboot.component.excel.mapper.ExcelColumnMapper">
|
||||
|
||||
</mapper>
|
|
@ -1,13 +0,0 @@
|
|||
package com.diboot.component.excel.mapper;
|
||||
|
||||
import com.diboot.component.excel.entity.ExcelImportRecord;
|
||||
import com.diboot.core.mapper.BaseCrudMapper;
|
||||
|
||||
/**
|
||||
* @author Lishuaifei
|
||||
* @description
|
||||
* @creatime 2019-07-11 17:03
|
||||
*/
|
||||
public interface ExcelImportRecordMapper extends BaseCrudMapper<ExcelImportRecord> {
|
||||
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"./mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.diboot.component.excel.mapper.ExcelImportRecordMapper">
|
||||
|
||||
</mapper>
|
|
@ -1,13 +0,0 @@
|
|||
package com.diboot.component.excel.service;
|
||||
|
||||
import com.diboot.component.excel.entity.ExcelColumn;
|
||||
import com.diboot.core.service.BaseService;
|
||||
|
||||
/**
|
||||
* @author Lishuaifei
|
||||
* @description
|
||||
* @creatime 2019-07-11 17:05
|
||||
*/
|
||||
public interface ExcelColumnService extends BaseService<ExcelColumn> {
|
||||
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
package com.diboot.component.excel.service;
|
||||
|
||||
import com.diboot.component.excel.entity.ExcelImportRecord;
|
||||
import com.diboot.core.entity.BaseEntity;
|
||||
import com.diboot.core.service.BaseService;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Lishuaifei
|
||||
* @description
|
||||
* @creatime 2019-07-11 17:05
|
||||
*/
|
||||
public interface ExcelImportRecordService extends BaseService<ExcelImportRecord> {
|
||||
|
||||
boolean batchCreateRecords(String fileUid, List<? extends BaseEntity> modelList);
|
||||
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
package com.diboot.component.excel.service.impl;
|
||||
|
||||
import com.diboot.component.excel.entity.ExcelColumn;
|
||||
import com.diboot.component.excel.mapper.ExcelColumnMapper;
|
||||
import com.diboot.component.excel.service.ExcelColumnService;
|
||||
import com.diboot.core.service.impl.BaseServiceImpl;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author Lishuaifei
|
||||
* @description
|
||||
* @creatime 2019-07-11 17:06
|
||||
*/
|
||||
@Service
|
||||
public class ExcelColumnServiceImpl extends BaseServiceImpl<ExcelColumnMapper, ExcelColumn> implements ExcelColumnService {
|
||||
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
package com.diboot.component.excel.service.impl;
|
||||
|
||||
import com.diboot.component.excel.entity.ExcelImportRecord;
|
||||
import com.diboot.component.excel.mapper.ExcelImportRecordMapper;
|
||||
import com.diboot.component.excel.service.ExcelImportRecordService;
|
||||
import com.diboot.core.entity.BaseEntity;
|
||||
import com.diboot.core.service.impl.BaseServiceImpl;
|
||||
import com.diboot.core.util.V;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Lishuaifei
|
||||
* @description
|
||||
* @creatime 2019-07-11 17:06
|
||||
*/
|
||||
@Service
|
||||
public class ExcelImportRecordServiceImpl extends BaseServiceImpl<ExcelImportRecordMapper, ExcelImportRecord> implements ExcelImportRecordService {
|
||||
|
||||
@Override
|
||||
public boolean batchCreateRecords(String fileUid, List<? extends BaseEntity> modelList) {
|
||||
List<ExcelImportRecord> recordList = new ArrayList<>();
|
||||
if(V.notEmpty(modelList)){
|
||||
for(BaseEntity entity : modelList){
|
||||
ExcelImportRecord record = new ExcelImportRecord();
|
||||
record.setFileUuid(fileUid);
|
||||
record.setRelObjType(entity.getClass().getSimpleName());
|
||||
record.setRelObjId(entity.getId());
|
||||
recordList.add(record);
|
||||
}
|
||||
}
|
||||
return createEntities(recordList);
|
||||
}
|
||||
}
|
|
@ -1,103 +0,0 @@
|
|||
package com.diboot.component.excel.utils;
|
||||
|
||||
import com.alibaba.excel.EasyExcel;
|
||||
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
|
||||
import com.diboot.component.excel.entity.BaseExcelDataEntity;
|
||||
import com.diboot.component.excel.listener.BaseExcelDataListener;
|
||||
import com.diboot.core.util.V;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
/***
|
||||
* excel数据导入导出工具类
|
||||
* @auther wangyl
|
||||
* @date 2019-10-9
|
||||
*/
|
||||
public class EasyExcelHelper {
|
||||
private static final Logger logger = LoggerFactory.getLogger(EasyExcelHelper.class);
|
||||
|
||||
/**
|
||||
* 简单读取excel文件数据,当isPreview=false时,保存到数据库
|
||||
* @param filePath
|
||||
* @param clazz
|
||||
* @param listener
|
||||
* @return
|
||||
*/
|
||||
public static <T extends BaseExcelDataEntity> List<T> simpleRead(String filePath, Class<T> clazz, BaseExcelDataListener listener, boolean isPreview) throws Exception{
|
||||
File file = new File(filePath);
|
||||
if(!file.exists()){
|
||||
logger.error("找不到指定文件,路径:"+filePath);
|
||||
throw new Exception("找不到指定文件,导入excel失败");
|
||||
}
|
||||
listener.setPreview(isPreview);
|
||||
EasyExcel.read(filePath, clazz, listener).sheet().doRead();
|
||||
return listener.getDataList();
|
||||
}
|
||||
|
||||
public static <T extends BaseExcelDataEntity> boolean simpleReadAndSave(String filePath, Class<T> clazz, BaseExcelDataListener listener) throws Exception{
|
||||
File file = new File(filePath);
|
||||
if(!file.exists()){
|
||||
logger.error("找不到指定文件,路径:"+filePath);
|
||||
throw new Exception("找不到指定文件,导入excel失败");
|
||||
}
|
||||
listener.setPreview(false);
|
||||
EasyExcel.read(filePath, clazz, listener).sheet().doRead();
|
||||
if(V.notEmpty(listener.getErrorMsgs())){
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 简单将数据写入excel文件
|
||||
* @param filePath
|
||||
* @param clazz
|
||||
* @param dataList
|
||||
* @param <T>
|
||||
* @return
|
||||
*/
|
||||
public static <T extends BaseExcelDataEntity> boolean simpleWrite(String filePath, Class<T> clazz, List dataList) throws Exception{
|
||||
return simpleWrite(filePath, clazz, null, dataList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 简单将数据写入excel文件
|
||||
* @param filePath
|
||||
* @param clazz
|
||||
* @param sheetName
|
||||
* @param dataList
|
||||
* @param <T>
|
||||
* @return
|
||||
*/
|
||||
public static <T extends BaseExcelDataEntity> boolean simpleWrite(String filePath, Class<T> clazz, String sheetName, List dataList) throws Exception{
|
||||
try {
|
||||
EasyExcel.write(filePath, clazz).sheet(sheetName).doWrite(dataList);
|
||||
} catch (Exception e) {
|
||||
logger.error("数据写入excel文件失败",e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 简单将数据写入excel文件,列宽自适应数据长度
|
||||
* @param filePath
|
||||
* @param clazz
|
||||
* @param dataList
|
||||
* @param <T>
|
||||
* @return
|
||||
*/
|
||||
public static <T extends BaseExcelDataEntity> boolean simpleWriteWithAdaptColumnWidth(String filePath, Class<T> clazz, List dataList) throws Exception{
|
||||
try {
|
||||
EasyExcel.write(filePath, clazz).registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).sheet().doWrite(dataList);
|
||||
} catch (Exception e) {
|
||||
logger.error("数据写入excel文件失败",e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
dependencies {
|
||||
// 依赖core
|
||||
compile project(":diboot-core")
|
||||
// 图片压缩
|
||||
compile ("net.coobird:thumbnailator:0.4.8")
|
||||
// 文件下载
|
||||
compile("org.apache.httpcomponents:httpclient:4.5.9")
|
||||
}
|
||||
|
||||
jar{
|
||||
manifest {
|
||||
attributes('Implementation-Title': 'Diboot component - file',
|
||||
'Implementation-Version': '2.0.3'
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,175 +0,0 @@
|
|||
package com.diboot.component.file.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.diboot.core.entity.BaseEntity;
|
||||
import org.hibernate.validator.constraints.Length;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* file基础父类
|
||||
* @author wangyl
|
||||
* @version v2.0
|
||||
* @date 2019/07/18
|
||||
*/
|
||||
@TableName("file")
|
||||
public class BaseFile extends BaseEntity {
|
||||
private static final long serialVersionUID = 201L;
|
||||
|
||||
public enum FILE_STATUS {
|
||||
S,
|
||||
F
|
||||
}
|
||||
// 废弃默认主键
|
||||
@TableField(exist = false)
|
||||
private Long id;
|
||||
|
||||
// 声明新主键uuid
|
||||
@NotNull(message = "编号不能为空!")
|
||||
@Length(max = 32, message = "编号长度超出了最大限制!")
|
||||
@TableId(type = IdType.UUID)
|
||||
private String uuid = null;
|
||||
|
||||
@NotNull(message = "关联对象类型不能为空!")
|
||||
@Length(max = 50, message = "关联对象类型长度超出了最大限制!")
|
||||
@TableField
|
||||
private String relObjType = null;
|
||||
@TableField
|
||||
@NotNull(message = "关联对象ID不能为空!")
|
||||
private Long relObjId;
|
||||
|
||||
@TableField
|
||||
@NotNull(message = "文件名不能为空!")
|
||||
@Length(max = 100, message = "文件名长度超出了最大限制!")
|
||||
private String name;
|
||||
|
||||
@TableField
|
||||
@NotNull(message = "文件链接不能为空!")
|
||||
@Length(max = 255, message = "文件链接长度超出了最大限制!")
|
||||
private String link;
|
||||
|
||||
@TableField
|
||||
@NotNull(message = "文件路径不能为空!")
|
||||
@Length(max = 255, message = "文件路径长度超出了最大限制!")
|
||||
private String path;
|
||||
|
||||
@TableField
|
||||
@Length(max = 20, message = "文件类型长度超出了最大限制!")
|
||||
private String fileType;
|
||||
|
||||
@TableField
|
||||
private int dataCount = 0;
|
||||
|
||||
@TableField
|
||||
private Long size;
|
||||
|
||||
@TableField
|
||||
@Length(max = 1, message = "状态长度超出了最大限制!")
|
||||
private String status;
|
||||
|
||||
@TableField
|
||||
@Length(max = 255, message = "备注长度超出了最大限制!")
|
||||
private String comment;
|
||||
|
||||
public String getUuid() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
public void setUuid(String uuid) {
|
||||
this.uuid = uuid;
|
||||
}
|
||||
|
||||
public String getRelObjType() {
|
||||
return this.relObjType;
|
||||
}
|
||||
|
||||
public void setRelObjType(String relObjType) {
|
||||
this.relObjType = relObjType;
|
||||
}
|
||||
|
||||
public Long getRelObjId() {
|
||||
return this.relObjId;
|
||||
}
|
||||
|
||||
public void setRelObjId(Long relObjId) {
|
||||
this.relObjId = relObjId;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getLink() {
|
||||
return this.link;
|
||||
}
|
||||
|
||||
public void setLink(String link) {
|
||||
this.link = link;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return this.path;
|
||||
}
|
||||
|
||||
public void setPath(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public String getFileType() {
|
||||
return this.fileType;
|
||||
}
|
||||
|
||||
public void setFileType(String fileType) {
|
||||
this.fileType = fileType;
|
||||
}
|
||||
|
||||
public Long getSize() {
|
||||
return this.size;
|
||||
}
|
||||
|
||||
public void setSize(Long size) {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public String getComment() {
|
||||
return this.comment;
|
||||
}
|
||||
|
||||
public void setComment(String comment) {
|
||||
this.comment = comment;
|
||||
}
|
||||
|
||||
public int getDataCount() {
|
||||
return this.dataCount;
|
||||
}
|
||||
|
||||
public void setDataCount(int dataCount) {
|
||||
this.dataCount = dataCount;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return this.status;
|
||||
}
|
||||
|
||||
public String getStatusLabel(){
|
||||
if(FILE_STATUS.S.name().equals(this.status)){
|
||||
return "成功";
|
||||
}else if(FILE_STATUS.F.name().equals(this.status)){
|
||||
return "失败";
|
||||
}else{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void setStatus(String status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,640 +0,0 @@
|
|||
package com.diboot.component.file.file;
|
||||
|
||||
import com.diboot.component.file.file.http.CustomSSLSocketFactory;
|
||||
import com.diboot.core.util.PropertiesUtils;
|
||||
import com.diboot.core.util.S;
|
||||
import net.coobird.thumbnailator.Thumbnails;
|
||||
import org.apache.commons.fileupload.servlet.ServletFileUpload;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import org.springframework.web.multipart.MultipartHttpServletRequest;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.*;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/***
|
||||
* 文件操作辅助类
|
||||
* @author Mazc
|
||||
*/
|
||||
public class FileHelper{
|
||||
private static final Logger logger = LoggerFactory.getLogger(FileHelper.class);
|
||||
|
||||
/**
|
||||
* image验证
|
||||
*/
|
||||
public static final String VALID_IMAGE_SUFFIX = "|png|jpg|jpeg|gif|bmp|";
|
||||
/**
|
||||
* file验证
|
||||
*/
|
||||
public static final String DANGER_FILE_SUFFIX = "|exe|bat|bin|dll|sh";
|
||||
/**
|
||||
* excel格式
|
||||
*/
|
||||
public static final String EXCEL_SUFFIX = "|xls|xlsx|xlsm|";
|
||||
/**
|
||||
* 文件存储路径参数名
|
||||
*/
|
||||
public static final String FILE_STORAGE_DIRECTORY = "files.storage.directory";
|
||||
|
||||
/**
|
||||
* 文件存储路径
|
||||
*/
|
||||
private static final String PATH_FILE = "/upload/file";
|
||||
private static final String PATH_IMG = "/upload/img";
|
||||
private static final String PATH_AUDIO = "/upload/audio";
|
||||
|
||||
/**
|
||||
* 日期格式-文件夹名称
|
||||
*/
|
||||
public static final String FORMAT_DATE_Y2M = "yyMM";
|
||||
public static final String FORMAT_DATE_Y2MD = "yyMMdd";
|
||||
|
||||
/***
|
||||
* 默认contextType
|
||||
*/
|
||||
private static final String DEFAULT_CONTEXT_TYPE = "application/octet-stream";
|
||||
|
||||
/***
|
||||
* 文件扩展名-ContentType的对应关系
|
||||
*/
|
||||
private static Map<String, String> EXT_CONTENT_TYPE_MAP = new HashMap(){{
|
||||
put("xls", "application/x-msdownload");
|
||||
put("xlsx", "application/x-msdownload");
|
||||
put("doc", "application/x-msdownload");
|
||||
put("docx", "application/x-msdownload");
|
||||
put("dot", "application/x-msdownload");
|
||||
put("ppt", "application/x-msdownload");
|
||||
put("pptx", "application/x-msdownload");
|
||||
put("pdf", "application/pdf");
|
||||
put("avi", "video/avi");
|
||||
put("bmp", "application/x-bmp");
|
||||
put("css", "text/css");
|
||||
put("dll", "application/x-msdownload");
|
||||
put("dtd", "text/xml");
|
||||
put("exe", "application/x-msdownload");
|
||||
put("gif", "image/gif");
|
||||
put("htm", "text/html");
|
||||
put("html", "text/html");
|
||||
put("ico", "image/x-icon");
|
||||
put("jpeg", "image/jpeg");
|
||||
put("jpg", "image/jpeg");
|
||||
put("js", "application/x-javascript");
|
||||
put("mp3", "audio/mp3");
|
||||
put("mp4", "video/mpeg4");
|
||||
put("png", "image/png");
|
||||
put("svg", "text/xml");
|
||||
put("swf", "application/x-shockwave-flash");
|
||||
put("tif", "image/tiff");
|
||||
put("tiff", "image/tiff");
|
||||
put("tld", "text/xml");
|
||||
put("torrent", "application/x-bittorrent");
|
||||
put("tsd", "text/xml");
|
||||
put("txt", "text/plain");
|
||||
put("wav", "audio/wav");
|
||||
put("wma", "audio/x-ms-wma");
|
||||
put("wmf", "application/x-wmf");
|
||||
put("wsdl", "text/xml");
|
||||
put("xhtml", "text/html");
|
||||
put("xml", "text/xml");
|
||||
put("xsd", "text/xml");
|
||||
put("xsl", "text/xml");
|
||||
put("xslt", "text/xml");
|
||||
put("apk", "application/vnd.android.package-archive");
|
||||
}};
|
||||
|
||||
/**
|
||||
* 文件和图片的后台存储路径
|
||||
*/
|
||||
private static String fileStorageDirectory = null;
|
||||
|
||||
/***
|
||||
* 是否为合法的文件类型
|
||||
* @param ext
|
||||
* @return
|
||||
*/
|
||||
public static boolean isValidFileExt(String ext){
|
||||
return !DANGER_FILE_SUFFIX.contains("|"+ext.toLowerCase());
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是图片类型
|
||||
* @param ext
|
||||
* @return
|
||||
*/
|
||||
public static boolean isImage(String ext){
|
||||
return VALID_IMAGE_SUFFIX.contains("|"+ext.toLowerCase()+"|");
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是Excel文件
|
||||
* @param fileName
|
||||
* @return
|
||||
*/
|
||||
public static boolean isExcel(String fileName){
|
||||
String ext = getFileExtByName(fileName);
|
||||
return EXCEL_SUFFIX.contains("|"+ext.toLowerCase()+"|");
|
||||
}
|
||||
|
||||
/***
|
||||
* 获取系统临时目录
|
||||
* @return
|
||||
*/
|
||||
public static String getSystemTempDir(){
|
||||
return System.getProperty("java.io.tmpdir");
|
||||
}
|
||||
|
||||
/***
|
||||
* 将文件保存到系统临时目录
|
||||
* @param file
|
||||
* @param fileName
|
||||
* @return
|
||||
*/
|
||||
public static String saveFile2TempDir(MultipartFile file, String fileName){
|
||||
String fullPath = getSystemTempDir() + fileName;
|
||||
try {
|
||||
FileUtils.writeByteArrayToFile(new File(fullPath), file.getBytes());
|
||||
return fileName;
|
||||
}
|
||||
catch (IOException e1) {
|
||||
logger.error("保存原图片失败(image=" + fileName + "): ", e1);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存图片
|
||||
* @param file 上传文件
|
||||
* @param imgName 图片名称
|
||||
*/
|
||||
public static String saveImage(MultipartFile file, String imgName){
|
||||
// 生成图片路径
|
||||
String accessPath = getImageStoragePath(imgName);
|
||||
String fullPath = getFileStorageDirectory() + accessPath;
|
||||
try {
|
||||
// 创建文件夹
|
||||
makeDirectory(fullPath);
|
||||
FileUtils.writeByteArrayToFile(new File(fullPath), file.getBytes());
|
||||
if(logger.isDebugEnabled()){
|
||||
logger.debug("保存图片成功!路径为: " + accessPath);
|
||||
}
|
||||
return accessPath;
|
||||
}
|
||||
catch (IOException e1) {
|
||||
logger.error("保存原图片失败(image=" + accessPath + "): ", e1);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存图片
|
||||
* @param file 上传文件
|
||||
*/
|
||||
public static String saveImage(MultipartFile file){
|
||||
String fileName = file.getOriginalFilename();
|
||||
String ext = fileName.substring(fileName.lastIndexOf(".")+1);
|
||||
String newFileName = S.newUuid() + "." + ext;
|
||||
return saveImage(file, newFileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存图片
|
||||
* @param file 上传文件
|
||||
* @param imgName 图片名称
|
||||
* @param reserve 是否保留原图片
|
||||
* @return
|
||||
*/
|
||||
public static String saveImage(File file, String imgName, boolean reserve){
|
||||
// 生成图片路径
|
||||
String accessPath = getImageStoragePath(imgName);
|
||||
String fullPath = getFileStorageDirectory() + accessPath;
|
||||
try{
|
||||
// 创建文件夹
|
||||
makeDirectory(fullPath);
|
||||
FileUtils.copyFile(new File(fullPath), file);
|
||||
if(logger.isDebugEnabled()){
|
||||
logger.debug("保存图片成功!路径为: " + accessPath);
|
||||
}
|
||||
// 如果原文件与目标文件不相等且不保留原文件,则删除原文件
|
||||
if (!reserve && !StringUtils.equals(file.getAbsolutePath(), fullPath)){
|
||||
FileUtils.forceDelete(file);
|
||||
}
|
||||
return accessPath;
|
||||
} catch (Exception e){
|
||||
logger.error("保存原图片失败(image=" + accessPath + "): ", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* 上传文件
|
||||
* @param file 上传文件
|
||||
* @param fileName 文件名
|
||||
* @return
|
||||
*/
|
||||
public static String saveFile(MultipartFile file, String fileName) {
|
||||
// 生成文件路径
|
||||
String accessPath = getFileStoragePath(fileName);
|
||||
String fullPath = getFileStorageDirectory() + accessPath;
|
||||
try {
|
||||
// 创建文件夹
|
||||
makeDirectory(fullPath);
|
||||
FileUtils.writeByteArrayToFile(new File(fullPath), file.getBytes());
|
||||
if(logger.isDebugEnabled()){
|
||||
logger.debug("保存文件成功!路径为: " + fullPath);
|
||||
}
|
||||
return accessPath;
|
||||
}
|
||||
catch (IOException e1) {
|
||||
logger.error("保存文件失败(file=" + fullPath + "): ", e1);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* 上传文件
|
||||
* @param file 上传文件
|
||||
* @return
|
||||
*/
|
||||
public static String saveFile(MultipartFile file){
|
||||
String fileName = file.getOriginalFilename();
|
||||
String ext = fileName.substring(fileName.lastIndexOf(".")+1);
|
||||
String newFileName = S.newUuid() + "." + ext;
|
||||
return saveFile(file, newFileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传文件
|
||||
* @param file 上传文件
|
||||
* @param fileName 文件名
|
||||
* @param reserve 保留原文件
|
||||
* @return
|
||||
*/
|
||||
public static String saveFile(File file, String fileName, boolean reserve){
|
||||
// 生成文件路径
|
||||
String accessPath = getFileStoragePath(fileName);
|
||||
String fullPath = getFileStorageDirectory() + accessPath;
|
||||
try{
|
||||
// 创建文件夹
|
||||
makeDirectory(fullPath);
|
||||
FileUtils.copyFile(new File(fullPath), file);
|
||||
if(logger.isDebugEnabled()){
|
||||
logger.debug("保存文件成功!路径为: " + fullPath);
|
||||
}
|
||||
// 如果原文件与目标文件不相等且不保留原文件,则删除原文件
|
||||
if (!reserve && !StringUtils.equals(file.getAbsolutePath(), fullPath)){
|
||||
FileUtils.forceDelete(file);
|
||||
}
|
||||
return accessPath;
|
||||
} catch (Exception e){
|
||||
logger.error("保存文件失败(file=" + fullPath + "): ", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* 根据名称取得后缀
|
||||
* @param fileName
|
||||
* @return
|
||||
*/
|
||||
public static String getFileExtByName(String fileName){
|
||||
if(fileName.startsWith("http") && fileName.contains("/")){
|
||||
fileName = getFileName(fileName);
|
||||
}
|
||||
if(fileName.lastIndexOf(".") > 0){
|
||||
return fileName.substring(fileName.lastIndexOf(".")+1).toLowerCase();
|
||||
}
|
||||
logger.warn("检测到没有后缀的文件名:" + fileName);
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* 得到图片存储的全路径
|
||||
* @param fileName
|
||||
* @return
|
||||
*/
|
||||
public static String getImageStoragePath(String fileName){
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(PATH_IMG).append("/").append(getYearMonth()).append("/").append(fileName);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/***
|
||||
* 获取文件的存储路径
|
||||
* @param name
|
||||
* @return
|
||||
*/
|
||||
public static String getFileStoragePath(String name) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(PATH_FILE).append("/").append(getYearMonth()).append("/").append(name);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/***
|
||||
* 获取录音文件的存储路径
|
||||
* @param category
|
||||
* @return
|
||||
*/
|
||||
public static String getAudioStoragePath(String category, String name) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(PATH_AUDIO);
|
||||
if(StringUtils.isNotBlank(category)){
|
||||
sb.append("/").append(category);
|
||||
}
|
||||
sb.append("/").append(getYearMonthDay()).append("/").append(name);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/***
|
||||
* 获取文件的全路径
|
||||
* @return
|
||||
*/
|
||||
public static String getFullFilePath(String filePath){
|
||||
return getFileStorageDirectory()+filePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据文件URL解析出其文件名
|
||||
* @param fileURL
|
||||
* @return
|
||||
*/
|
||||
public static String getFileName(String fileURL){
|
||||
String temp = StringUtils.substring(fileURL, fileURL.lastIndexOf("/")+1);
|
||||
if(StringUtils.contains(fileURL, "?")){
|
||||
temp = StringUtils.substring(temp, 0, temp.lastIndexOf("?"));
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件的存储路径
|
||||
* @return
|
||||
*/
|
||||
public static String getFileStorageDirectory(){
|
||||
if(fileStorageDirectory == null){
|
||||
fileStorageDirectory = PropertiesUtils.get(FILE_STORAGE_DIRECTORY);
|
||||
}
|
||||
return fileStorageDirectory;
|
||||
}
|
||||
|
||||
/***
|
||||
* 创建文件夹
|
||||
* @param dirPath
|
||||
* @return
|
||||
*/
|
||||
public static boolean makeDirectory(String dirPath){
|
||||
String imageDirectory = StringUtils.substringBeforeLast(dirPath, "/");
|
||||
File dir = new File(imageDirectory);
|
||||
if(!dir.exists()){
|
||||
try {
|
||||
FileUtils.forceMkdir(dir);
|
||||
return true;
|
||||
}
|
||||
catch (IOException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 压缩图片
|
||||
* @param imgUrl
|
||||
* @return
|
||||
*/
|
||||
public static String generateThumbnail(String imgUrl, int width, int height){
|
||||
String file = imgUrl.substring(imgUrl.indexOf("/img/"));
|
||||
String imageFileDirectory = getFileStorageDirectory() + file;
|
||||
try {
|
||||
// 压缩图片
|
||||
String targetFile = imgUrl.replace(".", "_tn.");
|
||||
Thumbnails.of(imageFileDirectory).size(width, height).outputQuality(0.7f).toFile(getFileStorageDirectory() + targetFile);
|
||||
return targetFile;
|
||||
}
|
||||
catch (IOException e1) {
|
||||
logger.error("压缩图片异常(image=" + imageFileDirectory + "): ", e1);
|
||||
}
|
||||
return imgUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据文件路径与请求信息下载文件
|
||||
* @param path
|
||||
* @param request
|
||||
* @param response
|
||||
* @throws Exception
|
||||
*/
|
||||
public static void downloadLocalFile(String path, HttpServletRequest request, HttpServletResponse response) throws Exception{
|
||||
request.setCharacterEncoding("UTF-8");
|
||||
String downloadPath = path;
|
||||
BufferedInputStream bis = null;
|
||||
BufferedOutputStream bos = null;
|
||||
try{
|
||||
String outFileName = getFileName(path);
|
||||
String fileName = new String(outFileName.getBytes("utf-8"), "ISO8859-1");
|
||||
long fileLength = new File(downloadPath).length();
|
||||
response.setContentType(getContextType(fileName));
|
||||
response.setHeader("Content-disposition", "attachment; filename="+ fileName);
|
||||
response.setHeader("Content-Length", String.valueOf(fileLength));
|
||||
bis = new BufferedInputStream(new FileInputStream(downloadPath));
|
||||
bos = new BufferedOutputStream(response.getOutputStream());
|
||||
byte[] buff = new byte[2048];
|
||||
int bytesRead;
|
||||
while(-1 != (bytesRead = bis.read(buff, 0, buff.length))) {
|
||||
bos.write(buff, 0, bytesRead);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
logger.error("下载导出文件失败:"+path, e);
|
||||
}
|
||||
finally {
|
||||
if (bis != null) {
|
||||
bis.close();
|
||||
}
|
||||
if (bos != null) {
|
||||
bos.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/****
|
||||
* HTTP下载文件
|
||||
* @param fileUrl
|
||||
* @param targetFilePath
|
||||
* @return
|
||||
*/
|
||||
public static boolean downloadRemoteFile(String fileUrl, String targetFilePath) {
|
||||
CloseableHttpClient httpClient = HttpClients.createDefault();
|
||||
HttpGet httpGet = new HttpGet(fileUrl);
|
||||
try {
|
||||
HttpResponse httpResponse = httpClient.execute(httpGet);
|
||||
HttpEntity entity = httpResponse.getEntity();
|
||||
long length = entity.getContentLength();
|
||||
if(length <= 0){
|
||||
logger.warn("下载文件不存在!");
|
||||
return false;
|
||||
}
|
||||
FileUtils.copyInputStreamToFile(entity.getContent(), new File(targetFilePath));
|
||||
return true;
|
||||
}
|
||||
catch (MalformedURLException e) {
|
||||
logger.error("下载文件URL异常(url=" + fileUrl + "): ", e);
|
||||
return false;
|
||||
}
|
||||
catch (IOException e) {
|
||||
logger.error("下载文件IO异常(url=" + fileUrl + "): ", e);
|
||||
return false;
|
||||
}
|
||||
finally{
|
||||
try {
|
||||
httpClient.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
logger.error("关闭httpClient下载连接异常:", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/****
|
||||
* HTTP下载文件
|
||||
* @param fileUrl
|
||||
* @param
|
||||
* @return
|
||||
*/
|
||||
public static boolean downloadRemoteFileViaHttps(String fileUrl, String targetFilePath) {
|
||||
HttpClient httpClient = CustomSSLSocketFactory.newHttpClient();
|
||||
try {
|
||||
HttpGet httpGet = new HttpGet();
|
||||
httpGet.setURI(new URI(fileUrl));
|
||||
HttpResponse httpResponse = httpClient.execute(httpGet);
|
||||
HttpEntity entity = httpResponse.getEntity();
|
||||
long length = entity.getContentLength();
|
||||
if(length <= 0){
|
||||
logger.warn("下载文件不存在!");
|
||||
return false;
|
||||
}
|
||||
FileUtils.copyInputStreamToFile(entity.getContent(), new File(targetFilePath));
|
||||
return true;
|
||||
}
|
||||
catch (MalformedURLException e) {
|
||||
logger.error("下载文件URL异常(url=" + fileUrl + "): ", e);
|
||||
return false;
|
||||
}
|
||||
catch (IOException e) {
|
||||
logger.error("下载文件IO异常(url=" + fileUrl + "): ", e);
|
||||
return false;
|
||||
}
|
||||
catch (Exception e) {
|
||||
logger.error("下载文件异常(url=" + fileUrl + "): ", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/****
|
||||
* 删除文件
|
||||
* @param fileStoragePath
|
||||
*/
|
||||
public static void deleteFile(String fileStoragePath) {
|
||||
File wavFile = new File(fileStoragePath);
|
||||
if(wavFile.exists()){
|
||||
wavFile.delete();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据文件类型获取ContentType
|
||||
* @param fileName
|
||||
* @return
|
||||
*/
|
||||
public static String getContextType(String fileName){
|
||||
String ext = S.substringAfterLast(fileName, ".");
|
||||
String contentType = EXT_CONTENT_TYPE_MAP.get(ext);
|
||||
if(contentType == null){
|
||||
contentType = DEFAULT_CONTEXT_TYPE;
|
||||
}
|
||||
return contentType + ";charset=utf-8";
|
||||
}
|
||||
|
||||
/**
|
||||
* 得到当前的年月YYMM,用于生成文件夹名称
|
||||
* @return
|
||||
*/
|
||||
private static String getYearMonth(){
|
||||
Calendar cal = Calendar.getInstance();
|
||||
SimpleDateFormat sdf = new SimpleDateFormat(FORMAT_DATE_Y2M);
|
||||
return sdf.format(cal.getTime());
|
||||
}
|
||||
|
||||
/**
|
||||
* 得到当前的年月YYMM,用于生成文件夹
|
||||
* @return
|
||||
*/
|
||||
private static String getYearMonthDay(){
|
||||
Calendar cal = Calendar.getInstance();
|
||||
SimpleDateFormat sdf = new SimpleDateFormat(FORMAT_DATE_Y2MD);
|
||||
return sdf.format(cal.getTime());
|
||||
}
|
||||
|
||||
/***
|
||||
* 获取请求中的多个文件数据
|
||||
* @param request
|
||||
* @param fileInputName
|
||||
* @return
|
||||
*/
|
||||
public static List<MultipartFile> getFilesFromRequest(HttpServletRequest request, String... fileInputName){
|
||||
// 解析上传文件
|
||||
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
|
||||
if(!isMultipart){
|
||||
logger.warn("请上传文件!");
|
||||
return null;
|
||||
}
|
||||
// 获取附件文件名
|
||||
String inputName = "attachedFiles";
|
||||
if(fileInputName != null && fileInputName.length > 0){
|
||||
inputName = fileInputName[0];
|
||||
}
|
||||
// 解析上传文件
|
||||
List<MultipartFile> files = ((MultipartHttpServletRequest)request).getFiles(inputName);
|
||||
return files;
|
||||
}
|
||||
|
||||
/***
|
||||
* 获取请求中的单个文件数据
|
||||
* @param request
|
||||
* @param fileInputName
|
||||
* @return
|
||||
*/
|
||||
public static MultipartFile getFileFromRequest(HttpServletRequest request, String... fileInputName){
|
||||
// 解析上传文件
|
||||
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
|
||||
if(!isMultipart){
|
||||
logger.warn("请上传文件!");
|
||||
return null;
|
||||
}
|
||||
// 获取附件文件名
|
||||
String inputName = "attachedFiles";
|
||||
if(fileInputName != null && fileInputName.length > 0){
|
||||
inputName = fileInputName[0];
|
||||
}
|
||||
// 解析上传文件
|
||||
MultipartFile file = ((MultipartHttpServletRequest)request).getFile(inputName);
|
||||
return file;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
package com.diboot.component.file.file.audio;
|
||||
|
||||
import com.diboot.component.file.utils.RuntimeHelper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/***
|
||||
* Dibo 音频处理类
|
||||
* @author Mazc
|
||||
* @version 2016年11月7日
|
||||
* Copyright @ www.com.ltd
|
||||
*/
|
||||
public class AudioHelper {
|
||||
private static final Logger logger = LoggerFactory.getLogger(AudioHelper.class);
|
||||
|
||||
/***
|
||||
* 将wav音频转换为MP3格式
|
||||
* @param sourceFilePath
|
||||
* @param targetFilePath
|
||||
* @return
|
||||
*/
|
||||
public static String convertWavToMp3(String sourceFilePath, String targetFilePath){
|
||||
boolean success = RuntimeHelper.run("ffmpeg -i "+ sourceFilePath +" "+ targetFilePath); // -ar 8000 -ac 1 -y
|
||||
if(success){
|
||||
return targetFilePath;
|
||||
}
|
||||
else{
|
||||
return sourceFilePath;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,94 +0,0 @@
|
|||
package com.diboot.component.file.file.http;
|
||||
|
||||
import org.apache.http.HttpVersion;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.conn.ClientConnectionManager;
|
||||
import org.apache.http.conn.scheme.PlainSocketFactory;
|
||||
import org.apache.http.conn.scheme.Scheme;
|
||||
import org.apache.http.conn.scheme.SchemeRegistry;
|
||||
import org.apache.http.conn.ssl.SSLSocketFactory;
|
||||
import org.apache.http.impl.client.DefaultHttpClient;
|
||||
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
|
||||
import org.apache.http.params.BasicHttpParams;
|
||||
import org.apache.http.params.HttpParams;
|
||||
import org.apache.http.params.HttpProtocolParams;
|
||||
import org.apache.http.protocol.HTTP;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
import java.io.IOException;
|
||||
import java.net.Socket;
|
||||
import java.net.UnknownHostException;
|
||||
import java.security.*;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
/****
|
||||
* HttpClient工厂类, 解决HTTPS验证问题
|
||||
* @author Mazc
|
||||
* @version 2017年8月8日
|
||||
*
|
||||
*/
|
||||
public class CustomSSLSocketFactory extends SSLSocketFactory {
|
||||
private static final Logger logger = LoggerFactory.getLogger(CustomSSLSocketFactory.class);
|
||||
|
||||
SSLContext sslContext = SSLContext.getInstance("TLS");
|
||||
|
||||
public CustomSSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
|
||||
super(truststore);
|
||||
TrustManager tm = new X509TrustManager() {
|
||||
@Override
|
||||
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
|
||||
}
|
||||
@Override
|
||||
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
|
||||
}
|
||||
@Override
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
sslContext.init(null, new TrustManager[] { tm }, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException {
|
||||
return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
|
||||
}
|
||||
@Override
|
||||
public Socket createSocket() throws IOException {
|
||||
return sslContext.getSocketFactory().createSocket();
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回httpclient实例,避开https验证
|
||||
* @return
|
||||
*/
|
||||
public static HttpClient newHttpClient() {
|
||||
try {
|
||||
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
|
||||
trustStore.load(null, null);
|
||||
|
||||
SSLSocketFactory sf = new CustomSSLSocketFactory(trustStore);
|
||||
sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
|
||||
|
||||
HttpParams params = new BasicHttpParams();
|
||||
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
|
||||
HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
|
||||
|
||||
SchemeRegistry registry = new SchemeRegistry();
|
||||
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
|
||||
registry.register(new Scheme("https", sf, 443));
|
||||
|
||||
ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);
|
||||
|
||||
return new DefaultHttpClient(ccm, params);
|
||||
}
|
||||
catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,81 +0,0 @@
|
|||
package com.diboot.component.file.file.image;
|
||||
|
||||
import net.coobird.thumbnailator.Thumbnails;
|
||||
import net.coobird.thumbnailator.geometry.Positions;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Base64;
|
||||
|
||||
/***
|
||||
* 图片操作辅助类
|
||||
* @author Mazc
|
||||
*/
|
||||
public class ImageHandler {
|
||||
private static final Logger logger = LoggerFactory.getLogger(ImageHandler.class);
|
||||
|
||||
private static final String DATA_IMAGE_FLAG = "data:image/";
|
||||
private static final String BASE_64_FLAG = "base64,";
|
||||
|
||||
/**
|
||||
* 将Base64转换为图片
|
||||
* @param base64Str
|
||||
* @param fullFilePath
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
private static boolean convertBase64ToImage(String base64Str, String fullFilePath){
|
||||
if(base64Str == null){
|
||||
return false;
|
||||
}
|
||||
if(base64Str.contains(BASE_64_FLAG)){
|
||||
int suffixStart = StringUtils.indexOf(base64Str, DATA_IMAGE_FLAG)+ DATA_IMAGE_FLAG.length();
|
||||
String suffix = StringUtils.substring(base64Str, suffixStart, StringUtils.indexOf(base64Str, ";", suffixStart));
|
||||
base64Str = base64Str.substring(base64Str.indexOf(BASE_64_FLAG)+ BASE_64_FLAG.length());
|
||||
}
|
||||
try{
|
||||
byte[] data = Base64.getDecoder().decode(base64Str);
|
||||
File file = new File(fullFilePath);
|
||||
FileUtils.writeByteArrayToFile(file, data);
|
||||
data = null;
|
||||
return true;
|
||||
}
|
||||
catch(Exception e){
|
||||
logger.warn("base", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成缩略图
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public static String generateThumbnail(String sourcePath, String targetPath, int width, int height) throws Exception{
|
||||
// 创建文件
|
||||
File file = new File(sourcePath);
|
||||
if(!file.exists()){
|
||||
boolean result = file.mkdir();
|
||||
if(!result){
|
||||
logger.warn("创建文件夹"+sourcePath+"失败。");
|
||||
}
|
||||
}
|
||||
// 生成缩略图
|
||||
Thumbnails.of(sourcePath).size(width, height).toFile(targetPath);
|
||||
return targetPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* 给图片添加水印
|
||||
* @param filePath
|
||||
*/
|
||||
private static void addWatermark(String filePath, String watermark) throws Exception{
|
||||
Thumbnails.of(filePath).watermark(Positions.BOTTOM_RIGHT, ImageIO.read(new File(watermark)), 0.8f).toFile(filePath);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,167 +0,0 @@
|
|||
package com.diboot.component.file.file.zip;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.util.zip.CRC32;
|
||||
import java.util.zip.CheckedOutputStream;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
/***
|
||||
* 文件压缩操作辅助类
|
||||
* @author Mazc
|
||||
*/
|
||||
public class ZipHelper {
|
||||
private static final Logger logger = LoggerFactory.getLogger(ZipHelper.class);
|
||||
|
||||
/**
|
||||
* 递归压缩文件
|
||||
* @param srcRootDir
|
||||
* @param file
|
||||
* @param zos
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
private static void zipFile(String srcRootDir, File file, ZipOutputStream zos, String... matchKeyword) throws Exception {
|
||||
if (file == null) {
|
||||
logger.error("[Zip]file对象为空,压缩失败!");
|
||||
return;
|
||||
}
|
||||
|
||||
//如果是文件,则直接压缩该文件
|
||||
if (file.isFile()) {
|
||||
int count, bufferLen = 1024;
|
||||
byte[] data = new byte[bufferLen];
|
||||
String fileName = file.getName();
|
||||
|
||||
//包含在指定文件名范围内的文件进行压缩
|
||||
if (matchKeyword == null || matchKeyword.length == 0 || fileName.indexOf(matchKeyword[0]) >= 0) {
|
||||
//获取文件相对于压缩文件夹根目录的子路径
|
||||
String subPath = file.getAbsolutePath();
|
||||
subPath = subPath.replace("\\", "/"); //解决文件路径分割符Unix和Windows不兼容的问题
|
||||
if (subPath.indexOf(srcRootDir) != -1)
|
||||
{
|
||||
subPath = subPath.substring(srcRootDir.length() + File.separator.length());
|
||||
}
|
||||
ZipEntry entry = new ZipEntry(subPath);
|
||||
zos.putNextEntry(entry);
|
||||
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
|
||||
while ((count = bis.read(data, 0, bufferLen)) != -1)
|
||||
{
|
||||
zos.write(data, 0, count);
|
||||
}
|
||||
logger.info("[Zip]压缩成功:" + file.getName());
|
||||
bis.close();
|
||||
zos.closeEntry();
|
||||
}
|
||||
}
|
||||
else {
|
||||
//压缩目录中的文件或子目录
|
||||
File[] childFileList = file.listFiles();
|
||||
String filePath = "";
|
||||
if(childFileList != null) {
|
||||
for (int n=0; n<childFileList.length; n++)
|
||||
{
|
||||
if (!childFileList[n].isFile()) {
|
||||
filePath = childFileList[n].getPath();
|
||||
//不在指定目录名范围内的目录不进行压缩
|
||||
if (matchKeyword != null && matchKeyword.length > 0 && filePath.indexOf(matchKeyword[0]) == -1) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
childFileList[n].getAbsolutePath().indexOf(file.getAbsolutePath());
|
||||
zipFile(srcRootDir, childFileList[n], zos, matchKeyword);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 对文件或文件目录进行压缩
|
||||
* @param srcPath 要压缩的源文件路径。如果压缩一个文件,则为该文件的全路径;如果压缩一个目录,则为该目录的顶层目录路径
|
||||
* @param zipPath 压缩文件保存的路径。注意:zipPath不能是srcPath路径下的子文件夹
|
||||
* @param zipFileName 压缩文件名
|
||||
* @param excludeKeyword 需要剔除
|
||||
* @throws Exception
|
||||
*/
|
||||
public static boolean zip(String srcPath, String zipPath, String zipFileName, String... excludeKeyword) throws Exception {
|
||||
if (StringUtils.isEmpty(srcPath))
|
||||
{
|
||||
logger.error("[Zip]源文件路径为空,压缩失败!");
|
||||
return false;
|
||||
}
|
||||
if (StringUtils.isEmpty(zipPath))
|
||||
{
|
||||
logger.error("[Zip]压缩文件保存的路径为空,压缩失败!");
|
||||
return false;
|
||||
}
|
||||
if (StringUtils.isEmpty(zipFileName))
|
||||
{
|
||||
logger.error("[Zip]压缩文件名为空,压缩失败!");
|
||||
return false;
|
||||
}
|
||||
|
||||
CheckedOutputStream cos = null;
|
||||
ZipOutputStream zos = null;
|
||||
|
||||
File srcFile = new File(srcPath);
|
||||
|
||||
if (srcFile.exists()) {
|
||||
//判断压缩文件保存的路径是否为源文件路径的子文件夹,如果是,则终止压缩
|
||||
if (srcFile.isDirectory() && zipPath.indexOf(srcPath)!=-1)
|
||||
{
|
||||
logger.error("[Zip]压缩文件保存的路径是源文件的字文件夹,压缩失败!");
|
||||
return false;
|
||||
}
|
||||
|
||||
//判断压缩文件保存的路径是否存在,如果不存在,则创建目录
|
||||
File zipDir = new File(zipPath);
|
||||
if (!zipDir.exists() || !zipDir.isDirectory())
|
||||
{
|
||||
zipDir.mkdirs();
|
||||
}
|
||||
|
||||
//创建压缩文件保存的文件对象
|
||||
String zipFilePath = zipPath + "/" + zipFileName;
|
||||
File zipFile = new File(zipFilePath);
|
||||
if (zipFile.exists())
|
||||
{
|
||||
//删除已存在的目标文件
|
||||
zipFile.delete();
|
||||
}
|
||||
|
||||
cos = new CheckedOutputStream(new FileOutputStream(zipFile), new CRC32());
|
||||
zos = new ZipOutputStream(cos);
|
||||
|
||||
//如果只是压缩一个文件,则需要截取该文件的父目录
|
||||
String srcRootDir = srcPath;
|
||||
if (srcFile.isFile())
|
||||
{
|
||||
int index = srcPath.lastIndexOf("/");
|
||||
if (index != -1)
|
||||
{
|
||||
srcRootDir = srcPath.substring(0, index);
|
||||
}
|
||||
}
|
||||
//调用递归压缩方法进行目录或文件压缩
|
||||
zipFile(srcRootDir, srcFile, zos, excludeKeyword);
|
||||
zos.flush();
|
||||
|
||||
if (zos != null)
|
||||
{
|
||||
zos.close();
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
logger.error("[Zip]当前源目录不存在,压缩失败!" + srcPath);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
package com.diboot.component.file.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Constants;
|
||||
import com.diboot.component.file.entity.BaseFile;
|
||||
import com.diboot.core.mapper.BaseCrudMapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
|
||||
/**
|
||||
* 文件相关Mapper
|
||||
* @author Mazc
|
||||
* @version 2017/4/18
|
||||
*/
|
||||
public interface BaseFileMapper extends BaseCrudMapper<BaseFile> {
|
||||
|
||||
@Select("SELECT * FROM file ${ew.customSqlSegment}")
|
||||
BaseFile getModel(@Param(Constants.WRAPPER) Wrapper<BaseFile> wrapper);
|
||||
|
||||
int updateModel(@Param("m") BaseFile model);
|
||||
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"./mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.diboot.component.file.mapper.BaseFileMapper">
|
||||
|
||||
<sql id="setValues">
|
||||
<set>
|
||||
<if test="m.relObjType != null">rel_obj_type = #{m.relObjType},</if>
|
||||
<if test="m.relObjId != null">rel_obj_id = #{m.relObjId},</if>
|
||||
<if test="m.name != null">name = #{m.name},</if>
|
||||
<if test="m.link != null">link = #{m.link},</if>
|
||||
<if test="m.path != null">path = #{m.path},</if>
|
||||
<if test="m.fileType != null">file_type = #{m.fileType},</if>
|
||||
<if test="m.dataCount != null">data_count = #{m.dataCount},</if>
|
||||
<if test="m.size != null">size = #{m.size},</if>
|
||||
<if test="m.status != null">status = #{m.status},</if>
|
||||
<if test="m.comment != null">comment = #{m.comment},</if>
|
||||
<if test="m.deleted != null">is_deleted = #{m.deleted},</if>
|
||||
</set>
|
||||
</sql>
|
||||
|
||||
<update id="updateModel" parameterType="String">
|
||||
UPDATE file <include refid="setValues"/>
|
||||
WHERE uuid = #{m.uuid, jdbcType=VARCHAR}
|
||||
</update>
|
||||
|
||||
</mapper>
|
|
@ -1,291 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!--
|
||||
|
||||
Copyright 2009-2013 the original author or authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed joinOn 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.
|
||||
|
||||
-->
|
||||
|
||||
<!ELEMENT mapper (cache-ref | cache | resultMap* | parameterMap* | sql* | insert* | update* | delete* | select* )+>
|
||||
<!ATTLIST mapper
|
||||
xmlns:fo CDATA #IMPLIED
|
||||
namespace CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT cache-ref EMPTY>
|
||||
<!ATTLIST cache-ref
|
||||
namespace CDATA #REQUIRED
|
||||
>
|
||||
|
||||
<!ELEMENT cache (property*)>
|
||||
<!ATTLIST cache
|
||||
type CDATA #IMPLIED
|
||||
eviction CDATA #IMPLIED
|
||||
flushInterval CDATA #IMPLIED
|
||||
size CDATA #IMPLIED
|
||||
readOnly CDATA #IMPLIED
|
||||
blocking CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT parameterMap (parameter+)?>
|
||||
<!ATTLIST parameterMap
|
||||
id CDATA #REQUIRED
|
||||
type CDATA #REQUIRED
|
||||
>
|
||||
|
||||
<!ELEMENT parameter EMPTY>
|
||||
<!ATTLIST parameter
|
||||
property CDATA #REQUIRED
|
||||
javaType CDATA #IMPLIED
|
||||
jdbcType CDATA #IMPLIED
|
||||
mode (IN | OUT | INOUT) #IMPLIED
|
||||
resultMap CDATA #IMPLIED
|
||||
scale CDATA #IMPLIED
|
||||
typeHandler CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT resultMap (constructor?,id*,result*,association*,collection*, discriminator?)>
|
||||
<!ATTLIST resultMap
|
||||
id CDATA #REQUIRED
|
||||
type CDATA #REQUIRED
|
||||
extends CDATA #IMPLIED
|
||||
autoMapping (true|false) #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT constructor (idArg*,arg*)>
|
||||
|
||||
<!ELEMENT id EMPTY>
|
||||
<!ATTLIST id
|
||||
property CDATA #IMPLIED
|
||||
javaType CDATA #IMPLIED
|
||||
column CDATA #IMPLIED
|
||||
jdbcType CDATA #IMPLIED
|
||||
typeHandler CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT result EMPTY>
|
||||
<!ATTLIST result
|
||||
property CDATA #IMPLIED
|
||||
javaType CDATA #IMPLIED
|
||||
column CDATA #IMPLIED
|
||||
jdbcType CDATA #IMPLIED
|
||||
typeHandler CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT idArg EMPTY>
|
||||
<!ATTLIST idArg
|
||||
javaType CDATA #IMPLIED
|
||||
column CDATA #IMPLIED
|
||||
jdbcType CDATA #IMPLIED
|
||||
typeHandler CDATA #IMPLIED
|
||||
select CDATA #IMPLIED
|
||||
resultMap CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT arg EMPTY>
|
||||
<!ATTLIST arg
|
||||
javaType CDATA #IMPLIED
|
||||
column CDATA #IMPLIED
|
||||
jdbcType CDATA #IMPLIED
|
||||
typeHandler CDATA #IMPLIED
|
||||
select CDATA #IMPLIED
|
||||
resultMap CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT collection (constructor?,id*,result*,association*,collection*, discriminator?)>
|
||||
<!ATTLIST collection
|
||||
property CDATA #REQUIRED
|
||||
column CDATA #IMPLIED
|
||||
javaType CDATA #IMPLIED
|
||||
ofType CDATA #IMPLIED
|
||||
jdbcType CDATA #IMPLIED
|
||||
select CDATA #IMPLIED
|
||||
resultMap CDATA #IMPLIED
|
||||
typeHandler CDATA #IMPLIED
|
||||
notNullColumn CDATA #IMPLIED
|
||||
columnPrefix CDATA #IMPLIED
|
||||
resultSet CDATA #IMPLIED
|
||||
foreignColumn CDATA #IMPLIED
|
||||
autoMapping (true|false) #IMPLIED
|
||||
fetchType (lazy|eager) #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT association (constructor?,id*,result*,association*,collection*, discriminator?)>
|
||||
<!ATTLIST association
|
||||
property CDATA #REQUIRED
|
||||
column CDATA #IMPLIED
|
||||
javaType CDATA #IMPLIED
|
||||
jdbcType CDATA #IMPLIED
|
||||
select CDATA #IMPLIED
|
||||
resultMap CDATA #IMPLIED
|
||||
typeHandler CDATA #IMPLIED
|
||||
notNullColumn CDATA #IMPLIED
|
||||
columnPrefix CDATA #IMPLIED
|
||||
resultSet CDATA #IMPLIED
|
||||
foreignColumn CDATA #IMPLIED
|
||||
autoMapping (true|false) #IMPLIED
|
||||
fetchType (lazy|eager) #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT discriminator (case+)>
|
||||
<!ATTLIST discriminator
|
||||
column CDATA #IMPLIED
|
||||
javaType CDATA #REQUIRED
|
||||
jdbcType CDATA #IMPLIED
|
||||
typeHandler CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT case (constructor?,id*,result*,association*,collection*, discriminator?)>
|
||||
<!ATTLIST case
|
||||
value CDATA #REQUIRED
|
||||
resultMap CDATA #IMPLIED
|
||||
resultType CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT property EMPTY>
|
||||
<!ATTLIST property
|
||||
name CDATA #REQUIRED
|
||||
value CDATA #REQUIRED
|
||||
>
|
||||
|
||||
<!ELEMENT typeAlias EMPTY>
|
||||
<!ATTLIST typeAlias
|
||||
alias CDATA #REQUIRED
|
||||
type CDATA #REQUIRED
|
||||
>
|
||||
|
||||
<!ELEMENT select (#PCDATA | include | trim | where | set | foreach | choose | if | bind)*>
|
||||
<!ATTLIST select
|
||||
id CDATA #REQUIRED
|
||||
parameterMap CDATA #IMPLIED
|
||||
parameterType CDATA #IMPLIED
|
||||
resultMap CDATA #IMPLIED
|
||||
resultType CDATA #IMPLIED
|
||||
resultSetType (FORWARD_ONLY | SCROLL_INSENSITIVE | SCROLL_SENSITIVE) #IMPLIED
|
||||
statementType (STATEMENT|PREPARED|CALLABLE) #IMPLIED
|
||||
fetchSize CDATA #IMPLIED
|
||||
timeout CDATA #IMPLIED
|
||||
flushCache (true|false) #IMPLIED
|
||||
useCache (true|false) #IMPLIED
|
||||
databaseId CDATA #IMPLIED
|
||||
lang CDATA #IMPLIED
|
||||
resultOrdered (true|false) #IMPLIED
|
||||
resultSets CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT insert (#PCDATA | selectKey | include | trim | where | set | foreach | choose | if | bind)*>
|
||||
<!ATTLIST insert
|
||||
id CDATA #REQUIRED
|
||||
parameterMap CDATA #IMPLIED
|
||||
parameterType CDATA #IMPLIED
|
||||
timeout CDATA #IMPLIED
|
||||
flushCache (true|false) #IMPLIED
|
||||
statementType (STATEMENT|PREPARED|CALLABLE) #IMPLIED
|
||||
keyProperty CDATA #IMPLIED
|
||||
useGeneratedKeys (true|false) #IMPLIED
|
||||
keyColumn CDATA #IMPLIED
|
||||
databaseId CDATA #IMPLIED
|
||||
lang CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT selectKey (#PCDATA | include | trim | where | set | foreach | choose | if | bind)*>
|
||||
<!ATTLIST selectKey
|
||||
resultType CDATA #IMPLIED
|
||||
statementType (STATEMENT|PREPARED|CALLABLE) #IMPLIED
|
||||
keyProperty CDATA #IMPLIED
|
||||
keyColumn CDATA #IMPLIED
|
||||
order (BEFORE|AFTER) #IMPLIED
|
||||
databaseId CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT update (#PCDATA | selectKey | include | trim | where | set | foreach | choose | if | bind)*>
|
||||
<!ATTLIST update
|
||||
id CDATA #REQUIRED
|
||||
parameterMap CDATA #IMPLIED
|
||||
parameterType CDATA #IMPLIED
|
||||
timeout CDATA #IMPLIED
|
||||
flushCache (true|false) #IMPLIED
|
||||
statementType (STATEMENT|PREPARED|CALLABLE) #IMPLIED
|
||||
keyProperty CDATA #IMPLIED
|
||||
useGeneratedKeys (true|false) #IMPLIED
|
||||
keyColumn CDATA #IMPLIED
|
||||
databaseId CDATA #IMPLIED
|
||||
lang CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT delete (#PCDATA | include | trim | where | set | foreach | choose | if | bind)*>
|
||||
<!ATTLIST delete
|
||||
id CDATA #REQUIRED
|
||||
parameterMap CDATA #IMPLIED
|
||||
parameterType CDATA #IMPLIED
|
||||
timeout CDATA #IMPLIED
|
||||
flushCache (true|false) #IMPLIED
|
||||
statementType (STATEMENT|PREPARED|CALLABLE) #IMPLIED
|
||||
databaseId CDATA #IMPLIED
|
||||
lang CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!-- Dynamic -->
|
||||
|
||||
<!ELEMENT include (property+)?>
|
||||
<!ATTLIST include
|
||||
refid CDATA #REQUIRED
|
||||
>
|
||||
|
||||
<!ELEMENT bind EMPTY>
|
||||
<!ATTLIST bind
|
||||
name CDATA #REQUIRED
|
||||
value CDATA #REQUIRED
|
||||
>
|
||||
|
||||
<!ELEMENT sql (#PCDATA | include | trim | where | set | foreach | choose | if | bind)*>
|
||||
<!ATTLIST sql
|
||||
id CDATA #REQUIRED
|
||||
lang CDATA #IMPLIED
|
||||
databaseId CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT trim (#PCDATA | include | trim | where | set | foreach | choose | if | bind)*>
|
||||
<!ATTLIST trim
|
||||
prefix CDATA #IMPLIED
|
||||
prefixOverrides CDATA #IMPLIED
|
||||
suffix CDATA #IMPLIED
|
||||
suffixOverrides CDATA #IMPLIED
|
||||
>
|
||||
<!ELEMENT where (#PCDATA | include | trim | where | set | foreach | choose | if | bind)*>
|
||||
<!ELEMENT set (#PCDATA | include | trim | where | set | foreach | choose | if | bind)*>
|
||||
|
||||
<!ELEMENT foreach (#PCDATA | include | trim | where | set | foreach | choose | if | bind)*>
|
||||
<!ATTLIST foreach
|
||||
collection CDATA #REQUIRED
|
||||
item CDATA #IMPLIED
|
||||
index CDATA #IMPLIED
|
||||
open CDATA #IMPLIED
|
||||
close CDATA #IMPLIED
|
||||
separator CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT choose (when* , otherwise?)>
|
||||
<!ELEMENT when (#PCDATA | include | trim | where | set | foreach | choose | if | bind)*>
|
||||
<!ATTLIST when
|
||||
test CDATA #REQUIRED
|
||||
>
|
||||
<!ELEMENT otherwise (#PCDATA | include | trim | where | set | foreach | choose | if | bind)*>
|
||||
|
||||
<!ELEMENT if (#PCDATA | include | trim | where | set | foreach | choose | if | bind)*>
|
||||
<!ATTLIST if
|
||||
test CDATA #REQUIRED
|
||||
>
|
||||
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
package com.diboot.component.file.service;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.diboot.component.file.entity.BaseFile;
|
||||
import com.diboot.core.service.BaseService;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author Lishuaifei
|
||||
* @description 基础文件Service
|
||||
* @creatime 2019-07-18 15:20
|
||||
*/
|
||||
@Component
|
||||
public interface BaseFileService extends BaseService<BaseFile> {
|
||||
|
||||
/*
|
||||
* 自定义获取数据方法,解决查询不出is_deleted=1的数据的问题
|
||||
* */
|
||||
BaseFile getModel(Wrapper<BaseFile> wrapper);
|
||||
|
||||
/*
|
||||
* 自定义更新数据方法,解决无法更新is_deleted=1的数据的问题
|
||||
* */
|
||||
boolean updateModel(BaseFile model);
|
||||
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
package com.diboot.component.file.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.diboot.component.file.entity.BaseFile;
|
||||
import com.diboot.component.file.mapper.BaseFileMapper;
|
||||
import com.diboot.component.file.service.BaseFileService;
|
||||
import com.diboot.core.service.impl.BaseServiceImpl;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author Lishuaifei
|
||||
* @description 文件下载实现类
|
||||
* @creatime 2019-07-18 15:29
|
||||
*/
|
||||
@Service
|
||||
public class BaseFileServiceImpl extends BaseServiceImpl<BaseFileMapper, BaseFile> implements BaseFileService {
|
||||
|
||||
@Autowired
|
||||
private BaseFileMapper baseFileMapper;
|
||||
|
||||
@Override
|
||||
public BaseFile getModel(Wrapper<BaseFile> wrapper) {
|
||||
return baseFileMapper.getModel(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean updateModel(BaseFile model) {
|
||||
return baseFileMapper.updateModel(model)>0? true:false;
|
||||
}
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
package com.diboot.component.file.utils;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
|
||||
/***
|
||||
* Java执行命令行辅助类
|
||||
* @author Mazc
|
||||
*/
|
||||
public class RuntimeHelper {
|
||||
private static final Logger logger = LoggerFactory.getLogger(RuntimeHelper.class);
|
||||
|
||||
public static boolean run(String command){
|
||||
Runtime runtime = null;
|
||||
try{
|
||||
runtime = Runtime.getRuntime();
|
||||
Process process = runtime.exec(command); // -ar 8000 -ac 1 -y -ab 12.4k
|
||||
// 转换成功
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
|
||||
String line;
|
||||
while((line=reader.readLine())!=null){
|
||||
logger.debug(line);
|
||||
}
|
||||
int result = process.waitFor();
|
||||
if(result == 0){
|
||||
process.destroy();
|
||||
return true;
|
||||
}
|
||||
else{
|
||||
process.destroy();
|
||||
throw new RuntimeException("运行命令失败: "+command);
|
||||
}
|
||||
}
|
||||
catch(Exception e){
|
||||
logger.error("运行命令失败: ", e);
|
||||
return false;
|
||||
}
|
||||
finally{
|
||||
if(runtime!=null){
|
||||
runtime.freeMemory();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
|
||||
dependencies {
|
||||
compile project(":diboot-component-msg")
|
||||
|
||||
// java mail
|
||||
compile("javax.mail:mail:1.4.7",
|
||||
"org.apache.commons:commons-email:1.5")
|
||||
|
||||
testCompile group: 'junit', name: 'junit', version: '4.12'
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
package com.diboot.component.msg.email.service;
|
||||
|
||||
import com.diboot.component.msg.service.BaseSendService;
|
||||
|
||||
public interface EmailSendService extends BaseSendService {
|
||||
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
package com.diboot.component.msg.email.service;
|
||||
|
||||
import com.diboot.component.msg.email.utils.EmailUtil;
|
||||
import com.diboot.component.msg.entity.Message;
|
||||
import com.diboot.component.msg.service.impl.BaseSendServiceImpl;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
public class EmailSendServiceImpl extends BaseSendServiceImpl implements EmailSendService {
|
||||
private static final Logger logger = LoggerFactory.getLogger(EmailSendServiceImpl.class);
|
||||
|
||||
@Override
|
||||
public boolean sendMsg(Message message) throws Exception {
|
||||
String to = message.getReceiver();
|
||||
String toName = String.valueOf(message.getFromExt("toName"));
|
||||
String title = message.getTitle();
|
||||
String content = message.getContent();
|
||||
String[] ccEmails = (String[])message.getFromExt("ccEmails");
|
||||
String[] filePaths = (String[])message.getFromExt("filePaths");
|
||||
return EmailUtil.send(to, toName, title, content, ccEmails, filePaths);
|
||||
}
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
package com.diboot.component.msg.email.utils;
|
||||
|
||||
import com.diboot.core.config.Cons;
|
||||
import com.diboot.core.util.PropertiesUtils;
|
||||
import com.diboot.core.util.V;
|
||||
import org.apache.commons.mail.EmailAttachment;
|
||||
import org.apache.commons.mail.HtmlEmail;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class EmailUtil {
|
||||
private static final Logger logger = LoggerFactory.getLogger(EmailUtil.class);
|
||||
|
||||
private static final String EMAIL_NAME = PropertiesUtils.get("email.name");// 发送方称呼
|
||||
private static final String EMAIL_ADDRESS = PropertiesUtils.get("email.address");// 发送方email地址
|
||||
private static final String EMAIL_PASSWORD = PropertiesUtils.get("email.password");// 发送方授权码
|
||||
private static final String EMAIL_HOST = PropertiesUtils.get("email.host");//发送方smptHost
|
||||
private static final String EMAIL_SSLPORT = PropertiesUtils.get("email.sslport");// 发送端口
|
||||
|
||||
/*
|
||||
* 邮件发送
|
||||
* */
|
||||
public static boolean send(String to, String toName, String title, String content, String[] ccEmails, String... filePaths) throws Exception{
|
||||
if(logger.isDebugEnabled()){
|
||||
logger.debug(">>>发送邮件开始, 收件人:" + to);
|
||||
}
|
||||
// Create the email message
|
||||
HtmlEmail email = new HtmlEmail();
|
||||
email.setHostName(EMAIL_HOST);
|
||||
email.setCharset(Cons.CHARSET_UTF8);
|
||||
email.setSSLOnConnect(true);
|
||||
if(V.notEmpty(EMAIL_SSLPORT)){
|
||||
email.setSslSmtpPort(EMAIL_SSLPORT);
|
||||
}
|
||||
email.setAuthentication(EMAIL_ADDRESS, EMAIL_PASSWORD);
|
||||
email.addTo(to, toName);
|
||||
if(V.notEmpty(ccEmails)){
|
||||
for(String cc : ccEmails){
|
||||
email.addCc(cc);
|
||||
}
|
||||
}
|
||||
email.setFrom(EMAIL_ADDRESS, EMAIL_NAME);
|
||||
email.setSubject(title);
|
||||
// set the html message
|
||||
email.setHtmlMsg(content);
|
||||
// 发送附件
|
||||
if(V.notEmpty(filePaths)){
|
||||
for(String path : filePaths){
|
||||
File file = new File(path);
|
||||
if(!file.exists()){
|
||||
logger.warn("附件文件不存在,无法发送!path="+path);
|
||||
return false;
|
||||
}
|
||||
EmailAttachment attachment = new EmailAttachment();
|
||||
attachment.setName(file.getName());
|
||||
attachment.setPath(path);
|
||||
attachment.setDisposition(EmailAttachment.ATTACHMENT);
|
||||
email.attach(attachment);
|
||||
}
|
||||
}
|
||||
// send the email
|
||||
email.send();
|
||||
|
||||
if(logger.isDebugEnabled()){
|
||||
logger.debug("<<<发送邮件结束");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
|
||||
dependencies {
|
||||
compile project(":diboot-core")
|
||||
|
||||
testCompile group: 'junit', name: 'junit', version: '4.12'
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
package com.diboot.component.msg.config;
|
||||
|
||||
public class MsgCons {
|
||||
|
||||
/*
|
||||
* 消息类型
|
||||
* */
|
||||
public enum MSG_TYPE{
|
||||
EMAIL, //邮件消息
|
||||
SMS, //短信消息
|
||||
WECHAT //微信消息
|
||||
}
|
||||
}
|
|
@ -1,91 +0,0 @@
|
|||
package com.diboot.component.msg.controller;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.diboot.component.msg.entity.Message;
|
||||
import com.diboot.component.msg.service.MessageService;
|
||||
import com.diboot.component.msg.vo.MessageVO;
|
||||
import com.diboot.core.binding.RelationsBinder;
|
||||
import com.diboot.core.controller.BaseCrudRestController;
|
||||
import com.diboot.core.service.BaseService;
|
||||
import com.diboot.core.vo.JsonResult;
|
||||
import com.diboot.core.vo.Pagination;
|
||||
import com.diboot.core.vo.Status;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/message")
|
||||
public class MessageController extends BaseCrudRestController {
|
||||
|
||||
@Autowired
|
||||
private MessageService messageService;
|
||||
|
||||
@Override
|
||||
protected BaseService getService() {
|
||||
return messageService;
|
||||
}
|
||||
|
||||
@GetMapping("/list")
|
||||
public JsonResult list(Message message, Pagination pagination, HttpServletRequest request) throws Exception {
|
||||
//构建查询条件
|
||||
QueryWrapper<Message> queryWrapper = super.buildQueryWrapper(message);
|
||||
// 查询当前页的Entity主表数据
|
||||
List<Message> entityList = getService().getEntityList(queryWrapper, pagination);
|
||||
// 自动转换VO中注解绑定的关联
|
||||
List<MessageVO> voList = RelationsBinder.convertAndBind(entityList, MessageVO.class);
|
||||
//返回结果
|
||||
return new JsonResult(Status.OK, voList).bindPagination(pagination);
|
||||
}
|
||||
|
||||
/***
|
||||
* 查询Entity
|
||||
* @param id
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@GetMapping("/{id}")
|
||||
public JsonResult getModel(@PathVariable("id")Long id, HttpServletRequest request)
|
||||
throws Exception{
|
||||
MessageVO entityVO = messageService.getViewObject(id, MessageVO.class);
|
||||
return new JsonResult(entityVO);
|
||||
}
|
||||
|
||||
/***
|
||||
* 创建Entity
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@PostMapping("/")
|
||||
public JsonResult createEntity(@ModelAttribute Message entity, BindingResult result, HttpServletRequest request)
|
||||
throws Exception{
|
||||
return super.createEntity(entity, result);
|
||||
}
|
||||
|
||||
/***
|
||||
* 更新Entity
|
||||
* @param id
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@PutMapping("/{id}")
|
||||
public JsonResult updateModel(@PathVariable("id")Long id, @ModelAttribute Message entity, BindingResult result,
|
||||
HttpServletRequest request) throws Exception{
|
||||
return super.updateEntity(entity, result);
|
||||
}
|
||||
|
||||
/***
|
||||
* 删除
|
||||
* @param id
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@DeleteMapping("/{id}")
|
||||
public JsonResult deleteModel(@PathVariable("id")Long id, HttpServletRequest request) throws Exception{
|
||||
return super.deleteEntity(id);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,124 +0,0 @@
|
|||
package com.diboot.component.msg.controller;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.diboot.component.msg.entity.MessageTemplate;
|
||||
import com.diboot.component.msg.service.MessageTemplateService;
|
||||
import com.diboot.core.controller.BaseCrudRestController;
|
||||
import com.diboot.core.service.BaseService;
|
||||
import com.diboot.core.service.DictionaryService;
|
||||
import com.diboot.core.util.V;
|
||||
import com.diboot.core.vo.JsonResult;
|
||||
import com.diboot.core.vo.KeyValue;
|
||||
import com.diboot.core.vo.Pagination;
|
||||
import com.diboot.core.vo.Status;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.ui.ModelMap;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.List;
|
||||
|
||||
/*
|
||||
* 消息模板相关service
|
||||
* @author:wangyl
|
||||
* */
|
||||
@RestController
|
||||
@RequestMapping("/messageTemplate")
|
||||
public class MessageTemplateController extends BaseCrudRestController {
|
||||
|
||||
@Autowired
|
||||
private MessageTemplateService messageTemplateService;
|
||||
|
||||
@Autowired
|
||||
private DictionaryService dictionaryService;
|
||||
|
||||
@Override
|
||||
protected BaseService getService() {
|
||||
return messageTemplateService;
|
||||
}
|
||||
|
||||
@GetMapping("/list")
|
||||
public JsonResult list(MessageTemplate messageTemplate, Pagination pagination, HttpServletRequest request) throws Exception {
|
||||
//构建查询条件
|
||||
QueryWrapper<MessageTemplate> queryWrapper = super.buildQueryWrapper(messageTemplate);
|
||||
// 查询当前页的Entity主表数据
|
||||
List<MessageTemplate> entityList = getService().getEntityList(queryWrapper, pagination);
|
||||
//返回结果
|
||||
return new JsonResult(Status.OK, entityList).bindPagination(pagination);
|
||||
}
|
||||
|
||||
/***
|
||||
* 查询Entity
|
||||
* @param id
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@GetMapping("/{id}")
|
||||
public JsonResult getModel(@PathVariable("id")Long id, HttpServletRequest request)
|
||||
throws Exception{
|
||||
MessageTemplate entity = messageTemplateService.getEntity(id);
|
||||
return new JsonResult(entity);
|
||||
}
|
||||
|
||||
/***
|
||||
* 创建Entity
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@PostMapping("/")
|
||||
public JsonResult createEntity(@ModelAttribute MessageTemplate entity, BindingResult result, HttpServletRequest request)
|
||||
throws Exception{
|
||||
return super.createEntity(entity, result);
|
||||
}
|
||||
|
||||
/***
|
||||
* 更新Entity
|
||||
* @param id
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@PutMapping("/{id}")
|
||||
public JsonResult updateModel(@PathVariable("id")Long id, @ModelAttribute MessageTemplate entity, BindingResult result,
|
||||
HttpServletRequest request) throws Exception{
|
||||
return super.updateEntity(entity, result);
|
||||
}
|
||||
|
||||
/***
|
||||
* 删除
|
||||
* @param id
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@DeleteMapping("/{id}")
|
||||
public JsonResult deleteModel(@PathVariable("id")Long id, HttpServletRequest request) throws Exception{
|
||||
return super.deleteEntity(id);
|
||||
}
|
||||
|
||||
/***
|
||||
* 加载更多数据
|
||||
* @param request
|
||||
* @param modelMap
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/attachMore")
|
||||
public JsonResult attachMore(HttpServletRequest request, ModelMap modelMap){
|
||||
Wrapper wrapper = null;
|
||||
//消息模板元数据
|
||||
List<KeyValue> msgTempCodeKvList = dictionaryService.getKeyValueList(MessageTemplate.METADATA_TYPE.MSG_TEMP_CODE.name());
|
||||
modelMap.put("msgTempCodeKvList", msgTempCodeKvList);
|
||||
|
||||
return new JsonResult(modelMap);
|
||||
}
|
||||
|
||||
@GetMapping("/getTemplateVaribles/{code}")
|
||||
public JsonResult getTemplateVaribles(@PathVariable("code")String code, HttpServletRequest request) throws Exception{
|
||||
String[] varibles = messageTemplateService.getTemplateVaribles(code);
|
||||
if(V.isEmpty(varibles)){
|
||||
return new JsonResult(Status.FAIL_OPERATION, "获取变量列表为空");
|
||||
}
|
||||
return new JsonResult(Status.OK, varibles,"获取变量列表成功");
|
||||
}
|
||||
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
package com.diboot.component.msg.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.diboot.core.entity.BaseExtEntity;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
public class Message extends BaseExtEntity {
|
||||
|
||||
@TableField
|
||||
private String type;
|
||||
|
||||
@TableField
|
||||
private Long templateId;
|
||||
|
||||
@TableField
|
||||
private String businessType;
|
||||
|
||||
@TableField
|
||||
private Long businessId;
|
||||
|
||||
@TableField
|
||||
private String sender;
|
||||
|
||||
@TableField
|
||||
private String receiver;
|
||||
|
||||
@TableField
|
||||
private String title;
|
||||
|
||||
@TableField
|
||||
private String content;
|
||||
|
||||
@TableField
|
||||
private String url;
|
||||
|
||||
@TableField
|
||||
private String status;
|
||||
|
||||
@TableField
|
||||
private Date scheduleTime;
|
||||
|
||||
@TableField
|
||||
private String response;
|
||||
|
||||
@TableField
|
||||
private Long createBy;
|
||||
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
package com.diboot.component.msg.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.diboot.core.entity.BaseExtEntity;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class MessageTemplate extends BaseExtEntity {
|
||||
|
||||
public static enum METADATA_TYPE{
|
||||
MSG_TEMP_CODE, // 消息模板
|
||||
MSG_TEMP_VARIBLES // 消息模板变量
|
||||
}
|
||||
|
||||
@TableField
|
||||
private String type;
|
||||
|
||||
@TableField
|
||||
private String code;
|
||||
|
||||
@TableField
|
||||
private String msgType;
|
||||
|
||||
@TableField
|
||||
private String businessType;
|
||||
|
||||
@TableField
|
||||
private Long businessId;
|
||||
|
||||
@TableField
|
||||
private String title;
|
||||
|
||||
@TableField
|
||||
private String msgTitle;
|
||||
|
||||
@TableField
|
||||
private String content;
|
||||
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
package com.diboot.component.msg.mapper;
|
||||
|
||||
import com.diboot.component.msg.entity.Message;
|
||||
import com.diboot.core.mapper.BaseCrudMapper;
|
||||
|
||||
public interface MessageMapper extends BaseCrudMapper<Message> {
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "./mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.diboot.component.msg.mapper.MessageMapper">
|
||||
|
||||
</mapper>
|
|
@ -1,7 +0,0 @@
|
|||
package com.diboot.component.msg.mapper;
|
||||
|
||||
import com.diboot.component.msg.entity.MessageTemplate;
|
||||
import com.diboot.core.mapper.BaseCrudMapper;
|
||||
|
||||
public interface MessageTemplateMapper extends BaseCrudMapper<MessageTemplate> {
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "./mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.diboot.component.msg.mapper.MessageTemplateMapper">
|
||||
|
||||
</mapper>
|
|
@ -1,25 +0,0 @@
|
|||
package com.diboot.component.msg.service;
|
||||
|
||||
import com.diboot.component.msg.entity.Message;
|
||||
|
||||
/*
|
||||
* 消息发送基础service
|
||||
* @author:wangyl
|
||||
* */
|
||||
public interface BaseSendService {
|
||||
|
||||
/***
|
||||
* 保存并发送消息
|
||||
* @param msg
|
||||
* @return
|
||||
*/
|
||||
boolean createAndSendMsg(Message msg) throws Exception;
|
||||
|
||||
/***
|
||||
* 发送消息
|
||||
* @param msg
|
||||
* @return
|
||||
*/
|
||||
boolean sendMsg(Message msg) throws Exception;
|
||||
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
package com.diboot.component.msg.service;
|
||||
|
||||
import com.diboot.component.msg.entity.Message;
|
||||
import com.diboot.core.service.BaseService;
|
||||
|
||||
/*
|
||||
* 消息相关service
|
||||
* @author:wangyl
|
||||
* */
|
||||
public interface MessageService extends BaseService<Message> {
|
||||
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
package com.diboot.component.msg.service;
|
||||
|
||||
import com.diboot.component.msg.entity.MessageTemplate;
|
||||
import com.diboot.core.service.BaseService;
|
||||
|
||||
/*
|
||||
* 消息模板相关service
|
||||
* @author:wangyl
|
||||
* */
|
||||
public interface MessageTemplateService extends BaseService<MessageTemplate> {
|
||||
|
||||
/**
|
||||
* 根据code获取唯一的消息模板
|
||||
* @param code
|
||||
* @return
|
||||
*/
|
||||
MessageTemplate getMessageTemplate(String code);
|
||||
|
||||
/**
|
||||
* 根据code获取消息模板变量
|
||||
* @param code
|
||||
* @return
|
||||
*/
|
||||
String[] getTemplateVaribles(String code);
|
||||
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
package com.diboot.component.msg.service.impl;
|
||||
|
||||
import com.diboot.component.msg.entity.Message;
|
||||
import com.diboot.component.msg.mapper.MessageMapper;
|
||||
import com.diboot.component.msg.service.BaseSendService;
|
||||
import com.diboot.core.service.impl.BaseServiceImpl;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/*
|
||||
* 消息发送基础service
|
||||
* @author:wangyl
|
||||
* */
|
||||
@Service
|
||||
@Slf4j
|
||||
public abstract class BaseSendServiceImpl extends BaseServiceImpl<MessageMapper, Message> implements BaseSendService {
|
||||
|
||||
@Override
|
||||
public boolean createAndSendMsg(Message msg) throws Exception {
|
||||
boolean success = super.createEntity(msg);
|
||||
if(success){
|
||||
success = sendMsg(msg);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
package com.diboot.component.msg.service.impl;
|
||||
|
||||
import com.diboot.component.msg.entity.Message;
|
||||
import com.diboot.component.msg.mapper.MessageMapper;
|
||||
import com.diboot.component.msg.service.MessageService;
|
||||
import com.diboot.core.service.impl.BaseServiceImpl;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/*
|
||||
* 消息相关service实现
|
||||
* @author:wangyl
|
||||
* */
|
||||
@Service
|
||||
@Slf4j
|
||||
public class MessageServiceImpl extends BaseServiceImpl<MessageMapper, Message> implements MessageService {
|
||||
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
package com.diboot.component.msg.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.diboot.component.msg.entity.MessageTemplate;
|
||||
import com.diboot.component.msg.mapper.MessageTemplateMapper;
|
||||
import com.diboot.component.msg.service.MessageTemplateService;
|
||||
import com.diboot.core.entity.Dictionary;
|
||||
import com.diboot.core.service.DictionaryService;
|
||||
import com.diboot.core.service.impl.BaseServiceImpl;
|
||||
import com.diboot.core.util.S;
|
||||
import com.diboot.core.util.V;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/*
|
||||
* 消息模板相关service
|
||||
* @author:wangyl
|
||||
* */
|
||||
@Service
|
||||
@Slf4j
|
||||
public class MessageTemplateServiceImpl extends BaseServiceImpl<MessageTemplateMapper, MessageTemplate> implements MessageTemplateService {
|
||||
private static final Logger logger = LoggerFactory.getLogger(MessageTemplateServiceImpl.class);
|
||||
|
||||
@Autowired
|
||||
private DictionaryService dictionaryService;
|
||||
|
||||
@Override
|
||||
public MessageTemplate getMessageTemplate(String code) {
|
||||
LambdaQueryWrapper<MessageTemplate> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(MessageTemplate::getCode, code);
|
||||
List<MessageTemplate> list = this.getEntityList(wrapper);
|
||||
return V.notEmpty(list)? list.get(0) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getTemplateVaribles(String code) {
|
||||
LambdaQueryWrapper<Dictionary> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.ne(Dictionary::getParentId, 0)
|
||||
.eq(Dictionary::getItemName, code)
|
||||
.eq(Dictionary::getType, MessageTemplate.METADATA_TYPE.MSG_TEMP_VARIBLES.name());
|
||||
List<Dictionary> list = dictionaryService.getEntityList(wrapper);
|
||||
if (V.isEmpty(list)){
|
||||
return null;
|
||||
}
|
||||
return S.split(list.get(0).getItemValue());
|
||||
}
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
package com.diboot.component.msg.vo;
|
||||
|
||||
import com.diboot.component.msg.entity.Message;
|
||||
import com.diboot.component.msg.entity.MessageTemplate;
|
||||
import com.diboot.core.binding.annotation.BindDict;
|
||||
import com.diboot.core.binding.annotation.BindEntity;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class MessageVO extends Message {
|
||||
private static final long serialVersionUID = 141470955506938430L;
|
||||
|
||||
@BindDict(type="MSG_TYPE", field="type")
|
||||
private String typeLabel;
|
||||
|
||||
@BindDict(type="MSG_STATUS", field="status")
|
||||
private String statusLabel;
|
||||
|
||||
@BindEntity(entity=MessageTemplate.class, condition="this.template_id=id")
|
||||
private MessageTemplate messageTemplate;
|
||||
}
|
|
@ -48,14 +48,14 @@ private List<Role> roleList;
|
|||
### 1. 引入依赖
|
||||
Gradle:
|
||||
~~~gradle
|
||||
compile("com.diboot:diboot-core-spring-boot-starter:2.0.3-RC2")
|
||||
compile("com.diboot:diboot-core-spring-boot-starter:2.0.3")
|
||||
~~~
|
||||
或Maven
|
||||
~~~xml
|
||||
<dependency>
|
||||
<groupId>com.diboot</groupId>
|
||||
<artifactId>diboot-core-spring-boot-starter</artifactId>
|
||||
<version>2.0.3-RC2</version>
|
||||
<version>2.0.3</version>
|
||||
</dependency>
|
||||
~~~
|
||||
> * 使用diboot-devtools,会自动引入diboot-core,无需配置此依赖。
|
||||
|
@ -99,9 +99,9 @@ public class UserDTO{
|
|||
* 将映射为 queryWrapper.eq("gender", "M").like("realname", "张")
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
public JsonResult getVOList(UserDto userDto) throws Exception{
|
||||
//调用super.buildQueryWrapper(entityOrDto) 或者直接调用 QueryBuilder.toQueryWrapper(entityOrDto) 进行转换
|
||||
QueryWrapper<User> queryWrapper = super.buildQueryWrapper(userDto);
|
||||
public JsonResult getVOList(UserDto userDto, HttpServletRequest request) throws Exception{
|
||||
//调用super.buildQueryWrapper(entityOrDto, request) 或者直接调用 QueryBuilder.toQueryWrapper(entityOrDto) 进行转换
|
||||
QueryWrapper<User> queryWrapper = super.buildQueryWrapper(userDto, request);
|
||||
//... 查询list
|
||||
return new JsonResult(Status.OK, list);
|
||||
}
|
||||
|
|
|
@ -148,7 +148,7 @@ public class RelationsBinder {
|
|||
EntityBinder binder = buildEntityBinder(annotation, voList);
|
||||
if(binder != null){
|
||||
// 构建binder
|
||||
binder.set(fieldAnnotation.getFieldName());
|
||||
binder.set(fieldAnnotation.getFieldName(), fieldAnnotation.getFieldClass());
|
||||
// 解析条件并且执行绑定
|
||||
parseConditionsAndBinding(binder, annotation.condition());
|
||||
}
|
||||
|
@ -165,7 +165,7 @@ public class RelationsBinder {
|
|||
// 构建binder
|
||||
EntityListBinder binder = buildEntityListBinder(bindAnnotation, voList);
|
||||
if(binder != null){
|
||||
binder.set(fieldAnnotation.getFieldName());
|
||||
binder.set(fieldAnnotation.getFieldName(), fieldAnnotation.getFieldClass());
|
||||
// 解析条件并且执行绑定
|
||||
parseConditionsAndBinding(binder, bindAnnotation.condition());
|
||||
}
|
||||
|
|
|
@ -27,6 +27,10 @@ public class EntityBinder<T> extends BaseBinder<T> {
|
|||
* 给待绑定list中VO对象赋值的setter属性名
|
||||
*/
|
||||
protected String annoObjectField;
|
||||
/***
|
||||
* 给待绑定list中VO对象赋值的setter属性class类型
|
||||
*/
|
||||
protected Class<?> annoObjectFieldClass;
|
||||
|
||||
public EntityBinder(){}
|
||||
/***
|
||||
|
@ -47,8 +51,8 @@ public class EntityBinder<T> extends BaseBinder<T> {
|
|||
* @param <R> set方法参数类型
|
||||
* @return
|
||||
*/
|
||||
public <T1,R> BaseBinder<T> set(ISetter<T1, R> voSetter){
|
||||
return set(BeanUtils.convertToFieldName(voSetter));
|
||||
public <T1,R> BaseBinder<T> set(ISetter<T1, R> voSetter, Class annoObjectFieldClass){
|
||||
return set(BeanUtils.convertToFieldName(voSetter), annoObjectFieldClass);
|
||||
}
|
||||
|
||||
/***
|
||||
|
@ -56,8 +60,9 @@ public class EntityBinder<T> extends BaseBinder<T> {
|
|||
* @param annoObjectField VO中调用赋值的setter属性
|
||||
* @return
|
||||
*/
|
||||
public BaseBinder<T> set(String annoObjectField){
|
||||
public BaseBinder<T> set(String annoObjectField, Class annoObjectFieldClass){
|
||||
this.annoObjectField = annoObjectField;
|
||||
this.annoObjectFieldClass = annoObjectFieldClass;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -76,7 +81,7 @@ public class EntityBinder<T> extends BaseBinder<T> {
|
|||
return;
|
||||
}
|
||||
// 结果转换Map
|
||||
Map<String, T> valueEntityMap = new HashMap<>();
|
||||
Map<String, Object> valueEntityMap = new HashMap<>();
|
||||
// 通过中间表关联Entity
|
||||
// @BindEntity(entity = Organization.class, condition = "this.department_id=department.id AND department.org_id=id AND department.is_deleted=0")
|
||||
// Organization organization;
|
||||
|
@ -98,8 +103,8 @@ public class EntityBinder<T> extends BaseBinder<T> {
|
|||
continue;
|
||||
}
|
||||
String key = entry.getKey();
|
||||
T value = listMap.get(String.valueOf(fetchValueId));
|
||||
valueEntityMap.put(key, BeanUtils.cloneBean(value));
|
||||
T entity = listMap.get(String.valueOf(fetchValueId));
|
||||
valueEntityMap.put(key, cloneOrConvertBean(entity));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -116,11 +121,24 @@ public class EntityBinder<T> extends BaseBinder<T> {
|
|||
String refEntityPKFieldName = S.toLowerCaseCamel(referencedEntityPrimaryKey);
|
||||
for(T entity : list){
|
||||
String pkValue = BeanUtils.getStringProperty(entity, refEntityPKFieldName);
|
||||
valueEntityMap.put(pkValue, BeanUtils.cloneBean(entity));
|
||||
valueEntityMap.put(pkValue, cloneOrConvertBean(entity));
|
||||
}
|
||||
}
|
||||
}
|
||||
// 绑定结果
|
||||
BeanUtils.bindPropValueOfList(annoObjectField, annoObjectList, annoObjectForeignKey, valueEntityMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* 克隆Entity/VO对象(如果与Entity类型不一致,如VO则先转型)
|
||||
* @param value
|
||||
*/
|
||||
protected Object cloneOrConvertBean(T value){
|
||||
if(value.getClass().getName().equals(annoObjectFieldClass.getName())){
|
||||
return BeanUtils.cloneBean(value);
|
||||
}
|
||||
else{
|
||||
return BeanUtils.convert(value, annoObjectFieldClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ public class EntityListBinder<T> extends EntityBinder<T> {
|
|||
if(V.isEmpty(annoObjectForeignKeyList)){
|
||||
return;
|
||||
}
|
||||
Map<String, List<T>> valueEntityListMap = new HashMap<>();
|
||||
Map<String, List> valueEntityListMap = new HashMap<>();
|
||||
// 解析中间表查询 1-N关联,如:
|
||||
//User.class @BindEntityList(entity = Role.class, condition="this.id=user_role.user_id AND user_role.role_id=id")
|
||||
if(middleTable != null){
|
||||
|
@ -67,11 +67,11 @@ public class EntityListBinder<T> extends EntityBinder<T> {
|
|||
if(V.isEmpty(annoObjFKList)){
|
||||
continue;
|
||||
}
|
||||
List<T> valueList = new ArrayList();
|
||||
List valueList = new ArrayList();
|
||||
for(Object obj : annoObjFKList){
|
||||
T ent = entityMap.get(String.valueOf(obj));
|
||||
if(ent != null){
|
||||
valueList.add(BeanUtils.cloneBean(ent));
|
||||
valueList.add(cloneOrConvertBean(ent));
|
||||
}
|
||||
}
|
||||
valueEntityListMap.put(entry.getKey(), valueList);
|
||||
|
@ -86,12 +86,12 @@ public class EntityListBinder<T> extends EntityBinder<T> {
|
|||
if(V.notEmpty(list)){
|
||||
for(T entity : list){
|
||||
String keyValue = BeanUtils.getStringProperty(entity, S.toLowerCaseCamel(referencedEntityPrimaryKey));
|
||||
List<T> entityList = valueEntityListMap.get(keyValue);
|
||||
List entityList = valueEntityListMap.get(keyValue);
|
||||
if(entityList == null){
|
||||
entityList = new ArrayList<>();
|
||||
valueEntityListMap.put(keyValue, entityList);
|
||||
}
|
||||
entityList.add(BeanUtils.cloneBean(entity));
|
||||
entityList.add(cloneOrConvertBean(entity));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,30 +38,30 @@ public class BindAnnotationGroup {
|
|||
* @param fieldName
|
||||
* @param annotation
|
||||
*/
|
||||
public void addBindAnnotation(String fieldName, Annotation annotation){
|
||||
public void addBindAnnotation(String fieldName, Class<?> fieldClass, Annotation annotation){
|
||||
if(annotation instanceof BindDict){
|
||||
if(bindDictAnnotations == null){
|
||||
bindDictAnnotations = new ArrayList<>();
|
||||
}
|
||||
bindDictAnnotations.add(new FieldAnnotation(fieldName, annotation));
|
||||
bindDictAnnotations.add(new FieldAnnotation(fieldName, fieldClass, annotation));
|
||||
}
|
||||
else if(annotation instanceof BindField){
|
||||
if(bindFieldAnnotations == null){
|
||||
bindFieldAnnotations = new ArrayList<>();
|
||||
}
|
||||
bindFieldAnnotations.add(new FieldAnnotation(fieldName, annotation));
|
||||
bindFieldAnnotations.add(new FieldAnnotation(fieldName, fieldClass, annotation));
|
||||
}
|
||||
else if(annotation instanceof BindEntity){
|
||||
if(bindEntityAnnotations == null){
|
||||
bindEntityAnnotations = new ArrayList<>();
|
||||
}
|
||||
bindEntityAnnotations.add(new FieldAnnotation(fieldName, annotation));
|
||||
bindEntityAnnotations.add(new FieldAnnotation(fieldName, fieldClass, annotation));
|
||||
}
|
||||
else if(annotation instanceof BindEntityList){
|
||||
if(bindEntityListAnnotations == null){
|
||||
bindEntityListAnnotations = new ArrayList<>();
|
||||
}
|
||||
bindEntityListAnnotations.add(new FieldAnnotation(fieldName, annotation));
|
||||
bindEntityListAnnotations.add(new FieldAnnotation(fieldName, fieldClass, annotation));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
package com.diboot.core.binding.parser;
|
||||
|
||||
import com.diboot.core.util.BeanUtils;
|
||||
import com.diboot.core.util.V;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
|
@ -30,7 +34,7 @@ public class BindAnnotationGroupCache {
|
|||
// 获取注解并缓存
|
||||
group = new BindAnnotationGroup();
|
||||
// 获取当前VO的注解
|
||||
Field[] fields = voClass.getDeclaredFields();
|
||||
List<Field> fields = BeanUtils.extractAllFields(voClass);
|
||||
if(fields != null){
|
||||
for (Field field : fields) {
|
||||
//遍历属性
|
||||
|
@ -39,7 +43,16 @@ public class BindAnnotationGroupCache {
|
|||
continue;
|
||||
}
|
||||
for (Annotation annotation : annotations) {
|
||||
group.addBindAnnotation(field.getName(), annotation);
|
||||
Class<?> setterObjClazz = field.getType();
|
||||
if(setterObjClazz.equals(java.util.List.class) || setterObjClazz.equals(java.util.Collections.class)){
|
||||
// 如果是集合,获取其泛型参数class
|
||||
Type genericType = field.getGenericType();
|
||||
if(genericType instanceof ParameterizedType){
|
||||
ParameterizedType pt = (ParameterizedType) genericType;
|
||||
setterObjClazz = (Class<?>)pt.getActualTypeArguments()[0];
|
||||
}
|
||||
}
|
||||
group.addBindAnnotation(field.getName(), setterObjClazz, annotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,13 +14,18 @@ public class FieldAnnotation{
|
|||
* 字段名
|
||||
*/
|
||||
private String fieldName;
|
||||
/**
|
||||
* 字段类型
|
||||
*/
|
||||
private Class<?> fieldClass;
|
||||
/**
|
||||
* 注解
|
||||
*/
|
||||
private Annotation annotation;
|
||||
|
||||
public FieldAnnotation(String fieldName, Annotation annotation){
|
||||
public FieldAnnotation(String fieldName, Class fieldClass, Annotation annotation){
|
||||
this.fieldName = fieldName;
|
||||
this.fieldClass = fieldClass;
|
||||
this.annotation = annotation;
|
||||
}
|
||||
|
||||
|
@ -31,4 +36,8 @@ public class FieldAnnotation{
|
|||
public Annotation getAnnotation() {
|
||||
return annotation;
|
||||
}
|
||||
|
||||
public Class getFieldClass(){
|
||||
return fieldClass;
|
||||
}
|
||||
}
|
|
@ -12,11 +12,17 @@ public class Cons {
|
|||
*/
|
||||
public static final String CHARSET_UTF8 = "UTF-8";
|
||||
/**
|
||||
* 分隔符 ,
|
||||
* 逗号分隔符 ,
|
||||
*/
|
||||
public static final String SEPARATOR_COMMA = ",";
|
||||
|
||||
/**
|
||||
* 下划线分隔符_
|
||||
*/
|
||||
public static final String SEPARATOR_UNDERSCORE = "_";
|
||||
/**
|
||||
* 排序 - 降序标记
|
||||
*/
|
||||
public static final String ORDER_DESC = "DESC";
|
||||
/***
|
||||
* 默认字段名定义
|
||||
*/
|
||||
|
@ -36,7 +42,11 @@ public class Cons {
|
|||
/**
|
||||
* 逻辑删除标记字段
|
||||
*/
|
||||
deleted
|
||||
deleted,
|
||||
/**
|
||||
* 创建时间字段
|
||||
*/
|
||||
createTime
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -9,8 +9,6 @@ import com.diboot.core.util.S;
|
|||
import com.diboot.core.util.V;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.validation.ObjectError;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.*;
|
||||
|
@ -24,33 +22,11 @@ import java.util.*;
|
|||
public class BaseController {
|
||||
private static final Logger log = LoggerFactory.getLogger(BaseController.class);
|
||||
|
||||
/***
|
||||
* 字段
|
||||
*/
|
||||
protected static final String PARAM_FIELDS = "_fields";
|
||||
|
||||
/**
|
||||
* ID参数名
|
||||
*/
|
||||
protected static final String PARAM_ID = Cons.FieldName.id.name();
|
||||
|
||||
/**
|
||||
* 解析所有的验证错误信息,转换为JSON
|
||||
* @param result
|
||||
* @return
|
||||
*/
|
||||
protected String getBindingError(BindingResult result){
|
||||
if(result == null || !result.hasErrors()){
|
||||
return null;
|
||||
}
|
||||
List<ObjectError> errors = result.getAllErrors();
|
||||
List<String> allErrors = new ArrayList<>(errors.size());
|
||||
for(ObjectError error : errors){
|
||||
allErrors.add(error.getDefaultMessage().replaceAll("\"", "'"));
|
||||
}
|
||||
return S.join(allErrors);
|
||||
}
|
||||
|
||||
/***
|
||||
* 构建查询QueryWrapper (根据BindQuery注解构建相应的查询条件)
|
||||
* @param entityOrDto Entity对象或者DTO对象 (属性若无BindQuery注解,默认构建为为EQ相等条件)
|
||||
|
|
|
@ -4,15 +4,13 @@ import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
|||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.diboot.core.entity.BaseEntity;
|
||||
import com.diboot.core.service.BaseService;
|
||||
import com.diboot.core.util.BeanUtils;
|
||||
import com.diboot.core.util.ContextHelper;
|
||||
import com.diboot.core.util.V;
|
||||
import com.diboot.core.vo.JsonResult;
|
||||
import com.diboot.core.vo.Pagination;
|
||||
import com.diboot.core.vo.Status;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.validation.BindingResult;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.Serializable;
|
||||
|
@ -97,15 +95,10 @@ public class BaseCrudRestController<E extends BaseEntity, VO extends Serializabl
|
|||
/***
|
||||
* 创建资源对象,用于字类重写的方法
|
||||
* @param entity
|
||||
* @param result
|
||||
* @return JsonResult
|
||||
* @throws Exception
|
||||
*/
|
||||
protected JsonResult createEntity(E entity, BindingResult result, HttpServletRequest request) throws Exception {
|
||||
// Model属性值验证结果
|
||||
if (result != null && result.hasErrors()) {
|
||||
return new JsonResult(Status.FAIL_VALIDATION, super.getBindingError(result));
|
||||
}
|
||||
protected JsonResult createEntity(E entity, HttpServletRequest request) throws Exception {
|
||||
// 执行创建资源前的操作
|
||||
String validateResult = this.beforeCreate(entity);
|
||||
if (validateResult != null) {
|
||||
|
@ -130,16 +123,10 @@ public class BaseCrudRestController<E extends BaseEntity, VO extends Serializabl
|
|||
/***
|
||||
* 根据ID更新资源对象,用于字类重写的方法
|
||||
* @param entity
|
||||
* @param result
|
||||
* @return JsonResult
|
||||
* @throws Exception
|
||||
*/
|
||||
protected JsonResult updateEntity(Serializable id, E entity, BindingResult result,
|
||||
HttpServletRequest request) throws Exception {
|
||||
// Entity属性值验证结果
|
||||
if (result.hasErrors()) {
|
||||
return new JsonResult(Status.FAIL_VALIDATION, super.getBindingError(result));
|
||||
}
|
||||
protected JsonResult updateEntity(Serializable id, E entity, HttpServletRequest request) throws Exception {
|
||||
// 执行更新资源前的操作
|
||||
String validateResult = this.beforeUpdate(entity);
|
||||
if (validateResult != null) {
|
||||
|
@ -262,7 +249,7 @@ public class BaseCrudRestController<E extends BaseEntity, VO extends Serializabl
|
|||
*/
|
||||
protected Class<E> getEntityClass(){
|
||||
if(this.entityClass == null){
|
||||
initEntityVOClass();
|
||||
this.entityClass = BeanUtils.getGenericityClass(this.getClass(), 0);
|
||||
}
|
||||
return this.entityClass;
|
||||
}
|
||||
|
@ -273,25 +260,8 @@ public class BaseCrudRestController<E extends BaseEntity, VO extends Serializabl
|
|||
*/
|
||||
protected Class<VO> getVOClass(){
|
||||
if(this.voClasss == null){
|
||||
initEntityVOClass();
|
||||
this.voClasss = BeanUtils.getGenericityClass(this.getClass(), 1);
|
||||
}
|
||||
return this.voClasss;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化Entity和VO的class
|
||||
*/
|
||||
private void initEntityVOClass(){
|
||||
try{
|
||||
ResolvableType resolvableType = ResolvableType.forClass(this.getClass()).getSuperType();
|
||||
ResolvableType[] types = resolvableType.getSuperType().getGenerics();
|
||||
if(V.notEmpty(types)){
|
||||
this.entityClass = (Class<E>) types[0].resolve();
|
||||
this.voClasss = (Class<VO>) types[1].resolve();
|
||||
}
|
||||
}
|
||||
catch (Exception e){
|
||||
log.warn("初始化Entity,VO class异常: "+ e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -62,7 +62,7 @@ public abstract class BaseEntity implements Serializable {
|
|||
}
|
||||
|
||||
/***
|
||||
* model对象转为map
|
||||
* Entity对象转为map
|
||||
* @return
|
||||
*/
|
||||
public Map<String, Object> toMap(){
|
||||
|
@ -71,7 +71,7 @@ public abstract class BaseEntity implements Serializable {
|
|||
}
|
||||
|
||||
/**
|
||||
* model对象转为String
|
||||
* Entity对象转为String
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
|
|
|
@ -5,7 +5,7 @@ import java.util.Arrays;
|
|||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Model的List包装类,用于接收List并绑定校验的情况
|
||||
* Entity的List包装类,用于接收List并绑定校验的情况
|
||||
* @author Mazhicheng
|
||||
* @version 2.0
|
||||
* @date 2018/11/8
|
||||
|
@ -23,7 +23,7 @@ public class EntityList<T extends BaseEntity> {
|
|||
this.entityList = entityList;
|
||||
}
|
||||
|
||||
public List<T> getModelList(){
|
||||
public List<T> getEntityList(){
|
||||
return entityList;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,18 +1,22 @@
|
|||
package com.diboot.core.handle;
|
||||
package com.diboot.core.handler;
|
||||
|
||||
import com.diboot.core.exception.BusinessException;
|
||||
import com.diboot.core.util.S;
|
||||
import com.diboot.core.util.V;
|
||||
import com.diboot.core.vo.Status;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.validation.BindException;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.validation.ObjectError;
|
||||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 全局异常统一处理的默认实现
|
||||
|
@ -24,6 +28,30 @@ import java.util.Map;
|
|||
public class DefaultExceptionHandler {
|
||||
private final static Logger log = LoggerFactory.getLogger(DefaultExceptionHandler.class);
|
||||
|
||||
/**
|
||||
* 统一处理校验错误 BindResult
|
||||
* @param ex
|
||||
* @return
|
||||
*/
|
||||
@ExceptionHandler({BindException.class, MethodArgumentNotValidException.class})
|
||||
public Object validExceptionHandler(Exception ex){
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
BindingResult br = null;
|
||||
if(ex instanceof BindException){
|
||||
br = ((BindException)ex).getBindingResult();
|
||||
}
|
||||
else if(ex instanceof MethodArgumentNotValidException){
|
||||
br = ((MethodArgumentNotValidException)ex).getBindingResult();
|
||||
}
|
||||
if (br != null && br.hasErrors()) {
|
||||
map.put("code", Status.FAIL_VALIDATION.code());
|
||||
String validateErrorMsg = V.getBindingError(br);
|
||||
map.put("msg", validateErrorMsg);
|
||||
log.warn("数据校验失败, {}: {}", br.getObjectName(), validateErrorMsg);
|
||||
}
|
||||
return new ResponseEntity<>(map, HttpStatus.OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一异常处理类
|
||||
* @param request
|
||||
|
@ -43,8 +71,8 @@ public class DefaultExceptionHandler {
|
|||
map.put("code", status.value());
|
||||
map.put("msg", e.getMessage());
|
||||
}
|
||||
log.warn("请求处理异常", e);
|
||||
if(isJsonRequest(request)) {
|
||||
log.warn("JSON请求异常", e);
|
||||
return new ResponseEntity<>(map, HttpStatus.OK);
|
||||
}
|
||||
else {
|
||||
|
@ -96,4 +124,5 @@ public class DefaultExceptionHandler {
|
|||
return HttpStatus.INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,9 +1,9 @@
|
|||
package com.diboot.core.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.core.metadata.OrderItem;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.diboot.core.binding.RelationsBinder;
|
||||
|
@ -14,6 +14,7 @@ import com.diboot.core.config.BaseConfig;
|
|||
import com.diboot.core.config.Cons;
|
||||
import com.diboot.core.mapper.BaseCrudMapper;
|
||||
import com.diboot.core.service.BaseService;
|
||||
import com.diboot.core.util.BeanUtils;
|
||||
import com.diboot.core.util.S;
|
||||
import com.diboot.core.util.V;
|
||||
import com.diboot.core.vo.KeyValue;
|
||||
|
@ -23,7 +24,9 @@ import org.slf4j.LoggerFactory;
|
|||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/***
|
||||
* CRUD通用接口实现类
|
||||
|
@ -35,6 +38,10 @@ import java.util.*;
|
|||
*/
|
||||
public class BaseServiceImpl<M extends BaseCrudMapper<T>, T> extends ServiceImpl<M, T> implements BaseService<T> {
|
||||
private static final Logger log = LoggerFactory.getLogger(BaseServiceImpl.class);
|
||||
/**
|
||||
* Entity类与最佳排序字段间的映射缓存
|
||||
*/
|
||||
private static Map<String, String> ENTITY_ORDER_FIELD_CACHE_MAP = new ConcurrentHashMap<>();
|
||||
|
||||
/***
|
||||
* 获取当前的Mapper对象
|
||||
|
@ -52,7 +59,7 @@ public class BaseServiceImpl<M extends BaseCrudMapper<T>, T> extends ServiceImpl
|
|||
@Override
|
||||
public boolean createEntity(T entity) {
|
||||
if(entity == null){
|
||||
warning("createModel", "参数entity为null");
|
||||
warning("createEntity", "参数entity为null");
|
||||
return false;
|
||||
}
|
||||
return super.save(entity);
|
||||
|
@ -94,6 +101,7 @@ public class BaseServiceImpl<M extends BaseCrudMapper<T>, T> extends ServiceImpl
|
|||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean createOrUpdateEntities(Collection entityList) {
|
||||
if(V.isEmpty(entityList)){
|
||||
warning("createOrUpdateEntities", "参数entityList为空!");
|
||||
|
@ -128,7 +136,7 @@ public class BaseServiceImpl<M extends BaseCrudMapper<T>, T> extends ServiceImpl
|
|||
@Override
|
||||
public List<T> getEntityList(Wrapper queryWrapper, Pagination pagination) {
|
||||
if(pagination != null){
|
||||
IPage<T> page = convertToIPage(pagination);
|
||||
IPage<T> page = convertToIPage(queryWrapper, pagination);
|
||||
page = super.page(page, queryWrapper);
|
||||
// 如果重新执行了count进行查询,则更新pagination中的总数
|
||||
if(page.isSearchCount()){
|
||||
|
@ -170,7 +178,7 @@ public class BaseServiceImpl<M extends BaseCrudMapper<T>, T> extends ServiceImpl
|
|||
@Override
|
||||
public List<Map<String, Object>> getMapList(Wrapper queryWrapper, Pagination pagination) {
|
||||
if(pagination != null){
|
||||
IPage<T> page = convertToIPage(pagination);
|
||||
IPage<T> page = convertToIPage(queryWrapper, pagination);
|
||||
IPage<Map<String, Object>> resultPage = super.pageMaps(page, queryWrapper);
|
||||
// 如果重新执行了count进行查询,则更新pagination中的总数
|
||||
if(page.isSearchCount()){
|
||||
|
@ -261,30 +269,22 @@ public class BaseServiceImpl<M extends BaseCrudMapper<T>, T> extends ServiceImpl
|
|||
|
||||
/***
|
||||
* 转换为IPage
|
||||
* @param pagination
|
||||
* @param queryWrapper 查询条件
|
||||
* @param pagination 分页
|
||||
* @return
|
||||
*/
|
||||
protected Page<T> convertToIPage(Pagination pagination){
|
||||
protected Page<T> convertToIPage(Wrapper queryWrapper, Pagination pagination){
|
||||
if(pagination == null){
|
||||
return null;
|
||||
}
|
||||
Page<T> page = new Page<T>()
|
||||
.setCurrent(pagination.getPageIndex())
|
||||
.setSize(pagination.getPageSize())
|
||||
// 如果前端传递过来了缓存的总数,则本次不再count统计
|
||||
.setTotal(pagination.getTotalCount() > 0? -1 : pagination.getTotalCount());
|
||||
// 排序
|
||||
if(V.notEmpty(pagination.getAscList())){
|
||||
pagination.getAscList().forEach(s -> {
|
||||
page.addOrder(OrderItem.asc(s));
|
||||
});
|
||||
}
|
||||
if(V.notEmpty(pagination.getDescList())){
|
||||
pagination.getDescList().forEach(s -> {
|
||||
page.addOrder(OrderItem.desc(s));
|
||||
});
|
||||
}
|
||||
return page;
|
||||
// 优化排序
|
||||
String defaultOrderBy = getDefaultOrderField(queryWrapper);
|
||||
//默认id属性存在
|
||||
if(!Cons.FieldName.id.name().equals(defaultOrderBy)){
|
||||
// 最佳字段不是id(如create_time),但默认查询字段为id,需要清空默认值以免报错
|
||||
pagination.clearDefaultOrder();
|
||||
}
|
||||
return (Page<T>)pagination.toIPage();
|
||||
}
|
||||
|
||||
/***
|
||||
|
@ -295,4 +295,30 @@ public class BaseServiceImpl<M extends BaseCrudMapper<T>, T> extends ServiceImpl
|
|||
private void warning(String method, String message){
|
||||
log.warn(this.getClass().getName() + "."+ method +" 调用错误: "+message+", 请检查!");
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化Entity和VO的class
|
||||
*/
|
||||
private String getDefaultOrderField(Wrapper queryWrapper){
|
||||
Class entityClass = BeanUtils.getGenericityClass(this.getClass(), 1);
|
||||
if(entityClass == null){
|
||||
return null;
|
||||
}
|
||||
if(!ENTITY_ORDER_FIELD_CACHE_MAP.containsKey(entityClass.getName())){
|
||||
// 提取字段,如果有升序id首选id
|
||||
Field field = BeanUtils.extractField(entityClass, Cons.FieldName.id.name());
|
||||
if(field != null){
|
||||
TableField tableFieldAnno = field.getAnnotation(TableField.class);
|
||||
if(tableFieldAnno == null || tableFieldAnno.exist() == true){
|
||||
ENTITY_ORDER_FIELD_CACHE_MAP.put(entityClass.getName(), Cons.FieldName.id.name());
|
||||
}
|
||||
}
|
||||
if(!ENTITY_ORDER_FIELD_CACHE_MAP.containsKey(entityClass.getName())){
|
||||
ENTITY_ORDER_FIELD_CACHE_MAP.put(entityClass.getName(), "");
|
||||
log.warn("{} 的默认排序字段id不存在,请自行指定!", entityClass.getName());
|
||||
}
|
||||
}
|
||||
return ENTITY_ORDER_FIELD_CACHE_MAP.get(entityClass.getName());
|
||||
}
|
||||
|
||||
}
|
|
@ -3,6 +3,7 @@ package com.diboot.core.service.impl;
|
|||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.diboot.core.entity.Dictionary;
|
||||
import com.diboot.core.exception.BusinessException;
|
||||
import com.diboot.core.mapper.DictionaryMapper;
|
||||
import com.diboot.core.service.DictionaryService;
|
||||
import com.diboot.core.util.BeanUtils;
|
||||
|
@ -11,6 +12,7 @@ import com.diboot.core.util.ISetter;
|
|||
import com.diboot.core.util.V;
|
||||
import com.diboot.core.vo.DictionaryVO;
|
||||
import com.diboot.core.vo.KeyValue;
|
||||
import com.diboot.core.vo.Status;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
|
@ -74,32 +76,33 @@ public class DictionaryServiceImpl extends BaseServiceImpl<DictionaryMapper, Dic
|
|||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean addDictTree(DictionaryVO dictVO) {
|
||||
//将DictionaryVO转化为Dictionary
|
||||
Dictionary dictionary = new Dictionary();
|
||||
dictionary = (Dictionary) BeanUtils.copyProperties(dictVO, dictionary);
|
||||
if(!super.createEntity(dictionary)){
|
||||
log.warn("新建父数据字典失败,type="+dictVO.getType());
|
||||
log.warn("新建数据字典定义失败,type="+dictVO.getType());
|
||||
return false;
|
||||
}
|
||||
List<Dictionary> children = dictVO.getChildren();
|
||||
if(V.notEmpty(children)){
|
||||
try {
|
||||
for(Dictionary dict : children){
|
||||
dict.setParentId(dictionary.getId());
|
||||
dict.setType(dictionary.getType());
|
||||
boolean success = true;
|
||||
for(Dictionary dict : children){
|
||||
dict.setParentId(dictionary.getId());
|
||||
dict.setType(dictionary.getType());
|
||||
boolean insertOK = super.createEntity(dict);
|
||||
if (!insertOK){
|
||||
log.warn("dictionary插入数据字典失败,请检查!");
|
||||
success = false;
|
||||
}
|
||||
if(!super.createEntities(children)){
|
||||
log.warn("新建子数据字典失败,type="+dictVO.getType());
|
||||
throw new RuntimeException();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("新建子数据字典失败,type="+dictVO.getType());
|
||||
throw new RuntimeException();
|
||||
}
|
||||
if(!success){
|
||||
String errorMsg = "新建数据字典子项失败,type="+dictVO.getType();
|
||||
log.warn(errorMsg);
|
||||
throw new BusinessException(Status.FAIL_OPERATION, errorMsg);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -8,6 +8,7 @@ import org.slf4j.LoggerFactory;
|
|||
import org.springframework.beans.BeanWrapper;
|
||||
import org.springframework.beans.PropertyAccessorFactory;
|
||||
import org.springframework.cglib.beans.BeanCopier;
|
||||
import org.springframework.core.ResolvableType;
|
||||
|
||||
import java.beans.BeanInfo;
|
||||
import java.beans.Introspector;
|
||||
|
@ -37,7 +38,7 @@ public class BeanUtils {
|
|||
* 忽略对比的字段
|
||||
*/
|
||||
private static final Set<String> IGNORE_FIELDS = new HashSet<String>(){{
|
||||
add("createTime");
|
||||
add(Cons.FieldName.createTime.name());
|
||||
}};
|
||||
|
||||
/***
|
||||
|
@ -145,26 +146,26 @@ public class BeanUtils {
|
|||
Object[] args = new Object[1];
|
||||
String fieldType = type.getName();
|
||||
// 类型不一致,需转型
|
||||
if(!value.getClass().getTypeName().equals(fieldType)){
|
||||
if(value != null && !value.getClass().getTypeName().equals(fieldType)){
|
||||
if(value instanceof String){
|
||||
// String to Date
|
||||
if(fieldType.equalsIgnoreCase(Date.class.getName())){
|
||||
if(fieldType.equals(Date.class.getName())){
|
||||
args[0] = D.fuzzyConvert((String)value);
|
||||
}
|
||||
// Map中的String型转换为其他型
|
||||
else if(fieldType.equalsIgnoreCase(Boolean.class.getName())){
|
||||
else if(fieldType.equals(Boolean.class.getName())){
|
||||
args[0] = V.isTrue((String)value);
|
||||
}
|
||||
else if (fieldType.equalsIgnoreCase(Integer.class.getName()) || "int".equals(fieldType)) {
|
||||
else if (fieldType.equals(Integer.class.getName()) || "int".equals(fieldType)) {
|
||||
args[0] = Integer.parseInt((String)value);
|
||||
}
|
||||
else if (fieldType.equalsIgnoreCase(Long.class.getName())) {
|
||||
else if (fieldType.equals(Long.class.getName())) {
|
||||
args[0] = Long.parseLong((String)value);
|
||||
}
|
||||
else if (fieldType.equalsIgnoreCase(Double.class.getName())) {
|
||||
else if (fieldType.equals(Double.class.getName())) {
|
||||
args[0] = Double.parseDouble((String)value);
|
||||
}
|
||||
else if (fieldType.equalsIgnoreCase(Float.class.getName())) {
|
||||
else if (fieldType.equals(Float.class.getName())) {
|
||||
args[0] = Float.parseFloat((String)value);
|
||||
}
|
||||
else{
|
||||
|
@ -172,9 +173,19 @@ public class BeanUtils {
|
|||
log.warn("类型不一致,暂无法自动绑定,请手动转型一致后调用!字段类型: {} vs {} ", value.getClass().getTypeName(), fieldType);
|
||||
}
|
||||
}
|
||||
// Integer 向上转型为 Long 绑定
|
||||
else if(value.getClass().getTypeName().equals(Integer.class.getName()) && fieldType.equals(Long.class.getName())){
|
||||
Integer intValue = (Integer)value;
|
||||
args[0] = intValue.longValue();
|
||||
}
|
||||
// Float 向上转型为 Double 绑定
|
||||
else if(value.getClass().getTypeName().equals(Float.class.getName()) && fieldType.equals(Double.class.getName())){
|
||||
Float floatValue = (Float)value;
|
||||
args[0] = floatValue.doubleValue();
|
||||
}
|
||||
else{
|
||||
args[0] = value;
|
||||
log.warn("类型不一致,且Map中的value非String类型,暂无法自动绑定,请手动转型一致后调用! {} vs {} ", value.getClass().getTypeName(), fieldType);
|
||||
log.warn("类型不一致,暂无法自动绑定,请手动转型一致后调用! {} vs {} ", value.getClass().getTypeName(), fieldType);
|
||||
}
|
||||
}
|
||||
else{
|
||||
|
@ -318,104 +329,74 @@ public class BeanUtils {
|
|||
}
|
||||
|
||||
/***
|
||||
* 构建上下级关联的树形结构的model
|
||||
* @param allModels
|
||||
* 构建上下级关联的树形结构的model(上级parentId、子节点children),根节点=0
|
||||
* @param allNodes 所有节点对象
|
||||
* @param <T>
|
||||
* @return
|
||||
*/
|
||||
public static <T extends BaseEntity> List<T> buildTree(List<T> allModels){
|
||||
if(V.isEmpty(allModels)){
|
||||
public static <T> List<T> buildTree(List<T> allNodes){
|
||||
return buildTree(allNodes, 0);
|
||||
}
|
||||
|
||||
/***
|
||||
* 构建指定根节点的上下级关联的树形结构(上级parentId、子节点children)
|
||||
* @param allNodes 所有节点对象
|
||||
* @param rootNodeId 跟节点ID
|
||||
* @param <T>
|
||||
* @return
|
||||
*/
|
||||
public static <T> List<T> buildTree(List<T> allNodes, Object rootNodeId){
|
||||
if(V.isEmpty(allNodes)){
|
||||
return null;
|
||||
}
|
||||
// 提取所有的top level对象
|
||||
List<T> topLevelModels = new ArrayList();
|
||||
for(T model : allModels){
|
||||
for(T model : allNodes){
|
||||
Object parentId = getProperty(model, Cons.FieldName.parentId.name());
|
||||
if(parentId == null || V.fuzzyEqual(parentId, 0)){
|
||||
if(parentId == null || V.fuzzyEqual(parentId, rootNodeId)){
|
||||
topLevelModels.add(model);
|
||||
}
|
||||
}
|
||||
if(V.isEmpty(topLevelModels)){
|
||||
return topLevelModels;
|
||||
}
|
||||
// 提取向下一层的对象
|
||||
buildDeeperLevelTree(topLevelModels, allModels);
|
||||
// 返回第一层级节点(二级及以上子级通过children属性获取)
|
||||
// 遍历第一级节点,并挂载 children 子节点
|
||||
for(T node : allNodes) {
|
||||
Object nodeId = getProperty(node, Cons.FieldName.id.name());
|
||||
List<T> children = buildTreeChildren(nodeId, allNodes);
|
||||
setProperty(node, Cons.FieldName.children.name(), children);
|
||||
}
|
||||
return topLevelModels;
|
||||
}
|
||||
|
||||
/*
|
||||
* 构建上下级关联的树形结构,去除顶层父级实体的parentId必须是为null或0的限制
|
||||
* 注:通常情况下parentModels参数传null值就可以
|
||||
* */
|
||||
public static <T extends BaseEntity> List<T> buildTree(List<T> parentModels, List<T> allModels){
|
||||
if(V.isEmpty(allModels)){
|
||||
return null;
|
||||
}
|
||||
//获取顶层父级实体,根据一个实体的parentId是否是allModels中的某个实体的主键来判断该实体是否为顶层父级实体
|
||||
if(parentModels == null){
|
||||
parentModels = new ArrayList<>();
|
||||
Set<Long> idSet = new HashSet<>();
|
||||
for(T model : allModels){
|
||||
idSet.add(model.getId());
|
||||
}
|
||||
for(T model : allModels){
|
||||
if(!idSet.contains((Long)getProperty(model, Cons.FieldName.parentId.name()))){
|
||||
parentModels.add(model);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(T parent : parentModels){
|
||||
List<T> children = new ArrayList<>();
|
||||
for(T model : allModels){
|
||||
if(V.fuzzyEqual(parent.getId(), getProperty(model, Cons.FieldName.parentId.name()))
|
||||
&& !V.fuzzyEqual(model.getId(), getProperty(model, Cons.FieldName.parentId.name()))){ //解除自循环,如:实体的id==parentId的情况
|
||||
children.add(model);
|
||||
}
|
||||
}
|
||||
//递归调用
|
||||
buildTree(children, allModels);
|
||||
if(V.notEmpty(children)){
|
||||
setProperty(parent, Cons.FieldName.children.name(), children);
|
||||
}
|
||||
}
|
||||
|
||||
return parentModels;
|
||||
}
|
||||
|
||||
/***
|
||||
* 构建下一层级树形结构
|
||||
* @param parentModels
|
||||
* @param allModels
|
||||
* @param <T>
|
||||
/**
|
||||
* 递归构建树节点的子节点
|
||||
* @param parentId
|
||||
* @param nodeList
|
||||
* @return
|
||||
*/
|
||||
private static <T extends BaseEntity> void buildDeeperLevelTree(List<T> parentModels, List<T> allModels){
|
||||
List<T> deeperLevelModels = new ArrayList();
|
||||
Map<String, T> parentLevelModelMap = convertToStringKeyObjectMap(parentModels, Cons.FieldName.id.name());
|
||||
for(T model : allModels){
|
||||
Object parentId = getProperty(model, Cons.FieldName.parentId.name());
|
||||
if(parentLevelModelMap.keySet().contains(String.valueOf(parentId)) && !parentId.equals(model.getId())){
|
||||
deeperLevelModels.add(model);
|
||||
}
|
||||
}
|
||||
if(V.isEmpty(deeperLevelModels)){
|
||||
return;
|
||||
}
|
||||
for(T model : deeperLevelModels){
|
||||
Object parentId = getProperty(model, Cons.FieldName.parentId.name());
|
||||
T parentModel = parentLevelModelMap.get(String.valueOf(parentId));
|
||||
if(parentModel!=null){
|
||||
List children = (List) getProperty(parentModel, Cons.FieldName.children.name());
|
||||
private static <T> List<T> buildTreeChildren(Object parentId, List<T> nodeList) {
|
||||
List<T> children = null;
|
||||
for(T node : nodeList) {
|
||||
Object nodeParentId = getProperty(node, Cons.FieldName.parentId.name());
|
||||
if(nodeParentId != null && V.equals(nodeParentId, parentId)) {
|
||||
if(children == null){
|
||||
children = new ArrayList();
|
||||
setProperty(parentModel, Cons.FieldName.children.name(), children);
|
||||
children = new ArrayList<>();
|
||||
}
|
||||
children.add(model);
|
||||
children.add(node);
|
||||
}
|
||||
}
|
||||
// 递归进入下一层级
|
||||
buildDeeperLevelTree(deeperLevelModels, allModels);
|
||||
if(children != null){
|
||||
for(T child : children) {
|
||||
Object nodeId = getProperty(child, Cons.FieldName.id.name());
|
||||
List<T> childNodeChildren = buildTreeChildren(nodeId, nodeList);
|
||||
if(childNodeChildren == null) {
|
||||
childNodeChildren = new ArrayList<>();
|
||||
}
|
||||
setProperty(child, Cons.FieldName.children.name(), childNodeChildren);
|
||||
}
|
||||
}
|
||||
return children;
|
||||
}
|
||||
|
||||
/***
|
||||
|
@ -635,7 +616,7 @@ public class BeanUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
* 获取类所有属性(包含父类)
|
||||
* 获取类所有属性(包含父类中属性)
|
||||
* @param clazz
|
||||
* @return
|
||||
*/
|
||||
|
@ -657,6 +638,40 @@ public class BeanUtils {
|
|||
return fieldList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取类的指定属性(包含父类中属性)
|
||||
* @param clazz
|
||||
* @param fieldName
|
||||
* @return
|
||||
*/
|
||||
public static Field extractField(Class clazz, String fieldName){
|
||||
List<Field> allFields = extractAllFields(clazz);
|
||||
if(V.notEmpty(allFields)){
|
||||
for(Field field : allFields){
|
||||
if(field.getName().equals(fieldName)){
|
||||
return field;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从宿主类定义中获取泛型定义类class
|
||||
* @param hostClass
|
||||
* @param index
|
||||
* @return
|
||||
*/
|
||||
public static Class getGenericityClass(Class hostClass, int index){
|
||||
ResolvableType resolvableType = ResolvableType.forClass(hostClass).getSuperType();
|
||||
ResolvableType[] types = resolvableType.getSuperType().getGenerics();
|
||||
if(V.notEmpty(types) && types.length > index){
|
||||
return types[index].resolve();
|
||||
}
|
||||
log.warn("无法从 {} 类定义中获取泛型类{}", hostClass.getName(), index);
|
||||
return null;
|
||||
}
|
||||
|
||||
/***
|
||||
* 获取类对应的Lambda
|
||||
* @param fn
|
||||
|
|
|
@ -8,7 +8,6 @@ import org.springframework.beans.BeansException;
|
|||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.context.ContextLoader;
|
||||
|
||||
|
@ -71,11 +70,11 @@ public class ContextHelper implements ApplicationContextAware {
|
|||
|
||||
/***
|
||||
* 获取指定类型的单个Bean实例
|
||||
* @param type
|
||||
* @param clazz
|
||||
* @return
|
||||
*/
|
||||
public static Object getBean(Class type){
|
||||
return getApplicationContext().getBean(type);
|
||||
public static <T> T getBean(Class<T> clazz){
|
||||
return getApplicationContext().getBean(clazz);
|
||||
}
|
||||
|
||||
/***
|
||||
|
@ -131,9 +130,9 @@ public class ContextHelper implements ApplicationContextAware {
|
|||
Map<String, IService> serviceMap = getApplicationContext().getBeansOfType(IService.class);
|
||||
if(V.notEmpty(serviceMap)){
|
||||
for(Map.Entry<String, IService> entry : serviceMap.entrySet()){
|
||||
String entityClassName = getEntityClassByServiceImpl(entry.getValue().getClass());
|
||||
if(V.notEmpty(entityClassName)){
|
||||
ENTITY_SERVICE_CACHE.put(entityClassName, entry.getValue());
|
||||
Class entityClass = BeanUtils.getGenericityClass(entry.getValue().getClass(), 1);
|
||||
if(entityClass != null){
|
||||
ENTITY_SERVICE_CACHE.put(entityClass.getName(), entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -152,31 +151,13 @@ public class ContextHelper implements ApplicationContextAware {
|
|||
Map<String, BaseService> serviceMap = getApplicationContext().getBeansOfType(BaseService.class);
|
||||
if(V.notEmpty(serviceMap)){
|
||||
for(Map.Entry<String, BaseService> entry : serviceMap.entrySet()){
|
||||
String entityClassName = getEntityClassByServiceImpl(entry.getValue().getClass());
|
||||
if(V.notEmpty(entityClassName)){
|
||||
ENTITY_BASE_SERVICE_CACHE.put(entityClassName, entry.getValue());
|
||||
Class entityClass = BeanUtils.getGenericityClass(entry.getValue().getClass(), 1);
|
||||
if(entityClass != null){
|
||||
ENTITY_BASE_SERVICE_CACHE.put(entityClass.getName(), entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ENTITY_BASE_SERVICE_CACHE.get(entity.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据Service实现类的bean解析出Entity类名
|
||||
* @param currentClass
|
||||
* @return
|
||||
*/
|
||||
private static String getEntityClassByServiceImpl(Class currentClass){
|
||||
ResolvableType superType = ResolvableType.forClass(currentClass).getSuperType();
|
||||
ResolvableType[] genericsTypes = superType.getSuperType().getGenerics();
|
||||
if(V.notEmpty(genericsTypes) && genericsTypes.length >= 2){
|
||||
log.debug("Entity-Service: {} -> {}", genericsTypes[1].toString(), currentClass.getName());
|
||||
return genericsTypes[1].toString();
|
||||
}
|
||||
else{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -2,6 +2,8 @@ package com.diboot.core.util;
|
|||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.validation.ObjectError;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.*;
|
||||
|
@ -385,4 +387,21 @@ public class V {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析所有的验证错误信息,转换为JSON
|
||||
* @param result
|
||||
* @return
|
||||
*/
|
||||
public static String getBindingError(BindingResult result){
|
||||
if(result == null || !result.hasErrors()){
|
||||
return null;
|
||||
}
|
||||
List<ObjectError> errors = result.getAllErrors();
|
||||
List<String> allErrors = new ArrayList<>(errors.size());
|
||||
for(ObjectError error : errors){
|
||||
allErrors.add(error.getDefaultMessage().replaceAll("\"", "'"));
|
||||
}
|
||||
return S.join(allErrors);
|
||||
}
|
||||
|
||||
}
|
|
@ -34,9 +34,19 @@ public class JsonResult implements Serializable {
|
|||
}
|
||||
|
||||
/**
|
||||
* 默认成功,有返回数据(及附加提示信息)
|
||||
* 默认成功,有返回数据
|
||||
*/
|
||||
public JsonResult(Object data, String... additionalMsg){
|
||||
public JsonResult(Object data){
|
||||
this.code = Status.OK.code();
|
||||
this.msg = Status.OK.label();
|
||||
initMsg(null);
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 默认成功,有返回数据、及附加提示信息
|
||||
*/
|
||||
public JsonResult(Object data, String additionalMsg){
|
||||
this.code = Status.OK.code();
|
||||
this.msg = Status.OK.label();
|
||||
initMsg(additionalMsg);
|
||||
|
@ -44,11 +54,22 @@ public class JsonResult implements Serializable {
|
|||
}
|
||||
|
||||
/***
|
||||
* 非成功,指定状态(及附加提示信息)
|
||||
* 非成功,指定状态
|
||||
* @param status
|
||||
*/
|
||||
public JsonResult(Status status){
|
||||
this.code = status.code();
|
||||
this.msg = status.label();
|
||||
initMsg(null);
|
||||
this.data = null;
|
||||
}
|
||||
|
||||
/***
|
||||
* 非成功,指定状态及附加提示信息
|
||||
* @param status
|
||||
* @param additionalMsg
|
||||
*/
|
||||
public JsonResult(Status status, String... additionalMsg){
|
||||
public JsonResult(Status status, String additionalMsg){
|
||||
this.code = status.code();
|
||||
this.msg = status.label();
|
||||
initMsg(additionalMsg);
|
||||
|
@ -56,9 +77,21 @@ public class JsonResult implements Serializable {
|
|||
}
|
||||
|
||||
/**
|
||||
* 非成功,指定状态、返回数据(及附加提示信息)
|
||||
* 非成功,指定状态、返回数据
|
||||
* @param status
|
||||
* @param data
|
||||
*/
|
||||
public JsonResult(Status status, Object data){
|
||||
this.code = status.code();
|
||||
this.msg = status.label();
|
||||
initMsg(null);
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 非成功,指定状态、返回数据、及附加提示信息
|
||||
*/
|
||||
public JsonResult(Status status, Object data, String... additionalMsg){
|
||||
public JsonResult(Status status, Object data, String additionalMsg){
|
||||
this.code = status.code();
|
||||
this.msg = status.label();
|
||||
initMsg(additionalMsg);
|
||||
|
@ -99,13 +132,13 @@ public class JsonResult implements Serializable {
|
|||
* 赋值msg(去掉重复前缀以支持与BusinessException嵌套使用)
|
||||
* @param additionalMsg
|
||||
*/
|
||||
private void initMsg(String... additionalMsg){
|
||||
private void initMsg(String additionalMsg){
|
||||
if(V.notEmpty(additionalMsg)){
|
||||
if(S.startsWith(additionalMsg[0], this.msg)){
|
||||
this.msg = additionalMsg[0];
|
||||
if(S.startsWith(additionalMsg, this.msg)){
|
||||
this.msg = additionalMsg;
|
||||
}
|
||||
else{
|
||||
this.msg += ": " + additionalMsg[0];
|
||||
this.msg += ": " + additionalMsg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ package com.diboot.core.vo;
|
|||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* KeyValue键值对形式的VO
|
||||
* KeyValue键值对形式的VO(用于构建显示名Name-存储值Value形式的结果)
|
||||
* @author Mazhicheng
|
||||
* @version v2.0
|
||||
* @date 2019/1/4
|
||||
|
@ -19,7 +19,7 @@ public class KeyValue implements Serializable {
|
|||
}
|
||||
|
||||
/***
|
||||
* key: 显示值
|
||||
* key: 显示值,需要显示的name/label文本
|
||||
*/
|
||||
private String k;
|
||||
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
package com.diboot.core.vo;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.core.metadata.OrderItem;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.diboot.core.config.BaseConfig;
|
||||
import com.diboot.core.config.Cons;
|
||||
import com.diboot.core.util.S;
|
||||
import com.diboot.core.util.V;
|
||||
import org.slf4j.Logger;
|
||||
|
@ -8,7 +12,6 @@ import org.slf4j.LoggerFactory;
|
|||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
|
@ -34,14 +37,14 @@ public class Pagination implements Serializable {
|
|||
* count总数
|
||||
*/
|
||||
private long totalCount = 0;
|
||||
/***
|
||||
* 排序-升序排列的字段
|
||||
/**
|
||||
* 默认排序
|
||||
*/
|
||||
private List<String> ascList = null;
|
||||
/***
|
||||
* 降序排列的字段(默认以create_time降序排列,当指定了其他排列方式时以用户指定为准)
|
||||
private static final String DEFAULT_ORDER_BY = Cons.FieldName.id.name()+":"+Cons.ORDER_DESC;
|
||||
/**
|
||||
* 排序
|
||||
*/
|
||||
private List<String> descList = new ArrayList<>(Arrays.asList("create_time"));
|
||||
private String orderBy = DEFAULT_ORDER_BY;
|
||||
|
||||
public Pagination(){
|
||||
}
|
||||
|
@ -81,46 +84,20 @@ public class Pagination implements Serializable {
|
|||
this.totalCount = totalCount;
|
||||
}
|
||||
|
||||
public void setOrderBy(String orderBy){
|
||||
if(V.isEmpty(orderBy)){
|
||||
return;
|
||||
}
|
||||
// 先清空默认排序规则
|
||||
clearDefaultOrder();
|
||||
// 指定新的排序规则
|
||||
String[] orderByFields = S.split(orderBy);
|
||||
for(String field : orderByFields){
|
||||
// orderBy=name:DESC,age:ASC,birthdate
|
||||
if(field.contains(":")){
|
||||
String[] fieldAndOrder = S.split(field, ":");
|
||||
if("DESC".equalsIgnoreCase(fieldAndOrder[1])){
|
||||
if(descList == null){
|
||||
descList = new ArrayList<>();
|
||||
}
|
||||
descList.add(fieldAndOrder[0]);
|
||||
}
|
||||
else{
|
||||
if(ascList == null){
|
||||
ascList = new ArrayList<>();
|
||||
}
|
||||
ascList.add(fieldAndOrder[0]);
|
||||
}
|
||||
}
|
||||
else{
|
||||
if(ascList == null){
|
||||
ascList = new ArrayList<>();
|
||||
}
|
||||
ascList.add(field);
|
||||
}
|
||||
}
|
||||
/***
|
||||
* 获取数据库字段的列排序
|
||||
* @return
|
||||
*/
|
||||
public String getOrderBy() {
|
||||
return this.orderBy;
|
||||
}
|
||||
|
||||
/***
|
||||
* 清除默认排序
|
||||
/**
|
||||
* 设置排序
|
||||
* @param orderBy
|
||||
*/
|
||||
public void clearDefaultOrder(){
|
||||
ascList = null;
|
||||
descList = null;
|
||||
public void setOrderBy(String orderBy){
|
||||
this.orderBy = orderBy;
|
||||
}
|
||||
|
||||
/***
|
||||
|
@ -134,20 +111,52 @@ public class Pagination implements Serializable {
|
|||
return (int)Math.ceil((float) totalCount / pageSize);
|
||||
}
|
||||
|
||||
/***
|
||||
* 获取数据库字段的列排序,用于service层调用
|
||||
* @return
|
||||
/**
|
||||
* 清空默认排序
|
||||
*/
|
||||
public List<String> getAscList() {
|
||||
return ascList;
|
||||
public void clearDefaultOrder(){
|
||||
// 是否为默认排序
|
||||
if(V.equals(orderBy, DEFAULT_ORDER_BY)){
|
||||
orderBy = null;
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* 获取数据库字段的列排序,,用于service层调用
|
||||
/**
|
||||
* 转换为IPage
|
||||
* @param <T>
|
||||
* @return
|
||||
*/
|
||||
public List<String> getDescList() {
|
||||
return descList;
|
||||
public <T> IPage<T> toIPage(){
|
||||
List<OrderItem> orderItemList = null;
|
||||
// 解析排序
|
||||
if(V.notEmpty(this.orderBy)){
|
||||
orderItemList = new ArrayList<>();
|
||||
// orderBy=shortName:DESC,age:ASC,birthdate
|
||||
String[] orderByFields = S.split(this.orderBy);
|
||||
for(String field : orderByFields){
|
||||
if(field.contains(":")){
|
||||
String[] fieldAndOrder = S.split(field, ":");
|
||||
String columnName = S.toSnakeCase(fieldAndOrder[0]);
|
||||
if(Cons.ORDER_DESC.equalsIgnoreCase(fieldAndOrder[1])){
|
||||
orderItemList.add(OrderItem.desc(columnName));
|
||||
}
|
||||
else{
|
||||
orderItemList.add(OrderItem.asc(columnName));
|
||||
}
|
||||
}
|
||||
else{
|
||||
orderItemList.add(OrderItem.asc(S.toSnakeCase(field)));
|
||||
}
|
||||
}
|
||||
}
|
||||
IPage<T> page = new Page<T>()
|
||||
.setCurrent(getPageIndex())
|
||||
.setSize(getPageSize())
|
||||
// 如果前端传递过来了缓存的总数,则本次不再count统计
|
||||
.setTotal(getTotalCount() > 0? -1 : getTotalCount());
|
||||
if(orderItemList != null){
|
||||
((Page<T>) page).addOrder(orderItemList);
|
||||
}
|
||||
return page;
|
||||
}
|
||||
|
||||
}
|
|
@ -58,7 +58,7 @@ public enum Status {
|
|||
FAIL_EXCEPTION(5000, "系统异常"),
|
||||
|
||||
/***
|
||||
* 系统异常
|
||||
* 缓存清空
|
||||
*/
|
||||
MEMORY_EMPTY_LOST(9999, "缓存清空");
|
||||
|
||||
|
|
|
@ -47,7 +47,9 @@ public class TestEntityBinder {
|
|||
// 验证直接关联和通过中间表间接关联的绑定
|
||||
Assert.assertEquals(vo.getDepartmentId(), vo.getDepartment().getId());
|
||||
Assert.assertNotNull(vo.getDepartment().getOrgId());
|
||||
Assert.assertNotNull(vo.getOrganization());
|
||||
// 测试绑定VO
|
||||
Assert.assertNotNull(vo.getOrganizationVO());
|
||||
System.out.println(JSON.stringify(vo.getOrganizationVO()));
|
||||
System.out.println(JSON.stringify(vo));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import diboot.core.test.binder.entity.Department;
|
|||
import diboot.core.test.binder.entity.User;
|
||||
import diboot.core.test.binder.service.DepartmentService;
|
||||
import diboot.core.test.binder.service.UserService;
|
||||
import diboot.core.test.binder.vo.DepartmentVO;
|
||||
import diboot.core.test.binder.vo.EntityListComplexBinderVO;
|
||||
import diboot.core.test.binder.vo.EntityListSimpleBinderVO;
|
||||
import diboot.core.test.config.SpringMvcConfig;
|
||||
|
@ -58,7 +59,7 @@ public class TestEntityListBinder {
|
|||
System.out.println(JSON.stringify(vo));
|
||||
|
||||
if(vo.getChildren() != null){
|
||||
for(Department dept : vo.getChildren()){
|
||||
for(DepartmentVO dept : vo.getChildren()){
|
||||
System.out.println(dept.toString());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
package diboot.core.test.binder.vo;
|
||||
|
||||
import com.alibaba.fastjson.annotation.JSONField;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.diboot.core.entity.BaseEntity;
|
||||
import diboot.core.test.binder.entity.Department;
|
||||
|
||||
/**
|
||||
* 定时任务
|
||||
* @author Mazhicheng
|
||||
* @version v2.0
|
||||
* @date 2018/12/27
|
||||
*/
|
||||
public class DepartmentVO {
|
||||
private static final long serialVersionUID = -4849732665419794547L;
|
||||
|
||||
@TableField
|
||||
private Long parentId;
|
||||
|
||||
@TableField(exist = false)
|
||||
private String name;
|
||||
|
||||
public Long getParentId() {
|
||||
return parentId;
|
||||
}
|
||||
|
||||
public void setParentId(Long parentId) {
|
||||
this.parentId = parentId;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
|
@ -19,19 +19,20 @@ public class EntityBinderVO extends User {
|
|||
|
||||
// 通过中间表关联Entity
|
||||
@BindEntity(entity = Organization.class, condition = "this.department_id=department.id AND department.org_id=id") // AND ...
|
||||
private Organization organization;
|
||||
|
||||
private OrganizationVO organizationVO;
|
||||
|
||||
public Department getDepartment() {
|
||||
return department;
|
||||
}
|
||||
|
||||
public void setDepartment(Department department) {
|
||||
this.department = department;
|
||||
}
|
||||
public Organization getOrganization() {
|
||||
return organization;
|
||||
|
||||
public OrganizationVO getOrganizationVO() {
|
||||
return organizationVO;
|
||||
}
|
||||
public void setOrganization(Organization organization) {
|
||||
this.organization = organization;
|
||||
public void setOrganizationVO(OrganizationVO organizationVO) {
|
||||
this.organizationVO = organizationVO;
|
||||
}
|
||||
}
|
|
@ -15,13 +15,13 @@ public class EntityListSimpleBinderVO extends Department {
|
|||
|
||||
// 直接关联多个Entity
|
||||
@BindEntityList(entity = Department.class, condition = "this.id=parent_id")
|
||||
private List<Department> children;
|
||||
private List<DepartmentVO> children;
|
||||
|
||||
public List<Department> getChildren() {
|
||||
public List<DepartmentVO> getChildren() {
|
||||
return children;
|
||||
}
|
||||
|
||||
public void setChildren(List<Department> children) {
|
||||
public void setChildren(List<DepartmentVO> children) {
|
||||
this.children = children;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package diboot.core.test.binder.vo;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
|
||||
/**
|
||||
* <Description>
|
||||
*
|
||||
* @author Mazhicheng
|
||||
* @version v2.0
|
||||
* @date 2019/12/06
|
||||
*/
|
||||
public class OrganizationVO {
|
||||
|
||||
private Long parentId;
|
||||
|
||||
private String name;
|
||||
|
||||
public Long getParentId() {
|
||||
return parentId;
|
||||
}
|
||||
|
||||
public void setParentId(Long parentId) {
|
||||
this.parentId = parentId;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
}
|
|
@ -7,6 +7,7 @@ import com.diboot.core.service.DictionaryService;
|
|||
import com.diboot.core.util.BeanUtils;
|
||||
import com.diboot.core.util.SqlExecutor;
|
||||
import com.diboot.core.util.V;
|
||||
import com.diboot.core.vo.KeyValue;
|
||||
import com.diboot.core.vo.Pagination;
|
||||
import diboot.core.test.StartupApplication;
|
||||
import diboot.core.test.config.SpringMvcConfig;
|
||||
|
@ -134,6 +135,13 @@ public class BaseServiceTest {
|
|||
Assert.assertTrue(success);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testKV(){
|
||||
List<KeyValue> keyValues = dictionaryService.getKeyValueList("GENDER");
|
||||
Assert.assertTrue(keyValues.size() == 2);
|
||||
Assert.assertTrue(keyValues.get(0).getV().equals("M"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空测试数据
|
||||
* @param type
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package diboot.core.test.util;
|
||||
|
||||
import com.diboot.core.util.D;
|
||||
import com.diboot.core.vo.JsonResult;
|
||||
import com.diboot.core.vo.Status;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
|
@ -27,4 +29,18 @@ public class DTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJsonResult(){
|
||||
String token = "token";
|
||||
JsonResult j1 = new JsonResult(token);
|
||||
JsonResult j2 = new JsonResult(token, "申请token成功");
|
||||
JsonResult j3 = new JsonResult(Status.OK, token);
|
||||
JsonResult j4 = new JsonResult(Status.OK, token, "申请token成功");
|
||||
JsonResult j5 = new JsonResult(Status.OK);
|
||||
System.out.println(j1.getData());
|
||||
System.out.println(j2.getData());
|
||||
System.out.println(j3.getData());
|
||||
System.out.println(j4.getData());
|
||||
System.out.println(j5.getData());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ public class PropertiesTest {
|
|||
@Test
|
||||
public void testGetString(){
|
||||
String str1 = PropertiesUtils.get("spring.datasource.url");
|
||||
String str2 = PropertiesUtils.get("spring.datasource.username2");
|
||||
String str2 = PropertiesUtils.get("spring.datasource.username");
|
||||
Assert.assertNotNull(str1);
|
||||
Assert.assertNotNull(str2);
|
||||
}
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
# spring config
|
||||
spring.devtools.restart.enabled=true
|
||||
|
||||
#datasource config
|
||||
spring.datasource.url=jdbc:mysql://localhost:3306/diboot_example?characterEncoding=utf8&serverTimezone=GMT%2B8
|
||||
spring.datasource.username=diboot
|
||||
spring.datasource.password=123456
|
||||
spring.datasource.hikari.maximum-pool-size=5
|
||||
# 数据库驱动
|
||||
spring.datasource.hikari.driver-class-name=com.mysql.cj.jdbc.Driver
|
||||
|
||||
# logging config
|
||||
logging.level.root=debug
|
||||
logging.level.org.apache=info
|
||||
logging.level.org.hibernate.validator=info
|
||||
logging.level.org.springframework=info
|
||||
logging.level.com.zaxxer.hikari=info
|
||||
logging.level.com.diboot=debug
|
||||
logging.level.org.mybatis=debug
|
|
@ -14,7 +14,7 @@
|
|||
</div>
|
||||
<div class="custom content">
|
||||
<div class="features">
|
||||
<div class="feature" style="max-width: 35%;">
|
||||
<div class="feature col-1">
|
||||
<h2>diboot-core 精简高效内核</h2>
|
||||
<p>
|
||||
<ul>
|
||||
|
@ -26,7 +26,7 @@
|
|||
</ul>
|
||||
</p>
|
||||
</div>
|
||||
<div class="feature" style="max-width: 60%">
|
||||
<div class="feature col-2">
|
||||
<h2>diboot-devtools 强大开发助理</h2>
|
||||
<p>
|
||||
<ul>
|
||||
|
@ -44,29 +44,31 @@
|
|||
<div class="footer-content">
|
||||
<div class="footer-item"></div>
|
||||
<div class="footer-item">
|
||||
<h4>微信(扫码进群)</h4>
|
||||
<img src="../public/add_wechat.png" alt="" width="120">
|
||||
<h4>QQ群: 731690096</h4>
|
||||
<img src="../public/add_qqqun.png" alt="" width="120">
|
||||
</div>
|
||||
<div class="footer-item">
|
||||
<h4>联系我们</h4>
|
||||
<ul>
|
||||
<li>电话:0512-62988949</li>
|
||||
<li>Q Q:281550336</li>
|
||||
<li>QQ群:731690096</li>
|
||||
<li>邮箱:service@dibo.ltd</li>
|
||||
</ul>
|
||||
<h4>微信群: wx20201024</h4>
|
||||
<img src="../public/add_wechat.png" alt="" width="120">
|
||||
</div>
|
||||
<div class="footer-item">
|
||||
</div>
|
||||
</div>
|
||||
<p class="copy-right">© 2015-2019 <a href="http://www.dibo.ltd">苏州帝博信息技术有限公司</a></p>
|
||||
<p class="copy-right">© 2015-2020 <a href="http://www.dibo.ltd">苏州帝博信息技术有限公司</a>
|
||||
<br>
|
||||
<a class="ba-a" href="http://www.beian.miit.gov.cn/">
|
||||
<u>
|
||||
苏ICP备15013001号
|
||||
</u>
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal-cover" v-show="showModal" @click="closeModal">
|
||||
<div class="modal-content" @click="onModalContentClick($event)">
|
||||
<video src="https://diboot.oss-cn-shanghai.aliyuncs.com/file/%E5%BC%80%E5%A7%8B%E4%BD%BF%E7%94%A8diboot%E4%B8%8E%E5%85%B3%E8%81%94%E6%BC%94%E7%A4%BA_%E5%AD%97%E5%B9%95.mp4?nsukey=Z8MYZulBJM0GZXYNQgYGJGxRDvYMIWMsGj%2FkV%2BQpZD2aN7hsk7hreW1mXv71kxX7W5Sd61warYIPAAT4xDifYZEv3cQiiQiVW%2BqF%2FqomaxhPm1ht5jV5YkWLGiwcqQKeHmN5jn9%2FRWzaWTNweSZjWuif%2FZIciG6BX8UddZ0klnyyGfrtdB2eWCBAh%2F5n5rMPGdyUhYXAzzDsdPtyBxcY7w%3D%3D"
|
||||
class="homeVideo" id="homeVideo" height="666" controls>
|
||||
class="homeVideo" id="homeVideo" controls>
|
||||
</video>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -152,7 +154,7 @@
|
|||
}
|
||||
}
|
||||
.footer {
|
||||
padding: 1rem 2.5rem 2.5rem;
|
||||
padding: 1rem 2.5rem .5rem 2.5rem;
|
||||
border-top: 1px solid #eaecef;
|
||||
text-align: left;
|
||||
color: #4e6e8e;
|
||||
|
@ -227,7 +229,7 @@ a.button.white {
|
|||
height: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
z-index: 1000;
|
||||
position: absolute;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
text-align: center;
|
||||
|
@ -246,10 +248,64 @@ a.button.white {
|
|||
background-color: white;
|
||||
box-shadow: 0 0 15px black;
|
||||
}
|
||||
.homeVideo{
|
||||
height: 666px;
|
||||
}
|
||||
.donate-image{
|
||||
display: block;
|
||||
margin: 10px auto;
|
||||
width: 500px;
|
||||
height: auto;
|
||||
}
|
||||
.feature.col-1{
|
||||
max-width: 35%;
|
||||
}
|
||||
.feature.col-2{
|
||||
max-width: 60%;
|
||||
}
|
||||
.ba-line{
|
||||
margin: 0;
|
||||
line-height: 28px;
|
||||
text-align: center;
|
||||
}
|
||||
.copy-right .ba-a{
|
||||
font-size: 16px;
|
||||
color: #999;
|
||||
}
|
||||
@media screen and (max-width: 750px) {
|
||||
.button.has-icon{
|
||||
margin-top: 15px;
|
||||
}
|
||||
.home {
|
||||
padding: 0;
|
||||
}
|
||||
.home .feature{
|
||||
padding: 0;
|
||||
}
|
||||
.feature.col-1{
|
||||
max-width: 100%;
|
||||
}
|
||||
.feature.col-2{
|
||||
max-width: 100%;
|
||||
}
|
||||
.home .footer{
|
||||
padding: 1rem 0;
|
||||
}
|
||||
.home .footer .footer-content .footer-item{
|
||||
max-width: 100%;
|
||||
flex-basis: 100%;
|
||||
}
|
||||
.modal-content{
|
||||
width: 320px;
|
||||
height: 180px;
|
||||
margin-top: -90px;
|
||||
margin-left: -160px;
|
||||
}
|
||||
.homeVideo{
|
||||
height: 180px;
|
||||
}
|
||||
a.button.white{
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,6 +1,6 @@
|
|||
module.exports = {
|
||||
title: 'Diboot 轻代码开发平台',
|
||||
description: '2.0 - 更好更强的轻代码开发平台',
|
||||
description: '2.0 - 您的自动化开发助理',
|
||||
head: [
|
||||
['link', {rel: 'icon', href: '/logo.png'}]
|
||||
],
|
||||
|
@ -55,7 +55,7 @@ module.exports = {
|
|||
]
|
||||
},
|
||||
nav: [{
|
||||
text: '首页', link: '/'
|
||||
text: '首页', link: '/index.html'
|
||||
}, {
|
||||
text: 'core内核 指南',
|
||||
link: '/guide/diboot-core/安装'
|
||||
|
@ -63,12 +63,14 @@ module.exports = {
|
|||
text: 'devtools助理 指南',
|
||||
link: '/guide/diboot-devtools/介绍'
|
||||
},{
|
||||
text: '捐助Diboot团队',
|
||||
text: '捐助我们',
|
||||
link: '/guide/donate/'
|
||||
},{
|
||||
text: '项目合作',
|
||||
link:'http://www.dibo.ltd/contect.html'
|
||||
},{
|
||||
text: 'Gitee', link: 'https://gitee.com/dibo_software/diboot-v2'
|
||||
},{
|
||||
text: 'GitHub', link: 'https://github.com/dibo-software/diboot-v2'
|
||||
},{
|
||||
text: '1.x旧版', link: 'https://www.diboot.com/diboot-v1/'
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 206 KiB |
Binary file not shown.
After Width: | Height: | Size: 415 KiB |
|
@ -0,0 +1,3 @@
|
|||
yarn
|
||||
yarn build
|
||||
gulp
|
|
@ -21,17 +21,19 @@ MySQL、MariaDB、ORACLE、SQLServer、PostgreSQL
|
|||
|
||||
参考样例 [diboot-core-example](https://github.com/dibo-software/diboot-v2-example/tree/master/diboot-core-example)
|
||||
|
||||
> 如果您使用diboot-devtools,diboot-core会被自动引入,无需再配置依赖。
|
||||
|
||||
## 相关依赖
|
||||
|
||||
:::tip
|
||||
以下依赖在引入diboot-core-starter依赖中,可以不再引入。
|
||||
:::
|
||||
* **javax.servlet-api**(javax.servlet:javax.servlet-api:4.0.1)
|
||||
* **spring-boot-starter-web**(org.springframework.boot:spring-boot-starter-web:2.1.8.RELEASE)
|
||||
* **spring-boot-starter-web**(org.springframework.boot:spring-boot-starter-web:2.2.1.RELEASE)
|
||||
* **mybatis-plus-boot-starter**(com.baomidou:mybatis-plus-boot-starter:3.2.0)
|
||||
* **commons-io**(commons-io:commons-io:2.6)
|
||||
* **commons-lang3**(org.apache.commons:commons-lang3:3.8.1)
|
||||
* **fastjson**(com.alibaba:fastjson:1.2.60)
|
||||
|
||||
:::tip
|
||||
以上依赖在引入diboot-core-starter依赖的项目中,可以不再引入。
|
||||
需要额外添加的jar
|
||||
:::
|
||||
* **数据库驱动包** (如 mysql:mysql-connector-java:8.0.18)
|
||||
|
||||
|
|
|
@ -91,17 +91,17 @@ Map map = BeanUtils.convertToStringKeyObjectListMap(allLists, fields);
|
|||
|
||||
* buildTree 方法
|
||||
```java
|
||||
//该方法用来构建上下级关联的实体关系树形结构,顶层父级实体的parentId必须是为null或0,入参为对象集合(allModels)
|
||||
//该方法用来构建支持无限层级的树形结构,默认顶层父级节点的parentId=0,入参为对象集合(allNodes)
|
||||
//方法定义
|
||||
public static <T extends BaseEntity> List<T> buildTree(List<T> allModels){...}
|
||||
public static <T> List<T> buildTree(List<T> allNodes){...}
|
||||
//方法调用示例
|
||||
List list = BeanUtils.buildTree(allModels);
|
||||
List<Menu> menuTree = BeanUtils.buildTree(allNodes);
|
||||
|
||||
//该方法用来构建上下级关联的实体关系树形结构,去除顶层父级实体的parentId必须是为null或0的限制,入参为对象集合(allModels)
|
||||
//该方法用来构建支持无限层级的树形结构,指定顶层父级节点的parentId,入参为(allNodes, rootNodeId)
|
||||
//方法定义
|
||||
public static <T extends BaseEntity> List<T> buildTree(List<T> parentModels, List<T> allModels){...}
|
||||
public static <T> List<T> buildTree(List<T> allNodes, Object rootNodeId){
|
||||
//方法调用示例
|
||||
List list = BeanUtils.buildTree(parentModels, allModels);
|
||||
List<Menu> menuTree = BeanUtils.buildTree(allNodes, 1L);
|
||||
```
|
||||
|
||||
* extractDiff 方法
|
||||
|
|
|
@ -1 +1,14 @@
|
|||
# 异常处理
|
||||
## DefaultExceptionHandler
|
||||
|
||||
* 默认异常处理,继承自该类并添加@ControllerAdvice注解即可自动支持:
|
||||
* 兼容JSON请求和Html页面请求的Exception异常处理
|
||||
* Entity绑定校验的统一处理(BindException.class, MethodArgumentNotValidException.class)
|
||||
|
||||
* 示例代码
|
||||
~~~java
|
||||
@ControllerAdvice
|
||||
public class GeneralExceptionHandler extends DefaultExceptionHandler{
|
||||
|
||||
}
|
||||
~~~
|
|
@ -108,6 +108,7 @@ private String orgName;
|
|||
|
||||
### 绑定单个实体
|
||||
> 绑定单个实体使用**@BindEntity**注解进行处理,将得到关联表对应的单个实体。
|
||||
> 如果属性类型为VO等非Entity对象类型,将自动转换为您指定的类型再绑定。
|
||||
* 使用@BindEntity注解时需传两个参数,分别是entity和condition。
|
||||
* entity表示关联实体类;
|
||||
* condition表示关联条件。
|
||||
|
@ -124,6 +125,7 @@ private Organization organization;
|
|||
|
||||
### 绑定实体列表
|
||||
> 绑定实体列表使用**@BindEntityList**注解进行处理,将得到关联表对应的实体列表。
|
||||
> 如果待绑定List中的泛型参数类型为VO等非Entity对象,将自动转换为您指定的类型再绑定。
|
||||
* 使用@BindEntityList注解时需传两个参数,分别是entity和condition。
|
||||
* entity表示关联实体类;
|
||||
* condition表示关联条件。
|
||||
|
|
|
@ -24,9 +24,9 @@ public class UserDTO{
|
|||
* 将映射为 queryWrapper.eq("gender", "M").like("realname", "张")
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
public JsonResult getVOList(UserDto userDto) throws Exception{
|
||||
//调用super.buildQueryWrapper(entityOrDto) 或者直接调用 QueryBuilder.toQueryWrapper(entityOrDto) 进行转换
|
||||
QueryWrapper<User> queryWrapper = super.buildQueryWrapper(userDto);
|
||||
public JsonResult getVOList(UserDto userDto, HttpServletRequest request) throws Exception{
|
||||
//调用super.buildQueryWrapper(entityOrDto, request) 或者直接调用 QueryBuilder.toQueryWrapper(entityOrDto) 进行转换
|
||||
QueryWrapper<User> queryWrapper = super.buildQueryWrapper(userDto, request);
|
||||
//... 查询list
|
||||
return new JsonResult(Status.OK, list);
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue