文章目录
- 博客管理系统
- 一、项目演示
- 二、项目介绍
- 三、系统部分功能截图
- 四、部分代码展示
- 五、底部获取项目(9.9¥带走)
博客管理系统
一、项目演示
博客系统
二、项目介绍
三个角色:游客 用户 管理员
游客可以浏览文章, 游客可以登录注册成用户,发布文章 管理自己的文章,评论和回复,点赞评论回复文章等
管理员可以对整个系统用户管理,文章管理,分类管理,角色权限管理,评论管理等等
2、项目技术
语言:java
框架:SpringBoot、MyBatis、JQuery、html
数据库:MySQL
三、系统部分功能截图
四、部分代码展示
package com.example.forum.config.shiro;import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Validator;
import com.example.forum.common.constant.CommonConstant;
import com.example.forum.entity.Permission;
import com.example.forum.entity.Role;
import com.example.forum.service.PermissionService;
import com.example.forum.service.RoleService;
import com.example.forum.service.UserService;
import com.example.forum.entity.User;
import com.example.forum.enums.CommonParamsEnum;
import com.example.forum.enums.TrueFalseEnum;
import com.example.forum.enums.UserStatusEnum;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;@Slf4j
public class MyRealm extends AuthorizingRealm {@Autowired@Lazyprivate UserService userService;@Autowired@Lazyprivate RoleService roleService;@Autowired@Lazyprivate PermissionService permissionService;/*** 认证信息(身份验证) Authentication 是用来验证用户身份*/@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {log.info("认证-->MyShiroRealm.doGetAuthenticationInfo()");//1.验证用户名User user;String account = (String) token.getPrincipal();if (Validator.isEmail(account)) {user = userService.findByEmail(account);} else {user = userService.findByUserName(account);}if (user == null) {//用户不存在log.info("用户不存在! 登录名:{}, 密码:{}", account, token.getCredentials());return null;}Role role = roleService.findByUserId(user.getId());if (role != null) {user.setRole(role.getRole());}//2.判断账号是否被封号if (!Objects.equals(user.getStatus(), UserStatusEnum.NORMAL.getCode())) {throw new LockedAccountException("账号被封禁");}//3.首先判断是否已经被禁用已经是否已经过了10分钟Date loginLast = DateUtil.date();if (null != user.getLoginLast()) {loginLast = user.getLoginLast();}Long between = DateUtil.between(loginLast, DateUtil.date(), DateUnit.MINUTE);if (StringUtils.equals(user.getLoginEnable(), TrueFalseEnum.FALSE.getValue()) && (between < CommonParamsEnum.TEN.getValue())) {log.info("账号已锁定! 登录名:{}, 密码:{}", account, token.getCredentials());throw new LockedAccountException("账号被锁定,请10分钟后再试");}//4.封装authenticationInfo,准备验证密码SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user, // 用户名user.getUserPass(), // 密码ByteSource.Util.bytes(CommonConstant.PASSWORD_SALT), // 盐getName() // realm name);System.out.println("realName:" + getName());return authenticationInfo;}@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();User user = (User) principals.getPrimaryPrincipal();Role role = roleService.findByRoleId(user.getId());authorizationInfo.addRole(role.getRole());List<Permission> permissions = permissionService.listPermissionsByRoleId(role.getId());//把权限的URL全部放到authorizationInfo中去Set<String> urls = permissions.stream().map(p -> p.getUrl()).collect(Collectors.toSet());authorizationInfo.addStringPermissions(urls);return authorizationInfo;}
}
package com.example.forum.controller.admin;import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.forum.controller.common.BaseController;
import com.example.forum.entity.Category;
import com.example.forum.dto.JsonResult;
import com.example.forum.service.CategoryService;
import com.example.forum.util.PageUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;/*** <pre>* 后台分类管理控制器* </pre>**/
@Slf4j
@Controller
@RequestMapping(value = "/admin/category")
public class CategoryController extends BaseController {@Autowiredprivate CategoryService categoryService;/*** 查询所有分类并渲染category页面** @return 模板路径admin/admin_category*/@GetMappingpublic String categories(@RequestParam(value = "page", defaultValue = "0") Integer pageNumber,@RequestParam(value = "size", defaultValue = "10") Integer pageSize,@RequestParam(value = "sort", defaultValue = "cateSort") String sort,@RequestParam(value = "order", defaultValue = "desc") String order, Model model) {Page page = PageUtil.initMpPage(pageNumber, pageSize, sort, order);Page<Category> categoryPage = categoryService.findAll(page);model.addAttribute("categories", categoryPage.getRecords());model.addAttribute("pageInfo", PageUtil.convertPageVo(page));return "admin/admin_category";}/*** 新增/修改分类目录** @param category category对象* @return 重定向到/admin/category*/@PostMapping(value = "/save")@ResponseBodypublic JsonResult saveCategory(@ModelAttribute Category category) {categoryService.insertOrUpdate(category);return JsonResult.success("保存成功");}/*** 删除分类** @param cateId 分类Id* @return JsonResult*/@DeleteMapping(value = "/delete")@ResponseBodypublic JsonResult checkDelete(@RequestParam("id") Long cateId) {//1.判断这个分类有文章Integer count = categoryService.countPostByCateId(cateId);if (count != 0) {return JsonResult.error("该分类已经有了文章,无法删除");}categoryService.delete(cateId);return JsonResult.success("删除成功");}/*** 跳转到修改页面** @param cateId cateId* @param model model* @return 模板路径admin/admin_category*/@GetMapping(value = "/edit")public String toEditCategory(Model model,@RequestParam(value = "page", defaultValue = "0") Integer pageNumber,@RequestParam(value = "size", defaultValue = "10") Integer pageSize,@RequestParam(value = "sort", defaultValue = "cateSort") String sort,@RequestParam(value = "order", defaultValue = "desc") String order,@RequestParam("id") Long cateId) {Page page = PageUtil.initMpPage(pageNumber, pageSize, sort, order);//更新的分类Category category = categoryService.get(cateId);if (category == null) {return this.renderNotFound();}model.addAttribute("updateCategory", category);// 所有分类Page<Category> categoryPage = categoryService.findAll(page);model.addAttribute("categories", categoryPage.getRecords());model.addAttribute("pageInfo", PageUtil.convertPageVo(page));return "admin/admin_category";}
}
package com.example.forum.controller.admin;import cn.hutool.http.HtmlUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.forum.controller.common.BaseController;
import com.example.forum.entity.Comment;
import com.example.forum.entity.Post;
import com.example.forum.entity.User;
import com.example.forum.exception.MyBusinessException;
import com.example.forum.dto.JsonResult;
import com.example.forum.dto.QueryCondition;
import com.example.forum.enums.*;
import com.example.forum.service.CommentService;
import com.example.forum.service.PostService;
import com.example.forum.service.UserService;
import com.example.forum.util.PageUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;import java.util.List;
import java.util.Objects;/*** <pre>* 后台回复管理控制器* </pre>*/
@Slf4j
@Controller
@RequestMapping(value = "/admin/comment")
public class CommentController extends BaseController {@Autowiredprivate CommentService commentService;@Autowiredprivate PostService postService;@Autowiredprivate UserService userService;/*** 渲染回复管理页面** @param model model* @param pageNumber page 当前页码* @param pageSize size 每页显示条数* @return 模板路径admin/admin_comment*/@GetMappingpublic String comments(Model model,@RequestParam(value = "keywords", defaultValue = "") String keywords,@RequestParam(value = "page", defaultValue = "1") Integer pageNumber,@RequestParam(value = "size", defaultValue = "15") Integer pageSize,@RequestParam(value = "sort", defaultValue = "createTime") String sort,@RequestParam(value = "order", defaultValue = "desc") String order) {Page page = PageUtil.initMpPage(pageNumber, pageSize, sort, order);Comment condition = new Comment();
// condition.setAcceptUserId(loginUserId);condition.setCommentContent(keywords);Page<Comment> comments = commentService.findAll(page, new QueryCondition<>(condition));List<Comment> commentList = comments.getRecords();commentList.forEach(comment -> comment.setPost(postService.get(comment.getPostId())));commentList.forEach(comment -> comment.setUser(userService.get(comment.getUserId())));model.addAttribute("comments", commentList);model.addAttribute("pageInfo", PageUtil.convertPageVo(page));model.addAttribute("keywords", keywords);model.addAttribute("sort", sort);model.addAttribute("order", order);return "admin/admin_comment";}/*** 我发送的回复** @param model model* @param pageNumber page 当前页码* @param pageSize size 每页显示条数* @return 模板路径admin/admin_comment*/@GetMapping("/send")public String sendComments(Model model,@RequestParam(value = "keywords", defaultValue = "") String keywords,@RequestParam(value = "page", defaultValue = "1") Integer pageNumber,@RequestParam(value = "size", defaultValue = "15") Integer pageSize,@RequestParam(value = "sort", defaultValue = "createTime") String sort,@RequestParam(value = "order", defaultValue = "desc") String order) {User user = getLoginUser();Page page = PageUtil.initMpPage(pageNumber, pageSize, sort, order);Comment condition = new Comment();condition.setUserId(user.getId());condition.setCommentContent(keywords);Page<Comment> comments = commentService.findAll(page, new QueryCondition<>(condition));List<Comment> commentList = comments.getRecords();commentList.forEach(comment -> comment.setPost(postService.get(comment.getPostId())));commentList.forEach(comment -> comment.setUser(userService.get(comment.getUserId())));model.addAttribute("comments", commentList);model.addAttribute("pageInfo", PageUtil.convertPageVo(page));model.addAttribute("keywords", keywords);model.addAttribute("sort", sort);model.addAttribute("order", order);return "admin/admin_comment";}/*** 我发送的回复** @param model model* @param pageNumber page 当前页码* @param pageSize size 每页显示条数* @return 模板路径admin/admin_comment*/@GetMapping("/receive")public String receiveComments(Model model,@RequestParam(value = "keywords", defaultValue = "") String keywords,@RequestParam(value = "page", defaultValue = "1") Integer pageNumber,@RequestParam(value = "size", defaultValue = "15") Integer pageSize,@RequestParam(value = "sort", defaultValue = "createTime") String sort,@RequestParam(value = "order", defaultValue = "desc") String order) {User user = getLoginUser();Page page = PageUtil.initMpPage(pageNumber, pageSize, sort, order);Comment condition = new Comment();condition.setAcceptUserId(user.getId());condition.setCommentContent(keywords);Page<Comment> comments = commentService.findAll(page, new QueryCondition<>(condition));List<Comment> commentList = comments.getRecords();commentList.forEach(comment -> comment.setPost(postService.get(comment.getPostId())));commentList.forEach(comment -> comment.setUser(userService.get(comment.getUserId())));model.addAttribute("comments", commentList);model.addAttribute("pageInfo", PageUtil.convertPageVo(page));model.addAttribute("keywords", keywords);model.addAttribute("sort", sort);model.addAttribute("order", order);return "admin/admin_comment";}/*** 删除回复** @param commentId commentId* @return string 重定向到/admin/comment*/@DeleteMapping(value = "/delete")@ResponseBodypublic JsonResult moveToAway(@RequestParam("id") Long commentId) {//回复Comment comment = commentService.get(commentId);//检查权限basicCheck(comment);commentService.delete(commentId);return JsonResult.success("删除成功");}/*** 回复回复,并通过回复** @param commentId 被回复的回复* @param commentContent 回复的内容* @return 重定向到/admin/comment*/@PostMapping(value = "/reply")@ResponseBodypublic JsonResult replyComment(@RequestParam("id") Long commentId,@RequestParam("commentContent") String commentContent) {//博主信息User loginUser = getLoginUser();//被回复的回复Comment lastComment = commentService.get(commentId);User user = userService.get(lastComment.getUserId());String at = user != null ? user.getUserDisplayName() : "楼上";if (lastComment == null) {return JsonResult.error("回复不存在");}Post post = postService.get(lastComment.getPostId());if (post == null) {return JsonResult.error("文章不存在");}//保存回复Comment comment = new Comment();comment.setUserId(loginUser.getId());comment.setPostId(lastComment.getPostId());String lastContent = "<a href='#comment-id-" + lastComment.getId() + "'>@" + at + "</a> ";comment.setCommentContent(lastContent + HtmlUtil.escape(commentContent));comment.setCommentParent(commentId);comment.setAcceptUserId(lastComment.getUserId());comment.setPathTrace(lastComment.getPathTrace() + lastComment.getId() + "/");commentService.insertOrUpdate(comment);return JsonResult.success("回复成功");}/*** 批量删除** @param ids 回复ID列表* @return*/@DeleteMapping(value = "/batchDelete")@ResponseBodypublic JsonResult batchDelete(@RequestParam("ids") List<Long> ids) {//批量操作//1、防止恶意操作if (ids == null || ids.size() == 0 || ids.size() >= 100) {return new JsonResult(ResultCodeEnum.FAIL.getCode(), "参数不合法!");}//2、检查用户权限//文章作者、回复人、管理员才可以删除List<Comment> commentList = commentService.findByBatchIds(ids);for (Comment comment : commentList) {basicCheck(comment);}//3、删除commentService.batchDelete(ids);return JsonResult.success("删除成功");}/*** 检查文章是否存在和用户是否有权限控制** @param comment*/private void basicCheck(Comment comment) {Long loginUserId = getLoginUserId();if (comment == null) {throw new MyBusinessException("回复不存在");}//文章Post post = postService.get(comment.getPostId());if (post == null) {throw new MyBusinessException("回复所在文章不存在");}//检查权限,文章的作者和收到回复和管理员的可以删除if (!Objects.equals(post.getUserId(), loginUserId) && !Objects.equals(comment.getAcceptUserId(), loginUserId) && !loginUserIsAdmin()) {throw new MyBusinessException("没有权限");}}}
五、底部获取项目(9.9¥带走)
有问题,或者需要协助调试运行项目的也可以