0


Spring Boot面试题

什么是 Spring Boot?

Spring Boot 是 Spring 开源组织下的子项目,其设计目的是专注于Spring应用的开发,开发人员可以把更多的精力放在业务代码上,而无需过多关注XML的配置,从而简化Spring应用开发,提高开发效率

Spring Boot 有哪些优点/Spring boot 相对 Spring有什么优势 ?

1.可快速构建独立的Spring应用

Spring Boot主要是通过注解和自动化配置的方式推出的全新框架,旨在快速、敏捷的开发新一代基于Spring框架的应用程序。在构建Spring Boot项目时,只要根据需求选择对应的场景依赖,Spring Boot会自动添加该场景所需要的全部依赖并提供自动化配置,在无需额外手动添加配置的情况下可以快速构建出一个独立的Spring应用程序。

2.直接嵌入Tomcat、Jetty和Undertow服务器(无需部署WAR文件)

Spring Boot项目不需要像传统的Spring应用一样打成WAR包的形式部署到Tomcat、Jetty或Undertow服务器中,运行一个Spring Boot项目,可以直接将项目打成JAR包的形式,并通过命令“java -jar xx.jar”运行。这是因为,Spring Boot项目内嵌了Tomcat、Jetty和Undertow服务器,因此在部署过程中减少了对第三方插件的依赖和管理。

3.提供依赖启动器简化构建配置

在Spring Boot项目构建过程中,无需准备各种独立的JAR文件,只需在构建项目时根据开发场景需求选择对应的依赖启动器“starter”即可,在引入的依赖启动器“starter”内部已经包含了对应开发场景所需的依赖,并会自动下载和拉取相关JAR包。例如,在Web开发时,只需在构建项目时选择对应的Web场景依赖启动器spring-boot-starter-web,Spring Boot项目便会自动导入spring-webmvc、spring-web、spring-boot-starter-tomcat等子依赖,并自动下载和拉取Web开发需要的相关JAR包。

4.极大程度的自动化配置Spring和第三方库

Spring Boot充分考虑到了与传统Spring框架以及其他第三方库融合的场景,在提供了各种场景依赖启动器的基础上,内部还默认提供了大量的各种自动化配置类(例如RedisAutoConfiguration)。使用Spring Boot开发项目时,一旦引入了某个场景的依赖启动器,Spring Boot内部提供的默认自动化配置类就会生效,开发者无需再手动进行配置文件的配置(除非开发者修改了相关默认配置,例如Redis地址、密码等),从而极大减少了开发人员的工作量,提高了程序的开发效率。

5.提供监控应用

Spring Boot提供了一些用于生产环境运行时的特性,例如指标、健康检查和外部化配置。其中,指标和监控检查可以很方便的帮助运维人员在运维期间监控项目运行情况;外部化配置可以很方便的让运维人员快速、方便的外部化配置和部署工作。

6.极少的代码生成和XML配置

Spring Boot框架内部已经实现了与Spring以及其他常用第三方库的整合连接,并提供了默认最优化的整合配置,使用时基本上不需要额外生成配置代码和XML配置文件。在需要自定义配置的情况下,Spring Boot更加提倡使用Java config(Java配置类)替换传统的XML配置方式,这样更加方便查看和管理。

Spring Boot 的核心注解是哪个?它主要由哪几个注解组成的?

启动类上面的注解是@SpringBootApplication,它是 Spring Boot 的核心注解

主要组合包含了以下 3 个注解:

1、**@SpringBootConfiguration**

@SpringBootConfiguration里面就只有一个@Configuration主要注解,也就是把该类变成一个配置类所以@SpringBootConfiguration就相当于@Configuration。实现配置文件的功能

2、**@EnableAutoConfiguration**

@EnableAutoConfiguration是由 @AutoConfigurationPackage和@Import(EnableAutoConfigurationImportSelector.class)这两个组成的

打开自动配置的功能,帮助SpringBoot应用将所有符合条件的@Configuration配置都加载到当前SpringBoot,并创建对应配置类的Bean,并把该Bean实体交给IoC容器进行管理。

@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })

如上所示可以关闭某个自动配置的选项,如关闭数据源自动配置功能

3、@ComponentScan

@ComponentScan注解是Spring组件扫描注解,默认就会装配标识了@Controller,@Service,@Repository,@Component注解的类到spring容器中

什么是 JavaConfig?JavaConfig 的优点?

JavaConfig就是使用注解来配置Bean,为 Spring IoC 容器的配置提供了纯Java 方法。它有助于避免使用 XML 配置。

使用 JavaConfig 的优点

1、面向对象的配置。javaConfig使用纯java代码的方式,可以充分利用复用、继承、多态等特性,例如一个配置类可以继承另一个,重写它的@Bean 方法等。

