SpringBoot

概述

  • Spring Boot 可以轻松创建独立的、生产级的基于 Spring 的应用程序,您可以“直接运行”。

特征

  • 创建独立的 Spring 应用程序
  • 直接嵌入Tomcat,Jetty或Undertow(无需部署WAR文件)

  • 提供固执己见的“入门”依赖项以简化构建配置

  • 尽可能自动配置 Spring 和第三方库

  • 提供生产就绪功能,如指标、运行状况检查和外部化配置

  • 绝对无需生成代码,也无需 XML 配置

什么是微服务?

  • 微服务是一种架构风格,它要求我们在开发一个应用的时候,这个应用必须构建成一系列小服务的组合;可以通过http的方式进行互通。

SpringBoot原理

自动配置:
pox .xml

  • spring-boot-dependencies:核心依赖在父工程中
  • 当引入一些SpringBoot以来的时候,不需要指定版本,因为有版本仓库

启动器

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-staeter</artifactId>
</dependency>
  • 启动类:说白了就是SpringBoot的启动场景
  • 比如spring-boot-starter-web ,它会帮我们自动导入web环境的所有依赖。
  • springboot会将所有的功能场景都变成一个个启动器

主程序


//@SpringBootApplication:标注这个类是一个springboot的应用
@SpringBootApplication
public class AliyunApplication {public static void main(String[] args) {//将springboot应用启动SpringApplication.run(AliyunApplication.class, args);}}

注解

@SpringBootConfiguration :springboot的配置@Configuration :spring配置类@Component:说明这是一个spring的组件
@EnableAutoConfiguration 自动配置@AutoConfigurationPackage:自动配置包@Import({AutoConfigurationImportSelector.class}):导入选择 

结论: springboot所有自动加载都是在启动的时候扫描并加载spring.factories所有的自动配置类都在这里面,但不一定生效,要判断条件是否成立,只需要导入对应的start,就有对应的启动器了,有了启动其自动配置就会成效,然后配置成功。

