SpringBoot+Mybatis+RocketMQ+SpringCloud(一,SpringBoot整合)

简单说下自己目前的理解:springBoot是对spring的升级,为什么升级?因为各种语言发展到现在,已经非常方便了。但是java,甚至是spring都需要大量的jar包,编译,然后放入tomcat/apache中去执行,上线也需要很多。但是如果使用springBoot,就可以使用它自动生成的相当于main函数的,直接运行。上线,也变得简单。(待写)
特点:

  1. 创建独立的Spring应用程序
  2. 嵌入的Tomcat,无需部署WAR文件
  3. 简化Maven配置
  4. 自动配置Spring
  5. 提供生产就绪型功能,如指标,健康检查和外部配置
  6. 绝对没有代码生成并且对XML也没有配置要求

SpringBoot其实就相当于一个库:简单理解就是springboot并不是什么新型的框架,而是整合了spring,springmvc等框架,默认了很多配置,从而减少了开发者的开发时间。需要什么就去maven.

下面,请开始你的表演。
基础结构说明:src/main/java.是下的程序入口,spring-boot会自动加载启动类所在包下及其子包下的所有组件.。
src/main/resources:配置文件
src/test/java:测试入口

在这里插入图片描述
前面写了一半,隔了一段时间,中间换了电脑,那么重新来过。
1,构建SpringBoot项目
首先确保maven的引入:正确引入后才能构建maven项目。
在这里插入图片描述
1,构建项目,去到https://start.spring.io/;推荐maven + jar的形式,下面的有依赖添加,比如Mybatise,数据库等,你需要的直接勾上即可。
在这里插入图片描述
在这里插入图片描述
下载后,将该项目导入eclipse或者IDEA中。导入:直接导入已有maven项目即可,没什么可说的。
import - > 搜索maven --> 选择existed maven project --> 选择即可。如下:
在这里插入图片描述
关于配置信息的对应关系前面已经写过,不在累述。
尝试运行,运行结果:(运行方式:不要选择run on server,选择Java application选择你的主类运行)
这里普及下运行相关的知识:
maven build是重新对该maven项目进行打包
maven clean : 清除target目录下的之前打好的jar包或者是war包
maven install :是对上面两个命令的集合,既是通过maven自带的原生命令,同时执行了clean 和build,比较节省时间
打包推荐操作:maven clean + maven install 生成最新的jar包或其他包(这样是最保险的)
在这里插入图片描述

