1.目的:excel->读数据->存数据库表中
2.项目前后端不分离、工具Idea
3.前端使用jsp+jQuery+bootstrap
4.后端使用SpringBoot框架
5.excel是xlsx后缀
前端页面:
1.放入插件:需要引入插件:4个
<head>
<!-- //css和js都需要放在初始化方法后引用,否则可能导致页面不能正常渲染。一般引用min版,提高页面加载速度 -->
<!--bootstrap-fileinput的css插件:用于文件上传-->
/css/fileinput-rtl.min.css" rel="stylesheet">
<link href="<%=bootstrap%>/css/fileinput.min.css" rel="stylesheet">
</head>
2.添加按钮
<body>
<!--文件上传按钮-->
<input id="upfile" type="file"
accept="image/*,application/pdf,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
multiple="multiple">
</div>
<script src="<%=bootstrap%>/js/fileinput.js"></script>
<script src="<%=bootstrap%>/js/fileinput_locale_zh.js"></script>
</body>
3.js处写法
3.3前后端交互路径
var urlUpload = path +'/building/upfile.do'; //文件上传
3.1//初始化
$(function() {
fileinput1();
})
3.2//实现excel导入功能
function fileinput1() {
//初始化 - 插件的初始化方法应该在页面加载后立即调用,并且只调用一次
$("#upfile").fileinput({
theme:"fa",
language:"zh", //设置语言
uploadAsync:true, //异步上传
dropZoneEnabled:false, //是否显示拖拽区域
showPreview:false, //显示预览信息
uploadUrl: urlUpload,
showPreview:false, //是否显示预览
maxFileSize:20 *1024, //单个文件大小,单位为kb,如果为0表示不限制文件大小
maxFileCount:10, //允许上传的最大文件个数
minFileCount:1, //允许上传的最小文件个数
//uploadExtraData: { "bid": "1"}, //参数
uploadExtraData:function() {//向后台动态传递参数
var data = {bid: buildingid};
return data;
},
allowedFileExtensions: ["xlsx"],
showUpload:true ,//显示上传按钮
}).on("fileuploaded", function(event, data, previewId, index) {
//根据data.response判断是否上传成功
if (data.response.meta.code =="200") {
//alert("123");
$(event.target).fileinput('clear').fileinput('unlock');
swal("上传成功!", "您已经上传了这条信息。", "success");
}else {
swal({
title: data.response.meta.msg, //失败的错误信息
type:"error",
confirmButtonText:"确定"
});
}
});
}
后端:
controller层:
package com.maptechinc.practice.gengqn.building.controller;
import java.io.File;
@Controller
@RequestMapping("/building")
public class BuildingController extends AbstractBaseController {
@Autowired
private BuildingService buildingService;
@Autowired
private HouseService houseService;
//引入配置的路径
@Value("${fileSaveDir}")
private String fileSaveDir;
/**
* excel表上传
* @param request
* @param response
* @throws BusinessException
* @throws IOException
*/
@RequestMapping(value = "/upfile.do")
public void upfile( MultipartFile file_data,HttpServletRequest request, HttpServletResponse response) throws BusinessException, IOException{
Map<String, Object> map = conditionalTransitions(request);
//获取参数,bid=buildingid
String bid = map.get("bid")==null?"":map.get("bid").toString();
List<List<HousePO>> list = this.importExcel(request);
//判断是否选中一条
if("".equals(bid)){
responseJsonWriter(response, Result.failed("请先选择一行数据再上传,谢谢"));
}else{
//excel导入
Result result = buildingService.importHouseExcel(file_data,request,response,bid);
if(result.ok){
responseJsonWriter(response,Result.success("上传成功"));
}else {
responseJsonWriter(response, map, result.msg);
}}}}
Service层:
package com.maptechinc.practice.gengqn.building.service;
import java.io.InputStream;
/**
* <p>类描述:楼房管理 </p>
* <p>类名称:com.maptechinc.practice.gengqn.building.service.BuildingService </p>
* <p>创建人:耿倩楠 </p>
* <p>邮箱:${email} </p>
* <p>创建时间:2023-07-25 11:22:20 </p>
*/
@Service
public class BuildingService{
@Autowired
BuildingDao buildingDao;
@Autowired
HouseDao houseDao;
@Autowired
HousePODao housePODao;
@Autowired
BuildingPODao buildingPODao;
/**
* 导入excel
* 导入字段说明:
* unit<单元>、
* floor<所在层>、
* serialNo<房号>为一个合适大小的正整数,且不可空缺。
* houseCode<单元间号>如果空缺,则系统自动拼接:<单元>+<所在层>+<房号>,用“-”连接,比如1-3-2,如果不空缺,则读取导入的数据。
* houseType<房屋用途>不可空缺,且只能为以下几种之一:住宅,商业,工业,设备用房,其他。
* coveredArea<建筑面积>,privateArea<套内面积>可空缺,空缺时数据库存入0,但如果有值则必须为数字。
* chanjiNo<产籍号>可空缺,空缺时以0补齐。
*/
public Result importHouseExcel(MultipartFile file_data, HttpServletRequest request, HttpServletResponse response,String bid) {
StringBuffer returnmess=new StringBuffer();//用于拼接 上传excel 错误信息
String regex = "^\\d+$"; //正则表达式 只能是数字
Pattern pattern = Pattern.compile(regex); //正则表达式 只能是数字
//flag用于校验的标识
boolean flag=false;
//创建datainsertList,用于存放表格数据
List<Map<String,Object>> datainsertList=new ArrayList<Map<String,Object>>();
try {
//获取文件流
InputStream inputStream = file_data.getInputStream();
//根据路径获取这个操作excel的实例
XSSFWorkbook excel = new XSSFWorkbook(inputStream);
//根据页面index 获取sheet页
Sheet sheet = excel.getSheetAt(0);
//获取sheet页共有多少行
int totalRos = sheet.getPhysicalNumberOfRows();
//System.out.println("=========总行数为:"+totalRos);
for (int i = 2; i <totalRos; i++) {//第1/2行是表头 不需要取
Map<String,Object> aa=new HashMap<String, Object>();
//获取某行数据
int lastCellNum = sheet.getRow(i).getLastCellNum();
aa.put("id",UUID.randomUUID().toString().replaceAll("-", ""));
//判断house表中是否有此buildingId
int count = houseDao.checkByBuildingId(bid.toString());
if(count>0){
flag=true;
returnmess.append("第"+i+"楼栋已存在房屋信息,不可再次导入,请检查");
}else{
aa.put("buildingId",bid);
}
//获取第i行 第几格的数据
aa.put("unit", sheet.getRow(i).getCell(0).toString());
aa.put("floor", sheet.getRow(i).getCell(1).toString());
aa.put("serialNo", sheet.getRow(i).getCell(2).toString());
aa.put("houseCode", sheet.getRow(i).getCell(3).toString());
//获取第i行 第4格的数据
String cellValueHouseType =sheet.getRow(i).getCell(4).toString();
//校验字段,有问题返回
if("".equals(cellValueHouseType)){
flag=true;
returnmess.append("第"+i+"行房屋用途为空,请检查");
}
if(!"住宅".equals(cellValueHouseType)&&
!"商业".equals(cellValueHouseType)&&
!"工业".equals(cellValueHouseType)&&
!"设备用房".equals(cellValueHouseType)){
flag=true;
returnmess.append("第"+i+"行房屋用途,只能为以下几种之一:住宅,商业,工业,设备用房,请检查;");
}
aa.put("houseType", sheet.getRow(i).getCell(4).toString());
//校验字段,有问题返回
String cellValueCoveredArea =sheet.getRow(i).getCell(5).toString();
if(cellValueCoveredArea==""){
aa.put("coveredArea", "0");
}else{
Matcher matcher = pattern.matcher(cellValueCoveredArea);
if (matcher.matches()) { //正则匹配:如果是数字则返回false 反之返回true
flag=true;
returnmess.append("第"+i+"行建筑面积只能是数字,请检查;");
}else{
aa.put("coveredArea", sheet.getRow(i).getCell(5).toString());
}
}
aa.put("privateArea", sheet.getRow(i).getCell(6).toString());
aa.put("status","0");
//校验字段,有问题返回
String cellValueChanjiNo =sheet.getRow(i).getCell(7).toString();
if(cellValueChanjiNo == ""){
aa.put("chanjiNo", "0");
}else{
aa.put("chanjiNo", sheet.getRow(i).getCell(7).toString());
}
datainsertList.add(aa);
}
} catch (Exception e) {
e.printStackTrace();
}
if(flag){
//responseJsonWriter(response, Result.failed(returnmess.toString()));
return Result.failed(returnmess.toString());
}else{
//将数据存到house数据库中
for(int r=0;r<datainsertList.size();r++){
Map<String,Object> map3 = datainsertList.get(r);
houseDao.insert(map3);
}
return Result.success("上传成功");
}
}
}
Dao层:
package com.maptechinc.practice.gengqn.building.dao;
import java.util.List;
@Mapper
public interface BuildingDao {
/**
* 新增一条数据
* @param map
* @return
*/
int insert(Map<String, Object> map);
/**
* 判断楼栋名称是否重复
* @param map
* @return
*/
int checkByName(Map<String, Object> map);
}
XML:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.maptechinc.practice.gengqn.building.dao.BuildingDao">
<select id="dataList" parameterType="java.util.Map" resultType="java.util.Map">
SELECT pb.id,pb.projectId,p.projectName projectName,pb.buildingNo buildingNo,pb.address address,pb.cost cost,COUNT(pb.id) houseCount
FROM practice_building pb
LEFT JOIN practice_project p ON pb.projectId = p.id
LEFT JOIN practice_house ph ON pb.id = ph.buildingId
GROUP BY pb.id,pb.projectId,p.projectName,pb.buildingNo,pb.address,pb.cost;
</select>
<select id="checkByName" parameterType="java.util.Map" resultType="java.lang.Integer">
SELECT COUNT(1)
FROM practice_building
WHERE buildingNo=#{buildingNo};
</select>
<select id="projectDropDown" resultType="com.maptechinc.practice.gengqn.project.bo.Project" parameterType="java.util.Map">
select p.id,p.projectName from `practice_project` p
</select>
<delete id="deleteByProjectId" parameterType="java.util.Map">
DELETE FROM practice_building
WHERE projectId=#{id}
</delete>
</mapper>