Spring MVC 数据绑定

【基本类型 or 包装类型】

基本类型 => 必传 (不传的话爆 500 服务器端的错)

包装类型 => 可选 不传为 null(+ @RequestParam )

 

【数组类型】

基本类型 包装类型 String[]

 

【POJO】

前端传 POJO 的字段就可以。

=》 如果字段也是 POJO ,比如 ContactInfo,前端传 contanctInfo.phone 即可。

=》 如果方法入参是两个相似的 POJO ,比如 Admin 和 User,前端传 admin.name 和 user.name 即可,但需要后端配合 @InitBinder

@InitBinder
public void initUser(WebDataBinder binder){
    binder.setFieldDefaultPrefix("user.");
}

@InitBinder
public void initAdmin(WebDataBinder binder){
    binder.setFieldDefaultPrefix("admin.");
}

 

【List Set Map】

List 【适合:连续的索引】

前端传 【/list.do?users[0].name=Bob&users[99].name=Alice】,后端配合 UserListForm 实现数据绑定。(规律就是 SpringMVC 允许前端传 Pojo 的字段过来)

@Data // lombok setter getter 
public class UserListForm{ private List<User> users; } // Controller 相关代码 @GetMapping("list.do")
@ResponseBody
public String addUsers(UserListForm userListForm){ return userListForm.toString(); }//坑:userListForm.getUserList().size = 前端最大索引99

 

 

Set 【坑:目的用来排重,但是 Spring MVC 初始化 Set 索引大小是按照 前端传的数据去重后的大小,因为 index < set.size() 然后抛异常】

【绕过坑的办法,Set 转 List 返回给前端,用 List 进行前端数据绑定】

POJO => 配合 Set ,实现 equals 和 hashcode 方法,equals 相同 hashcode 必须相同,equals 不同 hashcode可以相同,没那么绕,因为 equals 比较的字段比 hashcode 多。

 

前端传 【/set.do?users[0].name=Alice&users[99].name=Alice】,后端配合 UserSetForm 实现数据绑定(相对 List 要求初始化 Set,所以索引是确定的)。

// 代码 【数据绑定实现方式 和 List 相似】

 

 

Map【适合:Map<String,Object>】

 

前端传 【/map.do?users["X"].name=Tom&users["X"].name=Alice】,后端配合 UserMapForm 实现数据绑定。

// 代码 【数据绑定实现方式 和 List 相似】

 

 

【JSON XML】

JSON ,前端传一个 User 的 Json 对象,后端使用 @RequestBody 支持入参实现数据绑定。

<dependency>
    <groupId>org.codehaus.jackson</groupId>
    <artifactId>jackson-mapper-asl</artifactId>
    <version>1.9.13</version>
</dependency>


@GetMapping("json.do")
@ResponseBody
public String getJson(@RequestBody User user){ return user.toString(); }

 

 

XML 前端传 xml ,后端使用 @XmlRootElement @XmlElement ,其他和 JSON 数据绑定相似。

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-oxm</artifactId>
    <version>4.3.17.RELEASE</version>
</dependency>


// 注解 POJO 
@XmlRootElement(name = "user")
@Data // lombok
public class User{
    @XmlElement(name = "name")
    private Sring name;
    
    @XmlElement(name = "age")
    prviate int age;          
}

/////////////////////////////
// Controller 

 

 

 

【PropertyEditor PropertyEditorSupport】局部使用 WebDataBinder

约定 前端传 "foo,19"

 

public class MyPropertyEditor extends PropertyEditorSupport{
    @Override
    public void setAsText(String text)throws Ille...{
        String[] textArray = text.spilt(",");
        User user = new User();
       
        user.setName(textArray[0]);
        user.setAge(Integer.parseInt(textArray[1]));
        this.setValue(user);
    }    
}

 

 

 

解决问题一 前端传 /date1.do?date1=2018-01-01 后端使用 webdatabinder 仍然使用 Spring MVC 的数据绑定功能。

 

@GetMapping("date1.do")
@ResponseBody
public String getDate1(Date date1){
    return date1.toString();  
}

@InitBinder
public void initDate1(WebDataBinder binder){
    binder.registerCustomEditor(Date.class,
        new CustomEditor(
            new SimpleDateFormat("yyyy-MM-dd"),true));
}

 

 

 

 

【Formatter<T> extends Printer<T>, Parser<T>】 针对 String 

 

    @Test
    public void testPrint(){
        CurrencyFormatter formatter = new CurrencyFormatter();
        formatter.setFractionDigits(2);//保留小数后2位
        formatter.setRoundingMode(RoundingMode.CEILING);
        Assert.assertEquals("$123.00",formatter.print(new BigDecimal("123"), Locale.US));
    }
    @Test
    public void testParse() throws ParseException {
        CurrencyFormatter formatter = new CurrencyFormatter();
        formatter.setFractionDigits(2);//保留小数后2位
        formatter.setRoundingMode(RoundingMode.CEILING);
        Assert.assertEquals(new BigDecimal("123.13"),formatter.parse("$123.125", Locale.US));
    }

解决问题一 (全局)

public class MyDateFormatter implements Formatter<Date>{
    @Override
    public Date parse(String text,Locale locale) throws ParseE{
        SimpleDateFormat sdf = new Sim("yyyy-MM-dd");
        return sdf.parse(text);
    }
// print method
}

//dispatcherServlet
<context:component-scan base-package="com" annotation-config="true"/>
<mvn:annotation-driven conversion-service="myDateFormatter"/> 
<bean id="myDateFormatter" class="springframework.format.support.FCServiceFactoryBean"
    <property name="formatters">
        <set>
            <bean class="MyDateFormatter">
               
            </bean>
        </set>
    </property>
<bean>        

 

 

【Converter 】内置的不可扩展 final ,我们要直接实现接口

解决问题一(全局 + 可自定义类型)

public class MyDateConverter implements Converter<String,Date>{
    @Override
    public Date convert(String src) throws ParseE{
        SimpleDateFormat sdf = new Sim("yyyy-MM-dd");
        return sdf.parse(src);
    }
}

//dispatcherServlet
<context:component-scan base-package="com" annotation-config="true"/>
<mvn:annotation-driven conversion-service="myDateConverter"/> 
<bean id="myDateConverter" class="org.springframework.format.support.FCServiceFactoryBean"
    <property name="convertters">
        <set>
            <bean class="MyDateConverter">
               
            </bean>
        </set>
    </property>
<bean>   

 

…………………………

【RESTful URI】

https://book.douban.com/subject/3024391/ 对,用了名词

https://book.douban.com/show/subject/3024391/ 错,不应该用动词

@GetMapping("/subject/{subjectId}")
@ResponseBody
public String getOneBook(@PathVariable("subjectId")Integer subjectId){

    return bookService.selectBookByPrimaryKey(subjectId).toString();
}

 

 

POST /accounts/1/transfer/500/to/2 错

POST /transaction

from=1&to=2&amount=500.00

 

www.example.com/app/v1 不好

www.example.com/app   使用 HEADER version=1.0

 

posted @ 2018-06-11 13:34  chenhui7373  阅读(174)  评论(0编辑  收藏  举报