❤ 作者主页: 欢迎来到我的技术博客😎
❀ 个人介绍:大家好,本人热衷于 Java后端开发,欢迎来交流学习哦!( ̄▽ ̄)~*
🍊 如果文章对您有帮助,记得 关注、 点赞、 收藏、 评论⭐️⭐️⭐️
📣 您的支持将是我创作的动力,让我们一起加油进步吧!!!🎉🎉
第一章:初始 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 +
'}';
}
}
2. 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 +
'}';
}
}
3. 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;
}
}
二、 配置文件
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
三、 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);
}
在 resources
下创建 mapper
包,在此包下创建 user-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.nowcoder.community.dao.UserMapper">
<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>
</mapper>
2. 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);
}
在 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.nowcoder.community.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>
四、 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);
}
2. 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);
}
}
五、 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";
}
}
六、功能演示
启动 CommunityApplication
类,在浏览器中输入地址http://localhost:8080/community/index
此时显示的是前端的首页:
分页功能演示:
总结:本章的主要内容是通过MVC思想来实现首页的帖子数目的显示,以及实现分页的功能。
创作不易,如果有帮助到你,请给文章==点个赞和收藏==,让更多的人看到!!!
==关注博主==不迷路,内容持续更新中。