  1. springboot在启动的时候,从类路径下/META-INF/spring.factories获取指定的值;
  2. 将这些自动配置的类导入容器,自动配置就会生效,帮我们进行自动配置!
  3. 以前我们需要自动配置的东西,现在springboot就帮我们做了。
  4. 整个javaEE解决方案与自动配置的东西都在spring-boot-autoconfigure-2.6.11.jar这个包下
  5. 它会把所有需要导入的组件,以类名的形式返回,这些组件就会北添加到容器;
  6. 容器中也会存在非常多的xxxAutoConfiguration的文件(@Bean),就是这邪恶类给容器中导入了所有的组件;并自动配置,@Configuration,JavaConfig
  7. 有了这些自动配置类,免去了我们手动编写配置文件的工作!

yaml

简介:YAML(/ˈjæməl/,尾音类似camel骆驼)是一个可读性高,用来表达数据序列化的格式。YAML参考了其他多种语言,包括:C语言、Python、Perl,并从XML、电子邮件的数据格式(RFC 2822)中获得灵感。Clark Evans在2001年首次发表了这种语言,另外Ingy döt Net与Oren Ben-Kiki也是这语言的共同设计者。当前已经有数种编程语言或脚本语言支持(或者说解析)这种语言。

基本语法

server:port: 8080#普通的的key-value
name: springboot#对象
student:name: zhangsanage: 20#行内写法
teacher: { name: lisi,age: 22 }#数组
pets:- cat- dog- pigAnimals: [cat,dog,pig]

yaml可以直接给实体类赋值。
Dog类

package com.example.aliyun.pojo;import org.springframework.stereotype.Component;@Component
public class Dog {private String name;private Integer age;public Dog() {}public Dog(String name, Integer age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}@Overridepublic String toString() {return "Dog{" +"name='" + name + '\'' +", age=" + age +'}';}
}

Person类:

package com.example.aliyun.pojo;import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;import java.util.Date;
import java.util.List;
import java.util.Map;@Component
@ConfigurationProperties(prefix = "person")
public class Person {private String name;private Integer age;private Boolean happy;private Date birthday;private Map<String, Object> maps;private List<Object> list;private Dog dog;public Person() {}public Person(String name, Integer age, Boolean happy, Date birthday, Map<String, Object> maps, List<Object> list, Dog dog) {this.name = name;this.age = age;this.happy = happy;this.birthday = birthday;this.maps = maps;this.list = list;this.dog = dog;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}public Boolean getHappy() {return happy;}public void setHappy(Boolean happy) {this.happy = happy;}public Date getBirthday() {return birthday;}public void setBirthday(Date birthday) {this.birthday = birthday;}public Map<String, Object> getMaps() {return maps;}public void setMaps(Map<String, Object> maps) {this.maps = maps;}public List<Object> getList() {return list;}public void setList(List<Object> list) {this.list = list;}public Dog getDog() {return dog;}public void setDog(Dog dog) {this.dog = dog;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +", happy=" + happy +", birthday=" + birthday +", maps=" + maps +", list=" + list +", dog=" + dog +'}';}
}

application.yaml

person:name: lisiage: 18happy: falsebirthday: 2023/1/1maps: {hight: 188,weight: 72}list:- code- music- filmdog:name: 小黑age: 2

Test测试类

package com.example.aliyun;import com.example.aliyun.pojo.Person;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;@SpringBootTest
class AliyunApplicationTests {@Autowiredprivate Person person;@Testvoid contextLoads() {System.out.println(person);}}

运行结果

值得注意的是yaml可以使用${}
Dog类

package com.example.aliyun.pojo;import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;@Component
@ConfigurationProperties(prefix = "dog")
public class Dog {private String name;private Integer age;public Dog() {}public Dog(String name, Integer age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}@Overridepublic String toString() {return "Dog{" +"name='" + name + '\'' +", age=" + age +'}';}
}

applicat.yaml

dog:name: 小黑${random.uuid}age: ${random.int}

测试类

package com.example.aliyun;import com.example.aliyun.pojo.Dog;
import com.example.aliyun.pojo.Person;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;@SpringBootTest
class AliyunApplicationTests {@Autowiredprivate Dog dog;@Testvoid contextLoads() {System.out.println(dog);}}

运行结果

松散绑定
比如我们在yaml中写的是last-name在类中的属性为驼峰命名法的lastName,这两个之间还是可以绑定起来
Dog类

package com.example.aliyun.pojo;import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;@Component
@ConfigurationProperties(prefix = "dog")
public class Dog {private String lastName;private Integer age;public Dog() {}public Dog(String lastName, Integer age) {this.lastName = lastName;this.age = age;}public String getLastName() {return lastName;}public void setLastName(String lastName) {this.lastName = lastName;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}@Overridepublic String toString() {return "Dog{" +"lastName='" + lastName + '\'' +", age=" + age +'}';}
}

application.yaml

dog:last-name: 小黑${random.uuid}age: ${random.int}

运行结果

JSR303校验:就是在字段上增加一层过滤器验证,可以保证数据的合法性


测试一下
Person类

package com.example.aliyun.pojo;import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;import java.util.Date;
import java.util.List;
import java.util.Map;
import javax.validation.constraints.Email;@Component
@ConfigurationProperties(prefix = "person")
@Validated
public class Person {@Email(message = "你的邮箱格式错了")private String name;private Integer age;private Boolean happy;private Date birthday;private Map<String, Object> maps;private List<Object> list;private Dog dog;public Person() {}public Person(String name, Integer age, Boolean happy, Date birthday, Map<String, Object> maps, List<Object> list, Dog dog) {this.name = name;this.age = age;this.happy = happy;this.birthday = birthday;this.maps = maps;this.list = list;this.dog = dog;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}public Boolean getHappy() {return happy;}public void setHappy(Boolean happy) {this.happy = happy;}public Date getBirthday() {return birthday;}public void setBirthday(Date birthday) {this.birthday = birthday;}public Map<String, Object> getMaps() {return maps;}public void setMaps(Map<String, Object> maps) {this.maps = maps;}public List<Object> getList() {return list;}public void setList(List<Object> list) {this.list = list;}public Dog getDog() {return dog;}public void setDog(Dog dog) {this.dog = dog;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +", happy=" + happy +", birthday=" + birthday +", maps=" + maps +", list=" + list +", dog=" + dog +'}';}
}

application.yaml

person:name: lisiage: 18happy: falsebirthday: 2023/1/1maps: {hight: 188,weight: 72}list:- code- music- filmdog:last-name: 小黑age: 2

测试类

package com.example.aliyun;import com.example.aliyun.pojo.Dog;
import com.example.aliyun.pojo.Person;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;@SpringBootTest
class AliyunApplicationTests {@Autowiredprivate Person person;;@Testvoid contextLoads() {System.out.println(person);}}

运行结果

多环境配置以及配置文件位置

配置文件位置

