一、SpringBoot介绍
原有Spring优缺点分析
Spring的优点
Spring是Java企业版(Java Enterprise Edition,JEE,也称J2EE)的轻量级代替品。无需开发重量级的Enterprise JavaBean(EJB),Spring为企业级Java开发提供了一种相对简单的方法,通过依赖注入和面向切面编程,用简单 的Java对象(Plain Old Java Object,POJO)实现了EJB的功能。
Spring的缺点分析
**虽然Spring的组件代码是轻量级的,但它的配置却是重量级的。**一开始,Spring用XML配置,而且是很多XML配 置。Spring 2.5引入了基于注解的组件扫描,这消除了大量针对应用程序自身组件的显式XML配置。Spring 3.0引入 了基于Java的配置,这是一种类型安全的可重构配置方式,可以代替XML。 所有这些配置都代表了开发时的损耗。因为在思考Spring特性配置和解决业务问题之间需要进行思维切换,所以编 写配置挤占了编写应用程序逻辑的时间。和所有框架一样,Spring实用,但与此同时它要求的回报也不少。 除此之外,项目的依赖管理也是一件耗时耗力的事情。在环境搭建时,需要分析要导入哪些库的坐标,而且还需要 分析导入与之有依赖关系的其他库的坐标,一旦选错了依赖的版本,随之而来的不兼容问题就会严重阻碍项目的开发进度。
SpringBoot概念简介
- Spring Boot是Spring公司的一个*项目,和Spring Framework是一个级别的。
- Spring Boot实际上是利用Spring Framework 4 自动配置特性完成。编写项目时不需要编写xml文件。发展到现在,Spring Boot已经具有很很大的生态圈,各种主流技术已经都提供了Spring Boot的启动器。
什么是启动器
Spring框架在项目中作用是Spring整合各种其他技术,让其他技术使用更加方便。Spring Boot的启动器实际上就是一个依赖。这个依赖中包含了整个这个技术的相关jar包,还包含了这个技术的自动配置,以前绝大多数XML配置都不需要配置了。当然了,启动器中自动配置无法实现所有内容的自动配置,在使用Spring Boot时还需要进行少量的配置(这个配置不是在xml中了,而是在properties或yml中即可)。如果是Spring自己封装的启动器的artifact id名字满足:spring-boot-starter-xxxx,如果是第三方公司提供的启动满足:xxxx-spring-boot-starter。以后每次使用Spring Boot整合其他技术时首先需要考虑导入启动器。
Spring Boot优点
- 使用Spring Boot可以创建独立的Spring应用程序
- 在Spring Boot中直接嵌入了Tomcat、Jetty、Undertow等Web 容器,在使用SpringBoot做Web开发时不需要部署WAR文件
- 通过提供自己的启动器(Starter)依赖,简化项目构建配置
- 尽量的自动配置Spring和第三方库
- 绝对没有代码生成,也不需要XML配置文件
Spring Boot的核心
起步依赖- 起步依赖本质上是一个Maven项目对象模型(Project Object Model,POM),定义了对其他库的传递依赖,这些东西加在一起即支持某项功能。 简单的说,起步依赖就是将具备某种功能的坐标打包到一起,并提供一些默认的功能。
自动配置 -Spring Boot的自动配置是一个运行时(更准确地说,是应用程序启动时)的过程,考虑了众多因素,才决定 Spring配置应该用哪个,不该用哪个。该过程是Spring自动完成的。
二、SpringBoot项目搭建
导入依赖
<dependencies>
<!--也可以用继承父项目的方式-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.1</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.4.5</version>
</dependency>
</dependencies>
controller
@Controller
public class MyController {
@RequestMapping("/test")
@ResponseBody
public String testController(){
return "Ok!";
}
}
启动类
@SpringBootApplication
public class SpringBoot01Application {
public static void main(String[] args) {
//会扫描该类下的所有注解
SpringApplication.run(SpringBoot01Application.class,args);
}
}
使用IDEA插件创建【推荐】
创建的过程中可能会提示创建失败,连接不上spring官网。多试几次就好。这样就创建了一个SpingBoot的项目。
编写controller,运行启动类SpringbootStudyApplication测试。
@Controller
public class FirstController {
@RequestMapping("/first")
@ResponseBody
public String firstController(){
return "hello springBoot";
}
}
项目配置
SpringBoot默认读取项目下名字为application开头的 yml yaml properties配置文件。
配置端口、项目上下文、数据源
server:
port: 8080
servlet:
context-path: /springboot
spring:
datasource:
driver-class-name:
url:
username:
password:
基本格式要求
① 大小写敏感
② 使用缩进代表层级关系
③ 相同的部分只出现一次
④ 注意空格
三、整合其他技术
整合Mybatis
导入启动器
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.21</version>
</dependency>
application.yml配置
# 整合mybatis
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/mydb?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
username: root
password: 123456
mybatis:
type-aliases-package: com.lzf.pojo
mapper-locations: classpath:com/lzf/mapper/*.xml
整合druid
导入启动器
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
application.yml配置
spring:
datasource:
# 使用阿里的Druid连接池
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
# 填写你数据库的url、登录名、密码和数据库名
url: jdbc:mysql://127.0.0.1:3306/mydb?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
username: root
password: 123456
druid:
# 连接池的配置信息
# 初始化大小,最小,最大
initial-size: 5
min-idle: 5
maxActive: 20
# 配置获取连接等待超时的时间
maxWait: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
timeBetweenEvictionRunsMillis: 60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
# 打开PSCache,并且指定每个连接上PSCache的大小
poolPreparedStatements: true
maxPoolPreparedStatementPerConnectionSize: 20
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
filters: stat,wall,slf4j
# 通过connectProperties属性来打开mergeSql功能;慢SQL记录
connectionProperties: druid.stat.mergeSql\=true;druid.stat.slowSqlMillis\=5000
# 配置DruidStatFilter
web-stat-filter:
enabled: true
url-pattern: "/*"
exclusions: "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*"
# 配置DruidStatViewServlet
stat-view-servlet:
url-pattern: "/druid/*"
# IP白名单(没有配置或者为空,则允许所有访问)
allow: 127.0.0.1,192.168.8.109
# IP黑名单 (存在共同时,deny优先于allow)
deny: 192.168.1.188
# 禁用HTML页面上的“Reset All”功能
reset-enable: false
# 登录名
login-username: admin
# 登录密码
login-password: 123456
整合Lockback
不需要额外的添加Logback的依赖,因为在spring-boot-starter或者spring-boot-starter-web中已经包含了
classpath下创建logback.xml
<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
<!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
<property name="LOG_HOME" value="${catalina.base}/logs/" />
<!-- 控制台输出 -->
<appender name="Stdout" class="ch.qos.logback.core.ConsoleAppender">
<!-- 日志输出格式 -->
<layout class="ch.qos.logback.classic.PatternLayout">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n
</pattern>
</layout>
</appender>
<!-- 按照每天生成日志文件 -->
<appender name="RollingFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--日志文件输出的文件名-->
<FileNamePattern>${LOG_HOME}/server.%d{yyyy-MM-dd}.log</FileNamePattern>
<MaxHistory>30</MaxHistory>
</rollingPolicy>
<layout class="ch.qos.logback.classic.PatternLayout">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n
</pattern>
</layout>
<!--日志文件最大的大小-->
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<MaxFileSize>10MB</MaxFileSize>
</triggeringPolicy>
</appender>
<!-- 日志输出级别 -->
<root level="info">
<appender-ref ref="Stdout" />
<!-- <appender-ref ref="RollingFile" />-->
</root>
<logger name="com.lzf.mapper" level="DEBUG"></logger>
<!--日志异步到数据库 -->
<!--<appender name="DB" class="ch.qos.logback.classic.db.DBAppender">
日志异步到数据库
<connectionSource class="ch.qos.logback.core.db.DriverManagerConnectionSource">
连接池
<dataSource class="com.mchange.v2.c3p0.ComboPooledDataSource">
<driverClass>com.mysql.jdbc.Driver</driverClass>
<url>jdbc:mysql://127.0.0.1:3306/databaseName</url>
<user>root</user>
<password>root</password>
</dataSource>
</connectionSource>
</appender> -->
</configuration>
整合PageHelper
导入启动器
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.12</version>
</dependency>
在service中查询全部的方法基础上添加两句代码就OK
@Override
public PageInfo<Emp> findByPage(Integer pageNum, Integer pageSize) {
PageHelper.startPage(pageNum, pageSize);
List<Emp> list = empMapper.findAll();
PageInfo<Emp> pageInfo = new PageInfo(list);
return pageInfo;
}
整合Freemarker
导入启动器
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
controller往域中放入数据
@RequestMapping("/show")
public String freemarker(Map<String,Object> map){
map.put("name","猪八戒");
return "/show";
}
模板引擎中取出数据
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
${name}
</body>
</html>
遍历集合
<#--遍历List集合-->
<#list emps as emp>
<tr>
<td>${emp_index}</td>
<td>${emp.empno}</td>
<td>${emp.ename}</td>
<td>${emp.job}</td>
<td>${emp.sal}</td>
<td>${emp.deptno}</td>
</tr>
</#list>
<#--遍历amp集合-->
<#list empMap?keys as k>
<tr>
<td>${k_index}</td>
<td>${k}</td>
<td>${empMap[k].ename}</td>
<td>${empMap[k].job}</td>
<td>${empMap[k].sal}</td>
<td>${empMap[k].deptno}</td>
</tr>
</#list>
if指令
<!--判空 ?? 和 ! -->
<#if empList??>
<#list empList as emp>
<tr>
<td>${emp.mgr!'无'}</td>
</tr>
</#list>
</#if>
<!--隔行变色-->
<tr <#if emp_index%2 ==0 > style="background-color: gray" </#if>>
</tr>
整合Thymeleaf
导入启动器
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
<version>2.4.5</version>
</dependency>
添加约束
<html xmlns:th="http://www.thymeleaf.org">
controller往域中放入数据
@RequestMapping("/showIndex")
public String showIndex(Map<String,Object> map){
map.put("msg","猪八戒");
return "index";
}
模板引擎中取出数据
<body>
<!--th:text属性-->
<span th:text="${msg}"></span>
<!--th:value-->
<input th:value="${msg}">
</body>
遍历
<tr th:each="emp,i:${emps}">
<td th:text="${i.index}"></td>
<td th:text="${i.count}"></td>
<td th:text="${i.size}"></td>
<td th:text="${i.odd}"></td>
<td th:text="${i.even}"></td>
<td th:text="${i.first}"></td>
<td th:text="${i.last}"></td>
<td th:text="${emp.empno}"></td>
<td th:text="${emp.ename}"></td>
<td th:text="${emp.job}"></td>
<td th:text="${emp.mgr}"></td>
<td th:text="${emp.hiredate}"></td>
<td th:text="${emp.sal}"></td>
<td th:text="${emp.comm}"></td>
<td th:text="${emp.deptno}"></td>
</tr>
th:if
<span th:if="${name}!='张三'">会显示</span>
th:href
<a th:href="@{/getParam(id=1,name='msb')}" >跳转</a>
<!-- 获取作用域值-->
<a th:href="@{/getParam(name=${stu.name},age=${stu.age})}"
th:onclick
<!--写法1:仅仅支持数字和布尔类型参数的传递,字符串不支持-->
<a href="javascript:viod(0)" th:onclick="'del('+${emp.empno}+')'">删除</a>
<!--写法2:支持数字和文本类型的参数传递-->
<a href="javascript:void(0)" th:onclick="delEmp([[${emp.empno}]],[[${emp.ename}]])">删除</a>
<script>
function removeEmp(empno,ename){
var resulet =confirm("确定要删除编号为"+empno+"的"+ename);
if(resulet){
window.location.href="removeEmp?empno="+empno+"&ename="+ename;
}
}
</script>
四、项目部署打包
添加打包插件,IDEA插件创建的springboot项目就已经自带了
<!--打包插件-->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork>
</configuration>
</plugin>
</plugins>
</build>
导出jar包并运行
指定打包为jar
<packaging>jar</packaging>
使用maven package指令打包即可
打成包后,可以通过dos java -jar指令直接启动运行
导出war包并运
指定打包为war
<packaging>war</packaging>
排除项目中自带的所有的Tomcat插件和jsp servlet 依赖,因为这里要将项目放到一个Tomcat上运行
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<!--排除web启动中自动依赖的tomcat插件-->
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 手动依赖tomcat插件,但是表明项目打包时该依赖不会被打进去,目的主要是保证开发阶段本地SpringBoot项目可以正常运行-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
SpringBoot的启动类继承SpringBootServletInitializer,并重写configure
@SpringBootApplication
public class Springboot04Application extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(Springboot04Application.class);
}
}
使用maven package指令打包,并将war包放到tomcat下的webapps下,启动tomcat即可。
五、异常处理
-
设置具体的状态码页面
在templates/下新建error文件夹,在error中新建:状态码.html的页面。例如当出现500时显示的页面为500.html -
使用x进行模糊匹配
当出现5开头状态码的错误时,显示页面可以命名为5xx.html
当出现50开头状态码的错误时,显示页面可以命名为50x.html -
统一错误显示页面
在templates下新建error.html。如果项目中不存在具体状态码的页面或没有使用x成功匹配的页面时,显示error.html作为错误显示页面。
六、拦截器
新建拦截器类。
注意:不要忘记类上注解@Component
@Component
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("执行拦截器");
return true;
}
}
配置拦截器
@Configuration
public class MyConfig implements WebMvcConfigurer {
@Autowired
private MyInterceptor myInterceptor;
//配置拦截器的映射
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(myInterceptor).addPathPatterns("/**").excludePathPatterns("/login");
}
}
ass MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println(“执行拦截器”);
return true;
}
}
配置拦截器
```java
@Configuration
public class MyConfig implements WebMvcConfigurer {
@Autowired
private MyInterceptor myInterceptor;
//配置拦截器的映射
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(myInterceptor).addPathPatterns("/**").excludePathPatterns("/login");
}
}