史上最全SpringBoot的基础入门内容和使用方法

SpringBoot的概念

  • SpringBoot是Spring公司的一个顶级项目,与Spring Framework是一个级别的。SpringBoot实际上是利用Spring Framework 4自动配置特性完成的。

  • 在编写项目时不需要编写xml文件。到现在,各种主流技术都提供了SpringBoot的启动器

  • 启动器?Spring框架在项目中的作用经常是整合各种其他技术,让其他技术使用的更加的便捷。SpringBoot的启动器实际上就是一个maven的依赖,一个依赖中包含了相关技术的jar包,还包含了该技术的自动配置,使得以前绝大数xml文件已经不需要再配置了,例如mybaist-config.xml、jdbc.properties、log4j.properties、applicationContext.xml、springmvc.xml等等的配置文件都无需再进行配置。但是还是需要在SpringBoot的配置文件中进行少量的配置。

  • Spring官方提供的启动器命名规则为** spring-boot-starter-xxx,而如果是第三方技术提供的启动器命名规则是:xxx-spring-boot-starter**

  • SpringBoot的本质就是Spring Framework,学习SpringBoot就是在学习如何整合其他技术

创建第一个SpringBoot的MVC项目

创建maven项目,使用jar的打包方式

默认就是jar的打包方式。如果默认不是的,自行选择。

在pom文件中引入SpringBoot依赖的两种方式,并引入web开发所需的启动器

通过继承的方式

    <!-- 第一种:引入springboot的依赖 -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.10.RELEASE</version>
    </parent>

    <dependencies>
        <!-- spring web开发模式启动器,内包含web开发所需的jar包 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

通过依赖的方式

        <!-- 第二种引入SpringBoot依赖的方式:注意type和scope必须要为pom和import,记得注释掉其中一种 -->
        <!--<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>2.1.10.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>-->

创建一个Controller进行测试

@Controller
public class MyController {
    
    @RequestMapping("/demo")
    @ResponseBody
    public String helloSpringBoot() {

        return "hello Spring boot";
    }
}

创建项目的包结构,并在最后一级的包之前的上一个包中创建SpringBoot的启动java类

/**
 * 对了,这里会相当于有一个包扫描,扫描位置为该类所在包的子包。
 */
@SpringBootApplication
public class FristSpringBootApplication {
    public static void main(String[] args) {
        SpringApplication.run(FristSpringBootApplication.class, args);
    }
}

项目的目录结构

访问测试

看到该URL可以知道,默认的path虚拟路径为 /

使用Springboot完成各类的技术整合

首先了解一下SpringBoot的配置文件

  • SpringBoot项目在启动的时候,会默认查找根路径resources(不唯一)下的application.properties或application.yml文件,读取其中的配置进行加载。

  • 至于SpringBoot寻找配置文件的路径,以及配置文件的加载顺序,这里就不做深究,有兴趣的可以自行查询其他文章

  • 以下有一篇文章由SpringBoot官方提供,展示了SpringBoot配置文件的各种能配置的基础属性。
    SpringBoot配置属性介绍

  • 示例:配置SpringBoot内置tomcat服务的端口号和path虚拟路径

  • 重新运行FristSpringBootApplicaiton中的main方法并访问测试

SpringBoot整合Junit进行单元测试

引入SpringBoot官方提供的测试启动器

        <!-- SpringBoot 单元测试启动器 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

创建一个测试类,代码如下

// 告诉SpringBoot需要使用哪个单元测试的工具,这里使用Junit4
@RunWith(SpringJUnit4ClassRunner.class)
// 标识当前类为测试类。并且指定SpringBoot启动类的Class
@SpringBootTest(classes = FristSpringBootApplication.class)
public class MyTest {
    @Autowired
    private MyController myController;

    @Test
    public void test(){
        System.out.println(myController.helloSpringBoot());
    }
}

SpringBoot整合Mybaits并完成分页开发pageHelper

首先引入Mybaits提供的SpringBoot启动器以及PageHelper的启动器

对了,别忘了springboot提供的web启动器

        <!-- 配置mybaits启动器 -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.1</version>
        </dependency>
        <!-- 配置分页插件启动器 -->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.2.12</version>
        </dependency>
        
        <!-- SpringBoot的默认mysql驱动版本就是8,而我用的也是mysql8,用mysql5的可以自行添加版本信息 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

