0%

仿牛客论坛项目01-首页功能

仿牛客论坛项目01-首页功能,内容记录

首页

代码写的顺序:Dao->Service->Controller

DAO

方法1:需要查询所有的帖子,查询所有的不需要参数;考虑到之后还有功能个人主页上显示自己的博客,因此,方法中要加上userID参数;还有分页功能,方法中还要加上页数的索引offset,以及每页的限制limit

方法2:为了实现分页功能,需要查询所有帖子的行数

1
2
3
4
5
6
@Mapper
public interface DiscussPostMapper {
List<DiscussPost> selectDiscussPosts(int userId, int offset, int limit);
int selectDiscussPostsRows(@Param("userId") int userId);
}

对应的配置文件:

不选择拉黑的帖子,拼接动态SQL

首先按是否置顶排序,再按创建时间降序排序,最近发布的在上面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<sql id="selectField">
id, user_id, title, content, type, status, create_time, comment_count, score
</sql>

<select id="selectDiscussPosts" resultType="DiscussPost">
select <include refid="selectField"></include>
from discuss_post
where status != 2
<if test="userId != 0">
and user_id = #{userId}
</if>
order by type desc, create_time desc
limit #{offset}, #{limit}
</select>

<select id="selectDiscussPostsRows" resultType="int">
select count(id)
from discuss_post
where status != 2
<if test="userId != 0">
and user_id = #{userId}
</if>
</select>

Service

DiscussPostService调用Dao层中的方法,并将获取到的数据通过userIdusername一起返回,因此还需要一个UserService

Controller

静态资源、页面导入

在该层中调用Service,返回模板的路径

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@RequestMapping(value = "/index", method = RequestMethod.GET)
public String getIndexPage(Model model, Page page) {
// SpringMVC会将Page自动注入到Model,并将请求中的查询参数映射到这个对象上
// 这样Thymeleaf可以直接使用Page中的数据
// 服务端可以设置的分页参数
page.setRows(discussPostService.findDiscussPostsRows(0));
page.setPath("/index");

List<DiscussPost> list = discussPostService.findDiscussPosts(0, page.getOffset(), page.getLimit());
List<Map<String, Object>> postList = new ArrayList<>();
if(list != null) {
for(DiscussPost post : list) {
// 将用户名加入列表中
User user = userService.findUserById(post.getUserId());
Map<String, Object> map = new HashMap<>();
map.put("post", post);
map.put("user", user);
postList.add(map);
}
}
model.addAttribute("discussPosts", postList);
return "/index";
}

分页功能

分页类需要用到的参数:

  1. current 为当前页码
  2. limit 为每页上限
  3. rows 为数据总数
  4. path 为查询路径(封装在里面,查询时就不用字符串拼接了)

上述参数有限制条件可以在setter中写,比如当前页数不能为负数。

分页类需要用到的方法:

  1. getOffset 获取当前页的起始行,在数据库查询时需要用到
  2. getTotal 获取总页码,页面上显示的页码不能超过总页码
  3. getFrom 当页码还要显示前后几个页码,获取这段页码的起始页码
  4. getTo 获取这段页码的结束页码

index页面中分页实现逻辑:

  1. 没有数据时不需要分页
  2. 用遍历显示当前页码,和前两个到后两个的页码
  3. 当前页的按钮状态为激活
  4. 处于第一页时,上一页禁用
  5. 处于最后一页时,下一页禁用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!-- 分页 -->
<nav class="mt-5" th:if="${page.rows>0}">
<ul class="pagination justify-content-center">
<!-- /index?current=1 -->
<li class="page-item">
<a class="page-link" th:href="@{${page.path}(current=1)}">首页</a>
</li>
<li th:class="|page-item ${page.current==1?'disabled':''}|" >
<a class="page-link" th:href="@{${page.path}(current=${page.current-1})}">上一页
</a>
</li>
<li th:class="|page-item ${i==page.current?'active':''}|"
th:each="i:${#numbers.sequence(page.from, page.to)}">
<a class="page-link" th:href="@{${page.path}(current=${i})}" th:text="${i}">1</a>
</li>
<li th:class="|page-item ${page.current==page.total?'disabled':''}|" >
<a class="page-link" th:href="@{${page.path}(current=${page.current+1})}">下一页</a>
</li>
<li class="page-item">
<a class="page-link" th:href="@{${page.path}(current=${page.total})}">末页</a>
</li>
</ul>
</nav>

Thymeleaf语法

thymeleaf作用:前端页面中使用Thymeleaf表达式来访问Model中的数据

导入thymeleaf<html lang="en" xmlns:th="http://www.thymeleaf.org">

页面中导入的静态资源有相对路径时,需要使用thymeleaf语法

<link rel="stylesheet" th:href="@{css/global.css}" /> 这样写默认去static下寻找

循环:th:each="map:${discussPosts}" map是遍历时的元素

内容:th:utext="${map.post.title}" utext可以解析转义字符

判断:th:if="${map.post.type==1}"

时间格式化:th:text="${#dates.format(map.post.createTime, 'yyyy-MM-dd HH:mm:ss')}"

Thymeleaf符号

  1. # :标识Thymeleaf内置的标准表达式对象,如#dates用于日期操作

  2. $ :用于获取变量的值,并将其插入到模板中,如post.title

  3. @ :用于表示Thymeleaf中的URL表达式

  4. | :可以将一个静态的字符串和一个表达式拼接在一起

    <li th:class="|page-item ${page.current==page.total?'disabled':''}|" >

  5. th:text :用于设置标签内文本的值

  6. th:if :用于条件判断,根据条件的真假来显示或隐藏标签

  7. th:each:用于遍历集合或数组,将集合中的每个元素逐个处理

    1
    2
    3
    <ul>
    <li th:each="item : ${items}" th:text="${item}">Item</li>
    </ul>
  8. th:href:用于设置链接的URL

  9. ``th:class`:用于设置标签的类名

    1
    2
    <div th:class="${condition} ? 'class1' : 'class2'">Content</div>
    <li th:class="|page-item ${page.current==page.total?'disabled':''}|" >
  10. th:fragment:用于定义一个可重用的模板片段,可以在其他模板被引入并重用

  11. th:replace:用于在一个模板中引入另一个模板,替换该标签的内容

    <div th:replace="fragments :: myFragment"></div>表示

Content

在Thymeleaf中,context类主要用于传递变量和数据模型到模板引擎,以便在HTML模板中进行数据渲染。

问题

  1. 在page类里没有配置total属性,但是有一个getTotal方法,controller类里将page注入给了model,为什么在thymeleaf中可以直接使用page.total,而不用getTotal

    尽管Page类没有直接定义一个名为total的属性,但是存在一个getTotal()方法。根据JavaBean的命名规则,Thymeleaf会认为getTotal()方法是用来获取total属性的值的。因此,Thymeleaf允许直接使用page.total来访问这个属性的值,而不需要显式调用getTotal()方法。