SpringBoot详解

SpringBoot详解

Spring Boot 主要目标是:

为所有 Spring 的开发者提供一个非常快速的、广泛接受的入门体验
开箱即用(启动器starter-其实就是SpringBoot提供的一个jar包),但通过自己设置参数
(.properties),即可快速摆脱这种方式。
提供了一些大型项目中常见的非功能性特性,如内嵌服务器、安全、指标,健康检测、外部化配置等,绝对没有代码生成,也无需 XML 配置。

总结:Spring Boot在Spring框架的基础上,简化了配置、优化依赖管理、优化与常用第三方框架的集成、开箱即用。

配置SpringBoot基本环境

  1. 创建Maven项目
  2. 导入依赖
<!--   使用jdk1.8版  -->
    <properties>
        <java.version>1.8</java.version>
    </properties>
<!--    导入springboot父依赖-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

<!--    导入springboot依赖项-->
    <dependencies>
<!--    导入web启动器-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
<!--    导入test启动器-->     
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

       <!--导入配置文件处理器,配置文件进行绑定就会有提示-->
       <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-configuration-processor</artifactId>
             <optional>true</optional>
       </dependency>

    </dependencies> 

<!--  springboot插件,将程序打包成可执行jar包的插件  -->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
  1. 测试
@SpringBootApplication  // 表示此类为spring boot 应用,是spring boot框架的入口文件
public class HolleSpringBootController {
    public static void main(String[] args){
//        在main方法中运行HolleSpringBootController类
        SpringApplication.run(HolleSpringBootController.class,args);
    }
}
  1. 浏览器运行测试 http://localhost:8080/HolleController
    在这里插入图片描述
    出现这些文字,表示springboot环境搭建成功

SpringBoot项目结构

在这里插入图片描述

默认生成的Spring Boot项目结构;

●主程序已经生成好了,我们只需要编写我们自己的逻辑
●resources文件夹中目录结构

  • static :保存所有的静态资源; js CSS images ;
  • templates :保存所有的模板页面; ( Spring Boot默认jar包使用嵌入式的Tomcat ,默认不支持JSP页面) ;可以使用模板引擎( freemarker、thymeleaf ) ;
  • application.properties : Spring Boot应用的配置文件;可以修改一 些默认设置;

SpringBoot常用注解

@SpringBootApplication: // Spring Boot应用标注在某介类上说明这个类是SpringBoot的主配置类, SpringBoot就应该运行这个类的main方法来启动SpringBoot应用;

@SpringBootConfiguration: // 表示Spring Boot的配置类(是springboot的注解,是基于@Configuration的再封装)
         //标注在某个类上,表示这是一个Spring Boot的配置类;

// 配置文件属性值注入相关
@ConfigurationProperties(prefix = "person")  		
					// 默认读取全局配置文件(application*.yml,或者application.properties),从配置文件中获取指定的值(以person开头的值)和bean的属性进行绑定

@Value		// 默认读取全局配置文件(application*.yml,或者application.properties),单个属性注入,不支持复杂类型的注入(如数组等等)

// 测试类注解
@SpringBootTest         /*表示使用springboot内部集成的测试工具*/
@RunWith(SpringRunner.class)        /*表示使用spring内核进行测试*/
public class StudentServiceImplTest {}


// 加载配置文件相关1@PropertySource(value = {"classpath:person.properties"})
								// 加载指定的properties配置文件,可以指定多个配置文件2@ImportResource(locations = {"classpath:beans.xml"})    // 不推荐使用
								// 加载指定的xml文件,让配置文件生效,可以指定多个配置文件,3@Configuration				// 有此注解的类为配置类
	// 注意:Spring Boot里面没有Spring的配置文件,我们自己编写的配置文件,也不能自动识别;
	// 想让Spring的配置文件生效,加载进来; @ImportResource标注在一个配置类上并指定spring的配置文件,让其生效

// 注意:springboot默认加载application*.*文件作为配置文件,可以使用以上三种方式导入自定义的其他的配置文件

