feat: bookmark replace
This commit is contained in:
parent
dfee41ef5a
commit
5c8468260a
@ -3,8 +3,13 @@ package com.wmyun.farmwork.word.core;
|
|||||||
import cn.hutool.core.io.FileUtil;
|
import cn.hutool.core.io.FileUtil;
|
||||||
import cn.hutool.core.io.IoUtil;
|
import cn.hutool.core.io.IoUtil;
|
||||||
import cn.hutool.core.io.file.FileNameUtil;
|
import cn.hutool.core.io.file.FileNameUtil;
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
import com.wmyun.farmwork.word.core.model.BookmarkInfo;
|
import com.wmyun.farmwork.word.core.model.BookmarkInfo;
|
||||||
import com.wmyun.farmwork.word.core.model.BookmarkReplaceDataModel;
|
import com.wmyun.farmwork.word.core.model.BookmarkReplaceDataModel;
|
||||||
|
import com.wmyun.farmwork.word.core.model.TableBookmarkInfo;
|
||||||
|
import com.wmyun.farmwork.word.core.model.ext.ListExData;
|
||||||
|
import com.wmyun.farmwork.word.core.model.ext.TableExData;
|
||||||
|
import com.wmyun.farmwork.word.core.model.ext.TextExData;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.poi.xwpf.usermodel.*;
|
import org.apache.poi.xwpf.usermodel.*;
|
||||||
import org.apache.xmlbeans.XmlCursor;
|
import org.apache.xmlbeans.XmlCursor;
|
||||||
@ -38,15 +43,31 @@ public class BookmarkExec {
|
|||||||
private static final String ATTR_BOOKMARK_ID = "w:id";
|
private static final String ATTR_BOOKMARK_ID = "w:id";
|
||||||
private static final String ATTR_BOOKMARK_NAME = "w:name";
|
private static final String ATTR_BOOKMARK_NAME = "w:name";
|
||||||
|
|
||||||
|
private static final String TABLE_ROW_BOOKMARK_START = "w:colFirst";
|
||||||
|
private static final String TABLE_ROW_BOOKMARK_END = "w:colLast";
|
||||||
|
|
||||||
public static File replace(List<BookmarkReplaceDataModel> data, byte[] word, File file) {
|
public static File replace(List<BookmarkReplaceDataModel> data, byte[] word, File file) {
|
||||||
Map<String, BookmarkReplaceDataModel> dataMap = data.stream()
|
|
||||||
.collect(Collectors.toMap(BookmarkReplaceDataModel::getName, b -> b));
|
|
||||||
try (XWPFDocument doc = new XWPFDocument(IoUtil.toStream(word))) {
|
try (XWPFDocument doc = new XWPFDocument(IoUtil.toStream(word))) {
|
||||||
|
|
||||||
|
// 收集文档中所有段落
|
||||||
List<XWPFParagraph> allParagraphs = new ArrayList<>();
|
List<XWPFParagraph> allParagraphs = new ArrayList<>();
|
||||||
collectionAllParagraphs(doc, allParagraphs);
|
collectionAllParagraphs(doc, allParagraphs);
|
||||||
|
// 列表书签
|
||||||
List<String> listMark = new ArrayList<>();
|
List<String> listMark = new ArrayList<>();
|
||||||
|
// 表格内书签信息
|
||||||
|
List<TableBookmarkInfo> tableBookmarkInfos = queryBookmarkInTable(doc);
|
||||||
|
// 所有待替换数据
|
||||||
|
Map<String, BookmarkReplaceDataModel> allDataMap = data.stream()
|
||||||
|
.collect(Collectors.toMap(BookmarkReplaceDataModel::getName, b -> b));
|
||||||
|
// 常规替换数据
|
||||||
|
Map<String, BookmarkReplaceDataModel> dataMap = data.stream()
|
||||||
|
.filter(d -> {
|
||||||
|
List<String> bookmarks = tableBookmarkInfos.stream()
|
||||||
|
.flatMap(info -> info.getBookmark().stream())
|
||||||
|
.toList();
|
||||||
|
return bookmarks.contains(d.getName());
|
||||||
|
}) // 过滤表格中需要整行替换的书签
|
||||||
|
.collect(Collectors.toMap(BookmarkReplaceDataModel::getName, b -> b));
|
||||||
|
|
||||||
// 处理段落中书签
|
// 处理段落中书签
|
||||||
for (XWPFParagraph paragraph : allParagraphs) {
|
for (XWPFParagraph paragraph : allParagraphs) {
|
||||||
@ -76,7 +97,9 @@ public class BookmarkExec {
|
|||||||
ctr.removeT(i);
|
ctr.removeT(i);
|
||||||
}
|
}
|
||||||
CTText newTextNode = ctr.addNewT();
|
CTText newTextNode = ctr.addNewT();
|
||||||
newTextNode.setStringValue(model.getExtData().getValue());
|
if (model.getExtData() instanceof TextExData exData) {
|
||||||
|
newTextNode.setStringValue(exData.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
// 删除其余的run
|
// 删除其余的run
|
||||||
for (int i = startIdx + 1; i < endIdx; i++) {
|
for (int i = startIdx + 1; i < endIdx; i++) {
|
||||||
@ -92,10 +115,26 @@ public class BookmarkExec {
|
|||||||
|
|
||||||
// 处理列表
|
// 处理列表
|
||||||
for (String mk : listMark) {
|
for (String mk : listMark) {
|
||||||
handleListContent(doc, new String[]{"行1", "行2", "行3", "行4", "行5"}, mk);
|
if (allDataMap.containsKey(mk)) {
|
||||||
|
BookmarkReplaceDataModel model = allDataMap.get(mk);
|
||||||
|
if (model.getExtData() instanceof ListExData exData) {
|
||||||
|
handleListContent(doc, exData.getValue(), mk);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 处理表格
|
||||||
|
for (TableBookmarkInfo tableBkInfo : tableBookmarkInfos) {
|
||||||
|
String masterBookmark = tableBkInfo.getMasterBookmark();
|
||||||
|
if (allDataMap.containsKey(masterBookmark)) {
|
||||||
|
BookmarkReplaceDataModel model = allDataMap.get(masterBookmark);
|
||||||
|
if (model.getExtData() instanceof TableExData exData) {
|
||||||
|
handleTableContent(doc, tableBkInfo, exData.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存文件
|
||||||
File outFile = FileUtil.newFile(tmpDir + "gen/" + FileNameUtil.getName(file));
|
File outFile = FileUtil.newFile(tmpDir + "gen/" + FileNameUtil.getName(file));
|
||||||
File parentDir = outFile.getParentFile();
|
File parentDir = outFile.getParentFile();
|
||||||
if (!parentDir.exists()) {
|
if (!parentDir.exists()) {
|
||||||
@ -110,6 +149,126 @@ public class BookmarkExec {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理word中的表格,删除模板行,新增行
|
||||||
|
*/
|
||||||
|
private static void handleTableContent(XWPFDocument doc, TableBookmarkInfo tableBkInfo, List<Map<String, String>> values) {
|
||||||
|
List<XWPFTable> tables = doc.getTables();
|
||||||
|
int tableIdx = tableBkInfo.getTableIdx();
|
||||||
|
XWPFTable table = tables.get(tableIdx);
|
||||||
|
int templateRowIdx = tableBkInfo.getTemplateRowIdx();
|
||||||
|
|
||||||
|
// 获取模板行
|
||||||
|
XWPFTableRow templateRow = table.getRow(templateRowIdx);
|
||||||
|
|
||||||
|
// 提取各列的书签名称
|
||||||
|
List<String> columnKeys = new ArrayList<>();
|
||||||
|
for (XWPFTableCell cell : templateRow.getTableCells()) {
|
||||||
|
String bookmarkName = null;
|
||||||
|
// 遍历单元格的段落,查找第一个书签
|
||||||
|
for (XWPFParagraph paragraph : cell.getParagraphs()) {
|
||||||
|
for (CTBookmark bookmark : paragraph.getCTP().getBookmarkStartList()) {
|
||||||
|
bookmarkName = bookmark.getName();
|
||||||
|
break; // 取第一个书签
|
||||||
|
}
|
||||||
|
if (bookmarkName != null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (bookmarkName == null) {
|
||||||
|
throw new IllegalArgumentException("模板行的单元格中未找到书签");
|
||||||
|
}
|
||||||
|
columnKeys.add(bookmarkName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 插入新行并填充数据
|
||||||
|
int currentInsertPos = templateRowIdx; // 初始插入位置为模板行的索引
|
||||||
|
for (Map<String, String> dataRow : values) {
|
||||||
|
// 在指定位置插入新行
|
||||||
|
XWPFTableRow newRow = table.insertNewTableRow(currentInsertPos);
|
||||||
|
// 复制模板行的每个单元格的格式并填充数据
|
||||||
|
for (int i = 0; i < templateRow.getTableCells().size(); i++) {
|
||||||
|
XWPFTableCell templateCell = templateRow.getCell(i);
|
||||||
|
XWPFTableCell newCell = newRow.addNewTableCell();
|
||||||
|
|
||||||
|
// 复制单元格样式
|
||||||
|
CTTcPr templateTcPr = templateCell.getCTTc().getTcPr();
|
||||||
|
if (templateTcPr != null) {
|
||||||
|
newCell.getCTTc().setTcPr((CTTcPr) templateTcPr.copy());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置单元格内容
|
||||||
|
String key = columnKeys.get(i);
|
||||||
|
String value = dataRow.getOrDefault(key, "");
|
||||||
|
// 清除单元格原有内容
|
||||||
|
newCell.removeParagraph(0); // 移除默认创建的段落
|
||||||
|
XWPFParagraph paragraph = newCell.addParagraph();
|
||||||
|
XWPFRun run = paragraph.createRun();
|
||||||
|
run.setText(value);
|
||||||
|
}
|
||||||
|
currentInsertPos++; // 插入位置后移
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除模板行(此时模板行的新索引为原索引加上插入的行数)
|
||||||
|
int finalTemplateRowIndex = templateRowIdx + values.size();
|
||||||
|
table.removeRow(finalTemplateRowIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询word中表格中需要整行替换的书签
|
||||||
|
*/
|
||||||
|
private static List<TableBookmarkInfo> queryBookmarkInTable(XWPFDocument doc) {
|
||||||
|
|
||||||
|
List<TableBookmarkInfo> list = new ArrayList<>();
|
||||||
|
List<XWPFTable> tables = doc.getTables();
|
||||||
|
|
||||||
|
// 表格
|
||||||
|
for (XWPFTable table : tables) {
|
||||||
|
int idx = tables.indexOf(table);
|
||||||
|
TableBookmarkInfo info = new TableBookmarkInfo();
|
||||||
|
List<String> filterMark = new ArrayList<>();
|
||||||
|
|
||||||
|
// 行
|
||||||
|
for (XWPFTableRow row : table.getRows()) {
|
||||||
|
int currentRowIdx = table.getRows().indexOf(row);
|
||||||
|
|
||||||
|
// 单元格
|
||||||
|
for (XWPFTableCell cell : row.getTableCells()) {
|
||||||
|
boolean isReplaceRow = false;
|
||||||
|
List<XWPFParagraph> paragraphs = cell.getParagraphs();
|
||||||
|
for (XWPFParagraph paragraph : paragraphs) {
|
||||||
|
CTP ctp = paragraph.getCTP();
|
||||||
|
List<CTBookmark> bookmark = ctp.getBookmarkStartList();
|
||||||
|
|
||||||
|
// 单元格内书签
|
||||||
|
for (CTBookmark bk : bookmark) {
|
||||||
|
NamedNodeMap attr = bk.getDomNode().getAttributes();
|
||||||
|
Optional<Node> startAttrOpt = Optional.ofNullable(attr.getNamedItem(TABLE_ROW_BOOKMARK_START));
|
||||||
|
Optional<Node> endAttrOpt = Optional.ofNullable(attr.getNamedItem(TABLE_ROW_BOOKMARK_END));
|
||||||
|
|
||||||
|
// 是否是整行是书签,如果是,标记这一行为模板
|
||||||
|
if (startAttrOpt.map(Node::getNodeValue).isPresent() && endAttrOpt.map(Node::getNodeValue).isPresent()) {
|
||||||
|
filterMark.add(bk.getName());
|
||||||
|
isReplaceRow = true;
|
||||||
|
info.setTableIdx(idx);
|
||||||
|
info.setTemplateRowIdx(currentRowIdx);
|
||||||
|
info.setMasterBookmark(bk.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 收集模板行的所有书签
|
||||||
|
if (isReplaceRow) {
|
||||||
|
filterMark.addAll(bookmark.stream().map(CTBookmark::getName).collect(Collectors.toSet()));
|
||||||
|
info.setBookmark(filterMark);
|
||||||
|
list.add(info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询本段中的书签信息
|
* 查询本段中的书签信息
|
||||||
*
|
*
|
||||||
@ -138,6 +297,9 @@ public class BookmarkExec {
|
|||||||
return new ArrayList<>(set);
|
return new ArrayList<>(set);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查找书签在段落中包含的位置
|
||||||
|
*/
|
||||||
private static void queryBookmarkIdx(XWPFParagraph paragraph, BookmarkInfo info) {
|
private static void queryBookmarkIdx(XWPFParagraph paragraph, BookmarkInfo info) {
|
||||||
List<XWPFRun> runs = paragraph.getRuns();
|
List<XWPFRun> runs = paragraph.getRuns();
|
||||||
boolean foundStart = false;
|
boolean foundStart = false;
|
||||||
@ -198,9 +360,6 @@ public class BookmarkExec {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取文档中所有段落
|
* 获取文档中所有段落
|
||||||
*
|
|
||||||
* @param doc 文档
|
|
||||||
* @param allParagraphs 段落
|
|
||||||
*/
|
*/
|
||||||
private static void collectionAllParagraphs(XWPFDocument doc, List<XWPFParagraph> allParagraphs) {
|
private static void collectionAllParagraphs(XWPFDocument doc, List<XWPFParagraph> allParagraphs) {
|
||||||
|
|
||||||
@ -241,9 +400,9 @@ public class BookmarkExec {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理行新增
|
* 处理列表行新增
|
||||||
*/
|
*/
|
||||||
public static void handleListContent(XWPFDocument doc, String[] newListItems, String bookmarkName) {
|
public static void handleListContent(XWPFDocument doc, List<String> newListItems, String bookmarkName) {
|
||||||
// 查找书签所在的段落
|
// 查找书签所在的段落
|
||||||
XWPFParagraph bookmarkParagraph = findBookmarkParagraph(doc, bookmarkName);
|
XWPFParagraph bookmarkParagraph = findBookmarkParagraph(doc, bookmarkName);
|
||||||
if (bookmarkParagraph == null) {
|
if (bookmarkParagraph == null) {
|
||||||
@ -316,7 +475,7 @@ public class BookmarkExec {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void insertNewListItems(XWPFDocument doc, String[] items, int insertPos,
|
private static void insertNewListItems(XWPFDocument doc, List<String> items, int insertPos,
|
||||||
BigInteger numId, BigInteger ilvl, XWPFParagraph originalPara, XWPFRun xwpfRun) {
|
BigInteger numId, BigInteger ilvl, XWPFParagraph originalPara, XWPFRun xwpfRun) {
|
||||||
// 获取插入位置的游标锚点
|
// 获取插入位置的游标锚点
|
||||||
XmlCursor cursor = findInsertCursor(doc, insertPos);
|
XmlCursor cursor = findInsertCursor(doc, insertPos);
|
||||||
|
@ -18,7 +18,11 @@ public enum BookmarkType {
|
|||||||
|
|
||||||
PICTURE("PICTURE"),
|
PICTURE("PICTURE"),
|
||||||
|
|
||||||
PICTURE_DESC("PICTURE_DESC");
|
PICTURE_DESC("PICTURE_DESC"),
|
||||||
|
|
||||||
|
TABLE("TABLE"),
|
||||||
|
|
||||||
|
LIST("LIST"),;
|
||||||
|
|
||||||
private final String type;
|
private final String type;
|
||||||
|
|
||||||
|
@ -4,7 +4,9 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
|||||||
import com.fasterxml.jackson.annotation.JsonSubTypes;
|
import com.fasterxml.jackson.annotation.JsonSubTypes;
|
||||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||||
import com.wmyun.farmwork.word.core.enums.BookmarkType;
|
import com.wmyun.farmwork.word.core.enums.BookmarkType;
|
||||||
|
import com.wmyun.farmwork.word.core.model.ext.ListExData;
|
||||||
import com.wmyun.farmwork.word.core.model.ext.PictureExData;
|
import com.wmyun.farmwork.word.core.model.ext.PictureExData;
|
||||||
|
import com.wmyun.farmwork.word.core.model.ext.TableExData;
|
||||||
import com.wmyun.farmwork.word.core.model.ext.TextExData;
|
import com.wmyun.farmwork.word.core.model.ext.TextExData;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
@ -23,12 +25,12 @@ import lombok.Data;
|
|||||||
@JsonSubTypes({
|
@JsonSubTypes({
|
||||||
@JsonSubTypes.Type(value = TextExData.class, name = "TEXT"),
|
@JsonSubTypes.Type(value = TextExData.class, name = "TEXT"),
|
||||||
@JsonSubTypes.Type(value = PictureExData.class, name = "PICTURE"),
|
@JsonSubTypes.Type(value = PictureExData.class, name = "PICTURE"),
|
||||||
@JsonSubTypes.Type(value = PictureExData.class, name = "PICTURE_DESC")
|
@JsonSubTypes.Type(value = PictureExData.class, name = "PICTURE_DESC"),
|
||||||
|
@JsonSubTypes.Type(value = ListExData.class, name = "LIST"),
|
||||||
|
@JsonSubTypes.Type(value = TableExData.class, name = "TABLE")
|
||||||
})
|
})
|
||||||
public class AbstractExData {
|
public class AbstractExData {
|
||||||
|
|
||||||
@JsonProperty("type")
|
@JsonProperty("type")
|
||||||
private BookmarkType type;
|
private BookmarkType type;
|
||||||
|
|
||||||
private String value;
|
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,9 @@ public class BookmarkInfo {
|
|||||||
// 是否是列表
|
// 是否是列表
|
||||||
private boolean listMark;
|
private boolean listMark;
|
||||||
|
|
||||||
|
// 是否在表格中
|
||||||
|
private boolean tableMark;
|
||||||
|
|
||||||
public BookmarkInfo(String bookmarkName, String bookmarkId) {
|
public BookmarkInfo(String bookmarkName, String bookmarkId) {
|
||||||
this.bookmarkName = bookmarkName;
|
this.bookmarkName = bookmarkName;
|
||||||
this.bookmarkId = bookmarkId;
|
this.bookmarkId = bookmarkId;
|
||||||
|
@ -0,0 +1,27 @@
|
|||||||
|
package com.wmyun.farmwork.word.core.model;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: TODO
|
||||||
|
* @Date: 2025/3/7 16:35
|
||||||
|
* @Created: by ZZSLL
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class TableBookmarkInfo {
|
||||||
|
|
||||||
|
// 表格在word中的index
|
||||||
|
private int tableIdx;
|
||||||
|
|
||||||
|
private String masterBookmark;
|
||||||
|
|
||||||
|
private List<String> bookmark;
|
||||||
|
|
||||||
|
private int templateRowIdx;
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
package com.wmyun.farmwork.word.core.model.ext;
|
||||||
|
|
||||||
|
import com.wmyun.farmwork.word.core.model.AbstractExData;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: TODO
|
||||||
|
* @Date: 2025/3/7 16:52
|
||||||
|
* @Created: by ZZSLL
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class ListExData extends AbstractExData {
|
||||||
|
|
||||||
|
private List<String> value;
|
||||||
|
|
||||||
|
}
|
@ -28,16 +28,18 @@ public class PictureExData extends AbstractExData {
|
|||||||
|
|
||||||
private PictureProvideDataType dataType;
|
private PictureProvideDataType dataType;
|
||||||
|
|
||||||
|
private String value;
|
||||||
|
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public byte[] readAsByteArray() {
|
public byte[] readAsByteArray() {
|
||||||
if (PictureProvideDataType.BASE64.equals(dataType)) {
|
if (PictureProvideDataType.BASE64.equals(dataType)) {
|
||||||
return Base64.getDecoder().decode(this.getValue());
|
return Base64.getDecoder().decode(value);
|
||||||
}
|
}
|
||||||
if (PictureProvideDataType.DOWNLOAD_URL.equals(dataType)) {
|
if (PictureProvideDataType.DOWNLOAD_URL.equals(dataType)) {
|
||||||
return HttpUtil.downloadBytes(this.getValue());
|
return HttpUtil.downloadBytes(value);
|
||||||
}
|
}
|
||||||
if (PictureProvideDataType.ABSOLUTE_PATH.equals(dataType)) {
|
if (PictureProvideDataType.ABSOLUTE_PATH.equals(dataType)) {
|
||||||
return FileUtil.readBytes(this.getValue());
|
return FileUtil.readBytes(value);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
package com.wmyun.farmwork.word.core.model.ext;
|
||||||
|
|
||||||
|
import com.wmyun.farmwork.word.core.model.AbstractExData;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: TODO
|
||||||
|
* @Date: 2025/3/7 16:52
|
||||||
|
* @Created: by ZZSLL
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class TableExData extends AbstractExData {
|
||||||
|
private List<Map<String, String>> value;
|
||||||
|
}
|
@ -15,6 +15,8 @@ import lombok.Data;
|
|||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class TextExData extends AbstractExData {
|
public class TextExData extends AbstractExData {
|
||||||
|
|
||||||
|
private String value;
|
||||||
|
|
||||||
private Boolean bold;
|
private Boolean bold;
|
||||||
|
|
||||||
private Boolean italic;
|
private Boolean italic;
|
||||||
|
Loading…
Reference in New Issue
Block a user