1 MockMvc的使用
利用MockMvc可以快速实现MVC测试
坑01:利用MockMvc进行测试时应用上下文路径是不包含在请求路径中的
1.1 创建一个SpringBoot项目
1.2 创建一个用户实体类
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
package cn.test.demo.base_demo.entity.po; import java.util.Date; /** * @author 王杨帅 * @create 2018-05-05 22:03 * @desc 用户实体类 **/ public class User { private Integer userId; private String userName; private String password; private Date birthday; public Integer getUserId() { return userId; } public void setUserId(Integer userId) { this.userId = userId; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } }
1.3 创建一个用户控制类
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
package cn.test.demo.base_demo.controller; import cn.test.demo.base_demo.entity.po.User; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.ArrayList; import java.util.List; /** * @author 王杨帅 * @create 2018-05-05 22:02 * @desc 用户模块控制层 **/ @RestController @RequestMapping(value = "/user") public class UserController { @GetMapping public List<User> queryList() { List<User> userList = new ArrayList<>(); userList.add(new User()); userList.add(new User()); userList.add(new User()); return userList; } }
1.4 创建一个测试类
该测试类主要测试用户控制类中的相关方法
1.4.1 引入测试类注解以及日志注解
@RunWith(SpringRunner.class) @SpringBootTest @Slf4j
1.4.2 依赖注入WebApplicationContext
@Autowired private WebApplicationContext wac;
1.4.3 实例化MockMvc
private MockMvc mockMvc; @Before public void setup() { mockMvc = MockMvcBuilders.webAppContextSetup(wac).build(); }
1.4.4 利用MockMvc对象模拟HTTP请求
@Test public void queryList() throws Exception { String result = mockMvc.perform( MockMvcRequestBuilders.get("/user") .contentType(MediaType.APPLICATION_JSON_UTF8) ) .andExpect(MockMvcResultMatchers.status().isOk()) .andReturn().getResponse().getContentAsString(); log.info("===/" + className + "/queryList===" + result); }
1.4.5 测试类代码汇总
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
package cn.test.demo.base_demo.controller; import lombok.extern.slf4j.Slf4j; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.http.MediaType; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MockMvcBuilder; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.result.MockMvcResultMatchers; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; import static org.junit.Assert.*; @RunWith(SpringRunner.class) @SpringBootTest @Slf4j public class UserControllerTest { private final String className = getClass().getName(); @Autowired private WebApplicationContext wac; private MockMvc mockMvc; @Before public void setup() { mockMvc = MockMvcBuilders.webAppContextSetup(wac).build(); } @Test public void queryList() throws Exception { String result = mockMvc.perform( MockMvcRequestBuilders.get("/user") .contentType(MediaType.APPLICATION_JSON_UTF8) ) .andExpect(MockMvcResultMatchers.status().isOk()) .andReturn().getResponse().getContentAsString(); log.info("===/" + className + "/queryList===" + result); } }
2 JsonPath
JsonPath是GitHub上的一个开源项目,主要用来对Json格式的数据进行一些处理
技巧:jsonPath是MockMvcResultMatchers中的一个静态方法
具体使用:点击前往
2.1 简单实例
@Test public void test01() throws Exception { mockMvc.perform( MockMvcRequestBuilders.get("/user") .contentType(MediaType.APPLICATION_JSON_UTF8) ) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.jsonPath("$.length()").value(3)); }
3 请求参数
3.1 PathVarible
主要获取请求路径中的数据
技巧01:PathVarible获取到的数据是请求路径的一部分
技巧02:@PathVariable注解中的name和value两个成员的作用是一样的,是用来解决路径名和请求处理方法形参名不一致的问题
技巧03:@PathVariable支持正则表达式,如果路径参数不满足正则表达式就会匹配失败;参考博文
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package org.springframework.web.bind.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.springframework.core.annotation.AliasFor; @Target({ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface PathVariable { @AliasFor("name") String value() default ""; @AliasFor("value") String name() default ""; boolean required() default true; }
3.1.1 控制类
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
package cn.test.demo.base_demo.controller; import cn.test.demo.base_demo.entity.po.User; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.ArrayList; import java.util.List; /** * @author 王杨帅 * @create 2018-05-05 22:02 * @desc 用户模块控制层 **/ @RestController @RequestMapping(value = "/user") @Slf4j public class UserController { private final String className = getClass().getName(); @GetMapping public List<User> queryList() { List<User> userList = new ArrayList<>(); userList.add(new User()); userList.add(new User()); userList.add(new User()); return userList; } @GetMapping(value = "/{id}") public User queryInfoByUserId( @PathVariable(name = "id") String userId ) { System.out.println("===路径参数:" + userId); // log.info("===/" + className + "/queryInfoByUserId===路径参数为:{}", userId); User user = new User(); return user; } }
3.1.2 测试类
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
package cn.test.demo.base_demo.controller; import lombok.extern.slf4j.Slf4j; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.http.MediaType; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MockMvcBuilder; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.result.MockMvcResultMatchers; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; import static org.junit.Assert.*; @RunWith(SpringRunner.class) @SpringBootTest @Slf4j public class UserControllerTest { private final String className = getClass().getName(); @Autowired private WebApplicationContext wac; private MockMvc mockMvc; @Before public void setup() { mockMvc = MockMvcBuilders.webAppContextSetup(wac).build(); } @Test public void queryList() throws Exception { String result = mockMvc.perform( MockMvcRequestBuilders.get("/user") .contentType(MediaType.APPLICATION_JSON_UTF8) ) .andExpect(MockMvcResultMatchers.status().isOk()) .andReturn().getResponse().getContentAsString(); log.info("===/" + className + "/queryList===" + result); } /** * 测试JosnPath * @throws Exception */ @Test public void test01() throws Exception { mockMvc.perform( MockMvcRequestBuilders.get("/user") .contentType(MediaType.APPLICATION_JSON_UTF8) ) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.jsonPath("$.length()").value(3)); } /** * 测试:路径参数 * @throws Exception */ @Test public void test02() throws Exception { String result = mockMvc.perform( MockMvcRequestBuilders.get("/user/123") .contentType(MediaType.APPLICATION_JSON_UTF8) ) .andExpect(MockMvcResultMatchers.status().isOk()) .andReturn().getResponse().getContentAsString(); System.out.println("====/" + result ); } }
3.2 RequestParam
主要获取请求路径后面的 K-V 键值对
技巧01:@RequestParam注解中的name和value属性的作用都是一样的,都是为了解决前端变量名和后台请求处理方法形参不一致的问题
技巧02:@RequestParam 可以指定默认值(即:指定了默认之后,即使前端不传入参数也不会报400错误,而是采用设定的默认值)
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package org.springframework.web.bind.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.springframework.core.annotation.AliasFor; @Target({ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface RequestParam { @AliasFor("name") String value() default ""; @AliasFor("value") String name() default ""; boolean required() default true; String defaultValue() default "\n\t\t\n\t\t\n\ue000\ue001\ue002\n\t\t\t\t\n"; }
3.2.1 控制类
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
package cn.test.demo.base_demo.controller; import cn.test.demo.base_demo.entity.po.User; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.*; import java.util.ArrayList; import java.util.List; /** * @author 王杨帅 * @create 2018-05-05 22:02 * @desc 用户模块控制层 **/ @RestController @RequestMapping(value = "/user") @Slf4j public class UserController { private final String className = getClass().getName(); @GetMapping public List<User> queryList() { List<User> userList = new ArrayList<>(); userList.add(new User()); userList.add(new User()); userList.add(new User()); return userList; } /** * 路径参数 * @param userId * @return */ @GetMapping(value = "/{id}") public User queryInfoByUserId( @PathVariable(name = "id") String userId ) { System.out.println("===路径参数:" + userId); // log.info("===/" + className + "/queryInfoByUserId===路径参数为:{}", userId); User user = new User(); return user; } @GetMapping(value = "/findByName") public void findByName( @RequestParam(value = "name") String username ) { System.out.println("===请求参数为:/" + username); } }
3.2.2 测试类
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
package cn.test.demo.base_demo.controller; import lombok.extern.slf4j.Slf4j; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.http.MediaType; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MockMvcBuilder; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.result.MockMvcResultMatchers; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; import static org.junit.Assert.*; @RunWith(SpringRunner.class) @SpringBootTest @Slf4j public class UserControllerTest { private final String className = getClass().getName(); @Autowired private WebApplicationContext wac; private MockMvc mockMvc; @Before public void setup() { mockMvc = MockMvcBuilders.webAppContextSetup(wac).build(); } @Test public void queryList() throws Exception { String result = mockMvc.perform( MockMvcRequestBuilders.get("/user") .contentType(MediaType.APPLICATION_JSON_UTF8) ) .andExpect(MockMvcResultMatchers.status().isOk()) .andReturn().getResponse().getContentAsString(); log.info("===/" + className + "/queryList===" + result); } /** * 测试JosnPath * @throws Exception */ @Test public void test01() throws Exception { mockMvc.perform( MockMvcRequestBuilders.get("/user") .contentType(MediaType.APPLICATION_JSON_UTF8) ) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.jsonPath("$.length()").value(3)); } /** * 测试:路径参数 * @throws Exception */ @Test public void test02() throws Exception { String result = mockMvc.perform( MockMvcRequestBuilders.get("/user/123") .contentType(MediaType.APPLICATION_JSON_UTF8) ) .andExpect(MockMvcResultMatchers.status().isOk()) .andReturn().getResponse().getContentAsString(); System.out.println("====/" + result ); } @Test public void test03() throws Exception { mockMvc.perform( MockMvcRequestBuilders.get("/user/findByName") .param("username", "王杨帅") .contentType(MediaType.APPLICATION_JSON_UTF8) ) .andExpect(MockMvcResultMatchers.status().isOk()); } }
3.3 RequestBody
可以将前端参数封装成一个对象传到后台
技巧01:请求体中的数据会自动转化成字符串进行传输
3.3.1 新建一个数据传输类
该类主要用于整合前端传过来的数据
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
package cn.test.demo.base_demo.entity.dto; public class UserQueryCondition { private String username; private Integer age; private Integer ageTo; private String xxx; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Integer getAgeTo() { return ageTo; } public void setAgeTo(Integer ageTo) { this.ageTo = ageTo; } public String getXxx() { return xxx; } public void setXxx(String xxx) { this.xxx = xxx; } @Override public String toString() { return "UserQueryCondition [username=" + username + ", age=" + age + ", ageTo=" + ageTo + ", xxx=" + xxx + "]"; } }
3.3.2 控制类
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
package cn.test.demo.base_demo.controller; import cn.test.demo.base_demo.entity.dto.UserQueryCondition; import cn.test.demo.base_demo.entity.po.User; import com.fasterxml.jackson.annotation.JsonView; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.*; import java.util.ArrayList; import java.util.List; /** * @author 王杨帅 * @create 2018-05-05 22:02 * @desc 用户模块控制层 **/ @RestController @RequestMapping(value = "/user") @Slf4j public class UserController { private final String className = getClass().getName(); @GetMapping @JsonView(value = User.UserSimple.class) public List<User> queryList() { List<User> userList = new ArrayList<>(); userList.add(new User()); userList.add(new User()); userList.add(new User()); return userList; } /** * 路径参数 * @param userId * @return */ @GetMapping(value = "/{id}") public User queryInfoByUserId( @PathVariable(name = "id") String userId ) { System.out.println("===路径参数:" + userId); // log.info("===/" + className + "/queryInfoByUserId===路径参数为:{}", userId); User user = new User(); return user; } /** * 请求参数 * @param username */ @GetMapping(value = "/findByName") public void findByName( @RequestParam(value = "name") String username ) { System.out.println("===请求参数为:/" + username); } /** * 请求体 * @param userQueryCondition */ @PostMapping() public void create( @RequestBody UserQueryCondition userQueryCondition ) { System.out.println("===前端获取到的数据为:" + userQueryCondition); } }
3.3.3 测试类
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
package cn.test.demo.base_demo.controller; import lombok.extern.slf4j.Slf4j; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.http.MediaType; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MockMvcBuilder; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.result.MockMvcResultMatchers; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; import static org.junit.Assert.*; @RunWith(SpringRunner.class) @SpringBootTest @Slf4j public class UserControllerTest { private final String className = getClass().getName(); @Autowired private WebApplicationContext wac; private MockMvc mockMvc; @Before public void setup() { mockMvc = MockMvcBuilders.webAppContextSetup(wac).build(); } @Test public void queryList() throws Exception { String result = mockMvc.perform( MockMvcRequestBuilders.get("/user") .contentType(MediaType.APPLICATION_JSON_UTF8) ) .andExpect(MockMvcResultMatchers.status().isOk()) .andReturn().getResponse().getContentAsString(); // log.info("===/" + className + "/queryList===" + result); System.out.println("===/结果为:" + result); } /** * 测试JosnPath * @throws Exception */ @Test public void test01() throws Exception { mockMvc.perform( MockMvcRequestBuilders.get("/user") .contentType(MediaType.APPLICATION_JSON_UTF8) ) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.jsonPath("$.length()").value(3)); } /** * 测试:路径参数 * @throws Exception */ @Test public void test02() throws Exception { String result = mockMvc.perform( MockMvcRequestBuilders.get("/user/123") .contentType(MediaType.APPLICATION_JSON_UTF8) ) .andExpect(MockMvcResultMatchers.status().isOk()) .andReturn().getResponse().getContentAsString(); System.out.println("====/" + result ); } /** * 测试:请求参数 * @throws Exception */ @Test public void test03() throws Exception { mockMvc.perform( MockMvcRequestBuilders.get("/user/findByName") .param("name", "王杨帅") .contentType(MediaType.APPLICATION_JSON_UTF8) ) .andExpect(MockMvcResultMatchers.status().isOk()); } @Test public void test04() throws Exception { String content = "{\"username\":\"王杨帅\",\"age\":\"24\"}"; mockMvc.perform( MockMvcRequestBuilders.post("/user") .content(content) .contentType(MediaType.APPLICATION_JSON_UTF8) ) .andExpect(MockMvcResultMatchers.status().isOk()); } }
3.3.4 参数验证
参考博文:点击前往
4 JsonView
需求:有的请求需要返回一个实体对象的全部字段,而有的请求只需要返回一个实体对象的部分字段;但是两个请求的数据都来自同一个实体类,怎么样才可以避免实体类重复定义
JsonView可以通过一个实体类实现多种视图显示
4.1 声明多个视图
在一个实体类中利用接口实现声明多个视图
技巧01:视图之间可以继承,如果视图A继承了视图B,那么在利用视图A进行显示时视图B对应的字段也会被显示出来
4.2 设置实例属性
在实例变量的Get方法上设置视图
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
package cn.test.demo.base_demo.entity.po; import com.fasterxml.jackson.annotation.JsonView; import java.util.Date; /** * @author 王杨帅 * @create 2018-05-05 22:03 * @desc 用户实体类 **/ public class User { public interface UserSimple {}; public interface UserDetail extends UserSimple {}; private Integer userId; private String userName; private String password; private Date birthday; @JsonView(value = UserSimple.class) public Integer getUserId() { return userId; } public void setUserId(Integer userId) { this.userId = userId; } @JsonView(value = UserSimple.class) public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } @JsonView(value = UserDetail.class) public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @JsonView(value = UserDetail.class) public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } }
4.3 设置响应视图
在控制类中方法中设置响应视图
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
package cn.test.demo.base_demo.controller; import cn.test.demo.base_demo.entity.po.User; import com.fasterxml.jackson.annotation.JsonView; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.*; import java.util.ArrayList; import java.util.List; /** * @author 王杨帅 * @create 2018-05-05 22:02 * @desc 用户模块控制层 **/ @RestController @RequestMapping(value = "/user") @Slf4j public class UserController { private final String className = getClass().getName(); @GetMapping @JsonView(value = User.UserSimple.class) public List<User> queryList() { List<User> userList = new ArrayList<>(); userList.add(new User()); userList.add(new User()); userList.add(new User()); return userList; } /** * 路径参数 * @param userId * @return */ @GetMapping(value = "/{id}") public User queryInfoByUserId( @PathVariable(name = "id") String userId ) { System.out.println("===路径参数:" + userId); // log.info("===/" + className + "/queryInfoByUserId===路径参数为:{}", userId); User user = new User(); return user; } @GetMapping(value = "/findByName") public void findByName( @RequestParam(value = "name") String username ) { System.out.println("===请求参数为:/" + username); } }
5 分页查询参数
5.1 控制方法形参类型
在controller层的控制方法中利用 Pageable 对象去接收前端传过来的路径参数
技巧01:在springBoot项目中需要引入 spring-boot-starter-data-jpa 相关jar包才可以使用 Pageable 去接收分页查询参数
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency>
技巧02:Pageable 所在的包名为:import org.springframework.data.domain.Pageable;
技巧03:如果前端没有传入先关的参数,Pageable 是有默认值的,即使不用 @PageableDefault 指定默认值也是可以的(如果不指定:默认页码为第一页,默认每页记录数为20)
技巧04:Pagealbe 可以利用 @PageableDefault 设置默认值(即:前端不传入任何参数,直接使用开发者指定的数值),例如:
@PageableDefault(size = 14, page = 14, sort = "username", direction = Direction.DESC) Pageable pageable
5.2 前端传参
在前端直接在请求路径中利用 k-v 键值对传入即可,形如
技巧01:分页查询的参数变量必须是page、size、sort,分别代表页码、每页记录数、排序字段及其升降序;前端传入这三个参数,后台会自动封装到 Pageable 对象中
http://127.0.0.1:9999/test/page?page=12&size=23&sort=name,asc
疑惑01:后台明明时利用 Pageable 去接收前端的参数,为什么打印出来的日志信息却是一个 Page 对象;(理解:SpringMVC框架对Pageable进行了一次封装)
5.3 SpringJPA 中有直接进行分页查询的接口
参考文档:点击前往
6 JsonProperty
6.1 需求
当后台响应实体类的变量名和前台的需要的不一致时该如何解决;前端需要按照前端的变量规则来传,后端按照后端的变量规则来传,如何保证前后端的数据对应;例如:
》前端要求的对象格式
》后端要求的对象格式
6.2 解决办法
在定义后端的实体对象时利用 @JsonProperty 指定前端的变量名,例如:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
package cn.xiangxu.product.VO; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import javax.persistence.Column; import java.util.List; /** * @author 王杨帅 * @create 2018-07-23 14:22 * @desc 商品类型视图 **/ @Data public class CategoryVO { /** * 类目名字 */ @JsonProperty(value = "name") private String categoryName; /** * 类目编号 */ @JsonProperty(value = "type") private Integer categoryType; /** 商品视图列表 */ @JsonProperty(value = "foods") private List<ProductVO> productVOList; }
6.3 测试
6.3.1 准备
》创建一个SpringBoot项目,并引入lombok、spring-boot-starter-web依赖
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--日志、get\set\toString satrt--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <!--<version>1.18.0</version>--> <!--<scope>provided</scope>--> </dependency> <!--日志、get\set\toString end-->
》编写视图类和视图类工具
》》响应视图类
技巧01:@Data注解的目的是自动生成get\set\toString等方法
坑01:利用IDEA开发时就算引入了lombok依赖,也在相关类中添加了@Data注解,但是启动应用时会报错;因为lombok会在应用打包时自动给我们生成相关方法,直接利用IDEA启动应用时那些方法还没有生成,所以会报错;解决办法是在IDEA中安装一个lombok插件
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
package cn.xiangxu.product.VO; import lombok.Data; /** * @author 王杨帅 * @create 2018-07-23 13:58 * @desc 数据封装视图 **/ @Data public class ResultVO<T> { private Integer code; private String msg; private T data; }
》》响应视图类工具
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
package cn.xiangxu.product.utils; import cn.xiangxu.product.VO.ResultVO; /** * @author 王杨帅 * @create 2018-07-23 14:06 * @desc 响应视图工具类 **/ public class ResultVoUtil { public static ResultVO success(Object data) { ResultVO resultVO = new ResultVO(); resultVO.setCode(0); resultVO.setMsg("请求成功"); resultVO.setData(data); return resultVO; } }
》》数据视图类
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
package cn.xiangxu.product.VO; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import javax.persistence.Column; import java.util.List; /** * @author 王杨帅 * @create 2018-07-23 14:22 * @desc 商品类型视图 **/ @Data public class CategoryVO { /** * 类目名字 */ @JsonProperty(value = "name") private String categoryName; /** * 类目编号 */ @JsonProperty(value = "type") private Integer categoryType; /** 商品视图列表 */ @JsonProperty(value = "foods") private List<ProductVO> productVOList; }
6.3.2 测试Get请求
6.3.3 测试POST请求
6.3.4 代码汇总
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
package cn.xiangxu.product.controller; import cn.xiangxu.product.VO.CategoryVO; import cn.xiangxu.product.VO.ResultVO; import cn.xiangxu.product.utils.ResultVoUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.*; /** * @author 王杨帅 * @create 2018-07-23 15:51 * @desc 测试控制层 **/ @RestController @RequestMapping(value = "/test") @Slf4j public class TestController { @GetMapping(value = "/connect") public ResultVO connect() { String result = "前后台连接成功"; log.info(result); return ResultVoUtil.success(result); } @GetMapping(value = "/test01") public ResultVO test01() { CategoryVO categoryVO = new CategoryVO(); categoryVO.setCategoryName("熟食"); categoryVO.setCategoryType(2); categoryVO.setProductVOList(null); return ResultVoUtil.success(categoryVO); } @PostMapping(value = "/test02") public ResultVO test02( @RequestBody CategoryVO categoryVO ) { log.info("前端传过来的参数信息为:" + categoryVO); return ResultVoUtil.success(categoryVO); } }