eec icon indicating copy to clipboard operation
eec copied to clipboard

请教如何设置超链接?

Open FudanSE-Nick opened this issue 1 year ago • 6 comments

你好,请问如何对某个单元格的值设置超链接?没有找到生成excel时配置Hyperlink的地方。

FudanSE-Nick avatar Mar 07 '24 10:03 FudanSE-Nick

没有直接设置的方法需扩展,明天贴出示例,下个版本内置超链接

Message ID: @.***>

wangguanquan avatar Mar 07 '24 12:03 wangguanquan

自定义的话有点麻烦,如果不急用的话可以等待下一个版本,需要急用的话可以参照如下方式扩展

  1. 新建一个扩展目录eec.ext(非必须)
  2. 新建一个自定义注解Hyperlink(非必须)
@Target({ ElementType.FIELD, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface Hyperlink { }
  1. 新建ListSheet扩展类MyListSheet用来解析Hyperlink 注解
public class MyListSheet<T> extends ListSheet<T> {
    // 看情况覆写父类的Constructor
    public MyListSheet(List<T> data) {
        super(data);
    }

    @Override
    protected EntryColumn createColumn(AccessibleObject ao) {
        EntryColumn column = super.createColumn(ao);
        // 解析Hyperlink,只需要简单的设置一个标记位即可,标记该列为超链接
        Hyperlink Hyperlink = ao.getAnnotation(Hyperlink.class);
        if (Hyperlink != null) column.getTail().option |= 1 << 16;
        return column;
    }
}
  1. 内置Relationship设计有缺陷无法支持超链接,需要重写
public class Relationship extends org.ttzero.excel.entity.Relationship {
    private String targetMode,target,type,id;

    public Relationship(String target, String type, String targetMode) {
        super(target, type);
        this.target = target;
        this.type = type;
        this.targetMode = targetMode;
    }
}
  1. 新建XMLWorksheetWriter扩展类MyXMLWorksheetWriter用来处理Hyperlink列
public static class MyXMLWorksheetWriter extends XMLWorksheetWriter {
    Map<String, List<String>> hyperlinkMap;

    @Override
    protected void writeString(String s, int row, int column, int xf) throws IOException {
        // 超链接
        // 这里只适应单行表头,如果有多行需要改为row > startHeaderRow + 表头行数
        if (row > startHeaderRow && (columns[column].option >> 16) == 1) {
            Relationship myRelationship = new Relationship(s, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink", "External");
            org.ttzero.excel.entity.Relationship relationship = sheet.getRelManager().add(myRelationship);
            myRelationship.id = relationship.getId();
            if (hyperlinkMap == null) hyperlinkMap = new HashMap<>();
            List<String> dim = hyperlinkMap.computeIfAbsent(relationship.getId(), k -> new ArrayList<>());
            dim.add(new String(int2Col(column + 1)) + row);

            // 添加超链接的样式
            int style = styles.getStyleByIndex(xf);
            Font font = styles.getFont(style).clone();
            font.setStyle(0).underLine(); // 先清除样式的其它附加属性
            font.setColor(ColorIndex.themeColors[10]); // 设置超链接颜色
            xf = styles.of(styles.modifyFont(style, font));
        }
        super.writeString(s, row, column, xf);
    }

    @Override
    protected void afterSheetData() throws IOException {
        super.afterSheetData();
        // 添加超链接
        if (hyperlinkMap != null) {
            bw.write("<hyperlinks>");
            for (Map.Entry<String, List<String>> entry : hyperlinkMap.entrySet()) {
                for (String dim : entry.getValue()) {
                    bw.write("<hyperlink ref=\"");
                    bw.write(dim);
                    bw.write("\" r:id=\"");
                    bw.write(entry.getKey());
                    bw.write("\"/>");
                }
            }
            bw.write("</hyperlinks>");
        }
    }
}

wangguanquan avatar Mar 08 '24 01:03 wangguanquan

测试代码

@Test public void hyperlinkTest() throws IOException {
    List<Item> list = new ArrayList<>();
    list.add(new Item("京东", "https://www.jd.com"));
    list.add(new Item("天猫", "https://www.tmall.com"));
    list.add(new Item("淘宝", "https://www.taobao.com"));

    new Workbook().addSheet(new MyListSheet<>(list).setSheetWriter(new MyXMLWorksheetWriter())).writeTo(Paths.get("./超连接测试.xlsx"));
}

wangguanquan avatar Mar 08 '24 02:03 wangguanquan

非常感谢!

另,请问如何在同一个sheet中,拼接两个List<VO> 的字段。 在同一行中展示数据呢?

FudanSE-Nick avatar Mar 08 '24 06:03 FudanSE-Nick

暂时不支持,只能在外部拼接好,模板工作表TemplateSheet开发好后可以使用模板。

暂时的话可以只能在对象中拼接,你可以定义一个对象,包含2个数组,在新对象中对值进行拼接

@ExcelColumn public String join() { return list1.get(0).getNmae() + list2.get(0).getNum(); }

wangguanquan avatar Mar 08 '24 09:03 wangguanquan

v0.5.14支持超设置超链接且新增模板文件导出,拼接两个List 的字段应该可以使用模板来实现

wangguanquan avatar Apr 22 '24 12:04 wangguanquan