通过Maven工具,在pom.xml导入坐标

<!--用于获取Excel表的内容-->
<dependency>
<groupId>net.sourceforge.jexcelapi</groupId>
<artifactId>jxl</artifactId>
<version>2.6.12</version>
</dependency>

实体类:

/**
* 自己写的实体类
*/
public class KjtboundOrder {
/**
* 运单号
*/
private String logisticsno;
/**
* 企业名称
*/
private String ebpname;



public KjtboundOrder() {
}

public KjtboundOrder(String logisticsno, String ebpname) {
this.logisticsno = logisticsno;
this.ebpname = ebpname;
}

public String getLogisticsno() {
return logisticsno;
}

public void setLogisticsno(String logisticsno) {
this.logisticsno = logisticsno;
}

public String getEbpname() {
return ebpname;
}

public void setEbpname(String ebpname) {
this.ebpname = ebpname;
}



@Override
public String toString() {
return "KjtboundOrder{" +
"logisticsno='" + logisticsno + '\'' +
", ebpname='" + ebpname + '\'' +
'}';
}
}

Controller层:

用于:获取前端传递过来的execl文件,并且保存,在读取本地的文件,在通过指定的行和列读取所有的运单号信息,并且存储到集合中,在调用业务层对象的方法把集合传入。

/**
* 运单号识别并且分类
*
* @param request
* @param file
* @return
*/
@RequestMapping("/importOrder")
@ResponseBody
public R importOrder(HttpServletRequest request, @RequestParam(value = "excel", required = true) MultipartFile file){
System.out.println("进入到自己写的Controller中");
//创建list集合用于存储数据
ArrayList<String> PostcodeID=null;

Map<String,Object> map=null;
//判断文件是否为空
if (null!=file && !file.isEmpty()){

PostcodeID=new ArrayList<>();

//证明里面有数据
//设置保存的路径
String path=FileUtil.getClasspath()+"/files/ExcelCache/";
SimpleDateFormat sdf=new SimpleDateFormat("YYYYMMddHHmmss");
//保存的文件名称
String updateFileName = sdf.format(new Date());
//保存前端的传输的数据,并且返回文件名称
String fileName = FileUpload.fileUp(file, path, updateFileName);

//全路径
String name=path+fileName;

System.out.println("前端保存路径地址:"+name);


try {
//使用workBook 获取表
Workbook readxls=Workbook.getWorkbook(new File(name));
//2.获取第一张表
Sheet readsheet = readxls.getSheet(0);
//3.获取sheet表的总行数
int rows = readsheet.getRows();
//4.获取sheet表的总列数
int columns = readsheet.getColumns();

System.out.println("总行数:"+rows);
System.out.println("总列数"+columns);
//5.获取单元格的信息
for (int i = 1; i <rows; i++) {
for (int j = 2; j <=2; j++) {//获取第二列的数据
//获取表格的坐标(列,行)
Cell cell = readsheet.getCell(j,i);
//通过表格坐标得到数据信息
String contents = cell.getContents();
//判断获取的元素是否为空
if(!StringUtils.isEmpty(contents)){
//不为空添加到数据中
PostcodeID.add(contents);
System.out.print(contents+"\t");
}
}
}

String AccessPath = kjtOrderService.batchSelect(PostcodeID);
System.out.println("文件名称:"+AccessPath);

map=new HashMap<>();
map.put("msg","上传成功<br>合计上传:"+PostcodeID.size()+"条数据");
map.put("code","200");
map.put("load",AccessPath);//把文件名称存储到load参数中,用于前端发送请求下载文件

} catch (IOException e) {
e.printStackTrace();
} catch (BiffException e) {
e.printStackTrace();
}
System.out.println("传入的数据一共有多少个单号:"+PostcodeID.size());

}else{
//传入的是空数据
return R.error(500,"数据为空");
}

//return R.ok("成功...共上传的订单号总和: "+PostcodeID.size());
return R.ok(map);
}


其中的R就是封装了些方法,用于返回json数据


Service业务层​:

用于:获取Controller层传递的集合并且遍历运单号,在通过manager层对象调用持久层对象。当数据库查询到数据存放到集合中在传递给工具类把数据写到Execl中,并且返回Execl文件名称。

