基于JAVAEE的B/S架構(gòu)由于java語言的跨平臺(tái)性
所以操控Window客戶端資源能力有限, 目前比較流行是用其他語言如Delphi,VB,C++開發(fā)客戶端控件 然后再html中用js調(diào)用。 但對(duì)于java開發(fā)者而言,這種方式比較不方便,尤其在分工合作 而對(duì)方開發(fā)水平也有限的情況下,調(diào)試比較繁瑣。 統(tǒng)觀現(xiàn)在的在線掃描控件,大部分都是收費(fèi)的,無論國(guó)內(nèi)還是國(guó)外。 收費(fèi),代碼不可見應(yīng)該是JAVA程序員比較反感的吧,總感覺受制于人,至少我是這樣的啊。 Applet現(xiàn)在雖然不流行被ActiveX所替代,但對(duì)java程序員開發(fā)B/S架構(gòu) 需要操縱客戶端資源,還是比較可行的。 尤其是在HtmlConvert的出現(xiàn)后,其編程方式可以把Applet標(biāo)簽轉(zhuǎn)換成 object標(biāo)簽。 雖說需要客戶端下載并安裝JRE,下載速度比較慢,但由于是在企業(yè)級(jí)應(yīng)用的局域網(wǎng)的 環(huán)境下,這些并不是最大的缺點(diǎn)。(現(xiàn)在jre可以通過cab包的形式在客戶端自動(dòng)下載及安裝jre,通過改變url讓此cab在局域網(wǎng)內(nèi)下載 html中如下:<object classid = "clsid:8AD9C840-044E-11D1-B3E9-00805F499D93" codebase = "http://localhost:8090/emr-archive-app/arc/cabs/jinstall-1_5-windows-i586.cab#Version=5,0,0,5" WIDTH = "240" VSPACE = "20" ALT = "Sorry" > <PARAM NAME = CODE VALUE = "com.founder.applet.scan.ScannerApplet.class" > <PARAM NAME = ARCHIVE VALUE = "scanner.jar" > <param name = "type" value = "application/x-java-applet;version=1.5"> <param name = "scriptable" value = "false"> </object>) 目前所做的項(xiàng)目是基于JAVA EE的應(yīng)用,需要在客戶端進(jìn)行文檔掃描并提交到客戶端 進(jìn)行進(jìn)一步處理,如進(jìn)行OCR文字識(shí)別,建立基于內(nèi)容檢索的索引創(chuàng)建等應(yīng)用。 目前能用的反應(yīng)普遍比較好的是ScanOnWeb控件,做到確實(shí)比較好,好處就不再細(xì)說。, 但我試用完后發(fā)現(xiàn)的缺點(diǎn)如下: 1.收費(fèi),雖說不貴,但對(duì)比較大的管理規(guī)范的公司,由于售后服務(wù)產(chǎn)品保障方面,購買審批難。 2.通用性并不好,同樣是遵循Twain協(xié)議的掃描儀器,有的掃描儀并不能很好的識(shí)別 我用的攝像頭,帶獨(dú)立電源的Microtek,和USB供電的Canon進(jìn)行測(cè)試 其中的最新的Canon他無法識(shí)別,需要先進(jìn)入控件的界面然后再插上掃描儀,如果一直 連著掃描儀,將報(bào)錯(cuò)。 3.掃描的文件太大了,普通的一頁紙張可以達(dá)到2M。 由于目前的掃描儀或者攝像頭都支持Twain協(xié)議,同時(shí)也有一個(gè)開源的mmsc_tawin工java開發(fā)者使用 所以開發(fā)基于Applet的掃描儀控件是可行的。 開發(fā)步驟如下: 1.基于mmsc_twain開發(fā)掃描Applet 2.把mmsc_twain的jar包及相關(guān)依賴的jar包中class按 包的結(jié)構(gòu)解壓到一個(gè)目錄下。 3.把這些class打包成一個(gè)jar包 3.對(duì)這個(gè)jar包進(jìn)行數(shù)字簽名 4.通過html_conv把html中的applet標(biāo)簽,轉(zhuǎn)換成object 通過以上步驟即可完成在線掃描的控件。 下面代碼是通過applet及servlet把掃描的文件 轉(zhuǎn)成PDF格式然后上傳到web服務(wù)器,進(jìn)行進(jìn)一步的文字識(shí)別 及基于內(nèi)容檢索。 經(jīng)過測(cè)試,基于applet的在線掃描的優(yōu)點(diǎn)是硬件識(shí)別率高,掃描的文件小,速度快,秉承b/s架構(gòu)易于維護(hù)特性,對(duì)java開著者而言最重要的是靈活, 可以自由控制。 缺點(diǎn)也比較明顯就是對(duì)掃描的文件不能像scanOnWeb那樣進(jìn)行圖像的進(jìn)一步處理。但對(duì)于只是簡(jiǎn)單的紙質(zhì)文檔掃描的應(yīng)用來說這并不是應(yīng)用的重點(diǎn)。 如果有需要比較完整的代碼的可以繼續(xù)交流。 ====================================================================== 代碼參考如下: (htmlConvert,及jar包的數(shù)字簽名,mmsc_twain的源碼網(wǎng)上都可以找到) 測(cè)試代碼如下: import java.applet.Applet; import java.awt.Button; import java.awt.Graphics; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.image.BufferedImage; import java.awt.print.PrinterException; import java.io.BufferedWriter; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLConnection; import javax.imageio.ImageIO; import org.apache.pdfbox.pdmodel.PDDocument; import com.lowagie.text.Document; import com.lowagie.text.Font; import com.lowagie.text.Image; import com.lowagie.text.Paragraph; import com.lowagie.text.pdf.PdfWriter; import uk.co.mmscomputing.device.scanner.Scanner; import uk.co.mmscomputing.device.scanner.ScannerDevice; import uk.co.mmscomputing.device.scanner.ScannerIOException; import uk.co.mmscomputing.device.scanner.ScannerIOMetadata; import uk.co.mmscomputing.device.scanner.ScannerListener; public class ScannerApplet extends Applet { Scanner scanner = Scanner.getDevice(); public void init() { Button btn = new Button(); btn.setLabel("掃描"); btn.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { System.out.println(event.getActionCommand() + "||" + event.getSource() + "MouseClick"); try { scan(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }); add(btn); } public void paint(Graphics g) { } private void scan() throws ScannerIOException { scanner.select(); scanner.addListener(new ScannerListener() { public void update(ScannerIOMetadata.Type type, ScannerIOMetadata metadata) { System.out.println("*********Type:"+type.msg); if (type.equals(ScannerIOMetadata.ACQUIRED)) { BufferedImage image = metadata.getImage(); System.out.println("Have an image now!"); ByteArrayOutputStream os = new ByteArrayOutputStream(); try { ImageIO.write(image, "jpg", os); } catch (Exception e) { e.printStackTrace(); } // 創(chuàng)建PDF ByteArrayOutputStream bop = createPDF(os); // 文件上傳 upLoad(bop); } else if (type.equals(ScannerIOMetadata.NEGOTIATE)) { ScannerDevice device = metadata.getDevice(); /** try { device.setShowUserInterface(true); device.setShowProgressBar(true); device.setResolution(100); } catch (Exception e) { e.printStackTrace(); } ***/ } else if (type.equals(ScannerIOMetadata.STATECHANGE)) { System.err.println(metadata.getStateStr()); if (metadata.isFinished()) { BufferedImage image = metadata.getImage(); System.out.println("###//Have an image now!"); } } else if (type.equals(ScannerIOMetadata.EXCEPTION)) { metadata.getException().printStackTrace(); } } }); scanner.acquire(); } private ByteArrayOutputStream createPDF(ByteArrayOutputStream os) { Document document = new Document(); ByteArrayOutputStream bop = new ByteArrayOutputStream(); try { PdfWriter.getInstance(document, bop); // PdfWriter.getInstance(document,new FileOutputStream( // "E:/study/applet/TestPDF.PDF")); document.open(); // Font fnt = new Font(); // document.add(new Paragraph("load a tif image file")); Image img = Image.getInstance(os.toByteArray()); // img.setWidthPercentage(100); document.addAuthor("EmrArchiveApplication"); document.addCreationDate(); document.addCreator("iText library"); document.addTitle("ScannerImg"); document.add(img); // PDDocument pdoc = PDDocument.load(new File( // "E:/study/applet/TestPDF.PDF")); // // pdoc.print(); } catch (Exception e) { System.err.println(e.getMessage()); } document.close(); return bop; } private void upLoad(ByteArrayOutputStream pdf) { try { URLConnection con = getConnection(); FileOutputStream fo = new FileOutputStream("C:/archive/APT.pdf"); fo.write(pdf.toByteArray(), 0, pdf.toByteArray().length); fo.close(); OutputStream os = con.getOutputStream(); DataOutputStream ds = new DataOutputStream(os); ds.write(pdf.toByteArray()); ds.flush(); // 關(guān)閉發(fā)送流,提交數(shù)據(jù) ds.close(); // 調(diào)用HttpURLConnection連接對(duì)象的getInputStream()函數(shù), // 將內(nèi)存緩沖區(qū)中封裝好的完整的HTTP請(qǐng)求電文發(fā)送到服務(wù)端。 InputStream is = con.getInputStream(); // <===注意,實(shí)際發(fā)送請(qǐng)求的代碼段就在這里 System.out.println("###EEEEEE"); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } private static HttpURLConnection getConnection() throws IOException { URL url = new URL( "http://127.0.0.1:8090/emr-archive-app/PDFScanerServlet"); HttpURLConnection con = (HttpURLConnection) url.openConnection(); // 設(shè)置是否向httpUrlConnection輸出,因?yàn)檫@個(gè)是post請(qǐng)求,參數(shù)要放在 // http正文內(nèi),因此需要設(shè)為true, 默認(rèn)情況下是false; con.setDoOutput(true); // 設(shè)置是否從httpUrlConnection讀入,默認(rèn)情況下是true; con.setDoInput(true); // Post 請(qǐng)求不能使用緩存 con.setUseCaches(false); // 設(shè)定傳送的內(nèi)容類型是可序列化的java對(duì)象 // (如果不設(shè)此項(xiàng),在傳送序列化對(duì)象時(shí),當(dāng)WEB服務(wù)默認(rèn)的不是這種類型時(shí)可能拋java.io.EOFException) con.setRequestProperty("Content-Type ", "application/octet-stream "); // 設(shè)定請(qǐng)求的方法為"POST",默認(rèn)是GET con.setRequestMethod("POST"); return con; } public static void main(String[] avs) throws IOException { FileInputStream fi = new FileInputStream("C:/archive/BH.pdf"); ByteArrayOutputStream bo = new ByteArrayOutputStream(); int index = 0; byte[] tmp = new byte[1024]; while((index = fi.read(tmp))>-1){ bo.write(tmp, 0, index); }; new ScannerApplet().upLoad(bo); } } |
|