目录
痛点
@RequestBody接收的参数只能是一个对象,可以通过创建ViewObject对象来接收,但是对于各种不确定参数就需要非常多的ViewObject。
如果不用ViewObject,而是直接用原生Map<String,Object> map
接收,一样需要一个个取出来:
@PostMapping("login")
public Object login(@RequestBody Map<String,Object> map) {
String account = (String) map.get("account");
String pwd = (String) map.get("pwd");
...
}
目标方案
最终想要的效果是即使前端传json,后台先解析出来,再塞到方法参数中,这个过程是隐式完成,最终业务代码就可以非常简洁:
@PostMapping("login")
public Object login(String account,String pwd) {
String account = (String) map.get("account");
String pwd = (String) map.get("pwd");
...
}
个别问题Q&A
Q:如何区分POST的json和form形式的参数
A:先判断前端传的是json(通过contentType或者request.getInputStream),确认json后,解析json,然后赋值给方法的参数。同时,可以使用注解来指定(或排除)某些参数使用(或不使用)json对象赋值。
想要实现以上效果, 需要理解springmvc是哪一步获取请求体数据封装成@RequestBody参数对象,
以及其他表单参数是如何赋值,所以:
第一步:理解springmvc参数接收原理
因为springmvc本身是个庞大的架构体系,可以预知它对参数值的封装这个过程是通过某种设计模式完成的,而不是按代码顺序一步步写下来,这是读spring源码的一个方向。
从整个应用服务层面来看,请求体数据先进入tomcat(或其他),被封装形成基础request请求对象,然后经过filter过滤器,经过interceptor拦截器等,进入统一的DispatcherServlet(spring默认servlet),然后在DispatcherServlet中根据HandlerMapping找到匹配的Handler(也就是Controller中某一个方法),最后request请求对象交由匹配的这个Handler处理。
DispatcherServlet
public class DispatcherServlet extends FrameworkServlet {
--1、servlet的doService方法
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
try {
doDispatch(request, response);
}
....
}
--2、进入doDispatch方法
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
try {
HttpServletRequest processedRequest = request;
--3、 为当前request匹配对应的Handler
HandlerExecutionChain mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
return;
}
--4、 拿到HandlerAdapter 适配器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
--5、 先经过多个拦截器
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
--6、 实际调用handle处理(--7、 进入RequestMappingHandlerAdapter.handle()方法)
ModelAndView mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
...
applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
Exception dispatchException = ex;
}
catch (Throwable err) {
// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
Exception dispatchException = new NestedServletException("Handler dispatch failed", err);
}
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
}
RequestMappingHandlerAdapter
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
implements BeanFactoryAware, InitializingBean {
@Override
--