SpringBoot配置文件

SpringBoot,默认加载application*.yml 和 application*.properties文件为全局配置文件,其他配置文件SpringBoot不会自动识别。

配置文件的属性值注入

方式一:@ConfigurationProperties(prefix = “person”)

  1. 默认读取全局配置文件(application*.*),主要用于将配置文件中某一类属性整体批量读取并注入到某个Bean的属性中如(person)
  2. 注意:必须要有set方法
application.yml配置文件VO类,将配置的文件的字段值进行自动注入
,实体类中属性,必须要有set方法
单元测试
在这里插入图片描述在这里插入图片描述在这里插入图片描述

使用application.properties文件实现属性值注入,需要修改默认编码格式,否则中文会乱码

123456在这里插入图片描述

方式二:@Value 单个注入,不需要set方法,不能注入复杂的类型

@ConfigurationProperties / @Value 总结

在这里插入图片描述

配置文件占位符

在这里插入图片描述

random.uuid             # 获取随机的一串字符
random.int              # 获取随机的整数
person.hello:hello     # 如果person对象hello属性,没有值,则使用默认值hello

SpringBoot自动配置核心

SpringBoot在自动配置很多组件的时候,先看容器中有没有用户自己配置的( @Bean、@Component )如果有就用用户配置的,如果没有,才自动配置;如果有些组件可以有多个( ViewResolver )将用户配置的和自己默认的组合起来;
在这里插入图片描述

@SpringBootApplication: // Spring Boot应用标注在某介类上说明这个类是SpringBoot的主配置类, SpringBoot就应该运行这个类的main方法来启动SpringBoot应用;

@EnableAutoConfiguration// 开启自动配置功能;
		// 以前我们需要配置的东西,Spring Boot帮我们自动配置;@EnableAutoConfiguration告诉SpringBoot开启自动配置功能;这样自动配置才能生效;(注意,此注解有,以下的重要的子注解)
       @AutoConfigurationPackage :// 自动配置包
		 		@lmport(AutoConfigurationPackages.Registrar.class) :
				// Spring的底层注解@lmport ,给容器中导入一个组件;导入的组件由AutoConfigurationPackages.Registrar.class;这个类来指定:
  				AutoConfigurationPackages.Registrar.class功能:
          		// 将主配置类( @SpringBootApplication标注的类)的所在包及下面所有子包里面的所有组件扫描到Spring容器;
		@lmport(EnableAutoConfigurationImportSelector.class) ;
				/* 给容器中导入组件?
				EnableAutoConfigurationImportSelector :导入哪些组件的选择器;
				将所有需要导入的组件以全类名的方式返回;这些组件就会被添加到容器中;
				会给容器中导入非常多的自动配置类( xxxAutoConfiguration) ; 就是给容器中导入这个场景需要的所
有组件,并配置好这些组件;
				Spring Boot在启动的时候从类路径下的META-INF/spring.factories中获取EnableAutoConfiguration指定的值,
将这些值作为自动配置类导入到容器中,自动配置类就生效,帮我们进行自动配置工作;以前我们需要自己配置的
东西,自动配置类都帮我们;*/

自动配置相关的注解

@Configuration   //表示这是一个配置类,以前编写的配置文件一样,也可以给容器中添加组件

@EnableConfigurationProperties(HttpEncodingProperties.class)  
//启动指定类的ConfigurationProperties功能;将配置文件中对应的值和HttpEncodingProperties绑定起来;并把HttpEncodingProperties加入到ioc容器中

@ConditionalOnWebApplication 
//Spring底层@Conditional注解(Spring注解版),根据不同的条件,如果满足指定的条件,整个配置类里面的配置就会生效;    判断当前应用是否是web应用,如果是,当前配置类生效

@ConditionalOnClass(CharacterEncodingFilter.class) 
// 这里的条件是OnClass,也就是满足以下类存在:Servlet、DispatcherServlet、WebMvcConfigurer,其中Servlet只要引入了tomcat依赖自然会有,后两个需要引入SpringMVC才会有。这里就是判断你是否引入了相关依赖,引入依赖后该条件成立,当前类的配置才会生效!

