spring mvc如何封装请求参数
使用spring mvc,可以直接把页面提交的参数转为对象,方便开发。但有时候会出现传不进参数的情况,本文通过调试spring mvc源码来分析几种传参方法.
1.不带标注,原生pojo对象传参
2.@RequestParam标注
3.@RequestBody标注
4.@PathVariable("username")标注
这个是取@RequestMapping(value="/login/{username}")中的值,也就是url中的值
5.request.getParameter取参
后面两种比较清晰,都是返回一个String,这个String是什么格式需要我们自己处理。前2种,我们都可以在Controller方法添加任意类型的参数。简单类型可以直接解析,String、Integer等都能正常解析.但复杂类型却不一定能解析成功。
1.先看下客户端用jquery的基本例子
$(document).ready(function(){ let url=location.href; let param=new Object(); param["url"]=url; $.ajax({ type: "POST", url: "/xx/xx.action", dataType: "json", data:param, success: function(obj){ } }); );
2.服务端spring mvc Controller方法分别定义如下三种方式:
public Result test(String entryWay) {
public Result test(@RequestParam("entryWay") Integer entryWay) {
public Result test(@RequestBody Integer entryWay) {
前两种可以用上面的客户端参数都可正常取到值11,而第三种不行。每三种可以把Integer改String得到原始的String,再自己解析,但这样就失去了用这个标注的意义。
3.分析源码,看三种方式都是怎么实现的。
在以下代码处打断点:
org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.getArgumentResolver(MethodParameter) line: 79
可以得到这三种情况的实现类,都实现了HandlerMethodArgumentResolver接口。
a.不带标注注入参数堆栈如下:
可以看出,最后还调用Method.invoke方法来调用set方法来实现的注入。
b.RequestParam堆栈如下:
这个可以看出,这种方式用的是request.getParameterValues获得参数,传入name就是标注里的填的值.
@RequestParam其实可不带参数,那么不带参数时,这个name取什么值呢?答案是取@RequestParam修饰参数的的变量名。比如:public Result test(@RequestParam String key1) 这里的name就是key1.
通过asm获得,堆栈如下:
@RequestParam其实可不带参数,那么不带参数时,这个name取什么值呢?答案是取@RequestParam修饰参数的的变量名。比如:public Result
通过asm获得,堆栈如下:
ClassReader的包名为:org.springframework.asm.ClassReader
c.RequestBody要与请求头的contentType参数配合使用
最常用的contentType值就是application/json,在jquery中有两种方法.
1.
$.ajax({ beforeSend: function (xhr) { debugger; xhr.setRequestHeader("Content-Type","application/json"); } });
2.
$.ajax({ contentType:’application/json’, });
注意上面的代码有跨域问题,与请求url同域才没有问题。
后台获取这个值来找对应的HttpMessageConverter来读取传入的值,如下:
最后来讨论下,如何传递自定义类参数.
定义类:
public class EntryWay{ private String name; public void setName(String name) { this.name = name; } }
后台分别用三种方式传值:
public Result test(EntryWay entryWay) {
public Result test(@RequestParam("entryWay") EntryWay entryWay) {
public Result test(@RequestBody EntryWay entryWay) {
第一种用这种方式传值,
$.ajax({ data:"name=abc", })
第二种没有找到可以传值的方法。
第三种用下面方式传值:
$.ajax({ contentType:’application/json’, data: JSON.stringify(paramObj) });
上面写的并不是完整的代码,但都是各种方式必须的代码,并且这些代码都不一样。
再记录一点,Controller的用法:
一般我把把注解直接写在Controller类上面就行了,比如:
@RequestMapping("/xx") @RestController public class TestController { @RequestMapping(value = "/doRequest") public String doRequest(@RequestParam("violationId") Integer id) { return ""; } }
但我也看过这样的代码,先定义一个接口,再去实现它:
@RequestMapping("/xx") @RestController public interface ViolationApi { @RequestMapping(value = "/doRequest") public String doRequest(@RequestParam("violationId")Integer violationId); }
实现:
@RestController public class ViolationApiImpl implements ViolationApi { public String doRequest(Integer id){ //do something } }
那么请问,这种接口加实现时。参数用"xx/doRequest?violationId=123",还是参数用"xx/doRequest?id=123" ?
答案是id才是正确的,那么这个接口中方法里的RequestParam根本没有用。有趣的是,接口中的RequestMapping等注解却用了。
spring mvc的数组参数怎么传?
Controller 参数代码:@RequestParam("schoolIds")List schoolIds
这里一定要有RequestParam这个标注,这是与其本类型的参数不一样的地方。
前端传参以","隔开:schoolIds=3000000000000313,111
如果是复杂对象数组,可以把数组在前端转为json,后端再解析回来。如:
//前端: var paramObj=new Object(); let cols=new Array(); let trs=$("#colTab tbody tr"); for(let i=0;i<trs.size();i++){ let tr=trs.get(i); let colObj=new Object(); colObj["colName"]=$(tr).find("input[name='colName']").val(); colObj["colType"]=$(tr).find("select[name='colType']").val(); cols.push(colObj); } paramObj["cols"]=JSON.stringify(cols); //后端: public CommonResult addDataSource(HttpServletRequest req, String cols) { List<ColReqParam> colObjs=JSONObject.parseObject(cols,new TypeReference<ArrayList<ColReqParam>>(){}); }
SpringMVC Controller那种参数写法,不允许为空?
1. @RequestParam(value = "code")
2. String code
答案是1,这个会抛异常.
1. @RequestParam(value = "code")
2. String code
答案是1,这个会抛异常.
对于异常参数的处理,捕获异常参数,并打印出请求地址:
@RestControllerAdvice public class BaseExceptionHandler { @ExceptionHandler(MethodArgumentTypeMismatchException.class) public JsonResult<Object> handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e,HttpServletRequest req){ log.error(e.getMessage()+" 请求地址:"+req.getServletPath()); return JsonResult.buildErrorResult(ResultEnum.PARAMETER_ERROR.msg()); } @ExceptionHandler(MissingServletRequestParameterException.class) public JsonResult<Object> handleMissingServletRequestParameterException(MissingServletRequestParameterException e,HttpServletRequest req) { log.error(e.getMessage()+" 请求地址:"+req.getServletPath()); return JsonResult.buildErrorResult(ResultEnum.PARAMETER_ERROR.msg()); } }
相关阅读
微信扫描-捐赠支持
加入QQ群-技术交流
评论:
↓ 广告开始-头部带绿为生活 ↓
↑ 广告结束-尾部支持多点击 ↑