开发社区首页

目录

1.前期工作

1.1 添加 spring boot项目

1.2 添加配置文件

​编辑

2.开发 DAO 层(数据访问层)

2.1 连接数据库

2.2 创建实体类

2.3 创建 Mapper (实现接口——DiscussPostMapper 类)

2.4 添加配置文件 mapper

3. 开发 Service 层(业务层)

3.1 创建业务组件 DiscussPostService 类

3.2 创建用户表 User

3.3 访问数据库(在 dao 包下新建一个 UserMapper 接口)

3.4 配置文件:给每一个方法提供需要的 SQL

3.5 创建 UserService:根据 UserId 查询到 User

4.开发 Controller 层

4.1 首先引入前端页面

4.2 在 controller 包下新建 HomeController 类

4.3 封装分页相关的信息

4.4 改进 Controller,支持分页功能(HomeController 类)


1.前期工作

1.1 添加 spring boot项目

1.2 添加配置文件

在 resources 文件下的 application.properties 中添加配置文件

# ThymeleafProperties
spring.thymeleaf.cache=false

# DataSourceProperties
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/community?characterEncoding=utf-8&useSSL=false&serverTimezone=Hongkong
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.type=com.zaxxer.hikari.HikariDataSource
spring.datasource.hikari.maximum-pool-size=15
spring.datasource.hikari.minimum-idle=5
spring.datasource.hikari.idle-timeout=30000

