ドキュメントのオンラインプレビューソリューション-openoffice変換


ドキュメントのオンラインプレビューは複雑な機能であり、officeはオンラインプレビュー機能を提供していますが、ドキュメントフォーマットの複雑さはさらに難しくなります.https://products.office.com/en-us/office-online/view-office-documents-online)しかし、まだ制限が多いような気がします.
筆者が現在研究している方案はopenofficeを利用してpdfのオンラインプレビューに変換することであり、現在多くのブラウザはpdfのオンラインプレビューをサポートしているが、現在携帯電話端末のブラウザはまだサポートできず、2つの方案がある:1、pdf.js 2、pdfを画像プレビューに変換します.
まず、インタフェース定義
public interface ResourceConverter {

    /**
     *  
     */
    String CONF_KEY_TEMP_DIR = "temp.dir";
    String CONF_KEY_MAX_PAGE_SIZE = "maxPageSize";

    /**
     *  
     *
     * @param resourceUri
     * @return
     */
    boolean support(String resourceUri);

    /**
     * @param resourceUri
     * @param config
     * @return
     */
    State trans(String resourceUri, Map config);

    /**
     *  , 
     *
     * @param tempImg
     * @param index
     * @return  URI,  null
     */
    String save(File tempImg, int index);

}

目的が明確であるため、インタフェースの定義も簡単であり、コアメソッドはtransであり、所与のリソースを変換して結果を与え、個性化設定(例えば、一時ファイルストレージパス、解像度など)に対してconfigを通じて伝達する.supportメソッドは,インタフェース実装が所与のリソース変換をサポートするかどうかを判断し,コンテキスト切替アルゴリズムを容易にするためにポリシーモードを参照するように定義する.出力結果を統一するために,筆者はStateを定義した.
public class State {
    private boolean state = false;
    private String info = null;
    private Map infoMap = new HashMap();

    State(boolean state, String info) {
        this.state = state;
        this.info = info;
    }

    public static State errorResource(String info) {
        return new State(false, StringUtils.defaultString(info, " "));
    }

    public static State pageSizeLimit() {
        return new State(false, " , 200 ");
    }

   //  getter,setter
}

State定義も簡単で、bool値は変換状態が成功または失敗したことを示し、infoは簡略情報を提供し、infoMapは最終変換後の有効情報を格納する.同時に,状態を返すのに便利な2つの一般的な意味化抽象ファクトリ法も提供した.
慣例に従って、インタフェースの実現はスケルトンの実現を与える(利点:1、インタフェースの実現の汎用機能を確定して、個性化の実現呼び出しを便利にして、2、拡張しやすくて、いったんインタフェースの新しい方法、スケルトンの実現はデフォルトの実現を与えることができて、以前定義した実現クラスは更新する必要はありません)
public abstract class AbstractResourcesConverter implements ResourceConverter {

    private static QiniuUtil qiniuUtil = QiniuUtil.getInstance(QiniuUtil.Namespace.ADMIN);

    public abstract State doTransHttpResource(InputStream inputStream, URL url, Map config);

    public abstract State doTransFileResource(File file, String filePath, Map config);

    public abstract String getTempDir(Map config);


    @Override
    public State trans(String resourceUri, Map config) {
        if (StringUtils.isBlank(resourceUri)) {
            return State.errorResource(null);
        }
        if (resourceUri.startsWith("http")) {
            try {
                URL url = new URL(resourceUri);
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                // 10S
                conn.setConnectTimeout(10000);
                return doTransHttpResource(conn.getInputStream(), url, config);
            } catch (Exception e) {
                e.printStackTrace();
                return State.errorResource(e.getMessage());
            }
        } else {
            File file = new File(resourceUri);
            if (!file.exists()) {
                return State.errorResource(null);
            }
            return doTransFileResource(file, resourceUri, config);
        }
    }

    protected int getMaxPageSize(Map config) {
        Object dpi = config.get(CONF_KEY_MAX_PAGE_SIZE);
        if (dpi == null) {
            return 200;
        }
        return (int) dpi;
    }

    protected void makeTempDir(Map config) {
        String imgFilePathPrefix = getTempDir(config);
        File dir = new File(imgFilePathPrefix);
        if (!dir.exists()) {
            dir.mkdirs();
        }
    }

