SpringBoot2
SpringBoot2 入门
ref:
要求
Java 8 & 兼容java14
Maven 3.3+
idea 2019.1.2
配置maven
- 默认jdk版本
<profile> <id>jdk-1.8</id> <activation> <activeByDefault>true</activeByDefault> <jdk>1.8</jdk> </activation> <properties> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion> </properties> </profile>
- 阿里云镜像
<mirror> <id>alimaven</id> <name>aliyun maven</name> <url>http://maven.aliyun.com/nexus/content/groups/public/</url> <mirrorOf>central</mirrorOf> </mirror>
HelloWorld
配置pom
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.4.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies>
- MainApplication
@SpringBootApplication // 这是一个应用 public class MainApplication { public static void main(String[] args) { SpringApplication.run(MainApplication.class, args); } }
- HelloController
@RestController public class HelloController { @RequestMapping("/") public String hello(){ return "hello SpringBoot2"; } }
main -> run
关于application.properties
可以修改配置 如 修改端口号
aserver.port = 8888
其他配置可选项详见官方文档
打包成jar
pom配置,无需配置xml,简化部署
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
运行jar
执行
java -jar xxx.jar
即可访问
pom依赖图解
Ctrl + Alt + Shift + U
@ComponentScan
默认扫描主程序所在层级的包,可以修改自定义包
@ComponentScan("com.xxx.boot")
@Configuration
示例
- 原来的配置方式
<?xml ... ?> <beans ...> <bean id="user01" class=" com.xxx.boot.bean.User"> <property name="name" value="zhangsan"></property> <property name="age" value="18"></property> </bean> </beans>
-
使用注解 @Configuration
-
创建两个实体类,User ,Pet
-
MyConfig
@Configuration // 这是一个配置类 相当于 配置了一个xml文件 public class MyConfig { /* * @Bean => 往容器中加组件 * 组件类型 => User, 组件id => user01 (函数名 或 自定义@Bean("xxx")) * */ @Bean("userXiaoMing") public User user01(){ return new User("小明", 18); } @Bean public Pet pet01(){ return new Pet("小猫咪"); } } -
MainApplication
@SpringBootApplication // 这是一个应用 public class MainApplication { public static void main(String[] args) { // IOC容器 ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args); String[] names = run.getBeanDefinitionNames(); // 查看组件 for (String name : names) { System.out.println(name); } } }
-
-
运行结果
... org.springframework.context.event.internalEventListenerFactory mainApplication org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory myConfig helloController userXiaoMing // 《- pet01 // 《- org.springframework.boot.autoconfigure.AutoConfigurationPackages org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration ... -
可以看到MyConfig本身也是一个组件
组件是单实例的
示例
- 示例一
@SpringBootApplication public class MainApplication { public static void main(String[] args) { ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args); // 获取实例 User bean1 = run.getBean("userXiaoMing", User.class); User bean2 = run.getBean("userXiaoMing", User.class); System.out.println(bean1 == bean2); System.out.println(bean1.equals(bean2)); } }
输出
true true
- 示例二
@SpringBootApplication public class MainApplication { public static void main(String[] args) { ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args); // 获取MyConfig组件 MyConfig beans = run.getBean(MyConfig.class); // 获取子组件 User user = beans.user01(); User user1 = beans.user01(); // 输出 System.out.println(user == user1); System.out.println(user.equals(user1)); } }
输出
true true
为什么
Ctrl + 鼠标左键 @Configuration 注解 可以看到
public @interface Configuration { @AliasFor( annotation = Component.class ) String value() default ""; boolean proxyBeanMethods() default true; }
proxyBeanMethods 默认为 true ,也就是说使用代理方法,每次请求组件检查是否已经存在该组件,进行重用
修改
@Configuration(proxyBeanMethods = false)
再次运行
结果
false false
同样,
User有Pet变量时,
return User实例,
User实例拿到的Pet实例
与 MyConfig的Pet实例
不相同
总结
Full -> 全模式 proxyBeanMethods = true 【需要检查,慢】
Lite -> 轻量级模式 proxyBeanMethods = false 【不需要检查,快】
@Import
MyConfig添加注解
@Import({DBAppender.class, User.class})
MainApplication
DBHelper bean = run.getBean(DBHelper.class); String[] beans = run.getBeanNamesForType(User.class); System.out.println(bean); for (String s : beans) { System.out.println(s); }
输出
ch.qos.logback.classic.db.DBHelper@36453307 com.abc.boot.bean.User userXiaoMing
@Conditional
条件装配,满足条件时才进行组件注入
示例
@ConditionalOnBean(name = "dog") @Bean("userXiaoMing") public User user01(){ return new User("小明", 18); } @Bean("cat") public Pet pet01(){ return new Pet("小猫咪"); }
存在cat组件时才往容器注入userXiaoMing
run.containsBean("userXiaoMing") // false
@ImportResource
导入Spring配置文件
MyConfig添加注解
@ImportResource("classpath:beans.xml")
beans.xml下的bean会被注册到该容器
@ConfigurationProperties
如果使用myCar会报错,
application.properties
mycar.brand = YADEA mycar.price = 2000
HelloController
@Component @ConfigurationProperties(prefix = "mycar") public class Car { private String brand; private Integer price; ... }
HelloController
@RestController public class HelloController { @Autowired // 自动注入 Car car; @RequestMapping("/car") public Car car(){ return car; } @RequestMapping("/") public String hello(){ return "hello SpringBoot2"; } }
启动程序并访问/car
{"brand":"YADEA","price":2000}
@EnableConfigurationProperties
springboot.properties
mycar.brand = YADEA mycar.price = 2000
MyConfig
@EnableConfigurationProperties(Car.class) // 开启配置绑定功能 自动注册到容器
Car
@ConfigurationProperties(prefix = "mycar") // 此时只需 @ConfigurationProperties
小技巧
Lombok
安装
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency>
file -> settings -> plugins 搜索并安装lombok插件
使用
标注了@Data的类自动生成setter、getter方法,
标注了@toString的类自动生成toString方法
@NoArgsConstructor -> 无参构造器
@AllArgsConstructor -> 全参构造器
@EqualsAndHashCode -> 按照属性重写哈希值
@Slf4j 的使用
@Slf4j // << @RestController public class HelloController { @RequestMapping("/") public String hello() { log.info("收到请求..."); // << return "hello SpringBoot2"; } }
dev-tools
Restart
安装
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> </dependency>
使用
代码更新后,Ctrl + F9 或 Buid -> Build Project
Spring Initailizr
安装
idea商业版自带
使用
file -> new project -> Spring Initailizr
可选配置
YAML
格式
k: v k: (k1: v1,k2: v2) 或 k: k1: v1 k2: v2
数组
k: [v1, v2, v3] 或 k: - v1 - v2 - v3
单双引号有区别,特殊字符处理
单引号下转义(行为改变)
双引号下不转义(行为不改变)
示例
java
@Data @ToString @NoArgsConstructor @AllArgsConstructor @ConfigurationProperties(prefix = "person") public class Person { private String name; private String gender; private Integer age; private Integer height; private String[] interests; private Map<String,Object> score; private Map<String, List<Pet>> allPets; }
yml
person: name: 张三 gender: 男 age: 18 height: 180 interests: [游泳,篮球] score: java: 80 c++: 81 html: 82 allPets: pet1: - dog - cat
yml提示-processor
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency>
排除-processor
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <excludes> <exclude> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> </exclude> </excludes> </configuration> </plugin> </plugins> </build>
目录结构
Web开发
静态资源路径默认配置
- ResourceProperties
//21 private static final String[] CLASSPATH_RESOURCE_LOCATIONS = new String[]{"classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/"};
区分静态资源
静态资源与web请求区分开
增加前缀/res
spring: mvc: static-path-pattern: /res/**
或者
# 修改默认 spring: resources: static-locations: classpath:/static
多个
resources: static-locations: [classpath:/static, classpath:/public]
webjars
引入jar
<dependency> <groupId>org.webjars</groupId> <artifactId>jquery</artifactId> <version>3.5.1</version> </dependency>
引用
http://localhost:8080/webjars/jquery/3.5.1/jquery.js
welcome与favicon
-
静态资源路径下index.html
-
可以配置静态资源路径
-
但是不可以配置静态资源的访问前缀。否则导致index.html不能被默认访问
spring: # mvC: # static-path-pattern: /res/** 这个会 导致welcome page 和 favicon 功能失效 resources: static- locations: [classpath: /haha/]
-
-
controller能处理/index
源码分析
静态资源管理
配置文件相关属性绑定
ResourceProperties => spring.resources
WebMvcProperties => spring.mvc
...
@Configuration(proxyBeanMethods = false) @ConditionalOnWebApplication(type = Type.SERVLET) @ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class }) @ConditionalOnMissingBean(WebMvcConfigurationSupport.class) @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10) @AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class }) public class WebMvcAutoConfiguration { ... @Configuration(proxyBeanMethods = false) @Import(EnableWebMvcConfiguration.class) @EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class }) @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) { this.resourceProperties = resourceProperties; this.mvcProperties = mvcProperties; this.beanFactory = beanFactory; this.messageConvertersProvider = messageConvertersProvider; this.resourceHandlerRegistrationCustomizer = resourceHandlerRegistrationCustomizerProvider.getIfAvailable(); this.dispatcherServletPath = dispatcherServletPath; this.servletRegistrations = servletRegistrations; } ... } ... }
静态资源访问处理代码
@Override public void addResourceHandlers(ResourceHandlerRegistry registry) { if (!this.resourceProperties.isAddMappings()) { logger.debug("Default resource handling disabled"); return; } Duration cachePeriod = this.resourceProperties.getCache().getPeriod(); CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl(); if (!registry.hasMappingForPattern("/webjars/**")) { customizeResourceHandlerRegistration(registry.addResourceHandler("/webjars/**") .addResourceLocations("classpath:/META-INF/resources/webjars/") .setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl)); } String staticPathPattern = this.mvcProperties.getStaticPathPattern(); if (!registry.hasMappingForPattern(staticPathPattern)) { customizeResourceHandlerRegistration(registry.addResourceHandler(staticPathPattern) .addResourceLocations(getResourceLocations(this.resourceProperties.getStaticLocations())) .setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl)); } }
Rest映射
OrderedHiddenHttpMethodFilter
HiddenHttpMethodFilter
页面表单的PUT、DELETE请求等需要开启过滤(不开启表单只需要携带_method参数过去)
spring: mvc: hiddenmethod: filter: enabled: true # 开启页面表单的Rest功能
默认的_method可修改,代码如下
@Configuration(proxyBeanMethods = false) public class WebConfig { @Bean public HiddenHttpMethodFilter hiddenHttpMethodFilter(){ HiddenHttpMethodFilter methodFilter = new HiddenHttpMethodFilter(); methodFilter.setMethodParam("_custom"); return methodFilter; } }
请求映射x
请求处理
常用注解
普通参数与基本注解
- 注解:
@PathVariable、@RequestHeader、 @ModelAttribute、 @RequestParam、 @MatrixVariable、 @CookieValue、
@RequestBody - Servlet API:
WebRequest、ServletRequest、 MultipartRequest、 HttpSession、 javax.servlet.http.PushBuilder、 Principal、
InputStream、Reader、 HttpMethod、 Locald、 TimeZone、 Zoneld - 复杂参数:
Map、Errors/BindingResult、 Model、 RedirectAttributes、 ServletResponse、 SessionStatus、
UriComponentsBuilder、ServletUriComponentsBuilder - 自定义对象参数:
可以自动类型转换与格式化,可以级联封装。
Thymeleaf
引入
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>
配置
自动配置
@Configuration(proxyBeanMethods = false) @EnableConfigurationProperties(ThymeleafProperties.class) @ConditionalOnClass({ TemplateMode.class, SpringTemplateEngine.class }) @AutoConfigureAfter({ WebMvcAutoConfiguration.class, WebFluxAutoConfiguration.class }) public class ThymeleafAutoConfiguration {}
SpringTemplateEngine...
路径
@ConfigurationProperties(prefix = "spring.thymeleaf") public class ThymeleafProperties { private static final Charset DEFAULT_ENCODING = StandardCharsets.UTF_8; public static final String DEFAULT_PREFIX = "classpath:/templates/"; public static final String DEFAULT_SUFFIX = ".html"; ... }
简单体验
模板代码
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1 th:text="${msg}">默认H1内容</h1> <h2> <a href="http://www.bilibili.com" th:href="${link}">$去B站</a><br> <a href="http://www.bilibili.com" th:href="@{link}">@去B站</a><br> </h2> </body> </html>
结果
<h1>hello Thymeleaf</h1> <a href="http://www.bilibili.com">$去B站</a><br> <a href="link">@去B站</a><br>
拦截器
登录拦截与静态资源放行
拦截示例
@Configuration public class AdminWebConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new LoginInterceptor()) .addPathPatterns("/**")// 拦截所有 .excludePathPatterns("/", "/login"); } }
public class LoginInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { HttpSession session = request.getSession(); Object loginUser = session.getAttribute("loginUser"); System.out.println("loginUser == null ?" + (loginUser == null)); if (loginUser != null){ return true; } response.sendRedirect("/"); return false; } ... }
放行静态资源示例
.excludePathPatterns("/", "/login","/css/**","/js/**","/img/**","/font/**");
postHandle 处理完preHandle执行
afterCompletion 渲染完页面后执行
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 提示词工程——AI应用必不可少的技术
· 字符编码:从基础到乱码解决
· 地球OL攻略 —— 某应届生求职总结