SpringMVC-4 处理模型数据

本文介绍了SpringMVC中处理模型数据的四种方法:使用ModelAndView、Map或Model、@SessionAttributes和@ModelAttribute,详细解释了每种方法的工作原理及应用场景。

  在SpringMVC中处理模型数据的具体实现代码下载地址:http://download.youkuaiyun.com/download/bingbeichen/9793370
  SpringMVC主要提供了以下几种途径来处理模型数据,即:

  • ModelAndView:目标处理器中处理方法的返回值类型为ModelAndView时, 方法体即可通过该对象添加模型数据;
  • Map及Model:入参为org.springframework.ui.Model、org.springframework.ui.ModelMap或java.uti.Map时,目标处理器中处理方法返回时,Map中的数据会自动添加到模型中;
  • @SessionAttributes:将模型中的某个属性暂存到HttpSession中,以便多个请求之间可以共享该属性;
  • @ModelAttribute:目标处理器中处理方法的入参标注该注解后,入参的对象即会放到数据模型中。

1. ModelAndView

  在目标处理器的处理方法中,若返回值为ModelAndView类型,则其既包含视图信息又包含模型数据信息。

@RequestMapping("/processModelData")
@Controller
public class ProcessModelData {

    private static final String SUCCESS = "success";

    /**
     * 目标方法的返回值可以是ModelAndView类型,其可以包含视图和模型数据
     * 原理:SpringMVC会将ModelAndView的model中的数据存放到request域对象中
     * @return
     */
    @RequestMapping("/testModelAndView")
    public ModelAndView testModelAndView() {
        ModelAndView modelAndView = new ModelAndView(SUCCESS);
        // 目标页面中可以直接用“${requestScope.time}”来获取所存放的模型数据
        modelAndView.addObject("time", new Date());
        return modelAndView;
    }

}

2. Map及Model

  Spring MVC在内部使用org.springframework.ui.Model接口来存储模型数据。即Spring MVC在调用目标方法前会创建一个隐含的模型对象作为模型数据的存储容器;如果方法的入参为Map或Model类型,Spring MVC会将隐含模型的引用传递给该入参。因此,在方法体内,开发者即可以通过该入参对象访问到模型中的所有数据,也可以向模型中添加新的属性数据。

@RequestMapping("/processModelData")
@Controller
public class ProcessModelData {

    private static final String SUCCESS = "success";

    /**
     * 目标方法可以添加Map类型的参数,实际上也可以是Model或ModelMap类型
     * @param map
     * @return
     */
    @RequestMapping("/testMap")
    public String testMap(Map<String, Object> map) {
        System.out.println(map.getClass().getName()); // BindingAwareModelMap
        // 在目标页面可以通过“${requestScope.names}”的方式来访问模型数据
        map.put("names", Arrays.asList("qiaobc", "qiaob", "qiaodb"));
        return SUCCESS;
    }

}

3. @SessionAttributes注解

  若希望在多个请求之间共用某个模型属性数据,则可以在控制器类上标注一个@SessionAttributes注解, Spring MVC将把模型中对应的属性暂存到HttpSession中。

@SessionAttributes(value={"username"}, types={Date.class})
@RequestMapping("/processModelData")
@Controller
public class ProcessModelData {

    private static final String SUCCESS = "success";

    /**
     * @SessionAttributes注解:
     *  1). 既可以通过属性名指定需要放到会话中的属性(实际上使用的是value属性值)
     *  2). 也可以通过属性类型指定要放到会话中的属性(实际上使用的是types属性值)
     *  3). 注意:该注解只可以标记在类上,而不能标记在方法上
     * @param map
     * @return
     */
    @RequestMapping("/testSessionAttributes")
    public String testSessionAttributes(Map<String, Object> map) {
        map.put("username", "whut-qiaobc");
        map.put("birth", new Date());
        return SUCCESS;
    }

}

4. @ModelAttribute注解

