Spring Boot 进阶,Spring Boot面试题高频出处

花了14天做了一张spring脑图,所有spring知识点都汇总了!2020最新Spring全家桶高频面试题 花了14天做了一张spring脑图,所有spring知识点都汇总了!2020最新Spring全家桶高频面试题,现在分享给大家。spring知识脑图放在文末。 对于那些想面试高级 Java 岗位的同学来说,spring是一大绕不过的坎!剩下针对实际工作的题目就属于真正的本事了,热门技术的细节和难点成为了面试时主要考察的内容。 这里总结了 70 道 Spring 相关面试题,有的很基础,有的很细节,大家可以评估一下自己掌握的情况。 这里把重要的知识点都写出来了,不管是核心知识点也好还是面试题也好,让大家对知识框 阅读详情

上一篇带领大家初步了解了如何使用 Spring Boot 搭建框架,通过 Spring Boot 和传统的 SpringMVC 架构的对比,我们清晰地发现 Spring Boot 的好处,它使我们的代码更加简单,结构更加清晰。Spring Boot面试题

从这一篇开始,我将带领大家更加深入的认识 Spring Boot ,将 Spring Boot 涉及到东西进行拆解,从而了解 Spring Boot 的方方面面。学完本文后,读者可以基于 Spring Boot 搭建更加复杂的系统框架。Spring Boot面试题

我们知道,Spring Boot 是一个大容器,它将很多第三方框架都进行了集成,我们在实际项目中用到哪个模块,再引入哪个模块。比如我们项目中的持久化框架用 MyBatis,则在 pom.xml 添加如下依赖:Spring Boot面试题

<dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.1.1</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.40</version>
        </dependency>

yaml/properties 文件Spring Boot面试题

我们知道整个 Spring Boot 项目只有一个配置文件,那就是 application.yml,Spring Boot 在启动时,就会从 application.yml 中读取配置信息,并加载到内存中。上一篇我们只是粗略的列举了几个配置项,其实 Spring Boot 的配置项是很多的,本文我们将学习在实际项目中常用的配置项(注:为了方便说明,配置项均以 properties 文件的格式写出,后续的实际配置都会写成 yaml 格式)。Spring Boot面试题

配置项说明举例
server.port应用程序启动端口server.port=8080,定义应用程序启动端口为 8080
server.servlet.context-path应用程序上下文server.servlet.context-path=/api,则访问地址为:http://ip:port/api
spring.servlet.multipart.maxFileSize最大文件上传大小,-1为不限制spring.servlet.multipart.maxFileSize=-1
spring.jpa.database数据库类型spring.jpa.database=MYSQL,指定数据库为mysql
spring.jpa.properties.hibernate.dialecthql方言spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
spring.datasource.url数据库连接字符串spring.datasource.url=jdbc:mysql://localhost:3306/database?useUnicode=true&characterEncoding=UTF-8&useSSL=true
spring.datasource.username数据库用户名spring.datasource.username=root
spring.datasource.password数据库密码spring.datasource.password=root
spring.datasource.driverClassName数据库驱动spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.jpa.showSql控制台是否打印 SQL 语句spring.jpa.showSql=true

下面是我参与的某个项目的 application.yml 配置文件内容:Spring Boot面试题

server:
  port: 8080
  servlet:
    context-path: /api
  tomcat:
    basedir: /data/tmp
    max-threads: 1000
    min-spare-threads: 50
  connection-timeout: 5000
spring:
  profiles:
    active: dev
  servlet:
    multipart:
      maxFileSize: -1
  datasource:
    url: jdbc:mysql://localhost:3306/database?useUnicode=true&characterEncoding=UTF-8&useSSL=true
    username: root
    password: root
    driverClassName: com.mysql.jdbc.Driver
  jpa:
    database: MYSQL
    showSql: true
    hibernate:
      namingStrategy: org.hibernate.cfg.ImprovedNamingStrategy
    properties:
      hibernate:
        dialect: org.hibernate.dialect.MySQL5Dialect
mybatis:
  configuration:
     #配置项:开启下划线到驼峰的自动转换. 作用:将数据库字段根据驼峰规则自动注入到对象属性
     map-underscore-to-camel-case: true

以上列举了常用的配置项,所有配置项信息都可以在官网中找到,本课程 就不一一列举了。
Spring Boot面试题

多环境配置Spring Boot面试题

在一个企业级系统中,我们可能会遇到这样一个问题:开发时使用开发环境,测试时使用测试环境,上线时使用生产环境。每个环境的配置都可能不一样,比如开发环境的数据库是本地地址,而测试环境的数据库是测试地址。那我们在打包的时候如何生成不同环境的包呢?