/**
* 用于批量查询
* @param postcodeID
*/
@Override
public String batchSelect(ArrayList<String> postcodeID) {
ArrayList<KjtboundOrder> kjtboundOrders=new ArrayList<>();
for (String id:postcodeID){
System.out.println("ID"+id);
//把每一个订单拿去查询
KjtboundOrder kjtboundOrder = kjtOrderManager.SelectLogisticsno(id);

if (kjtboundOrder!=null){
//数据不为空时进入
//把id设置进去
kjtboundOrder.setLogisticsno(id);
kjtboundOrders.add(kjtboundOrder);
}
}
String filename = KjtExcelUtils.WriterWaybillPartition(kjtboundOrders);

return filename;
}

manager

用于:调用dao持久层对象查询数据库并且返回。

@Override
public KjtboundOrder SelectLogisticsno(String id) {
//调用持久层对象查询运单号并且封装到实体类
return kjtInboundOrderMapper.selectLogisticsno(id);
}

Dao持久层:

用于:通过运单id去查询Oracle数据库并且返回给manager层

<!--自己写的查询运单号-->
<select id="selectLogisticsno" resultType="KjtboundOrder" >
select EBPNAME from kjt_order where logisticsno=#{id,jdbcType = VARCHAR}
</select>

工具类:

用于:完成前端数据的保存

public class FileUpload {

/**上传文件
* @param file //文件对象
* @param filePath //上传路径
* @param fileName //文件名
* @return 文件名
*/
public static String fileUp(MultipartFile file, String filePath, String fileName){
String extName = ""; // 扩展名格式:
try {
if (file.getOriginalFilename().lastIndexOf(".") >= 0){
extName = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
if (extName == ".xlsm" || extName.equals(".xlsm")) {
extName = ".xlsx";
}
}
copyFile(file.getInputStream(), filePath, fileName+extName).replaceAll("-", "");
} catch (IOException e) {
System.out.println(e);
}

return fileName+extName;
}
/**
* 写文件到当前目录的upload目录中
* @param in
* @param fileName
* @throws IOException
*/
private static String copyFile(InputStream in, String dir, String realName)
throws IOException {
File file = mkdirsmy(dir,realName);
FileUtils.copyInputStreamToFile(in, file);
return realName;
}
/**判断路径是否存在,否:创建此路径
* @param dir 文件路径
* @param realName 文件名
* @throws IOException
*/
public static File mkdirsmy(String dir, String realName) throws IOException{
File file = new File(dir, realName);
if (!file.exists()) {
if (!file.getParentFile().exists()) {
file.getParentFile().mkdirs();
}
file.createNewFile();
}
return file;
}
}

通过workbook 完成数据库查询并且把数据存储到Execl中并且返回Execl的名称

