从0开始码第一个Spring Boot项目(javaweb个人博客系统)之Spring拦截器使用及个人文章列表展示

拦截器

为什么使用拦截器,之前我们做的所有页面,用户只要输入正确的访问地址就可以进行一系列操作,尽管我们做了后台验证,但是这仍是不安全的,比如,如果用户没有登录就访问之前的http://loaclhoat:8080/publish,就可以进入到发布文章页面,为此我们需要做拦截器,当访问资源的时候,对其进行拦截并处理,选择通过还是不通过

配置:

编写一个拦截器类SessionIntercetpor.java,然后实现HandlerInterceptor接口,并重写preHandle、postHandle、afterCompletion方法
preHandle方法是在请求之前执行(Controller之前)
postHandle方法在preHandle方法返回true后执行(Controller之后)
afterCompletion方法也是在preHandle方法返回true后执行(整个请求完成之后)

SessionIntercetpor.java
@Component
public class SessionIntercetpor implements HandlerInterceptor {

    @Autowired
    private UserMapper userMapper;
    //preHandle方法是在请求之前执行(Controller之前)
    //处理用户Cookie验证,如果用户没登录,验证不通过,不允许访问,反之将用户信息写入session,用户后面页面访问获取
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    	//其他类中的这段代码将删除,具体可查看我的源码
        User user;
        Cookie[] cookies = request.getCookies();
        if(cookies!=null && cookies.length>0){
            for (Cookie cookie:cookies){
                if("token".equals(cookie.getName())){
                    String token = cookie.getValue();
                    user =  userMapper.selectUserByToken(token);
                    if(user!=null){
                        request.getSession().setAttribute("user",user);
                    }
                }
            }
        }
        return true;
    }

	//postHandle方法在preHandle方法返回true后执行(Controller之后)
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

	//afterCompletion方法也是在preHandle方法返回true后执行(整个请求完成之后)
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }
}

编写一个配置类,用于拦截器配置:

WebConfig.java
//编写配置类,用于Spring管理我们的自定义配置
@Configuration
public class WebConfig implements WebMvcConfigurer {

	//注入编写好的拦截器
    @Autowired
    private SessionIntercetpor sessionIntercetpor;

	//添加拦截器,并拦截所有请求
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //拦截所有请求
        registry.addInterceptor(sessionIntercetpor).addPathPatterns("/**");

    }
}

然后在Controller类中编写如下代码,用户session用户验证,获取不到用户信息将重定向到首页

//检查用户是否登录
User user = (User) request.getSession().getAttribute("user");
 if(user==null){
     return "redirect:/";
 }

做完如上处理后,我们就可以对所有资源进行拦截,如果没有登录,只能访问首页和登录页

个人文章列表展示

登录成功后,我们点击用户名称下拉菜单,然后选择我的文章,如下:
我的文章
点击之后页面会跳转到个人文章列表,这里只展示自己发布过的文章信息

我的文章

具体代码

html页面代码模板化引入,如下
我们将共用的头部导航栏和底部分页栏抽离成一个模板,这个模板可以在多个html中引入,避免html页面臃肿、代码重复等问题

顶部导航栏模板navigation.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<body>
<!--定义一个div然后起个名字,用于后面引入使用-->
<div th:fragment="nav">
    <!--顶部导航栏-->
    <nav class="navbar navbar-default">
        <div class="container-fluid">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
                    <span class="sr-only">个人博客</span>
                </button>
                <a class="navbar-brand" href="/">个人博客</a>
            </div>

            <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
                <form class="navbar-form navbar-left">
                    <div class="form-group">
                        <input type="text" class="form-control" placeholder="请搜索问题">
                    </div>
                    <button type="submit" class="btn btn-default">搜索</button>
                </form>
                <ul class="nav navbar-nav navbar-right">
                    <li th:if="${session.user!=null}">
                        <a href="/publish"><i class="iconfont icon-fabu2"></i>&nbsp;&nbsp;写文章</a>
                    </li>
                    <li th:if="${session.user==null}">
                        <a href="/login">登录</a>
                    </li>
                    <li class="dropdown" th:if="${session.user!=null}">
                        <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><span th:text="${session.user.name}"></span><span class="caret"></span></a>
                        <ul class="dropdown-menu">
                            <li><a href="/main/personal">个人中心</a></li>
                            <li><a href="/main/article">我的文章</a></li>
                            <li><a href="/main/message">我的消息</a></li>
                            <li role="separator" class="divider"></li>
                            <li><a href="/logout">退出登录</a></li>
                        </ul>
                    </li>
                </ul>
            </div>
        </div>
    </nav>