@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
// 这个条件与上面不同,OnMissingBean,是说环境中不存在指定的WebMvcConfigurationSupport这个bean时,这个默认实例就生效。其实这就是自定义配置的入口,也就是说,如果我们自己配置了一个WebMVCConfigurationSupport的实现类,那么这个默认配置就会失效,而会启用我们的自定义配置类!

@ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled", matchIfMissing = true)  
//判断配置文件中是否存在某个配置  spring.http.encoding.enabled;如果不存在,判断也是成立的

在这里插入图片描述

ProFile多环境配置

在实际开发中,应用程序通常需要部署到不同的运行环境中,例如开发环境、测试环境、生产环境等。不同的环境可能需要不同的环境配置,针对这种情况,不可能手动变更配置文件来适应不同的开发环境,通常需要对项目进行多环境配置,Spring Boot框架提供了两种多环境配置的方式,分别是Profile文件多环境配置和@Profile注解多环境配置。

在Spring Boot框架中,提供了使用Profile配置文件来进行多环境配置,该配置文件名必须满足application-{profile}.properties的格式,其中{profile}对应具体的环境标识。这里以开发环境、测试环境和生产环境为例,编写对应环境的配置文件,格式示例如下。

application-dev.properties // 开发环境配置文件
application-test.properties // 测试环境配置文件
application-prod.properties // 生产环境配置文件

激活开发环境配置文件

spring.profiles.active=dev		# 表示使用application-dev.properties环境

注册servlet三大组件

创建三大组件【Servlet、Filter、Listener】

注册Servlet三大组件【Servlet、Filter、Listener】

由于SpringBoot默认是以jar包的方式启动嵌入式的Servlet容器来启动SpringBoot的web应用,没有web.xml文件。

注册三大组件用以下方式

//ServletRegistrationBean 
@Bean            # 表示将返回的对象添加到spring容器中
public ServletRegistrationBean myServlet(){                                                                               
                                    # 注册的servlet对象(MyServlet) 拦截的请求
   ServletRegistrationBean registrationBean = new ServletRegistrationBean(new MyServlet(),"/myServlet");
   return registrationBean;
}

//FilterRegistrationBean
@Bean
public FilterRegistrationBean myFilter(){
   FilterRegistrationBean registrationBean = new FilterRegistrationBean();
   registrationBean.setFilter(new MyFilter());    #  注册MyFilter拦截器
   registrationBean.setUrlPatterns(Arrays.asList("/hello","/myServlet")); 
   return registrationBean;
}

//ServletListenerRegistrationBean
@Bean
public ServletListenerRegistrationBean myListener(){
   ServletListenerRegistrationBean<MyListener> registrationBean = new ServletListenerRegistrationBean<>(new MyListener());
   return registrationBean;
}

@WebFilter注解方式

在这里插入图片描述
网上有说使用这种方法配置过滤器,自己试了一下,发起请求时确实进到过滤器里来了,但是并没有按照“/test/list”路径进行过滤,而是过滤了所有URL请求。在百度之后找到解决方案如下:
解决方法:
首先,在上边TestFilter类上加@WebFilter注解是没错的,但是不要加@Component注解,然后在springboot的启动类上加上注解 @ServletComponentScan即可过滤指定路径。
原因:
如果添加了@Component或@Configuration,又添加了@WebFilter(),那么会初始化两次Filter,并且会过滤所有路径+自己指定的路径 ,便会出现对没有指定的URL也会进行过滤的情况。
注:@ServletComponentScan注解的含义:在SpringBootApplication(启动类)上使用@ServletComponentScan注解后,Servlet、Filter(过滤器)、Listener(监听器)可以直接通过@WebServlet、@WebFilter、@WebListener注解自动注册,无需其他代码!

静态资源与拦截器

