springboot3+vue3项目实例练习1
项目概述
项目名称: 大事件管理系统
技术栈: SpringBoot3+Vue3
核心功能: 用户管理、文章管理、分类管理、文件上传、登录认证等。
目标用户: 管理员或普通用户,用于管理文章和分类。
功能模块
用户管理
功能描述:
用户注册、登录、个人信息管理。
用户头像上传(使用阿里云OSS)。
用户密码加密存储(使用MD5加密)。
相关表:
user 表:存储用户信息(用户名、密码、昵称、邮箱、头像等)。
相关工具类:
Md5Util:用于密码的MD5加密和校验。
AliOssUtil:用于用户头像上传到阿里云OSS。
登录与认证
功能描述:
用户登录后生成JWT令牌,用于后续请求的身份验证。
使用JWT进行权限校验,未登录用户无法访问受保护的资源。
相关工具类:
JwtUtil:用于生成和解析JWT令牌。
ThreadLocalUtil:用于存储当前登录用户信息,方便在业务逻辑中获取用户信息。
分类管理
功能描述:
管理员可以创建、编辑、删除文章分类。
分类信息包括分类名称、分类别名等。
相关表:
category 表:存储分类信息。
实体类:
Category:分类的实体类,包含分类名称、别名、创建人等信息。
文章管理
功能描述:
用户可以创建、编辑、删除文章。
文章信息包括标题、内容、封面图片、状态(草稿或已发布)、分类等。
相关表:
article 表:存储文章信息。
实体类:
Article:文章的实体类,包含标题、内容、封面图片、状态等信息。
文件上传
功能描述:
用户上传头像或文章封面图片时,使用阿里云OSS进行文件存储。
上传成功后返回文件的公网访问地址。
相关工具类:
AliOssUtil:封装了阿里云OSS的上传逻辑。
分页查询
功能描述:
支持文章和分类的分页查询。
返回分页结果,包括总条数和当前页数据。
相关类:
PageBean:分页返回结果对象,包含总条数和当前页数据集合。
统一响应格式
功能描述:
所有接口返回统一的响应格式,包含状态码、提示信息和数据。
相关类:
Result:统一响应结果类,包含状态码、提示信息和数据。
数据库设计
-- 创建数据库
create database big_event;
-- 使用数据库
use big_event;
-- 用户表
create table user (
id int unsigned primary key auto_increment comment 'ID',
username varchar(20) not null unique comment '用户名',
password varchar(32) comment '密码',
nickname varchar(10) default '' comment '昵称',
email varchar(128) default '' comment '邮箱',
user_pic varchar(128) default '' comment '头像',
create_time datetime not null comment '创建时间',
update_time datetime not null comment '修改时间'
) comment '用户表';
-- 分类表
create table category(
id int unsigned primary key auto_increment comment 'ID',
category_name varchar(32) not null comment '分类名称',
category_alias varchar(32) not null comment '分类别名',
create_user int unsigned not null comment '创建人ID',
create_time datetime not null comment '创建时间',
update_time datetime not null comment '修改时间',
constraint fk_category_user foreign key (create_user) references user(id) -- 外键约束
);
-- 文章表
create table article(
id int unsigned primary key auto_increment comment 'ID',
title varchar(30) not null comment '文章标题',
content varchar(10000) not null comment '文章内容',
cover_img varchar(128) not null comment '文章封面',
state varchar(3) default '草稿' comment '文章状态: 只能是[已发布] 或者 [草稿]',
category_id int unsigned comment '文章分类ID',
create_user int unsigned not null comment '创建人ID',
create_time datetime not null comment '创建时间',
update_time datetime not null comment '修改时间',
constraint fk_article_category foreign key (category_id) references category(id),-- 外键约束
constraint fk_article_user foreign key (create_user) references user(id) -- 外键约束
)
后端代码
用户的实体类代码
package com.example.day0225.pojo;
//import net.minidev.json.annotate.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnore;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern;
import org.springframework.validation.annotation.Validated;
import java.time.LocalDateTime;
public class User {
// 实体参数校验
// 第一步实体类的成员变量上添加注解@NotNull/@NotEmpty/@Email
// 接口方法的实体参数上添加@Validated注解
@NotNull//值不能为null
private Integer id;//主键ID
private String username;//用户名
@JsonIgnore//让springmvc把当前对象转换成json字符串的时候,忽略password,最终的json字符串中就没有password这个属性了
private String password;//密码
@NotEmpty//值不能为null并且内容不为空
@Pattern(regexp = "^\\S{1,10}$")
private String nickname;//昵称
@NotEmpty
@Email//满足邮箱格式
private String email;//邮箱
private String userPic;//用户头像地址
private LocalDateTime createTime;//创建时间
private LocalDateTime updateTime;//更新时间
public User(LocalDateTime updateTime, LocalDateTime createTime, String userPic, String email, String nickname, String password, String username, Integer id) {
this.updateTime = updateTime;
this.createTime = createTime;
this.userPic = userPic;
this.email = email;
this.nickname = nickname;
this.password = password;
this.username = username;
this.id = id;
}
public User() {
}
public LocalDateTime getUpdateTime() {
return updateTime;
}
public void setUpdateTime(LocalDateTime updateTime) {
this.updateTime = updateTime;
}
public LocalDateTime getCreateTime() {
return createTime;
}
public void setCreateTime(LocalDateTime createTime) {
this.createTime = createTime;
}
public String getUserPic() {
return userPic;
}
public void setUserPic(String userPic) {
this.userPic = userPic;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
}
用户相关控制层代码
package com.example.day0225.controller;
import com.example.day0225.pojo.Result;
import com.example.day0225.pojo.User;
import com.example.day0225.service.UserService;
import com.example.day0225.utils.JwtUtil;
import com.example.day0225.utils.Md5Util;
import com.example.day0225.utils.ThreadLocalUtil;
import jakarta.validation.constraints.Pattern;
import org.hibernate.validator.constraints.URL;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/user")
@Validated
public class UserController {
@Autowired
private UserService userService;
@PostMapping("/register")
public Result register(@Pattern(regexp = "^\\S{5,16}$") String username, @Pattern(regexp = "^\\S{5,16}$")String password) {
//查询用户
User u =userService.findByUserName(username);
if (u == null) {
userService.register(username,password);
return Result.success();
}else{
//占用
return Result.error("用户名已被占用");
}
}
@PostMapping("/login")
public Result<String> login(@Pattern(regexp = "^\\S{5,16}$") String username, @Pattern(regexp = "^\\S{5,16}$")String password){
//根据用户名查询用户
User loginUser = userService.findByUserName(username);
//判断该用户是否存在
if(loginUser == null){
return Result.error("用户名错误");
}
//判断密码是否正确
if(Md5Util.getMD5String(password).equals(loginUser.getPassword())){
//登录成功
Map<String,Object> claims = new HashMap<>();
claims.put("id",loginUser.getId());
claims.put("username",loginUser.getUsername());
String token = JwtUtil.genToken(claims);
return Result.success(token);
}
return Result.error("密码错误");
}
@GetMapping("/userInfo")
public Result<User> userInfo(/*@RequestHeader(name ="Authorization") String token*/){
//根据用户名查询用户
// Map<String,Object> map = JwtUtil.parseToken(token);
// String username = (String) map.get("username");
Map<String,Object> map = ThreadLocalUtil.get();
String username = map.get("username").toString();
User user = userService.findByUserName(username);
return Result.success(user);
}
@PutMapping("/update")
public Result update (@RequestBody @Validated User user){
userService.update(user);
return Result.success();
}
// @URL对传进来的参数进行校验,判断是否为网页图片链接
@PatchMapping("/updateAvatar")
public Result updateAvatar(@RequestParam @URL String avatarUrl){
userService.updateAvatar(avatarUrl);
return Result.success();
}
@PatchMapping("/updatePwd")
public Result updatePwd(@RequestBody Map<String,String> params) {
//1.校验参数
String oldPwd = params.get("old_pwd");
String newPwd = params.get("new_pwd");
String rePwd = params.get("re_pwd");
if (!StringUtils.hasLength(oldPwd) || !StringUtils.hasLength(newPwd) || !StringUtils.hasLength(rePwd)){
return Result.error("缺少必要参数");
}
//校验原密码
//调用userService根据用户名拿到原密码,再和old_Pwd比对
Map<String,Object> map = ThreadLocalUtil.get();
String username = map.get("username").toString();
User loginUser = userService.findByUserName(username);
if (!loginUser.getPassword().equals(Md5Util.getMD5String(oldPwd))){
return Result.error("原密码填写不正确");
}
//newPwd和rePwd是否一致
if(!rePwd.equals(newPwd)){
return Result.error("两次填写的新密码不一致");
}
//2.调用service完成密码更新
userService.updatePwd(newPwd);
return Result.success();
}
}
用户service层代码
package com.example.day0225.service;
import com.example.day0225.pojo.User;
import org.springframework.stereotype.Service;
@Service
public interface UserService {
//根据用户名查询
User findByUserName(String username);
//注册
void register(String username, String password);
//更新
void update(User user);
//更新头像
void updateAvatar(String avatarUrl);
//更新密码
void updatePwd(String newPwd);
}
serviceImpl实现
package com.example.day0225.service.impl;
import com.example.day0225.mapper.UserMapper;
import com.example.day0225.pojo.User;
import com.example.day0225.service.UserService;
import com.example.day0225.utils.Md5Util;
import com.example.day0225.utils.ThreadLocalUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.Map;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public User findByUserName(String username) {
User u = userMapper.findByUserName(username);
return userMapper.findByUserName(username);
}
@Override
public void register(String username, String password) {
//加密
String md5String = Md5Util.getMD5String(password);
//添加
userMapper.add(username,md5String);
}
@Override
public void update(User user) {
user.setUpdateTime(LocalDateTime.now());
userMapper.update(user);
}
@Override
public void updateAvatar(String avatarUrl) {
Map<String,Object> map = ThreadLocalUtil.get();
Integer id = (Integer) map.get("id");
userMapper.updateAvatar(avatarUrl,id);
}
@Override
public void updatePwd(String newPwd) {
Map<String,Object> map = ThreadLocalUtil.get();
Integer id = (Integer) map.get("id");
userMapper.updatePwd(Md5Util.getMD5String(newPwd),id);
}
}
用户mapper层
package com.example.day0225.mapper;
import com.example.day0225.pojo.User;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
@Mapper
public interface UserMapper {
//根据用户名查询用户
@Select("select * from user where username=#{username}")
User findByUserName(String username);
//添加
@Insert("insert into user(username,password,create_time,update_time)" +
" values(#{username},#{password},now(),now()) ")
void add(String username, String password);
@Update("update user set nickname = #{nickname},email = #{email},update_time = #{updateTime} where id = #{id}")
void update(User user);
@Update("update user set user_pic = #{avatarUrl},update_time=now() where id = #{id}")
void updateAvatar(String avatarUrl,Integer id);
@Update("update user set password = #{md5String},update_time = now() where id = #{id}")
void updatePwd(String md5String,Integer id);
}

浙公网安备 33010602011771号