本篇是开发实用篇,接《springboot学习1》
目录
1. 启动热部署
重启(restart):自定义开发代码,包括类,页面、配置文件等,加载位置restart类加载器;
重载(reload):jar包,加载位置base类加载器
配置方法1:pom.xml添加依赖,maven刷新
// pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
使用构建项目按钮启动热部署(ctrl+f9 build project),热部署相当于restart过程,正常启动相当于restart+reload
然后需要在设置/compiler勾选build project atuomaitic
然后快捷键ctrl+shift+alt+/ ,勾选:compile.automake.allow.when.app.running
高版本在file->setting->Advanced Setttings里面勾选。
默认不触发重启的目录列表:/METE-INF/maven,/METE-INF/resources,、resources,/static,/public,/templates;默认是idea丢失焦点5s启动。
如果要修改范围,可自定义重启排除项
spring:
devtools:
restart:
exclude: static/**,public/**,config/application.yml
enabled: true
关闭热部署:通过设置高优先级属性禁用热部署。优先级可参看上一节的config优先级配置。
2.配置高级
(1)使用ConfigurationProperties可以为第三方bean绑定属性。
@Bean
@ConfigurationProperties(prefix = "datasource")
public DruidDataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
return ds;
}
// main函数
DruidDataSource ds = ctx.getBean(DruidDataSource.class);
System.out.println(ds.getDriverClassName());
// application.yml
datasource:
driverClassName: com.mysql.jdbc.Driver456
(2)EnableConfigurationProperties:注解可以将使用ConfigurationProperties注解的类加入到Spring容器。不能与@Component注解同时使用。
如果出现springboot Configuration Annotation Processor not configured,在pom里面添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
@ConfigurationProperties绑定属性支持属性名称松散绑定
@ConfigurationProperties(prefix = "datasource")
绑定的前缀命名规范:只能使用纯小写字母、数字、下划线作为合法字符。
@Value不支持松散绑定。
(3)常用的计量单位:
也可以在xml里面直接带单位
(4)Bean数据校验
导入JSR303与Hibernate校验框架坐标;
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
使用@Validated注解启用校验功能;使用具体校验规则规范数据校验格式。
@Component
@Data
@ConfigurationProperties(prefix = "servers")
@Validated
public class ServerConfig {
private String ipAddress;
private int port;
@Max(value=4000,message="最大值不能超过4000")
private long timeout;
}
(5)yml语法规则
注意yml文件对数字的定义支持进制书写格式,如需要使用字符串,就添加引号明确标注。
3.测试
在启动测试环境时,可以通过properties/args设置测试环境临时参数,用于小范围测试
@SpringBootTest(properties = {"test.prop=testValue1"},args = {"--test.prop=testValue2"})
class ApplicationTests {
@Value("${test.prop}")
private String msg;
@Test
void contextLoads() {
System.out.println(msg);
}
}
加载测试专用的配置,可使用import
测试类发起web请求,使用webEnvironment、MockMvcRequestBuilders、MockMvcResultMatchers
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
public class WebEnviromentTest {
@Test
void testRandomPort(){
}
@Test
void testWeb(@Autowired MockMvc mvc) throws Exception {
// 创建虚拟请求,当前访问/books
MockHttpServletRequestBuilder builder = MockMvcRequestBuilders.get("/books");
ResultActions actions = mvc.perform(builder);
// 设定预期值,与真实值进行比较,成功则测试通过,失败则测试失败
// 定义本次调用的预期值
StatusResultMatchers status = MockMvcResultMatchers.status();
// 预计本次调用时成功的状态200
ResultMatcher ok = status.isOk();
// 使用本次执行的真实值与预期结果进行比对
actions.andExpect(ok);
}
}
以上是状态对比,以下是内容比对的部分
ContentResultMatchers content = MockMvcResultMatchers.content();
// 预计本次调用时成功的状态200
ResultMatcher ok = content.string("springboot");
// 使用本次执行的真实值与预期结果进行比对
actions.andExpect(ok);
以下是Json匹配
请求头的匹配
数据层事务回滚,防止测试的数据保存到数据库。
测试用例数据设定:测试用例数据通常采用随机数进行测试,可使用SpringBoot提供的随机数为其赋值。
testcase:
book:
id: ${random.int} # 随机整数
id2: ${random.int(10)} # 10以内随机数
type: ${randowm.int(10,20)} # 10-20的随机数
uuid: ${random.uuid} # 随机uuid
name: ${randowm.value} # 随机字符串,MD5字符串,32位
publishTime: ${random.long} # 随机整数(long范围)
4.数据层解决方案
4.1 sql
数据层解决方案技术选型:druid+mybatis-plus+mysql
数据源:druid;持久化技术:mybatis-plus;数据库:mysql。以下为内置的讲解。
(1)SpringBoot提供了3种内嵌的数据源对象供开发者选择: HikariCP(默认使用),Tomcat提供的DataSource, Commons DBCP.
hikaricp的配置方法。
Druid配置。
也可以使用这样的方式。
(2)jdbcTemplate,这个是内置的持久化方案。通过传入rm参数,格式化返回数据格式。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
jdbcTemplate也有参数,可在application.yml设置。
(3)SpringBoot提供了3种内嵌数据库:H2,HSQL, Derby,内存级数据库,开发阶段测试用。
server:
port: 8010
spring:
h2:
console:
enabled: true
path: /h2 # 访问用户名sa, 默认密码123456
datasource:
url: jdbc:h2:~/test
hikari:
driver-class-name: org.h2.Driver
username: sa
password: 123456
# datasource:
# druid: // 或者采用druid等数据源
# url: jdbc:h2:~/test
# driver-class-name: org.h2.Driver
# username: sa
# password: 123456
运行程序, 访问localhost:8010/h2就可以进入h2面板
4.2 NoSql
常见的NoSql解决方案有:redis、Mongo、ES
(1)Redis是一款Key-Value存储结构的内存级NoSql数据库。支持多种数据存储格式,支持持久化,支持集群。
windows版本的安装包可直接解压安装或一键式安装。
服务端启动命令:redis-server.exe redis.windows.conf
客户端启动命令:redis-cli.exe
启动服务端可能存在bug,可先执行redis-cli.exe 然后 shutdown;然后exit;然后再使用redis-server.exe redis.windows.conf就可以了。
出现这个界面代表执行成功了。
常用命令:hset key field value:例如hset keya a1 aa1;hget key field:例如 hget keya a1;
keys *;springBoot整合redis: yml里面可不配置
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
RedisTemplate提供操作各种数据存储类型的接口API
客户端:RedisTemplate以对象作为key和value,内部对数据进行序列化
客户端:StringRedisTemplate以字符串作为key和value,与Redis客户端(redis-cli.exe)操作效果一致.xxxOperations<String,String>带泛型。
jedis:
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
需要在yml里面指定client-type: jedis,默认是lettuce
jedis连接redis服务器是直连模式,当多线程模式下使用jedis会存在线程安全问题,解决方案是通过配置连接池使每个连接可用,这样整体性能就大受影响。
lettuce基于Netty框架进行与Redis服务器连接,底层设计采用StateRedisConnection。StateRedisConnection是线程安全的,可以保障并发访问安全问题,所以一个连接可以被多线程复用。当然lettuce也支持多连接实例一起工作。
(2)Mongodb:
mongodb是一个开源、高性能、无模式的文档型数据库。NoSql数据库产品里面最像关系型数据库的非关系型数据库。
服务端启动:mongod --dbpath=..\data\db
客户端启动:mongo -- host=127.0.0.1 --port=27017
如果出现找不到vcrruntime140_1.dll。搜索下载dll文件;拷贝到system32目录下;执行regsvr32 vcruntime140_1.dll注册对应dll文件。
可视化客户端-rebo 3T。新建数据库,新建集合。
新增:db.集合名称.insert/save/insertOne(文档)
删除:db.集合名称.remove(条件)
修改:db.集合名称.update(条件,{操作种类:{文档}).
springboot整合mongodb
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
spring:
data:
mongodb:
url: mongodb://localhost/itheima
(3)Elasticsearch(ES)
es是一个分布式全文搜索引擎。原理:数据库分词,对应某些id(也就是倒排索引),这些id对应对应的简要文档数据数组(创建文档),搜索时(使用文档)出来搜索结果;
启动:elasticsearch.bat,时间比较长。
常用索引操作:get、put、delete/ 地址是 localhost:9200/xxx,这样的索引没有匹配规则,需要在put时添加Body/raw内容,此处用到分词器:elasticsearch-analysis-ik,下好插件解压缩放在安装目录下的plugins里面,目录名为ik,重新启动。
创建文档常用操作:
添加:
查询:
条件查询:
删除文档:
全量修改:
部分修改:
和springboot整合
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
elasticsearch:
rest:
url: http://localhost:9200
接口使用elasticsearchRestTemplate.
elasticsearch提供了两种级别的客户端接口(以上为低级别,默认的;以下采用高级别的)
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
</dependency>
高版本的yml不需要配置(springboot未提供)
创建索引,需要创建客户端和关闭客户端
也可以把创建和关闭客户端抽取出来,setUp和tearDown
简化后的操作,直接使用client
设置请求里面的参数(索引参数)
json = "xxx"; // 将参数从postman拷贝过来就可以,也就是上面mappings参数体。包括mappings
request.source(json,XContentType.JSON)
创建文档(单个创建)
创建文档(批处理),用到client.bulk()
使用文档(查询)
按照id查询
按条件查询
其中JSON.toStringfy和JSON.parseObject使用的是fastjson,需要添加依赖。
5.整合第三方技术
缓存、任务、邮件、消息。
缓存
缓存是一种介于数据永久存储介质和数据应用中间的数据临时存储介质,有效减少数据读取次数,提高性能。比如下方定义在service里面的catch,提供了一个临时数据存储空间。
springboot提供的cache:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
在applicion.java类上添加注解
@SpringBootApplication
@EnableCaching
需要用的地方使用注解@Cacheable
@Cacheable(value = "cacheSpace",key = "#id")
public boolean gettById(Integer id) {
return bookDao.selectById(id)>0;
}
springboot除了提供默认的缓存方案,还对其他缓存技术做了整合,统一接口,方便管理。常见的缓存技术有:Generic,JCache,Ehcache,Hazelcast,infinispan,Couchbase,redis,Caffenine,Simple(默认),memcached.
(1)simple
一个简单的生成验证码的工具方法
@Component
public class CodeUtils {
private String[] patch = {"00000","0000","000","00","0",""};
public String generator(String tel){
int hash = tel.hashCode ();
int encryption = 20220317;
long result = hash ^ encryption;
long now = System.currentTimeMillis ();
result = result ^ now;
long code =result % 1000000;
code = code<0?-code:code;
String codeStr = code + "";
int len = codeStr.length();
return patch[len-1] + codeStr;
}
@Cacheable(value="smsCode",key="#tel")
public String get(String tel){
return null;
}
public static void main(String[] args){
System.out.println (new CodeUtils ().generator ("18666699911"));
}
}
使用该方法,同时使用缓存。使用Cacheput,防止每次发出的验证码都是一个值
@Autowired
private CodeUtils codeUtils;
@Override
// @Cacheable(value = "smsCode",key = "#tel")
@CachePut(value = "smsCode",key = "#tel")
public String sendCodeToSMS(String tel) {
String code = codeUtils.generator (tel);
return code;
}
@Override
public Boolean checkCode(SMSCode smsCode) {
String code = smsCode.getCode ();
String cacheCode = codeUtils.get (smsCode.getTel ());
return code.equals (cacheCode);
}
在controller里面就可以使用了
@RestController
@RequestMapping("/sms")
public class SMSCodeController {
@Autowired
private SMSCodeService smsCodeService;
@GetMapping
public String getCode(String tel){
String code = smsCodeService.sendCodeToSMS (tel);
return code;
}
@PostMapping
public boolean checkCode(SMSCode smsCode){
return smsCodeService.checkCode (smsCode);
}
}
postman里面使用post:localhost:8082/sms?tel=xxx&code=xxx就可以了。
(2)Ehcache
PS:时隔半个多月再次开始更新,结合这半个月的工作经历,结论是:学习一定要一气呵成,不能三天打鱼两天晒网,不然断断续续的学习忘得太快,成本太高。
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>
# application.yml
cache:
type: ehcache
ehcache:
config: ehcache.xml
java代码和simple一样,不需要修改。
(3)Redis
数据淘汰机制:LRU:Least Recent used;LFU:Least Frequently used
添加依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
application.yml
cache:
type: redis
redis:
use-key-prefix: true
key-prefix: ssm_
cache-null-values: true
time-to-live: 10s
redis:
host: localhost
port: 6379
java代码不需要改
(4)memcached
<dependency>
<groupId>com.googlecode.xmemcached</groupId>
<artifactId>xmemcached</artifactId>
<version>2.4.7</version>
</dependency>
由于springboot未集成,也不需要在application.yml里面设置,直接硬编码
创建客户端配置类
// XMemcachedConfig.java
@Configuration
public class XMemcachedConfig {
@Autowired
private XMemcachedProperties memcachedProperties;
@Bean
public MemcachedClient getMemcached() throws IOException {
MemcachedClientBuilder memcachedClientBuilder = new XMemcachedClientBuilder(memcachedProperties.getServers());
memcachedClientBuilder.setConnectionPoolSize(memcachedProperties.getPoolSize());
memcachedClientBuilder.setOpTimeout(memcachedProperties.getOpTimeout());
MemcachedClient client = memcachedClientBuilder.build();
return client;
}
}
// XMemcachedProperties.java
@Component
@ConfigurationProperties(prefix = "memcached")
@Data
public class XMemcachedProperties {
private String servers;
private int poolSize;
private long opTimeout;
}
在application.yml里面设置参数
memcached:
servers: localhost:11211
pool-size: 10
op-timeout: 3000
使用:
(5)jetcache
jetCache对springcache进行了封装,在原有基础上实现了多级缓存,缓存统计,异步调用,自动刷新,数据报表等功能。是一个底层框架。支持①本地缓存:LinkedHashMap,Caffeine和②远程缓存:redis,tair
<dependency>
<groupId>com.alicp.jetcache</groupId>
<artifactId>jetcache-starter-redis</artifactId>
<version>2.6.2</version>
</dependency>
jetcache:
statIntervalMinutes: 15 # 非必须 缓存报告
areaInCacheName: false # 非必须
local:
default:
type: linkedhashmap
keyConvertor: fastjson
limit: 100 # 非必须
remote:
default:
type: redis
host: localhost
port: 6379
keyConvertor: fastjson # 非必须
valueEncoder: java # 非必须
valueDecoder: java # 非必须
poolConfig:
maxTotal: 50
minIdle: 5 # 非必须
maxIdle: 20 # 非必须
sms:
type: redis
host: localhost
port: 6379
poolConfig:
maxTotal: 50
// 开启jetcache注解支持
@SpringBootApplication
@EnableCreateCacheAnnotation
public class Application {}
@CreateCache(area = "default",name = "jetCache_",expire = 200,timeUnit = TimeUnit.SECONDS,cacheType = CacheType.BOTH)
private Cache<String, String> jetCache;
使用:
使用方法缓存
@SpringBootApplication
@EnableCreateCacheAnnotation
@EnableMethodCache(basePackages = "com.itheima")
public class Application {}
注意,缓存对象必须要可序列化,在实体类上添加 implements Serializable
(6)j2Cache
添加依赖
更多的j2Cache配置,参看jar包里面的实例配置文件