SpringMVC 之 @ModelAttribute&OOP处理

SpringMVC 之 @ModelAttribute&OOP处理

本节我们将学习一下SpringMVC中 @ModelAttribute 作用以及SpringMVC 对对象处理的方法和实现思路。


概念

在Spring mvc中,注解@ModelAttribute是一个非常常用的注解,其功能主要在两方面:

  • 运用在参数上,会将客户端传递过来的参数按名称注入到指定对象中,并且会将这个对象自动加入ModelMap中,便于View层使用同时也支持Controller层的调用。

  • 运用在方法上,会在每一个@RequestMapping标注的方法前执行,如果被调用的Controller方法有返回值,则自动将@ModelAttribute修饰方法中的对象加入到ModelMap中。


使用场景

假设现在我们需要处理这么一个问题:我们在实体层定义了一个Contract(合同实体),假设它拥有100个属性,现在用户需要在平台上修改他的合同,那么我们希望以下功能能被实现:

  • 该合同的某一些敏感属性不能被修改比如合同甲乙方,监管合同的Clean house等等。
  • 基于上述条件成立,我们只对用户提交的字段做修改处理,其他的字段一律不做修改。

如果只是为了实现以上功能不用Spring MVC 提供的任何功能使用纯JAVA EE 代码即可实现,但这样不高效,代码还会很臃肿。SpringMVC 为我们提供了这么一个简洁高效的处理POJO的方法那就是 @ModelAttribute


