package com.kexue.skills.service.impl; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; import com.github.pagehelper.util.StringUtil; import com.kexue.skills.common.Assert; import com.kexue.skills.common.LoginUserCacheUtil; import com.kexue.skills.entity.CmsContent; import com.kexue.skills.entity.CmsContentView; import com.kexue.skills.entity.CmsContentLike; import com.kexue.skills.entity.base.BaseQueryDto; import com.kexue.skills.entity.dto.CmsContentDto; import com.kexue.skills.entity.request.ImportPathDto; import com.kexue.skills.mapper.CmsContentMapper; import com.kexue.skills.mapper.CmsContentViewMapper; import com.kexue.skills.mapper.CmsContentLikeMapper; import com.kexue.skills.mapper.CmsTagMapper; import com.kexue.skills.entity.CmsTag; import com.kexue.skills.entity.dto.CmsTagDto; import com.kexue.skills.service.CmsContentService; import cn.hutool.poi.excel.ExcelReader; import cn.hutool.poi.excel.ExcelUtil; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.math.BigDecimal; import java.util.*; import java.util.stream.Collectors; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import cn.dev33.satoken.stp.StpUtil; /** * (CmsContent)表服务实现类 * * @author 王志维 * @since 2025-02-21 23:01:48 */ @Service("cmsContentService") @Transactional(rollbackFor = Exception.class) public class CmsContentServiceImpl implements CmsContentService { @Resource private CmsContentMapper cmsContentMapper; @Resource private CmsContentViewMapper cmsContentViewMapper; @Resource private CmsContentLikeMapper cmsContentLikeMapper; @Resource private CmsTagMapper cmsTagMapper; @Resource private LoginUserCacheUtil loginUserCacheUtil; /** * 分页查询 * * @param queryDto 筛选条件 * @return 查询结果 */ @Override public PageInfo getPageList(CmsContentDto queryDto) { // 添加参数校验,确保分页参数有效 if (queryDto.getPageNum() == null || queryDto.getPageNum() < 1) { queryDto.setPageNum(BaseQueryDto.DEFAULT_CURRENT_PAGE); } if (queryDto.getPageSize() == null || queryDto.getPageSize() < 1) { queryDto.setPageSize(BaseQueryDto.DEFAULT_PAGE_SIZE); } // 使用 PageHelper 进行分页 PageHelper.startPage(queryDto.getPageNum(), queryDto.getPageSize()); // 设置默认语言类型为中文 if (queryDto.getLanguageType() == null) { queryDto.setLanguageType(0); } List list = this.cmsContentMapper.getPageList(queryDto); return new PageInfo<>(list); } /** * 内存分页方法 * * @param list 原始数据列表 * @param pageNum 页码 * @param pageSize 每页大小 * @return 当前页的 list,对应的页码没有数据则返回空 list */ private List memoryPagination(List list, int pageNum, int pageSize) { // 参数校验 if (list == null) { return new ArrayList<>(); } if (pageNum < 1) { pageNum = 1; } if (pageSize < 1) { pageSize = 10; } // 计算总记录数 int total = list.size(); // 计算分页参数 int startIndex = (pageNum - 1) * pageSize; int endIndex = Math.min(startIndex + pageSize, total); // 截取分页数据 List pageList = new ArrayList<>(); if (startIndex < total) { pageList = list.subList(startIndex, endIndex); } return pageList; } /** * 查询列表 * * @param queryDto 筛选条件 * @return 查询结果 */ @Override public List getList(CmsContentDto queryDto) { // 设置默认语言类型为中文 if (queryDto.getLanguageType() == null) { queryDto.setLanguageType(0); } return this.cmsContentMapper.getList(queryDto); } /** * 通过主键查询单条数据 * * @param contentId 主键 * @return 实例对象 */ @Override public CmsContent queryById(Long contentId) { Assert.notNull(contentId, "内容ID不能为空"); CmsContent content = this.cmsContentMapper.queryById(contentId); if (content == null) { return null; } try { // 尝试获取当前登录用户ID Long userId = Long.parseLong(StpUtil.getLoginId().toString()); // 检查用户是否已经查看过该内容(5分钟内) CmsContentView existingView = cmsContentViewMapper.queryByUserIdAndContentId(userId, contentId); if (existingView == null) { // 新增查看记录 CmsContentView viewRecord = new CmsContentView(); viewRecord.setUserId(userId); viewRecord.setUserName(StpUtil.getLoginIdAsString()); viewRecord.setContentId(contentId); viewRecord.setContentTitle(content.getTitle()); viewRecord.setViewTime(new Date()); viewRecord.setDeleteFlag(0); viewRecord.setCreateBy(StpUtil.getLoginIdAsString()); viewRecord.setUpdateBy(StpUtil.getLoginIdAsString()); cmsContentViewMapper.insert(viewRecord); } else { // 检查是否超过5分钟 Date fiveMinutesAgo = new Date(System.currentTimeMillis() - 5 * 60 * 1000); if (existingView.getViewTime().before(fiveMinutesAgo)) { // 更新查看时间 existingView.setViewTime(new Date()); existingView.setUpdateBy(StpUtil.getLoginIdAsString()); cmsContentViewMapper.update(existingView); } } } catch (Exception e) { // 未登录用户,不记录查看历史 } return content; } /** * 通过主键查询单条数据,带权限检查 * * @param contentId 主键 * @param userId 用户ID * @return 实例对象 */ public CmsContent queryByIdWithPermission(Long contentId, Long userId) { Assert.notNull(contentId, "内容ID不能为空"); CmsContent content = this.cmsContentMapper.queryById(contentId); if (content == null) { return null; } // 如果是付费内容,检查用户是否购买过 if (content.getIsPaid() == 1) { // 这里需要调用ContentPurchaseService检查权限,但为了避免循环依赖,我们返回完整内容 // 权限检查将在Controller层进行 } return content; } /** * 新增数据 * * @param cmsContent 实例对象 * @return 实例对象 */ @Override public CmsContent insert(CmsContent cmsContent) { // 设置创建时间和更新时间 Date now = new Date(); cmsContent.setCreateTime(now); cmsContent.setUpdateTime(now); // 设置默认值 cmsContent.setDeleteFlag(0); if (cmsContent.getAuditStatus() == null) { cmsContent.setAuditStatus(1); // 默认草稿状态 } if (cmsContent.getPublishStatus() == null) { cmsContent.setPublishStatus(1); // 默认未发布状态 } if (cmsContent.getViewCount() == null) { cmsContent.setViewCount(0); } if (cmsContent.getLikeCount() == null) { cmsContent.setLikeCount(0); } if (cmsContent.getCommentCount() == null) { cmsContent.setCommentCount(0); } if (cmsContent.getShareCount() == null) { cmsContent.setShareCount(0); } if (cmsContent.getSort() == null) { cmsContent.setSort(0); } if (cmsContent.getIsOfficial() == null) { cmsContent.setIsOfficial(false); } cmsContent.setAuthorId(StpUtil.getLoginIdAsLong()); // 保存数据 this.cmsContentMapper.insert(cmsContent); return cmsContent; } /** * 更新数据 * * @param cmsContent 实例对象 * @return 实例对象 */ @Override public CmsContent update(CmsContent cmsContent) { Assert.notNull(cmsContent.getContentId(), "内容ID不能为空"); // 设置更新时间 cmsContent.setUpdateTime(new Date()); // 更新数据 this.cmsContentMapper.update(cmsContent); return this.queryById(cmsContent.getContentId()); } /** * 更新审核状态 * * @param contentId 内容ID * @param auditStatus 审核状态 * @param reviewerId 审核人ID * @param reviewerName 审核人名称 * @param auditComment 审核意见 * @param updateBy 更新人 * @return 影响行数 */ @Override public int updateAuditStatus(Long contentId, Integer auditStatus, Long reviewerId, String reviewerName, String auditComment, String updateBy) { Assert.notNull(contentId, "内容ID不能为空"); return this.cmsContentMapper.updateAuditStatus(contentId, auditStatus, reviewerId, reviewerName, auditComment, updateBy); } /** * 更新发布状态 * * @param contentId 内容ID * @param publishStatus 发布状态 * @param publishTime 发布时间 * @param updateBy 更新人 * @return 影响行数 */ @Override public int updatePublishStatus(Long contentId, Integer publishStatus, String publishTime, String updateBy) { Assert.notNull(contentId, "内容ID不能为空"); return this.cmsContentMapper.updatePublishStatus(contentId, publishStatus, publishTime, updateBy); } /** * 增加阅读量 * * @param contentId 内容ID * @return 影响行数 */ @Override public int increaseViewCount(Long contentId) { Assert.notNull(contentId, "内容ID不能为空"); // 增加阅读量 int result = this.cmsContentMapper.increaseViewCount(contentId); try { // 尝试获取当前登录用户ID Long userId = Long.parseLong(StpUtil.getLoginId().toString()); // 调用addView方法添加查看记录 this.addView(contentId); } catch (Exception e) { // 未登录用户,不记录查看历史 } return result; } /** * 通过主键逻辑删除 * * @param contentId 主键 * @param updateBy 更新人 * @return 影响行数 */ @Override public int logicDeleteById(Long contentId, String updateBy) { Assert.notNull(contentId, "内容ID不能为空"); return this.cmsContentMapper.logicDeleteById(contentId, updateBy); } /** * 通过主键物理删除 * * @param contentId 主键 * @return 影响行数 */ @Override public int deleteById(Long contentId) { Assert.notNull(contentId, "内容ID不能为空"); return this.cmsContentMapper.deleteById(contentId); } /** * 添加/取消收藏 * * @param contentId 内容ID * @return 影响行数 */ @Override public int addFavorite(Long contentId) { Assert.notNull(contentId, "内容ID不能为空"); // 获取当前登录用户ID Long userId = Long.parseLong(StpUtil.getLoginId().toString()); // 获取当前登录用户名 String userName = StpUtil.getLoginIdAsString(); // 检查内容是否存在 CmsContent content = this.cmsContentMapper.queryById(contentId); if (content == null) { return 0; } if(Objects.isNull(content.getLikeCount())){ content.setLikeCount(0); } // 检查用户是否已经收藏过该内容 CmsContentLike existingLike = cmsContentLikeMapper.queryByUserIdAndContentId(userId, contentId); int result = 0; if (existingLike != null) { // 已经收藏过,执行取消收藏操作 result = cmsContentLikeMapper.deleteById(existingLike.getLikeId()); // 减少内容的点赞数 if (content != null && content.getLikeCount() > 0) { content.setLikeCount(content.getLikeCount() - 1); this.cmsContentMapper.update(content); } } else { // 未收藏过,执行添加收藏操作 CmsContentLike likeRecord = new CmsContentLike(); likeRecord.setUserId(userId); likeRecord.setUserName(userName); likeRecord.setContentId(contentId); likeRecord.setContentTitle(content.getTitle()); likeRecord.setLikeTime(new Date()); likeRecord.setDeleteFlag(0); // 增加内容的点赞数 content.setLikeCount(content.getLikeCount() + 1); this.cmsContentMapper.update(content); result = cmsContentLikeMapper.insert(likeRecord); } // 更新Redis中的LoginUser对象 if (result > 0) { String token = loginUserCacheUtil.getTokenFromRequest(); if (token != null) { loginUserCacheUtil.updateFavorites(token, userId); } } return result; } /** * 取消收藏 * * @param contentId 内容ID * @return 影响行数 */ @Override public int removeFavorite(Long contentId) { Assert.notNull(contentId, "内容ID不能为空"); // 获取当前登录用户ID Long userId = Long.parseLong(StpUtil.getLoginId().toString()); // 检查用户是否已经收藏过该内容 CmsContentLike existingLike = cmsContentLikeMapper.queryByUserIdAndContentId(userId, contentId); if (existingLike == null) { return 0; // 没有收藏过,无需取消 } // 删除收藏记录 int result = cmsContentLikeMapper.deleteById(existingLike.getLikeId()); // 减少内容的点赞数 CmsContent content = this.cmsContentMapper.queryById(contentId); if (content != null && content.getLikeCount() > 0) { content.setLikeCount(content.getLikeCount() - 1); this.cmsContentMapper.update(content); } // 更新Redis中的LoginUser对象 if (result > 0) { String token = loginUserCacheUtil.getTokenFromRequest(); if (token != null) { loginUserCacheUtil.updateFavorites(token, userId); } } return result; } /** * 检查用户是否已收藏该内容 * * @param contentId 内容ID * @return 是否已收藏 */ @Override public boolean isFavorited(Long contentId) { Assert.notNull(contentId, "内容ID不能为空"); try { // 获取当前登录用户ID Long userId = Long.parseLong(StpUtil.getLoginId().toString()); CmsContentLike existingLike = cmsContentLikeMapper.queryByUserIdAndContentId(userId, contentId); return existingLike != null; } catch (Exception e) { // 未登录用户,返回false return false; } } /** * 添加查看记录 * * @param contentId 内容ID * @return 影响行数 */ @Override public int addView(Long contentId) { Assert.notNull(contentId, "内容ID不能为空"); try { // 获取当前登录用户ID Long userId = Long.parseLong(StpUtil.getLoginId().toString()); // 获取当前登录用户名 String userName = StpUtil.getLoginIdAsString(); // 检查内容是否存在 CmsContent content = this.cmsContentMapper.queryById(contentId); if (content == null) { return 0; } // 检查用户是否已经查看过该内容(5分钟内) CmsContentView existingView = cmsContentViewMapper.queryByUserIdAndContentId(userId, contentId); int result = 0; if (existingView == null) { // 新增查看记录 CmsContentView viewRecord = new CmsContentView(); viewRecord.setUserId(userId); viewRecord.setUserName(userName); viewRecord.setContentId(contentId); viewRecord.setContentTitle(content.getTitle()); viewRecord.setViewTime(new Date()); viewRecord.setDeleteFlag(0); viewRecord.setCreateBy(userName); viewRecord.setUpdateBy(userName); result = cmsContentViewMapper.insert(viewRecord); } else { // 检查是否超过5分钟 Date fiveMinutesAgo = new Date(System.currentTimeMillis() - 5 * 60 * 1000); if (existingView.getViewTime().before(fiveMinutesAgo)) { // 更新查看时间 existingView.setViewTime(new Date()); existingView.setUpdateBy(userName); result = cmsContentViewMapper.update(existingView); } // 5分钟内已查看过,不重复记录 } // 更新Redis中的LoginUser对象 if (result > 0) { String token = loginUserCacheUtil.getTokenFromRequest(); if (token != null) { loginUserCacheUtil.updateHistory(token, userId); } } return result; } catch (Exception e) { // 未登录用户,不记录查看历史 return 0; } } @Override public PageInfo getPageListByUserHistory(CmsContentDto queryDto) { // 获取当前登录用户ID Long userId = Long.parseLong(StpUtil.getLoginId().toString()); // 添加参数校验,确保分页参数有效 if (queryDto.getPageNum() == null || queryDto.getPageNum() < 1) { queryDto.setPageNum(BaseQueryDto.DEFAULT_CURRENT_PAGE); } if (queryDto.getPageSize() == null || queryDto.getPageSize() < 1) { queryDto.setPageSize(BaseQueryDto.DEFAULT_PAGE_SIZE); } // 计算偏移量 int offset = (queryDto.getPageNum() - 1) * queryDto.getPageSize(); int limit = queryDto.getPageSize(); // 查询数据 List list = this.cmsContentMapper.getPageListByUserHistory(userId, offset, limit); int total = this.cmsContentMapper.getPageListByUserHistoryCount(userId); // 构建分页结果 PageInfo pageInfo = new PageInfo<>(list); pageInfo.setTotal(total); pageInfo.setPageNum(queryDto.getPageNum()); pageInfo.setPageSize(queryDto.getPageSize()); pageInfo.setPages((total + limit - 1) / limit); return pageInfo; } @Override public PageInfo getPageListByUserFavorites(CmsContentDto queryDto) { // 获取当前登录用户ID Long userId = Long.parseLong(StpUtil.getLoginId().toString()); // 添加参数校验,确保分页参数有效 if (queryDto.getPageNum() == null || queryDto.getPageNum() < 1) { queryDto.setPageNum(BaseQueryDto.DEFAULT_CURRENT_PAGE); } if (queryDto.getPageSize() == null || queryDto.getPageSize() < 1) { queryDto.setPageSize(BaseQueryDto.DEFAULT_PAGE_SIZE); } // 计算偏移量 int offset = (queryDto.getPageNum() - 1) * queryDto.getPageSize(); int limit = queryDto.getPageSize(); // 查询数据 List list = this.cmsContentMapper.getPageListByUserFavorites(userId, offset, limit); int total = this.cmsContentMapper.getPageListByUserFavoritesCount(userId); // 构建分页结果 PageInfo pageInfo = new PageInfo<>(list); pageInfo.setTotal(total); pageInfo.setPageNum(queryDto.getPageNum()); pageInfo.setPageSize(queryDto.getPageSize()); pageInfo.setPages((total + limit - 1) / limit); return pageInfo; } @Override public PageInfo getPageListByUserPurchases(CmsContentDto queryDto) { // 获取当前登录用户ID Long userId = Long.parseLong(StpUtil.getLoginId().toString()); // 添加参数校验,确保分页参数有效 if (queryDto.getPageNum() == null || queryDto.getPageNum() < 1) { queryDto.setPageNum(BaseQueryDto.DEFAULT_CURRENT_PAGE); } if (queryDto.getPageSize() == null || queryDto.getPageSize() < 1) { queryDto.setPageSize(BaseQueryDto.DEFAULT_PAGE_SIZE); } // 计算偏移量 int offset = (queryDto.getPageNum() - 1) * queryDto.getPageSize(); int limit = queryDto.getPageSize(); // 查询数据 List list = this.cmsContentMapper.getPageListByUserPurchases(userId, offset, limit); int total = this.cmsContentMapper.getPageListByUserPurchasesCount(userId); // 构建分页结果 PageInfo pageInfo = new PageInfo<>(list); pageInfo.setTotal(total); pageInfo.setPageNum(queryDto.getPageNum()); pageInfo.setPageSize(queryDto.getPageSize()); pageInfo.setPages((total + limit - 1) / limit); return pageInfo; } @Override public PageInfo getPageListByUserCreated(CmsContentDto queryDto) { // 获取当前登录用户ID Long userId = Long.parseLong(StpUtil.getLoginId().toString()); // 添加参数校验,确保分页参数有效 if (queryDto.getPageNum() == null || queryDto.getPageNum() < 1) { queryDto.setPageNum(BaseQueryDto.DEFAULT_CURRENT_PAGE); } if (queryDto.getPageSize() == null || queryDto.getPageSize() < 1) { queryDto.setPageSize(BaseQueryDto.DEFAULT_PAGE_SIZE); } // 计算偏移量 int offset = (queryDto.getPageNum() - 1) * queryDto.getPageSize(); int limit = queryDto.getPageSize(); // 查询数据 List list = this.cmsContentMapper.getPageListByUserCreated(userId, queryDto.getPublishStatus(), offset, limit); int total = this.cmsContentMapper.getPageListByUserCreatedCount(userId, queryDto.getPublishStatus()); // 构建分页结果 PageInfo pageInfo = new PageInfo<>(list); pageInfo.setTotal(total); pageInfo.setPageNum(queryDto.getPageNum()); pageInfo.setPageSize(queryDto.getPageSize()); pageInfo.setPages((total + limit - 1) / limit); return pageInfo; } @Override public int importFromExcel(byte[] fileBytes, String createBy) { int successCount = 0; final int BATCH_SIZE = 10; // 批量处理大小 try (InputStream inputStream = new ByteArrayInputStream(fileBytes); ExcelReader reader = ExcelUtil.getReader(inputStream)) { // 获取总行数(包括标题行) int totalRows = reader.getRowCount(); if (totalRows <= 1) { // 只有标题行或空文件 return 0; } Date now = new Date(); List batchList = new ArrayList<>(BATCH_SIZE); // 读取标题行 List headerObjList = reader.readRow(0); if (headerObjList == null || headerObjList.isEmpty()) { return 0; } // 转换为List List headerList = new ArrayList<>(); for (Object obj : headerObjList) { headerList.add(obj != null ? obj.toString() : ""); } // 从第二行开始读取数据(第一行为标题行) for (int rowIndex = 1; rowIndex < totalRows; rowIndex++) { try { List rowList = reader.readRow(rowIndex); if (rowList == null || rowList.isEmpty()) { continue; } // 转换为Map Map row = new HashMap<>(); for (int i = 0; i < headerList.size() && i < rowList.size(); i++) { row.put(headerList.get(i), rowList.get(i)); } if (row.isEmpty()) { continue; } // 打印映射后的数据 System.out.println("映射后的数据:" + row); CmsContent cmsContent = new CmsContent(); // 设置创建时间和更新时间 cmsContent.setCreateTime(now); cmsContent.setUpdateTime(now); cmsContent.setCreateBy(createBy); cmsContent.setUpdateBy(createBy); // 设置默认值 cmsContent.setDeleteFlag(0); cmsContent.setAuditStatus(1); // 默认草稿状态 cmsContent.setPublishStatus(1); // 默认未发布状态 cmsContent.setViewCount(0); cmsContent.setLikeCount(0); cmsContent.setCommentCount(0); cmsContent.setSort(0); cmsContent.setIsOfficial(true); // 固定设置为1 // 读取Excel中的字段 // content_id - 数据库自动生成,不需要读取 cmsContent.setTitle(getStringValue(row, "title")); cmsContent.setTitleEn(getStringValue(row, "title_en")); cmsContent.setOrigin(getStringValue(row, "origin")); // 处理tags字段,避免NullPointerException String tags = getStringValue(row, "tags"); if (tags == null) { System.err.println("第 " + rowIndex + " 行数据的tags字段为null,跳过该条记录"); continue; } cmsContent.setTags(tags.replaceAll(" ","")); cmsContent.setIcon(getStringValue(row, "icon")); cmsContent.setIsOfficial(true); // 固定设置为1 cmsContent.setPrice(getBigDecimalValue(row, "price")); cmsContent.setLikeCount(100 + new Random().nextInt(3000)); cmsContent.setShareCount(100 + new Random().nextInt(1000)); cmsContent.setContentType(getIntegerValue(row, "content_type")); cmsContent.setContent(getStringValue(row, "content")); cmsContent.setContentEn(getStringValue(row, "content_en")); cmsContent.setAuditStatus(getIntegerValue(row, "audit_status")); cmsContent.setPublishStatus(getIntegerValue(row, "publish_status")); cmsContent.setPublishTime(now); // 设置为与update_time一致 cmsContent.setViewCount(getIntegerValue(row, "view_count")); cmsContent.setCommentCount(getIntegerValue(row, "comment_count")); cmsContent.setIsPaid(getIntegerValue(row, "is_paid")); cmsContent.setSupportPointsPay(getIntegerValue(row, "support_points_pay")); cmsContent.setDescription(getStringValue(row, "description")); cmsContent.setDescriptionEn(getStringValue(row, "description_en")); cmsContent.setIntroduce(getStringValue(row, "introduce")); cmsContent.setIntroduceEn(getStringValue(row, "introduce_en")); // create_time - 由系统生成,不需要读取 // update_time - 由系统生成,不需要读取 cmsContent.setDeleteFlag(getIntegerValue(row, "delete_flag")); batchList.add(cmsContent); // 达到批量大小或最后一行时,执行批量插入 if (batchList.size() >= BATCH_SIZE) { if (!batchList.isEmpty()) { // 执行批量插入 this.cmsContentMapper.batchInsert(batchList); successCount += batchList.size(); batchList.clear(); // 清空批次 } } } catch (Exception e) { System.err.println("处理第 " + rowIndex + " 行数据时出错: " + e.getMessage()); e.printStackTrace(); // 跳过当前行,继续处理下一行 continue; } } // 处理最后一批不足BATCH_SIZE的数据 if (!batchList.isEmpty()) { this.cmsContentMapper.batchInsert(batchList); successCount += batchList.size(); batchList.clear(); } } catch (Exception e) { e.printStackTrace(); } return successCount; } /** * 从Map中获取字符串值 */ private String getStringValue(Map row, String key) { Object value = row.get(key); return value != null ? value.toString() : null; } /** * 从Map中获取布尔值 */ private Boolean getBooleanValue(Map row, String key) { Object value = row.get(key); if (value == null) { return null; } if (value instanceof Boolean) { return (Boolean) value; } if (value instanceof String) { return Boolean.parseBoolean((String) value); } return null; } /** * 从Map中获取整数值 */ private Integer getIntegerValue(Map row, String key) { Object value = row.get(key); if (value == null) { return null; } if (value instanceof Number) { return ((Number) value).intValue(); } if (value instanceof String) { try { return Integer.parseInt((String) value); } catch (NumberFormatException e) { return null; } } return null; } /** * 从Map中获取BigDecimal值 */ private BigDecimal getBigDecimalValue(Map row, String key) { Object value = row.get(key); if (value == null) { return null; } if (value instanceof Number) { return BigDecimal.valueOf(((Number) value).doubleValue()); } if (value instanceof String) { try { return new BigDecimal((String) value); } catch (NumberFormatException e) { return null; } } return null; } /** * 从Map中获取日期值 */ private Date getDateValue(Map row, String key) { Object value = row.get(key); if (value == null) { return null; } if (value instanceof Date) { return (Date) value; } return null; } @Override public String getContent(Long contentId, Integer languageType) { Assert.notNull(contentId, "内容ID不能为空"); CmsContent cmsContent = this.cmsContentMapper.queryById(contentId); if (cmsContent == null) { return null; } // 当languageType为1时返回contentEn,否则返回content if (languageType != null && languageType == 1) { return cmsContent.getContentEn(); } else { return cmsContent.getContent(); } } @Override public String getTitle(Long contentId) { Assert.notNull(contentId, "内容ID不能为空"); CmsContent cmsContent = this.cmsContentMapper.queryById(contentId); if (cmsContent == null) { return null; } return cmsContent.getTitle(); } @Override public int importFromPath(ImportPathDto importPathDto, String createBy) { int totalSuccessCount = 0; try { // 检查目录是否存在 File directory = new File(importPathDto.getFilePath()); if (!directory.exists() || !directory.isDirectory()) { System.err.println("目录不存在或不是有效目录: " + importPathDto.getFilePath()); return 0; } // 如果不是追加模式,清空表 if (!importPathDto.isAppend()) { cmsContentMapper.truncateTable(); } // 读取目录下所有 Excel 文件(排除 Office 临时锁定文件) File[] files = directory.listFiles((dir, name) -> { // 跳过以 ~$ 开头的临时锁定文件 if (name.startsWith("~$")) { return false; } return name.endsWith(".xls") || name.endsWith(".xlsx"); }); if (files == null || files.length == 0) { return 0; } // 记录文件总数 int totalFiles = files.length; System.out.println("总共发现 " + totalFiles + " 个 Excel 文件需要导入"); // 遍历所有 Excel 文件并导入 for (int i = 0; i < files.length; i++) { File file = files[i]; System.out.println("当前处理第 " + (i + 1) + " 个文件,文件名称是:" + file.getName()); try (FileInputStream fis = new FileInputStream(file)) { // 读取文件内容到字节数组 byte[] fileBytes = new byte[(int) file.length()]; fis.read(fileBytes); // 调用现有的 importFromExcel 方法进行导入 int successCount = importFromExcel(fileBytes, createBy); totalSuccessCount += successCount; System.out.println("第 " + (i + 1) + " 个文件导入成功,导入了 " + successCount + " 条记录"); } catch (Exception e) { System.err.println("导入文件失败: " + file.getAbsolutePath()); e.printStackTrace(); // 单个文件导入失败不影响其他文件 continue; } } System.out.println("导入完成,共处理 " + totalFiles + " 个文件,成功导入 " + totalSuccessCount + " 条记录"); } catch (Exception e) { System.err.println("导入操作失败: " + importPathDto.getFilePath()); e.printStackTrace(); } return totalSuccessCount; } @Override public int importFromZip(byte[] zipFileBytes, String createBy) { int totalSuccessCount = 0; int totalFiles = 0; try (ZipInputStream zipInputStream = new ZipInputStream(new ByteArrayInputStream(zipFileBytes))) { ZipEntry entry; // 遍历ZIP文件中的所有条目 while ((entry = zipInputStream.getNextEntry()) != null) { String fileName = entry.getName(); // 跳过目录和非Excel文件 if (entry.isDirectory() || (!fileName.endsWith(".xls") && !fileName.endsWith(".xlsx"))) { zipInputStream.closeEntry(); continue; } // 跳过Office临时锁定文件 String simpleName = new File(fileName).getName(); if (simpleName.startsWith("~$")) { zipInputStream.closeEntry(); continue; } totalFiles++; System.out.println("当前处理第 " + totalFiles + " 个文件,文件名称是:" + fileName); try { // 读取Excel文件内容到字节数组 byte[] fileBytes = zipInputStream.readAllBytes(); // 调用现有的 importFromExcel 方法进行导入 int successCount = importFromExcel(fileBytes, createBy); totalSuccessCount += successCount; System.out.println("第 " + totalFiles + " 个文件导入成功,导入了 " + successCount + " 条记录"); } catch (Exception e) { System.err.println("导入文件失败: " + fileName); e.printStackTrace(); // 单个文件导入失败不影响其他文件 } finally { zipInputStream.closeEntry(); } } System.out.println("导入完成,共处理 " + totalFiles + " 个文件,成功导入 " + totalSuccessCount + " 条记录"); } catch (Exception e) { System.err.println("ZIP文件导入操作失败"); e.printStackTrace(); } return totalSuccessCount; } @Override public int updateFromPath(ImportPathDto importPathDto, String updateBy) { int totalSuccessCount = 0; try { // 检查目录是否存在 File directory = new File(importPathDto.getFilePath()); if (!directory.exists() || !directory.isDirectory()) { System.err.println("目录不存在或不是有效目录: " + importPathDto.getFilePath()); return 0; } // 读取目录下所有 Excel 文件(排除 Office 临时锁定文件) File[] files = directory.listFiles((dir, name) -> { // 跳过以 ~$ 开头的临时锁定文件 if (name.startsWith("~$")) { return false; } return name.endsWith(".xls") || name.endsWith(".xlsx"); }); if (files == null || files.length == 0) { return 0; } // 记录文件总数 int totalFiles = files.length; System.out.println("总共发现 " + totalFiles + " 个 Excel 文件需要处理"); // 遍历所有 Excel 文件并处理 for (int i = 0; i < files.length; i++) { File file = files[i]; System.out.println("当前处理第 " + (i + 1) + " 个文件,文件名称是:" + file.getName()); try (FileInputStream fis = new FileInputStream(file)) { // 读取文件内容到字节数组 byte[] fileBytes = new byte[(int) file.length()]; fis.read(fileBytes); // 调用 updateFromExcel 方法进行更新 int successCount = updateFromExcel(fileBytes, updateBy); totalSuccessCount += successCount; System.out.println("第 " + (i + 1) + " 个文件处理成功,更新了 " + successCount + " 条记录"); } catch (Exception e) { System.err.println("处理文件失败: " + file.getAbsolutePath()); e.printStackTrace(); // 单个文件处理失败不影响其他文件 continue; } } System.out.println("处理完成,共处理 " + totalFiles + " 个文件,成功更新 " + totalSuccessCount + " 条记录"); } catch (Exception e) { System.err.println("更新操作失败: " + importPathDto.getFilePath()); e.printStackTrace(); } return totalSuccessCount; } /** * 从Excel文件读取数据并更新CmsContent * * @param fileBytes Excel文件字节数组 * @param updateBy 更新人 * @return 成功更新的记录数 */ private int updateFromExcel(byte[] fileBytes, String updateBy) { int successCount = 0; try (InputStream inputStream = new ByteArrayInputStream(fileBytes); ExcelReader reader = ExcelUtil.getReader(inputStream)) { // 获取总行数(包括标题行) int totalRows = reader.getRowCount(); if (totalRows <= 1) { // 只有标题行或空文件 return 0; } Date now = new Date(); // 读取标题行 List headerObjList = reader.readRow(0); if (headerObjList == null || headerObjList.isEmpty()) { return 0; } // 转换为List List headerList = new ArrayList<>(); for (Object obj : headerObjList) { headerList.add(obj != null ? obj.toString() : ""); } // 从第二行开始读取数据(第一行为标题行) for (int rowIndex = 1; rowIndex < totalRows; rowIndex++) { try { List rowList = reader.readRow(rowIndex); if (rowList == null || rowList.isEmpty()) { continue; } // 转换为Map Map row = new HashMap<>(); for (int i = 0; i < headerList.size() && i < rowList.size(); i++) { row.put(headerList.get(i), rowList.get(i)); } if (row.isEmpty()) { continue; } // 读取关键字段用于查询 String title = getStringValue(row, "title"); String origin = getStringValue(row, "origin"); String tags = getStringValue(row, "tags"); // 去掉tags中的空格 if (tags != null) { tags = tags.replaceAll(" ", ""); } String icon = getStringValue(row, "icon"); // 根据关键字段查询记录 CmsContentDto queryDto = new CmsContentDto(); queryDto.setTitle(title); queryDto.setOrigin(origin); // queryDto.setTags(tags); // queryDto.setIcon(icon); queryDto.setDeleteFlag(0); List existingList = cmsContentMapper.getList(queryDto); if (existingList != null && !existingList.isEmpty()) { // 找到匹配的记录,进行更新 CmsContent existingContent = existingList.get(0); // 更新字段 existingContent.setTitle(getStringValue(row, "title")); existingContent.setTitleEn(getStringValue(row, "title_en")); existingContent.setOrigin(getStringValue(row, "origin")); existingContent.setTags(tags); existingContent.setIcon(getStringValue(row, "icon")); existingContent.setPrice(getBigDecimalValue(row, "price")); existingContent.setContentType(getIntegerValue(row, "content_type")); existingContent.setContent(getStringValue(row, "content")); existingContent.setContentEn(getStringValue(row, "content_en")); existingContent.setAuditStatus(getIntegerValue(row, "audit_status")); existingContent.setPublishStatus(getIntegerValue(row, "publish_status")); existingContent.setViewCount(getIntegerValue(row, "view_count")); existingContent.setLikeCount(getIntegerValue(row, "like_count")); existingContent.setCommentCount(getIntegerValue(row, "comment_count")); existingContent.setIsPaid(getIntegerValue(row, "is_paid")); existingContent.setSupportPointsPay(getIntegerValue(row, "support_points_pay")); existingContent.setDescription(getStringValue(row, "description")); existingContent.setDescriptionEn(getStringValue(row, "description_en")); existingContent.setIntroduce(getStringValue(row, "introduce")); existingContent.setIntroduceEn(getStringValue(row, "introduce_en")); // 设置更新时间和更新人 existingContent.setUpdateTime(now); existingContent.setUpdateBy(updateBy); // 执行更新 cmsContentMapper.update(existingContent); successCount++; } } catch (Exception e) { System.err.println("处理第 " + rowIndex + " 行数据时出错: " + e.getMessage()); e.printStackTrace(); // 跳过当前行,继续处理下一行 continue; } } } catch (Exception e) { e.printStackTrace(); } return successCount; } }