在SpringBoot的配置文件中进行如下配置

spring:
  datasource:
  # 注意改成自己的配置
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/demo1?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
    username: root
    password: root

mybatis:
  # 扫描你Mpper.xml文件所在的位置
  mapper-locations: classpath:mapper/*Mapper.xml

编写一个Mapper、实体类、xml文件,具体存放位置后面会放一个项目结构图

public interface UserMapper {
    List<User> findAll();
}

public class User {
    private Integer id;
    private String uname;
    private String pwd;
}

<mapper namespace="com.it.mapper.UserMapper">
    <select id="findAll" resultType="com.it.entity.User">
        select * from t_user
    </select>
</mapper>

启动类中给类加上@MapperScan("com.it.mapper")注解,这里面写自己的mapper层路径

编写一个测试类

// 告诉SpringBoot需要使用哪个单元测试的工具,这里使用Junit4
@RunWith(SpringJUnit4ClassRunner.class)
// 标识当前类为测试类。并且指定SpringBoot启动类的Class
@SpringBootTest(classes = FristSpringBootApplication.class)
public class MyTest {
    @Autowired
    private UserMapper userMapper;

    @Test
    public void test(){
        PageHelper.startPage(2,1);
        System.out.println(userMapper.findAll());
    }
}

SpringBoot整合Druid数据源

介绍:
Druid是由阿里巴巴推出的数据库连接池。它结合了C3P0、DBCP、PROXOOL等数据库连接池的优点。之所以从众多数据库连接池中脱颖而出,还有一个重要的原因:就是它包含控制台记录操作日志。

引入Druid数据源的启动器

        <!-- 配置Druid数据源的启动器 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.10</version>
        </dependency>

在SpringBoot的配置文件中进行配置

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/demo1?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
    username: root
    password: root
    # 配置使用Durid的数据源
    type: com.alibaba.druid.pool.DruidDataSource
    druid:
      # 连接池的配置信息
      # 初始化大小,最小,最大
      initial-size: 5
      min-idle: 5
      maxActive: 20
      # 配置获取连接等待超时的时间
      maxWait: 60000
      # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
      timeBetweenEvictionRunsMillis: 60000
      # 配置一个连接在池中最小生存的时间,单位是毫秒
      minEvictableIdleTimeMillis: 300000
      validationQuery: SELECT 1
      testWhileIdle: true
      testOnBorrow: false
      testOnReturn: false
      # 打开PSCache,并且指定每个连接上PSCache的大小
      poolPreparedStatements: true
      maxPoolPreparedStatementPerConnectionSize: 20
      # 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
      filters: stat,wall,slf4j
      # 通过connectProperties属性来打开mergeSql功能;慢SQL记录
      connectionProperties: druid.stat.mergeSql\=true;druid.stat.slowSqlMillis\=5000
      # 配置DruidStatFilter
      web-stat-filter:
        enabled: true
        url-pattern: "/*"
        exclusions: "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*"
      # 配置DruidStatViewServlet
      stat-view-servlet:
        url-pattern: "/druid/*"
        # IP白名单(没有配置或者为空,则允许所有访问)
        allow: 127.0.0.1,192.168.21.128
        # IP黑名单 (存在共同时,deny优先于allow)
        deny: 192.168.21.129
        #  禁用HTML页面上的“Reset All”功能
        reset-enable: false
        # 登录名
        login-username: admin
        # 登录密码
        login-password: 123456

在浏览器访问Druid的控制台(前提:启动项目)

SpringBoot整合LogBack

直接在resources目录下添加logback.xml的配置文件

<?xml version="1.0" encoding="UTF-8"?>
<!--每分钟查看一下配置有没有变化,并重新加载-->
<configuration scan="true" scanPeriod="60 seconds" debug="false">
    <!-- 定义参数常量 -->
    <property name="log.level" value="debug"/>
    <property name="log.maxHistory" value="30"/>
    <!--修改生成的日志所在文件夹-->
    <property name="LOG_HOME" value="logs/"/>
    <property name="log.pattern"
              value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n"/>
    <!-- 控制台设置 -->
    <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
        <!-- 转换成字符串并输出 -->
        <encoder>
            <pattern>${log.pattern}</pattern>
        </encoder>
    </appender>
    <!-- DEBUG ,根据文件的大小或者是时间来生成新的日志文件-->
    <appender name="debugAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 文件路径 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--生成日志文件名称-->
            <FileNamePattern>
                ${LOG_HOME}/debug/%d{yyyy-MM-dd}.%i.log
                <timeBasedFileNamingAndTriggeringPolicy
                        class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                    <maxFileSize>100MB</maxFileSize>
                </timeBasedFileNamingAndTriggeringPolicy>
            </FileNamePattern>
        </rollingPolicy>
        <!-- 转换成字符串并输出,并输出到文件里面 -->
        <encoder>
            <pattern>${log.pattern}</pattern>
        </encoder>
        <!--过滤器,只保留DEBUG相关信息-->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>DEBUG</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>
    <!-- INFO -->
    <appender name="infoAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 文件路径 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <FileNamePattern>
                ${LOG_HOME}/info/%d{yyyy-MM-dd}.%i.log
                <timeBasedFileNamingAndTriggeringPolicy
                        class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                    <maxFileSize>100MB</maxFileSize>
                </timeBasedFileNamingAndTriggeringPolicy>
            </FileNamePattern>
        </rollingPolicy>
        <encoder>
            <pattern>${log.pattern}</pattern>
        </encoder>
        <!--过滤器,只保留 INFO 相关信息-->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>INFO</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>
    <!-- ERROR -->
    <appender name="errorAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 文件路径 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <FileNamePattern>
                ${LOG_HOME}/error/%d{yyyy-MM-dd}.%i.log
                <timeBasedFileNamingAndTriggeringPolicy
                        class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                    <maxFileSize>100MB</maxFileSize>
                </timeBasedFileNamingAndTriggeringPolicy>
            </FileNamePattern>
        </rollingPolicy>
        <encoder>
            <pattern>${log.pattern}</pattern>
        </encoder>
        <!--过滤器,只保留 ERROR 相关信息-->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>
    <!--logger需要关注哪个package,根据自己项目包名命名不同修改-->
    <logger name="com.it" level="${log.level}" additivity="true">
        <!--对其要输出的logger进行绑定-->
        <appender-ref ref="debugAppender"/>
        <appender-ref ref="infoAppender"/>
        <appender-ref ref="errorAppender"/>
    </logger>

    <root level="info">
        <appender-ref ref="consoleAppender"/>
    </root>

    <!--输出sql语句-->
    <logger name="com.it.mapper" level="DEBUG"></logger>
</configuration>

SpringBoot整合JSP

(因为SpringBoot默认是不支持jsp的)所以需要引入如下依赖

        <!-- jsp jstl-->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
        </dependency>
        <!-- 添加对jsp的支持 -->
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
            <scope>provided</scope>
        </dependency>

在main目录下创建一个目录,名叫webapp,并指定为web目录

在SpringBoot的配置文件中配置视图解析器

spring:
  mvc:
    view:
      prefix: /WEB-INF/jsp/
      suffix: .jsp

编写一个公共的JSP访问方法

    @RequestMapping("/{url}")
    public String url(@PathVariable String url) {
        return url;
    }

启动项目,测试运行

SpringBoot整合Thymeleaf

在原SpringBoot项目下添加Thymeleaf的启动器

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

在resoureces目录下创建文件夹 templates(因为默认templates的视图解析器就是这个位置)

该文件名不能随意更改

在templates目录下创建任意一个html,修改其命名空间,这里还对一些常用标签进行了示例

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>thymeleaf的学习与使用</title>
</head>
<body>
<!-- th:text :填充标签的内容信息,相当于js方法的innerText-->
    <p th:text="你好呀"></p>
    <!--  从request作用域用获取数据   -->
    <p th:text="${reqMsg}"></p>
    <!--  从session作用域用获取数据   -->
    <p th:text="${session.sesMsg}"></p>

<!-- th:value 设置表单的value属性值时使用 -->
    <p>
        <input type="text" th:value="我是thymeleaf设置的默认值--对了这里也能使用el表达式" />
    </p>

<!-- th:if 进行逻辑判断,如果为true则显示标签,否则不显示 -->
    <p>
        <span th:if="${reqMsg!=null}">如果reqMsg不等于null我就会显示</span>
    </p>

<!--
    th:each,对集合或数组进行遍历
    这里写的item是每次遍历出来的值,
    而这个state是一个对象,其中有4个属性
        index:当前的索引,默认从0开始
        count:当前遍历的个数,默认从1开始
        size:当前遍历的list对象一共有几个元素
        current:与item是一致的,都是每次遍历出来的值
-->
    <ul>
        <li th:each="item,state:${reqList}">
            <span th:text='${"姓名:" + item + "  --- 当前索引对象:" + state}'></span>
        </li>
    </ul>

<!-- th:href 为a标签添加链接,当然,也可以在link中使用,th:src同理 -->
    <p>
        <!--
            默认会以项目名称作为基础路径进行查找,也会拼接上多层的请求转发的路径,例如该页面是用/user/demo访问的,
            那么则普通的a标签超链接则会以 : 项目基础路径/user/aaa.js查找资源
        -->
        <a href="aaa.js">我是一个普通的超链接</a>
        <!--  始终以项目的基础路径进行查找,不会拼接上请求转发到该html的路径  -->
        <a th:href="@{/aaa.js}">我是一个th:href设置的超链接</a>
    </p>
</body>
</html>

声明控制器完成请求转发

    @RequestMapping("/demo")
    public String url(HttpServletRequest request, HttpSession session) {
        request.setAttribute("reqMsg","request作用域的数据");
        session.setAttribute("sesMsg","session作用域的数据");

        // 存储一个List数据
        List<String> list = Arrays.asList("zhangsan1","zhangsan2","zhangsan3","zhangsan4","zhangsan5");
        request.setAttribute("reqList",list);

        return "my";
    }

thymeleaf默认错误页面

按照状态码来响应错误页面

  • 在templdates路径下创建一个error文件夹,可以在error文件夹下创建: 状态码.html的页面,那么出现了状态码相同错误时,则会响应该html给浏览器。
  • 例如在error文件夹中创建一个500.html,那么当浏览器访问服务器出现500错误时,就会跳转到该页面
  • 当然,也可以进行模糊匹配
    • 当出现5开头的错误时,显示页面可以命名为5xx.html
    • 当出现4开头的错误时,显示页面可以命名为4xx.html

统一错误显示页面

  • 在templdates文件夹下创建一个error.html
  • 当出现的状态码匹配不到error文件夹下的错误页面时,会显示error.html作为错误显示页面

运行测试

SpringBoot整合Quartz

引入quartz提供的springboot启动器,如果需要进行持久化(驱动、jdbc等)

    <parent>
        <artifactId>spring-boot-parent</artifactId>
        <groupId>org.springframework.boot</groupId>
        <version>2.1.3.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-quartz</artifactId>
        </dependency>

编写一个SpringBoot启动类

@SpringBootApplication
public class SpringBootQuartzApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringBootQuartzApplication.class, args);
    }
}

编写SpringBoot的配置文件,在resources目录下

spring:
  datasource:
    # 注意改成自己的配置
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/quartz?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
    username: root
    password: root
  quartz:
    jdbc:
      initialize-schema: never # 永不重建数据表
    job-store-type: jdbc # 设置持久化
   # properties: 可以定义一些自定义的属性,可用于配置集群、rmi等

编写job任务类,继承QuartzJobBean类,这里可以直接使用依赖注入

public class MyJob extends QuartzJobBean {
    /**
     * 这里的话博主随便写了一个User类,添加了@Component注解
     */
    @Autowired
    private User user;

    @Override
    protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        System.out.println("我是springboot整合quartz后的一个任务 " + user);

    }
}