Spring Boot 默认为我们提供了静态资源处理,使用 WebMvcAutoConfiguration 中的配置各种属性。
这里,我们可以通过查看ResourceProperties类来查看Spring Boot默认提供的静态资源映射:

在这里插入图片描述

注释说明:静态资源文件位置,默认为classpath类路径下:[/META-INF/resources/,/resources/, /static/, /public/]
从上述源码内容以及注释说明可知,Spring Boot的默认配置方式,提供的静态资源映射如下:

classpath:/META-INF/resources
classpath:/resources
classpath:/static
classpath:/public
// 静态资源的访问路径:localhsot/资源文件名

在工程里面路径是这样:
在这里插入图片描述
如果使用的是IDEA开发工具创建的Spring Boot项目,通常会默认提供一个classpath:/static目录,而我们的静态资源文件通常就可以直接放在该目录下。
当然,如果非要自定义静态资源文件的放置路径的话,可以在Spring Boot的配置文件application.properties中配置属性spring.resources.static-locations覆盖默认路径。示例如下:
在这里插入图片描述

我们可以通过修改spring.mvc.static-path-pattern来修改默认的映射,例如我改成/hopu/**,那运行的
时候访问 http://lcoalhost:8080/hopu/index.html 才对应到默认静态资源路径下的index.html页面。

SpringBoot值Web管理

  1. 如果Spring Boot提供的Sping MVC不符合要求,则可以通过一个配置类==(注解有@Configuration的类)加上@EnableWebMvc注解来实现完全自己控制的MVC配置(这样就会关闭Spring Boot提供的所有默认Web配置)。==
  2. 当然,通常情况下,Spring Boot的自动配置是符合我们大多数需求的。在你既需要保留Spring Boot提供的便利,有需要增加自己的额外的配置的时候,可以定义一个配置类并实现WebMvcConfigurer接口,无需使用@EnableWebMvc注解。
  3. 这里我们提到这个WebMvcConfigurer这个接口,重写这个接口中的方法可以让我们增加额外的配置,

这里展示WebMvcConfigurer接口几个常用方法: https://blog.csdn.net/zhangpower1993/article/details/89016503

/* 拦截器配置 */
void addInterceptors(InterceptorRegistry var1);

/* 视图跳转控制器 */
void addViewControllers(ViewControllerRegistry registry);

/**静态资源处理**/
void addResourceHandlers(ResourceHandlerRegistry registry);

/* 默认静态资源处理器 */
void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer);

/**这里配置视图解析器**/
void configureViewResolvers(ViewResolverRegistry registry);

/* 配置内容裁决的一些选项*/
void configureContentNegotiation(ContentNegotiationConfigurer configurer);

/** 解决跨域问题 **/
public void addCorsMappings(CorsRegistry registry) ;

从上可以看出,WebMvcConfigurer接口中提供了众多Web相关的方法,如果有扩展需要,都可以自定义一个该接口的实现类并重写相关方法。
拦截器addInterceptors
这里,我们就一开发中最常用的拦截器为例进行演示说明。
要实现拦截器功能需要完成以下2个步骤:

  1. 创建我们自己的拦截器类并实现 HandlerInterceptor 接口;
  2. 其实重写WebMvcConfigurer中的addInterceptors()方法把自定义的拦截器类添加进来即可。

拦截器

自定义拦截器

package cn.mldn.lxh.xmz.web.Intercepto;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

// 自定义拦截器
public class MyInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("*************拦截成功*************");
// 返回true表示放行,false则拦截
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                           ModelAndView modelAndView) throws Exception {}

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {}
}

配置拦截器

package cn.mldn.lxh.xmz.config;

import cn.mldn.lxh.xmz.web.Intercepto.MyInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/*springboot的web管理,需要继承WebMvcConfigurer*/
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
    /*用于管理拦截器的添加*/
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyInterceptor())
                .addPathPatterns("/**")                     /*用于添加拦截的路径*/
                .excludePathPatterns("/index.html");       /*用于排除拦截的路径*/
    }
}

