欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

仿9GAG制作过程(三)

程序员文章站 2022-07-06 11:07:22
...

有话要说

这次准备讲述后台服务器的搭建以及前台访问到数据的过程。

成果

仿9GAG制作过程(三)

准备

  1. 安装了eclipse
  2. 安装了Tomcat7
  3. 安装了数据库管理工具:Navicat

搭建服务器

eclipse直接创建一个web工程,并将运行环境设置为Tomcat7

接着定义了四个类来实现了一个简单的接口(通过servlet的方式),下面来看看这四个类

NewsBean.java

package com.lanxingren.bean;

import java.util.List;

public class NewsBean {
    
    //段子标识
    private int id;
    
    //段子文本
    private String title;
    
    //段子包含的图片链接
    private List<String> urls;
    
    //段子点赞数
    private int like;
    
    //段子点踩数
    private int unlike;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public List<String> getUrls() {
        return urls;
    }

    public void setUrls(List<String> urls) {
        this.urls = urls;
    }

    public int getLike() {
        return like;
    }

    public void setLike(int like) {
        this.like = like;
    }

    public int getUnlike() {
        return unlike;
    }

    public void setUnlike(int unlike) {
        this.unlike = unlike;
    }

    @Override
    public String toString() {
        return "NewsBean [id=" + id + ", title=" + title + ", urls=" + urls + ", like=" + like + ", unlike=" + unlike
                + "]";
    }
    
}

该类是段子类的一个bean类,各个属性代表的意思在代码里已经说清楚了。


DatabaseUtil.java

package com.lanxingren.util;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

public class DatabaseUtil {
    
    private static String url = "jdbc:mysql://localhost:3306/imitating9gag?serverTimezone=GMT%2B8&useSSL=false";
    private static String user = "root";
    private static String password = "root";
    
    private static Connection conn;
    
    //获取数据库连接
    public static Connection getConnection() {
        
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            conn = DriverManager.getConnection(url, user, password);
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        return conn;
    }
    