实例

  • ExampleController.java

    package com.spring.sstps.controller;
    
    import org.springframework.web.bind.annotation.ModelAttribute;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.servlet.ModelAndView;
    
    import com.spring.sstps.pojo.Contract;
    import com.spring.sstps.pojo.TradePolicy;
    
    @RestController("/example")
    public class ExampleController {
    
        @ModelAttribute("contract")
        public Contract getContractInfo(@RequestParam(value = "id", required = false) Integer id) {
            Contract contract = null;
            if (id == null) {
                System.out.println("Id is inavaliable-----");
                try {
                    TradePolicy tradePolicy = new TradePolicy("EPGR", "epClear");
                    contract = new Contract("c:yujh4464564", "tx41574644", "2017-11-28 18:18:18", "NA", tradePolicy);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } else {
                System.out.println("Id is avaliable:" + id);
            }
    
            return contract;
    
        }
    
        @RequestMapping("/saveContract")
        public ModelAndView setContract(@ModelAttribute("contract") Contract contract) throws Exception {
            ModelAndView modelAndView = new ModelAndView();
            // 每一次调用该方法都将强制修改 ContractId 属性的至
            System.out.println("Contract:" + contract);
            modelAndView.addObject("CONTRACT", contract);
            modelAndView.setViewName("contract/saveContract");
            return modelAndView;
        }
    
        @RequestMapping("/toSaveContract")
        public String tosetContract() throws Exception {
            return "contract/toSaveContract";
        }
    }
    
  • Contract.java

    package com.spring.sstps.pojo;
    
    public class Contract {
    
        private String contractId;
        private String contractTxId;
        private String createTime;
        private String area;
        private TradePolicy tradePolicy;
        public Contract(String contractId, String contractTxId, String createTime, String area, TradePolicy tradePolicy) {
            super();
            this.contractId = contractId;
            this.contractTxId = contractTxId;
            this.createTime = createTime;
            this.area = area;
            this.tradePolicy = tradePolicy;
        }
        public String getContractId() {
            return contractId;
        }
        public void setContractId(String contractId) {
            this.contractId = contractId;
        }
        public String getContractTxId() {
            return contractTxId;
        }
        public void setContractTxId(String contractTxId) {
            this.contractTxId = contractTxId;
        }
        public String getCreateTime() {
            return createTime;
        }
        public void setCreateTime(String createTime) {
            this.createTime = createTime;
        }
        public String getArea() {
            return area;
        }
        public void setArea(String area) {
            this.area = area;
        }
        public TradePolicy getTradePolicy() {
            return tradePolicy;
        }
        public void setTradePolicy(TradePolicy tradePolicy) {
            this.tradePolicy = tradePolicy;
        }
        @Override
        public String toString() {
            return "Contract [contractId=" + contractId + ", contractTxId=" + contractTxId + ", createTime=" + createTime
                    + ", area=" + area + ", tradePolicy=" + tradePolicy + "]";
        }
    
    
    }
    
  • TradePolicy.java

    package com.spring.sstps.pojo;
    
    public class TradePolicy {
    
        private String clearHouse;
        private String epType;
    
        public TradePolicy(String clearHouse, String epType) {
            this.clearHouse = clearHouse;
            this.epType = epType;
        }
    
        public String getClearHouse() {
            return clearHouse;
        }
    
        public void setClearHouse(String clearHouse) {
            this.clearHouse = clearHouse;
        }
    
        public String getEpType() {
            return epType;
        }
    
        public void setEpType(String epType) {
            this.epType = epType;
        }
    
        @Override
        public String toString() {
            return "TradePolicy [clearHouse=" + clearHouse + ", epType=" + epType + "]";
        }
    }
    
  • JSP

    <%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"%>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>toSaveContract</title>
    </head>
    <body>
        <form action="saveContract" method="Post">
            ContractId:<input  type="text" name="contractId"/>
            <br>
            ContractTxId:<input type="text" name="contractTxId"  />
            <br>
            Area:<input type="text" name="area"/>
            <br>
            epType:<input type="text" name="tradePolicy.epType"/>
            <br>
            <input type="Submit" name="Submit"/>
            <br>
        </form>
    
    
    </body>
    </html>
  • 代码解读:

    • 有@ModelAttribute修饰的方法,在每一个目标方法被调用之前都将会被SpringMVC调用。

    • @ModelAttribute注解可以用来修饰目标方法的POJO类的入参,其value值(@ModelAttribute(“contract”)的value值为contract)作用如下:

      • SpringMVC 会使用value的属性值在implicitModel(所有POJO的集合,Map《String,Object类型>)中查找对象,如存在则直接传入到将目标方法中。

      • SpringMVC 会以 该value(此处特指contract) 为key, POJO类型的对象(入参之后的POJO即修改了属性之后的,接下来我们将学习目标方法的POJO入参过程)为Value 存入值request中。

    • POJO 支持级联入参(本例子),入参的value 要匹配 POJO 类的属性名称。

  • 以上代码运行流程:

    • 执行 @ModelAttribute 注解修饰的方法: 从数据库中取出对象, 把对象放入到了 implicitModel 的 Map 中. 键为: contract

    • SpringMVC 从 Map 中取出 Contract对象, 并把表单的请求参数赋给该 Contract对象的对应属性.

    • SpringMVC 把上述对象传入目标方法的参数.

    • 方法调用完毕之后 SpringMVC 将会把 Contract对象返回给视图层,供视图层调用。

注意: 在 @ModelAttribute 修饰的方法中, 放入到 Map 时的键需要和目标方法入参类型的第一个字母小写的字符串一致!


POJO 类型入的过程

  • 确定一个 key

    • 若目标方法的 POJO 类型的参数木有使用 @ModelAttribute 作为修饰, 则 key 为 POJO 类名第一个字母的小写

    • 若使用了 @ModelAttribute 来修饰, 则 key 为 @ModelAttribute 注解的 value 属性值

  • 在 implicitModel 中查找 key 对应的对象, 若存在, 则作为入参传入

    • 若在 @ModelAttribute 标记的方法中在 Map 中保存过, 且 key 和 1 确定的 key 一致, 则会获取到
  • 若 implicitModel 中不存在 key 对应的对象, 则检查当前的 Handler 是否使用 @SessionAttributes 注解修饰,若使用了该注解, 且 @SessionAttributes 注解的 value 属性值中包含了 key, 则会从 HttpSession 中来获取 key 所对应的 value 值, 若存在则直接传入到目标方法的入参中. 若不存在则将抛出异常

  • 若 Handler 没有标识 @SessionAttributes 注解或 @SessionAttributes 注解的 value 值中不包含 key, 则会通过反射来创建 POJO 类型的参数, 传入为目标方法的参数

  • SpringMVC 会把 key 和 POJO 类型的对象保存到 implicitModel 中, 进而会保存到 request 中


整体源代码理解过程

由于需要大量截图和大量实例来说明,下面我们只讲 Fuck Iterms !!!

  • 调用 @ModelAttribute 注解修饰的方法. 实际上把 @ModelAttribute 方法中 Map 中的数据放在了 implicitModel 中

  • 解析请求处理器的目标参数, 实际上该目标参数来自于 WebDataBinder 对象的 target 属性

    • 创建 WebDataBinder 对象

      • 确定 objectName 属性: 若传入的 attrName 属性值为 “”, 则 objectName 为类名第一个字母小写注意: attrName. 若目标方法的 POJO 属性使用了 @ModelAttribute 来修饰, 则 attrName 值即为 @ModelAttribute的 value 属性值

      • 确定 target 属性

      • 在 implicitModel 中查找 attrName 对应的属性值. 若存在,则直接赋值,若不存在: 则验证当前 Handler 是否使用了 @SessionAttributes 进行修饰, 若使用了, 则尝试从 Session 中获取 attrName 所对应的属性值. 若 session 中没有对应的属性值, 则抛出了异常

      • 若 Handler 没有使用 @SessionAttributes 进行修饰, 或 @SessionAttributes 中没有使用 value 值指定的 key和 attrName 相匹配, 则通过反射创建了 POJO 对象

  • SpringMVC 把表单的请求参数赋给了 WebDataBinder 的 target 对应的属性

  • SpringMVC 会把 WebDataBinder 的 attrName 和 target 给到 implicitModel近而传到 request 域对象中

  • 把 WebDataBinder 的 target 作为参数传递给目标方法的入参


小结

  • 总的来说SpingMVC 提供的@ModelAttribute 是OOP 的一个重要体现。

  • 要了解@ModelAttribute的作用需要理解 POJO 构造初始化、POJO入参、POJO构造完成整个流程。算是SpringMVC中比较抽象同时又是 狠狠狠 重要的一个功能点。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了小程序应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值