本文由 Oo鲁毅oO 首发于 掘金,下方为原文链接
一文带你学习 SpringBoot
产生背景:Spring开发比较繁琐,配置文件很多,部署流程复杂,整合第三方框架难度大。这会降低开发效率
SpringBoot是一个简化Spring应用创建和开发的框架
整合了整个Spring技术栈,是JavaEE开发一站式解决方案
优点:
步骤:
传统的应用需要创建web工程,然后将应用打成war包,然后部署在容器中
而SpringBoot只需要打成一个jar包,其中内置了tomcat
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>com.lygroupId>
<artifactId>springboot01-helloworldartifactId>
<version>1.0-SNAPSHOTversion>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.1.9.RELEASEversion>
parent>
<name>springboot01-helloworldname>
<url>http://www.example.comurl>
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<maven.compiler.source>1.8maven.compiler.source>
<maven.compiler.target>1.8maven.compiler.target>
properties>
<dependencies>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.11version>
<scope>testscope>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
dependencies>
<build>
build>
project>
package com.ly.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* Author: LuYi
* Date: 2019/10/27 11:05
* Description: 描述
*/
@Controller
public class HelloController {
@RequestMapping("/hello")
@ResponseBody
public String hello(){
return "Hello World";
}
}
package com.ly;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* Author: LuYi
* Date: 2019/10/27 11:05
* Description: 使用@SpringBootApplication将类标注成SpringBoot应用
*/
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
默认会扫描@SpringBootApplication
注解所在的包及其子包,也可使用@ComponentScan("com.ly.controller")
注解进行指定
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
添加该插件,将应用打成可执行的jar包, 执行:java -jar jar文件
父工程
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.1.9.RELEASEversion>
parent>
父工程的父工程:用来管理SpringBoot应用中依赖的版本,进行版本控制
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-dependenciesartifactId>
<version>2.1.9.RELEASEversion>
<relativePath>../../spring-boot-dependenciesrelativePath>
parent>
依赖:通过starter
指定依赖
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
SpringBoot提供了很多starter(启动器),分别对应了不同的应用场景,当在项目中引入这些starter时,相应场景的依赖就会被导入进来
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)
@SpringBootApplication
标注在类上,表示这个类是SpringBoot的启动类,通过该类的Main方法启动SpringBoot应用
@SpringBootConfiguration
标注在类上,表示这个类是SpringBoot的配置类
层级关系:SpringBootConfiguration——>@Configuration——>@Component
@Configuration:标注在类上,表示这个类是Spring的配置类,相当于XML配置文件
@EnableAutoConfiguration
开启自动配置功能,简化了以前繁琐的配置
SpringBoot在启动时会在/META-INF/spring.factories中EnableAutoConfiguration指定的值,将这些值作为自动配置类添加到容器中,这些自动配置类会帮我们完成很多配置工作。
@ComponentScan
标注在类上,指定要扫描的包及其子包
使用Spring initializer快速构建SpringBoot项目
pom文件和主程序类自动生成,直接写业务逻辑即可
resources文件夹的目录结构
|-static 存放静态资源,如js,css,images
|-template 存放模板引擎,如freemarker、thymeleaf等
|-application.properties SpringBoot应用的配置文件,可以修改默认设置
SpringBoot的默认全局配置文件有两种:
文件名固定,存放在classpath:/或classpath:/config/目录下
可以修改Spring Boot默认配置,具体参考: https://docs.spring.io/spring-boot/docs/2.1.9.RELEASE/reference/html/common-application-properties.html
注意:SpringBoot2.0和1.0的配置有区别,有的配置项已被删除
YAML不是一种标记语言,YAML是专门用来写配置文件的,它以数据为中心,简介强大,比xml和properties更适合做配置文件
YAML文件以.yml或.yaml为后置名
server:
port: 8081 #写法:key: value 冒号后面必须有空格
servlet:
context-path: /springboot03/
#
表示注释YAML支持的数据结构有三种:
三种数据结构的用法:
1.字面量:普通的值,如数字、字符串、布尔值
number: 12.5
str: hello
name: 'tom cruise' #如字符串包含空格及特殊字符需要使用 引号 引起来
name: 'tom \n cruise' #不会对特殊字符进行转义 结果为:tom 换行 cruise
name: "tom \n cruise" #对特殊字符进行转义,会作为普通字符输出, 结果为 tom \n cruise
对象,也成为映射Map,包含属性和值
# 写法1:换行写
user:
name: tom
age: 20
sex: male
# 写法2:行内写法
user: {name: tom, age: 20, sex: male}
# 写法1: 一组短横线开头的行
names:
- tom
- jack
- alice
# 写法2: 行内写法
name: {tom,jack,alice}
通过加载配置文件,为类中的属性注入值
user:
username: admin
age: 21
status: true
birthday: 2019/2/14
address:
province: 黑龙江省
city: 哈尔滨市
lists:
- list1
- list2
- list3
maps: {k1: v1,k2: v2}
User
package com.luyi.bean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* Author: LuYi
* Date: 2019/10/27 13:49
* Description: 通过加载配置文件为当前类中的属性注入值
*/
// 必须将当前类加入到容器
@Component
// 默认读取全局配置文件获取值,当前类中的所有属性与 user 进行绑定
@ConfigurationProperties(value = "user")
public class User {
private String username;
private Integer age;
private Boolean status;
private Date birthday;
private Address address;
private List<String> lists;
private Map<String, Object> maps;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Boolean getStatus() {
return status;
}
public void setStatus(Boolean status) {
this.status = status;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
public List<String> getLists() {
return lists;
}
public void setLists(List<String> lists) {
this.lists = lists;
}
public Map<String, Object> getMaps() {
return maps;
}
public void setMaps(Map<String, Object> maps) {
this.maps = maps;
}
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
", age=" + age +
", status=" + status +
", birthday=" + birthday +
", address=" + address +
", lists=" + lists +
", maps=" + maps +
'}';
}
}
Address
package com.luyi.bean;
/**
* Author: LuYi
* Date: 2019/10/27 13:50
* Description: 描述
*/
public class Address {
private String province;
private String city;
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
@Override
public String toString() {
return "Address{" +
"province='" + province + '\'' +
", city='" + city + '\'' +
'}';
}
}
package com.luyi.springboot03config;
import com.luyi.bean.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class Springboot03ConfigApplicationTests {
@Autowired
private User user;
@Test
void contextLoads() {
System.out.println(user);
}
}
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-configuration-processorartifactId>
<optional>trueoptional>
dependency>
user.username=alice
user.age=22
user.status=false
user.birthday=2019/10/27
user.address.province=黑龙江省
user.address.city=哈尔滨
user.lists=list1,list2,list3
user.maps.k1=v1
user.maps.k2=v2
注意:在IDEA中默认使用UTF-8编码,properties文件默认使用ASCII编码,所以会出现乱码,可通过勾选解决
优先级:properties > yml
@Value("${user.username}")
private String username;
@Value("${user.age}")
private Integer age;
@Value("${user.status}")
private Boolean status;
@Value("${user.birthday}")
private Date birthday;
//@Value不支持复杂类型封装
private Address address;
@Value("${user.lists}")
private List<String> lists;
private Map<String, Object> maps;
@Value与@ConfigurationProperties比较:
可以为不同环境提供不同配置信息,如开发环境、测试环境、生产环境等
两种方式:
步骤:
1.创建不同环境的properties文件
文件命名必须符合aplication-xxx.properties的格式
application-dev.properties
server.port=9991
application-test.properties
server.port=9992
application-prod.properties
server.port=9993
2.在application.properties中指定需要激活的配置
#指定要激活的配置
spring.profiles.active=prod
1.在yml中使用三个短横线定义多个文档块
spring:
profiles: dev
server:
port: 9991
---
spring:
profiles: test
server:
port: 9992
---
spring:
profiles: prod
server:
port: 9993
2.在第一个文档块指定要激活的环境
spring:
profiles:
active: test
---
问题:@ConfigurationProperties默认是从全局配置文件中读取值,如果想自定义属性文件中获取值怎么办?
解决:使用@PropertySource注解加载外部属性文件
// 必须将当前类加入到容器
@Component
//加载外部的属性文件
@PropertySource({"classpath:user.properties"})
// 默认读取全局配置文件获取值,当前类中的所有属性与 user 进行绑定
@ConfigurationProperties(value = "user")
public class User{
问题:如果有信息需要写道xml文件中,想加载xml文件怎么办
解决:使用@ImportResource加载外部配置文件
推荐使用全注解方式向Spring容器添加组件,@Configuration和@Bean
/**
* Author: LuYi
* Date: 2019/10/28 14:49
* Description: 描述
*/
//添加在类上,表示这个类是一个配置类,相当于spring配置文件
@Configuration
public class SpringConfig {
//标注在方法上,用来向容器中添加组件,将方法的返回值添加到容器中,方法名作为bean的id
@Bean
public Address address(){
Address address = new Address();
address.setProvince("山东");
address.setCity("日照");
return address;
}
}
1.SpringBoot启动时加载主配置类,使用@EnableAutoConfiguration开启了自动配置功能
2.@EnableAutoConfiguration中使用了 @Import({AutoConfigurationImportSelector.class})向容器中添加了一些组件(自动配置类)
查看AutoConfigurationImportSelector类中的selectImports方法,再点击getAutoConfigurationEntry方法中的`getCandidateConfigurations方法
通过getCandidateConfigurations中的loadFactoryNames方法加载到SpringFactory,
再通过classLoader加载META-INF/spring.factories
的配置,从配置中获取EnableAutoConfiguration(spring-boot-autoconfigure-2.1.9.RELEASE.jar)对应的值。
将这些自动配置类(xxxAutoConfiguration)添加到容器中
3.通过自动配置类完成自动配置功能。
以HttpEncodingAutoConfiguration为例,就是以前在web.xml中配置的CharacterEncodingFilter过滤器
//表示这是一个配置类,相当于以前编写的Spring配置文件
@Configuration
//启用HttpProperties类的ConfigurationProperties功能,通过配置文件为属性注入值,并将其添加到容器中
@EnableConfigurationProperties({HttpProperties.class})
//当该应用是web应用时才生效
@ConditionalOnWebApplication(
type = Type.SERVLET
)
//必须包含CharacterEncodingFilter类才生效
@ConditionalOnClass({CharacterEncodingFilter.class})
//如果配置文件中有spring.http.encoding选项则该配置生效,否则不生效。但是默认已经生效了
@ConditionalOnProperty(
prefix = "spring.http.encoding",
value = {"enabled"},
matchIfMissing = true
)
public class HttpEncodingAutoConfiguration {
private final Encoding properties;
//将容器中的HttpProperties注入
public HttpEncodingAutoConfiguration(HttpProperties properties) {
this.properties = properties.getEncoding();
}
//将返回的filter添加到容器中,作为bean
@Bean
//如果容器中没有这个bean才会生效
@ConditionalOnMissingBean
public CharacterEncodingFilter characterEncodingFilter() {
CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
filter.setEncoding(this.properties.getCharset().name());
filter.setForceRequestEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.REQUEST));
filter.setForceResponseEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.RESPONSE));
return filter;
}
//从配置文件中获取指定的值,然后绑定到指定的属性值
@ConfigurationProperties(
prefix = "spring.http"
)
public class HttpProperties {
private Charset charset;
private Boolean force;
private Boolean forceRequest;
private Boolean forceResponse;
private Map<Locale, Charset> mapping;
注意:
可以通过开启debug模式查看自动配置类的匹配情况
#开启debug模式
debug=true
使用SpringBoot开发Web应用的步骤:
1.创建SpringBoot项目,添加对应的starter
2.在配置文件中指定必要的少量配置
3.编写业务代码
Web开发的自动配置类WebMvcAutoConfiguration
查看WebMvcAutoConfiguration——>addResourceHandlers()——>getStaticLocations()——>staticLocations
静态资源的默认位置
"classpath:/META-INF/resources/",
"classpath:/resources/",
"classpath:/static/",
"classpath:/public/"
可以通过上面的文件夹可以访问到静态资源
也可以在配置文件中自己指定可以访问的位置
# 指定静态资源的位置 存放在根目录下的public文件夹中
spring.resources.static-locations=classpath:/public
查看WebMvcAutoConfiguration—>welcomePageHandlerMapping()—>getWelcomePage()
将index.html页面放到任意一个静态资源文件夹中的
查看WebMvcAutoConfiguration—>内部类FaviconConfiguration—>faviconHandlerMapping
将favicon.ico放到静态资源的任意文件夹中即可
目前Java Web开发推荐使用模板引擎,不建议使用jsp页面
常用的模板引擎:Freemarker、Thymeleaf等
SpringBoot推荐Thymeleaf,且默认不支持jsp,因为jsp必须要打成war包。
补充:目前主流的web开发更推荐前后端分离,前端使用MVVM框架,Vue.js、Angular、React等
步骤:
1.添加Thymeleaf的依赖
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-thymeleafartifactId>
dependency>
2.将html页面放到templates下
templates下的html不能直接访问,需要使用Controller跳转,由Thymeleaf进行渲染
ThymeleafAutoConfiguration—>ThymeleafProperties
public static final String DEFAULT_PREFIX = "classpath:/templates/";
public static final String DEFAULT_SUFFIX = ".html";
默认拼接前缀和后缀
3.使用thymeleaf
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<h2>successh2>
<p th:text="${name}">p>
body>
html>
4.修改页面后,让其实时生效
由于thymeleaf默认启用了缓存,将缓存禁用掉
#禁用thymeleaf的缓存
spring.thymeleaf.cache=false
补充:还需要开启idea的自动编译,idea默认保存时不会自动编译
th:text、th:utext
设置元素中的文本内容
th:text对特殊字符进行转义,等价于内联方式[[${ }]]
th:utext不对特殊字符集进行转义,等价于内联方式[(${ })]
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<div th:text="${hello}">aaadiv>
<div th:utext="${hello}">bbbdiv>
<div>[[${hello}]]aaadiv>
<div>[(${hello})]bbbdiv>
body>
html>
th:html原生属性
用来替换指定的html原生属性的值
@RequestMapping("/test2")
public String test2(Model model){
model.addAttribute("hello", "你好");
model.addAttribute("id", "mydiv");
model.addAttribute("title", "this is a div");
return "result";
}
<div id="div1" title="这是一个div" th:id="${id}" th:title="${title}">divdiv>
th:if、th:unless、th:switch、th:case
条件判断,类似于if
<div th:if="${age>=18}">成年div>
<p th:unless="${age<18}">成年p>
<p th:switch="${role}">
<span th:case="student">学生span>
<span th:case="teacher">老师span>
<span th:case="*">其他span>
p>
<hr>
th:each
循环,类似于for each
<ul>
<li th:each="name:${names}" th:text="${name}">li>
ul>
th:object、th:field
用于表单数据对象的绑定,将表单绑定到Controller的一个JavaBean参数,常与th:field
一起使用,需要和*{}选择表达式配合使用
<h2>修改用户信息h2>
<form action="modify" method="post" th:object="${user}">
编号:<input type="text" th:field="*{id}" readonly> <br>
姓名:<input type="text" th:field="*{name}"> <br>
年龄:<input type="text" th:field="*{age}"> <br>
<input type="submit" value="修改">
form>
th:fragment
声明代码片段,常用于页面头部和尾部的引入
<header th:fragment="head">
这是页面的头部,导航
header>
th:include、th:insert、th:replace
引入代码片段,类似于jsp:include
<div th:include="include/header::head">div>
三者之间的区别
th:include会保留自己的标签,不要th:fragment的标签(Thymeleaf 3.0 后不推荐使用)
th:insert保留自己的标签,也保留th:fragment的标签
th:relpace不保留自己的标签,保留thfragment的标签
${} 变量表达式
获取对象的属性、方法
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<div th:text="${user.name}">div>
<div th:text="${user['age']}">div>
<div th:text="${users[1].name}">div>
<div>[[${users.size()}]]个div>
body>
html>
使用内置的基本对象,如session和application
<div th:text="${session.sex}">div>
<div th:text="${application.hobby}">div>
使用内置的工具对象,如#strings、#dates、#arrays、#lists、#maps等
<div th:text="${#strings.startsWith(user.name, 't')}">div>
<div th:text="${#strings.substring(user.name, 0, 2)}">div>
<div th:text="${#strings.length(user.name)}">div>
<div th:text="${#dates.createNow()}">div>
<div th:text="${#dates.create(2018, 10, 14)}">div>
<div th:text="${#dates.format(birthday, 'yyyy-MM-dd HH:mm:ss')}">div>
*{} 选择表达式(星号表达式)
<div th:object="${user}">
<div th:text="*{id}">div>
<div th:text="*{name}">div>
<div th:text="*{age}">div>
div>
@{} url表达式
<head>
<meta charset="UTF-8">
<title>Titletitle>
<link rel="stylesheet" th:href="@{/css/style.css}">
head>
<a th:href="@{/findUser(name=${user.name})}">查询指定的用户信息a>
<a href="product/list.html" th:href="@{/product/list}">商品列表a>
<script th:src="@{/js/common.js}">script>
运算符
eq gt le == != 三目运算符
使用SpringBoot提供的devtools实现热部署
原理:实时监控classpath下文件的变化,如果发生变化自动重启
配置:添加devtools依赖
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-devtoolsartifactId>
<optional>trueoptional>
dependency>
以前在SpringMVC中可以通过如下代码进行视图跳转和拦截器:
<mvc:view-controller path="/showLogin" view-name="login"/>
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/hello"/>
<bean class="com.luyi.interceptor.HelloInterceptor"/>
mvc:interceptor>
mvc:interceptors>
SpringBoot默认配置默认没有提供以上功能,需要自己扩展,使用WebMvcConfigurer接口
步骤:
1.定义一个配置类,实现WebMvcConfigurer接口
2.实现需要的方法
/**
* Author: LuYi
* Date: 2019/10/29 17:58
* Description: 扩展默认的SpringMVC的功能
* 要求:
* 1.将该类标记为配置类
* 2.实现WebMvcConfigurer接口
* 3.根据需要实现接口中相应的方法
*
* 注意:这个接口中的方法都添加了jdk1.8中的default方法修饰,不强制实现所有方法(jdk1.8新特性)
* 在SpringBoot1.0中是继承WebMvcConfigurerAdapter类,SpringBoot2.0是基于jdk1.8的,
* 所以通过实现WebMvcConfigurer的方式
*/
//将该类设置为配置类
@Configuration
public class CustomMvcConfig implements WebMvcConfigurer {
//添加ViewController
@Override
public void addViewControllers(ViewControllerRegistry registry) {
//将访问login页面的url设置为showLogin
registry.addViewController("/showLogin").setViewName("login");
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**")
.excludePathPatterns("/test2");
}
}
当程序出现异常时进行全局处理,SpringBoot默认的异常信息提示:Whitelabel Error Page
两种方式:
创建 错误状态码.html
页面,放到templates/error目录中,当发生错误时会自动到该目录下查找对应的错误页面
可以创建如 4xx.html
或5xx.html
页面,用来匹配所有该类型的错误(会优先进行精确匹配
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<h2>5xx错误h2>
<h3>状态码:[[${status}]]h3>
<h3>异常消息:[[${message}]]h3>
<h3>错误提示:[[${error}]]h3>
<h3>时间戳:[[${timestamp}]]h3>
body>
html>
/**
* Author: LuYi
* Date: 2019/10/29 18:45
* Description: 异常通知:用来处理全局异常
*/
@ControllerAdvice
public class ExceptionAdvice {
@ExceptionHandler(ArithmeticException.class)
public String arithmetic(Exception e){
System.out.println("警报:程序出现异常,发短信:" + e.getMessage());
return "error/5xx";
}
@ExceptionHandler(Exception.class)
public String exception(Exception e){
System.out.println("警报:程序出现异常,发邮件:" + e.getMessage());
return "error/5xx";
}
}
SpringBoot中默认内置了Servlet:Tomcat
问题:SpringBoot默认以jar包方式启动内置的Servlet容器,没有web.xml文件,如何注册Servlet三大组件:Servlet、Filter、Listener
解决:通过自定义Servlet配置,使用ServletRegistrationBean、FilterRegistrationBean、ServletListenerRegistrationBean
步骤:
1.定义一个配置类
2.自定义一个方法,用来注册组件
/**
* Author: LuYi
* Date: 2019/10/29 19:12
* Description: 自定义Servlet配置
*/
//将该类声明为配置类
@Configuration
public class CustomServletConfig {
//将方法返回值放到Spring容器
@Bean
public ServletRegistrationBean myServlet(){
ServletRegistrationBean<Servlet> registrationBean = new ServletRegistrationBean<>();
//对MyServlet进行注册
registrationBean.setServlet(new MyServlet());
ArrayList<String> urls = new ArrayList<>();
urls.add("/myServlet");
registrationBean.setUrlMappings(urls);
return registrationBean;
}
//注册Filter
@Bean
public FilterRegistrationBean myFilter(){
FilterRegistrationBean<Filter> registrationBean = new FilterRegistrationBean<>();
//注册filter
registrationBean.setFilter(new MyFilter());
registrationBean.addUrlPatterns("/showLogin", "/test1");
return registrationBean;
}
//注册Listener
@Bean
public ServletListenerRegistrationBean myListener(){
ServletListenerRegistrationBean<MyListener> registrationBean = new ServletListenerRegistrationBean<>();
registrationBean.setListener(new MyListener());
return registrationBean;
}
}
使用内置Servlet容器:
优点:使用简单,将应用打成jar包
缺点:不支持jsp、可定制性不高
使用外部的Servlet容器
优点:支持jsp、可定制性高
缺点:需要将应用打成war包
步骤:
1.创建一个Maven的war工程
有如下三个变化
1.打包方式变为war
<packaging>warpackaging>
2.将内置的tomcat的scope配置为provided
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-tomcatartifactId>
<scope>providedscope>
dependency>
3.定义了一个SpringBootServletInitializer的子类
/**
* 要求:
* 1.必须继承SpringBootServletInitializer
* 2.重写configure()方法
* 3.调用SpringApplicationBuilder的sources()方法,传入主程序类的
*/
public class ServletInitializer extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Springboot05WarApplication.class);
}
}
2.创建web目录的结构
3.配置前缀和后缀
spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp
4.配置Tomcat
要使用SpringBoot需要的Tomcat版本
步骤:
1.创建工程,选择以下模板:web、jdbc、mysql
2.配置数据库连接信息
#指定数据库连接参数
spring.datasource.driver-class-name= com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/springboot?useUnicode=true&characterEncoding=utf-8&useSSL=false
spring.datasource.username=root
spring.datasource.password=root
#指定数据源
spring.datasource.type=org.apache.commons.dbcp.BasicDataSource
3.测试
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
class Springboot06JdbcApplicationTests {
@Autowired
private DataSource dataSource;
@Test
void contextLoads() throws SQLException {
System.out.println("---------------------------");
System.out.println("DataSource的类型: " + dataSource.getClass());
System.out.println("Connection的连接: " + dataSource.getConnection());
}
}
4.配置连接池参数
spring.datasource.initialSize=10
spring.datasource.maxActive=100
spring.datasource.minIdle=5
spring.datasource.maxWait=50000
问题:添加上面的参数不生效,因为SpringBoot默认并不支持这些参数(DataSourceProperties)
解决:自定义数据源配置
/**
* Author: LuYi
* Date: 2019/10/30 16:09
* Description: 描述
*/
@Configuration
public class DatasourceConfig {
@Bean
//从配置文件中读取spring.datasource属性,并注入给数据源的属性
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource(){
return new BasicDataSource();
}
}
5.使用JdbcTemplate操作数据库
/**
* Author: LuYi
* Date: 2019/10/30 16:17
* Description: 描述
*/
@Controller
@RequestMapping("/user")
public class UserController {
@Autowired
private JdbcTemplate jdbcTemplate;
@RequestMapping("/findAll")
@ResponseBody
public List<Map<String, Object>> findAll(){
String sql = "select * from t_user";
List<Map<String, Object>> list = jdbcTemplate.queryForList(sql);
return list;
}
}
1.创建工程,先择以下模块:web、mybatis
2.配置数据源
#配置DataSource
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/springboot?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: root
initialSize: 5
maxActive: 100
minIdle: 3
maxWait: 50000
#配置MyBatis
mybatis:
type-aliases-package: com.luyi.pojo
mapper-locations: classpath:mapper/*.xml
3.编写Mapper、Service、Controller
4.配置MyBatisConfig配置类
/**
* Author: LuYi
* Date: 2019/10/30 16:57
* Description: 描述
*/
@Configuration
//扫描MyBatis接口所在的包
@MapperScan("com.luyi.mapper")
public class MyBatisConfig {
@Bean
//加载主配置文件,注入配置信息
@ConfigurationProperties(prefix = "spring.datasource")
public DruidDataSource druidDataSource(){
return new DruidDataSource();
}
}
步骤:
1.添加PageHelper依赖
<dependency>
<groupId>com.github.pagehelpergroupId>
<artifactId>pagehelper-spring-boot-starterartifactId>
<version>1.2.10version>
dependency>
2.配置PageHelper的属性
#配置PageHelper
pagehelper:
helper-dialect: mysql
3.使用PageHelper
@Override
public PageInfo<User> findByPage(int pageNum, int pageSize) {
//使用PageHelper设置分页
PageHelper.startPage(pageNum, pageSize);
List<User> users = userMapper.selectAll();
PageInfo<User> pageInfo = new PageInfo<>(users);
return pageInfo;
}
参考:http://mp.baomidou.com/
步骤:
1.添加MyBatis Plus的依赖
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-boot-starterartifactId>
<version>3.1.0version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
<version>1.1.20version>
dependency>
2.配置全局配置文件
#配置DataSource
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/springboot?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: root
initialSize: 5
maxActive: 100
minIdle: 3
maxWait: 50000
#配置MyBatis Plus
mybatis-plus:
mapper-locations: classpath:mapper/*Mapper.xml
type-aliases-package: com.luyi.pojo
global-config:
db-config:
#主键类型
id-type: auto
#字段策略
field-strategy: not_empty
#驼峰下划线转换
table-underline: true
#全局表前缀
table-prefix: t_
#刷新mapper神器
refresh-mapper: true
3 配置MyBatis Plus
/**
* Author: LuYi
* Date: 2019/10/31 9:59
* Description: 描述
*/
@Configuration
@MapperScan("com.luyi.mapper")
public class MyBatisPlusConfig {
/**
* 分页插件,自动识别数据库类型
* @return
*/
@Bean
public PaginationInterceptor paginationInterceptor(){
return new PaginationInterceptor();
}
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource(){
return new DruidDataSource();
}
}
4.编写Mapper,继承BaseMapper
/**
* Author: LuYi
* Date: 2019/10/31 10:07
* Description: 继承BaseMapper接口
*/
public interface UserMapper extends BaseMapper<User> {
}
5.测试
@RunWith(SpringRunner.class)
@SpringBootTest
class Springboot08MpApplicationTests {
@Autowired
private UserMapper userMapper;
@Test
void contextLoads() {
}
@Test
public void add(){
User user = new User();
user.setUsername("xxx");
user.setPassword("111");
userMapper.insert(user);
System.out.println("-------------" + user);
}
@Test
public void removeById(){
int i = userMapper.deleteById(3);
System.out.println(i);
}
@Test
public void modifyById(){
User user = new User();
user.setId(6);
user.setUsername("zhangsan");
user.setPassword("123");
userMapper.updateById(user);
}
@Test
public void findById(){
User user = userMapper.selectById(1);
System.out.println(user);
}
@Test
public void findByCondition(){
//定义条件构造器,用来封装查询条件
QueryWrapper<User> wrapper = new QueryWrapper<>();
// wrapper.eq("username", "tom");
wrapper.like("username", "%a%");
List<User> users = userMapper.selectList(wrapper);
for (User user : users) {
System.out.println(user);
}
}
@Test
public void findByPage(){
Page<User> page = new Page<>(2, 2);
QueryWrapper<User> wrapper = new QueryWrapper<>();
IPage<User> userIPage = userMapper.selectPage(page, wrapper.select("id", "username", "password"));
assertThat(page).isSameAs(userIPage);
System.out.println("总条数---->" + userIPage.getTotal());
System.out.println("当前页数---->" + userIPage.getCurrent());
System.out.println("当前每页显示数---->" + userIPage.getSize());
System.out.println(userIPage.getRecords());
System.out.println("----------自带分页----------");
}
}
补充:lombok的使用
步骤:
1.添加依赖
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>1.18.8version>
<scope>providedscope>
dependency>
2.使用lombok提供的注解
/**
* Author: LuYi
* Date: 2019/10/30 16:32
* Description: Lombok的使用
* Lombok提供了许多注解,标注在类上或者属性上
*/
@Getter
@Setter
@ToString
@Data //相当于以上注解
@TableName(value = "t_user") //指定当前数据库表的名称
public class User implements Serializable {
private Integer id;
private String username;
private String password;
}
3.在Idea中安装lombok插件
由于源代码中没有getter/setter等的定义,Idea无法识别,可以安装lombok插件解决
Redis是一个内存数据库,可以作为缓存、消息中间件、key-value数据库等来使用
步骤:
1.添加依赖
注意:在SpringBoot1.0中使用的Redis客户端时Jedis,在SpringBoot2.0中使用的时Lettuce
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-redisartifactId>
<exclusions>
<exclusion>
<groupId>io.lettucegroupId>
<artifactId>lettuce-coreartifactId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>redis.clientsgroupId>
<artifactId>jedisartifactId>
dependency>
2.配置redis
#redis配置
spring.redis.host=192.168.52.128
spring.redis.port=6379
spring.redis.database=0
spring.redis.jedis.pool.max-active=100
spring.redis.jedis.pool.max-idle=10
spring.redis.jedis.pool.min-idle=3
3.基本用法
使用SpringDataRedis提供的工具类:StringRedisTemplate、RedisTemplate
封装JsonUtils
/**
* Author: LuYi
* Date: 2019/10/31 17:37
* Description: Json工具类,基于jackson
*/
public class JsonUtils {
//获取jackson对象
private static ObjectMapper objectMapper = new ObjectMapper();
/**
* 将对象转换为Json字符串
*/
public static String objectToJson(Object obj){
try {
//将对象转换为Json字符串
String jsonStr = objectMapper.writeValueAsString(obj);
return jsonStr;
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
/**
* 将Json字符串转换为对象
*/
public static <T> T jsonToObject(String jsonStr, Class<T> clazz){
try {
T t = objectMapper.readValue(jsonStr, clazz);
return t;
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
}
测试
@RunWith(SpringRunner.class)
@SpringBootTest
public class Springboot09RedisApplicationTests {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Autowired
private RedisTemplate<String, String> redisTemplate;
@Test
public void contextLoads() {
}
/**
* 使用StringRedisTemplate
* Redis数据类型:String、List、Set、ZSet、Hash
*/
@Test
public void test1(){
/**
* 操作redis
*/
// ValueOperations value = stringRedisTemplate.opsForValue();
// ListOperations list = stringRedisTemplate.opsForList();
// SetOperations set = stringRedisTemplate.opsForSet();
// ZSetOperations zset = stringRedisTemplate.opsForZSet();
// HashOperations hash = stringRedisTemplate.opsForHash();
/**
* 操作String
*/
// stringRedisTemplate.opsForValue().set("username", "admin");
// System.out.println(stringRedisTemplate.opsForValue().get("username"));
/**
* 操作List
*/
// stringRedisTemplate.opsForList().leftPush("name", "tom");
// stringRedisTemplate.opsForList().leftPushAll("name", "aaa", "bbb", "ccc");
// System.out.println(stringRedisTemplate.opsForList().range("name", 0, -1));
/**
* 存储对象
*/
User user = new User();
user.setId(1001);
user.setUsername("tom");
user.setPassword("123");
//将对象转换为json格式
String jsonStr = JsonUtils.objectToJson(user);
System.out.println(jsonStr);
stringRedisTemplate.opsForValue().set("user", jsonStr);
//获取jsonStr
String str = stringRedisTemplate.opsForValue().get("user");
//将str转换为对象
User u = JsonUtils.jsonToObject(str, User.class);
System.out.println(u);
}
/**
* 使用redisTemplate
*/
@Test
public void test2(){
redisTemplate.opsForValue().set("sex", "male");
String sex = redisTemplate.opsForValue().get("sex");
System.out.println(sex);
}
}