两亩三分地

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  17 随笔 :: 20 文章 :: 2 评论 :: 0 Trackbacks

2009年10月5日 #

     摘要: 之前项目有个模块要求用树形解决,附带要实现checkbox,增删修改以及copy/cut/paste等等功能; 因为之前写的人用了xloadTree,其他功能都实现了,但是客户要求要有cookie功能,实现不了麻烦啊~ 正巧现在在学习用Ext,发现Ext的tree本身就很强大基本的功能都可以实现。 Code highlighting produced by Actipro Cod...  阅读全文
posted @ 2010-08-08 23:17 Chucky 阅读(1950) | 评论 (0)编辑 收藏

Border布局作为Ext中整个框架的布局应该说很普遍,一般North放一个应用的Logo bar,West一般会作为导航栏的放置位置;
而Center(East)往往作为整个应用的核心部分,而South位置也往往放置一些应用的版权等信息。

而导航栏一般会采用的呈现方式一般无非是Treepanel或者根据模块放置多个Panel,而多数会采用的布局方式,往往是
Accordion的布局。比如像这样(偷个懒直接用设计器写的):
MyViewportUi = Ext.extend(Ext.Viewport, {
    layout: 'border',
    initComponent: 
function() {
        
this.items = [
            {
                xtype: 'panel',
                title: 'north',
                region: 'north'
            },
            {
                xtype: 'panel',
                title: 'west',
                region: 'west',
                width: 
201,
                split: 
true,
                layout: 'accordion',
                activeItem: 
0,
                items: [
                    {
                        xtype: 'panel',
                        title: 'panel1',
                        layout: 'column',
                        width: 
180,
                        items: [
                            {
                                xtype: 'button',
                                text: 'Button1',
                                scale: 'large'
                            },
                            {
                                xtype: 'button',
                                text: 'Button2',
                                scale: 'large'
                            },
                            {
                                xtype: 'button',
                                text: 'Button3',
                                scale: 'large'
                            },
                            {
                                xtype: 'button',
                                text: 'Button4',
                                scale: 'large'
                            },
                            {
                                xtype: 'button',
                                text: 'Button5',
                                scale: 'large'
                            },
                            {
                                xtype: 'button',
                                text: 'Button6',
                                scale: 'large'
                            }
                        ]
                    },
                    {
                        xtype: 'panel',
                        title: 'panel2'
                    },
                    {
                        xtype: 'panel',
                        title: 'panel3'
                    }
                ]
            },
            {
                xtype: 'panel',
                title: 'east',
                region: 'center'
            },
            {
                xtype: 'panel',
                title: 'south',
                region: 'south'
            }
        ];
        MyViewportUi.superclass.initComponent.call(
this);
    }
});
一个基本的框架就产生了,而问题也随之而来。最主要的问题是IE和FF显示不一样。应该说FF显示很正常,按键根据导航栏的大小,改变每一行显示的数量;
而IE呢,在第一次导航栏宽带变大的时候,一切正常;而当导航栏宽度缩小的时候,原来每行的按键数却并不变。想想这Ext都3.2了,不会还有这么脑残的bug吧;
google了下,国内似乎对这个问题也没有什么讨论的;于是直接去官网的论坛问。

最初别人的提议是,更改westPanel的属性
layout: {
    type: 'accordion',
    autoWidth: 
false
}
等于禁止westPanel的子栏目自动变化宽度,试了如果westPanel的子栏目只有一个工作正常,但是如果多个的话,又悲剧了~

因为每次只有1个子栏目的宽度在变化,所以产生这个问题也不足为奇了。

最后某个网友提供了一个自己写的补丁,问题解决了。
Ext.layout.AccordionPatch = Ext.extend(Ext.layout.Accordion, {
    
    inactiveItems: [],
//ADDED

    
// private
    onLayout : function(ct, target){//ADDED
        Ext.layout.AccordionPatch.superclass.onLayout.call(this, ct, target);
        
if(this.autoWidth === false) {
            
for(var i = 0; i < this.inactiveItems.length; i++) {
                
var item = this.inactiveItems[i];
                item.setSize(target.getStyleSize());
            }
        }
    },
    
// private
    beforeExpand : function(p, anim){//MODFIED
        var ai = this.activeItem;
        
if(ai){
            
if(this.sequence){
                
delete this.activeItem;
                ai.collapse({callback:
function(){
                    p.expand(anim 
|| true);
                }, scope: 
this});
                
return false;
            }
else{
                ai.collapse(
this.animate);
                
if(this.autoWidth === false && this.inactiveItems.indexOf(ai) == -1)//*****
                    this.inactiveItems.push(ai);//*****
            }
        }
        
this.activeItem = p;
        
if(this.activeOnTop){
            p.el.dom.parentNode.insertBefore(p.el.dom, p.el.dom.parentNode.firstChild);
        }
        
if(this.autoWidth === false && this.inactiveItems.indexOf(this.activeItem) != -1)//*****
            this.inactiveItems.remove(this.activeItem);//*****
        this.layout();
    }
    
});

