【Java学习】SpringBoot

178 阅读9分钟

简介(启动即用)

Spring: 一种框架,是为了企业级应用开发的复杂性而创建的,简化开发。

Spring是如何简化Java开发的?

  • 基于POJO的轻量级和最小入侵性编程;
  • 通过IOC(控制反转),依赖注入(DI)和面向接口实现松耦合;
  • 基于切面(AOP(本质:动态代理))和惯例进行声明式编程;
  • 通过切面和模板减少样式代码。

SpringBoot: 一个javaweb的开发框架,和SpringMVC类似,约定大于配置,能快速开发web应用,几行代码开发一个http接口。(Spring配置文件复杂)

SpringBoot基于Spring开发,SpringBoot本身不提供Spring框架的核心特性以及扩展功能,只是用于快速、敏捷地开发新一代基于Spring框架的应用程序。它不是用来替代Spring的解决方案,而是和Spring框架紧密结合用于提升Spring开发者体验的工具。SpringBoot以约定大于配置为核心思想,默认帮我们进行了很多设置,多数SpringBoot应用只需要很少的Spring配置。同时它集成了大量常用的第三方库配置(例如Redis、MonfoDB、Jpa、RabbitMQ、Quartz等等),SpringBoot应用中这些第三方库几乎可以零配置的开箱即用。

就像maven整合了所有的jar包,SpringBoot整合了所有的框架。

SpringBoot主要优点:

  • 为所有Spring开发者更快的入门
  • 开箱即用,提供各种默认配置来简化项目配置
  • 内嵌式容器简化Web项目
  • 没有冗余代码生成和XML配置的要求

第一个SpringBoot程序

自动配置

pom.xml

  • spring-boot-dependencies:核心依赖在父工程中
  • 我们在写或者引入一些Springboot依赖的时候,不需要指定版本,就是因为有这些版本仓库

启动器

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
  • 启动器就是Springboot的启动场景;
  • 比如spring-boot-starter-web,它会帮我们自动导入web环境所有的依赖;
  • springboot会将所有的功能场景,都变成一个个的启动器;
  • 要使用某个功能,就找到对应的启动器。

主程序

//这个类是一个springboot的应用
@SpringBootApplication
public class Springboot01HelloworldApplication {
    public static void main(String[] args) {
        //将springboot应用启动
        SpringApplication.run(Springboot01HelloworldApplication.class, args);
    }
}
  • 注解
@SpringBootConfiguration:springboot的配置
    @Configuration:spring配置类
    @Component:说明这也是一个spring的组件
    
@EnableAutoConfiguration:自动配置
    @AutoConfigurationPackage:自动配置包

(原理听懵了,先搁置)

结论: springboot所有自动配置都是在启动的时候扫描并加载:spring.factories所有的自动配置类都在这里面,但是不一定生效,要判断条件是否成立,只要导入了对应的start,就有对应的启动器了,有了启动器,我们自动装配就会生效,然后就配置成功!

关于SpringBoot,谈谈你的理解

  • 自动装配
  • run()
    • 推断应用的类型是普通的项目还是Web项目
    • 查找并加载所有可用初始化器,设置到initializers属性中
    • 找出所有的应用程序监听器,设置到listeners属性中
    • 推断并设置main方法的定义类,找到运行的主类

yaml语法讲解

SpringBoot使用一个全局的配置文件,配置文件名称是固定的

  • application.properties
    • 语法结构:key = value
  • application.yml
    • 语法结构:key:空格 value

配置文件的作用: 修改SpringBoot自动配置的默认值,因为SpringBoot在底层都给我们自动配置好了。

YAML 是"YAML Ain't a Markup Language"(YAML不是一种标记语言)的递归缩写。

properties只能保存键值对!

使用yaml要注意 空格。

截屏2023-04-03 22.45.22.png

yaml给属性赋值

  • pojo编写实体类
