相對于上一篇的CategoryServlet,BlogServlet相對復雜一些。
不如在做添加博文的時候,我們要考慮的不僅僅是blog本身的主題,內容還要考慮blog所對應的類別;
一般我們把類別做成一個List以供選擇。所以在blog添加的前,我們首先要處理category信息,那么
如果要添加blog的話,首先要做的是預處理category。
在list所有blog記錄的時候,我們同樣要考慮到category信息,
category name(程序中的Blog類里的category)沒有顯示出來,數據顯示是null。
這是因為DbUtils 在做表到對象的映射時要求列名和對象的屬性名必須一致,也就是說對應blog類里的category屬性正確的名稱應該是name。
所以當
BasicRowProcessor.java
解決的方法就是將以上2段程序中的getColumnName()方法改成getColumnLabel(),然后重新編譯DbUtils源文件。然后將fixed的DbUtils文件重新加入庫就可以解決問題了。
commons-dbutils-1.2_fixed.jar
BlogServlet中其他方法就不一一介紹了。
不如在做添加博文的時候,我們要考慮的不僅僅是blog本身的主題,內容還要考慮blog所對應的類別;
一般我們把類別做成一個List以供選擇。所以在blog添加的前,我們首先要處理category信息,那么
如果要添加blog的話,首先要做的是預處理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上看,預處理與blog類并沒有關系,而是針對category的。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 }
在list所有blog記錄的時候,我們同樣要考慮到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表關聯起來,運行該SQL命令也成功找到相應的數據;但是在程序里,對應的JSP顯示卻不成功,與blog相關的數據正確,但是與categoryId對應的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 }
category name(程序中的Blog類里的category)沒有顯示出來,數據顯示是null。
這是因為DbUtils 在做表到對象的映射時要求列名和對象的屬性名必須一致,也就是說對應blog類里的category屬性正確的名稱應該是name。
所以當
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不能將數據映射到category屬性里。在發現并解決了DbUtils項目的一個問題指出,問題的關鍵是DbUtils在處理數據表的時候是使用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
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 }
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段程序 讀了就會發現問題所在了。DbUtils利用getColumnName()來處理列名,所以類似c.name as category, c.id as categoryId的語句并不適用與DbUtils。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段程序中的getColumnName()方法改成getColumnLabel(),然后重新編譯DbUtils源文件。然后將fixed的DbUtils文件重新加入庫就可以解決問題了。
commons-dbutils-1.2_fixed.jar
BlogServlet中其他方法就不一一介紹了。