项目创建
项目启动
请求响应
RestController
1.返回值处理
@RestController:这个注解结合了@Controller和@ResponseBody的功能。它默认将所有处理请求的方法的返回值直接作为响应体内容返回,主要用于构建RESTful API。返回的数据格式通常是JSON或XML,这取决于请求中的Accept头部或配置的消息转换器。
Controller:这个注解的返回值通常会经过视图解析器解析,然后返回给用户一个渲染后的HTML页面。如果需要在Controller中返回JSON或XML数据,需要在方法上额外添加@ResponseBody注解。
2. 用途和场景
@RestController:主要用于构建RESTful Web服务,它简化了开发RESTful风格的控制器的代码,使得开发者能够更加专注于业务逻辑的实现,而无需关注底层的请求-响应处理细节。它支持get、post、put、delete等HTTP方法,适用于前后端分离的架构。
@Controller:更多地与视图渲染和页面跳转相关,适用于传统的MVC(Model-View-Controller)架构。通过页面模板引擎(如JSP、Thymeleaf等)将数据渲染成HTML页面返回给用户。
创建 HelloController.java
package org.example.myspringboot;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
// @RequestMapping("/api")
@RestController
public class HelloController {
@RequestMapping("/hello")
public String hello() {
return "hello";
}
}
请求 http://127.0.0.1:8080/hello 访问接口
增加 @RequestMapping("/api") 访问变成:http://127.0.0.1:8080/api/hello
RequestMapping
参数:
- value 路由 默认 /
- method 请求方式:默认GET
RequestMethod.GET,RequestMethod.POST, RequestMethod.PUT, RequestMethod.DELETE@RequestMapping(value = "/hello", method = RequestMethod.DELETE)
RequestParam
@RequestParam注解用于将HTTP请求中的参数绑定到方法的参数上
参数:
- value 获取的字段名
- required 字段值是否为必须,false为非必须
- defaultValue 字段默认值
例如url: http://127.0.0.1:8080/api/hello?name=xx ,获取name的值
package org.example.myspringboot;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/api")
@RestController
public class HelloController {
@RequestMapping(value = "/hello", method = RequestMethod.GET)
public String hello(@RequestParam(value = "name", required = false, defaultValue = "Alex") String name) {
System.out.println(name);
return "hello";
}
}
处理多个参数
http://127.0.0.1:8080/api/hello?name=xx&age=18
package org.example.myspringboot;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/api")
@RestController
public class HelloController {
@RequestMapping(value = "/hello", method = RequestMethod.GET)
public String hello(
@RequestParam(value = "name") String name,
@RequestParam(value = "age") Integer age
) {
System.out.println(name + " " + age);
return "hello";
}
}
使用Map处理多个参数
package org.example.myspringboot;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
@RequestMapping("/api")
@RestController
public class HelloController {
@RequestMapping(value = "/hello", method = RequestMethod.GET)
public String hello(Map<String, String> params) {
String name = params.get("name");
String age = params.get("age");
System.out.println(name + " " + age);
return "hello";
}
}
使用List处理多个相同参数
http://127.0.0.1:8080/api/hello?name=xx&name=yy
package org.example.myspringboot;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Map;
@RequestMapping("/api")
@RestController
public class HelloController {
@RequestMapping(value = "/hello", method = RequestMethod.GET)
public String hello(@RequestParam List<String> name) {
System.out.println(name);
return "hello";
}
}
PathVariable
@PathVariable注解获取url中的参数
http://127.0.0.1:8080/api/hello/100/Alex
package org.example.myspringboot;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
@RequestMapping("/api")
@RestController
public class HelloController {
@RequestMapping(value = "/hello/{id}/{name}", method = RequestMethod.GET)
public String hello(@PathVariable String id, @PathVariable String name) {
System.out.println(id);
System.out.println(name);
return "hello";
}
}
RequestBody
@RequestBody注解:将JSON数据映射到形参的实体类对象中(JSON中的key和实体类中的属性名保持一致)
package org.example.myspringboot;
import org.springframework.web.bind.annotation.*;
@RestController
public class DataController {
public static class Address{
public String street;
public String city;
// public Address() {} // 添加无参构造函数
}
public static class User{
public Integer id;
public String name;
public Integer age;
public Address address;
// public User() {} // 添加无参构造函数
}
@RequestMapping(value = "user/{id}", method = {RequestMethod.POST, RequestMethod.GET})
public String data(@RequestBody User user, @PathVariable Integer id){
System.out.println(user.name);
return "Hello World";
}
}
@RequestBody User user 可以将 请求体中json数据映射到 User中
上传文件
package org.example.myspringboot;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.awt.*;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
@RestController
public class FilesController {
private static final String UPLOAD_PATH = "uploads" ;
@RequestMapping(value = "file", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public String files(@RequestParam("file") MultipartFile file) {
try {
Path uploadPath = Paths.get(UPLOAD_PATH);
// 路径是否存在,不存在创建
if (!Files.exists(uploadPath)) {
Files.createDirectories(uploadPath);
}
String fileName = file.getOriginalFilename();
// 保存文件
Files.copy(file.getInputStream(), uploadPath.resolve(fileName));
return UPLOAD_PATH + "/" + fileName;
} catch (IOException e) {
e.printStackTrace();
}
return "上传失败";
}
}
private static final String UPLOAD_PATH = "uploads";
UPLOAD_DIR
是一个静态常量,其值为 "uploads"
。这个变量用来指示文件上传的目标目录。让我们详细解释一下这段代码及其各个部分的意义:
常量定义
private
: 这个关键字表示这个变量只能在定义它的类内部被访问。这是封装的一个体现,有助于保护数据不被外部直接修改。static
: 表示这是一个静态变量,即它是属于类的而不是实例的。这意味着所有该类的实例都将共享同一个UPLOAD_DIR
的值。final
: 这个关键字表示这个变量是最终的,不可改变的。一旦赋值,就不能再重新赋值。在这个场景中,我们希望上传目录的路径是一次性设定好的,并且在整个应用程序运行期间保持不变。
作用
- 路径确定性: 使用常量可以确保上传目录的路径在应用启动时就被确定下来,这样每次上传操作都能知道文件应该保存在哪里。
- 可维护性: 如果将来需要更改上传目录,只需要修改这一个地方即可,不需要在整个应用中搜索并替换所有的路径字符串。
- 易读性和易理解: 声明为常量使得其他开发人员更容易理解这个字符串是用来做什么的,同时也使得代码更加清晰和易于维护。
使用final
关键字有几个好处:
- 不可变性: 它保证了一旦给定一个值之后,这个值就不会被改变。这对于配置信息特别有用,因为配置项通常是固定的,在程序运行期间不应该改变。
- 线程安全性: 在多线程环境下,
final
变量提供了天然的可见性保证,因为它们在初始化后不会被修改,所有线程看到的都是相同的值。 - 性能优化: 编译器和JVM能够对
final
字段进行一些优化,因为它们知道这些字段的值不会改变。
consumes = MediaType.MULTIPART_FORM_DATA_VALUE
consumes
属性的作用
consumes
属性用于指定该方法能够消费(接受)哪种类型的HTTP请求体内容。这里MediaType.MULTIPART_FORM_DATA_VALUE
指定了该方法期望接收的数据类型为multipart/form-data
,这是一种常见的用于上传文件的媒体类型。
- 指定支持的媒体类型:
consumes
属性告诉Spring MVC框架,只有当请求的内容类型(Content-Type)与consumes
指定的媒体类型匹配时,才会调用该方法来处理请求。 - 消息转换器:Spring MVC使用消息转换器(Message Converters)来读取和写入请求/响应体。对于
multipart/form-data
类型的数据,Spring默认使用CommonsMultipartResolver
或者StandardServletMultipartResolver
来解析这类请求。 - 自动绑定:当
consumes
指定为MediaType.MULTIPART_FORM_DATA_VALUE
时,Spring可以自动将请求体中的数据绑定到方法参数上。例如,@RequestParam
用于获取普通表单字段的值,而@RequestParam("file") MultipartFile
则用于接收上传的文件
MultipartFile file
MultipartFile
是一个特殊的类型,它扩展了Part
接口,并且专门用于处理上传的文件。MultipartFile
提供了访问上传文件的方法,如获取文件名、文件类型、读取文件内容等。
@RequestParam("file") MultipartFile file
这一行代码的意思是:
@RequestParam("file")
:这表明HTTP请求中必须包含一个名为"file"
的参数。这个参数通常是由HTML表单中的<input type="file" name="file">
标签发送过来的。MultipartFile file
:这个参数类型表明这个方法期望接收到的是一个上传的文件。Spring MVC会将"file"
参数对应的文件内容封装成一个MultipartFile
对象,并传递给这个方法参数。
下载文件
package org.example.myspringboot;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
@RestController
public class FilesController {
private static final String UPLOAD_PATH = "/Users/apple/Downloads";
@GetMapping("file/{fileName}/download")
public ResponseEntity<InputStreamResource> downloadFile(@PathVariable String fileName) throws IOException {
Path path = Paths.get(UPLOAD_PATH + "/" + fileName);
if (!Files.exists(path)) {
return ResponseEntity.notFound().build();
}
File file = new File(String.valueOf(path));
InputStreamResource resource = new InputStreamResource(new FileInputStream(file));
HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + file.getName() + "\"");
headers.add(HttpHeaders.CONTENT_TYPE, "application/octet-stream");
return ResponseEntity.ok().headers(headers).body(resource);
}
@RequestMapping("file/{fileName}/preview")
public ResponseEntity<Resource> previewFile(@PathVariable String fileName) throws IOException {
Path path = Paths.get(UPLOAD_PATH + "/" + fileName);
Resource imageFile = new UrlResource(path.toUri());
if (!imageFile.exists() && !imageFile.isReadable()) {
return ResponseEntity.notFound().build();
}
String contentType = Files.probeContentType(path);
if (contentType == null) {
return ResponseEntity.notFound().build();
}
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.parseMediaType(contentType));
return ResponseEntity.ok().headers(headers).body(imageFile);
}
}
返回静态页面
package org.example.myspringboot;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class IndexController {
@RequestMapping
public String index() {
return "/index.html";
}
}
ResponseBody
@responseBody注解的作用是将controller的方法返回的对象通过适当的转换器转换为指定的格式之后,写入到response对象的body区,通常用来返回JSON数据或者是XML数据
ResponseEntity
ResponseEntity可以更灵活地处理HTTP响应,而不仅仅局限于返回简单的数据类型
返回string
@RequestMapping(value = "user", method = {RequestMethod.POST, RequestMethod.GET})
public ResponseEntity<String> data(){
System.out.println(user.name);
return ResponseEntity.ok()
.header("Content-Type", "application/json")
.body("提交成功");
}
返回自定义类型
package org.example.myspringboot;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@RestController
public class DataController {
public static class Address{
public String street;
public String city;
}
public static class User{
public Integer id;
public String name;
public Integer age;
public Address address;
}
@RequestMapping(value = "user/{id}", method = {RequestMethod.POST, RequestMethod.GET})
public ResponseEntity<User> data(@RequestBody User user, @PathVariable Integer id){
System.out.println(user.name);
return ResponseEntity.ok()
.header("Content-Type", "application/json")
.body(user);
}
}
设置响应状态码
@RequestMapping(value = "user", method = {RequestMethod.POST, RequestMethod.GET})
public ResponseEntity<String> data(){
System.out.println(user.name);
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.header("Content-Type", "application/json")
.body("未来找到数据");
}
参考
Java Spring Boot 全面教程_java springboot-CSDN博客