SpringBoot 进阶
springboot配置文件
yml
yaml (yaml ain't a markup language)yaml不是一种标记语言,通常以.yml为后缀的文件,是一种直观的能够被电脑识别的数据序列化格式,并且容易被人类阅读,容易和脚本语言交互的,可以被支持yaml库的不同的编程语言程序导入,一种专门用来写配置文件的语言。
yml是代替xml的最优解决方案,语法简洁,清晰易读,跨平台性和扩展性良好好,可以表达复杂的数据结构;
基本语法:
1.数据以key: value
键值对的形式存储
需要强调的是冒号后面必须有一个空格
name: jerry
2.不区分数据类型
name: jerry age: 18
3.使用缩进来表示作用域,相同缩进的键值对处于同一个级别
student: name: jerry age: 18
4.[]表示数组或集合
numbser: [1,2,3,4]
5.{}可以在同一行书写map/对象
maps: {key1: value1,key2: value2}
6.数组和字典中的元素也可以使用 -
来分隔到多行
#字符数组/list: hobby: - game - music #存储map/对象的 数组/list: dogs: - name: 阿花 age: 1 - name: 啊丑 age: 2 - {name: 啊啊,age: 3}
7.日期
birthday: 2020/12/12 10:10:10
8.文档块,可在同一个文件中编写两份不同的配置
server: port: 8081 spring: profiles: active: prod #激活对应的文档块 --- server: port: 8083 spring: profiles: dev #指定属于哪个环境 --- server: port: 8084 spring: profiles: prod #指定属于哪个环境
案例:
java类:
public class person { private string name; private int age; private string[] hobby; private hashset<string> gfs; private map<string,string> maps; private dog dog; private list<dog> dogs; private date birth; public date getbirth() { return birth; } } class dog { private string name; }
yml:
person: name: jerry age: 18 hobby: #[game,music] - game - music gfs: [a,b,c] maps: {key1: value1,key2: value2} #maps: # key1: value1 #key2: value2 dog: name: 大黄 dogs: - name: 阿花 age: 18 - name: 啊丑 age: 20 birth: 2020/12/12 23:56:10
获取配置信息
1.当容器中的bean需要使用配置文件中的内容时,可以使用@value注解:当然要保证该类的bean以及加入容器
@value("${myname}") private string myname;
2.当有很多属性都要注入到bean中时可以采用@configurationproperties
注解,springboot会按照属性名称进行注入,注意:必须提供set方法
@component //perfix指定要映射的key名称 与配置文件中对应 @configurationproperties(prefix = "person") public class person { private string name; private int age; public string getname() {return name;} public void setname(string name) {this.name = name;} public int getage() {return age;} public void setage(int age) {this.age = age;} }
切换配置文件
在项目开发过程中我们为了不影响线上数据,通常会使用一套专门用于开发阶段的配置,在编写完成后再切换到线上配置比如redis,zookeeper,数据库等等,springboot可以帮助我们轻松实现配置文件的切换;
配置文件的命名:
根据不同使用场景,创建格式为application-环境标识.yml(/properties)
的配置文件,例如:
application-dev.yml
application-prod.yml
指定要使用的配置文件
方式一:
创建名为application-dev.yml的配置文件,springboot默认会读取该文件,在文件中指定要使用的配置文件信息:
spring: profiles: active: dev #dev即为环境标识
方式二
不需要创建默认的application.yml,而是在运行程序时通过参数来指定要使用的配置文件
- 通过java虚拟机参数:
java -jar -dspring.profiles.active=prod /users/jerry/ideaprojects/springbootdemo/target/springbootdemo-1.0-snapshot.jar
- 也可以通过springboot参数指定:
java -jar /users/jerry/ideaprojects/springbootdemo/target/springbootdemo-1.0-snapshot.jar --spring.profiles.active=prod
注意:使用该方式则必须在引导类中将获取的命令行参数传递给springboot
@springbootapplication public class application { public static void main(string[] args) { //args 即为命令行参数 springapplication.run(application.class,args); } }
常见配置项:
# ---------------------------------------- # web properties # ---------------------------------------- # embedded server configuration (serverproperties) server.port=8080 # server http port. server.servlet.context-path= # context path of the application. server.servlet.path=/ # path of the main dispatcher servlet. # http encoding (httpencodingproperties) spring.http.encoding.charset=utf-8 # charset of http requests and responses. added to the "content-type" header if not set explicitly. # jackson (jacksonproperties) spring.jackson.date-format= # date format string or a fully-qualified date format class name. for instance, `yyyy-mm-dd hh:mm:ss`. # spring mvc (webmvcproperties) spring.mvc.servlet.load-on-startup=-1 # load on startup priority of the dispatcher servlet. spring.mvc.static-path-pattern=/** # path pattern used for static resources. spring.mvc.view.prefix= # spring mvc view prefix. spring.mvc.view.suffix= # spring mvc view suffix. # datasource (datasourceautoconfiguration & datasourceproperties) spring.datasource.driver-class-name= # fully qualified name of the jdbc driver. auto-detected based on the url by default. spring.datasource.password= # login password of the database. spring.datasource.url= # jdbc url of the database. spring.datasource.username= # login username of the database. # jest (elasticsearch http client) (jestproperties) spring.elasticsearch.jest.password= # login password. spring.elasticsearch.jest.proxy.host= # proxy host the http client should use. spring.elasticsearch.jest.proxy.port= # proxy port the http client should use. spring.elasticsearch.jest.read-timeout=3s # read timeout. spring.elasticsearch.jest.username= # login username.
参考官网:去看看
springboot中redis的使用
添加起步依赖
<!-- 配置使用redis启动器 --> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-data-redis</artifactid> </dependency>
配置redis信息
-
单机
spring: redis: host: 10.211.55.6 port: 6379 #sprin boot 默认使用的是lettuce作为redis客户端,使用异步io,且线程安全 lettuce: pool: max-active: 10 max-idle: 5 #连接池不是必须的配置项,基础配置只需要host和port即可
-
集群
spring: redis: cluster: nodes: 10.211.55.6:6379,10.211.55.6:6380,10.211.55.6:6381,10.211.55.6:6382,10.211.55.6:6383,10.211.55.6:6384 #节点之间使用逗号隔开
数据读写案列
@service public class userserviceimpl implements userservice { @autowired stringredistemplate redistemplate; @autowired usermapper mapper; @autowired objectmapper objectmapper;//用于json序列化 @override public list<user> getall() { try { //从redis获取数据 string users_json = redistemplate.opsforvalue().get("users"); //如果存在则直接返回 if (users_json != null && users_json.length() > 0){ system.out.println("缓存数据......."); return objectmapper.readvalue(users_json,list.class); }else{ //不存在则查询数据库 list<user> users = mapper.selectuserlist(); //并放入redis redistemplate.opsforvalue().set("users",objectmapper.writevalueasstring(users)); //返回 return users; } } catch (jsonprocessingexception e) { e.printstacktrace(); } return mapper.selectuserlist(); } }
请求测试:http://localhost:8080/user/list,可以看到输出缓存数据
表示redis已正常工作
事务管理
涉及数据库的操作就免不了事务,在ssm项目中我们需要配置事务管理器等相关信息,这写配置但多数情况下也都是差不多的,所以在springboot中,我们不需要编写任何的配置信息,只要在需要进行事务管理的方法上添加事务注解即可
事务测试案例:
@service public class userserviceimpl implements userservice { @override @transactional(propagation = propagation.required) public void updateuser(){ user user = mapper.selectuserbyid(1); user.setusername("jerry1"); mapper.updatebyprimarykey(user); int i = 1/0; } }
若不生效可在引导类上添加@enabletransactionmanagement
注解
@enabletransactionmanagement public class application { public static void main(string[] args) { //启动spring boot 需要指定引导类 springapplication.run(application.class,args); } }
日志配置
当我们加入了web的起步依赖后,springboot就已经自动的配置了日志了,其默认使用的是slf4j+logback,并将日志直接输出到控制台,一些情况下我们需要自己来修改日志的一些参数,如级别,输出位置等;
日志的起步依赖:当然这不需要我们自己添加,springboot已经有了
<dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-logging</artifactid> </dependency>
输出日志
@controller public class usercontroller { //获取一个logger private logger logger = loggerfactory.getlogger(getclass()); @autowired userservice service; @requestmapping("/show") public string showlist(model model){ logger.info("request path:/show"); logger.info("request path:/show"); logger.debug("request path:/show"); logger.warn("request path:/show"); list<user> all = service.getall(); model.addattribute("userlist",all); return "userlist"; } }
简单配置
logging: level: root: info # rootlogger的级别 com.kkb.controller: debug #某个包的日志级别 file: path: ./logs/ #日志输出目录 max-size: 1gb #文件大小 max-history: 5 #文件个数 pattern: console: "%d{yyyy/mm/dd-hh:mm:ss} [%thread] %-5level %logger-%msg哈哈哈哈%n"
切换至log4j
logback的配置文件基本上和log4j差不多,但仍然有一些差别,当我们需要对日志进行详细的定制时无疑会增加我们的学习成本,推荐直接使用log4j,单从对比数据上来看log4j更有优势;
使用前需要先将原本的logback依赖排除掉,然后添加log4f的依赖
添加依赖:
<dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-log4j2</artifactid> </dependency> <!--找到spring-web的起步依赖 排除logback--> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-web</artifactid> <exclusions> <exclusion> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-logging</artifactid> </exclusion> </exclusions> </dependency>
在resources下提供log4j2.xml
日志配置:
<?xml version="1.0" encoding="utf-8"?> <configuration status="warn"> <!--自定义属性信息--> <properties> <property name="log_home">logs</property> <property name="file_name">applog</property> </properties> <appenders> <console name="console" target="system_out"> <patternlayout pattern="%d{hh:mm:ss.sss} [%t] %-5level %logger{36} - %msg%n"/> </console> <!--滚动日志配置 filepattern用于设置滚动文件的命名规则 若以.zip为结尾则会自动归档日志文件 也支持其他的格式.gz, .zip, .bz2, 等--> <rollingrandomaccessfile name="rollingappender" filename="${log_home}/${file_name}.log" filepattern="${log_home}/$${date:yyyy-mm}/${file_name}-%d{yyyy-mm-dd hh-mm}-%i.log"> <patternlayout pattern="%d{yyyy-mm-dd hh:mm:ss.sss} [%t] %-5level %logger{36} - %msg%n"/> <policies> <!--滚动时间间隔 该参数需结合filepattern中的时间格式 此时表示为1分钟更换一个新文件 若时间格式为%d{yyyy-mm-dd hh}则表示每小时更换一个新文件--> <timebasedtriggeringpolicy interval="1"/> <!--单个日志文件最大容量 --> <sizebasedtriggeringpolicy size="1 mb"/> </policies> <!--最大保留的日志文件个数 默认为7个 --> <defaultrolloverstrategy max="20"/> </rollingrandomaccessfile> </appenders> <loggers> <root level="info"> <appenderref ref="console"/> </root> <logger name="com.kkb.controller" level="debug"> <appenderref ref="rollingappender"/> <appenderref ref="console"/> </logger> </loggers> </configuration>
若名称不是默认的log42.xml
则可以在springboot中添加配置来指定:
logging: config: classpath:log4j3.xml
handler拦截器
还记得拦截器是用来干什么的吗,它在什么时候执行?
在web-mvc中我们已经认识了拦截器,它可以在一个请求到达handler处理之前对请求进行拦截,从而可以轻松的实现权限控制,登录认证等功能;
定义拦截器:
public class loggininterceptor implements handlerinterceptor { @override public boolean prehandle(httpservletrequest request, httpservletresponse response, object handler) throws exception { system.out.println("拦截器执行.................."); if (request.getrequesturi().contains("login")){ return true; } if (request.getsession().getattribute("user") == null){ response.sendredirect("/login.html"); return false; } return true; } }
控制器添加代登录接口和登录页面
@requestmapping("/login") public string userlogin(user user, httpsession session){ user u = service.userlogin(user); if (user.getusername().equals("jerry") && user.getpassword().equals("123")){ session.setattribute("user",user); return "redirect:/show"; } return "redirect:/login.html"; } @requestmapping("/login.html") public string getage(){ return "login"; }
创建mvc配置类添加自定义的拦截器
@configuration public class myconfigruation implements webmvcconfigurer { @override public void addinterceptors(interceptorregistry registry) { registry.addinterceptor(new loggininterceptor()).addpathpatterns("/**"); } }
异常处理
webmvc中异常处理采用的是aop,我开门只需要提供用于处理异常的通知即可
定义异常处理通知:
@controlleradvice //异常处理使用的是aop 所以处理逻辑 将做为通知被织入 public class globalexceptionhandler { //日志记录器 private logger logger = loggerfactory.getlogger(getclass()); //指定该方法可以处理的异常类型 @exceptionhandler(exception.class) //model 用于向错误页面传递数据 public string defaulthandler(model model,exception e){ model.addattribute("error",e.getmessage());//添加错误信息 logger.error(e.getmessage(),e);//输出到日志 return "error";//跳转error.html } }
提供一个错误页面:
<!doctype html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="utf-8"> <title>title</title> </head> <body> <h1>系统错误</h1> 原因:<span th:text="${error}" style="color:red"/> </body> </html>
springboo工程的打包
在pom中添加springboot的maven插件,这将使得maven打包时会将所有依赖的jar包全部打包,形成一个fat jar,这样一来只要有java环境就能运行工程了,不需要在配置相关的依赖;
添加插件:
<plugin> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-maven-plugin</artifactid> <configuration> <fork>true</fork> </configuration> </plugin>
执行命令:
#cd到工程根目录下: mavem package #打包前会先执行项目中的所有单元测试,若不需要运行测试可以使用以下参数跳过测试直接打包 maven -dskiptests package
运行打包好的项目:
#打包完成后会在项目根目录下生产target目录,里面就包含了打包完的jar,进入target后执行以下命令即可 java -jar ./target/springbootdemo-1.0-snapshot.jar
整合dubbo
服务提供方和消费方依然是独立的项目,各自管理自己的依赖关系,然后抽取公共部分
创建工程:
| common (空的maven) | helloservice | provider (dubbo + springbot) | helloserviceimpl | consumer (dubbo + springbot + webmvc) | hellocontroller
服务提供方:
pom文件:
<dependencies> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter</artifactid> <version>2.2.4.release</version> </dependency> <dependency> <groupid>org.apache.dubbo</groupid> <artifactid>dubbo-spring-boot-starter</artifactid> <version>2.7.5</version> </dependency> <dependency> <groupid>com.101tec</groupid> <artifactid>zkclient</artifactid> <version>0.11</version> </dependency> <dependency> <groupid>org.apache.curator</groupid> <artifactid>curator-framework</artifactid> <version>4.2.0</version> </dependency> <dependency> <groupid>org.apache.curator</groupid> <artifactid>curator-recipes</artifactid> <version>4.2.0</version> </dependency> <dependency> <groupid>org.example</groupid> <artifactid>common</artifactid> <version>1.0-snapshot</version> <scope>compile</scope> </dependency>
实现类:
@service //注意 要使用dubbo提供的service注解 public class helloserviceimpl implements helloservice { @override public string sayhello(string name) { return "hello "+name; } }
配置文件:
dubbo: application: name: my-provider qos-enable: false registry: protocol: zookeeper address: 10.211.55.5:2182 protocol: name: dubbo port: 21888
引导类:
@springbootapplication @enabledubbo public class application { public static void main(string[] args) { springapplication.run(application.class,args); } }
消费方:
pom文件:
<dependencies> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-web</artifactid> <version>2.2.4.release</version> </dependency> <dependency> <groupid>org.apache.dubbo</groupid> <artifactid>dubbo-spring-boot-starter</artifactid> <version>2.7.5</version> </dependency> <dependency> <groupid>com.101tec</groupid> <artifactid>zkclient</artifactid> <version>0.11</version> </dependency> <dependency> <groupid>org.apache.curator</groupid> <artifactid>curator-framework</artifactid> <version>4.2.0</version> </dependency> <dependency> <groupid>org.apache.curator</groupid> <artifactid>curator-recipes</artifactid> <version>4.2.0</version> </dependency> <dependency> <groupid>org.example</groupid> <artifactid>common</artifactid> <version>1.0-snapshot</version> <scope>compile</scope> </dependency> <dependency> <groupid>org.example</groupid> <artifactid>common</artifactid> <version>1.0-snapshot</version> <scope>compile</scope> </dependency> </dependencies>
控制器:
@restcontroller public class heollocontroller { @reference helloservice helloservice; @requestmapping("/test/{name}") public string servicetest(@pathvariable string name){ return helloservice.sayhello(name); } }
配置文件:
dubbo: application: name: my-consumer qos-enable: false registry: protocol: zookeeper address: 10.211.55.5:2182 #集群写法 address: zookeeper://192.168.50.132:2181?backup=192.168.50.133:2181,192.168.50.134:2181
引导类:
@springbootapplication public class consumerapplication { public static void main(string[] args) { springapplication.run(consumerapplication.class,args); } }
访问测试:http://localhost:8080/test/jerry
页面输出名字即访问成功
dubbo的pom文件和普通的springboot略微不同,不用指定parent
推荐阅读