    @Override
    public String save(File tempImg, int index) {
        String key = qiniuUtil.upload(tempImg);
        tempImg.delete();
        return key == null ? key : key;
    }
}

筆者が提示したスケルトンの実現には、3つの説明が必要である:1.httpリソースとローカルファイルリソースを分化し、エラーリソースのフィードバックを事前に処理しました.2.テンポラリファイル作成ディレクトリコードを汎用処理した.一時的なリソースのストレージもデフォルトで実現され、正式な環境では、一般的にリソースをサーバにストレージします.筆者はここで変換リソースを七牛雲にストレージします.
各種リソースの変換実装
Openofficeを使用してドキュメントタイプをpdfに変換
public class Doc2PdfConverter extends AbstractResourcesConverter {
    private static final Logger logger = LoggerFactory.getLogger(Doc2PdfConvert.class);
    public static final String CONF_KEY_OPEN_OFFICE_HOST = "openoffice.host";
    public static final String CONF_KEY_OPEN_OFFICE_PORT = "openoffice.port";
    public static final String SUPPORT_TYPE_PATTERN = ".*(.doc|.docx|.ppt|.pptx|.xls|.xlsx)$";
    public static final String RESULT_INFO_KEY_PDF = "pdf";

    @Override
    public boolean support(String resourceUri) {
        return Pattern.matches(SUPPORT_TYPE_PATTERN, resourceUri);
    }

    @Override
    public State doTransHttpResource(InputStream inputStream, URL url, Map config) {
        try {
            return doTrans(inputStream, buildFormat(url.toString()), config);
        } catch (Exception e) {
            return State.errorResource(null);
        }
    }

    @Override
    public State doTransFileResource(File file, String filePath, Map config) {
        try {
            return doTrans(new FileInputStream(file), buildFormat(filePath), config);
        } catch (Exception e) {
            return State.errorResource(null);
        }
    }

    private State doTrans(InputStream inputStream, DocumentFormat sourceType, Map config) {
        State state = new State(true, "");
        int openofficePort = getOpenofficePort(config);
        String openofficeHost = getOpenofficeHost(config);
        String pdfOutputFile = getTempDir(config) + System.currentTimeMillis() + ".pdf";
        OpenOfficeConnection connection = new SocketOpenOfficeConnection(openofficeHost, openofficePort);
        OutputStream dist = null;
        try {
            makeTempDir(config);
            connection.connect();
            dist = new FileOutputStream(pdfOutputFile);
            DocumentConverter converter = new OpenOfficeDocumentConverter(connection);
            converter.convert(inputStream, sourceType, dist, buildFormat(pdfOutputFile));
            state.putInfo(RESULT_INFO_KEY_PDF, pdfOutputFile);
        } catch (Exception e) {
            logger.error("open office converting ERROR, maybe it's not running with port" + openofficePort, e);
            //  
            new File(pdfOutputFile).deleteOnExit();
            return State.errorResource("open office converting occur an ERROR");
        } finally {
            connection.disconnect();
            IOUtils.closeQuietly(inputStream);
            IOUtils.closeQuietly(dist);
        }
        return state;
    }

    private DocumentFormat buildFormat(String filePath) {
        String extension = FilenameUtils.getExtension(filePath);
        DefaultDocumentFormatRegistry defaultDocumentFormatRegistry = new DefaultDocumentFormatRegistry();
        DocumentFormat format = defaultDocumentFormatRegistry.getFormatByFileExtension(extension);
        return format;
    }

    private int getOpenofficePort(Map config) {
        Object port = config.get(CONF_KEY_OPEN_OFFICE_PORT);
        if (port == null) {
            return 8100;
        }
        return (int) port;
    }

    private String getOpenofficeHost(Map config) {
        Object host = config.get(CONF_KEY_OPEN_OFFICE_HOST);
        if (host == null) {
            return "localhost";
        }
        return (String) host;
    }

    @Override
    public String getTempDir(Map config) {
        return config.get(CONF_KEY_TEMP_DIR) + "/doc/";
    }

}