其他要点

springboot事务处理

@Transactional:是springboot提供的事务处理,在启动程序时,springboot会自动扫描注解,并启动事务的支持

@Service
public class BookServiceImpl implements Iservice<BookInfo> {
    @Autowired
    RoomServiceImpl roomService;

    @Transactional(rollbackFor = Exception.class)     //  开启事务,当发生异常或者手动抛出异常时进行回滚
    @Override
    public boolean insert(Test test) throws Exception {
         roomService.insert(test);
         int i = 10 / 0;                                 // 发生异常,自动进行回滚
        return false;
    }

定时任务

Spring框架的定时任务调度功能支持配置和注解两种方式,Spring Boot在Spring框架的基础上实现了继承,并对其中基于注解方式的定时任务实现了非常好的支持。

定时任务注解
  1. @EnableScheduling
    @EnableScheduling注解是Spring框架提供的,用于开启基于注解方式的定时任务支持,该注解主要用在项目启动类上。
  2. @Scheduled
    @Scheduled注解同样是Spring框架提供的,配置定时任务的执行规则,该注解主要用在定时业务方法上。

@Scheduled注解提供有多个属性,精细化配置定时任务执行规则,这些属性及说明如表所示。

属性说明
cron类似于cron的表达式,可以定制定时任务触发的秒、分钟、小时、月中的日、月、周中的日
zone指定cron表达式将被解析的时区。默认情况下,该属性是空字符串(即使用服务器的本地时区)
fixedDelay表示在上一次任务执行结束后在指定时间后继续执行下一次任务(属性值为long类型)
fixedDelayString表示在上一次任务执行结束后在指定时间后继续执行下一次任务(属性值为long类型的字符串形式)
fixedRate表示每隔指定时间执行一次任务(属性值为long类型)
fixedRateString表示每隔指定时间执行一次任务(属性值为long类型的字符串形式)
initialDelay表示在fixedRate或fixedDelay任务第一次执行之前要延迟的毫秒数(属性值为long类型)
initialDelayString表示在fixedRate或fixedDelay任务第一次执行之前要延迟的毫秒数(属性值为long类型的字符串形式)
cron属性

其属性值由类似于cron表达式,的6位数组成,可以详细地指定定时任务执行的秒、分、小时、日、月、星期。

示例代码如下

@Scheduled(cron = "0 * * * * MON-FRI")
//上述代码中,cron = "0 * * * * MON-FRI"表示周一到周五每一分钟执行一次定时任务。其中,第一位属于秒位,0表示整数时间段,按照每一分钟计算;中间的三位分别属于分、时、日、月位,*表示任意时刻;最后一位属于星期位,MON-FRI表示周一到周五时间区间。

除此之外,cron属性值的每一位还支持非常丰富的字段值,具体说明如表所示。

字段可取值允许的特殊字符
0~59, - * /
0~59, - * /
小时0~23, - * /
1~31, - * / ? L
1~12、月份对应英文前三个字母(大小写均可), - * /
星期0~7(0和7表示SUN)、星期对应英文前三个字母(大小写均可), - * / ? L

上表中列举了@Schedule注解中cron属性6位字段的可取值,这些字段值除了基本的数字之外还有一些特殊字符。其中,上述特殊字符的具体说明及示例如表所示。

特殊字符说明示例
,表示枚举@Scheduled(cron = “1,3,5 * * * * *”)表示任意时间的1、3、5秒钟都会执行
-表示区间参考前面已列举示例
*表示任意可取值参考前面已列举示例
/表示步长@Scheduled(cron = “0/5 * * * * *”)表示从任意时间的整秒开始,每隔5秒都会执行
?日/星期冲突匹配符@Scheduled(cron = “0 * * 26 * ?”)表示每月的26日每一分钟都执行
L最后@Scheduled(cron = “0 0 * L * ?”)表示每月最后一日每一小时都执行
zone属性

zone属性主要与cron属性配合使用,指定解析cron属性值的时区。通常情况下,不需要指定zone属性,cron属性值会自动以服务器所在区域作为本地时区进行表达式解析。例如,中国地区服务器的时区,通常默认为Asia/Shanghai。

fixedDelay和fixedDelayString属性

fixedDelay和fixedDelayString属性的作用类似,指定在上一次任务执行结束后在指定时间后继续执行 下一次任务,它们的主要区别是属性值的类型不同,其中fixedDelay属性值为long类型,而fixedDelayString属性值为long类型的字符串。

下面,通过一个具体的示例说明,示例代码如下。

@Scheduled(fixedDelay = 5000)
@Scheduled(fixedDelayString = "5000")
// 上述代码中,fixedDelay = 5000和fixedDelayString = "5000"都表示在程序启动后,会立即执行一次定时任务,然后在任务执行结束后,相隔5秒钟(5000毫秒)重复执行定时任务。

注意:fixedDelay和fixedDelayString属性:上一次任务执行完后开始计时, => 那么定时任务的相隔时间 = fixedDelay值 + 方法内执行时间

fixedRate和fixedRateString属性

fixedRate和fixedRateString属性的作用类似,指定每相隔一段时间重复执行一次定时任务,它们的主要区别是属性值的类型不同,其中fixedRate属性值为long类型,fixedRateString属性值为long类型的字符串。

下面,通过一个具体的示例说明,示例代码如下。

@Scheduled(fixedRate = 5000)
@Scheduled(fixedRateString = "5000")
// 上述代码中,fixedRate = 5000和fixedRateString = "5000"都表示在程序启动后,会立即执行一次定时任务,然后相隔5秒钟(5000毫秒)重复执行定时任务。

注意:fixedRate和fixedRateString属性:是在上一个任务开始时,就开始计时了,不会管上一个任务是否执行完毕

initialDelay和initialDelayString属性

initialDelay和initialDelayString属性的作用类似,主要是与fixedRate/fixedRateString或者fixedDelay/fixedDelayString属性配合使用,指定,定时任务第一次执行的延迟时间,然后再按照各自相隔时间重复执行任务。

下面,通过一个具体的示例说明,示例代码如下

@Scheduled(initialDelay=1000, fixedDelay=5000)
@Scheduled(initialDelay=1000, fixedRate=5000)
// 上述代码中,都表示在程序启动后,会延迟1秒(1000毫秒)后再执行第一次定时任务,然后相隔5秒钟(5000毫秒)重复执行定时任务。
总结

注意:fixedRate/fixedRateString属性与fixedDelay/fixedDelayString属性的作用有些类似,都是相隔一段时间再重复执行定时任务,它们主要区别是:

  • fixedDelay/fixedDelayString属性的下一次执行时间必须是在上一次任务执行完成后开始计时;
  • fixedRate/fixedRateString属性的下一次,执行时间是在上一次任务执行开始计时,如果遇到配置相隔时间小于定时任务执行时间,那么下一次任务会在上一次任务执行完成后立即重复执行。
案例

1、开启基于注解的定时任务支持

@SpringBootApplication
@EnableScheduling       /*开启定时任务*/
public class SpringBootDay02 {
    public static void main(String[] args) {
        SpringApplication.run(SpringBootDay02.class,args);
    }
}

2、编写定时业务

// 每隔10秒钟执行一次,从第一次任务开始时,开始计时,每隔5s执行,
@Scheduled(fixedRate = 5000)
public void scheduledTaskImmediately() throws InterruptedException {
    System.out.println(String.format("fixedRate第%s次执行,当前时间为:%s",
            count1++, dateFormat.format(new Date())));
    Thread.sleep(5000);
}

// 每次任务执行完后相隔5秒再执行一次,方法中间的延迟操作有效, Thread.sleep(10000);生效,
@Scheduled(fixedDelay = 5000)
public void scheduledTaskAfterSleep() throws InterruptedException {
    System.out.println(String.format("fixedDelay第%s次执行,当前时间为:%s",
            count2++, dateFormat.format(new Date())));
    Thread.sleep(5000);
}

// 每次任务执行完后相隔5秒再执行一次,
@Scheduled(cron = "0/5 * * * * *")/*cron表达式的含义是,每个月的每星期的每天的每小时,每分钟内,5s执行一次*/
public void scheduledTaskCron() throws InterruptedException {
    System.out.println(String.format("cron第%s次执行,当前时间为:%s",
            count3++, dateFormat.format(new Date())));
    sendSimpleMailTest();
    Thread.sleep(10000);
}

邮件服务

在实际开发中,邮件发送服务应该是网站的必备功能之一,例如用户注册验证、忘记密码、给用户发送营销信息等。在早期开发过程中,通常会使用JavaMail相关Api实现邮件发送功能,后来Spring推出了JavaMailSender简化了邮件发送的过程和实现,Spring Boot框架对Spring提出的邮件发送服务也进行了整合支持。下面,针对Spring Boot框架整合支持的邮件任务进行讲解。

发送纯文本邮件

(1)导入依赖

<!-- 邮件发送依赖启动器 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mail</artifactId>
</dependency>

当添加上述依赖后,Spring Boot自动配置的邮件服务会生效,在邮件发送任务时,可以直接使用Spring框架提供的JavaMailSender接口或者它的实现类JavaMailSenderImpl邮件发送。

(2)添加邮件服务配置
在项目中添加邮件服务依赖启动器后,还需要在配置文件中添加邮件服务相关的配置,确保邮件服务正常发送。打开项目的application.properties全局配置文件,在该文件中添加发件人邮箱服务配置和邮件服务超时的相关配置,内容如下所示。

# 发件人邮服务器相关配置
spring.mail.host=smtp.qq.com
# 邮件端口
spring.mail.port=587
# 配置个人QQ账户和密码(密码是加密后的授权码)
spring.mail.username=2811659799@qq.com
# 授权码
spring.mail.password=hcewsvqodvsfdgfg
spring.mail.default-encoding=UTF-8
# 邮件服务超时时间配置
spring.mail.properties.mail.smtp.connectiontimeout=5000
spring.mail.properties.mail.smtp.timeout=3000
spring.mail.properties.mail.smtp.writetimeout=5000

注意:使用java程序发送邮件,必须在发件人邮箱中开启POP3/SMTP服务 开启后会给你一个授权码,根据这个授权码就可以操作这个邮箱发送邮件了

(3)编写业务

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.MailException;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.stereotype.Service;

// 发送邮件服务类
@Service
public class SendEmailService {
    @Autowired
    private JavaMailSenderImpl mailSender;
    @Value("${spring.mail.username}")
    private String from;    //发件人地址

