比较合适的前后端交互方式

这篇博客是对过去博客的整理与总结,现在,以下的博客都可以认为过时了。

使用Ajax向SpringMVC传递Json数据

存在日期类型的JSON数据,进行SpringMVC参数绑定时存在的问题和解决方案

SpringMVC配置数据验证(JSR-303)

 

前端发送请求

    var jsonObj = {
        'name' : '啊aaaa',                 // 乱码问题
        'date' : '1905-01-02 14:23:59',    // 时间转化问题
        'money' : '10.333',                // 小数
        'no' : '9',                        // 数字
        'serial' : '2147483999'            // Long
    };

    $.ajax({
        type : "post",
        url : "/interaction",
        dataType : "json",
        contentType : 'application/json',
        data : JSON.stringify(jsonObj),
        success : function(data) {
            alter(data);
        },
        error : function(data) {
            // TODO
        }
    });

 

没什么问题。

 

后端绑定参数

1、首先需要指定SpringMVC参数绑定之前的JSON转化策略,选择Jackson。

2、其次需要自定义一个ObjectMapper类,目的是在Jackson的ObjectMapper上追加定制对于日期转化的策略。

3、最后,把这些策略反映在SpringMVC的配置文件中。

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.9.0</version>
        </dependency>

 

public class JacksonObjectMapper extends ObjectMapper {

    private static final long serialVersionUID = -8909209092708797621L;

    public JacksonObjectMapper() {
        super();
        configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
    }

}

 

    <mvc:annotation-driven>
        <mvc:message-converters>
            <bean
                class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
                <property name="objectMapper">
                    <bean
                        class="io.spldeolin.bestpractice.util.JacksonObjectMapper"/>
                </property>
            </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>

 

通过写个请求方法和实体类来测试一下

    @RequestMapping(value = "interaction", method = RequestMethod.POST)
    @ResponseBody
    public String interaction(@RequestBody InteractionInput input) {
        LOG.info(input);
        return "success";
    }

 

package io.spldeolin.bestpractice.input;

import java.math.BigDecimal;
import java.util.Date;

public class InteractionInput {

    private String name;

    private Date date;

    private BigDecimal money;

    private Integer no;

    private Long serial;

  // getters and setters

}

 

 

结果

 

绑定失败时的处理

示例中,如果前端把jsonObj.date改成"1905-------01-------02 14爱上打是的:23ssssss:59"这样的非法格式,绑定就会失败,如图所示

 

这样的提示实际上不够友好(虽然发生的原因基本上是前端BUG),但最好还是捕获一下。

    @ExceptionHandler(HttpMessageNotReadableException.class)
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public String processHttpMessageNotReadableException(HttpMessageNotReadableException e) {
        return "请求不可读(可能原因:1.没有Request Body 2.Request Body格式有误)";
    }

 

结果

 

参数校验

参数绑定成功了,但最好再加一层校验,比如年龄,用Integer类型绑定,虽然上万的数字也可以成功绑定,但显然是不合理的。所以应该引入JSR303的实现

        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>5.4.1.Final</version>
        </dependency>

 

package io.spldeolin.bestpractice.input;

import java.math.BigDecimal;
import java.util.Date;
import javax.validation.constraints.Max;

public class InteractionInput {

    private String name;

    private Date date;

    @Max(value = 10L, message = "钱太多")
    private BigDecimal money;

    private Integer no;

    private Long serial;

  // getters and setters

}

 

    @RequestMapping(value = "interaction", method = RequestMethod.POST)
    @ResponseBody
    public String interaction(@RequestBody @Valid InteractionInput input, BindingResult checker) {
        // 这里只是为了演示,实际上这段解析BindingResult对象的代码最好抽到共通类中
        if (checker.hasFieldErrors()) {
            for (FieldError error : checker.getFieldErrors()) {
                String errmsg = error.getDefaultMessage();
                LOG.error(errmsg);
                return errmsg;
            }
        }
        LOG.info(input);
        return "success";
    }

 

 

返回值

最好返回一个实体类对象,而不是一个具体的String什么的,比如

    @RequestMapping(value = "interaction", method = RequestMethod.POST)
    @ResponseBody
    public RequestResult interaction(@RequestBody @Valid InteractionInput input, BindingResult checker) {
        // 这里只是为了演示,实际上这段解析BindingResult对象的代码最好抽到共通类中
        if (checker.hasFieldErrors()) {
            for (FieldError error : checker.getFieldErrors()) {
                String errmsg = error.getDefaultMessage();
                LOG.error(errmsg);
                return RequestResult.failure().errmsg(errmsg);
            }
        }
        LOG.info(input);
        return RequestResult.success().data("交互成功。(实际开发中data参数可以放各种想要传给前端的对象)");
    }

 

function interaction() {
    var jsonObj = {
        'name' : '啊aaaa', // 乱码问题
        'date' : '1905-01-02 14:23:59', // 时间转化问题
        'money' : '10.333', // 小数
        'no' : '9', // 数字
        'serial' : '2147483999' // Long
    };
    $.ajax({
        type : "post",
        url : "/interaction",
        dataType : "json",
        contentType : 'application/json',
        data : JSON.stringify(jsonObj),
        success : function(resp) {
            if (resp.result) {
                alert(resp.data);
                // 或者解析这个resp.data
            } else {
                alert(resp.errmsg);
            }
        },
        error : function(data) {
            // TODO
        }
    });
}

 

public class RequestResult {

    private boolean result;

    private Object data;

    private String errmsg;

    public boolean isResult() {
        return result;
    }

    private RequestResult() {}

    public static RequestResult success() {
        RequestResult instance = new RequestResult();
        instance.setResult(true);
        return instance;
    }

    public static RequestResult failure() {
        RequestResult instance = new RequestResult();
        instance.setResult(false);
        return instance;
    }

    public RequestResult data(Object data) {
        this.data = data;
        return this;
    }

    public RequestResult errmsg(String errmsg) {
        this.errmsg = errmsg;
        return this;
    }

}

 

posted @ 2017-12-06 16:31  Deolin  阅读(551)  评论(0编辑  收藏  举报