У меня есть функция создания отчетов Excel в моем приложении Java.
Мне наконец-то удалось добавить к изображению гиперссылку без ошибок с помощью следующего кода.
buildHyperLinksMenu является основной функцией, которая устанавливает гиперссылку
createHyperLinkWithUri - это подфункция, которая создает гиперссылку Uri
public void buildHyperLinksMenu(String linkName, XSSFSheet sheet, String tabLinked, String referencedCell) {
List<XSSFShape> shapes = sheet.getDrawingPatriarch().getShapes();
Iterator<XSSFShape> elementsIterator = shapes.iterator();
while (elementsIterator.hasNext()) {
XSSFShape shape = elementsIterator.next();
if (shape instanceof XSSFPicture) {
CTPicture ctPicture = ((XSSFPicture) shape).getCTPicture();
CTPictureNonVisual ctpicturenonvisual = ctPicture.getNvPicPr();
CTNonVisualDrawingProps ctnonvisualdrawingprops = ctpicturenonvisual.getCNvPr();
String finalname = ctnonvisualdrawingprops.getName();
//HomeLink is the name of the picture assigned in the sheet to
//the image when uploading the Excel template
if (finalname.equals("HomeLink")) {
CTHyperlink link = createHyperLinkWithUri(linkName, sheet, tabLinked, referencedCell);
((XSSFPicture) shape).getCTPicture().getNvPicPr().getCNvPr().setHlinkClick(link);
}
}
}
}
private CTHyperlink createHyperLinkWithUri(String linkName, XSSFSheet sheet, String tabLinked, String referencedCell) {
CTHyperlink link = CTHyperlink.Factory.newInstance();
try {
String hyperlinkAddress = sheet.getPackagePart().getPartName() + "/#'" + tabLinked + "'!" + referencedCell + "";
URI uri = new URI(null, null, hyperlinkAddress, null, null);
sheet.getDrawingPatriarch().getPackagePart().addRelationship(uri, TargetMode.INTERNAL, XSSFRelation.SHEET_HYPERLINKS.getRelation());
String relationshipId = null;
PackageRelationshipCollection prc = sheet.getDrawingPatriarch().getPackagePart().getRelationships();
for (PackageRelationship pr : prc) {
URI targetURI = pr.getTargetURI();
String target = targetURI.getPath();
if (target.equals(hyperlinkAddress)) {
relationshipId = pr.getId();
break;
}
}
CTHyperlink hyperlink = CTHyperlink.Factory.newInstance();
// Set ID of hyperlink to be the same as Relationship ID
hyperlink.setId(relationshipId);
return hyperlink;
} catch (URISyntaxException | InvalidFormatException e) {
return link;
}
}
Теперь проблема в том, что после генерации Excel (при открытии) выдаст сообщение «нечитаемый контент» и гиперссылка не будет добавлена.
Я хотел бы понять, если это проблема фрагмента кода, который я разместил, который мне не хватает, или что-то более раздражающее, например, версии библиотек и т. Д.
Я подтверждаю, что if (finalname.equals("HomeLink"))
выполняется один и только один раз.
Вот простая функция, вызываемая для записи файла в вывод:
protected byte[] workbookToByteArray(XSSFWorkbook workbook) {
try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {
workbook.write(byteArrayOutputStream);
return byteArrayOutputStream.toByteArray();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
Спасибо
Davide
UDPATE
Я сгенерировал документ Excel с функциональностью добавления гиперссылки и без нее (в основном код выше).
Поврежденный Excel говорит, что поврежден файл xl \ drawing \ drawing4.xml.
Поэтому я взял два экземпляра, разархивировал их и сравнил XML-файлы. Единственные различия между этими двумя:
Правильный файл
<a:blip xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" r:embed="rId2">
против
Неверный файл
<a:blip r:embed="rId2">
Эта разница происходит много раз таким же образом. Много других
UDPATE
Похоже, что строка, которая создает проблему, при добавлении отношения к пакету
sheet.getDrawingPatriarch().getPackagePart().addRelationship(uri, TargetMode.INTERNAL, XSSFRelation.SHEET_HYPERLINKS.getRelation());
КОД РЕШЕНИЯ
public void buildHyperLinksMenu(String linkName, XSSFSheet sheet, String tabLinked, String referencedCell) {
List<XSSFShape> shapes = sheet.getDrawingPatriarch().getShapes();
Iterator<XSSFShape> elementsIterator = shapes.iterator();
while (elementsIterator.hasNext()) {
XSSFShape shape = elementsIterator.next();
if (shape instanceof XSSFPicture) {
CTPicture ctPicture = ((XSSFPicture) shape).getCTPicture();
CTPictureNonVisual ctpicturenonvisual = ctPicture.getNvPicPr();
CTNonVisualDrawingProps ctnonvisualdrawingprops = ctpicturenonvisual.getCNvPr();
String finalname = ctnonvisualdrawingprops.getName();
if (finalname.equals("HomeLink")) {
CTHyperlink link = createHyperLinkWithUri(linkName, sheet, tabLinked, referencedCell);
((XSSFPicture) shape).getCTPicture().getNvPicPr().getCNvPr().setHlinkClick(link);
}
}
}
}
private CTHyperlink createHyperLinkWithUri(String linkName, XSSFSheet sheet, String tabLinked, String referencedCell) {
CTHyperlink link = CTHyperlink.Factory.newInstance();
try {
CTHyperlink hyperlink = CTHyperlink.Factory.newInstance();
String hyperlinkAddress = "#'" + tabLinked + "'!" + referencedCell + "";
sheet.getDrawingPatriarch().getPackagePart().addExternalRelationship(hyperlinkAddress, PackageRelationshipTypes.HYPERLINK_PART);
String relationshipId = null;
PackageRelationshipCollection prc = sheet.getDrawingPatriarch().getPackagePart().getRelationships();
for (PackageRelationship pr : prc) {
String targetURI = pr.getTargetURI().toString();
if (targetURI.equals(hyperlinkAddress)) {
relationshipId = pr.getId();
break;
}
}
// Set ID of hyperlink to be the same as Relationship ID
hyperlink.setId(relationshipId);
return hyperlink;
} catch (InvalidFormatException e) {
return link;
}
}