1 WEB开发-静态资源访问
1.1 基本介绍
(1)只要静态资源放在类路径的以下目录:/static、/public、/resources、/META-INF/resources 可以被直接访问。maven项目的类路径即为main/resources目录--对应SpringBoot源码为WebProperties.java类
(2)常见静态资源:JS、CSS、图片、字体文件(Fonts)等
(3)访问方式默认为:项目根路径/ + 静态资源名。比如 http://localhost:8080/hi.jpg --对应SpringBoot源码为WebMvcProperties.java类
1.2 快速入门
(1)在resources目录下创建相关静态资源目录,并放入测试图片
(2)创建并启动主程序
package com.springboot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
(3)浏览器输入网址进行测试:
- localhost:8080/1.png
- localhost:8080/2.png
- localhost:8080/3.png
- localhost:8080/4.png
1.3 注意事项
(1)静态资源访问原理:静态映射是/**,也就是对所有请求进行拦截,请求进来,会先看Controller 能不能处理,不能处理的请求就会交给静态资源处理器,如果静态资源也找不到则响应404页面
(2) 改变静态资源访问前缀,比如如果希望 localhost:8080/wwj/1.png 去请求静态资源。应用场景:静态资源访问前缀和控制器请求路径冲突
设置方式如下
- 在类路径,即main/resources目录下,新建文件 application.yml
spring:
mvc:
static-path-pattern: /wwj/**
- 重启应用,完成测试,浏览器输入: localhost:8080/wwj/1.png
(3)改变默认的静态资源路径,比如希望在类路径下增加wwjimg目录作为静态资源路径
- 修改 application.yml 即可
spring:
mvc:
# 修改静态资源访问前缀
static-path-pattern: /wwj/**
web:
resources:
# 添加静态资源路径
static-locations:
- "classpath:/META-INF/resources/"
- "classpath:/resources/"
- "classpath:/static/"
- "classpath:/public/"
- "classpath:/wwjimg/"
2 Rest风格请求处理
2.1 基本介绍
(1)Rest风格支持:使用HTTP请求方式动词来表示对资源的操作
(2)举例说明:
- 请求方式:/monster
- GET-获取怪物
- DELETE-删除怪物
- PUT-修改怪物
- POST-添加怪物
2.2 SpringBoot Rest风格应用实例
需求:演示 SpringBoot 中如何实现Rest风格的增删改查
(1)创建MonsterController.java,模拟四种请求方式
package com.springboot.controller;
import org.springframework.web.bind.annotation.*;
@RestController
public class MonsterController {
//以下写法等价于 @RequestMapping(value = "/monster", method = RequestMethod.GET)
@GetMapping("/monster")
public String getMonster(){
return "GET-查询妖怪";
}
@PostMapping("/monster")
public String addMonster(){
return "POST-添加妖怪";
}
@PutMapping("/monster")
public String putMonster(){
return "PUT-修改妖怪";
}
@DeleteMapping("/monster")
public String deleteMonster(){
return "DELETE-删除妖怪";
}
}
(2)使用postman 工具进行测试,分别用这四种方式请求/monster
2.3 注意事项
(1)客服端是PostMan 可以直接发送Put、Delete等方式请求,可不设置Filter
(2)如果要 SpringBoot 支持表单的 Rest 功能,需要注意如下细节
- Rest风格请求核心Filter是 HiddenHttpMethodFilter,表单请求会被 HiddenHttpMethodFilter 拦截,获取到表单_method的值,再判断是PUT/DELETE/PATCH(PATCH方法是新引入的,是对PUT方法的补充,用来对已知资源进行局部更新)
- 如果要 SpringBoot 支持表单的 Rest 功能,需要在application.yml启动filter功能
spring:
mvc:
# 修改静态资源访问前缀
static-path-pattern: /wwj/**
hiddenmethod:
filter:
# 开启页面表单的 Rest 功能
enabled: true
3 配置视图解析器
3.1 @ResponseBody
思考:为什么上面案例中 return "GET-查询妖怪",返回的是字符串,而不是转发到对应的资源文件?
这是因为我们在类上加了一个 @RestController 注解,这个注解是一个复合注解,含有 @ResponseBody,所以springboot底层(springmvc),在处理 return "xxx" 时,会以 @ResponseBody 注解进行解析处理,即返回字符串"xxx",而不会使用视图解析器来处理。如果把 @RestController 改成 @Controller,当你访问getMonster()时,如果存在 xxx.html 就会转发到 xxx.html,如果不存在就会报404
3.2 在 application.yml 配置视图解析器
(1)在 application.yml 配置视图解析器
spring:
mvc:
# 修改静态资源访问前缀
static-path-pattern: /wwj/**
hiddenmethod:
filter:
# 开启页面表单的 Rest 功能
enabled: true
# 配置视图解析器
view:
# 后缀
suffix: .html
# 前缀
prefix: /wwj/ # 这里需要注意 prefix 需要和当前的 static-path-pattern一致
(2)修改 MonsterController.java
把 @RestController 注解替换为 @Controller 注解
//@RestController
@Controller
public class MonsterController {
在 MonsterController.java 中新增一个方法来测试视图解析器。该方法进行转发的时候,如果没有配置视图解析器,就会看controller 有没有 /hello;如果配置了视图解析器,就按照视图解析器来定位,这时候如果想要在控制器方法之间进行请求转发,可以这样写return "forward:/hello"
@RequestMapping("/go")
public String go() {
return "hello";
}
(3)在resources/public 创建静态页面 hello.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>hello</title>
</head>
<body>
<h1>hello,springboot</h1>
</body>
</html>
(4)启动主程序,在浏览器输入 http://localhost:8080/go 进行测试,测试效果如下
4 接收参数的相关注解
4.1 基本介绍
(1)SpringBoot 接收客户端提交数据/参数会使用到的相关注解
(2)详解 @PathVariable、@RequestHeader、@RequestParam、@CookieValue、@RequestBody。这些注解在springmvc中均有提及。SpringBoot的新注解有@RequestAttribute、@SessionRequest
4.2 应用实例
需求:演示各种方式提交数据/参数给服务器,服务器如何使用注解接收
在 resources/public 目录下创建静态页面 index.html 用来提交数据
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>index</title>
</head>
<body>
<h1>接收参数的相关注解演示</h1>
<hr/>
<a href="/monster/100/king">@PathVariable-路径变量 monster/100/king</a><br><br>
</body>
</html>
在controller 下创建 ParameterController.java 来接收数据
package com.springboot.controller;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ParameterController {
}
4.2.1 @PathVariable
(1)在index.html 中加入超链接
<a href="/monster/100/king">@PathVariable-路径变量 monster/100/king</a><br><br>
路径说明:href="/monster/100/king" 中的 / 在浏览器中进行解析,和被解析成 ip+端口,整体就是http://lcoalhost:8080/monster/100/king。如果不加 /,写成 monster/100/king 就会在前面加上当前页面的路径,即 http://lcoalhost:8080/wwj/monster/100/king。(wwj 是我们前面在application.yml 文件中配置的静态资源访问前缀)
(2)在 ParameterController.java 中增加方法
// 超链接默认请求方式为get
@GetMapping("/monster/{id}/{name}")
public String pathVariable(@PathVariable("id") Integer monsterId,
@PathVariable("name") String monsterName,
@PathVariable Map<String,String> map) {
System.out.println("monsterId=" + monsterId);
System.out.println("monsterName=" + monsterName);
System.out.println("map=" + map);
return "success";
}
解读:
- /monster/{id}/{name} 构成完整请求路径,{id}、{name}就是占位变量
- @PathVariable("name"): 这里的 name 需要和 {name} 命名保持一致
- String monsterName 这个形参名可以自己定义
- @PathVariable Map<String,String> map 会把所有传递的值都传入map,key为占位变量名,即id、name
(3)启动主程序,在浏览器输入 localhost:8080/wwj/index.html 进行测试,效果如下
点击后效果如下
控制台输出:
4.2.2 @RequestHeader
@RequestHeader 可以用来获取请求头的信息,可获取的信息如下
(1)在index.html 中加入超链接
<a href="/requestHeader">@RequestHeader-获取Http请求头</a><br><br>
(2)在 ParameterController.java 中增加方法
@GetMapping("/requestHeader")
public String requestHeader(@RequestHeader("Host") String host,
@RequestHeader Map<String, String> map){
System.out.println("Host =" + host);
System.out.println("以下是http请求头的 所有信息");
for (Map.Entry<String, String> o : map.entrySet()) {
System.out.println(o.getKey() + ": " + o.getValue());
}
return "success";
}
解读
- @RequestHeader("Host") 获取http请求头的 host 信息,即主机ip+端口
- @RequestHeader Map<String, String> map 获取http请求头的 所有信息
(3)启动主程序,在浏览器输入 localhost:8080/wwj/index.html 进行测试,效果如下
点击后控制台输出
4.2.3 @RequestParam
(1)在index.html 中加入超链接
<a href="/hi?name=孙悟空&fruit=apple&fruit=pear">@RequestParam-获取请求参数</a><br><br>
(2)在 ParameterController.java 中增加方法
@GetMapping("/hi")
public String hi(@RequestParam(value = "name", required = false) String userName,
@RequestParam("fruit") List<String> fruits,
@RequestParam Map<String,String> map){
System.out.println("userName = " + userName);
System.out.println("fruits = " + fruits);
System.out.println("map = " + map);
return "success";
}
代码解读:
- @RequestParam(value = "name", required = false) 拿到参数名为 name 的请求参数,
- required = false 表示这个参数不是必须要有的,如果没有传这个参数过来也不会报错,默认为true
- @RequestParam("fruit") 拿到参数名为 fruit 的请求参数,因为该参数名的参数有多个,所以要用集合来接收
- @RequestParam Map<String,String> map 可以获取到所有的请求参数,但需要注意的是,如果有多个同名参数,只会得到第一个
(3)启动主程序,在浏览器输入 localhost:8080/wwj/index.html 进行测试,效果如下
点击后控制台输出
4.2.4 @CookieValue
(1)在index.html 中加入超链接
<a href="/cookie">@CookieValue-获取cookie值</a><br><br>
(2)在 ParameterController.java 中增加方法
@GetMapping("/cookie")
public String cookie(@CookieValue(value = "cookie_key", required = false) String cookie_value,
@CookieValue(value = "username", required = false) Cookie cookie,
HttpServletRequest request){
System.out.println("cookie_value = " + cookie_value);
System.out.println("cookie对象 - cookie名字:" + cookie.getName() + " - cookie值:" + cookie.getValue());
// 这里也可以使用原生的方式的方式获取到cookie
System.out.println("----------------");
Cookie[] cookies = request.getCookies();
for (Cookie c : cookies) {
System.out.println(c.getName() + "=" + c.getValue());
}
return "success";
}
代码解读
- @CookieValue(value = "cookie_key", required = false),表示接收名字为cookie_key的cookie
- 如果浏览器携带来了对应的cookie,要是后面的形参类型为 String,则接收到的是对应的 value 值
- 要是后面的形参类型为 Cookie,则接收到的是封装好的对应的 Cookie 对象
- 也可以使用原生的方式获取到cookie,使用HttpServletRequest 对象的 getCookies()方法
(3)启动主程序,在浏览器输入 localhost:8080/wwj/index.html 进行测试,效果如下
由于浏览器目前没有cookie,如果要测试,可以手动在浏览器设置对应的cookie,步骤如下
在当前页面点击 F12 进入开发者模式
设置好后刷新当前页面,点击最后一条链接进行测试,点击后控制台输出如下
4.2.5 @RequestBody
在 SpringMVC 中 @RequestBody 可以将提交的json字符串数据填充给指定Javabean。在SpringBoot 该注解新增了一个功能,可以整体取出Post请求内容,这里先介绍这个功能。而填充指定Javabean的功能在后面自定义对象参数里面进行了回顾
(1)在index.html 中加入超链接
<h1>测试@RequestBody获取数据: 获取POST请求体</h1>
<form action="/save" method="post">
姓名: <input name="name"/><br/>
年龄: <input name="age"/><br/>
<input type="submit" value="提交">
</form>
(2)在 ParameterController.java 中增加方法
/**
* @RequestBody 是整体取出Post请求内容
*/
@PostMapping("/save")
public String postMethod(@RequestBody String content){
System.out.println("content: " + content);
return "success";
}
(3)启动主程序,在浏览器输入 localhost:8080/wwj/index.html 进行测试,效果如下
点击提交后控制台输出如下
4.2.6 @RequestAttribute 和 @SessionAttribute
@RequestAttribute用来获取 request 域属性,@SessionAttribute用来获取session域属性(使用原生的 Servlet api 同样可以获取)
(1)在index.html 中加入超链接
<br><br><a href="/login">@RequestAttribute 和 @SessionAttribute-分别获取request域和session域属性</a>
(2)创建RequestController.java,向 request 域中添加数据
package com.springboot.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestAttribute;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.SessionAttribute;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
@Controller
public class RequestController {
@GetMapping("/login")
public String login(HttpServletRequest request){
// 向request域中添加了数据
request.setAttribute("user","小王");
// 向 session 域中添加数据
request.getSession().setAttribute("website", "http://www.baidu.com");
//告诉 Spring MVC 你希望进行请求转发,而不是视图解析
return "forward:/ok"; //请求转发到 /ok
}
@GetMapping("/ok")
@ResponseBody
public String ok(
@RequestAttribute(value = "user", required = false) String username,
HttpServletRequest request,
@SessionAttribute(value = "website", required = false) String website,
HttpSession session){
// 获取到request域中的数据
System.out.println("username=" + username);
System.out.println("通过servlet api 获取 username = " + request.getAttribute("user"));
// 获取到session域中的数据
System.out.println("website=" + website);
System.out.println("通过servlet api 获取 website =" + session.getAttribute("website"));
return "success";
}
}
(3)启动主程序,在浏览器输入 localhost:8080/wwj/index.html 进行测试,效果如下
点击后控制台输出如下
4.3 复杂参数
4.3.1 基本介绍
(1)SpringBoot在响应客户端请求时,也支持复杂参数,例如:Map、Model、Error/BindingResult、RedirectAttributes、ServletResponse、SessionStatus、UriComponentsBuilder、ServletUriComponentsBuilder、HttpSession。重要的有Map、Model、ServletResponse
(2)Map、Model 数据会被放到request域
(3)RedirectAttributes 表示重定向携带数据
4.3.2 复杂参数应用实例
需求说明:
- 测试Map、Model 数据会被放到request域
- 演示创建cookie,并通过 response 添加到浏览器/客户端
(1)在 RequestController.java 增加方法
// 响应一个注册请求
@GetMapping("/register")
public String register(Map<String, Object> map,
Model model,
HttpServletResponse response){
// 这些形参表示如果发过来一个注册请求,会将注册数据封装到map或model
// map 和 model 中的数据,会被放入request域中
map.put("user","wwj");
map.put("job","开发工程师");
model.addAttribute("sal", 80000);
//演示创建cookie,并通过 response 添加到浏览器/客户端
Cookie cookie = new Cookie("email", "wwj@qq.com");
response.addCookie(cookie);
// 请求转发
return "forward:/registerOk";
}
@ResponseBody
@GetMapping("/registerOk")
public String registerOk(HttpServletRequest request){
System.out.println("user=" + request.getAttribute("user"));
System.out.println("job=" + request.getAttribute("job"));
System.out.println("sal=" + request.getAttribute("sal"));
return "success";
}
(2)启动主程序,在浏览器直接输入 localhost:8080/register 进行测试,控制台输出如下。成功从request中获取到了 map 和 model 的值
在浏览器按下F12 打开开发者模式,可以看到成功获取到了cookie
4.4 自定义对象参数 javabean -自动封装
4.4.1 基本介绍
(1)SpringBoot在响应客户端/浏览器请求时,有支持自定义对象参数
(2)自动完成类型转换与格式化,并支持级联封装
4.4.2 应用实例
需求说明:演示自定义对象参数使用,完成自动封装,类型转换
代码实现:
(1)创建实体类 Car.java 和 Monster.java
package com.springboot.entity;
import lombok.Data;
import org.springframework.stereotype.Component;
@Data
@Component
public class Car {
private String name;
private Double price;
}
package com.springboot.entity;
import lombok.Data;
import org.springframework.stereotype.Component;
import java.util.Date;
@Data
@Component
public class Monster {
private Integer id;
private String name;
private Integer age;
private Boolean isMarried;
private Date birth;
private Car car;
}
(2)在resources/public 目录下新建静态html文件,save.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>添加妖怪</title>
</head>
<body>
<h1>添加妖怪(测试封装POJO)</h1>
<form action="/saveMonster" method="post">
编号: <input name="id" value="100"><br/>
姓名: <input name="name" value="牛魔王"><br/>
年龄: <input name="age" value="500"><br/>
婚否: <input name="isMarried" value="true"><br/>
生日: <input name="birth" value="2000/11/11"><br/>
坐骑名称: <input name="car.name" value="法拉利"><br/>
坐骑价格: <input name="car.price" value="1000000"><br/>
<input type="submit" value="保存">
</form>
</body>
</html>
(3)修改 ParameterController.java 增加方法
// 添加monster
@PostMapping("/saveMonster")
public String saveMonster(Monster monster) {
System.out.println("monster-" + monster);
return "success";
}
(4)启动主程序,在浏览器输入 localhost:8080/wwj/save.html 进行测试,效果如下
点击保存后控制台输出如下