之前想了不少方法,为了在 Excel 中直接查看 SAP 表的结构和数据,比如 厌倦了SE11/SE16N? 告诉你如何在Excel中查看SAP的表数据 这篇博文的介绍。本次基于 VSTO COM AddIn 的方式则是我认为最方便的。
设计的思路大致如下:
结合 C# 和 Python 语言,通过 PyRFC 调用 SAP 的 RFC_READ_TABLE 函数,获取数据表的 data dictionary 和 data,由 Flask 将数据对以 Restful API 方式暴露。在 VSTO 中,通过第三方库 RestSharp 消费 Flask 的 Restful Service,并数据导入到 Excel 工作表。之所以选择 Python,主要考虑两点,一是对 SAP 没有侵入性,不需要 SAP 系统的编程配合;二是 PyRFC 调用 RFC 函数的代码最为简洁。
本篇的示例,不对 PyRFC 的函数调用做过多说明,将写另外的文章来介绍。为了解决 RFC_READ_TABLE 函数字段长度的限制,在调用的时候采取分批每次调用 5 个字段的方法解决。RFC_READ_TABLE 函数的局限性请参考我之前的博文。
Flask 提供的 Restful API 有两个接口:
/tabledata/<tablename>/<lines>?options=xxx
上面的接口用户获取表的数据,lines 表示获取数据的行数,默认为 200 行,options 表示符合 ABAP 符合 RFC_READ_TABLE 筛选条件的字符串。下面是 Postman 调用 T001 表的示例:
/tablefields/<tablename>
根据 tablename 获取数据表的 DDIC,如 Postman 测试的结果:
消费 Restful API
从上篇示例工程代码,拷贝一份作为新的工程,创建 SAPTableService 类,从服务器端的 URL 获取 json 格式的数据:
using RestSharp;
using System.Data;
namespace VSTODemo {
public class SapTableService {
private string baseUrl = "http://localhost:5000";
private RestClient restClient;
public SapTableService() {
restClient = new RestClient(baseUrl);
}
public DataTable GetTableFields(string tableName) {
DataTable result = null;
var url = baseUrl + "/tablefields/" + tableName;
var request = new RestRequest(url, Method.GET);
var resp = restClient.Execute(request);
if (resp.IsSuccessful) {
result = JsonUtils.ToTable(resp.Content);
}
return result;
}
public DataTable GetTableContent(string tableName, string criteria, string rows) {
DataTable result = null;
string url = null;
if (string.IsNullOrEmpty(criteria)) {
url = baseUrl + $"/tabledata/{tableName}/{rows}";
}
else {
url = baseUrl + $"/tabledata/{tableName}/{rows}?options={criteria}";
}
var request = new RestRequest(url, Method.GET);
var resp = restClient.Execute(request);
if (resp.IsSuccessful) {
result = JsonUtils.ToTable(resp.Content);
}
return result;
}
}
}
代码中用到了 RestSharp 第三方模块,用于 Http 请求,以及 Newtonsoft.Json 模块,用于将 json 数据转换为 DataTable 类型。Json 转 DataTable 使用下面的代码:
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Data;
namespace VSTODemo {
public class JsonUtils {
public static DataTable ToTable(string json) {
var srcArray = JArray.Parse(json); // json格式约定最上层为 array
var trgArray = new JArray();
foreach (JObject row in srcArray.Children<JObject>()) {
var cleanRow = new JObject();
foreach (JProperty column in row.Properties()) {
// Only include JValue types
if (column.Value is JValue) {
cleanRow.Add(column.Name, column.Value);
}
}
trgArray.Add(cleanRow);
}
return JsonConvert.DeserializeObject<DataTable>(trgArray.ToString());
}
}
}
这段代码来自 StackOverflow 的这篇帖子:c# - Convert JSON to DataTable - Stack Overflow,稍作变更。
设计界面
在工程中,新建一个 WinForm,界面如下:
Ribbon 菜单增加一个按钮,弹出该 Form,点击该 Form 的确认按钮,将输入导入到工作表中:
数据导入到工作表:
using Microsoft.Office.Interop.Excel;
using System;
using System.Windows.Forms;
namespace VSTODemo {
public partial class SAPTableForm : Form {
public SAPTableForm() {
InitializeComponent();
}
private void btnConfirm_Click(object sender, EventArgs e) {
var sapService = new SapTableService();
if (tableFieldsCheckBox.Checked) {
var tableFields = sapService.GetTableFields(txtTableName.Text.Trim().ToUpper());
Worksheet sheet = ThisAddIn.ExcelApp.Worksheets.Add();
sheet.Name = $"{txtTableName.Text.ToUpper()}_strucutre_{sheet.Name}";
ExcelUtils.CopyFromDataTable(tableFields, sheet);
}
if (tableContentCheckBox.Checked) {
var tableContent = sapService.GetTableContent(
txtTableName.Text.ToUpper().Trim(),
txtCriteria.Text.Trim(),
txtRows.Text);
Worksheet sheet = ThisAddIn.ExcelApp.Worksheets.Add();
sheet.Name = $"{txtTableName.Text.ToUpper()}_{sheet.Name}";
ExcelUtils.CopyFromDataTable(tableContent, sheet);
}
this.Close();
}
}
}
源代码
Gitee - 04-Query SAP Table