当前位置:   article > 正文

SpringBoot个人博客项目(1)

springboot个人博客项目

基于SpringBoot开发的个人博客项目

– 项目背景–

项目原型为李仁密老师的小而美的个人博客作品,视频中所采用的持久层ORM框架为JPA,这里我将其改成了mybatis
项目原型地址.

– 技术选型 –

项目总体为前后端整合型开发
前端: JQuery、semanticUI、thymeleaf 等
后端: SSM、SpringBoot 、MySQL 等

– 项目搭建 –

【前端部分】

前端部分就跟着李仁密老师的B站视频 P1 - P19 从头至尾敲了下来,框架选用了semanticUI,其中集成了很多插件。如:markdown编辑器、代码高亮、二维码生成、滚动侦测、平滑滚动、生成目录、中文排版、animate过渡动画等,由于本人专注于后端,前端部分就不多做赘述了。

【后端部分】

  • 框架搭建
开发工具及依赖版本
JDK1.8
IDEIntelliJ IDEA 2020.3.2
SpringBoot2.6.4
MySQL驱动8.0+
  • 创建一个SpringBoot项目
    删除多余文件夹及文件,等待项目加载完毕。
    添加相关依赖 pom.xml
    <!--依赖-->
    <dependencies>
        <!--thymeleaf模板引擎-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <!--web启动器-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--mybatis整合springboot-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.2</version>
        </dependency>

        <!--热部署-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <!--mysql驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
         <!-- AOP 织入包-->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.13</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 添加配置文件
    总配置文件、开发环境、生产环境
    配置文件
    • 总配置文件
    spring:
    	thymeleaf:
    		cache: false
    		mode: HTML
    	profiles:
    		active: dev
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 开发环境配置文件
    server:
    	 port: 8080
    spring:
    	datasource:
       		username: root
    		password: root
    		url: https://jdbc:mysql://localhost:3306/blog?&useSSL=false&serverTimezone=UTC
    		driver-class-name: com.mysql.cj.jdbc.Driver
    
    mybatis:
    	type-aliases-package: com.yy.blog.pojo
    	mapper-locations: classpath:mybatis/mapper/*.xml
    
    logging:
    	level:
    		root: info
    		com.yy: debug
    	file:
    		name: log/blog-dev.log
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 生产环境配置文件
    	server:
    	 port: 8081
    spring:
    	datasource:
       		username: root
    		password: root
    		url: https://jdbc:mysql://localhost:3306/blog?&useSSL=false&serverTimezone=UTC
    		driver-class-name: com.mysql.cj.jdbc.Driver
    
    mybatis:
    	type-aliases-package: com.yy.blog.pojo
    	mapper-locations: classpath:mybatis/mapper/*.xml
    
    logging:
    	level:
    		root: warn
    		com.yy: info
    	file:
    		name: log/blog-pro.log
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
  • 异常处理
    当出现错误时,应做异常的处理。如404页面、500页面、以及错误页面的定制。
    在resources/templates目录下建立error文件夹,SpringBoot在出现访问异常时,会自动查找error目录下的HTML文件,并跳转到相应的错误页面。
    异常页面
    注意:异常页面的命名一定要为404、500等,否则springboot会找不到
    • 404 页面定制
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>404 Not Found</title>
    <style>
        body {
            background: #000;
            height: 100vh;
            overflow: hidden;
            display: flex;
            font-family: 'Anton', sans-serif;
            justify-content: center;
            align-items: center;
            -webkit-perspective: 1000px;
            perspective: 1000px;
        }

        div {
            -webkit-transform-style: preserve-3d;
            transform-style: preserve-3d;
        }

        .rail {
            position: absolute;
            width: 100%;
            height: 100%;
            display: flex;
            justify-content: center;
            align-items: center;
            -webkit-transform: rotateX(-30deg) rotateY(-30deg);
            transform: rotateX(-30deg) rotateY(-30deg);
        }
        .rail .stamp {
            position: absolute;
            width: 200px;
            height: 200px;
            display: flex;
            justify-content: center;
            align-items: center;
            background: #141414;
            color: #fff;
            font-size: 7rem;
        }
        .rail .stamp:nth-child(1) {
            -webkit-animation: stampSlide 40000ms -2300ms linear infinite;
            animation: stampSlide 40000ms -2300ms linear infinite;
        }
        .rail .stamp:nth-child(2) {
            -webkit-animation: stampSlide 40000ms -4300ms linear infinite;
            animation: stampSlide 40000ms -4300ms linear infinite;
        }
        .rail .stamp:nth-child(3) {
            -webkit-animation: stampSlide 40000ms -6300ms linear infinite;
            animation: stampSlide 40000ms -6300ms linear infinite;
        }
        .rail .stamp:nth-child(4) {
            -webkit-animation: stampSlide 40000ms -8300ms linear infinite;
            animation: stampSlide 40000ms -8300ms linear infinite;
        }
        .rail .stamp:nth-child(5) {
            -webkit-animation: stampSlide 40000ms -10300ms linear infinite;
            animation: stampSlide 40000ms -10300ms linear infinite;
        }
        .rail .stamp:nth-child(6) {
            -webkit-animation: stampSlide 40000ms -12300ms linear infinite;
            animation: stampSlide 40000ms -12300ms linear infinite;
        }
        .rail .stamp:nth-child(7) {
            -webkit-animation: stampSlide 40000ms -14300ms linear infinite;
            animation: stampSlide 40000ms -14300ms linear infinite;
        }
        .rail .stamp:nth-child(8) {
            -webkit-animation: stampSlide 40000ms -16300ms linear infinite;
            animation: stampSlide 40000ms -16300ms linear infinite;
        }
        .rail .stamp:nth-child(9) {
            -webkit-animation: stampSlide 40000ms -18300ms linear infinite;
            animation: stampSlide 40000ms -18300ms linear infinite;
        }
        .rail .stamp:nth-child(10) {
            -webkit-animation: stampSlide 40000ms -20300ms linear infinite;
            animation: stampSlide 40000ms -20300ms linear infinite;
        }
        .rail .stamp:nth-child(11) {
            -webkit-animation: stampSlide 40000ms -22300ms linear infinite;
            animation: stampSlide 40000ms -22300ms linear infinite;
        }
        .rail .stamp:nth-child(12) {
            -webkit-animation: stampSlide 40000ms -24300ms linear infinite;
            animation: stampSlide 40000ms -24300ms linear infinite;
        }
        .rail .stamp:nth-child(13) {
            -webkit-animation: stampSlide 40000ms -26300ms linear infinite;
            animation: stampSlide 40000ms -26300ms linear infinite;
        }
        .rail .stamp:nth-child(14) {
            -webkit-animation: stampSlide 40000ms -28300ms linear infinite;
            animation: stampSlide 40000ms -28300ms linear infinite;
        }
        .rail .stamp:nth-child(15) {
            -webkit-animation: stampSlide 40000ms -30300ms linear infinite;
            animation: stampSlide 40000ms -30300ms linear infinite;
        }
        .rail .stamp:nth-child(16) {
            -webkit-animation: stampSlide 40000ms -32300ms linear infinite;
            animation: stampSlide 40000ms -32300ms linear infinite;
        }
        .rail .stamp:nth-child(17) {
            -webkit-animation: stampSlide 40000ms -34300ms linear infinite;
            animation: stampSlide 40000ms -34300ms linear infinite;
        }
        .rail .stamp:nth-child(18) {
            -webkit-animation: stampSlide 40000ms -36300ms linear infinite;
            animation: stampSlide 40000ms -36300ms linear infinite;
        }
        .rail .stamp:nth-child(19) {
            -webkit-animation: stampSlide 40000ms -38300ms linear infinite;
            animation: stampSlide 40000ms -38300ms linear infinite;
        }
        .rail .stamp:nth-child(20) {
            -webkit-animation: stampSlide 40000ms -40300ms linear infinite;
            animation: stampSlide 40000ms -40300ms linear infinite;
        }

        @-webkit-keyframes stampSlide {
            0% {
                -webkit-transform: rotateX(90deg) rotateZ(-90deg) translateZ(-200px) translateY(130px);
                transform: rotateX(90deg) rotateZ(-90deg) translateZ(-200px) translateY(130px);
            }
            100% {
                -webkit-transform: rotateX(90deg) rotateZ(-90deg) translateZ(-200px) translateY(-3870px);
                transform: rotateX(90deg) rotateZ(-90deg) translateZ(-200px) translateY(-3870px);
            }
        }

        @keyframes stampSlide {
            0% {
                -webkit-transform: rotateX(90deg) rotateZ(-90deg) translateZ(-200px) translateY(130px);
                transform: rotateX(90deg) rotateZ(-90deg) translateZ(-200px) translateY(130px);
            }
            100% {
                -webkit-transform: rotateX(90deg) rotateZ(-90deg) translateZ(-200px) translateY(-3870px);
                transform: rotateX(90deg) rotateZ(-90deg) translateZ(-200px) translateY(-3870px);
            }
        }
        .world {
            -webkit-transform: rotateX(-30deg) rotateY(-30deg);
            transform: rotateX(-30deg) rotateY(-30deg);
        }
        .world .forward {
            position: absolute;
            -webkit-animation: slide 2000ms linear infinite;
            animation: slide 2000ms linear infinite;
        }
        .world .box {
            width: 200px;
            height: 200px;
            -webkit-transform-origin: 100% 100%;
            transform-origin: 100% 100%;
            -webkit-animation: roll 2000ms cubic-bezier(1, 0.01, 1, 1) infinite;
            animation: roll 2000ms cubic-bezier(1, 0.01, 1, 1) infinite;
        }
        .world .box .wall {
            position: absolute;
            width: 200px;
            height: 200px;
            background: rgba(10, 10, 10, 0.8);
            border: 1px solid #fafafa;
            box-sizing: border-box;
        }
        .world .box .wall::before {
            content: '';
            position: absolute;
            width: 100%;
            height: 100%;
            display: flex;
            justify-content: center;
            align-items: center;
            color: #fff;
            font-size: 7rem;
        }
        .world .box .wall:nth-child(1) {
            -webkit-transform: translateZ(100px);
            transform: translateZ(100px);
        }
        .world .box .wall:nth-child(2) {
            -webkit-transform: rotateX(180deg) translateZ(100px);
            transform: rotateX(180deg) translateZ(100px);
        }
        .world .box .wall:nth-child(3) {
            -webkit-transform: rotateX(90deg) translateZ(100px);
            transform: rotateX(90deg) translateZ(100px);
        }
        .world .box .wall:nth-child(3)::before {
            -webkit-transform: rotateX(180deg) rotateZ(90deg) translateZ(-1px);
            transform: rotateX(180deg) rotateZ(90deg) translateZ(-1px);
            -webkit-animation: zeroFour 4000ms -2000ms linear infinite;
            animation: zeroFour 4000ms -2000ms linear infinite;
        }
        .world .box .wall:nth-child(4) {
            -webkit-transform: rotateX(-90deg) translateZ(100px);
            transform: rotateX(-90deg) translateZ(100px);
        }
        .world .box .wall:nth-child(4)::before {
            -webkit-transform: rotateX(180deg) rotateZ(-90deg) translateZ(-1px);
            transform: rotateX(180deg) rotateZ(-90deg) translateZ(-1px);
            -webkit-animation: zeroFour 4000ms -2000ms linear infinite;
            animation: zeroFour 4000ms -2000ms linear infinite;
        }
        .world .box .wall:nth-child(5) {
            -webkit-transform: rotateY(90deg) translateZ(100px);
            transform: rotateY(90deg) translateZ(100px);
        }
        .world .box .wall:nth-child(5)::before {
            -webkit-transform: rotateX(180deg) translateZ(-1px);
            transform: rotateX(180deg) translateZ(-1px);
            -webkit-animation: zeroFour 4000ms linear infinite;
            animation: zeroFour 4000ms linear infinite;
        }
        .world .box .wall:nth-child(6) {
            -webkit-transform: rotateY(-90deg) translateZ(100px);
            transform: rotateY(-90deg) translateZ(100px);
        }
        .world .box .wall:nth-child(6)::before {
            -webkit-transform: rotateX(180deg) rotateZ(180deg) translateZ(-1px);
            transform: rotateX(180deg) rotateZ(180deg) translateZ(-1px);
            -webkit-animation: zeroFour 4000ms linear infinite;
            animation: zeroFour 4000ms linear infinite;
        }

        @-webkit-keyframes zeroFour {
            0% {
                content: '4';
            }
            100% {
                content: '0';
            }
        }

        @keyframes zeroFour {
            0% {
                content: '4';
            }
            100% {
                content: '0';
            }
        }
        @-webkit-keyframes roll {
            0% {
                -webkit-transform: rotateZ(0deg);
                transform: rotateZ(0deg);
            }
            85% {
                -webkit-transform: rotateZ(90deg);
                transform: rotateZ(90deg);
            }
            87% {
                -webkit-transform: rotateZ(88deg);
                transform: rotateZ(88deg);
            }
            90% {
                -webkit-transform: rotateZ(90deg);
                transform: rotateZ(90deg);
            }
            100% {
                -webkit-transform: rotateZ(90deg);
                transform: rotateZ(90deg);
            }
        }
        @keyframes roll {
            0% {
                -webkit-transform: rotateZ(0deg);
                transform: rotateZ(0deg);
            }
            85% {
                -webkit-transform: rotateZ(90deg);
                transform: rotateZ(90deg);
            }
            87% {
                -webkit-transform: rotateZ(88deg);
                transform: rotateZ(88deg);
            }
            90% {
                -webkit-transform: rotateZ(90deg);
                transform: rotateZ(90deg);
            }
            100% {
                -webkit-transform: rotateZ(90deg);
                transform: rotateZ(90deg);
            }
        }
        @-webkit-keyframes slide {
            0% {
                -webkit-transform: translateX(0);
                transform: translateX(0);
            }
            100% {
                -webkit-transform: translateX(-200px);
                transform: translateX(-200px);
            }
        }
        @keyframes slide {
            0% {
                -webkit-transform: translateX(0);
                transform: translateX(0);
            }
            100% {
                -webkit-transform: translateX(-200px);
                transform: translateX(-200px);
            }
        }
    </style>
</head>
<body>
<div class="rail">
    <div class="stamp four">4</div>
    <div class="stamp zero">0</div>
    <div class="stamp four">4</div>
    <div class="stamp zero">0</div>
    <div class="stamp four">4</div>
    <div class="stamp zero">0</div>
    <div class="stamp four">4</div>
    <div class="stamp zero">0</div>
    <div class="stamp four">4</div>
    <div class="stamp zero">0</div>
    <div class="stamp four">4</div>
    <div class="stamp zero">0</div>
    <div class="stamp four">4</div>
    <div class="stamp zero">0</div>
    <div class="stamp four">4</div>
    <div class="stamp zero">0</div>
    <div class="stamp four">4</div>
    <div class="stamp zero">0</div>
    <div class="stamp four">4</div>
    <div class="stamp zero">0</div>
</div>
<div class="world">
    <div class="forward">
        <div class="box">
            <div class="wall"></div>
            <div class="wall"></div>
            <div class="wall"></div>
            <div class="wall"></div>
            <div class="wall"></div>
            <div class="wall"></div>
        </div>
    </div>
</div>
</body>
</html>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 500 页面定制
    同上,修改一下即可
  • 全局异常类的处理 ControllerExceptionInterceptor
    核心注解:
    @ControllerAdvice
    @ExceptionHandler(Exception.class)

@ControllerAdvice :是Spring 3.2 提供的新注解,它是一个Controller增强器,可对controller中被 @RequestMapping注解的方法加一些逻辑处理。最常用的就是异常处理。

package com.yy.blog.interceptor;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;

//会拦截所有带 @Controller 的控制器 做异常处理
@ControllerAdvice
public class ControllerExceptionInterceptor {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    //标识这个方法可以做异常处理 , 拦截掉所有Exception
    @ExceptionHandler(Exception.class)
    public ModelAndView exceptionHandler(HttpServletRequest request,Exception e) throws Exception {
        //记录日志信息
        logger.error("Request URL : {},Exception : {}",request.getRequestURL(),e);
        /*对标识了 @ResponseStatus() 的异常 单独做处理!
        * 不会返回到error,而是交给springboot自己来处理,去404
        * */
        if(AnnotationUtils.findAnnotation(e.getClass(),ResponseStatus.class) != null){
            throw e;
        }
        ModelAndView mv = new ModelAndView();
        mv.addObject("url",request.getRequestURL());
        mv.addObject("exception",e);
        mv.setViewName("error/error");
        return mv;
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

