1、关于MVC导入数据,这里用的是NPOI插件导入,该插件可以在VS软件中自行下载。
话不多说,直接上代码。
导入Excel数据
(1)导入数据,必须先要准备一个模板文件,供用户下载,然后在控制器 中写一个下载模板的方法
(2)在视图中通过window.open()方法调用控制器中的这个方法就好了
视图代码:
//======导入操作
//1、下载导入模板文件
function downImportTemplate()
{
window.open("@Url.Content("~/Main/DownImportTemplate")");
}
控制器代码
public ActionResult DownImportTemplate()
{
//返回与web服务器上的指定虚拟路径相对应的文件物理路径
string filePath = Server.MapPath("~/Document/用户导入模板.xls");
//判断模板文件是否存在
if (System.IO.File.Exists(filePath))
{
//获取文件的名称
string strfileName = Path.GetFileName(filePath);
/*File:返回一个文件
参数一:具体返回文件(这里相当于声明一个文件类型FileStream(参数一: 文件物理路径,参数二:打开文件方式)),也可以是流
参数二:返回文件格式
参数三:返回文件名称
*/
return File(new FileStream(filePath, FileMode.Open), "application/octet-stream", strfileName);
}
else
{
//Content:返回字符对象
return Content("模板文件不存在,请练习系统运维人员。");
}
}
控制器代码二:
public ActionResult ImportExcel(HttpPostedFileBase xlsFile)
{
ReturnJson msg = new ReturnJson();
try
{
//获取文件的后缀
string strExtension = Path.GetExtension(xlsFile.FileName);
//检查文件是不是我们需要的格式
if (".xls".Equals(strExtension, StringComparison.CurrentCultureIgnoreCase))
{
//2、把文件转换为二进制数组
byte[] fileBytes = new byte[xlsFile.ContentLength];
//2.2将上传的文件转换为二进制数组
xlsFile.InputStream.Read(fileBytes, 0, xlsFile.ContentLength);
//3、将二进制数组转换为内存流
MemoryStream excleMemoryStream = new MemoryStream(fileBytes);
//利用NPOI把内存流中的数据读取成Excel
NPOI.SS.UserModel.IWorkbook wokbook = new NPOI.HSSF.UserModel.HSSFWorkbook(excleMemoryStream);//HSSFWorkbook:将内容流转化工作簿
//判断该工作簿是否有工作表 NumberOfSheets:判断工作表的
if(wokbook.NumberOfSheets > 0)
{
//获取第一个工作表
NPOI.SS.UserModel.ISheet sheet = wokbook.GetSheetAt(0);
//判断工作表是否存在行
if (sheet.PhysicalNumberOfRows > 0)
{
//创建一个临时表
DataTable dt = new DataTable();
//先获取表头行,为第二行,索引为1,因为第一行是说明
NPOI.SS.UserModel.IRow rowHeader = sheet.GetRow(1);
/*
FirstCellNum:获取某行第一个单元格下标
LastCellNum:获取某行的列数 !!!!!(只有这个获取的是数值,其它三个获取的都是索引)
FirstRowNum:获取第一个实际行的下标
LastRowNum:获取最后一个实际行的下标(获取当前行最后一个单元格的值)
*/
//获取表格总列数
int cellCount = rowHeader.LastCellNum;
//获取表格总行数
int rowCount = sheet.LastRowNum + 1;
//1、Excel表头作为dt的列
for (int i = rowHeader.FirstCellNum; i < cellCount; i++)
{
DataColumn dtColumn = new DataColumn(rowHeader.GetCell(i).StringCellValue.Trim());
//Columns:添加列
dt.Columns.Add(dtColumn);
}
//2、Excel数据作为dt的数据
for (int i = (sheet.FirstRowNum) + 2; i < rowCount; i++)
{
//获取行
NPOI.SS.UserModel.IRow row = sheet.GetRow(i);
DataRow dtRow = dt.NewRow();
if(row != null)
{
//第一次循环j是从第三行第一个单元格
for (int j = row.FirstCellNum; j < cellCount; j++)
{
if(row.GetCell(j) != null)
{
dtRow[j] = row.GetCell(j).ToString();
}
}
}
//将一行的数据添加到DataTable(临时表)中
dt.Rows.Add(dtRow);
}
//移除空行
removeEmptyRow(dt);
#region 数据验证
//查询学生表
List<S_Student> userStudent = (from tb in myModel.S_Student
select tb).ToList();
//查询班级表
List<S_Class> userClass = (from tb in myModel.S_Class
select tb).ToList();
//定义存放新增数据容器(用于保存新增的数据)
List<S_Student> saveUsers = new List<S_Student>();
//遍历DataTable(临时表)中的数据
for (int i = 0; i < dt.Rows.Count; i++)
{
try
{
DataRow dr = dt.Rows[i];
S_Student addStudent = new S_Student();
//1、编号
string studentNumber = dr["编号"].ToString().Trim();
int oldCount = userStudent.Count(o => o.studentNumber == studentNumber);
if(oldCount > 0)
{
msg.Text = "第" + (i + 1) + "条数据的编号:【" + studentNumber + "】已存在,请修改";
return Json(msg, JsonRequestBehavior.AllowGet);
}
addStudent.studentNumber = studentNumber;
//2、班级
string className = dr["班级"].ToString().Trim();
//根据班级名称 去到班级表 提取班级ID
addStudent.classID = userClass.Single(o => o.calssName == className).calssID;
//3、姓名
string studentName = dr["姓名"].ToString().Trim();
if (string.IsNullOrEmpty(studentName))
{
msg.Text = "第" + (i + 1) + "条数据的姓名未填写,请检查";
return Json(msg, JsonRequestBehavior.AllowGet);
}
addStudent.studentName = studentName;
//4、性别
string studentSex = dr["性别"].ToString().Trim();
if (string.IsNullOrEmpty(studentSex))
{
msg.Text = "第" + (i + 1) + "条数据的性别未填写,请检查";
return Json(msg, JsonRequestBehavior.AllowGet);
}
addStudent.studentSex = studentSex;
//5、手机号
string telephone = dr["手机号"].ToString().Trim();
if (string.IsNullOrEmpty(telephone))
{
msg.Text = "第" + (i + 1) + "条数据的手机号未填写,请检查";
return Json(msg, JsonRequestBehavior.AllowGet);
}
addStudent.telephone = telephone;
//6、身份证
string studentIDCard = dr["身份证号"].ToString().Trim();
int oldCount2 = userStudent.Count(o => o.studentIDCard == studentIDCard);
if (oldCount2 > 0)
{
msg.Text = "第" + (i + 1) + "条数据的身份证:【" + studentIDCard + "】已存在,请修改";
return Json(msg, JsonRequestBehavior.AllowGet);
}
addStudent.studentIDCard = studentIDCard;
//添加到要保存的列表中
saveUsers.Add(addStudent);
//添加到用于查看的列表allUseris
userStudent.Add(addStudent);
}
catch (Exception e)
{
Console.Write(e);
msg.Text = "第" + (i + 1) + "条数据不正确,请检查!";
return Json(msg, JsonRequestBehavior.AllowGet);
}
}
#endregion
#region 新增保存
//=============进行数据保存
try
{
//遍历新增数据
foreach (S_Student item in saveUsers)
{
//保存学生数据
myModel.S_Student.Add(item);
myModel.SaveChanges();
}
msg.State = true;
msg.Text = "数据导入成功,成功导入" + saveUsers.Count() + "条用户数据";
}
catch (Exception)
{
msg.Text = "数据导入保存失败";
return Json(msg, JsonRequestBehavior.AllowGet);
}
#endregion
}
else
{
msg.Text = "导入失败,请检查第一个工作表中是否存在数据!";
}
}
else
{
msg.Text = "导入失败,请检查工作表是否存在";
}
}
else
{
msg.Text = "导入失败,请上传.xls类型的文件";
}
}
catch (Exception)
{
msg.Text = "导入失败,请检查是否有工作表,是否有数据,是否按照模板填写!";
}
return Json(msg, JsonRequestBehavior.AllowGet);
}
/// <summary>
/// 5.3 去除datatable空行
/// </summary>
/// <param name="dt"></param>
private void removeEmptyRow(DataTable dt)
{
//存放需要移除的DataRow
List<DataRow> removeList = new List<DataRow>();
//遍历所有的行
for (int i = 0; i < dt.Rows.Count; i++)
{
bool rowDataIsEmpty = true;//标识是否是空行-默认为空行
//遍历DataRow的所有列
for (int j = 0; j < dt.Columns.Count; j++)
{
//判断数据是否为空
if (!string.IsNullOrEmpty(dt.Rows[i][j].ToString().Trim()))
{
rowDataIsEmpty = false;
}
}
//如果是空行,添加到removeList
if (rowDataIsEmpty)
{
removeList.Add(dt.Rows[i]);
}
}
//移除掉空行
for (int i = 0; i < removeList.Count; i++)
{
dt.Rows.Remove(removeList[i]);
}
}
ReturnJson 这个是封装的一个实体类,代码如下:
namespace PartOne.EntityClass
{
public class ReturnJson
{
/// <summary>
/// 状态
/// </summary>
public bool State { get; set; }
/// <summary>
/// 状态码
/// </summary>
public string Code { get; set; }
/// <summary>
/// 文本
/// </summary>
public String Text { get; set; }
/// <summary>
/// 附加数据
/// </summary>
public object Object { get; set; }
}
}
最后说一下导入数据整体思路:
第一步:判断文件类型是否是.xls,判断正确后再执行下面操作
1、获取上传的文件
2、把文件转换为二进制数组
3、将二进制数组转化为内存流
4、利用NPOI把内存流中的数据读取成Excel
5、使用NPOI读取数据
第二步:判断工作簿中是否有工作表
第三步:判断工作表中是否有数据
第四步:获取数据,保证数据的准确性和判断数据的重复性、移除空行
第五步:保存数据
最后:
其实不管是导出还是导入:都需要用到NPOI将表格数据转化为内存 流,在进行下一步
导出:将表格数据数据转化为内存流在导出
导入:将文件转化为二进制数组,在将二进制数组转化为内存流,然后将内存流的数据读取成Excel,在使用NPOI来读取数据
当修改模板的时候:选择另存为的时候,类型最好选这一个,因为这一个类型的兼容性是最好的