- 需要jar包:freemarker-2.3.19.jar
- 使用office 的word,另存xml格式,再修改后缀名为ftl,例如:scanResult.ftl
- 代码如下:
-
package com.sbr.sdsp.tj.action; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStreamWriter; import java.io.Writer; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.annotation.Resource; import javax.servlet.ServletOutputStream; import org.apache.log4j.Logger; import org.apache.struts2.convention.annotation.Action; import com.sbr.platform.exception.SBRBusinessException; import com.sbr.sdp.platform.common.action.BaseAction; import com.sbr.sdsp.tj.model.SdspTjPort; import com.sbr.sdsp.tj.model.SdspTjTask; import com.sbr.sdsp.tj.model.SdspTjVuln; import com.sbr.sdsp.tj.service.ISdspTjPortService; import com.sbr.sdsp.tj.service.ISdspTjTaskService; import com.sbr.sdsp.tj.service.ISdspTjVulnService; import com.sbr.sdsp.util.HtmlRegexpUtil; import com.sbr.smwp.export.action.ExportWordAction; import freemarker.template.Configuration; import freemarker.template.DefaultObjectWrapper; import freemarker.template.Template; @Action(value = "sdspTjExportWord") public class SdspTjExportWordAction extends BaseAction{ private static final long serialVersionUID = 1L; private static final Logger LOGGER = Logger.getLogger(SdspTjExportWordAction.class); @Resource private ISdspTjTaskService sdspTjTaskService; @Resource private ISdspTjVulnService sdspTjVulnService; @Resource private ISdspTjPortService sdspTjPortService; private SdspTjTask sdspTjTask = new SdspTjTask(); private String id; /** * * @brief 根据ftl文件创建word模板 * @return File * @author * @date 2016-7-27 * @copyright */ public static File createDoc(Map<?, ?> dataMap, String type) throws Exception { Configuration cfg = new Configuration(); cfg.setDefaultEncoding("utf-8"); cfg.setClassForTemplateLoading(ExportWordAction.class, "/"); cfg.setObjectWrapper(new DefaultObjectWrapper()); String name = "temp" + (int) (Math.random() * 100000) + ".doc"; File f = new File(name); Template t = cfg.getTemplate(type + ".ftl", "utf-8"); try { // 这个地方不能使用FileWriter因为需要指定编码类型否则生成的Word文档会因为有无法识别的编码而无法打开 Writer w = new OutputStreamWriter(new FileOutputStream(f), "utf-8"); t.process(dataMap, w); w.close(); } catch (Exception ex) { ex.printStackTrace(); throw new RuntimeException(ex); } return f; } /** * * @brief 导出任务扫描结果的word * @return void * @author * @date 2016-7-27 * @copyright */ public void ExportResults() { // 任务 sdspTjTask = sdspTjTaskService.retrieveSdspTjTaskById(id); // 任务扫描对应的漏洞列表 List<SdspTjVuln> vulns = sdspTjVulnService.retrieveSdspTjVulnsByTaskId(id); vulns = filterHtmlTag(vulns); // 任务扫描对应的端口列表 List<SdspTjPort> ports = sdspTjPortService.retrieveSdspTjPortsByTaskId(id); //查询scanner_service表获取端口类型和描述 ports = translateToScanPortList(ports); // 漏洞数 Map<String, Integer> vulnMap = sdspTjVulnService.countVulnByTaskId(id); // 端口数 int portCount = sdspTjPortService.countPortByTaskId(id); // 得到填充数据 Map<String, Object> dataMap = new HashMap<String, Object>(); // 封装word数据 packageData(dataMap, sdspTjTask.getTaskName(), sdspTjTask.getSysOrganization().getName(), sdspTjTask.getTargetIp(), vulns, ports, vulnMap, portCount); //导出word exportWord(dataMap); } /** * * @brief 封装导出word数据 * @return void * @author * @date 2016-7-28 * @copyright */ private void packageData(Map<String, Object> dataMap, String taskName, String orgName, String targetIP, List<SdspTjVuln> vulns, List<SdspTjPort> ports, Map<String, Integer> vulnMap, int portCount) { dataMap.put("taskName", taskName); dataMap.put("orgName", orgName); dataMap.put("targetIP", targetIP); dataMap.put("vulns", vulns); dataMap.put("ports", ports); dataMap.putAll(vulnMap); dataMap.put("portCount", portCount); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");// 设置日期格式 dataMap.put("createDate", sdf.format(new Date()).toString()); } /** * * @brief 导出word * @return void * @author * @date 2016-7-28 * @copyright */ private void exportWord(Map<String, Object> dataMap){ File file = null; InputStream fis = null; ServletOutputStream out = null; try { file = createDoc(dataMap, "scanResult"); fis = new FileInputStream(file); getResponse().setCharacterEncoding("utf-8"); getResponse().setContentType("application/msword"); // 设置浏览器下载附件名称 getResponse().addHeader("Content-Disposition","attachment;filename=" + new String((sdspTjTask.getTaskName()+"系统漏洞扫描结果").getBytes("gbk"),"ISO8859-1") + ".doc"); out = getResponse().getOutputStream(); byte[] buffer = new byte[1024]; int len = -1; while ((len = fis.read(buffer)) != -1) { out.write(buffer, 0, len); } out.flush(); } catch (Exception e) { LOGGER.error("扫描结果导出word失败!"); throw new SBRBusinessException("扫描结果导出word失败!原因是:"+e); } finally { try { if (fis != null){ fis.close(); } if (out != null) out.close(); if (file != null) file.delete(); // 删除临时文件 } catch (IOException e) { LOGGER.error("关闭文件流失败!"); throw new SBRBusinessException("关闭文件流失败!原因是:"+e); } } } /** * * @brief 过滤html标签 * @return void * @author * @date 2016-7-28 * @copyright */ private List<SdspTjVuln> filterHtmlTag(List<SdspTjVuln> vulns){ if(vulns == null || vulns.size() <= 0){ return new ArrayList<SdspTjVuln>(); } List<SdspTjVuln> list = new ArrayList<SdspTjVuln>(); for (SdspTjVuln vuln : vulns) { String remedy = HtmlRegexpUtil.filterHtml(vuln.getRemedy()); remedy = replaceTag(remedy); vuln.setRemedy(remedy); String desc = HtmlRegexpUtil.filterHtml(vuln.getDescription()); desc = replaceTag(desc); vuln.setDescription(desc); vuln.setRiskLevel(transRiskLevel(vuln.getVulnSeverity())); SdspTjVuln v = sdspTjVulnService.getscannerVuln(vuln.getId(), vuln.getVulnId()); vuln.setNodeName(v.getNodeName()); vuln.setShortDesc(v.getShortDesc()); list.add(vuln); } return list; } /** * * @brief 危险级别 * @return String * @author * @date 2016-7-28 * @copyright */ private String transRiskLevel(int riskLevel){ if(riskLevel == 3){ return"高危"; }else if(riskLevel == 2){ return"中危"; }else if(riskLevel == 1){ return"低危"; }else if(riskLevel == 4){ return"信息"; }else{ return"未知"; } } /** * * @brief 获取端口类型和描述 * @return List<SdspTjPort> 端口服务列表 * @author * @date 2016-8-1 * @copyright */ private List<SdspTjPort> translateToScanPortList(List<SdspTjPort> ports){ if(ports == null || ports.size() <= 0){ return new ArrayList<SdspTjPort>(); } List<SdspTjPort> list = new ArrayList<SdspTjPort>(); for (SdspTjPort port : ports) { SdspTjPort p = sdspTjPortService.getScanPortById(port.getId()); if(p != null){ list.add(p); } } return list; } /** * * @brief 过滤特殊符号 * @return String 过滤后的结果返回 * @param input 字符串 * @author * @date 2016-7-28 * @copyright */ public String replaceTag(String input) { if (!hasSpecialChars(input)) { return input; } StringBuffer filtered = new StringBuffer(input.length()); char c; for (int i = 0; i <= input.length() - 1; i++) { c = input.charAt(i); switch (c) { case '<': filtered.append("<"); break; case '>': filtered.append(">"); break; case '"': filtered.append("""); break; case '&': filtered.append("&"); break; default: filtered.append(c); } } return (filtered.toString()); } /** * * @brief 判断标记是否存在 * @return boolean * @param input 字符串 * @author * @date 2016-7-28 * @copyright */ public boolean hasSpecialChars(String input) { boolean flag = false; if ((input != null) && (input.length() > 0)) { char c; char c1; for (int i = 0; i <= input.length() - 2; i++) { c = input.charAt(i); c1 = input.charAt(i+1); String str = String.valueOf(c)+String.valueOf(c1); if(!"/".contains(str)){// /:/ 不参与过滤 switch (c) { case '>': flag = true; break; case '<': flag = true; break; case '"': flag = true; break; case '&': flag = true; break; } } } } return flag; } @Override public Object getModel() { return sdspTjTask; } public String getId() { return id; } public void setId(String id) { this.id = id; } }
word表格数据不支持html代码,需要过滤掉,导出的word才能正常打开
过滤类如下:
package com.sbr.sdsp.util;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Title: HTML相关的正则表达式工具类
* Description: 包括过滤HTML标记,转换HTML标记,替换特定HTML标记
*/
public class HtmlRegexpUtil {
private final static String regxpForHtml = "<([^>]*)>"; // 过滤所有以<开头以>结尾的标签
private final static String regxpForImgTag = "<\\s*img\\s+([^>]*)\\s*>"; // 找出IMG标签
private final static String regxpForImaTagSrcAttrib = "src=\"([^\"]+)\""; // 找出IMG标签的SRC属性
/**
*
*/
public HtmlRegexpUtil() {
}
/**
*
* 基本功能:替换标记以正常显示
* <p>
*
* @param input
* @return String
*/
public String replaceTag(String input) {
if (!hasSpecialChars(input)) {
return input;
}
StringBuffer filtered = new StringBuffer(input.length());
char c;
for (int i = 0; i <= input.length() - 1; i++) {
c = input.charAt(i);
switch (c) {
case '<':
filtered.append("<");
break;
case '>':
filtered.append(">");
break;
case '"':
filtered.append(""");
break;
case '&':
filtered.append("&");
break;
default:
filtered.append(c);
}
}
return (filtered.toString());
}
/**
*
* 基本功能:判断标记是否存在
* <p>
*
* @param input
* @return boolean
*/
public boolean hasSpecialChars(String input) {
boolean flag = false;
if ((input != null) && (input.length() > 0)) {
char c;
for (int i = 0; i <= input.length() - 1; i++) {
c = input.charAt(i);
switch (c) {
case '>':
flag = true;
break;
case '<':
flag = true;
break;
case '"':
flag = true;
break;
case '&':
flag = true;
break;
}
}
}
return flag;
}
/**
*
* 基本功能:过滤所有以"<"开头以">"结尾的标签
* <p>
*
* @param str
* @return String
*/
public static String filterHtml(String str) {
Pattern pattern = Pattern.compile(regxpForHtml);
Matcher matcher = pattern.matcher(str);
StringBuffer sb = new StringBuffer();
boolean result1 = matcher.find();
while (result1) {
matcher.appendReplacement(sb, "");
result1 = matcher.find();
}
matcher.appendTail(sb);
return sb.toString();
}
/**
*
* 基本功能:过滤指定标签
* <p>
*
* @param str
* @param tag
* 指定标签
* @return String
*/
public static String filterHtmlTag(String str, String tag) {
String regxp = "<\\s*" + tag + "\\s+([^>]*)\\s*>";
Pattern pattern = Pattern.compile(regxp);
Matcher matcher = pattern.matcher(str);
StringBuffer sb = new StringBuffer();
boolean result1 = matcher.find();
while (result1) {
matcher.appendReplacement(sb, "");
result1 = matcher.find();
}
matcher.appendTail(sb);
return sb.toString();
}
/**
*
* 基本功能:替换指定的标签
* <p>
*
* @param str
* @param beforeTag
* 要替换的标签
* @param tagAttrib
* 要替换的标签属性值
* @param startTag
* 新标签开始标记
* @param endTag
* 新标签结束标记
* @return String
* @如:替换img标签的src属性值为[img]属性值[/img]
*/
public static String replaceHtmlTag(String str, String beforeTag,
String tagAttrib, String startTag, String endTag) {
String regxpForTag = "<\\s*" + beforeTag + "\\s+([^>]*)\\s*>";
String regxpForTagAttrib = tagAttrib + "=\"([^\"]+)\"";
Pattern patternForTag = Pattern.compile(regxpForTag);
Pattern patternForAttrib = Pattern.compile(regxpForTagAttrib);
Matcher matcherForTag = patternForTag.matcher(str);
StringBuffer sb = new StringBuffer();
boolean result = matcherForTag.find();
while (result) {
StringBuffer sbreplace = new StringBuffer();
Matcher matcherForAttrib = patternForAttrib.matcher(matcherForTag.group(1));
if (matcherForAttrib.find()) {
matcherForAttrib.appendReplacement(sbreplace, startTag + matcherForAttrib.group(1) + endTag);
}
matcherForTag.appendReplacement(sb, sbreplace.toString());
result = matcherForTag.find();
}
matcherForTag.appendTail(sb);
return sb.toString();
}
}