  1. file:./config/
  2. file:./
  3. classpath:./config/
  4. classpath:./

优先级顺序

多环境配置

方式一(application.properties)
现在有三个端口【默认:8081】【开发环境:8081】【测试环境:8082】

application.properties

server.port=8080

application-dev.properties

server.port=8081

application-test.properties

server.port=8082

springboot的多环境配置:可以选择激活哪一个文件配置

application.properties

spring.profiles.active=dev

运行结果

application.properties

spring.profiles.active=test

运行结果


方式二(application.yaml)[推荐使用]
注意:---为分割线,分割其他环境
spring: profiles:的作用相当于起名称
application.yaml

server:port: 8080---
server:port: 8081
spring:profiles: dev
---
server:port: 8082
spring:profiles: test

这就相当于方式一的三个文件了
springfiles: active:选择要激活的版本
比如现在需要激活dev环境
applicat.yaml

server:port: 8080
spring:profiles:active: dev
---
server:port: 8081
spring:profiles: dev
---
server:port: 8082
spring:profiles: test

运行结果

如果现在需要激活test环境

server:port: 8080
spring:profiles:active: test
---
server:port: 8081
spring:profiles: dev
---
server:port: 8082
spring:profiles: test

运行结果

由此可以发现yaml格式要方便的多

自动装配原理的精髓重点

  1. SpringBoot启动会加载大量的自动配置类
  2. 我们看我们需要的功能有没有在SpringBoot默任写好的自动配置类当中;
  3. 我们再来看这个自动装配类中到底配置了哪些组件;(只要我们要用的组件存在其中,我们就不再需要手动配置了)
  4. 给容器中自动配置类添加组件的时候,会从properties类中获取某些属性。我们只需要在配置文件中指定这些属性的值即可。
    xxxAutoConfiguration:自动配置类;给容器中添加组件;
    xxxPeoperties:封装配置文件中的相关属性;
    通过springboot配置 ...yaml去修改属性

可以通过debug: ture查看哪些自动配置类生效,哪些自动配置类没有生效
运行结果


springWeb开发

首先要解决的问题

  • 导入静态资源…
  • 固定首页
  • jsp,模板引擎Thymeleaf
  • 装配扩展SpringMVC
  • 增删改查
  • 拦截器
  • 国际化
静态资源
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {if (!this.resourceProperties.isAddMappings()) {logger.debug("Default resource handling disabled");return;}addResourceHandler(registry, "/webjars/**", "classpath:/META-INF/resources/webjars/");addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> {registration.addResourceLocations(this.resourceProperties.getStaticLocations());if (this.servletContext != null) {ServletContextResource resource = new ServletContextResource(this.servletContext, SERVLET_LOCATION);registration.addResourceLocations(resource);}});
}

什么是webjars
Webjars本质就是以jar包的方式引入我们的静态资源 , 我们以前要导入一个静态资源文件,直接导入即可。
例如以maven的方式引入jQuery

<dependency><groupId>org.webjars</groupId><artifactId>jquery</artifactId><version>3.4.1</version>
</dependency>

第一种方式


当这三种方式同时存在时比较优先级

结论:当三种方式同时存在时:resources包下面的优先级最高

删除resources包下的1.js,比较剩下两种的优先级

再删除static包下的1.js,

结论 优先级从高到低:resources->static->public


1. 在springboot中我们可以使用以下方式处理静态资源

