JavaWeb 第8章 项目实战 任务2 使用 Ajax 技术改造新闻发布系统 8.2.1 以 Ajax 方式根据主题动态加载新闻

     系统首页新闻中心部分使用 Ajax 技术按主题动态显示新闻功能,根据条件加载全

部主题或某个主题下得新闻,并使用 Ajax 技术实现分页显示。使用 Ajax 技术加载添

加主题页面,并以 Ajax 方式实现添加主题功能,以及用 Ajax 技术实现主题的修改和

删除。

    8.2.1  以 Ajax 方式根据主题动态加载新闻

   1. 需求介绍

     访问系统首页,以 Ajax 方式加载页面 "新闻中心" 部分的新闻列表,默认加载所有

主题下得新闻,按创建时间降序排列,并实现分页,如图 8.1 所示。

      单击某个主题的超链接时,以 Ajax 方式加载该主题下得新闻,按创建时间降序排列,

并实现分页。

     2.实现思路

     (1)实现数据层访问

      需求中存在两个分页查询的要求:对所有主题下的新闻进行分页查询,以及对某个

主题下得新闻进行分页查询。实际上,这两个查询对于 SQL 语句而言,仅相差一个主

题 id  的查询。实际上,这两个查询对于 SQL 语句而言,仅相差一个主题 id 的查询条件,

故而考虑将两个查询进行整合设计。

                图 8.1  分页展示全部类别的新闻

      修改 NewsDao 接口中分页查询相关方法的设计,加入主题 id 参数。

public interface NewsDao {
    ……// 省略其他方法
    //获得新闻总数
    public int getTotalCount(Integer id) throws SQLException;
    //分页获得新闻
    public List<News> getPageNewsList(Integer tid,
                        int pageNo,int pageSize) throws SQLException;
}

        在其实现类 NewsDaoImpl 中根据传入参数 tid 是否有效,动态拼装 SQL 语句和查

询条件。

public class NewsDaoImpl extends BaseDao implements NewsDao{
    public NewsDaoImpl(Connection conn){
        super(conn);
    }
    ……//省略其他方法
    //获得新闻的数量
    public int getTotalCount(Integer tid) throws SQLEception{
        ResultSet rs = null:
        List<Object> params = new ArrayList <Object>();
        String sql = "SELECT COUNT('nid') FROM 'news'";
        if(tid!= null){
            sql += "WHERE 'ntid' = ?";
            params.add(tid);
        }
        int count = -1;
        try {
            rs = this.executeQuery(sql,params.toArrary()) ;
            rs.next();
            count = rs.getInt(1);
        }……省略异常处理和资源释放代码
        return count;
    }
    //分页获得新闻
    public List<News> getPageNewsList(Integer tid,
                int pageNo,int pageSize) throws SQLException{
        List<News> list = new ArrayList <News>();
        ResultSet rs = null;
        List<Object> params = new ArrayList <Object>();
        String sql = "SELECT'nid','ntid','ntitle','nauthor',"
            +"'ncreateDate','nsummary','tname' FROM 'NEWS',"
            +"'TOPIC''WHERE''NEWS'.'NTID' = 'TOPIC'.'tid'";
        if{tid! = null){
            sql +="AND 'NEWS'.'ntid' = ?";
            params.add(tid);
        }
        sql += " ORDER BY 'ncreateDate' DESC LIMIT ?,?";
        params.add((pageNo - 1)* pageSize);
        params.add(pageSize);
        try{
            rs = this.executeQuery(sql,params.toArray());
            ……// 省略封装数据过程
        }……//省略异常处理和资源释放代码
        return list;
    }
}

(2) 实现业务层

      业务层接口 NewsService 及其实现类 NewsServiceImpl 也相应进行调整设计,对分

也方法增加传入参数主题 id。

      修改 NewsService 接口中分页相关方法的设计,加入主题 id 参数。

