<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    posts - 0, comments - 77, trackbacks - 0, articles - 356
      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

    struts+MySQL實現圖片的存儲與顯示

    Posted on 2006-12-17 16:30 semovy 閱讀(1361) 評論(0)  編輯  收藏 所屬分類: struts 、My SQL數據庫方面

    人事信息管理系統中,需要管理用戶的個人身份照片。通常這種格式的照片只有幾 K 到幾十 K 大小,保存在數據庫中易于進行管理和維護(如果放在文件夾下容易發生誤操作而引起數據被修改或丟失)。

    功能設計: 給用戶提供一個上傳的界面,并設定上傳文件的尺寸上限。用戶上傳的照片先統一保存在一個臨時文件夾中,之后可以用 <img> 指向臨時文件夾中的這個圖片,讓用戶可以預覽自己上傳的照片。當所有的用戶信息都收集完成后,將圖片和其他信息一并提交,保存到數據庫中。保存成功以后,刪除臨時文件夾中的圖片。

    實現步驟:

    我使用的是從 struts 主頁上下載的 struts-1.2.8-src ,其中 web/examples/ 目錄下有一個 upload 的例子,稍微修改了一下就直接拿過來用了。這是一個 JSP 頁面、 ActionForm Action 的組合。下面分別列出各自的代碼。

    upload.jsp 的部分源代碼:

    <html:form action="/UploadSubmit" enctype="multipart/form-data">?????

    ????? 請選擇需要上傳的照片 :

    ???? <html:file property="theFile"/>

    ???? <html:submit value=" 上傳 "/>?????

    </html:form>

    接下來需要在 ActionForm 中聲明這個屬性,并設置 getter setter 方法,這部分源代碼如下:

    public class UploadForm extends ActionForm {

    ??? protected FormFile theFile;

    ??? public FormFile getTheFile() {

    ??????? return theFile;

    ??? }

    ??? public void setTheFile(FormFile theFile) {

    ??????? this.theFile = theFile;

    ??? }

    }

    這個表單的 theFile 屬性不是 String boolean ,而是 org.apache.struts.upload.FormFile 。因為用戶上傳的是一個二進制文件,而 HTTP 協議是以文本形式傳輸數據的,這就需要進行轉換。打個比方,一輛汽車需要從甲地送到乙地,但是兩地之間只有一條索道,汽車沒法開,所以就想個辦法在甲地把汽車先拆了,把零件送到乙地再重新組裝成一輛汽車。 FormFile 起的就是拆卸和組裝的作用,只不過它把拆卸、傳輸和組裝的過程都封裝起來了,我們看到的是一輛汽車從甲地開進 FormFile ,過一會它就從乙地開出來了 J 我們要決定的只是把它停到什么地方,這就是 Action 的活了。

    按照功能設計, Action 要把這部車停到一個臨時文件夾下面,這部分源代碼如下:

    public ActionForward execute(ActionMapping mapping,

    ???????????????????????????????? ActionForm form,

    ???????????????????????????????? HttpServletRequest request,

    ???????????????????????????????? HttpServletResponse response)

    ??????? throws Exception {

    ??????? if (form instanceof UploadForm) {

    ??????????? UploadForm theForm = (UploadForm) form;

    ????? ?????? // 獲取上傳的數據文件

    ??????????? FormFile file = theForm.getTheFile();

    ??????????? // 獲取文件名

    ??????????? String filename= file.getFileName();

    ??????????? // 設置圖片文件臨時存放的路徑

    ??????????? HttpSession session = request.getSession();

    ??????????? String path = session.getServletContext().getRealPath("/") + "temp\\" + filename;

    ??????????? try {

    ??????????????? // 讀取文件中的數據,獲取二進制的數據流

    ???????????? InputStream stream = file.getInputStream();

    ???????????? // 把數據寫到指定路徑

    ???????????? OutputStream bos = new FileOutputStream(path);

    ???????????? int bytesRead = 0;

    ???????????? byte[] buffer = new byte[8192];

    ???????????? while ((bytesRead = stream.read(buffer, 0, 8192)) != -1) {

    ???????????????? bos.write(buffer, 0, bytesRead);

    ???????????? }

    ???????????? bos.close();

    ???????????? logger.info("The file has been written to \""

    ???????????????????? ? + path + "\"");

    ??????????????? // 設計一個標記,說明用戶已經上傳過照片了。 ??????????????

    ???????????? session.setAttribute("imageuploaded","true");

    ???????????? session.setAttribute("filename",filename);

    ???????????? // close the stream

    ???????????? stream.close();

    ???????????? bos.flush();

    ???????????? bos.close();

    ??????????? }catch (FileNotFoundException fnfe) {

    ??????????????? return null;

    ??????????? }catch (IOException ioe) {

    ??????????????? return null;

    ??????????? }

    ??????????? //destroy the temporary file created

    ??????????? file.destroy();

    ??????????? // 轉向下一個頁面

    ??????????? return mapping.findForward("next");

    ??????? }

    ????? ??//this shouldn't happen in this example

    ??????? return null;

    ??? }

    這樣圖片就被放在 temp 的臨時文件夾下,顯示的時候,只需要先檢查一下標記,看看用戶是否上傳了照片,如果已經上傳,就用一個 <img src=””> 引用這個圖片。還有一個小地方需要修改,因為限定上傳的是身份照片,需要限定一個尺寸上限,這個在 struts upload 里面有現成的例子。先在 struts-config.xml 中配置這個 ActionForm Action

    <form-bean name="uploadForm"

    ?type="org.apache.struts.webapp.upload.UploadForm"/>

    ……

    <action input="/pages/hr/error.jsp" name="uploadForm"

    ? ??????? path="/UploadSubmit" scope="request"

    type="org.apache.struts.webapp.upload.UploadAction" validate="true">

    ?? <forward name="next" path="/pages/hr/input.jsp"/>

    </action>

    ……

    <controller maxFileSize="2M" inputForward="true" />

    在配置文件中已經看到 <action> validate 屬性被設置成“ true ”,這就是說表單提交之前先要對其內容進行驗證,這里我們要驗證的就是 theFile 是否超出了 controller 中設定的最大尺寸 2M 。這個驗證是通過 ActionForm validate 方法來實現的:

    /**

    ???? * Check to make sure the client hasn't exceeded the maximum allowed upload size inside of this validate method.

    **/

    ??? public ActionErrors validate(ActionMapping mapping,

    ??????? HttpServletRequest request) {???????????

    ??????? ActionErrors errors = null;

    ??????? //has the maximum length been exceeded?

    ??????? Boolean maxLengthExceeded =

    ??????????? (Boolean) request.getAttribute(

    ??????????????? MultipartRequestHandler.ATTRIBUTE_MAX_LENGTH_EXCEEDED);???????????????

    ??????? if ((maxLengthExceeded != null) && (maxLengthExceeded.booleanValue())) {

    ??????????? errors = new ActionErrors();

    ??????????? errors.add(

    ??????????????? ActionMessages.GLOBAL_MESSAGE ,

    ??????????????? new ActionMessage("maxLengthExceeded"));

    ??????????? errors.add(

    ??????????????? ActionMessages.GLOBAL_MESSAGE ,

    ??????????????? new ActionMessage("maxLengthExplanation"));

    ??????? }

    ??????? return errors;

    ??? }

    這里我估計有個 hook 之類的東西先截獲了表單(應該和 controller 有關),對 theFile 的尺寸進行校驗,然后把結果保存在 request scope 中。 Validate 方法只要檢查一下這個結果就可以了,如果尺寸超標,表單就不會被提交給 Action 。

    以上算是完成了第一步,從用戶那里拿到照片,并保存在臨時文件夾當中。接下來要做的就是把照片保存到 MySQL 數據庫中,這個字段我用的是 MEDIUMBLOB ,因為 BLOB 最大長度是 216-1 字節,大約 64K ; MEDIUMBLOB 224-1 字節,約 16M ,足夠用了。保存圖片的主要代碼如下:

    /**

    ?* 將用戶的照片保存在數據表中,添加成功后,刪除臨時文件夾中的圖片。

    ?* @param id 用戶的身份號,作為圖片的標識碼

    ?* @param path 圖片存放的路徑。一般存放在一個臨時文件夾中。

    ?* @return

    ?*/

    public static void saveImage(int id, String path) throws SQLException{

    ???? String time = new java.util.Date().toString();

    ???? Connection conn = null;

    ???? PreparedStatement pstmt = null;

    ???? boolean flag = false;

    ???? // 獲取連接

    ???? try {

    ???????? conn = DbManager.getConnection();

    ???????? logger.info(time + ":saveImage() DbManager 數據庫連接池獲取一個連接。 ");

    ???? } catch (SQLException e) {

    ???????? // 如果沒有能夠從 DbManager 獲取連接,此次查詢操作失敗

    ???????? logger.error(time + ": saveImage() 不能獲取數據庫連接,無法保存圖片! ");

    ???????? throw new SQLException(":saveImage() 不能獲取數據庫連接,無法保存圖片! ");

    ???? }

    ????

    ???????? // 執行查詢

    ???? try {

    ???????? pstmt = conn.prepareStatement("UPDATE hr01 SET hr01_photo=? where hr01_id=?");

    ???????? FileInputStream in = new FileInputStream(path);

    ???????? pstmt.setBinaryStream(1,in,in.available());

    ???????? pstmt.setInt(2,id);???? ???

    ???????? pstmt.executeUpdate();

    ???????? pstmt.executeUpdate("COMMIT");

    ???????? logger.info(" 圖片 " + path + " 被添加到數據庫中! ");

    ???????? flag = true;???????????

    ???? }catch(IOException e){

    ???????? logger.error(" 圖片 " + path + " 文件讀寫錯誤!請檢查文件路徑是否正確 ");

    ???????? throw new SQLException(" 無法保存圖片! ");

    ???? }catch (SQLException ex) {

    ???????? logger.error(new java.util.Date() + "Error:Insert into table."

    ???????????????? + ex.getMessage());????????

    ???????? logger.error(" 圖片 " + path +" 沒有被保存到數據庫 .");

    ???????? throw new SQLException(" 圖片 " + path +" 沒有被保存到數據庫 .");

    ????????

    ???? } finally {

    ???????? try {

    ???????????? pstmt.close();

    ???????????? conn.close();

    ???????????? logger.info("DbHrinfo saveImage() closed the connection created at " + time);

    ???????? } catch (SQLException e) {

    ???????? }

    ???? }
    >????

    ???? // 圖片添加成功以后就刪除臨時文件夾中的圖片數據

    ???? if(flag == true){

    ???????? File file = new File(path);

    ???????? if(file.exists()){

    ???????????? file.delete();

    ???????? }

    ???? }

    }

    需要注意的是 pstmt.executeUpdate("COMMIT"); 這行代碼,最初我并沒有寫這行,程序能順利執行,日志中也顯示“圖片××被添加到數據庫中”,但是到庫里一查詢,什么都沒有。 SQL 語句被提交,但是數據庫里面沒有即時的顯示,估計是緩沖區的作用,它把我的 SQL 語句緩存起來而不是立即提交給數據庫。后來我在 textpad 里面單獨執行這段代碼,發現不用“ COMMIT SQL 語句就立即被提交了。這個地方還沒有弄清楚,以后需要繼續研究。

    功能上做一點小改進,用戶提交了照片以后,瀏覽了一下覺得不滿意,只要還沒有最終提交數據,當然允許他重新上傳一個照片。我們只需要在 <img src=””> 下面提供一個“重新提交”的鏈接就可以了。這個鏈接指向一個 AlterImageAction ,它的功能就是清除 session 中用戶已經上傳照片的標記,并把剛才保存到臨時文件夾中的照片刪掉,等待用戶重新上傳。這部分代碼如下:

    public ActionForward execute(ActionMapping mapping,

    ???????? ActionForm form,HttpServletRequest request,

    ???????? HttpServletResponse response)

    throws IOException,ServletException{

    ????????

    ???? HttpSession session = request.getSession();

    ??????? //1. 從臨時文件夾中刪除圖片

    ???? String filename = (String)session.getAttribute("filename");

    ???? String path = session.getServletContext().getRealPath("/")

    + "temp\\" + filename;

    ???? File file = new File(path);

    ???? if(file.exists()){

    ???????? file.delete();

    ???????? logger.info(" 文件 " + path + " 已經被刪除 ");

    ???? }

    ????

    ???? //2. session 中清除上傳圖片的標記

    ????

    ???? session.removeAttribute("imageuploaded");

    ???? session.removeAttribute("filename");???????

    ???? return mapping.findForward("next");????

    }

    提交和保存到此功德圓滿。下次用戶想要查詢自己的信息的時候,因為臨時文件夾中已經沒有用戶照片,需要從數據庫中讀取。用一個 ShowImageAction 來實現這個功能:

    public ActionForward execute(ActionMapping mapping,

    ???????? ActionForm form, HttpServletRequest request,

    ???????? HttpServletResponse response)

    throws IOException,ServletException{

    ???? // 需要的情況下設置數據源

    ???? if (!DbManager.hasSetDataSource()) {

    ???????? javax.sql.DataSource dataSource;

    ???????? try {

    ???????????? dataSource = getDataSource(request);

    ???????????? DbManager.setDataSource(dataSource);

    ???????? } catch (Exception e) {

    ???????????? logger.error(e.getMessage());

    ???????????? mapping.findForward("error");

    ???????? }

    ???? }

    ????

    ???? String photo_no = request.getParameter("photo_no");

    ???? Connection conn = null;

    ???? Statement stmt = null;

    ???? // 獲取連接

    ???? try {

    ???????? conn = DbManager.getConnection();

    ???????? logger.info("showimage.jsp DbManager 數據庫連接池獲取一個連接。 ");

    ???? } catch (SQLException e) {

    ???????? // 如果沒有能夠從 DbManager 獲取連接,此次查詢操作失敗

    ??????? logger.error(" showimage.jsp 不能獲取數據庫連接,無法讀取圖片! ");

    ???? }

    ???? try {

    ???????? // 準備語句執行對象

    ???????? stmt = conn.createStatement();

    ???????? String sql = " SELECT hr01_photo FROM hr01 WHERE hr01_id='" + photo_no + "'";

    ???????? ResultSet rs = stmt.executeQuery(sql);

    ???????? if (rs.next()) {

    ???????????? InputStream in = rs.getBinaryStream("hr01_photo");

    ???????????? int bytesRead = 0;

    byte[] buffer = new byte[8192];

    ???????????? response.setContentType("image/jpeg");

    ???????????? response.setContentLength(in.available());

    ???????????? OutputStream outs = response.getOutputStream();

    ???? ???????????????????????

    ???????????? while ((bytesRead = in.read(buffer, 0, 8192)) != -1) {

    ???????????????? outs.write(buffer, 0, bytesRead);

    ???????????? }

    ???????????? outs.flush();

    ???????????? in.close();

    ???????????? rs.close();

    ???????? } else {

    ???????????? rs.close();

    ???????????? response.sendRedirect("error.jsp");

    ???????? }

    ???? }catch(SQLException e){

    ????????

    ???? }finally {

    ???????? try{

    ???????? stmt.close();

    ???????? conn.close();

    ???????? }catch(SQLException ex){

    ????????????

    ???????? }

    ???? }

    ???? return null;

    }

    以前一直不清楚 execute 方法中的 response 參數的用法,因為處理完以后總要 redirect 到另外一個頁面,所以用的最多的就是把數據保存在 session 中,在另一個頁面里再取出來用。這次純粹是試驗性地在 response 中寫入 image/jpeg 內容,然后返回一個 null 值。最后的執行結果跟我預期的一樣,在瀏覽器中直接顯示從數據庫中讀出的圖片。那么接下來就很好做了,只需要在 JSP 頁面中設置一個 <image> 標簽,指向這個 Action 就可以,當然,在這之前需要在 struts-config.xml 中先部署這個 Action

    <action path="/ShowImage"

    ?type="software.action.ShowImageAction"></action>

    然后在 JSP 頁面中引用這個 Action 來顯示圖像 :

    <img src="/tibet/ShowImage.do?photo_no=666542">


    < p>
    主站蜘蛛池模板: 日韩免费a级在线观看| 亚洲日韩av无码| 一级A毛片免费观看久久精品| 夜夜春亚洲嫩草影院| 亚洲香蕉免费有线视频| 亚洲AV永久无码精品一福利 | 亚洲日韩中文字幕在线播放| 精品无码人妻一区二区免费蜜桃| 在线a亚洲老鸭窝天堂av高清| 亚洲欧洲日产国码一级毛片| 久久久久久精品免费看SSS| 国产亚洲日韩在线a不卡| 久久精品国产亚洲AV高清热| 国产大片51精品免费观看| 久久精品电影免费动漫| 亚洲av无码专区首页| 综合自拍亚洲综合图不卡区| www.亚洲精品.com| 成人黄色免费网站| a级毛片高清免费视频| 男人的天堂av亚洲一区2区| 综合自拍亚洲综合图不卡区| 亚洲精品成人在线| 成全高清视频免费观看| 日本中文字幕免费高清视频| 免费福利资源站在线视频| 亚洲午夜一区二区电影院| 亚洲伊人久久大香线蕉综合图片| 青青草免费在线视频| 人人玩人人添人人澡免费| 深夜免费在线视频| 亚洲一线产区二线产区区| 日韩亚洲AV无码一区二区不卡 | 亚洲日韩在线观看| 成年性生交大片免费看| 免费A级毛片在线播放| 国产视频精品免费视频| 极品色天使在线婷婷天堂亚洲| 亚洲无限乱码一二三四区| 久久精品国产亚洲AV麻豆不卡| 亚洲人AV永久一区二区三区久久|