4.1 使用场景

  在更新数据表记录且记录中存在不能修改的字段时,会先在目标方法中新建一个对应类的对象,表单会将修改后的字段值传递给该对象的指定属性,而不能修改字段的属性值却为空;此时,可在form表单中添加隐藏域(缺点:不便维护、可能泄露隐私)或从数据库中重新查找出该字段值。
  在SpringMVC中即可先从数据库中获取模型数据,再根据表单参数修改获取的模型数据,进而进行更新操作,具体如下图所示:
  这里写图片描述

4.2 具体实现
//@SessionAttributes(value={"username"}, types={Date.class})
@RequestMapping("/processModelData")
@Controller
public class ProcessModelData {

    private static final String SUCCESS = "success";

    /**
     * 1. @ModelAttribute注解标记的方法会在每个目标方法执行之前执行
     * 2. @ModelAttribute注解也可以修饰目标方法POJO类型的入参,其value属性值有如下作用:
     *      > SpringMVC会使用value属性值在implicitModel中查找对应的对象,若存在则直接入参
     *      > SpringMVC会以value为key、POJO类型的对象为value,放入request域对象中
     * @param id
     * @param map
     */
    @ModelAttribute
    public void getUserModel(@RequestParam(value="id", required=false) Integer id, Map<String, Object> map) {
        if(id != null) {
            // 模拟从数据库获取记录
            User user = new User(1, "whut-qiaobc", "qiaobc@whut.edu.cn", "123456", 23);
            System.out.println("修改前:" + user);
            // 将记录放入request请求域中
            map.put("user", user);
        }
        System.out.println("@ModelAttribute");
    }

    @RequestMapping("/testModelAttribute")
    public String testModelAttribute(User user) {
        System.out.println("修改后:" + user);
        return SUCCESS;
    }

}
<!-- 模拟修改数据库记录 -->
<form action="processModelData/testModelAttribute" method="post">
    <input type="hidden" name="id" value="1">
    username:<input type="text" name="username" value="whut-qiaobc">
    <br><br>
    email:<input type="text" name="email" value="qiaobc@whut.edu.cn">
    <br><br>
    age:<input type="text" name="age" value="23">
    <br><br>
    <input type="submit" value="submit">
</form>

  注意:在使用SpringMVC进行数据绑定时,要主要目标控制器中处理方法的参数名与请求页面中的参数名相同,否则会出现“The request sent by the client was syntactically incorrect().”错误,其实质即是SpringMVC在进行参数绑定时出错。

4.3 运行流程
/**
 * 运行流程:
 *  1. 执行@ModelAttribute注解修饰的方法,即从数据库获取对象,并将该对象放入Map中(键为user)
 *  2. SpringMVC从Map中取出User对象,并将表单的请求参数赋给该User对象对应的属性
 *  3. SpringMVC将User对象传递给目标方法的入参
 *  
 * 特别注意:在@ModelAttribute标记的方法中,放入Map的键应与目标方法入参类型的小写字符串一致
 * 
 * 源代码分析的运行流程:
 *  1. 调用@ModelAttribute注解修饰的方法,实际上是将该方法Map中的数据放入到implicitModel中
 *  2. 解析请求处理器的目标参数,实际上该目标参数来自于WebDataBinder对象的target属性
 *      1). 创建WebDataBinder对象
 *          a). 确定ObjectName属性:
 *              > 若传入的attrName属性值为"",则objectName为目标方法的入参类型名称的第一个字母小写
 *              * 注意:若目标方法的POJO属性使用@ModelAttribute注解修饰,则attrName为其value属性值
 *          b). 确定target属性:
 *              > 在implicitModel中查找attrName对应的属性值,存在则返回;
 *              > 若不存在,则验证当前处理器是否使用@sessionAttributes注解修饰:
 *                  > 若使用,且其value值指定的key与attrName相匹配 或 其types值指定的类型与目标方法的入参类型相匹配
 *                      > 则尝试从Session中获取attrName对应的属性值,若获取不到则抛出异常
 *              > * 否则,则根据目标方法的参数类型以反射的方式创建POJO对象。
 *      2). SpringMVC调用doBind()方法将表单的请求参数赋给WebDataBinder的target对应的属性
 *      3). * SpringMVC将WebDataBinder的attrName和target属性赋给implicitModel,进而传到request域对象中
 *  3. 将WebDataBinder的target作为参数传递给目标处理器处理方法的入参
 * 
 */
