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配置 # 日志配置
1. # 根日志级别
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);
1. //想输出日志的地方
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
(来自于主配置)。