创建maven工程
在pom中引入依赖
org.springframework.boot
spring-boot-starter-web
创建主程序
/**
* 主程序类
* @SpringBootApplication:这是一个SpringBoot应用
*/
@SpringBootApplication
public class MainApplication {
public static void main(String[] args) {
SpringApplication.run(MainApplication.class,args);
}
}
编写业务Controller
@RestController
public class HelloController {
@RequestMapping("/hello")
public String handle01(){
return "Hello, Spring Boot 2!";
}
}
配置application.properties
server.port=8888
测试运行main方法
也可以把项目打成jar包,直接在目标服务器执行
org.springframework.boot
spring-boot-maven-plugin
maven工具栏的clean和package
结果
依赖管理
spring-boot-starter-parent的父项目spring-boot-dependencies
几乎声明了所有开发中常用的依赖的版本号,自动版本仲裁机制
开发导入starter场景启动器
1、见到很多 spring-boot-starter-* : *就某种场景
2、只要引入starter,这个场景的所有常规需要的依赖我们都自动引入
3、SpringBoot所有支持的场景
https://docs.spring.io/spring-boot/docs/current/reference/html/using-spring-boot.html#using-boot-starter
4、见到的 *-spring-boot-starter: 第三方为我们提供的简化开发的场景启动器。
5、所有场景启动器最底层的依赖
org.springframework.boot
spring-boot-starter
2.3.4.RELEASE
compile
无需关注版本号,自动版本仲裁
1、引入依赖默认都可以不写版本
2、引入非版本仲裁的jar,要写版本号。
可以修改默认版本号
1、查看spring-boot-dependencies里面规定当前依赖的版本 用的 key。
2、在当前项目里面重写配置
5.1.43
自动配置
自动配好Web常见功能,如:字符编码问题
默认的包结构
主程序所在包及其下面的所有子包里面的组件都会被默认扫描进来
无需以前的包扫描配置
想要改变扫描路径,
@SpringBootApplication(scanBasePackages=“com.atguigu”)
或者@ComponentScan 指定扫描路径
各种配置拥有默认值
默认配置(写在.properties里的)最终都是映射到某个类上,如:MultipartProperties
配置文件的值最终会绑定每个类上,这个类会在容器中创建对象
按需加载所有自动配置项
如何给容器中添加组件,比如Pet类和User类
在spring中,写beans.xml
@Configuration
可以使用一个配置类代替beans.xml,加上@Configuration注解
/**
* 1.配置类里面使用@Bean标注在方法上给容器注册组件,默认也是单实例的
* 2.这个配置类本身也是一个组件
* 3.proxyBeanMethods:代理bean的方法
* Full(proxyBeanMethods = true) 每次外接调用都会检查容器中有没有,比如下面这种依赖的情况需要用到
* Lite(proxyBeanMethods = false) 速度更快,如果不依赖组件推荐这个
* 组件依赖
*/
@Configuration(proxyBeanMethods = false) //告诉SpringBoot这是一个配置类 == 配置文件
public class MyConfig {
/**
* 外部无论对配置类中的这个组件注册方法调用多少次获取的都是之前注册容器中的单实例对象
* @return
*/
@Bean //给容器添加组件,方法名作为组件的id,返回类型就是组件类型。返回的值就是组件在容器中的实例
public User user01(){
User zhangsan = new User("zhangsan", 18);
//User组件依赖了Pet组件
zhangsan.setPet(tomcatPet());
return zhangsan;
}
@Bean("tom") //不想让组件名就是方法名,可以在这个注解里面指定名字
public Pet tomcatPet(){
return new Pet("tomcat");
}
}
改成true后,调用的才是同一个
除了Configuration,以前还使用@Component,@Controller,@Service,@Repository给容器中添加组件
@Import注解也可以导入组件
@Import({User.class, DBHelper.class})
给容器中自动创建出这两个类型的组件、默认组件的名字就是全类名
//5.获取组件
System.out.println("========================");
String[] type = run.getBeanNamesForType(User.class);
for (String s : type) {
System.out.println(s);
}
DBHelper b = run.getBean(DBHelper.class);
System.out.println(b);
其中user01是前面已经加入容器中的
@Conditional
条件装配:满足Conditional指定的条件,则进行组件注入,有很多派生的子注解,可以放在类和方法上
以@ConditionalOnBean为例
@ConditionalOnBean(name = "tom")
@Bean //给容器添加组件,方法名作为组件的id,返回类型就是组件类型。返回的值就是组件在容器中的实例
public User user01(){
User zhangsan = new User("zhangsan", 18);
//User组件依赖了Pet组件
zhangsan.setPet(tomcatPet());
return zhangsan;
}
// @Bean("tom") //不想让组件名就是方法名,可以在这个注解里面指定名字
public Pet tomcatPet(){
return new Pet("tomcat");
}
由于里面没有tom组件,那么user01组件也不会注入,如果有tom组件,它的代码也要放在前面才行。如果该注解放在类上就是一荣俱荣一损俱损。
@ImportResource
以前很多都是用的bean.xml方式,如何让老办法也能生效呢
@ImportResoure("classpath:beans.xml") //导入Spring的配置文件
如何让application.properties和javabean绑定
如果用java原生代码做很麻烦
public class getProperties {
public static void main(String[] args) throws FileNotFoundException, IOException {
Properties pps = new Properties();
pps.load(new FileInputStream("a.properties"));
Enumeration enum1 = pps.propertyNames();//得到配置文件的名字
while(enum1.hasMoreElements()) {
String strKey = (String) enum1.nextElement();
String strValue = pps.getProperty(strKey);
System.out.println(strKey + "=" + strValue);
//封装到JavaBean。
}
}
}
使用@ConfigurationProperties注解
//application.properties文件中
mycar.brand=BYD
mycar.price=100000
//为什么要加@Component注解?因为只有在容器中的组件,才会拥有SpringBoot提供的强大功能
@Component
@ConfigurationProperties(prefix = "mycar")
public class Car {
private String brand;
private Integer price;
...
}
除了@Component注解,还有一种方式,在配置类上面加注解代替之,可以防止想要注册的类是默认不可修改的类
@EnableConfigurationProperties(Car.class)
//1.开启Car配置绑定功能
//2.把Car这个组件自动注册到容器中
public class MyConfig {
...
以上有可能都是boot底层经常用到的注解,暂时放一下
实践
引入场景依赖
查看自动配置了哪些(选做)
是否需要修改
Lombok
包含在spring-boot-dependencies-2.4.1.pom里面。可以简化javaBean的编写,不用写构造函数,gettersetter和toString方法,都用注解代替
还有一个@Slf4j注解用于controller层的日志输出
dev-tools
org.springframework.boot
spring-boot-devtools
true
再按Ctrl+F9可以实现Restart,热重启
Spring Initailizr(项目初始化向导)
语法
k: v
行内写法: k: {k1:v1,k2:v2,k3:v3}
#或
k:
k1: v1
k2: v2
k3: v3
行内写法: k: [v1,v2,v3]
#或者
k:
- v1
- v2
- v3
注意:
key: value;kv之间有空格
大小写敏感
使用缩进表示层级关系
缩进不允许使用tab,只允许空格
缩进的空格数不重要,只要相同层级的元素左对齐即可
'#'表示注释
字符串无需加引号,如果要加,’'与""表示字符串内容 会被 转义/不转义
练习
给定Person类
@Component
@ConfigurationProperties(prefix = "person")
@Data
@ToString
public class Person {
private String userName;
private Boolean boss;
private Date birth;
private Integer age;
private Pet pet;
private String[] interests;
private List animal;
private Map score;
private Set salarys;
private Map> allPets;
}
对应绑定的yml文件内容
person:
userName: zhangsan
boss: false
birth: 2019/12/12 20:12:33
age: 18
pet:
name: tomcat
weight: 23.4
interests: [篮球,游泳]
animal:
- jerry
- mario
score:
english:
first: 30
second: 40
third: 50
math: [131,140,148]
chinese: {first: 128,second: 136}
salarys: [3999,4999.98,5999.99]
allPets:
sick:
- {name: tom}
- {name: jerry,weight: 47}
health: [{name: mario,weight: 47}]
yml配置提示
在官方文档里找到Metadata Format,里面有pom配置代码
org.springframework.boot
spring-boot-configuration-processor
true
再在里面写不用打包到war包的代码,貌似2.4以后默认不用写了,都不会打包
静态资源访问
静态资源目录
只要静态资源放在类路径下: called /static
(or /public
or /resources
or /META-INF/resources
访问 : 当前项目根路径/ + 静态资源名
原理: 静态映射/**。
请求进来,先去找Controller看能不能处理。不能处理的所有请求又都交给静态资源处理器。静态资源也找不到则响应404页面
改变默认的静态资源路径
spring:
resources:
# 把静态资源放在haha文件夹下
static-locations: [classpath:/haha/]
静态资源访问前缀
默认无前缀不方便后期拦截器的使用,比如要拦截没有登录的/**的请求,前面加/res的可以放行
spring:
mvc:
# 浏览器地址前面要加上res才能访问静态资源
static-path-pattern: /res/**
当前项目 + static-path-pattern + 静态资源名 = 静态资源文件夹下找
webjar
自动映射 /webjars/**
https://www.webjars.org/
org.webjars
jquery
3.5.1
访问地址:http://localhost:8080/webjars/jquery/3.5.1/jquery.js 后面地址要按照依赖里面的包路径
欢迎页
静态资源路径下 index.html
自定义Favicon(页面图标)
controller能处理/index
Rest映射及原理分析
使用
@xxxMapping;
Rest风格支持(使用HTTP请求方式动词来表示对资源的操作)
用法: 表单method=post,隐藏域 _method=put
SpringBoot中手动开启
spring:
mvc:
hiddenmethod:
filter:
enabled: true #开启页面表单的Rest功能
@RequestMapping(value = "/user",method = RequestMethod.GET)
public String getUser(){
return "GET-张三";
}
@RequestMapping(value = "/user",method = RequestMethod.POST)
public String saveUser(){
return "POST-张三";
}
@RequestMapping(value = "/user",method = RequestMethod.PUT)
public String putUser(){
return "PUT-张三";
}
@RequestMapping(value = "/user",method = RequestMethod.DELETE)
public String deleteUser(){
return "DELETE-张三";
}
//源码
@Bean
@ConditionalOnMissingBean(HiddenHttpMethodFilter.class)
@ConditionalOnProperty(prefix = "spring.mvc.hiddenmethod.filter", name = "enabled", matchIfMissing = false) //要手动开成true
public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {
return new OrderedHiddenHttpMethodFilter();
}
//自定义filter
@Bean
public HiddenHttpMethodFilter hiddenHttpMethodFilter(){
HiddenHttpMethodFilter methodFilter = new HiddenHttpMethodFilter();
methodFilter.setMethodParam("_m");
return methodFilter;
}
普通参数与基本注解
注解
@RestController
public class HelloController {
@GetMapping("/car/{id}/owner/{username}")
public Map getCar(@PathVariable("id") Integer id,
@PathVariable("username") String name,
@PathVariable Map pv,
@RequestHeader("User-Agent") String userAgent,
@RequestHeader Map header,
@RequestParam("age") Integer age,
@RequestParam("inters") List inters,
@RequestParam Map params,
@CookieValue("Idea-ce2cbf95") String co,
@CookieValue("Idea-ce2cbf95") Cookie cookie){
Map map = new HashMap<>();
map.put("id",id);
map.put("name",name);
map.put("pv",pv);
// map.put("userAgent",userAgent);
// map.put("header",header); 这两个太多了
map.put("age",age);
map.put("inters",inters);
map.put("params",params);
map.put("Idea-ce2cbf95",co);
System.out.println(cookie.getName()+":"+cookie.getValue());
return map;
}
@PostMapping("/save")
public Map postMethods(@RequestBody String content){ //这个必须是Post才有body
Map map = new HashMap<>();
map.put("content",content);
return map;
}
}
car/{id}/owner/{username}
再演示@RequestAttribute
@Controller
public class RequestController {
@GetMapping("/goto")
public String goToPage(HttpServletRequest request){
request.setAttribute("msg","成功了");
request.setAttribute("code",200);
return "forward:/success";
}
@ResponseBody
@GetMapping("/success")
//两种方法接收
public Map success(@RequestAttribute("msg") String msg,
HttpServletRequest request){
Object msg1 = request.getAttribute("msg");
Map map = new HashMap<>();
map.put("reqMethod_msg",msg1);
map.put("annotation_msg",msg);
return map;
}
}
还有一个矩阵变量注解,先放一放
模板引擎 Thymeleaf
语法
使用
引入Starter
org.springframework.boot
spring-boot-starter-thymeleaf
自动配置好了thymeleaf
页面开发
@Controller
public class ViewTestController {
@GetMapping("/atguigu")
public String atguigu(Model model){
model.addAttribute("msg","你好 atguigu");
model.addAttribute("link","www.baidu.com");
return "success";
}
}
自动跳转到->>
Title
//会后端传来的值会覆盖掉“哈哈”
哈哈
去百度
去百度2
配置了的话,模板引擎会自动加上项目的访问路径
server:
servlet:
context-path: /world
构建后台管理系统
项目创建,
这里可以直接使用脚手架,勾选thymeleaf,web-starter,devtools,lombok
静态资源处理
把css,js,fonts,images等所有静态文件放到static文件夹
编写登录跳转到主页面代码
@Controller
public class IndexController {
/**
* 去登录页
* @return
*/
@GetMapping(value={"/","/login"})
public String loginPage(){
return "login";
}
@PostMapping("/login")
//User已经写好了bean类,包含userName和password
public String main(User user, HttpSession session, Model model){
if(StringUtils.hasLength(user.getUserName())&&"123456".equals(user.getPassword())){
//把登录成功的用户保存起来
session.setAttribute("loginUser",user);
//登录成功重定向到main.html; 重定向防止表单重复提交
return "redirect:/main.html";
}else {
model.addAttribute("msg","账号或者密码错误");
//回到登录页面
return "login";
}
}
/**
* 去main页面
* @param session
* @param model
* @return
*/
@GetMapping("/main.html") //这里不会跳到主页面,因为模板引擎跳转页面必须return才可以
public String mainPage(HttpSession session, Model model){
//判断是否登录, 可以用拦截器,过滤器,下面只是简单处理一下
Object loginUser = session.getAttribute("loginUser");
if(loginUser != null){
//跳转到主页面
return "main";
}else {
model.addAttribute("msg","请登录");
return "login";
}
}
}
login.html登录部分代码