这里的解决方案有很多:Spring Boot面试题

  1. 每次编译之前手动把所有配置信息修改成当前运行的环境信息。这种方式导致每次都需要修改,相当麻烦,也容易出错。
  2. 利用 Maven,在 pom.xml 里配置多个环境,每次编译之前将 settings.xml 里面修改成当前要编译的环境 ID。这种方式会事先设置好所有环境,缺点就是每次也需要手动指定环境,如果环境指定错误,发布时是不知道的。
  3. 第三种方案就是本文重点介绍的,也是作者强烈推荐的方式。
    Spring Boot面试题
    首先,创建 application.yml 文件,在里面添加如下内容:
spring:
  profiles:
    active: dev

含义是指定当前项目的默认环境为 dev,即项目启动时如果不指定任何环境,Spring Boot 会自动从 dev 环境文件中读取配置信息。我们可以将不同环境都共同的配置信息写到这个文件中。

然后创建多环境配置文件,文件名的格式为:application-{profile}.yml,其中,{profile} 替换为环境名字,如 application-dev.yml,我们可以在其中添加当前环境的配置信息,如添加数据源:

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/database?useUnicode=true&characterEncoding=UTF-8&useSSL=true
    username: root
    password: root
    driverClassName: com.mysql.jdbc.Driver

这样,我们就实现了多环境的配置,每次编译打包我们无需修改任何东西,编译为 jar 文件后,运行命令:

java -jar api.jar --spring.profiles.active=dev

其中 --spring.profiles.active 就是我们要指定的环境。Spring Boot面试题

常用注解Spring Boot面试题

我们知道,Spring Boot 主要采用注解的方式,在《第01课:Spring Boot 入门》一节的入门实例中,我们也用到了一些注解。

本文,我将详细介绍在实际项目中常用的注解。

@SpringBootApplication Spring Boot面试题

我们可以注意到 Spring Boot 支持 main 方法启动,在我们需要启动的主类中加入此注解,告诉 Spring Boot,这个类是程序的入口。如:

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

如果不加这个注解,程序是无法启动的。Spring Boot面试题

我们查看下 SpringBootApplication 的源码,源码如下:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
        @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
        @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {

    /**
     * Exclude specific auto-configuration classes such that they will never be applied.
     * @return the classes to exclude
     */
    @AliasFor(annotation = EnableAutoConfiguration.class, attribute = "exclude")
    Class<?>[] exclude() default {};

    /**
     * Exclude specific auto-configuration class names such that they will never be
     * applied.
     * @return the class names to exclude
     * @since 1.3.0
     */
    @AliasFor(annotation = EnableAutoConfiguration.class, attribute = "excludeName")
    String[] excludeName() default {};

    /**
     * Base packages to scan for annotated components. Use {@link #scanBasePackageClasses}
     * for a type-safe alternative to String-based package names.
     * @return base packages to scan
     * @since 1.3.0
     */
    @AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
    String[] scanBasePackages() default {};

    /**
     * Type-safe alternative to {@link #scanBasePackages} for specifying the packages to
     * scan for annotated components. The package of each class specified will be scanned.
     * <p>
     * Consider creating a special no-op marker class or interface in each package that
     * serves no purpose other than being referenced by this attribute.
     * @return base packages to scan
     * @since 1.3.0
     */
    @AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
    Class<?>[] scanBasePackageClasses() default {};

}

在这个注解类上有 3 个注解,如下:Spring Boot面试题

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
        @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
        @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })

因此,我们可以用这三个注解代替 SpringBootApplication,如:

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

其中,SpringBootConfiguration 表示 Spring Boot 的配置注解,EnableAutoConfiguration 表示自动配置,ComponentScan 表示 Spring Boot 扫描 Bean 的规则,比如扫描哪些包。
Spring Boot面试题Spring Boot面试题

@Configuration Spring Boot面试题Spring Boot面试题

加入了这个注解的类被认为是 Spring Boot 的配置类,我们知道可以在 application.yml 设置一些配置,也可以通过代码设置配置。Spring Boot面试题

如果我们要通过代码设置配置,就必须在这个类上标注 Configuration 注解。如下代码:

@Configuration
public class WebConfig extends WebMvcConfigurationSupport{

    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
        super.addInterceptors(registry);
        registry.addInterceptor(new ApiInterceptor());
    }
}

不过 Spring Boot 官方推荐 Spring Boot 项目用 SpringBootConfiguration 来代替 Configuration。

@Bean Spring Boot面试题

这个注解是方法级别上的注解,主要添加在 @Configuration 或 @SpringBootConfiguration 注解的类,有时也可以添加在 @Component 注解的类。它的作用是定义一个Bean。Spring Boot面试题