添加任务

@RunWith(SpringJUnit4ClassRunner.class)
// 标识当前类为测试类。并且指定SpringBoot启动类的Class
@SpringBootTest(classes = SpringBootQuartzApplication.class)
public class MyTest {
    @Autowired
    private Scheduler scheduler;

 
    @Test
    public void addJob() throws SchedulerException, InterruptedException {
        scheduler.start();

        JobDetail jobDetail = JobBuilder
                .newJob(MyJob.class)
                .withIdentity("job1","g1")
                .build();
        Trigger trigger = TriggerBuilder
                .newTrigger()
                .withIdentity("trigger1","g1")
                .forJob(jobDetail)
                .startNow()
                .withSchedule(
                        SimpleScheduleBuilder.repeatSecondlyForever(2)
                ).build();
        
        scheduler.scheduleJob(jobDetail, trigger);

        Thread.sleep(10000);
    }
}

修改任务的触发(修改Trigger)

/**
     * 重新调度job,使用新的触发器。
     * @throws SchedulerException
     * @throws InterruptedException
     */
    @Test
    public void rescheduleJob() throws SchedulerException, InterruptedException {

        TriggerKey triggerKey = TriggerKey.triggerKey("trigger1","g1");

        Trigger newTrigger = TriggerBuilder
                .newTrigger()
                .withIdentity("trigger2","g1")
                .startNow()
                .withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(1))
                .build();

        // 此操作会替换之前在数据库中的Trigger
        scheduler.rescheduleJob(triggerKey,newTrigger);

        Thread.sleep(10000);
    }