2、减少或消除 XML 配置

3、类型安全和重构友好

Spring Boot 自动配置原理是什么?

我们知道SpringBoot可以帮我们减少很多的配置,也肯定听过“约定大于配置”这么一句话,那SpringBoot是怎么做的呢?其实靠的就是@EnableAutoConfiguration注解。

简单来说,这个注解可以帮助我们自动载入应用程序所需要的所有默认配置。

发现有两个比较重要的注解

  • @AutoConfigurationPackage:自动配置包
  • @Import:给IOC容器导入组件

@AutoConfigurationPackage

我们可以发现,依靠的还是@Import注解

@AutoConfigurationPackage注解就是在默认的情况下就是将主配置类(@SpringBootApplication这个注解所在包及其子包里边的组件)扫描到Spring容器中

看起来跟@ComponentScan注解一样的作用,但是扫描的对象不一样,比如说,你用了Spring Data JPA,可能会在实体类上写@Entity注解。这个@Entity注解由 @AutoConfigurationPackage扫描并加载,而我们平时开发用的@Controller/@Service/@Component/@Repository这些注解是由@ComponentScan来扫描并加载的。

简单理解:这二者扫描的对象是不一样的。

@Import(AutoConfigurationImportSelector.class)

AutoConfigurationImportSelector这个类中有个selectImports方法,其中getCandidateConfigurations方法可以获取很多的配置信息

那这些配置信息哪里来的呢?

这里包装了一层,我们看到的只是通过SpringFactoriesLoader来加载获取到的配置信息,还没看到关键信息,继续进去:

解析

  • FACTORIES_RESOURCE_LOCATION(工厂资源加载路径)的值是META-INF/spring.factories
  • Spring启动的时候会扫描所有jar路径下的META-INF/spring.factories,将其文件包装成Properties对象
  • 从Properties对象获取到key值为EnableAutoConfiguration的数据,然后添加到容器里边。

最后我们会默认加载113个默认的配置类:

Spring Boot 自动配置原理是什么?

其中@EnableAutoConfiguration是关键(启用自动配置),这个注解里的

@Import(AutoConfigurationImportSelector.class)(auto 啊4 tou3)注解起核心作用,Spring启动的时候会扫描所有jar路径下的META-INF/spring.factories,将其文件包装成Properties对象,从Properties对象获取到key值为EnableAutoConfiguration的数据(这些数据都是SpringBoot默认配置好了的配置文件数据,例如Redis常用配置的数据,这样就不需要我们配置了,我们只要简单配置几个核心的数据就可以用Redis了,从而简化了配置),加载到IOC容器中,实现自动配置功能!

SpringBoot 常用的配置形式,按照配置生效的优先级从高到低排列?

  1. 命令行参数

  2. 操作系统环境变量

  3. 配置文件(YAML 文件、Properties 文件)

4.@Configuration 注解类上的@PropertySource 指定的配置文件

什么是 YAML?

YAML 是一种易读的数据序列化语言。它通常用于配置文件。与properties文件相比,YAML 文件具有结构化、有序、不容易混淆、分层、简洁的优点。

YAML 配置的优缺点?

优点

  • 简洁、分层、结构化、有序
  • 支持数组,数组中的元素可以是基本数据类型也可以是对象

yml中数组对象的写法

yml中数组的写法

缺点

不支持 @PropertySource 注解导入自定义的 YAML 配置。

补充:新建一个 person.properties 配置文件,用来存放 Person 类的配置信息。接下来使用 @ PropertySource 注解,来实现通过读取该配置,实现配置文件与 Java Bean 类的注入操作。

//person.properties
person.id=111
person.name=扛麻袋的少年
person.age=18
person.manager=true
person.birthday=2020/03/27
person.map.k1=v1
person.map.k2=v2
person.list=basketball,tennis,swim
person.address.province=山西省
person.address.distinct=晋中市
person.address.county=祁县

添加 @PropertySource(value = {“classpath:person.properties”})注解,通过 value 属性让它去加载指定路径配置文件。代码如下:

@Component
@ConfigurationProperties(prefix = "person")
@PropertySource(value = "classpath:person.properties",encoding = "UTF-8")    //读取指定路径配置文件
public class Person {

    private String id;

    private String name;

    private int age;

    private boolean isManager;

    private Date birthday;

    private Map<String, Object> map;

    private List<String> list;

    private Address address;

    /**
     * 省略get/set/toString() 方法
     */
 }

Spring Boot 是否可以使用 XML 配置 ?

Spring Boot 推荐使用 Java 配置而非 XML 配置,但是 Spring Boot 中也可以使用 XML 配置,通过@ImportResource 注解可以引入一个 XML 配置。

spring boot 核心配置文件是什么?bootstrap.properties 和application.properties 有何区别 ?