# MybatisProperties
mybatis.mapper-locations=classpath:mapper/*.xml
mybatis.type-aliases-package=com.example.demo.entity
mybatis.configuration.useGeneratedKeys=true
mybatis.configuration.mapUnderscoreToCamelCase=true

# logger
logging.level.com.nowcoder.community=debug

开发流程:1次请求的执行过程

实现:

  • 开发社区首页,显示前10个帖子
  • 开发分页组件,分页显示所有的帖子

2.开发 DAO 层(数据访问层)

2.1 连接数据库

2.2 创建实体类

首先开发 DAO(数据访问层),首先需要创建实体类(在 entity 包下创建 DiscussPost 类)进行封装数据

package com.example.demo.entity;
import java.util.Date;
public class DiscussPost {
    private int id;
    private int userId;
    private String title;
    private String content;
    private int type;
    private int status;//帖子状态
    private Date createTime;//创建时间
    private int commentCount;//评论数量
    private double score;//分数
    public int getId() {return id;}
    public void setId(int id) {this.id = id;}
    public int getUserId() {return userId;}
    public void setUserId(int userId) {this.userId = userId;}
    public String getTitle() {return title;}
    public void setTitle(String title) {this.title = title;}
    public String getContent() {return content;}
    public void setContent(String content) {this.content = content;}
    public int getType() {return type;}
    public void setType(int type) {this.type = type;}
    public int getStatus() {return status;}
    public void setStatus(int status) {this.status = status;}
    public Date getCreateTime() {return createTime;}
    public void setCreateTime(Date createTime) {this.createTime = createTime;}
    public int getCommentCount() {return commentCount;}
    public void setCommentCount(int commentCount) {this.commentCount = commentCount;}
    public double getScore() {return score;}
    public void setScore(double score) {this.score = score;}

    @Override
    public String toString() {
        return "DiscussPost{" +
                "id=" + id +
                ", userId=" + userId +
                ", title='" + title + '\'' +
                ", content='" + content + '\'' +
                ", type=" + type +
                ", status=" + status +
                ", createTime=" + createTime +
                ", commentCount=" + commentCount +
                ", score=" + score +
                '}';
    }
}

2.3 创建 Mapper (实现接口——DiscussPostMapper 类)

  • 分页查询查到的是多条数据,返回设置为集合(集合中放入帖子对象)
  • 分页用 limit 关键字,后面加两个参数:起始行行号(offset)和每一页显示多少行数据(limit)
  • @Param注解用于给参数取别名, 如果只有一个参数,并且在<if>里使用,则必须加别名
package com.example.demo.dao;
import com.example.demo.entity.DiscussPost;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@Mapper
public interface DiscussPostMapper {

    List<DiscussPost> selectDiscussPosts(int userId, int offset, int limit);

    // @Param注解用于给参数取别名, 如果只有一个参数,并且在<if>里使用,则必须加别名.
    //查询帖子的行数
    int selectDiscussPostRows(@Param("userId") int userId);
}

2.4 添加配置文件 mapper

要想实现上述方法,需要提供一个配置文件,需要给每一个方法提供需要的 SQL,在 resources 文件中 mapper 目录下创建 discusspost-mapper.xml:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.dao.DiscussPostMapper">

    <sql id="selectFields">
        id, user_id, title, content, type, status, create_time, comment_count, score
    </sql>

    <select id="selectDiscussPosts" resultType="DiscussPost">
        select <include refid="selectFields"></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="selectDiscussPostRows" resultType="int">
        select count(id)
        from discuss_post
        where status != 2
        <if test="userId!=0">
            and user_id = #{userId}
        </if>
    </select>

</mapper>

到这里 DAO 已经开发完成,进行测试:

package com.example.demo;
import com.example.demo.dao.DiscussPostMapper;
import com.example.demo.entity.DiscussPost;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest
public class MapperTests {
    //注入 discussPostMapper
    @Autowired
    private DiscussPostMapper discussPostMapper;
    @Test
    public void testSelectPosts() {
        List<DiscussPost> list = discussPostMapper.selectDiscussPosts(149, 0, 10);
        for(DiscussPost post : list) {
            System.out.println(post);
        }
        int rows = discussPostMapper.selectDiscussPostRows(149);
        System.out.println(rows);
    }

}

3. 开发 Service 层(业务层)

3.1 创建业务组件 DiscussPostService 类

在 service 包下创建业务组件 DiscussPostService 类(业务层会调用数据访问层):

  • 调用 Mapper,注入 DiscussPostMapper
  • 声明一个业务方法:查询某一页的方法,返回类型是集合
  • 再添加一个查询行数的方法
package com.example.demo.service;
import com.example.demo.dao.DiscussPostMapper;
import com.example.demo.entity.DiscussPost;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class DiscussPostService {

    //查询,调用 Mapper,注入 DiscussPostMapper
    @Autowired
    private DiscussPostMapper discussPostMapper;

    //声明一个业务方法:查询某一页的方法,返回类型是集合
    public List<DiscussPost> findDiscussPosts(int userId, int offset, int limit) {
        return discussPostMapper.selectDiscussPosts(userId, offset, limit);
    }

    //查询行数的方法
    public int findDiscussPostRows(int userId) {
        return discussPostMapper.selectDiscussPostRows(userId);
    }

}

得到用户名称username:得到数据,针对每一个单独的 DiscussPost 查询 useId ,把查到的 useId 和 DiscussPost 组合在一起返回给页面

需要提供一个业务方法:根据 userId 查询到 user

3.2 创建用户表 User

首先我们看用户表中有哪些属性:

对 User 表进行增删改查,首先要访问实体类(分装表里的数据),在 entity 包下新建 User 类:

package com.example.demo.entity;
import java.util.Date;
public class User {

    private int id;
    private String username;
    private String password;
    private String salt;//盐,为了防止用户密码过于简单进行加密
    private String email;
    private int type;
    private int status;
    private String activationCode;//激活码
    private String headerUrl;//头像访问路径
    private Date createTime;//注册时间

    public int getId() {
        return id;
    }

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

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getSalt() {
        return salt;
    }

    public void setSalt(String salt) {
        this.salt = salt;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public int getType() {
        return type;
    }

    public void setType(int type) {
        this.type = type;
    }

    public int getStatus() {
        return status;
    }

    public void setStatus(int status) {
        this.status = status;
    }

    public String getActivationCode() {
        return activationCode;
    }

    public void setActivationCode(String activationCode) {
        this.activationCode = activationCode;
    }

    public String getHeaderUrl() {
        return headerUrl;
    }

    public void setHeaderUrl(String headerUrl) {
        this.headerUrl = headerUrl;
    }

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", salt='" + salt + '\'' +
                ", email='" + email + '\'' +
                ", type=" + type +
                ", status=" + status +
                ", activationCode='" + activationCode + '\'' +
                ", headerUrl='" + headerUrl + '\'' +
                ", createTime=" + createTime +
                '}';
    }

}

3.3 访问数据库(在 dao 包下新建一个 UserMapper 接口)

  • 添加注解 @Mapper
  • 根据 id 查询
  • 根据用户名查询 user
  • 根据邮箱查询 user
  • 增加用户(参数为 user 包含的所有数据)
  • 修改用户状态(返回修改条数)
  • 更新头像路径
  • 更新密码
package com.example.demo.dao;
import org.apache.catalina.User;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface UserMapper {

    //根据 id 查询
    User selectById(int id);

    //根据用户名查询 user
    User selectByName(String username);

    //根据邮箱查询 user
    User selectByEmail(String email);

    //增加用户(参数为 user 包含的所有数据)
    int insertUser(User user);

    //修改用户状态(返回修改条数
    int updateStatus(int id, int status);

    //更新头像路径
    int updateHeader(int id, String headerUrl);

    //更新密码
    int updatePassword(int id, String password);

}

3.4 配置文件:给每一个方法提供需要的 SQL

要想实现上述方法,需要提供一个配置文件,需要给每一个方法提供需要的 SQL,在 resources 文件中 mapper 目录下创建一个 user-mapper 的配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.dao.UserMapper">

    <sql id="insertFields">
        username, password, salt, email, type, status, activation_code, header_url, create_time
    </sql>

    <sql id="selectFields">
        id, username, password, salt, email, type, status, activation_code, header_url, create_time
    </sql>

    <select id="selectById" resultType="User">
        select <include refid="selectFields"></include>
        from user
        where id = #{id}
    </select>

    <select id="selectByName" resultType="User">
        select <include refid="selectFields"></include>
        from user
        where username = #{username}
    </select>

    <select id="selectByEmail" resultType="User">
        select <include refid="selectFields"></include>
        from user
        where email = #{email}
    </select>

    <insert id="insertUser" parameterType="User" keyProperty="id">
        insert into user (<include refid="insertFields"></include>)
        values(#{username}, #{password}, #{salt}, #{email}, #{type}, #{status}, #{activationCode}, #{headerUrl}, #{createTime})
    </insert>

    <update id="updateStatus">
        update user set status = #{status} where id = #{id}
    </update>

    <update id="updateHeader">
        update user set header_url = #{headerUrl} where id = #{id}
    </update>

    <update id="updatePassword">
        update user set password = #{password} where id = #{id}
    </update>

</mapper>

3.5 创建 UserService:根据 UserId 查询到 User

在 service 包下创建 UserService 类:

  • 添加注解 @Service
  • 查询用户:需要注入用户的 Mapper(UserMapper)
package com.example.demo.service;
import com.example.demo.dao.UserMapper;
import org.apache.catalina.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
 * 根据 UserId 查询到 User
 */