Ext.Container.LAYOUTS['accordionpatch'] 
= Ext.layout.AccordionPatch; 
配合补丁,westPanel的属性也要有相应的变化
layout: {
    type:
'accordionpatch',
    autoWidth: false
}




posted @ 2010-08-07 13:24 Chucky 阅读(313) | 评论 (0)编辑 收藏

     摘要: 发表,浏览,回复之后,我们将讨论的是删除和编辑留言。 因为这个只是一个简单的留言板,没有用户认证之类繁琐的事情,所以对于编辑和删除留言,必须输入 正确的id号和password;如果在发表或回复留言的时候没有输入密码的话,就不能对留言进行编辑或者删除。 这里将写的EditAction class与之前的有所不同,extends org.apache.struts.actions.Dispat...  阅读全文
posted @ 2009-10-29 17:22 Chucky 阅读(231) | 评论 (0)编辑 收藏

整个项目第二个重点就是回复留言,我的思路是在浏览留言的时候,回复键传送主题的ID,一个Action Class处理这个请求,
将与这个ID相关的留言查询出来,写入ActionForm。
  1. 打开display.jsp文件,找到下面这几行,后面添加一个form,用来提交查询请求。
     1 <table>
     2     <tr>
     3         <td>
     4             <bean:write name="topic" property="post.subject"/> 留言者:<bean:write name="topic" property="post.name" /> 留言日:<bean:write name="topic" property="post.date" format="yyyy/MM/dd(E) HH:mm" />  No.<bean:write name="topic" property="post.id" />
     5         </td>
     6         <td>
     7             <html:form action="read">
     8                 <input type="hidden" name="id" value="<bean:write name='topic' property='post.id'/>"/>
     9               <html:submit value="回复" />
    10             </html:form>
    11       </td>
    12    </tr>
    13   </table>
    6-11行,就是新加入的对id的一个请求,这里我用了普通的html标志来提交请求,当然我们也可以用<html:hidden name="topic" property="post.id"/>,但是在处理请求的时候,相对的request.getParameter("id"),就要换成
    request.getParameter("post.id")了;或者我们可以在那个Topic类里,添加一个id字段,那么在浏览留言的时候(ListAction的execute方法,list.add(new Topic(post,replies)); 改成list.add(new Topic(post,replies,post.getId()));)<html:hidden name="topic" property="id"/>也可以这样用了。

  2. 添加一个ActionForm bean ThreadForm.java,除了记录一段留言外,还包括了行将用以回复的留言的预处理;
     1 public class ThreadForm extends org.apache.struts.action.ActionForm {
     2     
     3     private int id;
     4     private String name;
     5     private String subject;
     6     private String content;
     7     private String url;
     8     private String email;
     9     private int iconId;
    10     private String icon;
    11     private String password;
    12     private int replyId;
    13     private String font;
    14 
    15     private List icons;
    16 
    17     private Topic topic;
    18 
    19     // accessor methods..
    20     
    21 
    22     public ThreadForm() {
    23         super();
    24         // TODO Auto-generated constructor stub
    25         setUrl("http://");
    26         setFont("#800000");
    27         String sql = "select id,name,src from icon order by id";
    28         QueryRunner qr = DbHelper.getQueryRunner();
    29         List list = null;
    30         try {
    31             list = (List) qr.query(sql, new BeanListHandler(Icon.class));
    32             // TODO Auto-generated constructor stub
    33         } catch (SQLException ex) {
    34             Logger.getLogger(ThreadForm.class.getName()).log(Level.SEVERE, null, ex);
    35         }
    36         setIcons(list);
    37     }
    38     
    39   
    40 }
    41
    3-15行是负责对回复的预处理,ThreadForm()方法中主要也是处理图标。

  3. 这个回复过程其实是2部,1.预处理:包括列出与ID相关的留言,预设回复的默认标题以及对应的回复id (replyId);2.回复留言,添加记录。
    a.  PreReplyAction.java
    public class PreReplyAction extends org.apache.struts.action.Action {
        
        
    /* forward name="success" path="" */
        
    private static final String SUCCESS = "bbs.read";
        
        
    /**
         * This is the action called from the Struts framework.
         * 
    @param mapping The ActionMapping used to select this instance.
         * 
    @param form The optional ActionForm bean for this request.
         * 
    @param request The HTTP Request we are processing.
         * 
    @param response The HTTP Response we are processing.
         * 
    @throws java.lang.Exception
         * 
    @return
         
    */
        @Override
        
    public ActionForward execute(ActionMapping mapping, ActionForm form,
                HttpServletRequest request, HttpServletResponse response)
               {
            ThreadForm f 
    = (ThreadForm) form;
            String id 
    = (String) request.getParameter("id");
            String sql;
            QueryRunner qr 
    = DbHelper.getQueryRunner();
            
            List list 
    = null;
            sql 
    = "select * from guestbook where id = " + id;
            
    try {
                list 
    = (List) qr.query(sql, new BeanListHandler(Post.class));
            } 
    catch (SQLException ex) {
                Logger.getLogger(PreReplyAction.
    class.getName()).log(Level.SEVERE, null, ex);
            }
            Post post 
    = null;
            post 
    = (Post)list.get(0);
            List replies 
    = null;
            sql 
    = "select * from guestbook where replyId =" + id + " order by id";
            
    try {
                replies 
    = (List) qr.query(sql, new BeanListHandler(Post.class));
            } 
    catch (SQLException ex) {
                Logger.getLogger(PreReplyAction.
    class.getName()).log(Level.SEVERE, null, ex);
            }
            
            Topic topic 
    = new Topic(post,replies);
            f.setTopic(topic);
            f.setSubject(
    "Re :" + post.getSubject());
            f.setReplyId(post.getId());

            
    return mapping.findForward(SUCCESS);
        }
    }

    b. ReplyAction.java
     1 public class ReplyAction extends org.apache.struts.action.Action {
     2     
     3     /* forward name="success" path="" */
     4     private static final String SUCCESS = "bbs.reply";
     5     
     6     /**
     7      * This is the action called from the Struts framework.
     8      * @param mapping The ActionMapping used to select this instance.
     9      * @param form The optional ActionForm bean for this request.
    10      * @param request The HTTP Request we are processing.
    11      * @param response The HTTP Response we are processing.
    12      * @throws java.lang.Exception
    13      * @return
    14      */
    15     @Override
    16     public ActionForward execute(ActionMapping mapping, ActionForm form,
    17             HttpServletRequest request, HttpServletResponse response)
    18             throws Exception {
    19         ThreadForm f = (ThreadForm)form;
    20         String sql = "insert into guestbook (name,subject,email,url,content,iconId,password,font,replyId,date,lastReplyTime) " +
    21                 "values(?,?,?,?,?,?,?,?,?,now(),now())";
    22         String content = f.getContent();
    23         content = content.replaceAll(" ""&nbsp;");
    24         content = content.replaceAll("\n","<br>");
    25         String params[] = {f.getName(),f.getSubject(),f.getEmail(),f.getUrl(),content,new Integer(f.getIconId()).toString(),f.getPassword(),f.getFont(),new Integer(f.getReplyId()).toString()};
    26 
    27         QueryRunner qr = DbHelper.getQueryRunner();
    28         try {
    29             qr.update(sql, params);
    30         } catch (SQLException ex) {
    31             Logger.getLogger(ReplyAction.class.getName()).log(Level.SEVERE, null, ex);
    32         }
    33        sql = "update guestbook set lastReplyTime= now() where id = " + f.getReplyId();
    34         try {
    35             qr.update(sql);
    36         } catch (SQLException ex) {
    37             Logger.getLogger(ReplyAction.class.getName()).log(Level.SEVERE, null, ex);
    38         }
    39         return mapping.findForward(SUCCESS);
    40     }
    41 }
    这个基本和添加留言的一直,只是在insert回复记录以后,更新主题留言的最近的回复时间,可以保证浏览留言的时候,该主题能在最前端。

  4. reply.jsp 基本和之前写的jsp页面区别不大,省略了。

  5. 添加相应的forwarding信息。
    <global-forwards>
            
    <forward name="bbs.post" path="/result.jsp"/>
            
    <forward name="bbs.list" path="/display.jsp"/>
            
    <forward name="bbs.read" path="/reply.jsp" />
            
    <forward name="bbs.reply" path="/list.do" />
            
    <forward name="welcome"  path="/Welcome.do"/>
    </global-forwards>
    根据forward的指向,我们可以看到在reply.jsp按下回复键以后,直接转向list.do动作。
    至于action-mapping 没有什么要注意的。

  6. 整个回复过程就此完成。