在这个异常处理类中,当在请求controller时发生异常时,会自动调用exceptionHandler方法对异常做处理,处理方式为:创建一个ModelAndView ,携带获取请求的URL和Exception,设置视图名称跳转到error页面并返回。

其中对自定义的异常作了单独处理,当抛出的异常为这个自定义异常时,不会做此异常处理,而是正常抛出,让SpringBoot来处理。

if(AnnotationUtils.findAnnotation(e.getClass(),ResponseStatus.class) != null){
     throw e;
}
  • 1
  • 2
  • 3
  • error页面
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>错误</title>
</head>
<body>
    <h1>错误</h1>

    <!--在控制台打印异常信息-->
    <div>
        <div th:utext="'&lt;!--'" th:remove="tag"></div>
        <div th:utext="'Failed Request URL : ' + ${url}" th:remove="tag"></div>
        <div th:utext="'Exception Message : ' + ${exception.message}" th:remove="tag"></div>
        <ul th:remove="tag">
            <li th:each="st : ${exception.stackTrace}" th:remove="tag">
                <span th:utext="${st}" th:remove="tag"></span>
            </li>
        </ul>
        <div th:utext="'--&gt;'" th:remove="tag"></div>
    </div>

</body>
</html>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

error页面会使用thymeleaf ,获取到异常处理后传过来的请求URL以及Exception并显示在浏览器源代码里

  • 自定义异常NotFoundException
    一定要用@ResponseStatus(HttpStatus.NOT_FOUND)注解标识该异常,才能被上面异常处理扫描到。
