兩畝三分地

            BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
            17 隨筆 :: 20 文章 :: 2 評(píng)論 :: 0 Trackbacks

          #

          在使用Netbeans的時(shí)候,除了Struts應(yīng)用所需需要的Struts庫文件與配置文件以外,創(chuàng)建一個(gè)Struts應(yīng)用與
          創(chuàng)建其他任何一個(gè)網(wǎng)絡(luò)應(yīng)用沒有什么區(qū)別。其實(shí)創(chuàng)建一個(gè)Struts應(yīng)用的方法和任何一個(gè)其他網(wǎng)絡(luò)應(yīng)用的方法
          都一樣。
          • 選擇File > New Project. 在Categories里面選擇Web。Projects項(xiàng)目下面,選擇Web Application然后按Next。
          • 在輸入項(xiàng)目名稱和位置的面板里面,輸入BBS作為項(xiàng)目名稱,然后按Next;
          • 在服務(wù)器與設(shè)置面板里面,選擇選擇一個(gè)你準(zhǔn)備用來deploy應(yīng)用的服務(wù)器(如:GlassFish v2.1),同時(shí)注意面板下方的
            Context Path的路徑與我們的項(xiàng)目名稱一致,按Next;
          • 在Framework面板里,選擇Struts

            將Application Resource里的名稱com.myapp.struts.ApplicationResource改成com.bbs.struts.ApplicationResource .
          • 按下Finish,Struts的一個(gè)應(yīng)用就建立完成了。
          在項(xiàng)目管理器里面,所有的Struts指定的配置文件以及應(yīng)用deploy所用的文件,都被放置在Configuration Files的目錄里。
          打開web.xml,我們可以看一下文件是如何管理Struts的。
          <?xml version="1.0" encoding="UTF-8"?>
          <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation
          ="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
              
          <servlet>
                  
          <servlet-name>action</servlet-name>
                  
          <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
                  
          <init-param>
                      
          <param-name>config</param-name>
                      
          <param-value>/WEB-INF/struts-config.xml</param-value>
                  
          </init-param>
                  
          <init-param>
                      
          <param-name>debug</param-name>
                      
          <param-value>2</param-value>
                  
          </init-param>
                  
          <init-param>
                      
          <param-name>detail</param-name>
                      
          <param-value>2</param-value>
                  
          </init-param>
                  
          <load-on-startup>2</load-on-startup>
                  
          </servlet>
              
          <servlet-mapping>
                  
          <servlet-name>action</servlet-name>
                  
          <url-pattern>*.do</url-pattern>
              
          </servlet-mapping>
              
          <session-config>
                  
          <session-timeout>
                      30
                  
          </session-timeout>
              
          </session-config>
              
          <welcome-file-list>
                  
          <welcome-file>index.jsp</welcome-file>
                  
          </welcome-file-list>
              
          </web-app>

          posted @ 2009-10-20 18:07 Chucky 閱讀(207) | 評(píng)論 (0)編輯 收藏

          到16節(jié) 和項(xiàng)目相關(guān)的東西,覺得已經(jīng)沒什么要寫的了;基本還剩下一些css之類的頁面設(shè)計(jì)和美化工作。
          這方面沒有什么感覺,總之把跟這個(gè)項(xiàng)目相關(guān)的東西放在一起(src和web相關(guān)的東西);有興趣可以下來看看。
          blog_servlet

          Ok 跟blog_servlet相關(guān)的東西到這里結(jié)束了,下周開始做blog Struts相關(guān)的項(xiàng)目。

          posted @ 2009-10-08 19:04 Chucky 閱讀(114) | 評(píng)論 (0)編輯 收藏

               摘要: 對(duì)于表格數(shù)據(jù)處理的話,displayTag有很大的優(yōu)勢(shì);但是有些時(shí)候還得自己動(dòng)手做點(diǎn)工作; 我自己寫了一個(gè)PageTag的類來處理一些簡單的工作。 PageTag.java Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ -->&n...  閱讀全文
          posted @ 2009-10-07 18:58 Chucky 閱讀(251) | 評(píng)論 (0)編輯 收藏

               摘要: 上一節(jié)談了displaytag的基本用法,這一節(jié)就結(jié)合項(xiàng)目來看一下。按照常理,可能使用到displaytag的地方, 集中在管理頁面里,譬如對(duì)博文的管理或者是針對(duì)comments的管理;相對(duì)而言category似乎并不需要使用分頁; 很少會(huì)有人開幾十個(gè)不同的分類吧 XD。 好吧,我們來比較一下,displaytag和原來的代碼有什么不同。 這是原先的頁面 網(wǎng)頁的code: ...  閱讀全文
          posted @ 2009-10-07 16:37 Chucky 閱讀(215) | 評(píng)論 (0)編輯 收藏

          隨著博文的增加或者評(píng)論的增加,是必要考慮一下分頁問題。
          在這個(gè)項(xiàng)目里,對(duì)于分頁問題,我采取2種處理的方法。對(duì)于管理頁面表格型的記錄采用displayTag組件;
          而對(duì)于那些博文或者評(píng)論采用自己寫的PageTags類來管理。

          1. displayTag組件

          上面的圖片可以看出:事實(shí)上這個(gè)display tag庫就是用來顯示表格的;給它一個(gè)對(duì)象的list,它將搞定類似顯示列,排序,分頁等等事務(wù),并以表格的形式顯示出來。

          a. 安裝:
             將displaytag-version.jar 文件與以下5個(gè)文件一起放置在應(yīng)用的WEB-INF/lib目錄里
          • commons-logging
          • commons-lang
          • commons-collections
          • commons-beanutils
          • log4j
             在使用的時(shí)候,在jps頁面中,
          <%@ taglib uri="http://displaytag.sf.net" prefix="display" %>

          b. 使用:
             這里使用blog列表做例子
           <% List blogs = (List) request.getAttribute("blogs");%>
              
          <h2>文章管理</h2>
          <display:table name="blogs" htmlId="tab" pagesize="10" />
          每頁顯示10條記錄

          對(duì)于每條記錄我們可能有顯示要求
          <display:table name="blogs" id=" blog" htmlId="tab" pagesize="10" >
              
          <display:column property="id" title="編號(hào)"/>
              
          <display:column property="title" title="主題"/>
              
          <display:column property="category" title="類別"/>
              
          <display:column property="date" format="{0,date,yyyy-MM-dd  HH:mm:ss}" title="日期",sortable="true"/>
              
          <display:column title="操作">
                  
          <href="/Blogs/BlogServlet?method=edit&id=${blog.id}"><img src="/Blogs/admin/img/edit.gif" border=0 /></a>
                          
          <href="/Blogs/BlogServlet?method=delete&id=${blog.id}" onclick="javascript:return del()"><img src="/Blogs/admin/img/delete.gif" border=0 /></a>|
                          
          <href="/Blogs/CommentServlet?method=list&bid=${blog.id}">管理評(píng)論</td> 
              
          </display:column>
              
          </display:table>
          比如id字段顯示為 標(biāo)號(hào);title主題;category類別;日期么安裝年-月-日 小時(shí):分鐘:秒的格式顯示;并且可以手動(dòng)選擇排序。
          是不是很簡單。

          c.其他問題:
            配置文件displaytag.properties,需要放置在src目錄的根部,主要顯示一些文字之類的設(shè)置,支持localization,但是要注意的是,文件必須轉(zhuǎn)換成unicode才可以正常顯著。
          以下是displaytag_Zh_CN.properties的示例:
           1 #sort.behavior=list
           2 #sort.amount=list
           3 #basic.empty.showtable=true
           4 #basic.msg.empty_list=No results matched your criteria.
           5 #paging.banner.placement=top
           6 #paging.banner.onepage=<span class="pagelinks"></span>
           7 export.types=csv excel xml pdf rtf
           8 export.excel=true
           9 export.csv=true
          10 export.xml=true
          11 export.pdf=true
          12 export.rtf=true
          13 export.excel.class=org.displaytag.export.excel.DefaultHssfExportView
          14 export.pdf.class=org.displaytag.export.DefaultPdfExportView
          15 export.rtf.class=org.displaytag.export.DefaultRtfExportView
          16 # if set, file is downloaded instead of opened in the browser window
          17 #export.[mymedia].filename=
          18 paging.banner.placement=bottom
          19 # messages
          20 
          21 basic.msg.empty_list=\u6CA1\u6709\u7B26\u5408\u6761\u4EF6\u7684\u8BB0\u5F55
          22 basic.msg.empty_list_row=<tr class="empty"><td colspan="{0}">\u6CA1\u6709\u7B26\u5408\u6761\u4EF6\u7684\u8BB0\u5F55</td></tr>
          23 error.msg.invalid_page=\u65E0\u6548\u9875\u9762
          24 
          25 export.banner=<div class="exportlinks">Export options: {0}</div>
          26 export.banner.sepchar= |
          27 
          28 paging.banner.item_name=
          29 paging.banner.items_name=
          30 
          31 paging.banner.no_items_found=
          32 paging.banner.one_item_found=
          33 paging.banner.all_items_found=
          34 paging.banner.some_items_found=
          35 
          36 paging.banner.full=<span class="pagelinks"><font align>[<a href="{1}">|<</a>/<a href="{2}"><</a>] {0[<a href="{3}">></a>/<a href="{4}">>|</a>]</span>
          37 paging.banner.first=<span class="pagelinks">[\u9996\u9875/\u4E0A\u4E00\u9875] {0[<a href="{3}">\u4E0B\u4E00\u9875</a>/<a href="{4}">\u5C3E\u9875</a>]</span>
          38 paging.banner.last=<span class="pagelinks">[<a href="{1}">\u9996\u9875</a>/<a href="{2}">\u4E0A\u4E00\u9875</a>] {0[\u4E0B\u4E00\u9875/\u5C3E\u9875]</span>
          39 paging.banner.onepage=<span class="pagelinks">{0}</span>
          40 
          41 paging.banner.page.selected=<strong>{0}</strong>
          42 paging.banner.page.link=<a href="{1}" title="{0}">{0}</a>
          43 paging.banner.page.separator=, \
          38行paging.banner.placement=bottom 指定分頁欄出現(xiàn)在表格的下面,當(dāng)然還有top/both兩個(gè)選擇。
            
           

          posted @ 2009-10-05 17:07 Chucky 閱讀(274) | 評(píng)論 (0)編輯 收藏

          到11節(jié)基本的東西都已經(jīng)實(shí)現(xiàn)了,剩下的都是一點(diǎn)細(xì)節(jié)問題;比如由于注冊(cè)用戶和普通瀏覽用戶權(quán)限不同,所以大家看的也有所不同;
          在項(xiàng)目設(shè)計(jì)的時(shí)候,普通用戶可以看博客,發(fā)表評(píng)論;為了避免不必要的麻煩,將普通用戶的操作特別的寫一個(gè)servlet,這樣也比較容易控制。
          HomeServlet主要就是負(fù)責(zé)這個(gè)任務(wù)。
          在HomeServlet里面主要就是兩個(gè)方法,為了配合以后的頁面設(shè)計(jì),相對(duì)之前的BlogServlet等等,相對(duì)復(fù)雜一點(diǎn)(其實(shí)還好)。

          讓我們來看看這個(gè)Sql語句的作用
          sql= select b.id as id,b.title as title,b.content as content,b.date as date,c.name as category,categoryId,comments from
          (
          select blog.id as id ,blog.title as title,blog.category_id as categoryId,count(comment.blog_id) as comments,blog.content as content,blog.date as date from blog
          left
           join comment on blog.id = comment.blog_id group by blog.id) as b, category c
          where categoryId = c.id
          order by date desc;
          首先
          select blog.id as id ,blog.title as title,blog.category_id as categoryId,count(comment.blog_id) as comments,blog.content as content,blog.date as date from blog
          left join comment on blog.id = comment.blog_id group by blog.id
          comment表中對(duì)blog_id一致的記錄做統(tǒng)計(jì),與blog表左連接;
          然后再blog新表與category根據(jù)categoryId做連接。

          然后修改一下Blog類,添加一個(gè)comments屬性(記錄此blog對(duì)象所包含的評(píng)論數(shù)目)。

          2.對(duì)blog.content做下處理,在顯示所有博文的時(shí)候,對(duì)blog.content的內(nèi)容做一個(gè)簡報(bào)。
          很簡單的一個(gè)getBriefContent()方法:
          public String getBriefContent() {
                  StringBuffer briefContent 
          = new StringBuffer(content);
                  
          int length = 200;
                  
          if (briefContent.length() < length) {
                      length 
          = briefContent.length();
                  }
                  briefContent 
          = briefContent.delete(length, briefContent.length());

                  
          //filter html mark;
                  briefContent.append(" ..");
                  
          return briefContent.toString();
              }
          限定200字符長度,如果博文內(nèi)容多于200字符,那么取前200字符;否則直接貼上博文內(nèi)容。

          3.對(duì)blog.content另一個(gè)修改。因?yàn)閷懖┪牡臅r(shí)候,可能所選用的字體啊什么每次都不同,以至于在瀏覽所有博文的時(shí)候會(huì)很亂;
          所以以下doFilter(StringBuffer sb)方法,主要對(duì)文字進(jìn)行過濾,將充滿HTML MARK的文章過濾一下。
          private StringBuffer doFilter(StringBuffer source) {
                  StringBuffer header 
          = new StringBuffer(source);
                  
          while((header.indexOf("<")!=-1)&&(header.indexOf(">")!=-1)){
                     
          int startPos = header.indexOf("<");
                     
          int endPos = header.indexOf(">");
                      header 
          = header.delete(startPos, endPos+1);
                  }
                  
          return header;
              }
          因此getBriefContent()方法也要插上一句(Line 3):
           1 public String getBriefContent() {
           2         StringBuffer briefContent = new StringBuffer(content);
           3         briefContent = doFilter(briefContent);
           4         int length = 200;
           5         if (briefContent.length() < length) {
           6             length = briefContent.length();
           7         }
           8         briefContent = briefContent.delete(length, briefContent.length());
           9 
          10         //filter html mark;
          11         briefContent.append(" ..");
          12         return briefContent.toString();
          13     }



          posted @ 2009-10-05 16:26 Chucky 閱讀(152) | 評(píng)論 (0)編輯 收藏

          我們大家都有使用博客或者其他類似系統(tǒng)的經(jīng)驗(yàn),往往都是通過用戶驗(yàn)證以后,才進(jìn)行其他的操作。
          上一節(jié),在處理完login事務(wù)以后,我們可以訪問某個(gè)頁面對(duì)自己的博文或者博文分類等等進(jìn)行操作。
          但是由于網(wǎng)頁的關(guān)系,如果沒有對(duì)每頁進(jìn)行用戶認(rèn)證,而我們知道準(zhǔn)確的地址的話,我們可以直接訪問地址來對(duì)數(shù)據(jù)進(jìn)行操作。
          比如:
          http://localhost:8080/Blog/BlogServlet?method=list
          可以查看所有的博文;而
          http://localhost:8080/Blog/BlogServlet?method=delete&cid=1
          這個(gè)地址可以對(duì)編號(hào)為1的博文進(jìn)行刪除操作。
          所以我們必須對(duì)每一頁或者沒一次操作進(jìn)行用戶認(rèn)證。因?yàn)閡ser對(duì)象是放置在session中的,所有我們可以每次通過檢測(cè)session內(nèi)容來達(dá)到驗(yàn)證的效果。

          在這里,我寫了一個(gè)輔助類UserValidator,來簡化操作。
          package com.blog.utils;

          import com.blog.User;
          import javax.servlet.http.HttpServletRequest;
          import javax.servlet.http.HttpSession;

          /**
           *
           * 
          @author Chucky
           
          */
          public class UserValidator {
              
          public static boolean isValid(HttpServletRequest request){
                  HttpSession session 
          = request.getSession();
                  User user 
          = (User) session.getAttribute("user");
                  
          return user!=null?true:false;
              }
          }
          一般Servlet的里面,可以直接把UserValidator的檢驗(yàn)直接放置在processRequest方法里,如果檢驗(yàn)失敗的話,轉(zhuǎn)到用戶登錄界面
           1 protected void processRequest(HttpServletRequest request, HttpServletResponse response)
           2             throws ServletException, IOException {
           3         response.setContentType("text/html;charset=UTF-8");
           4         request.setCharacterEncoding("UTF-8");
           5 
           6         String method = request.getParameter("method");
           7 
           8         if (!UserValidator.isValid(request)) {
           9             response.sendRedirect(request.getContextPath()+"/admin/");
          10         } else {
          11             if (method.equals("add")) {
          12                 add(request, response);
          13             } else if (method.equals("delete")) {
          14                 delete(request, response);
          15             } else if (method.equals("edit")) {
          16                 preEdit(request, response);
          17             } else if (method.equals("update")) {
          18                 update(request, response);
          19             } else if (method.equals("list")) {
          20                 list(request, response);
          21             } else if (method.equals("get")) {
          22                 get(request, response);
          23             } else if (method.equals("preAdd")) {
          24                 preAdd(request, response);
          25             }
          26         }
          27     }
          而一些直接讀取的jsp頁面,也可以把驗(yàn)證直接寫在頁面里。
          <% User user = (User)session.getAttribute("user");
             if (user == null){
             
          response.sendRedirect(request.getContextPath()+"/admin/");
             }
          %>


          posted @ 2009-09-30 16:47 Chucky 閱讀(220) | 評(píng)論 (0)編輯 收藏

          UserServlet主要用于用戶登錄,退出以及密碼修改方面的事務(wù)。鑒于對(duì)網(wǎng)絡(luò)應(yīng)用的安全性考慮,
          所以u(píng)ser將被寫在session里面,用以在某些管理頁面達(dá)到認(rèn)證作用。
           1 private void login(HttpServletRequest request, HttpServletResponse response)
           2             throws ServletException, IOException {
           3         String userName = request.getParameter("username");
           4         String password = request.getParameter("password");
           5         String sql = "select id,username,password from users where username = ? and password = ?";
           6         String params[] = {userName, password};
           7         List users = null;
           8 
           9         QueryRunner qr = DbHelper.getQueryRunner();
          10         try {
          11             users = (List) qr.query(sql, new BeanListHandler(User.class), params);
          12         } catch (SQLException ex) {
          13             Logger.getLogger(UserServlet.class.getName()).log(Level.SEVERE, null, ex);
          14         }
          15         if (users.size()!=0) {
          16             User user = (User) users.get(0);
          17             HttpSession session = request.getSession();
          18             session.setAttribute("user", user);
          19             response.sendRedirect(request.getContextPath()+"/BlogServlet?method=list");
          20         } else {
          21             request.setAttribute("message""錯(cuò)誤的用戶名或密碼");
          22             request.getRequestDispatcher("/admin/login.jsp").forward(request, response);
          23         }
          24     }

          logout相對(duì)很簡單,使session失效即可
          1 private void logout(HttpServletRequest request, HttpServletResponse response)
          2             throws ServletException, IOException {
          3         HttpSession session = request.getSession();
          4         session.invalidate();
          5         response.sendRedirect(request.getContextPath());
          6     }

          modifyPassword
           1  private void modify(HttpServletRequest request, HttpServletResponse response)
           2             throws ServletException, IOException {
           3         String oldPassword = request.getParameter("oldPassword");
           4         String newPassword = request.getParameter("newPassword");
           5         String confirmPassword = request.getParameter("confirmPassword");
           6 
           7         HttpSession session = request.getSession();
           8         User user = (User) session.getAttribute("user");
           9         if (!user.getPassword().equals(oldPassword)) {
          10             request.setAttribute("message""與原密碼不匹配");
          11         } else {
          12             if (!newPassword.equals(confirmPassword)) {
          13                 request.setAttribute("message""新密碼與確認(rèn)密碼不匹配");
          14             } else {
          15                 String sql = "update users set password =? where id = "+ user.getId();
          16                 QueryRunner qr = DbHelper.getQueryRunner();
          17                 try {
          18                     qr.update(sql, newPassword);
          19                 } catch (SQLException ex) {
          20                     Logger.getLogger(UserServlet.class.getName()).log(Level.SEVERE, null, ex);
          21                 }
          22                  request.setAttribute("message""密碼修改成功");
          23             }
          24         }
          25         request.getRequestDispatcher("/admin/modifyPassword.jsp").forward(request, response);
          26     }


          posted @ 2009-09-30 14:22 Chucky 閱讀(207) | 評(píng)論 (0)編輯 收藏

          為了讓博文編輯更方便,這里介紹一下FCKeditor這個(gè)組件, 在這個(gè)項(xiàng)目里我們主要利用這個(gè)組件的工具欄
           

          FCKeditor提供了很詳細(xì)的文檔,關(guān)于FCKeditor的安裝,軟件本身提供了對(duì)多種語言的支持,根據(jù)項(xiàng)目的需要,這里著重介紹javascript的安裝方法。
          首先在網(wǎng)頁的表頭添加下面的聲明
          <script type="text/javascript" src="fckeditor/fckeditor.js"></script>
          接下來有3種不同的方法使用FCKeditor,
          方法一. inline方式 在網(wǎng)頁body部分,把編輯器放在你想放的地方(通常在表單里面),在該位置添加以下腳本:
          <script type="text/javascript">
          var oFCKeditor = new FCKeditor('FCKeditor1');
          oFCKeditor.BasePath 
          = "/fckeditor/";
          oFCKeditor.Create();
          </script>
          方法一實(shí)例
          <html>
          <head>
          <title>FCKeditor - Sample</title>
          <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
          <meta name="robots" content="noindex, nofollow">
          <script type="text/javascript" src="fckeditor/fckeditor.js"></script>
          </head>
          <body>
          <form>
          <script type="text/javascript">
          var oFCKeditor = new FCKeditor('FCKeditor1');
          oFCKeditor.BasePath 
          = "/fckeditor/";
          oFCKeditor.Create();
          </script>
          </form>
          </body>
          </html>

          方法二 替換TextArea方式
          1.先在Head部位添加onload方法
          <script type="text/javascript">
          window.onload 
          = function()
          {
          var oFCKeditor = new FCKeditor( 'MyTextarea' ) ;
          oFCKeditor.BasePath 
          = "/fckeditor/" ;
          oFCKeditor.ReplaceTextarea() ;
          }
          </script>
          2.在<body>部分 添加并替換原先的TextArea
          <textarea id="MyTextarea" name="MyTextarea">This is <b>the</b> initial value.</textarea>
          注意 textarea的名字和FCKeditor的對(duì)象名稱一致

          現(xiàn)在我們就可以使用一個(gè)很漂亮方便的工具欄了


          但是在個(gè)漂亮的工具欄Font里面是沒有宋體,黑體之類的中文字體的,所以在使用前,我們還要做一定的修改。
          打開fckeditor/fckconfig.js,找到并修改FCKConfig.FontNames如下
          FCKConfig.FontNames        = '宋體;黑體;隸書;楷體_GB2312;幼圓;Arial;Comic Sans MS;Courier New;Tahoma;Times New Roman;Verdana' ;

          好了經(jīng)過安裝FCKeditor這個(gè)編輯器基本就可以使用了。
          值得注意的是,F(xiàn)CKeditor的屬性是case sensitive,所以在使用的時(shí)候千萬注意。

          posted @ 2009-09-29 17:16 Chucky 閱讀(113) | 評(píng)論 (0)編輯 收藏

          相對(duì)于上一篇的CategoryServlet,BlogServlet相對(duì)復(fù)雜一些。
          不如在做添加博文的時(shí)候,我們要考慮的不僅僅是blog本身的主題,內(nèi)容還要考慮blog所對(duì)應(yīng)的類別;
          一般我們把類別做成一個(gè)List以供選擇。所以在blog添加的前,我們首先要處理category信息,那么
          如果要添加blog的話,首先要做的是預(yù)處理category。
           1 private void preAdd(HttpServletRequest request, HttpServletResponse response)
           2             throws ServletException, IOException {
           3         List categories = null;
           4         String sql = "select id,name from category order by name";
           5         QueryRunner qr = DbHelper.getQueryRunner();
           6         try {
           7             categories = (List) qr.query(sql, new BeanListHandler(Category.class));
           8         } catch (SQLException ex) {
           9             Logger.getLogger(BlogServlet.class.getName()).log(Level.SEVERE, null, ex);
          10         }
          11         request.setAttribute("categories", categories);
          12         request.getRequestDispatcher("/admin/addBlog.jsp").forward(request, response);
          13     }
          從code上看,預(yù)處理與blog類并沒有關(guān)系,而是針對(duì)category的。

          在list所有blog記錄的時(shí)候,我們同樣要考慮到category信息,
           1 private void list(HttpServletRequest request, HttpServletResponse response)
           2             throws ServletException, IOException {
           3         String sql = "select b.id as id,title,content,date,c.name as category, c.id as categoryId from blog b,category c where category_id=c.id order by b.date desc";
           4         QueryRunner qr = DbHelper.getQueryRunner();
           5         List blogs = null;
           6         try {
           7             blogs = (List) qr.query(sql, new BeanListHandler(Blog.class));
           8         } catch (SQLException ex) {
           9             Logger.getLogger(BlogServlet.class.getName()).log(Level.SEVERE, null, ex);
          10         }
          11         request.setAttribute("blogs", blogs);
          12         request.getRequestDispatcher("/admin/adminBlogList.jsp").forward(request, response);
          13     }
          第3行的sql語句將blog表與category表關(guān)聯(lián)起來,運(yùn)行該SQL命令也成功找到相應(yīng)的數(shù)據(jù);但是在程序里,對(duì)應(yīng)的JSP顯示卻不成功,與blog相關(guān)的數(shù)據(jù)正確,但是與categoryId對(duì)應(yīng)的
          category name(程序中的Blog類里的category)沒有顯示出來,數(shù)據(jù)顯示是null。
          這是因?yàn)镈bUtils 在做表到對(duì)象的映射時(shí)要求列名和對(duì)象的屬性名必須一致,也就是說對(duì)應(yīng)blog類里的category屬性正確的名稱應(yīng)該是name。
          所以當(dāng)
          String sql = "select b.id as id,title,content,date,c.name as category, c.id as categoryId from blog b,category c where category_id=c.id order by b.date desc";
          QueryRunner不能將數(shù)據(jù)映射到category屬性里。在發(fā)現(xiàn)并解決了DbUtils項(xiàng)目的一個(gè)問題指出,問題的關(guān)鍵是DbUtils在處理數(shù)據(jù)表的時(shí)候是使用getColumnName()方法
          BasicRowProcessor.java
           1 /** 
           2      * Convert a <code>ResultSet</code> row into a <code>Map</code>.  This 
           3      * implementation returns a <code>Map</code> with case insensitive column
           4      * names as keys.  Calls to <code>map.get("COL")</code> and 
           5      * <code>map.get("col")</code> return the same value.
           6      * @see org.apache.commons.dbutils.RowProcessor#toMap(java.sql.ResultSet)
           7      */
           8     public Map toMap(ResultSet rs) throws SQLException {
           9         Map result = new CaseInsensitiveHashMap();
          10         ResultSetMetaData rsmd = rs.getMetaData();
          11         int cols = rsmd.getColumnCount();
          12 
          13         for (int i = 1; i <= cols; i++) {
          14             result.put(rsmd.getColumnName(i), rs.getObject(i));
          15         }
          16 
          17         return result;
          18     }
          BeanProcessor.java
           1     /**
           2      * The positions in the returned array represent column numbers.  The 
           3      * values stored at each position represent the index in the 
           4      * <code>PropertyDescriptor[]</code> for the bean property that matches 
           5      * the column name.  If no bean property was found for a column, the 
           6      * position is set to <code>PROPERTY_NOT_FOUND</code>.
           7      * 
           8      * @param rsmd The <code>ResultSetMetaData</code> containing column 
           9      * information.
          10      * 
          11      * @param props The bean property descriptors.
          12      * 
          13      * @throws SQLException if a database access error occurs
          14      *
          15      * @return An int[] with column index to property index mappings.  The 0th 
          16      * element is meaningless because JDBC column indexing starts at 1.
          17      */
          18     protected int[] mapColumnsToProperties(ResultSetMetaData rsmd,
          19             PropertyDescriptor[] props) throws SQLException {
          20 
          21         int cols = rsmd.getColumnCount();
          22         int columnToProperty[] = new int[cols + 1];
          23         Arrays.fill(columnToProperty, PROPERTY_NOT_FOUND);
          24 
          25         for (int col = 1; col <= cols; col++) {
          26             String columnName = rsmd.getColumnName(col);
          27             for (int i = 0; i < props.length; i++) {
          28 
          29                 if (columnName.equalsIgnoreCase(props[i].getName())) {
          30                     columnToProperty[col] = i;
          31                     break;
          32                 }
          33             }
          34         }
          35 
          36         return columnToProperty;
          37     }
          以上2段程序 讀了就會(huì)發(fā)現(xiàn)問題所在了。DbUtils利用getColumnName()來處理列名,所以類似c.name as category, c.id as categoryId的語句并不適用與DbUtils。
          解決的方法就是將以上2段程序中的getColumnName()方法改成getColumnLabel(),然后重新編譯DbUtils源文件。然后將fixed的DbUtils文件重新加入庫就可以解決問題了。
          commons-dbutils-1.2_fixed.jar

          BlogServlet中其他方法就不一一介紹了。





          posted @ 2009-09-29 13:52 Chucky 閱讀(121) | 評(píng)論 (0)編輯 收藏

          僅列出標(biāo)題
          共4頁: 上一頁 1 2 3 4 下一頁 
          主站蜘蛛池模板: 略阳县| 区。| 商丘市| 镇安县| 绍兴县| 来安县| 青海省| 威宁| 青阳县| 西乡县| 乌兰察布市| 秦皇岛市| 离岛区| 望奎县| 墨脱县| 双峰县| 竹北市| 西宁市| 达拉特旗| 龙岩市| 从化市| 柳江县| 无棣县| 电白县| 三台县| 家居| 四川省| 瓦房店市| 喀什市| 福贡县| 亳州市| 阿合奇县| 竹溪县| 综艺| 安乡县| 买车| 南投县| 永吉县| 平顶山市| 民和| 仁化县|