posted @ 2009-10-28 13:14 Chucky 阅读(339) | 评论 (0)编辑 收藏

     摘要: 既然我们已经成功完成了第一个ActionForm Bean和与之相关的Action Class;后面的专题中将不再详细的去写与他们相关的开发步骤了。 现在我们开始写留言板的主体部分,即对整个留言就行浏览。因为每个post都有一个replyId字段,用来对应其所回复的留言id;如果这个 replyId等于-1的话,即该留言没有对应的回复。好了还是先从这个JSP页面写起。 displ...  阅读全文
posted @ 2009-10-23 17:40 Chucky 阅读(257) | 评论 (0)编辑 收藏

PostAction主要是处理留言添加工作。
  1. 和创建NewForm bean一样,点击Source Packages > com.bbs.struts,右键New > Java Package... 创建一个com.bbs.struts.action的package用于存放所有action类;

  2. 右键com.bbs.struts.action, New > Struts Action...如果New菜单里没有的话,选择other...,categories里选择
    Struts,File types一栏里选择Struts Action ...;

  3. 在New Struts Action面板里面,Class Name填PostAction;Action Path 填/post;按Next


  4. 按照下面的设置,完成对Action的设置


  5. 在struts-config.xml的文档中,IDE自动添加了对PostForm的声明。
    <action-mappings>
            
    <action input="/post.jsp" name="NewForm" path="/post" scope="request" type="com.bbs.struts.action.PostAction"/>
            
    <action path="/Welcome" forward="/welcomeStruts.jsp"/>
    </action-mappings>

  6. 右边的Source Editor中,新建的PostAction.java已经打开了;接下来我们要把记录在NewForm bean里的数据保存进数据库,为了测试的需要,在添加数据以后,将添加成功与否的结果显示在result.jsp上面。
     1     public ActionForward execute(ActionMapping mapping, ActionForm form,
     2             HttpServletRequest request, HttpServletResponse response) {
     3         NewForm f = (NewForm) form;
     4         String sql = "insert into guestbook (name,subject,email,url,content,iconId,password,font,replyId,date,lastReplyTime) " +
     5                 " values(?,?,?,?,?,?,?,?,-1,now(),now())";
     6 
     7         String content = f.getContent();
     8         content = content.replaceAll(" ""&nbsp;");
     9         content = content.replaceAll("\n""<br>");
    10 
    11         String params[] = {f.getName(), f.getSubject(), f.getEmail(), f.getUrl(), content, new Integer(f.getIconId()).toString(), f.getPassword(), f.getFont()};
    12 
    13         QueryRunner qr = DbHelper.getQueryRunner();
    14 
    15         String result = null;
    16         try {
    17             if (qr.update(sql, params) == 1){
    18                 result = "更新成功";
    19             }else{
    20                 result = "更新失败";
    21             }
    22         } catch (SQLException ex) {
    23             Logger.getLogger(PostAction.class.getName()).log(Level.SEVERE, null, ex);
    24         }
    25         f.setResult(result);
    26         return mapping.findForward(SUCCESS);
    27     }
    7,8,9行主要是将content里的空格和回车符号转成html中所对应的空格和回车。

  7. 在PostAction.java,IDE自动给我们设置了一个 private static final String SUCCESS = "success"; 这是为action forward所设置的forward标志,success的名称我们可以自己取,比如我们可以把它改成bbs.post。关键是在结束对这个action class的编程以后,我们需要在struts-config.xml中添加forward声明。在source editor中打开struts-config.xml,右键菜单Struts > Add Forward,在Add Forward的面板里如下设置,按Add完成添加。