    //关闭数据库连接
    public static void close (Connection conn, PreparedStatement ps) {
        try {
            if (ps != null) {
                ps.close();
            }
            if (conn != null) {
                conn.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    //关闭数据库连接
    public static void close (Connection conn, PreparedStatement ps, ResultSet rs) {
        try {
            if (rs != null) {
                rs.close();
            }
            if (ps != null) {
                ps.close();
            }
            if (conn != null) {
                conn.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

该类是一个工具类,主要用来创建数据库连接以及关闭数据库连接。

其中,由于MySQL更新到了最新的版本,所以设置了useSSLfalse,否则连接会出问题。

而且,最新的MySQL其实并不需要通过Class.forName来加载驱动了。


NewsDAO.java

package com.lanxingren.dao;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import com.lanxingren.bean.NewsBean;
import com.lanxingren.util.DatabaseUtil;

public class NewsDAO {
    
    //page是页数,pageSize是每页条数
    public List<NewsBean> queryNewsByPage (int page, int pageSize) {
        List<NewsBean> newsList = new ArrayList<NewsBean>();
        
        Connection conn = DatabaseUtil.getConnection();
        
        String sql = "select * from news order by id desc limit " + (page - 1)*pageSize + ", " + pageSize;
        PreparedStatement pstmt = null;
        
        try {
            pstmt = (PreparedStatement)conn.prepareStatement(sql);
            ResultSet rs = pstmt.executeQuery();
            while (rs.next()) {
                NewsBean nb = new NewsBean();
                nb.setId(rs.getInt("id"));
                nb.setTitle(rs.getString("title"));
                nb.setLike(rs.getInt("like"));
                nb.setUnlike(rs.getInt("unlike"));
                newsList.add(nb);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        finally {
            DatabaseUtil.close(conn, pstmt);
        }
        
        return newsList;
    }
    
    // 根据段子id获取段子所包含的图片
    public List<String> queryUrlsByNewsId (int newsId) {
        List<String> urls = new ArrayList<String>();
        
        Connection conn = DatabaseUtil.getConnection();
        
        String sql = "select url from news_pics where newsid = " + newsId;
        PreparedStatement pstmt = null;
        try {
            pstmt = conn.prepareStatement(sql);
            ResultSet rs = pstmt.executeQuery();
            while (rs.next()) {
                urls.add(rs.getString("url"));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        finally {
            DatabaseUtil.close(conn, pstmt);
        }
        
        return urls;
    }
    
}

该类定义了两个方法,分别为获取段子信息的方法和获取图片的方法。

其中sql用了倒序是为了让段子按照时间流的顺序在前台展示。


QueryNewsServlet.java

package com.lanxingren.servlet;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.google.gson.Gson;
import com.lanxingren.bean.NewsBean;
import com.lanxingren.dao.NewsDAO;

@WebServlet("/QueryNewsServlet")
public class QueryNewsServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
    
    int pageSize = 5;
       
    public QueryNewsServlet() {
        super();
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/json; charset=utf-8");
        PrintWriter out = response.getWriter();
        
        String page = request.getParameter("page");
        List<NewsBean> newsList = new ArrayList<NewsBean>();
        List<NewsBean> realList = new ArrayList<NewsBean>();
        NewsDAO dao = new NewsDAO();
        
        String news = "";
        
        if (page != null) {
            newsList = dao.queryNewsByPage(Integer.parseInt(page), pageSize);
        }
        
        if (newsList != null && newsList.size() > 0) {
            for (NewsBean nb : newsList) {
                List<String> urls = dao.queryUrlsByNewsId(nb.getId());
                if (urls != null && urls.size() > 0) {
                    nb.setUrls(urls);
                    realList.add(nb);
                }
            }
        }
        
        Gson gson = new Gson();
        news = gson.toJson(realList);
        
        out.print(news);
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
    
}

通过注解的方式来设置servlet的地址,并将数据转化成json输出。

通过以上的方式,就完成了后台查询段子接口的开发,并且可通过page参数来获取第page页的信息,接口URL为:http://localhost:8080/Imitating9GAG/QueryNewsServlet?page=2

接着,将项目在Tomcat下启动后台服务器就正式搭建完成了,通过该URL获取的数据见下图:
仿9GAG制作过程(三)

前台获取数据并展示

public List<NewsBean> newsBeans = new ArrayList<NewsBean>();// 段子集合
private String baseUrl = "http://192.168.10.14:8080/Imitating9GAG/QueryNewsServlet?page=";
new Thread(new Runnable() {
    @Override
    public void run() {
        String url = baseUrl + (currentPage);
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder()
                .url(url)
                .build();
        try {
            Response response = client.newCall(request).execute();
            String json = response.body().string();
            if (json != null) {
                Gson gson = new Gson();
                newsBeans.addAll(0, (List<NewsBean>)gson.fromJson(json, new TypeToken<List<NewsBean>>(){}.getType()));
            }
            Message message = new Message();
            message.what = QUERY_NEWS;
            handler.sendMessage(message);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}).start();

由于请求网络是一个耗时操作,因此放进了子线程中。在子线程中请求网络并将返回的数据放入段子集合中。

Handler如下:

// 请求网络结束后的更新View
private Handler handler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case QUERY_NEWS:
                recyclerView.getAdapter().notifyDataSetChanged();
                break;
            case UPDATE_NEWS:
                recyclerView.getAdapter().notifyDataSetChanged();
                swipeRefreshLayout.setRefreshing(false);
                break;
            case LOAD_MORE:
                ((NewsAdapter)recyclerView.getAdapter()).changeStatus(NewsAdapter.UNLOADING);
                currentState = NewsAdapter.UNLOADING;
                break;
        }
    }
};

结束语

这样,获取数据+后台服务器搭建+前台页面展示的过程整个就已经完整了。

下一篇准备讲述官方自带的SwipeRefreshLayout刷新控件。

由于该控件没有上拉加载功能,于是就在RecyclerView中实现了上拉加载功能。