删除任务

@Test
    public void deleteJob() throws SchedulerException, InterruptedException {

        JobKey jobKey = JobKey.jobKey("job1","g1");
        scheduler.deleteJob(jobKey);

    }

暂停任务

@Test
    public void pauseJob() throws SchedulerException, InterruptedException {

        JobKey jobKey = JobKey.jobKey("job1","g1");
        scheduler.pauseJob(jobKey);
    }

开始暂停的任务

 /**
     * 开始暂停的任务
     * @throws SchedulerException
     * @throws InterruptedException
     */
    @Test
    public void resumeJob() throws SchedulerException, InterruptedException {

        JobKey jobKey = JobKey.jobKey("job1","g1");
        scheduler.resumeJob(jobKey);
    }

查询当前所拥有的任务(任务管理后台会用到)

/**
     * 查询任务
     * @throws SchedulerException
     * @throws InterruptedException
     */
    @Test
    public void selectJob() throws SchedulerException, InterruptedException {
        // 获取到所有的组
        GroupMatcher<JobKey> tGroupMatcher = GroupMatcher.anyGroup();
        // 通过组获得到对应的JobKey
        Set<JobKey> jobKeySet = scheduler.getJobKeys(tGroupMatcher);

        // 遍历JobKey
        for (JobKey jobKey : jobKeySet) {
            // 通过jobKey获取到其触发器
            List<? extends Trigger> triggerTriggerList= scheduler.getTriggersOfJob(jobKey);
            System.out.println("-------------------------------");

            for (Trigger trigger : triggerTriggerList) {
                System.out.println("当前触发器的名称为:" + trigger.getKey().getName());
                System.out.println("当前触发器的组为:" + trigger.getKey().getGroup());
                System.out.println("当前触发器的状态为:" + scheduler.getTriggerState(trigger.getKey()));

                // 将当前触发器转换为Cron触发器
                CronTrigger cronTrigger = (CronTrigger) trigger;
                System.out.println("当前触发器的Cron表达式:" + cronTrigger.getCronExpression());
            }
        }
    }

