个人博客系统

个人博客系统

一、项目演示

博客系统

二、项目介绍

三个角色:游客 用户 管理员

游客可以浏览文章, 游客可以登录注册成用户,发布文章 管理自己的文章,评论和回复,点赞评论回复文章等

管理员可以对整个系统用户管理,文章管理,分类管理,角色权限管理,评论管理等等

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
    @Lazy
    private UserService userService;

    @Autowired
    @Lazy
    private RoleService roleService;

    @Autowired
    @Lazy
    private PermissionService permissionService;


    /**
     * 认证信息(身份验证) Authentication 是用来验证用户身份
     */
    @Override
    protected 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;
    }


    @Override
    protected 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 {

    @Autowired
    private CategoryService categoryService;


    /**
     * 查询所有分类并渲染category页面
     *
     * @return 模板路径admin/admin_category
     */
    @GetMapping
    public 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")
    @ResponseBody
    public JsonResult saveCategory(@ModelAttribute Category category) {
        categoryService.insertOrUpdate(category);
        return JsonResult.success("保存成功");
    }

    /**
     * 删除分类
     *
     * @param cateId 分类Id
     * @return JsonResult
     */
    @DeleteMapping(value = "/delete")
    @ResponseBody
    public 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 {

    @Autowired
    private CommentService commentService;

    @Autowired
    private PostService postService;

    @Autowired
    private UserService userService;


    /**
     * 渲染回复管理页面
     *
     * @param model      model
     * @param pageNumber page 当前页码
     * @param pageSize   size 每页显示条数
     * @return 模板路径admin/admin_comment
     */
    @GetMapping
    public 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")
    @ResponseBody
    public 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")
    @ResponseBody
    public 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")
    @ResponseBody
    public 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¥带走)

有问题,或者需要协助调试运行项目的也可以

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一杯奶茶¥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值