【框架】SpringBoot

188 阅读7分钟

注:本文介绍的内容都是相对基础的部分,有些地方挖坑未填,请按需阅读谢谢。

1. 相关介绍

  SpringBoot用于简化Spring应用开发,有以下优点:

  • 能快速创建独立的Spring项目
  • 使用嵌入式的Servlet容器,无需打成war包,打成jar包用java -jar即可运行
  • 很多配置都是自动配置的,我们也可以修改对应的默认值

2. 快速入门

  需求:发送一个hello请求,响应Hello World

1、创建一个maven工程,在pom.xml中添加如下内容

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

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

2、编写一个controller

package pers.ljc.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class HelloController {
    /**
     * @ResponseBody
     *  1.不加该注解,返回字符串时会认为是jsp页面
     *  2.加上该注解,当返回对象时会转换为json数据,当返回字符串时则原样返回
     */
    @ResponseBody
    @RequestMapping("/hello")
    public String hello() {
        return "Hello World";
    }
}

3、编写主程序,启动SpringBoot应用

package pers.ljc;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @SpringBootApplication 用于标注一个主程序类,说明这是一个SpringBoot应用
 */
@SpringBootApplication
public class App {
    public static void main(String[] args) {
        // run方法传入的参数一必须是@SpringBootApplication注解标注的类
        SpringApplication.run(App.class, args);
    }
}

4、运行主程序的main方法即可实现需求

5、在pom.xml中添加如下内容,并双击下图中的"package"即可打包成jar包

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

015-01.png

6、使用java -jar命令也能运行 015-02.png

3. 配置文件

  全局配置文件有一个,application.properties或者application.yml,用于修改SpringBoot自动配置的默认值。yml文件格式比较简洁,例子如下

# 使用缩进表示上下级关系,左对齐的是同级关系,冒号与内容之间有一个空格
server:
  port: 8081

3.1 yaml语法

3.1.1 字面量

  直接填写即可,字符串不需要加单引号或双引号。

  • 单引号,会转义特殊字符:如 name: 'zhangsan \n lisi' 则输出zhangsan 换行 lisi
  • 双引号,不会转义特殊字符:如 name: "zhangsan \n lisi" 则输出zhangsan \n lisi

3.1.2 对象

  两种写法,如下所示

student:
  name: zhangsan
  age: 20
student: {name: zhangsan, age: 20}

3.1.3 数组

  两种写法,如下所示

pets:
  - cat
  - dog
  - pig
pets: [cat, dog, pig]

3.2 获取配置文件自定义内容

1、在application.yml配置文件中有如下内容

student:
  name: zhangsan
  age: 20

2、在pom.xml加入如下依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>

3、自定义Student类并加上两个注解

/**
 * @ConfigurationProperties 默认从全局文件获取数据
 * @PropertySource 可以从指定文件中获取数据
 * @ImportResource 可以导入Spring的配置文件,一般写在启动类上
 */
@Component
@ConfigurationProperties(prefix = "student")
public class Student {
    private String name;
    private int age;
    // get和set方法...
}

4、在测试类中可以使用@Autowired注解就能自动注入内容

@SpringBootTest
class SpringbootTestApplicationTests {
    @Autowired
    private Student student;
    @Test
    void contextLoads() {
        System.out.println(student);
    }
}

3.3 给容器添加组件

/**
 * @Configuration 指明当前类是一个配置类
 */
@Configuration
public class MyConfig {
    /**
     * @Bean 将方法的返回值添加到容器中,该组件的id就是方法名
     */
    @Bean
    public HelloService helloService() {
        System.out.println("配置文件生效");
        return new HelloService();
    }
}

3.4 Profile

  用于快速切换不同环境(开发、测试、运维等)的配置文件。yml配置文件可以用"---"来分隔各个环境的配置文件。

server:
  port: 8081
spring:
  profiles:
    active: prod # 激活prod环境配置,运行时就会看到端口号为8083
--- # 分隔各个配置块
server:
  port: 8082
spring:
  profiles: dev # 声明这是dev环境的配置
