springMVC Controller接收 多对象的json数据

妖精的绣舞 提交于 2019-12-20 17:30:44

第一种方法,用包装类封装对象

实体类对象

  1. public class User {
  2. private int id;
  3. private String userName;
  4. private String realName;
  5. public int getId() {
  6. return id;
  7. }
  8. public void setId(int id) {
  9. this.id = id;
  10. }
  11. public String getUserName() {
  12. return userName;
  13. }
  14. public void setUserName(String userName) {
  15. this.userName = userName;
  16. }
  17. public String getRealName() {
  18. return realName;
  19. }
  20. public void setRealName(String realName) {
  21. this.realName = realName;
  22. }
  23. @Override
  24. public String toString() {
  25. return "User{" +
  26. "id=" + id +
  27. ", userName='" + userName + '\'' +
  28. ", realName='" + realName + '\'' +
  29. '}';
  30. }
  31. }
  32. public class Info {
  33. private int id;
  34. private String address;
  35. public int getId() {
  36. return id;
  37. }
  38. public void setId(int id) {
  39. this.id = id;
  40. }
  41. public String getAddress() {
  42. return address;
  43. }
  44. public void setAddress(String address) {
  45. this.address = address;
  46. }
  47. @Override
  48. public String toString() {
  49. return "Info{" +
  50. "id=" + id +
  51. ", address='" + address + '\'' +
  52. '}';
  53. }
  54. }
  55. public class RequestParam {
  56. private User user;
  57. private Info info;
  58. public User getUser() {
  59. return user;
  60. }
  61. public void setUser(User user) {
  62. this.user = user;
  63. }
  64. public Info getInfo() {
  65. return info;
  66. }
  67. public void setInfo(Info info) {
  68. this.info = info;
  69. }
  70. }

定义了三个实体 RequestParam里面又封装了User类和Info类

JAVA代码

  1. @RequestMapping(value = "/show",method = RequestMethod.POST)
  2. public String show(@RequestBody RequestParam param){
  3. User user = param.getUser();
  4. Info info = param.getInfo();
  5. return user.toString();
  6. }

前台代码

  1. $("#ok2").click(function(){
  2. var json = {"user":{"id":9527,"userName":"zcy","realName":"钢铁侠"},"info":{"id":998,"address":"纽约"}};
  3. $.ajax({
  4. url:"http://localhost:8080/more/show",
  5. type:"post",
  6. cache:false,
  7. contentType:"application/json",
  8. data:JSON.stringify(json),
  9. success:function(data){
  10. alert(data);
  11. }
  12. });
  13. });

可以成功接收到对象,但是显得没有那么优雅,每次请求数据不同都要另外写一个包装类,显得很麻烦。


第二种方法,用Map对象接收 更加简单粗暴

JAVA代码

  1. @RequestMapping(value = "/show")
  2. public String test(@RequestBody Map<String,Object> map){
  3. // 拿到Object之后 再做转换为实体即可 可以用FastJson
  4. Object user = map.get("user");
  5. Object info = map.get("info");
  6. return "success";
  7. }

也不够方便 每个对象还要再做一次转换

第三种方法,使用自定义的HandlerMethodArgumentResolver

自定义注解 加在控制器的参数前作为标记

  1. @Target(ElementType.PARAMETER)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. public @interface JsonObject {
  5. }

自定义处理类 实现HandlerMethodArgumentResolver接口

  1. public class JsonObjectArgResolverHandler implements HandlerMethodArgumentResolver {
  2. @Override
  3. public boolean supportsParameter(MethodParameter methodParameter) {
  4. return methodParameter.hasParameterAnnotation(JsonObject.class);
  5. }
  6. @Override
  7. public Object resolveArgument(MethodParameter methodParameter,
  8. ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest,
  9. WebDataBinderFactory webDataBinderFactory) throws Exception {
  10. // 获取Controller中的参数名
  11. String name = methodParameter.getParameterName();
  12. // 获取Controller中参数的类型
  13. Class clazz = methodParameter.getParameterType();
  14. Object arg = null;
  15. // 获取该参数实体的所用属性
  16. Field[] fields = clazz.getDeclaredFields();
  17. // 实例化
  18. Object target = clazz.newInstance();
  19. // 创建WebDataBinder对象 反射 遍历fields给属性赋值
  20. WebDataBinder binder = webDataBinderFactory.createBinder(nativeWebRequest,null,name);
  21. for (Field field:fields){
  22. field.setAccessible(true);
  23. String fieldName = field.getName();
  24. Class<?> fieldType = field.getType();
  25. // 在request中 多对象json数据的key被解析为 user[id] user[realName] info[address] 的这种形式
  26. String value = nativeWebRequest.getParameter(name + "[" + fieldName + "]");
  27. arg = binder.convertIfNecessary(value,fieldType,methodParameter);
  28. field.set(target,arg);
  29. }
  30. return target;
  31. }
  32. }

