SpringBoot2学习笔记

信息来源:https://www.bilibili.com/video/BV19K4y1L7MT?p=5&vd_source=3969f30b089463e19db0cc5e8fe4583a

作者提供的文档:https://www.yuque.com/atguigu/springboot

作者提供的代码:https://gitee.com/leifengyang/springboot2

-------------------------------------------------------------------------------------------------------

简明内容:

1、springboot简介
通过starter及第三方库快速创建spring应用

2、Spring注解
@Bean:给容器中添加组件,以方法名作为组件id
@Configuration:配置类组件,相当于创建了beans.xml配置文件
@Component:代表它是一个组件
@Controller:代表它是一个控制器
@Service:代表它是一个业务逻辑组件
@Repository:代表它是一个数据库层组件
@ComponentScan:定义包扫描规则
@Import:给容器中自动引入组件
@Conditional:满足Conditional指定的条件,则进行组件注入
@ConfigurationProperties:含参数prefix,把一些内容写到配置文件中,只需要通过该注解即可封装到JavaBean中
@SpringBootConfiguration:代表当前是一个配置类
@ComponentScan:指定扫描哪些包

@GetMapping:将HTTP的GET请求映射到指定的处理方法上
@PostMapping:将HTTP的POST请求映射到指定的处理方法上
@PathVariable:将URL绑定的占位符映射到控制器的参数中
@RequestHeader:将请求头中的参数映射到控制器的参数中
@RequestParam:将请求参数映射到控制器的参数中
@RequestPart:接收表单和文件数据
@RequestBody:将请求体映射到控制器的参数中,仅限POST请求
@ResponseBody:将controller返回的对象转换为指定的格式之后,写入到response对象的body中,通常返回json格式
@RequestAttribute:获取由过滤器或者拦截器创建的、预先存在的请求属性


3、@Bean标注方法的对象参数
给@Bean标注的方法传入了对象参数,这个参数的值就会从容器中找,然后赋值再返回。

4、Lombok简化类的定义及日志
@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
@Slf4j

5、MVC架构模式
Model:处理应用程序中数据逻辑的部分,通常Model负责在数据库中存取数据。
View:应用程序中处理数据显示的部分,是用户看到并与之交互的界面。
Controller:应用程序中处理用户交互的部分,通常Controller负责从View中读取数据、控制用户输入,并向Model发送数据。

6、@Controller和@RestController的区别
@RestController = @Controller + @ResponseBody

7、POJO对象
普通JavaBean对象,区别于EJB(Enterprise Java Beans,分布式事务处理组件)

8、自定义Converter
在SpringMVC中添加一种新的Converter,以实现特定数据类型之间的转化。
WebMvcConfigurer定制化SpringMVC的功能

9、HandlerInterceptor拦截器步骤:
编写一个拦截器实现HandlerIntercepter接口
拦截器注册到容器中(实现WebMvcConfigurer的addInterceptors)
指定拦截规则【如果是拦截所有,静态资源也会被拦截】

10、Servlet、Filter、Listener区别
(1)Servlet
接收请求数据
处理请求:通常会在Service、doPost或者doGet方法进行接收参数,并且调用业务层(service)的方法来处理请求。
完成响应。处理完请求后,一般会转发(forward)或者重定向(redirect)到某个页面,转发是HttpServletRequest中的方法,重定向是HttpServletResponse中的方
(2)Filter
与Servlet相似,但是Servlet主要负责处理请求,而filter主要负责拦截请求和放行
(3)Listener
监听器,监听Application、Session、Request对象,当这些对象发生变化就会调用对应的监听方法

11、JDBC、Druid、MyBatis区别
JDBC:Java Database Connectivity java和数据库的连接技术
Druid:数据库连接池,普通JDBC数据库连接使用DriverManager来获取会出现很多问题。为了解决创痛开发中数据库的连接问题,使用数据库连接池负责分配、管理和释放数据库连接。
Mybatis:进一步封装了jdbc,sql语句写在配置文件中,面向对象操作,有一二级缓存功能。

12、MyBatis使用方法
(1)引入mybatis-starter
(2)配置application.yaml,指定mapper-location位置即可
(3)编写Mapper接口并标注@Mapper注解
(4)简单方法直接注解方式、复杂方法编写XXXmapper.xml进行绑定映射
(5)@MapperScan(“xxx”)简化,其他的接口就可以不用标注@Mapper注解

-------------------------------------------------------------------------------------------------------

1、spring-boot简介

能够让我们快速集成spring解决方案和第三方库。

(1)快速创建独立Spring应用

之前SSM框架中,需要导包、写配置、启动运行,现在直接配置下就可以了。

(2)直接嵌入tomcat、jetty(无需部署war包)

之前需要一个linux环境,java环境、安装tomcat,打一个war包放到tomcat的webapps下。现在只要java环境,把程序打成jar包,直接java -jar即可运行。

(3)提供可选的starter(场景启动器),简化应用整合。

以前需要开发web、json、邮件服务、oss、异步、定时任务、缓存…等,需要导包一堆,并且需要控制好版本。现在springboot为每一种场景准备好了一个依赖,web-starter、mybatis-starter,只要配置这个依赖,所以事情都帮搞定。

(4)按需自动配置spring以及第三方库

如果这些场景需要使用,则这个场景的所有配置都会自动配置好。

约定大于配置:每个场景都有很多默认配置。如果需要自定义,则在配置文件中修改几项即可。

(5)提供生产级特性:如监控指标、健康检查、外部化配置等。

健康检查:如果发送一个请求检查应用是否活着,否则发送个请求重启。

外部化配置:比如发布了一个应用,通过java -jar demo.jar启动了。如果修改了配置则修改源码需要重启。后续外部化配置就可以在一个目录下放置配置文件,就不需要重启了。

(6)无代码生成、无xml

总结:简化开发、简化配置、简化整合、简化部署、简化监控、简化运维。

2、第一个springboot程序解读

(1)pom文件

<!-- 所有springboot项目都必须继承自 spring-boot-starter-parent -->
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.4.RELEASE</version>
</parent>
<dependencies><!-- web开发的场景启动器 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>
</dependencies>

配置了一个springboot工程的parent父项,外加一个web的场景启动器。

(2)MainApplication

@SpringBootApplication // 这是一个SpringBoot应用
public class MainApplication {public static void main(String[] args) {SpringApplication.run(MainApplication.class, args);}
}

程序主入口,SpringBootApplication注解告诉框架这个一个springboot应用。

执行完上述两步之后就可以启动程序了,localhost:8080会显示一个404的页面。

(3)配置rest的controller

@RestController
public class HelloController {@RequestMapping("/hello")public String handler01() {return "hello, springboot!";}
}

ResponseBody注解告诉框架这个请求返回的是一个响应式的body,而不是一个跳转之类的。如果把该注解放到类上,表明该类的所有方法都是返回body。

Controller注解+ResponseBody注解 = RestController注解。

(4)配置文件修改

在resources下新增application.properties(文件名固定不可修改),

新增:server.port=8888

(5)程序打包

在pom中添加:

<build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><executions><execution><goals><goal>repackage</goal></goals></execution></executions></plugin></plugins>
</build>

然后在IDEA右侧的Maven Projects中运行clean、package,就在target目录中得到jar包。然后通过java -jar <xx.jar>即可启动服务。

3、父项目做依赖管理

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

每个springboot工程都有这么一个父项目,它的父项目的父项目中几乎声明了所有开发中常用的依赖的版本号。这样子项目<dependency>依赖这个父项目就不需要写版本号。

当父项目中提供的依赖不满意时,可以自定义依赖的版本号,操作为:

在parent同级下添加:

<properties><mysql.version>5.1.43</mysql.version>
</properties>

假如依赖的包没在parent的版本仲裁中,则需要自己写版本号。

4、自动配置功能

(1)自动配好tomcat:引入tomcat依赖、配置tomcat

(2)自动配好SpringMVC:引入SpringMVC全套组件、自动配好springVMC常用组件

(3)自动配好Web常见功能,如字符编码问题。

(4)默认包结构:主程序所在包及其下面的所有子包的组件都会被默认扫描进来,无需以前的包扫描配置。如果一定要加载不再主程序下面的组件,则需要在组程序中修改:@SpringBootApplication(scanBasePackage=”com.xxx”)或者@ComponentScan(“com.xx”)。

(5)各种配置拥有默认值,这些配置最终都映射到MultipartProperties。配置文件的值最终会绑定到某个类上,这个类会在容器中创建对象。

(6)按需加载所有自动配置项。虽然有非常多的starter,但是引入了哪些场景这个场景的自动配置才会开启。Springboot所有的自动配置功能都在spring-boot-autoconfigure包里面。

5、@Configuration注解

创建完Bean后创建配置类。

@Configuration
public class MyConfig {@Beanpublic User user01() {return new User("zhangsan", 18);}@Beanpublic Pet tomcatPet() {return new Pet("tomcat");}
}

创建类就相当于创建了beans.xml文件,通过@Configuration就相当于告诉框架这个是配置类,等同于以前的配置文件。

@Bean:给容器中添加组件,以方法名作为组件的id,返回类型就是组件类型,返回的值就是组件在容器中的实例。外部无论对配置类中的这个组件注册方法调用多少次,获取的都是之前注册容器中的单实例对象。

配置类说明:

1)配置类里面使用@Bean标注在方法上给容器注册组件,默认也是单实例的。

2)配置类本身也是组件

3)proxyBeanMethods:代理@Bean的方法

        Full(proxyBeanMethods = true) // 检查容器调用单实例

         Lite(proxyBeanMethods = false) // 不检查容器重新生成实例,SpringBoot启动更快

4)最佳实战:

配置类组件之间无依赖关系用Lite模式加速容器启动过程,减少判断。

配置类组件之间有依赖关系,方法会被调用得到之前单实例组件,用Full模式。

6、其他组件标注

@Component:代表它是一个组件

@Controller:代表它是一个控制器

@Service:代表它是一个业务逻辑组件

@Repository:代表它是一个数据库层组件

@ComponentScan:定义包扫描规则

7、@Import注解

位置:任何一个配置类或者组件里面。

@Import({User.class, DBHelper.class})

作用:给容器中自动创建这两个类型的组件,默认组件的名字为全类名(类型包含import时的包信息,比如com.hugh.boot.bean.User)

8、@Conditional注解

条件装配:满足Conditional指定的条件,则进行组件注入。

它是一个根类,包含ConditionalOnBean\ConditionalOnClass等子类

@Bean("user02")

@ConditionalOnBean(name="tom2")

 public User user02(){

      return new User("hugh", 20);

  }

上面只有当tom2的组件存在时user02的组件才会生效。

boolean user = run.containsBean("user02");

System.out.println("容器中user组件:" + user);

当tom2组件 不存在时,上面代码如果去掉@ConditionalOnBean(name="tom2")则显示true,否则显示false。

9、@ConfigurationProperties注解

把一些内容写到配置文件中,只需要通过该注解即可封装到JavaBean中,以供随时使用。

比如有一个Car的Bean如下:

public class Car {

    private String brand;

    private Integer price;

我们希望通过application.properties中添加配置信息从而生成JavaBean,配置文件内容为:

mycar.brand=BYD

mycar.price=100000

如果希望Car的Bean装载这些信息,Bean改造如下:

@Component

@ConfigurationProperties(prefix="mycar")

public class Car {

    private String brand;

    private Integer price;

此时一定要加上@Component的信息,因为只有在容器中的组件,才会拥有SpringBoot提供的强大功能。

在RestController中使用如下:

@Autowired
Car car;@RequestMapping("/car")
public Car car(){return car;
}

此时body返回的信息为: {"brand":"BYD","price":100000}

还有一种方式是通过@EnableConfigurationProperties注解的方式。

Car种只需要配置@ConfigurationProperties(prefix="mycar"),不需要配置@Component,然后在Config类中配置@EnableConfigurationProperties(Car.class)来开启Car属性的配置功能。

该方法的好处是,好多源码中只配置了@ConfigurationProperties(prefix="mycar")注解,又不能修改源码增加@Component信息,就可以通过Config类来开启配置属性。

10、自动配置原理

主程序注解@SpringBootApplication主要由三部分组成:

(1)@SpringBootConfiguration

代表当前是一个配置类

(2)@ComponentScan

指定扫描哪些包

(3)@EnableAutoConfiguration

该注解实现时包含另一个注解:

@AutoConfigurationPackage,自动配置包(自己写的组件),它利用Registrar给容器导入一系列组件。将指定的一个包下的所有组件导入进来?MainApplication所在包下。

@Import({AutoConfigurationImportSelector.class}),给容器中批量导入一些依赖包的组件,默认扫描当前系统里面所有META-INF/spring.factories位置的文件。(如下两个例子)。

spring-boot-autoconfigure中有127项需要加载的包,文件里面写死了spring-boot一启动就要给容器中加载的所有配置类。

虽然我们127个场景的所有自动配置启动的时候默认全部加载,但是按照条件(@Conditional)装配规则会按需配置

如上示例,通过@ConditionalOnClass()方法只有在aspectJ的Advice类有的时候AopAutoConfiguration才会生效。

11、自动配置的“修改默认配置”功能

@Bean
@ConditionalOnBean(MultipartResolver.class) // 当容器中有这个类型组件
@ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME)
// 当容器中没有这个名字(multipartResolver)组件 		
public MultipartResolver multipartResolver(MultipartResolver resolver){// Detect if the user has created a MultipartResolver but named it incorrectly 			return resolver;
}

上述代码给容器中加入了文件上传解析器。

给@Bean标注的方法传入了对象参数,这个参数的值就会从容器中找,然后赋值再返回。在SpringMVC中Bean名有严格的规定,通过上述操作可以防止有些用户配置的文件上传解析器不符合规范的问题。

12、第10-11部分总结

(1)SpringBoot先加载所有的自动配置类

(2)每个自动配置类按照条件进行生效,默认都会绑定配置文件指定的值

(3)生效的配置类就会给容器中装配很多组件

(4)只要容器中有这些组件,相当于这些功能就有了。

(5)只要用户有自己配置的,就以用户的优先。

(6)定制化配置的2种方法

用户直接自己@Bean替换底层的组件

用户去看这个组件是获取的配置文件什么值就去替换,取值步骤如下:

XxxAutoConfiguration à 组件 à xxxProperties里面拿值 à application.properties

以HTTP中处理Encode为例,对应源码:

@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(ServerProperties.class)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@ConditionalOnClass(CharacterEncodingFilter.class)
@ConditionalOnProperty(prefix = "server.servlet.encoding", value = "enabled", matchIfMissing = true)
public class HttpEncodingAutoConfiguration {private final Encoding properties;public HttpEncodingAutoConfiguration(ServerProperties properties) {this.properties = properties.getServlet().getEncoding();}@Bean@ConditionalOnMissingBeanpublic CharacterEncodingFilter characterEncodingFilter() {CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();filter.setEncoding(this.properties.getCharset().name());filter.setForceRequestEncoding(this.properties.shouldForce(Encoding.Type.REQUEST));filter.setForceResponseEncoding(this.properties.shouldForce(Encoding.Type.RESPONSE));return filter;}

第一种情况,如果@ConditionalOnMissingBean,即没有CharacterEncodingFilter组件,则通过characterEncodingFilter方法(默认的Bean组件名字)加载encode。方法中的this.properties来自于ServerProperties类,而这个类又通过EnableConfigurationProperties(ServerProperties.class)生效的,进一步同application.properties关联配置信息。

第二种情况,假如我们在自己的Config类中编写了如下代码,就可以替换掉默认的encode方法。

@Bean

public CharacterEncodingFilter filter(){

    return null;

}

13、SpringBoot最佳实践

(1)引入场景依赖

看下SpringBoot或者第三方有没有开发好的场景依赖

Spring Boot Reference Documentation

(2)查看自动配置了哪些(选做)

在application.properties中写:debug=true 开启自动配置报告

Negative:都是不生效的;

Positive:都是生效的

(3)是否需要修改

  • 参考文档修改配置项

Spring Boot Reference Documentation

或者自己分析。XxxProperties绑定了配置文件的哪些前缀

  • 自定义加入或者替换组件

@Bean @Component

  • 自定义器 xxxxCustomizer

14、Lombok工具简化开发

(1)pom中引入依赖

<dependency>

        <groupId>org.projectlombok</groupId>

        <artifactId>lombok</artifactId>

    </dependency>

(2)安装lombok插件

(3)通过lombok对原Bean的改造

@Data | @ToString | @NoArgsConstructor | @AllArgsConstructor

       这样Pet只剩private String name;一行代码了。

(4)增加日志功能

 增加@Slf4j (import lombok.extern.slf4j.Slf4j;)注解。

然后使用log.info(“xxx”); 显示注释信息。

 15、Yaml使用

是Markup标记语言,非常适合用来做以数据为中心的配置文件

(1)基本语言

  • key:  value;kv之间有空格
  • 大小写敏感
  • 使用缩进表示层级关系
  • 缩进不允许使用tab,只允许空格
  • 缩进的空格数不重要,只要相同层级的元素左对齐即可
  • #表示注释
  • ‘’与”” 表示字符串内容,会被 不转义/转义
  • 注解方式装载JavaBean

如果通过配置文件装载可使用@ConfigurationProperties(prefix=”xxx”)的方式。

按优先级会读取application.properties和application.yaml文件加载信息

上述Bean对应的yaml文件可以表示为:

Spring配置东西,首选配置在yaml文件中。

16、配置文件-自定义类绑定的配置提示

目的:在写yaml文件时能够自动给出提示

使用时在pom.xml中配置:

<dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-configuration-processor</artifactId>

    <optional>true</optional>

</dependency>

然后运行一次主程序后,再在yaml中编写就会有提示词出来。

17、静态资源访问

只要静态资源放在类路径(main/resources)下:/static或/public或/resources或/META-INF/resources,通过当前项目路径/+静态资源名即可访问。

比如:文件放在/static下,通过http://localhost:8888/beauty.png即可访问。

原理:静态映射到/**,也就是拦截所有请求。请求进来,先去找Controller看能不能处理,不能处理的所有请求又都交给静态资源处理器。静态资源也找不到则404。

18、静态资源访问前缀

程序开发过程中需要设置一些拦截器,为了拦截方便需要区分开静态资源,所以静态资源访问需要带上前缀以便让拦截器放行。

默认无前缀,application.yaml加上前缀如下:

spring:

  mvc:

    static-path-pattern: /res/**

19、欢迎页支持

实现的两种方法:

1)在静态资源路径下放index.html,但是不能配置静态资源的访问前缀(static-path-pattern)

2)Controller能处理/index

访问:<ip>: <port>即可访问index.html页面。

20、静态资源加载原理中的关键信息

源码位于:spring-boot-autoconfigure.jar下的org.springframework.boot.autoconfigure.web中的WebMvcAutoConfiguration类中。

@Configuration(proxyBeanMethods = false)
@Import(EnableWebMvcConfiguration.class)
@EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class })  // 和配置相关属性进行了绑定WebMvcProperties(spring.mvc)| ResourceProperties(spring.resources)
@Order(0)
public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer {public WebMvcAutoConfigurationAdapter(ResourceProperties resourceProperties, WebMvcProperties mvcProperties,ListableBeanFactory beanFactory, ObjectProvider<HttpMessageConverters> messageConvertersProvider,ObjectProvider<ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider,ObjectProvider<DispatcherServletPath> dispatcherServletPath,ObjectProvider<ServletRegistrationBean<?>> servletRegistrations) {}
}

当@Configure配置类只有一个有参构造器,有参构造器所有参数的值都会从容器中确定

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {String staticPathPattern = this.mvcProperties.getStaticPathPattern();  // 指为/**,即拦截所有请求if (!registry.hasMappingForPattern(staticPathPattern)) {customizeResourceHandlerRegistration(registry.addResourceHandler(staticPathPattern).addResourceLocations(getResourceLocations(this.resourceProperties.getStaticLocations())).setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));}staticLocations对应:"classpath:/META-INF/resources/","classpath:/resources/", "classpath:/static/", "classpath:/public/"

21、请求映射原理

所有的请求都由DispatcherServlet来处理。

继承关系如下:

HttpServlet的doGet和doPost都需要子类重写。

在FrameworkServlet中有重写的doGet方法,调用processRequest(request, response)方法,该方法的核心是doService(request, response),在FrameworkServlet中一个抽象类。

接着查看DispatcherServlet的doService方法,核心方法是:doDispatch(request, response)。

所以SpringMVC功能分析都从DispatcherServlet的doDispatch开始。

mappedHandler = getHandler(processedRequest); // 找到当前请求读由哪个Handler(Controller的方法)处理。

// HandlerMappings,处理器映射,/*** -> xxx

每个mapping保存了路径和handler的处理关系,如下图所示:

总结:

所有的请求映射都在HandlerMapping中。

  • SpringBoot自动配置欢迎页的WelcomePageHandlerMapping,访问/能访问到index.html
  • SpringBoot自动配置了默认的RequestMappingHandlerMapping
  • 请求进来,换个尝试所有的HandlerMapping看是否有请求信息。

如果有就找这个请求对应的Handler

如果没有就是下一个HandlerMapping

  • 我们需要一些自定义的映射处理,我们也可以自己给容器中放HandlerMapping,自定义HandlerMapping。

22、MVC架构模式

MVC全程:Model(模型) View(视图) Controller(控制器)

Model:处理应用程序中数据逻辑的部分,通常Model负责在数据库中存取数据。

View:应用程序中处理数据显示的部分,是用户看到并与之交互的界面。

Controller:应用程序中处理用户交互的部分,通常Controller负责从View中读取数据、控制用户输入,并向Model发送数据。

23、请求处理中常用参数注解使用

(1)@GetMapping

将HTTP GET请求映射到指定的处理方法上。

示例:@GetMapping("/car/{id}/owner/{username}")

(2)@PostMapping

将HTTP POST请求映射到指定的处理方法上。

示例:

@PostMapping("/users")

    public User createUser(@RequestBody User user) {

        // 创建用户

        return user;

    }

(3)@PathVariable

作用:将URL绑定的占位符映射到控制器的参数中。URL中{xxx}占位符可以通过@Pathvariable(“XXX”)进行绑定,@Pathvariable可以将全部参数放入Map<String, String>结构的对象中。

使用示例:

@GetMapping("/car/{id}/owner/{username}")

    public Map<String, Object> getCar(@PathVariable("id") Integer id,

                                   @PathVariable("username") String username,

                                   @PathVariable Map<String, String> pv

    ){

        Map<String, Object> map = new HashMap<>();

        map.put("id", id);

        map.put("username", username);

        map.put("pv", pv);

        return map;

    }

请求链接:http://localhost:8888/car/123/owner/hugh

返回:{"pv":{"id":"123","username":"hugh"},"id":123,"username":"hugh"}

(4)@RequestHeader

作用:将请求头中的参数映射到控制器的参数中。

使用示例:

public Map<String, Object> getCar(@RequestHeader("user-agent") String agent,

                               @RequestHeader Map<String, String> headers

浏览器中请求头查看方法:

(5)@RequestParam

作用:将请求参数映射到控制器的参数中。

使用示例:

@GetMapping("/person")

    public Map<String, Object> getCar(@RequestParam("age") Integer age,

                                   @RequestParam("inters") List<String> inters,

                                   @RequestParam Map<String, String> params

请求头:http://localhost:8888/person?age=18&inters=basketbal&inters=baseball

(6)@RequestBody

作用:将请求体映射到控制器的参数中,仅限POST请求

使用示例:

@PostMapping("/hello/post")

    public Map<String, Object> getHello(@RequestBody String content){

(7)@ResponseBody

将controller返回的对象转换为指定的格式之后,写入到response对象的body中,通常返回json格式。

(8)@Controller和@RestController的区别

@Controller+@GetMapping返回一个视图,

而@RestController+@GetMapping返回的是json数据

@RestController = @Controller + @ResponseBody

然后localhost:8080/list返回了list.html页面。

然后localhost:8080/list返回json数据。

(9)@RequestAttribute

作用:获取由过滤器或者拦截器创建的、预先存在的请求属性

示例:

   @GetMapping("/goto")public String goToPage(HttpServletRequest request) {request.setAttribute("msg", "成功了...");request.setAttribute("code", 200);return "forward:/success"; //转发到 /sucess请求}@ResponseBody@GetMapping("/success")public Map<String, Object> success(@RequestAttribute("msg") String msg,@RequestAttribute("code") Integer code) {Map<String, Object> map = new HashMap<>();map.put("msg", msg);map.put("code", code);return map;}}

在goToPage()函数完成后,所有的请求数据和视图都会放入ModelAndViewContainer中,包含要去的页面地址view,还包含Model数据。接下来处理派发结果,processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException)。上面的mv就是ModelAndViewContainer的内容。

exposeModelAsRequestAttributes(model, request);

暴露模型作为请求属性,把model中的所有数据遍历挨个放在请求域中。

24、自定义POJO对象数据绑定

当表单提交字段比较多时,使用POJO对象(普通JavaBean对象,区别于EJB(Enterprise Java Beans,分布式事务处理组件))保存变量。

我们解析字段通常使用@PathVariable注解或者@RequestParam注解,但是当字段过多时,我们不可能每个字段都给一个对应的参数给函数,此时SpringMVC给我们提供了POJO对象,用于将参数包装成一个对象。

示例:

POJO对象定义:

@Data

public class Student {

    private String userName;

    private Integer age;

    private Date birth;

}

Html中表单提交:

<form action="/savestudent" method="post">

    姓名:<input name="userName" value="zhangsan"><br/>

    年龄:<input name="age" value="18"><br/>

    生日:<input name="birth" value="2019/12/20"><br/>

    <input type="submit" value="保存">

</form>

Controller中获取用户数据:

@PostMapping("/savestudent")

   public Student savestudent(Student student){

      return student;

}

在上述方法中,Spring框架调用get与set函数封装成对象。

POJO封装过程原理说明:

ServletModelAttributeMethodProcessor,这个参数处理器支持

是否为简单类型?POJO并非简单类型。

然后创建一个空的Student对象。

WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name);

WebDataBinder为Web数据绑定器,它的作用是把请求参数webRequest绑定到指定的JavaBean(attribute)里面。

WebDataBinder利用它里面的Converters将请求数据(String类型)转成指定的数据类型(JavaBean对应字段的类型),从而实现封装到JavaBean中。

GenericConversionService:在设置每一个值的时候,找它里面的所有converter哪个可以将这个数据类型(request带来参数的字符串)转换到指定的类型。

未来我们可以给WebDataBinder里面放自己的Converter;

Private static final class StringToNumber<T extends Number> implements Converter<String T>

25、自定义Converter

目的:在SpringMVC中添加一种新的Converter,以实现特定数据类型之间的转化。

示例:

POJO定义:

@Data

public class Student {

    private String userName;

    private Integer age;

    private Date birth;

    private Pet pet;

}

Form表格中pet的两个字段通过逗号隔开:

<form action="/savestudent" method="post">

    姓名:<input name="userName" value="zhangsan"><br/>

    年龄:<input name="age" value="18"><br/>

    生日:<input name="birth" value="2019/12/20"><br/>

    宠物:<input name="pet" value="猫,2"><br/>

    <input type="submit" value="保存">

</form>

WebMvcConfigurer定制化SpringMVC的功能

    @Bean

    public WebMvcConfigurer webMvcConfigurer(){

        return new WebMvcConfigurer() {

            // 参数解析中的自定义Converter

            @Override

            public void addFormatters(FormatterRegistry registry) {

                registry.addConverter(new Converter<String, Pet>() {

                    @Override

                    public Pet convert(String source) {

                        if(!StringUtils.isEmpty(source)){

                            Pet pet = new Pet();

                            String[] split = source.split(",");

                            pet.setName(split[0]);

                            pet.setAge(Integer.parseInt(split[1]));

                            return pet;

                        }

                        return null;

                    }

                });

            }

        };

    }

其中addFormatters函数的说明见注释,可以提供add converter功能。

/**

        * Add {@link Converter Converters} and {@link Formatter Formatters} in addition to the ones

        * registered by default.

        */

       default void addFormatters(FormatterRegistry registry) {

       }

26、ReturnValueHandler原理剖析

由第21个知识点可知,SpringMVC功能分析都从DispatcherServlet的doDispatch开始。

mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

继而:

handleInternal(request, response, (HandlerMethod) handler)

继而:

mav = invokeHandlerMethod(request, response, handlerMethod)

继而:

invocableMethod.invokeAndHandle(webRequest, mavContainer)

给前端自动返回json数据:

1)返回值解析器

2)返回值处理器处理返回值

this.returnValueHandlers.handleReturnValue(

        returnValue, getReturnValueType(returnValue), mavContainer, webRequest)

继而:

####1)返回值处理器判断是否支持这种类型返回值supportsReturnType

####2)返回值处理器调用handleReturnValue的selectHandler进行处理

####3)选中了RequestResponseBodyMethodProcessor可以处理返回值标了@ResponseBody注解的。

  writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage

使用消息转化器进行写出操作。

  利用MessageConverters进行处理,将数据写为json的过程如下:

1)内容协商(浏览器默认会以请求头的方式告诉服务器它能接受什么样的内容类型)

*/*表示能接受任何类型的数据

Accept表示我能接受什么内容。

2)服务器最终根据自身的能力,决定服务器能生产什么样内容类型的数据

3)SpringMVC会挨个遍历所有容器底层的HttpMessageConverter,看谁能处理?

HttpMessageConverter:看是否支持将此Class类型的对象,转为MediaType类型的数据。例如:Person对象转为JSON,或者JSON转为Person。

最终MappingJackson2HttpMessageConverter把对象转为JSON

总结:@ResponseBody,利用返回值处理器里面的消息转换器,将对象默认转换为json传出去(如果有指定则可以是其他格式)。

27、内容协商原理

根据客户端接收能力不同,返回不同媒体类型的数据。

先说示例:

1)pom中引入xml依赖

<dependency>

    <groupId>com.fasterxml.jackson.dataformat</groupId>

    <artifactId>jackson-dataformat-xml</artifactId>

</dependency>

2)controller信息

@GetMapping("/test/pet")

@ResponseBody

public Pet getPet(){

   Pet pet = new Pet();

   pet.setName("猫");

   pet.setAge(3);

   return pet;

}

3)浏览器显示

4)Postman显示

两者的主要区别在于:

浏览器中Accept为:text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7

其中xml的优先级(q值)高于*/*,所以返回了xml格式的数据。

而postman中Accept为:*/*,所以返回了json格式的数据。

总结:只需要改变请求头中Accept字段,Http协议中规定的,告诉服务器本客户端可以接收的数据类型。

再说原理:

1)判断当前响应头中是否已经有确定的媒体类型,MediaType

2)获取客户端(PostMan、浏览器)支持接收的内容类型。List<MediaType> acceptableTypes = getAcceptableMediaTypes(request),获取客户端Accept请求头。【application/xml】

3)遍历循环所有当前系统的MessageConverter,看谁支持操作这个对象(Pet)

4)找到支持操作Pet的Converter(canRead、canWrite),把Converter支持的媒体类型统计出来。

canRead的含义:通过@RequestBody 传过来Pet类型,支持这个类型数据的读取再写为json类型等。

canWrite的含义:内部的Pet类型的数据,转化为json类型后再传出去。

5)客户端需要【application/xml】,服务端能力【10种、json+xml】

6)进行内容协商的最佳匹配媒体类型

7)用支持将对象转为最佳匹配类型的converter,调用它进行转换

28、开启浏览器参数方式内容协商功能

浏览器中不方便改请求头Accept信息,为了方便内容协商,开启基于请求参数的内容协商功能。

示例:

在第27个知识点中pom配置xml包后浏览器返回的也是xml。

1)在application.yaml中添加:

spring:

  mvc:

    contentnegotiation:

      favor-parameter: true

2)点击favor-parameter打开源码,找到注释说明

3)在请求中通过添加format参数即可控制内容协商

原理说明:

在获取请求媒体类型的策略中,之前只有HeaderContentNegotiationStrategy,通过配置favor-parameter: true之后,新增了一个策略:ParameterContentNegotiationStrategy。

确定客户端接收什么样的内容类型:Parameter策略优先确定是要返回json数据(获取请求参数中的format的值)

29、自定义MessageConverter

需求:如果硅谷app发请求,返回自定义协商数据 【application/x-guigu】 xxxConverter

流程:

1)添加自定义的MessageConverter进系统底层

2)系统底层就会统计出所有MessageConverter能操作哪些类型

3)客户端内容协商(guigu à guigu)

示例:

一个入口给容器中添加一个WebMvcConfigurer,重写extendMessageConverters接口。

1)新增一个Converter

2)在WebMvcConfigurer中extendMessageConverters

// 数据返回时的自定义Converter

@Override

public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {

    converters.add(new GuiguMessageConverter());

}

3)Postman中发送Get请求后(Accept=application/x-guigu)

30、自定义内容协商中的参数策略中的类型

需求:支持如下请求http://localhost:8888/test/pet?format=gg

当前有两个内容协商策略器,其中ParameterContentNegotiationStrategy只支持xml和json的默认配置,现在需要新增对gg的支持。

示例:

在WebMvcConfigurer中配置内容协商的策略配置器,其为覆盖而非新增模式

@Override

public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {

// 配置ParameterContentNegotiationStrategy

Map<String, MediaType> mediaTypes = new HashMap<>();

mediaTypes.put("json", MediaType.APPLICATION_JSON);

mediaTypes.put("xml", MediaType.APPLICATION_XML);

mediaTypes.put("gg", MediaType.parseMediaType("application/x-guigu"));

// 指定支持解析哪些参数对应的哪些媒体类型

ParameterContentNegotiationStrategy parameterStrategy = new ParameterContentNegotiationStrategy(mediaTypes);

// 配置HeaderContentNegotiationStrategy

HeaderContentNegotiationStrategy headerStrategy = new HeaderContentNegotiationStrategy();

configurer.strategies(Arrays.asList(parameterStrategy, headerStrategy));

}

31、 视图解析原理流程

1)目标方法处理的过程中,所有数据都会放在ModelAndViewContainer里面,包括数据和视图地址

2)方法的参数是一个自定义类型对象(从请求参数中确定的),把他重新放在ModelAndViewContainer

3)任何目标方法执行完成以后都会返回ModelAndView(数据和视图地址)

4)ProcessDispatchResult 处理派发结果(页面该如何响应)

4.1)render(mv, request, response)进行页面渲染

      4.1.1)根据方法的String返回值得到View对象【定义了页面的渲染逻辑】

                 4.1.1.1)所有的视图解析器尝试是否能根据当前返回值得到view对象

               

                 4.1.1.2)得到了redirect/main.html -> Thymeleaf new RedirectView()

                 4.1.1.3) ContentNegotiationViewResolver 里面包含了下面所有的视图解析器,内部还是利用下面所有视图解析器得到视图对象

                 4.1.1.4)view.render(mv.getModelInternal(), request, response); 视图对象调用自定义的render进行页面渲染工作

+++++RedirectView 如何渲染:【重定向到一个页面】

  1. 获取目标url地址
  2. Response.sendRedirect(encodedURL);

+++++视图解析:

  1. 返回值以forward:开始:new InternalResourceView(forwardUrl);  -》 request.getRequestDispatcher(path).forward(request, response);
  2. 返回值以redirect:开始:new RedirectView();  à render重定向
  3. 返回值是普通字符串: new ThymeleafView()

32、HandlerInterceptor拦截器

三个拦截点的示意图如下:

步骤:

  1. 编写一个拦截器实现HandlerIntercepter接口
  2. 拦截器注册到容器中(实现WebMvcConfigurer的addInterceptors)
  3. 指定拦截规则【如果是拦截所有,静态资源也会被拦截】

       示例:

编写拦截器类

public class LoginInterceptor implements HandlerInterceptor {

    /**

     * 目标方法执行完成以前

     * @param request

     * @param response

     * @param handler

     * @return

     */

    @Override

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {

        // 登录检查

        HttpSession session = request.getSession();

        Object loginUser = session.getAttribute("loginUser");

        if(loginUser != null){

            // 放行

            return true;

        }

        // 拦截住

        request.setAttribute("msg", "请先登录");

        try {

            request.getRequestDispatcher("/").forward(request, response);

        } catch (ServletException e) {

            e.printStackTrace();

        } catch (IOException e) {

            e.printStackTrace();

        }

        return false;

    }

在WebMvcConfigurer中注册一个拦截器:

    // 配置拦截器

@Override

public void addInterceptors(InterceptorRegistry registry) {

       registry.addInterceptor(new LoginInterceptor())

                     .addPathPatterns("/**")   //所有请求都被拦截,包括静态资源

                     .excludePathPatterns("/", "/login", "/css/**", "/fonts/**", "/js/**");  // 放行的请求

}

 33、拦截器的原理

1)根据当前请求,找到HandlerExecutionChain可以处理请求的handler以及handler的所有拦截器

2)先来顺序执行所有拦截器的preHandler方法

     如果当前拦截器prehandler返回为true,则执行下一个拦截器的preHandler

     如果当前拦截器返回为false,倒序执行所有已经执行了的拦截器的afterCompletion方法。

3)如果任何一个拦截器false,直接跳出不执行目标方法

4)所有拦截器都返回true,执行目标方法

5)倒序执行所有拦截器的postHandler方法

6)前面的步骤有任何异常都会直接触发afterCompletion

7)页面成功渲染完成以后,也会倒序触发afterCompletion

34、文件上传实现

流程:

  1. HTML的form中增加上传功能
  2. Controller类中处理上传请求
  3. Yaml文件中增加文件相关的配置

示例:

1)HTML编写:

2)Controller类处理上传请求:

3)yaml配置:

35、文件上传原理

文件上传自动配置类——MultipartAutoConfiguration-MultipartProperties

自动配置好了 StandardServletMultipartResolver【文件上传解析器】

原理步骤:

1)请求进来使用文件上传解析器判断(isMultipart)并封装(resolveMultipart, 返回MultipartHttpServletRequest)文件上传请求

2)参数解析器来解析请求中的文件内容封装成MultipartFile

3)将request中文件信息封装为一个Map,MultiValueMap<String, MultipartFile>

FileCopyUtils实现文件流的拷贝

36、异常处理

默认规则:

1)默认情况下,SpringBoot提供/error处理所有错误的映射

2)对于机器客户端,它将生成JSON响应,其中包含错误、HTTP状态和异常消息的详细信息;对于浏览器客户端,响应一个“whitelabel”错误视图,以HTML格式呈现相同的数据 

异常处理自动配置原理 

ErrorMvcAutoConfiguration 自动配置异常处理规则

1)容器中的组件:类型:DefaultErrorAttributes  à id: errorAttributes

2)容器中的组件:类型:BasicErrorController –》id:basicErrorController

处理默认/error路径的请求:页面响应new ModelAndView(“error”, model);

容器中有组件View -> id是error

容器中放组件BeanNameViewResolver(视图解析器):按照返回的视图名作为组件的id去容器中找View对象。

3)容器中的组件:类型DefaultErrorViewResolver -> id: conventionErrorViewResolver

如果发生错误,会以HTTP的状态码作为视图页地址(viewName),找到真正的页面

error/ViewName.html   404.html 5xx.html


37、JavaWeb三大组件(Servlet、Filter、Listener)

(1)Servlet:

作用:处理客户端请求的动态资源。

任务:

  1. 接收请求数据
  2. 处理请求:通常会在Service、doPost或者doGet方法进行接收参数,并且调用业务层(service)的方法来处理请求。
  3. 完成响应。处理完请求后,一般会转发(forward)或者重定向(redirect)到某个页面,转发是HttpServletRequest中的方法,重定向是HttpServletResponse中的方法。

生命周期:

  1. servlet的初始化方法,Servlet是单例的,整个服务器就只能创建一个同类型Servlet
  2. servlet的处理请求方法:每处理一次请求,就会被调用一次
  3. servlet销毁之前执行的方法:只执行一次

(2)Filter

       与Servlet相似,但是Servlet主要负责处理请求,而filter主要负责拦截请求和放行

(3)Listener

监听器,监听Application、Session、Request对象,当这些对象发生变化就会调用对应的监听方法。

38、Web原生组件注入(Servlet、Filter、Listener)

有两种方法,使用Servlet API和使用RegistrationBean。

在使用Servlet API中:

创建MyServlet类:

@WebServlet(urlPatterns = "/my")

public class MyServlet extends HttpServlet {

    @Override

    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        resp.getWriter().write("6666");

    }

}

在main中将servlet扫描进来

@SpringBootApplication // 这是一个SpringBoot应用

@ServletComponentScan(basePackages = "com.hugh.boot")  // 将servlet扫描进来

public class MainApplication {

使用总结:

@ServletComponentScan(basePackages = "com.hugh.boot"):指定原生Servlet组件都放在哪里

@WebServlet(urlPatterns = "/my") 效果:直接响应,没有Spring拦截器

创建MyFilter类

创建MyServletContextListener类

@Slf4j

@WebListener

public class MyServletContextListener implements ServletContextListener {

    @Override

    public void contextInitialized(ServletContextEvent sce) {

        log.info("MyServletContextListener监听项目初始化完成");

    }

}

在使用RegistrationBean中:

@Configuration(proxyBeanMethods = true) // 单例模式:保证依赖的组件始终是单例的

public class MyRegisterConfig {

    @Bean

    public ServletRegistrationBean myServlets(){

        MyServlet myServlet = new MyServlet();

        return new ServletRegistrationBean(myServlet, "/my");

    }

    @Bean

    public FilterRegistrationBean myFilter(){

        MyFilter myFilter = new MyFilter();

        return new FilterRegistrationBean(myFilter, myServlets());

    }

}

39、 DispatchServlet注入原理

1)容器中自动配置了DispatcherServlet,属性绑定到WebMvcProperties;对应的配置文件配置项是spring.mvc

2)通过ServletRegistrationBean<DispatcherServlet>把Dispatcher配置进来

3)默认映射的是 / 路径

Tomcat-Servlet:

多个Servlet都能处理同一层路径,精确优先原则

40、嵌入式Servlet容器

原理:

1)SpringBoot容器启动发现当前是web应用。Web场景-导入tomcat

2)Web应用会创建一个web版的ioc容器 ServletWebServerApplicationContext

3)ServletWebServerApplicationContext启动的时候寻找 ServletWebServerFactory(Servlet的web服务器工厂-à servlet的web服务器)

4)SpringBoot底层默认有很多的WebServer工厂

5)底层直接会有一个自动配置类,ServletWebServerFactoryAutoConfiguration

6)ServletWebServerFactoryAutoConfiguration导入了ServletWebServerFactoryConfiguration(配置类)

7)ServletWebServerFactoryConfiguration配置类,根据动态判断系统中到底导入了哪个Web服务器的包,(默认是web-starter导入tomcat包),容器中就有TomcatServletWebServerFactory

8)TomcatServletWebServerFactory创建出Tomat服务器并启动

9)内部服务器,就是手动把启动服务器的代码调用(tomcat核心jar包存在)

41、SpringBoot定制化组件

默认情况下,springboot是运行良好的,这得益于它默认的良好配置,原理如下:

场景starter -> xxxxAutoConfiguration -> 通过@Bean导入xxxx组件 -> 绑定xxxProperties -> 绑定配置文件项

 定制化的常见方式

1)修改配置文件

2)XxxxCustomizer

3)编写自定义的配置类xxxConfiguration+@Bean替换,增加容器中默认组件;视图解析器

4)Web应用实现WebMvcConfigurer即可定制化web功能

5)@EnableWebMvc+WebMvcConfigurer ----@Bean可以全面接管SpringMvc,所有规则全部自己重新配置,实现定制和扩展功能

对于5)的原理:

  • WebMvcAutoConfiguration默认的SpringMVC的自动配置功能类。静态资源、欢迎页….
  • 一旦使用@EnableWebMvc,会@Import(DelegatingWebMvcConfiguration.class)
  • DelegatingWebMvcConfiguration的作用,只保证SpringMVC最基本的使用

把所有系统中的WebMvcConfigurer拿过来,所有功能的定制都是这些WebMvcConfigurer合起来一起生效

自动配置了一些非常底层的组件。RequestMappingHandlerMapping,这些组件依赖的组件都是从容器中获取

Public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSuppor

  • WebMvcAutoConfiguration里面的配置要能生效必须

@ConfitionalOnMissingBean(WebMvcConfigurationSupport.class)

@EnableWebMvc 导致了WebMvcAutoConfiguration没有生效

42、数据库访问

1)导入JDBC场景

  • <dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-data-jdbc</artifactId>

    </dependency>

    数据库驱动?

    为什么导入JDBC场景,官方不导入驱动?官方不知道我们接下来要操作什么数据库。

    <dependency>

    <groupId>mysql</groupId>

    <artifactId>mysql-connector-java</artifactId>

    </dependency>

    想要修改版本:

  • 直接依赖引入具体版本(maven的就近依赖原则)
  • 重新声明版本,增加properties配置项。(maven的属性的就近优先原则分析)2

2)分析自动配置

自动配置的类

  • DataSourceAutoConfiguration:数据源的自动配置

       修改数据源相关的配置:spring.datasource

       数据库连接池的配置,是自己容器中没有DataSource才自动配置

       底层配置好的连接池是:HikariDataSource

  • DataSourceTransactionManagerAutoConfiguration:事务管理器的配置
  • JdbcTemplateAutoConfiguration:JdbcTemplate的自动配置,可以对数据库进行crud

可以修改这个配置项@ConfigurationProperties(prefix=”spring.jdbc”)来修改jdbcTemplate

@Bean@Primary JdbcTemplate:容器中有这个组件

3)数据库的yaml配置

datasource:

    url: jdbc:mysql://localhost:3306/test?serverTimezone=UTC

    username: root

    password: root

driver-class-name: com.mysql.jdbc.Driver

4)示例

Pom.xml添加:

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-test</artifactId>

<scope>test</scope>

</dependency>

<dependency>

<groupId>junit</groupId>

<artifactId>junit</artifactId>

<version>4.12</version>

<scope>test</scope>

</dependency>

Java代码:

@RunWith(SpringJUnit4ClassRunner.class)

@SpringBootTest

public class JDBCTest {

    @Autowired

    JdbcTemplate jdbcTemplate;

    @Test

    public void testQuery(){

        Long aLong = jdbcTemplate.queryForObject("select count(1) as cnt from account;", Long.class);

        System.out.println("记录总数:" + aLong);

    }

}

43、自定义方式整合Druid数据源

它包含了数据源的全套解决方案,包括防止SQL的注入攻击

Druid官方地址:GitHub - alibaba/druid: 阿里云计算平台DataWorks(https://help.aliyun.com/document_detail/137663.html) 团队出品,为监控而生的数据库连接池

1)pom中增加druid信息

2)构造配置类,给容器中注入DataSource的组件

@Configuration

public class MyDataSourceConfig {

    // 默认的自动配置是判断容器中没有自会配@ConfitionalOnMissingBean(DataSource.class)

    @ConfigurationProperties("spring.datasource")

    @Bean

    public DataSource dataSource() throws SQLException {

        DruidDataSource druidDataSource = new DruidDataSource();

        // 加入监控功能

        druidDataSource.setFilters("stat");

        return druidDataSource;

}

3)查看dataSource的类型

4)配置Druid监控

// 给容器中放入servlet

/**

 * 配置druid的监控页面

 * @return

 */

@Bean

public ServletRegistrationBean StatViewServlet(){

       StatViewServlet statViewServlet = new StatViewServlet();

       ServletRegistrationBean<StatViewServlet> registrationBean = new ServletRegistrationBean<>(statViewServlet, "/druid/*");

       return registrationBean;

}

44、Starter方式整合Druid

1)引入druid-starter

<dependency>

<groupId>com.alibaba</groupId>

<artifactId>druid-spring-boot-starter</artifactId>

<version>1.1.17</version>

</dependency>

2)分析自动配置

  1. 扩展配置项:spring.datasource.druid
  2. DruidSpringAopConfiguration.class,:监控spring组件
  3. DruidStatViewServletConfiguration.class,:监控页的配置
  4. DruidWebStatFilterConfiguration.class, web监控配置
  5. DruidFilterConfiguration.class:所有druid自己filter配置

所有功能都可操作yaml文件进行配置

spring->datasource:

druid:

      filter: stat,wall

      stat-view-servlet:

        enabled: true

        login-username: root

        login-password: root

      web-stat-filter:

        enabled: true

        url-pattern: /*

        exclusions: '*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*'

45、JDBC、Druid、MyBatis区别

JDBC:Java Database Connectivity java和数据库的连接技术

Druid:数据库连接池,普通JDBC数据库连接使用DriverManager来获取会出现很多问题。为了解决创痛开发中数据库的连接问题,使用数据库连接池负责分配、管理和释放数据库连接。

Mybatis:进一步封装了jdbc,sql语句写在配置文件中,面向对象操作,有一二级缓存功能。

46、配置Mybatis

1)引入mybatis包

<dependency>

<groupId>org.mybatis.spring.boot</groupId>

<artifactId>mybatis-spring-boot-starter</artifactId>

<version>2.1.0</version>

</dependency>

2)配置模式

可以修改配置文件中mybatis开始的所有

SqlSessionFactory:自动配置好了

SqlSession:自动配置了SqlSessionTemplate组合了SqlSession

Mapper:只要我们写的操作MyBatis的接口标注了@Mapper,就会被自动扫描进来

实操流程

MyBatis对应文档:mybatis – MyBatis 3 | 简介

  1. 导入mybats官方starter
  2. 编写mapper接口。标注@Mapper注释
  3. 编写sql映射文件并绑定mapper接口
  4. 在application.yaml中指定Mapper配置文件的位置,以及指定全局配置文件的信息(建议:配置在mybatis.configuration)

实操示例:(任务:获取mysql中的数据)

1)查询mysql中的数据

2)构造数据对应的Account类(Account.java)

@Data

@ToString

@NoArgsConstructor

@AllArgsConstructor

public class Account {

    private String name;

    private String phone;

}

3)创建mapper接口(AccountMapper.java)

@Mapper

public interface AccountMapper {

    public Account getAcct(String name);

}

4)编写sql映射文件(AccountMapper.xml)

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE mapper

        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"

        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.hugh.boot.mapper.AccountMapper">

    <select id="getAcct" resultType="com.hugh.boot.bean.Account">

        select * from account where name = #{name}

    </select>

</mapper>

5)yaml中增加mybatis规则(xxxmapper.xml文件读取)

# 配置mybatis规则

mybatis:

  mapper-locations: classpath: mybatis/mapper/*.xml

6)构造Service类,读取mapper中接口的数据(AccountService.java)

@Service

public class AccountService {

    @Autowired

    AccountMapper accountMapper;

    public Account getAcctByName(String name){

        return accountMapper.getAcct(name);

    }

}

7)在Controller中使用service类获取数据并返回请求结果

@Autowired

AccountService accountService;

@ResponseBody

@GetMapping("/acct")

public Account getByName(@RequestParam("name") String name){

       return accountService.getAcctByName(name);

}

       假如不希望写第4)步的mapper文件,则可以直接在mapper接口上进行注解:

其他步骤保持不变。

混合模式:注解模式和配置文件模式可以共存。

       假如mapper目录下每个类都标记@Mapper太麻烦,则可以直接在主程序中通过@MapperScan(“map的目录”)进行自动装载,这样每个mapper接口就不用@Mapper进行标注了。

最佳实战:

  1. 引入mybatis-starter
  2. 配置application.yaml,指定mapper-location位置即可
  3. 编写Mapper接口并标注@Mapper注解
  4. 简单方法直接注解方式
  5. 复杂方法编写@mapper.xml进行绑定映射
  6. @MapperScan(“xxx”)简化,其他的接口就可以不用标注@Mapper注解

47、整合MyBatisPlus

MyBatis-Plus是一个MyBatis的增强工具,在MyBatis的基础上只做增强不做改变,为简化开发,提供效率而生。

1)pom中引入依赖

<dependency>

       <groupId>com.baomidou</groupId>

       <artifactId>mybatis-plus-boot-starter</artifactId>

       <version>3.5.1</version>

</dependency>

2)自动配置

  1. MybatisPlusAutoConfiguration配置类,MybatisPlusProperties配置项绑定,mybatis-plus: xxx就是对mybatis-plus的定制
  2. SqlSessionFactory自动配置好。底层是容器中默认的数据源。(druid)
  3. MapperLocations自动配置好,有默认值。Classpath*:/mapper/**/*.xml:任意包的类路径下所有mapper文件夹下任意路径下的所有xml都是sql映射文件。建议以后sql映射文件,放在mapper下
  4. 容器中也自动配置好了SqlSessionTemplate
  5. @Mapper标注的接口也会被自动扫描,建议@MapperScan(“xxx”)批量扫描就行

优点:

只需要我们的Mapper继承BaseMapper就可以拥有crud能力

实战:

1)在mysql中创建数据

2)编写数据库对应的Bean类

@Data

@ToString

@AllArgsConstructor

@NoArgsConstructor

@TableName(“user”)  // 当表名与类名不一致时可显示指定表名

public class User {

    /**

     * 使用mybatis-plus时所有属性都应在在数据库中

     */

    @TableField(exist=false)    // 数据库中无该字段

    private String userName;

    @TableField(exist=false)

    private String password;

    private Long id;

    private String name;

    private Integer age;

    private String email;

}

3)编写Mapper接口(mybatis-plus的精华部分)

public interface UserMapper extends BaseMapper<User> {

}

只需要我们的Mapper继承BaseMapper就可以拥有crud能力

4)单元测试中调用mapper接口实现查询

@Autowired

UserMapper userMapper;

@Test

public void testMapper(){

       User user = userMapper.selectById(1L);

       System.out.println("用户信息:" + user);

}

48、通过Mybatis接口快速实现CRUD

关键点:

  1. 继承IService<T>构造Service层
  2. 继承ServiceImpl<xxxxMapper, T>实现IService<T>的默认方法
  3. 注入service即可直接使用

1)UserService接口类

public interface UserService extends IService<User> {

}

继承MyBatis中的IService,它是所有Service层的总接口,需要写一个泛型

2)UserServiceImpl实现类

@Service

public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

}

MyBatis又提供了一个对顶级Service的实现类,ServiceImpl中提供了非常多的增删改查的方法。

getxxx:查询的

list:查询的

page:分页的

remove:删除的

save:保存的

update:更新的

后续只要注入Service,就可以直接使用这些方法

3)使用

@Autowired

UserService userService;

@ResponseBody

@GetMapping("/test/query")

public List<User> queryTable(@RequestParam(value="pn", defaultValue = "1") Integer pn){

// 分页查询数据

Page<User> userPage = new Page<>(pn, 2);

// 分页查询结果

Page<User> page = userService.page(userPage, null);

log.info("page:{ }", page);

// 查询数据库中所有记录

List<User> list = userService.list();

return list;

}

49、Redis使用

安装参考:Windows 安装 Redis_redis windows_羽之大公公的博客-CSDN博客

Redis自动配置

1)pom中引入依赖

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-data-redis</artifactId>

</dependency>

2)依赖包分析

3)自动配置

  • RedisAutoConfiguration自动配置类,RedisProperties属性类-> spring.redis.xxx是对redis的配置
  • 连接工厂是准备好的。LettuceConnectionConfiguration
  • 自动注入了RedisTemplate<Object, Object>:xxxTemplate;
  • 自动注入了StringRedisTemplate
  • Key: value。
  • 底层只要我们使用StringRedisTemplate、RedisTemplate就可以操作redis

4)使用示例

Yaml中进行配置:

redis:

  url: redis://localhost:6379

测试类中编写代码:

@Autowired

StringRedisTemplate stringRedisTemplate;

@Test

public void testRedis(){

ValueOperations operations = redisTemplate.opsForValue();

operations.set("hello", "world");

String hello = (String) operations.get("hello");

System.out.println("redis返回:" + hello);

}

 50、Filter和Interceptor几乎拥有相同的功能,区别

Filter是Servlet定义的原生组件,好处,脱离Spring应用也能使用

Interceptor是Spring定义的接口,可以使用Spring的自动装配功能

51、测试类(Junit4)

1)引入包

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-test</artifactId>

<scope>test</scope>

</dependency>

2)编写测试类代码

@RunWith(SpringJUnit4ClassRunner.class)

@SpringBootTest

public class JDBCTest {

3)SpringBoot整合Junit以后

编写测试方法:@Test标注

Junit类具有Spring的功能,@Autowired,比如@Transactional标注测试方法,测试完成后自动回滚

52、指标监控

SpringBoot Actuator

未来每一个微服务在云上部署以后,我们都需要对其进行监控、追踪、审计、控制等。SpringBoot就抽取了Actuator场景,使得我们每个微服务快速引用即可获得生产级别的应用监控、审计等功能。

1)pom引入依赖包

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-actuator</artifactId>

</dependency>

2)访问http://localhost:8080/actuator/

默认情况下可以访问health和info的endpoint,其他都以jmx方式暴露,http方式没有暴露

3)yaml中配置暴露所有的http方式

# management 是所有actuator的配置

management:

  endpoints:

    enabled-by-default: true  # 默认开启所有监控端点

    web:

      exposure:

        include: '*'  # 以web方式暴露所有端点

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/19090.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Verilog语法学习——边沿检测

边沿检测 代码 module edge_detection_p(input sys_clk,input sys_rst_n,input signal_in,output edge_detected );//存储上一个时钟周期的输入信号reg signal_in_prev;always (posedge sys_clk or negedge sys_rst_n) beginif(!sys_rst_n)signal_in_prev < 0;else…

12. Mybatis 多表查询 动态 SQL

目录 1. 数据库字段和 Java 对象不一致 2. 多表查询 3. 动态 SQL 使用 4. if 标签 5. trim 标签 6. where 标签 7. set 标签 8. foreach 标签 9. 通过注解实现 9.1 查找所有数据 9.2 通过 id 查找 1. 数据库字段和 Java 对象不一致 我们先来看一下数据库中的数…

解决Hadoop审计日志hdfs-audit.log过大的问题

【背景】 新搭建的Hadoop环境没怎么用&#xff0c;就一个环境天天空跑&#xff0c;结果今天运维告诉我说有一台服务器磁盘超过80%了&#xff0c;真是太奇怪了&#xff0c;平台上就跑了几个spark测试程序&#xff0c;哪来的数据呢&#xff1f; 【问题调查】 既然是磁盘写满了&…

mysql主从配置及搭建(gtid方式)

一、搭建主从-gtid方式 搭建步骤查看第一篇。bin-log方式。可以进行搭建1.1 gtid和二进制的优缺点 使用 GTID 的主从复制优点&#xff1a; 1、简化配置&#xff1a;使用 GTID 可以简化主从配置&#xff0c;不需要手动配置每个服务器的二进制日志文件和位置。 2、自动故障转移…

MySQL 其他数据库日志

我们了解数据库事务时&#xff0c;知道两种日志&#xff1a;重做日志&#xff0c;回滚日志。 对于线上数据库应用系统&#xff0c;突然遭遇 数据库宕机 怎么办&#xff1f;在这种情况下&#xff0c;定位宕机的原因 就非常关键。我们可以查看数据库的 错误日志。因为日志中记录…

给你一个小技巧,解放办公室管理!

电力的稳定供应对于现代社会中的办公室和企业来说至关重要。为了应对这些潜在的问题&#xff0c;许多办公室和企业都采用了不间断电源&#xff08;UPS&#xff09;系统来提供电力备份。UPS可以保持关键设备的运行&#xff0c;确保生产和业务不受干扰。 然而&#xff0c;仅仅安装…

力扣468 验证IP地址

ipv4地址&#xff1a;1.必须是四个非空子串 2.每个非空子串不含前导零 3.子串里字符只能是0~255 ipv6地址&#xff1a;1.必须是八个非空子串 2。每段非空串得长度是否在1~4之间&#xff0c;且不含0-9&#xff0c;a-f&#xff0c;A-F之外得字符。 3.同时0-9也不允许含前导零 cl…

【JAVASE】什么是方法

⭐ 作者&#xff1a;小胡_不糊涂 &#x1f331; 作者主页&#xff1a;小胡_不糊涂的个人主页 &#x1f4c0; 收录专栏&#xff1a;浅谈Java &#x1f496; 持续更文&#xff0c;关注博主少走弯路&#xff0c;谢谢大家支持 &#x1f496; 方法 1. 方法概念及使用1.1 什么是方法1…

[学习笔记]全面掌握Django ORM

参考资料&#xff1a;全面掌握Django ORM 1.1 课程内容与导学 学习目标&#xff1a;独立使用django完成orm的开发 学习内容&#xff1a;Django ORM所有知识点 2.1 ORM介绍 ORM&#xff1a;Object-Relational Mapping Django的ORM详解 在django中&#xff0c;应用的文件夹…

Elisp之buffer-substring-no-properties用法(二十七)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

2023.07.29 驱动开发DAY6

通过epoll实现一个并发服务器 服务器 #include <stdio.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/epoll.h…

上位机一般的开发工具?

上位机开发工具是用于开发和构建上位机应用程序的软件工具。它们提供了一系列功能和资源&#xff0c;帮助开发人员设计、编写和调试上位机应用程序。以下是一些常见的上位机开发工具&#xff1a;Visual Studio&#xff1a;作为一种集成开发环境&#xff08;IDE&#xff09;&…

【有趣的设计模式】23 种设计模式详解和场景分析

前言 七大设计原则 1、单一原则&#xff1a;一个类只负责一个职责 2、开闭原则&#xff1a;对修改关闭&#xff0c;对扩展开放 3、里氏替换原则&#xff1a;不要破坏继承关系 4、接口隔离原则&#xff1a;暴露最小接口&#xff0c;避免接口过于臃肿 5、依赖倒置原则&#xff1…

MySQL 实现分库和分表的备份 2023.7.29

1、分库备份 [rootlocalhost mysql-backup]# cat db_bak.sh #!/bin/bash k_userroot bak_password123456 bak_path/root/mysql-backup/ bak_cmd"-u$bak_user -p$bak_password" exc_db"Database|information_schema|mysql|performance_schema|sys" dbname…

Spring之BeanDefinition(二)

Spring之BeanDefinition 文章目录 Spring之BeanDefinition1、对象和bean的区别2、BeanDefinition作用AutowireCandidate说明Primary说明ConstructorArgumentValues说明第一种使用方式第二种使用方式 MutablePropertyValuesabstract小结 3、BeanDefinition的发展历程3、BeanDefi…

pve安装ikuai并设置,同时把pve的网络连接到ikuai虚拟机

目录 前因 前置条件 安装ikuai 进入ikuai的后台 配置lan口&#xff0c;以及wan口 配置lan口桥接 按实际情况来设置了 单拨&#xff08;PPOE拨号&#xff09; 多拨(内外网设置点击基于物理网卡的混合模式) 后续步骤 pve连接虚拟机ikuai的网络以及其他虚拟机连接ikuai的网…

Arcgis地图实战一:单个图层中设施的隐藏及显示

文章目录 1.效果图预览2.弹框的实现3.显示及隐藏的实现 1.效果图预览 2.弹框的实现 let alert this.alertCtrl.create();alert.setTitle(请选择设施);for (let item of this.ctralllayers) {alert.addInput({type: checkbox,label: item.name,value: item.id,checked: item.vi…

什么是线程?为什么需要线程?和进程的区别?

目录 前言 一.线程是什么&#xff1f; 1.1.为什么需要线程 1.2线程的概念 1.3线程和进程的区别 二.线程的生命周期 三.认识多线程 总结 &#x1f381;个人主页&#xff1a;tq02的博客_CSDN博客-C语言,Java,Java数据结构领域博主 &#x1f3a5; 本文由 tq02 原创&#xf…

ChatGPT能否撰写科研论文?

ChatGPT&#xff0c;这款被许多人誉为语言处理领域的“黑马”&#xff0c;究竟能否应用于撰写科研论文&#xff1f;近期&#xff0c;以色列理工学院生物学家兼数据科学家Roy Kishony带领的团队&#xff0c;针对这一问题进行了系列研究&#xff0c;其结果已在《Nature》杂志上发…

Andorid解析XML格式数据遇到的坑

以下是《第一行代码 第三版》解析XML格式数据部分遇到的坑 一、首先是安装Apache遇到的坑 具体参考文章Apache服务器下载安装及使用&#xff08;更新&#xff09;_apache下载_★邱↓邱★的博客-CSDN博客&#xff08;可以不看文中的安装部分了&#xff09; 启动服务那块儿建议…