上一篇博客介绍了如何完整的基于ssm搭建一个可用于实战开发的项目,本文开始将用此项目用来开发若干idea。本文就先小试牛刀开发基于ssm框架实现poi导入导出excel文件,凭良心讲,这一需求其实在目前企业级应用开发中几乎都用得到,那么本文我将基于自己在项目中遇到的需求来介绍如何实现poi导入导出。如有相关疑问可来此交流:java开源技术交流群-583522159-我是debug (视频教程地址:https://edu.csdn.net/course/detail/8894 欢迎支持!!)
首先我们将基于这样的场景:某部门需要经常导出目前仓库具有产品列表;或者偶尔隔一段时间需要导入一些产品到系统数据库中用于其他业务使用!为了方便展示,首先我们建立一个表:产品表product,建表语句如下:
CREATE TABLE `product` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL COMMENT '名称',
`unit` varchar(20) DEFAULT NULL COMMENT '单位',
`price` double(15,2) DEFAULT NULL COMMENT '单价',
`stock` double(11,0) DEFAULT NULL COMMENT '库存量',
`remark` varchar(1000) DEFAULT NULL,
`purchase_date` date DEFAULT NULL COMMENT '采购日期',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='产品信息表';
然后我们使用mybatis逆向工具生成实体类的相关文件,依次是实体类Product.java,ProductMapper.java以及ProductMapper.xml文件
package com.debug.steadyjack.model;
import java.util.Date;
public class Product {
private Integer id;
private String name;
private String unit;
private Double price;
private Double stock;
private String remark;
private Date purchaseDate;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name == null ? null : name.trim();
}
public String getUnit() {
return unit;
}
public void setUnit(String unit) {
this.unit = unit == null ? null : unit.trim();
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark == null ? null : remark.trim();
}
public Date getPurchaseDate() {
return purchaseDate;
}
public void setPurchaseDate(Date purchaseDate) {
this.purchaseDate = purchaseDate;
}
public Double getStock() {
return stock;
}
public void setStock(Double stock) {
this.stock = stock;
}
@Override
public String toString() {
return "Product [id=" + id + ", name=" + name + ", unit=" + unit
+ ", price=" + price + ", stock=" + stock + ", remark="
+ remark + ", purchaseDate=" + purchaseDate + "]";
}
}
package com.debug.steadyjack.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import com.debug.steadyjack.model.Product;
public interface ProductMapper {
int deleteByPrimaryKey(Integer id);
int insert(Product record);
int insertSelective(Product record);
Product selectByPrimaryKey(Integer id);
int updateByPrimaryKeySelective(Product record);
int updateByPrimaryKey(Product record);
List selectAll(@Param("name") String name);
void insertBatch(@Param("dataList") List dataList);
}
id, name, unit, price, stock, remark, purchase_date
delete from product
where id = #{id,jdbcType=INTEGER}
insert into product (id, name, unit,
price, stock, remark,
purchase_date)
values (#{id,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR}, #{unit,jdbcType=VARCHAR},
#{price,jdbcType=DOUBLE}, #{stock,jdbcType=DOUBLE}, #{remark,jdbcType=VARCHAR},
#{purchaseDate,jdbcType=DATE})
insert into product
id,
name,
unit,
price,
stock,
remark,
purchase_date,
#{id,jdbcType=INTEGER},
#{name,jdbcType=VARCHAR},
#{unit,jdbcType=VARCHAR},
#{price,jdbcType=DOUBLE},
#{stock,jdbcType=DOUBLE},
#{remark,jdbcType=VARCHAR},
#{purchaseDate,jdbcType=DATE},
update product
name = #{name,jdbcType=VARCHAR},
unit = #{unit,jdbcType=VARCHAR},
price = #{price,jdbcType=DOUBLE},
stock = #{stock,jdbcType=DOUBLE},
remark = #{remark,jdbcType=VARCHAR},
purchase_date = #{purchaseDate,jdbcType=DATE},
where id = #{id,jdbcType=INTEGER}
update product
set name = #{name,jdbcType=VARCHAR},
unit = #{unit,jdbcType=VARCHAR},
price = #{price,jdbcType=DOUBLE},
stock = #{stock,jdbcType=DOUBLE},
remark = #{remark,jdbcType=VARCHAR},
purchase_date = #{purchaseDate,jdbcType=DATE}
where id = #{id,jdbcType=INTEGER}
insert into product (name, unit,price, stock, remark,purchase_date)
values (#{data.name,jdbcType=VARCHAR}, #{data.unit,jdbcType=VARCHAR},#{data.price,jdbcType=DOUBLE},
#{data.stock,jdbcType=DOUBLE}, #{data.remark,jdbcType=VARCHAR}, #{data.purchaseDate,jdbcType=DATE})
其中,我在上面以及实现了:查询产品列表(也可用于搜索)、批量插入产品数据 的sql-将分别用于导出以及导入
然后,我们就得开发导出以及导入的controller功能了,PoiController.java:
package com.debug.steadyjack.controller;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Workbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import com.debug.steadyjack.dto.BaseResponse;
import com.debug.steadyjack.enums.StatusCode;
import com.debug.steadyjack.mapper.ProductMapper;
import com.debug.steadyjack.model.Product;
import com.debug.steadyjack.service.PoiService;
import com.debug.steadyjack.utils.ExcelBeanUtil;
import com.debug.steadyjack.utils.ExcelUtil;
import com.debug.steadyjack.utils.WebUtil;
/**
* 导入导出controller
* @author zhonglinsen
*
*/
@Controller
public class PoiController {
private static final Logger log=LoggerFactory.getLogger(PoiController.class);
private static final String prefix="poi";
@Autowired
private ProductMapper productMapper;
@Autowired
private PoiService poiService;
@Value("${poi.excel.sheet.name}")
private String sheetProductName;
@Value("${poi.excel.file.name}")
private String excelProductName;
/**
* 获取产品列表-可用于搜索
* @param name
* @return
*/
@RequestMapping(value=prefix+"/list",method=RequestMethod.GET)
@ResponseBody
public BaseResponse> list(String name){
BaseResponse> response=new BaseResponse>(StatusCode.Success);
try {
List products=productMapper.selectAll(name);
response.setData(products);
} catch (Exception e) {
log.error("获取产品列表发生异常: ",e.fillInStackTrace());
}
return response;
}
/**
* 下载excel
* @param response
* @return
*/
@RequestMapping(value=prefix+"/excel/export",method=RequestMethod.GET)
public @ResponseBody String exportExcel(HttpServletResponse response,String search){
try {
List products=productMapper.selectAll(search);
String[] headers=new String[]{"id编号","名称","单位","单价","库存量","采购日期","备注信息"};
List
在上面涉及到了一些工具类,这些工具类在上篇博文已经贴出来了,自行去找即可!在这里重点再贴一个工具类ExcelBeanUtil.java:专门用于处理某些“业务实体”的excel工具
package com.debug.steadyjack.utils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.debug.steadyjack.model.Product;
/**
* 导入excel bean数据工具类
* @author zhonglinsen
*
*/
public class ExcelBeanUtil {
/**
* 处理产品列表 塞入list-map 等待塞入excel的workbook进行处理
* @param products
* @return
*/
public static List
接下来介绍一下导入导出的思路:
1、导出:对于导出而已,首先我们得明确一点就是最终数据是导出到excel中,而观察excel每个sheet发现,是一个 “二维的世界”,即“矩阵”格式的数据: 头部行是你需要命名的那些字段名,之后的每一行的每一列都是那些字段对应的实际的值,如下图所示:
所以,按照这个逻辑,首先我们需要定好头部行的字段名(当然啦,你也可以配置在配置文件),在这里我是直接建立一个字符串数组存储了,然后你还需要获取你需要导出到excel的productList。按照上面的截图,你会发现,其实每一行就是 一个Object,而多个Object构成了一个list,即List
/**
* 处理产品列表 塞入list-map 等待塞入excel的workbook进行处理
* @param products
* @return
*/
public static List> manageProductList(final List products){
List> dataList=new ArrayList<>();
if (products!=null && products.size()>0) {
int length=products.size();
Map dataMap;
Product bean;
for (int i = 0; i < length; i++) {
bean=products.get(i);
dataMap=new HashMap<>();
dataMap.put(0, bean.getId());
dataMap.put(1, bean.getName());
dataMap.put(2, bean.getUnit());
dataMap.put(3, bean.getPrice());
dataMap.put(4, bean.getStock());
dataMap.put(5, bean.getPurchaseDate());
dataMap.put(6, bean.getRemark());
dataList.add(dataMap);
}
}
return dataList;
}
之后就可以将“头部行”以及“转化后的List
private static final Logger log=LoggerFactory.getLogger(ExcelUtil.class);
private static final String dateFormat="yyyy-MM-dd";
private static final SimpleDateFormat simpleDateFormat=new SimpleDateFormat(dateFormat);
/**
* excel sheet填充数据
* @param dataList
* @param wb
* @param headers
* @param sheetName
*/
public static void fillExcelSheetData(List> dataList,Workbook wb,String[] headers,String sheetName){
Sheet sheet=wb.createSheet(sheetName);
//TODO:创建sheet的第一行数据-即excel的头部信息
Row headerRow=sheet.createRow(0);
for(int i=0;i rowMap:dataList){
try {
row=sheet.createRow(rowIndex++);
for(int i=0;i
最后调用WebUtil直接往输出流塞workbook即可-即excel文件!
直接访问:localhost:8090/ssm_poi/poi/excel/export.do 即可下载
2、导入的话,就比较简单:读取excel->构建workbook->读取excel中sheet数据并入List
package com.debug.steadyjack.service;
import java.util.ArrayList;
import java.util.List;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import com.debug.steadyjack.model.Product;
import com.debug.steadyjack.utils.DateUtil;
import com.debug.steadyjack.utils.ExcelUtil;
@Service
public class PoiService {
private static final Logger log=LoggerFactory.getLogger(PoiService.class);
/**
* 读取excel数据
* @param wb
* @return
* @throws Exception
*/
public List readExcelData(Workbook wb) throws Exception{
Product product=null;
List products=new ArrayList();
Row row=null;
int numSheet=wb.getNumberOfSheets();
if (numSheet>0) {
for(int i=0;i0) {
for(int j=1;i
在上面需要用到excelUtil,上一篇找即可!
然后用postman模拟一下即可实现,其中文件的上传可以用你上面导出来的excel,然后上传即可,如下图:
在这期间,我构建了一个通用 与前端异步交互时 响应信息类BaseResponse.java:
package com.debug.steadyjack.dto;
import com.debug.steadyjack.enums.StatusCode;
public class BaseResponse {
private Integer code;
private String msg;
private T data;
public BaseResponse() {
super();
}
public BaseResponse(StatusCode statusCode) {
this.code=statusCode.getCode();
this.msg=statusCode.getMsg();
}
public BaseResponse(StatusCode statusCode,T data) {
this.code=statusCode.getCode();
this.msg=statusCode.getMsg();
this.data = data;
}
public BaseResponse(Integer code, String msg, T data) {
super();
this.code = code;
this.msg = msg;
this.data = data;
}
public BaseResponse(Integer code, String msg) {
super();
this.code = code;
this.msg = msg;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
状态码类StatusCode.java:
package com.debug.steadyjack.enums;
/**
* 通用状态码enum
* @author zhonglinsen
*
*/
public enum StatusCode {
Success(0,"成功"),
Fail(-1,"失败"),
Invalid_Param(1001,"无效的参数"),
System_Error(1002,"系统错误");
private Integer code;
private String msg;
private StatusCode(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
最后附上项目中后端代码的目录结构:
至此,这个ssm版本的poi导入导出excel就介绍到这里了。至于代码,几乎都贴在这篇博文以及上篇博文了。源码,加群583522159即可领取!!!另外我还录制成了一个视频以及将思路整理成为一个文档以更好的理解,如果需要可付给我一杯咖啡的费用找我要1948831260!
总结:
1、后面会实现根据上线的excel自动判断用HSSFWorkBook还是XSSFWorkBook来区分2003还是2007(网上有些童鞋是根据后缀名来区分,这很明显是错误的:如果我改了一个实质是2007的文档的后缀名为.xls,那就报错了!)
2、整合界面来看效果!