SpringBoot进阶

SpringBoot配置文件

YML

YAML不是一种标记语言,通常以.yml为后缀的文件,是一种直观的能够被电脑识别的数据序列化格式,并且容易被人类阅读,容易和脚本语言交互的,可以被支持YAML库的不同的编程语言程序导入,一种专门用来写配置文件的语言。

YML是代替XML的最优解决方案,语法简洁,清晰易读,跨平台性和扩展性良好好,可以表达复杂的数据结构;

基本语法:

1.数据以key: value键值对的形式存储

需要强调的是冒号后面必须有一个空格

name: lbb

2.不区分数据类型

name: lbb
age: 18

3.使用缩进来表示作用域,相同缩进的键值对处于同一个级别

student:
	name: lbb
	age: 18

4.[]表示数组或集合

numbser: [1,2,3,4]

5.{}可以在同一行书写map/对象

maps: {key1: value1,key2: value2}

6.数组和字典中的元素也可以使用 - 来分隔到多行

#字符数组/list:
hobby:
  - game
  - music
#存储map/对象的 数组/list:
dogs:
  - name: key1
      age: 1
  - name: key2
      age: 2
  - {name: key3,age: 3}

7.日期

birthday: 2020/7/30 10:10:10

8.文档块,可在同一个文件中编写两份不同的配置

server:
  port: 8081
spring:
  profiles:
    active: prod #激活对应的文档块

---
server:
  port: 8083
spring:
  profiles: dev #指定属于哪个环境

---
server:
  port: 8084
spring:
  profiles: prod  #指定属于哪个环境

案例

pojo类:

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: lbb
  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: 8
    - name: 小白
      age: 10
  birth: 2020/7/30 23:56:10

获取配置信息

1.当容器中的bean需要使用配置文件中的内容时,可以使用@Value注解:当然要保证该类的Bean以及加入容器

@Value("${myname}")
private String myname;

2.环境变量,获取加载到的配置信息

//注入环境变量,可以获取加载到的配置信息
@Autowired
private Environment environment;

 //测试类
@Test
public void test1(){
	//获取配置信息里的内容
   System.out.println(environment.getProperty("myname"));
}

3.当有很多属性都要注入到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;}
}

对于上面使用了 @Component 加入bean容器,在其他类直接注入使用即可:

@Autowired
private TestPojo testPojo;

切换配置文件

对于properties 文件和 yaml 文件,springboot首先寻找 properties 文件,如果有的话就使用 properties 文件,如果没有再去寻找 yaml 文件。

在项目开发过程中我们为了不影响线上数据,通常会使用一套专门用于开发阶段的配置,在编写完成后再切换到线上配置比如redis,zookeeper,数据库等等,SpringBoot可以帮助我们轻松实现配置文件的切换;

配置文件的命名:

根据不同使用场景,创建格式为application-环境标识.yml(/properties)的配置文件,例如:

application-dev.yml

application-product.yml

指定要使用的配置文件

方式一:

创建名为application-dev.yml的配置文件,在application.yml配置文件中指定要使用的配置文件信息,SpringBoot默认会读取该文件,:

spring:
	profiles:
  	active: dev  #dev即为环境标识,开发环境

方式二

不需要创建默认的application.yml,而是在运行程序时通过参数来指定要使用的配置文件

  • 通过java虚拟机参数:

    1.开发时直接在idea添加参数 –spring.profiles.active=dev 指定配置文件:
    在这里插入图片描述在这里插入图片描述

    2.打包后,也可以直接在执行时指定:

java -jar -Dspring.profiles.active=product  /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=product  

注意:使用该方式则必须在引导类中将获取的命令行参数传递给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>
<!--连接池依赖-->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>

配置redis信息

  • 单机
spring:
	redis:
		host: 192.168.74.128
		port: 65500
    	#Sprin boot 默认使用的是lettuce作为redis客户端,使用异步IO,且线程安全
		lettuce:
		#连接池不是必须的配置项,基础配置只需要host和port即可
		pool:
		#最大连接数量,闲置数,等待时间
		max-active: 10
		max-idle: 5
		max-wait: 10

集群

spring:
	redis:
		cluster:
		nodes: 192.168.74.128:7001,192.168.74.128:7002,192.168.74.128:7003,192.168.74.128:7004,192.168.74.128:7005,192.168.74.128:7006
  #节点之间使用逗号隔开

redis读写案例

@Service
public class UserServiceImpl implements UserService {
	//springboot默认提供的,用于操作redis的模板对象
    @Autowired
    StringRedisTemplate redisTemplate;

    @Autowired
    UserMapper mapper;
    
	//springboot默认提供了一个用于json序列化的ObjectMapper
    @Autowired
    ObjectMapper objectMapper;