package com.yy.blog.exception;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;

//所有抛出该异常都状态标识为 NOT_FOUND
@ResponseStatus(HttpStatus.NOT_FOUND)
public class NotFoundException extends RuntimeException{

    public NotFoundException() {
    }
    public NotFoundException(String message) {
        super(message);
    }

    public NotFoundException(String message, Throwable cause) {
        super(message, cause);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 异常测试
    异常处理到这就完成了,写一个controller来测试一下,当出现异常时,是否会根据上面做的异常处理来操作。

【当正常抛出异常时】

@Controller
public class IndexController {

    @GetMapping("/")
    public String index(){
        int i = 1 / 0;
        return "index";
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

error
在这里插入图片描述
测试结果:携带URL和Exception跳转到error页面,并将错误信息输出在浏览器源代码中

【当抛出自定义异常时】

@Controller
public class IndexController {

    @GetMapping("/")
    public String index(){
        String blog = null;
        //如果查询出来的博客为空,则抛出自定义异常!
        if (blog == null){
            throw new NotFoundException("博客不存在!");
        }
        return "index";
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

404
测试结果:当抛出自定义异常时,正常抛出,不做异常处理,跳转到 404

  • 日志处理
    在我们发出一次请求时,我们想记录一下请求者的ip地址、请求的URL、请求的哪个方法、请求的参数是什么,这时候该如何做呢?
    这里采用了 Spring aop 的方式,以controller包里所有的类的所有方法作为切面,当请求经过每个controller时,都会将上述内容记录下来并生成日志。
    具体实现:
    • 引入 aspectjweaver 织入包
    <!-- AOP 织入包-->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.13</version>
        </dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 编写日志切面类
    package com.yy.blog.aspect;
    
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.annotation.*;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Component;
    import org.springframework.web.context.request.RequestContextHolder;
    import org.springframework.web.context.request.ServletRequestAttributes;
    import javax.servlet.http.HttpServletRequest;
    import java.util.Arrays;
    
    @Aspect
    @Component
    public class LogAspect {
    
        private final Logger logger  = LoggerFactory.getLogger(this.getClass());
    
        //定义切面,log()可以理解为切面的名称
        @Pointcut("execution(* com.yy.blog.controller.*.*(..))")
        public void log(){}
    
        @Before("log()")
        public void doBefore(JoinPoint joinPoint){
            //获取请求的URL
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = attributes.getRequest();
            String url = request.getRequestURL().toString();
            //获取请求的ip地址
            String ip = request.getRemoteAddr();
            //获取请求的方法
            String classMethod = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName();
            //获取请求的参数列表
            Object[] args = joinPoint.getArgs();
            RequestLog requestLog = new RequestLog(url,ip,classMethod,args);
            logger.info("Request ; {}",requestLog);
        }
    
        @After("log()")
        public void doAfter(){
    //        logger.info("---------------doAfter()-----------------");
        }
    
        @AfterReturning(returning = "result",pointcut = "log()")
        public void doAfterReturn(Object result){
            logger.info("Result : {}", result);
        }
    
        private class RequestLog{
            private String url;
            private String ip;
            private String classMethod;
            private Object[] args;
    
            public RequestLog(String url, String ip, String classMethod, Object[] args) {
                this.url = url;
                this.ip = ip;
                this.classMethod = classMethod;
                this.args = args;
            }
    
            @Override
            public String toString() {
                return  "\n请求的URL = '" + url + '\'' + '\n' +
                        "请求者的ip地址 = '" + ip + '\'' + '\n' +
                        "请求的方法 = '" + classMethod + '\'' + '\n' +
                        "请求的参数 = '" + Arrays.toString(args);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 测试请求测试请求

内容太长了! C S D N 的 M a r k D o w n 编辑器好卡 ! \color{#FF0000}{内容太长了!CSDN的MarkDown编辑器好卡!} 内容太长了!CSDNMarkDown编辑器好卡!

下一章见! \color{#FF0000}{下一章见!} 下一章见!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小惠珠哦/article/detail/746415
推荐阅读
相关标签
  

闽ICP备14008679号