spring boot 核心配置文件是什么?

spring boot 核心的两个配置文件bootstrap(不 t s 抓 p) . yml和application . yml

bootstrap.properties 和application.properties 有何区别 ?

  • 两者主要区别是加载顺序不同,bootstrap.yml(bootstrap.properties)先加载,application.yml(application.properties)后加载,bootstrap 由父 ApplicationContext 加载,比 application 优先加载

  • bootstrap 里面的属性不能被覆盖,一旦 bootStrap 被加载,则内容不会被覆盖,即便后期加载的 application 的内容标签与 bootstrap 的标签一致,application 也不会覆盖 bootstrap, 而 application 里面的内容可以动态替换。

  • 应用场景不一样,application.yml主要用于spring boot 项目的自动化配置,bootstrap 配置文件有以下几个应用场景。

    • 使用 Spring Cloud Config 配置中心时,这时需要在 bootstrap 配置文件中添加连接到配置中心的配置属性来加载外部配置中心的配置信息;- 一些固定的不能被覆盖的属性- 一些加密/解密的场景;

补充

启动上下文时,Spring Cloud会创建一个BootStrap Context,作为Spring应用的Application Context的父上下文。初始化的时候,Bootstrap Context负责从外部源加载配置属性并解析配置。这两个上下文共享一个从外部获取的Environment。Bootstrap属性有高优先级,默认情况下,他们不会被本地配置覆盖。
Bootstrap Context和Application Context有着不同的约定,所以新增了一个bootstrap.properties,而不是使用application.properties。保证Bootstrap Context和Application Context配置的分离。

什么是 Spring Profiles?

实际开发中会同时存在dev、uat、prod等多套环境,这些环境共用一套代码逻辑,但却需要不同的配置。例如dev环境要连接测试数据库,而prod则需要连接生产数据库等等。profile最主要的目的就是可以区分不同的环境,进而对不同环境进行配置

当profile为default时,只使用application.yaml,SpringBoot默认Server端口为8080。将当前profile激活为dev时, SpringBoot就会额外加载application-dev.yaml 后合并到application.yaml中,若其中有相同的配置则覆盖掉。

如何在自定义端口上运行 Spring Boot 应用程序?

为了在自定义端口上运行 Spring Boot 应用程序,您可以在application.properties 中指定端口。server.port = 8090

如何实现 Spring Boot 应用程序的安全性?

为了实现 Spring Boot 的安全性,我们使用 spring-boot-starter-security 依赖项,并且必须添加安全配置。它只需要很少的代码。

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

由于springboot对starter依赖进行了自动化的配置,即约定大于配置,也就是带有starter的依赖在整合springboot时,在我们不做任何配置时,默认使用starter约定的配置,只有当我们进行自定义配置时,springboot才会使用我们的配置

通过配置类的方式实现security的自定义配置

通过配置类的方式实现security的自定义配置,配置类将必须扩展WebSecurityConfigurerAdapter 并覆盖其configure方法。

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
 
    //自定义配置URL资源的权限控制
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.
                //对所有请求进行权限认证
                authorizeRequests()
                //自定义配置请求地址权限
                .mvcMatchers("/test/security").permitAll()
                // permitAll()    对所有请求放行
                .mvcMatchers("/admin/security").hasRole("admin")
                .mvcMatchers("/user/security").hasRole("user")
                .mvcMatchers("/tUser/selectAll").anonymous()
                // anonymous()    允许匿名访问,登陆状态不能访问
 
                .anyRequest().authenticated()       //所有请求都需要进行认证
                .and()
                .formLogin()
                //.loginPage("login")       自定义登陆页面
                .permitAll()        //所有用户都可以访问
                .and()
                .logout()
                //.logoutUrl("logout")      自定义配置退出登陆页面
                .permitAll();
    }
 
 
    //自定义配置认证规则
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //spring内置了两种UserDetailManager实现,一种基于内存的InMemoryUserDetailsManager,另一种是基于数据库的JdbcUserDetailsManager
 
        auth.
                //使用内存中的InMemoryUserDetailsManager(内存用户管理器)
                inMemoryAuthentication()
                //不使用passwordEncoder密码加密
                .passwordEncoder(NoOpPasswordEncoder.getInstance())
                //在内存中给配置user用户
                .withUser("admin").password("admin").roles("admin")
                .and()
                //在内存中配置admin用户
                .withUser("user").password("user").roles("user");
 
    }
}

security配置类搞定之后,我们新建UserController和AdminController两个接口测试类,具体如下

@RestController
    @RequestMapping("/user")
    public class UserController {

        @GetMapping("/security")
        public String security(){
            return "user-spring-security登陆成功";
        }
    }