SpringBoot的异常处理

SpringBoot除了设置错误页面,还可以通过注解的方式实现错误处理。

在控制器类中添加任意一个方法,结合@ExceptionHandler。但是只能对当前控制器中方法出现异常进行解决。

这里示例的是处理ArithmeticException异常

    @ResponseBody
    @ExceptionHandler(ArithmeticException.class)
    public String errorByZeroHandler(Exception e){
        return "出现了异常" + e.getMessage();
    }

定义一个以@ControllerAdvice标注的Java类,并结合@ExceptionHandler进行异常处理

@ControllerAdvice
public class GlobalExceptionController {

    @ExceptionHandler(ArithmeticException.class)
    @ResponseBody
    public String ariExceptioin(Exception e){
        return "全局异常处理:" + e.getMessage();
    }

}
#### 全局异常、局部异常、错误页面的执行顺序
- 如果有局部异常处理,则走局部异常处理,不执行全局异常处理。

- 没有局部异常处理则走全局异常处理。
- 如果全局异常处理也没有就走错误页面了。
局部异常 -> 全局异常 -> 错误页面

SpringBoot中的Bean管理

通过创建一个类,使用@Configuration标识,在其中就可以进行@Bean进行配置

@Configuration
public class MyBeanConfigure {

    /**
     * 在Spring容器中添加一个Bean
     * 这个Bean注解中写的 user1相当于该bean的id属性
     */

