相对于上一篇的CategoryServlet,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的。
在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对应的
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
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段程序中的getColumnName()方法改成getColumnLabel(),然后重新编译DbUtils源文件。然后将fixed的DbUtils文件重新加入库就可以解决问题了。
commons-dbutils-1.2_fixed.jar
BlogServlet中其他方法就不一一介绍了。