</div>
</body>
</html>
底部分页栏pagination.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<body>
<!--定义一个div然后起个名字,用于后面引入使用-->
<div th:fragment="page">
    <!--分页-->
    <nav aria-label="Page navigation" class="page-right" th:if="${paginationInfo.countPage != 0}">

        <ul class="pagination">
            <li th:if="${paginationInfo.isHasFirstPage()}">
                <a th:href="@{${#httpServletRequest.getContextPath()}(page=1)}" aria-label="First">
                    <span aria-hidden="true">&lt;&lt;</span>
                </a>
            </li>
            <li th:if="${paginationInfo.isHasPrePage()}">
                <a th:href="@{${#httpServletRequest.getContextPath()}(page=${paginationInfo.page-1})}" aria-label="Previous">
                    <span aria-hidden="true">&lt;</span>
                </a>
            </li>
            <li th:each="page: ${paginationInfo.getPageList()}" th:class="${page==paginationInfo.page}? 'active'"><a th:href="@{${#httpServletRequest.getContextPath()}(page = ${page})}" th:text="${page}"></a></li>
            <li th:if="${paginationInfo.isHasNextPage()}">
                <a th:href="@{${#httpServletRequest.getContextPath()}(page=${paginationInfo.page+1})}" aria-label="Next">
                    <span aria-hidden="true">&gt;</span>
                </a>
            </li>
            <li th:if="${paginationInfo.isHasLastPage()}">
                <a th:href="@{${#httpServletRequest.getContextPath()}(page=${paginationInfo.getCountPage()})}" aria-label="Last">
                    <span aria-hidden="true">&gt;&gt;</span>
                </a>
            </li>
        </ul>
    </nav>
    <div class="noArticle" th:if="${paginationInfo.countPage == 0}">暂无数据,点击 <a th:href=" @{/publish}">这里</a>编写第一篇文章吧</div>
</div>
</body>
</html>

我们可以使用如下方式进行引入:

<!-- 使用thymelaf的th:replace语法进行引入,::之前是html页面名字,后面是之前起的div名字-->
<div th:replace="pagination :: page"></div>
我的文章列表页面布局article.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <!-- 踩过的坑,springboot引入静态资源路径不要加/static/,否则会报404-->
    <title>个人博客</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <link rel="stylesheet" href="/bootstrap-3.3.7/css/bootstrap.min.css">
    <link rel="stylesheet" href="/css/community.css">
    <link rel="stylesheet" href="//at.alicdn.com/t/font_1643567_rm1fqucxtan.css">
    <link rel="stylesheet" href="/bootstrap-3.3.7/css/bootstrap-theme.min.css">
    <script src="/jquery-1.12.4/jquery-1.12.4.min.js"></script>
    <script src="/bootstrap-3.3.7/js/bootstrap.min.js"></script>
</head>
<body>

<div th:replace="navigation :: nav"></div>