---
server:
  port: 8083
spring:
  profiles: prod # 声明这是prod环境的配置

3.5 配置文件加载顺序

  SpringBoot的配置文件加载顺序如下,会从以下位置去找application.properties或application.yml,优先级由高到低,相同配置则高优先级的会覆盖低的,且是互补配置。

  • -file:./config/

  • -file:./

  • -classpath:/config/

  • -calsspath:/

  以IDEA为例,当这四个位置都配置了端口号时,最终采取的是配置文件1

015-03.png

4. 日志

  • 常见的日志框架如下

    抽象层具体实现
    jcl、slf4j、jboss-logginglog4j、jul、log4j2、logback
  • SpringBoot采用slf4j+logback,开发时应该调用抽象层的方法,而配置文件应该写具体实现框架的配置文件

  • 日志级别由高到低排序:error > warn > info > debug > trace,SpringBoot默认级别是info

  • 常用配置

    # 在application.properties中配置
    # pers.ljc包下的日志级别为warn
    logging.level.pers.ljc=warn
    
    # 在E:/log文件夹下生成spring.log日志文件
    logging.file.path=E:/log
    

5. Web开发

5.1 静态资源映射关系

  • /webjars/** 访问的是 classpath:/META-INF/resources/webjars/

    webjars:以jar包方式引入的静态资源

  • /** 访问当前项目的任何路径,如果没处理,则去下列位置(静态资源文件夹)找

    • classpath:/META-INF/resources/
    • classpath:/resources/
    • classpath:/static/
    • classpath:/public/
    • / (当前项目的根路径)

    (注:classpath后面的'/'是IDEA工程中的resources文件夹)

  • 项目首页(如index.html)是放在静态资源文件夹中

  • 所有页面的小图标都是从静态资源文件夹中找

5.2 Thymeleaf模板引擎

  SpringBoot推荐的模板引擎是Thymeleaf。

5.2.1 导入依赖

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

5.2.2 快速使用

/**
 * 如果这里使用@RestController,则不会把字符串作为html页面的前缀,就找不到相应的html页面
 */
@Controller
public class HelloController {
    @RequestMapping("/hello")
    public String hello(Map<String, Object> map) {
        // 会去classpath:/templates/下找hello.html
        return "hello";
    }
}

5.2.3 语法格式

  官方语法说明点这里

1、在html页面导入Thymeleaf命名空间

<html lang="en" xmlns:th="http://www.thymeleaf.org">

2、使用${}可获取controller层放置的数据

@RequestMapping("/hello")
public String hello(Map<String, Object> map) {
    map.put("hello", "你好");
    return "hello";
}
<body>
    <h1>欢迎</h1>
    <!-- th:text设置div的文本内容 -->
    <div th:text="${hello}"></div>
</body>

  更多内容可查看官方文档。

5.3 SpringMVC的自动配置

  (该部分暂未理解清楚...)

  根据官方文档,SpringBoot为SpringMVC配置了如下内容

  • Inclusion of ContentNegotiatingViewResolver and BeanNameViewResolver beans.

    配置了ViewResolver即视图解析器,根据方法的返回值得到视图对象,视图对象决定如何渲染(转发、重定向等)

    ContentNegotiatingViewResolver:组成所有视图解析器

  • Support for serving static resources, including support for WebJars.

  • Automatic registration of Converter, GenericConverter, and Formatter beans.

  • Support for HttpMessageConverters.

  • Automatic registration of MessageCodesResolver.

  • Static index.html support.

  • Custom Favicon support.

  • Automatic use of a ConfigurableWebBindingInitializer bean.

5.4 错误处理

  (该部分暂未理解清楚...)

  在ErrorMvcAutoConfiguration类中,有下列这些组件:

  • DefaultErrorAttributes

  • BasicErrorController:两个处理/error请求的方法,浏览器的请求会响应html页面,其他客户端的请求会响应JSON数据

  • ErrorPageCustomizer

  • DefaultErrorViewResolver

  一旦出现4xx或5xx的错误,内部类ErrorPageCustomizer就会生效并定制错误的响应规则,发送/error请求,然后BasicErrorController来处理该/error请求。