public interface NewsService{
    ……//省略其他方法
    //分页获取新闻
public void findPageNews(Integer tid,Page pageObj)
        throws SQLException;
}

   在其实现类 NewsServiceImpl 中调用 Dao 相关方法时传入 tid 即可。

public class NewsServiceImpl implements NewsService{
    ……//省略部分方法
    //分页获取新闻
    public void findPageNews(Inter tid,Page pageObj)
            throws SQLException{
        Connection conn = null;
        try{
            conn = DatebaseUtil.getConnection();
            NewsDao newsDao = new NewsDaoImpl(conn);
            ……//省略部分代码
            List<News> newsList = newsDao.getPageNewsList(tid,
                                        pageObj.getCurrPageNo(),
                                        pageObj.getPageSize());
            ……//省略部分代码
            }……// 省略异常处理和资源释放
        }
    }
}

(3)编写 Servlet

      将原有的首页初始化公告拆解成两部分:按传统初始化最新消息和主题列表(如

图 8.2 所示)及采用 Ajax 方法分页加载新闻列表(如图 8.1 所示)。

          图8.2   初始化最新消息和主题列表

      按传统方式初始化最新消息和主题列表的关键代码如下。

……//省略其他功能
else if("topicLatest".equals(opr)){//初始化首页侧边栏和主题列表
    Map<Integer,Integer>topics = new HashMap<Integer,Integer>();
    topics.put(1,5);
    topics.put(2,5);
    topics.Put(5,5);
    List<List<News>> latests = newsService
                            .findLatestNewsByTid(topics);   //查询最新消息
    List<Topic> list = topicService.findAllTopics();        //查询所有主题
    request.setAttribute("list1",latests.get(0));            // 左侧国内新闻
    request.setAttribute("list2",latests.get(1));             //左侧国际新闻
    request.setAttribute("list3",latests.get(2));            // 左侧国际新闻
    request.setAttribute("list",list);  //所有的主题
    request.getRequestDispatcher("/index.jsp").forward(request,response);
}……//省略其他功能   

  处理分页加载新闻列表的 Ajax 请求的关键代码如下。

else if("topicNews".equals(opr)){ //分页查询新闻
    //获得主题id 和当前页数
    String tid = request.getParameter("tid");
    String pageIndex = request.getParameter("pageIndex");
    ……//省略部分代码
    Page pageObj = new page();
    ……//省略部分代码
    //调用业务方法查询
    if(tid ==null||(tid = tid.trim()).length() ==0)
        newsService.findPageNews(null,pageObj);
    else
        newsService.findPageNews(Integer.valueOf(tid),pageObj);
    //使用 FastJSON 将 Page 对象序列化成 JSON 字符串
    String newsJSON = JSON.toJSONStringWithDataFormat(pageObj,
                                "yyyy-MM-dd HH:mm:ss",
                                SerializerFeature.WriteMapNullValue);
    //向客户端返回响应数据
    out.print("[{\"tid\":\""+tid+"\"},"+newsJSON +"]");
  }……//省略其他功能

     注意

        为了保证客户端分页条件的完整,响应数据时一个 JSON 数组,包括主题 id

   和查询结果两部分内容。

(4) 调整 index.jsp 页面

    将原有的获取和输出新闻列表的相关代码删除,仅保留列表的容器。

……//省略其他页面内容
<ul class = "classlist">
    <!--分页显示新闻区域-->
</ul>
……//省略其他页面内容

     为了和拆分后的 Servlet 功能及现实 Ajax  分页的要求相适应,主题列表的超链接在

输出时也需要进行相应调整。

<ul class = "class_data">
<c:forEach items = "${requestScope.list}" var="topic"
            varStatus = "i">
    <C:if test = "${i.count%11==1}"> <li id = 'class_month'></c:if>
    <a href = "javascript:;" id = "${topic.tid}">
            <b>${topic.tname}</b></a>
    <c:if test = "${i.count%11 ==0}"></li></c:if>
    <C:set var = "n" value = "${i.count}"/>
