之前有个Asp.Net项目中需要从Excel中里导入数据,导出合同及合同的借据,心想着就用办公室提供的提供的那堆DLL库吧,简单方便,可是这堆DLL库严重依赖办公室,不可能在服务器上装个办公吧吧。于是Google了一下,搜出来那么一两个可以使用的库,一个是【NPOI 】,另外一个是【FreeSpire.Office】.FreeSpire.Office的API相对NPOI 的API要相对简单一些.FreeSpire.Office的正式版要收费,比如要使用到Spire.Office的一些功能(如:导出超过三页的PDF格式,EXCEL的Sheet创建五个以上等)就要收费了。
根据项目的情况,经过简单的分析,最后决定采用免费版的FreeSpire.Office,做一些复杂一点的操作时再用NPOI 。
这里先讲解一下项目中使用到的FreeSpire.Office的功能。
先准备存有数据的出色文件:
读取数据的C#代码(忘了之前那段读取的代码在哪了,所以有写了段示例意思意思)
public static List FromExcel(string filePath)
{
if (!File.Exists(filePath))
{
throw new Exception("文件不存在");
}
List ps = new List();
try
{
Workbook workbook = new Workbook();
workbook.LoadFromFile(filePath);//加载excel文件
//获取第一个Sheet
Worksheet sheet = workbook.Worksheets[0];
//循环读取数据
int count = 2;
while (true)
{
if (string.IsNullOrEmpty(sheet.Range[$"A{count}"].Text)) { break; }
ps.Add(new Person()
{
Name = sheet.Range[$"A{count}"].Text,
Gender = sheet.Range[$"B{count}"].Text
});
count++;
}
}
catch
{
throw;
}
return ps;
}
准备要写入的数据:
Dictionary dict = new Dictionary();//单元格位置,内容
{
dict.Add("A3", $"合同编号:{m2.LoanAgreementNO}");
dict.Add("E3", $"担保合同编号:{m2.GuaranteeNO}");
dict.Add("B7", $"(币种)人民币:{m2.MoneyDaXue}");
dict.Add("P8", m2.MoneyFeng);//分
dict.Add("O8", m2.MoneyJiao);//角
dict.Add("N8", m2.MoneyYuan);//元
dict.Add("M8", m2.MoneyShi);//十
dict.Add("L8", m2.MoneyBai);//百
dict.Add("K8", m2.MoneyQian);//千
dict.Add("J8", m2.MoneyWan);//万
dict.Add("I8", m2.MoneyShiWan);//十万
dict.Add("H8", m2.MoneyBaiWan);//百万
dict.Add("G8", m2.MoneyQianWan);//千万
dict.Add("C9", $"{m2.StartDtYear}年{m2.StartDtMonth}月{m2.StartDtDay}日至{m2.EndDtYear}年{m2.EndDtMonth}月{m2.EndDtDay}日共{m2.Deadline}个月");
dict.Add("G9", $"借款方式:{m2.JKFS}");
dict.Add("j9", $"月利率:{m2.InteresRate}%");
dict.Add("M9", $"还款方式:{m2.HKFS}");
dict.Add("P22", m2.MoneyFeng);//分
dict.Add("O22", m2.MoneyJiao);//角
dict.Add("N22", m2.MoneyYuan);//元
dict.Add("M22", m2.MoneyShi);//十
dict.Add("L22", m2.MoneyBai);//百
dict.Add("K22", m2.MoneyQian);//千
dict.Add("J22", m2.MoneyWan);//万
dict.Add("I22", m2.MoneyShiWan);//十万
dict.Add("H22", m2.MoneyBaiWan);//百万
dict.Add("G22", m2.MoneyQianWan);//千万
dict.Add("C23", $"{m2.StartDtYear}年{m2.StartDtMonth}月{m2.StartDtDay}日至{m2.EndDtYear}年{m2.EndDtMonth}月{m2.EndDtDay}日共{m2.Deadline}个月");
dict.Add("G23", $"借款方式:{m2.JKFS}");
dict.Add("j23", $"月利率:{m2.InteresRate}%");
dict.Add("M23", $"还款方式:{m2.JKFS}");
dict.Add("P36", m2.MoneyFeng);//分
dict.Add("O36", m2.MoneyJiao);//角
dict.Add("N36", m2.MoneyYuan);//元
dict.Add("M36", m2.MoneyShi);//十
dict.Add("L36", m2.MoneyBai);//百
dict.Add("K36", m2.MoneyQian);//千
dict.Add("J36", m2.MoneyWan);//万
dict.Add("I36", m2.MoneyShiWan);//十万
dict.Add("H36", m2.MoneyBaiWan);//百万
dict.Add("G36", m2.MoneyQianWan);//千万
dict.Add("C37", $"{m2.StartDtYear}年{m2.StartDtMonth}月{m2.StartDtDay}日至{m2.EndDtYear}年{m2.EndDtMonth}月{m2.EndDtDay}日共{m2.Deadline}个月");
dict.Add("G37", $"借款方式:{m2.JKFS}");
dict.Add("j37", $"月利率:{m2.InteresRate}%");
dict.Add("M37", $"还款方式:{m2.JKFS}");
}
写入的方法:
public static class ToExcel
{
///
///
///
/// 模板路径
/// 目标路径
/// 需要替换的excel的单元格及字符串
///
public static bool ToExcelByMuban(string yuanPath,string mubiaoPath,Dictionary dict) {
if (dict == null)
{
throw new Exception("字典为空!");
}
if (!File.Exists(yuanPath))
{
throw new Exception("指定路径的模板文件不存在!");
}
try
{
Workbook book = new Workbook();
book.LoadTemplateFromFile(yuanPath);
Worksheet sheet = book.Worksheets[0];
foreach (var d in dict)
{
sheet.Range[d.Key].Text = d.Value;
}
book.SaveToFile(mubiaoPath, ExcelVersion.Version97to2003);
return true;
}
catch
{
return false;
}
}
}
调用写入方法:
bool b1 = ToExcel.ToExcelByMuban(JieJuYuanUrl, Server.MapPath(JieJuMubiaoUrl),dict);
1.准备文档模板
2.在文字文档中制定要替换的内容
以上图中的编号举例说明:
调出字中的【开发工具】选项卡
【文件】 - >【选项】 - >【自定义公能区】 - >勾选【开发工具】 - >确认
选中要替换的位置:【开发工具】,【工具箱】,【旧式窗体】,【AB |】插入一个【文本域(窗体控件)】
添加唯一标识符:选中上一步骤添加的【文本域(窗体控件)】,双击,调出【文本域(窗体控件)】选项,填写【书签】
导出合同的方法:
///
///
///
///
/// 对象(其中的字段的名称和word模板文档中【文本域(窗体控件)】的【书签】的名称一致)
/// 模板文档目录
/// 导出文件的目录
///
public static bool ExportWordByFields(T mod, string TempleteFilePath, string ExpFilePath)
{
if (mod == null)
{
throw new Exception("模型为空!");
}
System.Reflection.PropertyInfo[] properties = mod.GetType().GetProperties(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
if (properties.Length <= 0)
{
throw new Exception("模型属性为空!");
}
if (!File.Exists(TempleteFilePath))
{
throw new Exception("指定路径的模板文件不存在!");
}
try
{
Document doc = new Document();
doc.LoadFromFile(TempleteFilePath);
#region 替换文字
//doc.Replace("海关", "海关口岸", true, true);
//doc.Replace("报验", "报检", true, true);
#endregion
//清除表单域阴影
doc.Properties.FormFieldShading = false;
FormFieldCollection collection = doc.Sections[0].Body.FormFields;
//遍历Word模板中的文本域(field.name为文本域名称)
foreach (FormField field in collection)
{
foreach (System.Reflection.PropertyInfo prop in properties)
{
string name = prop.Name; //属性名称
object value = prop.GetValue(mod, null); //属性值
//string des = ((DescriptionAttribute)Attribute.GetCustomAttribute(prop, typeof(DescriptionAttribute))).Description;// 属性描述值
//注意:文本域名称 == 模型中属性的 Description 值 !!!!!!
//也可以: 文本域名称 == 模型中属性的 Name 值 !!!!!!
if (field.Name == name && value != null)
{
if (field.DocumentObjectType == DocumentObjectType.TextFormField) //文本域
{
if (prop.PropertyType.Name == "Boolean")
{
if ((Boolean)value)
{
field.Text = "☑"; //插入勾选符号
}
else
{
field.Text = "⬜"; //插入勾选符号
}
break;
}
else
{
field.Text = value.ToString(); //向Word模板中插入值
break;
}
}
else if (field.DocumentObjectType == DocumentObjectType.CheckBox) //复选框
{
(field as CheckBoxFormField).Checked = (value as bool?).HasValue ? (value as bool?).Value : false;
}
}
}
}
doc.Protect(ProtectionType.AllowOnlyReading, Guid.NewGuid().ToString());//加密文档
doc.SaveToFile(ExpFilePath, FileFormat.Docx);
doc.Close();
return true;
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
在上面导出合同中没有涉及到循环导出的问题
该项目还有另外一中合同涉及到多人一起签署合同的情况,需要把合同的签署人一起到处
我的办法是,在模板里添加一个一行一列的表格,弄成无边框的,
在代码中拼接内容,在把内容添加到表格中(因为合同中有三个地方需要添加,所以弄了三个表格,另外两个地方是以表格的形式显示的)
TableCollection tableCollection = doc.Sections[0].Tables;//获取文档内的所有表格
int i = 0;
foreach (Table v in tableCollection)
{
int j = 0;
foreach (EMultilevelJointInsurance c in eMultilevelJointInsurances)
{
if (i == 0)
{
Paragraph p = v.Rows[0].Cells[0].AddParagraph();
p.AppendText("联保人:").CharacterFormat.FontSize = 15;
TextRange range = p.AppendText(c.Name);
range.CharacterFormat.UnderlineStyle = UnderlineStyle.Single;
range.CharacterFormat.FontSize = 15;
p.AppendText("身份证号码:").CharacterFormat.FontSize = 15;
TextRange rangeId = p.AppendText(c.IDCardNo);
rangeId.CharacterFormat.FontSize = 15;
rangeId.CharacterFormat.UnderlineStyle = UnderlineStyle.Single;
p.AppendText("\n");
p.AppendText("居住地址:").CharacterFormat.FontSize = 15;
TextRange rangeAdd = p.AppendText(c.ResidenceAddress);
rangeAdd.CharacterFormat.FontSize = 15;
rangeAdd.CharacterFormat.UnderlineStyle = UnderlineStyle.Single;
}
else if (i == 1)
{
v.AddRow();
Paragraph p = v.Rows[j + 1].Cells[0].AddParagraph();
p.Format.HorizontalAlignment = HorizontalAlignment.Center;
p.AppendText((j + 1).ToString());
Paragraph p1 = v.Rows[j + 1].Cells[1].AddParagraph();
p1.Format.HorizontalAlignment = HorizontalAlignment.Center;
p1.AppendText(c.Name);
Paragraph p2 = v.Rows[j + 1].Cells[2].AddParagraph();
p2.Format.HorizontalAlignment = HorizontalAlignment.Center;
p2.AppendText(c.IDCardNo);
Paragraph p3 = v.Rows[j + 1].Cells[3].AddParagraph();
p3.Format.HorizontalAlignment = HorizontalAlignment.Center;
p3.AppendText((c.ApprovalQuota * 10000).ToString());
Paragraph p4 = v.Rows[j + 1].Cells[4].AddParagraph();
p4.Format.HorizontalAlignment = HorizontalAlignment.Center;
p4.AppendText(c.LoanUsage);
CellFormat cellStyle = v.Rows[j + 1].Cells[0].CellFormat;
cellStyle.VerticalAlignment = VerticalAlignment.Middle;
}
else if(i == 2)
{
v.AddRow();
Paragraph p = v.Rows[j + 2].Cells[0].AddParagraph();
p.Format.HorizontalAlignment = HorizontalAlignment.Center;
p.AppendText(c.Name + $"({j + 1})");
Paragraph p1 = v.Rows[j + 2].Cells[3].AddParagraph();
p1.Format.HorizontalAlignment = HorizontalAlignment.Center;
p1.AppendText(c.IDCardNo);
CellFormat cellStyle = v.Rows[j + 1].Cells[0].CellFormat;
cellStyle.VerticalAlignment = VerticalAlignment.Middle;
}
j++;
}
i++;
}
随便也说了一下word中表格的简单操作
同样也准备借据的模板:
根据以上借据分析,只有【联保成员】需要循环获取,其他地方只需要用【文本域(窗体控件)】替换旧可以了
我的做法是把联保人所涉及到的行全部删除,在导出的时候,把联保组长所在的行复制下来,再替换其内容
所以代码变成如下的了
TableCollection tableCollection = doc.Sections[0].Tables;//获取文档内的所有表格
foreach (Table v in tableCollection)
{
//组长
v.Rows[0].Cells[1].Paragraphs[0].Text = insurance.Name;//联保组织姓名
//v.Rows[0].Cells[3].Paragraphs[0].Text = "建行";//开户行
//v.Rows[0].Cells[5].Paragraphs[0].Text = "6217 0039 10000 853";//银行账号
v.Rows[1].Cells[1].Paragraphs[0].Text = $"(大写)人民币{insurance.MoneyDaXue}元";//大写的金额
v.Rows[2].Cells[2].Paragraphs[0].Text = insurance.MoneyBaiWan;//百
v.Rows[2].Cells[3].Paragraphs[0].Text = insurance.MoneyShiWan;//十
v.Rows[2].Cells[4].Paragraphs[0].Text = insurance.MoneyWan;//万
v.Rows[2].Cells[5].Paragraphs[0].Text = insurance.MoneyQian;//千
v.Rows[2].Cells[6].Paragraphs[0].Text = insurance.MoneyBai;//百
v.Rows[2].Cells[7].Paragraphs[0].Text = insurance.MoneyShi;//十
v.Rows[2].Cells[8].Paragraphs[0].Text = insurance.MoneyYuan;//元
v.Rows[2].Cells[9].Paragraphs[0].Text = insurance.MoneyJiao;//角
v.Rows[2].Cells[10].Paragraphs[0].Text = insurance.MoneyFeng;//分
int i = 0;
foreach (EMultilevelJointInsurance c in eMultilevelJointInsurances)
{
//把联保组长的【行】复制下来
v.Rows.Insert((3 * i) + 3, v.Rows[0].Clone());
v.Rows.Insert((3 * i) + 4, v.Rows[1].Clone());
v.Rows.Insert((3 * i) + 5, v.Rows[2].Clone());
v.Rows[(3 * i) + 3].Cells[0].Paragraphs[0].Text = $"联保成员({i + 1})";
v.Rows[(3 * i) + 3].Cells[1].Paragraphs[0].Text = c.Name;
v.Rows[(3 * i) + 3].Cells[3].Paragraphs[0].Text = "";//开户行
v.Rows[(3 * i) + 3].Cells[5].Paragraphs[0].Text = "";//银行账号
v.Rows[(3 * i) + 4].Cells[1].Paragraphs[0].Text = $"(大写)人民币{c.MoneyDaXue}元";//大写的金额
v.Rows[(3 * i) + 5].Cells[2].Paragraphs[0].Text = c.MoneyBaiWan;//百
v.Rows[(3 * i) + 5].Cells[3].Paragraphs[0].Text = c.MoneyShiWan;//十
v.Rows[(3 * i) + 5].Cells[4].Paragraphs[0].Text = c.MoneyWan;//万
v.Rows[(3 * i) + 5].Cells[5].Paragraphs[0].Text = c.MoneyQian;//千
v.Rows[(3 * i) + 5].Cells[6].Paragraphs[0].Text = c.MoneyBai;//百
v.Rows[(3 * i) + 5].Cells[7].Paragraphs[0].Text = c.MoneyShi;//十
v.Rows[(3 * i) + 5].Cells[8].Paragraphs[0].Text = c.MoneyYuan;//元
v.Rows[(3 * i) + 5].Cells[9].Paragraphs[0].Text = c.MoneyJiao;//角
v.Rows[(3 * i) + 5].Cells[10].Paragraphs[0].Text = c.MoneyFeng;//分
i++;
}
}
因为要导出的数据较多,而FreeSpire.Office免费版限制,所以使用NPOI,这里只给出代码
private bool ExportToExcelAll(ISession iSession, List es,string path,string fileName)
{
try
{
EAssessmentResultDetail.Schema s = new EAssessmentResultDetail.Schema();
XSSFWorkbook book = new XSSFWorkbook();
int i = 0;
foreach (EAssessmentResult e in es)
{
var sheet = book.CreateSheet($"{i + 1}-{e.FullPathName}"); //创建工作表
var row_Title = sheet.CreateRow(0); //创建列头行
row_Title.CreateCell(0).SetCellValue("指标名称"); //创建单元格
row_Title.CreateCell(1).SetCellValue("指标类型"); //创建单元格
row_Title.CreateCell(2).SetCellValue("评分"); //创建单元格
row_Title.CreateCell(3).SetCellValue("权重"); //创建单元格
row_Title.CreateCell(4).SetCellValue("考评分数"); //创建单元格
int j = 1;
double total = 0;
List lst = QAssessmentResultDetail.Get(iSession, s.AssessmentResultsID == e.AssessmentResultsID, null);
foreach (EAssessmentResultDetail d in lst)
{
var row = sheet.CreateRow(j);
row.CreateCell(0).SetCellValue(d.Name); //创建单元格
row.CreateCell(1).SetCellValue(d.IndicatorsTypeName); //创建单元格
row.CreateCell(2).SetCellValue(d.Rating.ToString()); //创建单元格
row.CreateCell(3).SetCellValue(d.Weights.ToString()); //创建单元格
row.CreateCell(4).SetCellValue(d.Score.ToString()); //创建单元格
total += d.Score;
j++;
}
var rowTotal = sheet.CreateRow(j);
rowTotal.CreateCell(0).SetCellValue("总分");
rowTotal.CreateCell(4).SetCellValue(total.ToString());
i++;
}
if (!Directory.Exists(Server.MapPath(path)))
{
Directory.CreateDirectory(Server.MapPath(path));
}
FileStream fs2 = File.Create(Server.MapPath(path + fileName));
book.Write(fs2);
fs2.Close();
}
catch(Exception ex)
{
throw ex;
}
return true;
}