【新增】 word考点基于docx4j 第一版
This commit is contained in:
@@ -153,6 +153,37 @@
|
||||
<version>2.4.2-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.docx4j</groupId>
|
||||
<artifactId>docx4j-core</artifactId>
|
||||
<version>11.5.3</version> <!-- 或使用最新版本 -->
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.docx4j</groupId>
|
||||
<artifactId>docx4j-JAXB-MOXy</artifactId>
|
||||
<version>11.5.3</version>
|
||||
</dependency>
|
||||
<!-- 必须加这个,不然 marshaltoString 会报错 -->
|
||||
<dependency>
|
||||
<groupId>org.docx4j</groupId>
|
||||
<artifactId>docx4j-JAXB-Internal</artifactId>
|
||||
<version>8.3.9</version>
|
||||
</dependency>
|
||||
|
||||
<!-- MOXy 实现 -->
|
||||
<dependency>
|
||||
<groupId>org.eclipse.persistence</groupId>
|
||||
<artifactId>org.eclipse.persistence.moxy</artifactId>
|
||||
<version>3.0.2</version>
|
||||
</dependency>
|
||||
|
||||
<!-- JAXB API -->
|
||||
<dependency>
|
||||
<groupId>jakarta.xml.bind</groupId>
|
||||
<artifactId>jakarta.xml.bind-api</artifactId>
|
||||
<version>3.0.1</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
@@ -45,6 +45,11 @@ public class WpsController {
|
||||
JudgementWpsPptxService judgementWpsPptxService;
|
||||
@Resource
|
||||
JudgementWpsExcelService judgementWpsExcelService;
|
||||
@GetMapping("/docxMaster")
|
||||
public CommonResult<String> docxMaster() throws Exception {
|
||||
judgementWpsWordService.docxMaster("D:\\Project\\Exam\\Software\\Temp\\1.docx");
|
||||
return CommonResult.success("");
|
||||
}
|
||||
/**
|
||||
* wps word
|
||||
* @return 判分
|
||||
|
@@ -19,6 +19,7 @@ import java.util.List;
|
||||
*/
|
||||
public interface JudgementWpsWordService {
|
||||
|
||||
void docxMaster(String path) throws Exception;
|
||||
/**
|
||||
* 获取word文件内得考点及描述
|
||||
* @param path minio文件路径
|
||||
|
@@ -19,6 +19,7 @@ import pc.exam.pp.module.judgement.service.auto_tools.AutoToolsService;
|
||||
import pc.exam.pp.module.judgement.service.auto_tools.vo.SourceAndText;
|
||||
import pc.exam.pp.module.judgement.utils.HtmlAppender;
|
||||
import pc.exam.pp.module.judgement.utils.wps_word.WpsWordUtils;
|
||||
import pc.exam.pp.module.judgement.utils.wps_word.docx4j.DocxMaster;
|
||||
import pc.exam.pp.module.judgement.utils.wps_word.vo.WordInfoReqVo;
|
||||
import pc.exam.pp.module.judgement.utils.wps_word.vo.WordVO;
|
||||
import pc.exam.pp.module.system.dal.dataobject.user.AdminUserDO;
|
||||
@@ -47,6 +48,11 @@ public class JudgementWpsWordServiceImpl implements JudgementWpsWordService {
|
||||
@Resource
|
||||
private AdminUserService userService;
|
||||
|
||||
@Override
|
||||
public void docxMaster(String path) throws Exception {
|
||||
DocxMaster.docxMaster(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<WordInfoReqVo> programmingWpsWord(String path) throws Exception {
|
||||
String pathName = "";
|
||||
|
@@ -0,0 +1,101 @@
|
||||
package pc.exam.pp.module.judgement.utils.wps_word.docx4j;
|
||||
|
||||
import jakarta.xml.bind.JAXBElement;
|
||||
import org.docx4j.XmlUtils;
|
||||
import org.docx4j.model.structure.HeaderFooterPolicy;
|
||||
import org.docx4j.model.structure.SectionWrapper;
|
||||
import org.docx4j.openpackaging.exceptions.Docx4JException;
|
||||
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
|
||||
import org.docx4j.openpackaging.parts.WordprocessingML.HeaderPart;
|
||||
import org.docx4j.openpackaging.parts.WordprocessingML.NumberingDefinitionsPart;
|
||||
import org.docx4j.openpackaging.parts.WordprocessingML.StyleDefinitionsPart;
|
||||
import org.docx4j.wml.*;
|
||||
import pc.exam.pp.module.judgement.utils.wps_word.docx4j.paragraph.Convert;
|
||||
import pc.exam.pp.module.judgement.utils.wps_word.docx4j.paragraph.Paragraphs;
|
||||
import pc.exam.pp.module.judgement.utils.wps_word.docx4j.paragraph.RunText;
|
||||
import pc.exam.pp.module.judgement.utils.wps_word.docx4j.section.SectionPage;
|
||||
import pc.exam.pp.module.judgement.utils.wps_word.docx4j.vo.JudgementWordsVO;
|
||||
|
||||
import java.io.File;
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author REN
|
||||
*/
|
||||
public class DocxMaster {
|
||||
|
||||
public static void docxMaster(String path) throws Docx4JException {
|
||||
|
||||
// 一共分为 段落
|
||||
// 创建考点数组
|
||||
List<JudgementWordsVO> judgementWordsVOS = new ArrayList<>();
|
||||
WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.load(new File(path));
|
||||
List<Object> paragraphs = wordMLPackage.getMainDocumentPart().getContent();
|
||||
StyleDefinitionsPart stylePart = wordMLPackage.getMainDocumentPart().getStyleDefinitionsPart();
|
||||
NumberingDefinitionsPart ndp = wordMLPackage.getMainDocumentPart().getNumberingDefinitionsPart();
|
||||
List<SectionWrapper> sections = wordMLPackage.getDocumentModel().getSections();
|
||||
|
||||
int index = 0;
|
||||
for (Object obj : paragraphs) {
|
||||
Object realObj = XmlUtils.unwrap(obj);
|
||||
if (realObj instanceof P) {
|
||||
index++;
|
||||
P paragraph = (P) realObj;
|
||||
PPr pPr = paragraph.getPPr();
|
||||
// 安全判断:pPr 为空或 pPr 中没有 sectPr,才认为是普通段落
|
||||
if (pPr == null || pPr.getSectPr() == null) {
|
||||
String firstId = Convert.getStringRandom();
|
||||
// 首先先创建段落
|
||||
JudgementWordsVO judgementWordsVO = new JudgementWordsVO();
|
||||
judgementWordsVO.setName("第" + index + "段");
|
||||
judgementWordsVO.setParentId("0");
|
||||
judgementWordsVO.setId(firstId);
|
||||
judgementWordsVOS.add(judgementWordsVO);
|
||||
judgementWordsVOS = Paragraphs.getParagraphAlignment(paragraph, stylePart, judgementWordsVOS, index, firstId);
|
||||
judgementWordsVOS = Paragraphs.getParagraphOutlineLvl(paragraph, stylePart, judgementWordsVOS, index, firstId);
|
||||
judgementWordsVOS = Paragraphs.getParagraphIndent(paragraph, stylePart, judgementWordsVOS, index, firstId);
|
||||
judgementWordsVOS = Paragraphs.getParagraphSpacing(paragraph, stylePart, judgementWordsVOS, index, firstId);
|
||||
judgementWordsVOS = Paragraphs.getParagraphList(paragraph, ndp, judgementWordsVOS, index, firstId);
|
||||
|
||||
System.out.println(judgementWordsVOS);
|
||||
} else {
|
||||
Paragraphs.getParagraphCols(paragraph, stylePart);
|
||||
}
|
||||
// 句子
|
||||
List<Object> contents = paragraph.getContent();
|
||||
for (Object content : contents) {
|
||||
if (content instanceof R) {
|
||||
R run = (R) content;
|
||||
String text = getRunText(run);
|
||||
if (text == null || text.trim().isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
// 句子-字体
|
||||
RunText.getParagraphAlignment(run, text);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
SectionPage.getSectionPageHeader(sections, wordMLPackage);
|
||||
SectionPage.getSectionPageFooter(sections, wordMLPackage);
|
||||
|
||||
}
|
||||
|
||||
// 提取 run 中的文本内容
|
||||
private static String getRunText(R run) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (Object content : run.getContent()) {
|
||||
if (content instanceof Text) {
|
||||
sb.append(((Text) content).getValue());
|
||||
} else if (content instanceof JAXBElement) {
|
||||
Object val = ((JAXBElement<?>) content).getValue();
|
||||
if (val instanceof Text) {
|
||||
sb.append(((Text) val).getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
@@ -0,0 +1,22 @@
|
||||
package pc.exam.pp.module.judgement.utils.wps_word.docx4j;
|
||||
|
||||
import pc.exam.pp.module.judgement.utils.wps_word.docx4j.vo.JudgementWordsVO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author REN
|
||||
*/
|
||||
public class DocxSetInfo {
|
||||
public static List<JudgementWordsVO> setInfo(List<JudgementWordsVO> judgementWordsVOS, String id, String parentId, String contentIn, String content, String name) {
|
||||
JudgementWordsVO judgementWordsVO = new JudgementWordsVO();
|
||||
judgementWordsVO.setId(id);
|
||||
judgementWordsVO.setParentId(parentId);
|
||||
judgementWordsVO.setContentIn(contentIn);
|
||||
judgementWordsVO.setContent(content);
|
||||
judgementWordsVO.setName(name);
|
||||
judgementWordsVOS.add(judgementWordsVO);
|
||||
return judgementWordsVOS;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,84 @@
|
||||
package pc.exam.pp.module.judgement.utils.wps_word.docx4j.paragraph;
|
||||
|
||||
import org.docx4j.openpackaging.parts.WordprocessingML.NumberingDefinitionsPart;
|
||||
import org.docx4j.wml.*;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
public class Convert {
|
||||
public static String getStringRandom() {
|
||||
String characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
Random random = new Random();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
// 生成指定长度的随机字符字符串
|
||||
for (int i = 0; i < 10; i++) {
|
||||
int randomIndex = random.nextInt(characters.length());
|
||||
// 随机字符
|
||||
sb.append(characters.charAt(randomIndex));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
public static String convertJc(String val) {
|
||||
switch (val) {
|
||||
case "left": return "左对齐";
|
||||
case "center": return "居中对齐";
|
||||
case "right": return "右对齐";
|
||||
case "both": return "两端对齐";
|
||||
case "distribute": return "分散对齐";
|
||||
default: return "未知对齐方式(" + val + ")";
|
||||
}
|
||||
}
|
||||
|
||||
public static String convertOutlineLvl(String val) {
|
||||
switch (val) {
|
||||
case "0":
|
||||
return "标题1";
|
||||
case "1":
|
||||
return "标题2";
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static Numbering.AbstractNum getAbstractNumById(NumberingDefinitionsPart ndp, BigInteger abstractNumId) {
|
||||
List<Numbering.AbstractNum> abstractNums = ndp.getJaxbElement().getAbstractNum();
|
||||
for (Numbering.AbstractNum abs : abstractNums) {
|
||||
if (abs.getAbstractNumId().equals(abstractNumId)) {
|
||||
return abs;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void printBorder(String name, CTBorder ctBorder) {
|
||||
if (ctBorder != null) {
|
||||
System.out.println(name + " 样式: " + ctBorder.getVal()); // eg: single, double, dashed
|
||||
System.out.println(name + " 颜色: #" + ctBorder.getColor()); // hex color
|
||||
System.out.println(name + " 宽度: " + ctBorder.getSz() + " 八分之一磅"); // 单位是1/8 pt
|
||||
System.out.println(name + " 间距: " + ctBorder.getSpace()); // twips之间距(可选)
|
||||
}
|
||||
}
|
||||
|
||||
public static String getFirstRunFont(P paragraph) {
|
||||
List<Object> runs = paragraph.getContent();
|
||||
for (Object runObj : runs) {
|
||||
if (runObj instanceof R) {
|
||||
R run = (R) runObj;
|
||||
RPr rPr = run.getRPr();
|
||||
if (rPr != null && rPr.getRFonts() != null) {
|
||||
RFonts fonts = rPr.getRFonts();
|
||||
if (fonts.getAscii() != null) {
|
||||
return fonts.getAscii();
|
||||
} else if (fonts.getHAnsi() != null) {
|
||||
return fonts.getHAnsi();
|
||||
}
|
||||
}
|
||||
break; // 只取第一个文字 Run
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@@ -0,0 +1,381 @@
|
||||
package pc.exam.pp.module.judgement.utils.wps_word.docx4j.paragraph;
|
||||
|
||||
import jakarta.xml.bind.JAXBElement;
|
||||
import org.docx4j.openpackaging.parts.WordprocessingML.NumberingDefinitionsPart;
|
||||
import org.docx4j.openpackaging.parts.WordprocessingML.StyleDefinitionsPart;
|
||||
import org.docx4j.wml.*;
|
||||
import pc.exam.pp.module.judgement.utils.wps_word.docx4j.DocxSetInfo;
|
||||
import pc.exam.pp.module.judgement.utils.wps_word.docx4j.vo.JudgementWordsVO;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author REN
|
||||
*/
|
||||
public class Paragraphs {
|
||||
/**
|
||||
* 段落-对齐方式
|
||||
* @param paragraph
|
||||
* @param stylePart
|
||||
* @param judgementWordsVOS
|
||||
* @param betoLong
|
||||
* @param firstId
|
||||
* @return
|
||||
*/
|
||||
public static List<JudgementWordsVO> getParagraphAlignment(P paragraph, StyleDefinitionsPart stylePart, List<JudgementWordsVO> judgementWordsVOS, int betoLong, String firstId) {
|
||||
String name = "【第" + betoLong + "段】";
|
||||
String parName = "【段落格式(常规)】【对齐方式】";
|
||||
if (paragraph == null) {
|
||||
return judgementWordsVOS;
|
||||
}
|
||||
// 先查段落自身
|
||||
PPr pPr = paragraph.getPPr();
|
||||
String parentId = Convert.getStringRandom();
|
||||
if (pPr != null && pPr.getJc() != null && pPr.getJc().getVal() != null) {
|
||||
String value = Convert.convertJc(pPr.getJc().getVal().value());
|
||||
if (value != null) {
|
||||
judgementWordsVOS = DocxSetInfo.setInfo(judgementWordsVOS, parentId, firstId, name + parName + value, name + parName + value, name);
|
||||
}
|
||||
}
|
||||
// 若段落未定义对齐方式,则尝试从样式中继承
|
||||
if (pPr != null && pPr.getPStyle() != null && stylePart != null) {
|
||||
String styleId = pPr.getPStyle().getVal();
|
||||
Style style = stylePart.getStyleById(styleId);
|
||||
if (style != null && style.getPPr() != null && style.getPPr().getJc() != null) {
|
||||
String value = Convert.convertJc(style.getPPr().getJc().getVal().value());
|
||||
if (value != null) {
|
||||
judgementWordsVOS = DocxSetInfo.setInfo(judgementWordsVOS, parentId, firstId, name + parName + value, name + parName + value, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 都没有设置,返回默认
|
||||
return judgementWordsVOS;
|
||||
}
|
||||
|
||||
// 段落-大纲级别
|
||||
public static List<JudgementWordsVO> getParagraphOutlineLvl(P paragraph, StyleDefinitionsPart stylePart, List<JudgementWordsVO> judgementWordsVOS, int betoLong, String firstId) {
|
||||
if (paragraph == null) {
|
||||
return judgementWordsVOS;
|
||||
}
|
||||
String name = "【第" + betoLong + "段】";
|
||||
String parName = "【段落格式(常规)】【大纲级别】";
|
||||
String parentId = Convert.getStringRandom();
|
||||
// 先查询自身段落数据
|
||||
PPr pPr = paragraph.getPPr();
|
||||
if (pPr != null && pPr.getOutlineLvl() != null && pPr.getOutlineLvl().getVal() != null) {
|
||||
String value = Convert.convertOutlineLvl(pPr.getOutlineLvl().getVal().toString());
|
||||
if (value != null) {
|
||||
judgementWordsVOS = DocxSetInfo.setInfo(judgementWordsVOS, parentId, firstId, name + parName + value, name + parName + value, name);
|
||||
}
|
||||
}
|
||||
// 没有设置,从公共方法中获取参数
|
||||
if (pPr != null && pPr.getPStyle() != null && stylePart != null) {
|
||||
String styleId = pPr.getPStyle().getVal();
|
||||
Style style = stylePart.getStyleById(styleId);
|
||||
if (style != null && style.getPPr() != null && style.getPPr().getJc() != null) {
|
||||
String value = Convert.convertJc(style.getPPr().getOutlineLvl().getVal().toString());
|
||||
if (value != null) {
|
||||
judgementWordsVOS = DocxSetInfo.setInfo(judgementWordsVOS, parentId, firstId, name + parName + value, name + parName + value, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
return judgementWordsVOS;
|
||||
}
|
||||
// 段落-缩进
|
||||
public static List<JudgementWordsVO> getParagraphIndent(P paragraph, StyleDefinitionsPart stylePart, List<JudgementWordsVO> judgementWordsVOS, int betoLong, String firstId) {
|
||||
if (paragraph == null) {
|
||||
return judgementWordsVOS;
|
||||
}
|
||||
String name = "【第" + betoLong + "段】";
|
||||
String parentId = Convert.getStringRandom();
|
||||
// 先查询自身段落数据
|
||||
PPr pPr = paragraph.getPPr();
|
||||
PPrBase.Ind ind = pPr.getInd();
|
||||
if (ind != null) {
|
||||
if (ind.getLeft() != null) {
|
||||
String value = ind.getLeft().intValue() + " 磅";
|
||||
String parName = "【段落格式(缩进)】【左缩进】";
|
||||
if (value != null) {
|
||||
judgementWordsVOS = DocxSetInfo.setInfo(judgementWordsVOS, parentId, firstId, name + parName + value, name + parName + value, name);
|
||||
}
|
||||
}
|
||||
if (ind.getRight() != null) {
|
||||
String value = ind.getRight().intValue() + " 磅";
|
||||
String parName = "【段落格式(缩进)】【右缩进】";
|
||||
if (value != null) {
|
||||
judgementWordsVOS = DocxSetInfo.setInfo(judgementWordsVOS, parentId, firstId, name + parName + value, name + parName + value, name);
|
||||
}
|
||||
}
|
||||
if (ind.getFirstLine() != null) {
|
||||
String value = ind.getFirstLine().intValue() + " 磅";
|
||||
String parName = "【段落格式(缩进)】【首行缩进】";
|
||||
if (value != null) {
|
||||
judgementWordsVOS = DocxSetInfo.setInfo(judgementWordsVOS, parentId, firstId, name + parName + value, name + parName + value, name);
|
||||
}
|
||||
}
|
||||
if (ind.getHanging() != null) {
|
||||
String value = ind.getHanging().intValue() + " 磅";
|
||||
String parName = "【段落格式(缩进)】【悬挂缩进】";
|
||||
if (value != null) {
|
||||
judgementWordsVOS = DocxSetInfo.setInfo(judgementWordsVOS, parentId, firstId, name + parName + value, name + parName + value, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pPr != null && pPr.getPStyle() != null && stylePart != null) {
|
||||
String styleId = pPr.getPStyle().getVal();
|
||||
Style style = stylePart.getStyleById(styleId);
|
||||
if (style != null && style.getPPr() != null && style.getPPr().getInd() != null) {
|
||||
PPrBase.Ind indStyle = style.getPPr().getInd();
|
||||
if (indStyle.getLeft() != null) {
|
||||
String value = indStyle.getLeft().intValue() + " 磅";
|
||||
String parName = "【段落格式(缩进)】【左缩进】";
|
||||
if (value != null) {
|
||||
judgementWordsVOS = DocxSetInfo.setInfo(judgementWordsVOS, parentId, firstId, name + parName + value, name + parName + value, name);
|
||||
}
|
||||
}
|
||||
if (indStyle.getRight() != null) {
|
||||
String value = indStyle.getRight().intValue() + " 磅";
|
||||
String parName = "【段落格式(缩进)】【右缩进】";
|
||||
if (value != null) {
|
||||
judgementWordsVOS = DocxSetInfo.setInfo(judgementWordsVOS, parentId, firstId, name + parName + value, name + parName + value, name);
|
||||
}
|
||||
}
|
||||
if (indStyle.getFirstLine() != null) {
|
||||
String value = indStyle.getFirstLine().intValue() + " 磅";
|
||||
String parName = "【段落格式(缩进)】【首行缩进】";
|
||||
if (value != null) {
|
||||
judgementWordsVOS = DocxSetInfo.setInfo(judgementWordsVOS, parentId, firstId, name + parName + value, name + parName + value, name);
|
||||
}
|
||||
}
|
||||
if (indStyle.getHanging() != null) {
|
||||
String value = indStyle.getHanging().intValue() + " 磅";
|
||||
String parName = "【段落格式(缩进)】【悬挂缩进】";
|
||||
if (value != null) {
|
||||
judgementWordsVOS = DocxSetInfo.setInfo(judgementWordsVOS, parentId, firstId, name + parName + value, name + parName + value, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return judgementWordsVOS;
|
||||
}
|
||||
// 段落-间距
|
||||
public static List<JudgementWordsVO> getParagraphSpacing(P paragraph, StyleDefinitionsPart stylePart, List<JudgementWordsVO> judgementWordsVOS, int betoLong, String firstId) {
|
||||
if (paragraph == null) {
|
||||
return judgementWordsVOS;
|
||||
}
|
||||
String name = "【第" + betoLong + "段】";
|
||||
String parentId = Convert.getStringRandom();
|
||||
// 先查询自身段落数据
|
||||
PPr pPr = paragraph.getPPr();
|
||||
if (pPr != null && pPr.getSpacing() != null) {
|
||||
BigInteger before = pPr.getSpacing().getBefore();
|
||||
BigInteger after = pPr.getSpacing().getAfter();
|
||||
BigInteger line = pPr.getSpacing().getLine();
|
||||
String beforeName = "【段落格式(间距)】【段前】";
|
||||
if (before != null) {
|
||||
judgementWordsVOS = DocxSetInfo.setInfo(judgementWordsVOS, parentId, firstId, name + beforeName + before, name + beforeName + before, name);
|
||||
}
|
||||
String afterName = "【段落格式(间距)】【段后】";
|
||||
if (after != null) {
|
||||
judgementWordsVOS = DocxSetInfo.setInfo(judgementWordsVOS, parentId, firstId, name + afterName + after, name + afterName + after, name);
|
||||
}
|
||||
String lineName = "【段落格式(间距)】【行距】";
|
||||
if (line != null) {
|
||||
judgementWordsVOS = DocxSetInfo.setInfo(judgementWordsVOS, parentId, firstId, name + lineName + line, name + lineName + line, name);
|
||||
}
|
||||
String linesName = "【段落格式(间距)】【行距值】";
|
||||
if (line != null) {
|
||||
judgementWordsVOS = DocxSetInfo.setInfo(judgementWordsVOS, parentId, firstId, name + linesName + line, name + linesName + line, name);
|
||||
}
|
||||
}
|
||||
if (pPr != null && pPr.getPStyle() != null && stylePart != null) {
|
||||
String styleId = pPr.getPStyle().getVal();
|
||||
Style style = stylePart.getStyleById(styleId);
|
||||
if (style != null && style.getPPr() != null && style.getPPr().getSpacing() != null) {
|
||||
PPrBase.Spacing spacing = style.getPPr().getSpacing();
|
||||
BigInteger before = spacing.getBefore();
|
||||
BigInteger after = spacing.getAfter();
|
||||
BigInteger line = spacing.getLine();
|
||||
String beforeName = "【段落格式(间距)】【段前】";
|
||||
if (before != null) {
|
||||
judgementWordsVOS = DocxSetInfo.setInfo(judgementWordsVOS, parentId, firstId, name + beforeName + before, name + beforeName + before, name);
|
||||
}
|
||||
String afterName = "【段落格式(间距)】【段后】";
|
||||
if (after != null) {
|
||||
judgementWordsVOS = DocxSetInfo.setInfo(judgementWordsVOS, parentId, firstId, name + afterName + after, name + afterName + after, name);
|
||||
}
|
||||
String lineName = "【段落格式(间距)】【行距】";
|
||||
if (line != null) {
|
||||
judgementWordsVOS = DocxSetInfo.setInfo(judgementWordsVOS, parentId, firstId, name + lineName + line, name + lineName + line, name);
|
||||
}
|
||||
String linesName = "【段落格式(间距)】【行距值】";
|
||||
if (line != null) {
|
||||
judgementWordsVOS = DocxSetInfo.setInfo(judgementWordsVOS, parentId, firstId, name + linesName + line, name + linesName + line, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
return judgementWordsVOS;
|
||||
}
|
||||
// 段落-编号列表
|
||||
public static List<JudgementWordsVO> getParagraphList(P paragraph, NumberingDefinitionsPart ndp, List<JudgementWordsVO> judgementWordsVOS, int betoLong, String firstId) {
|
||||
if (paragraph == null) {
|
||||
return judgementWordsVOS;
|
||||
}
|
||||
String name = "【第" + betoLong + "段】";
|
||||
String parentId = Convert.getStringRandom();
|
||||
// 先查询自身段落数据
|
||||
PPr pPr = paragraph.getPPr();
|
||||
if (pPr != null && pPr.getNumPr() != null && pPr.getNumPr().getNumId() != null) {
|
||||
PPrBase.NumPr numPr = pPr.getNumPr();
|
||||
BigInteger numId = numPr.getNumId() != null ? numPr.getNumId().getVal() : null;
|
||||
BigInteger ilvl = numPr.getIlvl() != null ? numPr.getIlvl().getVal() : null;
|
||||
String trueName = "【编号列表】【应用编号列表】存在";
|
||||
judgementWordsVOS = DocxSetInfo.setInfo(judgementWordsVOS, parentId, firstId, name + trueName, name + trueName, name);
|
||||
String jiBieName = "【编号列表】【列表级别】" + (ilvl != null ? ilvl.intValue() : "未知");
|
||||
judgementWordsVOS = DocxSetInfo.setInfo(judgementWordsVOS, parentId, firstId, name + jiBieName, name + jiBieName, name);
|
||||
if (numId != null && ndp != null) {
|
||||
Numbering.Num num = ndp.getJaxbElement().getNum().stream()
|
||||
.filter(n -> n.getNumId().equals(numId))
|
||||
.findFirst().orElse(null);
|
||||
|
||||
if (num != null) {
|
||||
BigInteger abstractNumId = num.getAbstractNumId().getVal();
|
||||
Numbering.AbstractNum absNum = Convert.getAbstractNumById(ndp, abstractNumId);
|
||||
|
||||
if (absNum != null && ilvl != null) {
|
||||
Lvl lvl = absNum.getLvl().stream()
|
||||
.filter(l -> l.getIlvl().equals(ilvl))
|
||||
.findFirst().orElse(null);
|
||||
|
||||
if (lvl != null) {
|
||||
String bianHaoYangShiName = "【编号列表】【编号样式】" + lvl.getNumFmt().getVal();
|
||||
judgementWordsVOS = DocxSetInfo.setInfo(judgementWordsVOS, parentId, firstId, name + bianHaoYangShiName, name + bianHaoYangShiName, name);
|
||||
String bianHaoGeShiName = "【编号列表】【编号格式】" + lvl.getLvlText().getVal();
|
||||
judgementWordsVOS = DocxSetInfo.setInfo(judgementWordsVOS, parentId, firstId, name + bianHaoGeShiName, name + bianHaoGeShiName, name);
|
||||
if ("bullet".equals(lvl.getNumFmt().getVal().value())) {
|
||||
String xiangMuFuHaoName = "【编号列表】【项目符号】" + lvl.getLvlText().getVal();
|
||||
judgementWordsVOS = DocxSetInfo.setInfo(judgementWordsVOS, parentId, firstId, name + xiangMuFuHaoName, name + xiangMuFuHaoName, name);
|
||||
String lieBiaoName = "【编号列表】【列表类型】无序列表";
|
||||
judgementWordsVOS = DocxSetInfo.setInfo(judgementWordsVOS, parentId, firstId, name + lieBiaoName, name + lieBiaoName, name);
|
||||
|
||||
} else {
|
||||
String lieBiaoName = "【编号列表】【列表类型】有序列表";
|
||||
judgementWordsVOS = DocxSetInfo.setInfo(judgementWordsVOS, parentId, firstId, name + lieBiaoName, name + lieBiaoName, name);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return judgementWordsVOS;
|
||||
}
|
||||
// 段落-边框
|
||||
// public static List<JudgementWordsVO> getParagraphBorder(P paragraph, StyleDefinitionsPart stylePart, List<JudgementWordsVO> judgementWordsVOS, int betoLong, String firstId) {
|
||||
// if (paragraph == null) {
|
||||
// return judgementWordsVOS;
|
||||
// }
|
||||
// String name = "【第" + betoLong + "段】";
|
||||
// String parentId = Convert.getStringRandom();
|
||||
// // 先查询自身段落数据
|
||||
// PPr pPr = paragraph.getPPr();
|
||||
// if (pPr != null && pPr.getPBdr() != null) {
|
||||
// PPrBase.PBdr border = pPr.getPBdr();
|
||||
// String topName = "【】【】";
|
||||
// Convert.printBorder("上边框", border.getTop());
|
||||
// Convert.printBorder("下边框", border.getBottom());
|
||||
// Convert.printBorder("左边框", border.getLeft());
|
||||
// Convert.printBorder("右边框", border.getRight());
|
||||
// Convert.printBorder("内横线", border.getBetween());
|
||||
// Convert.printBorder("内竖线", border.getBar());
|
||||
// }
|
||||
// }
|
||||
|
||||
// 段落-底纹
|
||||
public static void getParagraphShd(P paragraph, StyleDefinitionsPart stylePart) {
|
||||
if (paragraph == null) {
|
||||
return ;
|
||||
}
|
||||
// 先查询自身段落数据
|
||||
PPr pPr = paragraph.getPPr();
|
||||
if (pPr != null && pPr.getShd() != null) {
|
||||
CTShd shd = pPr.getShd();
|
||||
System.out.println("图案样式 (val): " + shd.getVal()); // 如 clear, solid, nil
|
||||
System.out.println("图案颜色 (color): " + shd.getColor()); // 图案颜色(文字上的线)
|
||||
System.out.println("填充颜色 (fill): " + shd.getFill()); // 背景色(段落底色)
|
||||
}
|
||||
}
|
||||
// 段落-首字下沉
|
||||
public static void getParagraphDropCap(P paragraph, StyleDefinitionsPart stylePart) {
|
||||
if (paragraph == null) {
|
||||
return ;
|
||||
}
|
||||
PPr pPr = paragraph.getPPr();
|
||||
if (pPr != null && pPr.getFramePr() != null) {
|
||||
CTFramePr framePr = pPr.getFramePr();
|
||||
System.out.println("---- 首字下沉 ----");
|
||||
System.out.println("存在首字下沉: 是");
|
||||
|
||||
if (framePr.getDropCap() != null) {
|
||||
System.out.println("首字位置 (dropCap): " + framePr.getDropCap().value()); // drop | none | margin
|
||||
}
|
||||
|
||||
if (framePr.getLines() != null) {
|
||||
System.out.println("下沉行数 (lines): " + framePr.getLines().intValue());
|
||||
}
|
||||
|
||||
if (framePr.getHSpace() != null) {
|
||||
System.out.println("距正文 (hSpace): " + framePr.getHSpace().intValue()); // twips
|
||||
}
|
||||
|
||||
// 获取首字字体
|
||||
String fontName = Convert.getFirstRunFont(paragraph);
|
||||
if (fontName != null) {
|
||||
System.out.println("字体: " + fontName);
|
||||
}
|
||||
} else {
|
||||
System.out.println("不存在首字下沉");
|
||||
}
|
||||
}
|
||||
// 段落-分栏
|
||||
public static void getParagraphCols(P paragraph, StyleDefinitionsPart stylePart) {
|
||||
if (paragraph == null) {
|
||||
return ;
|
||||
}
|
||||
PPr pPr = paragraph.getPPr();
|
||||
SectPr sectPr = null;
|
||||
sectPr = pPr.getSectPr();
|
||||
// 优先取段落自身的节属性
|
||||
if (pPr != null && pPr.getSectPr() != null) {
|
||||
sectPr = pPr.getSectPr();
|
||||
}
|
||||
|
||||
// 或最后一个段落中会有一个节结束的SectPr
|
||||
if (sectPr == null && paragraph.getContent().size() > 0) {
|
||||
Object lastObj = paragraph.getContent().get(paragraph.getContent().size() - 1);
|
||||
if (lastObj instanceof JAXBElement && ((JAXBElement<?>) lastObj).getValue() instanceof SectPr) {
|
||||
sectPr = (SectPr) ((JAXBElement<?>) lastObj).getValue();
|
||||
}
|
||||
}
|
||||
|
||||
if (sectPr != null && sectPr.getCols() != null) {
|
||||
CTColumns cols = sectPr.getCols();
|
||||
|
||||
System.out.println("---- 分栏信息 ----");
|
||||
System.out.println("栏数: " + (cols.getNum() != null ? cols.getNum().intValue() : "未设置"));
|
||||
System.out.println("是否栏宽相等 (equalWidth): " + (cols.isEqualWidth() ? "是" : "否"));
|
||||
System.out.println("是否有分隔线 (sep): " + (cols.isSep() ? "是" : "否"));
|
||||
|
||||
if (cols.getCol() != null && !cols.getCol().isEmpty()) {
|
||||
int index = 1;
|
||||
for (CTColumn col : cols.getCol()) {
|
||||
System.out.println("第 " + index + " 栏宽度 (twips): " + col.getW());
|
||||
System.out.println("第 " + index + " 栏间距 (twips): " + col.getSpace());
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,170 @@
|
||||
package pc.exam.pp.module.judgement.utils.wps_word.docx4j.paragraph;
|
||||
|
||||
import org.docx4j.XmlUtils;
|
||||
import org.docx4j.openpackaging.parts.WordprocessingML.StyleDefinitionsPart;
|
||||
import org.docx4j.wml.*;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class RunText {
|
||||
|
||||
// 句子-字体
|
||||
public static void getParagraphAlignment(R run, String text) {
|
||||
if (run == null) {
|
||||
return ;
|
||||
}
|
||||
RPr rPr = run.getRPr();
|
||||
String eastAsiaFont = null, asciiFont = null, hAnsiFont = null;
|
||||
String fontSize = null;
|
||||
|
||||
if (rPr != null) {
|
||||
// 字体
|
||||
if (rPr.getRFonts() != null) {
|
||||
RFonts fonts = rPr.getRFonts();
|
||||
eastAsiaFont = fonts.getEastAsia();
|
||||
asciiFont = fonts.getAscii();
|
||||
hAnsiFont = fonts.getHAnsi();
|
||||
}
|
||||
// 字号(单位是半磅;20 = 10.0pt)
|
||||
if (rPr.getSz() != null) {
|
||||
BigInteger sz = rPr.getSz().getVal();
|
||||
fontSize = sz != null ? (sz.intValue() / 2.0) + " pt" : null;
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println("文本内容: " + text);
|
||||
System.out.println("中文字体: " + (eastAsiaFont != null ? eastAsiaFont : "未设置"));
|
||||
System.out.println("西文字体(ASCII): " + (asciiFont != null ? asciiFont : "未设置"));
|
||||
System.out.println("西文字体(HAnsi): " + (hAnsiFont != null ? hAnsiFont : "未设置"));
|
||||
System.out.println("字号: " + (fontSize != null ? fontSize : "未设置"));
|
||||
System.out.println("--------");
|
||||
}
|
||||
|
||||
// 字体-字形
|
||||
public static void getParagraphFontStyle(R run, String text) {
|
||||
RPr rPr = run.getRPr();
|
||||
boolean isBold = false;
|
||||
boolean isItalic = false;
|
||||
|
||||
if (rPr != null) {
|
||||
isBold = rPr.getB() != null && rPr.getB().isVal();
|
||||
isItalic = rPr.getI() != null && rPr.getI().isVal();
|
||||
}
|
||||
|
||||
System.out.println("文本: " + text);
|
||||
if (isBold && isItalic) {
|
||||
System.out.println("样式: 加粗 + 倾斜");
|
||||
} else if (isBold) {
|
||||
System.out.println("样式: 加粗");
|
||||
} else if (isItalic) {
|
||||
System.out.println("样式: 倾斜");
|
||||
} else {
|
||||
System.out.println("样式: 常规");
|
||||
}
|
||||
System.out.println("--------");
|
||||
}
|
||||
// 字体-所有文字
|
||||
public static void getParagraphFontColor(R run, StyleDefinitionsPart stylePart, String text) {
|
||||
RPr rPr = run.getRPr();
|
||||
|
||||
String color = "默认";
|
||||
String underlineVal = "无";
|
||||
String underlineColor = "默认";
|
||||
|
||||
if (rPr != null) {
|
||||
if (rPr.getColor() != null && rPr.getColor().getVal() != null) {
|
||||
color = rPr.getColor().getVal(); // 如 "FF0000"
|
||||
}
|
||||
|
||||
if (rPr.getU() != null) {
|
||||
if (rPr.getU().getVal() != null) {
|
||||
underlineVal = rPr.getU().getVal().value(); // single, double, none 等
|
||||
}
|
||||
if (rPr.getU().getColor() != null) {
|
||||
underlineColor = rPr.getU().getColor(); // 例如 "0000FF"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println("文本: " + text);
|
||||
System.out.println("字体颜色: " + color);
|
||||
System.out.println("下划线样式: " + underlineVal);
|
||||
System.out.println("下划线颜色: " + underlineColor);
|
||||
System.out.println("--------");
|
||||
}
|
||||
// 字体-效果-删除线
|
||||
public static void getParagraphStrike(R run, String text) {
|
||||
RPr rPr = run.getRPr();
|
||||
|
||||
boolean isStrike = false;
|
||||
boolean isDoubleStrike = false;
|
||||
String verticalAlign = "正常";
|
||||
|
||||
if (rPr != null) {
|
||||
isStrike = rPr.getStrike() != null && rPr.getStrike().isVal();
|
||||
isDoubleStrike = rPr.getDstrike() != null && rPr.getDstrike().isVal();
|
||||
|
||||
if (rPr.getVertAlign() != null && rPr.getVertAlign().getVal() != null) {
|
||||
verticalAlign = rPr.getVertAlign().getVal().value(); // superscript or subscript
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println("文本: " + text);
|
||||
System.out.println("删除线: " + (isStrike ? "有" : "无"));
|
||||
System.out.println("双删除线: " + (isDoubleStrike ? "有" : "无"));
|
||||
System.out.println("上下标: " + verticalAlign); // superscript/subscript/normal
|
||||
System.out.println("--------");
|
||||
}
|
||||
|
||||
// 字体-字符间距
|
||||
public static void getParagraphFontSpacing(R run, String text) {
|
||||
RPr rPr = run.getRPr();
|
||||
|
||||
String scale = "100%";
|
||||
String spacing = "0";
|
||||
String position = "0";
|
||||
String kern = "无";
|
||||
String snapToGrid = "否";
|
||||
|
||||
if (rPr != null) {
|
||||
if (rPr.getW() != null && rPr.getW().getVal() != null) {
|
||||
scale = rPr.getW().getVal().toString() + "%";
|
||||
}
|
||||
if (rPr.getSpacing() != null && rPr.getSpacing().getVal() != null) {
|
||||
spacing = rPr.getSpacing().getVal().toString() + " twips";
|
||||
}
|
||||
if (rPr.getPosition() != null && rPr.getPosition().getVal() != null) {
|
||||
position = rPr.getPosition().getVal().toString() + " pt(1/2)";
|
||||
}
|
||||
if (rPr.getKern() != null && rPr.getKern().getVal() != null) {
|
||||
kern = rPr.getKern().getVal().toString() + " (1/100 pt)";
|
||||
}
|
||||
if (rPr.getSnapToGrid() != null) {
|
||||
snapToGrid = rPr.getSnapToGrid().isVal() ? "是" : "否";
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println("文本: " + text);
|
||||
System.out.println("缩放比例: " + scale);
|
||||
System.out.println("字符间距: " + spacing);
|
||||
System.out.println("字符位置: " + position);
|
||||
System.out.println("最小间距 (Kern): " + kern);
|
||||
System.out.println("对齐到网格: " + snapToGrid);
|
||||
System.out.println("--------");
|
||||
}
|
||||
// 字体-文本效果
|
||||
public static void getParagraphTextEffect(R run, String text) {
|
||||
|
||||
// 转换为 XML 文本
|
||||
String runXml = XmlUtils.marshaltoString(run, true);
|
||||
System.out.println("文本: " + text);
|
||||
|
||||
// 检测特效
|
||||
System.out.println("文本填充 (textFill): " + (runXml.contains("w14:textFill") ? "是" : "否"));
|
||||
System.out.println("文本轮廓 (textOutline): " + (runXml.contains("w14:textOutline") ? "是" : "否"));
|
||||
System.out.println("阴影 (shadow): " + (runXml.contains("w14:shadow") ? "是" : "否"));
|
||||
System.out.println("倒影 (reflection): " + (runXml.contains("w14:reflection") ? "是" : "否"));
|
||||
System.out.println("发光 (glow): " + (runXml.contains("w14:glow") ? "是" : "否"));
|
||||
System.out.println("--------");
|
||||
}
|
||||
}
|
@@ -0,0 +1,309 @@
|
||||
package pc.exam.pp.module.judgement.utils.wps_word.docx4j.section;
|
||||
|
||||
import jakarta.xml.bind.JAXBElement;
|
||||
import org.docx4j.XmlUtils;
|
||||
import org.docx4j.model.structure.HeaderFooterPolicy;
|
||||
import org.docx4j.model.structure.SectionWrapper;
|
||||
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
|
||||
import org.docx4j.openpackaging.parts.WordprocessingML.FooterPart;
|
||||
import org.docx4j.openpackaging.parts.WordprocessingML.HeaderPart;
|
||||
import org.docx4j.wml.*;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author REN
|
||||
*/
|
||||
public class SectionPage {
|
||||
|
||||
// 节-上下左右设置页边距
|
||||
public static void getSectionPageSettings(P paragraph) {
|
||||
PPr pPr = paragraph.getPPr();
|
||||
if (pPr != null && pPr.getSectPr() != null) {
|
||||
SectPr sectPr = pPr.getSectPr();
|
||||
SectPr.PgMar pgMar = sectPr.getPgMar();
|
||||
|
||||
if (pgMar != null) {
|
||||
System.out.println("---- 节页面设置 ----");
|
||||
System.out.println("上边距 (twips): " + pgMar.getTop());
|
||||
System.out.println("下边距 (twips): " + pgMar.getBottom());
|
||||
System.out.println("左边距 (twips): " + pgMar.getLeft());
|
||||
System.out.println("右边距 (twips): " + pgMar.getRight());
|
||||
System.out.println("装订线宽度 (twips): " + pgMar.getGutter());
|
||||
System.out.println("-------------------");
|
||||
}
|
||||
}
|
||||
}
|
||||
// 纸张方向 大小
|
||||
public static void getSectionPageSize(P paragraph) {
|
||||
PPr pPr = paragraph.getPPr();
|
||||
if (pPr != null && pPr.getSectPr() != null) {
|
||||
SectPr sectPr = pPr.getSectPr();
|
||||
SectPr.PgSz pgSz = sectPr.getPgSz();
|
||||
|
||||
if (pgSz != null) {
|
||||
System.out.println("---- 节页面大小设置 ----");
|
||||
|
||||
// 页面宽度 & 高度(单位是 twips:1/20 pt)
|
||||
System.out.println("页面宽度 (twips): " + pgSz.getW());
|
||||
System.out.println("页面高度 (twips): " + pgSz.getH());
|
||||
double widthMM = twipToMM(Integer.parseInt(pgSz.getW().toString()));
|
||||
double heightMM = twipToMM(Integer.parseInt(pgSz.getH().toString()));
|
||||
|
||||
// 保留一位小数误差范围
|
||||
double w = Math.min(widthMM, heightMM);
|
||||
double h = Math.max(widthMM, heightMM);
|
||||
String pageSize = "";
|
||||
if (Math.abs(w - 210) < 5 && Math.abs(h - 297) < 5) {
|
||||
pageSize = "A4";
|
||||
}
|
||||
if (Math.abs(w - 297) < 5 && Math.abs(h - 420) < 5) {
|
||||
pageSize = "A3";
|
||||
}
|
||||
if (Math.abs(w - 216) < 5 && Math.abs(h - 279) < 5) {
|
||||
pageSize = "Letter";
|
||||
}
|
||||
if (Math.abs(w - 216) < 5 && Math.abs(h - 356) < 5) {
|
||||
pageSize = "Legal";
|
||||
}
|
||||
if (Math.abs(w - 176) < 5 && Math.abs(h - 250) < 5) {
|
||||
pageSize = "B5";
|
||||
}
|
||||
if (Math.abs(w - 184) < 5 && Math.abs(h - 267) < 5) {
|
||||
pageSize = "Executive";
|
||||
}
|
||||
System.out.println("纸型: " + pageSize);
|
||||
// 页面方向
|
||||
STPageOrientation orientation = pgSz.getOrient();
|
||||
if (orientation != null) {
|
||||
System.out.println("纸张方向: " + ("landscape".equals(orientation.value()) ? "横向" : "纵向"));
|
||||
} else {
|
||||
System.out.println("纸张方向: 默认纵向");
|
||||
}
|
||||
|
||||
System.out.println("----------------------");
|
||||
}
|
||||
}
|
||||
}
|
||||
public static double twipToMM(int twips) {
|
||||
return twips * 0.0176389;
|
||||
}
|
||||
// 水印
|
||||
public static void getSectionPageWatermark(R run) {
|
||||
// 检查是否包含 Drawing(图片水印)
|
||||
if (XmlUtils.marshaltoString(run, true).contains("<w:drawing")) {
|
||||
System.out.println("水印类型:图片水印(Drawing)");
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查是否包含 VML 文字水印(WordArt)
|
||||
if (XmlUtils.marshaltoString(run, true).contains("<v:shape") &&
|
||||
XmlUtils.marshaltoString(run, true).contains("style=")) {
|
||||
System.out.println("水印类型:文字水印(WordArt)");
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 页眉
|
||||
public static void getSectionPageHeader(List<org.docx4j.model.structure.SectionWrapper> sections, WordprocessingMLPackage wordMLPackage) {
|
||||
for (int i = 0; i < sections.size(); i++) {
|
||||
org.docx4j.model.structure.SectionWrapper section = sections.get(i);
|
||||
HeaderFooterPolicy hfp = section.getHeaderFooterPolicy();
|
||||
System.out.println("📄 节 " + (i + 1));
|
||||
|
||||
if (hfp.getDefaultHeader() != null) {
|
||||
System.out.println("【默认/奇数页 页眉】");
|
||||
extractTextFromHeader(hfp.getDefaultHeader(), wordMLPackage);
|
||||
}
|
||||
|
||||
if (hfp.getEvenHeader() != null) {
|
||||
System.out.println("【偶数页 页眉】");
|
||||
extractTextFromHeader(hfp.getEvenHeader(), wordMLPackage);
|
||||
}
|
||||
|
||||
if (hfp.getFirstHeader() != null) {
|
||||
System.out.println("【首页 页眉】");
|
||||
extractTextFromHeader(hfp.getFirstHeader(), wordMLPackage);
|
||||
}
|
||||
|
||||
System.out.println("----------------------------");
|
||||
}
|
||||
}
|
||||
|
||||
// 页脚
|
||||
public static void getSectionPageFooter(List<org.docx4j.model.structure.SectionWrapper> sections, WordprocessingMLPackage wordMLPackage) {
|
||||
for (int i = 0; i < sections.size(); i++) {
|
||||
SectionWrapper section = sections.get(i);
|
||||
HeaderFooterPolicy hfp = section.getHeaderFooterPolicy();
|
||||
System.out.println("📄 节 " + (i + 1));
|
||||
|
||||
if (hfp.getDefaultFooter() != null) {
|
||||
System.out.println("【默认/奇数页 页脚】");
|
||||
extractTextFromFooter(hfp.getDefaultFooter(), wordMLPackage);
|
||||
}
|
||||
|
||||
if (hfp.getEvenFooter() != null) {
|
||||
System.out.println("【偶数页 页脚】");
|
||||
extractTextFromFooter(hfp.getEvenFooter(), wordMLPackage);
|
||||
}
|
||||
|
||||
if (hfp.getFirstFooter() != null) {
|
||||
System.out.println("【首页 页脚】");
|
||||
extractTextFromFooter(hfp.getFirstFooter(), wordMLPackage);
|
||||
}
|
||||
|
||||
System.out.println("----------------------------");
|
||||
}
|
||||
}
|
||||
|
||||
public static void extractTextFromHeader(HeaderPart headerPart, WordprocessingMLPackage wordMLPackage) {
|
||||
List<Object> contents = headerPart.getContent();
|
||||
for (Object obj : contents) {
|
||||
if (obj instanceof P) {
|
||||
P paragraph = (P) obj;
|
||||
StringBuilder text = new StringBuilder();
|
||||
String font = null;
|
||||
Double fontSizePt = null;
|
||||
String colorHex = null;
|
||||
String alignment = null;
|
||||
|
||||
// 获取对齐方式
|
||||
if (paragraph.getPPr() != null && paragraph.getPPr().getJc() != null) {
|
||||
alignment = paragraph.getPPr().getJc().getVal().value();
|
||||
}
|
||||
|
||||
// 获取文本与样式
|
||||
for (Object o : paragraph.getContent()) {
|
||||
if (o instanceof R) {
|
||||
R run = (R) o;
|
||||
|
||||
// 样式信息
|
||||
RPr rPr = run.getRPr();
|
||||
if (rPr != null) {
|
||||
if (rPr.getRFonts() != null) {
|
||||
font = rPr.getRFonts().getAscii();
|
||||
}
|
||||
if (rPr.getSz() != null) {
|
||||
fontSizePt = rPr.getSz().getVal().intValue() / 2.0;
|
||||
}
|
||||
if (rPr.getColor() != null) {
|
||||
colorHex = rPr.getColor().getVal();
|
||||
}
|
||||
}
|
||||
|
||||
// 文本信息
|
||||
for (Object rContent : run.getContent()) {
|
||||
Object val = (rContent instanceof JAXBElement)
|
||||
? ((JAXBElement<?>) rContent).getValue()
|
||||
: rContent;
|
||||
|
||||
if (val instanceof Text) {
|
||||
text.append(((Text) val).getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 输出页眉段落信息
|
||||
if (text.length() > 0) {
|
||||
System.out.println("页眉文本: " + text);
|
||||
System.out.println("字体: " + font);
|
||||
System.out.println("字号: " + fontSizePt + " pt");
|
||||
System.out.println("颜色: " + colorHex);
|
||||
System.out.println("对齐方式: " + alignment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 提取页边距(节属性中的 header/left/right)
|
||||
SectPr sectPr = wordMLPackage.getMainDocumentPart().getJaxbElement().getBody().getSectPr();
|
||||
if (sectPr != null && sectPr.getPgMar() != null) {
|
||||
SectPr.PgMar pgMar = sectPr.getPgMar();
|
||||
if (pgMar.getHeader() != null) {
|
||||
System.out.println("页眉距顶端: " + (pgMar.getHeader().intValue() / 20.0) + " pt");
|
||||
}
|
||||
if (pgMar.getLeft() != null) {
|
||||
System.out.println("左边距: " + (pgMar.getLeft().intValue() / 20.0) + " pt");
|
||||
}
|
||||
if (pgMar.getRight() != null) {
|
||||
System.out.println("右边距: " + (pgMar.getRight().intValue() / 20.0) + " pt");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void extractTextFromFooter(FooterPart footerPart, WordprocessingMLPackage wordMLPackage) {
|
||||
List<Object> contents = footerPart.getContent();
|
||||
for (Object obj : contents) {
|
||||
if (obj instanceof P) {
|
||||
P paragraph = (P) obj;
|
||||
StringBuilder text = new StringBuilder();
|
||||
String font = null;
|
||||
Double fontSizePt = null;
|
||||
String colorHex = null;
|
||||
String alignment = null;
|
||||
|
||||
// 获取对齐方式
|
||||
if (paragraph.getPPr() != null && paragraph.getPPr().getJc() != null) {
|
||||
alignment = paragraph.getPPr().getJc().getVal().value();
|
||||
}
|
||||
|
||||
// 遍历 run 内容
|
||||
for (Object o : paragraph.getContent()) {
|
||||
if (o instanceof R) {
|
||||
R run = (R) o;
|
||||
|
||||
// 获取样式
|
||||
RPr rPr = run.getRPr();
|
||||
if (rPr != null) {
|
||||
if (rPr.getRFonts() != null) {
|
||||
font = rPr.getRFonts().getAscii();
|
||||
}
|
||||
if (rPr.getSz() != null) {
|
||||
fontSizePt = rPr.getSz().getVal().intValue() / 2.0;
|
||||
}
|
||||
if (rPr.getColor() != null) {
|
||||
colorHex = rPr.getColor().getVal();
|
||||
}
|
||||
}
|
||||
|
||||
// 提取文本
|
||||
for (Object rContent : run.getContent()) {
|
||||
Object val = rContent instanceof JAXBElement ? ((JAXBElement<?>) rContent).getValue() : rContent;
|
||||
if (val instanceof Text) {
|
||||
text.append(((Text) val).getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 打印段落信息
|
||||
if (text.length() > 0) {
|
||||
System.out.println("页脚文本: " + text);
|
||||
System.out.println("字体: " + font);
|
||||
System.out.println("字号: " + fontSizePt + " pt");
|
||||
System.out.println("颜色: " + colorHex);
|
||||
System.out.println("对齐方式: " + alignment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 获取 section 页边距信息
|
||||
SectPr sectPr = wordMLPackage.getMainDocumentPart().getJaxbElement().getBody().getSectPr();
|
||||
if (sectPr != null && sectPr.getPgMar() != null) {
|
||||
SectPr.PgMar pgMar = sectPr.getPgMar();
|
||||
if (pgMar.getFooter() != null) {
|
||||
System.out.println("页脚距底端: " + (pgMar.getFooter().intValue() / 20.0) + " pt");
|
||||
}
|
||||
if (pgMar.getLeft() != null) {
|
||||
System.out.println("左边距: " + (pgMar.getLeft().intValue() / 20.0) + " pt");
|
||||
}
|
||||
if (pgMar.getRight() != null) {
|
||||
System.out.println("右边距: " + (pgMar.getRight().intValue() / 20.0) + " pt");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
package pc.exam.pp.module.judgement.utils.wps_word.docx4j.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author REN
|
||||
*/
|
||||
@Data
|
||||
public class JudgementWordsVO {
|
||||
|
||||
// 名称(相当于类型)
|
||||
private String name;
|
||||
|
||||
// 考点
|
||||
private String content;
|
||||
|
||||
// 考点名称
|
||||
private String contentIn;
|
||||
|
||||
// 父节点
|
||||
private String parentId;
|
||||
|
||||
// 节点id
|
||||
private String id;
|
||||
}
|
52
pom.xml
52
pom.xml
@@ -141,32 +141,32 @@
|
||||
|
||||
<!-- 使用 huawei / aliyun 的 Maven 源,提升下载速度 -->
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>huaweicloud</id>
|
||||
<name>huawei</name>
|
||||
<url>https://mirrors.huaweicloud.com/repository/maven/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>aliyunmaven</id>
|
||||
<name>aliyun</name>
|
||||
<url>https://maven.aliyun.com/repository/public</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>spring-milestones</id>
|
||||
<name>Spring Milestones</name>
|
||||
<url>https://repo.spring.io/milestone</url>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>spring-snapshots</id>
|
||||
<name>Spring Snapshots</name>
|
||||
<url>https://repo.spring.io/snapshot</url>
|
||||
<releases>
|
||||
<enabled>false</enabled>
|
||||
</releases>
|
||||
</repository>
|
||||
<!-- <repository>-->
|
||||
<!-- <id>huaweicloud</id>-->
|
||||
<!-- <name>huawei</name>-->
|
||||
<!-- <url>https://mirrors.huaweicloud.com/repository/maven/</url>-->
|
||||
<!-- </repository>-->
|
||||
<!-- <repository>-->
|
||||
<!-- <id>aliyunmaven</id>-->
|
||||
<!-- <name>aliyun</name>-->
|
||||
<!-- <url>https://maven.aliyun.com/repository/public</url>-->
|
||||
<!-- </repository>-->
|
||||
<!-- <repository>-->
|
||||
<!-- <id>spring-milestones</id>-->
|
||||
<!-- <name>Spring Milestones</name>-->
|
||||
<!-- <url>https://repo.spring.io/milestone</url>-->
|
||||
<!-- <snapshots>-->
|
||||
<!-- <enabled>false</enabled>-->
|
||||
<!-- </snapshots>-->
|
||||
<!-- </repository>-->
|
||||
<!-- <repository>-->
|
||||
<!-- <id>spring-snapshots</id>-->
|
||||
<!-- <name>Spring Snapshots</name>-->
|
||||
<!-- <url>https://repo.spring.io/snapshot</url>-->
|
||||
<!-- <releases>-->
|
||||
<!-- <enabled>false</enabled>-->
|
||||
<!-- </releases>-->
|
||||
<!-- </repository>-->
|
||||
<repository>
|
||||
<id>maven-central</id>
|
||||
<name>Maven Central Repository</name>
|
||||
|
Reference in New Issue
Block a user