javase :OOP
mysql : 持久化
html+css+js+jquery+框架 :视图,框架不熟练,css不好
javaweb:独立开发MVC三层架构的网站:原始
ssm:框架:简化了我们的开发流程,配置也开始较为复杂
war包:Tomcat运行
微服务阶段:
spring再简化:SpringBoot ,jar‘包:内嵌tomcat; 微服务架构
服务越来越多:springcloud
Spring是一个开源框架,Spirng是为了解决企业级应用开发的复杂性而创建的,简化开发。
为了降低Java开发的复杂性,Spring采用了以下4种关键策略:
SpringBoot ,就是一个javaweb的开发框架,简化开发,约定大于配置,能迅速的开发web应用。
随着Spring不断的发展,涉及的领域越来越多,项目整合开发需要配合各种各样的文件,慢慢变得不那么易用简单,人称配置地域。Spring Boot 正是在这样的一个背景下被抽象出来的开发框架,目的为了让大家更容易的使用Spring、更容易集成各种常用的中间件、开源软件;
Spring Boot 基于Spring开发,SpringBoot 本身并不提供Spring框架的核心特性以及扩展功能,只是用于快速、敏捷的开发新一代基于Spring框架的应用程序,也就是说,它并不是用来替代Spring的解决方案,而是和Spring框架紧密结合用于提升Spring开发体验的工具。
Spring Boot的主要优点:
是指,我们将一个应用中的所有应用服务都封装在一个应用中
所谓微服务架构,就是打破之前all in one的架构方式,把每个功能元素独立出来,把独立出来的功能元素动态组合,需要的功能元素才去拿来组合,需要多一些时可以整合多个功能元素。所以微服务架构是对功能元素进行复制,而没有对整个应用进行复制。
这样做的好处是:
这种庞大的系统架构给部署和运维带来很大的难度,于是Spring为我们带来了构建大型分布式微服务的全套、全程产品:
package com.example.springboot01;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
//本身就是spring的一个组件
//程序的主入口
@SpringBootApplication
public class Springboot01Application {
public static void main(String[] args) {
SpringApplication.run(Springboot01Application.class, args);
}
}
是springboot的核心配置文件
package com.example.springboot01;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
//单元测试
@SpringBootTest
class Springboot01ApplicationTests {
@Test
void contextLoads() {
}
}
<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.0modelVersion>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.7.2version>
<relativePath/>
parent>
<groupId>com.examplegroupId>
<artifactId>springboot-01artifactId>
<version>0.0.1-SNAPSHOTversion>
<name>springboot-01name>
<description>springboot-01description>
<properties>
<java.version>1.8java.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
project>
parent:继承spring-boot-starter-parent的依赖管理,控制版本与打包等内容
dependencies:项目具体依赖 spring-boot-starter-web 用于实现HTTP接口,该依赖中包含了springMVC,即“使用SpringMVC构建WEB应用程序,使用Tomcat作为默认嵌入式容器”
package com.example.springboot01.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
//自动装配
@RestController
public class HelloController {
//接口:http://localhost:8080/hello
@RequestMapping("/hello")
public String hello(){
//调用业务,接收前端的参数!
return "hello,World";
}
}
在配置文件中application.properties
server.port=8081
即可修改当前程序端口号
自动配置
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
@SpringBootApplication:标注这个类是一个springboot的应用:启动类下的所有资源被导入
点进去@SpringBootApplication:
@SpringBootConfiguration:springboot的配置:
@EnableAutoConfiguration:自动导入包
@AutoConfigurationPackage:自动配置包,>@Import({AutoConfigurationPackages.Registrar.class}):导入选择器:自动配置‘包注册’
@Import({AutoConfigurationImportSelector.class}):导入选择器:自动配置选择器
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = new ArrayList(SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader()));
ImportCandidates.load(AutoConfiguration.class, this.getBeanClassLoader()).forEach(configurations::add);
Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories nor in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you are using a custom packaging, make sure that file is correct.");
return configurations;
}
//获取候选的配置
@ComponentScan :扫描当前主启动类同级的包
结论:springboot所有自动配置都是在启动的时候扫描并加载:所有的自动配置类都在spring.factories里面,但是不一定生效,要判断条件是否成立----只有导入了对应的start,有对应的启动器,我们的自动装配才会生效,然后才配置成功。
public static void main(String[] args) {
SpringApplication.run(Springboot01Application.class, args);
}
}
这个类主要做了以下四件事
1)推断应用的类型是普通的项目还是Web项目
2)查找并加载所有可用初始化器,设置到initializers属性中
3)找出所有的应用程序监听器,设置到listeners属性中
4)推断并设置main方法的定义类,找到运行的主类
ps:创建springboot项目时,url报错,解决方案:
Springboot使用一个全局的配置文件,配置文件名称是固定的
application.properties
application.yml
配置文件的作用:修改SpringBoot自动配置的默认值,因为SpringBoot在底层都给我们自动配置好了
以前的配置文件,大多数都是使用xml来配置,比如一个简单的端口配置,对比xml和yaml
xml:
<server>
<port>8081port>
server>
yaml:
server:
port: 8080
基础语法
server:
port: 8081
#对空格的要求很严格
# 对象
student:
name: xqh
age: 3
# 行内写法
person: {name:xqh,age:3}
#数组
pets:
- cat
- dog
- pig
pets1: [cat,dog,pig]
实体类Dog.java
package com.example.pojo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
//成为spring的组件
@Component
public class Dog {
@Value("旺财")
private String name;
@Value("3")
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
测试类
package com.example;
import com.example.pojo.Dog;
import com.example.pojo.Person;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class Springboot02ApplicationTests {
@Autowired
private Dog dog;
@Test
void contextLoads() {
System.out.println(dog);
}
}
//输出结果:Dog{name=‘旺财’, age=3}
实体类Person.java
package com.example.pojo;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.List;
import java.util.Map;
@Component //注册bean
@ConfigurationProperties(prefix = "person")
//@ConfigurationProperties作用:
//将配置文件中的每一个属性的值,映射到这个组件中;告诉springboot将本类中的所有属性和配置文件中相关的配置进行绑定;
//参数prefix=“person” :将配置文件中的person下面的的所有属性一一对应
//只有这个组件是容器中的组件,才能使用@ConfigurationProperties,所以要先@Component,让它成为spring的组件
public class Person {
private String name;
private Integer age;
private Boolean happy;
private Date birth;
private Map<String,Object>maps;
private List<Object>lists;
private Dog dog;
public Person() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Boolean getHappy() {
return happy;
}
public void setHappy(Boolean happy) {
this.happy = happy;
}
public Date getBirth() {
return birth;
}
public void setBirth(Date birth) {
this.birth = birth;
}
public Map<String, Object> getMaps() {
return maps;
}
public void setMaps(Map<String, Object> maps) {
this.maps = maps;
}
public List<Object> getLists() {
return lists;
}
public void setLists(List<Object> lists) {
this.lists = lists;
}
public Dog getDog() {
return dog;
}
public void setDog(Dog dog) {
this.dog = dog;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", happy=" + happy +
", birth=" + birth +
", maps=" + maps +
", lists=" + lists +
", dog=" + dog +
'}';
}
}
配置文件 application.yml
person:
name: qinjiang
age: 3
happy: false
birth: 2019/11/2
maps: {k1: v1,k2: v2}
lists:
- code
- music
- girl
dog:
name: 旺财
age: 3
测试:
package com.example;
import com.example.pojo.Dog;
import com.example.pojo.Person;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class Springboot02ApplicationTests {
@Autowired
private Person person;
@Test
void contextLoads() {
System.out.println(person);
}
}
//结果:Person{name=‘qinjiang’, age=3, happy=false, birth=Sat Nov 02 00:00:00 CST 2019, maps={k1=v1, k2=v2}, lists=[code, music, girl], dog=Dog{name=‘旺财’, age=3}}
实体类Person.java
package com.example.pojo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.List;
import java.util.Map;
@Component //注册bean
//加载指定的配置文件
@PropertySource(value = "classpath:person.properties")
public class Person {
@Value("${name}")
private String name;
private Integer age;
private Boolean happy;
private Date birth;
private Map<String,Object>maps;
private List<Object>lists;
private Dog dog;
public Person() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Boolean getHappy() {
return happy;
}
public void setHappy(Boolean happy) {
this.happy = happy;
}
public Date getBirth() {
return birth;
}
public void setBirth(Date birth) {
this.birth = birth;
}
public Map<String, Object> getMaps() {
return maps;
}
public void setMaps(Map<String, Object> maps) {
this.maps = maps;
}
public List<Object> getLists() {
return lists;
}
public void setLists(List<Object> lists) {
this.lists = lists;
}
public Dog getDog() {
return dog;
}
public void setDog(Dog dog) {
this.dog = dog;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", happy=" + happy +
", birth=" + birth +
", maps=" + maps +
", lists=" + lists +
", dog=" + dog +
'}';
}
}
配置文件.properties
name=xqh
测试
package com.example;
import com.example.pojo.Dog;
import com.example.pojo.Person;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class Springboot02ApplicationTests {
@Autowired
private Person person;
@Test
void contextLoads() {
System.out.println(person);
}
}
松散绑定:即便是实体类中属性名为firstName,而配置文件中写的first-name,一样可以进行绑定
前者支持JSR303数据校验,后者不支持
前者支持复杂类型封装,后者不支持。如yaml中可以封装对象,而@value就不行
JSR303数据校验:我们可以在字段增加一层过滤器验证,可以保证数据的合法性
@Validated //数据校验
public class Person {
@Email(message="邮箱格式错误") //这样后,如果配置文件中对应的属性赋值不是email的话,就会报错
private String name;
常用校验注解:
1、空检查
Constraint | 详细信息 |
---|---|
@Null | 验证对象是否为null |
@NotNull | 验证对象是否不为null,无法检查长度为0的字符串 |
@NotBlank | 检查约束字符串是不是NULL还有被Trim的长度是否大于0,只对字符串,且会去掉前后空格。 |
@NotEmpty | 检查约束元素是否为NULL或者EMPTY. |
2、Boolean检查
Constraint | 详细信息 |
---|---|
@AssertTrue | 验证 Boolean 对象是否为 true |
@AssertFalse | 验证 Boolean 对象是否为 false |
3、长度检查
Constraint | 详细信息 |
---|---|
@Size(min=,max=) | 验证对象(Array,Collection,Map,String) 长度是否在给定方位之内 |
@Length(min=,max=) | Validates that the annotated string is between min and max included. |
4、日期检查
Constraint | 详细信息 |
---|---|
@Past | 验证 Date 和 Calendar 对象是否在当前时间之前 |
@Future | 验证 Date 和 Calendar 对象是否在当前时间之后 |
@Pattern | 验证 String 对象是否符号正则表达式的规则 : 正则表达式 |
项目下config文件夹内的配置文件 > 项目下的配置文件 > resource文件夹下的config文件夹内的配置文件 >resource文件夹下的配置文件
第一种方法分开文件写
真实开发环境中,比如有application.yml , application-dev.yml , application-test.yml三个不同环境下的配置文件
application.yml
spring.profiles.active: dev
即可切换到使用application-dev.yml配置文件
第二种方法,在一个文件中写(因为yaml可以模块化配置)
application.yml
server:
port: 8080
spring:
profiles:
active: dev
---
server:
port: 8082
spring:
profiles: dev
---
server:
port: 8081
spring:
profiles: test
用—分隔开不同环境下
配置文件到底能写什么-----联系------spring.factories(在spring-boot-autoconfigure\2.3.7.RELEASE\spring-boot-autoconfigure-2.3.7.RELEASE.jar!\META-INF\spring.factories)
//表示这是一个配置类
@Configuration(
proxyBeanMethods = false
)
//自动装配属性:ServerProperties
@EnableConfigurationProperties({ServerProperties.class})
//spring的底层注解:根据不同的条件,来判断当前配置或者类是否生效
@ConditionalOnWebApplication(
type = Type.SERVLET
)//是不是这个类型
@ConditionalOnClass({CharacterEncodingFilter.class}) //是否存在这个字符编码过滤器
@ConditionalOnProperty(
prefix = "server.servlet.encoding",
value = {"enabled"},
matchIfMissing = true
)//是否存在这些配置
@ConfigurationProperties(
//配置前缀是server
prefix = "server",
ignoreUnknownFields = true
)
public class ServerProperties {
//这些属性就是配置文件中能配置的属性
private Integer port;
private InetAddress address;
@NestedConfigurationProperty
private final ErrorProperties error = new ErrorProperties();
private ForwardHeadersStrategy forwardHeadersStrategy;
private String serverHeader;
private DataSize maxHttpHeaderSize = DataSize.ofKilobytes(8L);
private Shutdown shutdown;
@NestedConfigurationProperty
private Ssl ssl;
@NestedConfigurationProperty
private final Compression compression;
@NestedConfigurationProperty
private final Http2 http2;
private final Servlet servlet;
private final Tomcat tomcat;
private final Jetty jetty;
private final Netty netty;
private final Undertow undertow;
...
server:
port:
server-header:
address:
forward-headers-strategy:
...
作用:判断是否满足当前指定条件,后缀不同对应着不同条件
在我们这配置文件中能配置的东西,都存在一个固有规律,对应着 xxxAutoConfiguration中的xxxProperties中的属性,配置文件绑定。
自动装配原理再总结
xxxAutoConfiguration:自动配置类;给容器中添加组件
xxxProperties:封装配置文件中相关属性
debug: true
jar:webapp
自动装配
要解决的问题:
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
} else {
Duration cachePeriod = this.resourceProperties.getCache().getPeriod();
CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();
if (!registry.hasMappingForPattern("/webjars/**")) {
this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{"/webjars/**"}).addResourceLocations(new String[]{"classpath:/META-INF/resources/webjars/"}).setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl));
}
String staticPathPattern = this.mvcProperties.getStaticPathPattern();
if (!registry.hasMappingForPattern(staticPathPattern)) {
this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{staticPathPattern}).addResourceLocations(WebMvcAutoConfiguration.getResourceLocations(this.resourceProperties.getStaticLocations())).setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl));
}
}
}
在resources下建文件夹public、static、resource,springboot会自动扫描这些文件内的静态资源,且优先级是:
resources>static>public
logger.debug(“Default resource handling disabled”);意思是如果自己在配置文件中配置了静态资源路径,那么前面的默认的配置就不生效
在springboot,我们可以使用一下方式处理静态资源
优先级:
resources>static(默认)>public
@Bean
public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext, FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) {
WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping(new TemplateAvailabilityProviders(applicationContext), applicationContext, this.getWelcomePage(), this.mvcProperties.getStaticPathPattern());
welcomePageHandlerMapping.setInterceptors(this.getInterceptors(mvcConversionService, mvcResourceUrlProvider));
welcomePageHandlerMapping.setCorsConfigurations(this.getCorsConfigurations());
return welcomePageHandlerMapping;
}
private Optional<Resource> getWelcomePage() {
String[] locations = WebMvcAutoConfiguration.getResourceLocations(this.resourceProperties.getStaticLocations());
return Arrays.stream(locations).map(this::getIndexHtml).filter(this::isReadable).findFirst();
}
private Resource getIndexHtml(String location) {
return this.resourceLoader.getResource(location + "index.html");
}
springboot会自动识别resource下的index.html,并把它设置为首页
springboot这个项目以jar的方式,默认是不支持jsp的,不支持jsp,如果我们直接用静态页面的方式,那给我们开发会带来非常大的麻烦,所以SpringBoot推荐使用模板引擎
jsp其实就是一个模板引擎,还有用的比较多的freemarker,包括springboot给我们推荐的Thymeleaf
导入依赖
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-thymeleafartifactId>
<version>2.2.1.RELEASEversion>
dependency>
package com.example.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
//在templates目录下的所有页面,只能通过controller来跳转
@Controller
public class IndexController {
@RequestMapping("/test")
public String test(){
return "test";
}
}
test.html在templates下
doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Documenttitle>
head>
<body>
<h1>testh1>
body>
html>
测试,可以跳转到test页面
加入标签 xmlns:th="http://www.w3.org/1999/xhtml“
doctype html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Documenttitle>
head>
<body>
<div th:text="${msg}">div>
body>
html>
取文本内容
package com.example.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
//在templates目录下的所有页面,只能通过controller来跳转
@Controller
public class IndexController {
@RequestMapping("/test")
public String test(Model model){
model.addAttribute("msg","hello,springboot");
return "test";
}
}
这样就可以取到了!
常用标签
标签 | 作用 | 示例 |
---|---|---|
th:text |
替换文本 | th:text="${title}" |
th:value |
替换值 | th:value="${user.name}" |
th:each |
迭代 | th:each="stu:${user}" |
th:href |
替换链接 | th:href="@{/index.html}" |
th:src |
替换资源 | th:src="@{/img/Wechat.jpg}" |
th:if |
条件判断 | th:if="${isVip}" |
th:switch th:case |
条件判断 | th:switch="${sex}" th:case="'man'" |
th:insert |
插入 | th:insert="footer :: copy" |
th:replace |
替换 | th:replace="footer :: copy" |
th:fragment |
定义片段 | th:fragment="frag (onevar,twovar)" |
<body>
<div th:text="${msg}">div>
<div th:utext="${msg}">div>
body>
后端输入数据
model.addAttribute("users", Arrays.asList("java","python"));
页面中获取数据
<h3 th:each="user:${users}" >[[${user}]]h3>
推荐使用第一种
package com.example.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.Locale;
//如果你想diy一些定制化的功能,只要写这个组件,然后将它交给springboot,springboot就会帮我们自动装配
//写组件(@Configuration),自定义(继承这个功能的接口类)---->注入到springboot(@Bean) ---->springboot会帮我们自动装配
//扩展mvc
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
// public interface ViewResolver 实现了视图解析器接口的类,我们就可以把它看做视图解析器(现在默认是springboot自动装配的)
@Bean
public ViewResolver myViewResolver(){
return new MyViewResolver();
}
//自定义一个自己的视图解析器MyViewResolver
public static class MyViewResolver implements ViewResolver{
@Override
public View resolveViewName(String s, Locale locale) throws Exception {
return null;
}
}
}
package com.example.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
//如果我们要扩展springmvc,官方建议我们这样去做,@Configuration成为组件,然后继承类,然后重写方法
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
//视图跳转
//实现重命名,从/view也可以跳转到test
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/view").setViewName("test");
}
}