</c:forEach>
<c:if test = "${n%11!=0}"></li></c:if>
</ul>

       单击主题超链接查询相关新闻的功能将在 JavaScript 脚本中使用 Ajax 方式实现,

增加 id 属性用于在单击事件中获取作为查询参数的主题 id.

    (5)  编写 JavaScript 脚本

    在以下代码块中分别编写相关 JavaScript 脚本。

jQuery.noConflict();//让渡 "$" 的使用权,其他脚本库可以使用 "$"
(function($){
    $(document).ready(function(){
        //其他脚本编写于此处
    });
})(jQuery);

1. 编写发送 Ajax 分页请求的 getpagi() 方法并进行调用,以便在首页加载时初始

化新闻列表。

function getPagi(tid,pageIndex){    //发送 Ajax 请求实现分页
    var data = "opr = topicNews";    //准备请求参数
    if(tid)
        data += "&tid=" +tid;
    if(pageIndex && pageIndex>0)
        data += "&pageIndex="+pageIndex;
    $.getJSON("util/news",data,pagi);    //发送 Ajax 请求
};
getPage();//首页加载时,初始化加载新闻列表

2.编写回调方法 pagi() 处理响应,主要完成两件事:展示本页数据和生成分页操作链接。

//获取显示新闻列表的首页中心区域
var $centerNewsList = $("#container.main.content.classlist");

function pagi(data){ //分页查询的回调函数
    var tid = datas[0].tid == "null"?"";datas[0].tid;
    var data = datas[1];        //获取分页相关数据
    //1.展示本页新闻数据
    $centerNewsList.html("");
    if(data.newsList == null)
        $centerNewsList.html(
            "<h6>出现错误,请稍后再试或与管理员联系</h6">;
    else{
        var news;
        for(var i = 0 ;i<data.newsList.length;){
        $centerNewsList.append(
            "<li><a href = "util/news?opr=readNew&nid="
            +news.nid+"'>"+news.ntitle +"</a><span>"
            +news.ncreatedate + "</span></li>");
        if((++i)%5 == 0)
            $centerNewsList.append("<li class='space'></li>");
        }
    }//本页新闻展示完毕
//2.生成分页操作链接并注册事件,单击时调用 getPagi()方法
var $operArea = $("<p align=\"center\">当前页数:["
                        +data.currPageNo = "/"
                        +data.totalPageCount = "]&nbsp;</p>")
                    .appendTo($centerNewsList);
if(data.currPageNo>1){
    var $first = $("<a href=\"javascrit:;\">首页</a>").click(
                function(){getPagi(tid,1);});
    var $prev = $("<a href = \"javascript:;\">上一页</a>).click(
                function(){getPagi(tid,(data.currPageNo-1));});
    $operArea.append($first).append("&nbsp;").append($prev);
}
if(data.currPageNo<data.totalPageCount){
    var $next = $("<a href=\"javascrit:;\">下一页</a>").click(
                function(){getPagi(tid,(data.currPageNo+1))+1;});
    var $last = $("<a href = \"javascript:;\">末页</a>).click(
                function(){getPagi(tid,data.totalPageCount);});
    $operArea.append($next).append("&nbsp;").append($last);
}
}//pagi() 方法结束

3. 为 index.jsp 页面中的主题超链添加单击事件,单击以 Ajax 方式实现按主题

分页查看新闻。

//从页面获取主题链接,并注册单击事件,使用 id 属性存储的主题 id 作为查询条件
     $centerNewsList.prev("ul.class_data").find("a").each(function(){
        var a = this;
        a.onclick = function(){getPagi(a.id,1)};//id 属性值条件
    });

6.部署运行并测试

了解具体实现请扫描二维码。

加载新闻源码。

猜你喜欢

转载自blog.csdn.net/weixin_44129498/article/details/93420479