02 首页功能开发

首页开发

对于首页开发来说,要做到下面两点:

  • 确定好每页的页数,最好是有一个默认值

    前端可以选择各种成熟的element-ui即可

  • 确定好前端返回的数据类型

页面参数

这是前端api的请求

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
 /**
   * 获取帖子
   * @param {int} current 当前页码
   * @param {int} limit 每页条数
   * @param {int} orderMode 排序模式,0 最新 1 热门
   * @returns
   */
  static async getDiscussPosts(current = 1, limit = 5, orderMode = 0) {
    return get('/index', {
      current,
      limit,
      orderMode
    })
  }

前端会使用get方法来向后端传递三个参数,分别是:

  • 当前的页数:current

  • 每页最大帖子数:limit

  • 展示帖子的优先级:orderMode

    这个参数的意思是,在默认情况(orderMode = 0)下展示的帖子都是根据创建时间来进行展示的,当orderMode = 1时意思是首页展示的页面要根据热度去进行排序。

功能开发

在开发时我们要遵守mvc三层架构的形式去进行开发

  • controller

    前端的请求参数

  • service

    业务逻辑方法

  • mapper

    数据库调用

Homecontroller

根据前端来确定对应的方法

1
2
@GetMapping
public Result<List<Map<String, Object>>> getDiscussPosts(@RequestParam(defaultValue = "1") int current, @RequestParam(defaultValue = "5") int limit, @RequestParam(defaultValue = "0") int orderMode)

这是函数签名,因为前端在传递这些参数的时候是有默认值的,所以我们可以使用RequestParam注解来设定默认值。

因为数据返回的是一个List<Map<>>的形式,所以我们还需要一个可以展示post的一个实体类,这样就可以把前端查询到的帖子数据由实体类进行返回。

HomeService

HomeService里面需要实现查询封装页数的行为,在数据库中的分页查询就是limit语句,像下面这样

1
2
3
select * 
from Post
limit offset, pageSize

所以对于pagepageSize这两个参数来说,其中

  • page = (current - 1) * pageSize
  • pageSize = limit

service层可以拼接好这两个字段,然后传递到mapper层里面

HomeMapper

在首页展示出所有的帖子其实执行的就是一次select语句,这个方法与根据特定用户id进行查找的方式很像,所以我们可以封装一个userId参数,这样在实现根据用户id进行查找的时候就可以传进用户id来进行查找,而不用额外的去写一个方法。

因为userId是可有可无的,所以对于此类比较复杂的动态sql,我们可以将其书写在xml文件里面。

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

<select id="getDiscussPosts" resultType="com.zxp.nowcodercommunity.pojo.DiscussPost">
    select <include refid="commonField"/>
    from discuss_post
    where status != 2
    <if test="userId != 0">
        and user_id = #{userId}
    </if>
    order by type desc,
    <if test="orderMode == 1">
        score desc,
    </if>
    create_time desc
    limit #{offset}, #{limit}
</select>

构造返回数据

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
24
25
26
{
    "code": 200,
    "msg": null,
    "data": [
        {
            "post": {
                "id": 275,
                "userId": 11,
                "title": "我是管理员",
                "content": "我是管理员,你们都老实点!",
                "type": 1,
                "status": 1,
                "createTime": "2019-05-16T10:58:44.000+00:00",
                "commentCount": 12,
                "score": 1751.2900346113624
            },
            "user": {
                "id": 11,
                "username": "nowcoder11",
                "headerUrl": "http://images.nowcoder.com/head/11t.png",
                "type": null,
                "createTime": null
            }
        }
}
      

也就是说需要我们显示的去构造一个List类型的数据,最后返回。

获取来自mapper的数据

获取来自mapper数据后

1
List<DiscussPost> list = homeService.getDiscussPosts(0, page.getCurrent(), page.getLimit(), 0);

显然,list里面存储的就是我们的post数据,我们还要根据post里面的userId来构造user数据,这个过程可以使用stream流来进行操作。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
List<Map<String, Object>> data = list.stream().map(post -> {
            Map<String, Object> map = new HashMap<>();
            map.put("post", post);

            // 获取用户信息并拷贝属性
            User user = userService.getUserById(post.getUserId());
            UserVo userVo = new UserVo();
    		// 拷贝到UserVo里面
            BeanUtils.copyProperties(user, userVo);
            map.put("user", userVo);

            return map;
        }).collect(Collectors.toList());

测试

前端工程是vue3项目,所以在准备好前端工程前使用postman来进行测试

测试/index接口

在向前端发送数据后,可以看到确实接收到了数据

image-20250325222422310

前后端联调

启动vue项目后,可以看到首页已经成功的将帖子展示了出来

image-20250325222652076

但是当前页面还有一个缺点就是时间格式显示的不太正常,这是因为我们并未给定时间格式的形式。一种简单的方式是在参数上指定好日期格式。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
public class DiscussPost {

    private int id;
    private int userId;
    private String title;
    private String content;
    private int type;
    private int status;
    @JsonFormat(pattern = "yyyy-MM-dd hh:mm:ss")
    private Date createTime;
    private int commentCount;
    private double score;
}

这样时间就可以按照我们需要的格式去显示

image-20250325223100619

同时,我们还需要开发一个查询帖子总数的服务,这个比较简单,思路和分页查询差不多,就不写了。

总结

我觉得对于一个初学者,下面几点都很重要

  • 分层架构
  • 统一的数据响应格式
  • 良好的数据封装
Licensed under CC BY-NC-SA 4.0
花有重开日,人无再少年
使用 Hugo 构建
主题 StackJimmy 设计