  • webjars 访问方式:localhost:8080/webjars/
  • resources、static、public ,/** 访问方式:localhost:8080/

2. 优先级:resource>static>public
3.当我们自定义了一个访问静态资源的路径,那么默认的路径都会失效
例如:

spring:mvc:static-path-pattern: "/hello/**"

结果如下:

需要用我们自定义的路径去访问

首页和图标的定制

源码

@Beanpublic WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext,FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) {WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping(new TemplateAvailabilityProviders(applicationContext), applicationContext, getWelcomePage(),this.mvcProperties.getStaticPathPattern());welcomePageHandlerMapping.setInterceptors(getInterceptors(mvcConversionService, mvcResourceUrlProvider));welcomePageHandlerMapping.setCorsConfigurations(getCorsConfigurations());return welcomePageHandlerMapping;}@Override@Bean@ConditionalOnMissingBean(name = DispatcherServlet.LOCALE_RESOLVER_BEAN_NAME)public LocaleResolver localeResolver() {if (this.webProperties.getLocaleResolver() == WebProperties.LocaleResolver.FIXED) {return new FixedLocaleResolver(this.webProperties.getLocale());}AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();localeResolver.setDefaultLocale(this.webProperties.getLocale());return localeResolver;}@Override@Bean@ConditionalOnMissingBean(name = DispatcherServlet.THEME_RESOLVER_BEAN_NAME)public ThemeResolver themeResolver() {return super.themeResolver();}@Override@Bean@ConditionalOnMissingBean(name = DispatcherServlet.FLASH_MAP_MANAGER_BEAN_NAME)public FlashMapManager flashMapManager() {return super.flashMapManager();}private Resource getWelcomePage() {for (String location : this.resourceProperties.getStaticLocations()) {Resource indexHtml = getIndexHtml(location);if (indexHtml != null) {return indexHtml;}}ServletContext servletContext = getServletContext();if (servletContext != null) {return getIndexHtml(new ServletContextResource(servletContext, SERVLET_LOCATION));}return null;}private Resource getIndexHtml(String location) {return getIndexHtml(this.resourceLoader.getResource(location));}private Resource getIndexHtml(Resource location) {try {Resource resource = location.createRelative("index.html");if (resource.exists() && (resource.getURL() != null)) {return resource;}}catch (Exception ex) {}return null;}

通过源码我们可以发现这些路径的根目录下的index.html会被当成首页
1. classpath:/META-INF/resources/
2.classpath:/resources/
3.classpath:/static/
4.classpath:/public/

注意:直接放classpath:/resources/下需要引入依赖Thymeleaf(导入一个jar包)否则无法访问到
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
注意:如果不引入这个jar包,即便是templates目录下的文件也无法访问。
注意:即使引入jar包,templates目录里的页面需要通过走controller后端接口代码去访问,代码中指定跳转的页面,默认就会跳转到/templates/下。
注意:通过controller返回的指定页面,也必须是templates下的页面。

自定义页面图标

  1. 找一个图片,命名为favicon.ico放在static或者public目录下。
  2. 2.0一下版本需要在yaml文件中配置关闭默认图标
spring:mvc:favicon:enabled: false

模板引擎
1.导入jar包依赖

      <dependency><groupId>org.thymeleaf</groupId><artifactId>thymeleaf-spring5</artifactId></dependency><dependency><groupId>org.thymeleaf.extras</groupId><artifactId>thymeleaf-extras-java8time</artifactId></dependency>
  1. 在templates下面创建一个test.html
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>thymeleaf</title>
</head>
<body>
<h1>测试一下thymeleaf</h1>
</body>
</html>
  1. 写一个controller类
    注意要使用的是@Controller标签而不是@RestController标签
package com.example.aliyun.controller;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;@Controller
public class Test {@GetMapping("/test")public String test() {return "test";}
}

运行结果


比较一下@Controller与@RestController两个标签的区别

  1. @RestController相当于@Controller和@ResponseBody合在一起的作用;
  2. 如果使用@RestController注解Controller层的话,则返回的是return里面的内容,无法返回到指定的页面,配置的视图解析器InternalResourceViewResolver也就自然没有作用了;
  3. 如果要返回到指定的页面,则需要用@Controller配合视图解析器InternalResourceViewResolver;
  4. 如果需要返回JSON、XML或自定义mediaType内容到页面,则需要在对应的方法上加上@ResponseBody注解。

结论:要使用thymeleaf,只需要导入对应的依赖就可以了,我们将html放在我们的templates目录下即可!

thymeleaf基本语法

先来传个参数感受一下
test.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>thymeleaf</title>
</head>
<body>
<div th:text="${msg}"></div></body>
</html>

test类

package com.example.aliyun.controller;import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;@Controllerpublic class Test {@GetMapping("/test")public String test(Model model) {model.addAttribute("msg", "hello,springboot");return "test";}}

运行结果

自动配置原理分析

  1. WebMvcAutoConfiguration类
 @Bean@ConditionalOnBean(ViewResolver.class)@ConditionalOnMissingBean(name = "viewResolver", value = ContentNegotiatingViewResolver.class)public ContentNegotiatingViewResolver viewResolver(BeanFactory beanFactory) {ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();resolver.setContentNegotiationManager(beanFactory.getBean(ContentNegotiationManager.class));// ContentNegotiatingViewResolver uses all the other view resolvers to locate// a view so it should have a high precedenceresolver.setOrder(Ordered.HIGHEST_PRECEDENCE);return resolver;}

2.进入ContentNegotiatingViewResolver类

  @Nullablepublic View resolveViewName(String viewName, Locale locale) throws Exception {RequestAttributes attrs = RequestContextHolder.getRequestAttributes();Assert.state(attrs instanceof ServletRequestAttributes, "No current ServletRequestAttributes");List<MediaType> requestedMediaTypes = this.getMediaTypes(((ServletRequestAttributes)attrs).getRequest());if (requestedMediaTypes != null) {List<View> candidateViews = this.getCandidateViews(viewName, locale, requestedMediaTypes);View bestView = this.getBestView(candidateViews, requestedMediaTypes, attrs);if (bestView != null) {return bestView;}}


3.查看getCandidateViews时如何获取候选试图的

private List<View> getCandidateViews(String viewName, Locale locale, List<MediaType> requestedMediaTypes) throws Exception {List<View> candidateViews = new ArrayList();if (this.viewResolvers != null) {Assert.state(this.contentNegotiationManager != null, "No ContentNegotiationManager set");Iterator var5 = this.viewResolvers.iterator();while(var5.hasNext()) {ViewResolver viewResolver = (ViewResolver)var5.next();View view = viewResolver.resolveViewName(viewName, locale);if (view != null) {candidateViews.add(view);}Iterator var8 = requestedMediaTypes.iterator();while(var8.hasNext()) {MediaType requestedMediaType = (MediaType)var8.next();List<String> extensions = this.contentNegotiationManager.resolveFileExtensions(requestedMediaType);Iterator var11 = extensions.iterator();while(var11.hasNext()) {String extension = (String)var11.next();String viewNameWithExtension = viewName + '.' + extension;view = viewResolver.resolveViewName(viewNameWithExtension, locale);if (view != null) {candidateViews.add(view);}}}}}if (!CollectionUtils.isEmpty(this.defaultViews)) {candidateViews.addAll(this.defaultViews);}return candidateViews;}


可以发现在getCandidateViewsget中它是将所有的视图解析器拿来,进行while循环,挨个解。
ContentNegotiatingViewResolver 这个视图解析器就是用来组合所有的视图解析器的

分析ContentNegotiatingViewResolver中有一个初始化方法

    protected void initServletContext(ServletContext servletContext) {Collection<ViewResolver> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(this.obtainApplicationContext(), ViewResolver.class).values();ViewResolver viewResolver;if (this.viewResolvers == null) {this.viewResolvers = new ArrayList(matchingBeans.size());Iterator var3 = matchingBeans.iterator();while(var3.hasNext()) {viewResolver = (ViewResolver)var3.next();if (this != viewResolver) {this.viewResolvers.add(viewResolver);}}} else {for(int i = 0; i < this.viewResolvers.size(); ++i) {viewResolver = (ViewResolver)this.viewResolvers.get(i);if (!matchingBeans.contains(viewResolver)) {String name = viewResolver.getClass().getName() + i;this.obtainApplicationContext().getAutowireCapableBeanFactory().initializeBean(viewResolver, name);}}}AnnotationAwareOrderComparator.sort(this.viewResolvers);this.cnmFactoryBean.setServletContext(servletContext);}


接下来我们自定义一个试图解析器

package com.example.aliyun.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;import java.util.Locale;@Configuration
public class MyMvcConfig implements WebMvcConfigurer {//    ViewResolver实现了视图解析器接口的类,我们就可以把它看作视图解析器/*** 自定义了一个自己的视图解析器MyViewResolver*/@Beanpublic ViewResolver myViewResolver() {return new MyViewResolver();}public static class MyViewResolver implements ViewResolver {@Overridepublic View resolveViewName(String viewName, Locale locale) throws Exception {return null;}}}

