若依前后端分离Net版-导入功能优化(表头修改为中文、添加readConverterExp)

背景

框架: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字典里存放的是表头列名及第几列。列名可能是中文名 也可能是英文名。因此,在获取单元格这里,列的位置需要分两种情况来获取。

 取到单元格后,当字段类型为字符串时,添加单元格值的转换。

  1. 取出字段的readConverterExp
  2. 调用转换方法得到值

 4.接下来,进行测试。模板里填写数据

 

 

 处理完成后,可以看到,实体的Sex属性值为0

<think>好的,我需要解决用户的问题:在导出Excel时包含某个字段,但在导入时排除该字段。用户提到他们使用的是SpringBoot,并且已经通过注解实现了自动导入导出功能。现在需要找到一种方法,在保持导出包含某字段的同时,禁止导入该特定字段。 首先,我得回忆一下SpringBoot中处理Excel导入导出的常用库,比如Apache POI或者可能是更高级的封装库,比如EasyExcel。用户提到使用注解,这可能是指像@ExcelProperty这样的注解,或者是自定义的注解来标记需要导出的字段。 用户的需求是导出时包含字段A,但导入时不处理字段A。这意味着在数据对象中,字段A在导出时应该被序列化,但在导入时不被反序列化。可能的解决方案包括: 1. **使用不同的模型**:创建两个不同的数据对象,一个用于导出(包含字段A),另一个用于导入(不包含字段A)。这种方法简单直接,但可能需要维护两个类,增加代码量。 2. **利用注解的动态配置**:查找是否有现有的注解支持在导入和导出时有不同的行为。例如,EasyExcel的@ExcelProperty可能有属性可以控制是否在导入或导出时忽略字段。例如,有没有类似`ignoreImport`或`ignoreExport`的参数。 3. **自定义注解和处理器**:如果现有注解不支持,可能需要自定义注解,例如@ExcludeOnImport,并在导入时通过自定义的Converter或Listener来跳过该字段的处理。 4. **使用条件判断**:在导入逻辑中,手动排除该字段。例如,在读取Excel数据后,从对象中移除字段A,或者在反序列化时忽略该字段。 接下来需要验证这些方法的可行性。假设用户使用的是EasyExcel,查阅文档发现@ExcelProperty有一个参数`readConverterExp`,但可能不直接支持导入/导出的单独控制。但EasyExcel允许通过自定义转换器或者使用@ExcelIgnore注解来完全忽略字段,但这无法区分导入和导出。 因此,可能的方法是在字段上使用@ExcelProperty,但在导入时通过自定义监听器或处理器来动态忽略该字段。例如,在读取Excel时,使用自定义的ReadListener,在读取到该字段时,不将其设置到对象中。 或者,在数据对象中使用同一个类,但在导入时通过反射或其他方式排除该字段。例如,使用Jackson的@JsonIgnore,但这可能只适用于JSON而不是Excel。 另一个思路是在导出时正常包含字段A,而在导入的代码逻辑中,将字段A设为只写(即在反序列化时忽略)。例如,使用Lombok的@Setter注解,但只在导出时生成getter,导入时不生成setter。但这种方法可能不灵活,因为字段通常需要读写。 可能更有效的方式是使用两个不同的配置:导出时使用包含字段A的配置,导入时使用排除字段A的配置。例如,在EasyExcel中,可以通过定义不同的Excel头来指定导入时忽略某些列。或者在读取时动态调整映射的字段。 总结可能的步骤: 1. 在数据对象中,字段A标记为导出需要的注解,例如@ExcelProperty。 2. 在导出的代码中正常使用该对象,字段A会被包含。 3.导入时,使用自定义的ReadListener或通过设置ExcelReader的head来排除字段A。例如,动态构建导入时的头信息,不包含字段A,这样导入时该字段不会被读取。 或者,使用同一个类,但在导入时通过自定义Converter忽略该字段的值。例如,在Converter中检查字段名,如果是字段A,则跳过设置值。 可能需要查阅EasyExcel的文档或示例,找到动态排除字段的方法。例如,EasyExcel的head可以通过设置一个排除后的列表,这样在导入时只处理需要的字段,忽略字段A。 例如,在读取时,构建一个不包含字段A的HeadMap,然后传递给EasyExcel.read方法。这样,导入时字段A不会被解析,即使Excel中存在该列,数据也不会被读取到对象中。 这样,导出时使用完整的类定义,包含字段A,而导入时使用动态调整后的头信息,排除字段A,从而实现需求。 因此,最终的解决方案可能是在导入时动态调整映射的字段,排除不需要的字段A,而导出时正常处理。这需要根据使用的具体库来实现,但思路是分离导入和导出的配置。</think>在SpringBoot中实现导出包含某字段但导入排除该字段的功能,可以通过以下步骤实现: ### 1. 使用不同注解控制导入/导出行为 若使用**EasyExcel**库,可通过自定义注解或动态设置表头实现: ```java public class DataDTO { // 导出时包含,导入时忽略 @ExcelProperty("字段A") private String fieldA; @ExcelProperty("字段B") private String fieldB; // 导入时手动清空该字段 public void setFieldA(String fieldA) { // 空实现或添加标记 } } ``` ### 2. 动态表头配置(推荐) 在导入时动态过滤字段: ```java // 导出逻辑(包含fieldA) List<List<String>> exportHead = Arrays.asList( Collections.singletonList("字段A"), Collections.singletonList("字段B") ); EasyExcel.write(outputStream, DataDTO.class) .head(exportHead) .sheet().doWrite(dataList); // 导入逻辑(排除fieldA) List<List<String>> importHead = Arrays.asList( Collections.singletonList("字段B") // 仅包含需要导入的字段 ); EasyExcel.read(inputStream, DataDTO.class, new ImportIgnoreListener()) .head(importHead) .sheet().doRead(); ``` ### 3. 使用DTO分离模型 创建两个数据类: ```java // 导出专用DTO public class ExportDTO { @ExcelProperty("字段A") private String fieldA; @ExcelProperty("字段B") private String fieldB; } // 导入专用DTO public class ImportDTO { @ExcelProperty("字段B") private String fieldB; } ``` ### 技术原理说明 1. **动态表头**:通过控制`head()`参数,可指定导入/导出时处理的字段[^1] 2. **Setter控制**:在setter方法中阻止字段赋值,实现导入时自动忽略 3. **注解组合**:配合`@JsonIgnore`等注解实现更精细控制
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值