public class KjtExcelUtils {
/**
* 通过公司名称分类运单号
*
* @param kjtboundOrders 传递的运单信息集合
* @return 返回文件保存的名称
*/
public static String WriterWaybillPartition(List<KjtboundOrder> kjtboundOrders) {
//第一步,创建一个workbook对应一个excel文件
HSSFWorkbook workbook = new HSSFWorkbook();
HSSFSheet sheet = null;//工作簿
HSSFRow row = null;//行
HSSFCell cell = null;//单元格

//第二步,写入实体数据,实际应用中这些数据从数据库得到,对象封装数据。对象的属性值对应表的每行的值
//遍历集合对象元素
for (int i = 0; i < kjtboundOrders.size(); i++) {
//获取一个实体类对象
KjtboundOrder kjtboundOrder = kjtboundOrders.get(i);
//第三步 :设置内容
//3.1 首先要进行判断当前的工作表是不是实体类中的公司名称
String ebpname = kjtboundOrder.getEbpname();//获取公司名称
//通过公司获取工作簿
sheet = workbook.getSheet(ebpname);
//System.out.println("工作表叫:" + sheet);

//3.2 判断是否为null 如果为null则工作簿不存在
if (sheet == null) {
//3.2 证明没有该公司的工作簿,则创建工作簿用公司名称命名
sheet = workbook.createSheet(ebpname);

//3.3设置工作簿的单元格大小:列的索引,列的宽度
//这里你会发现一个有趣的现象,SetColumnWidth的第二个参数要乘以256,
// 这是怎么回事呢?其实,这个参数的单位是1/256个字符宽度,也就是说,
// 这里是把A列的宽度设置为了18个字符。
sheet.setColumnWidth(0,18*256);//设置的是运单列
sheet.setColumnWidth(1,30*256);//设置的是公司列



//3.4 在sheet表中添加表头第0行,老版本的poi对sheet的行列有限制
row = sheet.createRow(0);//创建第0行
//3.5 创建单元格,设置表头
cell = row.createCell(0);//第0行的第0个列
cell.setCellValue("运单号");//并且设置内容

cell = row.createCell(1);//第0行的第1个列
cell.setCellValue("企业名称");//并且设置内容

}

//4. 如果有该公司的工作簿则添加数据
//4.1 获取工作簿的最后一行是多少
int lastRowNum = sheet.getLastRowNum();
//System.out.println("当前的表我末尾是几行" + lastRowNum);

//4.2 创建第lastRowNum+1的行
row = sheet.createRow(lastRowNum + 1);//创建行单元格

cell = row.createCell(0);//第lastRowNum+1行的第0个列
cell.setCellValue(kjtboundOrder.getLogisticsno());//并且设置该列的值信息

cell = row.createCell(1);//第lastRowNum+1行的第1个列
cell.setCellValue(kjtboundOrder.getEbpname());//并且设置该列的值信息

System.out.println("获取行数:" + sheet.getRepeatingColumns());
}

//5 设置保存的路径
String path= FileUtil.getClasspath()+"/files/Excel/";
File folder=new File(path);
//5.1 判断路径是否存在不存在创建
if (!folder.exists()){
//文件夹不存在创建文件夹
folder.mkdirs();
}
//5.2 设置文件的名称
SimpleDateFormat sdf=new SimpleDateFormat("YYYYMMddHHmmss");
//保存的文件名称
String updateFileName = sdf.format(new Date());
String Filename=path+updateFileName+".xls";

//5.3 判断该文件是否存在
File file = new File(Filename);
if (file.exists()) {
//存在删除
file.delete();
}
//将文件保存到指定的位置
try {
//创建新文件
file.createNewFile();
//6 通过Workbook 方法保存文件
workbook.write(file);
System.out.println("写入成功");
//6.2 释放资源
workbook.close();
} catch (IOException e) {
e.printStackTrace();
}

//返回文件的地址
//return file.getAbsolutePath();

//6.3返回文件名称
return file.getName();
}
}

这样就差不多完成业务逻辑,接着前端需要下载Execl表格:

前端js

通过Workbook完成,按照公司名称分类Execl_数据

url="../../sys/inboundOrder/downimportOrderExcel?filename="+data.load;
dialogAlert(data.msg+"<br>"+'<a style="color:blue;font-size: 18px" href="'+url+'" >点击下载Excel表格</a>');

发送请求到Controller层

/**
* 运单号分类后的Excl模板下载
*
* @param response
* @param filename 需要下载的文件名称
* @throws Exception
*/
@RequestMapping(value = "/downimportOrderExcel")
public void downimportOrderExcel(HttpServletResponse response,String filename) throws Exception {
FileUtil.fileDownload(response, FileUtil.getClasspath() + "/files/Excel/"+filename, "运单分类汇总"+filename);
}

工具类:

/**
* 文件下载
* @param response
* @param filePath 需要传入的数据路径
* @param fileName 传输到前端文件的名称
* @throws Exception
*/
public static void fileDownload(final HttpServletResponse response,
String filePath, String fileName) throws Exception {
byte[] data = toByteArray2(filePath);
fileName = URLEncoder.encode(fileName, "UTF-8");
response.reset();
response.setHeader("Content-Disposition", "attachment; filename=\""
+ fileName + "\"");
response.addHeader("Content-Length", "" + data.length);
response.setContentType("application/octet-stream;charset=UTF-8");
//缓冲输出流
OutputStream outputStream = new BufferedOutputStream(
response.getOutputStream());
//把数据写进去
outputStream.write(data);
//释放资源
outputStream.flush();
outputStream.close();
response.flushBuffer();
}

效果展示:

通过Workbook完成,按照公司名称分类Execl_数据_02

杂乱的单号通过公司名称,分类邮件。

通过Workbook完成,按照公司名称分类Execl_文件名_03

分类完成后点击下载排序好的分类

通过Workbook完成,按照公司名称分类Execl_文件名_04

分类完成