请看下面代码:

    @Bean
    public ApiInterceptor interceptor(){
        return new ApiInterceptor();
    }

那么,我们可以在 ApiInterceptor 里面注入其他 Bean,也可以在其他 Bean 注入这个类。

@Value Spring Boot面试题

通常情况下,我们需要定义一些全局变量,都会想到的方法是定义一个 public static 变量,在需要时调用,是否有其他更好的方案呢?答案是肯定的。下面请看代码:Spring Boot面试题

    @Value("${server.port}")
    String port;
    @RequestMapping("/hello")
    public String home(String name) {
        return "hi "+name+",i am from port:" +port;
    }

其中,server.port 就是我们在 application.yml 里面定义的属性,我们可以自定义任意属性名,通过 @Value 注解就可以将其取出来。

它的好处不言而喻:

  1. 定义在配置文件里,变量发生变化,无需修改代码。
  2. 变量交给Spring来管理,性能更好。

注: 本课程默认针对于对 SpringMVC 有所了解的读者,Spring Boot 本身基于 Spring 开发的,因此,本文不再讲解其他 Spring 的注解。

注入任何类 Spring Boot面试题

本节通过一个实际的例子来讲解如何注入一个普通类,并且说明这样做的好处。Spring Boot面试题

假设一个需求是这样的:项目要求使用阿里云的 OSS 进行文件上传。Spring Boot面试题

我们知道,一个项目一般会分为开发环境、测试环境和生产环境。OSS 文件上传一般有如下几个参数:appKey、appSecret、bucket、endpoint 等。不同环境的参数都可能不一样,这样便于区分。按照传统的做法,我们在代码里设置这些参数,这样做的话,每次发布不同的环境包都需要手动修改代码。Spring Boot面试题

这个时候,我们就可以考虑将这些参数定义到配置文件里面,通过前面提到的 @Value 注解取出来,再通过 @Bean 将其定义为一个 Bean,这时我们只需要在需要使用的地方注入该 Bean 即可。Spring Boot面试题

首先在 application.yml 加入如下内容:Spring Boot面试题

oss:
  appKey: 1
  appSecret: 1
  bucket: lynn
  endPoint: https://www.aliyun.com

其次创建一个普通类:

public class Aliyun {
    
    private String appKey;
    
    private String appSecret;
    
    private String bucket;
    
    private String endPoint;
    
    public static class Builder{

        private String appKey;

        private String appSecret;

        private String bucket;

        private String endPoint;
        
        public Builder setAppKey(String appKey){
            this.appKey = appKey;
            return this;
        }
        
        public Builder setAppSecret(String appSecret){
            this.appSecret = appSecret;
            return this;
        }
        
        public Builder setBucket(String bucket){
            this.bucket = bucket;
            return this;
        }
        
        public Builder setEndPoint(String endPoint){
            this.endPoint = endPoint;
            return this;
        }
        
        public Aliyun build(){
            return new Aliyun(this);
        }
    }
    
    public static Builder options(){
        return new Aliyun.Builder();
    }
    
    private Aliyun(Builder builder){
        this.appKey = builder.appKey;
        this.appSecret = builder.appSecret;
        this.bucket = builder.bucket;
        this.endPoint = builder.endPoint;
    }

    public String getAppKey() {
        return appKey;
    }

    public String getAppSecret() {
        return appSecret;
    }

    public String getBucket() {
        return bucket;
    }

    public String getEndPoint() {
        return endPoint;
    }
}

然后在 @SpringBootConfiguration 注解的类添加如下代码:

    @Value("${oss.appKey}")
    private String appKey;
    @Value("${oss.appSecret}")
    private String appSecret;
    @Value("${oss.bucket}")
    private String bucket;
    @Value("${oss.endPoint}")
    private String endPoint;
    
    @Bean
    public Aliyun aliyun(){
        return Aliyun.options()
                .setAppKey(appKey)
                .setAppSecret(appSecret)
                .setBucket(bucket)
                .setEndPoint(endPoint)
                .build();
    }

最后在需要的地方注入这个 Bean 即可:

    @Autowired
    private Aliyun aliyun;

以上代码其实并不完美,如果增加一个属性,就需要在 Aliyun 类新增一个字段,还需要在 Configuration 类里注入它,扩展性不好,那么我们有没有更好的方式呢?

答案是肯定的,我们可以利用 ConfigurationProperties 注解更轻松地将配置信息注入到实体中。

1.创建实体类 AliyunAuto,并编写以下代码:

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties(prefix = "oss")
public class AliyunAuto {

    private String appKey;