<div class="row main">
    <div class="col-lg-9 col-md-12 col-sm-12 col-xs-12 col-left">
        <div class="row">
            <div class="col-lg-3 col-md-3 col-sm-3 col-xs-3"><h4><i class="iconfont icon-liebiao"></i>&nbsp;我的文章</h4></div>
        </div>
        <div class="media media_list" th:each="article : ${myArticleList}">
            <div class="media-left">
                <a href="#">
                    <img class="media-object img-rounded" th:src="${article.user.getAvatarUrl()}"  >
                </a>
            </div>
            <div class="media-body">
                <h4 class="media-heading" th:text="${article.title}">标题标题</h4>
                <span th:text="${article.answerCount}"></span> 个回复 • <span th:text="${article.readCount}"></span> 次浏览 • 发布时间<span th:text="${#dates.format(article.createTime,'yyyy-MM-dd HH:mm:ss')}"></span>
            </div>
        </div>

        <!-- 分页 -->
        <div th:replace="pagination :: page"></div>
    </div>
    <div class="col-lg-3 col-md-12 col-sm-12 col-xs-12">
        <div class="list-group">
            <a href="/main/personal" th:class="${selection=='personal'?'active list-group-item':'list-group-item'} ">个人中心</a>
            <a href="/main/article" th:class="${selection=='article'?'active list-group-item':'list-group-item'} ">我的文章</a>
            <a href="/main/message" th:class="${selection=='message'?'active list-group-item':'list-group-item'} ">我的消息<span class="badge">4</span></a>
        </div>
    </div>
</div>
</body>
</html>
MainSelectionController.java
@Controller
public class MainSelectionController{

    @Autowired
    private ArticleMapper articleMapper;

    @Autowired
    private PaginationService paginationService;

    @GetMapping("/main/{selection}")
    public String article(@PathVariable(name = "selection") String selection,
                          @RequestParam(name = "page" ,defaultValue = "1") int page,
                          @RequestParam(name = "size" ,defaultValue = "5") int size,
                          HttpServletRequest request,
                          Model model){
        //检查用户是否登录
        User user = (User) request.getSession().getAttribute("user");
        if(user==null){
            return "redirect:/";
        }
        int totalCount = articleMapper.count(user.getId());
        PaginationDTO paginationDTO =  paginationService.getPageInfo(page,size,totalCount);
        model.addAttribute("paginationInfo",paginationDTO);
        switch (selection){
            case "article":
            //修改articleMapper中的list列表方法,我们这里传入用户id,如果id为空则表示查询所有,如果id不为空,则查询当前id的用户信息
                List<Article> myArticleList = articleMapper.list(user.getId(), paginationDTO.getOffset(), size);
                model.addAttribute("myArticleList",myArticleList);
                //用于判断当前的操作
                model.addAttribute("selection",selection);
                return "article";
            case "personal":
                return "personal";
            case "message":
                return "message";
            default:
                return "redirect:/";
        }
    }
}

ArticleMapper.java中查询语句修改
 //查询文章列表信息
 	//手动拼接sql语句,可做一些判断
    @Select({"<script> " +
            "select u.*,a.id as aid,a.title,a.author_id, a.description,a.read_count,a.answer_count,a.like_count,a.create_time from article a,user u " +
            "where a.author_id = u.id " +
            "<if test='uId!=null'> and a.author_id=#{uId}</if>"+
            "limit #{page},#{size}"+
            "</script>"})
    @Results(id="ArticleUser",value = {
            @Result(id=true,property = "id",column = "id"),
            @Result(property = "id",column = "aid"),
            @Result(property = "title",column = "title"),
            @Result(property = "description",column = "description"),
            @Result(property = "authorId",column = "author_id"),
            @Result(property = "readCount",column = "read_count"),
            @Result(property = "answerCount",column = "answer_count"),
            @Result(property = "likeCount",column = "like_count"),
            @Result(property = "user.name",column = "name"),
            @Result(property = "user.avatarUrl",column = "avatar_url")
    })
    List<Article> list(@Param(value = "uId") Long uId, @Param(value = "page") int page,@Param(value = "size") int size);

    //查询总文章数
    @Select({"<script> " +
            "select count(1) from article a,user u where a.author_id = u.id"+
            "<if test='uId!=null'> and u.id=#{uId}</if>"+
            "</script>"})
    int count(@Param(value = "uId") Long uId);
源码

个人博客系统长期更新,所有源码都放在了我的GitHub上了。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值