ここでの具体的な実現は何も言うことはありません.openofficeが提供するjar(jodconverter-2.2.2.jar)を使えばいいです.jarパッケージバージョン2.2.2はdocx、pptxをサポートしていますが、maven中央倉庫にはこのバージョンがありません.筆者の解決策は公式サイトからjarパッケージをダウンロードしてmaven私服にアップロードすることです.このjarパッケージには他にも依存が多いので、pomファイルをアップロードする必要があります.
pdf回転画像
public class Pdf2ImgConverter extends AbstractResourcesConverter {
    public static final String CONF_KEY_DPI = "pdf.dpi";
    public static final String RESULT_INFO_KEY_DIST = "dist";

    @Override
    public State doTransHttpResource(InputStream inputStream, URL url, Map config) {
        try {
            PDDocument document = PDDocument.load(inputStream);
            PDFRenderer renderer = new PDFRenderer(document);
            PdfReader pdfReader = new PdfReader(url);
            return doTrans(renderer, pdfReader, config);
        } catch (Exception e) {
            return State.errorResource(null);
        }
    }

    @Override
    public State doTransFileResource(File file, String filePath, Map config) {
        try {
            PDDocument document = PDDocument.load(file);
            PDFRenderer renderer = new PDFRenderer(document);
            PdfReader pdfReader = new PdfReader(filePath);
            return doTrans(renderer, pdfReader, config);
        } catch (Exception e) {
            return State.errorResource(null);
        }
    }

    @Override
    public String getTempDir(Map config) {
        return config.get(CONF_KEY_TEMP_DIR) + "/pdf/";
    }

    protected State doTrans(PDFRenderer renderer, PdfReader pdfReader, Map config) {
        State state = new State(true, "");
        try {
            int pageCount = pdfReader.getNumberOfPages();
            int maxPageSize = getMaxPageSize(config);
            if (pageCount > maxPageSize) {
                return State.pageSizeLimit();
            }
            makeTempDir(config);
            List distFiles = new ArrayList<>();
            for (int i = 0; i < pageCount; i++) {
                BufferedImage image = renderer.renderImageWithDPI(i, getDPIFromConfig(config));
                File distFile = new File(getTempDir(config) + System.currentTimeMillis() + ".png");
                ImageIO.write(image, "png", distFile);
                distFiles.add(save(distFile, i));
            }
            state.putInfo(RESULT_INFO_KEY_DIST, StringUtils.join(distFiles, ","));
        } catch (Exception e) {
            return new State(false, " ");
        }
        return state;
    }

    protected float getDPIFromConfig(Map config) {
        Object dpi = config.get(CONF_KEY_DPI);
        if (dpi == null) {
            return 100F;
        }
        return (float) dpi;
    }


    @Override
    public boolean support(String resourceUri) {
        return StringUtils.endsWith(resourceUri, ".pdf");
    }

}

実際に変換するにはLinuxにopenofficeをインストールする必要があります
インストールパッケージのダウンロード
tar -zxvf Apache_OpenOffice_4.x.x _Linux_x86-64_install-rpm_zh-CN.tar.gz
解凍後、現在のディレクトリにzh-CNフォルダが生成され、zh-CN内のRPMSに入ります.
cd ./zh-CN/RPMS
yum localinstall *.rpm
成功すると、現在のディレクトリにdesktop-integrationフォルダが生成され、このフォルダに入ります.
cd ./desktop-integration
yum localinstall openoffice_4.x.x-redhat-menus-x.x.x.noarch.rpm
インストールに成功すると、/optディレクトリの下にoppenoffice 4フォルダが生成されます
開始
nohup /opt/openoffice4/program/soffice -headless -accept="socket,host=127.0.0.1,port=8100;urp;" -nofirststartwizard &

発生する可能性のある問題
 error while loading shared libraries: libXext.so.6

  :
  yum install libXext.x86_64

  no suitable windowing system found, exiting

   :
  yum groupinstall "X Window System" 

サービスが正常に開始されたかどうかを確認
ps -ef | grep openoffice
netstat -lntp | grep 8100
環境の準備が完了した後に必要な問題は中国語の文字化けして、これはLinuxがwinの上のフォントファイルがないため、フォントファイルをインストールする必要があります、インストールが完了した後にopenofficeを再起動する必要があります、openofficeは1つのクライアントjarを提供して、このjarパケットを借りて変換が完璧かどうかをテストすることができます
java -jar jodconverter-cli-2.2.2.jar source.doc tagert.pdf