SpringBoot概述
设计目的:简化Spring应用初始搭建和开发过程。
特点(了解):
-
创建独立的Spring应用
-
嵌入的Tomcat,无需手动部署war文件
-
简化Maven的配置
-
自动配置Spring
SpringBoot = Spring(工厂)+SpringMVC(控制器)
SpringBoot2.2.5的环境搭建
环境要求
-
MAVEN 3.3.x+
-
JDK1.8 +
SpringBoot2.2.x+包装的是Spring框架5.x+
1. POM文件修改
<!--继承springboot的父项目--> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.5.RELEASE</version> </parent> <dependencies> <!--引入springboot的web支持--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies>
2.加入配置文件
基础应用甚至可以不写配置文件,但也仅限于基础应用了……
配置文件的位置在src/main/resources/application.properties
# 修改内嵌服务器端口号,默认8080,可以不修改 server.port=8989 # 修改项目名,需要以斜杠开头,默认无项目名,可以不修改 server.servlet.context-path=/boot_day1
3.创建入口类
package com.baizhi; //注意入口类要在所有子包外面 @SpringBootApplication //用在类上,标识这是springboot的入口类 public class Day1Application { public static void main(String[] args) { //参数1:入口类对象 参数2:main函数的参数 SpringApplication.run(Day1Application.class, args); } }
SpringBoot入口类注解说明(了解)
@SpringBootApplication等价于以下三个注解的组合
@SpringBootConfiguration //启动SpringBoot应用时自动进行配置 @EnableAutoConfiguration //启动SpringBoot应用时对第三方引入的springboot相关依赖自动配置 @ComponentScan //用来扫描当前包和子包中的注解
4.开发控制器
@Controller @RequestMapping("/test") public class TestController { @RequestMapping("/hello") @ResponseBody //SpringBoot默认没有集成JSP,之后会集成 public String hello(){ return "Hello Spring"; } }
SpringBoot管理对象
简单对象:@Component @Repository @Service @Controller ...
复杂对象(类中没有构造方法或者构造方法不能调用,如接口类型或抽象类实例):
@Configuration //这个注解表示这个类是一个配置类,相当于xml配置文件 public class BeansConfig { @Bean public Connection getConnection() throws Exception { Class.forName("com.mysql.jdbc.Driver"); return DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/ajax?characterEncoding=UTF-8","root","1234"); } }
-
使用复杂对象时一般按类型做自动注入即可。
-
如果需要按名称做自动注入,默认的名称和方法名一致,可以使用
@Bean("xxx")
修改。
SpringBoot中集成jsp显示
1.引入依赖
<dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-jasper</artifactId> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency>
2.配置视图解析器
# 配置前缀prefix和后缀.jsp spring.mvc.view.prefix=/ spring.mvc.view.suffix=.jsp
补充:开发环境中启用jsp页面热部署
jsp页面热部署可以使得对jsp的修改无需重启服务器,但会略微降低整个应用的运行性能,如果项目上线后无需使用到这个功能,可以结合之后会讲的“配置分离”实现只在开发期间启用jsp热部署。
# 启用jsp页面热部署 server.servlet.jsp.init-parameters.development=true
SpringBoot和Mybatis整合
1.引入依赖
<dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.2</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.12</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.38</version> </dependency>
2.配置文件
# 数据源配置 # 连接池 spring.datasource.type=com.alibaba.druid.pool.DruidDataSource # 驱动类 spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/ajax?characterEncoding=UTF-8 spring.datasource.username=root spring.datasource.password=1234 # mybatis配置 # mapper文件位置 mybatis.mapper-locations=classpath:com/baizhi/mapper/*.xml # 这个包里的类会自动成为别名 mybatis.type-aliases-package=com.baizhi.entity
3.入口类配置
@SpringBootApplication @MapperScan("com.baizhi.dao") //自动注册Dao public class Day1Application { public static void main(String[] args) { SpringApplication.run(Day1Application.class, args); } }
4.Mybatis相关
建表、实体类、Dao、Mapper、Service省略
5.测试
引入测试依赖,注意:需要把junit的依赖去掉
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency>
测试类
@RunWith(SpringRunner.class) @SpringBootTest(classes = Day1Application.class) public class TestUserService { @Autowired private UserService userService; @Test public void test(){ List<User> users = userService.findAll(); for (User user : users) { System.out.println(user); } } }
也可以采用继承基础测试类的方式来减少冗余代码:
//基础测试类 @RunWith(SpringRunner.class) @SpringBootTest(classes = Day1Application.class) public class BasicTest { } //真正测试类 public class TestUserService extends BasicTest { @Autowired private UserService userService; @Test public void test(){ List<User> users = userService.findAll(); for (User user : users) { System.out.println(user); } } }
总结:环境搭建步骤
SpringBoot+JSP
-
pom:
①父项目
spring-boot-starter-parent
②依赖
spring-boot-starter-web
、tomcat-embed-jasper
、jstl
-
入口类:
①加注解
@SpringBootApplication
②写主函数
SpringApplication.run(入口类.class, args)
-
配置文件
spring.mvc.view.prefix=/
spring.mvc.view.suffix=.jsp
SpringBoot+Mybatis
-
pom:
①父项目
spring-boot-starter-parent
②依赖
spring-boot-starter-web
、mybatis-spring-boot-starter
、druid
、数据库驱动(如mysql-connector-java)
-
入口类:
①加注解
@SpringBootApplication
@MapperScan("dao包名")
②写主函数
SpringApplication.run(入口类.class, args)
-
配置文件:
①
spring.datasource
:.type=连接池
.driver-class-name=驱动类
.url=连接串
.username=用户名
.password=密码
②
mybatis
:.mapper-locations=mapper文件位置
.type-aliases-package=实体类包名
SpringBoot 切面编程
引入依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
相关注解
-
@Aspect 用在类上,代表这个类是一个切面的配置类
-
@Before 用在方法上,代表这个方法是一个前置通知方法
-
@AfterReturning 用在方法上,代表这个方法是一个返回后通知方法
-
@AfterThrowing 用在方法上,代表这个方法是一个异常通知方法
-
@Around 用在方法上,代表这个方法是一个环绕通知方法
@Before、@AfterReturning 、@AfterThrowing 、@Around的value属性值均是切入点表达式。
前置切面
@Aspect @Component public class MyAspect { @Before("execution(* com.baizhi.service.*ServiceImpl.*(..))") public void before(JoinPoint point){ System.out.println("前置通知"); } }
返回后切面
@Aspect @Component public class MyAspect { //returning = "r" 表示形参中使用r接收返回值,如果不需要可以不写 @AfterReturning(value = "execution(* com.baizhi.service.*ServiceImpl.*(..))", returning = "r") public void after(JoinPoint point, Object r){ System.out.println("后置通知"); System.out.println("返回值:" + r); } }
异常切面
@Aspect @Component public class MyAspect { //throwing = "a" 表示形参中使用a接收抛出的异常,如果不需要可以不写 @AfterThrowing(value = "execution(* com.baizhi.service.*ServiceImpl.*(..))", throwing = "a") public void afterThrowing(JoinPoint point, Throwable a){ System.out.println("异常通知"); System.out.println(a.getMessage()); } }
环绕切面
@Aspect @Component public class MyAspect { @Around("execution(* com.baizhi.service.*ServiceImpl.*(..))") public Object around(ProceedingJoinPoint point) { try { System.out.println("环绕 - 前"); Object proceed = point.proceed(); System.out.println("环绕 - 后"); return proceed; }catch (Throwable a){ System.out.println("环绕 - 异常"); a.printStackTrace(); } return null; } }
补充知识:HTTP状态码
百科词条:HTTP状态码_百度百科
用来表示响应的状态。
常见状态码:
状态码 | 状态说明 | 备注 |
---|---|---|
200 | 响应成功 | |
304 | 未修改,可使用缓存 | 也是响应成功 |
400 | 请求有误 | 较常见的是参数格式不正确 |
403 | 无权限请求 | |
404 | 请求路径未找到 | |
500 | 服务器内部错误 | 通俗说,服务器代码抛异常了 |
SpringBoot的全局异常处理
请求路径未找到(404)
在webapp
目录建立文件夹error
,在里面使用404.jsp
作为找不到路径的显示页。
服务器内部错误(500)
方式一:error/500
在webapp
目录建立文件夹error
,在里面使用500.jsp
作为服务器内部错误的显示页。在这个页面,可以通过EL表达式${message}
获取错误信息。
方式二:@ControllerAdvice + @ExceptionHandler
@ControllerAdvice public class GlobalExceptionHandler { //可以书写多个方法来分别处理不同的异常,value值是个数组,里面是要处理的异常的类对象 @ExceptionHandler(Exception.class) //处理所有的异常(Exception类和其子类) public String handlerException(HttpServletRequest request, Exception ex){ ex.printStackTrace(); request.setAttribute("errorMsg", ex.getMessage()); return "error"; } //可以书写多个方法来分别处理不同的异常,value值是个数组,里面是要处理的异常的类对象 @ExceptionHandler({SqlException.class, IOException.class}) //处理Sql异常和IO异常(SqlException类和其子类、IOException类和其子类) public String handlerSqlAndIOException(HttpServletRequest request, Exception ex){ ex.printStackTrace(); request.setAttribute("errorMsg", "出错了!!!"); return "error"; } }
另外,SpringBoot依然可以采用以下方式处理异常:
-
直接在Controller方法中
try……catch
:单独处理这个方法的异常,并且可以通过多个catch块实现不同异常不同处理。 -
使用拦截器的afterCompletion处理异常:可以针对不同路径采用不同的异常处理方式,并且可以配合
instanceof
实现不同异常不同处理。
SpringBoot的文件上传下载
本身不需要依赖,但如果需要且项目中没有org.apache.commons.io.IOUtils
或org.apache.commons.io.FilenameUtils
这两个在上传下载业务中经常使用的工具类,则可以引入依赖:
<dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.6</version> </dependency>
配置文件上传大小限制(不是必须的配置,但最好配置一下,因为默认值不一定符合项目需要):
# 单个文件最大大小 spring.servlet.multipart.max-file-size=500KB # 整个请求最大大小 spring.servlet.multipart.max-request-size=2MB # 大小单位 KB MB GB TB PB
编码部分和Spring MVC一致。
因为idea不会打包空文件夹,所以如果需要把用户上传的文件保存到项目里时,用于保存用户上传文件的文件夹内需要放一个任意文件来“占位”。
SpringBoot中的拦截器
拦截器开发部分和SpringMVC基本一致(区别:不需要工厂创建对象,且可以按照自己的需求实现以下任意方法):
public class MyInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) throws Exception { System.out.println("======1====="); return true;//返回true 放行 返回false阻止 } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object o, ModelAndView modelAndView) throws Exception { System.out.println("=====3====="); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object o, Exception e) throws Exception { System.out.println("=====4====="); } }
配置拦截器(和SpringMVC区别很大):
@Configuration //这个注解表示这个类是一个配置类,相当于xml配置文件 public class InterceptorConfig implements WebMvcConfigurer { //用来加入拦截器相关配置 参数1(registry): 拦截器注册对象 @Override public void addInterceptors(InterceptorRegistry registry) { //添加拦截器 registry.addInterceptor(new MyInterceptor()) .addPathPatterns("/a/*") //拦截的路径,可以写多个 .excludePathPatterns("/a/test2"); //放行的路径,可以写多个 //可以添加多个拦截器 registry.addInterceptor(new LoginInterceptor()) .addPathPatterns("/**") //拦截的路径,可以写多个 .excludePathPatterns("/user/login", "/user/reg"); //放行的路径,可以写多个 } }
SpringBoot war包部署(了解)
大部分web项目部署,只需要使用maven-Lifecycle-package
打成war包后部署到服务器就可以,但SpringBoot内嵌一个Tomcat服务器,因此改成外部服务器部署时需要额外做一些操作。
1.检查pom.xml确认打包方式为war
<packaging>war</packaging>
2.排除内嵌的tomcat
对于这种要临时修改pom依赖的情况,一定要做好记录和依赖搜索(先根据artifactId搜一下有没有这个依赖再按照下面的形式修改,不是直接把下面的依赖复制进去)
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> <scope>provided</scope> <!--去掉内嵌tomcat--> </dependency> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-jasper</artifactId> <scope>provided</scope> <!--去掉使用内嵌tomcat解析jsp--> </dependency>
3.修改入口类
//1. 继承SpringBootServletInitializer public class Day1Application extends SpringBootServletInitializer { public static void main(String[] args) { SpringApplication.run(Day1Application.class, args); } //2. 覆盖configure方法 @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) { //这里的参数是当前这个入口类的类对象 return builder.sources(Day1Application.class); } }
4. 进行打包
执行maven-Lifecycle-package
来打包,然后target
中就会出现项目的war包,可部署到tomcat根目录内的webapps文件夹进行测试和运行。
打包前会自动运行测试类代码,如果不想运行,可以使用“小闪电”图标切换为“跳过测试”模式(Toggle 'Skip Tests' Mode )。
注意事项
一旦使用war包部署注意:application.properties
中配置的server.port
、server.servlet.context-path
均失效,访问时使用打成war包的名字作为项目名(也可通过删除ROOT文件夹后,war包改名为ROOT.war来去掉项目名)和外部tomcat端口号进行项目访问。
logback日志集成(了解)
logback是由log4j创始人设计的又一个开源日志组件。目前,logback分为三个模块:logback-core,logback-classic和logback-access。是对log4j日志展示进一步改进。
logback中的概念
日志级别:OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL (从高到低),级别越高,输出的日志越少(比如设置为WARN时,是输出WARN、ERROR和FATAL级别)。
日志分类:根日志(rootLogger,全局日志)、分支日志(logger,包级别的日志),其中根日志必须存在。
SpringBoot中logback的使用
-
SpringBoot中已经集成了logback,因此无需单独引入依赖
-
application配置
# 日志配置 # 根日志级别 logging.level.root=error # 单独某个包的分支日志级别 logging.level.com.baizhi=debug # 关闭Mybatis的SQL语句输出 logging.level.com.baizhi.dao=error # 日志写到这个文件,不需要输出到文件的话可以不写这个配置 logging.file.name=C:\\MyComputer\\SpringLog\\aa.log
-
自己使用日志对象来输出日志
//成员变量中 //参数一般为当前类 private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class); //想输出日志的地方 log.debug("debug"); log.info("info"); log.warn("warn"); log.error("error"); //也可以采用{}占位符输出形式 log.info("name: {}, id: {}", user.getName(), user.getId());
SpringBoot中配置文件的拆分(了解)
在实际开发过程中生产环境和开发环境的配置有可能是不一样的,因此将生产中的配置和开发中的配置拆分开是非常必要的。
配置拆分由一个主配置文件
application.properties
和多个子配置文件application-xxx.properties
组成,主配置文件可以决定让哪个子配置文件生效。子配置文件会对主配置文件进行智能的整合和覆盖,因此进行配置文件拆分后,写起来依然比较灵活。
整合和覆盖的规则:
子配置文件中不存在的配置项,会使用主配置文件 - 整合。
子配置文件会覆盖主配置文件的同一配置项 - 覆盖。
例如:
主配置文件application.properties
server.port=8989 # 当前使用的子配置文件为application-dev.properties spring.profiles.active=dev spring.mvc.view.prefix=/ spring.mvc.view.suffix=.jsp
开发配置文件application-dev.properties
server.port=10010 server.servlet.context-path=/dev_day1 server.servlet.jsp.init-parameters.development=true
生产配置文件application-prod.properties
server.port=8888
配置效果:
-
当主配置文件中
spring.profiles.active=dev
时,端口为10010
(来自于dev子配置对主配置的覆盖),项目名为/dev_day1
(直接来自于dev子配置),启用了jsp热部署(直接来自于dev自配置),视图前后缀为/
、.jsp
(来自于主配置)。 -
当主配置文件中
spring.profiles.active=prod
时,端口为8888
(来自于prod子配置对主配置的覆盖),视图前后缀为/
、.jsp
(来自于主配置)。