@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;

    //根据一个用户 id 查询用户的方法
    public User findUserById(int id) {
        return userMapper.selectById(id);
    }

}

4.开发 Controller 层

4.1 首先引入前端页面

<!doctype html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
	<link rel="icon" href="https://static.nowcoder.com/images/logo_87_87.png"/>
	<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" crossorigin="anonymous">
	<link rel="stylesheet" th:href="@{/css/global.css}" />
	<title>牛客网-首页</title>
</head>
<body>	
	<div class="nk-container">
		<!-- 头部 -->
		<header class="bg-dark sticky-top">
			<div class="container">
				<!-- 导航 -->
				<nav class="navbar navbar-expand-lg navbar-dark">
					<!-- logo -->
					<a class="navbar-brand" href="#"></a>
					<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
						<span class="navbar-toggler-icon"></span>
					</button>
					<!-- 功能 -->
					<div class="collapse navbar-collapse" id="navbarSupportedContent">
						<ul class="navbar-nav mr-auto">
							<li class="nav-item ml-3 btn-group-vertical">
								<a class="nav-link" href="index.html">首页</a>
							</li>
							<li class="nav-item ml-3 btn-group-vertical">
								<a class="nav-link position-relative" href="site/letter.html">消息<span class="badge badge-danger">12</span></a>
							</li>
							<li class="nav-item ml-3 btn-group-vertical">
								<a class="nav-link" href="site/register.html">注册</a>
							</li>
							<li class="nav-item ml-3 btn-group-vertical">
								<a class="nav-link" href="site/login.html">登录</a>
							</li>
							<li class="nav-item ml-3 btn-group-vertical dropdown">
								<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
									<img src="http://images.nowcoder.com/head/1t.png" class="rounded-circle" style="width:30px;"/>
								</a>
								<div class="dropdown-menu" aria-labelledby="navbarDropdown">
									<a class="dropdown-item text-center" href="site/profile.html">个人主页</a>
									<a class="dropdown-item text-center" href="site/setting.html">账号设置</a>
									<a class="dropdown-item text-center" href="site/login.html">退出登录</a>
									<div class="dropdown-divider"></div>
									<span class="dropdown-item text-center text-secondary">nowcoder</span>
								</div>
							</li>
						</ul>
						<!-- 搜索 -->
						<form class="form-inline my-2 my-lg-0" action="site/search.html">
							<input class="form-control mr-sm-2" type="search" aria-label="Search" />
							<button class="btn btn-outline-light my-2 my-sm-0" type="submit">搜索</button>
						</form>
					</div>
				</nav>
			</div>
		</header>

		<!-- 内容 -->
		<div class="main">
			<div class="container">
				<div class="position-relative">
					<!-- 筛选条件 -->
					<ul class="nav nav-tabs mb-3">
						<li class="nav-item">
							<a class="nav-link active" href="#">最新</a>
						</li>
						<li class="nav-item">
							<a class="nav-link" href="#">最热</a>
						</li>
					</ul>
					<button type="button" class="btn btn-primary btn-sm position-absolute rt-0" data-toggle="modal" data-target="#publishModal">我要发布</button>
				</div>
				<!-- 弹出框 -->
				<div class="modal fade" id="publishModal" tabindex="-1" role="dialog" aria-labelledby="publishModalLabel" aria-hidden="true">
					<div class="modal-dialog modal-lg" role="document">
						<div class="modal-content">
							<div class="modal-header">
								<h5 class="modal-title" id="publishModalLabel">新帖发布</h5>
								<button type="button" class="close" data-dismiss="modal" aria-label="Close">
									<span aria-hidden="true">&times;</span>
								</button>
							</div>
							<div class="modal-body">
								<form>
									<div class="form-group">
										<label for="recipient-name" class="col-form-label">标题:</label>
										<input type="text" class="form-control" id="recipient-name">
									</div>
									<div class="form-group">
										<label for="message-text" class="col-form-label">正文:</label>
										<textarea class="form-control" id="message-text" rows="15"></textarea>
									</div>
								</form>
							</div>
							<div class="modal-footer">
								<button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
								<button type="button" class="btn btn-primary" id="publishBtn">发布</button>
							</div>
						</div>
					</div>
				</div>
				<!-- 提示框 -->
				<div class="modal fade" id="hintModal" tabindex="-1" role="dialog" aria-labelledby="hintModalLabel" aria-hidden="true">
					<div class="modal-dialog modal-lg" role="document">
						<div class="modal-content">
							<div class="modal-header">
								<h5 class="modal-title" id="hintModalLabel">提示</h5>
							</div>
							<div class="modal-body" id="hintBody">
								发布完毕!
							</div>
						</div>
					</div>
				</div>
				
				<!-- 帖子列表 -->
				<ul class="list-unstyled">
					<li class="media pb-3 pt-3 mb-3 border-bottom" th:each="map:${discussPosts}">
						<a href="site/profile.html">
							<img th:src="${map.user.headerUrl}" class="mr-4 rounded-circle" alt="用户头像" style="width:50px;height:50px;">
						</a>
						<div class="media-body">
							<h6 class="mt-0 mb-3">
								<a href="#" th:utext="${map.post.title}">备战春招,面试刷题跟他复习,一个月全搞定!</a>
								<span class="badge badge-secondary bg-primary" th:if="${map.post.type==1}">置顶</span>
								<span class="badge badge-secondary bg-danger" th:if="${map.post.status==1}">精华</span>
							</h6>
							<div class="text-muted font-size-12">
								<u class="mr-3" th:utext="${map.user.username}">寒江雪</u> 发布于 <b th:text="${#dates.format(map.post.createTime,'yyyy-MM-dd HH:mm:ss')}">2019-04-15 15:32:18</b>
								<ul class="d-inline float-right">
									<li class="d-inline ml-2">赞 11</li>
									<li class="d-inline ml-2">|</li>
									<li class="d-inline ml-2">回帖 7</li>
								</ul>
							</div>
						</div>						
					</li>
				</ul>
				<!-- 分页 -->
				<nav class="mt-5" th:if="${page.rows>0}">
					<ul class="pagination justify-content-center">
						<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" href="#" 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>
			</div>
		</div>

		<!-- 尾部 -->
		<footer class="bg-dark">
			<div class="container">
				<div class="row">
					<!-- 二维码 -->
					<div class="col-4 qrcode">
						<img src="https://uploadfiles.nowcoder.com/app/app_download.png" class="img-thumbnail" style="width:136px;" />
					</div>
					<!-- 公司信息 -->
					<div class="col-8 detail-info">
						<div class="row">
							<div class="col">
								<ul class="nav">
									<li class="nav-item">
										<a class="nav-link text-light" href="#">关于我们</a>
									</li>
									<li class="nav-item">
										<a class="nav-link text-light" href="#">加入我们</a>
									</li>
									<li class="nav-item">
										<a class="nav-link text-light" href="#">意见反馈</a>
									</li>
									<li class="nav-item">
										<a class="nav-link text-light" href="#">企业服务</a>
									</li>
									<li class="nav-item">
										<a class="nav-link text-light" href="#">联系我们</a>
									</li>
									<li class="nav-item">
										<a class="nav-link text-light" href="#">免责声明</a>
									</li>
									<li class="nav-item">
										<a class="nav-link text-light" href="#">友情链接</a>
									</li>
								</ul>
							</div>
						</div>
						<div class="row">
							<div class="col">
								<ul class="nav btn-group-vertical company-info">
									<li class="nav-item text-white-50">
										公司地址:北京市朝阳区大屯路东金泉时代3-2708北京牛客科技有限公司
									</li>
									<li class="nav-item text-white-50">
										联系方式:010-60728802(电话)&nbsp;&nbsp;&nbsp;&nbsp;admin@nowcoder.com
									</li>
									<li class="nav-item text-white-50">
										牛客科技©2018 All rights reserved
									</li>
									<li class="nav-item text-white-50">
										京ICP备14055008号-4 &nbsp;&nbsp;&nbsp;&nbsp;
										<img src="http://static.nowcoder.com/company/images/res/ghs.png" style="width:18px;" />
										京公网安备 11010502036488号
									</li>
								</ul>
							</div>
						</div>
					</div>
				</div>
			</div>
		</footer>
	</div>

	<script src="https://code.jquery.com/jquery-3.3.1.min.js" crossorigin="anonymous"></script>
	<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" crossorigin="anonymous"></script>
	<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" crossorigin="anonymous"></script>
	<script th:src="@{/js/global.js}"></script>
	<script th:src="@{js/index.js}"></script>
