posts - 0, comments - 77, trackbacks - 0, articles - 356
            BlogJava :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

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

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

          實(shí)現(xiàn)步驟:

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

          upload.jsp 的部分源代碼:

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

          ????? 請(qǐng)選擇需要上傳的照片 :

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

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

          </html:form>

          接下來(lái)需要在 ActionForm 中聲明這個(gè)屬性,并設(shè)置 getter setter 方法,這部分源代碼如下:

          public class UploadForm extends ActionForm {

          ??? protected FormFile theFile;

          ??? public FormFile getTheFile() {

          ??????? return theFile;

          ??? }

          ??? public void setTheFile(FormFile theFile) {

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

          ??? }

          }

          這個(gè)表單的 theFile 屬性不是 String boolean ,而是 org.apache.struts.upload.FormFile 。因?yàn)橛脩羯蟼鞯氖且粋€(gè)二進(jìn)制文件,而 HTTP 協(xié)議是以文本形式傳輸數(shù)據(jù)的,這就需要進(jìn)行轉(zhuǎn)換。打個(gè)比方,一輛汽車需要從甲地送到乙地,但是兩地之間只有一條索道,汽車沒法開,所以就想個(gè)辦法在甲地把汽車先拆了,把零件送到乙地再重新組裝成一輛汽車。 FormFile 起的就是拆卸和組裝的作用,只不過它把拆卸、傳輸和組裝的過程都封裝起來(lái)了,我們看到的是一輛汽車從甲地開進(jìn) FormFile ,過一會(huì)它就從乙地開出來(lái)了 J 我們要決定的只是把它停到什么地方,這就是 Action 的活了。

          按照功能設(shè)計(jì), Action 要把這部車停到一個(gè)臨時(shí)文件夾下面,這部分源代碼如下:

          public ActionForward execute(ActionMapping mapping,

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

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

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

          ??????? throws Exception {

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

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

          ????? ?????? // 獲取上傳的數(shù)據(jù)文件

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

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

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

          ??????????? // 設(shè)置圖片文件臨時(shí)存放的路徑

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

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

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

          ??????????????? // 讀取文件中的數(shù)據(jù),獲取二進(jìn)制的數(shù)據(jù)流

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

          ???????????? // 把數(shù)據(jù)寫到指定路徑

          ???????????? 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 + "\"");

          ??????????????? // 設(shè)計(jì)一個(gè)標(biāo)記,說明用戶已經(jīng)上傳過照片了。 ??????????????

          ???????????? 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();

          ??????????? // 轉(zhuǎn)向下一個(gè)頁(yè)面

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

          ??????? }

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

          ??????? return null;

          ??? }

          這樣圖片就被放在 temp 的臨時(shí)文件夾下,顯示的時(shí)候,只需要先檢查一下標(biāo)記,看看用戶是否上傳了照片,如果已經(jīng)上傳,就用一個(gè) <img src=””> 引用這個(gè)圖片。還有一個(gè)小地方需要修改,因?yàn)橄薅ㄉ蟼鞯氖巧矸菡掌枰薅ㄒ粋€(gè)尺寸上限,這個(gè)在 struts upload 里面有現(xiàn)成的例子。先在 struts-config.xml 中配置這個(gè) 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" />

          在配置文件中已經(jīng)看到 <action> validate 屬性被設(shè)置成“ true ”,這就是說表單提交之前先要對(duì)其內(nèi)容進(jìn)行驗(yàn)證,這里我們要驗(yàn)證的就是 theFile 是否超出了 controller 中設(shè)定的最大尺寸 2M 。這個(gè)驗(yàn)證是通過 ActionForm validate 方法來(lái)實(shí)現(xiàn)的:

          /**

          ???? * 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;

          ??? }

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

          以上算是完成了第一步,從用戶那里拿到照片,并保存在臨時(shí)文件夾當(dāng)中。接下來(lái)要做的就是把照片保存到 MySQL 數(shù)據(jù)庫(kù)中,這個(gè)字段我用的是 MEDIUMBLOB ,因?yàn)?/span> BLOB 最大長(zhǎng)度是 216-1 字節(jié),大約 64K MEDIUMBLOB 224-1 字節(jié),約 16M ,足夠用了。保存圖片的主要代碼如下:

          /**

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

          ?* @param id 用戶的身份號(hào),作為圖片的標(biāo)識(shí)碼

          ?* @param path 圖片存放的路徑。一般存放在一個(gè)臨時(shí)文件夾中。

          ?* @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 數(shù)據(jù)庫(kù)連接池獲取一個(gè)連接。 ");

          ???? } catch (SQLException e) {

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

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

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

          ???? }

          ????

          ???????? // 執(zhí)行查詢

          ???? 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 + " 被添加到數(shù)據(jù)庫(kù)中! ");

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

          ???? }catch(IOException e){

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

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

          ???? }catch (SQLException ex) {

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

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

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

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

          ????????

          ???? } finally {

          ???????? try {

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

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

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

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

          ???????? }

          ???? }
          >????

          ???? // 圖片添加成功以后就刪除臨時(shí)文件夾中的圖片數(shù)據(jù)

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

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

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

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

          ???????? }

          ???? }

          }

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

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

          public ActionForward execute(ActionMapping mapping,

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

          ???????? HttpServletResponse response)

          throws IOException,ServletException{

          ????????

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

          ??????? //1. 從臨時(shí)文件夾中刪除圖片

          ???? 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 + " 已經(jīng)被刪除 ");

          ???? }

          ????

          ???? //2. session 中清除上傳圖片的標(biāo)記

          ????

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

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

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

          }

          提交和保存到此功德圓滿。下次用戶想要查詢自己的信息的時(shí)候,因?yàn)榕R時(shí)文件夾中已經(jīng)沒有用戶照片,需要從數(shù)據(jù)庫(kù)中讀取。用一個(gè) ShowImageAction 來(lái)實(shí)現(xiàn)這個(gè)功能:

          public ActionForward execute(ActionMapping mapping,

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

          ???????? HttpServletResponse response)

          throws IOException,ServletException{

          ???? // 需要的情況下設(shè)置數(shù)據(jù)源

          ???? 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 數(shù)據(jù)庫(kù)連接池獲取一個(gè)連接。 ");

          ???? } catch (SQLException e) {

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

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

          ???? }

          ???? try {

          ???????? // 準(zhǔn)備語(yǔ)句執(zhí)行對(duì)象

          ???????? 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 參數(shù)的用法,因?yàn)樘幚硗暌院罂傄?/span> redirect 到另外一個(gè)頁(yè)面,所以用的最多的就是把數(shù)據(jù)保存在 session 中,在另一個(gè)頁(yè)面里再取出來(lái)用。這次純粹是試驗(yàn)性地在 response 中寫入 image/jpeg 內(nèi)容,然后返回一個(gè) null 值。最后的執(zhí)行結(jié)果跟我預(yù)期的一樣,在瀏覽器中直接顯示從數(shù)據(jù)庫(kù)中讀出的圖片。那么接下來(lái)就很好做了,只需要在 JSP 頁(yè)面中設(shè)置一個(gè) <image> 標(biāo)簽,指向這個(gè) Action 就可以,當(dāng)然,在這之前需要在 struts-config.xml 中先部署這個(gè) Action

          <action path="/ShowImage"

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

          然后在 JSP 頁(yè)面中引用這個(gè) Action 來(lái)顯示圖像 :

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


          < p>
          主站蜘蛛池模板: 古丈县| 曲松县| 宜兴市| 沙洋县| 二连浩特市| 靖江市| 祥云县| 裕民县| 宁蒗| 东宁县| 枣庄市| 靖江市| 信阳市| 黄石市| 大余县| 都江堰市| 体育| 屏山县| 临清市| 乌拉特后旗| 泸水县| 柘荣县| 马边| 临安市| 泸西县| 宜章县| 库尔勒市| 耒阳市| 晋宁县| 正蓝旗| 东乡县| 兴宁市| 容城县| 吉水县| 泸州市| 邵东县| 织金县| 德格县| 买车| 阿拉善盟| 盐山县|