debug一下

结果

因此,如果你需要自定义一些功能,只要写这个组件,然后将它交给springboot,springboot就会帮我们自动装配。

扩展SpringMvc

首先编写一个类

@Configuration
public class MyMvcConfig implements WebMvcConfigurer {//视图跳转@Overridepublic void addViewControllers(ViewControllerRegistry registry) {registry.addViewController("/view").setViewName("test");}
}

接下来我们访问http://localhost:8080/view
结果:

如果我们要扩展SpringMvc官方建议我们这样去做
不要@EnableWebMvc注解,这个注解就是导入了一个类:DelegatingWebMvcConfiguration,从容器中获取所有的webmvcconfig

SpringBoot快速上手相关推荐

  1. JavaEE学习笔记-SpringBoot快速上手、热部署、乱码问题、部分注解解释

    SpringBoot快速上手 一.快速创建SpringBoot应用 1.1利用IDEA提供的Spring Initializr创建Spring Boot应用 1.2Spring Boot生成的项目结构 ...

  2. SpringSecurity Oauth2 认证授权(二)springboot快速入门与底层介绍

    集成SpringBoot 快速上手 创建maven工程 导入pom <?xml version="1.0" encoding="UTF-8"?> & ...

  3. 快速上手Springboot项目(登录注册保姆级教程)

    本文章对SpringBoot开发后端项目结构做了简单介绍,并示范了使用SpringBoot+MySQL实现登录的后端功能,与本博客的另一篇文章 Vue 实现登录注册功能(前后端分离完整案例) | Ma ...

  4. 【快速上手系列】使用Springboot集成Swagger2的简单使用测试

    [快速上手系列]使用Springboot集成Swagger2的简单使用测试 简介 Swagger2是为了解决企业中接口(api)中定义统一标准规范的文档生成工具. 尤其是前后端分离时对一些业务接口也不 ...

  5. 一、快速上手SpringBoot

    一.快速上手SpringBoot 一.快速上手SpringBoot 1.SpringBoot快速入门(一) 2.SpringBoot快速入门(二) 3.SpringBoot快速入门(三) 4.Spri ...

  6. 云开发系列课程让你从入门到精通快速上手Serverless和云开发技术

    简介:云开发系列课程主要介绍了从入门到精通快速上手Serverless和云开发技术.学习内容涵盖云开发协同.云函数.云数据库.多媒体托管.前后端一体化框架等Serverless Web开发必备知识.希 ...

  7. 分布式作业 Elastic-Job 快速上手指南

    转载自 分布式作业 Elastic-Job 快速上手指南 Elastic-Job支持 JAVA API 和 Spring 配置两种方式配置任务,这里我们使用 JAVA API 的形式来创建一个简单的任 ...

  8. SpringBoot2.1.15(26) WebFlux快速上手——响应式Spring的道法术器

    SpringBoot2.1.15(26) WebFlux快速上手--响应式Spring的道法术器 Spring WebFlux Spring WebFlux是随Spring 5推出的响应式Web框架. ...

  9. 快速上手Spring WebFlux框架

    一.前言 本文主要介绍基于SpringBoot如何快速上手使用SpringFlux框架开发WEB网站. Spring 5.0在原有的Spring MVC Stack(又称Servlet Stack)以 ...

