1.1 诞生背景 在普通的java项目中,大量的XML文件配置起来是很繁琐就会导致开发效率低,整合第三方框架的配置可能存在冲突问题导致部署效率低,还有其它的问题,传统java项目的打包方式:打包成一个war放入到tomcatwebapps目录下进行执行,也就是说需要依赖外部的tomcat服务器才能执行。 1.2 springboot的优点 快速创建独立运行的Spring项目以及与主流框架集成 使用嵌入式的Servlet容器,应用无需打成WAR包 starters自动依赖与版本控制 大量的自动配置,简化开发,也可修改默认值 无需配置XML,无代码生成,开箱即用 准生产环境的运行时应用监控 与云计算的天然集成 1.3 微服务 微服务其实是一种架构风格,它提倡我们在开发的时候,一个应用应该是一组小型服务,每一个小服务都运行在自己的进程内,每一个小服务都通过HTTP的方式进行互通 使用微服务架构,每一个功能元素都是可以独立替换和独立升级的软件单元
2.1 创建maven工程 使用idea工具创建一个maven工程,该工程为普通的java工程即可 2.2 添加依赖
在pom.xml里面导入起步依赖
<!--spring-boot-starter-parent整合第三方常用框架的依赖信息--> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.1.RELEASE</version> </parent>SpringBoot要集成SpringMVC进行Controller的开发,所以项目要导入web的启动依赖
<!--spring-boot-starter-web 是springboot整合springMVC是maven的依赖继承关系 --> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies>2.3 编写controller 2.4 编写启动类
@EnableAutoConfiguration注解:作用在于让 Spring Boot根据应用所声明的依赖来对Spring框架进行自动配置这个注解告诉Spring Boot根据添加的jar依赖猜测你想如何配置Spring。由于spring-boot-starter-web添加了Tomcat和Spring MVC,所以auto-configuration将假定你正在开发一个web应用并相应地对Spring进行设置。@EnableAutoConfiguration扫描的时候,只能扫描到当前类@ComponentScan注解:由于@EnableAutoConfiguration注解只能扫描当前的类,这样对Controller里面的类进行管理很不方便,这个时候,我们可以用@ComponentScan注解来配置扫描包的范围。我们可以将启动器抽取成一个单独的类 @EnableAutoConfiguration @ComponentScan("com.oracle.controller") public class App { public static void main(String[] args) { SpringApplication.run(App.class,args); } }但是使用@ComponentScan进行扫包的时候,包比较多的情况下,写起来比较麻烦。比如我要扫码多个包: @ComponentScan(basePackages = {"com.oracle.user.controller","com.oracle.order.controller"})
我们可以使用@SpringBootApplication,一劳永逸的解决以上问题 @SpringBootApplication被@Configuration、@EnableAutoConfiguration、@ComponentScan 注解所修饰,换言之 Springboot 提供了统一的注解来替代以上三个注解
扫包范围:在启动类上加上@SpringBootApplication注解,当前包下或者子包下所有的类都可以扫到。 2.5 使用@SpringBootApplication注解编写启动类 但是此时需要注意App类所在的包中的位置
3.1 父项目
<!--spring-boot-starter-parent整合第三方常用框架的依赖信息--> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.1.RELEASE</version> </parent> 他的父项目是 <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.0.1.RELEASE</version> <relativePath>../../spring-boot-dependencies</relativePath> </parent> 它真正管理springboot项目里面的所有依赖版本,以后我们导入依赖默认是不需要写版本;(没有在dependencies里面管理的依赖自然需要声明版本号)3.2 启动器
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies>spring-boot-starter:spring-boot场景启动器;帮我们导入了web模块正常运行所依赖的组件; Spring Boot将所有的功能场景都抽取出来,做成一个个的starters(启动器),只需要在项目里面引入这些starter 相关场景的所有依赖都会导入进来。要用什么功能就导入什么场景的启动
5.1 YAML的基本语法 k:(空格)v:表示一对键值对(空格必须有); 以空格的缩进来控制层级关系;只要是左对齐的一列数据,都是同一个层级的 属性和值也是大小写敏感;
server: port: 8081 path: /hello此时port和path就是在同一个层级 5.2 值的写法
字面量:普通的值(字符串,数字,布尔值) k: v:字面直接来写; 字符串默认不用加上单引号或者双引号; “”:双引号;会转义字符串里面的特殊字符;特殊字符会作为本身想表示的意思 name: “zhangsan \n lisi”:输出;zhangsan 换行 lisi ‘’:单引号;不会转义特殊字符,特殊字符终只是一个普通的字符串数据 name: ‘zhangsan \n lisi’:输出;zhangsan \n lisi
对象 k: v:在下一行来写对象的属性和值的关系;注意缩进 对象还是k: v的方式
animal: name: Sunny age: 12行内写法:
friend: {fname: Oscar,age: 20} 数组(List Set) 用- 值表示数组中的一个元素 pets: - cat - dog - fish行内写法:
names: [cat,dog,fish]5.3 实例:将JavaBean注入到配置文件中 分别提供实体类 Person Dog
public class Person { private String lastName; private Integer age; private Boolean boss; private Date birth; private Map<String,Object> maps; private List<Object> lists; private Dog dog; //提供 Get Set方法 toString方法 } public class Dog { private String name; private Integer age; //提供 Get Set方法 toString方法 }在application.ymal中注入属性
person: lastName: Oscar age: 19 boss: false birth: 2019/10/10 maps: {k1: v1,k2: v2} lists: - eric - kobe dog: name: 大黄 age: 2在注入的Person的类上面添加注解 注意
@ConfigurationProperties:告诉springboot 将当前类的所有属性和配置文件中的相关信息进行绑定 prefix:配置文件中的哪个属性进行一一映射 @Component:只有将这个类配置在Spring容器中 才能使用@ConfigurationProperties的功能 使用@Autowired即可访问该对象以导入配置文件处理器,以后编写配置就有提示了
<!--配置文件处理器--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency>测试
@AutoWired Person person; @RequestMapping("/hello") public String hello(){ System.out.println(person); return "这是我的第一个springboot程序"; }5.4 Properties文件的配置
在application.properties文件中配置
server.port=8081 person.last-name=张三 person.age=12 person.birth=2019/12/30 person.boss=false person.lists=a,b,c person.maps.k1=value1 person.maps.k2=value2 person.dog.name=大黄 person.dog.age=1解决在application.properties文件中的中文乱码问题: 5.5 @Value获取值和@ConfigurationProperties获取值比校
在spring中@Value相当于在配置文件中的 <bean id=” ” class=” ”><property name=” ” value=” ”></ property></bean>
@Value注解支持字面量的注解方式
从配置文件中获取 application.yml配置文件中定义:
emp: empName: kobe age: 19 isMarried: trueEmp中使用@Value注解中获取属性 使用SPEL表达式获取 通过比较@ConfigurationProperties和@Value的区别 最大的区别就是@ConfigurationProperties支持数据校验,而@Value则不支持。 在application.yml文件中 email的值只能是邮箱类型,否则启动报错 总结: 配置文件yml还是properties他们都能获取到值; 如果说,我们只是在某个业务逻辑中需要获取一下配置文件中的某项值,使用@Value; 如果说,我们专门编写了一个javaBean来和配置文件进行映射,我们就直接使用@ConfigurationProperties;
5.6 @PropertySource 在前面的配置中,使用@ConfigurationProperties注解可以获取配置文件中的属性值。但是@ConfigurationProperties读取的配置文件是全局的,也就是说这个注解只能加载全局的配置文件(application.yml/application.properties).但是全局配置文件一般定义的都是有关spring配置的信息。如果我们需要定义一些与spring配置无关的信息,那么该如何呢?
我们可以定义局部的配置文件,然后使用@PropertySource注解进行获取。 1.定义emp.properties配置文件
emp.empName=kobe emp.age=19 emp.email=risswen@sina.com emp.isMarried=true2.定义实体类Emp 5.7 @ImportResource
导入Spring的配置文件,让配置文件里面的内容生效; Spring Boot里面没有Spring的配置文件,我们自己编写的配置文件,也不能自动识别; 想让Spring的配置文件生效,加载进来;@ImportResource标注在一个配置类上
实例: 定义一个UserSercice方法,使用xml配置文件的方式管理UserService类。如何在springboot项目中获取?
定义UserService
public class UserService { public void test(){ System.out.println("这是UserService里面的方法"); } }定义bean.xml配置文件,管理bean
<bean id="userService" class="com.oracle.service.UserService"></bean>在启动类上添加@importResource注解
@SpringBootApplication @ImportResource(locations = {"classpath:bean.xml"})//加载类路径下面的配置文件 public class App { public static void main(String[] args) { SpringApplication.run(App.class,args); } }测试
@RestController public class controller { @Autowired ApplicationContext applicationContext; @RequestMapping("/hello") public String hello(){ UserService userService = (UserService) applicationContext.getBean("userService"); userService.test(); return "这是我的第一个springboot程序"; } }注意!!!:在springboot项目中,我们在spring容器中添加组件,我们一般不用以上使用xml的方式。Springboot推荐我们使用全注解的方式在spring容器添加组件。
1、配置类@Configuration------>Spring配置文件 2、使用@Bean给容器中添加组件
定义OrderService
public class OrderService { public void test(){ System.out.println("这是OrderService里面的方法"); } }定义配置类
package com.oracle.config; import com.oracle.service.OrderService; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration /** * 指明当前类就是一个配置类,用来替代之前的配置文件<bean class=""></bean> */ public class MyAppConfig { //将方法的返回值添加到spring容器中,组件的默认id就是当前方法名 @Bean public OrderService orderService(){ return new OrderService(); } }测试调用
@RestController public class controller { @Autowired ApplicationContext applicationContext; @RequestMapping("/hello") public String hello(){ OrderService userService = (OrderService) applicationContext.getBean("orderService"); userService.test(); return "这是我的第一个springboot程序"; } }5.8 配置文件的占位符 随机数
${random.uuid} ${random.int(18,60)} ${random.value} …… randomdemo: #名字不能以驼峰命名 否则启动报错 id: ${random.uuid} 取随机的uuid age: ${random.int(18,60)} 取指定范围的随机数 address: ${random.value} 获取随机字符串默认值
randomdemo: id: ${random.uuid} age: ${random.int(18,60)} address: ${random.value} name: ${:铁蛋} 如果不写 默认值就是铁蛋5.9 springboot配置文件的加载位置 springboot 启动会扫描以下位置的application.properties或者application.yml文件作为Spring boot的默认配置文件
–file:./config/ 项目根目录下面的config文件夹 优先级最高 –file:./ 项目根目录下面 –classpath:/config/ resources文件夹下面的config文件夹 –classpath:/ resources文件夹下面 优先级最低
优先级由高到底,高优先级的配置会覆盖低优先级的配置; SpringBoot会从这四个位置全部加载主配置文件;互补配置;
测试: 在以上各级文件夹下面定义application.properties文件,里面定义server.port端口号。看看到底以哪一个端口号为准。
小细节: 如果需要给访问路径加上虚拟目录,那么在配置文件中可以配置:
server: port: 8081 servlet: context-path: /springboot #指定虚拟路径(1) SpringBoot启动的时候加载主配置类,开启了自动配置功能 @EnableAutoConfiguration
@SpringBootApplication @ImportResource(locations = {"classpath:bean.xml"}) public class App { public static void main(String[] args) { SpringApplication.run(App.class,args); } }(2)点击进入@SpringBootApplication注解的源码 (3)点击进入@EnableAutoConfiguration注解的源码 利用EnableAutoConfigurationImportSelector给容器中导入一些组件
(4)点击进入AutoConfigurationImportSelector这个类里面 这个类里面有一个selectImports方法 (5)点击进入getCandidateConfigurations方法 (7)点击进入SpringFactoriesLoader,进入SpringFactoriesLoader类 (8)查看SpringFactoriesLoader里面的loadFactoryNames方法 (9)加载的组件
7.1 springboot整合log4j日志记录 在resources目录下面创建log4j.properties日志文件,并引入
#log4j.rootLogger=CONSOLE,info,error,DEBUG log4j.rootLogger=info,error,CONSOLE,DEBUG log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout log4j.appender.CONSOLE.layout.ConversionPattern=%d{yyyy-MM-dd-HH-mm} [%t] [%c] [%p] - %m%n log4j.logger.info=info log4j.appender.info=org.apache.log4j.DailyRollingFileAppender log4j.appender.info.layout=org.apache.log4j.PatternLayout log4j.appender.info.layout.ConversionPattern=%d{yyyy-MM-dd-HH-mm} [%t] [%c] [%p] - %m%n log4j.appender.info.datePattern='.'yyyy-MM-dd log4j.appender.info.Threshold = info log4j.appender.info.append=true #log4j.appender.info.File=/home/admin/pms-api-services/logs/info/api_services_info log4j.appender.info.File=/Users/dddd/Documents/testspace/pms-api-services/logs/info/api_services_info log4j.logger.error=error log4j.appender.error=org.apache.log4j.DailyRollingFileAppender log4j.appender.error.layout=org.apache.log4j.PatternLayout log4j.appender.error.layout.ConversionPattern=%d{yyyy-MM-dd-HH-mm} [%t] [%c] [%p] - %m%n log4j.appender.error.datePattern='.'yyyy-MM-dd log4j.appender.error.Threshold = error log4j.appender.error.append=true #log4j.appender.error.File=/home/admin/pms-api-services/logs/error/api_services_error log4j.appender.error.File=/Users/dddd/Documents/testspace/pms-api-services/logs/error/api_services_error log4j.logger.DEBUG=DEBUG log4j.appender.DEBUG=org.apache.log4j.DailyRollingFileAppender log4j.appender.DEBUG.layout=org.apache.log4j.PatternLayout log4j.appender.DEBUG.layout.ConversionPattern=%d{yyyy-MM-dd-HH-mm} [%t] [%c] [%p] - %m%n log4j.appender.DEBUG.datePattern='.'yyyy-MM-dd log4j.appender.DEBUG.Threshold = DEBUG log4j.appender.DEBUG.append=true #log4j.appender.DEBUG.File=/home/admin/pms-api-services/logs/debug/api_services_debug log4j.appender.DEBUG.File=/Users/dddd/Documents/testspace/pms-api-services/logs/debug/api_services_debug log4j\u4EE3\u7801 private static final Logger logger = LoggerFactory.getLogger(IndexController.class);引入log4j依赖
<!-- springboot-log4j --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-log4j</artifactId> <version>1.3.8.RELEASE</version> </dependency>Controller
@RestController public class LoggController { private static final Logger logger = LoggerFactory.getLogger(LoggController.class); @RequestMapping("/printLog") public String printLog(){ logger.info("日志打印输出了......"); return "Hello World....."; } }7.2 使用Aop统一处理Web请求日志
导入依赖
<!--Aop依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> <!--lombok依赖:下面的slf4j会用到--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency>Aop处理日志的类
package com.bianyiit.aspect; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest; import java.util.Enumeration; @Aspect @Component @Slf4j public class WebLogAspect { @Pointcut("execution(public * com.bianyiit.controller.*.*(..))") public void webLog() { } @Before("webLog()") public void doBefore(JoinPoint joinPoint) throws Throwable { // 接收到请求,记录请求内容 ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); // 记录下请求内容 log.info("URL : " + request.getRequestURL().toString()); log.info("HTTP_METHOD : " + request.getMethod()); log.info("IP : " + request.getRemoteAddr()); Enumeration<String> enu = request.getParameterNames(); while (enu.hasMoreElements()) { String name = (String) enu.nextElement(); log.info("name:{},value:{}", name, request.getParameter(name)); } } @AfterReturning(returning = "ret", pointcut = "webLog()") public void doAfterReturning(Object ret) throws Throwable { // 处理完请求,返回内容 log.info("RESPONSE : " + ret); } }控制类
@RequestMapping("/getMember") public String getMember(String name,Integer age){ return "success"; }请求路径: http://localhost:8080/getMember?name=sunny&age=12
使用SpringBoot; 1)、创建SpringBoot应用,选中我们需要的模块; 2)、SpringBoot已经默认将这些场景配置好了,只需要在配置文件中指定少量配置就可以运行起来 3)、自己编写业务代码;
“/**” 访问当前项目的任何资源,都去(静态资源的文件夹)找映射
"classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/" "/":当前项目的根路径测试效果: 如果要实现http://localhost:8081/springboot_day03/static/test04.html 欢迎页; 静态资源文件夹下的所有index.html页面;被"/**"映射 localhost:8080/ 找index.html页面
引入Thymeleaf依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>只要我们把HTML页面放在classpath:/templates/,thymeleaf就能自动渲染; 编写控制器类:(注意:这里应该使用@Controller注解,而不是restController注解)
@Controller public class HelloController { @RequestMapping("/hello") public String success(){ return "success";//跳转到templates下面的success.html页面 } }使用http://localhost:8080/hello即可访问
2.1 Thymeleaf语法初体验
需求:通过控制器实现页面跳转,并将数据传递给前台html页面 在HTML页面导入thymeleaf的名称空间
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org">编写控制器类
@Controller public class HelloController { @RequestMapping("/hello") public String success(Map<String,Object> map){ map.put("name","Sunny"); return "success"; } }页面取值
<body> <h3>这是一个成功页面</h3> 欢迎你,<span th:text="${name}"></span> </body>2.4 thyemleaf的语法规则
th语法 th:text;改变当前元素里面的文本内容; th:任意html属性;来替换原生属性的值
<body> <h3>这是一个成功页面</h3> 欢迎你,<span th:text="${name}" id="s1" class="span1" th:id="${name}" th:class="${name}"></span> </body>以上的th:id、th:class的值就替换了原来的id和class属性的值 小实验 控制器:
@RequestMapping("/hello") public String success(Map<String,Object> map){ map.put("name","Oscar"); map.put("content","<h2>大家好</h2>"); List<String> list = new ArrayList<>(); list.add("Sunny"); list.add("Kobe"); list.add("Ketty"); map.put("list",list); return "success"; }HTML页面展示
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h3>这是一个成功页面</h3> 欢迎你,<span th:text="${name}" id="s1" class="span1" th:id="${name}" th:class="${name}"></span> <hr> <!--循环展示--> <h2> <div th:each="list:${list}" th:text="${list}"></div> </h2> <!--th:utext--> <div th:utext="${content}"></div> <!--转义--> <div th:text="${content}"></div> <!--不转义--> <!--循环战士的另一种写法--> <div id="box" th:each="names:${list}">[[${names}]]</div> </body> </html>2.5 springboot中springMVC
Springmvc的扩展配置 在springboot中,提供了很多springMVC的自动配置,但是这些自动配置还不满足我们的开发需求,所以我们可以在默认的配置上进行扩展。
如何扩展? 编写一个配置类(@Configuration),是WebMvcConfigurerAdapter类型;不能标注@EnableWebMvc
@Configuration public class MyMVCConfig extends WebMvcConfigurerAdapter { @Override public void addViewControllers(ViewControllerRegistry registry) { registry.addViewController("/oracle").setViewName("index"); } }以上代码:指定了我们访问路径跳转到的执行页面。
全面接管springMVC的配置 SpringBoot对SpringMVC的自动配置不需要了,所有都是我们自己配置;所有的SpringMVC的自动配置都失效了我们需要在配置类中添加@EnableWebMvc即可。 测试:这样我们直接访问项目的静态页面就会访问不到