微博项目
项目概述
该项目是一款社交媒体应用,用户可以在平台上发表短文、图片等信息,分享自己的想法、心情和生活。微博的用户群体广泛,包括个人、娱乐明星、公司、政府官方等。
项目功能
-
用户管理
用户可以注册微博账号,登录登出微博网站。
-
发布微博
用户可以在平台上发布文本形式的微博。
-
查看微博
用户可以查看所有的微博。
-
评论功能
用户可以对所有微博进行评论,并且查看某条微博的所有评论。
数据库设计
- 本项目共计3张表
- 用户表:存储用户信息;
- 微博表:存储发布的微博信息;
- 评论表:存储每条微博的评论。
- 表关系
- 用户表和微博表:一对多,一个用户可以发布多条微博,一条微博只能归属于一个用户;
- 用户表和评论表:一对多,一个用户可以发布多条评论,一条评论只能归属于一个用户;
- 微博表和评论表:一对多,一条微博下可以有多条评论,一条评论只能归于与一条微博。
- 表字段设计
- 用户表user
- 用户编号:id
- 用户名:username
- 密码:password
- 昵称:nickname
- 注册时间:created
- 微博表weibo
- 微博编号:id
- 微博内容:content
- 发布时间:created
- 用户编号:user_id
- 评论表comment
- 评论编号:id
- 评论内容:content
- 评论时间:created
- 用户编号:user_id
- 微博编号:weibo_id
- 用户表user
项目实现
1 建库建表
-
库名:blog
-
SQL语句
DROP DATABASE IF EXISTS blog; CREATE DATABASE blog; USE blog; CREATE TABLE user( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50), password VARCHAR(50), nickname VARCHAR(50), created TIMESTAMP ); CREATE TABLE weibo( id INT PRIMARY KEY AUTO_INCREMENT, content VARCHAR(255), created TIMESTAMP, user_id INT ); CREATE TABLE comment( id INT PRIMARY KEY AUTO_INCREMENT, content VARCHAR(255), created TIMESTAMP, user_id INT, weibo_id INT );
2 项目准备
-
创建工程weibo,3个钩,SpringBoot版本为2.7.11;
-
application.properties中配置数据库连接信息
spring.datasource.url=jdbc:mysql://localhost:3306/blog?serverTimezone=Asia/Shanghai&characterEncoding=utf8 spring.datasource.username=root spring.datasource.password=root
-
application.properties中配置MyBatis-xml映射路径配置
# 设置MyBatis框架的映射(Mapper)配置文件的位置 mybatis.mapper-locations=classpath:mappers/*.xml
-
将weibo-html中所有html文件拷贝到当前工程的static目录下
- index.html 微博首页
- reg.html 微博注册页
- login.html 微博登录页
- insert.html 发布微博页面
- detail.html 微博详情页
-
启动工程浏览器测试
http://localhost:8080/index.html
3 用户模块
3.1 注册功能
-
注册API接口
-
请求地址:/v1/users/reg
-
请求方法:POST
-
请求体数据:username、passsword、nickname
-
返回响应:int
返回值为1,代表注册成功
返回值为2,代表用户名已存在
-
-
功能实现
-
工程目录下新建包Package,com.liner.weibo.pojo.entity
-
创建VO的Package和DTO的Package
com.liner.weibo.pojo.vo
com.liner.weibo.pojo.dto
-
entity中创建3个实体类
-
entity.User 封装用户表实体类
public class User { private Integer id; private String username; private String password; private String nickname; private Date created; // Getter() Setter() toString() }
-
entity.Weibo 封装微博表实体类
public class Weibo { private Integer id; private String content; private Date created; private Integer userId; // Getter() Setter() toString() }
-
entity.Comment 封装评论表实体类
public class Comment { private Integer id; private String content; private Date created; private Integer userId; private Integer weiboId; // Getter() Setter() toString() }
-
-
pojo.dto下新建UserRegDTO,为客户端向服务器端传递的数据
public class userRegDTO { private String username; private String password; private String nickname; // Getter() Setter() toString() }
-
实现注册功能 controller.UserController
@RestController @RequestMapping("/v1/users/") public class UserController { @RequestMapping("reg") public int reg(@RequestBody UserRegDTO userRegDTO){ System.out.println("userRegDTO = " + userRegDTO); // 用户表中查询该用户名是否被占用 return 1; } }
-
重启工程浏览器测试一下
-
处理mapper相关
-
7-1 创建mapper.UserMapper
public interface UserMapper { UserVO selectByUsername(String username); }
-
7-2 创建config.MybatisConfig
@Configuration @MapperScan("com.liner.weibo.mapper") public class MybatisConfig { }
-
7-3 创建pojo.vo.UserVO 为数据库查询数据给到客户端
public class UserVO { /** 需要数据: id,后期登录完成后用户要发微博需要使用用户id password,登录时的密码校验也需要用到 nickname,登录成功后需要在页面展示用户的昵称 */ private Integer id; private String password; private String nickname; // 生成setter() getter() toString() }
-
7-4 创建mappers目录,拷贝xml文件重命名为 UserMapper.xml
<!-- 填写namespace,写UserMapper的绝对路径 --> <mapper namespace="com.liner.weibo.mapper.UserMapper"> <select id="selectByUsername" resultType="com.liner.weibo.pojo.vo.UserVO"> SELECT id,password,nickname FROM user WHERE username=#{username} </select> </mapper>
-
-
controller.UserController 处理注册请求
@RestController @RequestMapping("/v1/users/") public class UserController { @Autowired(required = false) UserMapper mapper; @RequestMapping("reg") public int reg(@RequestBody UserRegDTO userRegDTO){ System.out.println("userRegDTO = " + userRegDTO); /**判断用户名是否被占用 */ UserVO userVO = mapper.selectByUsername(userRegDTO.getUsername()); if (userVO != null){ return 2; // 用户名已存在 } // 存入数据:存入数据永远使用实体类 User user = new User(); // 把DTO中已有的属性复制到实体类中 BeanUtils.copyProperties(userRegDTO, user); // 给id和created赋值,id会自动赋值 user.setCreated(new Date()); // 存入数据库 mapper.insert(user); return 1; } }
-
mapper.UserMapper 封装映射接口
int insert(User user);
-
mappers.UserMapper.xml 定义xml配置文件
<insert id="insert"> INSERT INTO user VALUES (NULL,#{username},#{password},#{nickname},#{created}) </insert>
-
重启工程浏览器测试
-
3.2 登录功能
-
登录功能API接口
-
请求的地址:/v1/users/login
-
请求方法:POST
-
请求体数据:用户名username、密码password
-
返回响应:整型int
1 - 登录成功
2 - 密码错误
3 - 用户名不存在
-
-
功能实现
-
controller.UserController 处理请求
@RequestMapping("login") public int login(@RequestBody UserLoginDTO userLoginDTO){ System.out.println("userLoginDTO = " + userLoginDTO); return 1; }
-
pojo.dto.UserLoginDTO 封装登录的DTO
public class UserLoginDTO { private String username; private String password; // 生成setter() getter() toString() }
-
controller.UserController 继续处理请求
@RequestMapping("login") public int login(@RequestBody UserLoginDTO userLoginDTO){ System.out.println("userLoginDTO = " + userLoginDTO); UserVO userVO = mapper.selectByUsername(userLoginDTO.getUsername()); if (userVO != null){ if (userVO.getPassword().equals(userLoginDTO.getPassword())){ return 1; // 登录成功 } return 2; // 密码错误 } return 3; // 用户名不存在 }
-
重启工程浏览器测试
-
3.3 判断登录状态
-
说明
进入首页时,会自动向后端发请求,获取当前用户的登录状态,分为以下两种情况:
如果未登录,则显示注册登录页面;
如果是登录状态,则显示欢迎xxx回来,并显示退出登录按钮。
-
未登录显示首页面
-
登录显示首页面
-
-
API文档
- 请求地址:/v1/users/currentUser
- 请求方法:GET
- 查询字符串:无
- 返回响应
- 用户对象:表示是登录状态,示例:UserVO{id=1,nickname=“赵丽颖”,password=“123456”}
- 空值null: 表示未登录状态
-
功能实现
-
controller.UserController 处理请求
@RequestMapping("currentUser") public UserVO currentUser(){ /** 1.如何获取当前登录用户的对象?使用会话技术 在登录成功时将UserVO存入会话中(服务器内存中),在此controller中来获取该值 1.1 获取到UserVO: 登录状态 1.2 获取不到UserVO: 未登录状态 2.说明 每个客户端都会有一个专属的会话对象,所以需要在登录成功的时候存入会话对象,后期再获取 */ return null; }
-
修改登录功能的 controller ,保存登录状态
@RequestMapping("login") // 1.添加会话参数 public int login(@RequestBody UserLoginDTO userLoginDTO, HttpSession session){ System.out.println("userLoginDTO = " + userLoginDTO); UserVO userVO = mapper.selectByUsername(userLoginDTO.getUsername()); if (userVO != null){ if (userVO.getPassword().equals(userLoginDTO.getPassword())){ // 2.登录成功后将UserVO保存到当前客户端的会话状态中 session.setAttribute("user", userVO); return 1; // 登录成功 } return 2; // 密码错误 } return 3; // 用户名不存在 }
-
完成获取当前登录状态的controller 获取登录状态
@RequestMapping("currentUser") // 1.添加会话参数 public UserVO currentUser(HttpSession session){ // 2.从当前客户端对应的会话对象中取出登录的UserVO UserVO user = (UserVO) session.getAttribute("user"); /** 如果登录过返回user对象,未登录过返回null */ return user; }
-
重启工程测试
-
3.4 退出登录功能
-
说明
用户登录成功后,点击退出登录,则返回首页,并为未登录的状态。
-
API文档
点击退出登录按钮时
- 请求地址:/v1/users/logout
- 请求方法:GET
- 返回值:无
-
功能实现
-
controller.UserController 处理退出登录请求
// 退出登录功能 @RequestMapping("logout") public void logOut(HttpSession session){ session.removeAttribute("user"); }
-
重启工程测试
-
4 微博模块
4.1 发布微博功能
insert.html
-
接口说明
-
请求地址:/v1/weibo/insert
-
请求方法:POST
-
请求体数据:微博内容content
-
返回值:
1 - 发布成功;
2 - 未登录,发布微博失败。
-
-
- 功能实现
-
controller.WeiboController 处理发布微博请求
@RestController @RequestMapping("/v1/weibo/") public class WeiboController { // 发布微博功能 @RequestMapping("insert") // 1.封装发布微博的数据对象 public int insert(@RequestBody WeiboDTO weiboDTO, HttpSession session){ // 2.从会话对象中得到登录成功时保存的用户对象 UserVO user = (UserVO) session.getAttribute("user"); if (user == null){ //未登录 return 2; } return 1; } }
-
pojo.dto.WeiboDTO 封装客户端传递给服务端的数据
public class WeiboDTO { private String content; // 生成setter() getter() toString() }
-
controller.WeiboController 处理发布微博请求
@RestController @RequestMapping("/v1/weibo/") public class WeiboController { // 5.装配 @Autowired(required = false) WeiboMapper weiboMapper; // 发布微博功能 @RequestMapping("insert") // 1.封装发布微博的数据对象 public int insert(@RequestBody WeiboDTO weiboDTO, HttpSession session){ // 2.从会话对象中得到登录成功时保存的用户对象 UserVO user = (UserVO) session.getAttribute("user"); if (user == null){ //未登录 return 2; } // 3.将数据存入微博表,注意复制属性 Weibo w = new Weibo(); BeanUtils.copyProperties(weiboDTO, w); w.setCreated(new Date()); w.setUserId(user.getId()); // 4.通过mapper存入数据表 weiboMapper.insert(w); return 1; } }
-
mapper.WeiboMapper 定义映射入口
@Mapper public interface WeiboMapper { // 将数据存入微博表 int insert(Weibo weibo); }
-
mappers.WeiboMapper.xml 定义xml配置文件
<mapper namespace="com.liner.weibo.mapper.WeiboMapper"> <insert id="insert"> INSERT INTO weibo VALUES (NULL,#{content},#{created},#{userId}) </insert> </mapper>
-
重启工程测试
SELECT * FROM weibo;
4.2 首页微博列表展示
index.html
-
说明
用户进入首页会自动向后端发请求获取所有微博,用户可以看到所有的微博,无须登录。
-
API文档
- 请求地址:/v1/weibo/selectIndex
- 请求方法:GET
- 查询参数:无
- 返回响应:List
-
功能实现
-
controller.WeiboController 处理查询微博请求
// 首页展示微博列表 @RequestMapping("selectIndex") public List<WeiboIndexVO> selectIndex(){ return weiboMapper.selectIndex();
-
-
pojo.vo.WeiboIndexVO 封装服务端需要返回给客户端的数据
public class WeiboIndexVO { // 显示微博的id content , 再显示一个nickname private Integer id; private String content; private String nickname; }
-
mapper.WeiboMapper 定义映射接口
// 首页微博列表数据 List<WeiboIndexVO> selectIndex();
-
mappers.WeiboMapper.xml 定义xml配置文件
<select id="selectIndex" resultType="com.liner.weibo.pojo.vo.WeiboIndexVO"> SELECT w.id, w.content, u.nickname FROM weibo w JOIN user u ON w.user_id=u.id; </select>
-
重启工程测试
4.3 微博详情页功能
-
说明
用户在列表页点击微博,进入微博详情页,会显示该条微博的内容、发布者昵称、图片、发布时间等信息。
-
API文档
- 请求地址:/v1/weibo/selectById?id=微博id
- 请求方法:GET
- 查询参数:?id=微博id
- 返回响应:WeiboDetailVO
-
功能实现
-
controller.WeiboController 处理微博详情页查询请求
// 微博详情页列表 @RequestMapping("selectById") public WeiboDetailVO selectById(int id){ return weiboMapper.selectById(id); }
-
pojo.vo.WeiboDetailVO 封装服务端返回给客户端的数据
public class WeiboDetailVO { // 原则:用啥查啥 private Integer id; private String content; @JsonFormat(pattern = "yyyy年MM月dd号 HH点mm分ss秒", timezone = "GMT+8") private Date created; private String nickname; // setter() getter() toString() }
-
mapper.WeiboMapper 定义映射接口
// 微博详情页数据 WeiboDetailVO selectById(int id);
-
mappers.WeiboMapper.xml 定义xml配置文件
<select id="selectById" resultType="com.liner.weibo.pojo.vo.WeiboDetailVO"> SELECT w.id, w.content,w.created, u.nickname FROM weibo w JOIN user u ON w.user_id=u.id WHERE w.id=#{id} </select>
-
重启工程测试
-
5 评论模块
5.1 发布评论功能
-
说明
用户在微博详情页可以输入内容,对此条微博内容进行评论,必须为登录状态。
-
API文档
用户点击评论按钮时触发
-
请求地址:/v1/comment/insert
-
请求方法:POST
-
请求体数据:评论内容comment、微博的id
-
响应内容:整型int
1 - 评论成功
2 - 未登录,不能评论,前端会跳转到登录页面
-
-
功能实现
-
controller.CommentController 处理发布评论的请求
@RestController @RequestMapping("/v1/comment/") public class CommentController { // 发表评论 @RequestMapping("insert") public int insert(@RequestBody CommentDTO commentDTO, HttpSession session){ return 1; } }
-
pojo.dto.CommentDTO 封装客户端传递给服务端的数据
public class CommentDTO { // 评论内容,微博ID private String content; private Integer weiboId; // setter() getter() toString() }
-
mapper.CommentMapper 定义映射接口
// 存入评论表 int insert(Comment comment);
-
mappers.CommentMapper.xml 定义xml配置文件
<mapper namespace="com.liner.weibo.mapper.CommentMapper"> <insert id="insert"> INSERT INTO comment VALUES (NULL,#{content},#{created},#{userId},#{weiboId}) </insert> </mapper>
-
controller.CommentController 继续处理发布评论请求
@RestController @RequestMapping("/v1/comment/") public class CommentController { @Autowired(required = false) CommentMapper commentMapper; // 发表评论 @RequestMapping("insert") public int insert(@RequestBody CommentDTO commentDTO, HttpSession session){ System.out.println("commentDTO = " + commentDTO); // 1.校验登录状态 UserVO userVO = (UserVO) session.getAttribute("user"); if (userVO == null){ return 2; } // 2.利用实体类存入数据 Comment c = new Comment(); BeanUtils.copyProperties(commentDTO, c); c.setCreated(new Date()); c.setUserId(userVO.getId()); commentMapper.insert(c); return 1; } }
-
重启工程测试
select * from comment;
-
5.2 获取评论列表
-
说明
用户进入微博详情页之后,会显示该条微博的所有评论,此功能无须登录。
-
API文档
- 请求地址:/v1/comment/selectByWeiboId?id=微博id
- 请求方法:GET
- 查询参数:?id=微博id
- 响应内容:List
-
功能实现
-
controller.CommentController 处理查询微博评论请求
// 获取评论 @RequestMapping("selectByWeiboId") public List<CommentVO> selectByWeiboId(int id){ return commentMapper.selectByWeiboId(id); }
-
pojo.vo.CommentVO 封装服务端传递给客户端的数据
public class CommentVO { private Integer id; private String content; @JsonFormat(pattern = "yyyy/MM/dd HH:mm:ss", timezone = "GMT+8") private Date created; private String nickname; // setter() getter() toString() }
-
mapper.CommentMapper 定义映射接口
List<CommentVO> selectByWeiboId(int id);
-
mappers.CommentMapper.xml 定义xml配置文件
<select id="selectByWeiboId" resultType="com.liner.weibo.pojo.vo.CommentVO"> SELECT c.id,c.content,c.created,u.nickname FROM comment c JOIN user u ON c.user_id=u.id WHERE weibo_id=#{id} </select>
-
重启工程到微博详情页测试
-