zoukankan      html  css  js  c++  java
  • 复杂结构数据提交

    问题抛出

    在前台需要一次保存结构复杂的数据组织,界面原型如下:

    复杂结构数据提交-原型

    导致问题复杂的原因有2个:

    1. 多实例
    如界面原型所示,绿茶属于一个实例,白茶属于另一个实例。多实例下,需要保证实例之间的属性的隔离性,以及可能的实例之间的顺序。

    2. 属性结构复杂
    实体的属性不再都是简单的类型,例如主要成茶就是一个一维集合类型。多维度下,需要保证复杂类型属性的值结构,比如说值的顺序。

    笨拙的方案

    基于表单提交的形式,将含有name属性值、非disable的input元素,按照name进行组织。相同name的input元素,以一维数组的形式进行组织。这种形式对数据的组织是浅层的:在后台可以得到的结果仅仅是线性的参数序列,每个参数值或者是简单的字符串,或者是一维字符数组。当想要实现更高层的数据结构时,需要在前台进行低维展开,在后台进行高维收缩。

    前台的低维展开,可以借助于为name添加前缀来实现。比如绿茶和白茶,本来都应该是name=“kind”,可以展开成一个name="lc_kind"和name=“bc_kind”;同理,发酵程度degree可 以展开成name="lc_degree"和name="bc_degree"。需要考虑排重。

    后台的高维收缩,根据name的前缀进行关联和数据的重新结构化。后台的收缩逻辑需要和前台的展开逻辑相一致,就好像序列化与反序列化、加密和解密。前台和后台的耦合度会比较高。

    推荐的方案

    JS对象+序列化+异步提交。

    1. 组织和封装

    以JS对象格式组织数据,最终封装到一个顶层的js对象或者数组里。比如界面原型中的数据结构,可以这样封装:

     1 var lc = {
     2     "kind": "绿茶",
     3     "degree": "0%",
     4     "example": ["龙井", "瓜片", "碧螺春茶", "毛峰茶", "云雾茶"]
     5 };
     6 var bc = {
     7     "kind": "白茶",
     8     "degree": "5%-10%",
     9     "example": ["包种茶", "白毫银针茶", "白牡丹茶", "香片"]   
    10 };
    11 var teas = [lc, bc]; 

    当然,各属性的值是需要通过定位dom元素来获取的,而不是常量。最后的teas就是组织封装之后的结果,在这种情形里,封装的结果是一个数组;还有一种情况,封装的结果是一个普通的对象。数组在后台会被解析成List结构,普通对象在后台会被解析成Map结构。

    2. 序列化

    var data = JSON.stringify(teas);

    注:需要引入依赖的json.js文件。

    3. 异步提交

     1 $.ajax({
     2     url : "/basic/demo/cds/report.action",
     3     type : "post",
     4     data : data,
     5     dataType : "json",
     6     contentType : "application/json; charset=GBK", // so important
     7     success : function(response) {
     8         if (response.state == "success") {
     9             alert("保存成功!");
    10         } else {
    11             alert("保存失败!");
    12         }
    13     },
    14     error : function (response) {
    15         alert("保存失败!");
    16     }
    17 }); 

    注:
    a. 这里data是序列化的结果;
    b. 要求发送数据至服务器时,内容编码类型contentType是 “application/json”,而默认的是“application/x-www-form-urlencoded”,所以需要显示设置;所以在jquery提供的ajax系列方法中,只能使用原生的$.ajax(url,[settings])了。

    4. 后台解析

    后台会将数据解析成List或者Map结构(数组则解析成List,普通对象则解析成Map,也可以都作为Object对象来对待)。

    1 @RequestMapping("/report")
    2 public String report(Model model, @RequestBody List<Map<String, Object>> teas) {
    3     model.addAttribute("state", "success");
    4     model.addAttribute("data", teas);
    5     return VIEW_JSON;
    6 } 

    注:参数必须使用@RequestBody注解,且只需要一个这样的参数, 所有的请求参数都解析到了注解对应的参数中;即使声明了更多的参数,也无用。

    问题记录

    1. 自动解析成Bean的集合

    后台获取到的数据,是List、Map交互嵌套,叶子元素为String的结构体;而不是对应bean的结构体。我们需要另外进行转换,包括将String类型的数据转换为其他类型,将Map转化为Bean。
    该问题目前无解。

    2. 额外的配置

    根据之前的预研,是需要在spring-mvc相关配置中添加一些配置,将 MappingJacksonHttpMessageConverter的bean注入AnnotationMethodHandlerAdapter的 messageConverters属性中:

    1 <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
    2     <property name="messageConverters">
    3         <list>
    4             <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" />
    5         </list>
    6     </property>
    7 </bean> 

    但是最新的尝试,没有配置也可行。

    3. 新窗口打开

    在某种“预览”的需求下,根据当前的临时数据,进行展示。如果临时数据结构复杂,应该使用文中推荐的方案,并返回一个url。js脚本使用url打开新窗口,展示临时数据。ajax异步提交的数据要在新的页面中使用,涉及到缓存。可以缓存到session里,或者数据库。推荐缓存到session里,参考在Spring Controller中将数据缓存到session

  • 相关阅读:
    Spring容器启动前传——web应用
    三方依赖bean初始化导致项目启动失败问题
    一个静态内部类单例引发的思考
    依赖传递
    kafka
    设置旋转元素的基点位置
    keep-alive 的 Props && 钩子函数
    css处理文字: 单行居中 多行居左
    localStorage 存 取 删
    for循环中暂停,async await
  • 原文地址:https://www.cnblogs.com/ywjy/p/5016152.html
Copyright © 2011-2022 走看看