欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

SpringBoot 进阶

程序员文章站 2022-07-06 12:27:18
SpringBoot配置文件 YML YAML (YAML Ain't a Markup Language)YAML不是一种标记语言,通常以.yml为后缀的文件,是一种直观的能够被电脑识别的数据序列化格式,并且容易被人类阅读,容易和脚本语言交互的,可以被支持YAML库的不同的编程语言程序导入,一种专 ......

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