前面我们已经实现了在后台管理系统中,对配置数据的增删查改。但每次添加只能添加一条数据,实际生产中,大量数据通过手工一条一条添加不太现实。本章我们就实现通过Excel导入配置数据的功能。这里我们还是以地图数据为例,其他配置项可参照此例。

  涉及的功能点主要有对office文档的编程、文件上传功能。流程图大致如下:

一、添加依赖项

  解析office文档推荐使用免费的开源组件POI,已经可以满足80%的功能需求。上传文件需要依赖commons-fileupload包。我们在pom中添加下列代码:

<!-- office组件 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.1.0</version>
</dependency>
<!-- 文件上传 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>

  另外,之前我们配置的mvc视图解析器只能解析简单的视图,上传文件需要支持multipart。在spring-mvc.xml中添加如下配置:

<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="UTF-8"></property>
<property name="maxUploadSize" value="10485770"></property>
<property name="maxInMemorySize" value="10485760"></property>
</bean>

  这里配置了上传最大限制10MB,对于excel上传来说足矣。

二、文件上传、解析、落库

  在MapController中,我们添加3个方法

    @ResponseBody
@RequestMapping(value = "/importExcel", method = RequestMethod.POST)
public Object importExcel(HttpServletRequest request) {
try {
ServletContext servletContext = request.getServletContext();
String uploadPath = servletContext.getRealPath("/upload");
File dir = new File(uploadPath);
if (!dir.exists()) {
dir.mkdir();
} CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(servletContext);
if (multipartResolver.isMultipart(request)) {
MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request;
Iterator<String> iter = multiRequest.getFileNames();
while (iter.hasNext()) {
MultipartFile file = multiRequest.getFile(iter.next());
if (file.getSize() > 0) {
String fileName = file.getOriginalFilename();
String extension = fileName.substring(fileName.lastIndexOf("."));
if (!extension.toLowerCase().equals(".xls") && !extension.toLowerCase().equals(".xlsx")) {
throw new Exception("不支持的文档格式!请上传.xls或.xlsx格式的文档!");
} String destFileName = fileName + "_" + System.currentTimeMillis() + extension;
File destFile = new File(uploadPath, destFileName);
file.transferTo(destFile);
List<WowMap> dataList = this.loadExcelData(destFile.getPath());
this.saveExcelData(dataList);
if (!destFile.delete()) {
logger.warn("临时文件删除失败:" + destFile.getAbsolutePath());
}
}
}
} return CommonResult.success();
} catch (Exception ex) {
logger.error(ex.getMessage(), ex);
return CommonResult.fail();
}
} protected List<WowMap> loadExcelData(String excelPath) throws Exception {
FileInputStream fileInputStream = new FileInputStream(excelPath);
XSSFWorkbook workbook = new XSSFWorkbook(fileInputStream);
Sheet sheet = workbook.getSheet("地图");
List<WowMap> wowMapList = new ArrayList<>();
// 处理当前页,循环读取每一行
String createUser = this.currentUserName();
for (int rowNum = 2; rowNum <= sheet.getLastRowNum(); rowNum++) {
XSSFRow row = (XSSFRow) sheet.getRow(rowNum);
String name = PoiUtil.getCellValue(row.getCell(2));
DataDict.Occupy occupy = DataDict.Occupy.getByDesc(PoiUtil.getCellValue(row.getCell(4)));
WowMap wowMap = new WowMap();
wowMap.setName(name);
wowMap.setOccupy(occupy.getCode());
wowMap.setDescription("");
wowMap.setCreateUser(createUser);
wowMapList.add(wowMap);
} fileInputStream.close();
return wowMapList;
} protected void saveExcelData(List<WowMap> dataList) {
wowMapManager.batchInsert(dataList);
}

MapController.java

  其中,importExcel方法,时候对应前端点击导入按钮时的后端入口,在这个方法中,我们定义了临时文件上传路径,校验了文件名后缀,保存上传的文件到服务器,并在操作结束后将临时文件删除; loadExcelData方法,利用POI组件读取解析Excel数据,Excel数据怎么配我们可以自由定义,这里读取时自由调整对应的行列即可,本例使用的Excel在文末给出的源码中可以找到; saveExcelData方法,将解析到的数据列表存入数据库,这里调用的batchInsert批量添加方法,在前面讲增删查改的时候已经提前实现了。

  另外,在使用POI组件读取Excel数据时,需要先判断单元格格式,我们创建一个工具类PoiUtil来实现此功能,这种在以后的其他项目中也可以使用的工具类,我们把它提取出来,放到util模块中,作为我们的通用工具包,以便日后使用。在util模块新建包com.idlewow.util.poi,并添加PoiUtil类:

package com.idlewow.util.poi;

import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.DateUtil; import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Date; public class PoiUtil {
public static String getCellValue(Cell cell) {
CellType cellType = cell.getCellType();
if (cellType.equals(CellType.STRING)) {
return cell.getStringCellValue();
} else if (cellType.equals(CellType.NUMERIC)) {
if (DateUtil.isCellDateFormatted(cell)) {
Date date = cell.getDateCellValue();
return date == null ? "" : new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date);
} else {
return new DecimalFormat("0.##").format(cell.getNumericCellValue());
}
} else if (cellType.equals(CellType.FORMULA)) {
if (StringUtils.isNotBlank(cell.getStringCellValue())) {
return cell.getStringCellValue();
} else {
return cell.getNumericCellValue() + "";
}
} else if (cellType.equals(CellType.BOOLEAN)) {
return cell.getBooleanCellValue() ? "TRUE" : "FALSE";
} else {
return "";
}
}
}

PoiUtil.java

  工具类提取到util模块后,需要在util模块也添加对Poi的依赖,并在rms模块添加对util的依赖。这里util模块中,依赖项的scope为provided即可,仅在编译阶段使用,因为在引用此工具包的模块中肯定已经引入了POI依赖,无需重复打包:

<dependencies>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>

三、修改前端页面

在地图列表页面list.jsp中,添加导入excel的按钮。

<form>
…………
…………
<div class="layui-inline layui-show-xs-block">
<button type="button" class="layui-btn" onclick="xadmin.open('添加地图','add',500,500)">
<i class="layui-icon"></i>添加地图
</button>
</div>
<div class="layui-upload layui-inline layui-show-xs-block">
<button type="button" class="layui-btn layui-btn-normal" id="btnSelectFile">选择Excel</button>
<button type="button" class="layui-btn" id="btnImport">开始导入</button>
</div>
</form>

在列表页面的list.js中,绑定相应的按钮事件。

layui.use(['upload', 'table', 'form'], function () {
…………
………… layui.upload.render({
elem: '#btnSelectFile',
url: '/manage/map/importExcel',
accept: 'file',
exts: 'xls|xlsx',
auto: false,
bindAction: '#btnImport',
done: function (result) {
if (result.code === 1) {
layer.alert(result.message, {icon: 6},
function () {
layui.layer.closeAll();
layui.table.reload('datatable');
});
} else {
layer.alert(result.message, {icon: 5});
}
}
});
});

四、运行效果

  以上,excel导入的功能就全部完成了,我们运行下看下效果:

  

小结

  本章通过导入Excel文件,实现了批量录入的功能。

  源码下载地址:https://idlestudio.ctfile.com/fs/14960372-383760599

  本文原文地址:https://www.cnblogs.com/lyosaki88/p/idlewow_6.html

  下一章,预计实现添加、修改时的参数校验。

  项目交流群:329989095