必须先说明两点:①必须加web依赖,不是web项目,启动不了;②由于加入依赖Mybatis,需要加上注解保证能扫描到(当然也可以application.properties中添加数据库信息)。另外也可能是其他的原因:properties文件没有被扫描到,需要在pom文件中添加,来保证文件都能正常被扫描到并且加载成功.
这里说明下注解:
@SpringBootApplication // Springboot的核心 全局注解,
可以看到这是一个注解接口包含自动扫描和开启自动配置

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
	@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
	@Filter(type = FilterType.CUSTOM,
			classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {

/**
 * Exclude specific auto-configuration classes such that they will never be applied.
 * @return the classes to exclude
 */
@AliasFor(annotation = EnableAutoConfiguration.class)  //开启自动配置
Class<?>[] exclude() default {};

/**
 * Exclude specific auto-configuration class names such that they will never be
 * applied.
 * @return the class names to exclude
 * @since 1.3.0
 */
@AliasFor(annotation = EnableAutoConfiguration.class)
String[] excludeName() default {};

/**
 * Base packages to scan for annotated components. Use {@link #scanBasePackageClasses}
 * for a type-safe alternative to String-based package names.
 * @return base packages to scan
 * @since 1.3.0
 */
@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")  //自动扫描
String[] scanBasePackages() default {};

/**
 * Type-safe alternative to {@link #scanBasePackages} for specifying the packages to
 * scan for annotated components. The package of each class specified will be scanned.
 * <p>
 * Consider creating a special no-op marker class or interface in each package that
 * serves no purpose other than being referenced by this attribute.
 * @return base packages to scan
 * @since 1.3.0
 */
@AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
Class<?>[] scanBasePackageClasses() default {};

}

在这里插入图片描述
依赖查看:Dependencies可查看有那些依赖;Dependency hierarchy可查看每一个依赖包含的内容。从下面可以看到已经导入很多的包。
在这里插入图片描述
更改端口号:(及运行结果)
在这里插入图片描述
测试controller

package com.example.demo;

//import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

// 复合注解 @RestController注解:其实就是@Controller和@ResponseBody注解加在一起
// 复合注解
@RestController
//@EnableAutoConfiguration
@RequestMapping(value = "/demo")
public class HelloController {

@RequestMapping("/test")
String index() {
    return "nihao!zhouyi";
}
}

启动项目:结果如下:(纠结了一天终于解决了)
在这里插入图片描述
但是这其中有很多坑:
①报错端口无端被占用,只能是在配置文件中改端口或者cmd命令查看端口并在任务管理器中关闭对应的PID,(重启端口被占用的根本原因查看日志可以发现一次启动却启动了两次tomcat,这是因为项目部署的tomcat没有移除的原因)---------这里告诉我一个道理,分析日志可以解决很多问题。

②报错This application has no explicit mapping for /error, so you are seeing this as a fallback.
查了很多网上的方法:(但是都没有解决我的问题)
出现这个异常说明了跳转页面的url无对应的值.
原因1:
Application启动类的位置不对.要将Application类放在最外侧,即包含所有子包
原因:spring-boot会自动加载启动类所在包下及其子包下的所有组件.
原因2:
在springboot的配置文件:application.yml或application.properties中关于视图解析器的配置问题:
当pom文件下的spring-boot-starter-paren版本高时使用:
spring.mvc.view.prefix/spring.mvc.view.suffix
当pom文件下的spring-boot-starter-paren版本低时使用:
spring.view.prefix/spring.view.suffix
原因3:
控制器的URL路径书写问题
@RequestMapping(“xxxxxxxxxxxxxx”)
实际访问的路径与”xxx”不符合.
原因4:
我在这里补充我自己问题:是因为我原先启动的项目是由tomcat去运行的。然而SpringBoot的项目是不需要这个,因为SpringBoot本身嵌入了Tomcat,前面已经说过(?????)。上面的两个问题都是由这个原因引起的,解决方式:请删除本地的Tomcat部署。

测试测试类Tests

// 以classes = SpringBootDemoApplication.class为基础做单元测试,在里面写测试内容即可。
@RunWith(SpringRunner.class)
@SpringBootTest(classes = SpringBootDemoApplication.class)
public class SpringBootDemoApplicationTests {

@Test
public void contextLoads() {
}
}

SpringBoot静态资源访问
1.springboot访问静态资源的几种方式
在src/main/resources/目录下创建 static文件夹 或 resources文件夹 或 public文件夹 或 META-INF 或 resources文件夹
例如:
在这里插入图片描述
结果与访问方式:直接图片名称即可:http://localhost:8003/IO.PNG
在这里插入图片描述
测试打包项目:(maven clean + maven install)。maven打出jar包直接跑起来就是个网站
运行结果:对应目录中查看(这里说明一点如果是第一次打包需要maven很多东西,很耗时)
在这里插入图片描述
SpringBoot提供的模板引擎
springBoot默认配置的模板引擎有以下几种:使用以下某一个模板引擎的时候,默认的配置路径为:
src/main/resources/templates下。
①Thymeleaf : 主要适用于邮件。是一个XML/XHTML/HTML5的开源模板引擎。可用于web和非web环境中开发。是二次渲染,不太推荐。
② FreeMarker : 一种基于模板和要改变的数据,并用来生成输出文本(HTML网页、电子邮件、配置文件、源代码等)的通用工具。推荐使用。
③ Velocity:
④ Groovy
⑤ Mustache
⑥ JSP(强烈不推推荐使用)

SpringBoot整合Swagger : (前后端分离建议使用)
参考 https://www.cnblogs.com/jtlgb/p/8532433.html;
postman做单个测试还行,但是较多时,接口文档太多,不好管理。
里面说的非常详尽,实测通过。接下来是大自然的搬运工:????????
1.整体结构和Swagger2的maven配置。建议去Swagger2官网看依赖,
在这里插入图片描述
2.代码部分。
启动类:

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;

import springfox.documentation.swagger2.annotations.EnableSwagger2;

// Springboot的核心 全局注解
@SpringBootApplication(exclude= {DataSourceAutoConfiguration.class})
@EnableSwagger2 //加上注解@EnableSwagger2 表示开启Swagger,这个注解不可少
public class SpringBootDemoApplication {

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

Swagger2配置类

package com.example.demo;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;

/**
* @author zhouyi
 * @Description
 */
@Configuration
public class Swagger2 {

// 用@Configuration注解该类,等价于XML中配置beans;用@Bean标注方法等价于XML中配置bean。
@Bean
public Docket createRestApi() {
    return new Docket(DocumentationType.SWAGGER_2)
            .apiInfo(apiInfo())
            .select()
            .apis(RequestHandlerSelectors.basePackage("com.example.demo.controller"))
            .paths(PathSelectors.any())
            .build();
}

private ApiInfo apiInfo() {
    return new ApiInfoBuilder()
            .title("springboot利用swagger构建api文档")
            .description("简单优雅的restfun风格,http://blog.csdn.net/saytime")
            .termsOfServiceUrl("http://blog.csdn.net/saytime")
            .version("1.0")
            .build();
}
}

控制类controller

package com.example.demo.controller;

import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.example.demo.entities.JsonResult;
import com.example.demo.entities.User;

import springfox.documentation.annotations.ApiIgnore;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author zh
 * @Description
 */
@RestController
public class UserController {

// 创建线程安全的Map
static Map<Integer, User> users = Collections.synchronizedMap(new HashMap<Integer, User>());

/**
 * 根据ID查询用户
 * @param id
 * @return
 */
@ApiOperation(value="获取用户详细信息", notes="根据url的id来获取用户详细信息")
@ApiImplicitParam(name = "id", value = "用户ID", required = true, dataType = "Integer", paramType = "path")
@RequestMapping(value = "user/{id}", method = RequestMethod.GET)
public ResponseEntity<JsonResult> getUserById (@PathVariable(value = "id") Integer id){
    JsonResult r = new JsonResult();
    try {
        User user = users.get(id);
        r.setResult(user);
        r.setStatus("ok");
    } catch (Exception e) {
        r.setResult(e.getClass().getName() + ":" + e.getMessage());
        r.setStatus("error");
        e.printStackTrace();
    }
    return ResponseEntity.ok(r);
}

/**
 * 查询用户列表
 * @return
 */
@ApiOperation(value="获取用户列表", notes="获取用户列表")
@RequestMapping(value = "users", method = RequestMethod.GET)
public ResponseEntity<JsonResult> getUserList (){
    JsonResult r = new JsonResult();
    try {
        List<User> userList = new ArrayList<User>(users.values());
        r.setResult(userList);
        r.setStatus("ok");
    } catch (Exception e) {
        r.setResult(e.getClass().getName() + ":" + e.getMessage());
        r.setStatus("error");
        e.printStackTrace();
    }
    return ResponseEntity.ok(r);
}

/**
 * 添加用户
 * @param user
 * @return
 */
@ApiOperation(value="创建用户", notes="根据User对象创建用户")
@ApiImplicitParam(name = "user", value = "用户详细实体user", required = true, dataType = "User")
@RequestMapping(value = "user", method = RequestMethod.POST)
public ResponseEntity<JsonResult> add (@RequestBody User user){
    JsonResult r = new JsonResult();
    try {
        users.put(user.getId(), user);
        r.setResult(user.getId());
        r.setStatus("ok");
    } catch (Exception e) {
        r.setResult(e.getClass().getName() + ":" + e.getMessage());
        r.setStatus("error");

        e.printStackTrace();
    }
    return ResponseEntity.ok(r);
}

/**
 * 根据id删除用户
 * @param id
 * @return
 */
@ApiOperation(value="删除用户", notes="根据url的id来指定删除用户")
@ApiImplicitParam(name = "id", value = "用户ID", required = true, dataType = "Long", paramType = "path")
@RequestMapping(value = "user/{id}", method = RequestMethod.DELETE)
public ResponseEntity<JsonResult> delete (@PathVariable(value = "id") Integer id){
    JsonResult r = new JsonResult();
    try {
        users.remove(id);
        r.setResult(id);
        r.setStatus("ok");
    } catch (Exception e) {
        r.setResult(e.getClass().getName() + ":" + e.getMessage());
        r.setStatus("error");

        e.printStackTrace();
    }
    return ResponseEntity.ok(r);
}

/**
 * 根据id修改用户信息
 * @param user
 * @return
 */
@ApiOperation(value="更新信息", notes="根据url的id来指定更新用户信息")
@ApiImplicitParams({
        @ApiImplicitParam(name = "id", value = "用户ID", required = true, dataType = "Long",paramType = "path"),
        @ApiImplicitParam(name = "user", value = "用户实体user", required = true, dataType = "User")
})
@RequestMapping(value = "user/{id}", method = RequestMethod.PUT)
public ResponseEntity<JsonResult> update (@PathVariable("id") Integer id, @RequestBody User user){
    JsonResult r = new JsonResult();
    try {
        User u = users.get(id);
        u.setUsername(user.getUsername());
        u.setAge(user.getAge());
        users.put(id, u);
        r.setResult(u);
        r.setStatus("ok");
    } catch (Exception e) {
        r.setResult(e.getClass().getName() + ":" + e.getMessage());
        r.setStatus("error");

        e.printStackTrace();
    }
    return ResponseEntity.ok(r);
}

@ApiIgnore//使用该注解忽略这个API
@RequestMapping(value = "/hi", method = RequestMethod.GET)
public String  jsonTest() {
    return " hi you!";
}
}

实体和对象转换类(get/set自己生成)
在这里插入图片描述
这里的get/set太烦,于是引入Lombok.jar.依赖添加

<dependency>
	<groupId>org.projectlombok</groupId>
	<artifactId>lombok</artifactId>
	<version>1.18.6</version>
	<scope>provided</scope>
</dependency>

但是发现还是不能用Getter/Setter,于是再去Lombok的官网查看要求:意思是maven之后,本地也要下载Lombok。
在这里插入图片描述
eclipse中于是:(完成重启)

  1. 将 lombok.jar 复制到 myeclipse.ini / eclipse.ini 所在的文件夹目录下
  2. 打开 eclipse.ini / myeclipse.ini,在最后面插入以下两行并保存:
    -Xbootclasspath/a:lombok.jar
    -javaagent:lombok.jar
    运行结果:(ctrl + O查看,显然已经加进来了)
    在这里插入图片描述

测试运行结果:(http://localhost:8003/swagger-ui.html#/)
在这里插入图片描述
SpringBoot整合redis(这里暂时不去写)

SpringBoot统一异常处理
为什么要统一处理?因为如果系统发生了异常,不做统一异常处理,前端会给用户展示一大片看不懂的文字,显得杂乱无章非常费力。相反我们做了统一处理,会极大提高效率。
参考链接:https://blog.csdn.net/u013042707/article/details/82053705
在SpringBoot中有/error异常处理的,结果如下:它使用public class RuntimeException extends Exception 关系抛出的异常,因此我们要修改只需要继承RuntimeException接口,设计统一异常处理。
在这里插入图片描述
1,开始做统一异常处理(当然我觉得这是一种思维,你想要的都可以扩展定义 异常)
自定义异常类:再写之前先说明一种编写程序的思维。人不是的记忆是有限的,不可记住所有,学习也好,都是如此:在前面我们已经说过要用继承RuntimeException接口的方式去实现,但是发现真的去写的时候,有点不知道怎么去写,此时打开他所继承的你就应该有思路了。**以下测试只过了一半,有时间来完善,目前看来问题出现在ResultUtils **
在这里插入图片描述

package com.example.demo.config;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class MyException extends RuntimeException {

 private Integer code;

 public MyException(String msg){

   super(msg);

   }

 public MyException(Integer code,String msg){

   super(msg);

   this.code=code;

  }

}

2,自定义枚举类(用以列举异常类型)

package com.example.demo.config;

import lombok.Getter;

@Getter
public enum ResultEnum {

SUCCESS(200,"成功"),// 提示没有构造,那么就先构造。
FIAL(100,"失败"), // 注意是逗号连接,分号结束。
EXCEPTION(300,"异常"),
UNLOGIN(201,"未登录");

private Integer code;

private String msg;

private ResultEnum(Integer code,String msg) {
    this.code = code;
    this.msg = msg;
}

public void setCode(Integer code) {
    this.code = code;
}
}

3,自定义返回数据类以及utils
数据类

package com.example.demo.entities;

/**
* 用来封装返回信息
 * @author zy962
 *
 */
public class ExceptionResult {

// 异常码
private Integer code;

// 异常信息
private String msg;

// 数据集合
private Object object;

public Object getObject() {
    return object;
}

public void setObject(Object object) {
    this.object = object;
}

public Integer getCode() {
    return code;
}

public void setCode(Integer code) {
    this.code = code;
}

public String getMsg() {
    return msg;
}

public void setMsg(String msg) {
    this.msg = msg;
}


// builder构建
public static class Builder {
    
    // 异常码
    private Integer code;
    
    // 异常信息
    private String msg;
    
    // 数据集合
    private Object object;
    
    public Builder code(Integer code) {
        this.code = code;
        return this;
    }
    
    public Builder msg(String msg) {
        this.msg = msg;
        return this;
    }
    
    public Builder object(Object object) {
        this.object = object;
        return this;
    }
    
    public ExceptionResult build() {
        return new ExceptionResult(this);
    }
    
}

public ExceptionResult(Builder builder) {
    this.code = builder.code;
    this.msg = builder.msg;
    this.object = builder.object;
}

//    public static void main(String[] args) {
//        ExceptionResultUtils result = new Builder().code(100).msg("登陆错误").object(new 	Object()).build();
//        System.out.println(result);
//    }
}

utils

package com.example.demo.entities;

import com.example.demo.config.ResultEnum;

public class ResultUtils {

public static ExceptionResult success(int i, String info) {
    ExceptionResult result = null;
    result.setCode(i);
    result.setMsg(info);
    return result;
}

public static ExceptionResult success(ResultEnum unlogin) {
    ExceptionResult result = null;
    result.setCode(unlogin.getCode());
    result.setMsg(unlogin.getMsg());
    result.setObject(new Object());
    return result;
}

public static ExceptionResult success(String info) {
    ExceptionResult result = null;
    result.setCode(200);
    result.setObject(new String[] {"一个人也挺好,不要去考虑别人的感受"});
    return result;
}

}

4,自定义全局异常捕获类

package com.example.demo.controller;

import javax.servlet.http.HttpServletRequest;

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import com.example.demo.config.MyException;
import com.example.demo.config.ResultEnum;
import com.example.demo.entities.ExceptionResult;

@ControllerAdvice
public class MyExceptionAdvice {

@ExceptionHandler(value = Exception.class)
@ResponseBody
public ExceptionResult defaultException(HttpServletRequest request,Exception e){

     e.printStackTrace();

     return new ExceptionResult.Builder()

               .code(ResultEnum.EXCEPTION.getCode())

               .msg(ResultEnum.EXCEPTION.getMsg())

               .build();

}



@ExceptionHandler(value = MyException.class)

@ResponseBody

public ExceptionResult myException(HttpServletRequest request,MyException e){

     e.printStackTrace();

     Integer code=e.getCode();

     String message=e.getMessage();



     if (e.getCode()==null){

          code=ResultEnum.EXCEPTION.getCode();

     }

     if (e.getMessage()==null){

          message=ResultEnum.EXCEPTION.getMsg();

     }

     return new ExceptionResult.Builder()

               .code(code)

               .msg(message)

               .build();

}
}

5,测试类:输入对应请求,举例较完整的测试请求,比如:http://localhost:8001/testE/exception?name=zhouyi&pwd=823

package com.example.demo.controller;

import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.example.demo.config.MyException;
import com.example.demo.config.ResultEnum;
import com.example.demo.entities.ExceptionResult;
import com.example.demo.entities.ResultUtils;

@RestController
@RequestMapping("/testE")
public class MyExceptionController {
    
       @RequestMapping("/exception")
       public ExceptionResult exception(String name,String pwd) throws Exception {
     
               String realname="zhouyi";
     
               String realPwd="823";
     
     
     
               if(null!=name&&name.equals("xx")){
     
                   throw new Exception("系统异常!");
     
               }
     
               if(StringUtils.isEmpty(name)||StringUtils.isEmpty(pwd)){
     
                   throw new MyException("参数必须传!");
     
               }else if (!name.equals(realname)||!pwd.equals(realPwd)){
     
                   throw new MyException("用户名或密码不正确!");
     
               }else if (name.equals("aa")){
     
                   throw new MyException(200,"用户名存在!");
     
               }
     
               String info="你好["+name+"]!";
     
           return ResultUtils.success(info);
     
       }
     
       @RequestMapping("/unlogin")
     
       public ExceptionResult unlogin() throws Exception {
     
           return ResultUtils.success(ResultEnum.UNLOGIN);
     
       }
     
       @RequestMapping("/success")
     
       public ExceptionResult success() throws Exception {
     
           return ResultUtils.success(200,"自定义消息");
     
       }
}

测试的结果:
在这里插入图片描述
SpringBoot定时任务
先看看SpringBoot提供的几种方式:
@Scheduled(fixedRate = 5000) :上一次开始执行时间点之后5秒再执行
@Scheduled(fixedDelay = 5000) :上一次执行完毕时间点之后5秒再执行
@Scheduled(initialDelay=1000, fixedRate=5000) :第一次延迟1秒后执行,之后按fixedRate的规则每5秒执行一次
@Scheduled(cron="*/5 * * * * *") :通过cron表达式定义规则
注意,这里的时间,单位是毫秒,1秒=1000毫秒
主类:

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.scheduling.annotation.EnableScheduling;

import springfox.documentation.swagger2.annotations.EnableSwagger2;

// Springboot的核心 全局注解
@SpringBootApplication(exclude= {DataSourceAutoConfiguration.class})
	@EnableSwagger2 //加上注解@EnableSwagger2 表示开启Swagger
@EnableScheduling // 开启定时任务注解
public class SpringBootDemoApplication {

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

定时类:

package com.example.demo.task;

import java.text.SimpleDateFormat;
import java.util.Date;

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component // 纳入bean容器中
public class ScheduledTasks {
private static final SimpleDateFormat dateFormat = new SimpleDateFormat();

/**
 * 每间隔5秒输出时间
 */
@Scheduled(fixedRate = 5000)
public void reportCurrentTime() {
    System.out.println("当前时间: " + dateFormat.format(new Date()));
}
}

运行结果:
在这里插入图片描述
但是上面的程序是有点问题的,如果我们想要去改定时时间,那么就得去改动程序这样是不好的。
定时器的实现总结:
① 前面总结线程池有写过用:ScheduledExecutorService来时来实现。
② Spring Task:Spring提供的一个任务调度工具,支持注解和配置文件形式,支持Cron表达式,使用简单但功能强大,也就是上面的例子,实现较为简单。
③ Quartz :一款功能强大的任务调度器,可以实现较为复杂的调度功能,如每月一号执行、每天凌晨执行、每周五执行等等,还支持分布式调度,就是配置稍显复杂。

SpringBoot整合Quartz:(为什么是使用?多任务情况下,quartz更容易管理,可以实现动态配置 )
在2.0.0后spring-boot-starter中已经包含了quart的依赖,则可以直接使用spring-boot-starter-quartz依赖

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

参考来自:https://blog.csdn.net/upxiaofeng/article/details/79415108,
亲测完美运行。

SpringBoot整合JavaMailSender发送邮件
同样在后spring-boot-starter中已经集成,spring-boot-starter-mail直接添加依赖即可,不累述。
准备:首先你得有邮箱:去设置里找到服务器地址。
在这里插入图片描述
先说其中的坑:
报错:Could not connect to SMTP host: smtp.163.com, port: 25,这是因为官方对25号端口禁用。于是端口改成465。我运行就报错Could not connect to SMTP host: smtp.163.com, port: 465,这是因为我使用了ssl加密,没有设置为ture,于是加上下面这句。

spring.mail.properties.mail.smtp.ssl.enable=true

我以为加上就可以了,天真!又报错:550 User has no permissio说没有授权,于是我又去网易邮箱获取授权码。终于成功了。????????
配置文件:

spring.mail.host=smtp.163.com
spring.mail.port=465
spring.mail.username=zy96249454@163.com
spring.mail.password=###########
spring.mail.properties.smtp.auth=true
spring.mail.properties.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.starttls.required=true
#ssl must be true
spring.mail.properties.mail.smtp.ssl.enable=true

简单邮件:(图就不给了)

package com.example.demo.mail;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping(value = "/mail")
public class MailController {
 @Autowired
 JavaMailSender mailSender; // 这是有spring-boot-starter自动注入的

 @GetMapping("/send")
 public String send(){
    
    //建立邮件消息
    SimpleMailMessage mainMessage = new SimpleMailMessage();
    //发送者
    mainMessage.setFrom("zy96249454@163.com");
    //接收者
    mainMessage.setTo("1770187049@qq.com");
    //发送的标题
    mainMessage.setSubject("这是简单邮件");
    //发送的内容
    mainMessage.setText("不爱就不爱吧!");
    
    mailSender.send(mainMessage);
    return "发送简单邮件";  //访问http://localhost:8002/mail/send,查看发送成功与否。
}
}

以下关于复杂邮件的发送。我是大自然的搬运工。
html模板邮件发送:

@RequestMapping("/sendHtmlMail")
public String testHtmlMail() {
    String content="<html>\n" +
            "<body>\n" +
            "    <h3>hello world ! 这是一封Html邮件!</h3>\n" +
            "</body>\n" +
            "</html>";
    MimeMessage message = javaMailSender.createMimeMessage();  // 复杂邮件

    try {
        //true表示需要创建一个multipart message
        MimeMessageHelper helper = new MimeMessageHelper(message, true); // 复杂邮件的容器
        helper.setFrom(sender);
        helper.setTo(receiver);
        helper.setSubject("html mail");
        helper.setText(content, true);  /这里的网页你也可以去新建一个html模板网页放进去。

        javaMailSender.send(message); // 发送给邮件
        logger.info("html邮件发送成功");
    } catch (MessagingException e) {
        logger.error("发送html邮件时发生异常!", e);
    }
    return "success";
    }

带有附件的邮件发送:

@RequestMapping("/sendFilesMail")
public String sendFilesMail() {
    String filePath="/Users/dalaoyang/Downloads/article_tag.sql";
    MimeMessage message = javaMailSender.createMimeMessage();

    try {
        MimeMessageHelper helper = new MimeMessageHelper(message, true);
        helper.setFrom(sender);
        helper.setTo(receiver);
        helper.setSubject("附件邮件");
        helper.setText("这是一封带附件的邮件", true);

        FileSystemResource file = new FileSystemResource(new File(filePath));
        String fileName = filePath.substring(filePath.lastIndexOf(File.separator));
        helper.addAttachment(fileName, file);  // 这是附件添加方法(图片等所有都可以算作附件)

        javaMailSender.send(message);
        logger.info("带附件的邮件已经发送。");
    } catch (MessagingException e) {
        logger.error("发送带附件的邮件时发生异常!", e);
    }
    return "success";
}

这里上面有三个方法,在实际中可以分开封装,你需要调用即可。
SpringBoot还有许多的整合(以后遇到再来添加)
最后给出较为完整的build

<build>
    <!-- 打包文件名后面可带版本号等demo -->
    <finalName>demo</finalName>
    <!-- 打包包含properties和xml -->
    <resources>
       <resource>
           <directory>src/main/java</directory>
           <includes>
               <include>**/*.properties</include>
               <include>**/*.xml</include>
               <!-- 是否替换资源中的属性 -->
           </includes>
           <filtering>true</filtering>
       </resource>
       <resource>
           <directory>src/main/resources</directory>
       </resource>
    </resources>
	<plugins>
	    <!-- 单元测试 -->
	    <plugin>
	        <groupId>org.apache.maven.plugins</groupId>
	        <artifactId>maven-jar-plugin</artifactId>
	        <configuration>
	              <skip>true</skip>
	              <includes>
	                  <include>**/*test*.java</include>
	              </includes>
	              <testFailureIgnore>true</testFailureIgnore>
	        </configuration>
	    </plugin>
	    <!-- 解决maven更新版本降低 -->
	    <plugin>
	          <groupId>org.apache.maven.plugins</groupId>
	          <artifactId>maven-compiler-plugin</artifactId>
	          <configuration>
	              <source>1.8</source>
	              <target>1.8</target>
	          </configuration>
	    </plugin>
	    
		<plugin>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-maven-plugin</artifactId>
		</plugin>
	</plugins>
</build>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值