一、springboot的优势
在学习springboot之前我们一定使用过SSM做过项目,我们发现SSM在开发上非常方便,但它的配置却很繁琐,特别是在稍微大一点的项目中,我们要保证所有依赖的版本不发生冲突是很麻烦的一件事,springboot的出现就是为了解决这一问题,它只需要我们指明一个启动器(可以是官方的也可以是第三方),就可以将一类相关资源安全导入进来,大大节约了我们配置的时间。
特征:
① 使用Spring Boot可以创建独立的Spring应用程序
② 在Spring Boot中直接嵌入了Tomcat、Jetty、Undertow等Web 容器,所以在使用SpringBoot做Web开发时不需要部署WAR文件
③ 通过提供自己的启动器(Starter)依赖,简化项目构建配置
④ 尽量的自动配置Spring和第三方库
⑤ 绝对没有代码生成,也不需要XML配置文件,自定义配置集中在yml文件里面(日志配置文件除外)
springboot创建
方式一:继承
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.13.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
方式二:依赖
当我们的项目需要继承另一个项目时,我们可以使用依赖来配置springboot
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.1.13.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
启动类
启动类是用来启动springboot项目的,它跟启动器不是一个东西。启动类在启动时还会做注解扫描,所以启动类应该放在包的根目录下
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class,args);
}
}
其他的地方跟SSM没有区别,springboot的主要作用是用来整合依赖。
配置文件读取顺序
如果同一个目录下,有application.yml也有application.properties,默认先读取application.properties。
如果同一个配置属性,在多个配置文件都配置了,默认使用第1个读取到的,后面读取的不覆盖前面读取到的。
springboot整合SSM框架
pom文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.13.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.codeXie</groupId>
<artifactId>02_marriedmanager</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>02_marriedmanager</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.11</version>
</dependency>
<!--配置Druid的启动器依赖-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<!--配置PageHelper分页插件的启动器依赖-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.12</version>
</dependency>
<!--配置freeMarker的启动器依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>RELEASE</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
由于pagehelper中有mybatis的启动器,为了避免版本冲突问题我们不用在项目中引入新的mybatis启动器了。
yml文件
# 端口设置
server:
port: 8080
# spring配置
spring:
datasource:
# 使用阿里的Druid连接池
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
# 填写你数据库的url、登录名、密码和数据库名
url: jdbc:mysql://127.0.0.1:3306/tingyu?characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8
username: root
password: j3391111
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.163.1
# IP黑名单 (存在共同时,deny优先于allow)
deny: 192.168.1.188
# 禁用HTML页面上的“Reset All”功能
reset-enable: false
# 登录名
login-username: admin
# 登录密码
login-password: j3391111
# mybatis配置
##配置Mybatis的mapper配置文件路径
mybatis:
mapper-locations: classpath:mybatis/*.xml
yml文件主要是用来对插件做一些自定义配置的,比如数据源的设定、mapper文件路径等等
springboot整合logback
Spring Boot默认使用Logback组件作为日志管理。Logback是由log4j创始人设计的一个开源日志组件。
在Spring Boot项目中我们不需要额外的添加Logback的依赖,因为在spring-boot-starter或者spring-boot-starter-web中已经包含了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.bjsxt.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>
将这个xml文件放在resources目录下即可
FreeMarker基础 之常用指令
List指令
遍历list
<#list stus as stu>
<tr><td>${stu_index+1}</td>
<td>${stu.name}</td>
<td>${stu.age}</td>
<td>${stu.mondy}</td>
</tr>
</#list>
说明: _index:得到循环的下标,使用方法是在stu后边加"_index",它的值是从0开始
遍历map
<#list stuMap?keys as k>
<tr>
<td>${k_index + 1}</td>
<td>${stuMap[k].name}</td>
<td>${stuMap[k].age}</td>
<td >${stuMap[k].mondy}</td>
</tr>
</#list>
if指令
if 指令即判断指令,是常用的FTL指令,freemarker在解析时遇到if会进行判断,条件为真则输出if中间的内容,否 则跳过内容不再输出。
<#list stus as stu>
<tr>
<td <#if stu.name =='小明'>style="background:red;"</#if>>${stu.name}</td>
<td>${stu.age}</td>
<td >${stu.mondy}</td>
</tr>
</#list>
通过阅读上边的代码,实现的功能是:如果姓名为“小明”则背景色显示为红色。
运算符
1、算数运算符 FreeMarker表达式中完全支持算术运算,FreeMarker支持的算术运算符包括:+, - , * , / , %
2、逻辑
运算符 逻辑运算符有如下几个: 逻辑与:&& 逻辑或:|| 逻辑非:! 逻辑运算符只能作用于布尔值,否则将产生错误
3、比较运算符
表达式中支持的比较运算符有如下几个:
① =或者==:判断两个值是否相等.
② !=:判断两个值是否不等.
③ > 或者gt:判断左边值是否大于右边值
④ >=或者gte:判断左边值是否大于等于右边值
⑤ <或者lt:判断左边值是否小于右边值
⑥ <=或者lte:判断左边值是否小于等于右边值
注意: =和!=可以用于字符串,数值和日期来比较是否相等,但=和!=两边必须是相同类型的值,否则会产生错误,而且FreeMarker是精确比较,“x”,"x ","X"是不等的.其它的运行符可以作用于数字和日期,但不能作用于字符串,大部分的时候,使用gt等字母运算符代替>会有更好的效果,因为 FreeMarker会把>解释成FTL标签的结束字符,当然,也可以使用括号来避免这种情况,如:<#if (x>y)>
空值处理
方式一:判断方式
<#if stus??>
.......
</#if>
若stus为空则返回false,中间部分内容不会执行
方式二:默认值方式
${name!“xie”} 若name为null则显示xie
内建函数
格式:变量名?方法名
1.集合大小
${stus?size} //放回集合的长度
2.日期格式化
显示年月日: ${today?date}
显示时分秒:${today?time}
显示日期+时间:${today?datetime} <br>
自定义格式化: ${today?string("yyyy年MM月")}
springboot整合JSP
第一步:在main目录下创建webapp并将它标记为Sources Root
第二步:打开项目结构,将创建的webapp设置为Web Resources Directories
注意:即使我们整合了JSP,我们也只能通过请求转发来访问我们的页面
SpringBoot整合Thymeleaf
Thymeleaf是原生的,不依赖于标签库.它能够在接受原始HTML的地方进行编辑和渲染.因为它没有与Servelet规范耦合,因此Thymeleaf模板能进入jsp所无法涉足的领域。
Thymeleaf在Spring Boot项目中放入到resources/templates中。这个文件夹中的内容是无法通过浏览器URL直接访问的(和WEB-INF效果一样),所有Thymeleaf页面必须先走控制器。
使用流程
1.添加启动器
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
2.在template下建立html文件
//为了有提示,修改html页面中<html>标签为
<html xmlns:th="http://www.thymeleaf.org" >
3.通过请求转发来访问这些页面,Thymeleaf为我们设置了视图解析器,我们只用返回页面对于resources/templates的相对路径就可以了,也不用写后缀
语法
th:text属性
向HTML标签内部输出信息。
<!--直接向标签内部填充内容,清空原有内容 -->
<span th:text="jqk"></span>
<!-- 从作用于中获取name输入到标签内部 -->
<span th:text="${name}"></span>
th:value
表单元素,设置HTML标签中表单元素value属性时使用。
<input type="text" th:value="${name}"/>
th:if
进行逻辑判断。如果成立该标签生效(显示),如果不成立,此标签无效(不显示)。
注意:判断条件中逻辑判断符号写在${}外面的
<span th:if="${name}!='张三'">会显示</span>
th:each
循环遍历.
示例中u为迭代遍历。
th:each=”u,i : ${list}” 其中i表示迭代状态。
1,index:当前迭代器的索引 从0开始
2,count:当前迭代对象的计数 从1开始
3,size:被迭代对象的长度
4,even/odd:布尔值,当前循环是否是偶数/奇数 从0开始
5,first:布尔值,当前循环的是否是第一条,如果是返回true否则返回false
6,last:布尔值,当前循环的是否是最后一条,如果是则返回true否则返回false
<table>
<thead>
<tr>
<td>用户编号</td>
<td>用户名</td>
<td>密码</td>
<td>电话</td>
<td>婚期</td>
</tr>
</thead>
<tbody>
<tr th:each="u,i:${list}">
<td th:text="${u.pid}"></td>
<td th:text="${u.pname}" th:if="${u.pname}!='xielei'"></td>
<td th:text="${u.ppwd}"></td>
<td th:text="${u.phone}"></td>
<td th:text="${#dates.format(u.marrydate,'yyyy-MM-dd')}"></td>
</tr>
</tbody>
</table>
th:href
设置href属性的。取值使用@{}取值
<a th:href="@{/getParam(id=1,name='bjsxt')}" >跳转</a>
<!-- 获取作用域值-->
<a th:href="@{/getParam(name=${name})}">跳转二</a>
th:onclick
点击传递参数的单击事件
<th><a href="javascript:viod(0)" th:onclick="del([[${stu.sid}]])">删除</a></th>
使用内置对象的语法
1)引用内置对象需要使用#
2)大部分内置对象的名称都以s结尾。如:strings、numbers、dates
字符串
${#strings.isEmpty(key)}
判断字符串是否为空,如果为空返回true,否则返回false
${#strings.contains(msg,'T')}
判断字符串是否包含指定的子串,如果包含返回true,否则返回false
${#strings.startsWith(msg,'a')}
判断当前字符串是否以子串开头,如果是返回true,否则返回false
${#strings.endsWith(msg,'a')}
判断当前字符串是否以子串结尾,如果是返回true,否则返回false
${#strings.length(msg)}
返回字符串的长度
${#strings.indexOf(msg,'h')}
查找子串的位置,并返回该子串的下标,如果没找到则返回-1
日期格式化处理
${#dates.format(key)}
格式化日期,默认的以浏览器默认语言为格式化标准
${#dates.format(key,'yyyy/MM/dd')}
按照自定义的格式做日期转换
${#dates.year(key)}
${#dates.month(key)}
${#dates.day(key)}
Year:取年
Month:取月
Day:取日
操作域对象
HttpServletRequest
request.setAttribute("req", "HttpServletRequest");
<span th:text="${#httpServletRequest.getAttribute('req')}"></span>
<span th:text="${#request.getAttribute('req')}"></span>
HttpSession
request.getSession().setAttribute("ses", "HttpSession");
<span th:text="${session.ses}"></span><br/>
<span th:text="${#session.getAttribute('ses')}"></span><br/>
ServletContext
request.getSession().getServletContext().setAttribute("app", "Application");
<span th:text="${application.app}"></span>
<span th:text="${#servletContext.getAttribute('app')}"></span>
Springboot项目打包
SpringBoot项目打包分为jar包和war包,在实际应用中我们一般将其打成jar包(因为操作简单且不容易出问题),而war包的打包繁琐复杂并且代码中的请求路径容易出问题,所以我们尽量不要打成war包
(一) 配置打包插件
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork>
</configuration>
</plugin>
</plugins>
</build>
(二)操作流程
运行jar包项目
① 在本地windows系统中运行
把此jar粘贴到任意目录,示例粘贴到D根目录下
启动windows命令行。依次输入:
java-jar 文件名.jar
也可以新建一个批处理文件,例如:run.bat,在文件中添加
d:
java -jar 文件名.jar
② 部署到linux
和windows步骤一样。把jar上传到linux后放入到任意目录中,进入到jar所在目录 后执行java -jar 文件.jar 就可以运行。
也可以在jar所在文件夹中新建一个文件,执行运行文件。
# vim startup.sh` \\文件中输入java -jar 文件.jar
# chmod a+x startup.sh
# ./startup
springboot处理异常
(一)异常显示页面
1 设置具体的状态码页面
在templates/下新建error文件夹,在error中新建:状态.html的页面。例如当出现500时显示的页面为500.html
2 使用x进行模糊匹配
当出现5开头状态码的错误时,显示页面可以命名为5xx.html
当出现50开头状态码的错误时,显示页面可以命名为50x.html
3 统一错误显示页面
在templates下新建error.html。如果项目中不存在具体状态码的页面或没有使用x成功匹配的页面时,显示error.html作为错误显示页面。
(二) 异常处理机制
在Spring Boot项目中除了设置错误页面,还可以通过注解实现错误处理。
常见方式如下:
- 局部方式:在控制器类中添加一个方法,结合@ExceptionHandler。但是只能对当前控制器中方法出现异常进行解决。
- 全局方式:新建全局异常类,通过@ControllerAdvice结合@ExceptionHandler。
当全局异常处理和局部处理同时存在时,局部生效(就近原则)
1.局部方式
通过@ExceptionHandler注解处理异常
@Controller
public class UsersController {
@RequestMapping("showInfo")
public String showInfo(){
String str = null;
str.length();
return "ok";
}
@ExceptionHandler(value = {java.lang.NullPointerException.class} )
public ModelAndView nullpointExcepitonHandler(Exception e){
ModelAndView mv = new ModelAndView();
mv.addObject("err",e.toString());
mv.setViewName("error1");
return mv;
}
}
2.全局方式
为全局异常类配置一个bean交给spring容器,内部采用aop的方式处理controller的异常
通过@ControllerAdvice与@ExceptionHandler注解处理异常
/**
* 全局异常处理类
*/
@ControllerAdvice
public class GlobalException {
@ExceptionHandler(value = {java.lang.NullPointerException.class} )
public ModelAndView nullpointExcepitonHandler(Exception e){
ModelAndView mv = new ModelAndView();
mv.addObject("err",e.toString());
mv.setViewName("error1");
return mv;
}
@ExceptionHandler(value = {java.lang.ArithmeticException.class} )
public ModelAndView arithmeticExceptionHandler(Exception e){
ModelAndView mv = new ModelAndView();
mv.addObject("err",e.toString());
mv.setViewName("error2");
return mv;
}
}
springboot整合junit单元测试
(一)添加启动器
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
(二)编写测试类
在src/main/test里面新建com.bjsxt.MyTest
注意:
- 测试类不能叫做Test
- 测试方法必须是public
- 测试方法返回值必须是void
- 测试方法必须没有参数
//告诉SpringBoot使用哪个单元测试工具
@RunWith(SpringJUnit4ClassRunner.class)
//当前类为测试类,classes指定哪个类为启动类
@SpringBootTest(classes = MyApplication.class)
public class MyTest {
@Autowired
UserMapper userMapper;
@Autowired
private UserService userService;
@Test
public void test(){
User user = userMapper.selectById(1L);
System.out.println(user);
System.out.println(userService.test());
}
}