@RestController
    @RequestMapping("/admin")
    public class AdminController {

        @GetMapping("/security")
        public String security(){
            return "admin-spring-security登陆成功";
        }
    }

重新启动应用,并分别访问http://localhost/test/security、http://localhost/user/security、http://localhost/admin/security三个地址,我们会发现第一个地址不用登陆就能直接访问,第二个地址需要user角色权限,第三个地址需要admin角色权限;需要注意的是,当我们访问第二个地址并使用user角色登录之后,我们访问第三个地址会报403错误,其原因是浏览器在我们使用user登录时缓存了user的登录会话信息即session状态,所以当我们登录第三个地址时浏览器会以user的登录状态去访问admin角色下的接口,显然这是访问不到的。

基于注解的方式实现对接口中方法的权限认证

首先在SecurityConfig配置类中添加@EnableGlobalMethodSecurity(prePostEnabled = true) 注解开启该功能

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)      //开启基于方法的注解权限认证,默认为false
public class SecurityConfig extends WebSecurityConfigurerAdapter {

然后我们就可以在想要进行权限校验的方法上使用@PreAuthorize("hasAuthority('ROLE_user')")或者@PreAuthorize("hasRole('user')")进行相应的权限校验了。

特别说明:hasRole和hasAuthority基本上没有区别,主要差异在于hasRole会在我们添加的角色名称前添加ROLE_前缀,所以在数据库中的权限字符串需要加上 ROLE_ 前缀。即数据库中存储的用户角色如果是 ROLE_admin,这里就是 admin。hasAuthority和数据库一样就行

Spring Boot 中如何解决跨域问题 ?

跨域问题现象

been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource

上面的意思就是 你访问一个什么地址被CORS 协议阻止, 没有 在Hearder 里面发现 Access-Control-Allow-Origin 的参数的资源

跨域问题的原因

浏览器出于安全考虑,限制访问本站点以外的资源。

比如你有一个 网站 127.0.0.1:8080/ , 并且上面挂了一个页面 ,那么在这个页面中 ,你只访问本站点的资源不会受到限制,但是你如果访问其他站点,比如 127.0.0.1:8081 的资源就会受到限制。

什么是源和跨域

源(origin)就是协议、域名和端口号。

URL由协议、域名、端口和路径组成,如果两个URL的协议、域名和端口全部相同,则表示他们同源。否则,只要协议、域名、端口有任何一个不同就是跨域。

https://www.baidu.com/index.html进行跨域比较:

什么是同源策略?

同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。

同源策略又分为以下两种

  • DOM同源策略:禁止对不同源页面DOM 进行操作。这里主要场景是iframe跨域的情况,不同域名的iframe是限制互相访问的。
  • XMLHttpRequest同源策略:禁止使用XHR对象向不同源的服务器地址发起HTTP请求。

Spring Boot跨域问题解决方案

  1. 创建一个filter解决跨域

项目中前后端分离部署,页面和接口一般不是一个程序,所以需要解决跨域的问题。 我们使用cookie存放用户登录的信息,在spring拦截器进行权限控制,当权限不符合时,直接返回给用户固定的json结果。 当用户登录以后,正常使用;当用户退出登录状态时或者token过期时,由于拦截器和跨域的顺序有问题,出现了跨域的现象。 我们知道一个http请求,先走filter,到达servlet后才进行拦截器的处理,如果我们把cors放在filter里,就可以优先于权限拦截器执行。

@Configuration
public class CorsConfig {
​
    @Bean
    public CorsFilter corsFilter() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedOrigin("*");
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedMethod("*");
        corsConfiguration.setAllowCredentials(true);
        
        UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
        urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
        return new CorsFilter(urlBasedCorsConfigurationSource);
    }
​
}
  1. 基于WebMvcConfigurer配置加入Cors的跨域

跨域可以在前端通过 JSONP 来解决,但是 JSONP 只可以发送 GET 请求,无法发送其他类型的请求,在 RESTful 风格的应用中,就显得非常鸡肋,因此我们推荐在后端通过 (CORS,Cross-origin resource sharing) 来解决跨域问题。这种解决方案并非 Spring Boot 特有的,在传统的 SSM 框架中,就可以通过 CORS 来解决跨域问题,只不过之前我们是在 XML 文件中配置 CORS ,现在可以通过实现WebMvcConfigurer接口然后重写addCorsMappings方法解决跨域问题。

@Configuration
public class CorsConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowCredentials(true)
                .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
                .maxAge(3600);
    }

}
  1. controller配置CORS

controller方法的CORS配置,您可以向@RequestMapping注解处理程序方法添加一个@CrossOrigin注解,以便启用CORS(默认情况下,@CrossOrigin允许在@RequestMapping注解中指定的所有源和HTTP方法):