从零开始实现放置游戏(六)——实现后台管理系统(4)Excel批量导入的更多相关文章

  1. 从零开始实现放置游戏(七)——实现挂机战斗(5)RMS系统后台参数校验

    前面几章实现了在RMS系统中进行数据的增删查改以及通过Excel批量导入.但仍有遗留的问题,比如在新增或编辑时,怪物的生命值.护甲等数据我们可以输入负值,这种数据是不合理且没有意义的.本章我们就实现服 ...

  2. 从零开始实现放置游戏(六)——实现挂机战斗(4)导入Excel数值配置

    前面我们已经实现了在后台管理系统中,对配置数据的增删查改.但每次添加只能添加一条数据,实际生产中,大量数据通过手工一条一条添加不太现实.本章我们就实现通过Excel导入配置数据的功能.这里我们还是以地 ...

  3. 从零开始实现放置游戏(十)——实现战斗挂机(1)hessian服务端搭建

    前面实现RMS系统时,我们让其直接访问底层数据库.后面我们在idlewow-game模块实现游戏逻辑时,将不再直接访问底层数据,而是通过hessian服务暴露接口给表现层. 本章,我们先把hessia ...

  4. 从零开始实现放置游戏(十三)——实现战斗挂机(4)添加websocket组件

    前两张,我们已经实现了登陆界面和游戏的主界面.不过游戏主界面的数据都是在前端写死的文本,本章我们给game模块添加websocket组件,实现前后端通信,这样,前端的数据就可以从后端动态获取到了. 一 ...

  5. 从零开始编写自己的C#框架(8)——后台管理系统功能设计

    还是老规矩先吐下槽,在规范的开发过程中,这个时候应该是编写总体设计(概要设计)的时候,不过对于中小型项目来说,过于规范的遵守软件工程,编写太多文档也会拉长进度,一般会将它与详细设计合并到一起来处理,所 ...

  6. vue从入门到女装??:从零开始搭建后台管理系统(二)用vue-docute生成线上文档

    教程 vue从入门到女装??:从零开始搭建后台管理系统(一)安装框架 一个系统开发完成了总要有操作说明手册,接口文档之类的东西吧?这种要全部纯手写就很麻烦了,可以借助一些插件,比如: vue-docu ...

  7. 从零开始搭建vue+element-ui后台管理系统项目到上线

    前言 之前有些过移动端的项目搭建的文章,感觉不写个pc端管理系统老感觉少了点什么,最近公司项目比较多,恰巧要做一个申报系统的后台管理系统,鉴于对vue技术栈比较熟悉,所以考虑还是使用vue技术栈来做: ...

  8. 从零开始搞后台管理系统(1)——shin-admin

      shin 的读音是[ʃɪn],谐音就是行,寓意可行的后台管理系统,shin-admin 的特点是: 站在巨人的肩膀上,依托Umi 2.Dva 2.Ant Design 3和React 16.8搭建 ...

  9. ASP.NET MVC5+EF6+EasyUI 后台管理系统(1)-前言与目录(持续更新中...)

    开发工具:VS2015(2012以上)+SQL2008R2以上数据库  您可以有偿获取一份最新源码联系QQ:729994997 价格 666RMB  升级后界面效果如下: 任务调度系统界面 http: ...

随机推荐

  1. SpringBoot(14)—注解装配Bean

    SpringBoot(14)-注解装配Bean SpringBoot装配Bean方式主要有两种 通过Java配置文件@Bean的方式定义Bean. 通过注解扫描的方式@Component/@Compo ...

  2. java基础(18):集合、Iterator迭代器、增强for循环、泛型

    1. 集合 1.1 集合介绍 集合,集合是java中提供的一种容器,可以用来存储多个数据. 在前面的学习中,我们知道数据多了,可以使用数组存放或者使用ArrayList集合进行存放数据.那么,集合和数 ...

  3. 962. Maximum Width Ramp

    本题题意: 在数组中,找到最大的j-i,使得i<j and A[i] <= A[j] 思路: 维持一个递减的栈,遇到比栈顶小的元素,进栈: 比大于等于栈顶的元素-> 找到栈中第一个小 ...

  4. [转]关于maven pom.xml中dependency type 为pom的应用

    原文地址:http://blog.csdn.net/yao123long/article/details/49925659 dependency为什么会有type为pom,默认的值是什么?depend ...

  5. python从入门到放弃--线程进阶

    # ### 死锁,递归锁,互斥锁 from threading import Thread,Lock import time noodle_lock = Lock() kuaizi_lock = Lo ...

  6. 事务的四大性质:ACID

    1. 原子性(Atomicity) 一个原子事务要么完整执行,要么干脆不执行.这意味着,工作单元中的每项任务都必须正确执行.如果有任一任务执行失败,则整个工作单元或事务就会被终止.即此前对数据所作的任 ...

  7. 海思Hi3519A MPP从入门到精通(一 系统概述)

    1. 概述 海思提供的媒体处理软件平台(Media Process Platform,简称 MPP),可支持应用软件快速 开发.该平台对应用软件屏蔽了芯片相关的复杂的底层处理,并对应用软件直接提供 M ...

  8. STM32HAL快速上手

    STM32HAL快速上手 资料下载 如果在下面的网站中没有账户,建议用edu邮箱创建账户. STMicroeletronic 意法半导体官网 首页 - STMicroelectronics 意法半导体 ...

  9. Centos系统配置bond0

    版权声明:本文为博主原创文章,支持原创,转载请附上原文出处链接和本声明. 本文链接地址:https://www.cnblogs.com/wannengachao/p/11942254.html 1.查 ...

  10. blue bossa

    blue bossa