按F6 运行项目,浏览器输入:http://localhost:8080/BBS/post.jsp对程序进行测试。如果添加成功的话,下一页将有更新成功的字样。
posted @ 2009-10-23 00:31 Chucky 阅读(439) | 评论 (0)编辑 收藏

ActionForm Bean在Struts里用来保存网页request传递之间的数据。比如我们现在写的NewForm Bean用来收集表格内的信息,
类似于servlet的request.getParamenter()的作用;当用户提交以后,数据将保存在bean内,然后再做处理。
  1. 点击Source Packages > com.bbs.struts,右键New > Java Package... 创建一个com.bbs.struts.form的package用于存放
    所有form;

  2. 右键com.bbs.struts.form, New > Struts ActionForm Bean...如果New菜单里没有的话,选择other...,categories里选择
    Struts,File types一栏里选择Struts ActionForm Bean...;

  3. 为这个ActionForm取名叫NewForm,然后按Finish完成。
    IDE将创建一个NewForm bean,并在右边的Source Editor里面打开它。默认的话,IDE将创造2个一个String型的name和int型的number,2个属性;并且定义了它们的accessor方法。另外IDE将在struts-config.xml里面,添加对这个bean的声明;
    <form-beans>
            
    <form-bean name="NewForm" type="com.bbs.struts.form.NewForm"/>
    </form-beans>

  4. 在Source Editor里面,将原来的name,number字段删除,并删除与之相关的accessor方法。然后为NewForm添加以下字段,这些字段与之前的post.jsp所用到的字段一一对应。
        private String name;
        
    private String subject;
        
    private String content;
        
    private String url;
        
    private String email;
        
    private int iconId;
        
    private String password;
        
    private String font;

        
    private List icons;
        
    private String result;
    利用insert code...功能,添加相应的accessor方法。

  5. 考虑到因为图标的列其实在生成这个网页的时候就自动添加的,所以在这个ActionForm bean的Constructor的方法里面,就要处理icon了,还有就是对字色,网络链接做一下预处理:
        public NewForm() {
            
    super();
            
    // TODO Auto-generated constructor stub
            setUrl("http://");
            setFont(
    "#800000");
            String sql 
    = "select id,name,src from icon order by id";
            QueryRunner qr 
    = DbHelper.getQueryRunner();
            List list 
    = null;
            
    try {
                list 
    = (List) qr.query(sql, new BeanListHandler(Icon.class));
                
    // TODO Auto-generated constructor stub
            } catch (SQLException ex) {
                Logger.getLogger(NewForm.
    class.getName()).log(Level.SEVERE, null, ex);
            }
            setIcons(list);
        }

  6. 同样在validate方法里,添加对subject验证,如果subject为空的话,改名“无题”。
       public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) {
            ActionErrors errors 
    = new ActionErrors();

            
    if (getSubject() == null || getSubject().length() < 1) {
                setSubject(
    "无题");
            }
            
    return errors;
        }

  7. 第一个ActionForm Bean就完成了。