</body>
</html>

4.2 在 controller 包下新建 HomeController 类

  • 省略 Controller 的访问路径,直接访问方法即可
  • 在查询的时候调用 Service,因此注入 DiscussPostService
  • 注入 UserService:通过 discussPostService 查询到数据中的只是 userId,通过 UserService 把 user的详细数据查询到
package com.example.demo.controller;
import com.example.demo.entity.DiscussPost;
import com.example.demo.service.DiscussPostService;
import com.example.demo.service.UserService;
import org.apache.catalina.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Controller
public class HomeController {

    //在查询的时候调用 Service,因此注入 DiscussPostService
    @Autowired
    private DiscussPostService discussPostService;
    //通过 discussPostService 查询到数据中的只是 userId,通过 UserService 把 user的详细数据查询到
    @Autowired
    private UserService userService;

    @RequestMapping(path = "/index", method = RequestMethod.GET)//访问首页路径
    public String getIndexPage(Model model) {
        //只是查询到 userId,不是用户名,但是我们需要展示用户名
        List<DiscussPost> list = discussPostService.findDiscussPosts(0,0,10);
        //遍历集合,针对每一个 DiscussPost 的 userId 查询到 user,再把数据组装放到新的集合返回给页面
        //新建集合,能够封装 DiscussPost 和 User 对象
        List<Map<String, Object>> discussPosts = new ArrayList<>();
        if(list != null) {
            for (DiscussPost post : list) {
                Map<String, Object> map = new HashMap<>();//最终结果放到 Map 中,实例化 Map
                map.put("post", post);
                User user = userService.findUserById(post.getUserId());//得到 user 的完整数据
                map.put("user", user);
                discussPosts.add(map);
            }
        }
        model.addAttribute("discussPosts", discussPosts);
        return "/index";//返回模板路径
    }
}