    // 发送简单邮件,调用这个方法,传入收件人,邮件标题,邮件内容,则可以发送纯文本的邮件了
    public void sendSimpleEmail(String to, String subject, String text) {
// 定制纯文本邮件信息SimpleMailMessage
        SimpleMailMessage message = new SimpleMailMessage();
        message.setFrom(from);      /*发件人邮件地址*/
        message.setTo(to);          /*收件人邮件地址*/
        message.setSubject(subject);    /*邮件标题*/
        message.setText(text);      /*邮件内容*/
        try {
            // 发送邮件
            mailSender.send(message);
            System.out.println("纯文本邮件发送成功");
        } catch (MailException e) {
            System.out.println("纯文本邮件发送失败 " + e.getMessage());
            e.printStackTrace();
        }
    }
}

发送thymeleaf模板邮件

编写服务

// 发送邮件服务类
@Service
public class SendEmailService {
    @Autowired
    private JavaMailSenderImpl mailSender;
    @Value("${spring.mail.username}")
    private String from;     //发件人地址
/**
 * 发送thymeleaf模板邮件
 * @param to       收件人地址
 * @param subject  邮件标题
 * @param content  html,thymeleaf模板页面内容
 */
public void sendTemplateEmail(String to, String subject, String content) {
    MimeMessage message = mailSender.createMimeMessage();
    try {
        // 使用MimeMessageHelper帮助类,并设置multipart多部件使用为true
        MimeMessageHelper helper = new MimeMessageHelper(message, true);
        helper.setFrom(from);
        helper.setTo(to);
        helper.setSubject(subject);
        helper.setText(content, true);
        // 发送邮件
        mailSender.send(message);
        System.out.println("模板邮件发送成功");
    } catch (MessagingException e) {
        System.out.println("模板邮件发送失败 " + e.getMessage());
        e.printStackTrace();
    }
}

发送邮件