posted @ 2009-10-22 23:15 Chucky 阅读(219) | 评论 (0)编辑 收藏


之前的准备工作完成,现在算是正式进入struts项目的环节了,首先我们写一个发表留言的jsp页面。
  1. 右键点击BBS项目, 选择 New > JSP, 命名新文件为post. 点击Finish. post.jsp将在右边的编辑器里打开了。

  2. 首先在编辑器中,将<title></title>中间的文字改成发表留言。

  3. 在文件顶部,添加以下2个taglib:
    <%@taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
    <%@taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
    bean tag为用户提供了若干tag,主要针对表单中form bean;html tag用来代替普通的html标签,达到简化操作的目的。

  4. 在<body>里面添加:
    <html:form action="post">

    </html:form>

  5. 从IDE的Palette面板的HTML的分类里将Table拉入<html:form action="post">之间,设置rows 8, columns 2。

  6. 在<td>之间添加数值
    <html:form action="post">
                
    <table border="1">
                    
    <tbody>
                        
    <tr>
                            
    <td>名字</td>
                            
    <td><html:text property="name" /></d>
                        
    </tr>
                        
    <tr>
                            
    <td>邮件</td>
                            
    <td><html:text property="email" /></td>
                        
    </tr>
                        
    <tr>
                            
    <td>题目</td>
                            
    <td><html:text property="subject" /> <html:submit value="发送"/><html:cancel value="重置"/></td>
                        
    </tr>
                        
    <tr>
                            
    <td colspan="2">正文<br>
                                
    <html:textarea cols="60" rows="8" property="content" />
                            
    </td>
                        
    </tr>
                        
    <tr>
                            
    <td>网站</td>
                            
    <td><html:text property="url"/></td>
                        
    </tr>
                        
    <tr>
                            
    <td>图标</td>
                            
    <td>
                                
    <html:select property="iconId">
                                    
    <logic:iterate id="icon" name="NewForm" property="icons">
                                     
    <option value="<bean:write name='icon' property='id'/>"><bean:write name="icon" property="name"/></option>
                                    
    </logic:iterate>
                                
    </html:select>
                            
    </td>
                        
    </tr>
                        
    <tr>
                            
    <td>密码</td>
                            
    <td><html:password property="password"/>(英数8文字内)</td>
                        
    </tr>
                        
    <tr>
                            
    <td>字色</td>
                            
    <td>
                                
    <html:radio property="font" value="#800000"><font color="#800000"></font></html:radio>
                                
    <html:radio property="font" value="#DF0000"><font color="#DF0000"></font></html:radio>
                                
    <html:radio property="font" value="#008040"><font color="#008040"></font></html:radio>
                                
    <html:radio property="font" value="#0000FF"><font color="#0000FF"></font></html:radio>
                                
    <html:radio property="font" value="#C100C1"><font color="#C100C1"></font></html:radio>
                                
    <html:radio property="font" value="#FF80C0"><font color="#FF80C0"></font></html:radio>
                                
    <html:radio property="font" value="#FF8040"><font color="#FF8040"></font></html:radio>
                                
    <html:radio property="font" value="#000080"><font color="#000080"></font></html:radio>
                            
    </td>
                        
    </tr>
                    
    </tbody>
                
    </table>
            
    </html:form>
        
    </body>

    第一个JSP页面就完成了。