4.3 封装分页相关的信息

在 entity 包下新建 Page类:

package com.example.demo.entity;

/**
 * 封装分页相关的信息.
 */
public class Page {

    // 当前页码
    private int current = 1;
    // 显示上限
    private int limit = 10;
    // 数据总数(用于计算总页数)
    private int rows;
    // 查询路径(用于复用分页链接)
    private String path;

    public int getCurrent() {
        return current;
    }

    public void setCurrent(int current) {
        if (current >= 1) {
            this.current = current;
        }
    }

    public int getLimit() {
        return limit;
    }

    public void setLimit(int limit) {
        if (limit >= 1 && limit <= 100) {
            this.limit = limit;
        }
    }

    public int getRows() {
        return rows;
    }

    public void setRows(int rows) {
        if (rows >= 0) {
            this.rows = rows;
        }
    }

    public String getPath() {
        return path;
    }

    public void setPath(String path) {
        this.path = path;
    }

    /**
     * 获取当前页的起始行
     *
     * @return
     */
    public int getOffset() {
        // current * limit - limit
        return (current - 1) * limit;
    }

    /**
     * 获取总页数
     *
     * @return
     */
    public int getTotal() {
        // rows / limit [+1]
        if (rows % limit == 0) {
            return rows / limit;
        } else {
            return rows / limit + 1;
        }
    }