最新文章

  1. 转:初探 jQuery 的 Sizzle 选择器
  2. 公开课 | 微信高级研究员解析深度学习在NLP中的发展和应用
  3. 爬虫入门的基本原理,如果你连这些都不知道那你可以放弃爬虫了
  4. 腾讯游戏分享汇:天天飞车六大研发经验
  5. LeetCode 75 Sort Colors(颜色排序)
  6. Hibernate常见问题集锦
  7. 第六章实验报告(函数和宏定义实验)
  8. 其他几个未公开的存储过程
  9. 序列化与反序列化(XML、二进制)
  10. 动手动脑(Java)
  11. excel下拉速度太慢_全靠这些Excel、Word一键录入技巧,我才能用10分钟完成3小时工作...
  12. 通过mac地址查找ip
  13. 类似京东淘宝历史搜索自适应长度搜索项超两行折叠功能实现
  14. cesium城市建筑物光效(cesium篇.23)
  15. FUTEX_SWAP补丁分析-SwitchTo 如何大幅度提升切换性能?
  16. 美国的网络空间安全国家战略
  17. 它听键盘声就知道你敲的是什么——GitHub 热点速览 Vol.51
  18. 图片版权保护 用这个盲水印API就够了
  19. mysql2008和mysql2000_[转载]SQL 2008到2005和2000版本的转换
  20. 人工智能正在向经济学领域渗透

热门文章

  1. SLAM中多目三角化
  2. 微信小程序:图标的使用(icon)
  3. 计算机四级网络工程师
  4. 更安全的ftp服务器Pure-FTP搭建(4)
  5. 突然有一天,我老无所依
  6. 阿里云API网关(9)常见问题
  7. vue获取列表中的数量_vue.js中列表里面的子元素怎么获取列表的索引index值
  8. 记录一次线上Mysql数据库迁移方案制定与实施
  9. WebRTC源码下载与编译
  10. hostname -I(大写i)显示主机IP