掘金 后端 ( ) • 2024-04-19 17:56

项目场景:

需要读取飞书云文档的电子表格,但是表格有公式计算的值,以及合并单元格。

问题显示:调用api可以读取表格。1.公式不自动计算,直接返回公式。2.读取合并的单元格,只有第一行有数据,其余合并的无数据。

image.png 直接看读取表格的代码:

public SpreadsheetData getSheet(String token, String sheetId) {  
// 发起请求  
try {  
String url = "https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/" + token + "/values_batch_get?ranges=" + sheetId;  
RawResponse resp = client.get(url, null, AccessTokenType.Tenant);  
if (resp.getStatusCode() == 200) {  
//LarkResult<SpreadsheetData>用来封装api响应体
Type type = new TypeToken<LarkResult<SpreadsheetData>>() {}.getType(); 
LarkResult<SpreadsheetData> result = Jsons.DEFAULT.fromJson(new String(resp.getBody()), type);  
return result.getData();  
}  
throw new AIGCBusinessExceptions(ResultCodeEnum.HTTP_REQUEST_FAILED.getCode(), Arrays.toString(resp.getBody()));  
} catch (Exception e) {  
throw new AIGCBusinessExceptions(Result.HTTP_REQUEST_FAILED.getCode(), "读取电子表格报错" + e.getMessage());  
}  
}

打断点看一下api返回的东西:

image.png 重点对比一下第三行和四五行的数据,因为从第三行开始合并的单元格以及公式计算

image.png 现在需要解决这两个问题:

1.显示数据,不显示公式。

2.合并的单元格也要显示数据

问题1:公式计算

飞书api官方文档

读取多个范围 - 服务端 API - 开发文档 - 飞书开放平台 (feishu.cn) 根据项目需求,我调用的是这个api。这个问题好解决,加一个查询参数valueRenderOption=FormattedValue 计算并格式化单元格;

String url = "https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/" + token + "/values_batch_get?ranges=" + sheetId+"&valueRenderOption=FormattedValue";

image.png okk, 公式计算的问题解决了,现在显示结果了。下次要认真阅读api文档,官方文档写了.....查询参数那列valueRenderOption

image.png

问题2:读取合并单元格

这个问题官方文档好像是没写,翻阅了官方文档没找到。需求在那也只能硬着头皮写了。 以下是我自己的方法,感觉不是很好用,有大佬知道这个问题请多多指教。

1.调用api查询出表合并单元格的相关信息

查询工作表 - 服务端 API - 开发文档 - 飞书开放平台 (feishu.cn) 响应体中的merges会返回表合并单元格的相关信息。 image.png

public List<Merges> getSheetDetail(String token, String sheetId){  
try {  
    String substring = sheetId.substring(0, sheetId.indexOf('!'));  
    String url="https://open.feishu.cn/open-apis/sheets/v3/spreadsheets/"+ token +"/sheets/"+substring;  
    RawResponse resp = client.get(url, null, AccessTokenType.Tenant);  
    if (resp.getStatusCode() == 200) {  
        Type type = new TypeToken<LarkResult<Spreadsheet>>() {}.getType();  
        LarkResult<Spreadsheet> result = Jsons.DEFAULT.fromJson(new String(resp.getBody()), type);  
        Spreadsheet spreadsheet = result.getData();  
        List<Merges> merges = spreadsheet.getSheet().getMerges();  
        return merges;  
}  
    throw new AIGCBusinessExceptions(ResultCodeEnum.HTTP_REQUEST_FAILED.getCode(), Arrays.toString(resp.getBody()));  
} catch (Exception e) {  
    throw new AIGCBusinessExceptions(Result.HTTP_REQUEST_FAILED.getCode(), "读取电子表格报错" + e.getMessage());  
}  
}

image.png 注意:这里返回的行列index都是,第n行列-1。start_row_index=2实际上是第三行

2.给合并单元格赋值

现在只取游戏图那一列合并单元格的数据

/**
* spreadsheetData 表数据
* mergesList 合并单元格的信息
*/

public void mergeCell(SpreadsheetData spreadsheetData,List<Merges> mergesList){  
    //获取游戏图所在的列,get(0)是表头
    SpreadsheetData.ValueRange head = spreadsheetData.getValueRanges().get(0);  
    List<List<Object>> headValues = head.getValues();  
    List<Object> headObjects = headValues.get(0);  
    Integer index=0;  
    for (int i = 0; i < headObjects.size(); i++) {  
        if (headObjects.get(i).equals("游戏图")){  
            index=i;  
            break;  
        }  
    }  
    //取合并单元格的行号
    List<Integer> indexList=new ArrayList<>();  
    for (Merges merges : mergesList) {  
        if (merges.getStart_column_index().equals(index) && merges.getEnd_column_index().equals(index)){  
            Integer startRowIndex = merges.getStart_row_index();  
            Integer endRowIndex = merges.getEnd_row_index();  
            for (int i=startRowIndex;i<=endRowIndex;i++){  
                indexList.add(i);  
            }  
         }  
    }  
    //get(1)取表内的数据
    SpreadsheetData.ValueRange valueRange = spreadsheetData.getValueRanges().get(1);  
    String range = valueRange.getRange();  
    //取开始行号 ,计算每行数据在表格内的行号,与indexList进行对比
    int startRow = Integer.parseInt(range.substring(range.indexOf('!') + 2, range.indexOf(':')));  
    List<List<Object>> values = valueRange.getValues();  
    Object temp=null;  
    for (int i = 0; i < values.size(); i++) {  
        Object o = values.get(i).get(index);  
        if (o!=null){  
            temp= o;  
        }  
        if (o ==null && indexList.contains(i+startRow-1) ){  
            values.get(i).set(index,temp);  
        }  
    }  
}

3.最后

public SpreadsheetData getSheet(String token, String sheetId) {  
// 发起请求  
try {  
String url = "https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/" + token + "/values_batch_get?ranges=" + sheetId+"&valueRenderOption=FormattedValue";  
RawResponse resp = client.get(url, null, AccessTokenType.Tenant);  
if (resp.getStatusCode() == 200) {  
Type type = new TypeToken<LarkResult<SpreadsheetData>>() {}.getType();  
LarkResult<SpreadsheetData> result = Jsons.DEFAULT.fromJson(new String(resp.getBody()), type);  
SpreadsheetData spreadsheetData = result.getData();  
//获取合并的单元格,下标从0开始  
List<Merges> mergesList = getSheetDetail(token, sheetId);  
mergeCell(spreadsheetData,mergesList);  
return result.getData();  
}  
throw new AIGCBusinessExceptions(ResultCodeEnum.HTTP_REQUEST_FAILED.getCode(), Arrays.toString(resp.getBody()));  
} catch (Exception e) {  
throw new AIGCBusinessExceptions(Result.HTTP_REQUEST_FAILED.getCode(), "读取电子表格报错" + e.getMessage());  
}  
  
}

image.png 结果:“游戏图”那列的合并单元格,不止第三行,第四五行都有了数据。

最后:如果有大佬有更好的方法,请多多指教