配置API文档的分组
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.groupName("狂神")
.enable(flag) //enable是否启动swagger,如果为false,则swagger不能在浏览器中访问
//select apis build 是一套的
.select()
.apis(RequestHandlerSelectors.basePackage("com.kuang.swagger.controller"))
//paths()过滤什么路径
//.paths(PathSelectors.ant("/kuang/**"))
.build();
如何配置多个分组:
package com.kuang.swagger.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.core.env.Profiles;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.util.ArrayList;
@Configuration //相当于@Component
@EnableSwagger2 //开启Swagger2
public class SwaggerConfig {
@Bean
public Docket docket1(){
return new Docket(DocumentationType.SWAGGER_2).groupName("A");
}
@Bean
public Docket docket2(){
return new Docket(DocumentationType.SWAGGER_2).groupName("B");
}
@Bean
public Docket docket3(){
return new Docket(DocumentationType.SWAGGER_2).groupName("C");
}
//配置了swagger的Docket的bean实例
@Bean
public Docket docket(Environment environment){
//设置要显示的Swagger环境
Profiles profiles = Profiles.of("dev","test");
//获取项目环境
//通过environment.acceptsProfiles() 判断是否处在自己设定的环境当中
boolean flag = environment.acceptsProfiles(profiles);
System.out.println(flag);
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.groupName("狂神")
.enable(flag) //enable是否启动swagger,如果为false,则swagger不能在浏览器中访问
//select apis build 是一套的
.select()
.apis(RequestHandlerSelectors.basePackage("com.kuang.swagger.controller"))
//paths()过滤什么路径
//.paths(PathSelectors.ant("/kuang/**"))
.build();
}
//配置Swagger信息 = apiInfo
private ApiInfo apiInfo(){
//作者信息
Contact contact = new Contact("秦疆", "https://blog.kuangstudy.com/", "24736743@qq.com");
return new ApiInfo("狂神的SwaggerAPI文档",
"即使再小的帆也能远航",
"v1.0", "https://blog.kuangstudy.com",
contact, "Apache 2.0",
"http://www.apache.org/licenses/LICENSE-2.0",
new ArrayList());
}
}
实体类配置:
HelloController.java
package com.kuang.swagger.controller;
import com.kuang.swagger.pojo.User;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController //由于我们没有页面所有要给他返回一个字符串
public class HelloController {
@GetMapping(value = "/hello")
public String hello(){
return "hello";
}
//只要我们的接口中,返回值中存在实体类,他就会被扫描到Swagger中
@PostMapping(value = "/user")
public User user(){
return new User();
}
}
User.java
package com.kuang.swagger.pojo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
// 注意:这里的实体类的属性是不能private的 私有属性不会被暴露和注释
@ApiModel("用户实体类")//给实体类添加文档注释
public class User {
@ApiModelProperty("用户名") //给字段生成文档注释
public String username;
@ApiModelProperty("密码")
public String password;
}
结果显示
package com.kuang.swagger.controller;
import com.kuang.swagger.pojo.User;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController //由于我们没有页面所有要给他返回一个字符串
public class HelloController {
@GetMapping(value = "/hello")
public String hello(){
return "hello";
}
//只要我们的接口中,返回值中存在实体类,他就会被扫描到Swagger中
@PostMapping(value = "/user")
public User user(){
return new User();
}
//Operation接口 不是放在类上的 是放在方法上的
@ApiOperation("Hello控制类")
@GetMapping(value = "/hello2")
public String hello2(@ApiParam("用户名") String username){
return "hello" + username;
}
}
结果显示
Post测试
@ApiOperation("Post测试类")
@PostMapping(value = "/postt")
public User post(@ApiParam("用户名") User user){
int i = 5 / 0 ;
return user;
}
总结:
1.我们可以通过Swagger给一些比较难理解的属性或者接口,增加注释信息
2.接口文档实时更新
3.可以在线测试
注意点:
在正式发布的时候,关闭Swagger。出于安全考虑,而且节省运行内存
任务
异步任务~
controller
AsyncController.java
package com.kuang.springboot11test.controller;
import com.kuang.springboot11test.service.AsyncService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class AsyncController {
@Autowired
AsyncService asyncService;
@RequestMapping("/hello")
public String hello(){
asyncService.hello();//停止3秒
return "OK";
}
}
service
service.java
package com.kuang.springboot11test.service;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
@Service //spring托管
public class AsyncService {
//告诉Spring这是一个异步的方法
@Async
public void hello(){
try {
//休息3秒
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("数据正在处理");
}
}
package com.kuang.springboot11test;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
//开启异步注解功能
@EnableAsync
@SpringBootApplication
public class Springboot11TestApplication {
public static void main(String[] args) {
SpringApplication.run(Springboot11TestApplication.class, args);
}
}
定时任务~
TaskScheduler 任务调度者
TaskExecutor 任务执行者
@EnableScheduling//开启定时功能的注解
@Scheuled//什么时候执行
cron表达式
package com.kuang.springboot11test;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
//开启异步注解功能
@EnableAsync
@EnableScheduling//开启定时功能的注解
@SpringBootApplication
public class Springboot11TestApplication {
public static void main(String[] args) {
SpringApplication.run(Springboot11TestApplication.class, args);
}
}
**service **
ScheduledService.java
package com.kuang.springboot11test.service;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
@Service
public class ScheduledService {
//在特定的时间执行这行方法 Timer
//cron表达式
//秒 分 时 日 月 周几
//* 代表匹配该域的任意值
// ? 代表只能用在DayofMonth和DayofWeek两个域,它也匹配域的任意值,但实际不会,因为DayofMonth和DayofWeek会相互影响
//0 0/53 16,18 * * ? 每天16点和18点,每隔53分钟执行一次
// 0 15 10 ? * 1-6 每个月的周一到周六 10点15分执行一次
//@Scheduled(cron = "0 * * * * 0-7") //周一到周七的任何时候的第0秒 就会去执行下面的代码
// @Scheduled(cron = "0 53 16 * * ?")// 0 53 16 * * ? 每天的16时 53分执行一次
@Scheduled(cron = "0/2 * * * * ?") //每两秒执行一次
public void hello(){
System.out.println("hello,你被执行了~");
}
}
邮件发送~
导入依赖pom.xml
<!-- javax.mail-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
application.properties
spring.mail.username=xxxxx@qq.com
spring.mail.password=授权码
spring.mail.host=smtp.qq.com
# 开启加密验证
spring.mail.properties.mail.smtp.ssl.enable=true
测试里面写的: test:
package com.kuang.springboot11test;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.io.File;
@SpringBootTest
class Springboot11TestApplicationTests {
@Autowired
JavaMailSenderImpl mailSender;
@Test
void contextLoads() {
//一个简单的邮件
SimpleMailMessage mailMessage = new SimpleMailMessage();
mailMessage.setSubject("小狂神你好呀");//邮件主题
mailMessage.setText("谢谢你的狂神说java系列课程");//邮件内容
mailMessage.setTo("xxxx@qq.com");
mailMessage.setFrom("xxxx@qq.com");
mailSender.send(mailMessage);
}
@Test
void contextLoads2() throws MessagingException {
//一个复杂的邮件
MimeMessage mimeMessage = mailSender.createMimeMessage();
//组装 正文
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage,true);
helper.setSubject("小狂神你好呀,好好学习");//设置主题
helper.setText("<p style='color:red'>谢谢你的狂神说Java系列课程</p>",true);
//组件
helper.addAttachment("1.jpg",new File("C:\\Users\\HP\\Desktop\\1.jpg"));
helper.addAttachment("2.jpg",new File("C:\\Users\\HP\\Desktop\\1.jpg"));
helper.setTo("xxxx@qq.com");
helper.setFrom("xxxx@qq.com");
mailSender.send(mimeMessage);
}
// 这里的操作是/** 加回车
/**
*
* @param html
* @param subject
* @param text
* @throws MessagingException
* @Author kuangshenya
*/
//封装
public void sendMail(Boolean html, String subject, String text) throws MessagingException {
//一个复杂的邮件
MimeMessage mimeMessage = mailSender.createMimeMessage();
//组装 正文
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage,html);
helper.setSubject(subject);//设置主题
helper.setText(text,true);
//组件
helper.addAttachment("1.jpg",new File("C:\\Users\\HP\\Desktop\\1.jpg"));
helper.addAttachment("2.jpg",new File("C:\\Users\\HP\\Desktop\\1.jpg"));
helper.setTo("xxxx@qq.com");
helper.setFrom("xxxx@qq.com");
mailSender.send(mimeMessage);
}
}
SpringBoot整合
SpringBoot操作数据:spring-data jpa jdbc mongodb redis!
SpringData也是和SpringBoot齐名的项目
说明:在springboot2.x之后,原来使用的jedis被替换为了lettuce
jedis:采用的直连,多个线程操作的话,是不安全的,如果想要避免不安全的,使用jedis pool 连接池 更像BIO阻塞模式
lettuce:采用nety,实例可以在多个线程中进行共享,不存在线程不安全的情况!可以减少线程数据了,更像NIO模式。
源码分析:
@Bean
@ConditionalOnMissingBean(
name = {"redisTemplate"}
) //我们可以自己定义一个redisTemplate来替换这个默认的
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
//默认的RedisTemplate 没有过多的设置, redis对象都需要序列化
//两个泛型都是Object , Object的类型,我们后面使用需要强制转换<String, Object>
RedisTemplate<Object, Object> template = new RedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
@Bean
@ConditionalOnMissingBean// 由于String 是redis中最常用的类型,所以说单独提出来了一个bean!
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
整合测试
- 导入依赖
<!-- 操作redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2.配置连接
# 配置reddis
spring.redis.host=127.0.0.1
spring.redis.port=6379
3.测试
package com.kuang;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisTemplate;
@SpringBootTest
class Redis02SpringbootApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void contextLoads() {
//redisTemplate 操作不同的数据类型 api和我们的指令是一样的
// opsForValue 操作字符串的 类似String
//opsForList 操作List 类似List
//opsForGeo
//opsForHash
//opsForZSet
//opsForSet
//opsForHyperLogLog
//除了基本的操作,我们常用的方法都可以直接通过 redisTemplate 操作 比如事务和CRUD
// 获取redis的连接对象
// RedisConnection connection = redisTemplate.getConnectionFactory().getConnection();
// connection.flushDb();
// connection.flushAll();
redisTemplate.opsForValue().set("mykey","kuangshen");
System.out.println(redisTemplate.opsForValue().get("mykey"));
}
}
因为这部分的知识需要用到Redis 所以 现在开始学习Redis部分
Nosql概述
为什么要用Nosql
1.单机MySQL的年代
90年代,一个基本的网站访问量一般不会太大,单个数据库完全足够
那个时候,更多的去使用静态网页Html,服务器根本没有太大的压力!
思考一下,这种情况下:整个网站的 瓶颈是什么??
1.数据量如果太大,一个机器放不下
2.数据的索引(B + Tree),一个机器内存也放不下
3.访问量(读写混合),一个服务器承受不了
只要出现以上的三种情况之一,那么就必须晋级。
2.Memcached(缓存)+ MySQL+垂直拆分(读写分离)
网站80%都是在读,每次去查询数据库就很麻烦!所以说我们希望减轻数据库的压力,我们可以使用缓存保证。
发展过程:优化数据库和索引 --> 文件缓存(IO)—>Memcached(当时最热门的技术!)
3分库分表 + 水平拆分 + MySQL集群
本质:数据库(读,写)
早些年MyISAM:表锁,十分影响效率,会锁住一个表!高并发下就会出现严重的锁问题
转战Innodb:行锁,只锁定一行
慢慢的就开始使用分库分表来解决写的压力!
为什么要用NoSQL
用户的个人信息,社交网络,地理位置,用户自己产生的数据,用户日志等爆发式增长!
这时候我们就需要使用Nosql数据库, NoSQL可以很好的处理以上问题。
NoSQL
Nosql
Nosql = Not Only SQL(不仅仅是SQL)
泛指非关系性数据库,随着web2.0互联网的诞生!传统的关系型数据库很难对付web2.0时代!尤其是超大规模的高并发的社区!暴露出来很多难以克服的问题,NoSQL在当今大数据环境下发展的十分迅速,Redis是发展最快的,而且是我们当下必须要掌握的技术。
很多的数据类型用户的个人信息,社交网络,地理位置,这些数据类型的存储不需要一个固定的格式!不需要多余的操作就可以横向扩展的。Map<String, Object>
NoSQL特点
解耦!
1.方便扩展(数据库之间没有关系,很好扩展)
2.大数据量高性能(Redis一秒写8万次,读取11万次,NoSQL的缓存记录级,是一种细粒度的缓存,性能会比较高)
3.数据类型是多样类型的(不需要事先设计数据库!随取随用,如果数据量十分大的表,很多人就无法去设计了)
- 五大基本数据类型
- String
- Lust
- Set
- Hash
- Zset
- 三种特殊数据类型
- geo
- hyperloglog
- bitmap
4.传统RDBMS(关系型数据库) 和NoSQL的区别
传统的 ROBMS
- 结构化组织
- SQL
- 数据和关系都存在单独的表中 row col
- 数据操作,数据定义语言
- 严格的一致性
- 基础的事务
- ...
Nosql
- 不仅仅是数据
- 没有固定的查询语言
- 键值对存储,列存储,图形数据库(社交关系)
- 最终一致性
- CAP定理和BASE(异地多活) 初级架构师
- 高性能,高可用,高可扩
-......
了解:3 V + 3高
大数据时代的3V :主要是描述问题
- 海量Volume
- 多样Variety
- 实时Velocity
大数据时代的3高:主要是对程序的要求
1.高并发
2.高可扩
3.高性能(保证用户体验和性能)
真正在公司中的实践:Nosql + ROBMS
B站学习网址:【狂神说Java】SpringBoot最新教程IDEA版通俗易懂_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili