springBoot自动装配原理探究&springBoot配置类&Thymeleaf模板引擎

微服务

微服务是一种架构风格,由于单体架构不利于团队协作完成并且代码量较大,后期维护成本较高,逐渐有了微服务架构。微服务是将一个项目拆分成不同的服务,各个服务之间相互独立互不影响,互相通过轻量级机制通信比如http通信。各个服务模块可以看成是一个单独的项目,可以由不同的编程语言,不同的数据存储技术进行开发,从而有效的实现“松耦合”。**微服务的目的就在于拆分应用、模块独立开发和部署。**相比于单体架构,微服务最大的优势就是实现了拆分应用、统一管理。

什么是springBoot

SpringBoot是一款基于Spring的快速开发框架,使用springBoot可以快速开发spring应用

springBoot为了简化使用ssm的大量复杂的配置文件,因此它内置了大量的市面主流组件,而任何一个springBoot内置的组件都对应有一个配置类。比如模板引擎thymeleaf对应的配置类ThymeleafProperties。并且我们依然可以在此基础上继续扩展或者进行其他配置,可以通过application.yml或者application.properties进行配置

SpringBoot内部集成了TomCat,不需要额外的配置,启动主程序即可运行

搭建SpringBoot

Spring内置了大量的第三方组件供我们使用,我们不再需要单独的去导入这些组件的依赖,这些组件都位于spring-boot-starter-xxx中可以理解为是一个启动器。并且spring也提供了这些组件的各个参数,来实现自定义组件开发,spring会根据我们的配置文件以及所导入的启动器来进行自动装配,自动装配是spring的核心所在
自动装配基于启动器,启动器配置依赖在Pom.xml文件中,比如

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

将需要使用的依赖项配置即可,官网示例

在这里插入图片描述

下面是spring提供的主程序,也就是整个项目的入口。因为spring已经内置了一些服务器组件比如tomcat,我们从主程序启动就会由spring来完成服务器的项目部署以及运行。

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

spring自动装配原理

@SpringBootApplication注解,其中包含

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
// 上述四个是定义注解需要  核心注解是下面三个
@SpringBootConfiguration  // SpringBoot配置
@EnableAutoConfiguration  //  自动配置
@ComponentScan(   // 扫描包
  excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
  ), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
  )}
)

可以看到@SpringBootApplication是一个符合注解,也就是说如果直接定义@SprngBootConfiguration、@EnableAutoConfiguration、@ComponentScan三个注解也可以启动项目

@SpringBootConfigUration的内部其实是一个@Configuration注解,其作用就是将该注解所修饰的当前类作为配置类并且交给Spring容器托管,那么spring在扫描配置时便会扫描到该类,配置即可生效

@ComponentScan扫描包,相当于在spring的application-context.xml文件中去配置了conext:component-scan,如果不配置路径就会扫描当前所在包及其子包中的所有注解。目的就是让@Controller、@Service等注解生效

@EnableAutoConfiguration是实现自动装配的关键,它包含两个注解分别是@Import和@AutoConfigurationPackage
@Import引入了一个类AutoConfigurationImportSelector.class
该类是完成自动装配的重点:

  1. 先看该类下的selectImports方法,
public String[] selectImports(AnnotationMetadata annotationMetadata) {
  // 判断注解的数据是否存在
  if (!this.isEnabled(annotationMetadata)) {
    // 没有数据九返回  No-IMPORTS一个空的String数组
    return NO_IMPORTS;
  } else {
    // 否则将注解数据封装为自动配置的实体对象
    AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);
    return 
// 获取注解中的全部数据并转换成String数组  返回
StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
  }
}
  1. 点开封装注解数据的方法getAutoConfigurationEntry(annotationMetadata)

在这里插入图片描述

  1. getCandidateConfigurations方法:
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
  List<String> configurations = new ArrayList(SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader()));
  ImportCandidates.load(AutoConfiguration.class, this.getBeanClassLoader()).forEach(configurations::add);
  Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories nor in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you are using a custom packaging, make sure that file is correct.");
  return configurations;
}

可以发现当中给出了错误提示:根据@EnableConfiguration的全限定名去META-INF/spring.factories文件中获取我们需要导入的类,
@EnableConfiguration全限定名为:

org.springframework.boot.autoconfigure.EnableAutoConfiguration

最终会找到文件spring.factories,也就是大量需要自动装配的类

在这里插入图片描述
@AutoConfigurationPackage就是将主程序所在的包作为自动配置的包,spring默认会扫描本包及子包下的注解

@ConfigurationProperties注解可以将该配置类中的每一个属性值映射到yml文件当中进行绑定 该注解提供prefix字段用于指定yml同名的属性,我们可以使用该注解指定配置类

松散绑定:yml中的属性字段可以使用-进行风格,则其对应配置类中的属性就是连接-前后的字段并改为驼峰命名的属性。
例如:yml文件中:student-count对应student类中的studentCount属性,与mybatis中的驼峰命名映射类似

yml语法:

# 以key-value形式存储  key不能重复
server:
port: 8081
# 对象 行内写法
student: { name: yuqu,age: 13 }
# 对象
student2:
name: yuqu
age: 13
# 数组
students:
- 张三
- 李四
- 王五

进行配置时,你可以使用@Value注解直接为某字段赋值,也可以使用properties文件进行赋值,但是两者都没有yml更加灵活

JSR303校验

@Validatad数据校验注解,放在配置类的声明上,放置后则可以在该类下的字段上进行其他具体的校验配置,比如邮箱@Email()则该字段必须符合邮箱格式,否则报错,记得要添加JSR303校验的启动器,就是依赖

<!--        JSR303数据校验-->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-validation</artifactId>
</dependency>
@Validated
public class Person {
  @Email()
  private String name;

常用HSR303注解

空检查
  @Null       验证对象是否为null
  @NotNull    验证对象是否不为null, 无法查检长度为0的字符串
  @NotBlank 检查约束字符串是不是Null还有被Trim的长度是否大于0,只对字符串,且会去掉前后空格.
  @NotEmpty 检查约束元素是否为NULL或者是EMPTY.

  Booelan检查
  @AssertTrue     验证 Boolean 对象是否为 true  
  @AssertFalse    验证 Boolean 对象是否为 false  

  长度检查
  @Size(min=, max=) 验证对象(Array,Collection,Map,String)长度是否在给定的范围之内  
  @Length(min=, max=) Validates that the annotated string is between min and max included.

  日期检查
  @Past           验证 DateCalendar 对象是否在当前时间之前  
  @Future     	验证 DateCalendar 对象是否在当前时间之后  
  @Pattern    	验证 String 对象是否符合正则表达式的规则

  数值检查,建议使用在Stirng,Integer类型,不建议使用在int类型上,因为表单值为“”时无法转换为int,但可以转换为Stirng"",Integernull
  @Min            验证 NumberString 对象是否大等于指定的值  
  @Max            验证 NumberString 对象是否小等于指定的值  
  @DecimalMax 被标注的值必须不大于约束中指定的最大值. 这个约束的参数是一个通过BigDecimal定义的最大值的字符串表示.小数存在精度
  @DecimalMin 被标注的值必须不小于约束中指定的最小值. 这个约束的参数是一个通过BigDecimal定义的最小值的字符串表示.小数存在精度
  @Digits     验证 NumberString 的构成是否合法  
  @Digits(integer=,fraction=) 验证字符串是否是符合指定格式的数字,interger指定整数精度,fraction指定小数精度。

  @Range(min=, max=) 检查数字是否介于min和max之间.
  @Range(min=10000,max=50000,message="range.bean.wage")
  private BigDecimal wage;

@Valid  递归的对关联对象进行校验, 如果关联对象是个集合或者数组,那么对其中的元素进行递归校验,如果是一个map,则对其中的值部分进行校验.(是否进行递归验证)

  @CreditCardNumber 信用卡验证
  @Email  验证是否是邮件地址,如果为null,不进行验证,算通过验证。
  @ScriptAssert(lang= ,script=, alias=)

  @URL(protocol=,host=, port=,regexp=, flags=)

SpringBoot核心:自动配置

导入静态资源

  1. 可以使用下面方式处理静态资源

    1. webjars
    2. public
    3. static
    4. /* *
    5. resource
  2. 这些是spring规定的默认扫描静态资源的位置,优先级为

    static > public > resource

在这里插入图片描述

定制首页:

默认情况下spring会在静态资源中寻找名叫index.html的页面作为首页
在templates下面的所有页面只能通过controller进行跳转,但需要模板引擎的支持

thymeleaf模板引擎

导入依赖

<!--     thymeleaf模板引擎   -->
<dependency>
  <groupId>org.thymeleaf</groupId>
  <artifactId>thymeleaf-spring5</artifactId>
</dependency>
<dependency>
  <groupId>org.thymeleaf.extras</groupId>
  <artifactId>thymeleaf-extras-java8time</artifactId>
</dependency>

之前在使用springmvc开发时,依然是使用jsp视图与后端进行数据交互。但是spring并不推崇使用jsp,因为jsp的前后端耦合性过高。spring推荐使用html,只负责前端视图的展示,而数据交互就使用模板引擎比如上面提到的thymeleaf。简单来说就是之前我们使用servlet+jsp 换成了现在的servlet+thymeleaf+html

  1. 所有的模板引擎卸载templates包下
  2. 必须是以.html后缀结尾
  3. 引入命名空间:<html lang="en" xmlns:th="http://www.thymeleaf.org">

示例:

@Controller
// 自动交由thymeleaf解析,并跳转至templates下的hello页面
// 注意如果没有配置thymeleaf依赖是无法跳转的
public class controller {
  @RequestMapping(value = "/hello")
  public String hello(){
    return "hello";
  }
}

由此,我们不需要再去配置springmvc的视图解析器并配置指定包下的.jsp文件后缀,全部交由模板引擎thymeleaf可以正常完成跳转

一些常用的thymeleaf语法:

<!--th:text 设置当前元素的文本内容,常用,优先级不高-->
<p th:text="${thText}" />
<!--th:value 设置当前元素的value值,常用,优先级仅比th:text高-->
<input type="text" th:value="${thValue}" />
<!-- 遍历数组 -->
<div>
    <p th:each="user: ${users}" th:text="${user}"></p>
</div>
<!--th:if 条件判断,类似的有th:switch,th:case,优先级仅次于th:each, 其中#strings是变量表达式的内置方法-->
<p th:text="${thIf}" th:if="${not #strings.isEmpty(thIf)}"></p>
<!-- 使用format函数指定格式 -->
th:text="${#dates.format(emp.getBirth(),'yyyy-MM-dd HH:mm:ss')}"
<!-- restFul风格传参 -->
th:href="@{/delete/}+${emp.getId()}"
<!--  js函数传参  -->
th:οnclick="update([[${emp.getId()}]])"

fragment抽取公共页面

在需要抽离的html中的最大标签定义th:fragment="sidebar",名称可以自定义,在需要引入的地方插入th:insert="~{dashboard::sidebar}",对应dashboard就是页面名称,后边为自定义字段

自动配置SpringMVC

自动转换器:前端提交的数据,经自动转换器自动封装为后台接收的对象
视图解析器、静态资源支持等等这些是SpringBoot已经内置好的springmvc的特性,我们依然可以通过手动去继续扩展其他配置比如拦截器、格式化器等等

自定义配置类,实现WebMvcConfigurer接口,利用@Configuration注解修饰,而且不能标注@EnableWebMvc。以自定义视图解析器DispatcherServlet为例:

@Configuration
public class MyConfig implements WebMvcConfigurer {
  public static class MyViewResolver implements ViewResolver{
    @Override
    public View resolveViewName(String viewName, Locale locale) throws Exception {
      return null;
    }
  }
  @Bean
  public ViewResolver myViewResolver(){
    return new MyViewResolver();
  }
}

排错关于静态资源加载

针对thymeleaf加载静态资源时出现No mapping for GET /css/bootstrap.min.css等一系列资源找不到的问题,原因是利用@EnableWebMvc注解修饰了配置类,导致springBoot无法根据默认的静态资源位置进行扫描所以找不到。解决方法两种:

  1. 取出@EnableWebMvc注解
  2. 实现WebMvcConfigurer接口之后重新定义CLASSPATH_RESOURCE_LOCATIONS静态资源路径和资源处理器,如下
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = {
  "classpath:/META-INF/resources/", "classpath:/resources/",
  "classpath:/static/", "classpath:/public/" };

// 资源处理
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
  if (!registry.hasMappingForPattern("/webjars/**")) {
    registry.addResourceHandler("/webjars/**").addResourceLocations(
      "classpath:/META-INF/resources/webjars/");
  }
  if (!registry.hasMappingForPattern("/**")) {
    registry.addResourceHandler("/**").addResourceLocations(
      CLASSPATH_RESOURCE_LOCATIONS);
  }

国际化消息转换LocaleResolver(区域设置解析)

配置i18n文件:在这里插入图片描述在这里插入图片描述

分别对应英文和中文,配置完成后修改前端界面的具体字段,以“请 登 录”为例:

<h1 class="h3 mb-3 font-weight-normal" th:text="#{login.login}">Please sign in</h1>

也可以继续进行扩展,利用a标签实现点击切换中英文对照,如下:

<a class="btn btn-sm" th:href="@{/index.html(lang='zh_CN')}">中文</a>
<a class="btn btn-sm" th:href="@{/index.html(lang='en_US')}">English</a>

配置地区分解组件,并将其注入到配置类中托管给spring

// 地区分解  视图中英文调换
public class MyLocaleResolve implements LocaleResolver {
  // 解析请求
  @Override
  public Locale resolveLocale(HttpServletRequest request) {
    // 获取请求的语言参数
    String lang = request.getParameter("lang");
    System.out.println("获取到视图传回的lang="+lang);
    // 默认语言参数
    Locale locale = Locale.getDefault();
    if (!StringUtils.isEmpty(lang)){
      // 不为空  使用请求的语言
      String[] s = lang.split("_");
      locale = new Locale(s[0], s[1]);
    }
    return locale;
  }
  @Override
  public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
  }
}

注入@Configuration配置类中

// 自定义地区分解组件注入  生效
@Bean
public LocaleResolver localeResolver(){
  return new MyLocaleResolve();
}

yml配置:

spring:
  # 关闭thymeleaf缓存
  thymeleaf:
    cache: false
    # 配置中英转换
  messages:
    basename: i18n.login

拦截器

设置未登录用户权限,拦截请求

  1. 自定义登录拦截器 LoginHandlerInterceptor实现HandlerInterceptor接口并重写preHandle方法,根据用户是否登录和请求url进行判断,
// 登录拦截器
public class LoginHandlerInterceptor implements HandlerInterceptor {
  // 配置拦截器 请求拦截
  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    // 查看当前用户是否已经登录
    Object currentUser = request.getSession().getAttribute("currentUser");
    if (currentUser==null){
      request.setAttribute("message","没有权限,请先登录!");
      // 没有登录返回登陆界面
 request.getRequestDispatcher("/index.html").forward(request,response);
      return false;
    }else {
      return true;
    }
  }
}
  1. 向配置类中注入自定义的拦截器
// 注入自定义拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
  registry.addInterceptor(new LoginHandlerInterceptor()).addPathPatterns("/**")
.excludePathPatterns("/index.html","/","/user/login","/css/*","/js/*","/img/*");
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

绿仔牛奶_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值