从零开始实现放置游戏(六)——实现挂机战斗(4)导入Excel数值配置
前面我们已经实现了在后台管理系统中,对配置数据的增删查改。但每次添加只能添加一条数据,实际生产中,大量数据通过手工一条一条添加不太现实。本章我们就实现通过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数值配置的更多相关文章
- 从零开始实现放置游戏(十三)——实现战斗挂机(4)添加websocket组件
前两张,我们已经实现了登陆界面和游戏的主界面.不过游戏主界面的数据都是在前端写死的文本,本章我们给game模块添加websocket组件,实现前后端通信,这样,前端的数据就可以从后端动态获取到了. 一 ...
- 从零开始实现放置游戏(十)——实现战斗挂机(1)hessian服务端搭建
前面实现RMS系统时,我们让其直接访问底层数据库.后面我们在idlewow-game模块实现游戏逻辑时,将不再直接访问底层数据,而是通过hessian服务暴露接口给表现层. 本章,我们先把hessia ...
- 从零开始实现放置游戏(七)——实现挂机战斗(5)RMS系统后台参数校验
前面几章实现了在RMS系统中进行数据的增删查改以及通过Excel批量导入.但仍有遗留的问题,比如在新增或编辑时,怪物的生命值.护甲等数据我们可以输入负值,这种数据是不合理且没有意义的.本章我们就实现服 ...
- 从零开始实现放置游戏(六)——实现后台管理系统(4)Excel批量导入
前面我们已经实现了在后台管理系统中,对配置数据的增删查改.但每次添加只能添加一条数据,实际生产中,大量数据通过手工一条一条添加不太现实.本章我们就实现通过Excel导入配置数据的功能.这里我们还是以地 ...
- 从零开始一个http服务器(六)-多路复用和压力测试
从零开始一个http服务器(六)-多路复用和压力测试 代码地址 : https://github.com/flamedancer/cserver git checkout step6 运行: make ...
- 微信小程序从零开始开发步骤(六)4种页面跳转的方法
用法:用于页面跳转,相当于html里面的<a></a>标签. API教程:https://mp.weixin.qq.com/debug/wxadoc/dev/component ...
- CentOS6安装各种大数据软件 第六章:HBase分布式集群的配置
相关文章链接 CentOS6安装各种大数据软件 第一章:各个软件版本介绍 CentOS6安装各种大数据软件 第二章:Linux各个软件启动命令 CentOS6安装各种大数据软件 第三章:Linux基础 ...
- 《手把手教你》系列技巧篇(六十六)-java+ selenium自动化测试 - 读写excel文件 - 上篇(详细教程)
1.简介 在自动化测试,有些我们的测试数据是放到excel文件中,尤其是在做数据驱动测试的时候,所以需要懂得如何操作获取excel内的内容.由于java不像python那样有直接操作Excle文件的类 ...
- (NO.00005)iOS实现炸弹人游戏(六):游戏数据的初始化(三)
大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 现在我们来看看实际初始化地图的randomCreateMap方法 ...
随机推荐
- (78)zabbix值缓存(value cache)说明
在zabbix-2.2版本之前,zabbix计算trigger与calculated/aggregate值都是直接通过sql语句查询并处理出来的结果,为了提高这块的性能与效率,zabbix引入了val ...
- 6- vue django restful framework 打造生鲜超市 -完成商品列表页(下)
Vue+Django REST framework实战 搭建一个前后端分离的生鲜超市网站 Django rtf 完成 商品列表页下 drf中的request和response drf对于django的 ...
- CentOS 7 bonding模式双网卡绑定
1.1 查看系统内核是否支持bonding [root@cobbler-node1 ~]# cat /boot/config-3.10.0-693.el7.x86_64 | grep -i bo ...
- JZOJ 4732. 【NOIP2016提高A组模拟8.23】函数
4732. [NOIP2016提高A组模拟8.23]函数 (Standard IO) Time Limits: 1500 ms Memory Limits: 262144 KB Detailed ...
- Sublime Text配置python以及快捷键总结
1.打开Tools > Build System > New Build System.. 2.点击New Build System后,会生成一个空配置文件,在这个配置文件内覆盖配置信息, ...
- 51nod 1105 二分答案法标准题目
二分答案法例题,用于练习二分答案的基本思想非常合适,包括了思维方式转换的内容(以前我们所做的一直是利用二分法求得数组元素对应指针之类,但是现在是直接对答案进行枚举). 思路是:首先对输入数组进行排序, ...
- python之时间处理time模块
import time import datetime ''' print(time.time()) #返回当前系统时间戳 print(time.ctime()) #返回当前系统时间 print(ti ...
- Java程序占用实际内存大小
很多人错误的认为运行Java程序时使用-Xmx和-Xms参数指定的就是程序将会占用的内存,但是这实际上只是Java堆对象将会占用的内存.堆只是影响Java程序占用内存数量的一个因素.要更好的理解你的J ...
- Python中str、list、numpy分片操作
在Python里,像字符串(str).列表(list).元组(tupple)和这类序列类型都支持切片操作 对对象切片,s是一个字符串,可以通过类似数组索引的方式获取字符串中的字符,同时也可以用s[a: ...
- laravel5.2总结--数据迁移
迁移就像是数据库中的版本控制,它让团队能够轻松的修改跟共享应用程序的数据库结构. 1 创建一个迁移 1.1 使用artisan命令make:migration来创建一个新的迁移: ph ...