/* * Power by www.xiaoi.com */ package com.eastrobot.doc.web; import com.eastrobot.doc.config.BaseController; import com.eastrobot.doc.config.SystemConstants; import com.eastrobot.doc.config.WebappContext; import com.eastrobot.doc.util.HtmlUtils; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiImplicitParams; import io.swagger.annotations.ApiOperation; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.util.Calendar; import javax.servlet.http.HttpServletRequest; import org.apache.commons.io.FileUtils; import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.IOUtils; import org.artofsolving.jodconverter.OfficeDocumentConverter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.util.FileCopyUtils; import org.springframework.util.ResourceUtils; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; /** * @author <a href="mailto:[email protected]">eko.zhan</a> * @date 2017年7月29日 上午9:44:36 * @version 1.0 */ @Api @RequestMapping("index") @RestController public class IndexController extends BaseController { private final static Logger logger = LoggerFactory.getLogger(IndexController.class); private final String outputExtension = "html"; /** * 文件列表 * @author eko.zhan at 2017年8月9日 下午8:32:19 * @return * @throws FileNotFoundException */ @ApiOperation(value="获取文件数据列表", notes="获取固定路径下的文件,并返回文件名,文件所在路径和文件大小") @RequestMapping(value="getDataList", method=RequestMethod.POST) public JSONArray getDataList() throws FileNotFoundException{ JSONArray arr = new JSONArray(); File dir = ResourceUtils.getFile("classpath:static/DATAS"); File[] files = dir.listFiles(); for (File file : files){ if (file.isFile()){ JSONObject json = new JSONObject(); json.put("path", file.getPath()); json.put("name", file.getName()); json.put("size", file.length()); arr.add(json); } } return arr; } /** * 加载文件 * @author eko.zhan at 2017年8月9日 下午8:32:30 * @param name * @param request * @return * @throws FileNotFoundException * @throws IOException */ @ApiOperation(value="根据指定的文件名称获取文件内容", notes="返回文件内容会自动过滤图片信息") @ApiImplicitParams({ @ApiImplicitParam(name="name", value="文件相对路径", required=true, dataType="String") }) @RequestMapping(value="loadFileData", produces="text/plain;charset=utf-8", method=RequestMethod.POST) public String loadFileData(String name, HttpServletRequest request) throws FileNotFoundException, IOException{ File file = ResourceUtils.getFile("classpath:static/DATAS/" + name); String basename = FilenameUtils.getBaseName(file.getName()); File targetFile = new File(file.getParent() + "/" + basename + "/" + basename + "." + outputExtension); if (targetFile.exists()){ //logger.debug(HtmlUtils.getFileEncoding(targetFile)); String data = IOUtils.toString(new FileInputStream(targetFile), HtmlUtils.getFileEncoding(targetFile)); //logger.debug(data); //获取文件头部,每个文件转换出的html头部样式都不一样,动态获取 //截图 <BODY 之前的所有代码 String header = HtmlUtils.HEAD_TEMPLATE; try{ header = data.substring(0, data.toLowerCase().indexOf("<body")); String tmp = data.substring(data.toLowerCase().indexOf("<body")); header += tmp.substring(0, tmp.indexOf(">") + 1); header = HtmlUtils.replaceCharset(header); }catch(StringIndexOutOfBoundsException e){ e.printStackTrace(); logger.error("html页面数据解析异常"); } request.getSession().setAttribute(SystemConstants.HTML_HEADER, header); //TODO 如果是网络图片,如何处理? //TODO 保存后再次打开html文档,如何处理? //data = HtmlUtils.replaceHtmlTag(data, "img", "src", "src=\"" + request.getContextPath() + "/index/loadFileImg?name=" + name + "&imgname=", "\""); return data; } return ""; } /** * 加载 html 中的图片资源 * @author eko.zhan at 2017年8月9日 下午8:32:06 * @param name * @param imgname * @return * @throws IOException */ @ApiOperation(value="加载图片内容", notes="获取word文档中内嵌的图片资源,返回图片内容") @ApiImplicitParams({ @ApiImplicitParam(name="name", value="文件相对路径", required=true, dataType="String"), @ApiImplicitParam(name="imgname", value="图片名称", required=true, dataType="String") }) @RequestMapping(value="loadFileImg", method=RequestMethod.GET) public ResponseEntity<byte[]> loadFileImg(String name, String imgname){ try { String basename = FilenameUtils.getBaseName(name); File file = ResourceUtils.getFile("classpath:static/DATAS/" + basename + "/" + imgname); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.IMAGE_PNG); return new ResponseEntity<byte[]>(IOUtils.toByteArray(new FileInputStream(file)), headers, HttpStatus.OK); } catch (FileNotFoundException e) { logger.error("文件[" + name + "]不存在, " + e.getMessage()); } catch (IOException e) { logger.error(e.getMessage()); e.printStackTrace(); } return null; } /** * 上传文件 * @author eko.zhan at 2017年8月9日 下午8:32:39 * @param uploadFile * @param request * @return */ @ApiOperation(value="上传文件", notes="") @ApiImplicitParams({ @ApiImplicitParam(name="uploadFile", value="待上传的文件", required=true, dataType="__file") }) @RequestMapping(value="uploadData", method=RequestMethod.POST) public JSONObject uploadData(@RequestParam("uploadFile") MultipartFile uploadFile, HttpServletRequest request){ JSONObject json = new JSONObject(); json.put("result", 1); WebappContext webappContext = WebappContext.get(request.getServletContext()); OfficeDocumentConverter converter = webappContext.getDocumentConverter(); try { File targetDir = ResourceUtils.getFile("classpath:static/DATAS/"); String inputExtension = FilenameUtils.getExtension(uploadFile.getOriginalFilename()); String inputFilename = String.valueOf(Calendar.getInstance().getTimeInMillis()); File file = new File(targetDir.getAbsolutePath() + "/" + inputFilename + "." + inputExtension); FileCopyUtils.copy(uploadFile.getBytes(), file); File outputFile = new File(targetDir.getAbsolutePath() + "/" + inputFilename + "/" + inputFilename + "." + outputExtension); try { long startTime = System.currentTimeMillis(); converter.convert(file, outputFile); long conversionTime = System.currentTimeMillis() - startTime; logger.info(String.format("successful conversion: %s [%db] to %s in %dms", inputExtension, file.length(), outputExtension, conversionTime)); } catch (Exception e) { logger.error(String.format("failed conversion: %s [%db] to %s; %s; input file: %s", inputExtension, file.length(), outputExtension, e, file.getName())); } } catch (FileNotFoundException e) { e.printStackTrace(); json.put("result", 0); } catch (IOException e) { e.printStackTrace(); json.put("result", 0); } return json; } /** * 保存html内容 * @author eko.zhan at 2017年8月9日 下午9:04:20 * @param name * @param data * @throws IOException */ @ApiOperation(value="保存文件", notes="") @ApiImplicitParams({ @ApiImplicitParam(name="name", value="文件相对路径", required=true, dataType="String"), @ApiImplicitParam(name="data", value="文件内容", required=true, dataType="String") }) @RequestMapping(value="saveFileData", method=RequestMethod.POST) public JSONObject saveFileData(String name, String data, HttpServletRequest request){ //TODO 这是一个伪保存,只是修改了 HTML 内容,并未修改 file 文件,如果用户单击下载,依然会存在问题 //TODO 如果用户修改了图片,如何处理? JSONObject json = new JSONObject(); json.put("result", 1); try { //DONE 优化底层 DefaultDocumentFormatRegistry.java 后可实现html转docx //boolean is07Xml = false; //是否是07以后的文档(docx/xlsx/pptx/),如果是,需要将html转成97版本的office文件,再从97转成07,直接将html转成07存在问题 File file = ResourceUtils.getFile("classpath:static/DATAS/" + name); File newFile = new File(file.getParent() + "/" + Calendar.getInstance().getTimeInMillis() + "_" + name); if (!name.toLowerCase().endsWith("x")){ newFile = new File(file.getParent() + "/" + Calendar.getInstance().getTimeInMillis() + "_" + name + "x"); } String basename = FilenameUtils.getBaseName(file.getName()); File targetFile = new File(file.getParent() + "/" + basename + "/" + basename + "." + outputExtension); if (targetFile.exists()){ //将html中的body内容替换为当前 data 数据 //String htmlData = IOUtils.toString(new FileInputStream(targetFile), HtmlUtils.getFileEncoding(targetFile)); String htmlData = (String)request.getSession().getAttribute(SystemConstants.HTML_HEADER) + data + HtmlUtils.FOOT_TEMPLATE; //DONE 如何处理文件编码?保存后尽管通过请求能访问中文内容,但是直接磁盘双击html文件显示乱码 //add by eko.zhan at 2017-08-11 14:55 解决方案:重写Html头,编码修改为 utf-8 //IOUtils.write(htmlData.getBytes(HtmlUtils.UTF8), new FileOutputStream(targetFile)); IOUtils.write(htmlData.getBytes(), new FileOutputStream(targetFile)); //DONE 由于html文件编码不正确,导致转换成word后文件编码也不正确 //add by eko.zhan at 2017-08-11 15:05 上面处理了html编码后,转换的编码问题也相应解决了 //TODO 由html转换成doc会导致doc样式有误 convert(targetFile, newFile); } } catch (FileNotFoundException e) { json.put("result", 0); e.printStackTrace(); } catch (IOException e) { json.put("result", 0); e.printStackTrace(); } return json; } /** * 删除文件 * @author eko.zhan at 2017年8月9日 下午9:32:18 * @param name * @return */ @ApiOperation(value="删除文件", notes="") @ApiImplicitParams({ @ApiImplicitParam(name="name", value="文件相对路径", required=true, dataType="String") }) @RequestMapping(value="delete", method=RequestMethod.POST) public JSONObject delete(String name){ //TODO windows操作系统上如果html文件被占用则无法删除,是否可以用 File.creteTempFile 来解决? JSONObject json = new JSONObject(); json.put("result", 1); try { File file = ResourceUtils.getFile("classpath:static/DATAS/" + name); String basename = FilenameUtils.getBaseName(file.getName()); File targetDir = new File(file.getParent() + "/" + basename); if (targetDir.exists()){ FileUtils.deleteDirectory(targetDir); } FileUtils.forceDelete(file); } catch (FileNotFoundException e) { json.put("result", 0); json.put("msg", e.getMessage()); e.printStackTrace(); } catch (IOException e) { json.put("result", 0); json.put("msg", e.getMessage()); e.printStackTrace(); } return json; } }