package com.example.springboot02config.pojo;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class Dog {

    private String name;
    private Integer age;

    public Dog() {}

    public Dog(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public Integer getAge() {
        return age;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + ''' +
                ", age=" + age +
                '}';
    }
}
package com.example.springboot02config.pojo;

import com.sun.org.apache.xpath.internal.operations.Bool;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.List;
import java.util.Map;

@Component
@ConfigurationProperties(prefix = "person")
public class Person {
    private String name;
    private Integer age;
    private Boolean happy;
    private Date birth;
    private Map<String, Object> maps;
    private List<Object> list;
    private Dog dog;

    public Person() {
    }

    public Person(String name, Integer age, Boolean happy, Date birth, Map<String, Object> maps, List<Object> list, Dog dog) {
        this.name = name;
        this.age = age;
        this.happy = happy;
        this.birth = birth;
        this.maps = maps;
        this.list = list;
        this.dog = dog;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Boolean getHappy() {
        return happy;
    }

    public void setHappy(Boolean happy) {
        this.happy = happy;
    }

    public Date getBirth() {
        return birth;
    }

    public void setBirth(Date birth) {
        this.birth = birth;
    }

    public Map<String, Object> getMaps() {
        return maps;
    }

    public void setMaps(Map<String, Object> maps) {
        this.maps = maps;
    }

    public List<Object> getList() {
        return list;
    }

    public void setList(List<Object> list) {
        this.list = list;
    }

    public Dog getDog() {
        return dog;
    }

    public void setDog(Dog dog) {
        this.dog = dog;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + ''' +
                ", age=" + age +
                ", happy=" + happy +
                ", birth=" + birth +
                ", maps=" + maps +
                ", list=" + list +
                ", dog=" + dog +
                '}';
    }
}
  • 编写.yaml文件
server:
  port: 8080

person:
  name: macondo
  age: 3
  happy: false
  birth: 2019/11/02
  maps: {k1: v1,k2: v2}
  list:
    - code
    - music
    - book
  dog:
    name: 旺财
    age: 3
  • 测试
package com.example.springboot02config;

import com.example.springboot02config.pojo.Dog;
import com.example.springboot02config.pojo.Person;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class Springboot02ConfigApplicationTests {

    @Autowired
    private Person person;
    @Test
    void contextLoads() {
        System.out.println(person);
    }

}
  • 遇到报错,导入依赖
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>
  • 结果

截屏2023-04-04 11.15.51.png

.yaml文件配置位置

截屏2023-04-04 13.00.11.png
  • 项目目录下的config优先级最高
  • pom.xml上面那个优先级其次
  • resources/config下面的第三
  • 默认生成的是优先级最低的

多环境配置

.properties 截屏2023-04-04 13.05.59.png .yaml

截屏2023-04-04 13.08.15.png

自动装配原理再详解

  • SpringBoot启动会加载大量的自动配置类;
  • 我们看我们需要的功能有没有在SpringBoot默认写好的自动配置类当中;
  • 我们再看这个自动配置类中到底配置了哪些组件;(只要我们要用的组件存在其中,我们就不需要再手动配置了)
  • 给容器中自动配置类添加组件的时候,会从properties类中获取某些属性。我们只需要在配置文件中指定这些属性的值即可。

xxxAutoConfiguration:自动配置类,给容器中添加组件

xxxProperties:封装配置文件中相关属性

SpringBoot Web开发

导入静态资源

在springboot中,我们可以使用以下方式处理静态资源

截屏2023-04-04 20.08.02.png 优先级:resources > static(默认) > public

Thymeleaf

导入依赖即可使用。

所有的html元素都可以被thymeleaf替换接管:

th : 元素名

整合Druid数据源

截屏2023-04-06 20.27.34.png
  • pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>springboot-03-data</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springboot-03-data</name>
    <description>springboot-03-data</description>
    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>2.6.13</spring-boot.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>

        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.16</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring-boot.version}</version>
                <configuration>
                    <mainClass>com.example.springboot03data.Springboot03DataApplication</mainClass>
                    <skip>true</skip>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>
  • application.yaml
spring:
  datasource:
    username: "root"
    password: "12345678"
    url: jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=UTC&rewriteBatchedStatements=true
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource
    filters: stat
  • DruidConfig.java
package com.example.springboot03data.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

@Configuration
public class DruidConfig {

    @ConfigurationProperties(prefix = "spring.datasource")
    @Bean
    public DataSource druidDataSource() {
        return new DruidDataSource();
    }

    //后台监控
    @Bean
    public ServletRegistrationBean statViewServlet() {
        ServletRegistrationBean<StatViewServlet> bean = new ServletRegistrationBean<>(new StatViewServlet(), "/druid/*");

        //后台需要有人登录,账号密码配置
        HashMap<String, String> initParameters = new HashMap<>();

        //增加配置
        initParameters.put("loginUsername", "admin");
        initParameters.put("loginPassword", "123456");

        //允许谁可以访问
        initParameters.put("allow", ""); //所有人可以访问

        bean.setInitParameters(initParameters); //设置初始化参数
        return bean;
    }

    //filter
    @Bean
    public FilterRegistrationBean webStatFilter() {
        FilterRegistrationBean bean = new FilterRegistrationBean();
        bean.setFilter(new WebStatFilter());
        //可以过滤的请求
        Map<String, String> initParameters = new HashMap<>();

        //不进行统计
        initParameters.put("exclusions", "*.js, *.css, /druid/*");
        bean.setInitParameters(initParameters);
        return bean;
    }
}
  • JDBCController.java
package com.example.springboot03data.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.Map;

@RestController
public class JDBCController {

    @Autowired
    JdbcTemplate jdbcTemplate;

    //查询数据库的所有信息
    @GetMapping("/userList")
    public List<Map<String, Object>> userList() {
        String sql = "select * from user";
        List<Map<String, Object>> maps = jdbcTemplate.queryForList(sql);
        return maps;
    }

    @GetMapping("/addUser")
    public String addUser() {
        String sql = "insert into mybatis.user(id, name, pwd) values(5, '小明', '123456')";
        jdbcTemplate.update(sql);
        return "add-ok";
    }