@RestController
@RequestMapping("/account")
public class AccountController {
 
    @CrossOrigin
    @GetMapping("/{id}")
    public Account retrieve(@PathVariable Long id) {
        // ...
    }
 
    @DeleteMapping("/{id}")
    public void remove(@PathVariable Long id) {
        // ...
    }
}

@CrossOrigin中的参数

@CrossOrigin 表示所有的URL均可访问此资源

@CrossOrigin(origins = “http://127.0.0.1:8080”)//表示只允许这一个url可以跨域访问这个controller

代码说明:@CrossOrigin这个注解用起来很方便,这个可以用在方法上,也可以用在类上。如果你不设置他的value属性,或者是origins属性,就默认是可以允许所有的URL/域访问。

  • value属性可以设置多个URL。
  • origins属性也可以设置多个URL。
  • maxAge属性指定了准备响应前的缓存持续的最大时间。就是探测请求的有效期。
  • allowCredentials属性表示用户是否可以发送、处理 cookie。默认为false
  • allowedHeaders 属性表示允许的请求头部有哪些。
  • methods 属性表示允许请求的方法,默认get,post,head。

@CrossOrigin不起作用的原因

1、是springMVC的版本要在4.2或以上版本才支持@CrossOrigin

2、非@CrossOrigin没有解决跨域请求问题,而是不正确的请求导致无法得到预期的响应,导致浏览器端提示跨域问题。

3、在Controller注解上方添加@CrossOrigin注解后,仍然出现跨域问题,解决方案之一就是:在@RequestMapping注解中没有指定Get、Post方式,具体指定后,问题解决。

@CrossOrigin
@RestController
public class person{
    
    @RequestMapping(method = RequestMethod.GET)
    public String add() {
        // 若干代码
    }
}

什么是 CSRF 攻击?

CSRF(Cross-site request forgery)也被称为 one-click attack或者 session riding,中文全称是叫跨站请求伪造。一般来说,攻击者通过伪造用户的浏览器的请求,向访问一个用户自己曾经认证访问过的网站发送出去,使目标网站接收并误以为是用户的真实操作而去执行命令。常用于盗取账号、转账、发送虚假消息等。攻击者利用网站对请求的验证漏洞而实现这样的攻击行为,网站能够确认请求来源于用户的浏览器,却不能验证请求是否源于用户的真实意愿下的操作行为。

Spring Boot 中的监视器是什么?

监视器就是一个类似现实生活中的监控,但是它监控的是程序内部运行情况。Spring Boot自带监控组件—Actuator,它就负责监控程序的健康状况、Bean加载情况、环境变量、日志信息、线程信息等,Actuator的核心是端点(Endpoint),它用来监视、提供应用程序的信息,Spring Boot提供的spring-boot-actuator组件中已经内置了非常多的Endpoint(health、info、beans、metrics、httptrace、shutdown等),每个端点都可以启用和禁用。

如何在 Spring Boot 中禁用 Actuator 端点安全性?

可以使用management.security.enabled = false来禁用安全性。只有在执行机构端点在防火墙后访问时,才建议禁用安全性。

我们如何监视所有 Spring Boot 微服务?

Spring Boot 提供监视器端点来监控。这些端点对于获取有关应用程序的信息(如它们是否已启动)以及它们的组件(如数据库等)是否正常运行很有帮助。但是,使用监视器的一个主要缺点或困难是,我们必须单独打开应用程序的端点来了解其状态或健康状况。想象一下涉及 50 个应用程序的微服务,管理员将不得不击中所有 50 个应用程序的执行终端。为了帮助我们处理这种情况,我们将使用位于 GitHub - codecentric/spring-boot-admin: Admin UI for administration of spring boot applications 的开源项目。 它建立在 Spring Boot Actuator 之上,它提供了一个 Web UI,使我们能够可视化多个应用程序的度量。

如何集成 Spring Boot 和 ActiveMQ?

Spring Boot针对ActiveMQ专门提供了spring-boot-starter-activemq,用来支持ActiveMQ在Spring Boot的自动集成配置。在此基础上我们可以很轻易的进行集成和使用。

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

什么是 Swagger?你用 Spring Boot 实现了它吗?

Swagger 是一个可视化 RESTful 风格的 Web 服务框架,支持 API 自动生成同步的在线文档:使用 Swagger 后可以直接通过代码生成文档,不再需要自己手动编写接口文档了,

Swagger 生成的文档还支持在线测试。参数和格式都定好了,直接在界面上输入参数对应的值即可在线测试接口。

@Api:用在请求的类上,表示对类的说明
    tags="说明该类的作用,可以在UI界面上看到的注解"
    value="该参数没什么意义,在UI界面上也看到,所以不需要配置"
 
 
@ApiOperation:用在请求的方法上,说明方法的用途、作用
    value="说明方法的用途、作用"
    notes="方法的备注说明"
 
 
@ApiImplicitParams:用在请求的方法上,表示一组参数说明
    @ApiImplicitParam:用在@ApiImplicitParams注解中,指定一个请求参数的各个方面
        name:参数名
        value:参数的汉字说明、解释
        required:参数是否必须传
        paramType:参数放在哪个地方
            · header --> 请求参数的获取:@RequestHeader
            · query --> 请求参数的获取:@RequestParam
            · path(用于restful接口)--> 请求参数的获取:@PathVariable
            · body(不常用)
            · form(不常用)    
        dataType:参数类型,默认String,其它值dataType="Integer"       
        defaultValue:参数的默认值
 
 
@ApiResponses:用在请求的方法上,表示一组响应
    @ApiResponse:用在@ApiResponses中,一般用于表达一个错误的响应信息
        code:数字,例如400
        message:信息,例如"请求参数没填好"
        response:抛出异常的类
 
 
@ApiModel:用于响应类上,表示一个返回响应数据的信息
            (这种一般用在post创建的时候,使用@RequestBody这样的场景,
            请求参数无法使用@ApiImplicitParam注解进行描述的时候)
    @ApiModelProperty:用在属性上,描述响应类的属性

Swagger使用案例

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.9.2</version>
</dependency>
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.9.2</version>
</dependency>
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

/**
 1. swagger配置类
 */
@Configuration
@EnableSwagger2
public class SwaggerConfig {
    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                //是否开启 (true 开启  false隐藏。生产环境建议隐藏)
                //.enable(false)
                .select()
                //扫描的路径包,设置basePackage会将包下的所有被@Api标记类的所有方法作为api
                .apis(RequestHandlerSelectors.basePackage("com.mcy.springbootswagger.controller"))
                //指定路径处理PathSelectors.any()代表所有的路径
                .paths(PathSelectors.any())
                .build();
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                //设置文档标题(API名称)
                .title("SpringBoot中使用Swagger2接口规范")
                //文档描述
                .description("接口说明")
                //服务条款URL
                .termsOfServiceUrl("http://localhost:8080/")
                //版本号
                .version("1.0.0")
                .build();
    }
}