    /**
     * 获取起始页码:最近的两页
     *
     * @return
     */
    public int getFrom() {
        int from = current - 2;
        return from < 1 ? 1 : from;
    }

    /**
     * 获取结束页码:同样也是两页
     *
     * @return
     */
    public int getTo() {
        int to = current + 2;
        int total = getTotal();
        return to > total ? total : to;
    }

}

4.4 改进 Controller,支持分页功能(HomeController 类)

  • 分页会传入分页的条件,使用 Page 进行分装
  • 设置分页总行数、分页访问路径
  • 这时候查询帖子的时候就可以动态的写入:获取当前页的起始行——page.getOffset(), 总页码—— page.getLimit()
  • 方法调用之前, SpringMVC 会自动实例化 Model 和 Page ,并将 Page 注入 Model,所以,在 thymeleaf 中可以直接访问 Page 对象中的数据.
package com.example.demo.controller;
import com.example.demo.entity.DiscussPost;
import com.example.demo.entity.Page;
import com.example.demo.entity.User;
import com.example.demo.service.DiscussPostService;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Controller
public class HomeController {

    //在查询的时候调用 Service,因此注入 DiscussPostService
    @Autowired
    private DiscussPostService discussPostService;

    //通过 discussPostService 查询到数据中的只是 userId,通过 UserService 把 user的详细数据查询到
    @Autowired
    private UserService userService;

    @RequestMapping(path = "/index", method = RequestMethod.GET)//访问首页路径
    public String getIndexPage(Model model, Page page) {
        // 方法调用之前,SpringMVC会自动实例化Model和Page,并将Page注入Model.
        // 所以,在thymeleaf中可以直接访问Page对象中的数据.
        //加入分页功能
        page.setRows(discussPostService.findDiscussPostRows(0));//设置总行数
        page.setPath("/index");//访问路径

        //只是查询到 userId,不是用户名,但是我们需要展示用户名
        List<DiscussPost> list = discussPostService.findDiscussPosts(0, page.getOffset(), page.getLimit());
        //遍历集合,针对每一个 DiscussPost 的 userId 查询到 user,再把数据组装放到新的集合返回给页面
        //新建集合,能够封装 DiscussPost 和 User 对象
        List<Map<String, Object>> discussPosts = new ArrayList<>();
        if (list != null) {
            for (DiscussPost post : list) {
                Map<String, Object> map = new HashMap<>();//最终结果放到 Map 中,实例化 Map
                map.put("post", post);
                User user = userService.findUserById(post.getUserId());//得到 user 的完整数据
                map.put("user", user);
                discussPosts.add(map);
            }
        }
        model.addAttribute("discussPosts", discussPosts);
        return "/index";//返回模板路径
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

奋斗小温

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值