5.4.1 定制错误页面

  以IDEA工程为例,在/resources/templates(或者static)文件夹下建立error文件夹,里面放置html页面。比如要响应404错误,就放置404.html页面,也可以放置4xx.html来响应以4开头的错误。

5.4.2 定制错误JSON数据

1、没有自适应效果,即浏览器和其他客户端都是响应JSON数据

@ControllerAdvice
public class MyExceptionHandler {
    @ResponseBody
    @ExceptionHandler(MyException.class)
    public Map<String, Object> handleException(Exception e) {
        Map<String, Object> map = new HashMap<>();
        map.put("code", "404");
        map.put("message", e.getMessage());
        return map;
    }
}

2、有自适应效果,浏览器响应html页面,其他客户端响应JSON数据

@ControllerAdvice
public class MyExceptionHandler {
    @ExceptionHandler(MyException.class)
    public String handleException(Exception e, HttpServletRequest request) {
        Map<String, Object> map = new HashMap<>();
        map.put("code", "404");
        map.put("message", e.getMessage());
        request.setAttribute("javax.servlet.error.status_code", 404);
        return "forward:/error";
    }
}

5.5 配置Server相关

5.5.1 修改配置

# application.properties
# 修改server相关配置
server.xxx
# 修改tomcat相关配置
server.tomcat.xxx

5.5.2 注册Servlet、Filter、Listener

1、自定义MyServlet、MyFilter、MyListener

public class MyServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().write("Hello MyServlet!");
    }
}

/**
 * 实现的接口是javax.servlet包下的
 */
public class MyFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {}

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("My filter process...");
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {}
}

public class MyListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("contextInitialized -> web应用启动");
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("contextDestroyed -> 销毁web项目");
    }
}

2、自定义配置类,注册这三个组件

@Configuration
public class MyServerConfig {
    /**
     * 注册Servlet
     */
    @Bean
    public ServletRegistrationBean myServlet() {
        // 该servlet对应的映射路径是/myServlet
        return new ServletRegistrationBean(new MyServlet(), "/myServlet");
    }

    /**
     * 注册Filter
     */
    @Bean
    public FilterRegistrationBean myFilter() {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
        registrationBean.setFilter(new MyFilter());
        // 该过滤器拦截以下url
        registrationBean.setUrlPatterns(Arrays.asList("/hello", "/myServlet"));
        return registrationBean;
    }

    /**
     * 注册Listener
     */
    @Bean
    public ServletListenerRegistrationBean myListener() {
        return new ServletListenerRegistrationBean<MyListener>(new MyListener());
    }
}

5.6 整合Mybatis

1、导入相关依赖

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.1.1</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

2、编写连接数据库的接口及其xml文件

public interface StudentMapper {
    Student getStudentById(String  id);
}
<!-- StudentMapper.xml,位于classpath:/mapper/下 -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="pers.ljc.springboot_mybatis.mapper.StudentMapper">
    <select id="getStudentById" resultType="student" parameterType="java.lang.String">
        select SId id, Sname name, Sage age, Ssex sex from student where SId = #{id}
    </select>
</mapper>

3、配置application.yml

spring:
  datasource:
    username: root
    password: persona5
    url: jdbc:mysql://127.0.0.1:3306/test?serverTimezone=UTC&useSSL=false
    driver-class-name: com.mysql.cj.jdbc.Driver
mybatis:
  mapper-locations: classpath:/mapper/*Mapper.xml
  type-aliases-package: pers.ljc.springboot_mybatis.model

4、响应的调用层调用即可

@RestController
@RequestMapping("/student")
public class StudentController {
    // 这里按照规范应该是放在service层中
    @Autowired
    private StudentMapper studentMapper;

    @RequestMapping(value = "/{id}", method = RequestMethod.GET)
    public Student getStudentById(@PathVariable String id) {
        return studentMapper.getStudentById(id);
    }
}

6. 相关链接