注】@Configuration注解,配置文件,就不多解释了。@EnableSwagger2的作用是启用Swagger2相关功能。

Docket对象包含三个方面信息:

  1. 整个API的描述信息,即ApiInfo对象包括的信息,这部分信息会在页面上展示。
  2. 指定生成API文档的包名。
  3. 指定生成API的路径。
import com.mcy.springbootswagger.User.User;
import com.mcy.springbootswagger.service.UserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/user")
//说明接口文件
@Api(value = "测试接口", tags = "用户管理相关的接口", description = "用户测试接口")
public class UserController {
    @Autowired
    private UserService userService;

    /**
     * 保存数据
     * @param user
     * @return
     */
    @PostMapping(value = "/save")
    //方法参数说明,name参数名;value参数说明,备注;dataType参数类型;required 是否必传;defaultValue 默认值
    @ApiImplicitParam(name = "user", value = "新增用户数据")
    //说明是什么方法(可以理解为方法注释)
    @ApiOperation(value = "添加用户", notes = "添加用户")
    public String saveUser(User user){
        userService.save(user);
        return "保存成功";
    }

    /**
     * 根据id查询用户
     * @param id
     * @return
     */
    @GetMapping(value = "findById")
    @ApiOperation(value = "根据id获取用户信息", notes = "根据id查询用户信息")
    public User getUser(Integer id){
        return userService.findById(id);
    }

    @DeleteMapping(value = "deleteById")
    @ApiOperation(value = "根据id删除数据", notes = "删除用户")
    public String delete(Integer id){
        userService.deleteById(id);
        return "删除成功";
    }
}

运行项目,输入http://localhost:8080/swagger-ui.html访问Swagger页面,页面如下:

Swagger注解详解:swagger2 注解说明 ( @ApiImplicitParams )_微风--轻许--的博客-CSDN博客_apiimplicitparams

前后端分离如何维护接口文档 ?

在 Spring Boot 中,这个问题常见的解决方案是 Swagger ,使用 Swagger 我们可以快速生成一个在线接口文档,控制器的内容一旦发生变化,文档就会自动更新,所有开发工程师访问这一个在线网站就可以获取到最新的接口文档,非常方便。

如何重新加载 Spring Boot 上的更改,而无需重新启动服务器?(热部署)

