Springboot:前后端分离——提交url返回json
参考
SpringBoot实现前后端数据交互、json数据交互、Controller接收参数的几种常用方式 - edda_huang - 爱码网
Spring Boot返回JSON数据(三种方式)_Eternal_Summer-的博客-CSDN博客
SpringBoot 返回 Json 数据格式_跑起来要带风!的博客-CSDN博客
Springboot之返回json数据格式的两种方式-yellowcong_drnrrwfs的博客-CSDN博客
Springboot-json做前后端分离 - 梦却了无影踪 - 博客园
1、前言
现在大多数互联网项目都是采用前后端分离的开发方式:
- 前端负责页面展示和数据获取;
- 后端负责业务逻辑和接口封装。
后端在与前端交互的过程中,常用Json数据与前端进行交互。
如果想获取前端送来的Json,需要用@RequestBody注解。
该注解用于获取http request的内容(字符串),通过SpringMVC提供的HttpMessageConverter接口将读取到的内容转换为Json、xml等格式的数据,并将其绑定到Controller方法的参数上,
提交方式为POST时
- 前端以application/x-www-form-urlencoded上传JSON对象,后端用@RequestParam或Servlet获取参数;
- 前端以application/json上传Json字符串,后端用@RequestBody或HttpServletRequest获取参数。
1.1、依赖
spring-boot-starter-web
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-json</artifactId> <version>2.0.3.RELEASE</version> <scope>compile</scope> </dependency>
2、注解
- @RestController:写在Controller类之前,添加该注解即可返回JSON格式的数据;@RestController = @Controller + @ResponseBody,@ResponseBody注解是将return的数据结构转换为JSON格式。
- @RequestMapping("/url"):写在Controller类前或类方法前,表示该类或该方法映射的URL,当我们访问该URL时,就会自动调用相应的处理方法;
- @PostMapping:相当于@RequestMapping(method = ReuqestMethod.POST )
- @GetMapping:相当于@RequestMapping(method = ReuqestMethod.GET )
- @PathVariable(GET专用):通常我们用URL Template样式映射,即url/{param}这种形式,我们可以获取到URL后的参数;
- @RequestParam(POST、GET均可):用于获取多个参数,以及application/x-www-form-urlencoded传来的JSON对象,在()中传入需要获取参数的参数名;
@RequestParam( required = false , defaultValue = "0" , value = "username" )
参数
说明
required 表明该参数是否必须;
如果为true且没有传入,会报404错误;
如果是false且没有传入,会默认为null;
value 请求中传入的参数名称;
如果不设置后台接口的value值,则会默认为该变量名。
defaultValue 参数的默认值;
如果request中没有同名参数,则变量默认为该值
- @RequestBody(POST专用):用的最多的注解,该注解与@RequestParam作用类似,区别在于将①传来的多个参数用Map或Entity统一接收,而不用对每个参数分别写注解;②application/json传来的Json字符串的处理;
- @RequestHeader:获取Header信息;
- @CookieValue:获取Cookie值。
后端JSON发给前端的过程中,注解的作用
当后端接收完前端JSON,响应也是返回JSON给前端,此时只需要在后台Controller类加上@ResponseBody注解即可。该注解用于将Controller方法返回的对象,通过HttpMessageConverter接口转换为指定格式的数据,如JSON、xml等,通过Response响应给前端。
更常用的是@RestController,它相当于@Controller + @ResponseBody。
3、请求路径参数:GET
注解:@RequestParam或@PathVariable
一般用于查询数据,采用明文传输,用于获取用户无关的信息。
可以用@GetMapping注解,它其实是@RequestMapping( method = ReuqestMethod.GET )的缩写。
3.1、GET请求,URL路径传参:用 url?param=value的形式
如:http://localhost:4001/api/unit?code=111
后端如果要获取这样的URL,可以用@RequestParam注解:
@RestController public class HelloController{ @RequestMapping(value="/hello",method=RequestMethod.GET) public String sayHello(@RequestParam Integer id){ return "id:"+id; } }
对上段代码的解释,对于URL为https://IP:端口/hello?Param=Value这种URL,使用@RequestParam 类型 Param的形式来获取,Value作为Param的值被传入,在方法中可以直接用变量Param来访问。
3.2、GET请求,URL路径参数:用url/value1/value2/...的形式
与3.1相比,省略了参数名。
如:http://localhost:4001/api/unit/1
后端如果要获取路径参数,可以用@PathVariable。
@RestController public class HelloController{ @RequestMapping(value="/hello/{id}/{name}",method=ReuqestMethod.GET) public String sayHello(@PathVariable("id") Integer id,@PathVariable("name") String name){ return "id:"+id+" name:"+name; } }
上文中,对于URL为https://IP:端口/hello/Value1/Value2这种URL,Value1作为@RequestParam变量id的值,Value2作为@RequestParam变量name的值被传入。
3.3、GET请求,只有路径没有参数,无注解,直接return
假设请求的URL为localhost/book,要返回一个JSON的做法为:
①先创建一个Book实体类(Entity)
package com.itlearn.springboot06json.beans; import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.Data; import java.util.Date; @Data public class Book { private String name; private String author; @JsonIgnore private Double price; @JsonFormat(pattern = "yyyy-MM-dd") private Date cationDate; }
- @JsonIgnore:转换为JSON时忽略该属性;
- @JsonFormat(pattern = "yyyy-MM-dd"):对该属性的值进行格式化。
②创建Controller,return book
@RestController public class BookController { @GetMapping("/book") public Book book(){ Book book = new Book(); book.setName("三国演义"); book.setAuthor("罗贯中"); book.setPrice(30D); book.setCationDate(new Date()); return book; }
这样在页面中显示的就是:
{"name":"三国演义","author":"罗贯中","cationDate":"2021-05-03"}
3.4、小结
路径传参:URL为URL?Param=Value,用@RequestMapping(value=URL) + @RequestParam 类型 变量名提取参数值;
路径参数:URL为URL/value1/value2/...,用@RequestMapping(value="url/{param1}/{param2}/...") + @PathVariable("param") 类型 变量名提取参数值。
3.5、SpringBoot如何将Entity自动转换为JSON?
SpringBoot之所以能自动将一个return的Entity转换为JSON,是因为引入的 spring-boot-starter-web依赖默认加入了Jackson作为JSON处理器,使我们不需添加额外的JSON处理器就可以直接返回一段JSON了。
4、POST请求
注解:
-
@RequestBody:用于application/json类型的POST;
-
@RequestParam:用于application/x-www-form-urlencoded类型的POST;
-
以上两个注解不能互相混用!
4.1、POST请求,Body传值(application/json与JSON字符串)
使用JSON格式传值,在postman中设置如下
@RequestBody注解(可以用Map或Entity类):
//用map接收 @PostMapping(path = "/demo1") public void demo1(@RequestBody Map<String,String> person){ System.out.println(person.get("name"));
System.out.println(person.get("code")); } //或者用Entity类对象接收 @PostMapping(path = "/demo1") public void demo1(@RequestBody Person person){ System.out.println(person.toString()) }
注意
- 使用@RequestBody注解接收参数时,要读取的数据放在Request Body中,Content-Type必须为application/json,否则会类型不支持的异常错误“org.springframework.web.HttpMediaTypeNotSupportedException”。
- 当Ajax用application/x-www-form-urlencoded格式上传数据时,会使用JSON对象,后台只能用@RequestParam或Servlet获取参数(见4.2节)。
- 当Ajax用application/json格式上传数据时,会使用JSON字符串,后台可以用@RequestBody或request获取参数。
如何定义后台接收参数,使之可以与前台发来的JSON数据对应呢?
前端JSON的Key在Entity类中必须找到对应的Field,就会自动映射;即前端传来的JSON的Key必须在Entity中存在,且同名,不然就会报错。
4.2、POST请求,Body传值(application/x-www-from-urlencoded与JSON对象)
参考
【转载】springboot如何接收application/x-www-form-urlencoded类型的请求_weixin_41734192的博客
数据
编码类型为application/x-www-form-urlencoded,这种格式的特点是name/value为一组,每组间用&连接,这种形式不能用复杂Json组织成Key-Value的形式。
要传输的数据,在postman中设置如下,格式为x-www-form-urlencoded,请求的URL为localhost/register:
注意,千万不能用@RequestBody来接收,否则会报错415:“Content type ‘application/x-www-form-urlencoded;charset=UTF-8’ not supported Http status 415 Unsupported Media Type”,只能用@RequestParam或者HttpServletRequest
4.1.1、@RequestParam(参数前注解)
可以用独立参数分别接收,也可以用Map一次性全部接收
1)独立参数分别接收
@PostMapping("/register") public void register(@RequestParam(value="username") String username, @RequestParam(value="password") String password, @RequestParam(value="identity") String identity)){ System.out.println("username="+username"); System.out.println("password="+password"); System.out.println("identity="+identity"); }
2)Map一次性接收
@PostMapping("/register") public void register(@RequestParam Map<String,String> person){ System.out.println("username="+person.get("username")); System.out.println("password="+person.get("password")); System.out.println("identity="+person.get("identity")); }
4.2.2、HttpServletRequest(参数前不需要注解)
@Controller public class LoginController { @PostMapping("/login") public void login(HttpServletRequest request){ System.err.println(request.getParameter("identity")); System.err.println(request.getParameter("username")); System.err.println(request.getParameter("password")); }
4.3、POST请求,Headers、Cookie传值
这里我们把Content-Type设置为JSON格式。
我们还可以在Headers中加入别的参数,比如Token。
后端可以通过HttpServletRequest获取请求头的内容,如:
//三个方法 request.getHeader(string name)方法:String request.getHeaders(String name)方法:Enumeration request.getHeaderNames()方法 @GetMapping("/demo3") public void demo3(HttpServletRequest request) { System.out.println(request.getHeader("myHeader")); for (Cookie cookie : request.getCookies()) { if ("myCookie".equals(cookie.getName())) { System.out.println(cookie.getValue()); } } }
后端用@RequestBody + Map接收,前端报200,后端就能接收参数::
@Controller public class LoginController { @PostMapping("/login") public void login(@RequestBody Map<String,Object> map){ System.err.println(map.get("username")); System.err.println(map.get("password")); System.err.println(map.get("openid")); } }
后端用@RequestBody + Entity对象来接收时。前端报200,后端也是OK:
public class LoginController { @PostMapping("/login") public void login(@RequestBody Form form){ System.err.println(form); } }
public class Form { private String openid; private String username; private String password; // get set @Override public String toString() { return "Form{" + "openid='" + openid + '\'' + ", username='" + username + '\'' + ", password='" + password + '\'' + '}'; } }
5、参数校验 @Valid + 字段前注解
后端接收到前端数据,如果要对前端数据进行校验,可以加入SpringBoot的Validate依赖:
<dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> </dependency>
使用时,只需要在接收数据的Entity前加@Valid注解,用BindingResult接收错误、不合法的提示信息:
public R hh(@RequestBody @Valid Users user , BindingResult result){ ... }
接收参数的Entity类的对应Field前还要加校验注解,比如@NotEmpty(message="密码不能为空")
还可以用正则表达式的方式来对属性进行校验,只需要加上如下注解:
@Pattern( regexp = 正则表达式, message = "输入格式不合法" )
字段前注解(配合@Valid完成校验)
下图为返回的JSON数据的前缀注解(写在Entity类相关Field前):
注意:
- 接收到的参数默认类型是String;
- 有的注解只能用在String类型的参数上;
- 可以用@JsonProperty实现前端属性名与后端Entity类的Field不一致的问题;
- 使用@RequestBody和@Valid对JSON参数进行获取与校验。
7、最终选择交互方式
7.1、POST请求
最常用的交互方法为:
- 前端用application/json,POST请求,上传JSON字符串
- 后端用@RequestBody使用Entity或Map接收参数
后端代码1,Entity:
@Controller public class LoginController { @PostMapping("/login") public void login(@RequestBody Form form){ System.err.println(form); } }
后端代码2,Map:
@Controller public class LoginController { @PostMapping("/login") public void login(@RequestBody Map<String,Object> map){ System.err.println(map.get("username")); System.err.println(map.get("password")); System.err.println(map.get("openid")); } }
7.2、GET请求
路径参数:用@RequestParam或@PathVariable获取路径参数
header传值:用HttpServletRequest获取