    private String appSecret;

    private String bucket;

    private String endPoint;

    public String getAppKey() {
        return appKey;
    }

    public void setAppKey(String appKey) {
        this.appKey = appKey;
    }

    public String getAppSecret() {
        return appSecret;
    }

    public void setAppSecret(String appSecret) {
        this.appSecret = appSecret;
    }

    public String getBucket() {
        return bucket;
    }

    public void setBucket(String bucket) {
        this.bucket = bucket;
    }

    public String getEndPoint() {
        return endPoint;
    }

    public void setEndPoint(String endPoint) {
        this.endPoint = endPoint;
    }

    @Override
    public String toString() {
        return "AliyunAuto{" +
                "appKey='" + appKey + '\'' +
                ", appSecret='" + appSecret + '\'' +
                ", bucket='" + bucket + '\'' +
                ", endPoint='" + endPoint + '\'' +
                '}';
    }
}

其中,ConfigurationProperties 指定配置文件的前缀属性,实体具体字段和配置文件字段名一致,如在上述代码中,字段为 appKey,则自动获取 oss.appKey 的值,将其映射到 appKey 字段中,这样就完成了自动的注入。如果我们增加一个属性,则只需要修改 Bean 和配置文件即可,不用显示注入。

拦截器

我们在提供 API 的时候,经常需要对 API 进行统一的拦截,比如进行接口的安全性校验。

本节,我会讲解 Spring Boot 是如何进行拦截器设置的,请看接下来的代码。

创建一个拦截器类:ApiInterceptor,并实现 HandlerInterceptor 接口:

public class ApiInterceptor implements HandlerInterceptor {
    //请求之前
    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
        System.out.println("进入拦截器");
        return true;
    }
    //请求时
    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {

    }
    //请求完成
    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {

    }
}

@SpringBootConfiguration 注解的类继承 WebMvcConfigurationSupport 类,并重写 addInterceptors 方法,将 ApiInterceptor 拦截器类添加进去,代码如下:

@SpringBootConfiguration
public class WebConfig extends WebMvcConfigurationSupport{

    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
        super.addInterceptors(registry);
        registry.addInterceptor(new ApiInterceptor());
    }
}

异常处理

我们在 Controller 里提供接口,通常需要捕捉异常,并进行友好提示,否则一旦出错,界面上就会显示报错信息,给用户一种不好的体验。最简单的做法就是每个方法都使用 try catch 进行捕捉,报错后,则在 catch 里面设置友好的报错提示。如果方法很多,每个都需要 try catch,代码会显得臃肿,写起来也比较麻烦。

我们可不可以提供一个公共的入口进行统一的异常处理呢?当然可以。方法很多,这里我们通过 Spring 的 AOP 特性就可以很方便的实现异常的统一处理。实现方法很简单,只需要在 Controller 类添加以下代码即可。

    @ExceptionHandler
    public String doError(Exception ex) throws Exception{
        ex.printStackTrace();
        return ex.getMessage();
    }

其中,在 doError 方法上加入 @ExceptionHandler 注解即可,这样,接口发生异常会自动调用该方法。

这样,我们无需每个方法都添加 try catch,一旦报错,则会执行 handleThrowing 方法。

优雅的输入合法性校验

为了接口的健壮性,我们通常除了客户端进行输入合法性校验外,在 Controller 的方法里,我们也需要对参数进行合法性校验,传统的做法是每个方法的参数都做一遍判断,这种方式和上一节讲的异常处理一个道理,不太优雅,也不易维护。

其实,SpringMVC 提供了验证接口,下面请看代码:

@GetMapping("authorize")
public void authorize(@Valid AuthorizeIn authorize, BindingResult ret){
    if(result.hasFieldErrors()){
            List<FieldError> errorList = result.getFieldErrors();
            //通过断言抛出参数不合法的异常
            errorList.stream().forEach(item -> Assert.isTrue(false,item.getDefaultMessage()));
        }
}
public class AuthorizeIn extends BaseModel{

    @NotBlank(message = "缺少response_type参数")
    private String responseType;
    @NotBlank(message = "缺少client_id参数")
    private String ClientId;

    private String state;

    @NotBlank(message = "缺少redirect_uri参数")
    private String redirectUri;

    public String getResponseType() {
        return responseType;
    }

    public void setResponseType(String responseType) {
        this.responseType = responseType;
    }

    public String getClientId() {
        return ClientId;
    }

    public void setClientId(String clientId) {
        ClientId = clientId;
    }

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }

    public String getRedirectUri() {
        return redirectUri;
    }

    public void setRedirectUri(String redirectUri) {
        this.redirectUri = redirectUri;
    }
}

