wangguanquan / eec

A fast and lower memory excel write/read tool.一个非POI底层,支持流式处理的高效且超低内存的Excel读写工具
https://github.com/wangguanquan/eec/wiki
Apache License 2.0
179 stars 54 forks source link

请教如何设置超链接? #371

Open FudanSE-Nick opened 7 months ago

FudanSE-Nick commented 7 months ago

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

wangguanquan commented 7 months ago

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

Message ID: @.***>

wangguanquan commented 6 months ago

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

  1. 新建一个扩展目录eec.ext(非必须)
  2. 新建一个自定义注解Hyperlink(非必须)
    @Target({ ElementType.FIELD, ElementType.METHOD })
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Hyperlink { }
  3. 新建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;
    }
    }
  4. 内置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;
    }
    }
  5. 新建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 commented 6 months ago

测试代码

@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"));
}
FudanSE-Nick commented 6 months ago

非常感谢!

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

wangguanquan commented 6 months ago

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

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

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

wangguanquan commented 5 months ago

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