    @Override
    public List<User> getAll() {
        try {
            //从redis获取数据
            String users_json = redisTemplate.opsForValue().get("users");
            //如果存在则直接返回
            if (users_json != null && users_json.length() > 0){
                //把查到的json数据反序列化
                CollectionType collectionType = objectMapper.getTypeFactory().constructCollectionType(List.class, User.class);
                
                return objectMapper.readValue(users_json, collectionType);
            }else{
                //不存在则查询数据库
                List<User> users = mapper.selectUserList();
                //序列化转成字符串
                String users_json2 = objectMapper.writeValueAsString(users);
                //并放入redis
              	redisTemplate.opsForValue().set("users",users_json2);
                //返回
                return users;
            }
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return mapper.selectUserList();
    }
}

事务管理

涉及数据库的操作就免不了事务,在ssm项目中我们需要配置事务管理器等相关信息,这写配置但多数情况下也都是差不多的,所以在SpringBoot中,我们不需要编写任何的配置信息,只要在需要进行事务管理的方法上添加事务注解即可

事务测试案例:

@Service
public class UserServiceImpl implements UserService {
  @Override
  //事务注解,可以在括号里面添加只读、传播行为等信息
  @Transactional(propagation = Propagation.REQUIRED)
  public void updateUser(){
      User user = mapper.selectUserById(1);
      user.setUsername("lbb");
      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());
    
    @RequestMapping("/show")
    @ResponseBody
    public String showList(Model model){
 		//配置文件里设置级别,设置的级别以下不输出
        logger.debug("debug");
        logger.trace("trace");
        logger.info("info");
        logger.warn("warn");
        logger.error("error");

        return "测试日志!!!";
    }
}

简单配置

logging:
  level:
    root: info   # rootLogger的级别
    com.kkb.controller: debug  #某个包的日志级别
  file:
    path: ./logs/  #日志输出目录
    name: ./logs/app.log   #设置日志文件名,前面要带路径,因此在设置name时,path可以不指定
    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的依赖

添加依赖:

<!--  log4j日志起步依赖  -->
<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>
   <!--  排除logback日志依赖  -->
    <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">weblog</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.lbb.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("lbb") && user.getPassword().equals("123456")){
    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,我们只需要提供用于处理异常的通知即可

定义异常处理通知

//异常处理使用的是AOP 所以处理逻辑 将做为通知被织入
@ControllerAdvice 
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);
        //跳转error.html
        return "error";
    }
}

提供一个错误页面

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>error</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到工程根目录下执行下面命令:
maven package
#打包前会先执行项目中的所有单元测试,若不需要运行测试可以使用以下参数跳过测试直接打包
maven -DskipTests package

运行打包好的项目

#打包完成后会在项目根目录下生产target目录,里面就包含了打包完的jar,进入target后执行以下命令即可
java -jar ./target/SpringBootDemo-1.0-SNAPSHOT.jar

整合Dubbo

服务提供方和消费方依然是独立的项目,各自管理自己的依赖关系,然后抽取公共部分。

Dubbo的pom文件和普通的SpringBoot略微不同,不用指定parent

创建工程

工程结构:

| common (空的maven)
	| User
	| UserService
| provider (dubbo + SpringBot)
	| UserServiceImpl
| consumer (dubbo + SpringBot + webMVC)
	| UserController

公共类

pojo类:

public class User implements Serializable {
    private String name;
    private Integer age;

    public User() {
    }
    public User(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
    
    get/set....
}

公共接口类:

public interface UserService {
    List<User> getUserList();
}

提供方

pom.xml

<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>
    </dependencies>

实现类:

//注意 要使用dubbo提供的Service注解
@Service
public class UserServiceImpl implements UserService {
    @Override
    public List<User> getUserList() {
        //模拟查询数据
        ArrayList<User> users = new ArrayList<>();
        users.add(new User("lbb1",18));
        users.add(new User("lbb2",19));
        users.add(new User("lbb3",20));
        users.add(new User("lbb4",21));
        return users;
    }
}

配置文件:

#配置
dubbo:
  application:
    #服务名
    name: myProvider
  registry:
    #注册中心
    protocol: zookeeper
    #地址
    address: 192.168.74.128:2181
  protocol:
    #协议
    name: dubbo
    #端口
    port: 20881

引导类:

@SpringBootApplication
启动dubbo并扫描实现类
@EnableDubbo(scanBasePackages = "com.lbb.service.impl")
public class ProviderRunner {
    public static void main(String[] args) {
        SpringApplication.run(ProviderRunner.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>
</dependencies>

控制器:

@Controller
public class UserConller {
	//dubbo引入服务 @Reference是dubbo的包下的
    @Reference
    private UserService userService;

    @RequestMapping("/getUserList")
    @ResponseBody
    public List<User> getUserList(){
        return userService.getUserList();
    }
}

配置文件:

#配置
dubbo:
  application:
    #服务名
    name: myConsumer
    #关闭qos
    qos-enable: false
  registry:
    #注册中心
    protocol: zookeeper
    #地址
    address: 192.168.74.128:2181
    #集群写法 
    #address: zookeeper://192.168.74.129:2181?backup=192.168.74.130:2181,192.168.74.131:2181
    #配置最大等待连接时间
    timeout: 10000
  config-center:
    timeout: 10000

引导类:

//dubbo注解最好在上,可以先加载dubbo
@EnableAutoConfiguration
@SpringBootApplication
public class CusumerRunner {
    public static void main(String[] args) {
        SpringApplication.run(CusumerRunner.class,args);
    }
}
©️2020 CSDN 皮肤主题: 创作都市 设计师:CSDN官方博客 返回首页