4.4 确定目标方法POJO类型参数的入参过程
/**
 *  1. 确定key
 *      1). 若目标方法的POJO类型参数使用@ModelAttribute修饰,则key为其value属性值
 *      2). 若未使用则key为目标方法POJO类型名称的第一个字母小写
 *  2. 先在implicitModel中查找key对应的对象,若存在则作为入参传入
 *      若在@ModelAttribute修饰的方法中向Map中保存过,且key与上述key相同则可获取到
 *  3. 若在implicitModel中不存在key对应的对象,则检查当前handler是否标记了@SessionAttributes注解
 *      1). 若使用,且注解的value属性值包含key,则尝试从HttpSession中获取key对应的属性
 *      2). 若存在则直接传入目标方法的入参中,若不存在则抛出异常
 *  4. 若当前handler未标记@SessionAttributes注解 或 该注解的value属性值不包含key,则通过反射创建POJO并入参
 *  5. SpringMVC将key和POJO类型的对象保存到implicitModel中,进而保存到request域对象中
 */
4.5 避免@SessionAttributes所引发的异常

  根据运行流程分析可知,当标记类的注解@SessionAttributes(value={"user"}, types={Date.class})与目标方法public String testModelAttribute(User user){}相遇,且implicitModel中没有user对应的属性时,则SpringMVC会尝试从会话中获取user对应的属性,若获取失败则会抛出HttpSessionRequiredException异常。

本系统采用Python编程语言中的Flask框架作为基础架构,实现了一个面向二手商品交易的网络平台。该平台具备完整的前端展示与后端管理功能,适合用作学术研究、课程作业或个人技术能力训练的实际案例。Flask作为一种简洁高效的Web开发框架,能够以模块化方式支持网站功能的快速搭建。在本系统中,Flask承担了核心服务端的角色,主要完成请求响应处理数据运算及业务流程控制等任务。 开发工具选用PyCharm集成环境。这款由JetBrains推出的Python专用编辑器集成了智能代码提示、错误检测、程序调试与自动化测试等多种辅助功能,显著提升了软件编写与维护的效率。通过该环境,开发者可便捷地进行项目组织与问题排查。 数据存储部分采用MySQL关系型数据库管理系统,用于保存会员资料、产品信息及订单历史等内容。MySQL具备良好的稳定性和处理性能,常被各类网络服务所采用。在Flask体系内,一般会配合SQLAlchemy这一对象关系映射工具使用,使得开发者能够通过Python类对象直接管理数据实体,避免手动编写结构化查询语句。 缓存服务由Redis内存数据库提供支持。Redis是一种支持持久化存储的开放源代码内存键值存储系统,可作为高速缓存、临时数据库或消息代理使用。在本系统中,Redis可能用于暂存高频访问的商品内容、用户登录状态等动态信息,从而加快数据获取速度,降低主数据库的查询负载。 项目归档文件“Python_Flask_ershou-master”预计包含以下关键组成部分: 1. 应用主程序(app.py):包含Flask应用初始化代码及请求路径映射规则。 2. 数据模型定义(models.py):通过SQLAlchemy声明与数据库表对应的类结构。 3. 视图控制器(views.py):包含处理各类网络请求并生成回复的业务函数,涵盖账户管理、商品展示、订单处理等操作。 4. 页面模板目录(templates):存储用于动态生成网页的HTML模板文件。 5. 静态资源目录(static):存放层叠样式表、客户端脚本及图像等固定资源。 6. 依赖清单(requirements.txt):记录项目运行所需的所有第三方Python库及其版本号,便于环境重建。 7. 参数配置(config.py):集中设置数据库连接参数、缓存服务器地址等运行配置。 此外,项目还可能包含自动化测试用例、数据库结构迁移工具以及运行部署相关文档。通过构建此系统,开发者能够系统掌握Flask框架的实际运用,理解用户身份验证、访问控制、数据持久化、界面动态生成等网络应用关键技术,同时熟悉MySQL数据库运维与Redis缓存机制的应用方法。对于入门阶段的学习者而言,该系统可作为综合性的实践训练载体,有效促进Python网络编程技能的提升。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值