    @GetMapping("/updateUser/{id}")
    public String updateUser(@PathVariable("id") int id) {
        String sql = "update mybatis.user set name = ?, pwd = ? where id =" + id;
        //封装
        Object[] objects = new Object[2];
        objects[0] = "小明2";
        objects[1] = "111111";
        jdbcTemplate.update(sql, objects);
        return "update-ok";
    }

    @GetMapping("/deleteUser/{id}")
    public String deleteUser(@PathVariable("id") int id) {
        String sql = "delete from mybatis.user where id = ?";
        jdbcTemplate.update(sql, id);
        return "delete-ok";
    }
}
  • Springboot03DataApplicationTests.java
package com.example.springboot03data;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;

@SpringBootTest
class Springboot03DataApplicationTests {

    @Autowired
    DataSource dataSource;

    @Test
    void contextLoads() throws SQLException {
        //查看默认数据源 class com.zaxxer.hikari.HikariDataSource
        System.out.println(dataSource.getClass());

        //获得数据库连接 HikariProxyConnection@745966298 wrapping com.mysql.cj.jdbc.ConnectionImpl@c1fca2a
        Connection connection = dataSource.getConnection();
        System.out.println(connection);

        //xxxx Template:SpringBoot已经配置好的模板bean 拿来即用 CRUD


        //关闭连接
        connection.close();
    }

}

SpringBoot整合Mybatis

  • 导入包
  • 配置文件
  • mybatis配置
  • 编写sql
  • 业务层调用dao层
  • controller层调用service层

SpringSecurity

简介

SpringSecurity是针对Spring项目的安全框架,也是SpringBoot底层安全模块默认的技术选型,它可以实现强大的Web安全控制,对于安全控制,我们仅需要引入spring-boot-starter-security模块,进行少量的配置,即可实现强大的安全管理。

  • WebSecurityConfigurerAdapter:自定义Security策略
  • AuthenticationManagerBuilder:自定义认证策略
  • @EnableWebSecurity:开启WebSecurity模式

SpringSecurity的两个主要目标是“认证”和“授权”(访问控制)。

  • “认证”(Authentication)
  • “授权”(Authorization)

shiro

什么是shiro?

  • Apache Shiro是一个Java的安全(权限)框架。
  • Shiro可以非常容易的开发出足够好的应用后,其不仅可以用在JavaSE环境,也可以用在JavaEE环境。
  • Shiro可以完成:认证、授权、加密、会话管理、Web集成、缓存等。

核心三大对象

  • Subject 用户
  • SecurityManager 管理所有用户
  • Realm 连接数据

Swagger:接口文档

Swagger简介

  • 一款Api框架;
  • Restful Api文档在线自动生成工具-->Api文档与Api定义同步更新;
  • 直接运行,可以在线测试Api接口;
  • 支持多种语言。

在项目中使用Swagger需要springfox

  • swagger2
  • ui

Swagger作用

  • 可以通过Swagger给一些比较难的属性或接口,增加注释信息
  • 接口文档实时更新
  • 可以在线测试

任务

异步任务

@Async 告诉Spring这是一个异步的方法
@EnableAsync 在main方法中开启异步注解功能

邮件任务

定时任务

Dubbo+Zookeeper 分布式开发

Dubbo

Dubbo是一个高性能的基于Java实现的RPC通信框架。

Dubbo提供了三大核心能力:

  • 面向接口的远程方法调用
  • 智能容错和负载均衡
  • 服务自动注册和发现

dubbo-admin:是一个监控管理后台,查看我们注册了哪些服务,哪些服务被消费了。 截屏2023-04-07 15.04.42.png

RPC

RPC(Remote Procedure Call)是一种远程过程调用,是一种进程间通信方式,它是一种技术的思想,而不是规范。它允许程序调用另一个地址空间(通常是共享网络的另一台机器上)的过程或函数,而不用程序员显式编码这个远程调用的细节。

RPC两个核心模块:

  • 通讯
  • 序列化:方便数据传输

zookeeper

服务注册中心。

步骤:

前提:zookeeper服务已开启

1.提供者提供服务

  • 导入依赖
  • 配置注册中心的地址,以及服务发现名和要扫描的包
  • 在想要被注册的服务上面增加一个注解 @Service

2.消费者如何消费

  • 导入依赖
  • 配置注册中心的地址,配置自己的服务名
  • 从远程注入服务 @Reference

总结

  • 架构是为了解耦。
  • 微服务架构:分布式架构问题会遇到的四个核心问题?
    • 众多服务,客户端该如何去访问?(Api网关处理、第三方组件、自己实现)
    • 众多服务,服务之间如何进行通信?(Dubbo、RPC框架)
    • 众多服务,如何治理呢?(服务注册与发现Zookeeper)
    • 服务崩了,怎么办?(熔断机制Hystrix)

而SpringCloud,作为一种生态,就是来解决以上分布式架构的4个问题,但是想使用SpringCloud,必须要掌握SpringBoot。

万变不离其宗,一通百通!

  • API网关,服务路由
  • HTTP、RPC框架、异步调用
  • 服务注册与发现、高可用
  • 熔断机制、服务降级

最后

终于简单过了一遍SpringBoot相关,可以开始做项目了。