考虑到后面的测试,再创建一个result.jsp页面;当post成功/失败的话,通过result.jsp来查看结果
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
   "http://www.w3.org/TR/html4/loose.dtd"
>
<%@taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
<html>
    
<head>
        
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        
<title>留言板</title>
    
</head>
    
<body>
        
<h1><bean:write name="NewForm" property="result" /></h1>
    
</body>
</html>



posted @ 2009-10-21 18:20 Chucky 阅读(219) | 评论 (0)编辑 收藏

正如之前所说的,开发一个struts应用和一般的web应用并没有什么两样。

1. 创建数据库
create database guestbook;

a. guestbook表:用于记录留言的所有信息
CREATE TABLE `guestbook` (
`id`  
int(11NOT NULL AUTO_INCREMENT ,
`name`  
varchar(40) ,
`email`  
varchar(60),
`url`  
varchar(60),
`subject`  
varchar(200),
`content`  
varchar(1024),
`font`  
varchar(100),
`date`  
datetime ,
`replyId`  
int(11)DEFAULT '-1' ,
`iconId`  
int(3),
`lastReplyTime`  
datetime ,
`password`  
varchar(16),
PRIMARY KEY (`id`)
);

 字段 说明
 id  留言编号
 name  留言人姓名
 email  email地址
 url  url地址
 subject  留言标题
 content  留言内容
 iconId  留言使用的表情图标编号
 font  内容字体颜色
 date  留言时间
 replyId  回复留言ID,默认为-1表示不是回复
 lastReplyTime  最近回复时间
 password  留言所用的密码(用于编辑)

b. ICON表:用于记录所有的图标记录
CREATE TABLE `icon` (
`id`  
int(11NOT NULL AUTO_INCREMENT ,
`name`  
varchar(20),
`src`  
varchar(200),
`alt`  
varchar(100),
PRIMARY KEY (`id`)
);

 字段 说明
 id  图标编号
 name  图标名称
 src  图标的位置
 alt  图标的说明

2. JDBC Resource与链接池
  • 给刚刚建的database建立一个连接,Services标签,点击Databases的MySql Server at localhost:3306;
  • 选择刚刚建的guestbook,按右键点击connect;我们可以看到在databases的列表里多了jdbc:mysql://localhost:3306/guestbook的链接;
  • 回到projects标签,点击项目名称BBS,按右键选择New > Other... 在Categories里面选择GlassFish;File types项目下面,选择JDBC Connection Pool,按Next;
  • 在New JDBC Connection Pool面板里,JDBC Connection Pool Name里输入GuestBookPool(随意),Extract from Existiong Connection的下拉菜单里选择刚刚建立的database连接jdbc:mysql://localhost:3306/guestbook,
    其他设置使用默认值即可,按finish结束连接池的创建。
  • 同样在Categories里面选择GlassFish;File types项目下面,选择JDBC Resource,按Next;
  • 在New JDBC Resource面板里,Using Existing JDBC Connection Pool里选择GuestBookPool(与之前创建的连接池对应);
    JNDI Name输入jdbc/bbs(随意),按finish,完成JDBC Resource配置。
3.中文乱码处理 
  记得在做上一个Servlet的项目的时候,在每个servlet处理request的时候(processRequest()方法),都做过一个request.setCharacterEncoding("UTF-8")的操作;将request的内容转成UTF-8的内码,以解决中文乱码问题。
  在Struts的项目里面,我们仍然会遇到中文乱码问题。而我们通过一个创建的CharacterEncodingFilter的辅助类来解决问题。
  •   CharacterEncodingFilter.java
    package com.bbs.struts.util;

    import java.io.IOException;
    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;

    /**
     *
     * 
    @author Chucky
     
    */
    public class CharacterEncodingFilter implements Filter {

        
    public void init(FilterConfig filterConfig) throws ServletException {
        }

        
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
            request.setCharacterEncoding(
    "UTF-8");
            chain.doFilter(request, response);
        }

        
    public void destroy() {

        }

    }
     
  • 打开web.xml,在Filters的面板中添加以下内容
中文乱码的问题解决了!

4. DbUtils
在处理数据连接的问题上,还是使用DbUtils这个类,详细请看Blog系统开发 5. JDBC的基本操作与DbUtils的使用 内容
这里还是写一个DbHelper的辅助类,来简化连接的操作。
DbHelper.java
package com.bbs.struts.util;

import java.util.logging.Level;
import java.util.logging.Logger;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
import org.apache.commons.dbutils.QueryRunner;

/**
 *
 * 
@author Chucky
 
*/
public class DbHelper {

    
public static QueryRunner getQueryRunner() {
        Context context 
= null;
        DataSource ds 
= null;
        
try {
            context 
= new InitialContext();
            ds 
= (DataSource) context.lookup("jdbc/bbs");
        } 
catch (NamingException ex) {
            Logger.getLogger(DbHelper.
class.getName()).log(Level.SEVERE, null, ex);
        }

        QueryRunner qr 
= new QueryRunner(ds);
        
return qr;
    }
}
注意context.lookup()中的数据源,要与之前的数据源匹配。

因为这个bbs的网页设计是按照日月星辰的留言板的页面制作的,所以类似icon之类的数据,直接添加到数据库(假设所有的icon都在
img 目录下,icon素材可以直接到星辰去抓的,sql的脚本)


posted @ 2009-10-21 17:31 Chucky 阅读(419) | 评论 (0)编辑 收藏

根据之前所建立的guestbook表和icon表;现在我们建立Icon类和Post类;
1. Icon类 Icon.java
public class Icon {
    
private int id;
    
private String name;
    
private String src;
    
private String alt;
}
在Icon.java的Source Editor上按右键,点击Insert Code... 选择Getter and Setter...;
在Generate Getter and Setter面板内,选择所有的属性;IDE将自动生成setter/getter方法。

同样建立一个Post类,除了原来guestbook里的字段以外,为了编程的方便再添加一个Icon的属性,相当于Icon类里的src值。
public class Post{
    private
 int id;
    
private String name;
    
private String subject;
    
private String content;
    
private String url;
    
private String email;
    
private int iconId;
    
private String icon;
    
private String password;
    
private Date date;
    
private Date lastReplyTime;
    
private int replyId;
    
private String font;
}
添加相应的getter/setter方法。

除了以上2个类,再建一个Topic类,这个类是一个post和它所有回复的一个集合。
public class Topic {
    
private Post post;
    
private List replies;
}
添加相应的getter/setter方法。




posted @ 2009-10-21 17:05 Chucky 阅读(217) | 评论 (0)编辑 收藏

在使用Netbeans的时候,除了Struts应用所需需要的Struts库文件与配置文件以外,创建一个Struts应用与
创建其他任何一个网络应用没有什么区别。其实创建一个Struts应用的方法和任何一个其他网络应用的方法
都一样。
  • 选择File > New Project. 在Categories里面选择Web。Projects项目下面,选择Web Application然后按Next。
  • 在输入项目名称和位置的面板里面,输入BBS作为项目名称,然后按Next;
  • 在服务器与设置面板里面,选择选择一个你准备用来deploy应用的服务器(如:GlassFish v2.1),同时注意面板下方的
    Context Path的路径与我们的项目名称一致,按Next;
  • 在Framework面板里,选择Struts

    将Application Resource里的名称com.myapp.struts.ApplicationResource改成com.bbs.struts.ApplicationResource .
  • 按下Finish,Struts的一个应用就建立完成了。
在项目管理器里面,所有的Struts指定的配置文件以及应用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 阅读(195) | 评论 (0)编辑 收藏

到16节 和项目相关的东西,觉得已经没什么要写的了;基本还剩下一些css之类的页面设计和美化工作。
这方面没有什么感觉,总之把跟这个项目相关的东西放在一起(src和web相关的东西);有兴趣可以下来看看。
blog_servlet

Ok 跟blog_servlet相关的东西到这里结束了,下周开始做blog Struts相关的项目。

posted @ 2009-10-08 19:04 Chucky 阅读(103) | 评论 (0)编辑 收藏

     摘要: 对于表格数据处理的话,displayTag有很大的优势;但是有些时候还得自己动手做点工作; 我自己写了一个PageTag的类来处理一些简单的工作。 PageTag.java Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ -->&n...  阅读全文
posted @ 2009-10-07 18:58 Chucky 阅读(236) | 评论 (0)编辑 收藏

     摘要: 上一节谈了displaytag的基本用法,这一节就结合项目来看一下。按照常理,可能使用到displaytag的地方, 集中在管理页面里,譬如对博文的管理或者是针对comments的管理;相对而言category似乎并不需要使用分页; 很少会有人开几十个不同的分类吧 XD。 好吧,我们来比较一下,displaytag和原来的代码有什么不同。 这是原先的页面 网页的code: ...  阅读全文
posted @ 2009-10-07 16:37 Chucky 阅读(204) | 评论 (0)编辑 收藏

随着博文的增加或者评论的增加,是必要考虑一下分页问题。
在这个项目里,对于分页问题,我采取2种处理的方法。对于管理页面表格型的记录采用displayTag组件;
而对于那些博文或者评论采用自己写的PageTags类来管理。

1. displayTag组件

上面的图片可以看出:事实上这个display tag库就是用来显示表格的;给它一个对象的list,它将搞定类似显示列,排序,分页等等事务,并以表格的形式显示出来。

a. 安装:
   将displaytag-version.jar 文件与以下5个文件一起放置在应用的WEB-INF/lib目录里
  • commons-logging
  • commons-lang
  • commons-collections
  • commons-beanutils
  • log4j
   在使用的时候,在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条记录

对于每条记录我们可能有显示要求
<display:table name="blogs" id=" blog" htmlId="tab" pagesize="10" >
    
<display:column property="id" title="编号"/>
    
<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}">管理评论</td> 
    
