【新增】 wps_word相关方法(考点创建、文件对比等)
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
package pc.exam.pp.module.judgement.controller.admin.WpsWord;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import pc.exam.pp.framework.common.enums.CommonStatusEnum;
|
||||
import pc.exam.pp.framework.common.pojo.CommonResult;
|
||||
import pc.exam.pp.framework.common.util.object.BeanUtils;
|
||||
import pc.exam.pp.module.judgement.controller.admin.WpsWord.vo.WordListReqVO;
|
||||
import pc.exam.pp.module.judgement.controller.admin.WpsWord.vo.WordRespVO;
|
||||
import pc.exam.pp.module.judgement.controller.admin.WpsWord.vo.WordSaveReqVO;
|
||||
import pc.exam.pp.module.judgement.controller.admin.WpsWord.vo.WordSimpleRespVO;
|
||||
import pc.exam.pp.module.judgement.dal.dataobject.wpsword.WpsWordLinkDO;
|
||||
import pc.exam.pp.module.judgement.service.wps_word.WpsWordLinkService;
|
||||
import pc.exam.pp.module.system.controller.admin.dept.vo.dept.DeptListReqVO;
|
||||
import pc.exam.pp.module.system.controller.admin.dept.vo.dept.DeptRespVO;
|
||||
import pc.exam.pp.module.system.controller.admin.dept.vo.dept.DeptSaveReqVO;
|
||||
import pc.exam.pp.module.system.controller.admin.dept.vo.dept.DeptSimpleRespVO;
|
||||
import pc.exam.pp.module.system.dal.dataobject.dept.DeptDO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static pc.exam.pp.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - wps_word")
|
||||
@RestController
|
||||
@RequestMapping("/wps/word")
|
||||
@Validated
|
||||
public class WordController {
|
||||
|
||||
@Resource
|
||||
private WpsWordLinkService wpsWordLinkService;
|
||||
|
||||
@PostMapping("create")
|
||||
@Operation(summary = "创建wps_word")
|
||||
public CommonResult<Long> createWord(@Valid @RequestBody WordSaveReqVO createReqVO) {
|
||||
Long wordId = wpsWordLinkService.createWord(createReqVO);
|
||||
return success(wordId);
|
||||
}
|
||||
|
||||
@PutMapping("update")
|
||||
@Operation(summary = "更新wps_word")
|
||||
public CommonResult<Boolean> updateWord(@Valid @RequestBody WordSaveReqVO updateReqVO) {
|
||||
wpsWordLinkService.updateWord(updateReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("delete")
|
||||
@Operation(summary = "删除wps_word")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
public CommonResult<Boolean> deleteWord(@RequestParam("id") Long id) {
|
||||
wpsWordLinkService.deleteWord(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "获取wps_word列表")
|
||||
public CommonResult<List<WordRespVO>> getWordList(WordListReqVO reqVO) {
|
||||
List<WpsWordLinkDO> list = wpsWordLinkService.getWordList(reqVO);
|
||||
return success(BeanUtils.toBean(list, WordRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping(value = {"/list-all-simple", "/simple-list"})
|
||||
@Operation(summary = "获取wps_word精简信息列表", description = "只包含被开启的wps_word,主要用于前端的下拉选项")
|
||||
public CommonResult<List<WordSimpleRespVO>> getSimpleWordList() {
|
||||
List<WpsWordLinkDO> list = wpsWordLinkService.getWordList(
|
||||
new WordListReqVO().setStatus(CommonStatusEnum.ENABLE.getStatus()));
|
||||
return success(BeanUtils.toBean(list, WordSimpleRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得wps_word信息")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
public CommonResult<WordRespVO> getDept(@RequestParam("id") Long id) {
|
||||
WpsWordLinkDO word = wpsWordLinkService.getWord(id);
|
||||
return success(BeanUtils.toBean(word, WordRespVO.class));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package pc.exam.pp.module.judgement.controller.admin.WpsWord;
|
||||
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import pc.exam.pp.framework.common.pojo.CommonResult;
|
||||
import pc.exam.pp.module.judgement.service.wps_word.JudgementWpsWordService;
|
||||
import pc.exam.pp.module.judgement.utils.wps_word.vo.WordVO;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* wps word
|
||||
* rwb
|
||||
*/
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/tool/wps_word")
|
||||
@Tag( name = "WPSWORD")
|
||||
@Validated
|
||||
public class WpsWordController {
|
||||
|
||||
@Autowired
|
||||
private JudgementWpsWordService judgementWpsWordService;
|
||||
|
||||
/**
|
||||
* wps word
|
||||
* @return 判分
|
||||
*/
|
||||
@GetMapping("/run_wps_word")
|
||||
public CommonResult<List<WordVO>> run_wps_word() throws Exception {
|
||||
return CommonResult.success(judgementWpsWordService.ProgrammingWpsWord("1"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package pc.exam.pp.module.judgement.controller.admin.WpsWord.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - WpsWord对应关系 Request VO")
|
||||
@Data
|
||||
public class WordListReqVO {
|
||||
|
||||
@Schema(description = "节点名称模糊匹配", example = "芋道")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "展示状态,参见 CommonStatusEnum 枚举类", example = "1")
|
||||
private Integer status;
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
private Integer type;
|
||||
|
||||
private Integer belongTo;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package pc.exam.pp.module.judgement.controller.admin.WpsWord.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - 节点信息 Response VO")
|
||||
@Data
|
||||
public class WordRespVO {
|
||||
|
||||
@Schema(description = "节点编号", example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "节点名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "父节点 ID", example = "1024")
|
||||
private Long parentId;
|
||||
|
||||
@Schema(description = "显示顺序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Integer sort;
|
||||
|
||||
@Schema(description = "节点方法")
|
||||
private String nodeFunction;
|
||||
|
||||
@Schema(description = "转中文")
|
||||
private String toChinese;
|
||||
|
||||
@Schema(description = "状态,见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "时间戳格式")
|
||||
private LocalDateTime createTime;
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
private Integer type;
|
||||
private Integer belongTo;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package pc.exam.pp.module.judgement.controller.admin.WpsWord.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.Email;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
import pc.exam.pp.framework.common.enums.CommonStatusEnum;
|
||||
import pc.exam.pp.framework.common.validation.InEnum;
|
||||
|
||||
@Schema(description = "管理后台 - 节点创建/修改 Request VO")
|
||||
@Data
|
||||
public class WordSaveReqVO {
|
||||
|
||||
@Schema(description = "节点编号", example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "节点名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道")
|
||||
@NotBlank(message = "节点名称不能为空")
|
||||
@Size(max = 30, message = "节点名称长度不能超过 30 个字符")
|
||||
private String name;
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
private Integer type;
|
||||
private Integer belongTo;
|
||||
|
||||
@Schema(description = "父节点 ID", example = "1024")
|
||||
private Long parentId;
|
||||
|
||||
@Schema(description = "显示顺序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
@NotNull(message = "显示顺序不能为空")
|
||||
private Integer sort;
|
||||
|
||||
@Schema(description = "节点方法")
|
||||
private String nodeFunction;
|
||||
|
||||
@Schema(description = "转中文")
|
||||
private String toChinese;
|
||||
|
||||
@Schema(description = "状态,见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "状态不能为空")
|
||||
@InEnum(value = CommonStatusEnum.class, message = "修改状态必须是 {value}")
|
||||
private Integer status;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package pc.exam.pp.module.judgement.controller.admin.WpsWord.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Schema(description = "管理后台 - 节点精简信息 Response VO")
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class WordSimpleRespVO {
|
||||
|
||||
@Schema(description = "节点编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "节点名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "父节点 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long parentId;
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
private Integer type;
|
||||
private Integer belongTo;
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package pc.exam.pp.module.judgement.dal.dataobject.wpsword;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import pc.exam.pp.framework.common.enums.CommonStatusEnum;
|
||||
import pc.exam.pp.framework.tenant.core.db.TenantBaseDO;
|
||||
import pc.exam.pp.module.judgement.utils.tree.vo.TreeVO;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* wps word关系对应表
|
||||
*
|
||||
*/
|
||||
@TableName("wps_word_link")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class WpsWordLinkDO extends TenantBaseDO {
|
||||
|
||||
public static final Long PARENT_ID_ROOT = 0L;
|
||||
|
||||
/**
|
||||
* 部门ID
|
||||
*/
|
||||
@TableId
|
||||
private Long id;
|
||||
/**
|
||||
* 部门名称
|
||||
*/
|
||||
private String name;
|
||||
/**
|
||||
* 父部门ID
|
||||
*
|
||||
* 关联 {@link #id}
|
||||
*/
|
||||
private Long parentId;
|
||||
/**
|
||||
* 显示顺序
|
||||
*/
|
||||
private Integer sort;
|
||||
/**
|
||||
* 节点功能
|
||||
*/
|
||||
private String nodeFunction;
|
||||
/**
|
||||
* 中文描述
|
||||
*/
|
||||
private String toChinese;
|
||||
/**
|
||||
* 状态
|
||||
*
|
||||
* 枚举 {@link CommonStatusEnum}
|
||||
*/
|
||||
private Integer status;
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
private Integer type;
|
||||
private String belongTo;
|
||||
|
||||
@TableField(exist = false)
|
||||
private List<WpsWordLinkDO> children = new ArrayList<>();
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package pc.exam.pp.module.judgement.dal.mysql.wpsword;
|
||||
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import pc.exam.pp.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import pc.exam.pp.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import pc.exam.pp.module.judgement.controller.admin.WpsWord.vo.WordListReqVO;
|
||||
import pc.exam.pp.module.judgement.dal.dataobject.wpsword.WpsWordLinkDO;
|
||||
import pc.exam.pp.module.judgement.utils.tree.vo.TreeVO;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface WpsWordLinkMapper extends BaseMapperX<WpsWordLinkDO> {
|
||||
|
||||
default List<WpsWordLinkDO> selectList(WordListReqVO reqVO) {
|
||||
return selectList(new LambdaQueryWrapperX<WpsWordLinkDO>()
|
||||
.likeIfPresent(WpsWordLinkDO::getName, reqVO.getName())
|
||||
.eqIfPresent(WpsWordLinkDO::getStatus, reqVO.getStatus()));
|
||||
}
|
||||
|
||||
default WpsWordLinkDO selectByParentIdAndName(Long parentId, String name) {
|
||||
return selectOne(WpsWordLinkDO::getParentId, parentId, WpsWordLinkDO::getName, name);
|
||||
}
|
||||
|
||||
default Long selectCountByParentId(Long parentId) {
|
||||
return selectCount(WpsWordLinkDO::getParentId, parentId);
|
||||
}
|
||||
|
||||
default List<WpsWordLinkDO> selectListByParentId(Collection<Long> parentIds) {
|
||||
return selectList(WpsWordLinkDO::getParentId, parentIds);
|
||||
}
|
||||
|
||||
List<TreeVO> selectTreeListByNodeFunction();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package pc.exam.pp.module.judgement.service.wps_word;
|
||||
|
||||
|
||||
|
||||
import pc.exam.pp.module.judgement.utils.wps_word.vo.WordVO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 判分逻辑集合(wps word)
|
||||
*
|
||||
* @author rwb
|
||||
*/
|
||||
public interface JudgementWpsWordService {
|
||||
|
||||
/**
|
||||
* 获取word文件内得考点及描述
|
||||
* @param path minio文件路径
|
||||
* @return 文件内得考点及描述
|
||||
* @throws Exception 异常
|
||||
*/
|
||||
public List<WordVO> ProgrammingWpsWord(String path) throws Exception;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package pc.exam.pp.module.judgement.service.wps_word;
|
||||
|
||||
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.stereotype.Service;
|
||||
import pc.exam.pp.module.infra.dal.dataobject.config.ConfigDO;
|
||||
import pc.exam.pp.module.infra.service.config.ConfigService;
|
||||
import pc.exam.pp.module.judgement.controller.admin.WpsWord.vo.WordListReqVO;
|
||||
import pc.exam.pp.module.judgement.dal.dataobject.wpsword.WpsWordLinkDO;
|
||||
import pc.exam.pp.module.judgement.dal.mysql.wpsword.WpsWordLinkMapper;
|
||||
import pc.exam.pp.module.judgement.service.auto_tools.AutoToolsService;
|
||||
import pc.exam.pp.module.judgement.utils.wps_word.WpsWordUtils;
|
||||
import pc.exam.pp.module.judgement.utils.wps_word.vo.WordVO;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class JudgementWpsWordServiceImpl implements JudgementWpsWordService {
|
||||
|
||||
@Resource
|
||||
WpsWordLinkMapper wpsWordLinkMapper;
|
||||
|
||||
@Resource
|
||||
AutoToolsService autoToolsService;
|
||||
|
||||
@Resource
|
||||
ConfigService configService;
|
||||
|
||||
@Override
|
||||
public List<WordVO> ProgrammingWpsWord(String path) throws Exception {
|
||||
// 1、获取文件临时下载路径
|
||||
ConfigDO config = configService.getConfigByKey("file_down_path");
|
||||
// 2、下载文件并返回文件完整路径
|
||||
String pathName = autoToolsService.downloadStudentFile(path, config.getValue());
|
||||
// 3、创建word考点tree
|
||||
WordListReqVO wordListReqVO = new WordListReqVO();
|
||||
wordListReqVO.setBelongTo(0);
|
||||
List<WpsWordLinkDO> list = wpsWordLinkMapper.selectList(wordListReqVO);
|
||||
// 4、docx文件读取并返回考点及说明信息
|
||||
List<WordVO> margins1 = WpsWordUtils.wps_word(pathName, list);
|
||||
// 5、已经读取完得考点删除源文件
|
||||
File file = new File(pathName);
|
||||
file.delete();
|
||||
return margins1;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
package pc.exam.pp.module.judgement.service.wps_word;
|
||||
|
||||
import pc.exam.pp.framework.common.util.collection.CollectionUtils;
|
||||
import pc.exam.pp.module.judgement.controller.admin.WpsWord.vo.WordListReqVO;
|
||||
import pc.exam.pp.module.judgement.controller.admin.WpsWord.vo.WordSaveReqVO;
|
||||
import pc.exam.pp.module.judgement.dal.dataobject.wpsword.WpsWordLinkDO;
|
||||
import pc.exam.pp.module.judgement.utils.tree.vo.TreeVO;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 节点 Service 接口
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public interface WpsWordLinkService {
|
||||
|
||||
/**
|
||||
* 创建节点
|
||||
*
|
||||
* @param createReqVO 节点信息
|
||||
* @return 节点编号
|
||||
*/
|
||||
Long createWord(WordSaveReqVO createReqVO);
|
||||
|
||||
/**
|
||||
* 更新节点
|
||||
*
|
||||
* @param updateReqVO 节点信息
|
||||
*/
|
||||
void updateWord(WordSaveReqVO updateReqVO);
|
||||
|
||||
/**
|
||||
* 删除节点
|
||||
*
|
||||
* @param id 节点编号
|
||||
*/
|
||||
void deleteWord(Long id);
|
||||
|
||||
/**
|
||||
* 获得节点信息
|
||||
*
|
||||
* @param id 节点编号
|
||||
* @return 节点信息
|
||||
*/
|
||||
WpsWordLinkDO getWord(Long id);
|
||||
|
||||
/**
|
||||
* 获得节点信息数组
|
||||
*
|
||||
* @param ids 节点编号数组
|
||||
* @return 节点信息数组
|
||||
*/
|
||||
List<WpsWordLinkDO> getWordList(Collection<Long> ids);
|
||||
|
||||
/**
|
||||
* 筛选节点列表
|
||||
*
|
||||
* @param reqVO 筛选条件请求 VO
|
||||
* @return 节点列表
|
||||
*/
|
||||
List<WpsWordLinkDO> getWordList(WordListReqVO reqVO);
|
||||
|
||||
/**
|
||||
* 获得指定编号的节点 Map
|
||||
*
|
||||
* @param ids 节点编号数组
|
||||
* @return 节点 Map
|
||||
*/
|
||||
default Map<Long, WpsWordLinkDO> getWordMap(Collection<Long> ids) {
|
||||
List<WpsWordLinkDO> list = getWordList(ids);
|
||||
return CollectionUtils.convertMap(list, WpsWordLinkDO::getId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得指定节点的所有子节点
|
||||
*
|
||||
* @param id 节点编号
|
||||
* @return 子节点列表
|
||||
*/
|
||||
default List<WpsWordLinkDO> getChildWordList(Long id) {
|
||||
return getChildWordList(Collections.singleton(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得指定节点的所有子节点
|
||||
*
|
||||
* @param ids 节点编号数组
|
||||
* @return 子节点列表
|
||||
*/
|
||||
List<WpsWordLinkDO> getChildWordList(Collection<Long> ids);
|
||||
|
||||
/**
|
||||
* 获得所有子节点,从缓存中
|
||||
*
|
||||
* @param id 父节点编号
|
||||
* @return 子节点列表
|
||||
*/
|
||||
Set<Long> getChildWordIdListFromCache(Long id);
|
||||
|
||||
/**
|
||||
* 校验节点们是否有效。如下情况,视为无效:
|
||||
* 1. 节点编号不存在
|
||||
* 2. 节点被禁用
|
||||
*
|
||||
* @param ids 角色编号数组
|
||||
*/
|
||||
void validateWordList(Collection<Long> ids);
|
||||
|
||||
List<TreeVO> getWordTreeList();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
package pc.exam.pp.module.judgement.service.wps_word;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import pc.exam.pp.framework.common.enums.CommonStatusEnum;
|
||||
import pc.exam.pp.framework.common.util.object.BeanUtils;
|
||||
import pc.exam.pp.framework.datapermission.core.annotation.DataPermission;
|
||||
import pc.exam.pp.framework.tenant.core.aop.TenantIgnore;
|
||||
import pc.exam.pp.module.judgement.controller.admin.WpsWord.vo.WordListReqVO;
|
||||
import pc.exam.pp.module.judgement.controller.admin.WpsWord.vo.WordSaveReqVO;
|
||||
import pc.exam.pp.module.judgement.dal.dataobject.wpsword.WpsWordLinkDO;
|
||||
import pc.exam.pp.module.judgement.dal.mysql.wpsword.WpsWordLinkMapper;
|
||||
import pc.exam.pp.module.judgement.utils.tree.vo.TreeVO;
|
||||
import pc.exam.pp.module.system.dal.redis.RedisKeyConstants;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static pc.exam.pp.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static pc.exam.pp.framework.common.util.collection.CollectionUtils.convertSet;
|
||||
import static pc.exam.pp.module.system.enums.ErrorCodeConstants.*;
|
||||
|
||||
/**
|
||||
* 节点 Service 实现类
|
||||
*
|
||||
*/
|
||||
@Service
|
||||
@Validated
|
||||
@Slf4j
|
||||
public class WpsWordLinkServiceImpl implements WpsWordLinkService {
|
||||
|
||||
@Resource
|
||||
private WpsWordLinkMapper wpsWordLinkMapper;
|
||||
|
||||
@Override
|
||||
@CacheEvict(cacheNames = RedisKeyConstants.WPS_WORD_CHILDREN_ID_LIST,
|
||||
allEntries = true) // allEntries 清空所有缓存,因为操作一个节点,涉及到多个缓存
|
||||
public Long createWord(WordSaveReqVO createReqVO) {
|
||||
if (createReqVO.getParentId() == null) {
|
||||
createReqVO.setParentId(WpsWordLinkDO.PARENT_ID_ROOT);
|
||||
}
|
||||
// 校验父节点的有效性
|
||||
validateParentWord(null, createReqVO.getParentId());
|
||||
// 校验节点名的唯一性
|
||||
validateWordNameUnique(null, createReqVO.getParentId(), createReqVO.getName());
|
||||
|
||||
// 插入节点
|
||||
WpsWordLinkDO wpsWordLinkDO = BeanUtils.toBean(createReqVO, WpsWordLinkDO.class);
|
||||
wpsWordLinkMapper.insert(wpsWordLinkDO);
|
||||
return wpsWordLinkDO.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
@CacheEvict(cacheNames = RedisKeyConstants.WPS_WORD_CHILDREN_ID_LIST,
|
||||
allEntries = true) // allEntries 清空所有缓存,因为操作一个节点,涉及到多个缓存
|
||||
public void updateWord(WordSaveReqVO updateReqVO) {
|
||||
if (updateReqVO.getParentId() == null) {
|
||||
updateReqVO.setParentId(WpsWordLinkDO.PARENT_ID_ROOT);
|
||||
}
|
||||
// 校验自己存在
|
||||
validateWordExists(updateReqVO.getId());
|
||||
// 校验父节点的有效性
|
||||
validateParentWord(updateReqVO.getId(), updateReqVO.getParentId());
|
||||
// 校验节点名的唯一性
|
||||
validateWordNameUnique(updateReqVO.getId(), updateReqVO.getParentId(), updateReqVO.getName());
|
||||
|
||||
// 更新节点
|
||||
WpsWordLinkDO updateObj = BeanUtils.toBean(updateReqVO, WpsWordLinkDO.class);
|
||||
wpsWordLinkMapper.updateById(updateObj);
|
||||
}
|
||||
|
||||
@Override
|
||||
@CacheEvict(cacheNames = RedisKeyConstants.WPS_WORD_CHILDREN_ID_LIST,
|
||||
allEntries = true) // allEntries 清空所有缓存,因为操作一个节点,涉及到多个缓存
|
||||
public void deleteWord(Long id) {
|
||||
// 校验是否存在
|
||||
validateWordExists(id);
|
||||
// 校验是否有子节点
|
||||
if (wpsWordLinkMapper.selectCountByParentId(id) > 0) {
|
||||
throw exception(WORD_NOT_FOUND);
|
||||
}
|
||||
// 删除节点
|
||||
wpsWordLinkMapper.deleteById(id);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void validateWordExists(Long id) {
|
||||
if (id == null) {
|
||||
return;
|
||||
}
|
||||
WpsWordLinkDO wpsWordLinkDO = wpsWordLinkMapper.selectById(id);
|
||||
if (wpsWordLinkDO == null) {
|
||||
throw exception(WORD_NOT_FOUND);
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void validateParentWord(Long id, Long parentId) {
|
||||
if (parentId == null || WpsWordLinkDO.PARENT_ID_ROOT.equals(parentId)) {
|
||||
return;
|
||||
}
|
||||
// 1. 不能设置自己为父节点
|
||||
if (Objects.equals(id, parentId)) {
|
||||
throw exception(DEPT_PARENT_ERROR);
|
||||
}
|
||||
// 2. 父节点不存在
|
||||
WpsWordLinkDO parentWord = wpsWordLinkMapper.selectById(parentId);
|
||||
if (parentWord == null) {
|
||||
throw exception(WORD_PARENT_NOT_EXITS);
|
||||
}
|
||||
// 3. 递归校验父节点,如果父节点是自己的子节点,则报错,避免形成环路
|
||||
if (id == null) { // id 为空,说明新增,不需要考虑环路
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < Short.MAX_VALUE; i++) {
|
||||
// 3.1 校验环路
|
||||
parentId = parentWord.getParentId();
|
||||
if (Objects.equals(id, parentId)) {
|
||||
throw exception(WORD_PARENT_IS_CHILD);
|
||||
}
|
||||
// 3.2 继续递归下一级父节点
|
||||
if (parentId == null || WpsWordLinkDO.PARENT_ID_ROOT.equals(parentId)) {
|
||||
break;
|
||||
}
|
||||
parentWord = wpsWordLinkMapper.selectById(parentId);
|
||||
if (parentWord == null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void validateWordNameUnique(Long id, Long parentId, String name) {
|
||||
WpsWordLinkDO wpsWordLinkDO = wpsWordLinkMapper.selectByParentIdAndName(parentId, name);
|
||||
if (wpsWordLinkDO == null) {
|
||||
return;
|
||||
}
|
||||
// 如果 id 为空,说明不用比较是否为相同 id 的节点
|
||||
if (id == null) {
|
||||
throw exception(WORD_NAME_DUPLICATE);
|
||||
}
|
||||
if (ObjectUtil.notEqual(wpsWordLinkDO.getId(), id)) {
|
||||
throw exception(WORD_NAME_DUPLICATE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public WpsWordLinkDO getWord(Long id) {
|
||||
return wpsWordLinkMapper.selectById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<WpsWordLinkDO> getWordList(Collection<Long> ids) {
|
||||
if (CollUtil.isEmpty(ids)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return wpsWordLinkMapper.selectBatchIds(ids);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<WpsWordLinkDO> getWordList(WordListReqVO reqVO) {
|
||||
List<WpsWordLinkDO> list = wpsWordLinkMapper.selectList(reqVO);
|
||||
list.sort(Comparator.comparing(WpsWordLinkDO::getSort));
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<WpsWordLinkDO> getChildWordList(Collection<Long> ids) {
|
||||
List<WpsWordLinkDO> children = new LinkedList<>();
|
||||
// 遍历每一层
|
||||
Collection<Long> parentIds = ids;
|
||||
for (int i = 0; i < Short.MAX_VALUE; i++) { // 使用 Short.MAX_VALUE 避免 bug 场景下,存在死循环
|
||||
// 查询当前层,所有的子节点
|
||||
List<WpsWordLinkDO> words = wpsWordLinkMapper.selectListByParentId(parentIds);
|
||||
// 1. 如果没有子节点,则结束遍历
|
||||
if (CollUtil.isEmpty(words)) {
|
||||
break;
|
||||
}
|
||||
// 2. 如果有子节点,继续遍历
|
||||
children.addAll(words);
|
||||
parentIds = convertSet(words, WpsWordLinkDO::getId);
|
||||
}
|
||||
return children;
|
||||
}
|
||||
|
||||
@Override
|
||||
@DataPermission(enable = false) // 禁用数据权限,避免建立不正确的缓存
|
||||
@Cacheable(cacheNames = RedisKeyConstants.WPS_WORD_CHILDREN_ID_LIST, key = "#id")
|
||||
public Set<Long> getChildWordIdListFromCache(Long id) {
|
||||
List<WpsWordLinkDO> children = getChildWordList(id);
|
||||
return convertSet(children, WpsWordLinkDO::getId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateWordList(Collection<Long> ids) {
|
||||
if (CollUtil.isEmpty(ids)) {
|
||||
return;
|
||||
}
|
||||
// 获得科室信息
|
||||
Map<Long, WpsWordLinkDO> wordMap = getWordMap(ids);
|
||||
// 校验
|
||||
ids.forEach(id -> {
|
||||
WpsWordLinkDO word = wordMap.get(id);
|
||||
if (word == null) {
|
||||
throw exception(WORD_NOT_FOUND);
|
||||
}
|
||||
if (!CommonStatusEnum.ENABLE.getStatus().equals(word.getStatus())) {
|
||||
throw exception(WORD_NOT_ENABLE, word.getName());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@TenantIgnore
|
||||
public List<TreeVO> getWordTreeList() {
|
||||
return wpsWordLinkMapper.selectTreeListByNodeFunction();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package pc.exam.pp.module.judgement.utils.count;
|
||||
|
||||
// 工具方法:twips 转厘米
|
||||
public class TwipsToCmUtils {
|
||||
|
||||
// 工具方法:twips 转厘米(保留两位小数)
|
||||
public static double convertTwipsToCm(String twipsStr) {
|
||||
if (twipsStr == null || twipsStr.isEmpty()) {
|
||||
return 0.0;
|
||||
}
|
||||
try {
|
||||
int twips = Integer.parseInt(twipsStr);
|
||||
double cm = twips * 2.54 / 1440;
|
||||
// 四舍五入保留两位小数
|
||||
return Math.round(cm * 100.0) / 100.0;
|
||||
} catch (NumberFormatException e) {
|
||||
return 0.0; // 解析失败返回0
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package pc.exam.pp.module.judgement.utils.tree;
|
||||
|
||||
import pc.exam.pp.module.judgement.dal.dataobject.wpsword.WpsWordLinkDO;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class TreeUtils {
|
||||
|
||||
public static List<WpsWordLinkDO> buildTree(List<WpsWordLinkDO> flatList) {
|
||||
Map<Integer, WpsWordLinkDO> nodeMap = new HashMap<>();
|
||||
List<WpsWordLinkDO> roots = new ArrayList<>();
|
||||
|
||||
// 先放入 map
|
||||
for (WpsWordLinkDO node : flatList) {
|
||||
nodeMap.put(Math.toIntExact(node.getId()), node);
|
||||
}
|
||||
|
||||
// 构建树关系
|
||||
for (WpsWordLinkDO node : flatList) {
|
||||
if (node.getParentId() == 0) {
|
||||
roots.add(node);
|
||||
} else {
|
||||
WpsWordLinkDO parent = nodeMap.get(node.getParentId().intValue());
|
||||
if (parent != null) {
|
||||
parent.getChildren().add(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
return roots;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package pc.exam.pp.module.judgement.utils.tree.vo;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import lombok.Data;
|
||||
import org.apache.ibatis.type.JdbcType;
|
||||
import pc.exam.pp.framework.tenant.core.db.TenantBaseDO;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@Data
|
||||
public class TreeVO extends TenantBaseDO {
|
||||
|
||||
private int id;
|
||||
private int parentId;
|
||||
private String name;
|
||||
private String nodeFunction;
|
||||
private String toChinese;
|
||||
private int type;
|
||||
private List<TreeVO> children = new ArrayList<>();
|
||||
|
||||
public TreeVO(int id, int parentId, String name, String nodeFunction, String toChinese, int type) {
|
||||
this.id = id;
|
||||
this.parentId = parentId;
|
||||
this.name = name;
|
||||
this.nodeFunction = nodeFunction;
|
||||
this.toChinese = toChinese;
|
||||
this.type = type;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,282 @@
|
||||
package pc.exam.pp.module.judgement.utils.wps_word;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
import org.apache.poi.xwpf.usermodel.*;
|
||||
import org.apache.xmlbeans.XmlCursor;
|
||||
import org.apache.xmlbeans.XmlObject;
|
||||
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
|
||||
import pc.exam.pp.module.judgement.dal.dataobject.wpsword.WpsWordLinkDO;
|
||||
import pc.exam.pp.module.judgement.utils.tree.TreeUtils;
|
||||
import pc.exam.pp.module.judgement.utils.wps_word.vo.WordVO;
|
||||
import java.io.FileInputStream;
|
||||
import java.util.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
public class WpsWordUtils {
|
||||
/**
|
||||
* 获取文档段落W:P标签得数量,判断出一个有多少段
|
||||
*/
|
||||
public static List<WordVO> wps_word(String filePath, List<WpsWordLinkDO> wpsWordLinkDOS) throws Exception {
|
||||
List<WordVO> wordVO = new ArrayList<>();
|
||||
int count = 0;
|
||||
// 路径初始化
|
||||
String xmlpath = "";
|
||||
XWPFDocument document = new XWPFDocument(new FileInputStream(filePath));
|
||||
String xmlString = XmlUtil.getDocumentXml(document);
|
||||
// 获取CTDocument对象
|
||||
XmlObject docXml = document.getDocument();
|
||||
List<WpsWordLinkDO> tree = TreeUtils.buildTree(wpsWordLinkDOS); // flatList 是你贴出的 JSON 解析出来的
|
||||
XmlObject xmlObject = document.getDocument(); // Word XML document
|
||||
// 创建一个list,存放word读取的数据
|
||||
for (WpsWordLinkDO wpsWordLinkDO : tree) {
|
||||
// 段落划分 根据w:p标签
|
||||
// 到达参数节点,构造 XPath 路径查询它的值
|
||||
String xpath = "declare namespace w='http://schemas.openxmlformats.org/wordprocessingml/2006/main' ";
|
||||
xpath += "//"+wpsWordLinkDO.getName();
|
||||
XmlCursor cursor = docXml.newCursor();
|
||||
int index = 0;
|
||||
cursor.selectPath(xpath);
|
||||
String xpathName = "declare namespace w='http://schemas.openxmlformats.org/wordprocessingml/2006/main' ";
|
||||
while (cursor.toNextSelection()) {
|
||||
// 每一段进行赋值,进行判断
|
||||
XmlObject paraObj = cursor.getObject();
|
||||
String paraText = paraObj.xmlText();
|
||||
// System.out.println(paraText);
|
||||
// System.out.println(cursor.getTextValue());
|
||||
index += 1;
|
||||
for (WpsWordLinkDO root : wpsWordLinkDO.getChildren()) {
|
||||
traverseTreeAndQueryXml(wordVO, wpsWordLinkDO.getName(), cursor.getTextValue(), xpathName, root, paraObj, new ArrayList<>(), new ArrayList<>(), index,1);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 读取页眉的方法(需要通过页眉查询,水印,页眉文字等信息)
|
||||
List<XWPFHeader> headers = document.getHeaderList();
|
||||
for (XWPFHeader header : headers) {
|
||||
if (!Objects.equals(header.getText(), "")) {
|
||||
headerAndFooter(header, null, wordVO);
|
||||
}
|
||||
// 获取底层 XML 对象
|
||||
CTHdrFtr ctHdrFtr = header._getHdrFtr(); // ✅ 正确方法
|
||||
String xpath = "declare namespace w='http://schemas.openxmlformats.org/wordprocessingml/2006/main' ";
|
||||
xpath += "//w:hdr/w:p/w:r/w:pict";
|
||||
XmlCursor cursor = ctHdrFtr.newCursor();
|
||||
cursor.selectPath(xpath);
|
||||
while (cursor.toNextSelection()) {
|
||||
// 查询 v:textpath 节点
|
||||
cursor.selectPath(
|
||||
"declare namespace v='urn:schemas-microsoft-com:vml' " +
|
||||
".//v:textpath"
|
||||
);
|
||||
while (cursor.toNextSelection()) {
|
||||
XmlObject textpathObj = cursor.getObject();
|
||||
String xml = textpathObj.xmlText();
|
||||
WordVO attr_word = new WordVO();
|
||||
|
||||
// 提取属性值
|
||||
String stringAttr = cursor.getAttributeText(new javax.xml.namespace.QName("string"));
|
||||
String styleAttr = cursor.getAttributeText(new javax.xml.namespace.QName("style"));
|
||||
attr_word.setWordText("水印");
|
||||
List<String> attr = new ArrayList<>();
|
||||
attr.add("水印文字 string 属性: " + stringAttr);
|
||||
attr.add("水印 style 属性: " + styleAttr);
|
||||
attr_word.setKeynoteChinese(attr);
|
||||
List<String> path = new ArrayList<>();
|
||||
path.add("name:"+stringAttr);
|
||||
path.add("style:"+styleAttr);
|
||||
attr_word.setExamKeynote(path);
|
||||
wordVO.add(attr_word);
|
||||
}
|
||||
}
|
||||
cursor.close();
|
||||
}
|
||||
// 获取页脚
|
||||
List<XWPFFooter> footers = document.getFooterList();
|
||||
for (XWPFFooter footer : footers) {
|
||||
if (!Objects.equals(footer.getText(), "")) {
|
||||
headerAndFooter(null, footer, wordVO);
|
||||
}
|
||||
}
|
||||
// 邮件合并
|
||||
List<String> email = getMailMergeFields(document);
|
||||
if (!email.isEmpty()) {
|
||||
// 使用了邮件合并功能
|
||||
WordVO email_word = new WordVO();
|
||||
email_word.setWordText("邮件合并");
|
||||
email_word.setExamKeynote(email);
|
||||
email_word.setKeynoteChinese(email);
|
||||
wordVO.add(email_word);
|
||||
}
|
||||
return wordVO;
|
||||
}
|
||||
// 页眉页脚
|
||||
public static void headerAndFooter(XWPFHeader header, XWPFFooter footer, List<WordVO> wordVO) {
|
||||
if (header != null) {
|
||||
for (XWPFParagraph para : header.getParagraphs()) {
|
||||
for (XWPFRun run : para.getRuns()) {
|
||||
String text = run.getText(0);
|
||||
if (text != null) {
|
||||
WordVO wordVO1 = new WordVO();
|
||||
wordVO1.setWordText("页眉:" + text);
|
||||
List<String> style_list = new ArrayList<>();
|
||||
style_list.add("字体: " + run.getFontFamily());
|
||||
style_list.add("字号: " + run.getFontSize());
|
||||
style_list.add("颜色: " + run.getColor());
|
||||
style_list.add("加粗: " + run.isBold());
|
||||
style_list.add("斜体: " + run.isItalic());
|
||||
wordVO1.setKeynoteChinese(style_list);
|
||||
wordVO.add(wordVO1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (footer != null) {
|
||||
for (XWPFParagraph para : footer.getParagraphs()) {
|
||||
for (XWPFRun run : para.getRuns()) {
|
||||
String text = run.getText(0);
|
||||
if (text != null) {
|
||||
WordVO wordVO1 = new WordVO();
|
||||
wordVO1.setWordText("页脚:" + text);
|
||||
List<String> style_list = new ArrayList<>();
|
||||
style_list.add("字体: " + run.getFontFamily());
|
||||
style_list.add("字号: " + run.getFontSize());
|
||||
style_list.add("颜色: " + run.getColor());
|
||||
style_list.add("加粗: " + run.isBold());
|
||||
style_list.add("斜体: " + run.isItalic());
|
||||
wordVO1.setKeynoteChinese(style_list);
|
||||
wordVO.add(wordVO1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
public static void traverseTreeAndQueryXml(List<WordVO> wordVOs, String firstTitle, String text, String xpath, WpsWordLinkDO node, XmlObject currentXml, List<String> pathSoFar, List<String> pathChinese, int index, int beginIndex) {
|
||||
// 到达参数节点,构造 XPath 路径查询它的值
|
||||
if (beginIndex == 1) {
|
||||
xpath += "//" + firstTitle + "[" + index + "]/";
|
||||
}
|
||||
pathSoFar.add(node.getName());
|
||||
pathChinese.add(node.getToChinese() + index);
|
||||
|
||||
if (node.getType() == 1) {
|
||||
// pathSoFar.remove(0);
|
||||
xpath += String.join("/", pathSoFar);
|
||||
// System.out.println(xpath);
|
||||
try (XmlCursor cursors = currentXml.newCursor()) {
|
||||
// System.out.println(xpath);
|
||||
cursors.selectPath(xpath);
|
||||
if (cursors.toNextSelection()) {
|
||||
// System.out.println(cursors.xmlText());
|
||||
// cursors.selectPath("declare namespace w='http://schemas.openxmlformats.org/wordprocessingml/2006/main' //@w:firstLine");
|
||||
// if (cursors.toNextSelection()) {
|
||||
// String texts = cursors.getTextValue();
|
||||
// System.out.println("值:" + texts);
|
||||
// }
|
||||
|
||||
String text_value = cursors.getTextValue();
|
||||
if (!Objects.equals(text_value, "")) {
|
||||
// 查找List里面是否已经存在相应文本的数据
|
||||
String finalText = text;
|
||||
int list_index = IntStream.range(0, wordVOs.size())
|
||||
.filter(i -> finalText.equals(wordVOs.get(i).getWordText()))
|
||||
.findFirst()
|
||||
.orElse(-1);
|
||||
// 判断在段落内的样式,如果出现样式,向上兼容,直接再出现样式标签
|
||||
// System.out.println(xpath);
|
||||
if (xpath.indexOf("w:sectPr") > 0 && xpath.indexOf("w:p[") > 0) {
|
||||
// 说明出现了文本页面设置,需要进行向上绑定
|
||||
// 在获取当前的数组长度,获取上面的属性 遍历已经存在的数据
|
||||
int tindex = 0;
|
||||
for (WordVO woVo : wordVOs) {
|
||||
// 判断标识是否为false,,代表没有进行赋值
|
||||
if (!woVo.getIsTrue()) {
|
||||
WordVO wordVO = wordVOs.get(tindex);
|
||||
wordVO.setWordText(wordVO.getWordText());
|
||||
woVo.setIsTrue(true);
|
||||
List<String> kchinese = woVo.getKeynoteChinese();
|
||||
List<String> examKeynote = woVo.getExamKeynote();
|
||||
examKeynote.add(String.join(" → ", pathSoFar) + ",value:" + text_value);
|
||||
kchinese.add(String.join(" → ", pathChinese) + ",值:" + text_value);
|
||||
wordVO.setKeynoteChinese(kchinese);
|
||||
wordVO.setExamKeynote(examKeynote);
|
||||
wordVOs.set(tindex, woVo);
|
||||
}
|
||||
tindex += 1;
|
||||
}
|
||||
} else if (list_index < 0) { // 如果没有查询到了
|
||||
if (xpath.indexOf("w:sectPr[") > 0) {
|
||||
// 页面属性
|
||||
// 文本
|
||||
text = "页面属性";
|
||||
}
|
||||
if (!Objects.equals(text, "")) {
|
||||
if (!text.contains("MERGEFIELD")) {
|
||||
// 给标志符
|
||||
WordVO wordVO = new WordVO();
|
||||
wordVO.setWordText(text);
|
||||
// 创建list进行存放数据
|
||||
List<String> kchinese = new ArrayList<>();
|
||||
List<String> examKeynote = new ArrayList<>();
|
||||
examKeynote.add(String.join(" → ", pathSoFar) + ",value:" + text_value);
|
||||
|
||||
kchinese.add(String.join(" → ", pathChinese) + ",值:" + text_value);
|
||||
// 组合完数据后进行存放数据
|
||||
wordVO.setKeynoteChinese(kchinese);
|
||||
wordVO.setExamKeynote(examKeynote);
|
||||
wordVO.setIsTrue(false);
|
||||
wordVOs.add(wordVO);
|
||||
}
|
||||
}
|
||||
} else { // 如果找到了
|
||||
WordVO wordVO = wordVOs.get(list_index);
|
||||
List<String> kchinese = wordVO.getKeynoteChinese();
|
||||
List<String> examKeynote = wordVO.getExamKeynote();
|
||||
examKeynote.add(String.join(" → ", pathSoFar) + ",value:" + text_value);
|
||||
kchinese.add(String.join(" → ", pathChinese) + ",值:" + text_value);
|
||||
wordVO.setKeynoteChinese(kchinese);
|
||||
wordVO.setExamKeynote(examKeynote);
|
||||
wordVO.setIsTrue(false);
|
||||
wordVOs.remove(list_index);
|
||||
wordVOs.add(wordVO);
|
||||
}
|
||||
// System.out.println("文本:" + text + " 参数路径:" + String.join(" → ", pathChinese) + ",值:" + text_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (WpsWordLinkDO child : node.getChildren()) {
|
||||
traverseTreeAndQueryXml(wordVOs, firstTitle, text, xpath, child, currentXml, new ArrayList<>(pathSoFar), new ArrayList<>(pathChinese), index,2);
|
||||
}
|
||||
}
|
||||
pathSoFar.remove(pathSoFar.size() - 1);
|
||||
pathChinese.remove(pathChinese.size() - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用邮件合并
|
||||
*/
|
||||
public static List<String> getMailMergeFields(XWPFDocument document) {
|
||||
List<String> fieldNames = new ArrayList<>();
|
||||
for (XWPFParagraph paragraph : document.getParagraphs()) {
|
||||
for (XWPFRun run : paragraph.getRuns()) {
|
||||
// 获取底层 CTR 对象
|
||||
CTR ctr = run.getCTR();
|
||||
for (CTText instrText : ctr.getInstrTextList()) {
|
||||
String text = instrText.getStringValue();
|
||||
if (text != null && text.contains("MERGEFIELD")) {
|
||||
// 正则提取字段名
|
||||
Pattern pattern = Pattern.compile("MERGEFIELD\\s+\"?([^\"\\s]+)\"?");
|
||||
Matcher matcher = pattern.matcher(text);
|
||||
if (matcher.find()) {
|
||||
String fieldName = matcher.group(1).trim();
|
||||
fieldNames.add(fieldName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return fieldNames;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package pc.exam.pp.module.judgement.utils.wps_word;
|
||||
|
||||
import org.apache.poi.xwpf.usermodel.XWPFDocument;
|
||||
import org.apache.xmlbeans.XmlObject;
|
||||
|
||||
import java.io.StringWriter;
|
||||
import javax.xml.transform.*;
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
|
||||
public class XmlUtil {
|
||||
public static String getDocumentXml(XWPFDocument doc) throws Exception {
|
||||
XmlObject xml = doc.getDocument(); // 获取底层 CTDocument1(org.openxmlformats.schemas.wordprocessingml.x2006.main.CTDocument1)
|
||||
|
||||
// 转换为 DOM
|
||||
org.w3c.dom.Node domNode = xml.getDomNode();
|
||||
Transformer tf = TransformerFactory.newInstance().newTransformer();
|
||||
tf.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
|
||||
tf.setOutputProperty(OutputKeys.INDENT, "yes");
|
||||
|
||||
StringWriter writer = new StringWriter();
|
||||
tf.transform(new DOMSource(domNode), new StreamResult(writer));
|
||||
return writer.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package pc.exam.pp.module.judgement.utils.wps_word.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class WordVO {
|
||||
|
||||
@Schema(description = "相关文本")
|
||||
private String wordText;
|
||||
|
||||
@Schema(description = "考试考点")
|
||||
private List<String> examKeynote;
|
||||
|
||||
@Schema(description = "考点汉化")
|
||||
private List<String> keynoteChinese;
|
||||
|
||||
@Schema(description = "是否有样式修饰")
|
||||
private Boolean isTrue;
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="pc.exam.pp.module.judgement.dal.mysql.wpsword.WpsWordLinkMapper">
|
||||
|
||||
<!--
|
||||
一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
|
||||
无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
|
||||
代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
|
||||
文档可见:https://www.iocoder.cn/MyBatis/x-plugins/
|
||||
-->
|
||||
<resultMap id="NodeResultMap" type="pc.exam.pp.module.judgement.utils.tree.vo.TreeVO">
|
||||
<id property="id" column="id" jdbcType="BIGINT"/>
|
||||
<result property="name" column="name" jdbcType="VARCHAR"/>
|
||||
<result property="parentId" column="parent_id" jdbcType="BIGINT"/>
|
||||
<result property="nodeFunction" column="node_function" jdbcType="VARCHAR"/>
|
||||
<result property="toChinese" column="to_chinese" jdbcType="VARCHAR"/>
|
||||
<result property="type" column="type" jdbcType="TINYINT"/>
|
||||
</resultMap>
|
||||
|
||||
|
||||
<select id="selectTreeListByNodeFunction" resultMap="NodeResultMap">
|
||||
SELECT
|
||||
*
|
||||
FROM
|
||||
wps_word_link
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
@@ -174,4 +174,13 @@ public interface ErrorCodeConstants {
|
||||
ErrorCode STUDENT_USERNAME_LOGIN = new ErrorCode(1_002_029_002, "学生账号无法登陆!");
|
||||
ErrorCode STUDENT_USERNAME_NOTLOGIN = new ErrorCode(1_002_029_003, "非学生账号无法登陆!");
|
||||
|
||||
|
||||
// ========== WpsWOrd 1-002-030-000 ==========
|
||||
ErrorCode WORD_NAME_DUPLICATE = new ErrorCode(1_002_030_000, "已经存在该名字的WORD节点");
|
||||
ErrorCode WORD_PARENT_NOT_EXITS = new ErrorCode(1_002_030_001,"父级WORD节点不存在");
|
||||
ErrorCode WORD_NOT_FOUND = new ErrorCode(1_002_030_002, "当前WORD节点不存在");
|
||||
ErrorCode WORD_EXITS_CHILDREN = new ErrorCode(1_002_030_003, "存在子WORD节点,无法删除");
|
||||
ErrorCode WORD_PARENT_ERROR = new ErrorCode(1_002_030_004, "不能设置自己为父WORD节点");
|
||||
ErrorCode WORD_NOT_ENABLE = new ErrorCode(1_002_030_006, "WORD节点({})不处于开启状态,不允许选择");
|
||||
ErrorCode WORD_PARENT_IS_CHILD = new ErrorCode(1_002_030_007, "不能设置自己的子WORD节点为父WORD节点");
|
||||
}
|
||||
|
||||
@@ -17,6 +17,14 @@ public interface RedisKeyConstants {
|
||||
*/
|
||||
String DEPT_CHILDREN_ID_LIST = "dept_children_ids";
|
||||
|
||||
/**
|
||||
* 指定WPS_WORD的所有子WPS_WORD编号数组的缓存
|
||||
* <p>
|
||||
* KEY 格式:wps_word_children_ids:{id}
|
||||
* VALUE 数据类型:String 子WPS_WORD编号集合
|
||||
*/
|
||||
String WPS_WORD_CHILDREN_ID_LIST = "wps_word_children_ids";
|
||||
|
||||
/**
|
||||
* 角色的缓存
|
||||
* <p>
|
||||
|
||||
Reference in New Issue
Block a user