注册自己写的处理类

  1. @Component
  2. public class MyWebAppConfig implements WebMvcConfigurer {
  3. @Override
  4. public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
  5. // 配置自定义接收参数
  6. WebMvcConfigurer.super.addArgumentResolvers(resolvers);
  7. resolvers.add(new JsonObjectArgResolverHandler());
  8. }
  9. }

Controller

  1. @RequestMapping(value = "/custom")
  2. public String custom(@JsonObject User user, @JsonObject Info info){
  3. System.out.println(user.toString());
  4. System.out.println(info.toString());
  5. return "success";
  6. }

前台代码

  1. $("#ok2").click(function(){
  2. var json = {"user":{"id":9527,"userName":"zcy","realName":"钢铁侠"},"info":{"id":998,"address":"纽约"}};
  3. $.ajax({
  4. url:"http://localhost:8080/more/custom",
  5. type:"post",
  6. cache:false,
  7. // 直接传josn对象 这里与上文不同
  8. data:json,
  9. success:function(data){
  10. alert(data);
  11. }
  12. });
  13. });

第三种方式相对比较好 但我有几点还是没明白

public Object resolveArgument(MethodParameter methodParameter,
                              ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest,
                              WebDataBinderFactory webDataBinderFactory) 
这个方法中的 ModelAndViewContainer和webDataBinderFactory 这两个对象的作用,怎样写能够优雅,欢迎大家不吝赐教。



                        <li class="tool-item tool-active is-like "><a href="javascript:;"><svg class="icon" aria-hidden="true">
                            <use xlink:href="#csdnc-thumbsup"></use>
                        </svg><span class="name">点赞</span>
                        <span class="count">2</span>
                        </a></li>
                        <li class="tool-item tool-active is-collection "><a href="javascript:;" data-report-click="{&quot;mod&quot;:&quot;popu_824&quot;}"><svg class="icon" aria-hidden="true">
                            <use xlink:href="#icon-csdnc-Collection-G"></use>
                        </svg><span class="name">收藏</span></a></li>
                        <li class="tool-item tool-active is-share"><a href="javascript:;"><svg class="icon" aria-hidden="true">
                            <use xlink:href="#icon-csdnc-fenxiang"></use>
                        </svg>分享</a></li>
                        <!--打赏开始-->
                                                <!--打赏结束-->
                                                <li class="tool-item tool-more">
                            <a>
                            <svg t="1575545411852" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5717" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M179.176 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5718"></path><path d="M509.684 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5719"></path><path d="M846.175 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5720"></path></svg>
                            </a>
                            <ul class="more-box">
                                <li class="item"><a class="article-report">文章举报</a></li>
                            </ul>
                        </li>
                                            </ul>
                </div>
                            </div>
            <div class="person-messagebox">
                <div class="left-message"><a href="https://blog.csdn.net/pozhenzi9010">
                    <img src="https://profile.csdnimg.cn/D/9/E/3_pozhenzi9010" class="avatar_pic" username="pozhenzi9010">
                                            <img src="https://g.csdnimg.cn/static/user-reg-year/1x/8.png" class="user-years">
                                    </a></div>
                <div class="middle-message">
                                        <div class="title"><span class="tit"><a href="https://blog.csdn.net/pozhenzi9010" data-report-click="{&quot;mod&quot;:&quot;popu_379&quot;}" target="_blank">七夜雪</a></span>
                                            </div>
                    <div class="text"><span>发布了5 篇原创文章</span> · <span>获赞 4</span> · <span>访问量 1万+</span></div>
                </div>
                                <div class="right-message">
                                            <a href="https://im.csdn.net/im/main.html?userName=pozhenzi9010" target="_blank" class="btn btn-sm btn-red-hollow bt-button personal-letter">私信
                        </a>
                                                            <a class="btn btn-sm  bt-button personal-watch" data-report-click="{&quot;mod&quot;:&quot;popu_379&quot;}">关注</a>
                                    </div>
                            </div>
                    </div>
    

    第一种方法,用包装类封装对象

    实体类对象

    1. public class User {
    2. private int id;
    3. private String userName;
    4. private String realName;
    5. public int getId() {
    6. return id;
    7. }
    8. public void setId(int id) {
    9. this.id = id;
    10. }
    11. public String getUserName() {
    12. return userName;
    13. }
    14. public void setUserName(String userName) {
    15. this.userName = userName;
    16. }
    17. public String getRealName() {
    18. return realName;
    19. }
    20. public void setRealName(String realName) {
    21. this.realName = realName;
    22. }
    23. @Override
    24. public String toString() {
    25. return "User{" +
    26. "id=" + id +
    27. ", userName='" + userName + '\'' +
    28. ", realName='" + realName + '\'' +
    29. '}';
    30. }
    31. }
    32. public class Info {
    33. private int id;
    34. private String address;
    35. public int getId() {
    36. return id;
    37. }
    38. public void setId(int id) {
    39. this.id = id;
    40. }
    41. public String getAddress() {
    42. return address;
    43. }
    44. public void setAddress(String address) {
    45. this.address = address;
    46. }
    47. @Override
    48. public String toString() {
    49. return "Info{" +
    50. "id=" + id +
    51. ", address='" + address + '\'' +
    52. '}';
    53. }
    54. }
    55. public class RequestParam {
    56. private User user;
    57. private Info info;
    58. public User getUser() {
    59. return user;
    60. }
    61. public void setUser(User user) {
    62. this.user = user;
    63. }
    64. public Info getInfo() {
    65. return info;
    66. }
    67. public void setInfo(Info info) {
    68. this.info = info;
    69. }
    70. }

    定义了三个实体 RequestParam里面又封装了User类和Info类

    JAVA代码

    1. @RequestMapping(value = "/show",method = RequestMethod.POST)
    2. public String show(@RequestBody RequestParam param){
    3. User user = param.getUser();
    4. Info info = param.getInfo();
    5. return user.toString();
    6. }

    前台代码

    1. $("#ok2").click(function(){
    2. var json = {"user":{"id":9527,"userName":"zcy","realName":"钢铁侠"},"info":{"id":998,"address":"纽约"}};
    3. $.ajax({
    4. url:"http://localhost:8080/more/show",
    5. type:"post",
    6. cache:false,
    7. contentType:"application/json",
    8. data:JSON.stringify(json),
    9. success:function(data){
    10. alert(data);
    11. }
    12. });
    13. });

    可以成功接收到对象,但是显得没有那么优雅,每次请求数据不同都要另外写一个包装类,显得很麻烦。


    第二种方法,用Map对象接收 更加简单粗暴

    JAVA代码

    1. @RequestMapping(value = "/show")
    2. public String test(@RequestBody Map<String,Object> map){
    3. // 拿到Object之后 再做转换为实体即可 可以用FastJson
    4. Object user = map.get("user");
    5. Object info = map.get("info");
    6. return "success";
    7. }

    也不够方便 每个对象还要再做一次转换

    第三种方法,使用自定义的HandlerMethodArgumentResolver

    自定义注解 加在控制器的参数前作为标记

    1. @Target(ElementType.PARAMETER)
    2. @Retention(RetentionPolicy.RUNTIME)
    3. @Documented
    4. public @interface JsonObject {
    5. }

    自定义处理类 实现HandlerMethodArgumentResolver接口

    1. public class JsonObjectArgResolverHandler implements HandlerMethodArgumentResolver {
    2. @Override
    3. public boolean supportsParameter(MethodParameter methodParameter) {
    4. return methodParameter.hasParameterAnnotation(JsonObject.class);
    5. }
    6. @Override
    7. public Object resolveArgument(MethodParameter methodParameter,
    8. ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest,
    9. WebDataBinderFactory webDataBinderFactory) throws Exception {
    10. // 获取Controller中的参数名
    11. String name = methodParameter.getParameterName();
    12. // 获取Controller中参数的类型
    13. Class clazz = methodParameter.getParameterType();
    14. Object arg = null;
    15. // 获取该参数实体的所用属性
    16. Field[] fields = clazz.getDeclaredFields();
    17. // 实例化
    18. Object target = clazz.newInstance();
    19. // 创建WebDataBinder对象 反射 遍历fields给属性赋值
    20. WebDataBinder binder = webDataBinderFactory.createBinder(nativeWebRequest,null,name);
    21. for (Field field:fields){
    22. field.setAccessible(true);
    23. String fieldName = field.getName();
    24. Class<?> fieldType = field.getType();
    25. // 在request中 多对象json数据的key被解析为 user[id] user[realName] info[address] 的这种形式
    26. String value = nativeWebRequest.getParameter(name + "[" + fieldName + "]");
    27. arg = binder.convertIfNecessary(value,fieldType,methodParameter);
    28. field.set(target,arg);
    29. }
    30. return target;
    31. }
    32. }

    注册自己写的处理类

    1. @Component
    2. public class MyWebAppConfig implements WebMvcConfigurer {
    3. @Override
    4. public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
    5. // 配置自定义接收参数
    6. WebMvcConfigurer.super.addArgumentResolvers(resolvers);
    7. resolvers.add(new JsonObjectArgResolverHandler());
    8. }
    9. }

    Controller

    1. @RequestMapping(value = "/custom")
    2. public String custom(@JsonObject User user, @JsonObject Info info){
    3. System.out.println(user.toString());
    4. System.out.println(info.toString());
    5. return "success";
    6. }

    前台代码

    1. $("#ok2").click(function(){
    2. var json = {"user":{"id":9527,"userName":"zcy","realName":"钢铁侠"},"info":{"id":998,"address":"纽约"}};
    3. $.ajax({
    4. url:"http://localhost:8080/more/custom",
    5. type:"post",
    6. cache:false,
    7. // 直接传josn对象 这里与上文不同
    8. data:json,
    9. success:function(data){
    10. alert(data);
    11. }
    12. });
    13. });

    第三种方式相对比较好 但我有几点还是没明白

    public Object resolveArgument(MethodParameter methodParameter,
                                  ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest,
                                  WebDataBinderFactory webDataBinderFactory) 
    这个方法中的 ModelAndViewContainer和webDataBinderFactory 这两个对象的作用,怎样写能够优雅,欢迎大家不吝赐教。



    易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
    该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!