</display:column>
    
</display:table>
比如id字段显示为 标号;title主题;category类别;日期么安装年-月-日 小时:分钟:秒的格式显示;并且可以手动选择排序。
是不是很简单。

c.其他问题:
  配置文件displaytag.properties,需要放置在src目录的根部,主要显示一些文字之类的设置,支持localization,但是要注意的是,文件必须转换成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 指定分页栏出现在表格的下面,当然还有top/both两个选择。
  
 

posted @ 2009-10-05 17:07 Chucky 阅读(263) | 评论 (0)编辑 收藏

到11节基本的东西都已经实现了,剩下的都是一点细节问题;比如由于注册用户和普通浏览用户权限不同,所以大家看的也有所不同;
在项目设计的时候,普通用户可以看博客,发表评论;为了避免不必要的麻烦,将普通用户的操作特别的写一个servlet,这样也比较容易控制。
HomeServlet主要就是负责这个任务。
在HomeServlet里面主要就是两个方法,为了配合以后的页面设计,相对之前的BlogServlet等等,相对复杂一点(其实还好)。

让我们来看看这个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表中对blog_id一致的记录做统计,与blog表左连接;
然后再blog新表与category根据categoryId做连接。

然后修改一下Blog类,添加一个comments属性(记录此blog对象所包含的评论数目)。

2.对blog.content做下处理,在显示所有博文的时候,对blog.content的内容做一个简报。
很简单的一个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字符长度,如果博文内容多于200字符,那么取前200字符;否则直接贴上博文内容。

3.对blog.content另一个修改。因为写博文的时候,可能所选用的字体啊什么每次都不同,以至于在浏览所有博文的时候会很乱;
所以以下doFilter(StringBuffer sb)方法,主要对文字进行过滤,将充满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 阅读(141) | 评论 (0)编辑 收藏