背景
框架:RuoYi-Net Vue2 + Net6
框架自带的导入模板下载功能。生成的模板,表头为字段名。对于用户来说不友好。因此,需要改进下,修改为中文表头,增加用户体验。
java版本的前后端分离框架里,有实现我们想要的功能。参考java版本,对net版本的方法进行优化。
添加Excel 特性
在Infrastructure.Attribute 下新建ExcelAttribute.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Infrastructure.Attribute
{
/// <summary>
/// Excel注释
/// </summary>
public class ExcelAttribute : System.Attribute
{
public string Name { get; set; }
public string readConverterExp { get; set; }
}
}
实体加Excel特性
添加引用using Infrastructure.Attribute; 实体添加Excel 特性
模板列转换为中文名
1.ExcelHelper 添加转换方法
添加一个静态方法,传入字段名,返回特性里的Name值
/// <summary>
/// 获取类里面字段别名
/// </summary>
/// <param name="columnname">字段名称</param>
/// <returns></returns>
public static string GetColumnAlias(string columnname)
{
string alias = "";
PropertyInfo info = typeof(T).GetProperty(columnname);
if (info != null)
{
ExcelAttribute excel = info.GetCustomAttribute<ExcelAttribute>();
if (excel != null && !string.IsNullOrEmpty(excel.Name))
{
alias = excel.Name;
}
}
return alias;
}
2.下载导入模板 调用转换方法
BaseController.DownloadImportTemplate
/// <summary>
/// 下载导入模板
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="list"></param>
/// <param name="stream"></param>
/// <param name="fileName">下载文件名</param>
/// <returns></returns>
protected string DownloadImportTemplate<T>(List<T> list, Stream stream, string fileName) where T : class, new()
{
IWebHostEnvironment webHostEnvironment = (IWebHostEnvironment)App.ServiceProvider.GetService(typeof(IWebHostEnvironment));
string sFileName = $"{fileName}模板.xlsx";
string newFileName = Path.Combine(webHostEnvironment.WebRootPath, "importTemplate", sFileName);
//调试模式需要加上
ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
if (!Directory.Exists(newFileName))
{
Directory.CreateDirectory(Path.GetDirectoryName(newFileName));
}
using (ExcelPackage package = new(new FileInfo(newFileName)))
{
// 添加worksheet
ExcelWorksheet worksheet = package.Workbook.Worksheets.Add(fileName);
//单元格自动适应大小
worksheet.Cells.Style.ShrinkToFit = true;
//全部字段导出
worksheet.Cells.LoadFromCollection(list, true, OfficeOpenXml.Table.TableStyles.Light13);
//替换别名
foreach (var cell in worksheet.Cells)
{
string cellname = cell.Text;
string alias = ExcelHelper<T>.GetColumnAlias(cellname);
if (!string.IsNullOrEmpty(alias))
{
cell.Value = alias;
}
}
package.SaveAs(stream);
}
return sFileName;
}
3.调试起来,重新下载用户的导入模板。可以看到对应的列已经显示为特性里配置的Name
单元格值格式化(即匹配数据字典value值)
1.先在ExcelHelper 添加格式化的方法
/// <summary>
/// 匹配表达式的值
/// </summary>
/// <param name="ConverterExp">数据字典字符串</param>
/// <param name="columnvalue">单元格的值</param>
/// <returns></returns>
public static string ConverterExpMap(string ConverterExp, string cellvalue)
{
string result = cellvalue;
try
{
string[] arr = ConverterExp.Split(',');
for (int i = arr.Length - 1; i >= 0; i--)
{
string[] explist = arr[i].Split('=');
//匹配到的话 就用新的值
if (explist[1].Trim().Equals(cellvalue))
{
result = explist[0];
}
}
return result;
}
catch (Exception)
{
return cellvalue;
}
}
2.修改MapPropertyInfo方法
原方法是按照列名(即字段名)匹配到实体。这里加上按照Excel特性里的Name属性进行匹配。
这样不影响框架里原有的导入功能。
/// <summary>
/// 查找Excel列名对应的实体属性
/// </summary>
/// <param name="columnName"></param>
/// <returns></returns>
public static PropertyInfo MapPropertyInfo(string columnName)
{
PropertyInfo[] propertyList = GetProperties(typeof(T));
//字段名匹配
PropertyInfo propertyInfo = propertyList.Where(p => p.Name == columnName).FirstOrDefault() ;
if (propertyInfo != null)
{
return propertyInfo;
}
//excel特性的Name 匹配
foreach (PropertyInfo item in propertyList)
{
if (item.GetCustomAttribute<ExcelAttribute>() == null)
{
continue;
}
if (item.GetCustomAttribute<ExcelAttribute>().Name == columnName)
{
return item;
}
}
if (propertyInfo != null)
{
return propertyInfo;
}
else
{
foreach (PropertyInfo tempPropertyInfo in propertyList)
{
System.ComponentModel.DescriptionAttribute[] attributes = (System.ComponentModel.DescriptionAttribute[])tempPropertyInfo.GetCustomAttributes(typeof(System.ComponentModel.DescriptionAttribute), false);
if (attributes.Length > 0)
{
if (attributes[0].Description == columnName)
{
return tempPropertyInfo;
}
}
}
}
return null;
}
3.修改导入方法
dictHeader字典里存放的是表头列名及第几列。列名可能是中文名 也可能是英文名。因此,在获取单元格这里,列的位置需要分两种情况来获取。
取到单元格后,当字段类型为字符串时,添加单元格值的转换。
- 取出字段的readConverterExp
- 调用转换方法得到值
4.接下来,进行测试。模板里填写数据
处理完成后,可以看到,实体的Sex属性值为0