文章目录
- 实现获取博客列表页功能
- 1. 约定前后端交互接口
- 2. 实现后端代码
- 3. 实现前端代码
- 4. 测试代码
- 5. 涉及到的两个 Bug
实现获取博客列表页功能
当前的博客列表上的数据都是写死的,符合逻辑的做法是,通过数据库读取数据后显示到页面上。
此处就需要打通前后端交互的操作。
让博客列表页在加载的时候,通过 Ajax 给服务器发一个请求,服务器查数据库获取到博客列表页数据,再返还给服务器,浏览器再根据数据构造页面的内容。
这样的交互过程也称为 前后端分离
意思是前端只向后端请求数据,而不请求具体的页面,后端也仅仅是返回数据。
这样设计的目的就是为了前端和后端更加的解耦,由浏览器进行具体的页面渲染,
减少了服务器的工作量。
1. 约定前后端交互接口
我们约定前端发起的 请求 是 GET,路径是 /blog
后端返回的 响应 使用的是 json 格式的数据来组织
以上就是一个 json 格式的数组。
2. 实现后端代码
此时创建一个新的 BlogServlet 类。
@WebServlet("/blog")
public class BlogServlet extends HttpServlet {
private ObjectMapper objectMapper = new ObjectMapper();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 1.先查询数据库
BlogDao blogDao = new BlogDao();
// 使用 List 来表示
List<Blog> blogs = blogDao.selectAll(); // 调用方法直接查询出全部的博客列表
// 2.使用 ObjectMapper 将 blogs 转成符合要求的 json 格式的字符串
String respJson = objectMapper.writeValueAsString(blogs);
// 写回去
resp.setContentType("application/json; charset=utf8");
resp.getWriter().write(respJson);
}
}
3. 实现前端代码
按照以下步骤用 vscode 打开这个博客列表页的文件。
在博客列表页加载过程中,触发 ajax ,访问服务器中的数据,再把拿到的数据构造到页面中。
将原来博客列表页的文章摘抄只留下一篇作为一个样例,这个样例在代码写完的时候也可以删除。
可以看到此时的博客就只有一篇了。
(1) 引入 jQuery
在前端代码下使用一个 script 标签,在这个标签里引入 jQuery。
(2) 在页面加载的时候,向服务器发起请求,获取博客列表的数据
<script>
// 在页面加载的时候,向服务器发起请求,获取博客列表的数据
function getBlogs() {
$.ajax({
type: 'get',
url: 'blog',
success: function(body) {
// 响应的正文是一个 json 格式的字符串,此时已经被 jQuery 自动解析成一个 js 的对象数组了
// 此时直接 for 循环遍历即可
for (let blog of body) {
// 按照之前的写好的 html 代码构造页面内容
}
}
})
}
// 记得调用方法
getBlogs();
</script>
上面的 type 和 url 分别是 get 和 blog ,这是因为这些都是在之前前后端交互接口中就约定好了。
(3) 构造页面内容
这里所构造的页面内容要参考之前写好的 html 代码。
根据上面的图片可以看到,有 5 个需要构造的内容。
① 构造整个博客
let blogDiv = document.createElement('div');
blogDiv.className = 'blog';
因为整个博客是一个 div 标签,因此这里的 createElement 里是一个 div。
而它的 类名 是 blog,因此这里的 clasName 为 blog。
② 构造标题
let titleDiv = document.createElement('div');
titleDiv.className = 'title';
// 把标题获取到并且设置进去
titleDiv.innerHTML = blog.title;
// 将构造好的标题添加进整个博客页面
blogDiv.appendChild(titleDiv);
因为 标题 是一个 div 标签,因此这里的 createElement 里是一个 div。
而它的 类名 是 title,因此这里的 clasName 为 title。
③ 构造发布时间
let dateDiv = document.createElement('div');
dateDiv.className = 'date';
dateDiv.innerHTML = blog.postTime;
blogDiv.appendChild(dateDiv);
这里的代码和上面的含义是一致的,只不过在第三条语句中的 blog.postTime。
因为在前后端交互接口中约定好了,发布时间是 postTime。
④ 构造博客摘要
let descDiv = document.createElement('div');
descDiv.className = 'desc';
descDiv.innerHTML = blog.content;
blogDiv.appendChild(descDiv);
这里的 blog.content 是由于前后端交互接口约定好了。
⑤ 构造查看全文按钮
let button = document.createElement('a');
button.innerHTML = '查看全文 >>';
// 期望点击按钮后会跳转到博客详情页
// 为了让博客详情页知道点了哪篇博客,把 blogId传过去
button.href = 'blog.detail.html?blogId=' + blog.blogId;
blogDiv.appendChild(button);
blog.detail.html 这是 博客详情页 的文件名,通过 blogId 来获取具体哪一篇博客。
此时的 blogDiv 只是创建出来了,还没有把它放到下图圈出的 div 里面。
此时需要先找到 父元素,上述图片中的 container-right 就是父元素。
首先在 for 循环的前面加上下面的代码。
let containerRight = document.querySelector('.container-right');
接着在 for 的里面加上下面的代码
// 把 blogDiv 加到父元素中
containerRight.appendChild(blogDiv);
整体代码
<script>
// 在页面加载的时候,向服务器发起请求,获取博客列表的数据
function getBlogs() {
$.ajax({
type: 'get',
url: 'blog',
success: function(body) {
// 响应的正文是一个 json 格式的字符串,此时已经被 jQuery 自动解析成一个 js 的对象数组了
// 此时直接 for 循环遍历即可
for (let blog of body) {
// 按照之前的写好的 html 代码构造页面内容
let containerRight = document.querySelector('.container-right');
// 构造整个博客
let blogDiv = document.createElement('div');
blogDiv.className = 'blog';
// 构造标题
let titleDiv = document.createElement('div');
titleDiv.className = 'title';
// 把标题获取到并且设置进去
titleDiv.innerHTML = blog.title;
// 将构造好的标题添加进整个博客页面中
blogDiv.appendChild(titleDiv);
// 构造发布时间
let dateDiv = document.createElement('div');
dateDiv.className = 'date';
dateDiv.innerHTML = blog.postTime;
blogDiv.appendChild(dateDiv);
// 构造博客摘要
let descDiv = document.createElement('div');
descDiv.className = 'desc';
descDiv.innerHTML = blog.content;
blogDiv.appendChild(descDiv);
// 构造查看全文按钮
let button = document.createElement('a');
button.innerHTML = '查看全文 >>';
// 期望点击按钮后会跳转到博客详情页
// 为了让博客详情页知道点了哪篇博客,把 blogId传过去
button.href = 'blog.detail.html?blogId=' + blog.blogId;
blogDiv.appendChild(button);
// 把 blogDiv 加到父元素中
containerRight.appendChild(blogDiv);
}
}
})
}
// 记得调用方法
getBlogs();
</script>
此时 博客列表页 就实现完成了。
4. 测试代码
首先要在数据库中插入测试数据。
在地址栏中输入 http://127.0.0.1:8080/blog-system/blog.list.html。
blog.list.html 是博客列表页的文件名,blog-system 是项目名称。
可以看到此时在数据库插入的数据就显示到了博客列表页中。
此时点击 “查看全文” 按钮,就会自动跳转到 博客详情页。
此时显示的就是博客详情页界面了。
代码中实现的和跳转到博客详情页之后得地址栏是相同的。
5. 涉及到的两个 Bug
1、时间戳
可以看到此时显示的是一个时间戳,而不是一个格式化时间。
2、顺序
按照书写博客的逻辑,应该是先完成的博客在下面,后完成的在上面。
但是此时的顺序是相反的
根据上面在数据库中插入的结果可以看出,博客列表页展示出来的效果的顺序的确是不符合逻辑的。
(1) 顺序问题的解决办法
在 BlogDao 类(在封装数据库的操作中) 中找到 selectAll 方法,将这个方法中的 sql 语句更改为以下语句:
String sql = "select * from blog order by postTime desc";
也就是在 blog 后面添加上 order by postTime desc。
order by postTime 表示的是 按照发布时间排序,desc 表示的是 排的是 降序。
(2) 时间戳问题的解决办法
搜索 SimpleFormatter,查一下它的格式。
接下来在 Blog 类中,添加上下面的这段代码。
public String getPostTime() {
// 把时间戳转成 格式化 时间
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return simpleDateFormat.format(postTime);
}
重启服务器后在地址栏输入路径。
可以看到此时的发布时间和顺序就已经正确了,此时博客列表页就已经全部完成了。