我没有对象是因为不想找吗?你不上清华北大是因为不想上吗?
后端代码放在https://gitee.com/siumu/springboot-xiumu.git
前端代码放在https://gitee.com/siumu/xiumu-admin-ui.git
问题
restful 规范中 GET
请求用来查询数据,但是它又不能在请求体里传递参数,如果把请求参数放在请求体里,大概率会直接被忽略掉,那么如何用 GET
请求传递复杂的参数呢?
举个例子
例如,分页请求规定的请求参数是这样的。
{
"condition": {}, // 查询条件
"size": 0, // 每页条数
"current": 0, // 当前页数
}
如果我要分页查询第1页,10条,性别为男的用户,那么传递的参数就是这个样子:
{
"condition": {
gender: '男'
},
"size": 10, // 每页条数
"current": 1, // 当前页数
}
这样的参数如果使用 GET
请求传递给后端,后端又该如何接收呢?或者更加复杂的对象结构又该如何传参呢?
解决办法
此时就需要前后端共同规定规范了。
- 前端: 将参数转成
json
格式,再通过Base64
编码之后拼在GET
请求的?
后面 - 后端: 自定义参数解析器,
Base64
解码之后,再通过json
工具将参数反序列化为对象
前端倒是很好解决,我们引入 js-base64
然后引入它的 Base64 对象
import { Base64 } from 'js-base64
// 将参数序列化成 json,再经过 Base64 编码之后放在 url 上传输
url = url + '?' + Base64.encode(JSON.stringify(params))
后端就需要我们自己自定义参数解析器了。这个也是非常简单。
- 首先我们模仿
@RequestBody
注解,自定义一个@RequestJson
注解
/**
* get 请求参数使用该注解就会使用自定义的参数解析器来解析复杂的参数
*/
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestJson {
}
- 自定义一个参数解析器。
/**
* 自定义参数解析器,请求参数使用该注解 {@link RequestJson} 就会使用以下解析方式。
* 说明:前端将参数序列化成 json,再经过 Base64 编码之后放在 url 上传输。
* 后端 Base64 解码之后,再通过 json 工具将参数反序列化为对象。
* 例如:http://localhost:8080/user/page?eyJjdXJyZW50IjoxLCJzaXplIjoxMCwidG90YWwiaG9uZSI6IiJ9fQ==
*/
@Slf4j
public class HandlerRequestJsonArgumentResolver implements HandlerMethodArgumentResolver {
/**
* 该方法判断是否要使用该参数解析器。这里我们就判断 有没有使用 @RequestJson 注解来判断是否使用该解析器
* 如果返回 true 就运行 resolveArgument 方法来解析参数
* 如果返回 false 使用其他参数解析器来解析参数,springframework 有很多参数解析器
*/
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(RequestJson.class);
}
/**
* 该方法真正用来解析参数。
* 先使用 Hutool 的 Base64 工具将 json 字符串解析出来
* 再使用 Hutool 的 JSONUtil 工具将 json 转成 Bean 对象
*/
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
try {
String json = Base64.decodeStr(request.getQueryString());
return JSONUtil.toBean(json, parameter.getGenericParameterType(),false);
} catch (Exception e) {
log.error("请求参数解析失败,请检查!" + e.getMessage());
throw new XiuMuException(SysException.SERVE_FAIL);
}
}
}
- 将该参数解析器注册一下
@Configuration
public class WebConfig implements WebMvcConfigurer {
/**
* 注册自定义参数解析器
*/
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(new HandlerRequestJsonArgumentResolver());
}
}
使用方式
像使用 @RequestBody
一样使用 @RequestJson
即可
/**
* 分页查询
* 可传递查询参数,按照某些字段分页查询
*
* @param pageQuery 分页条件,查询参数
* @return
*/
@GetMapping("/user/page")
public ResultJSON page( @RequestJson PageQuery pageQuery) {
return ResultJSON.success(userService.listPage(pageQuery));
}
后端代码放在https://gitee.com/siumu/springboot-xiumu.git
前端代码放在https://gitee.com/siumu/xiumu-admin-ui.git