前言
最近在做一个小项目,有个模块的功能涉及到excel的导入导出,并且要求对导出的excel文件部分列和单元格设置为只读不可更改,在网上到处查找了一番资料,结合自己的想法,发现也并不难,这里整理记录一下,给有相同想法和有这个需求的朋友们做个参考。
正文
java导出excel文件用的最多的就用poi的方式,这里也一样。POI 提供了对2003版本的Excel的支持 ---- HSSFWorkbook,可用于生成.xls。POI 提供了对2007版本以及更高版本的支持 ---- XSSFWorkbook ,可生成.xlsx后缀的excel文件。
导出的大致的思路,先从数据库查询出要导出的数据,这些数据可以放入一个List<bean>集合中,然后把数据按一定顺序写入excel的文件中,再对写入的数据到excel单元格进行样式设置,再以流的形式传给前端。大概流程就是上面描述的这样,细节还是在于对创建单元格写入数据后的格式进行设置为只读 (其目的就是为了规范化用户的操作,防止误改)。
我的处理方式是这样的:为方便和规范用户的使用,在项目里就先创建一个excel的模板,设置两行标题,第一行标题用中文,第二行标题用英文(设置英文的目的是可以用java反射来按字段的方式以便导入导出功能的编写),并将这两行标题设置为锁定,和保护,出这两行外的单元格不锁定,等在写入数据后再根据需要进行是否锁定,在获取数据库的数据后,先对模板文件进行复制,再把数据写入模板的复制文件中,最后再把复制文件以输出流的形式传给前端,再删除复制文件。excel模板文件的手动锁定保护在文章结尾给出。
1.先添加poi的依赖
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.1.2</version>
</dependency>
2.service层,调用自己写的ExcelUtil类的exportExcel静态方法
/**
* excel导出,导出当天最新的项目信息,这里提供给controller层调用
* @param request
* @param response
* @return
*/
@Override
@RequestMapping(method = RequestMethod.GET)
@ResponseBody
public String exportExcelMethod(HttpServletRequest request, HttpServletResponse response) {
//这里的List<bean>就是你的数据库取出对应的数据,这里有些不方便展示就以此代指了
List<Bean> ucmList = getBeanList();
try {
ExcelUtil.exportExcel(ucmList, response);
} catch (Exception e) {
e.printStackTrace();
}
return "导出成功!";
}
3.ExcelUtil类的exportExcel静态方法:功能先复制模板一份(不对模板进行操作),然后操作复制体的模板文件,对其进行数据写入,单元格的锁定和解锁设置,再通过流发送给前端,发送完后删除复制体模板文件。
public static void exportExcel(List<Bean> ucmBoList, HttpServletResponse response) {
String templatePath = System.getProperty("user.dir") + File.separator + "report/exceltemplate/";
String templateName = "template.xlsx";
String templatePathAndName = templatePath + templateName;
File templateFile = new File(templatePathAndName);
File copyFile = null;
if (templateFile != null && templateFile.exists()) {
copyFile = copyExcelTemplateByXSSF(templatePath, templateName);
} else {
return;
}
if (copyFile != null && copyFile.exists()) {
//创建一个工作簿
XSSFWorkbook xssfWorkbook = null;
//创建工作表
XSSFSheet xssfSheet = null;
XSSFCellStyle lockCellStyle = null;
XSSFCellStyle unLockCellStyle = null;
try {
xssfWorkbook = new XSSFWorkbook(copyFile);
// xssfSheet = xssfWorkbook.createSheet();
//这里是用自己已创建好的模板,所以就是getSheet(index)
xssfSheet = xssfWorkbook.getSheetAt(0);
//创建单元格
XSSFCell xssfCell;
//创建单元格样式,这里设置是否锁定
lockCellStyle = xssfWorkbook.createCellStyle();
lockCellStyle.setLocked(true);
//创建单元格样式,这里设置不锁定
unLockCellStyle = xssfWorkbook.createCellStyle();
unLockCellStyle.setLocked(false);
if (ucmBoList != null && ucmBoList.size() > 0) {
for (int i = 0; i < ucmBoList.size(); i++) {
UcmBean ucm = ucmBoList.get(i);
//细节,前两行为标题
XSSFRow xssfRow = xssfSheet.createRow(i + 2);
//录入日期
XSSFCell cell0 = xssfRow.createCell(0);
cell0.setCellValue(ucm.getOcDate());
//业务部门
XSSFCell cell1 = xssfRow.createCell(1);
cell1.setCellValue(ucm.getBusinessUnit());
//项目类别编号
XSSFCell cell2 = xssfRow.createCell(2);
cell2.setCellValue(ucm.getProjectTypeCode());
//项目类别名称
XSSFCell cell3 = xssfRow.createCell(3);
cell3.setCellValue(ucm.getProjectTypeName());
//项目编号
XSSFCell cell4 = xssfRow.createCell(4);
cell4.setCellValue(ucm.getProjectNo());
//项目名称
XSSFCell cell5 = xssfRow.createCell(5);
cell5.setCellValue(ucm.getProjectName());
//项目评级
XSSFCell cell6 = xssfRow.createCell(6);
cell6.setCellValue(ucm.getProjectRating());
//融资主体
List<FinancierBO> financierBOList = ucm.getFinancierInfo();
String finName = "", finCode = "", finRating = "";
if (financierBOList != null && financierBOList.size() > 0) {
for (FinancierBO financierBO : financierBOList) {
if (financierBO != null) {
if (financierBO.getName() != null) {
finName = finName + financierBO.getName() + "\n";
} else {
finName = finName + "" + "\n";
}
if (financierBO.getUniformCreditCode() != null) {
finCode = finCode + financierBO.getUniformCreditCode() + "\n";
} else {
finCode = finCode + "" + "\n";
}
if (financierBO.getRating() != null) {
finRating = finRating + financierBO.getRating() + "\n";
} else {
finRating = finRating + "" + "\n";
}
}
}
}
}
//是否体系内业务
XSSFCell cell7 = xssfRow.createCell(7);
cell7.setCellStyle(unLockCellStyle);
if (ucm.getSystemBusinessFlag() != null) {
if (ucm.getSystemBusinessFlag()) {
cell7.setCellValue("是");
} else {
cell7.setCellValue("否");
}
} else {
cell7.setCellValue("");
}
//行业分类
XSSFCell cell8 = xssfRow.createCell(8);
cell8.setCellStyle(unLockCellStyle);
cell8.setCellValue(ucm.getIndtNum());
//担保机构评级
XSSFCell cell9 = xssfRow.createCell(9);
cell9.setCellStyle(unLockCellStyle);
cell9.setCellValue(ucm.getGuarantorInstitutionRating());
setResponseHeader(response, copyFile.getName());
//锁定不锁定只有加了这个才有用(默认都是锁定后就不可以对单元格内容进行更改)
xssfSheet.protectSheet("123*456");
OutputStream out = response.getOutputStream();
xssfWorkbook.write(out);
out.flush();
out.close();
} catch (IOException e) {
e.printStackTrace();
} catch (InvalidFormatException e) {
e.printStackTrace();
} finally {
if (copyFile.exists()) {
copyFile.delete();
}
System.out.println("成功之后需要,删除复制的模板源文件,以免占用服务器的内存!");
}
} else {
return;
}
}
4. ExcelUtil类的copyExcelTemplateByXSS静态方法,复制模板文件,并以日期的形式作为文件名
/**
* 复制excel的模板
*
* @param excelFilePath 模板路径
* @param fileName 模板名称
* @return 复制后的模板副本文件,或null
*/
public static File copyExcelTemplateByXSSF(String excelFilePath, String fileName) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
String now = dateFormat.format(new Date());
String templateFilePathAndName = excelFilePath + fileName;
String copyFilePathAndName = excelFilePath + "/XXX模板" + now + ".xlsx";
File templateFile = new File(templateFilePathAndName);
File copyFile = null;
XSSFWorkbook xssfWorkbook = null;
if (templateFile.exists()) {
copyFile = new File(copyFilePathAndName);
try {
xssfWorkbook = new XSSFWorkbook(templateFile);
} catch (InvalidFormatException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
} else {
return copyFile;
}
try {
OutputStream out = new FileOutputStream(copyFile);
xssfWorkbook.write(out);
out.flush();
out.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
//file.delete();
}
return copyFile;
}
5. ExcelUtil类的setResponseHeader方法,用来设置respond的响应体形象,包括编码格式和以附件的形式进行下载
// 发送响应流方法
public static void setResponseHeader(HttpServletResponse response, String fileName) {
try {
try {
fileName = new String(fileName.getBytes("gbk"), "ISO8859-1");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
//response.setCharacterEncoding("utf-8");
response.reset();// 清空输出流
//告诉浏览器这个文件的名字和类型,attachment:作为附件下载;inline:直接打开
response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
// response.setContentType("application/vnd.ms-excel");如果设置为这种就是生成.xls文件
response.setContentType("application/msexcel");
response.addHeader("Pargam", "no-cache");
response.addHeader("Cache-Control", "no-cache");
response.setCharacterEncoding("ISO8859-1");
} catch (Exception ex) {
ex.printStackTrace();
}
}
6.control层调用service层
@Controller("/file")
public class ExcelController {
@Autowired
UcmService ucmService;
@RequestMapping("/downLoad")
//@ResponseBody
public void excletest(HttpServletRequest request, HttpServletResponse response){
ucmService.exportExcelMethod(request, response);
}
以上就是整个处理过程的的大致代码。下面给出excel模板的标题设置为不可修改。选中标题行右键单元格设置-->保护->锁定
-->确定
再到审阅,点击保护工作表-->购上下面的钩子,输入密码,再次确认密码即可。然后你想修改就必须输入密码才能更改了。