这可以使用 DEV 工具来实现。通过这种依赖关系,您可以节省任何更改,嵌入式tomcat 将重新启动。Spring Boot 有一个开发工具(DevTools)模块,它有助于提高开发人员的生产力。Java 开发人员面临的一个主要挑战是将文件更改自动部署到服务器并自动重启服务器。开发人员可以重新加载 Spring Boot 上的更改,而无需重新启动服务器。这将消除每次手动部署更改的需要。Spring Boot 在发布它的第一个版本时没有这个功能。这是开发人员最需要的功能。DevTools 模块完全满足开发人员的需求。该模块将在生产环境中被禁用。它还提供 H2 数据库控制台以更好地测试应用程序。

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

你使用了哪些 starter maven 依赖项?

  • spring-boot-starter-web 嵌入tomcat和web开发需要servlet与jsp支持
  • spring-boot-starter-data-redis redis数据库支持
  • spring-boot-starter-activemq 支持 activemq
  • mybatis-spring-boot-starter 第三方的mybatis集成starter

这有助于增加更少的依赖关系,并减少版本的冲突。

Spring Boot 中的 starter 到底是什么 ?

Starters可以理解为启动器,它包含了一系列可以集成到应用里面的依赖包,你可以一站式集成Spring及其他技术,而不需要到处找依赖包。Starters包含了许多项目中需要用到的依赖,它们能快速持续的运行,都是一系列得到支持的管理传递性依赖。

和自动配置一样,Spring Boot Starter的目的也是简化配置,而Spring Boot Starter解决的是依赖管理配置复杂的问题,有了它,当我需要构建一个Web应用程序时,不必再遍历所有的依赖包,一个一个地添加到项目的依赖管理中,而是只需要一个配置spring-boot-starter-web, 同理,如果想引入持久化功能,可以配置spring-boot-starter-data-jpa:

spring-boot-starter-parent 有什么用 ?

这里面进行了很多的默认配置

1、定义了 Java 编译版本为 1.8 。

2、使用 UTF-8 格式编码。

3、继承自 spring-boot-dependencies,这个里边定义了依赖的版本,也正是因为继承了这个依赖,所以我们在写依赖时才不需要写版本号。

4、执行打包操作的配置。

5、自动化的资源过滤。

6、自动化的插件配置。

7、针对 application.properties 和 application.yml 的资源过滤,包括通过 profile 定义的不同环境的配置文件, 例如 application-dev.properties 和 application-dev.yml。

Spring Boot 打成的 jar 和普通的 jar 有什么区别 ?

1、Spring Boot 中默认打包成的 jar 叫做 可执行 jar,这种 jar 不可以被其他项目依赖,即使强制依赖,也无法获取里边的类。但是普通的 jar 主要是被其他应用依赖,但是可执行 jar 并不是 Spring Boot 独有的,Java 工程本身就可以打包成可执行 jar

2、普通的 jar 不可以通过 java -jar xxx.jar 命令执行,Spring Boot 打成的 jar 可以通过 java -jar xxx.jar 命令执行执行

3、主要是两者的结构不同。普通的 jar 包,解压后直接就是包名,包里就是我们的代码,而 Spring Boot 打包成的可执行 jar 解压后,在 \BOOT-INF\classes 目录下才是我们的代码,因此无法被直接引用。如果非要引用,可以在 pom.xml 文件中增加配置,将 Spring Boot 项目打包成两个 jar ,一个可执行, 一个可引用。

运行 Spring Boot 有哪几种方式?

运行springboot工程四种方法:

1、直接运行启动类

2、利用mvn spring-boot:run运行

3、打包成jar包后,利用java -jar xxx.jar运行

4、打包成war包后,利用java -jar xxx.war运行

讲解地址:运行SpringBoot工程的四种方法 - 简书

Spring Boot 需要独立的容器运行吗?

可以不需要,内置了 Tomcat/ Jetty 等容器。

开启 Spring Boot 特性有哪几种方式?

1、继承spring-boot-starter-parent项目

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.6.RELEASE</version>
</parent>

这个时候再导入我们需要的springboot starter时,就可以忽略版本号:

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

2、导入spring-boot-dependencies项目依赖

<dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-dependencies</artifactId>
        <version>1.5.4.RELEASE</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
</dependencyManagement>

这个时候再导入我们需要的springboot starter时,就可以忽略版本号:

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

如何使用 Spring Boot 实现异常处理?

1、使用 @ExceptionHandler 注解处理局部异常(只能处理当前controller中的ArithmeticException和NullPointerException异常,缺点就是只能处理单个controller的异常)

@Controller
public class ExceptionHandlerController {
    
    @RequestMapping("/excep")
    public String exceptionMethod(Model model) throws Exception {
        String a=null;
        System.out.println(a.charAt(1));
        int num = 1/0;
        model.addAttribute("message", "没有抛出异常");
        return "index";
    }
    