我们再把验证的代码单独封装成方法:

protected void validate(BindingResult result){
        if(result.hasFieldErrors()){
            List<FieldError> errorList = result.getFieldErrors();
            errorList.stream().forEach(item -> Assert.isTrue(false,item.getDefaultMessage()));
        }
    }

这样每次参数校验只需要调用 validate 方法就行了,我们可以看到代码的可读性也大大提高了。

接口版本控制

一个系统上线后会不断迭代更新,需求也会不断变化,有可能接口的参数也会发生变化,如果在原有的参数上直接修改,可能会影响线上系统的正常运行,这时我们就需要设置不同的版本,这样即使参数发生变化,由于老版本没有变化,因此不会影响上线系统的运行。

一般我们可以在地址上带上版本号,也可以在参数上带上版本号,还可以再 header 里带上版本号,这里我们在地址上带上版本号,大致的地址如:http://api.example.com/v1/test,其中,v1 即代表的是版本号。具体做法请看代码:

@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface ApiVersion {

    /**
     * 标识版本号
     * @return
     */
    int value();
}
public class ApiVersionCondition implements RequestCondition<ApiVersionCondition> {

    // 路径中版本的前缀, 这里用 /v[1-9]/的形式
    private final static Pattern VERSION_PREFIX_PATTERN = Pattern.compile("v(\\d+)/");
     
    private int apiVersion;
     
    public ApiVersionCondition(int apiVersion){
        this.apiVersion = apiVersion;
    }
     
    @Override
    public ApiVersionCondition combine(ApiVersionCondition other) {
        // 采用最后定义优先原则,则方法上的定义覆盖类上面的定义
        return new ApiVersionCondition(other.getApiVersion());
    }
 
    @Override
    public ApiVersionCondition getMatchingCondition(HttpServletRequest request) {
        Matcher m = VERSION_PREFIX_PATTERN.matcher(request.getRequestURI());
        if(m.find()){
            Integer version = Integer.valueOf(m.group(1));
            if(version >= this.apiVersion)
            {
                return this;
            }
        }
        return null;
    }
 
    @Override
    public int compareTo(ApiVersionCondition other, HttpServletRequest request) {
        // 优先匹配最新的版本号
        return other.getApiVersion() - this.apiVersion;
    }
 
    public int getApiVersion() {
        return apiVersion;
    }
}
public class CustomRequestMappingHandlerMapping extends
        RequestMappingHandlerMapping {

    @Override
    protected RequestCondition<ApiVersionCondition> getCustomTypeCondition(Class<?> handlerType) {
        ApiVersion apiVersion = AnnotationUtils.findAnnotation(handlerType, ApiVersion.class);
        return createCondition(apiVersion);
    }
 
    @Override
    protected RequestCondition<ApiVersionCondition> getCustomMethodCondition(Method method) {
        ApiVersion apiVersion = AnnotationUtils.findAnnotation(method, ApiVersion.class);
        return createCondition(apiVersion);
    }
     
    private RequestCondition<ApiVersionCondition> createCondition(ApiVersion apiVersion) {
        return apiVersion == null ? null : new ApiVersionCondition(apiVersion.value());
    }
}
@SpringBootConfiguration
public class WebConfig extends WebMvcConfigurationSupport {

    @Bean
    public AuthInterceptor interceptor(){
        return new AuthInterceptor();
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new AuthInterceptor());
    }

    @Override
    @Bean
    public RequestMappingHandlerMapping requestMappingHandlerMapping() {
        RequestMappingHandlerMapping handlerMapping = new CustomRequestMappingHandlerMapping();
        handlerMapping.setOrder(0);
        handlerMapping.setInterceptors(getInterceptors());
        return handlerMapping;
    }
}

Controller 类的接口定义如下:

@ApiVersion(1)
@RequestMapping("{version}/dd")
public class HelloController{}

这样我们就实现了版本控制,如果增加了一个版本,则创建一个新的 Controller,方法名一致,ApiVersion 设置为2,则地址中 v1 会找到 ApiVersion 为1的方法,v2 会找到 ApiVersion 为2的方法。

自定义 JSON 解析

Spring Boot 中 RestController 返回的字符串默认使用 Jackson 引擎,它也提供了工厂类,我们可以自定义 JSON 引擎,本节实例我们将 JSON 引擎替换为 fastJSON,首先需要引入 fastJSON:

<dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>${fastjson.version}</version>
        </dependency>

其次,在 WebConfig 类重写 configureMessageConverters 方法:

@Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        super.configureMessageConverters(converters);
        /*
        1.需要先定义一个 convert 转换消息的对象;
        2.添加 fastjson 的配置信息,比如是否要格式化返回的 JSON 数据
        3.在 convert 中添加配置信息
        4.将 convert 添加到 converters 中
         */
        //1.定义一个 convert 转换消息对象
        FastJsonHttpMessageConverter fastConverter=new FastJsonHttpMessageConverter();
        //2.添加 fastjson 的配置信息,比如是否要格式化返回 JSON 数据
        FastJsonConfig fastJsonConfig=new FastJsonConfig();
        fastJsonConfig.setSerializerFeatures(
                SerializerFeature.PrettyFormat
        );
        fastConverter.setFastJsonConfig(fastJsonConfig);
        converters.add(fastConverter);
    }

单元测试

Spring Boot 的单元测试很简单,直接看代码:

@SpringBootTest(classes = DemoApplication.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class TestDB {

    @Test
    public void test(){
    }
}

模板引擎

在传统的 SpringMVC 架构中,我们一般将 JSP、HTML 页面放到 webapps 目录下面,但是 Spring Boot 没有 webapps,更没有 web.xml,如果我们要写界面的话,该如何做呢?

Spring Boot 官方提供了几种模板引擎:FreeMarker、Velocity、Thymeleaf、Groovy、mustache、JSP。

这里以 FreeMarker 为例讲解 Spring Boot 的使用。

首先引入 FreeMarker 依赖:

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

在 resources 下面建立两个目录:static 和 templates,如图所示:

这里写图片描述

其中 static 目录用于存放静态资源,譬如 CSS、JS、HTML 等,templates 目录存放模板引擎文件,我们可以在 templates 下面创建一个文件:index.ftl(freemarker 默认后缀为 .ftl),并添加内容:

<!DOCTYPE html>
<html>
    <head>
        
    </head>
    <body>
        <h1>Hello World!</h1>
    </body>
</html>

然后创建 PageController 并添加内容:

@Controller
public class PageController {

    @RequestMapping("index.html")
    public String index(){
        return "index";
    }
}

启动 Application.java,访问:http://localhost:8081/api/index.html,就可以看到如图所示:

enter image description here

点击了解《精通 Spring Boot 42 讲》,解决更多实际问题.

22道Java Spring Boot高频面试题 小编精心为大家准备了一手资料以上Java高级架构资料、源码、笔记、视频。Dubbo、Redis、设计模式、Netty、zookeeper、Spring cloud、分布式、高并发等架构技术【附】架构书籍BAT面试的20道高频数据库问题解析Java面试宝典Netty实战算法BATJ面试要点及Java架构师进阶资料《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!va面试宝典3. Netty实战4. 算法。 阅读详情

相关推荐

Spring Boot经典20道面试题及答案

这是一个基于 Web 的 UI,主要提供了使用可用依赖项创建新 Spring Boot 项目并下载创建为 zip 的项目的能力。例如:— 当我们在项目中添加spring-boot-starter-web依赖项时,Spring Boot 自动配置会查找 Spring MVC 是否在类路径中。通常,在控制器层我们注入服务,在服务层我们注入存储库来使用这个注解。我们可以以集中的方式做到这一点。简单地说,Spring Boot 框架的一个子项目,它使用 HTTP 端点来公开有关任何正在运行的应用程序的操作信息。

tangjieqing的博客 1418

最经典的20个Spring Boot面试题,95%以上会被问到,不服来战

这是一个基于 Web 的 UI,主要提供了使用可用依赖项创建新 Spring Boot 项目并下载创建为 zip 的项目的能力。例如:— 当我们在项目中添加spring-boot-starter-web依赖项时,Spring Boot 自动配置会查找 Spring MVC 是否在类路径中。通常,在控制器层我们注入服务,在服务层我们注入存储库来使用这个注解。spring-boot-starter-data-jpa依赖项时,我们会看到 Spring Boot 自动配置,自动配置一个数据源和一个实体管理器。

xxxzzzqqq_的博客 4万+

Spring高频面试题

答案是一种设计原则,它将对象的创建、组装和管理控制权从应用程序代码内部转移到外部容器(如 Spring IoC 容器)。传统方式下,主动通过new创建依赖对象;而 IoC 下,被动接收外部注入的依赖,控制流发生了“反转”。是IoC 原则的一种具体实现方式。它描述的是:组件之间依赖关系的建立,不是在组件内部硬编码,而是通过构造器、Setter 方法或字段注入等方式,由外部容器将依赖对象“注入”到组件中。三种常见注入形式构造器注入(推荐,保证不可变、强制依赖)Setter 注入(可选依赖)字段注入。

m0_47691180的博客 377

SpringBoot常见面试题汇总(超详细回答)

Spring Boot 高频面试题汇总,附详细答案。

qq_33129875的博客 2万+

Springboot 高频面试题

Spring Boot本质上是一个建立在Spring框架之上的快速应用开发框架。

m0_37145844的博客 1207

STM32与SD卡SPI接口硬件设计:从原理图到调试的完整指南

SPI(串行外设接口)作为一种广泛应用的同步串行通信协议,以其接线简单、驱动成熟的特点,成为连接微控制器与各类外设的经典方案。其工作原理基于主从架构,通过时钟、数据线和片选信号实现全双工通信,在嵌入式系统中具有极高的技术价值,常用于连接传感器、存储设备和显示模块等。在数据存储场景中,SD卡凭借其大容量和便携性成为首选,而通过SPI模式驱动SD卡,则平衡了性能与设计复杂度。本文聚焦于使用Altium Designer进行硬件设计的工程实践,详细解析了STM32微控制器与SD卡通过SPI通信时,电源管理、上拉电

weixin_34101784的博客 555

springBoot常见面试题(2024最新)

springBoot常见面试题(2023最新)

酷酷的馫博客 7万+

宝塔面板 python管理器2.0安装Mrdoc

自从python管理器从1.9升级2.0后,导致原教程不能使用。 故关于2.0新开教程如下。 关于python管理器2.0 最大的区别在于: python管理器2.0不再需要进入虚拟环境,直接在当前环境进行操作,但是需要指定python路径及pip路径。 1、新建mrdoc工程目录,下载源码: 新建目录【mrdoc】,进入mrdoc目录,并在宝塔ssh或或远程ssh中执行 ,下载源码 git clone https://gitee.com/yang_lite/MrDoc.git .

debj031634的专栏 5995

SpringBoot 框架的常考面试题总结

@RestController`注解是`@Controller`和`@ResponseBody`注解的组合注解,它们一起标识一个控制器类。通过在主类上标注@SpringBootApplication注解,就可以开启自动配置功能,Spring Boot会根据项目的依赖和配置自动配置相关的组件,简化了项目的配置过程,提高了开发效率。综上所述,`@RestController`注解适用于构建RESTful风格的API,返回的是数据格式,而`@Controller`注解适用于构建传统的Web应用,返回的是视图。

qq_58417838的博客 323

基于GIS的生态安全网络格局构建(附练习数据下载)

基于GIS的生态安全网络格局构建(附练习数据下载)

qq_43173805的博客 3124

深入傅里叶级数与傅里叶变换:从基础到应用

傅里叶分析为我们提供了一种理解信号频率结构的强大工具。从傅里叶级数到傅里叶变换,再到快速傅里叶变换(FFT),其理论与应用紧密结合,对现代科学技术的发展意义非凡。如果你对信号处理、数据分析或工程计算感兴趣,傅里叶分析是必须掌握的基础工具。希望本文能帮助你对傅里叶分析有更深入的理解!如果有问题或想法,欢迎在评论区讨论!

qq_56683019的博客 3526

Spring Boot面试题 35 问

1、什么是 Spring Boot? Spring Boot 是 Spring 开源组织下的子项目,是 Spring 组件一站式解决方案,主要是简化了使用 Spring 的难度,简省了繁重的配置,提供了各种启动器,开发者能快速上手。 2、为什么要用 Spring Boot? 快速开发 快速整合第三方框架(Maven依赖关系,Maven继承) 简化XML的配置 内置嵌入HTTP服务器(Tomcat(默认)、Jetty),降低了对环境的要求 3、Spring Boot 的优点? 容易上手,提升开发效率,为

养歌的博客 1万+

从零到一:EHB-电机复合制动系统的Simulink仿真实战指南

本文详细介绍了EHB-电机复合制动系统在纯电动汽车中的Simulink仿真实战指南。通过系统概述、建模核心模块解析、控制策略开发及典型问题排查,帮助读者掌握从零到一的开发流程。重点讲解了液压子系统建模、电机再生制动模型及整车动力学集成,为开发者提供了一套完整的解决方案。

hh234的博客 1009

松哥整理了 15 道 Spring Boot 高频面试题,看完当面霸

什么是面霸?就是在面试中,神挡杀神佛挡杀佛,见招拆招,面到面试官自惭形秽自叹不如!松哥希望本文能成为你面霸路上的垫脚石! 做 Java 开发,没有人敢小觑 Spring Boot 的重要性,现在出去面试,无论多小的公司 or 项目,都要跟你扯一扯 Spring Boot,扯一扯微服务,不会?没用过? Sorry ,我们不合适! 今天松哥就给大家整理了 15 道高频 Spring Boot 面试题...

江南一点雨的专栏 8626

手把手教你用Python+Playwright实现抖音/B站/视频号三平台自动上传(附完整配置流程)

本文详细介绍了如何使用Python和Playwright构建一个多平台视频自动化上传系统,涵盖抖音、B站和视频号三大平台。文章从环境搭建、身份验证持久化、平台特异性上传引擎设计到任务调度与错误处理,提供了完整的配置流程和实战代码,帮助开发者实现高效、稳定的批量上传功能。

weixin_29294975的博客 1150

SD--根据订单创建出库单(相关的函数列表的介绍系列篇(2))

创建订单样例代码参见:http://blog.csdn.net/CompassButton/archive/2007/05/09/1601712.aspx 可以根据一个订单或者部分订单项来创建出库单,代码如下:* Populating the item data lx_sales_item-ref_doc = l_vbeln. lx_sales_item-ref_item = c_000010

SAP BLOG--Jack Wu 6226

Spring Boot 常用注解面试题深度解析

Spring Boot 常用注解面试题深度解析

感谢阅读 5830

【计算机视觉】语义分割实战:FCN、U-Net与DeepLab系列详解

语义分割实战:FCN、U-Net与DeepLab系列详解,人工智能、大模型、AI深度学习在计算机视觉领域取得了令人瞩目的进展,语义分割作为计算机视觉领域的关键任务,旨在将图像中的每个像素都分配到特定的类别中,实现对图像内容的精细理解。与目标检测关注物体的类别与位置不同,语义分割能够对场景中的所有元素进行像素级别的分类,这在自动驾驶、医学图像分析、遥感图像解译等众多领域都有着至关重要的应用。例如,在自动驾驶中,准确的语义分割可以帮助车辆识别道路、行人、交通标志等,为安全行驶提供决策依据;在医学图像分析中……

不踩坑,不知道坑有多深;不总结,踩过的坑白踩。 9万+

面试中必须掌握的15道《Spring Boot 高频面试题》

做 Java 开发,没有人敢小觑 Spring Boot 的重要性,现在出去面试,无论多小的公司 or 项目,都要跟你扯一扯 Spring Boot,扯一扯微服务,不会?没用过? Sorry ,我们不合适!今天就给大家整理了 15 道高频 Spring Boot 面试题,希望能够帮助到刚刚走出校门的小伙伴以及准备寻找新的工作机会的小伙伴。一、什么是 Spring Boot ?传统的 SSM/SSH...

weixin_33709609的博客 886

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

10 个高频 Spring Boot 面试题解析:从自动装配到热部署原理

10 个高频 Spring Boot 面试题解析:从自动装配到热部署原理

梵心白莲的博客 1406

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

2020年Java面试高频的70 个 Spring 面试题

2020年Java面试高频的70 个 Spring 面试题 Spring、Spring boot、Spring Cloud、Spring MVC、MongoDB、MyBatis、微服务实战,Spring 全家桶,资深 Java 晋升前的必会内容。 对于那些想面试高级 Java 岗位的同学来说,除了算法属于比较「天方夜谭」的题目外,剩下针对实际工作的题目就属于真正的本事了,热门技术的细节和难点成为了主要考察的内容。 这里说「天方夜谭」并不是说算法没用,不切实际,而是想说算法平时其实很少用到,甚至面试官都对自己

weixin_47345084的博客 481

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

手慢无,阿里云神作被《Spring Boot进阶原理实战》成功扒下,限时

这是一本能带领读者全方位掌握Spring Boot技术体系的功能、原理和Z佳实践的著作,能帮助读者在Spring Boot领域快速实现从入门到进阶。 全书涵盖Spring Boot的6大核心主题:核心容器、Web服务、缓存、数据访问、并发执行、监控与扩展,内容具有以下4大特性:

Park33的博客 676

Spring Boot面试题精选汇总

Spring Boot面试题精选汇总

感谢阅读 1744

2022年大厂java高频面试题附带答案解析

本篇分享的面试题内容主要包括:Java、SpringMVC、Spring、SpringBoot、SpringCloud、MyBatis、ZooKeeper、Dubbo、Elasticsearch、Redis、MySQL、RabbitMQ、Kafka、Linux ,分布式、中间件、消息队列等技术栈。 Java基础 1,jdk和jre有什么区别 jdk:是java的开发环境,开发程序用的开发...

2万+
上一篇: Spring Boot 入门
下一篇: Spring Cloud 实例详解——业务代码实现
软件供应链安全
软件供应链安全 领域专家: 后端开发技术领域 领域专家: 后端开发技术领域
博客等级 码龄9年 1万+粉丝 347原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值