仿牛客社区项目(第一章)

131 阅读9分钟

第一章:初始 SpringBoot,开发社区首页 仿牛客社区项目开发首页功能 本章实现的是仿牛客社区的首页访问功能,项目按照MVC的编程思想,分为 dao 层,service 层,controller 层 和 view 层进行开发。

开发流程

1次请求的执行过程 分步实现

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

一. 实体引入 这里将列举本章涉及到的实体类,分别为用户 User 类、帖子 DiscussPost 类、分页 Page 类。

  1. User类 User 类用于封装用户的基本信息,在工程下创建 entity 实体包,在此包下创建 User 类,User 类的相关代码如下:

public class User {

private int id;
private String username;
private String password;
private String salt; // 盐
private String email;
private int type; // 0:普通用户 1:超级管理员 2:版主
private int status; // 0: 未激活 1:已激活
private String activationCode; // 激活码
private String headerUrl; // 用户头像url地址
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 +
            '}';
}

}

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 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109

  1. DiscussPost 类 DiscussPost 类用于封装帖子的相关信息,在 entity 包中创建 DiscussPost 类, DiscussPost 类的相关代码如下:

public class DiscussPost {

private int id;
private int userId;
private String title;
private String content;
private int type; // 0:普通 1:置顶
private int status; //  0:正常 1:精华  2:拉黑
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 +
            '}';
}

}

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 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99

  1. Page类 Page类对分页信息进行封装,以便在功能上实现分页的功能。 在分页 Page 类除了基本的信息外,还另外提供了几个方法:

getOffset():获取当前页的起始行 getTotal():获取总页数 getFrom():获取起始页码 getTo():获取结束页码 在entity包下创建 Page类,Page类的相关代码如下:

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() {
    return (current - 1) * limit;
}

/**
 * 获取总页数
 *
 * @return
 */
public int getTotal() {
    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;
}

}

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 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96

二、 配置文件 application.properties 相关代码如下:

ServerProperties

server.port=8080

项目名

server.servlet.context-path=/community

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=abc123 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.nowcoder.community.entity mybatis.configuration.useGeneratedKeys=true mybatis.configuration.mapUnderscoreToCamelCase=true

logger

logging.level.com.nowcoder.community=debug

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22

三、 dao层 dao层主要的功能为与MySQL进行交互,专门用来封装我们对于实体类的数据库的访问,就是增删改查,不加业务逻辑。

  1. UserMapper的实现 UserMapper的功能: 对数据库中的User表进行增删改查。 在工程下创建 dao 包,创建 UserMapper 接口,相关代码如下:

@Mapper public interface UserMapper {

User selectById(int id);

User selectByName(String username);

User selectByEmail(String email);

int insertUser(User user);

int updateStatus(int id, int status);

int updateHeader(int id, String headerUrl);

int updatePassword(int id, String password);

}

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17

在 resources 下创建 mapper 包,在此包下创建 user-mapper.xml,相关代码如下:

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

<sql id="insertFields">
    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>

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 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54

  1. DiscussPostMapper的实现 DiscussPostMapper的功能: DiscussPostMapper 对数据库中的DiscussPost表进行增删改查,本章只先实现两个功能 :

根据userId、offset、limit信息查询帖子集合,返回对应的实体类集合。 根据userId查询帖子数量。 在dao包下创建DiscussPost接口,相关代码如下:

@Mapper public interface DiscussPostMapper {

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

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

} 1 2 3 4 5 6 7 8 9 10

在 resources的 mapper 包下创建 discussPost-mapper.xml,相关代码如下:

<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>

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 27 28 29 30 31 32

四、 service层

  1. UserService类 service 层属于三层架构中的业务层,业务逻辑是放在 service 中的。 本章需要实现的功能是根据 User 实体类的 id 返回User 实体类。 在工程下创建 service 包,在此包下创建 UserService 类,相关代码如下:

@Service public class UserService implements CommunityConstant {

@Autowired
private UserMapper userMapper;

public User findUserById(int id){
    return userMapper.selectById(id);

} 1 2 3 4 5 6 7 8 9

  1. DiscussPost类 DiscussPost类提供与帖子操作相关的服务,本章需要实现的 功能是根据 userId,offset,limit 信息查询帖子集合;根据userId查询帖子集合总行数。 在 service 包下创建 DiscussPost 类,相关代码如下:

@Service public class DiscussPostService {

@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);
}

} 1 2 3 4 5 6 7 8 9 10 11 12 13 14

五、 controller层 controller,从字面上理解是控制器,所以它是负责业务调度的,所以在这一层应写一些业务的调度代码,是连接前端和后端的纽带。 UserController 在本章需要实现的功能是接受浏览器发送过来的请求,然后去响应 thymeleaf 的模板页面 index.html。 在工程下创建 controller 包,在此包下创建

@Controller public class HomeController {

@Autowired
private DiscussPostService discussPostService;

@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");

    List<DiscussPost> list = discussPostService.findDiscussPosts(0, page.getOffset(), page.getLimit());
    List<Map<String, Object>> discussPosts = new ArrayList<>();
    if (list != null) {
        for (DiscussPost post : list) {
            Map<String, Object> map = new HashMap<>();
            map.put("post", post);
            User user = userService.findUserById(post.getUserId());
            map.put("user", user);
            discussPosts.add(map);
        }
    }

    model.addAttribute("discussPosts", discussPosts);
    return "/index";
}

}

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 27 28 29 30 31 32

六、功能演示 启动 CommunityApplication类,在浏览器中输入地址http://localhost:8080/community/index

此时显示的是前端的首页:

分页功能演示:

**总结:**本章的主要内容是通过MVC思想来实现首页的帖子数目的显示,以及实现分页的功能。

创作不易,如果有帮助到你,请给文章点个赞和收藏,让更多的人看到!!! 关注博主不迷路,内容持续更新中。