    @Bean("user1")
    public User u1(){
        return new User();
    }

}

获取容器中的bean需要注意的2点

  • 如果当前Spring容器中有2个同样类型的bean,需要注意id的区分,取的时候参数名称写id名

    • 其实根据方法名区分也可以,取的时候,参数名称写方法名即可
  • 如果取的时候,参数名称不想更改为bean的id名或方法名。

    • 那么需要通过@Qualifier来指定bean的id(方法名不行)

Bean之间的依赖注入


	 @Bean("teacher")
		public Teacher t1(){
			return  new Teacher();
		}
	
    @Bean("user1")
    public User u1(Teacher teacher){
        User user = new User();
        user.setTeacher(teacher);
        return user;
    }

值得注意的点

  • 只需要在方法的形参上声明即可自动注入。默认是根据类型进行注入。

  • 注入的时候,如果Spring容器中只有一个bean,那么通过该需要依赖注入bean的方法名作为形参、id作为形参、或是任意写一个名称,都能够依赖注入成功。

  • 如果当前Spring容器中有多个同类型的bean,则可以通过将形参名更改为需要注入的bean的id,此时无法根据方法名当作形参名注入,需要使用@Qualifier注解。例如:

    @Bean("teacher1")
    public Teacher t1(){
        return  new Teacher();
    }

    @Bean("teacher2")
    public Teacher t2(){
        return  new Teacher();
    }

    @Bean("user1")
    public User u1(@Qualifier("teacher1") Teacher t){
        User user = new User();
        user.setTeacher(t);
        return user;
    }

SpringBoot拦截器功能

创建一个类,实现HandlerInterceptor接口,并重写方法,我这里顺便将其添加到了Spring的容器

@Component
public class MyInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("我是拦截器,嘿嘿,我执行了");
        return true;
    }
}

创建一个配置类,实现WebMvcConfigurer接口,重写addInterceptors方法

@Configuration
public class MyConfig implements WebMvcConfigurer {
    @Autowired
    private MyInterceptor myInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 将该拦截器注册到SpringMVC中
        registry.addInterceptor(myInterceptor).addPathPatterns("/demo1");
    }
}

SpringBoot项目的打包运行

SpringBoot打包成jar包。

设置pom.xml文件,将打包方式设置为jar,并引入SpringBoot的打包插件

    <packaging>jar</packaging>

    <build>
        <plugins>
            <!-- SpringBoot打包插件-->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

如果不配置打包插件,那么使用maven- install 打包出来的jar,运行时将会提示没有主清单属性。

使用maven执行打包

使用java -jar 你打包的jar即可运行

SpringBoot项目打包成war包

设置pom.xml文件中,添加打包插件并修改打包方式为war,web启动器中的tomcat依赖排除,并手动依赖

    <packaging>war</packaging>
	
        <!-- spring web开发模式启动器,内包含web开发所需的jar包 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <!-- 排除tomcat,因为打包成war后我们就会放在tomcat中运行,所以该自带的tomcat就不要了 -->
            <exclusions>
                <exclusion>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                    <groupId>org.springframework.boot</groupId>
                </exclusion>
            </exclusions>
        </dependency>

        <!--
            手动依赖tomcat插件,为啥排除了还要依赖呢?
            因为我们SpringBoot项目本地运行测试时还会用到
            而打包成war包的时候就不需要了,所以scope为provided
        -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>

SpringBoot的启动类继承SpringBootServletInitializer并重写configure方法

@SpringBootApplication
public class ThymeleafApplication extends SpringBootServletInitializer {
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
        return builder.sources(ThymeleafApplication.class);
    }

    public static void main(String[] args) {
        SpringApplication.run(ThymeleafApplication.class, args);
    }
}

使用maven-install打包,然后将打包后的war放在tomcat运行即可正常访问

全部评论

相关推荐

评论
点赞
收藏
分享
牛客网
牛客企业服务