SpringBoot整合:Druid、MyBatis、MyBatis-Plus、多数据源、knife4j、日志、Redis,Redis的Java操作工具类、封装发送电子邮件等等
SpringBoot笔记
一、SpringBoot 介绍
1.1、SpringBoot简介
SpringBoot 是一个快速开发的框架, 封装了Maven常用依赖、能够快速的整合第三方框架;简化XML配置,全部采用注解形式,内置Tomcat、Jetty、Undertow,帮助开发者能够实现快速开发,SpringBoot的Web组件 默认集成的是SpringMVC框架。
SpringBoot原理介绍:
1. 能够帮助开发者实现快速整合第三方框架 (原理:Maven依赖封装)
2. 去除xml配置 完全采用注解化 (原理:Spring体系中内置注解方式)
3. 无需外部Tomcat、内部实现服务器(原理:Java语言支持创建Tomcat服务器)
1.2、SpringBoot和SpringMVC的区别
SpringBoot 是一个快速开发的框架,能够快速的整合第三方框架,简化XML配置,全部采用注解形式,内置Tomcat容器,帮助开发者能够实现快速开发,SpringBoot的Web组件 默认集成的是SpringMVC框架。
SpringMVC是控制层。
1.3、SpringBoot和SpringColud区别
SpringBoot 是一个快速开发的框架,能够快速的整合第三方框架,简化XML配置,全部采用注解形式,内置Tomcat容器,帮助开发者能够实现快速开发,SpringBoot的Web组件 默认集成的是SpringMVC框架。
SpringCloud依赖与SpringBoot组件,使用SpringMVC编写Http协议接口,同时SpringCloud是一套完整的微服务解决框架。
二、第一个SpringBoot程序
需求:
编写一个http接口,实现访问/hello,在页面上输出hello SpringBoot字符串?
实现:
2.1、创建Maven jar项目
2.2、在pom.xml文件中给项目添加父工程
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-parent</artifactId>
<version>2.3.8.RELEASE</version>
</parent>
2.3、在项目的pom.xml文件中导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
2.4、两个依赖的作用
1.spring-boot-starter-parent作用
在pom.xml中引入spring-boot-start-parent,spring官方的解释叫什么stater poms,它可以提供dependency management,也就是说依赖管理。
2.spring-boot-starter-web作用
springweb 核心组件
2.5、编写启动类
/**
* 项目的启动类
*/
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class,args);
}
}
2.6、在启动类所在的包或者子包下创建controller包
2.7、创建DemoController
@Controller
public class DemoController {
@RequestMapping("/hello")
@ResponseBody
public String hello(){
return "Hello SpringBoot!";
}
}
2.8、启动、测试
2.9、部署SpringBoot程序
2.9.1 在pom.xml文件中添加打包插件
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
2.9.2 在命令行窗口执行mvn package
2.9.3 进入jar所在的目录–>cmd -->java -jar xxxx.jar
三、SpringBoot探究
3.1、启动类
/**
* @SpringBootApplication 表示他是一个SpringBoot程序
*/
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
//表示运行一个被@SpringBootApplication注解标注的Spring程序
SpringApplication.run(DemoApplication.class, args);
}
}
@SpringBootApplication 他是一个组合注解
@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 {
@SpringBootConfiguration :SpringBoot配置
@Configuration 使用这个注解标注的类是一个配置类 作用相当于我们之前学习的xxxx.xml
@EnableAutoConfiguration :启动SpringBoot自动配置
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
1. @AutoConfigurationPackage:自动配置包
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({Registrar.class})
public @interface AutoConfigurationPackage {
String[] basePackages() default {};
Class<?>[] basePackageClasses() default {};
}
@Import({Register.class})
//注册bean的定义信息 到spring的IOC容器
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
AutoConfigurationPackages.register(registry, (String[])(new AutoConfigurationPackages.PackageImports(metadata)).getPackageNames().toArray(new String[0]));
}
选中(new AutoConfigurationPackages.PackageImports(metadata)).getPackageNames() -->右键 -->Evaluate Expression 得出的结果为 项目启动类所在的包 ,也就是说和启动类在同一个包以及子包下定义的类会被注册到Spring的IOC容器中,也就解释了我们没有配置扫描某个包,却能注册bean到SpringIOC容器中
<font color="red">结论:我们创建的包必须是和启动类在同一个包或者子包内</font>
2. @Import({AutoConfigurationImportSelector.class}) 导入自动配置导入选择器
在这个AutoConfigurationImportSelector中有一个方法
```java
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return NO_IMPORTS;
} else {
AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
}
在这个方法中调用了getAutoConfigurationEntry(annotationMetadata)
```java
protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
} else {
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
configurations = this.removeDuplicates(configurations);
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
this.checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = this.getConfigurationClassFilter().filter(configurations);
this.fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
}
}
调试List configurations 或者的结果是127个xxxAutoConfiguration自动配置类,这些配置类在META-INF/spring.factories定义的
#### 3.2、SpringBoot配置文件
1. springboot的配置文件有2种:
yaml application.yml
properties application.properties
文件的名称必须叫以上2种,不能叫其他的
2. 配置文件优先级
properties的优先级高于yml
3. yaml的语法
1. yaml的基本语法:
使用缩进表示层级关系,缩进时不允许使用Tab键,只允许使用空格(例如:k:(空格) v),缩进的空格数目不重要,但是相同层级的元素左对齐即可,大小写敏感
2. YAML 支持的三种数据结构
- 字面量:单个的、不可再分的值
使用k: v 直接写
字符串类型的v默认不用双引号或者单引号;
“”:双引号;不会转义字符串里面的特殊字符;特殊字符会作为本身想表示的意思
eg: name: "zhangsan \n lisi" 输出:zhangsan 换行 lisi
‘’:单引号;会转义特殊字符,特殊字符最终只是一个普通的字符串数据
eg: name: "zhangsan \n lisi" 输出:zhangsan \n lisi
- 对象:键值对的集合
k: v 在下一行来写对象的属性和值的关系;注意缩进
1.还是k: v的方式
eg:
friends:
lastName: zhangsan
age: age
2.行内写法:
eg:
friends: {lastName: zhangsan,age: 18}
- 数组
一组按次序排列的值
1.用-值表示数组中的一个元素
eg:
pets:
-cat
-dog
-pig
2.行内写法:
pets: “cat,dog,pig”
4. properties的编码配置
![](\img\properties.jpg)
#### 3.3、SpringBoot配置文件中属性的读取
在需要读取yml文件中属性值的类添加2个注解@ConfigurationProperties(prefix="前缀")、@Configuration/@Component
```java
/**
* @author lrg on 2021/7/23
* @since 1.0.0
* @ConfigurationProperties(prefix = "user") 读取配置文件中前缀为user的数据,
* 然后就可以按照属性名称设置属性值,但是使用这个注解标注的类必须是一个组件或者是能扫描到这个类,
* 或者是一个配置类,也就是在类上添加一个@Configuration注解
*/
@Data
@Component
@ConfigurationProperties(prefix = "person")
@ToString
public class User {
private String name;
private String email;
private String address;
3.4、SpringBoot测试
-
添加依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency>
-
在测试类上添加注解
@RunWith(SpringRunner.class)
@SpringBootTest
@RunWith(SpringRunner.class) @SpringBootTest class Springboot02ApplicationTests { @Autowired private User user; @Test void contextLoads() { System.out.println(user.toString()); } }
3.5、常用注解
@propertysource 用于引入指定的属性文件
案例:
1. 在resources下创建一个user.properties属性文件
-
在属性文件中添加如下内容
person.name=zhangsan person.email=123456@qq.com person.address=北京市 person.dog.name=旺财 person.dog.strain=中华田园犬 person.aihao=[kanshu,xiezi,qiaodaima]
-
创建实体类User.java,如下:
@Data @ToString @Component @PropertySource("classpath:user.properties") //导入属性文件 @ConfigurationProperties(prefix = "person") public class User { private String name; private String email; private String address; private Dog dog; private List<String> aihao; }
- 编写测试类测试
@ImportResource 导入Spring的配置文件
@Bean 配置Spring IOC中的Bean
案例:
@Configuration
public class DruidConfiguration {
/*
* 类似于在Spring的配置文件中做了如下配置
* <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
* </bean>
*/
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource(){
return new DruidDataSource();
}
3.6、banner设置
默认banner:
步骤:
-
找到自己喜欢的banner
地址:https://www.bootschool.net/ascii
-
下载banner.txt
-
默认方式是将banner.txt放在resources下
-
不是默认方式就需要在SpringBoot的配置文件中去进行配置
例如:我将banner.txt文件放在resources/banner.txt,就需要在SpringBoot的配置文件中去做如下的配置
#设置banner spring: banner: location: banner/banner.txt
-
3.7、Profile
Profile是Spring对不同环境提供不同配置功能的支持,可以通过激活、指定参数等方式快速切换环境
- 多profile文件形式
-格式:application-{profile}.properties:
application-dev.properties、application-prod.properties
-
多profile文档模式:在主配置文件中指定多个环境
例如:
spring: profiles: active: test #指定使用的时哪一个环境 --- #开发环境dev spring: profiles: dev server: port: 8082 --- #测试环境 spring: profiles: test server: port: 8083
-
激活方式:
-配置文件 spring.profiles.active=dev
-命令行 --spring.profiles.active=dev
-jvm参数 -Dspring.profiles.active=dev
注意:第二种一般时项目已经写好并且已经打包好,在运行jar文件的时候去指定使用哪一个配置文件如: java -jar springboot-02-0.0.1-SNAPSHOT.jar --spring.profiles.active=test
3.8、配置文件的加载位置
spring boot启动会扫描以下位置的application.properties或者application.yml文件作为Spring boot的默认配置文件
-
-file:./config/
-
-file:./
-
-classpath:/config/
-
-classpath:/
以上是按照优先级从高到低的顺序,所有位置的文件都会被加载,高优先级配置内容会覆盖低优先级配置内容。 互补配置
我们也可以通过配置spring.config.location来改变默认配置。项目打包好以后,我们可以使用命令行参数的形式,启动项目的时候来指定配置文件的新位置;指定配置文件和默认加载的这些配置文件共同起作用形成互补配置;
java -jar xxx.jar -Dspring.config.location=E:/application.yml
四、Web开发
4.1、静态资源访问
在我们开发Web应用的时候,需要引用大量的js、css、图片等静态资源。
默认配置
Spring Boot默认提供静态资源目录位置需置于classpath下,目录名需符合如下规则:
/static
/public
/resources
/META-INF/resources
举例:我们可以在src/main/resources/目录下创建static,在该位置放置一个图片文件。启动程序后,尝试访问http://localhost:8080/D.jpg。如能显示图片,配置成功。
4.2、渲染Web页面
通过@RestController来处理请求,所以返回的内容为json对象。那么如果需要渲染html页面的时候,要如何实现呢?
模板引擎
在动态HTML实现上Spring Boot依然可以完美胜任,并且提供了多种模板引擎的默认配置支持,所以在推荐的模板引擎下,我们可以很快的上手开发动态网站。
Spring Boot提供了默认配置的模板引擎主要有以下几种:
Thymeleaf
FreeMarker
Velocity
Groovy
Mustache
Spring Boot建议使用这些模板引擎,避免使用JSP,若一定要使用JSP将无法实现Spring Boot的多种特性。
当你使用上述模板引擎中的任何一个,它们默认的模板配置路径为:src/main/resources/templates。当然也可以修改这个路径,具体如何修改,可在后续各模板引擎的配置属性中查询并修改。
4.3、全局捕获异常
@ExceptionHandler 表示拦截异常
@ControllerAdvice 是 controller 的一个辅助类,最常用的就是作为全局异常处理的切面类
@ControllerAdvice 可以指定扫描范围
@ControllerAdvice 约定了几种可行的返回值,如果是直接返回 model 类的话,需要使用 @ResponseBody 进行 json 转换
返回 String,表示跳到某个 view
返回 modelAndView
返回 model + @ResponseBody
@ControllerAdvice
public class MayiktExceptionHandler {
/**
* 拦截运行异常出现的错误~~~
*
* @return
*/
@ExceptionHandler(RuntimeException.class)
@ResponseBody
public Map<Object, Object> exceptionHandler() {
Map<Object, Object> map = new HashMap<>();
map.put("error", "500");
map.put("msg", "系统出现错误~");
return map;
}
}
五、数据访问
5.1、JdbcTemplate操作数据库
-
在pom.xml文件中添加依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> 这里要加MySQL的版本号 </dependency>
-
在SpringBoot的配置文件application.yml文件中配置数据源
spring: #配置数据源 datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/smbms?serverTimezone=GMT%2B8&useSSL=true username: root password: root
springboot默认给我们添加的数据源是:
com.zaxxer.hikari.HikariDataSource //这个数据源号称是效率最高的数据源
另外还提供了很多的数据源:如下
org.apache.tomcat.jdbc.pool.DataSource org.apache.commons.dbcp2.BasicDataSource
如果这些数据源我们不想要,还可以通过如下方法自定义数据源
@Configuration(proxyBeanMethods = false) @ConditionalOnMissingBean(DataSource.class) @ConditionalOnProperty(name = "spring.datasource.type") static class Generic { @Bean DataSource dataSource(DataSourceProperties properties) { return properties.initializeDataSourceBuilder().build(); } }
-
可以使用JdbcTemplate来操作数据库了
@Controller public class JdbcController { @Autowired private JdbcTemplate template; @RequestMapping("/index") @ResponseBody public List<Map<String, Object>> index(){ List<Map<String, Object>> maps = template.queryForList("select * from smbms_user"); return maps; } }
4. 访问测试
5.2、整合Druid
-
在pom.xml文件中添加如下依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!--导入阿里巴巴数据源的依赖--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.2.2</version> </dependency>
-
在配置文件application.yml文件中添加如下依赖
#以下配置是发送电子邮件的配置 spring: #以下是数据源的配置 datasource: url: jdbc:mysql://192.168.1.223:3306/itrip_db? useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8 #注意修改 driver-class-name: com.mysql.cj.jdbc.Driver username: root #注意修改 password: root #注意修改 type: com.alibaba.druid.pool.DruidDataSource #指定数据源的类型 #以下是alibaba数据源的配置 initialSize: 5 #初始化大小 minIdle: 5 #最小连接数 maxActive: 20 #最大连接数 maxWait: 60000 #获取连接等待超时时间 timeBetweenEvictionRunsMillis: 60000 #间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 minEvictableIdleTimeMillis: 300000 #一个连接在池中最小生存的时间,单位是毫秒 validationQuery: SELECT 1 FROM DUAL testWhileIdle: true testOnBorrow: false testOnReturn: false poolPreparedStatements: true # 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙 filters: stat,wall,slf4j maxPoolPreparedStatementPerConnectionSize: 20 useGlobalDataSourceStat: true connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
-
编写Druid的配置类
/** * DruidDataSource配置类 * */ @Configuration public class DruidConfiguration { /* * 类似于在Spring的配置文件中做了如下配置 * <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> * </bean> */ @Bean @ConfigurationProperties(prefix = "spring.datasource") public DataSource dataSource(){ return new DruidDataSource(); } //配置Druid的监控 //1、配置一个管理后台的Servlet //访问的地址为:http://ip:port/上下文/druid @Bean public ServletRegistrationBean statViewServlet(){ ServletRegistrationBean bean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*"); Map<String,String> initParams = new HashMap<>(); initParams.put("loginUsername","admin"); initParams.put("loginPassword","admin"); initParams.put("allow","");//配置允许哪一个IP地址访问 默认就是允许所有访问 initParams.put("deny","192.168.15.21");/*拒绝后面的这个IP地址访问*/ bean.setInitParameters(initParams); return bean; }
//2、配置一个web监控的filter
@Bean
public FilterRegistrationBean webStatFilter(){
FilterRegistrationBean bean = new FilterRegistrationBean();
bean.setFilter(new WebStatFilter());
Map<String,String> initParams = new HashMap<>();
//设置不拦截的路径
initParams.put("exclusions","*.js,*.css,/druid/*");
bean.setInitParameters(initParams);
//设置拦截的路径
bean.setUrlPatterns(Arrays.asList("/*"));
return bean;
}
}
-
编写控制器来测试
@RestController public class DruidController { @Autowired private JdbcTemplate jdbcTemplate; @GetMapping(value="/index") public List<Map<String,Object>> index(){ List<Map<String, Object>> list = jdbcTemplate.queryForList("select * from smbms_user"); return list; } }
-
访问测试
http://localhost:8080/index
http://localhost:8080/druid
5.3、整合MyBatis
步骤:
- 在pom.xml文件中添加如下依赖
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- springboot 整合mybatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<!--如果是我们自己整合的话命名为:项目名称-starter -->
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.1.1</version>
</dependency>
-
在SpringBoot的配置文件中做如下配置
#mybatis的配置 mybatis: type-aliases-package: com.kgc.demo.entity mapper-locations: classpath:mapper/*.xml configuration: log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl #mybatis日志输出 spring: #配置数据源 datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/smbms?serverTimezone=GMT%2B8&useSSL=true username: root password: root
-
在resources下创建mapper文件夹用来存放mybatis的映射文件
-
在启动类上去添加扫描mybatis接口的直接如下:
方式一:直接在启动类上添加注解@MapperScan(basePackages = “com.kgc.demo.mapper”)
@SpringBootApplication @MapperScan(basePackages = "com.kgc.demo.mapper") public class DemoApplication { public static void main(String[] args) { //表示运行一个被@SpringBootApplication注解标注的Spring程序 SpringApplication.run(DemoApplication.class, args); } }
方式二:和启动类在同一个包或者子包中去创建一个配置类如下:
@Configuration @MapperScan(basePackages = "com.kgc.demo.mapper") public class MyBatisConfiguration { }
-
启动测试
5.4、整合MyBatis_Plus
- 在maven项目的pom.xml中引入MyBatis_Plus的依赖包,代码如下
<!--mybatisplus和springboot整合的依赖-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.2.0</version>
</dependency>
<!--mybatisplus代码生成器的依赖-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>
- 在application.yml文件中添加如下关于mybatisplus的配置
mybatis-plus:
configuration:
map-underscore-to-camel-case: true #是否开启驼峰命名
auto-mapping-behavior: full #自动映射级别
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #mybatis日志输出
mapper-locations: classpath*:mapper/**/*Mapper.xml #映射文件路径配置
global-config:
db-config: # 逻辑删除配置
logic-not-delete-value: 1 # 删除前
logic-delete-value: 0 # 删除后
- 编写MyBatis_Plus配置类
/**
* 配置分页插件
*
*/
@Configuration
@MapperScan(backPackage="com.java.test.mapper")
public class MybatisPlusConfiguration {
/**
* 分页插件
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
}
- 新建一个包(codegenerator)来存放Mybatis-Plus的代码生成器类
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import java.util.Scanner;
public class CodeGenerator {
/**
* <p>
* 读取控制台内容
* </p>
*/
public static String scanner(String tip) {
Scanner scanner = new Scanner(System.in);
StringBuilder help = new StringBuilder();
help.append("请输入" + tip + ":");
System.out.println(help.toString());
if (scanner.hasNext()) {
String ipt = scanner.next();
if (StringUtils.checkValNotNull(ipt)) {
return ipt;
}
}
throw new MybatisPlusException("请输入正确的" + tip + "!");
}
public static void main(String[] args) {
// 代码生成器
AutoGenerator mpg = new AutoGenerator();
// 全局配置
GlobalConfig gc = new GlobalConfig();
gc.setOutputDir(scanner("请输入你的项目路径") + "/src/main/java");
gc.setAuthor("lrg");
gc.setOpen(false);//生成之后是否打开资源管理器
gc.setSwagger2(true); //实体属性 Swagger2 注解
gc.setFileOverride(false);//重新是否自动覆盖文件
gc.setServiceName("%sService");//%sService 为占位符,用于生成service层代码,默认生成名称第一个字符是有I
gc.setIdType(IdType.AUTO);//设置主键成成策略 自动增长
gc.setDateType(DateType.ONLY_DATE);//设置日期类型 只是用java.util.date 代替
mpg.setGlobalConfig(gc);
// 数据源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://localhost:3306/auth_db?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8");
// dsc.setSchemaName("public");
dsc.setDriverName("com.mysql.cj.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("root");
dsc.setDbType(DbType.MYSQL);//设置是用的是什么数据库
mpg.setDataSource(dsc);
// 包配置
PackageConfig pc = new PackageConfig();
pc.setModuleName(scanner("请输入模块名"));
pc.setParent("com.lyh.pro");
pc.setController("controller");
pc.setService("service");
pc.setServiceImpl("service.impl");
pc.setEntity("entity");
pc.setXml("mapper");
mpg.setPackageInfo(pc);
// 策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setInclude(scanner("表名,多个英文逗号分割").split(","));//设置那些表需要自动生成
strategy.setNaming(NamingStrategy.underline_to_camel);//设置驼峰命令
strategy.setColumnNaming(NamingStrategy.underline_to_camel);//设置_转驼峰命令
strategy.setEntityLombokModel(true);//设置实体类使用lombok
strategy.setRestControllerStyle(true);//设置controller的api风格 使用RestController
strategy.setControllerMappingHyphenStyle(true);//驼峰装连接符
strategy.setTablePrefix("tb_");//设置忽略tb_开头的前缀
mpg.setStrategy(strategy);
mpg.execute();
}
}
- 运行CodeGenerator里面的main方法生成代码
5.4、整合多数据源
- 配置文件中新增两个数据源
application.yml
spring:
datasource:
###会员数据库
member:
jdbc-url: jdbc:mysql://localhost:3306/user
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
###订单数据库
order:
jdbc-url: jdbc:mysql://localhost:3306/order
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
备注:如果是SpringBoot2配置多数据源 ,报如下错误:
“jdbcUrl is required with driverClassName.”或者Cause: java.lang.IllegalArgumentException: dataSource or dataSourceClassName or jdbcUrl is required.] with root cause
解决方案:
spring.datasource.url 和spring.datasource.driverClassName,换成
spring.datasource.jdbc-url和spring.datasource.driver-class-name
-
数据库数据源相关配置
会员数据库:
@Configuration @MapperScan(basePackages = "com.java.member.mapper", sqlSessionFactoryRef = "memberSqlSessionFactory") public class MemberDataSourceConfig { /** * 将会员db注册到容器中 * * @return */ @Bean(name = "memberDataSource") @ConfigurationProperties(prefix = "spring.datasource.member") public DataSource memberDataSource() { return DataSourceBuilder.create().build(); } /** * 将会员SqlSessionFactory注册到容器中 * * @param dataSource * @return * @throws Exception */ @Bean(name = "memberSqlSessionFactory") public SqlSessionFactory memberSqlSessionFactory(@Qualifier("memberDataSource") DataSource dataSource) throws Exception { SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean(); sqlSessionFactoryBean.setDataSource(memberDataSource()); return sqlSessionFactoryBean.getObject(); } /** * 创建会员管理器 * * @param dataSource * @return */ @Bean(name = "memberTransactionManager") public DataSourceTransactionManager memberTransactionManager(@Qualifier("memberDataSource") DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } /** * 创建会员sqlSesion模版 * * @param sqlSessionFactory * @return * @throws Exception */ @Bean(name = "memberSqlSessionTemplate") public SqlSessionTemplate menberSqlSessionTemplate( @Qualifier("memberSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception { return new SqlSessionTemplate(sqlSessionFactory); } }
订单数据源:
@Configuration @MapperScan(basePackages = "com.java.order.mapper", sqlSessionFactoryRef = "orderSqlSessionFactory") public class OrderDataSourceConfig { /** * 将订单db注册到容器中 * * @return */ @Bean(name = "orderDataSource") @ConfigurationProperties(prefix = "spring.datasource.order") public DataSource orderDataSource() { return DataSourceBuilder.create().build(); } /** * 将订单SqlSessionFactory注册到容器中 * * @param dataSource * @return * @throws Exception */ @Bean(name = "orderSqlSessionFactory") public SqlSessionFactory orderSqlSessionFactory(@Qualifier("orderDataSource") DataSource dataSource) throws Exception { SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean(); sqlSessionFactoryBean.setDataSource(orderDataSource()); return sqlSessionFactoryBean.getObject(); } /** * 创建订单管理器 * * @param dataSource * @return */ @Bean(name = "orderTransactionManager") public DataSourceTransactionManager orderTransactionManager(@Qualifier("orderDataSource") DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } /** * 创建订单sqlSesion模版 * * @param sqlSessionFactory * @return * @throws Exception */ @Bean(name = "orderSqlSessionTemplate") public SqlSessionTemplate menberSqlSessionTemplate( @Qualifier("orderSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception { return new SqlSessionTemplate(sqlSessionFactory); } }
- 创建分包Mapper
会员Mapper:
public interface MemberMapper { @Insert("insert into users values(null,#{name},#{age});") public int addUser(@Param("name") String name, @Param("age") Integer age); }
订单Mapper:
public interface OrderMapper { @Insert("insert into order_number values(null,#{number});") int inserOrder(@Param("number") String number); }
- 启动项目
- 数据库表结构
CREATE TABLE `users` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(32) NOT NULL COMMENT '用户名称', `age` int(11) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
CREATE TABLE order_number (
`id` int(11) NOT NULL AUTO_INCREMENT,
`order_name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
六、整合knife4j
-
在maven项目的
pom.xml
中引入Knife4j的依赖包,代码如下:<dependency> <groupId>com.github.xiaoymin</groupId> <artifactId>knife4j-spring-boot-starter</artifactId> <version>2.0.9</version> </dependency>
-
添加Knife4j的配置类
@Configuration @EnableSwagger2WebMvc public class Knife4jConfiguration { @Bean(value = "defaultApi2") public Docket defaultApi2() { Docket docket=new Docket(DocumentationType.SWAGGER_2) .apiInfo(new ApiInfoBuilder() //.title("swagger-bootstrap-ui-demo RESTful APIs") .description("# swagger-bootstrap-ui-demo RESTful APIs") .termsOfServiceUrl("http://www.xx.com/") .contact("xx@qq.com") .version("1.0") .build()) //分组名称 .groupName("2.X版本") .select() //这里指定Controller扫描包路径 .apis(RequestHandlerSelectors.basePackage("com.github.xiaoymin.knife4j.controller")) .paths(PathSelectors.any()) .build(); return docket; } }
-
DruidController.java
包含一个简单的RESTful接口,代码示例如下:@Api(tags = "首页模块") @RestController public class DruidController { @Autowired private JdbcTemplate jdbcTemplate; @ApiOperation(value = "查询所有用户数据", protocols = "http", httpMethod="GET", consumes="application/json", response=List.class, notes = "code:200 表示成功") @GetMapping(value="/index") public List<Map<String,Object>> index(){ List<Map<String, Object>> list = jdbcTemplate .queryForList("select * from smbms_user"); return list; } }
-
http://localhost:17790/doc.html
七、整合日志
7.1、市场上现在常用的日志框架
JUL(java.util.logging)、JCL、Jboss-logging、logback、log4j、log4j2、slf4j…
7.2、日志门面(日志的抽象层,可以把它理解为我们在编程的过程中写接口)
SLF4J(Simple Logging Facade for Java):是一个简单日志门面抽象框架,它本身只提供了日志Facade API 和一个简单的日志类实现,一般常配合Log4j,Logback,java.util.logging使用。Slf4j作为应用层的Log 接入时,程序可以根据实际应用场景动态调整底层的日志实现框架(Log4j/Logback/JdkLog…)
7.3、实现类(日志的实现层,可以把它理解为我们在编程的过程中写的接口的实现类)
Logback:Logback是一个日志框架,它与Log4j可以说是同出一源,都出自Ceki Gülcü之手,他是slf4j的 实现类。
7.4、SpringBoot的日志框架选用
SpringBoot底层是Spring,Spring选用的是JCL,SpringBoot对日志进行了封装选用的是slf4j和logback。
7.5、历史遗留问题
- MyBatis使用的日志框架是:log4j
- Spring使用的日志框架是: jcl
- Hibernate使用的日志框架是: jboos-logging
- 如何让系统中所有的日志都统一使用slf4j?
- 将系统中其他日志框架先排除出去
- springboot使用中间替换包把其他框架的日志都替换成了slf4j
- 如果我们引入其他框架一定要将这个框架中的日志依赖移除掉
7.6、springboot日志关系
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
<version>2.3.8.RELEASE</version>
<scope>compile</scope>
</dependency>
7.7、日志的使用
1. 默认配置:springboot已经帮我们配置好了日志框架,我们使用就行
@SpringBootTest
class SpringbootApplicationLoggingTests {
//定义日志记录器
private Logger log = LoggerFactory.getLogger(SpringbootApplicationLoggingTests.class);
@Test
void loggingTest(){
//日志的级别由低到高:trace<debug<info<warn<error
//可以调整输出的日志级别:日志就会在这个级别以后的高级别生效
log.info("这是info日志");
log.warn("这是warn日志");
log.debug("这是debug日志");
log.trace("这是trace日志");
log.error("这是error日志");
}
}
上面程序运行之后只输出类info、warn、error的日志信息,没有输出trace,debug类型的级别,也就是说SpringBoot日志默认输出的日志级别为info,info级别之前的日志级别不能输出出来。
-
修改日志级别
在springboot的配置文件,application.properties或者是application.yml文件中添加如下配置:
修改logback日志输出的级别,其中com.kgc.springboot是指什么包下的日志输出级别, 没有指定日志输出级别的包那就使用springboot默认指定输出的级别,也就是root级别
logging: level: com: kgc: springboot: trace
-
其他日志的的设置
logging: file: #不指定路径,在当前目录下生成springboot.log日志 #可以指定完整的路径,那么就是在指定的路径下创建日志文件 name: springboot.log #在当前磁盘下的根路径下创建spring文件夹和里面的log文件夹:使用spring.log作为默认文件 #path: D:/idea_kgc_13/log #logging.file.name和logging.file.path设置只能2选一如果2者都设置这是以logging.file.name为准 pattern: #定义日志输出在控制台的格式 console: -%d -%LOG_LEVEL -%msg%n #定义日志输出在文件中的格式 file:
-
自定义配置
在类路径下放上每个日志框架自己的配置文件即可,SpringBoot就不在使用默认的配置了
在resources下去创建一个logback-spring.xml文件文件的内容,如下:
<?xml version="1.0" encoding="UTF-8"?>
<!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出 -->
<!-- scan:当此属性设置为true时,配置文档如果发生改变,将会被重新加载,默认值为true -->
<!-- scanPeriod:设置监测配置文档是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。
当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
<!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->
<configuration scan="true" scanPeriod="10 seconds">
<contextName>logback</contextName>
<!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义后,可以使“${}”来使用变量。 -->
<property name="log.path" value="G:/logs/pmp" />
<!-- 定义日志文件名称 -->
<property name="appName" value="kgc-springboot"></property>
<!--0. 日志格式和颜色渲染 -->
<!-- 彩色日志依赖的渲染类 -->
<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
<conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
<conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
<!-- 彩色日志格式 -->
<property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
<!--1. 输出到控制台-->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>debug</level>
</filter>
<encoder>
<Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
<!-- 设置字符集 -->
<charset>UTF-8</charset>
</encoder>
</appender>
<!--2. 输出到文档-->
<!-- 2.1 level为 DEBUG 日志,时间滚动输出 -->
<appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文档的路径及文档名 -->
<file>${log.path}/web_debug.log</file>
<!--日志文档输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset> <!-- 设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志归档 -->
<fileNamePattern>${log.path}/web-debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文档保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文档只记录debug级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>debug</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 2.2 level为 INFO 日志,时间滚动输出 -->
<appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文档的路径及文档名 -->
<file>${log.path}/web_info.log</file>
<!--日志文档输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 每天日志归档路径以及格式 -->
<fileNamePattern>${log.path}/web-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文档保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文档只记录info级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>info</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 2.3 level为 WARN 日志,时间滚动输出 -->
<appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文档的路径及文档名 -->
<file>${log.path}/web_warn.log</file>
<!--日志文档输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset> <!-- 此处设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/web-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文档保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文档只记录warn级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>warn</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 2.4 level为 ERROR 日志,时间滚动输出 -->
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文档的路径及文档名 -->
<file>${log.path}/web_error.log</file>
<!--日志文档输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset> <!-- 此处设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/web-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文档保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文档只记录ERROR级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!--
<logger>用来设置某一个包或者具体的某一个类的日志打印级别、
以及指定<appender>。<logger>仅有一个name属性,
一个可选的level和一个可选的addtivity属性。
name:用来指定受此logger约束的某一个包或者具体的某一个类。
level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
还有一个特俗值INHERITED或者同义词NULL,代表强制执行上级的级别。
如果未设置此属性,那么当前logger将会继承上级的级别。
addtivity:是否向上级logger传递打印信息。默认是true。
<logger name="org.springframework.web" level="info"/>
<logger name="org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor" level="INFO"/>
-->
<!--
使用mybatis的时候,sql语句是debug下才会打印,而这里我们只配置了info,所以想要查看sql语句的话,有以下两种操作:
第一种把<root level="info">改成<root level="DEBUG">这样就会打印sql,不过这样日志那边会出现很多其他消息
第二种就是单独给dao下目录配置debug模式,代码如下,这样配置sql语句会打印,其他还是正常info级别:
【logging.level.org.mybatis=debug logging.level.dao=debug】
-->
<!--
root节点是必选节点,用来指定最基础的日志输出级别,只有一个level属性
level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
不能设置为INHERITED或者同义词NULL。默认是DEBUG
可以包含零个或多个元素,标识这个appender将会添加到这个logger。
-->
<!-- 4. 最终的策略 -->
<!-- 4.1 开发环境:打印控制台-->
<springProfile name="dev">
<logger name="com.sdcm.pmp" level="debug"/>
</springProfile>
<!--
这里设置的级别优先于下面引用的appender的级别
如果root标签指定了日志级别那么以根日志级别为准,
如果没有默认是debug当前追加器日志级别为准
-->
<root level="info">
<appender-ref ref="CONSOLE" />
<appender-ref ref="DEBUG_FILE" />
<appender-ref ref="INFO_FILE" />
<appender-ref ref="WARN_FILE" />
<appender-ref ref="ERROR_FILE" />
</root>
<!-- 4.2 生产环境:输出到文档
<springProfile name="pro">
<root level="info">
<appender-ref ref="CONSOLE" />
<appender-ref ref="DEBUG_FILE" />
<appender-ref ref="INFO_FILE" />
<appender-ref ref="ERROR_FILE" />
<appender-ref ref="WARN_FILE" />
</root>
</springProfile> -->
</configuration>
总结:
如果日志文件的名称为:
logback.xml:直接就被日志框架识别了;
logback-spring.xml:日志框架就不直接加载日志的配置项,由SpringBoot去加载,好处在于可以使用logback扩展功能,在帮助文档中有记载
八、发送电子邮件
8.1、发送电子邮件—qq
- 配置邮件服务器
不同的邮件服务器配置方式大同小异,一下以QQ邮件为例:
- 导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
- 在配置文件中配置发送邮件的信息
spring:
mail:
protocol: smtp #配置QQ发送邮件的协议
host: smtp.qq.com #配置QQ发送邮件的主机
port: 587 #配置QQ发送邮件的端口
username: 1964059406@qq.com #配置发送邮件的账户
password: xxxxxxxx #配置发送邮件的授权码
- 使用JavaMailSenderImpl发送邮件 测试
@SpringBootTest
class SpringbootApplicationTests {
@Autowired
private JavaMailSenderImpl mailSender;
/**
* 发送普通的电子邮件
*/
@Test
void sendSimpleMail() {
SimpleMailMessage message = new SimpleMailMessage();
message.setFrom("1964059406@qq.com");//设置发送者
message.setTo("liyanhua_pt@163.com");//设置发送给谁
message.setSubject("今晚打老虎");//邮件主题
message.setText("今晚子时西门大官人有情,不见不散");//邮件内容
mailSender.send(message);//发送邮件
}
/**
* 发送带附件的电子邮件
* @throws MessagingException
*/
@Test
void sendMineMail() throws MessagingException {
MimeMessage mimeMessage = mailSender.createMimeMessage();
//MimeMessageHelper 并设置是一个带附件的邮件
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage,true);
helper.setFrom("1964059406@qq.com");//设置发送者
helper.setTo("liyanhua_pt@163.com");//设置发送给谁
helper.setSubject("今晚打老虎");//邮件主题
helper.setText("今晚子时西门大官人有情,不见不散");//邮件内容
helper.addAttachment("meinv.jpg",
new File("C:\\Users\\Administrator\\Desktop\\test\\234.jpg"));//设置附件
mailSender.send(mimeMessage);
}
/**
* 发送HTML格式的邮件
* @throws MessagingException
*/
@Test
void sendHtmlMail() throws MessagingException {
MimeMessage mimeMessage = mailSender.createMimeMessage();
//MimeMessageHelper 并设置是一个带附件的邮件
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage,true);
helper.setFrom("1964059406@qq.com");//设置发送者
helper.setTo("liyanhua_pt@163.com");//设置发送给谁
helper.setSubject("今晚打老虎");//邮件主题
String html="<!DOCTYPE html>\n" +
"<html>\n" +
"<head>\n" +
" <meta charset=\"utf-8\" />\n" +
" <title></title>\n" +
"</head>\n" +
"<body>\n" +
"<div id=\"content_box\">\n" +
"<h1 style=\"color:red;\">true表示发送的是一个HTML格式的邮件</h1>\n"+
"</div>\n" +
"</body>\n" +
"</html>";
helper.setText(html,true);//邮件内容 true表示发送的是一个HTML格式的邮件
mailSender.send(mimeMessage);
}
}
8.2、发送带模板的电子邮件
说明: 这里使用的是Freemarker来做模板(模板引擎有很多)
- 导入依赖
<!--freemarker模板引擎是为了后面发送模板邮件 不需要的可以不引入-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
- 编写模板,例如: account_active.ftl
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<style type="text/css">
.content{
text-indent: 2em;
color: green;
font-size: 20px;
}
.footer{
text-align: right;
}
</style>
</head>
<body>
<div id="content_box">
<h2>尊敬的${name},您好!</h2>
<p class="content">
欢迎成为爱旅行家族成员的一份子,您此次账户注册的激活码为:${code},该激活码用于注册用户激活账户使用,请妥善保管!
请于30分钟内输入激活!
</p>
<div class="footer">
<span>爱旅行</span></br>
<span>${datetime}</span>
</div>
</div>
</body>
</html>
- 在application.yml配置文件中配置
#以下是Freemarker的配置
spring:
freemarker:
template-loader-path: classpath:/templates/mail/ #配置模板路径
suffix: .ftl #配置模板后缀
cache: false #配置模板是否缓存
charset: UTF-8 #配置模板字符编码
- 使用模板发送电子邮件
@SpringBootTest
class SpringbootApplicationTests {
@Autowired
private JavaMailSenderImpl mailSender;
@Autowired
private FreeMarkerConfigurer freeMarkerConfigurer;
/**
* 使用模板发送电子邮件
* @throws IOException
* @throws TemplateException
* @throws MessagingException
*/
@Test
void sendTemplateMail() throws IOException, TemplateException, MessagingException {
String templateName = "account_active.ftl";//模板名称
//用于设置你要替换模板中的哪个一个占位符,以及值
Map<String,Object> model = new HashMap<>();
model.put("name","张三");
model.put("code","5566");
model.put("datetime","2021-07-26");
// 获得模板对象
Template mailTemplate = freeMarkerConfigurer.getConfiguration().getTemplate(templateName);
// 传入数据模型到模板,替代模板中的占位符,并将模板转化为html字符串
String templateHtml = FreeMarkerTemplateUtils.processTemplateIntoString(mailTemplate,model);
// 该方法本质上还是发送html邮件,调用之前发送html邮件的方法
MimeMessage mimeMessage = mailSender.createMimeMessage();
//MimeMessageHelper 并设置是一个带附件的邮件
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage,true);
helper.setFrom("1964059406@qq.com");//设置发送者
helper.setTo("liyanhua_pt@163.com");//设置发送给谁
helper.setSubject("测试HTML模板邮件");//邮件主题
helper.setText(templateHtml,true);//邮件内容 true表示发送的是一个HTML格式的邮件
mailSender.send(mimeMessage);
}
}
8.3、封装发送电子邮件的组件
MailTools:
/**
* 发送电子邮件的工具类
* @author lyh 2021/7/26
* @since 1.0.0
*/
@Component
@ConfigurationProperties(prefix = "spring.mail")
@Data
public class MailTools {
@Resource
private JavaMailSenderImpl mailSender;
@Resource
private FreeMarkerConfigurer freeMarkerConfigurer;
private String subject;
private String from;
/**
* 发送普通的电子邮件
* @param mailContent 邮件内容
* @param to 发送给谁 可以设置多个
* @return 成功或者失败
*/
public void sendSimpleEmail(String mailContent,String...to){
this.sendSimpleEmail(subject,mailContent,to);
}
/**
* 发送普通的电子邮件
* @param subject 邮件主题
* @param mailContent 邮件内容
* @param to 发送给谁 可以设置多个
* @return 成功或者失败
*/
public void sendSimpleEmail(String subject,String mailContent,String...to){
SimpleMailMessage mailMessage = new SimpleMailMessage();
mailMessage.setSubject(subject);//设置邮件主题
mailMessage.setTo(to);//设置发送给谁
mailMessage.setFrom(from);//设置谁发送的邮件
mailMessage.setText(mailContent);//设置邮件内容
mailSender.send(mailMessage);
}
/**
* 发送带附件和html格式的邮件
* @param subject 主题
* @param mailContent 邮件内容
* @param to 发送给谁
* @throws MessagingException 邮件异常对象
*/
public void sendMimeMail(String subject,String mailContent,String...to) throws MessagingException {
this.sendMimeMail(subject,mailContent,null,to);
}
/**
* 发送带附件和html格式的邮件
* @param mailContent 邮件内容
* @param to 发送给谁
* @throws MessagingException 邮件异常对象
*/
public void sendMimeMail(String mailContent,String...to) throws MessagingException {
this.sendMimeMail(this.subject,mailContent,null,to);
}
/**
* 发送带附件和html格式的邮件
* @param subject 主题
* @param mailContent 邮件内容
* @param files 附件文件
* @param to 发送给谁
* @throws MessagingException 邮件异常对象
*/
public void sendMimeMail(String subject,String mailContent,File[] files,String...to) throws MessagingException {
MimeMessage mimeMessage = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage,true);//这个true表示发送带附件的邮件
helper.setFrom(from);
helper.setTo(to);
//设置主题
helper.setSubject(subject);
helper.setText(mailContent,true);//表示html类型的邮件
//设置附件
if(files!=null && files.length>0){
for (File file:files){
if(file!=null){
String filename = file.getName();//获取上传文件名称
helper.addAttachment(filename,file);
}
}
}
mailSender.send(mimeMessage);
}
/**
* 发送模板邮件
* @param subject 邮件主题
* @param model 用于替换模板中需要替换的内容的map集合
* @param templatePath 模板名称
* @param to 发送给谁
* @throws IOException
* @throws TemplateException
* @throws MessagingException
*/
public void sendTemplateMail(String subject, Map<String,Object> model, String templatePath, String...to) throws IOException, TemplateException, MessagingException {
// 获得模板
Template mailTemplate = freeMarkerConfigurer.getConfiguration().getTemplate(templatePath);
// 传入数据模型到模板,替代模板中的占位符,并将模板转化为html字符串
String templateHtml = FreeMarkerTemplateUtils.processTemplateIntoString(mailTemplate,model);
// 该方法本质上还是发送html邮件,调用之前发送html邮件的方法
this.sendMimeMail(subject,templateHtml,to);
}
}
九、整合Redis
9.1、导入依赖
<!--导入redis的依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
9.2、配置Redis
spring:
#以下时redis的配置
redis:
host: 192.168.1.133 #连接的主机地址
port: 6379 #配置连接的端口号
password: root #配置redis连接的密码
database: 0 #配置redis连接数据库索引
timeout: 5000 #配置连接超时间
jedis:
pool: #使用jedis连接池去管理连接数
max-active: 8 #配置最大激活数
max-idle: 4 #最大的空闲数
min-idle: 4 #最小的空闲数
max-wait: -1 #最大等待时间
9.3、操作Redis
整合之后SpringBoot提供了2个操作Redis的模板类给我们操作redis
- StringRedisTemplate
- RedisTemplate<Object,Object>
RedisTemplate中定义了5种数据结构操作
redisTemplate.opsForValue(); //操作字符串
redisTemplate.opsForHash(); //操作hash
redisTemplate.opsForList(); //操作list
redisTemplate.opsForSet(); //操作set
redisTemplate.opsForZSet(); //操作有序set
3.3 StringRedisTemplate和RedisTemplate区别
- 两者之间的关系
- 两者的关系是StringRedisTemplate继承RedisTemplate。
- 两者的数据是不共通的;也就是说StringRedisTemplate只能管理StringRedisTemplate里面的数据,RedisTemplate只能管理RedisTemplate中的数据。
- 其实他们两者之间的区别主要在于他们使用的序列化类:
RedisTemplate使用的是JdkSerializationRedisSerializer 存入数据会将数据先序列化成字节数组然后在存入Redis数据库。
StringRedisTemplate使用的是StringRedisSerializer
- 使用时注意事项:
当你的redis数据库里面本来存的是字符串数据或者你要存取的数据就是字符串类型数据的时候,那么你就使用StringRedisTemplate即可。
但是如果你的数据是复杂的对象类型,而取出的时候又不想做任何的数据转换,直接从Redis里面取出一个对象,那么使用RedisTemplate是更好的选择。
- RedisTemplate使用时常见问题:
redisTemplate 中存取数据都是字节数组。当redis中存入的数据是可读形式而非字节数组时,使用redisTemplate取值的时候会无法获取导出数据,获得的值为null。可以使用 StringRedisTemplate 试试
-
面试题
Redis中有几种数据类型?分别是什么?
Redis和Memcached的区别和使用场景?
-
使用StringRedisTemplate操作Redis:
@SpringBootTest
class SpringbootApplicationRedisTests {
@Autowired
private StringRedisTemplate stringRemplate;
@Autowired
private RedisTemplate<Object, Object> redisTemplate;
@Test
void testStringRedisTemplate(){
//stringRemplate.opsForValue().set("name","jack");
//向redis里存入数据和设置缓存时间
stringRemplate.opsForValue()
.set("test", "100",60*10, TimeUnit.SECONDS);
//将key为test的value减1
stringRemplate.boundValueOps("test").increment(-1);//val做-1操作
//根据key获取缓存中的val
String testValue = stringRemplate.opsForValue().get("test");
System.out.println("testValue:"+testValue);
//将key为test的value减1
stringRemplate.boundValueOps("test").increment(1);//val +1
//根据key获取过期时间
Long testExpire = stringRemplate.getExpire("test");
System.out.println("testExpire:"+testExpire);
//根据key获取过期时间并换算成指定单位
Long expire = stringRemplate.getExpire("test", TimeUnit.MILLISECONDS);
System.out.println("testExpire:"+expire+"ms");
//根据key删除缓存
//stringRemplate.delete("test");
Boolean isExists = stringRemplate.hasKey("546545");//检查key是否存在,返回boolean值
System.out.println("546545是否存在:"+isExists);
//向指定key中存放set集合
stringRemplate.opsForSet().add("red_123", "1","2","3");
//设置过期时间
stringRemplate.expire("red_123",1000 , TimeUnit.SECONDS);
//根据key查看集合中是否存在指定数据
stringRemplate.opsForSet().isMember("red_123", "1");
//根据key获取set集合
stringRemplate.opsForSet().members("red_123");
}
- 编写重新设置RedisTemplate的序列化器配置类
@Configuration
public class RedisConfiguration {
@Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
// 使用Jackson2JsonRedisSerialize 替换默认序列化
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer
= new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
//objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
// 设置value的序列化规则和 key的序列化规则
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
- 使用RedisTemplate类编写操作Redis的工具类
@SpringBootTest
class SpringbootApplicationRedisToolsTests {
@Autowired
private RedisTools redisTools;
@Test
public void redisToolsTest(){
//使用RedisTools向redis中存入String类型的K,V
redisTools.set("test","张三");
//使用RedisTools向redis中存入一个对象
User user = new User(1,"张三","123456@qq.com");
redisTools.set("user",user);
//使用RedisTools根据Key获取一个Object类型的值
Object user1 = redisTools.get("user");
System.out.println(user1);
//使用RedisTools根据Key获取一个User类型的值
User user_1 = redisTools.getObject("user", User.class);
System.out.println(user_1);
//使用RedisTools存入一个List集合
List<User> userList = new ArrayList<>();
userList.add(new User(1,"张三","123456@qq.com"));
userList.add(new User(2,"李四","123456@qq.com"));
redisTools.set("listUser",userList,60);
//使用RedisTools根据Key获取一个Object类型的值
Object listUser = redisTools.get("listUser");
//将上一步获取的值转换成一个集合
List<User> users = JSONArray.parseArray(
JSONArray.toJSONString(listUser),
User.class);
for (User us : users) {
System.out.println(us.getName()+"\t"+us.getEmail());
}
}
}
声明:有大部分笔记作者是:刘仁贵老师
如有侵权,请联系我,谢谢!
更多推荐
所有评论(0)