 @Autowired
   private TemplateEngine templateEngine;

//    每5秒,发送一次模板邮件
//    @Scheduled(cron = "0/5 * * * * *")
   public void sendTemplateEmail() {
       String to = "1943260672@qq.com";
       String subject = "【田波涛,你个憨憨】";
       // 使用模板邮件定制邮件正文内容
       Context context = new Context();
       //        给emailTemplate_vercode.html模板${}传值
       context.setVariable("username", "石头");
       context.setVariable("code", "456123");
       // 使用TemplateEngine设置要处理的模板页面
       String emailContent = templateEngine.process("emailTemplate_vercode", context);
       // 发送模板邮件
       sendEmailService.sendTemplateEmail(to, subject, emailContent);
   }
发送复杂邮件

发送邮件

// 发送邮件服务类
@Service
public class SendEmailService {
    @Autowired
    private JavaMailSenderImpl mailSender;
    @Value("${spring.mail.username}")
    private String from;     //发件人地址

/**
 * 发送复杂邮件(包括静态资源和附件)
 * @param to       收件人地址
 * @param subject  邮件标题
 * @param text     邮件内容
 * @param filePath 附件地址
 * @param rscId    静态资源唯一标识
 * @param rscPath  静态资源地址
 */
public void sendComplexEmail(String to, String subject, String text,
                             String filePath, String rscId, String rscPath) {
    // 定制复杂邮件信息MimeMessage
    MimeMessage message = mailSender.createMimeMessage();
    try {
        // 使用MimeMessageHelper帮助类,并设置multipart多部件使用为true
        MimeMessageHelper helper = new MimeMessageHelper(message, true);
        helper.setFrom(from);
        helper.setTo(to);
        helper.setSubject(subject);
        helper.setText(text, true);
        // 设置邮件静态资源
        FileSystemResource res = new FileSystemResource(new File(rscPath));
        helper.addInline(rscId, res);
        // 设置邮件附件
        FileSystemResource file = new FileSystemResource(new File(filePath));
        String fileName =
                filePath.substring(filePath.lastIndexOf(File.separator));
        helper.addAttachment(fileName, file);
        // 发送邮件
        mailSender.send(message);
        System.out.println("复杂邮件发送成功");
    } catch (MessagingException e) {
        System.out.println("复杂邮件发送失败 " + e.getMessage());
        e.printStackTrace();
    }
}

编写服务

//  每过5秒发送一封复杂邮件
@Scheduled(cron = "0/5 * * * * *")
public void sendComplexEmail() {
    String to="1943260672@qq.com";
    String subject="【邓春圆】标题";
    // 定义邮件内容
    StringBuilder text = new StringBuilder();
    text.append("<html><head></head>");
    text.append("<body><h1>祝大家元旦快乐!</h1>");
    // cid为固定写法,rscId自定义的资源唯一标识
    String rscId = "img001";
    text.append("<img src='cid:" +rscId+"'/></body>");
    text.append("</html>");
    // 指定静态资源文件和附件路径
    String rscPath="C:\\Users\\ssa\\Desktop\\图片\\png无背景图片\\手机图片\\A20.jpg";
    String filePath="C:\\Users\\ssa\\Desktop\\day02-springboot.pdf";
    // 发送复杂邮件
    sendEmailService.sendComplexEmail(to,subject,text.toString(),filePath,rscId,rscPath);
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值