    @ExceptionHandler(value = {ArithmeticException.class,NullPointerException.class})
    public String arithmeticExceptionHandle(Model model, Exception e) {
        model.addAttribute("message", "@ExceptionHandler" + e.getMessage());
        return "index";
    }
}

2、使用 @ControllerAdvice + @ExceptionHandler 注解处理全局异常(value后面可以填写数组),Spring 提供了一种使用 ControllerAdvice 处理异常的非常有用的方法。 我们通过实现一个 ControlerAdvice 类,来处理控制器类抛出的所有异常。

@ControllerAdvice
public class ControllerAdviceException {
    
    @ExceptionHandler(value = {NullPointerException.class})
    public String NullPointerExceptionHandler(Model model, Exception e) {
        model.addAttribute("message", "@ControllerAdvice + @ExceptionHandler :" + e.getMessage());
        return "index";
    }
}

3、配置 SimpleMappingExceptionResolver 类处理异常(配置类)

@Configuration
public class SimpleMappingException {
    @Bean
    public SimpleMappingExceptionResolver getSimpleMappingExceptionResolver(){

        SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver();
        Properties mappings = new Properties();
        //第一个参数为异常全限定名,第二个为跳转视图名称
        mappings.put("java.lang.NullPointerException", "index");
        mappings.put("java.lang.ArithmeticException", "index");
        //设置异常与视图映射信息的
        resolver.setExceptionMappings(mappings);
        return resolver;
    }
}

4、实现 HandlerExceptionResolver 接口处理异常

@Configuration
public class HandlerException implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {

        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("message", "实现HandlerExceptionResolver接口");

        //判断不同异常类型,做不同视图跳转
        if(ex instanceof NullPointerException){
            modelAndView.setViewName("index");
        }
        if(ex instanceof ArithmeticException){
            modelAndView.setViewName("index");
        }
        return modelAndView;
    }
}

如何使用 Spring Boot 实现分页和排序?

使用 Spring Boot 实现分页非常简单。使用 Spring Data-JPA 可以实现将可分页的传递给存储库方法。

讲解地址:Spring Boot入门(第十三章):排序与分页查询 - 简书

微服务中如何实现 session 共享 ?

在微服务中,一个完整的项目被拆分成多个不相同的独立的服务,各个服务独立部署在不同的服务器上,各自的 session 被从物理空间上隔离开了,但是经常,我们需要在不同微服务之间共享 session ,常见的方案就是 Spring Session + Redis 来实现 session 共享。将所有微服务的 session 统一保存在 Redis 上,当各个微服务对 session 有相关的读写操作时,都去操作 Redis 上的 session 。这样就实现了 session 共享,Spring Session 基于 Spring 中的代理过滤器实现,使得 session 的同步操作对开发人员而言是透明的,非常简便。

Spring Boot 中如何实现定时任务 ?

定时任务也是一个常见的需求,Spring Boot 中对于定时任务的支持主要还是来自 Spring 框架。

在 Spring Boot 中使用定时任务主要有两种不同的方式

  • 一个就是使用 Spring 中的 @Scheduled 注解
  • 另一个则是使用第三方框架 Quartz。

使用 Spring 中的 @Scheduled 的方式主要通过 @Scheduled 注解来实现。使用 Quartz ,则按照 Quartz 的方式,定义 Job 和 Trigger 即可。

Starters的命名和分类

Starters命名

Spring Boot官方的启动器都是以spring-boot-starter-命名的,代表了一个特定的应用类型。第三方的启动器不能以spring-boot开头命名,它们都被Spring Boot官方保留。一般一个第三方的应该这样命名,像mybatis的mybatis-spring-boot-starter。

Starters分类

Spring Boot应用类启动器

Spring Boot生产启动器

Spring Boot技术类启动器

如何在Spring Boot启动的时候运行一些特定的代码?

如果你想在Spring Boot启动的时候运行一些特定的代码,你可以实现接口ApplicationRunner或者CommandLineRunner,这两个接口实现方式一样,它们都只提供了一个run方法。

ApplicatonRunner和CommandLineRunner的区别

  • ApplicatonRunner接口的方法参数ApplicationArguments(啊4 gui3 men3 s)(是个对象)比CommandLineRunner接口的方法参数(是个可以接收多个string的参数)功能更强大。ApplicatonRunner接口的方法参数ApplicationArguments既可以获取参数的字符串,也可以直接获取key;CommandLineRunner接口的方法参数只能获取参数的字符串。
  • ApplicationRunner接口的实现方法比CommandLineRunner接口的实现方法前执行(当然也可以设置@Order的值来决定谁先执行)
标签: spring boot spring java

本文转载自: https://blog.csdn.net/qq_50954361/article/details/127919048
版权归原作者 骚戴 所有, 如有侵权,请联系我们删除。

“Spring Boot面试题”的评论:

还没有评论