forked from Gitlink/microservices
Compare commits
1 Commits
dev_monito
...
master
| Author | SHA1 | Date |
|---|---|---|
|
|
89cf31f69a |
|
|
@ -14,6 +14,7 @@ import org.springframework.web.multipart.MultipartFile;
|
|||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 文件服务
|
||||
|
|
@ -34,6 +35,17 @@ public interface RemoteFileService {
|
|||
@RequestParam("hierarchy") String hierarchy,
|
||||
@RequestHeader(SecurityConstants.FROM_SOURCE) String source);
|
||||
|
||||
/**
|
||||
* Base64 图片上传(HashMap 版本)
|
||||
*/
|
||||
@PostMapping(value = "/upload/base64")
|
||||
R<SysFileInfo> uploadBase64(
|
||||
@RequestBody Map<String, Object> params,
|
||||
@RequestParam("type") String type,
|
||||
@RequestParam("hierarchy") String hierarchy,
|
||||
@RequestHeader(SecurityConstants.FROM_SOURCE) String source
|
||||
);
|
||||
|
||||
/**
|
||||
* 根据文件Id列表获取文件列表
|
||||
*
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import org.springframework.web.multipart.MultipartFile;
|
|||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 文件服务降级处理
|
||||
|
|
@ -36,6 +37,11 @@ public class RemoteFileFallbackFactory implements FallbackFactory<RemoteFileServ
|
|||
return R.fail("上传文件失败:" + throwable.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public R<SysFileInfo> uploadBase64(Map<String, Object> params, String type, String hierarchy, String source) {
|
||||
return R.fail("上传base64文件失败:" + throwable.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public R<List<SysFileInfo>> getFileList(String fileIds) {
|
||||
return R.fail("获取文件列表失败:" + throwable.getMessage());
|
||||
|
|
|
|||
|
|
@ -0,0 +1,62 @@
|
|||
package com.microservices.system.api.utils;
|
||||
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
public class StandardMultipartFile implements MultipartFile {
|
||||
|
||||
private final byte[] content;
|
||||
private final String name;
|
||||
private final String originalFilename;
|
||||
private final String contentType;
|
||||
|
||||
public StandardMultipartFile(byte[] content, String name, String originalFilename, String contentType) {
|
||||
this.content = content != null ? content : new byte[0];
|
||||
this.name = name;
|
||||
this.originalFilename = originalFilename;
|
||||
this.contentType = contentType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOriginalFilename() {
|
||||
return originalFilename;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContentType() {
|
||||
return contentType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return content.length == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getSize() {
|
||||
return content.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getBytes() throws IOException {
|
||||
return content;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getInputStream() throws IOException {
|
||||
return new ByteArrayInputStream(content);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transferTo(File dest) throws IOException, IllegalStateException {
|
||||
try (FileOutputStream fos = new FileOutputStream(dest)) {
|
||||
fos.write(content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -13,17 +13,19 @@ import com.microservices.common.core.utils.reflect.ReflectUtils;
|
|||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.apache.commons.lang3.RegExUtils;
|
||||
import org.apache.commons.lang3.reflect.FieldUtils;
|
||||
import org.apache.poi.hssf.usermodel.*;
|
||||
import org.apache.poi.ss.usermodel.*;
|
||||
import org.apache.poi.ss.util.CellRangeAddress;
|
||||
import org.apache.poi.ss.util.CellRangeAddressList;
|
||||
import org.apache.poi.util.IOUtils;
|
||||
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
|
||||
import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
|
||||
import org.apache.poi.xssf.usermodel.XSSFDataValidation;
|
||||
import org.apache.poi.xssf.usermodel.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Field;
|
||||
|
|
@ -1458,4 +1460,288 @@ public class ExcelUtil<T>
|
|||
}
|
||||
return method;
|
||||
}
|
||||
|
||||
// 存储Excel中的图片(key: 行号_列号,value: MultipartFile)
|
||||
private final Map<String, MultipartFile> excelImageMap = new HashMap<>();
|
||||
|
||||
/**
|
||||
* 获取解析后的Excel图片映射表(行号_列号 -> MultipartFile)
|
||||
* <p>对外返回不可修改的Map,避免外部篡改,同时让静态检查识别到该集合被查询</p>
|
||||
* @return 图片映射表
|
||||
*/
|
||||
public Map<String, MultipartFile> getExcelImageMap() {
|
||||
// 返回不可修改的Map,提升代码安全性,同时让静态检查识别到集合被读取
|
||||
return Collections.unmodifiableMap(excelImageMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析Excel中的图片并转换为MultipartFile,存入{@link #excelImageMap}
|
||||
* @param sheet Excel工作表
|
||||
* @throws IOException 解析图片失败时抛出
|
||||
*/
|
||||
private void parseExcelImages(Sheet sheet) throws IOException {
|
||||
if (wb instanceof XSSFWorkbook) {
|
||||
parseXSSFImages((XSSFSheet) sheet);
|
||||
} else if (wb instanceof HSSFWorkbook) {
|
||||
parseHSSFImages((HSSFWorkbook) wb, sheet);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析XSSF格式(xlsx)图片
|
||||
*/
|
||||
private void parseXSSFImages(XSSFSheet sheet) {
|
||||
XSSFDrawing drawing = sheet.createDrawingPatriarch();
|
||||
List<XSSFShape> shapes = drawing.getShapes();
|
||||
|
||||
for (XSSFShape shape : shapes) {
|
||||
if (shape instanceof XSSFPicture) {
|
||||
XSSFPicture picture = (XSSFPicture) shape;
|
||||
XSSFPictureData pictureData = picture.getPictureData();
|
||||
XSSFClientAnchor anchor = picture.getPreferredSize();
|
||||
|
||||
// 获取图片所在单元格位置
|
||||
int row = anchor.getRow1();
|
||||
int col = anchor.getCol1();
|
||||
String cellKey = row + "_" + col;
|
||||
|
||||
// 转换为MultipartFile并存储
|
||||
MultipartFile multipartFile = bytesToMultipartFile(pictureData.getData(), "xlsx_image.png");
|
||||
excelImageMap.put(cellKey, multipartFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析HSSF格式(xls)图片
|
||||
*/
|
||||
private void parseHSSFImages(HSSFWorkbook workbook, Sheet sheet) {
|
||||
List<HSSFPictureData> pictureDataList = workbook.getAllPictures();
|
||||
|
||||
for (int i = 0; i < pictureDataList.size(); i++) {
|
||||
HSSFPictureData pictureData = pictureDataList.get(i);
|
||||
HSSFPatriarch patriarch = (HSSFPatriarch) sheet.createDrawingPatriarch();
|
||||
List<HSSFShape> shapes = patriarch.getChildren();
|
||||
|
||||
for (HSSFShape shape : shapes) {
|
||||
if (shape instanceof HSSFPicture) {
|
||||
HSSFPicture picture = (HSSFPicture) shape;
|
||||
if (picture.getPictureIndex() == i) {
|
||||
HSSFClientAnchor anchor = picture.getClientAnchor();
|
||||
int row = anchor.getRow1();
|
||||
int col = anchor.getCol1();
|
||||
String cellKey = row + "_" + col;
|
||||
|
||||
// 转换为MultipartFile并存储
|
||||
MultipartFile multipartFile = bytesToMultipartFile(pictureData.getData(), "xls_image.png");
|
||||
excelImageMap.put(cellKey, multipartFile);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义MultipartFile实现(通用版,无外部依赖)
|
||||
*/
|
||||
public static class CustomMultipartFile implements MultipartFile {
|
||||
private final byte[] content;
|
||||
private final String filename;
|
||||
private final String contentType;
|
||||
|
||||
public CustomMultipartFile(byte[] content, String filename, String contentType) {
|
||||
this.content = content;
|
||||
this.filename = filename;
|
||||
this.contentType = contentType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "file";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOriginalFilename() {
|
||||
return filename;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContentType() {
|
||||
return contentType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return content == null || content.length == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getSize() {
|
||||
return content.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getBytes() throws IOException {
|
||||
return content;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getInputStream() throws IOException {
|
||||
return new ByteArrayInputStream(content);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transferTo(java.io.File dest) throws IOException, IllegalStateException {
|
||||
try (java.io.OutputStream os = new java.io.FileOutputStream(dest)) {
|
||||
os.write(content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将字节数组转换为MultipartFile(核心工具方法)
|
||||
*/
|
||||
public MultipartFile bytesToMultipartFile(byte[] bytes, String fileName) {
|
||||
try {
|
||||
String suffix = "png";
|
||||
if (fileName != null && fileName.contains(".")) {
|
||||
suffix = fileName.substring(fileName.lastIndexOf(".") + 1);
|
||||
}
|
||||
String finalFileName = UUID.randomUUID().toString() + "." + suffix;
|
||||
String contentType = "image/" + suffix;
|
||||
|
||||
return new CustomMultipartFile(bytes, finalFileName, contentType);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("转换图片为MultipartFile失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
// 导入包含图片的excel
|
||||
public List<T> importExcelWithImages(String sheetName, InputStream is, int titleNum) throws Exception {
|
||||
this.type = Type.IMPORT;
|
||||
this.wb = WorkbookFactory.create(is);
|
||||
List<T> list = new ArrayList<T>();
|
||||
|
||||
Sheet sheet = StringUtils.isNotEmpty(sheetName) ? wb.getSheet(sheetName) : wb.getSheetAt(0);
|
||||
if (sheet == null) {
|
||||
throw new IOException("文件sheet不存在");
|
||||
}
|
||||
|
||||
// 1. 解析Excel中的图片,生成imageMap(行号_列号 -> MultipartFile)
|
||||
parseExcelImages(sheet);
|
||||
|
||||
int rows = sheet.getLastRowNum();
|
||||
if (rows > 0) {
|
||||
// ========== 参考原有逻辑:构建表头列名和下标映射 ==========
|
||||
Map<String, Integer> cellMap = new HashMap<>();
|
||||
Row heard = sheet.getRow(titleNum);
|
||||
for (int i = 0; i < heard.getPhysicalNumberOfCells(); i++) {
|
||||
Cell cell = heard.getCell(i);
|
||||
if (StringUtils.isNotNull(cell)) {
|
||||
String columnName = this.getCellValue(heard, i).toString().trim();
|
||||
cellMap.put(columnName, i);
|
||||
} else {
|
||||
cellMap.put(null, i);
|
||||
}
|
||||
}
|
||||
|
||||
// ========== 参考原有逻辑:构建字段映射(通过Excel注解匹配列名) ==========
|
||||
List<Object[]> fields = this.getFields();
|
||||
Map<Integer, Object[]> fieldsMap = new HashMap<Integer, Object[]>();
|
||||
for (Object[] objects : fields) {
|
||||
Excel attr = (Excel) objects[1];
|
||||
Integer column = cellMap.get(attr.name());
|
||||
if (column != null) {
|
||||
fieldsMap.put(column, objects);
|
||||
}
|
||||
}
|
||||
|
||||
// 找到「图片」列的下标(关键:和Excel模板的列名对应)
|
||||
Integer imageColumnIndex = cellMap.get("图片");
|
||||
|
||||
// ========== 遍历数据行(参考原有逻辑) ==========
|
||||
for (int i = titleNum + 1; i <= rows; i++) {
|
||||
Row row = sheet.getRow(i);
|
||||
if (isRowEmpty(row)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
T entity = null;
|
||||
// 生成当前行的图片key:行号_图片列下标(i是数据行号,对应Excel的行)
|
||||
String imageCellKey = i + "_" + imageColumnIndex;
|
||||
|
||||
// ========== 参考原有逻辑:遍历字段映射赋值 ==========
|
||||
for (Map.Entry<Integer, Object[]> entry : fieldsMap.entrySet()) {
|
||||
Integer columnIndex = entry.getKey();
|
||||
Object val = this.getCellValue(row, columnIndex);
|
||||
|
||||
// 如果不存在实例则新建
|
||||
entity = (entity == null ? clazz.newInstance() : entity);
|
||||
|
||||
// 从map中得到对应列的field和Excel注解
|
||||
Field field = (Field) entry.getValue()[0];
|
||||
Excel attr = (Excel) entry.getValue()[1];
|
||||
|
||||
// ========== 关键修改:如果是「图片」列,替换值为图片key ==========
|
||||
if (imageColumnIndex != null && columnIndex.equals(imageColumnIndex)) {
|
||||
val = imageCellKey; // 将单元格原始值替换为图片key(如1_12)
|
||||
}
|
||||
|
||||
// ========== 原有类型转换逻辑(完全复用) ==========
|
||||
Class<?> fieldType = field.getType();
|
||||
if (String.class == fieldType) {
|
||||
String s = Convert.toStr(val);
|
||||
if (StringUtils.endsWith(s, ".0")) {
|
||||
val = StringUtils.substringBefore(s, ".0");
|
||||
} else {
|
||||
String dateFormat = field.getAnnotation(Excel.class).dateFormat();
|
||||
if (StringUtils.isNotEmpty(dateFormat)) {
|
||||
val = parseDateToStr(dateFormat, val);
|
||||
} else {
|
||||
val = Convert.toStr(val);
|
||||
}
|
||||
}
|
||||
} else if ((Integer.TYPE == fieldType || Integer.class == fieldType) && StringUtils.isNumeric(Convert.toStr(val))) {
|
||||
val = Convert.toInt(val);
|
||||
} else if ((Long.TYPE == fieldType || Long.class == fieldType) && StringUtils.isNumeric(Convert.toStr(val))) {
|
||||
val = Convert.toLong(val);
|
||||
} else if (Double.TYPE == fieldType || Double.class == fieldType) {
|
||||
val = Convert.toDouble(val);
|
||||
} else if (Float.TYPE == fieldType || Float.class == fieldType) {
|
||||
val = Convert.toFloat(val);
|
||||
} else if (BigDecimal.class == fieldType) {
|
||||
val = Convert.toBigDecimal(val);
|
||||
} else if (Date.class == fieldType) {
|
||||
if (val instanceof String) {
|
||||
val = DateUtils.parseDate(val);
|
||||
} else if (val instanceof Double) {
|
||||
val = DateUtil.getJavaDate((Double) val);
|
||||
}
|
||||
} else if (Boolean.TYPE == fieldType || Boolean.class == fieldType) {
|
||||
val = Convert.toBool(val, false);
|
||||
}
|
||||
|
||||
// ========== 原有反射赋值逻辑(完全复用) ==========
|
||||
if (StringUtils.isNotNull(fieldType)) {
|
||||
String propertyName = field.getName();
|
||||
if (StringUtils.isNotEmpty(attr.targetAttr())) {
|
||||
propertyName = field.getName() + "." + attr.targetAttr();
|
||||
} else if (StringUtils.isNotEmpty(attr.readConverterExp())) {
|
||||
val = reverseByExp(Convert.toStr(val), attr.readConverterExp(), attr.separator());
|
||||
} else if (!attr.handler().equals(ExcelHandlerAdapter.class)) {
|
||||
val = dataFormatHandlerAdapter(val, attr);
|
||||
}
|
||||
// 使用原有工具类反射赋值(核心:替换自定义setEntityFieldValue)
|
||||
ReflectUtils.invokeSetter(entity, propertyName, val);
|
||||
}
|
||||
}
|
||||
|
||||
if (entity != null) {
|
||||
list.add(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import com.microservices.common.core.web.domain.AjaxResult;
|
|||
import com.microservices.common.core.web.page.TableDataInfo;
|
||||
import com.microservices.common.log.annotation.Log;
|
||||
import com.microservices.common.log.enums.BusinessType;
|
||||
import com.microservices.common.security.utils.SecurityUtils;
|
||||
import com.microservices.dms.achievementLibrary.domain.SchoolEnterpriseAchievements;
|
||||
import com.microservices.dms.achievementLibrary.service.ISchoolEnterpriseAchievementsService;
|
||||
import io.swagger.annotations.Api;
|
||||
|
|
@ -15,9 +16,11 @@ import io.swagger.annotations.ApiImplicitParams;
|
|||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 校企成果Controller
|
||||
|
|
@ -90,6 +93,21 @@ public class SchoolEnterpriseAchievementsController extends BaseController
|
|||
return AjaxResult.success(schoolEnterpriseAchievementsService.insertSchoolEnterpriseAchievements(schoolEnterpriseAchievements));
|
||||
}
|
||||
|
||||
@PostMapping("/importData")
|
||||
@Log(title = "校企成果", businessType = BusinessType.INSERT)
|
||||
public AjaxResult importData(@RequestPart("file") MultipartFile file,
|
||||
@RequestParam(value = "updateSupport", defaultValue = "false") boolean updateSupport) throws Exception {
|
||||
ExcelUtil<SchoolEnterpriseAchievements> util = new ExcelUtil<>(SchoolEnterpriseAchievements.class);
|
||||
// 1. 解析Excel,获取实体列表和图片Map
|
||||
List<SchoolEnterpriseAchievements> list = util.importExcelWithImages(StringUtils.EMPTY, file.getInputStream(), 0);
|
||||
Map<String, MultipartFile> imageMap = util.getExcelImageMap();
|
||||
// 2. 调用业务层处理(传入实体列表和图片Map)
|
||||
String operName = SecurityUtils.getUsername();
|
||||
String message = schoolEnterpriseAchievementsService.batchInsertSchoolEnterpriseAchievements(list, imageMap, updateSupport, operName);
|
||||
|
||||
return AjaxResult.success(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改校企成果
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -167,7 +167,7 @@ public class Achievements extends BaseEntity {
|
|||
/**
|
||||
* 成果图片
|
||||
*/
|
||||
@Excel(name = "成果图片")
|
||||
@Excel(name = "图片")
|
||||
private String images;
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -32,7 +32,10 @@ public class SchoolEnterpriseAchievements extends BaseEntity {
|
|||
/**
|
||||
* 成果领域1
|
||||
*/
|
||||
@Excel(name = "成果领域1")
|
||||
@Excel(
|
||||
name = "成果领域",
|
||||
readConverterExp = "1=理论研究,2=政策法规,3=医学,4=电子信息,5=通信工程,6=计算机科学,7=软件工程,9=人工智能,10=知识图谱,12=大数据,23=机器人,24=无人系统,25=创意征集,26=文献翻译,27=成果转化,28=科技协同,29=科研组织模式,30=新兴领域,31=其他,32=电子元器件,33=测试仪器,34=军事历史,35=计算机网络"
|
||||
)
|
||||
private String field1;
|
||||
|
||||
/**
|
||||
|
|
@ -50,7 +53,7 @@ public class SchoolEnterpriseAchievements extends BaseEntity {
|
|||
/**
|
||||
* 成果类型
|
||||
*/
|
||||
@Excel(name = "成果类型")
|
||||
@Excel(name = "成果类型", readConverterExp = "1=理论成果,2=技术成果,3=应用成果,4=软科学成果,5=文化艺术成果,6=社会服务成果,7=交叉领域成果")
|
||||
private String achievementType;
|
||||
|
||||
/**
|
||||
|
|
@ -74,7 +77,10 @@ public class SchoolEnterpriseAchievements extends BaseEntity {
|
|||
/**
|
||||
* 成果标签
|
||||
*/
|
||||
@Excel(name = "成果标签")
|
||||
@Excel(
|
||||
name = "成果标签",
|
||||
readConverterExp = "1=高校,2=企业,3=其他"
|
||||
)
|
||||
private String tags;
|
||||
|
||||
/**
|
||||
|
|
@ -159,7 +165,7 @@ public class SchoolEnterpriseAchievements extends BaseEntity {
|
|||
/**
|
||||
* 成果图片
|
||||
*/
|
||||
@Excel(name = "成果图片")
|
||||
@Excel(name = "图片")
|
||||
private String images;
|
||||
|
||||
/**
|
||||
|
|
@ -169,8 +175,15 @@ public class SchoolEnterpriseAchievements extends BaseEntity {
|
|||
private String attachments;
|
||||
private Integer achievementStatus;
|
||||
//成果小类型
|
||||
@Excel(
|
||||
name = "成果小类型",
|
||||
readConverterExp = "7=学术论文,8=学术专著,9=理论模型,10=发明专利,11=技术标准,12=软件系统,13=技术原型,14=产品设备,15=解决方案,16=示范工程,17=政策建议,18=咨询报告,19=行业标准,20=管理办法,21=文学作品,22=艺术作品,23=公益项目,24=社会调查报告,25=教育培训成果,26=理论模型+产品设备,27=学术论文+技术原型"
|
||||
)
|
||||
private String achievementLittleType;
|
||||
//成果状态
|
||||
@Excel(
|
||||
name = "成果状态",
|
||||
readConverterExp = "1=已有阶段性成果,2=已有成熟成果,3=已公开发表,4=已对外发布,5=已开展应用,6=已形成商业化产品"
|
||||
)
|
||||
private String achievementCurStatus;
|
||||
//团队名称
|
||||
private String teamName;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
package com.microservices.dms.achievementLibrary.service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.microservices.dms.achievementLibrary.domain.SchoolEnterpriseAchievements;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
/**
|
||||
* 校企成果Service接口
|
||||
|
|
@ -64,4 +67,6 @@ public interface ISchoolEnterpriseAchievementsService
|
|||
List<SchoolEnterpriseAchievements> listFront(SchoolEnterpriseAchievements schoolEnterpriseAchievements);
|
||||
|
||||
boolean getCheckSchoolAchName(SchoolEnterpriseAchievements schoolEnterpriseAchievements);
|
||||
|
||||
String batchInsertSchoolEnterpriseAchievements(List<SchoolEnterpriseAchievements> list, Map<String, MultipartFile> imageMap, boolean updateSupport, String operName);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,25 +1,34 @@
|
|||
package com.microservices.dms.achievementLibrary.service.impl;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.microservices.common.core.constant.SecurityConstants;
|
||||
import com.microservices.common.core.constant.UserConstants;
|
||||
import com.microservices.common.core.domain.R;
|
||||
import com.microservices.common.core.exception.ServiceException;
|
||||
import com.microservices.common.core.utils.DateUtils;
|
||||
import com.microservices.common.core.utils.StringUtils;
|
||||
import com.microservices.common.datasource.annotation.Slave;
|
||||
import com.microservices.common.security.utils.SecurityUtils;
|
||||
import com.microservices.dms.achievementLibrary.domain.AchievementTeam;
|
||||
import com.microservices.dms.achievementLibrary.domain.Achievements;
|
||||
import com.microservices.dms.achievementLibrary.mapper.AchievementTeamMapper;
|
||||
import com.microservices.dms.achievementLibrary.mapper.AchievementsMapper;
|
||||
import com.microservices.dms.achievementLibrary.service.IAchievementsService;
|
||||
import com.microservices.system.api.domain.SysUser;
|
||||
import com.microservices.system.api.RemoteFileService;
|
||||
import com.microservices.system.api.model.LoginUser;
|
||||
import org.apache.commons.fileupload.FileItem;
|
||||
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.microservices.dms.achievementLibrary.mapper.SchoolEnterpriseAchievementsMapper;
|
||||
import com.microservices.dms.achievementLibrary.domain.SchoolEnterpriseAchievements;
|
||||
import com.microservices.dms.achievementLibrary.service.ISchoolEnterpriseAchievementsService;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import org.springframework.web.multipart.commons.CommonsMultipartFile;
|
||||
|
||||
/**
|
||||
* 校企成果Service业务层处理
|
||||
|
|
@ -41,6 +50,9 @@ public class SchoolEnterpriseAchievementsServiceImpl implements ISchoolEnterpris
|
|||
@Autowired
|
||||
private AchievementsMapper achievementsMapper;
|
||||
|
||||
@Autowired
|
||||
private RemoteFileService remoteFileService;
|
||||
|
||||
/**
|
||||
* 查询校企成果
|
||||
*
|
||||
|
|
@ -124,6 +136,144 @@ public class SchoolEnterpriseAchievementsServiceImpl implements ISchoolEnterpris
|
|||
return UserConstants.UNIQUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入成果数据(包含图片处理)
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
@Slave
|
||||
public String batchInsertSchoolEnterpriseAchievements(List<SchoolEnterpriseAchievements> list,
|
||||
Map<String, MultipartFile> imageMap,
|
||||
boolean updateSupport,
|
||||
String operName) {
|
||||
if (list == null || list.isEmpty()) {
|
||||
throw new RuntimeException("导入成果数据不能为空!");
|
||||
}
|
||||
int successNum = 0;
|
||||
int failureNum = 0;
|
||||
int imageErrorNum = 0; // 新增:图片处理失败数
|
||||
StringBuilder successMsg = new StringBuilder();
|
||||
StringBuilder failureMsg = new StringBuilder();
|
||||
StringBuilder imageErrorMsg = new StringBuilder(); // 新增:图片错误信息
|
||||
|
||||
for (SchoolEnterpriseAchievements schoolEnterpriseAchievement : list) {
|
||||
try {
|
||||
// 处理图片字段(优化后:返回处理结果,不抛出异常)
|
||||
String imageHandleResult = handleAchievementImage(schoolEnterpriseAchievement, imageMap);
|
||||
if (imageHandleResult.contains("失败") || imageHandleResult.contains("异常")) {
|
||||
imageErrorNum++;
|
||||
imageErrorMsg.append("<br/>").append(imageErrorNum).append("、成果 ").append(schoolEnterpriseAchievement.getAchievementName()).append(" 图片处理失败:").append(imageHandleResult);
|
||||
}
|
||||
|
||||
// 原有查重和入库逻辑(不受图片处理影响)
|
||||
SchoolEnterpriseAchievements exist = schoolEnterpriseAchievementsMapper.selectSchoolEnterpriseAchievementsByName(schoolEnterpriseAchievement.getAchievementName());
|
||||
if (exist == null) {
|
||||
schoolEnterpriseAchievement.setCreateBy(operName);
|
||||
schoolEnterpriseAchievement.setCreateTime(new Date());
|
||||
schoolEnterpriseAchievement.setUpdateBy(operName);
|
||||
schoolEnterpriseAchievement.setUpdateTime(new Date());
|
||||
schoolEnterpriseAchievement.setStatus("0");
|
||||
schoolEnterpriseAchievement.setAchievementStatus(0);
|
||||
schoolEnterpriseAchievementsMapper.insertSchoolEnterpriseAchievements(schoolEnterpriseAchievement);
|
||||
successNum++;
|
||||
successMsg.append("<br/>").append(successNum).append("、成果 ").append(schoolEnterpriseAchievement.getAchievementName()).append(" 导入成功");
|
||||
} else {
|
||||
if (updateSupport) {
|
||||
schoolEnterpriseAchievement.setId(exist.getId());
|
||||
schoolEnterpriseAchievement.setCreateBy(exist.getCreateBy());
|
||||
schoolEnterpriseAchievement.setCreateTime(exist.getCreateTime());
|
||||
schoolEnterpriseAchievement.setUpdateBy(operName);
|
||||
schoolEnterpriseAchievement.setUpdateTime(new Date());
|
||||
schoolEnterpriseAchievementsMapper.updateSchoolEnterpriseAchievements(schoolEnterpriseAchievement);
|
||||
successNum++;
|
||||
successMsg.append("<br/>").append(successNum).append("、成果 ").append(schoolEnterpriseAchievement.getAchievementName()).append(" 更新成功");
|
||||
} else {
|
||||
failureNum++;
|
||||
failureMsg.append("<br/>").append(failureNum).append("、成果 ").append(schoolEnterpriseAchievement.getAchievementName()).append(" 已存在(未开启更新)");
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
failureNum++;
|
||||
String msg = "<br/>" + failureNum + "、成果 " + schoolEnterpriseAchievement.getAchievementName() + " 导入失败:";
|
||||
failureMsg.append(msg).append(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// 组装最终提示信息(包含图片处理错误)
|
||||
StringBuilder finalMsg = new StringBuilder();
|
||||
if (successNum > 0) {
|
||||
finalMsg.append("共 ").append(successNum).append(" 条数据导入/更新成功:").append(successMsg);
|
||||
}
|
||||
if (failureNum > 0) {
|
||||
finalMsg.append("<br/>共 ").append(failureNum).append(" 条数据导入失败:").append(failureMsg);
|
||||
}
|
||||
if (imageErrorNum > 0) {
|
||||
finalMsg.append("<br/>共 ").append(imageErrorNum).append(" 条数据图片处理失败:").append(imageErrorMsg);
|
||||
}
|
||||
|
||||
return finalMsg.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理成果图片:上传并格式化存储(FastJSON解析版)
|
||||
* @param achievement 成果实体
|
||||
* @param imageMap Excel解析出的图片映射表
|
||||
* @return 图片处理结果提示(成功/失败信息)
|
||||
*/
|
||||
private String handleAchievementImage(SchoolEnterpriseAchievements achievement, Map<String, MultipartFile> imageMap) {
|
||||
String imageCellKey = achievement.getImages();
|
||||
if (StringUtils.isEmpty(imageCellKey) || !imageMap.containsKey(imageCellKey)) {
|
||||
return "无图片,跳过处理";
|
||||
}
|
||||
|
||||
try {
|
||||
MultipartFile file = imageMap.get(imageCellKey);
|
||||
byte[] fileBytes = file.getBytes();
|
||||
|
||||
if (fileBytes == null || fileBytes.length == 0) {
|
||||
return "图片文件为空,跳过处理";
|
||||
}
|
||||
|
||||
// 构建 HashMap 参数
|
||||
String originalFilename = StringUtils.isEmpty(file.getOriginalFilename())
|
||||
? "excel_import_image_" + System.currentTimeMillis() + ".png"
|
||||
: file.getOriginalFilename();
|
||||
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("base64Data", Base64.getEncoder().encodeToString(fileBytes));
|
||||
params.put("fileName", originalFilename);
|
||||
params.put("contentType", file.getContentType());
|
||||
params.put("size", fileBytes.length);
|
||||
|
||||
// 调用 Base64 上传接口
|
||||
R<?> fileResult = remoteFileService.uploadBase64(params, "dms", "import", SecurityConstants.INNER);
|
||||
|
||||
// 解析结果(与原逻辑相同)
|
||||
if (StringUtils.isNull(fileResult) || StringUtils.isNull(fileResult.getData())) {
|
||||
String errorMsg = !StringUtils.isNull(fileResult) ? fileResult.getMsg() : "接口返回异常";
|
||||
return "图片上传失败:" + errorMsg;
|
||||
}
|
||||
|
||||
JSONObject resultJson = JSONObject.parseObject(JSONObject.toJSONString(fileResult.getData()));
|
||||
String fileOriginName = resultJson.getString("fileOriginName");
|
||||
String url = resultJson.getString("downloadUrl");
|
||||
Integer fileId = resultJson.getInteger("fileId");
|
||||
|
||||
if (StringUtils.isEmpty(fileOriginName) || StringUtils.isEmpty(url) || fileId == null) {
|
||||
return "图片上传成功,但返回数据不完整";
|
||||
}
|
||||
|
||||
String imageJson = String.format("[{\"k\":\"%s\",\"v\":\"%s\",\"id\":%d}]",
|
||||
fileOriginName, url, fileId);
|
||||
achievement.setImages(imageJson);
|
||||
|
||||
return "图片处理成功";
|
||||
|
||||
} catch (Exception e) {
|
||||
return "图片处理异常:" + e.getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 修改校企成果
|
||||
|
|
|
|||
|
|
@ -1,20 +1,26 @@
|
|||
package com.microservices.file.controller;
|
||||
|
||||
import com.microservices.common.core.domain.R;
|
||||
import com.microservices.common.core.utils.StringUtils;
|
||||
import com.microservices.common.core.web.controller.BaseController;
|
||||
import com.microservices.common.security.annotation.InnerAuth;
|
||||
import com.microservices.file.service.ISysFileInfoService;
|
||||
import com.microservices.system.api.domain.SysFile;
|
||||
import com.microservices.system.api.domain.SysFileInfo;
|
||||
import com.microservices.system.api.utils.StandardMultipartFile;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import springfox.documentation.annotations.ApiIgnore;
|
||||
|
||||
import java.util.Base64;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 文件请求处理
|
||||
*
|
||||
|
|
@ -49,4 +55,56 @@ public class SysFileController extends BaseController {
|
|||
return R.fail(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@InnerAuth
|
||||
@PostMapping("/upload/base64")
|
||||
public R<SysFileInfo> uploadBase64(@RequestBody Map<String, Object> params,
|
||||
@RequestParam("type") String type,
|
||||
@RequestParam("hierarchy") String hierarchy) {
|
||||
try {
|
||||
// 1. 提取参数
|
||||
String base64Data = (String) params.get("base64Data");
|
||||
String fileName = (String) params.get("fileName");
|
||||
String contentType = (String) params.get("contentType");
|
||||
|
||||
// 2. 参数校验
|
||||
if (StringUtils.isEmpty(base64Data)) {
|
||||
return R.fail("base64Data不能为空");
|
||||
}
|
||||
|
||||
// 3. Base64解码
|
||||
byte[] fileBytes;
|
||||
try {
|
||||
fileBytes = Base64.getDecoder().decode(base64Data);
|
||||
} catch (IllegalArgumentException e) {
|
||||
log.error("Base64解码失败", e);
|
||||
return R.fail("图片数据格式错误");
|
||||
}
|
||||
|
||||
if (fileBytes.length == 0) {
|
||||
return R.fail("解码后文件为空");
|
||||
}
|
||||
|
||||
// 4. 构造MultipartFile
|
||||
String originalFilename = StringUtils.isEmpty(fileName)
|
||||
? "base64_image_" + System.currentTimeMillis() + ".png"
|
||||
: fileName;
|
||||
|
||||
MultipartFile multipartFile = new StandardMultipartFile(
|
||||
fileBytes,
|
||||
"file", // 字段名,与原接口一致
|
||||
originalFilename,
|
||||
contentType
|
||||
);
|
||||
|
||||
// 5. 复用原有上传逻辑
|
||||
SysFileInfo fileInfo = sysFileInfoService.upload(multipartFile, type, hierarchy);
|
||||
|
||||
return R.ok(fileInfo);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("Base64上传文件失败", e);
|
||||
return R.fail(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue